--- /dev/null
+/*
+blender for the Gameboy Advance
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <string.h>
+#include "polyfill.h"
+#include "debug.h"
+
+static unsigned char *fb;
+static int fbwidth, fbheight;
+static short scantab[2][160] __attribute__((section(".iwram")));
+
+void polyfill_framebuffer(unsigned char *ptr, int w, int h)
+{
+ fb = ptr;
+ fbwidth = w;
+ fbheight = h;
+}
+
+#define VNEXT(p) (((p) == vlast) ? varr : (p) + 1)
+#define VPREV(p) ((p) == varr ? vlast : (p) - 1)
+#define VSUCC(p, side) ((side) == 0 ? VNEXT(p) : VPREV(p))
+
+void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col)
+{
+ int i, line, top, bot;
+ struct pvertex *vlast, *v, *vn;
+ int32_t x, y0, y1, dx, dy, slope, fx, fy;
+ short *tab, start, len;
+ unsigned char *fbptr;
+
+ vlast = varr + vnum - 1;
+ top = fbheight;
+ bot = 0;
+
+ for(i=0; i<vnum; i++) {
+ v = varr + i;
+ vn = VNEXT(v);
+
+ if(vn->y == v->y) continue;
+
+ if(vn->y > v->y) {
+ tab = scantab[0];
+ } else {
+ tab = scantab[1];
+ v = vn;
+ vn = varr + i;
+ }
+
+ dx = vn->x - v->x;
+ dy = vn->y - v->y;
+ slope = (dx << 8) / dy;
+
+ y0 = (v->y + 0x100) & 0xffffff00; /* start from the next scanline */
+ fy = y0 - v->y; /* fractional part before the next scanline */
+ fx = (fy * slope) >> 8; /* X adjust for the step to the next scanline */
+ x = v->x + fx; /* adjust X */
+ y1 = vn->y & 0xffffff00; /* last scanline of the edge <= vn->y */
+
+ line = y0 >> 8;
+ if(line < top) top = line;
+ if((y1 >> 8) > bot) bot = y1 >> 8;
+
+ if(line > 0) tab += line;
+
+ while(line < (y1 >> 8) && line < fbheight) {
+ if(line >= 0) {
+ int val = x < 0 ? 0 : x >> 8;
+ *tab++ = val < fbwidth ? val : fbwidth - 1;
+ }
+ x += slope;
+ line++;
+ }
+ }
+
+ fbptr = fb + top * fbwidth;
+ for(i=top; i<bot; i++) {
+ start = scantab[0][i];
+ len = scantab[1][i] - start;
+
+ if(len > 0) {
+ memset(fbptr + start, col, len);
+ }
+ fbptr += fbwidth;
+ }
+}