using the console input since the window is lagged on mac

This commit is contained in:
Adolfo Reyna
2026-01-12 22:36:57 -05:00
parent 257c858f98
commit 713d2c0cfd
3 changed files with 170 additions and 61 deletions

View File

@@ -7,7 +7,7 @@ CXXFLAGS = -std=c++11 -Wall
# Paths for Homebrew on macOS (Silicon/M1/M2/M3) # Paths for Homebrew on macOS (Silicon/M1/M2/M3)
ifeq ($(OS), Darwin) ifeq ($(OS), Darwin)
SFML_DIR = $(shell brew --prefix sfml) SFML_DIR = $(shell brew --prefix sfml@2)
INCLUDES = -I$(SFML_DIR)/include INCLUDES = -I$(SFML_DIR)/include
LIBS = -L$(SFML_DIR)/lib -lsfml-graphics -lsfml-window -lsfml-system LIBS = -L$(SFML_DIR)/lib -lsfml-graphics -lsfml-window -lsfml-system
else else

BIN
app

Binary file not shown.

211
main.cpp
View File

@@ -2,6 +2,9 @@
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include <cmath> #include <cmath>
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>
#include "./fonts/acme_5_outlines_font.h" #include "./fonts/acme_5_outlines_font.h"
const int V_WIDTH = 400; const int V_WIDTH = 400;
@@ -10,36 +13,55 @@ uint8_t bit_buffer[V_WIDTH * V_HEIGHT / 8];
// --- 1-BIT DRAWING PRIMITIVES --- // --- 1-BIT DRAWING PRIMITIVES ---
void set_pixel(int x, int y, bool on) { void set_pixel(int x, int y, bool on)
if (x < 0 || x >= V_WIDTH || y < 0 || y >= V_HEIGHT) return; {
if (x < 0 || x >= V_WIDTH || y < 0 || y >= V_HEIGHT)
return;
int bit_pos = y * V_WIDTH + x; int bit_pos = y * V_WIDTH + x;
if (on) bit_buffer[bit_pos / 8] |= (1 << (7 - (bit_pos % 8))); if (on)
else bit_buffer[bit_pos / 8] &= ~(1 << (7 - (bit_pos % 8))); bit_buffer[bit_pos / 8] |= (1 << (7 - (bit_pos % 8)));
else
bit_buffer[bit_pos / 8] &= ~(1 << (7 - (bit_pos % 8)));
} }
void draw_line(int x0, int y0, int x1, int y1, bool on) { void draw_line(int x0, int y0, int x1, int y1, bool on)
{
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1; int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2; int err = dx + dy, e2;
while (true) { while (true)
{
set_pixel(x0, y0, on); set_pixel(x0, y0, on);
if (x0 == x1 && y0 == y1) break; if (x0 == x1 && y0 == y1)
break;
e2 = 2 * err; e2 = 2 * err;
if (e2 >= dy) { err += dy; x0 += sx; } if (e2 >= dy)
if (e2 <= dx) { err += dx; y0 += sy; } {
err += dy;
x0 += sx;
}
if (e2 <= dx)
{
err += dx;
y0 += sy;
}
} }
} }
// Minimal 8x8 Bitmap Font (Example for 'A' and 'B') // Minimal 8x8 Bitmap Font (Example for 'A' and 'B')
void draw_char(int x, int y, char c) { void draw_char(int x, int y, char c)
{
static const uint8_t font[2][8] = { static const uint8_t font[2][8] = {
{0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00}, // A {0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00}, // A
{0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00} // B {0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00} // B
}; };
int idx = (c == 'A') ? 0 : 1; int idx = (c == 'A') ? 0 : 1;
for (int row = 0; row < 8; row++) { for (int row = 0; row < 8; row++)
for (int col = 0; col < 8; col++) { {
if (font[idx][row] & (1 << (7 - col))) set_pixel(x + col, y + row, true); for (int col = 0; col < 8; col++)
{
if (font[idx][row] & (1 << (7 - col)))
set_pixel(x + col, y + row, true);
} }
} }
} }
@@ -50,18 +72,23 @@ void draw_char(int x, int y, char c) {
* @param y Start y position * @param y Start y position
* @param c The character to draw * @param c The character to draw
*/ */
void draw_char_vcol(int x, int y, char c) { void draw_char_vcol(int x, int y, char c)
{
// The font table starts at space (ASCII 32) // The font table starts at space (ASCII 32)
if (c < 32 || c > 127) return; if (c < 32 || c > 127)
return;
int font_idx = c - 32; int font_idx = c - 32;
for (int col = 0; col < 6; col++) { for (int col = 0; col < 6; col++)
{
unsigned char column_byte = font[font_idx][col]; unsigned char column_byte = font[font_idx][col];
for (int row = 0; row < 8; row++) { for (int row = 0; row < 8; row++)
{
// Check if the bit for this row is set // Check if the bit for this row is set
// Most of these 1-bit fonts use bit 0 as the top pixel // Most of these 1-bit fonts use bit 0 as the top pixel
if (column_byte & (1 << row)) { if (column_byte & (1 << row))
{
set_pixel(x + col, y + row, true); set_pixel(x + col, y + row, true);
} }
} }
@@ -72,8 +99,10 @@ void draw_char_vcol(int x, int y, char c) {
* Draws a full string of text * Draws a full string of text
* @param spacing pixels between characters (usually 1 or 2) * @param spacing pixels between characters (usually 1 or 2)
*/ */
void draw_string(int x, int y, const std::string& text, int spacing = 1) { void draw_string(int x, int y, const std::string &text, int spacing = 1)
for (size_t i = 0; i < text.length(); i++) { {
for (size_t i = 0; i < text.length(); i++)
{
draw_char_vcol(x + (i * (6 + spacing)), y, text[i]); draw_char_vcol(x + (i * (6 + spacing)), y, text[i]);
} }
} }
@@ -82,20 +111,28 @@ void draw_string(int x, int y, const std::string& text, int spacing = 1) {
* Draws a scaled character using the 6x8 vertical column format * Draws a scaled character using the 6x8 vertical column format
* @param scale Integer multiplier (1 = 1x, 2 = 2x, etc.) * @param scale Integer multiplier (1 = 1x, 2 = 2x, etc.)
*/ */
void draw_char_scaled(int x, int y, char c, int scale) { void draw_char_scaled(int x, int y, char c, int scale)
if (c < 32 || c > 127) return; {
if (scale < 1) scale = 1; // Safety check if (c < 32 || c > 127)
return;
if (scale < 1)
scale = 1; // Safety check
int font_idx = c - 32; int font_idx = c - 32;
for (int col = 0; col < 6; col++) { for (int col = 0; col < 6; col++)
{
unsigned char column_byte = font[font_idx][col]; unsigned char column_byte = font[font_idx][col];
for (int row = 0; row < 8; row++) { for (int row = 0; row < 8; row++)
if (column_byte & (1 << row)) { {
if (column_byte & (1 << row))
{
// Draw a square of size [scale x scale] // Draw a square of size [scale x scale]
for (int sy = 0; sy < scale; sy++) { for (int sy = 0; sy < scale; sy++)
for (int sx = 0; sx < scale; sx++) { {
for (int sx = 0; sx < scale; sx++)
{
set_pixel(x + (col * scale) + sx, set_pixel(x + (col * scale) + sx,
y + (row * scale) + sy, y + (row * scale) + sy,
true); true);
@@ -109,65 +146,133 @@ void draw_char_scaled(int x, int y, char c, int scale) {
/** /**
* Draws a scaled string * Draws a scaled string
*/ */
void draw_string_scaled(int x, int y, const std::string& text, int scale, int spacing = 1) { void draw_string_scaled(int x, int y, const char* text, int scale, int spacing = 1)
for (size_t i = 0; i < text.length(); i++) { {
int i = 0;
while(text[i] != '\0')
{
// We multiply the character width (6) and spacing by the scale // We multiply the character width (6) and spacing by the scale
int next_x = x + (i * (6 + spacing) * scale); int next_x = x + (i * (6 + spacing) * scale);
draw_char_scaled(next_x, y, text[i], scale); draw_char_scaled(next_x, y, text[i], scale);
i++;
} }
} }
int main() { char command_buffer[256];
sf::RenderWindow window(sf::VideoMode(800, 600), "0.5Hz Update Emulator"); int command_buffer_index = 0;
int main()
{
// Save original terminal settings
struct termios old_tio, new_tio;
tcgetattr(STDIN_FILENO, &old_tio);
new_tio = old_tio;
new_tio.c_lflag &= (~ICANON & ~ECHO); // Disable canonical mode and echo
tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
sf::RenderWindow window(sf::VideoMode(400, 300), "0.5Hz Update Emulator");
std::vector<sf::Uint8> display_pixels(V_WIDTH * V_HEIGHT * 4); std::vector<sf::Uint8> display_pixels(V_WIDTH * V_HEIGHT * 4);
sf::Texture texture; sf::Texture texture;
texture.create(V_WIDTH, V_HEIGHT); texture.create(V_WIDTH, V_HEIGHT);
texture.setSmooth(false); // Keeps the 1-bit pixels sharp and blocky texture.setSmooth(false); // Keeps the 1-bit pixels sharp and blocky
sf::Sprite sprite(texture); sf::Sprite sprite(texture);
sprite.setScale(2.f, 2.f); sprite.setScale(1.f, 1.f);
sf::Clock clock; sf::Clock clock;
bool toggle = false; bool toggle = false;
while (window.isOpen()) { int counter = 0;
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) window.close();
}
while (window.pollEvent(event)) { while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed) if (event.type == sf::Event::Closed)
window.close(); window.close();
}
// Check for a single key press // Check for console input with timeout
if (event.type == sf::Event::KeyPressed) { fd_set readfds;
if (event.key.code == sf::Keyboard::Space) { FD_ZERO(&readfds);
// This happens only ONCE when you hit Space FD_SET(STDIN_FILENO, &readfds);
toggle = !toggle; struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000; // 10ms timeout
int retval = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);
if (retval > 0)
{
char c = getchar();
//printf("Key Pressed: %c\n", c);
if (c == '\n' || c == '\r')
{
printf("Command entered: %s\n", command_buffer);
command_buffer_index = 0;
command_buffer[0] = '\0';
}
else if (c == '\b' || c == 127) // Backspace
{
if (command_buffer_index > 0)
{
command_buffer_index--;
command_buffer[command_buffer_index] = '\0';
} }
} }
} else if (c >= 32 && c <= 126) // Printable characters
{
if (command_buffer_index < sizeof(command_buffer) - 1)
{
command_buffer[command_buffer_index++] = c;
command_buffer[command_buffer_index] = '\0';
}
}
// Update display immediately after input
// Clear buffer
for (int i = 0; i < sizeof(bit_buffer); i++)
bit_buffer[i] = 0;
// Draw content
draw_string_scaled(10, 10, "Hello World!", 3);
draw_string_scaled(10, 270, command_buffer, 1);
// Bridge: 1-bit to RGBA
for (int i = 0; i < V_WIDTH * V_HEIGHT; ++i)
{
bool is_on = (bit_buffer[i / 8] >> (7 - (i % 8))) & 1;
int base = i * 4;
sf::Uint8 color = is_on ? 0xFF : 0x00;
display_pixels[base] = display_pixels[base + 1] = display_pixels[base + 2] = color;
display_pixels[base + 3] = 255;
}
texture.update(display_pixels.data());
}
// --- TIMING LOGIC: Update twice per second (500ms) --- // --- TIMING LOGIC: Update twice per second (500ms) ---
if (clock.getElapsedTime().asMilliseconds() >= 500) { if (clock.getElapsedTime().asMilliseconds() >= 1000)
{
//printf("Updating display %d...\n", counter++);
clock.restart(); clock.restart();
toggle = !toggle; // Change something every half second toggle = !toggle; // Change something every half second
// Clear buffer // Clear buffer
for (int i = 0; i < sizeof(bit_buffer); i++) bit_buffer[i] = 0; for (int i = 0; i < sizeof(bit_buffer); i++)
bit_buffer[i] = 0;
// Draw content // Draw content
//draw_line(10, 10, 390, 290, true); // draw_line(10, 10, 390, 290, true);
draw_string_scaled(10, 10, "Hello World!", 3); draw_string_scaled(10, 10, "Hello World!", 3);
draw_string_scaled(10, 270, command_buffer, 1);
// Bridge: 1-bit to RGBA // Bridge: 1-bit to RGBA
for (int i = 0; i < V_WIDTH * V_HEIGHT; ++i) { for (int i = 0; i < V_WIDTH * V_HEIGHT; ++i)
{
bool is_on = (bit_buffer[i / 8] >> (7 - (i % 8))) & 1; bool is_on = (bit_buffer[i / 8] >> (7 - (i % 8))) & 1;
int base = i * 4; int base = i * 4;
sf::Uint8 color = is_on ? 0xFF : 0x00; sf::Uint8 color = is_on ? 0xFF : 0x00;
display_pixels[base] = display_pixels[base+1] = display_pixels[base+2] = color; display_pixels[base] = display_pixels[base + 1] = display_pixels[base + 2] = color;
display_pixels[base + 3] = 255; display_pixels[base + 3] = 255;
} }
texture.update(display_pixels.data()); texture.update(display_pixels.data());
@@ -176,6 +281,10 @@ int main() {
window.clear(); window.clear();
window.draw(sprite); window.draw(sprite);
window.display(); window.display();
} }
// Restore original terminal settings
tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
return 0; return 0;
} }