lowlevel render should work for the emulator and the hardware display

This commit is contained in:
Adolfo Reyna
2026-01-12 22:59:43 -05:00
parent 713d2c0cfd
commit 55475d10ec
30 changed files with 634 additions and 203 deletions

226
main.cpp
View File

@@ -5,159 +5,12 @@
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>
#include "./fonts/acme_5_outlines_font.h"
#include "low_level_render.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 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++;
}
}
char command_buffer[256];
int command_buffer_index = 0;
@@ -179,11 +32,11 @@ int main()
sf::Sprite sprite(texture);
sprite.setScale(1.f, 1.f);
LowLevelRenderer renderer(bit_buffer, V_WIDTH, V_HEIGHT);
sf::Clock clock;
bool toggle = false;
int counter = 0;
while (window.isOpen())
{
sf::Event event;
@@ -227,32 +80,11 @@ int main()
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) ---
if (clock.getElapsedTime().asMilliseconds() >= 1000)
if (clock.getElapsedTime().asMilliseconds() >= 500)
{
//printf("Updating display %d...\n", counter++);
clock.restart();
toggle = !toggle; // Change something every half second
@@ -260,11 +92,51 @@ int main()
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);
draw_string_scaled(10, 270, command_buffer, 1);
// Showcase drawing functions
// Rectangles
renderer.draw_rectangle(10, 50, 80, 60, true);
renderer.draw_filled_rectangle(110, 50, 80, 60, true);
renderer.draw_rounded_rectangle(210, 50, 80, 60, 10, true);
// Triangles
renderer.draw_triangle(20, 130, 80, 130, 50, 180, true);
renderer.draw_filled_triangle(120, 130, 180, 130, 150, 180, true);
// Polygons
std::vector<std::pair<int, int>> hex_points = {
{250, 130}, {280, 145}, {280, 175}, {250, 190}, {220, 175}, {220, 145}
};
renderer.draw_polygon(hex_points, true);
std::vector<std::pair<int, int>> star_points = {
{320, 140}, {325, 155}, {340, 155}, {330, 170}, {335, 185},
{320, 175}, {305, 185}, {310, 170}, {300, 155}, {315, 155}
};
renderer.draw_filled_polygon(star_points, true);
// Arcs
renderer.draw_arc(60, 270, 25, 45, 315, true); // Pac-man shape
renderer.draw_arc(160, 270, 25, 0, 180, true); // Semicircle
// Ellipses
renderer.draw_ellipse(60, 220, 30, 20, true);
renderer.draw_filled_ellipse(160, 220, 30, 20, true);
// Circles
renderer.draw_circle(60, 160, 25, true);
renderer.draw_filled_circle(160, 160, 25, true);
renderer.draw_circle(260, 160, 15, true); // Smaller circle
// Lines
renderer.draw_line(10, 200, 90, 250, true);
renderer.draw_line(110, 200, 190, 250, true);
// Text with different fonts
renderer.set_font(&font_acme_5_outlines);
renderer.draw_string_scaled(10, 10, "Drawing Demo", 2);
renderer.set_font(&font_5x5);
renderer.draw_string_scaled(10, 270, command_buffer, 1);
// Bridge: 1-bit to RGBA
for (int i = 0; i < V_WIDTH * V_HEIGHT; ++i)