From: John Tsiombikas Date: Sun, 14 Mar 2021 09:08:43 +0000 (+0200) Subject: polygon filler, rudimentary GL X-Git-Tag: v1.0~12 X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=gba_blender;a=commitdiff_plain;h=5b98299a1aa716cc17cb5f70498c8e23cac945cb polygon filler, rudimentary GL --- diff --git a/Makefile b/Makefile index 88f8d0e..37be9b5 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,12 @@ AS = $(ARCH)as OBJCOPY = $(ARCH)objcopy EMU = vbam -opt = -O1 -fomit-frame-pointer -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork +opt = -O3 -fomit-frame-pointer -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork #dbg = -g CFLAGS = $(opt) $(dbg) -pedantic -Wall -MMD ASFLAGS = -mthumb-interwork -LDFLAGS = -mthumb -mthumb-interwork -Wl,-print-gc-sections +LDFLAGS = -mthumb -mthumb-interwork -lm EMUFLAGS = -T 100 -f 1 --agb-print diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..d24af0a --- /dev/null +++ b/src/debug.c @@ -0,0 +1,21 @@ +#include +#include +#include "debug.h" + +__attribute__((target("arm"))) +void emuprint(const char *fmt, ...) +{ + char buf[128]; + va_list arg_list; + + va_start(arg_list, fmt); + vsnprintf(buf, 128, fmt, arg_list); + va_end(arg_list); + + __asm__ __volatile__( + "mov r0, %0\n\t" + "swi 0xff0000\n\t" : + : "r" (buf) + : "r0" + ); +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..41f2a23 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,6 @@ +#ifndef DEBUG_H_ +#define DEBUG_H_ + +void emuprint(const char *fmt, ...); + +#endif /* DEBUG_H_ */ diff --git a/src/gfx.h b/src/gfx.h index 5ea579a..6ba6af5 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -22,11 +22,9 @@ along with this program. If not, see . #define wait_vblank() while(REG_VCOUNT < 160) -#define swap_buffers() \ +#define present(x) \ do { \ - static int vis; \ - vis ^= 0x10; \ - REG_DISPCNT = DISPCNT_BG2 | 4 | vis; \ + REG_DISPCNT = DISPCNT_BG2 | 4 | ((x) << 4); \ } while(0) #define set_bg_color(idx, r, g, b) \ diff --git a/src/main.c b/src/main.c index 0eeaa5a..195f4a6 100644 --- a/src/main.c +++ b/src/main.c @@ -15,23 +15,45 @@ 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 . */ +#include #include #include "gbaregs.h" #include "timer.h" #include "keyb.h" #include "intr.h" #include "gfx.h" +#include "xgl.h" +#include "polyfill.h" +#include "debug.h" + +#define MENU_HEIGHT 17 +#define TRACK_HEIGHT 18 +#define VP_HEIGHT (160 - MENU_HEIGHT - TRACK_HEIGHT) static void handle_keys(void); extern struct { unsigned char r, g, b; } bgimg_cmap[]; extern unsigned char bgimg_pixels[]; +struct xvertex varr[] = { + {0, -0xd000}, + {-0x8000, 0x7000}, + {0x8000, 0x7000} +}; + int main(void) { int i; + unsigned int nframes = 0, backbuf; + unsigned long tm0, tm; uint16_t *cptr; unsigned char r, g, b; + unsigned char *fbptr[2], *fb; + struct pvertex benchv[3] = { + {120 << 8, 8 << 8}, + {75 << 8, 110 << 8}, + {164 << 8, 80 << 8} + }; intr_init(); reset_msec_timer(); @@ -40,6 +62,11 @@ int main(void) /* mode 4: 240x160 8bpp */ REG_DISPCNT = DISPCNT_BG2 | 4; + fbptr[0] = (unsigned char*)VRAM_LFB_FB0_ADDR; + fbptr[1] = (unsigned char*)VRAM_LFB_FB1_ADDR; + + set_bg_color(0xff, 31, 31, 31); + cptr = (uint16_t*)CRAM_BG_ADDR; for(i=0; i<128; i++) { r = bgimg_cmap[i].r >> 3; @@ -47,14 +74,42 @@ int main(void) b = bgimg_cmap[i].b >> 3; *cptr++ = r | (g << 5) | (b << 10); } - memcpy((void*)VRAM_LFB_FB0_ADDR, bgimg_pixels, 240 * 160); - memcpy((void*)VRAM_LFB_FB1_ADDR, bgimg_pixels, 240 * 160); + for(i=0; i<128; i++) { + r = (rand() & 0xf) + 8; + g = (rand() & 0xf) + 8; + b = (rand() & 0xf) + 8; + *cptr++ = r | (g << 5) | (b << 10); + } + memcpy(fbptr[0], bgimg_pixels, 240 * 160); + memcpy(fbptr[1], bgimg_pixels, 240 * 160); + + xgl_init(); + xgl_viewport(0, MENU_HEIGHT, 240, VP_HEIGHT); + + /* benchmark */ + polyfill_framebuffer(fbptr[0] + 240 * MENU_HEIGHT, 240, VP_HEIGHT); + tm0 = timer_msec; + for(i=0; i<2048; i++) { + polyfill_flat(benchv, 3, 128 + (i & 0x7f)); + } + tm = timer_msec - tm0; + emuprint("benchmark: %lu ms\n", tm); /*key_repeat(500, 75, KEY_LEFT | KEY_RIGHT | KEY_DOWN | KEY_UP);*/ for(;;) { + backbuf = ++nframes & 1; + + fb = fbptr[backbuf] + 240 * MENU_HEIGHT; + polyfill_framebuffer(fb, 240, VP_HEIGHT); + memset(fb, 14, 240 * VP_HEIGHT); + + xgl_load_identity(); + xgl_rotate_z(nframes << 8); + xgl_draw(XGL_TRIANGLES, varr, 3); + wait_vblank(); - swap_buffers(); + present(backbuf); } return 0; diff --git a/src/polyfill.c b/src/polyfill.c new file mode 100644 index 0000000..2595429 --- /dev/null +++ b/src/polyfill.c @@ -0,0 +1,99 @@ +/* +blender for the Gameboy Advance +Copyright (C) 2021 John Tsiombikas + +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 . +*/ +#include +#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; iy == 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 0) { + memset(fbptr + start, col, len); + } + fbptr += fbwidth; + } +} diff --git a/src/polyfill.h b/src/polyfill.h new file mode 100644 index 0000000..d637046 --- /dev/null +++ b/src/polyfill.h @@ -0,0 +1,30 @@ +/* +blender for the Gameboy Advance +Copyright (C) 2021 John Tsiombikas + +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 . +*/ +#ifndef POLYFILL_H_ +#define POLYFILL_H_ + +#include + +struct pvertex { + int32_t x, y; +}; + +void polyfill_framebuffer(unsigned char *fb, int width, int height); +void polyfill_flat(struct pvertex *v, int vnum, unsigned char col); + +#endif /* POLYFILL_H_ */ diff --git a/src/xgl.c b/src/xgl.c new file mode 100644 index 0000000..376d792 --- /dev/null +++ b/src/xgl.c @@ -0,0 +1,179 @@ +/* +blender for the Gameboy Advance +Copyright (C) 2021 John Tsiombikas + +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 . +*/ +#include +#include +#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> 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); + } +} diff --git a/src/xgl.h b/src/xgl.h new file mode 100644 index 0000000..1e531bb --- /dev/null +++ b/src/xgl.h @@ -0,0 +1,50 @@ +/* +blender for the Gameboy Advance +Copyright (C) 2021 John Tsiombikas + +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 . +*/ +#ifndef XGL_H_ +#define XGL_H_ + +enum { + XGL_LINES = 2, + XGL_TRIANGLES = 3, + XGL_QUADS = 4 +}; + +struct xvertex { + int32_t x, y, z; + unsigned char cidx; +}; + +void xgl_init(void); + +void xgl_viewport(int x, int y, int w, int h); + +void xgl_push_matrix(void); +void xgl_pop_matrix(void); +void xgl_load_identity(void); +void xgl_load_matrix(const int32_t *m); +void xgl_mult_matrix(const int32_t *m); + +void xgl_translate(int32_t x, int32_t y, int32_t z); +void xgl_rotate_x(int32_t angle); +void xgl_rotate_y(int32_t angle); +void xgl_rotate_z(int32_t angle); +void xgl_scale(int32_t x, int32_t y, int32_t z); + +void xgl_draw(int prim, const struct xvertex *varr, int vcount); + +#endif /* XGL_H_ */