3d cube and dirty drawing
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 26 Nov 2023 08:11:02 +0000 (10:11 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 26 Nov 2023 08:11:02 +0000 (10:11 +0200)
Makefile
src/3dgfx.c
src/3dgfx.h
src/config.h [new file with mode: 0644]
src/main.c
src/polyfill.c
src/vmath.c [new file with mode: 0644]
src/vmath.h [new file with mode: 0644]
src/vmath_s.asm [new file with mode: 0644]
tools/genlut.c

index 2f619d6..ab97777 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,10 @@
 
 !ifdef __UNIX__
 obj = src/main.obj src/video.obj src/3dgfx.obj src/3dgfx_s.obj &
 
 !ifdef __UNIX__
 obj = src/main.obj src/video.obj src/3dgfx.obj src/3dgfx_s.obj &
-       src/polyfill.obj src/lut.obj
+       src/polyfill.obj src/lut.obj src/vmath.obj src/vmath_s.obj
 !else
 obj = src\main.obj src\video.obj src\3dgfx.obj src\3dgfx_s.obj &
 !else
 obj = src\main.obj src\video.obj src\3dgfx.obj src\3dgfx_s.obj &
-       src\polyfill.obj src\lut.obj
+       src\polyfill.obj src\lut.obj src\vmath.obj src\vmath_s.obj
 !endif
 bin = low3d.exe
 
 !endif
 bin = low3d.exe
 
index f53ead6..5e2af06 100644 (file)
@@ -1,3 +1,5 @@
+#include "config.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -7,12 +9,14 @@
 static int32_t mvmat[16];
 static int32_t pmat[16];
 static int vp[4];
 static int32_t mvmat[16];
 static int32_t pmat[16];
 static int vp[4];
+static int dirty_x0, dirty_x1, dirty_y0, dirty_y1;
 
 unsigned char *g3d_fbpixels;
 int g3d_width, g3d_height;
 int g3d_curcidx;
 
 
 
 unsigned char *g3d_fbpixels;
 int g3d_width, g3d_height;
 int g3d_curcidx;
 
 
+
 int g3d_init(void)
 {
        memset(mvmat, 0, sizeof mvmat);
 int g3d_init(void)
 {
        memset(mvmat, 0, sizeof mvmat);
@@ -36,6 +40,103 @@ void g3d_framebuffer(int width, int height, void *fb)
        vp[0] = vp[1] = 0;
        vp[2] = width;
        vp[3] = height;
        vp[0] = vp[1] = 0;
        vp[2] = width;
        vp[3] = height;
+
+       g3d_reset_dirty();
+}
+
+void g3d_reset_dirty(void)
+{
+       dirty_x0 = XRES;
+       dirty_y0 = YRES;
+       dirty_x1 = 0;
+       dirty_y1 = 0;
+}
+
+void blkclear(void *p, int len, int col);
+#pragma aux blkclear = \
+       "mov ah, al" \
+       "shl eax, 8" \
+       "mov al, ah" \
+       "shl eax, 8" \
+       "mov al, ah" \
+       "shr ecx, 2" \
+       "rep stosd" \
+       parm [edi] [ecx] [eax] \
+       modify [eax ecx edi];
+
+extern volatile long nticks;
+#define COL    0
+
+void g3d_clear_dirty(void)
+{
+       unsigned char *ptr;
+       int i, count, nlines;
+
+       if(dirty_x0 < 0) dirty_x0 = 0;
+       if(dirty_y0 < 0) dirty_y0 = 0;
+       if(dirty_x1 >= XRES) dirty_x1 = XRES - 1;
+       if(dirty_y1 >= YRES) dirty_y1 = YRES - 1;
+
+       nlines = dirty_y1 - dirty_y0;
+       if(dirty_y1 <= 0 || nlines >= YRES) {
+               blkclear(g3d_fbpixels, XRES * YRES, COL);
+               goto end;
+       }
+
+       ptr = g3d_fbpixels + dirty_y0 * XRES;
+       if(dirty_x1 > XRES - 4) {
+               blkclear(ptr, nlines * XRES, COL);
+               goto end;
+       }
+
+       ptr = (unsigned char*)((uintptr_t)(ptr + dirty_x0) & 0xfffffffc);
+       count = dirty_x1 + 3 - dirty_x0;
+       for(i=0; i<nlines; i++) {
+               blkclear(ptr, count, COL);
+               ptr += XRES;
+       }
+end:
+       g3d_reset_dirty();
+}
+
+
+void vmemcopy(long fboffs, void *p, int len);
+#pragma aux vmemcopy = \
+       "mov edi, 0xa0000" \
+       "add edi, eax" \
+       "shr ecx, 2" \
+       "rep movsd" \
+       parm [eax] [esi] [ecx] \
+       modify [ecx edi esi];
+
+void g3d_copy_dirty(void)
+{
+       int i, count, nlines;
+       unsigned long fboffs;
+
+       if(dirty_x0 < 0) dirty_x0 = 0;
+       if(dirty_y0 < 0) dirty_y0 = 0;
+       if(dirty_x1 >= XRES) dirty_x1 = XRES - 1;
+       if(dirty_y1 >= YRES) dirty_y1 = YRES - 1;
+
+       nlines = dirty_y1 - dirty_y0;
+       if(dirty_y1 <= 0 || nlines >= YRES) {
+               vmemcopy(0, g3d_fbpixels, XRES * YRES);
+               return;
+       }
+
+       fboffs = dirty_y0 * XRES;
+       if(dirty_x1 > XRES - 4) {
+               vmemcopy(fboffs, g3d_fbpixels + fboffs, nlines * XRES);
+               return;
+       }
+
+       fboffs += dirty_x0 & 0xfffffffc;
+       count = dirty_x1 + 3 - dirty_x0;
+       for(i=0; i<nlines; i++) {
+               vmemcopy(fboffs, g3d_fbpixels + fboffs, count);
+               fboffs += XRES;
+       }
 }
 
 void g3d_modelview(const int32_t *m)
 }
 
 void g3d_modelview(const int32_t *m)
@@ -107,6 +208,15 @@ void g3d_draw_prim(int prim, struct g3d_vertex *varr)
                /* viewport transform */
                v[i].x = vpscale(v[i].x, vp[2], 1) + (vp[0] << 8);
                v[i].y = vpscale(-v[i].y, vp[3], 1) + (vp[1] << 8);
                /* viewport transform */
                v[i].x = vpscale(v[i].x, vp[2], 1) + (vp[0] << 8);
                v[i].y = vpscale(-v[i].y, vp[3], 1) + (vp[1] << 8);
+
+#if defined(USE_DIRTY_CLEAR) || defined(USE_DIRTY_COPY)
+               x = v[i].x >> 8;
+               y = v[i].y >> 8;
+               if(x - 4 < dirty_x0) dirty_x0 = x - 4;
+               if(y - 4 < dirty_y0) dirty_y0 = y - 4;
+               if(x + 8 > dirty_x1) dirty_x1 = x + 8;
+               if(y + 8 > dirty_y1) dirty_y1 = y + 8;
+#endif
        }
 
        switch(prim) {
        }
 
        switch(prim) {
index f4a1d28..d109ffd 100644 (file)
@@ -21,12 +21,18 @@ extern unsigned char *g3d_fbpixels;
 extern int g3d_width, g3d_height;
 extern int g3d_curcidx;
 
 extern int g3d_width, g3d_height;
 extern int g3d_curcidx;
 
+extern int g3d_bbox[4];
+
 
 int g3d_init(void);
 void g3d_shutdown(void);
 
 void g3d_framebuffer(int width, int height, void *fb);
 
 
 int g3d_init(void);
 void g3d_shutdown(void);
 
 void g3d_framebuffer(int width, int height, void *fb);
 
+void g3d_reset_dirty(void);
+void g3d_clear_dirty(void);
+void g3d_copy_dirty(void);
+
 void g3d_modelview(const int32_t *m);
 void g3d_projection(const int32_t *m);
 
 void g3d_modelview(const int32_t *m);
 void g3d_projection(const int32_t *m);
 
diff --git a/src/config.h b/src/config.h
new file mode 100644 (file)
index 0000000..962f3a7
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef CONFIG_H_
+#define CONFIG_H_
+
+#undef USE_VSYNC
+#define USE_DIRTY_CLEAR
+#define USE_DIRTY_COPY
+
+#endif /* CONFIG_H_ */
index 549ae6d..0dc0d6a 100644 (file)
@@ -1,3 +1,5 @@
+#include "config.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -5,6 +7,7 @@
 #include <dos.h>
 #include "video.h"
 #include "3dgfx.h"
 #include <dos.h>
 #include "video.h"
 #include "3dgfx.h"
+#include "vmath.h"
 #include "util.h"
 
 void update(void);
 #include "util.h"
 
 void update(void);
@@ -13,17 +16,18 @@ void interrupt timer_intr();
 
 static int quit;
 static unsigned char *fb;
 
 static int quit;
 static unsigned char *fb;
+static long nframes;
 
 
-static volatile unsigned long nticks;
+volatile unsigned long nticks;
 
 static void interrupt (*prev_timer_intr)();
 
 int main(void)
 {
 
 static void interrupt (*prev_timer_intr)();
 
 int main(void)
 {
-       long rate, nframes = 0;
-       long tstart, tdur;
+       int32_t proj[16];
+       long rate;
 
 
-       if(!(fb = malloc(64000))) {
+       if(!(fb = calloc(1, 64000))) {
                fprintf(stderr, "failed to allocate framebuffer\n");
                return 1;
        }
                fprintf(stderr, "failed to allocate framebuffer\n");
                return 1;
        }
@@ -33,11 +37,11 @@ int main(void)
        g3d_init();
        g3d_framebuffer(320, 200, fb);
 
        g3d_init();
        g3d_framebuffer(320, 200, fb);
 
+       mat_perspective(proj, 50, (4 << 16) / 3, 0x8000, 0x100000);
+       g3d_projection(proj);
+
        prev_timer_intr = _dos_getvect(0x1c);
        _dos_setvect(0x1c, timer_intr);
        prev_timer_intr = _dos_getvect(0x1c);
        _dos_setvect(0x1c, timer_intr);
-       _disable();
-       tstart = nticks;
-       _enable();
 
        for(;;) {
                while(kbhit()) {
 
        for(;;) {
                while(kbhit()) {
@@ -51,51 +55,63 @@ int main(void)
        }
 
 end:
        }
 
 end:
-       _disable();
-       tdur = nticks - tstart;
-       _enable();
        _dos_setvect(0x1c, prev_timer_intr);
 
        close_video();
        free(fb);
 
        _dos_setvect(0x1c, prev_timer_intr);
 
        close_video();
        free(fb);
 
-       rate = nframes * 100 * 18 / tdur;
-       printf("%ld frames in %ld sec, rate: %ld.%ld\n", nframes, tdur / 18,
+       rate = nframes * 100 * 18 / nticks;
+       printf("%ld frames in %ld sec, rate: %ld.%ld\n", nframes, nticks / 18,
                        rate / 100, rate % 100);
        return 0;
 }
 
                        rate / 100, rate % 100);
        return 0;
 }
 
+#define VERT(x, y, z) { x << 16, y << 16, z << 16, 0x10000 }
 struct g3d_vertex varr[] = {
 struct g3d_vertex varr[] = {
-       {0, 0x8000, 0, 0x10000},
-       {-0x8f00, -0x8000, 0, 0x10000},
-       {0x8c00, -0x6000, 0, 0x10000}
+       VERT(-1, -1, 1), VERT(1, -1, 1), VERT(1, 1, 1), VERT(-1, 1, 1),
+       VERT(1, -1, 1), VERT(1, -1, -1), VERT(1, 1, -1), VERT(1, 1, 1),
+       VERT(1, -1, -1), VERT(-1, -1, -1), VERT(-1, 1, -1), VERT(1, 1, -1),
+       VERT(-1, -1, -1), VERT(-1, -1, 1), VERT(-1, 1, 1), VERT(-1, 1, -1),
+       VERT(-1, 1, 1), VERT(1, 1, 1), VERT(1, 1, -1), VERT(-1, 1, -1),
+       VERT(-1, -1, -1), VERT(1, -1, -1), VERT(1, -1, 1), VERT(-1, -1, 1)
 };
 
 };
 
-void mat_rotz(int32_t *m, int theta)
-{
-       m[0] = XCOS(theta);
-       m[1] = XSIN(theta);
-       m[4] = -XSIN(theta);
-       m[5] = XCOS(theta);
-       m[10] = 0x10000;
-       m[15] = 0x10000;
-       m[2] = m[3] = m[6] = m[7] = m[8] = m[9] = m[11] = m[12] = m[13] = m[14] = 0;
-}
-
 void update(void)
 {
        int32_t xform[16];
 
 void update(void)
 {
        int32_t xform[16];
 
+#ifdef USE_DIRTY_CLEAR
+       g3d_clear_dirty();
+#else
        vid_clearfb(fb);
        vid_clearfb(fb);
+#endif
 
 
-       mat_rotz(xform, nticks);
+       mat_trans(xform, 0, 0, -0x40000);
+       mat_mul_rotx(xform, nframes);
+       mat_mul_roty(xform, nframes);
        g3d_modelview(xform);
 
        g3d_modelview(xform);
 
-       g3d_color(15);
-       g3d_draw(G3D_TRIANGLES, varr, sizeof varr / sizeof *varr);
-
-       /*wait_vsync();*/
+       g3d_color(9);
+       g3d_draw(G3D_QUADS, varr, 4);
+       g3d_color(10);
+       g3d_draw(G3D_QUADS, varr + 4, 4);
+       g3d_color(11);
+       g3d_draw(G3D_QUADS, varr + 8, 4);
+       g3d_color(12);
+       g3d_draw(G3D_QUADS, varr + 12, 4);
+       g3d_color(13);
+       g3d_draw(G3D_QUADS, varr + 16, 4);
+       g3d_color(14);
+       g3d_draw(G3D_QUADS, varr + 20, 4);
+
+#ifdef USE_VSYNC
+       wait_vsync();
+#endif
+#ifdef USE_DIRTY_COPY
+       g3d_copy_dirty();
+#else
        vid_copyfb(fb);
        vid_copyfb(fb);
+#endif
 }
 
 void handle_key(int key)
 }
 
 void handle_key(int key)
index ff62225..ac84ff2 100644 (file)
@@ -10,8 +10,18 @@ void g3d_polyfill(struct g3d_vertex *verts)
 {
        int i, topidx, botidx, mididx;
        int32_t dx, dy, dym;
 {
        int i, topidx, botidx, mididx;
        int32_t dx, dy, dym;
+       int32_t v01x, v01y, v02x, v02y;
        struct g3d_vertex vtmp;
 
        struct g3d_vertex vtmp;
 
+       /* calculate winding */
+       v01x = verts[1].x - verts[0].x;
+       v01y = verts[1].y - verts[0].y;
+       v02x = verts[2].x - verts[0].x;
+       v02y = verts[2].y - verts[0].y;
+       if(!((v01x * v02y - v02x * v01y) & 0x80000000)) {
+               return;
+       }
+
        topidx = botidx = 0;
        for(i=1; i<3; i++) {
                if(verts[i].y < verts[topidx].y) {
        topidx = botidx = 0;
        for(i=1; i<3; i++) {
                if(verts[i].y < verts[topidx].y) {
@@ -21,8 +31,10 @@ void g3d_polyfill(struct g3d_vertex *verts)
                        botidx = i;
                }
        }
                        botidx = i;
                }
        }
-       mididx = (topidx + 1) % 3;
-       if(mididx == botidx) mididx = (mididx + 1) % 3;
+       mididx = topidx + 1; if(mididx > 2) mididx = 0;
+       if(mididx == botidx) {
+               if(++mididx > 2) mididx = 0;
+       }
 
        dy = verts[botidx].y - verts[topidx].y;
        if(dy == 0) return;
 
        dy = verts[botidx].y - verts[topidx].y;
        if(dy == 0) return;
@@ -43,8 +55,9 @@ void g3d_polyfill(struct g3d_vertex *verts)
 static void filltop(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2)
 {
        struct g3d_vertex *vtmp;
 static void filltop(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2)
 {
        struct g3d_vertex *vtmp;
-       int x, xn, y, endy, len;
-       int32_t xl, xr, dxl, dxr, dxldy, dxrdy, dy;
+       int x, xn, line, lasty, len;
+       int32_t xl, xr, dxl, dxr, slopel, sloper, dy;
+       int32_t y0, y1, yoffs;
        unsigned char *fbptr;
 
        if(v1->x > v2->x) {
        unsigned char *fbptr;
 
        if(v1->x > v2->x) {
@@ -53,39 +66,45 @@ static void filltop(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_ver
                v2 = vtmp;
        }
 
                v2 = vtmp;
        }
 
-       y = v0->y >> 8;
-       endy = v1->y >> 8;
-       if(endy > YRES) endy = YRES;
-       x = v0->x >> 8;
-
-       fbptr = g3d_fbpixels + y * XRES + x;
-
-       xl = xr = v0->x;
        dy = v1->y - v0->y;
        dxl = v1->x - v0->x;
        dxr = v2->x - v0->x;
        dy = v1->y - v0->y;
        dxl = v1->x - v0->x;
        dxr = v2->x - v0->x;
-       dxldy = (dxl << 8) / dy;
-       dxrdy = (dxr << 8) / dy;
+       slopel = (dxl << 8) / dy;
+       sloper = (dxr << 8) / dy;
+
+       y0 = (v0->y + 0x100) & 0xffffff00;      /* start from the next scanline */
+       yoffs = y0 - v0->y;                                     /* offset of the next scanline */
+       xl = v0->x + ((yoffs * slopel) >> 8);
+       xr = v0->x + ((yoffs * sloper) >> 8);
+
+       line = y0 >> 8;
+       lasty = v1->y >> 8;
+       if(lasty >= YRES) lasty = YRES - 1;
+       x = xl >> 8;
 
 
-       while(y++ < endy) {
-               if(y > 0) {
-                       len = (xr - xl) >> 8;
+       fbptr = g3d_fbpixels + line * XRES + x;
+
+       while(line <= lasty) {
+               if(line >= 0) {
+                       len = ((xr + 0x100) >> 8) - (xl >> 8);
                        if(len > 0) memset(fbptr, g3d_curcidx, len);
                }
 
                        if(len > 0) memset(fbptr, g3d_curcidx, len);
                }
 
-               xl += dxldy;
-               xr += dxrdy;
+               xl += slopel;
+               xr += sloper;
                xn = xl >> 8;
                fbptr += XRES + (xn - x);
                x = xn;
                xn = xl >> 8;
                fbptr += XRES + (xn - x);
                x = xn;
+               line++;
        }
 }
 
 static void fillbot(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2)
 {
        struct g3d_vertex *vtmp;
        }
 }
 
 static void fillbot(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2)
 {
        struct g3d_vertex *vtmp;
-       int x, xn, y, endy, len;
-       int32_t xl, xr, dxl, dxr, dxldy, dxrdy, dy;
+       int x, xn, line, lasty, len;
+       int32_t xl, xr, dxl, dxr, slopel, sloper, dy;
+       int32_t y0, y1, yoffs;
        unsigned char *fbptr;
 
        if(v0->x > v1->x) {
        unsigned char *fbptr;
 
        if(v0->x > v1->x) {
@@ -94,31 +113,35 @@ static void fillbot(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_ver
                v1 = vtmp;
        }
 
                v1 = vtmp;
        }
 
-       y = v0->y >> 8;
-       endy = v2->y >> 8;
-       if(endy > YRES) endy = YRES;
-       x = v0->x >> 8;
-
-       fbptr = g3d_fbpixels + y * XRES + x;
-
-       xl = v0->x;
-       xr = v1->x;
        dy = v2->y - v0->y;
        dxl = v2->x - v0->x;
        dxr = v2->x - v1->x;
        dy = v2->y - v0->y;
        dxl = v2->x - v0->x;
        dxr = v2->x - v1->x;
-       dxldy = (dxl << 8) / dy;
-       dxrdy = (dxr << 8) / dy;
+       slopel = (dxl << 8) / dy;
+       sloper = (dxr << 8) / dy;
+
+       y0 = (v0->y + 0x100) & 0xffffff00;      /* start from the next scanline */
+       yoffs = y0 - v0->y;                                     /* offset of the next scanline */
+       xl = v0->x + ((yoffs * slopel) >> 8);
+       xr = v1->x + ((yoffs * sloper) >> 8);
+
+       line = y0 >> 8;
+       lasty = v2->y >> 8;
+       if(lasty >= YRES) lasty = YRES - 1;
+       x = xl >> 8;
+
+       fbptr = g3d_fbpixels + line * XRES + x;
 
 
-       while(y++ < endy) {
-               if(y > 0) {
-                       len = (xr - xl) >> 8;
+       while(line <= lasty) {
+               if(line >= 0) {
+                       len = ((xr + 0x100) >> 8) - (xl >> 8);
                        if(len > 0) memset(fbptr, g3d_curcidx, len);
                }
 
                        if(len > 0) memset(fbptr, g3d_curcidx, len);
                }
 
-               xl += dxldy;
-               xr += dxrdy;
+               xl += slopel;
+               xr += sloper;
                xn = xl >> 8;
                fbptr += XRES + (xn - x);
                x = xn;
                xn = xl >> 8;
                fbptr += XRES + (xn - x);
                x = xn;
+               line++;
        }
 }
        }
 }
diff --git a/src/vmath.c b/src/vmath.c
new file mode 100644 (file)
index 0000000..faebd48
--- /dev/null
@@ -0,0 +1,96 @@
+#include <string.h>
+#include <math.h>
+#include "vmath.h"
+#include "util.h"
+
+static const int32_t idmat[] = {
+       0x10000, 0, 0, 0,
+       0, 0x10000, 0, 0,
+       0, 0, 0x10000, 0,
+       0, 0, 0, 0x10000
+};
+
+void mat_identity(int32_t *m)
+{
+       memcpy(m, idmat, sizeof idmat);
+}
+
+void mat_trans(int32_t *m, int32_t x, int32_t y, int32_t z)
+{
+       memcpy(m, idmat, sizeof idmat);
+       m[3] = x;
+       m[7] = y;
+       m[11] = z;
+}
+
+void mat_rotx(int32_t *m, int32_t theta)
+{
+       memcpy(m, idmat, sizeof idmat);
+       m[5] = XCOS(theta);
+       m[6] = XSIN(theta);
+       m[9] = -XSIN(theta);
+       m[10] = XCOS(theta);
+}
+
+void mat_roty(int32_t *m, int32_t theta)
+{
+       memcpy(m, idmat, sizeof idmat);
+       m[0] = XCOS(theta);
+       m[2] = -XSIN(theta);
+       m[8] = XSIN(theta);
+       m[10] = XCOS(theta);
+}
+
+void mat_rotz(int32_t *m, int32_t theta)
+{
+       memcpy(m, idmat, sizeof idmat);
+       m[0] = XCOS(theta);
+       m[1] = XSIN(theta);
+       m[4] = -XSIN(theta);
+       m[5] = XCOS(theta);
+}
+
+void mat_mul_trans(int32_t *m, int32_t x, int32_t y, int32_t z)
+{
+       int32_t tmp[16];
+       mat_trans(tmp, x, y, z);
+       mat_mult(m, tmp);
+}
+
+void mat_mul_rotx(int32_t *m, int32_t theta)
+{
+       int32_t tmp[16];
+       mat_rotx(tmp, theta);
+       mat_mult(m, tmp);
+}
+
+void mat_mul_rotz(int32_t *m, int32_t theta)
+{
+       int32_t tmp[16];
+       mat_rotz(tmp, theta);
+       mat_mult(m, tmp);
+}
+
+void mat_mul_roty(int32_t *m, int32_t theta)
+{
+       int32_t tmp[16];
+       mat_roty(tmp, theta);
+       mat_mult(m, tmp);
+}
+
+void mat_perspective(int32_t *m, int vfov, int32_t aspect, int32_t znear, int32_t zfar)
+{
+       float halffov = (float)vfov * 3.1415926536f / 360.0f;
+       float s = 1.0f / (float)tan(halffov);
+       float zn = (float)znear / 65536.0f;
+       float zf = (float)zfar / 65536.0f;
+       float dz = zn - zf;
+
+       memset(m, 0, 16 * sizeof *m);
+       m[0] = (int32_t)((s / ((float)aspect / 65536.0f)) * 65536.0f);
+       m[5] = (int32_t)(s * 65536.0f);
+       m[10] = (int32_t)((zn + zf) / dz * 65536.0f);
+       m[11] = (int32_t)(2.0f * zn * zf / dz * 65536.0f);
+       m[14] = -0x10000;
+       m[15] = 0x10000;
+}
diff --git a/src/vmath.h b/src/vmath.h
new file mode 100644 (file)
index 0000000..134540f
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef VMATH_H_
+#define VMATH_H_
+
+#include "types.h"
+
+void mat_trans(int32_t *m, int32_t x, int32_t y, int32_t z);
+void mat_rotx(int32_t *m, int32_t theta);
+void mat_roty(int32_t *m, int32_t theta);
+void mat_rotz(int32_t *m, int32_t theta);
+
+void mat_mul_trans(int32_t *m, int32_t x, int32_t y, int32_t z);
+void mat_mul_rotx(int32_t *m, int32_t theta);
+void mat_mul_roty(int32_t *m, int32_t theta);
+void mat_mul_rotz(int32_t *m, int32_t theta);
+
+void mat_perspective(int32_t *m, int vfov, int32_t aspect, int32_t znear, int32_t zfar);
+
+void mat_mult(int32_t *ma, int32_t *mb);
+
+#endif /* VMATH_H_ */
diff --git a/src/vmath_s.asm b/src/vmath_s.asm
new file mode 100644 (file)
index 0000000..8b6c027
--- /dev/null
@@ -0,0 +1,109 @@
+       bits 32
+       section .text USE32
+       
+       ; eax: ma ptr, edx: mb ptr
+       global mat_mult_
+mat_mult_:
+       push ebp
+       mov ebp, esp
+       sub esp, 64
+       push ebx
+       push ecx
+       push esi
+       push edi
+
+       mov ebx, edx    ; mb to ebx
+       mov edi, eax    ; ma to edi
+
+%macro MULROWCOL 0
+       mov eax, [edi]                  ; eax <- row[0]
+       imul dword [ebx]                ; mul col[0]
+       shrd eax, edx, 16
+       mov ecx, eax
+       mov eax, [edi + 4]              ; eax <- row[1]
+       imul dword [ebx + 16]   ; mul col[1]
+       shrd eax, edx, 16
+       add ecx, eax
+       mov eax, [edi + 8]              ; eax <- row[2]
+       imul dword [ebx + 32]   ; mul col[2]
+       shrd eax, edx, 16
+       add ecx, eax
+       mov eax, [edi + 12]             ; eax <- row[3]
+       imul dword [ebx + 48]   ; mul col[3]
+       shrd eax, edx, 16
+       add eax, ecx                    ; dot product in eax
+%endmacro
+
+       ; row 0
+       MULROWCOL
+       mov [ebp - 64], eax
+       add ebx, 4                              ; next matrix b column
+       MULROWCOL
+       mov [ebp - 60], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 56], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 52], eax
+       sub ebx, 12                             ; return to mb column 0
+       add edi, 16                             ; next matrix a row
+
+       ; row 1
+       MULROWCOL
+       mov [ebp - 48], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 44], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 40], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 36], eax
+       sub ebx, 12                     ; return to mb column 0
+       add edi, 16                     ; next matrix a row
+       
+       ; row 2
+       MULROWCOL
+       mov [ebp - 32], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 28], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 24], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 20], eax
+       sub ebx, 12                     ; return to mb column 0
+       add edi, 16                     ; next matrix a row
+       
+       ; row 3
+       MULROWCOL
+       mov [ebp - 16], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 12], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 8], eax
+       add ebx, 4
+       MULROWCOL
+       mov [ebp - 4], eax
+       
+       sub edi, 48             ; return edi to the start of matrix a
+       lea esi, [ebp - 64]     ; esi to the temp matrix on stack
+       mov ecx, 16
+       rep movsd
+       
+       pop edi
+       pop esi
+       pop ecx
+       pop ebx
+       mov esp, ebp
+       pop ebp
+       ret
+
+; vi:ft=nasm ts=8 sts=8 sw=8:
+       ret
index cbd629c..45be022 100644 (file)
@@ -1,37 +1,37 @@
-#include <stdio.h>\r
-#include <math.h>\r
-\r
-#define SINTAB_SIZE            512\r
-#define SINTAB_SCALE   8192\r
-\r
-int main(void)\r
-{\r
-       int i, len;\r
-\r
-       printf("\tbits 32\n");\r
-       printf("\tsection .rodata\n\n");\r
-\r
-       printf("\tglobal _sintab\n");\r
-       printf("_sintab:\n");\r
-\r
-       fputs("\tdw", stdout);\r
-       len = 10;\r
-       for(i=0; i<SINTAB_SIZE; i++) {\r
-               double theta = (double)i / (double)SINTAB_SIZE * 6.28318530718;\r
-               double sf = sin(theta);\r
-               int sx = (int)(sf * SINTAB_SCALE);\r
-               len += printf(" %d", sx);\r
-               if(len >= 72) {\r
-                       putchar('\n');\r
-                       if(i < SINTAB_SIZE - 1) {\r
-                               fputs("\tdw", stdout);\r
-                               len = 10;\r
-                       }\r
-               } else {\r
-                       putchar(',');\r
-                       len++;\r
-               }\r
-       }\r
-       printf("\n\n; vi:ft=nasm ts=8 sts=8 sw=8:\n");\r
-       return 0;\r
-}\r
+#include <stdio.h>
+#include <math.h>
+
+#define SINTAB_SIZE            512
+#define SINTAB_SCALE   8192
+
+int main(void)
+{
+       int i, len;
+
+       printf("\tbits 32\n");
+       printf("\tsection .rodata\n\n");
+
+       printf("\tglobal _sintab\n");
+       printf("_sintab:\n");
+
+       fputs("\tdw", stdout);
+       len = 10;
+       for(i=0; i<SINTAB_SIZE; i++) {
+               double theta = (double)i / (double)SINTAB_SIZE * 6.28318530718;
+               double sf = sin(theta);
+               int sx = (int)(sf * SINTAB_SCALE);
+               len += printf(" %d", sx);
+               if(len >= 72) {
+                       putchar('\n');
+                       if(i < SINTAB_SIZE - 1) {
+                               fputs("\tdw", stdout);
+                               len = 10;
+                       }
+               } else {
+                       putchar(',');
+                       len++;
+               }
+       }
+       printf("\n\n; vi:ft=nasm ts=8 sts=8 sw=8:\n");
+       return 0;
+}