polygon filler, rudimentary GL
[gba_blender] / src / xgl.c
diff --git a/src/xgl.c b/src/xgl.c
new file mode 100644 (file)
index 0000000..376d792
--- /dev/null
+++ b/src/xgl.c
@@ -0,0 +1,179 @@
+/*
+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 <math.h>
+#include "xgl.h"
+#include "polyfill.h"
+
+#define MAT_STACK_SIZE 4
+
+static int vp[4];
+static int32_t mat[MAT_STACK_SIZE][16];
+static int mtop;
+
+void xgl_init(void)
+{
+       xgl_viewport(0, 0, 240, 160);
+       xgl_load_identity();
+}
+
+void xgl_viewport(int x, int y, int w, int h)
+{
+       vp[0] = x;
+       vp[1] = y;
+       vp[2] = w;
+       vp[3] = h;
+}
+
+void xgl_push_matrix(void)
+{
+       int prev;
+
+       if(mtop >= MAT_STACK_SIZE - 1) return;
+
+       prev = mtop++;
+       memcpy(mat[mtop], mat[prev], sizeof mat[0]);
+}
+
+void xgl_pop_matrix(void)
+{
+       if(mtop > 0) mtop--;
+}
+
+static const int32_t id[] = {
+       0x10000, 0, 0, 0,
+       0, 0x10000, 0, 0,
+       0, 0, 0x10000, 0,
+       0, 0, 0, 0x10000
+};
+
+void xgl_load_identity(void)
+{
+       xgl_load_matrix(id);
+}
+
+void xgl_load_matrix(const int32_t *m)
+{
+       memcpy(mat[mtop], m, sizeof mat[0]);
+}
+
+#define M(i,j) (((i) << 2) + (j))
+#define XMUL(a, b)     (((a) >> 8) * ((b) >> 8))
+void xgl_mult_matrix(const int32_t *m2)
+{
+       int i, j;
+       int32_t m1[16];
+       int32_t *dest = mat[mtop];
+
+       memcpy(m1, dest, sizeof m1);
+
+       for(i=0; i<4; i++) {
+               for(j=0; j<4; j++) {
+                       *dest++ = XMUL(m1[M(0, j)], m2[M(i, 0)]) +
+                               XMUL(m1[M(1, j)], m2[M(i, 1)]) +
+                               XMUL(m1[M(2, j)], m2[M(i, 2)]) +
+                               XMUL(m1[M(3, j)], m2[M(i, 3)]);
+               }
+       }
+}
+
+#define XSIN(x)                (int32_t)(sin(x / 65536.0f) * 65536.0f)
+#define XCOS(x)                (int32_t)(cos(x / 65536.0f) * 65536.0f)
+
+void xgl_translate(int32_t x, int32_t y, int32_t z)
+{
+       int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000};
+       m[12] = x;
+       m[13] = y;
+       m[14] = z;
+       xgl_mult_matrix(m);
+}
+
+void xgl_rotate_x(int32_t angle)
+{
+       int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000};
+       int32_t sa = XSIN(angle);
+       int32_t ca = XCOS(angle);
+       m[5] = ca;
+       m[6] = sa;
+       m[9] = -sa;
+       m[10] = ca;
+       xgl_mult_matrix(m);
+}
+
+void xgl_rotate_y(int32_t angle)
+{
+       int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000};
+       int32_t sa = XSIN(angle);
+       int32_t ca = XCOS(angle);
+       m[0] = ca;
+       m[2] = -sa;
+       m[8] = sa;
+       m[10] = ca;
+       xgl_mult_matrix(m);
+}
+
+void xgl_rotate_z(int32_t angle)
+{
+       int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000};
+       int32_t sa = XSIN(angle);
+       int32_t ca = XCOS(angle);
+       m[0] = ca;
+       m[1] = sa;
+       m[4] = -sa;
+       m[5] = ca;
+       xgl_mult_matrix(m);
+}
+
+void xgl_scale(int32_t x, int32_t y, int32_t z)
+{
+       int32_t m[16] = {0};
+       m[0] = x;
+       m[5] = y;
+       m[10] = z;
+       m[15] = 0x10000;
+       xgl_mult_matrix(m);
+}
+
+static void xform(struct xvertex *out, const struct xvertex *in, const int32_t *m)
+{
+       out->x = XMUL(m[0], in->x) + XMUL(m[4], in->y) + XMUL(m[8], in->z) + m[12];
+       out->y = XMUL(m[1], in->x) + XMUL(m[5], in->y) + XMUL(m[9], in->z) + m[13];
+       out->z = XMUL(m[2], in->x) + XMUL(m[6], in->y) + XMUL(m[10], in->z) + m[14];
+}
+
+void xgl_draw(int prim, const struct xvertex *varr, int vcount)
+{
+       int i;
+       struct xvertex xv[4];
+       struct pvertex pv[4];
+
+       while(vcount >= prim) {
+               for(i=0; i<prim; i++) {
+                       xform(xv + i, varr, mat[mtop]);
+                       varr++;
+
+                       /* viewport */
+                       pv[i].x = ((((xv[i].x + 0x10000) >> 1) * vp[2]) >> 8) + (vp[0] << 8);
+                       pv[i].y = ((((xv[i].y + 0x10000) >> 1) * vp[3]) >> 8) + (vp[1] << 8);
+               }
+               vcount -= prim;
+
+               polyfill_flat(pv, prim, 0xff);
+       }
+}