2 gbajam22 entry for the Gameboy Advance
3 Copyright (C) 2022 John Tsiombikas <nuclear@mutantstargoat.com>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
22 static unsigned char *fb;
23 static int fbwidth, fbheight;
24 static short scantab[2][160];
26 void polyfill_framebuffer(void *ptr, int w, int h)
33 #define VNEXT(p) (((p) == vlast) ? varr : (p) + 1)
34 #define VPREV(p) ((p) == varr ? vlast : (p) - 1)
35 #define VSUCC(p, side) ((side) == 0 ? VNEXT(p) : VPREV(p))
38 void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col)
40 int i, line, top, bot;
41 struct pvertex *vlast, *v, *vn;
42 int32_t x, y0, y1, dx, dy, slope, fx, fy;
43 short *tab, start, len;
45 uint16_t *pptr, pcol = ((uint16_t)col << 8) | (uint16_t)col;
47 vlast = varr + vnum - 1;
51 for(i=0; i<vnum; i++) {
55 if(vn->y == v->y) continue;
67 slope = (dx << 8) / dy;
69 y0 = (v->y + 0x100) & 0xffffff00; /* start from the next scanline */
70 fy = y0 - v->y; /* fractional part before the next scanline */
71 fx = (fy * slope) >> 8; /* X adjust for the step to the next scanline */
72 x = v->x + fx; /* adjust X */
73 y1 = vn->y & 0xffffff00; /* last scanline of the edge <= vn->y */
76 if(line < top) top = line;
77 if((y1 >> 8) > bot) bot = y1 >> 8;
79 if(line > 0) tab += line;
81 while(line <= (y1 >> 8) && line < fbheight) {
83 int val = x < 0 ? 0 : x >> 8;
84 *tab++ = val < fbwidth ? val : fbwidth - 1;
92 if(bot >= fbheight) bot = fbheight - 1;
94 fbptr = fb + top * fbwidth;
95 for(i=top; i<=bot; i++) {
96 start = scantab[0][i];
97 len = scantab[1][i] - start;
101 pptr = (uint16_t*)(fbptr + (start & 0xfffe));
102 *pptr = (*pptr & 0xff) | ((uint16_t)col << 8);
106 pptr = (uint16_t*)(fbptr + start);
112 *pptr = (*pptr & 0xff00) | col;
120 /* ----- line drawing and clipping ------ */
129 static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax)
135 } else if(x > xmax) {
140 } else if(y > ymax) {
146 #define FIXMUL(a, b) (((a) * (b)) >> 8)
147 #define FIXDIV(a, b) (((a) << 8) / (b))
149 #define LERP(a, b, t) ((a) + FIXMUL((b) - (a), (t)))
151 int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax)
155 int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax);
156 int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax);
158 long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax;
160 if(!(oc0 | oc1)) return 1; /* both points are inside */
174 if(oc0 & oc1) return 0; /* both have points with the same outbit, not visible */
175 if(!(oc0 | oc1)) break; /* both points are inside */
177 oc_out = oc0 ? oc0 : oc1;
180 t = FIXDIV(fymin - fy0, fy1 - fy0);
181 x = LERP(fx0, fx1, t);
183 } else if(oc_out & BOTTOM) {
184 t = FIXDIV(fymax - fy0, fy1 - fy0);
185 x = LERP(fx0, fx1, t);
187 } else if(oc_out & LEFT) {
188 t = FIXDIV(fxmin - fx0, fx1 - fx0);
190 y = LERP(fy0, fy1, t);
191 } else {/*if(oc_out & RIGHT) {*/
192 t = FIXDIV(fxmax - fx0, fx1 - fx0);
194 y = LERP(fy0, fy1, t);
200 oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax);
204 oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax);
216 #define PUTPIXEL(ptr) \
218 if(x0 >= 0 && x0 < fbwidth && y0 >= 0 && y0 < fbheight) { \
219 uint16_t *pptr = (uint16_t*)((uint32_t)ptr & 0xfffffffe); \
220 if((uint32_t)ptr & 1) { \
221 *pptr = (*pptr & 0xff) | (color << 8); \
223 *pptr = (*pptr & 0xff00) | color; \
227 #else /* !ALT_LCLIP */
228 #define PUTPIXEL(ptr) \
230 uint16_t *pptr = (uint16_t*)((uint32_t)ptr & 0xfffffffe); \
231 if((uint32_t)ptr & 1) { \
232 *pptr = (*pptr & 0xff) | (color << 8); \
234 *pptr = (*pptr & 0xff00) | color; \
239 void draw_line(int x0, int y0, int x1, int y1, unsigned short color)
241 int i, dx, dy, x_inc, y_inc, error;
245 unsigned char *fbptr = fb;
247 fbptr += y0 * fbwidth + x0;
273 for(i=0; i<=dx; i++) {
290 for(i=0; i<=dy; i++) {