grid axes
[gba_blender] / src / xgl.c
index 376d792..4880aba 100644 (file)
--- a/src/xgl.c
+++ b/src/xgl.c
@@ -19,17 +19,36 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <math.h>
 #include "xgl.h"
 #include "polyfill.h"
+#include "debug.h"
 
 #define MAT_STACK_SIZE 4
 
 static int vp[4];
 static int32_t mat[MAT_STACK_SIZE][16];
 static int mtop;
+static unsigned int opt;
+static int32_t ldir[3];
+
+static void draw_ptlines(int prim, const struct xvertex *varr, int vcount);
+
 
 void xgl_init(void)
 {
        xgl_viewport(0, 0, 240, 160);
        xgl_load_identity();
+
+       ldir[0] = ldir[1] = 0;
+       ldir[2] = -0x100;
+}
+
+void xgl_enable(unsigned int o)
+{
+       opt |= o;
+}
+
+void xgl_disable(unsigned int o)
+{
+       opt &= ~o;
 }
 
 void xgl_viewport(int x, int y, int w, int h)
@@ -157,23 +176,94 @@ static void xform(struct xvertex *out, const struct xvertex *in, const int32_t *
        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)
+{
+       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);
+       out->nz = XMUL(m[2], in->nx) + XMUL(m[6], in->ny) + XMUL(m[10], in->nz);
+}
+
+/* d = 1.0 / tan(fov/2) */
+#define PROJ_D 0x20000
+
 void xgl_draw(int prim, const struct xvertex *varr, int vcount)
 {
-       int i;
+       int i, cidx;
        struct xvertex xv[4];
        struct pvertex pv[4];
+       int32_t ndotl;
+
+       if(prim < 3) {
+               draw_ptlines(prim, varr, vcount);
+               return;
+       }
 
        while(vcount >= prim) {
-               for(i=0; i<prim; i++) {
+               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++;
+
+               for(i=1; i<prim; i++) {
                        xform(xv + i, varr, mat[mtop]);
+
+                       xv[i].x = (xv[i].x << 1) / (xv[i].z >> 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 */
+                       /* 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++;
+               }
+               vcount -= prim;
 
+               polyfill_flat(pv, prim, cidx);
+       }
+}
+
+static void draw_ptlines(int prim, const struct xvertex *varr, int vcount)
+{
+       int i;
+       struct xvertex xv[2];
+
+       while(vcount >= prim) {
+               for(i=0; i<prim; i++) {
+                       xform(xv + i, varr, mat[mtop]);
+
+                       xv[i].x = (xv[i].x << 1) / (xv[i].z >> 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 */
                        /* 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);
+                       xv[i].x = ((((xv[i].x + 0x100) >> 1) * vp[2]) >> 8) + vp[0];
+                       xv[i].y = ((((0x100 - xv[i].y) >> 1) * vp[3]) >> 8) + vp[1];
+                       varr++;
                }
                vcount -= prim;
 
-               polyfill_flat(pv, prim, 0xff);
+               /* line clipping */
+               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);
+               draw_line(xv[0].x, xv[0].y, xv[1].x, xv[1].y, varr[-2].cidx);
        }
 }