diff --git a/Makefile b/Makefile index 70ac9ab..21d05ee 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ CXXFLAGS = -std=c++11 -Wall # Paths for Homebrew on macOS (Silicon/M1/M2/M3) ifeq ($(OS), Darwin) - SFML_DIR = $(shell brew --prefix sfml) + SFML_DIR = $(shell brew --prefix sfml@2) INCLUDES = -I$(SFML_DIR)/include LIBS = -L$(SFML_DIR)/lib -lsfml-graphics -lsfml-window -lsfml-system else diff --git a/app b/app index 6485b87..5ae3212 100755 Binary files a/app and b/app differ diff --git a/main.cpp b/main.cpp index f4cc685..3ff510f 100644 --- a/main.cpp +++ b/main.cpp @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include "./fonts/acme_5_outlines_font.h" const int V_WIDTH = 400; @@ -10,36 +13,55 @@ uint8_t bit_buffer[V_WIDTH * V_HEIGHT / 8]; // --- 1-BIT DRAWING PRIMITIVES --- -void set_pixel(int x, int y, bool on) { - if (x < 0 || x >= V_WIDTH || y < 0 || y >= V_HEIGHT) return; +void set_pixel(int x, int y, bool on) +{ + if (x < 0 || x >= V_WIDTH || y < 0 || y >= V_HEIGHT) + return; int bit_pos = y * V_WIDTH + x; - if (on) bit_buffer[bit_pos / 8] |= (1 << (7 - (bit_pos % 8))); - else bit_buffer[bit_pos / 8] &= ~(1 << (7 - (bit_pos % 8))); + if (on) + 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 dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1; int err = dx + dy, e2; - while (true) { + while (true) + { set_pixel(x0, y0, on); - if (x0 == x1 && y0 == y1) break; + if (x0 == x1 && y0 == y1) + break; e2 = 2 * err; - if (e2 >= dy) { err += dy; x0 += sx; } - if (e2 <= dx) { err += dx; y0 += sy; } + if (e2 >= dy) + { + err += dy; + x0 += sx; + } + if (e2 <= dx) + { + err += dx; + y0 += sy; + } } } // 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] = { {0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00}, // A {0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00} // B }; - int idx = (c == 'A') ? 0 : 1; - 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); + int idx = (c == 'A') ? 0 : 1; + 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); } } } @@ -50,18 +72,23 @@ void draw_char(int x, int y, char c) { * @param y Start y position * @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) - if (c < 32 || c > 127) return; + if (c < 32 || c > 127) + return; 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]; - - for (int row = 0; row < 8; row++) { + + for (int row = 0; row < 8; row++) + { // Check if the bit for this row is set // 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); } } @@ -72,8 +99,10 @@ void draw_char_vcol(int x, int y, char c) { * Draws a full string of text * @param spacing pixels between characters (usually 1 or 2) */ -void draw_string(int x, int y, const std::string& text, int spacing = 1) { - for (size_t i = 0; i < text.length(); i++) { +void draw_string(int x, int y, const std::string &text, int spacing = 1) +{ + for (size_t i = 0; i < text.length(); i++) + { draw_char_vcol(x + (i * (6 + spacing)), y, text[i]); } } @@ -82,22 +111,30 @@ void draw_string(int x, int y, const std::string& text, int spacing = 1) { * Draws a scaled character using the 6x8 vertical column format * @param scale Integer multiplier (1 = 1x, 2 = 2x, etc.) */ -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 - +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 + 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]; - - for (int row = 0; row < 8; row++) { - if (column_byte & (1 << row)) { + + for (int row = 0; row < 8; row++) + { + if (column_byte & (1 << row)) + { // Draw a square of size [scale x scale] - for (int sy = 0; sy < scale; sy++) { - for (int sx = 0; sx < scale; sx++) { - set_pixel(x + (col * scale) + sx, - y + (row * scale) + sy, + for (int sy = 0; sy < scale; sy++) + { + for (int sx = 0; sx < scale; sx++) + { + set_pixel(x + (col * scale) + sx, + y + (row * scale) + sy, true); } } @@ -109,65 +146,133 @@ void draw_char_scaled(int x, int y, char c, int scale) { /** * Draws a scaled string */ -void draw_string_scaled(int x, int y, const std::string& text, int scale, int spacing = 1) { - for (size_t i = 0; i < text.length(); i++) { +void draw_string_scaled(int x, int y, const char* text, int scale, int spacing = 1) +{ + int i = 0; + while(text[i] != '\0') + { // We multiply the character width (6) and spacing by the scale int next_x = x + (i * (6 + spacing) * scale); draw_char_scaled(next_x, y, text[i], scale); + i++; } } -int main() { - sf::RenderWindow window(sf::VideoMode(800, 600), "0.5Hz Update Emulator"); - +char command_buffer[256]; +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 display_pixels(V_WIDTH * V_HEIGHT * 4); sf::Texture texture; texture.create(V_WIDTH, V_HEIGHT); texture.setSmooth(false); // Keeps the 1-bit pixels sharp and blocky sf::Sprite sprite(texture); - sprite.setScale(2.f, 2.f); - + sprite.setScale(1.f, 1.f); sf::Clock clock; bool toggle = false; - while (window.isOpen()) { + int counter = 0; + + while (window.isOpen()) + { sf::Event event; - while (window.pollEvent(event)) { - if (event.type == sf::Event::Closed) window.close(); + while (window.pollEvent(event)) + { + if (event.type == sf::Event::Closed) + window.close(); } - while (window.pollEvent(event)) { - if (event.type == sf::Event::Closed) - window.close(); + // Check for console input with timeout + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + 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'; + } + } - // Check for a single key press - if (event.type == sf::Event::KeyPressed) { - if (event.key.code == sf::Keyboard::Space) { - // This happens only ONCE when you hit Space - toggle = !toggle; + // 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) --- - if (clock.getElapsedTime().asMilliseconds() >= 500) { + if (clock.getElapsedTime().asMilliseconds() >= 1000) + { + //printf("Updating display %d...\n", counter++); clock.restart(); toggle = !toggle; // Change something every half second // 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_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, 270, command_buffer, 1); + // 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; 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] = display_pixels[base + 1] = display_pixels[base + 2] = color; display_pixels[base + 3] = 255; } texture.update(display_pixels.data()); @@ -176,6 +281,10 @@ int main() { window.clear(); window.draw(sprite); window.display(); + } + + // Restore original terminal settings + tcsetattr(STDIN_FILENO, TCSANOW, &old_tio); return 0; } \ No newline at end of file