X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fxgl.c;h=7d22b2bc4e65cab65946a9cab5ed721effc6ec38;hb=ee0d92a6e621e6a8135b16914a09def52bd70a4b;hp=deccdea962c6e727d6363c5eb426925ab54b1cdf;hpb=f57fab6afe62f2a476ef4afa1842c81722816451;p=gbajam22 diff --git a/src/xgl.c b/src/xgl.c index deccdea..7d22b2b 100644 --- a/src/xgl.c +++ b/src/xgl.c @@ -1,6 +1,6 @@ /* -blender for the Gameboy Advance -Copyright (C) 2021 John Tsiombikas +gbajam22 entry for the Gameboy Advance +Copyright (C) 2022 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 @@ -20,6 +20,7 @@ along with this program. If not, see . #include "xgl.h" #include "polyfill.h" #include "debug.h" +#include "util.h" #define MAT_STACK_SIZE 4 @@ -29,6 +30,8 @@ static int mtop; static unsigned int opt; static int32_t ldir[3]; +static int cur_cidx; + static void draw_ptlines(int prim, const struct xvertex *varr, int vcount); @@ -116,8 +119,13 @@ void xgl_mult_matrix(const int32_t *m2) } } +#if 0 #define XSIN(x) (int32_t)(sin(x / 65536.0f) * 65536.0f) #define XCOS(x) (int32_t)(cos(x / 65536.0f) * 65536.0f) +#else +#define XSIN(x) SIN(((x) << 8) / (X_2PI >> 8)) +#define XCOS(x) COS(((x) << 8) / (X_2PI >> 8)) +#endif void xgl_translate(int32_t x, int32_t y, int32_t z) { @@ -174,14 +182,19 @@ void xgl_scale(int32_t x, int32_t y, int32_t z) xgl_mult_matrix(m); } -static void xform(struct xvertex *out, const struct xvertex *in, const int32_t *m) +void xgl_index(int cidx) +{ + cur_cidx = cidx; +} + +static inline 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]; } -static void xform_norm(struct xvertex *out, const struct xvertex *in, const int32_t *m) +static inline void xform_norm(struct xvertex *out, const struct xvertex *in, const int32_t *m) { out->nx = XMUL(m[0], in->nx) + XMUL(m[4], in->ny) + XMUL(m[8], in->nz); out->ny = XMUL(m[1], in->nx) + XMUL(m[5], in->ny) + XMUL(m[9], in->nz); @@ -190,11 +203,14 @@ static void xform_norm(struct xvertex *out, const struct xvertex *in, const int3 /* d = 1.0 / tan(fov/2) */ #define PROJ_D 0x20000 +/* near Z = 0.5 */ +#define NEAR_Z 0x18000 +ARM_IWRAM void xgl_draw(int prim, const struct xvertex *varr, int vcount) { - int i, cidx; - struct xvertex xv[4]; + int i, cidx, clipnum; + struct xvertex xv[4], xvclip[8]; struct pvertex pv[4]; int32_t ndotl; @@ -204,47 +220,41 @@ void xgl_draw(int prim, const struct xvertex *varr, int vcount) } while(vcount >= prim) { - cidx = varr->cidx; + cidx = cur_cidx;//varr->cidx; xform(xv, varr, mat[mtop]); xform_norm(xv, varr, mat[mtop]); - if(xv->nz > 0) { - /* backface */ - varr += prim; - vcount -= prim; - continue; - } - + /* if(opt & XGL_LIGHTING) { ndotl = (xv->nx >> 8) * ldir[0] + (xv->ny >> 8) * ldir[1] + (xv->nz >> 8) * ldir[2]; if(ndotl < 0) ndotl = 0; cidx = 128 + (ndotl >> 9); if(cidx > 255) cidx = 255; } + */ - xv->x = (xv->x << 1) / (xv->z >> 8); /* assume aspect: ~2 */ - xv->y = (xv->y << 2) / (xv->z >> 8); /* the shift is * PROJ_D */ - /* projection result is 24.8 */ - /* viewport */ - pv->x = (((xv->x + 0x100) >> 1) * vp[2]) + (vp[0] << 8); - pv->y = (((0x100 - xv->y) >> 1) * vp[3]) + (vp[1] << 8); - varr++; - + /* transform the rest of the vertices to view space */ for(i=1; i> 8); /* assume aspect: ~2 */ - xv[i].y = (xv[i].y << 2) / (xv[i].z >> 8); /* the shift is * PROJ_D */ - /* projection result is 24.8 */ + /* clip against near plane */ + xgl_clip_near(xvclip, &clipnum, xv, prim); + + for(i=0; i> 8); /* assume aspect: ~2 */ + xvclip[i].y = (xvclip[i].y << 2) / (xvclip[i].z >> 8); /* the shift is * PROJ_D */ + /* transform result is 24.8 */ /* viewport */ - pv[i].x = (((xv[i].x + 0x100) >> 1) * vp[2]) + (vp[0] << 8); - pv[i].y = (((0x100 - xv[i].y) >> 1) * vp[3]) + (vp[1] << 8); - varr++; + pv[i].x = (((xvclip[i].x + 0x100) >> 1) * vp[2]) + (vp[0] << 8); + pv[i].y = (((0x100 - xvclip[i].y) >> 1) * vp[3]) + (vp[1] << 8); } - vcount -= prim; - polyfill_flat(pv, prim, cidx); + polyfill_flat(pv, clipnum, cidx); +skip_poly: + varr += prim; + vcount -= prim; } } @@ -284,7 +294,7 @@ static void draw_ptlines(int prim, const struct xvertex *varr, int vcount) #ifndef ALT_LCLIP clip_line((int*)&xv[0].x, (int*)&xv[0].y, (int*)&xv[1].x, (int*)&xv[1].y, vp[0], vp[1], vp[2] - 1, vp[3] - 1); #endif - draw_line(xv[0].x, xv[0].y, xv[1].x, xv[1].y, varr[-2].cidx); + draw_line(xv[0].x, xv[0].y, xv[1].x, xv[1].y, 0xff); } } @@ -292,3 +302,85 @@ void xgl_xyzzy(void) { mat[mtop][12] = mat[mtop][13] = 0; } + +#define ISECT_NEAR(v0, v1) ((((v0)->z - NEAR_Z) << 8) / ((v0)->z - (v1)->z)) + +#define LERP_VATTR(res, v0, v1, t) \ + do { \ + (res)->x = (v0)->x + (((v1)->x - (v0)->x) >> 8) * (t); \ + (res)->y = (v0)->y + (((v1)->y - (v0)->y) >> 8) * (t); \ + (res)->z = (v0)->z + (((v1)->z - (v0)->z) >> 8) * (t); \ + (res)->nx = (v0)->nx + (((v1)->nx - (v0)->nx) >> 8) * (t); \ + (res)->ny = (v0)->ny + (((v1)->ny - (v0)->ny) >> 8) * (t); \ + (res)->nz = (v0)->nz + (((v1)->nz - (v0)->nz) >> 8) * (t); \ + (res)->tx = (v0)->tx + (((v1)->tx - (v0)->tx) >> 8) * (t); \ + (res)->ty = (v0)->ty + (((v1)->ty - (v0)->ty) >> 8) * (t); \ + (res)->lit = (v0)->lit + (((v1)->lit - (v0)->lit) >> 8) * (t); \ + } while(0) + +ARM_IWRAM +static int clip_edge_near(struct xvertex *poly, int *vnumptr, struct xvertex *v0, struct xvertex *v1) +{ + int vnum = *vnumptr; + int in0, in1; + int32_t t; + struct xvertex *vptr; + + in0 = v0->z >= NEAR_Z ? 1 : 0; + in1 = v1->z >= NEAR_Z ? 1 : 0; + + if(in0) { + /* start inside */ + if(in1) { + /* all inside */ + poly[vnum++] = *v1; /* append v1 */ + *vnumptr = vnum; + return 1; + } else { + /* going out */ + vptr = poly + vnum; + t = ISECT_NEAR(v0, v1); /* 24:8 */ + LERP_VATTR(vptr, v0, v1, t); + ++vnum; /* append new vertex on the intersection point */ + } + } else { + /* start outside */ + if(in1) { + /* going in */ + vptr = poly + vnum; + t = ISECT_NEAR(v0, v1); + LERP_VATTR(vptr, v0, v1, t); + ++vnum; /* append new vertex ... */ + /* then append v1 */ + poly[vnum++] = *v1; + } else { + /* all outside */ + return -1; + } + } + + *vnumptr = vnum; + return 0; +} + +/* special case near-plane clipper */ +ARM_IWRAM +int xgl_clip_near(struct xvertex *vout, int *voutnum, struct xvertex *vin, int vnum) +{ + int i, nextidx, res; + int edges_clipped = 0; + + *voutnum = 0; + + for(i=0; i= vnum) nextidx = 0; + res = clip_edge_near(vout, voutnum, vin + i, vin + nextidx); + if(res == 0) { + ++edges_clipped; + } + } + + if(*voutnum <= 0) return -1; + return edges_clipped > 0 ? 0 : 1; +}