diff --git a/src/libgpanel/Makefile b/src/libgpanel/Makefile index 77a899f..56d7073 100644 --- a/src/libgpanel/Makefile +++ b/src/libgpanel/Makefile @@ -5,8 +5,8 @@ CFLAGS += -O -Wall -Werror MAN = gpanel.0 MANSRC = gpanel.3 -OBJS = open.o clear.o pixel.o line.o rect.o fill.o circle.o \ - image.o char.o text.o text_width.o +OBJS = open.o clear.o pixel.o line.o rect.o fill.o fill_triangle.o \ + circle.o image.o char.o text.o text_width.o all: ../libgpanel.a $(MAN) diff --git a/src/libgpanel/fill_triangle.c b/src/libgpanel/fill_triangle.c new file mode 100644 index 0000000..690d1bd --- /dev/null +++ b/src/libgpanel/fill_triangle.c @@ -0,0 +1,125 @@ +/* + * Fill a triangle. + * Code ported from AdaFruit TFT LCD library. + * + * Copyright (C) 2015 Serge Vakulenko, + * + * Permission to use, copy, modify, and distribute this software + * and its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaim all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author be liable for any + * special, indirect or consequential damages or any damages + * whatsoever resulting from loss of use, data or profits, whether + * in an action of contract, negligence or other tortious action, + * arising out of or in connection with the use or performance of + * this software. + */ +#include +#include + +/* + * Swap values of two integer variables. + */ +#define swapi(x,y) { int _t = x; x = y; y = _t; } + +void gpanel_fill_triangle(int color, int x0, int y0, + int x1, int y1, int x2, int y2) +{ + int a, b, y, last; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) { + swapi(y0, y1); + swapi(x0, x1); + } + if (y1 > y2) { + swapi(y2, y1); + swapi(x2, x1); + } + if (y0 > y1) { + swapi(y0, y1); + swapi(x0, x1); + } + + if (y0 == y2) { + // Handle awkward all-on-same-line case as its own thing + a = b = x0; + + if (x1 < a) + a = x1; + else if (x1 > b) + b = x1; + + if (x2 < a) + a = x2; + else if (x2 > b) + b = x2; + + gpanel_fill(color, a, y0, b-a+1, y0); + return; + } + + int dx01 = x1 - x0; + int dy01 = y1 - y0; + int dx02 = x2 - x0; + int dy02 = y2 - y0; + int dx12 = x2 - x1; + int dy12 = y2 - y1; + int sa = 0; + int sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if (y1 == y2) + last = y1; // Include y1 scanline + else + last = y1-1; // Skip it + + for (y=y0; y<=last; y++) { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + + /* longhand: + * a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + * b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + swapi(a, b); + + gpanel_fill(color, a, y, b-a+1, y); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = dx12 * (y - y1); + sb = dx02 * (y - y0); + for (; y<=y2; y++) { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + + /* longhand: + * a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + * b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + swapi(a, b); + + gpanel_fill(color, a, y, b-a+1, y); + } +} diff --git a/sys/include/gpanel.h b/sys/include/gpanel.h index e0a9a18..144338e 100644 --- a/sys/include/gpanel.h +++ b/sys/include/gpanel.h @@ -112,6 +112,7 @@ void gpanel_pixel(int color, int x, int y); void gpanel_line(int color, int x0, int y0, int x1, int y1); void gpanel_rect(int color, int x0, int y0, int x1, int y1); void gpanel_fill(int color, int x0, int y0, int x1, int y1); +void gpanel_fill_triangle(int color, int x0, int y0, int x1, int y1, int x2, int y2); void gpanel_circle(int color, int x, int y, int radius); void gpanel_image(int x, int y, int width, int height, const unsigned short *data); void gpanel_char(const struct gpanel_font_t *font, int color, int background, int x, int y, int sym);