3d cube and dirty drawing
[dos_low3d] / src / 3dgfx.c
index f53ead6..5e2af06 100644 (file)
@@ -1,3 +1,5 @@
+#include "config.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 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<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)
@@ -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);
+
+#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) {