From: John Tsiombikas Date: Sun, 26 Nov 2023 08:11:02 +0000 (+0200) Subject: 3d cube and dirty drawing X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=commitdiff_plain;h=885149ece88f5d4cfe206fe22ee7f5fa711032e7;p=dos_low3d 3d cube and dirty drawing --- diff --git a/Makefile b/Makefile index 2f619d6..ab97777 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ !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 & - src\polyfill.obj src\lut.obj + src\polyfill.obj src\lut.obj src\vmath.obj src\vmath_s.obj !endif bin = low3d.exe diff --git a/src/3dgfx.c b/src/3dgfx.c index f53ead6..5e2af06 100644 --- a/src/3dgfx.c +++ b/src/3dgfx.c @@ -1,3 +1,5 @@ +#include "config.h" + #include #include #include @@ -7,12 +9,14 @@ 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; + 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; + + 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= 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> 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) { diff --git a/src/3dgfx.h b/src/3dgfx.h index f4a1d28..d109ffd 100644 --- a/src/3dgfx.h +++ b/src/3dgfx.h @@ -21,12 +21,18 @@ extern unsigned char *g3d_fbpixels; 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); +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); diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..962f3a7 --- /dev/null +++ b/src/config.h @@ -0,0 +1,8 @@ +#ifndef CONFIG_H_ +#define CONFIG_H_ + +#undef USE_VSYNC +#define USE_DIRTY_CLEAR +#define USE_DIRTY_COPY + +#endif /* CONFIG_H_ */ diff --git a/src/main.c b/src/main.c index 549ae6d..0dc0d6a 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,5 @@ +#include "config.h" + #include #include #include @@ -5,6 +7,7 @@ #include #include "video.h" #include "3dgfx.h" +#include "vmath.h" #include "util.h" void update(void); @@ -13,17 +16,18 @@ void interrupt timer_intr(); 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) { - 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; } @@ -33,11 +37,11 @@ int main(void) 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); - _disable(); - tstart = nticks; - _enable(); for(;;) { while(kbhit()) { @@ -51,51 +55,63 @@ int main(void) } end: - _disable(); - tdur = nticks - tstart; - _enable(); _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; } +#define VERT(x, y, z) { x << 16, y << 16, z << 16, 0x10000 } 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]; +#ifdef USE_DIRTY_CLEAR + g3d_clear_dirty(); +#else 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_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); +#endif } void handle_key(int key) diff --git a/src/polyfill.c b/src/polyfill.c index ff62225..ac84ff2 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -10,8 +10,18 @@ void g3d_polyfill(struct g3d_vertex *verts) { int i, topidx, botidx, mididx; int32_t dx, dy, dym; + int32_t v01x, v01y, v02x, v02y; 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) { @@ -21,8 +31,10 @@ void g3d_polyfill(struct g3d_vertex *verts) 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; @@ -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; - 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) { @@ -53,39 +66,45 @@ static void filltop(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_ver 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; - 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); } - xl += dxldy; - xr += dxrdy; + xl += slopel; + xr += sloper; 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; - 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) { @@ -94,31 +113,35 @@ static void fillbot(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_ver 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; - 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); } - xl += dxldy; - xr += dxrdy; + xl += slopel; + xr += sloper; xn = xl >> 8; fbptr += XRES + (xn - x); x = xn; + line++; } } diff --git a/src/vmath.c b/src/vmath.c new file mode 100644 index 0000000..faebd48 --- /dev/null +++ b/src/vmath.c @@ -0,0 +1,96 @@ +#include +#include +#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 index 0000000..134540f --- /dev/null +++ b/src/vmath.h @@ -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 index 0000000..8b6c027 --- /dev/null +++ b/src/vmath_s.asm @@ -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 diff --git a/tools/genlut.c b/tools/genlut.c index cbd629c..45be022 100644 --- a/tools/genlut.c +++ b/tools/genlut.c @@ -1,37 +1,37 @@ -#include -#include - -#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= 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; -} +#include +#include + +#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= 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; +}