converted to unchained mode
[dos_low3d] / src / 3dgfx.c
index 5e2af06..3ebaa59 100644 (file)
@@ -4,12 +4,20 @@
 #include <stdlib.h>
 #include <string.h>
 #include "3dgfx.h"
+#include "video.h"
 #include "util.h"
 
+struct rect {
+       int x0, y0, x1, y1;
+};
+
+static void reset_dirty(struct rect *r);
+
 static int32_t mvmat[16];
 static int32_t pmat[16];
 static int vp[4];
-static int dirty_x0, dirty_x1, dirty_y0, dirty_y1;
+static struct rect dirty_rect[2];
+static unsigned int cur_dirty;
 
 unsigned char *g3d_fbpixels;
 int g3d_width, g3d_height;
@@ -24,6 +32,8 @@ int g3d_init(void)
        mvmat[0] = mvmat[5] = mvmat[10] = mvmat[15] = 0x10000;
        pmat[0] = pmat[5] = pmat[10] = pmat[15] = 0x10000;
        g3d_curcidx = 0xff;
+
+       cur_dirty = 0;
        return 0;
 }
 
@@ -33,7 +43,7 @@ void g3d_shutdown(void)
 
 void g3d_framebuffer(int width, int height, void *fb)
 {
-       g3d_fbpixels = fb;
+       g3d_fbpixels = fb ? fb : vid_backbuf;
        g3d_width = width;
        g3d_height = height;
 
@@ -41,102 +51,45 @@ void g3d_framebuffer(int width, int height, void *fb)
        vp[2] = width;
        vp[3] = height;
 
-       g3d_reset_dirty();
+       reset_dirty(dirty_rect);
+       reset_dirty(dirty_rect + 1);
 }
 
-void g3d_reset_dirty(void)
+void g3d_framebuf_addr(void *fb)
 {
-       dirty_x0 = XRES;
-       dirty_y0 = YRES;
-       dirty_x1 = 0;
-       dirty_y1 = 0;
+       g3d_fbpixels = vid_backbuf;
 }
 
-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)
+static void reset_dirty(struct rect *r)
 {
-       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();
+       r->x0 = XRES;
+       r->y0 = YRES;
+       r->x1 = 0;
+       r->y1 = 0;
 }
 
-
-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)
+void g3d_clear_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;
-       }
+       int width, height;
+       struct rect *dirty;
+
+       /* we need to clear based not on the last current dirty region, but the one
+        * before that. Then we need to reset the same one we used, and increment
+        * cur_dirty in preperation of this frames drawing
+        */
+       cur_dirty = (cur_dirty + 1) & 1;
+       dirty = dirty_rect + cur_dirty;
+
+       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;
+
+       width = dirty->x1 + 1 - dirty->x0;
+       height = dirty->y1 + 1 - dirty->y0;
+
+       vid_clearfb_rect(dirty->x0, dirty->y0, width, height);
+       reset_dirty(dirty);
 }
 
 void g3d_modelview(const int32_t *m)
@@ -212,10 +165,13 @@ void g3d_draw_prim(int prim, struct g3d_vertex *varr)
 #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;
+               {
+                       struct rect *dirty = dirty_rect + cur_dirty;
+                       if(x < dirty->x0) dirty->x0 = x;
+                       if(y < dirty->y0) dirty->y0 = y;
+                       if(x + 4 > dirty->x1) dirty->x1 = x + 4;
+                       if(y > dirty->y1) dirty->y1 = y;
+               }
 #endif
        }