1
0
Fork 0
forked from len0rd/rockbox

puzzles: resync with upstream 262f709.

This is the first resync with a fully unmodified upstream repo. This
includes a new scanline polygon renderer in the upstream puzzles
distribution. This allows us to get rid of the monstrosity of a
polygon renderer we had been shipping in rockbox.c.

Change-Id: I23628c74bb5ff7a9e7932bf16d68a1c867c49969
This commit is contained in:
Franklin Wei 2024-08-11 23:34:57 -04:00
parent 903e8c5b32
commit ea0e3704a8
15 changed files with 700 additions and 683 deletions

View file

@ -753,7 +753,7 @@ static void rb_color(int n)
/* clipping is implemented through viewports and offsetting
* coordinates */
static void rb_clip(void *handle, int x, int y, int w, int h)
static void rb_clip(drawing *dr, int x, int y, int w, int h)
{
if(!zoom_enabled)
{
@ -783,7 +783,7 @@ static void rb_clip(void *handle, int x, int y, int w, int h)
}
}
static void rb_unclip(void *handle)
static void rb_unclip(drawing *dr)
{
if(!zoom_enabled)
{
@ -800,7 +800,7 @@ static void rb_unclip(void *handle)
}
}
static void rb_draw_text(void *handle, int x, int y, int fonttype,
static void rb_draw_text(drawing *dr, int x, int y, int fonttype,
int fontsize, int align, int color, const char *text)
{
(void) fontsize;
@ -865,7 +865,7 @@ static void rb_draw_text(void *handle, int x, int y, int fonttype,
}
}
static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color)
static void rb_draw_rect(drawing *dr, int x, int y, int w, int h, int color)
{
rb_color(color);
if(!zoom_enabled)
@ -1007,7 +1007,7 @@ static void draw_antialiased_line(fb_data *fb, int w, int h, int x0, int y0, int
}
}
static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2,
static void rb_draw_line(drawing *dr, int x1, int y1, int x2, int y2,
int color)
{
rb_color(color);
@ -1035,349 +1035,7 @@ static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2,
}
}
#if 0
/*
* draw filled polygon
* originally by Sebastian Leonhardt (ulmutul)
* 'count' : number of coordinate pairs
* 'pxy': array of coordinates. pxy[0]=x0,pxy[1]=y0,...
* note: provide space for one extra coordinate, because the starting point
* will automatically be inserted as end point.
*/
/*
* helper function:
* find points of intersection between polygon and scanline
*/
#define MAX_INTERSECTION 32
static void fill_poly_line(int scanline, int count, int *pxy)
{
int i;
int j;
int num_of_intersects;
int direct, old_direct;
//intersections of every line with scanline (y-coord)
int intersection[MAX_INTERSECTION];
/* add starting point as ending point */
pxy[count*2] = pxy[0];
pxy[count*2+1] = pxy[1];
old_direct=0;
num_of_intersects=0;
for (i=0; i<count*2; i+=2) {
int x1=pxy[i];
int y1=pxy[i+1];
int x2=pxy[i+2];
int y2=pxy[i+3];
// skip if line is outside of scanline
if (y1 < y2) {
if (scanline < y1 || scanline > y2)
continue;
}
else {
if (scanline < y2 || scanline > y1)
continue;
}
// calculate x-coord of intersection
if (y1==y2) {
direct=0;
}
else {
direct = y1>y2 ? 1 : -1;
// omit double intersections, if both lines lead in the same direction
intersection[num_of_intersects] =
x1+((scanline-y1)*(x2-x1))/(y2-y1);
if ( (direct!=old_direct)
|| (intersection[num_of_intersects] != intersection[num_of_intersects-1])
)
++num_of_intersects;
}
old_direct = direct;
}
// sort points of intersection
for (i=0; i<num_of_intersects-1; ++i) {
for (j=i+1; j<num_of_intersects; ++j) {
if (intersection[j]<intersection[i]) {
int temp=intersection[i];
intersection[i]=intersection[j];
intersection[j]=temp;
}
}
}
// draw
for (i=0; i<num_of_intersects; i+=2) {
rb->lcd_hline(intersection[i], intersection[i+1], scanline);
}
}
/* two extra elements at end of pxy needed */
static void v_fillarea(int count, int *pxy)
{
int i;
int y1, y2;
// find min and max y coords
y1=y2=pxy[1];
for (i=3; i<count*2; i+=2) {
if (pxy[i] < y1) y1 = pxy[i];
else if (pxy[i] > y2) y2 = pxy[i];
}
for (i=y1; i<=y2; ++i) {
fill_poly_line(i, count, pxy);
}
}
#endif
/* I'm a horrible person: this was copy-pasta'd straight from
* xlcd_draw.c */
/* sort the given coordinates by increasing x value */
static void sort_points_by_increasing_x(int* x1, int* y1,
int* x2, int* y2,
int* x3, int* y3)
{
int x, y;
if (*x1 > *x3)
{
if (*x2 < *x3) /* x2 < x3 < x1 */
{
x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x;
y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y;
}
else if (*x2 > *x1) /* x3 < x1 < x2 */
{
x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x;
y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y;
}
else /* x3 <= x2 <= x1 */
{
x = *x1; *x1 = *x3; *x3 = x;
y = *y1; *y1 = *y3; *y3 = y;
}
}
else
{
if (*x2 < *x1) /* x2 < x1 <= x3 */
{
x = *x1; *x1 = *x2; *x2 = x;
y = *y1; *y1 = *y2; *y2 = y;
}
else if (*x2 > *x3) /* x1 <= x3 < x2 */
{
x = *x2; *x2 = *x3; *x3 = x;
y = *y2; *y2 = *y3; *y3 = y;
}
/* else already sorted */
}
}
#define sort_points_by_increasing_y(x1, y1, x2, y2, x3, y3) \
sort_points_by_increasing_x(y1, x1, y2, x2, y3, x3)
/* draw a filled triangle, using horizontal lines for speed */
static void zoom_filltriangle(int x1, int y1,
int x2, int y2,
int x3, int y3)
{
long fp_x1, fp_x2, fp_dx1, fp_dx2;
int y;
sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3);
if (y1 < y3) /* draw */
{
fp_dx1 = ((x3 - x1) << 16) / (y3 - y1);
fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1);
if (y1 < y2) /* first part */
{
fp_dx2 = ((x2 - x1) << 16) / (y2 - y1);
fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1);
for (y = y1; y < y2; y++)
{
zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y);
fp_x1 += fp_dx1;
fp_x2 += fp_dx2;
}
}
if (y2 < y3) /* second part */
{
fp_dx2 = ((x3 - x2) << 16) / (y3 - y2);
fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1);
for (y = y2; y < y3; y++)
{
zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y);
fp_x1 += fp_dx1;
fp_x2 += fp_dx2;
}
}
}
}
/* Should probably refactor this */
static void rb_draw_poly(void *handle, const int *coords, int npoints,
int fillcolor, int outlinecolor)
{
if(!zoom_enabled)
{
LOGF("rb_draw_poly");
if(fillcolor >= 0)
{
rb_color(fillcolor);
#if 1
/* serious hack: draw a bunch of triangles between adjacent points */
/* this generally works, even with some concave polygons */
for(int i = 2; i < npoints; ++i)
{
int x1, y1, x2, y2, x3, y3;
x1 = coords[0];
y1 = coords[1];
x2 = coords[(i - 1) * 2];
y2 = coords[(i - 1) * 2 + 1];
x3 = coords[i * 2];
y3 = coords[i * 2 + 1];
offset_coords(&x1, &y1);
offset_coords(&x2, &y2);
offset_coords(&x3, &y3);
xlcd_filltriangle(x1, y1,
x2, y2,
x3, y3);
#ifdef DEBUG_MENU
if(debug_settings.polyanim)
{
rb->lcd_update();
rb->sleep(HZ/4);
}
#endif
#if 0
/* debug code */
rb->lcd_set_foreground(LCD_RGBPACK(255,0,0));
rb->lcd_drawpixel(x1, y1);
rb->lcd_drawpixel(x2, y2);
rb->lcd_drawpixel(x3, y3);
rb->lcd_update();
rb->sleep(HZ);
rb_color(fillcolor);
rb->lcd_drawpixel(x1, y1);
rb->lcd_drawpixel(x2, y2);
rb->lcd_drawpixel(x3, y3);
rb->lcd_update();
#endif
}
#else
int *pxy = smalloc(sizeof(int) * 2 * npoints + 2);
/* copy points, offsetted */
for(int i = 0; i < npoints; ++i)
{
pxy[2 * i + 0] = coords[2 * i + 0];
pxy[2 * i + 1] = coords[2 * i + 1];
offset_coords(&pxy[2*i+0], &pxy[2*i+1]);
}
v_fillarea(npoints, pxy);
sfree(pxy);
#endif
}
/* draw outlines last so they're not covered by the fill */
assert(outlinecolor >= 0);
rb_color(outlinecolor);
for(int i = 1; i < npoints; ++i)
{
int x1, y1, x2, y2;
x1 = coords[2 * (i - 1)];
y1 = coords[2 * (i - 1) + 1];
x2 = coords[2 * i];
y2 = coords[2 * i + 1];
if(debug_settings.no_aa)
{
offset_coords(&x1, &y1);
offset_coords(&x2, &y2);
rb->lcd_drawline(x1, y1,
x2, y2);
}
else
draw_antialiased_line(lcd_fb, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2);
#ifdef DEBUG_MENU
if(debug_settings.polyanim)
{
rb->lcd_update();
rb->sleep(HZ/4);
}
#endif
}
int x1, y1, x2, y2;
x1 = coords[0];
y1 = coords[1];
x2 = coords[2 * (npoints - 1)];
y2 = coords[2 * (npoints - 1) + 1];
if(debug_settings.no_aa)
{
offset_coords(&x1, &y1);
offset_coords(&x2, &y2);
rb->lcd_drawline(x1, y1,
x2, y2);
}
else
draw_antialiased_line(lcd_fb, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2);
}
else
{
LOGF("rb_draw_poly");
if(fillcolor >= 0)
{
rb_color(fillcolor);
/* serious hack: draw a bunch of triangles between adjacent points */
/* this generally works, even with some concave polygons */
for(int i = 2; i < npoints; ++i)
{
int x1, y1, x2, y2, x3, y3;
x1 = coords[0];
y1 = coords[1];
x2 = coords[(i - 1) * 2];
y2 = coords[(i - 1) * 2 + 1];
x3 = coords[i * 2];
y3 = coords[i * 2 + 1];
zoom_filltriangle(x1, y1,
x2, y2,
x3, y3);
}
}
/* draw outlines last so they're not covered by the fill */
assert(outlinecolor >= 0);
rb_color(outlinecolor);
for(int i = 1; i < npoints; ++i)
{
int x1, y1, x2, y2;
x1 = coords[2 * (i - 1)];
y1 = coords[2 * (i - 1) + 1];
x2 = coords[2 * i];
y2 = coords[2 * i + 1];
draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2);
}
int x1, y1, x2, y2;
x1 = coords[0];
y1 = coords[1];
x2 = coords[2 * (npoints - 1)];
y2 = coords[2 * (npoints - 1) + 1];
draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2);
}
}
static void rb_draw_circle(void *handle, int cx, int cy, int radius,
static void rb_draw_circle(drawing *dr, int cx, int cy, int radius,
int fillcolor, int outlinecolor)
{
if(!zoom_enabled)
@ -1449,7 +1107,7 @@ static void trim_rect(int *x, int *y, int *w, int *h)
*h = y1 - y0;
}
static blitter *rb_blitter_new(void *handle, int w, int h)
static blitter *rb_blitter_new(drawing *dr, int w, int h)
{
LOGF("rb_blitter_new");
blitter *b = snew(blitter);
@ -1460,7 +1118,7 @@ static blitter *rb_blitter_new(void *handle, int w, int h)
return b;
}
static void rb_blitter_free(void *handle, blitter *bl)
static void rb_blitter_free(drawing *dr, blitter *bl)
{
LOGF("rb_blitter_free");
sfree(bl->bmp.data);
@ -1469,7 +1127,7 @@ static void rb_blitter_free(void *handle, blitter *bl)
}
/* copy a section of the framebuffer */
static void rb_blitter_save(void *handle, blitter *bl, int x, int y)
static void rb_blitter_save(drawing *dr, blitter *bl, int x, int y)
{
/* no viewport offset */
#if LCD_STRIDEFORMAT == VERTICAL_STRIDE
@ -1498,7 +1156,7 @@ static void rb_blitter_save(void *handle, blitter *bl, int x, int y)
#endif
}
static void rb_blitter_load(void *handle, blitter *bl, int x, int y)
static void rb_blitter_load(drawing *dr, blitter *bl, int x, int y)
{
LOGF("rb_blitter_load");
if(!bl->have_data)
@ -1528,7 +1186,7 @@ static void rb_blitter_load(void *handle, blitter *bl, int x, int y)
}
}
static void rb_draw_update(void *handle, int x, int y, int w, int h)
static void rb_draw_update(drawing *dr, int x, int y, int w, int h)
{
LOGF("rb_draw_update(%d, %d, %d, %d)", x, y, w, h);
@ -1552,9 +1210,9 @@ static void rb_draw_update(void *handle, int x, int y, int w, int h)
need_draw_update = true;
}
static void rb_start_draw(void *handle)
static void rb_start_draw(drawing *dr)
{
(void) handle;
(void) dr;
/* ... mumble mumble ... not ... reentrant ... mumble mumble ... */
@ -1565,9 +1223,9 @@ static void rb_start_draw(void *handle)
ud_d = LCD_HEIGHT;
}
static void rb_end_draw(void *handle)
static void rb_end_draw(drawing *dr)
{
(void) handle;
(void) dr;
if(debug_settings.highlight_cursor)
{
@ -1594,7 +1252,7 @@ static void rb_end_draw(void *handle)
#endif
}
static void rb_status_bar(void *handle, const char *text)
static void rb_status_bar(drawing *dr, const char *text)
{
if(titlebar)
sfree(titlebar);
@ -1692,7 +1350,7 @@ static void draw_mouse(void)
* glyph exists in a font) */
#if 0
/* See: https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/drawing.html#drawing-text-fallback */
static char *rb_text_fallback(void *handle, const char *const *strings,
static char *rb_text_fallback(drawing *dr, const char *const *strings,
int nstrings)
{
struct font *pf = rb->font_get(cur_font);
@ -1725,10 +1383,11 @@ static char *rb_text_fallback(void *handle, const char *const *strings,
#endif
const drawing_api rb_drawing = {
1,
rb_draw_text,
rb_draw_rect,
rb_draw_line,
rb_draw_poly,
draw_polygon_fallback,
rb_draw_circle,
rb_draw_update,
rb_clip,