#include #include #include #include #include "./fonts/acme_5_outlines_font.h" const int V_WIDTH = 400; const int V_HEIGHT = 300; 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; 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))); } 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) { set_pixel(x0, y0, on); if (x0 == x1 && y0 == y1) break; e2 = 2 * err; 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) { 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); } } } /** * Draws a single character using the 6x8 vertical column format * @param x Start x position * @param y Start y position * @param c The character to draw */ void draw_char_vcol(int x, int y, char c) { // The font table starts at space (ASCII 32) if (c < 32 || c > 127) return; int font_idx = c - 32; for (int col = 0; col < 6; col++) { unsigned char column_byte = font[font_idx][col]; 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)) { set_pixel(x + col, y + row, true); } } } } /** * 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++) { draw_char_vcol(x + (i * (6 + spacing)), y, text[i]); } } /** * 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 int font_idx = c - 32; 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)) { // 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, true); } } } } } } /** * 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++) { // 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); } } int main() { sf::RenderWindow window(sf::VideoMode(800, 600), "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); sf::Clock clock; bool toggle = false; 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(); // 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; } } } // --- TIMING LOGIC: Update twice per second (500ms) --- if (clock.getElapsedTime().asMilliseconds() >= 500) { clock.restart(); toggle = !toggle; // Change something every half second // Clear buffer for (int i = 0; i < sizeof(bit_buffer); i++) bit_buffer[i] = 0; // Draw content //draw_line(10, 10, 390, 290, true); draw_string_scaled(10, 10, "Hello World!", 3); // 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()); } window.clear(); window.draw(sprite); window.display(); } return 0; }