]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/hb/wl_draw.c
[16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / hb / wl_draw.c
diff --git a/src/lib/hb/wl_draw.c b/src/lib/hb/wl_draw.c
new file mode 100755 (executable)
index 0000000..3c32e39
--- /dev/null
@@ -0,0 +1,1419 @@
+// WL_DRAW.C\r
+\r
+#include "WL_DEF.H"\r
+#include <DOS.H>\r
+#pragma hdrstop\r
+\r
+//#define DEBUGWALLS\r
+//#define DEBUGTICS\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+// the door is the last picture before the sprites\r
+#define DOORWALL       (PMSpriteStart-8)\r
+\r
+#define ACTORSIZE      0x4000\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+#ifdef DEBUGWALLS\r
+unsigned screenloc[3]= {0,0,0};\r
+#else\r
+unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START};\r
+#endif\r
+unsigned freelatch = FREESTART;\r
+\r
+long   lasttimecount;\r
+long   frameon;\r
+\r
+unsigned       wallheight[MAXVIEWWIDTH];\r
+\r
+fixed  tileglobal      = TILEGLOBAL;\r
+fixed  mindist         = MINDIST;\r
+\r
+\r
+//\r
+// math tables\r
+//\r
+int                    pixelangle[MAXVIEWWIDTH];\r
+long           far finetangent[FINEANGLES/4];\r
+fixed          far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4);\r
+\r
+//\r
+// refresh variables\r
+//\r
+fixed  viewx,viewy;                    // the focal point\r
+int            viewangle;\r
+fixed  viewsin,viewcos;\r
+\r
+\r
+\r
+fixed  FixedByFrac (fixed a, fixed b);\r
+void   TransformActor (objtype *ob);\r
+void   BuildTables (void);\r
+void   ClearScreen (void);\r
+int            CalcRotate (objtype *ob);\r
+void   DrawScaleds (void);\r
+void   CalcTics (void);\r
+void   FixOfs (void);\r
+void   ThreeDRefresh (void);\r
+\r
+\r
+\r
+//\r
+// wall optimization variables\r
+//\r
+int            lastside;               // true for vertical\r
+long   lastintercept;\r
+int            lasttilehit;\r
+\r
+\r
+//\r
+// ray tracing variables\r
+//\r
+int                    focaltx,focalty,viewtx,viewty;\r
+\r
+int                    midangle,angle;\r
+unsigned       xpartial,ypartial;\r
+unsigned       xpartialup,xpartialdown,ypartialup,ypartialdown;\r
+unsigned       xinttile,yinttile;\r
+\r
+unsigned       tilehit;\r
+unsigned       pixx;\r
+\r
+int            xtile,ytile;\r
+int            xtilestep,ytilestep;\r
+long   xintercept,yintercept;\r
+long   xstep,ystep;\r
+\r
+int            horizwall[MAXWALLTILES],vertwall[MAXWALLTILES];\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void AsmRefresh (void);                        // in WL_DR_A.ASM\r
+\r
+/*\r
+============================================================================\r
+\r
+                          3 - D  DEFINITIONS\r
+\r
+============================================================================\r
+*/\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= FixedByFrac\r
+=\r
+= multiply a 16/16 bit, 2's complement fixed point number by a 16 bit\r
+= fraction, passed as a signed magnitude 32 bit number\r
+=\r
+========================\r
+*/\r
+\r
+#pragma warn -rvl                      // I stick the return value in with ASMs\r
+\r
+fixed FixedByFrac (fixed a, fixed b)\r
+{\r
+//\r
+// setup\r
+//\r
+asm    mov     si,[WORD PTR b+2]       // sign of result = sign of fraction\r
+\r
+asm    mov     ax,[WORD PTR a]\r
+asm    mov     cx,[WORD PTR a+2]\r
+\r
+asm    or      cx,cx\r
+asm    jns     aok:                            // negative?\r
+asm    neg     cx\r
+asm    neg     ax\r
+asm    sbb     cx,0\r
+asm    xor     si,0x8000                       // toggle sign of result\r
+aok:\r
+\r
+//\r
+// multiply  cx:ax by bx\r
+//\r
+asm    mov     bx,[WORD PTR b]\r
+asm    mul     bx                                      // fraction*fraction\r
+asm    mov     di,dx                           // di is low word of result\r
+asm    mov     ax,cx                           //\r
+asm    mul     bx                                      // units*fraction\r
+asm add        ax,di\r
+asm    adc     dx,0\r
+\r
+//\r
+// put result dx:ax in 2's complement\r
+//\r
+asm    test    si,0x8000               // is the result negative?\r
+asm    jz      ansok:\r
+asm    neg     dx\r
+asm    neg     ax\r
+asm    sbb     dx,0\r
+\r
+ansok:;\r
+\r
+}\r
+\r
+#pragma warn +rvl\r
+\r
+//==========================================================================\r
+\r
+/*\r
+========================\r
+=\r
+= TransformActor\r
+=\r
+= Takes paramaters:\r
+=   gx,gy              : globalx/globaly of point\r
+=\r
+= globals:\r
+=   viewx,viewy                : point of view\r
+=   viewcos,viewsin    : sin/cos of viewangle\r
+=   scale              : conversion from global value to screen value\r
+=\r
+= sets:\r
+=   screenx,transx,transy,screenheight: projected edge location and size\r
+=\r
+========================\r
+*/\r
+\r
+\r
+//\r
+// transform actor\r
+//\r
+void TransformActor (objtype *ob)\r
+{\r
+       int ratio;\r
+       fixed gx,gy,gxt,gyt,nx,ny;\r
+       long    temp;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+       gx = ob->x-viewx;\r
+       gy = ob->y-viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+       gxt = FixedByFrac(gx,viewcos);\r
+       gyt = FixedByFrac(gy,viewsin);\r
+       nx = gxt-gyt-ACTORSIZE;         // fudge the shape forward a bit, because\r
+                                                               // the midpoint could put parts of the shape\r
+                                                               // into an adjacent wall\r
+\r
+//\r
+// calculate newy\r
+//\r
+       gxt = FixedByFrac(gx,viewsin);\r
+       gyt = FixedByFrac(gy,viewcos);\r
+       ny = gyt+gxt;\r
+\r
+//\r
+// calculate perspective ratio\r
+//\r
+       ob->transx = nx;\r
+       ob->transy = ny;\r
+\r
+       if (nx<mindist)                 // too close, don't overflow the divide\r
+       {\r
+         ob->viewheight = 0;\r
+         return;\r
+       }\r
+\r
+       ob->viewx = centerx + ny*scale/nx;      // DEBUG: use assembly divide\r
+\r
+//\r
+// calculate height (heightnumerator/(nx>>8))\r
+//\r
+       asm     mov     ax,[WORD PTR heightnumerator]\r
+       asm     mov     dx,[WORD PTR heightnumerator+2]\r
+       asm     idiv    [WORD PTR nx+1]                 // nx>>8\r
+       asm     mov     [WORD PTR temp],ax\r
+       asm     mov     [WORD PTR temp+2],dx\r
+\r
+       ob->viewheight = temp;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+========================\r
+=\r
+= TransformTile\r
+=\r
+= Takes paramaters:\r
+=   tx,ty              : tile the object is centered in\r
+=\r
+= globals:\r
+=   viewx,viewy                : point of view\r
+=   viewcos,viewsin    : sin/cos of viewangle\r
+=   scale              : conversion from global value to screen value\r
+=\r
+= sets:\r
+=   screenx,transx,transy,screenheight: projected edge location and size\r
+=\r
+= Returns true if the tile is withing getting distance\r
+=\r
+========================\r
+*/\r
+\r
+boolean TransformTile (int tx, int ty, int *dispx, int *dispheight)\r
+{\r
+       int ratio;\r
+       fixed gx,gy,gxt,gyt,nx,ny;\r
+       long    temp;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+       gx = ((long)tx<<TILESHIFT)+0x8000-viewx;\r
+       gy = ((long)ty<<TILESHIFT)+0x8000-viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+       gxt = FixedByFrac(gx,viewcos);\r
+       gyt = FixedByFrac(gy,viewsin);\r
+       nx = gxt-gyt-0x2000;            // 0x2000 is size of object\r
+\r
+//\r
+// calculate newy\r
+//\r
+       gxt = FixedByFrac(gx,viewsin);\r
+       gyt = FixedByFrac(gy,viewcos);\r
+       ny = gyt+gxt;\r
+\r
+\r
+//\r
+// calculate perspective ratio\r
+//\r
+       if (nx<mindist)                 // too close, don't overflow the divide\r
+       {\r
+               *dispheight = 0;\r
+               return false;\r
+       }\r
+\r
+       *dispx = centerx + ny*scale/nx; // DEBUG: use assembly divide\r
+\r
+//\r
+// calculate height (heightnumerator/(nx>>8))\r
+//\r
+       asm     mov     ax,[WORD PTR heightnumerator]\r
+       asm     mov     dx,[WORD PTR heightnumerator+2]\r
+       asm     idiv    [WORD PTR nx+1]                 // nx>>8\r
+       asm     mov     [WORD PTR temp],ax\r
+       asm     mov     [WORD PTR temp+2],dx\r
+\r
+       *dispheight = temp;\r
+\r
+//\r
+// see if it should be grabbed\r
+//\r
+       if (nx<TILEGLOBAL && ny>-TILEGLOBAL/2 && ny<TILEGLOBAL/2)\r
+               return true;\r
+       else\r
+               return false;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= CalcHeight\r
+=\r
+= Calculates the height of xintercept,yintercept from viewx,viewy\r
+=\r
+====================\r
+*/\r
+\r
+#pragma warn -rvl                      // I stick the return value in with ASMs\r
+\r
+int    CalcHeight (void)\r
+{\r
+       int     transheight;\r
+       int ratio;\r
+       fixed gxt,gyt,nx,ny;\r
+       long    gx,gy;\r
+\r
+       gx = xintercept-viewx;\r
+       gxt = FixedByFrac(gx,viewcos);\r
+\r
+       gy = yintercept-viewy;\r
+       gyt = FixedByFrac(gy,viewsin);\r
+\r
+       nx = gxt-gyt;\r
+\r
+  //\r
+  // calculate perspective ratio (heightnumerator/(nx>>8))\r
+  //\r
+       if (nx<mindist)\r
+               nx=mindist;                     // don't let divide overflow\r
+\r
+       asm     mov     ax,[WORD PTR heightnumerator]\r
+       asm     mov     dx,[WORD PTR heightnumerator+2]\r
+       asm     idiv    [WORD PTR nx+1]                 // nx>>8\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= ScalePost\r
+=\r
+===================\r
+*/\r
+\r
+long           postsource;\r
+unsigned       postx;\r
+unsigned       postwidth;\r
+\r
+void   near ScalePost (void)           // VGA version\r
+{\r
+       asm     mov     ax,SCREENSEG\r
+       asm     mov     es,ax\r
+\r
+       asm     mov     bx,[postx]\r
+       asm     shl     bx,1\r
+       asm     mov     bp,WORD PTR [wallheight+bx]             // fractional height (low 3 bits frac)\r
+       asm     and     bp,0xfff8                               // bp = heightscaler*4\r
+       asm     shr     bp,1\r
+       asm     cmp     bp,[maxscaleshl2]\r
+       asm     jle     heightok\r
+       asm     mov     bp,[maxscaleshl2]\r
+heightok:\r
+       asm     add     bp,OFFSET fullscalefarcall\r
+       //\r
+       // scale a byte wide strip of wall\r
+       //\r
+       asm     mov     bx,[postx]\r
+       asm     mov     di,bx\r
+       asm     shr     di,1                                            // X in bytes\r
+       asm     shr     di,1\r
+       asm     add     di,[bufferofs]\r
+\r
+       asm     and     bx,3\r
+       /* begin 8086 hack\r
+       asm     shl     bx,3\r
+       */\r
+       asm push cx\r
+       asm mov cl,3\r
+       asm shl bx,cl\r
+       asm pop cx\r
+       /* end 8086 hack */\r
+       asm     add     bx,[postwidth]\r
+\r
+       asm     mov     al,BYTE PTR [mapmasks1-1+bx]    // -1 because no widths of 0\r
+       asm     mov     dx,SC_INDEX+1\r
+       asm     out     dx,al                                           // set bit mask register\r
+       asm     lds     si,DWORD PTR [postsource]\r
+       asm     call DWORD PTR [bp]                             // scale the line of pixels\r
+\r
+       asm     mov     al,BYTE PTR [ss:mapmasks2-1+bx]   // -1 because no widths of 0\r
+       asm     or      al,al\r
+       asm     jz      nomore\r
+\r
+       //\r
+       // draw a second byte for vertical strips that cross two bytes\r
+       //\r
+       asm     inc     di\r
+       asm     out     dx,al                                           // set bit mask register\r
+       asm     call DWORD PTR [bp]                             // scale the line of pixels\r
+\r
+       asm     mov     al,BYTE PTR [ss:mapmasks3-1+bx] // -1 because no widths of 0\r
+       asm     or      al,al\r
+       asm     jz      nomore\r
+       //\r
+       // draw a third byte for vertical strips that cross three bytes\r
+       //\r
+       asm     inc     di\r
+       asm     out     dx,al                                           // set bit mask register\r
+       asm     call DWORD PTR [bp]                             // scale the line of pixels\r
+\r
+\r
+nomore:\r
+       asm     mov     ax,ss\r
+       asm     mov     ds,ax\r
+}\r
+\r
+void  FarScalePost (void)                              // just so other files can call\r
+{\r
+       ScalePost ();\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= HitVertWall\r
+=\r
+= tilehit bit 7 is 0, because it's not a door tile\r
+= if bit 6 is 1 and the adjacent tile is a door tile, use door side pic\r
+=\r
+====================\r
+*/\r
+\r
+void HitVertWall (void)\r
+{\r
+       int                     wallpic;\r
+       unsigned        texture;\r
+\r
+       texture = (yintercept>>4)&0xfc0;\r
+       if (xtilestep == -1)\r
+       {\r
+               texture = 0xfc0-texture;\r
+               xintercept += TILEGLOBAL;\r
+       }\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit)\r
+       {\r
+               // in the same wall type as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+       // new wall\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();\r
+\r
+               lastside = true;\r
+               lastintercept = xtile;\r
+\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               if (tilehit & 0x40)\r
+               {                                                               // check for adjacent doors\r
+                       ytile = yintercept>>TILESHIFT;\r
+                       if ( tilemap[xtile-xtilestep][ytile]&0x80 )\r
+                               wallpic = DOORWALL+3;\r
+                       else\r
+                               wallpic = vertwall[tilehit & ~0x40];\r
+               }\r
+               else\r
+                       wallpic = vertwall[tilehit];\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);\r
+               (unsigned)postsource = texture;\r
+\r
+       }\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= HitHorizWall\r
+=\r
+= tilehit bit 7 is 0, because it's not a door tile\r
+= if bit 6 is 1 and the adjacent tile is a door tile, use door side pic\r
+=\r
+====================\r
+*/\r
+\r
+void HitHorizWall (void)\r
+{\r
+       int                     wallpic;\r
+       unsigned        texture;\r
+\r
+       texture = (xintercept>>4)&0xfc0;\r
+       if (ytilestep == -1)\r
+               yintercept += TILEGLOBAL;\r
+       else\r
+               texture = 0xfc0-texture;\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit)\r
+       {\r
+               // in the same wall type as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+       // new wall\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();\r
+\r
+               lastside = 0;\r
+               lastintercept = ytile;\r
+\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               if (tilehit & 0x40)\r
+               {                                                               // check for adjacent doors\r
+                       xtile = xintercept>>TILESHIFT;\r
+                       if ( tilemap[xtile][ytile-ytilestep]&0x80 )\r
+                               wallpic = DOORWALL+2;\r
+                       else\r
+                               wallpic = horizwall[tilehit & ~0x40];\r
+               }\r
+               else\r
+                       wallpic = horizwall[tilehit];\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);\r
+               (unsigned)postsource = texture;\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= HitHorizDoor\r
+=\r
+====================\r
+*/\r
+\r
+void HitHorizDoor (void)\r
+{\r
+       unsigned        texture,doorpage,doornum;\r
+\r
+       doornum = tilehit&0x7f;\r
+       texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0;\r
+\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lasttilehit == tilehit)\r
+       {\r
+       // in the same door as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();                   // draw last post\r
+       // first pixel in this door\r
+               lastside = 2;\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               switch (doorobjlist[doornum].lock)\r
+               {\r
+               case dr_normal:\r
+                       doorpage = DOORWALL;\r
+                       break;\r
+               case dr_lock1:\r
+               case dr_lock2:\r
+               case dr_lock3:\r
+               case dr_lock4:\r
+                       doorpage = DOORWALL+6;\r
+                       break;\r
+               case dr_elevator:\r
+                       doorpage = DOORWALL+4;\r
+                       break;\r
+               }\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage);\r
+               (unsigned)postsource = texture;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+====================\r
+=\r
+= HitVertDoor\r
+=\r
+====================\r
+*/\r
+\r
+void HitVertDoor (void)\r
+{\r
+       unsigned        texture,doorpage,doornum;\r
+\r
+       doornum = tilehit&0x7f;\r
+       texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0;\r
+\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lasttilehit == tilehit)\r
+       {\r
+       // in the same door as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();                   // draw last post\r
+       // first pixel in this door\r
+               lastside = 2;\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               switch (doorobjlist[doornum].lock)\r
+               {\r
+               case dr_normal:\r
+                       doorpage = DOORWALL;\r
+                       break;\r
+               case dr_lock1:\r
+               case dr_lock2:\r
+               case dr_lock3:\r
+               case dr_lock4:\r
+                       doorpage = DOORWALL+6;\r
+                       break;\r
+               case dr_elevator:\r
+                       doorpage = DOORWALL+4;\r
+                       break;\r
+               }\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage+1);\r
+               (unsigned)postsource = texture;\r
+       }\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= HitHorizPWall\r
+=\r
+= A pushable wall in action has been hit\r
+=\r
+====================\r
+*/\r
+\r
+void HitHorizPWall (void)\r
+{\r
+       int                     wallpic;\r
+       unsigned        texture,offset;\r
+\r
+       texture = (xintercept>>4)&0xfc0;\r
+       offset = pwallpos<<10;\r
+       if (ytilestep == -1)\r
+               yintercept += TILEGLOBAL-offset;\r
+       else\r
+       {\r
+               texture = 0xfc0-texture;\r
+               yintercept += offset;\r
+       }\r
+\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lasttilehit == tilehit)\r
+       {\r
+               // in the same wall type as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+       // new wall\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();\r
+\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               wallpic = horizwall[tilehit&63];\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);\r
+               (unsigned)postsource = texture;\r
+       }\r
+\r
+}\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= HitVertPWall\r
+=\r
+= A pushable wall in action has been hit\r
+=\r
+====================\r
+*/\r
+\r
+void HitVertPWall (void)\r
+{\r
+       int                     wallpic;\r
+       unsigned        texture,offset;\r
+\r
+       texture = (yintercept>>4)&0xfc0;\r
+       offset = pwallpos<<10;\r
+       if (xtilestep == -1)\r
+       {\r
+               xintercept += TILEGLOBAL-offset;\r
+               texture = 0xfc0-texture;\r
+       }\r
+       else\r
+               xintercept += offset;\r
+\r
+       wallheight[pixx] = CalcHeight();\r
+\r
+       if (lasttilehit == tilehit)\r
+       {\r
+               // in the same wall type as last time, so check for optimized draw\r
+               if (texture == (unsigned)postsource)\r
+               {\r
+               // wide scale\r
+                       postwidth++;\r
+                       wallheight[pixx] = wallheight[pixx-1];\r
+                       return;\r
+               }\r
+               else\r
+               {\r
+                       ScalePost ();\r
+                       (unsigned)postsource = texture;\r
+                       postwidth = 1;\r
+                       postx = pixx;\r
+               }\r
+       }\r
+       else\r
+       {\r
+       // new wall\r
+               if (lastside != -1)                             // if not the first scaled post\r
+                       ScalePost ();\r
+\r
+               lasttilehit = tilehit;\r
+               postx = pixx;\r
+               postwidth = 1;\r
+\r
+               wallpic = vertwall[tilehit&63];\r
+\r
+               *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);\r
+               (unsigned)postsource = texture;\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+//==========================================================================\r
+\r
+#if 0\r
+/*\r
+=====================\r
+=\r
+= ClearScreen\r
+=\r
+=====================\r
+*/\r
+\r
+void ClearScreen (void)\r
+{\r
+ unsigned floor=egaFloor[gamestate.episode*10+mapon],\r
+         ceiling=egaCeiling[gamestate.episode*10+mapon];\r
+\r
+  //\r
+  // clear the screen\r
+  //\r
+asm    mov     dx,GC_INDEX\r
+asm    mov     ax,GC_MODE + 256*2              // read mode 0, write mode 2\r
+asm    out     dx,ax\r
+asm    mov     ax,GC_BITMASK + 255*256\r
+asm    out     dx,ax\r
+\r
+asm    mov     dx,40\r
+asm    mov     ax,[viewwidth]\r
+asm    shr     ax,1\r
+asm    shr     ax,1\r
+asm    shr     ax,1\r
+asm    sub     dx,ax                                   // dx = 40-viewwidth/8\r
+\r
+asm    mov     bx,[viewwidth]\r
+asm    shr     bx,1                                    // bl = viewwidth/16\r
+asm    shr     bx,1\r
+asm    shr     bx,1\r
+asm    shr     bx,1\r
+asm    mov     bh,BYTE PTR [viewheight]\r
+asm    shr     bh,1                                    // half height\r
+\r
+asm    mov     ax,[ceiling]\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[bufferofs]\r
+\r
+toploop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     toploop\r
+\r
+asm    mov     bh,BYTE PTR [viewheight]\r
+asm    shr     bh,1                                    // half height\r
+asm    mov     ax,[floor]\r
+\r
+bottomloop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     bottomloop\r
+\r
+\r
+asm    mov     dx,GC_INDEX\r
+asm    mov     ax,GC_MODE + 256*10             // read mode 1, write mode 2\r
+asm    out     dx,ax\r
+asm    mov     al,GC_BITMASK\r
+asm    out     dx,al\r
+\r
+}\r
+#endif\r
+//==========================================================================\r
+\r
+unsigned vgaCeiling[]=\r
+{\r
+#ifndef SPEAR\r
+ 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf,\r
+ 0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d,\r
+ 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898,\r
+\r
+ 0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd,\r
+ 0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d,\r
+ 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd\r
+#else\r
+ 0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f,\r
+ 0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc\r
+#endif\r
+};\r
+\r
+/*\r
+=====================\r
+=\r
+= VGAClearScreen\r
+=\r
+=====================\r
+*/\r
+\r
+void VGAClearScreen (void)\r
+{\r
+ unsigned ceiling=vgaCeiling[gamestate.episode*10+mapon];\r
+\r
+  //\r
+  // clear the screen\r
+  //\r
+asm    mov     dx,SC_INDEX\r
+asm    mov     ax,SC_MAPMASK+15*256    // write through all planes\r
+asm    out     dx,ax\r
+\r
+asm    mov     dx,80\r
+asm    mov     ax,[viewwidth]\r
+asm    shr     ax,1\r
+asm    shr     ax,1\r
+asm    sub     dx,ax                                   // dx = 40-viewwidth/2\r
+\r
+asm    mov     bx,[viewwidth]\r
+asm    shr     bx,1                                    // bl = viewwidth/8\r
+asm    shr     bx,1\r
+asm    shr     bx,1\r
+asm    mov     bh,BYTE PTR [viewheight]\r
+asm    shr     bh,1                                    // half height\r
+\r
+asm    mov     es,[screenseg]\r
+asm    mov     di,[bufferofs]\r
+asm    mov     ax,[ceiling]\r
+\r
+toploop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     toploop\r
+\r
+asm    mov     bh,BYTE PTR [viewheight]\r
+asm    shr     bh,1                                    // half height\r
+asm    mov     ax,0x1919\r
+\r
+bottomloop:\r
+asm    mov     cl,bl\r
+asm    rep     stosw\r
+asm    add     di,dx\r
+asm    dec     bh\r
+asm    jnz     bottomloop\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= CalcRotate\r
+=\r
+=====================\r
+*/\r
+\r
+int    CalcRotate (objtype *ob)\r
+{\r
+       int     angle,viewangle;\r
+\r
+       // this isn't exactly correct, as it should vary by a trig value,\r
+       // but it is close enough with only eight rotations\r
+\r
+       viewangle = player->angle + (centerx - ob->viewx)/8;\r
+\r
+       if (ob->obclass == rocketobj || ob->obclass == hrocketobj)\r
+               angle =  (viewangle-180)- ob->angle;\r
+       else\r
+               angle =  (viewangle-180)- dirangle[ob->dir];\r
+\r
+       angle+=ANGLES/16;\r
+       while (angle>=ANGLES)\r
+               angle-=ANGLES;\r
+       while (angle<0)\r
+               angle+=ANGLES;\r
+\r
+       if (ob->state->rotate == 2)             // 2 rotation pain frame\r
+               return 4*(angle/(ANGLES/2));        // seperated by 3 (art layout...)\r
+\r
+       return angle/(ANGLES/8);\r
+}\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= DrawScaleds\r
+=\r
+= Draws all objects that are visable\r
+=\r
+=====================\r
+*/\r
+\r
+#define MAXVISABLE     50\r
+\r
+typedef struct\r
+{\r
+       int     viewx,\r
+               viewheight,\r
+               shapenum;\r
+} visobj_t;\r
+\r
+visobj_t       vislist[MAXVISABLE],*visptr,*visstep,*farthest;\r
+\r
+void DrawScaleds (void)\r
+{\r
+       int             i,j,least,numvisable,height;\r
+       memptr          shape;\r
+       byte            *tilespot,*visspot;\r
+       int                     shapenum;\r
+       unsigned        spotloc;\r
+\r
+       statobj_t       *statptr;\r
+       objtype         *obj;\r
+\r
+       visptr = &vislist[0];\r
+\r
+//\r
+// place static objects\r
+//\r
+       for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++)\r
+       {\r
+               if ((visptr->shapenum = statptr->shapenum) == -1)\r
+                       continue;                                               // object has been deleted\r
+\r
+               if (!*statptr->visspot)\r
+                       continue;                                               // not visable\r
+\r
+               if (TransformTile (statptr->tilex,statptr->tiley\r
+                       ,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS)\r
+               {\r
+                       GetBonus (statptr);\r
+                       continue;\r
+               }\r
+\r
+               if (!visptr->viewheight)\r
+                       continue;                                               // to close to the object\r
+\r
+               if (visptr < &vislist[MAXVISABLE-1])    // don't let it overflow\r
+                       visptr++;\r
+       }\r
+\r
+//\r
+// place active objects\r
+//\r
+       for (obj = player->next;obj;obj=obj->next)\r
+       {\r
+               if (!(visptr->shapenum = obj->state->shapenum))\r
+                       continue;                                               // no shape\r
+\r
+               spotloc = (obj->tilex<<6)+obj->tiley;   // optimize: keep in struct?\r
+               visspot = &spotvis[0][0]+spotloc;\r
+               tilespot = &tilemap[0][0]+spotloc;\r
+\r
+               //\r
+               // could be in any of the nine surrounding tiles\r
+               //\r
+               if (*visspot\r
+               || ( *(visspot-1) && !*(tilespot-1) )\r
+               || ( *(visspot+1) && !*(tilespot+1) )\r
+               || ( *(visspot-65) && !*(tilespot-65) )\r
+               || ( *(visspot-64) && !*(tilespot-64) )\r
+               || ( *(visspot-63) && !*(tilespot-63) )\r
+               || ( *(visspot+65) && !*(tilespot+65) )\r
+               || ( *(visspot+64) && !*(tilespot+64) )\r
+               || ( *(visspot+63) && !*(tilespot+63) ) )\r
+               {\r
+                       obj->active = true;\r
+                       TransformActor (obj);\r
+                       if (!obj->viewheight)\r
+                               continue;                                               // too close or far away\r
+\r
+                       visptr->viewx = obj->viewx;\r
+                       visptr->viewheight = obj->viewheight;\r
+                       if (visptr->shapenum == -1)\r
+                               visptr->shapenum = obj->temp1;  // special shape\r
+\r
+                       if (obj->state->rotate)\r
+                               visptr->shapenum += CalcRotate (obj);\r
+\r
+                       if (visptr < &vislist[MAXVISABLE-1])    // don't let it overflow\r
+                               visptr++;\r
+                       obj->flags |= FL_VISABLE;\r
+               }\r
+               else\r
+                       obj->flags &= ~FL_VISABLE;\r
+       }\r
+\r
+//\r
+// draw from back to front\r
+//\r
+       numvisable = visptr-&vislist[0];\r
+\r
+       if (!numvisable)\r
+               return;                                                                 // no visable objects\r
+\r
+       for (i = 0; i<numvisable; i++)\r
+       {\r
+               least = 32000;\r
+               for (visstep=&vislist[0] ; visstep<visptr ; visstep++)\r
+               {\r
+                       height = visstep->viewheight;\r
+                       if (height < least)\r
+                       {\r
+                               least = height;\r
+                               farthest = visstep;\r
+                       }\r
+               }\r
+               //\r
+               // draw farthest\r
+               //\r
+               ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight);\r
+\r
+               farthest->viewheight = 32000;\r
+       }\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==============\r
+=\r
+= DrawPlayerWeapon\r
+=\r
+= Draw the player's hands\r
+=\r
+==============\r
+*/\r
+\r
+int    weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY\r
+       ,SPR_MACHINEGUNREADY,SPR_CHAINREADY};\r
+\r
+void DrawPlayerWeapon (void)\r
+{\r
+       int     shapenum;\r
+\r
+#ifndef SPEAR\r
+       if (gamestate.victoryflag)\r
+       {\r
+               if (player->state == &s_deathcam && (TimeCount&32) )\r
+                       SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1);\r
+               return;\r
+       }\r
+#endif\r
+\r
+       if (gamestate.weapon != -1)\r
+       {\r
+               shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe;\r
+               SimpleScaleShape(viewwidth/2,shapenum,viewheight+1);\r
+       }\r
+\r
+       if (demorecord || demoplayback)\r
+               SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= CalcTics\r
+=\r
+=====================\r
+*/\r
+\r
+void CalcTics (void)\r
+{\r
+       long    newtime,oldtimecount;\r
+\r
+//\r
+// calculate tics since last refresh for adaptive timing\r
+//\r
+       if (lasttimecount > TimeCount)\r
+               TimeCount = lasttimecount;              // if the game was paused a LONG time\r
+\r
+       do\r
+       {\r
+               newtime = TimeCount;\r
+               tics = newtime-lasttimecount;\r
+       } while (!tics);                        // make sure at least one tic passes\r
+\r
+       lasttimecount = newtime;\r
+\r
+#ifdef FILEPROFILE\r
+               strcpy (scratch,"\tTics:");\r
+               itoa (tics,str,10);\r
+               strcat (scratch,str);\r
+               strcat (scratch,"\n");\r
+               write (profilehandle,scratch,strlen(scratch));\r
+#endif\r
+\r
+       if (tics>MAXTICS)\r
+       {\r
+               TimeCount -= (tics-MAXTICS);\r
+               tics = MAXTICS;\r
+       }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= FixOfs\r
+=\r
+========================\r
+*/\r
+\r
+void   FixOfs (void)\r
+{\r
+       VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+====================\r
+=\r
+= WallRefresh\r
+=\r
+====================\r
+*/\r
+\r
+void WallRefresh (void)\r
+{\r
+//\r
+// set up variables for this view\r
+//\r
+       viewangle = player->angle;\r
+       midangle = viewangle*(FINEANGLES/ANGLES);\r
+       viewsin = sintable[viewangle];\r
+       viewcos = costable[viewangle];\r
+       viewx = player->x - FixedByFrac(focallength,viewcos);\r
+       viewy = player->y + FixedByFrac(focallength,viewsin);\r
+\r
+       focaltx = viewx>>TILESHIFT;\r
+       focalty = viewy>>TILESHIFT;\r
+\r
+       viewtx = player->x >> TILESHIFT;\r
+       viewty = player->y >> TILESHIFT;\r
+\r
+       xpartialdown = viewx&(TILEGLOBAL-1);\r
+       xpartialup = TILEGLOBAL-xpartialdown;\r
+       ypartialdown = viewy&(TILEGLOBAL-1);\r
+       ypartialup = TILEGLOBAL-ypartialdown;\r
+\r
+       lastside = -1;                  // the first pixel is on a new wall\r
+       AsmRefresh ();\r
+       ScalePost ();                   // no more optimization on last post\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+========================\r
+=\r
+= ThreeDRefresh\r
+=\r
+========================\r
+*/\r
+\r
+void   ThreeDRefresh (void)\r
+{\r
+       int tracedir;\r
+\r
+// this wouldn't need to be done except for my debugger/video wierdness\r
+       outportb (SC_INDEX,SC_MAPMASK);\r
+\r
+//\r
+// clear out the traced array\r
+//\r
+asm    mov     ax,ds\r
+asm    mov     es,ax\r
+asm    mov     di,OFFSET spotvis\r
+asm    xor     ax,ax\r
+asm    mov     cx,2048                                                 // 64*64 / 2\r
+asm    rep stosw\r
+\r
+       bufferofs += screenofs;\r
+\r
+//\r
+// follow the walls from there to the right, drawwing as we go\r
+//\r
+       VGAClearScreen ();\r
+\r
+       WallRefresh ();\r
+\r
+//\r
+// draw all the scaled images\r
+//\r
+       DrawScaleds();                  // draw scaled stuff\r
+       DrawPlayerWeapon ();    // draw player's hands\r
+\r
+//\r
+// show screen and time last cycle\r
+//\r
+       if (fizzlein)\r
+       {\r
+               FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false);\r
+               fizzlein = false;\r
+\r
+               lasttimecount = TimeCount = 0;          // don't make a big tic count\r
+\r
+       }\r
+\r
+       bufferofs -= screenofs;\r
+       displayofs = bufferofs;\r
+\r
+       asm     cli\r
+       asm     mov     cx,[displayofs]\r
+       asm     mov     dx,3d4h         // CRTC address register\r
+       asm     mov     al,0ch          // start address high register\r
+       asm     out     dx,al\r
+       asm     inc     dx\r
+       asm     mov     al,ch\r
+       asm     out     dx,al           // set the high byte\r
+       asm     sti\r
+\r
+       bufferofs += SCREENSIZE;\r
+       if (bufferofs > PAGE3START)\r
+               bufferofs = PAGE1START;\r
+\r
+       frameon++;\r
+       PM_NextFrame();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r