ceda2vga/src/draw_demo.c

170 lines
3.7 KiB
C

#include "draw_demo.h"
#include "framebuffer.h"
#include "pico/platform.h"
#include <string.h>
static bool valid_coord(uint16_t x, uint16_t y)
{
if (x < 0 || x >= HPIXEL)
return false;
if (y < 0 || y >= VPIXEL)
return false;
return true;
}
// just because i did not need all the letters
// and didn't want to fill a proper array :-)
const Letter letters[] = {
{'A', 6, (Point[]){{0, 7}, {0, 0}, {7, 0}, {7, 7}, {7, 3}, {0, 3}}},
{'G', 6, (Point[]){{7, 0}, {0, 0}, {0, 7}, {7, 7}, {7, 3}, {3, 3}}},
{'L', 3, (Point[]){{0, 0}, {0, 7}, {7, 7}}},
{'M', 5, (Point[]){{0, 7}, {0, 0}, {3, 3}, {7, 0}, {7, 7}}},
{'O', 5, (Point[]){{0, 0}, {0, 7}, {7, 7}, {7, 0}, {0, 0}}},
{'P', 5, (Point[]){{0, 7}, {0, 0}, {7, 0}, {7, 3}, {0, 3}}},
{'R', 6, (Point[]){{0, 7}, {0, 0}, {7, 0}, {7, 3}, {0, 3}, {7, 7}}},
{'S', 6, (Point[]){{0, 7}, {7, 7}, {7, 3}, {0, 3}, {0, 0}, {7, 0}}},
};
void draw_path(uint16_t x, uint16_t y, Point points[], size_t len)
{
Point *old_point = &points[0];
for (int i = 1; i < len; ++i)
{
Point *current_point = &points[i];
draw_line(x + old_point->x, y + old_point->y, x + current_point->x, y + current_point->y,
true);
old_point = current_point;
}
}
void draw_letter(uint16_t x, uint16_t y, char c)
{
for (int i = 0; i < count_of(letters); ++i)
{
if (letters[i].letter == c)
{
draw_path(x, y, letters[i].points, letters[i].len);
break;
}
}
}
void draw_string(uint16_t x, uint16_t y, const char *s)
{
while (*s != 0)
{
draw_letter(x, y, *s);
s++;
x += 9;
}
}
void draw_demo(void)
{
// draw a little demo
// clear frame buffer
memset(&frame[0], 0, sizeof(frame));
// horizontal lines
draw_line(0, 0, 640 - 1, 0, true);
draw_line(0, 240 - 1, 640 - 1, 240 - 1, true);
draw_line(0, 480 - 1, 640 - 1, 480 - 1, true);
// vertical lines
draw_line(0, 0, 0, 480 - 1, true);
draw_line(320 - 1, 0, 320 - 1, 480 - 1, true);
draw_line(638, 0, 638, 480 - 1, true); // last pixel of a line can't be set, see set_pixel()
// cat eye
for (uint16_t x = 0; x < 640; x += 20)
{
draw_line(x, 0, 0, (480 - x * 480 / 640), true);
draw_line(640, x * 480 / 640, 640 - x, 480, true);
}
// string
draw_string(200, 200, "GLG PROGRAMS");
}
void draw_simple_line(uint16_t x, uint16_t y, uint16_t len, bool horizontal)
{
for (uint16_t i = 0; i < len; ++i)
{
if (horizontal)
set_pixel(x + i, y);
else
set_pixel(x, y + i);
}
}
void draw_line(uint16_t _x0, uint16_t _y0, uint16_t _x1, uint16_t _y1, bool fill)
{
const float x0 = _x0;
const float y0 = _y0;
const float x1 = _x1;
const float y1 = _y1;
if (x0 != x1)
{
const uint16_t x_begin = MIN(x0, x1);
const uint16_t x_end = MAX(x0, x1);
for (uint16_t x = x_begin; x < x_end; ++x)
{
const uint16_t y = (y1 - y0) * (x - x0) / (x1 - x0) + y0;
if (fill)
set_pixel(x, y);
else
clear_pixel(x, y);
}
}
else
{
const uint16_t y_begin = MIN(y0, y1);
const uint16_t y_end = MAX(y0, y1);
for (uint16_t y = y_begin; y < y_end; ++y)
{
if (fill)
set_pixel(x0, y);
else
clear_pixel(x0, y);
}
}
}
void set_pixel(uint16_t x, uint16_t y)
{
// ignore out of frame pixels
if (!valid_coord(x, y))
return;
// Since there is not much space in PIO program memory,
// it is not possible to set the last pixel of a line,
// because there is not enough program space to unset it
// in the hardware, and, if left set, will mess with
// the sync signals.
if (x == 639)
return;
// skip wasted blanking lines
// (see frame struct declaration)
y += VBBLANK + VSPULSE - 1;
// set bit
frame[y * 80 + x / 8] |= (1 << x % 8);
}
void clear_pixel(uint16_t x, uint16_t y)
{
if (!valid_coord(x, y))
return;
y += VBBLANK + VSPULSE - 1;
frame[y * 80 + x / 8] &= ~(1 << x % 8);
}