add more low level drawing functions

This commit is contained in:
Adolfo Reyna
2026-01-13 10:55:21 -05:00
parent 55475d10ec
commit 5e0fe7c6d9
4 changed files with 77 additions and 2 deletions

BIN
app

Binary file not shown.

View File

@@ -17,16 +17,64 @@
#include "./fonts/zxpix_font.h" #include "./fonts/zxpix_font.h"
LowLevelRenderer::LowLevelRenderer(uint8_t* buffer, int width, int height) LowLevelRenderer::LowLevelRenderer(uint8_t* buffer, int width, int height)
: bit_buffer(buffer), V_WIDTH(width), V_HEIGHT(height), current_font(&font_acme_5_outlines) {} : bit_buffer(buffer), V_WIDTH(width), V_HEIGHT(height), current_font(&font_acme_5_outlines),
clipping_enabled(false), clip_x(0), clip_y(0), clip_width(width), clip_height(height) {}
void LowLevelRenderer::set_font(const unsigned char (*font)[96][6]) { void LowLevelRenderer::set_font(const unsigned char (*font)[96][6]) {
current_font = font; current_font = font;
} }
// Clipping functions
void LowLevelRenderer::set_clip_rect(int x, int y, int width, int height) {
clip_x = x;
clip_y = y;
clip_width = width;
clip_height = height;
clipping_enabled = true;
}
void LowLevelRenderer::reset_clip_rect() {
clipping_enabled = false;
clip_x = 0;
clip_y = 0;
clip_width = V_WIDTH;
clip_height = V_HEIGHT;
}
bool LowLevelRenderer::is_clipping_enabled() const {
return clipping_enabled;
}
bool LowLevelRenderer::is_point_in_clip_rect(int x, int y) {
if (!clipping_enabled) return true;
return (x >= clip_x && x < clip_x + clip_width &&
y >= clip_y && y < clip_y + clip_height);
}
// Buffer operations
void LowLevelRenderer::invert_buffer() {
int buffer_size = (V_WIDTH * V_HEIGHT + 7) / 8; // Round up for bit buffer size
for (int i = 0; i < buffer_size; ++i) {
bit_buffer[i] = ~bit_buffer[i]; // Bitwise NOT to invert all bits
}
}
void LowLevelRenderer::clear_buffer() {
int buffer_size = (V_WIDTH * V_HEIGHT + 7) / 8;
for (int i = 0; i < buffer_size; ++i) {
bit_buffer[i] = 0;
}
}
void LowLevelRenderer::set_pixel(int x, int y, bool on) void LowLevelRenderer::set_pixel(int x, int y, bool on)
{ {
if (x < 0 || x >= V_WIDTH || y < 0 || y >= V_HEIGHT) if (x < 0 || x >= V_WIDTH || y < 0 || y >= V_HEIGHT)
return; return;
// Check clipping
if (!is_point_in_clip_rect(x, y))
return;
int bit_pos = y * V_WIDTH + x; int bit_pos = y * V_WIDTH + x;
if (on) if (on)
bit_buffer[bit_pos / 8] |= (1 << (7 - (bit_pos % 8))); bit_buffer[bit_pos / 8] |= (1 << (7 - (bit_pos % 8)));

View File

@@ -33,9 +33,12 @@ private:
int V_WIDTH; int V_WIDTH;
int V_HEIGHT; int V_HEIGHT;
const unsigned char (*current_font)[96][6]; const unsigned char (*current_font)[96][6];
bool clipping_enabled;
int clip_x, clip_y, clip_width, clip_height;
void draw_corner_arc(int center_x, int center_y, int radius, int quadrant, bool on); void draw_corner_arc(int center_x, int center_y, int radius, int quadrant, bool on);
void fill_bottom_flat_triangle(int x1, int y1, int x2, int y2, int x3, int y3, bool on); void fill_bottom_flat_triangle(int x1, int y1, int x2, int y2, int x3, int y3, bool on);
void fill_top_flat_triangle(int x1, int y1, int x2, int y2, int x3, int y3, bool on); void fill_top_flat_triangle(int x1, int y1, int x2, int y2, int x3, int y3, bool on);
bool is_point_in_clip_rect(int x, int y);
public: public:
LowLevelRenderer(uint8_t* buffer, int width, int height); LowLevelRenderer(uint8_t* buffer, int width, int height);
@@ -56,6 +59,16 @@ public:
void draw_polygon(const std::vector<std::pair<int, int>>& points, bool on); void draw_polygon(const std::vector<std::pair<int, int>>& points, bool on);
void draw_filled_polygon(const std::vector<std::pair<int, int>>& points, bool on); void draw_filled_polygon(const std::vector<std::pair<int, int>>& points, bool on);
void draw_arc(int center_x, int center_y, int radius, int start_angle, int end_angle, bool on); void draw_arc(int center_x, int center_y, int radius, int start_angle, int end_angle, bool on);
// Clipping functions
void set_clip_rect(int x, int y, int width, int height);
void reset_clip_rect();
bool is_clipping_enabled() const;
// Buffer operations
void invert_buffer();
void clear_buffer();
void draw_circle(int x, int y, int radius, bool on); void draw_circle(int x, int y, int radius, bool on);
void draw_filled_circle(int x, int y, int radius, bool on); void draw_filled_circle(int x, int y, int radius, bool on);
void draw_char_vcol(int x, int y, char c); void draw_char_vcol(int x, int y, char c);

View File

@@ -36,6 +36,7 @@ int main()
sf::Clock clock; sf::Clock clock;
bool toggle = false; bool toggle = false;
bool inverted = false;
while (window.isOpen()) while (window.isOpen())
{ {
@@ -87,6 +88,14 @@ int main()
{ {
clock.restart(); clock.restart();
toggle = !toggle; // Change something every half second toggle = !toggle; // Change something every half second
// Invert display every 4 seconds (8 cycles)
static int cycle_count = 0;
cycle_count++;
if (cycle_count % 8 == 0) {
renderer.invert_buffer();
inverted = !inverted;
}
// Clear buffer // Clear buffer
for (int i = 0; i < sizeof(bit_buffer); i++) for (int i = 0; i < sizeof(bit_buffer); i++)
@@ -131,9 +140,14 @@ int main()
renderer.draw_line(10, 200, 90, 250, true); renderer.draw_line(10, 200, 90, 250, true);
renderer.draw_line(110, 200, 190, 250, true); renderer.draw_line(110, 200, 190, 250, true);
// Demonstrate clipping - draw a circle that gets clipped
renderer.set_clip_rect(300, 200, 80, 60); // Small rectangle in bottom-right
renderer.draw_filled_circle(340, 230, 40, true); // Circle that extends outside clip rect
renderer.reset_clip_rect(); // Reset to full screen
// Text with different fonts // Text with different fonts
renderer.set_font(&font_acme_5_outlines); renderer.set_font(&font_acme_5_outlines);
renderer.draw_string_scaled(10, 10, "Drawing Demo", 2); renderer.draw_string_scaled(10, 10, inverted ? "INVERTED MODE" : "Drawing Demo", 2);
renderer.set_font(&font_5x5); renderer.set_font(&font_5x5);
renderer.draw_string_scaled(10, 270, command_buffer, 1); renderer.draw_string_scaled(10, 270, command_buffer, 1);