]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/hb/draw/c6_draw.c
going to start wolf3d core core (loop with input only) work soon. I was mostly brains...
[16.git] / src / lib / hb / draw / c6_draw.c
diff --git a/src/lib/hb/draw/c6_draw.c b/src/lib/hb/draw/c6_draw.c
new file mode 100755 (executable)
index 0000000..9d261a0
--- /dev/null
@@ -0,0 +1,1970 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+// C3_DRAW.C\r
+\r
+#include "DEF.H"\r
+#pragma hdrstop\r
+\r
+//#define DRAWEACH                              // draw walls one at a time for debugging\r
+\r
+unsigned        highest;\r
+unsigned        mostwalls,numwalls;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define PI      3.141592657\r
+#define ANGLEQUAD       (ANGLES/4)\r
+\r
+unsigned        oldend;\r
+\r
+#define FINEANGLES      3600\r
+\r
+#define MINRATIO        16\r
+\r
+\r
+const   unsigned        MAXSCALEHEIGHT  = (VIEWWIDTH/2);\r
+const   unsigned        MAXVISHEIGHT    = (VIEWHEIGHT/2);\r
+const   unsigned        BASESCALE               = 32;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+//\r
+// calculate location of screens in video memory so they have the\r
+// maximum possible distance seperating them (for scaling overflow)\r
+//\r
+\r
+unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START};\r
+unsigned freelatch = FREESTART;\r
+\r
+boolean         fizzlein;\r
+\r
+long    scaleshapecalll;\r
+long    scaletablecall;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+long    bytecount,endcount;             // for profiling\r
+int             animframe;\r
+int             pixelangle[VIEWWIDTH];\r
+int             far finetangent[FINEANGLES+1];\r
+int             fineviewangle;\r
+unsigned        viewxpix,viewypix;\r
+\r
+/*\r
+============================================================================\r
+\r
+                          3 - D  DEFINITIONS\r
+\r
+============================================================================\r
+*/\r
+\r
+fixed   tileglobal      = TILEGLOBAL;\r
+fixed   focallength     = FOCALLENGTH;\r
+fixed   mindist         = MINDIST;\r
+int             viewheight      = VIEWHEIGHT;\r
+fixed scale;\r
+\r
+\r
+tilept  tile,lasttile,          // tile of wall being followed\r
+       focal,                  // focal point in tiles\r
+       left,mid,right;         // rightmost tile in view\r
+\r
+globpt edge,view;\r
+\r
+int     segstart[VIEWHEIGHT],   // addline tracks line segment and draws\r
+       segend[VIEWHEIGHT],\r
+       segcolor[VIEWHEIGHT];   // only when the color changes\r
+\r
+\r
+walltype        walls[MAXWALLS],*leftwall,*rightwall;\r
+\r
+\r
+//==========================================================================\r
+\r
+//\r
+// refresh stuff\r
+//\r
+\r
+int screenpage;\r
+\r
+long lasttimecount;\r
+\r
+//\r
+// rendering stuff\r
+//\r
+\r
+int firstangle,lastangle;\r
+\r
+fixed prestep;\r
+\r
+fixed sintable[ANGLES+ANGLES/4],*costable = sintable+(ANGLES/4);\r
+\r
+fixed   viewx,viewy;                    // the focal point\r
+int     viewangle;\r
+fixed   viewsin,viewcos;\r
+\r
+int     zbuffer[VIEWXH+1];      // holds the height of the wall at that point\r
+\r
+//==========================================================================\r
+\r
+void    DrawLine (int xl, int xh, int y,int color);\r
+void    DrawWall (walltype *wallptr);\r
+void    TraceRay (unsigned angle);\r
+fixed   FixedByFrac (fixed a, fixed b);\r
+fixed   FixedAdd (void);\r
+fixed   TransformX (fixed gx, fixed gy);\r
+int             FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max);\r
+int             BackTrace (int finish);\r
+void    ForwardTrace (void);\r
+int             TurnClockwise (void);\r
+int             TurnCounterClockwise (void);\r
+void    FollowWall (void);\r
+\r
+void    NewScene (void);\r
+void    BuildTables (void);\r
+\r
+//==========================================================================\r
+\r
+\r
+#if 0\r
+/*\r
+==================\r
+=\r
+= DrawLine\r
+=\r
+= Must be in write mode 2 with all planes enabled\r
+= The bit mask is left set to the end value, so clear it after all lines are\r
+= drawn\r
+=\r
+= draws a black dot at the left edge of the line\r
+=\r
+==================\r
+*/\r
+\r
+unsigned static char dotmask[8] = {0x80,0x40,0x20,0x10,8,4,2,1};\r
+unsigned static char leftmask[8] = {0xff,0x7f,0x3f,0x1f,0xf,7,3,1};\r
+unsigned static char rightmask[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};\r
+\r
+void DrawLine (int xl, int xh, int y,int color)\r
+{\r
+  unsigned dest,xlp,xlb,xhb,maskleft,maskright,maskdot,mid;\r
+\r
+  xlb=xl/8;\r
+  xhb=xh/8;\r
+\r
+  if (xh<xl)\r
+       Quit("DrawLine: xh<xl");\r
+  if (y<VIEWY)\r
+       Quit("DrawLine: y<VIEWY");\r
+  if (y>VIEWYH)\r
+       Quit("DrawLine: y>VIEWYH");\r
+\r
+       xlp = xl&7;\r
+       maskleft = leftmask[xlp];\r
+       maskright = rightmask[xh&7];\r
+\r
+  mid = xhb-xlb-1;\r
+  dest = bufferofs+ylookup[y]+xlb;\r
+\r
+       //\r
+       // set the GC index register to point to the bit mask register\r
+       //\r
+       asm     mov     al,GC_BITMASK\r
+       asm     mov     dx,GC_INDEX\r
+       asm     out     dx,al\r
+\r
+  if (xlb==xhb)\r
+  {\r
+  //\r
+  // entire line is in one byte\r
+  //\r
+\r
+       maskleft&=maskright;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     di,[dest]\r
+       asm     mov     dx,GC_INDEX+1\r
+\r
+       asm     mov     al,[BYTE PTR maskleft]\r
+       asm     out     dx,al           // mask off pixels\r
+\r
+       asm     mov     al,[BYTE PTR color]\r
+       asm     xchg    al,[es:di]      // load latches and write pixels\r
+\r
+       return;\r
+  }\r
+\r
+asm     mov     es,[screenseg]\r
+asm     mov     di,[dest]\r
+asm     mov     dx,GC_INDEX+1\r
+asm     mov     bh,[BYTE PTR color]\r
+\r
+//\r
+// draw left side\r
+//\r
+asm     mov     al,[BYTE PTR maskleft]\r
+asm     out     dx,al           // mask off pixels\r
+\r
+asm     mov     al,bh\r
+asm     xchg    al,[es:di]      // load latches and write pixels\r
+asm     inc     di\r
+\r
+//\r
+// draw middle\r
+//\r
+asm     mov     al,255\r
+asm     out     dx,al           // no masking\r
+\r
+asm     mov     al,bh\r
+asm     mov     cx,[mid]\r
+asm     rep     stosb\r
+\r
+//\r
+// draw right side\r
+//\r
+asm     mov     al,[BYTE PTR maskright]\r
+asm     out     dx,al           // mask off pixels\r
+asm     xchg    bh,[es:di]      // load latches and write pixels\r
+\r
+}\r
+\r
+//==========================================================================\r
+\r
+void DrawLineDot (int xl, int xh, int y,int color)\r
+{\r
+  unsigned dest,xlp,xlb,xhb,maskleft,maskright,maskdot,mid;\r
+\r
+  xlb=xl/8;\r
+  xhb=xh/8;\r
+\r
+  if (xh<xl)\r
+       Quit("DrawLine: xh<xl");\r
+  if (y<VIEWY)\r
+       Quit("DrawLine: y<VIEWY");\r
+  if (y>VIEWYH)\r
+       Quit("DrawLine: y>VIEWYH");\r
+\r
+       xlp = xl&7;\r
+       maskdot = dotmask[xlp];\r
+       maskleft = leftmask[xlp];\r
+       maskright = rightmask[xh&7];\r
+\r
+  mid = xhb-xlb-1;\r
+  dest = bufferofs+ylookup[y]+xlb;\r
+\r
+       //\r
+       // set the GC index register to point to the bit mask register\r
+       //\r
+       asm     mov     al,GC_BITMASK\r
+       asm     mov     dx,GC_INDEX\r
+       asm     out     dx,al\r
+\r
+  if (xlb==xhb)\r
+  {\r
+  //\r
+  // entire line is in one byte\r
+  //\r
+\r
+       maskleft&=maskright;\r
+\r
+       asm     mov     es,[screenseg]\r
+       asm     mov     di,[dest]\r
+       asm     mov     dx,GC_INDEX+1\r
+\r
+       asm     mov     al,[BYTE PTR maskleft]\r
+       asm     out     dx,al           // mask off pixels\r
+\r
+       asm     mov     al,[BYTE PTR color]\r
+       asm     xchg    al,[es:di]      // load latches and write pixels\r
+\r
+\r
+       //\r
+       // write the black dot at the start\r
+       //\r
+       asm     mov     al,[BYTE PTR maskdot]\r
+       asm     out     dx,al           // mask off pixels\r
+\r
+       asm     xor     al,al\r
+       asm     xchg    al,[es:di]      // load latches and write pixels\r
+\r
+\r
+       return;\r
+  }\r
+\r
+asm     mov     es,[screenseg]\r
+asm     mov     di,[dest]\r
+asm     mov     dx,GC_INDEX+1\r
+asm     mov     bh,[BYTE PTR color]\r
+\r
+//\r
+// draw left side\r
+//\r
+asm     mov     al,[BYTE PTR maskleft]\r
+asm     out     dx,al           // mask off pixels\r
+\r
+asm     mov     al,bh\r
+asm     xchg    al,[es:di]      // load latches and write pixels\r
+\r
+//\r
+// write the black dot at the start\r
+//\r
+asm     mov     al,[BYTE PTR maskdot]\r
+asm     out     dx,al           // mask off pixels\r
+asm     xor     al,al\r
+asm     xchg    al,[es:di]      // load latches and write pixels\r
+asm     inc     di\r
+\r
+//\r
+// draw middle\r
+//\r
+asm     mov     al,255\r
+asm     out     dx,al           // no masking\r
+\r
+asm     mov     al,bh\r
+asm     mov     cx,[mid]\r
+asm     rep     stosb\r
+\r
+//\r
+// draw right side\r
+//\r
+asm     mov     al,[BYTE PTR maskright]\r
+asm     out     dx,al           // mask off pixels\r
+asm     xchg    bh,[es:di]      // load latches and write pixels\r
+\r
+}\r
+\r
+#endif\r
+\r
+//==========================================================================\r
+\r
+\r
+long            wallscalesource;\r
+\r
+#ifdef DRAWEACH\r
+/*\r
+====================\r
+=\r
+= ScaleOneWall\r
+=\r
+====================\r
+*/\r
+\r
+void near ScaleOneWall (int xl, int xh)\r
+{\r
+       int     x,pixwidth,height;\r
+\r
+       *(((unsigned *)&wallscalesource)+1) = wallseg[xl];\r
+\r
+       for (x=xl;x<=xh;x+=pixwidth)\r
+       {\r
+               height = wallheight[x];\r
+               pixwidth = wallwidth[x];\r
+               (unsigned)wallscalesource = wallofs[x];\r
+\r
+               *(((unsigned *)&scaletablecall)+1) = (unsigned)scaledirectory[height];\r
+               (unsigned)scaletablecall = scaledirectory[height]->codeofs[0];\r
+\r
+               //\r
+               // scale a byte wide strip of wall\r
+               //\r
+               asm     mov     bx,[x]\r
+               asm     mov     di,bx\r
+               asm     shr     di,1\r
+               asm     shr     di,1\r
+               asm     shr     di,1                                            // X in bytes\r
+               asm     add     di,[bufferofs]\r
+               asm     and     bx,7\r
+               asm     shl     bx,1\r
+               asm     shl     bx,1\r
+               asm     shl     bx,1\r
+               asm     add     bx,[pixwidth]                           // bx = pixel*8+pixwidth-1\r
+               asm     dec     bx\r
+               asm     mov     al,BYTE PTR [bitmasks1+bx]\r
+               asm     mov     dx,GC_INDEX+1\r
+               asm     out     dx,al                                           // set bit mask register\r
+               asm     mov     es,[screenseg]\r
+               asm     lds     si,[wallscalesource]\r
+               asm     call [DWORD PTR ss:scaletablecall]              // scale the line of pixels\r
+\r
+               asm     mov     al,BYTE PTR [ss:bitmasks2+bx]\r
+               asm     or      al,al\r
+               asm     jz      nosecond\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 ss:scaletablecall]      // scale the line of pixels\r
+       nosecond:\r
+               asm     mov     ax,ss\r
+               asm     mov     ds,ax\r
+       }\r
+}\r
+\r
+#endif\r
+\r
+char wall_anim_pos[NUMFLOORS];\r
+\r
+// EAST / WEST WALLS\r
+//\r
+int     far walllight1[NUMFLOORS] = {0,\r
+\r
+       0,//CRYSTAL1LIGHTPIC,\r
+       0,//EGYPT1LIGHTPIC,\r
+       EGYPT2LIGHTPIC,\r
+       EGYPT3LIGHTPIC,\r
+\r
+       FIREWALL1PIC,\r
+       FIREWALL2PIC,\r
+       FIREWALL3PIC,\r
+       FIREWALL4PIC,\r
+\r
+\r
+       NEMESISPIC,\r
+\r
+       ALTARLEFTPIC,\r
+       ALTARRIGHTPIC,\r
+\r
+       TEMPLEWALLLIGHTPIC,\r
+\r
+       TORCHWALL1PIC,\r
+       TORCHWALL2PIC,\r
+\r
+       BRNBRKLIGHTPIC,\r
+       BRNBRKEMLIGHTPIC,\r
+\r
+       IRONGATEPIC,\r
+\r
+       BRNFLGLIGHTPIC,\r
+       BRNFLGWINDOWLIGHTPIC,\r
+       BRNFLGVINELIGHTPIC,\r
+       BRNFLGDMGLIGHTPIC,\r
+\r
+       SPACEDMG1LIGHTPIC,\r
+       SPACEDMG2LIGHTPIC,\r
+\r
+       SPACE1LIGHTPIC,\r
+       SPACE2LIGHTPIC,\r
+       SPACE3LIGHTPIC,\r
+       SPACE4LIGHTPIC,\r
+\r
+       SPACE5LIGHTPIC,\r
+       SPACE6LIGHTPIC,\r
+       SPACE7LIGHTPIC,\r
+       SPACE8LIGHTPIC,\r
+\r
+       0,//SPACE9LIGHTPIC,\r
+       0,//SPACEDMG9LIGHTPIC,\r
+       SPACE10LIGHTPIC,\r
+       RUSTDOORLIGHTPIC,\r
+\r
+       SPACE11LIGHTPIC,\r
+       SPACE12LIGHTPIC,\r
+       SPACE13LIGHTPIC,\r
+       SPACE14LIGHTPIC,\r
+\r
+       SPACEDMG5LIGHTPIC,\r
+       SPACEDMG6LIGHTPIC,\r
+\r
+       TAP1PIC,\r
+       TAP2PIC,\r
+       ENDPIC,\r
+       0,//SIRONLIGHTPIC,\r
+\r
+       SPCDOOR1LIGHTPIC,\r
+       SPCDOOR2LIGHTPIC,\r
+       SPCDOOR3LIGHTPIC,\r
+       SPCDOOR4LIGHTPIC,\r
+\r
+       COLUMNSLIGHTPIC,\r
+\r
+       DEMONSTATUELIGHTPIC,\r
+\r
+       0,//CRYSTALBWALL1LIGHTPIC,\r
+\r
+       0,//SRUSTLIGHTPIC,\r
+\r
+       TROLLSTATUELIGHTPIC,\r
+\r
+       BRNDMGVINELIGHTPIC,\r
+       TAP3PIC,\r
+       HORNDOORPIC,\r
+       RUNEDOORPIC,\r
+\r
+       EXP_WALL_1PIC,\r
+       EXP_WALL_2PIC,\r
+       EXP_WALL_3PIC,\r
+       WATER_EXP_WALL_1PIC,\r
+       WATER_EXP_WALL_2PIC,\r
+       WATER_EXP_WALL_3PIC,\r
+\r
+       IRONDMGLIGHTPIC,\r
+       IRONLIGHTPIC,\r
+       0,\r
+       TROLLBLOODYLIGHTPIC,\r
+       TROLLLIGHTPIC,\r
+\r
+       0,                                                                                              // INVISIBLE WALL\r
+\r
+       STONEDOORLIGHTPIC,\r
+       0,\r
+\r
+       IRONWTR1LIGHTPIC,\r
+       IRONWTR2LIGHTPIC,\r
+       IRONWTR3LIGHTPIC,\r
+\r
+       RUSTWTR1LIGHTPIC,\r
+       RUSTWTR2LIGHTPIC,\r
+       RUSTWTR3LIGHTPIC,\r
+\r
+       CEMETARYLIGHTPIC,\r
+       0,      //      STAIRDWNLIGHTPIC,\r
+\r
+       WGRATE1LIGHTPIC,\r
+       WGRATE2LIGHTPIC,\r
+       WGRATE3LIGHTPIC,\r
+\r
+       MAS_WIN_LIGHTPIC,\r
+       MAS_DOOR_LIGHTPIC,\r
+       MAS_VINE1_LIGHTPIC,\r
+       MAS_VINE2_LIGHTPIC,\r
+\r
+  // Start of non-solid walls\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+\r
+  // solid walls\r
+       SGRATEPIC,\r
+};\r
+\r
+// NORTH / SOUTH WALLS\r
+//\r
+int     far walldark1[NUMFLOORS] = {0,\r
+\r
+       0,//CRYSTAL1DARKPIC,\r
+       0,//EGYPT1DARKPIC,\r
+       EGYPT2DARKPIC,\r
+       EGYPT3DARKPIC,\r
+\r
+       FIREWALL1PIC,\r
+       FIREWALL2PIC,\r
+       FIREWALL3PIC,\r
+       FIREWALL4PIC,\r
+\r
+       NEMESISPIC,\r
+\r
+       ALTARLEFTPIC,\r
+       ALTARRIGHTPIC,\r
+\r
+       TEMPLEWALLDARKPIC,\r
+\r
+       TORCHWALL1PIC,\r
+       TORCHWALL2PIC,\r
+\r
+       BRNBRKDARKPIC,\r
+       BRNBRKEMDARKPIC,\r
+\r
+       IRONGATEPIC,\r
+\r
+       BRNFLGDARKPIC,\r
+       BRNFLGWINDOWDARKPIC,\r
+       BRNFLGVINEDARKPIC,\r
+       BRNFLGDMGDARKPIC,\r
+\r
+       SPACEDMG1DARKPIC,\r
+       SPACEDMG2DARKPIC,\r
+\r
+       SPACE1DARKPIC,\r
+       SPACE2DARKPIC,\r
+       SPACE3DARKPIC,\r
+       SPACE4DARKPIC,\r
+\r
+       SPACE5DARKPIC,\r
+       SPACE6DARKPIC,\r
+       SPACE7DARKPIC,\r
+       SPACE8DARKPIC,\r
+\r
+       0,//SPACE9DARKPIC,\r
+       0,//SPACEDMG9DARKPIC,\r
+       SPACE10DARKPIC,\r
+       RUSTDOORDARKPIC,\r
+\r
+       SPACE11DARKPIC,\r
+       SPACE12DARKPIC,\r
+       SPACE13DARKPIC,\r
+       SPACE14DARKPIC,\r
+\r
+       SPACEDMG5DARKPIC,\r
+       SPACEDMG6DARKPIC,\r
+\r
+       TAP1PIC,\r
+       TAP2PIC,\r
+       ENDPIC,\r
+       0,//SIRONDARKPIC,\r
+\r
+       SPCDOOR1DARKPIC,\r
+       SPCDOOR2DARKPIC,\r
+       SPCDOOR3DARKPIC,\r
+       SPCDOOR4DARKPIC,\r
+\r
+       COLUMNSDARKPIC,\r
+\r
+       DEMONSTATUEDARKPIC,\r
+\r
+       0,//CRYSTALBWALL1DARKPIC,\r
+\r
+       0,//SRUSTDARKPIC,\r
+\r
+       TROLLSTATUEDARKPIC,\r
+\r
+       BRNDMGVINEDARKPIC,\r
+       TAP3PIC,\r
+       HORNDOORPIC,\r
+       RUNEDOORPIC,\r
+\r
+       EXP_WALL_1PIC,\r
+       EXP_WALL_2PIC,\r
+       EXP_WALL_3PIC,\r
+\r
+       WATER_EXP_WALL_1PIC,\r
+       WATER_EXP_WALL_2PIC,\r
+       WATER_EXP_WALL_3PIC,\r
+\r
+       IRONDMGDARKPIC,\r
+       IRONDARKPIC,\r
+       0,\r
+       TROLLBLOODYDARKPIC,\r
+\r
+       TROLLDARKPIC,\r
+\r
+       0,                                                                                      // INVISIBLE WALL\r
+\r
+       STONEDOORDARKPIC,\r
+       0,\r
+\r
+       IRONWTR1DARKPIC,\r
+       IRONWTR2DARKPIC,\r
+       IRONWTR3DARKPIC,\r
+\r
+       RUSTWTR1DARKPIC,\r
+       RUSTWTR2DARKPIC,\r
+       RUSTWTR3DARKPIC,\r
+\r
+       CEMETARYDARKPIC,\r
+       0,\r
+\r
+       WGRATE1DARKPIC,\r
+       WGRATE2DARKPIC,\r
+       WGRATE3DARKPIC,\r
+\r
+       MAS_WIN_DARKPIC,\r
+       MAS_DOOR_DARKPIC,\r
+       MAS_VINE1_DARKPIC,\r
+       MAS_VINE2_DARKPIC,\r
+\r
+  // Start of non-solid walls\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+       0,\r
+\r
+  // solid walls\r
+       SGRATEPIC,\r
+};\r
+\r
+\r
+/*\r
+=====================\r
+=\r
+= DrawVWall\r
+=\r
+= Draws a wall by vertical segments, for texture mapping!\r
+=\r
+= wallptr->side is true for east/west walls (constant x)\r
+=\r
+= fracheight and fracstep are 16.16 bit fractions\r
+=\r
+=====================\r
+*/\r
+\r
+void DrawVWall (walltype *wallptr)\r
+{\r
+       int                     x,i;\r
+       unsigned        source;\r
+       unsigned        width,sourceint;\r
+       unsigned        wallpic,wallpicseg;\r
+       unsigned        skip;\r
+       long            fracheight,fracstep,longheightchange;\r
+       unsigned        height;\r
+       int                     heightchange;\r
+       unsigned        slope,distance;\r
+       int                     traceangle,angle;\r
+       int                     mapadd;\r
+       unsigned        lastpix,lastsource,lastwidth;\r
+\r
+       if (wallptr->rightclip < wallptr->leftclip)\r
+               Quit ("DrawVWall: Right < Left");\r
+\r
+//\r
+// setup for height calculation\r
+//\r
+       wallptr->height1 >>= 1;\r
+       wallptr->height2 >>= 1;\r
+       wallptr->planecoord>>=10;                       // remove non significant bits\r
+\r
+       width = wallptr->x2 - wallptr->x1;\r
+       if (width)\r
+       {\r
+               heightchange = wallptr->height2 - wallptr->height1;\r
+               asm     mov     ax,[heightchange]\r
+               asm     mov     WORD PTR [longheightchange+2],ax\r
+               asm     mov     WORD PTR [longheightchange],0   // avoid long shift by 16\r
+               fracstep = longheightchange/width;\r
+       }\r
+\r
+       fracheight = ((long)wallptr->height1<<16)+0x8000;\r
+       skip = wallptr->leftclip - wallptr->x1;\r
+       if (skip)\r
+               fracheight += fracstep*skip;\r
+\r
+//\r
+// setup for texture mapping\r
+//\r
+// mapadd is 64*64 (to keep source positive) + the origin wall intercept\r
+// distance has 6 unit bits, and 6 frac bits\r
+// traceangle is the center view angle in FINEANGLES, moved to be in\r
+// the +-90 degree range (to thew right of origin)\r
+//\r
+       traceangle = fineviewangle;\r
+       //\r
+       // find wall picture to map from\r
+       //\r
+       if (wallptr->side)\r
+       {       // east or west wall\r
+\r
+               wallpic = walllight1[wallptr->color+wall_anim_pos[wallptr->color]];\r
+               if (wallptr->planecoord < viewxpix)\r
+               {\r
+                       distance = viewxpix-wallptr->planecoord;\r
+                       traceangle -= FINEANGLES/2;\r
+                       mapadd = (64-viewypix&63);              // the pixel spot of the origin\r
+               }\r
+               else\r
+               {\r
+                       distance = wallptr->planecoord-viewxpix;\r
+                       // traceangle is correct\r
+                       mapadd = viewypix&63;           // the pixel spot of the origin\r
+               }\r
+       }\r
+       else\r
+       {       // north or south wall\r
+\r
+               wallpic = walldark1[wallptr->color+wall_anim_pos[wallptr->color]];\r
+               if (wallptr->planecoord < viewypix)\r
+               {\r
+                       distance = viewypix-wallptr->planecoord;\r
+                       traceangle -= FINEANGLES/4;\r
+                       mapadd = viewxpix&63;           // the pixel spot of the origin\r
+               }\r
+               else\r
+               {\r
+                       distance = wallptr->planecoord-viewypix;\r
+                       traceangle -= FINEANGLES*3/4;\r
+                       mapadd = (64-viewxpix&63);              // the pixel spot of the origin\r
+               }\r
+       }\r
+\r
+       mapadd = 64*64-mapadd;                          // make sure it stays positive\r
+\r
+       wallpicseg = (unsigned)walldirectory[wallpic-FIRSTWALLPIC];\r
+       if (traceangle > FINEANGLES/2)\r
+               traceangle -= FINEANGLES;\r
+\r
+//\r
+// calculate everything\r
+//\r
+// IMPORTANT!  This loop is executed around 5000 times / second!\r
+//\r
+       lastpix = lastsource = (unsigned)-1;\r
+\r
+       for (x = wallptr->leftclip ; x <= wallptr->rightclip ; x++)\r
+       {\r
+               //\r
+               // height\r
+               //\r
+               asm     mov     ax,WORD PTR [fracheight]\r
+               asm     mov     dx,WORD PTR [fracheight+2]\r
+               asm     mov     cx,dx\r
+               asm     add     ax,WORD PTR [fracstep]\r
+               asm     adc     dx,WORD PTR [fracstep+2]\r
+               asm     mov     WORD PTR [fracheight],ax\r
+               asm     mov     WORD PTR [fracheight+2],dx\r
+               asm     mov     bx,[x]\r
+               asm     shl     bx,1\r
+               asm     cmp     cx,MAXSCALEHEIGHT\r
+               asm     jbe     storeheight\r
+               asm     mov     cx,MAXSCALEHEIGHT\r
+storeheight:\r
+               asm     mov WORD PTR [wallheight+bx],cx\r
+               asm     mov WORD PTR [zbuffer+bx],cx\r
+\r
+//              height = fracheight>>16;\r
+//              fracheight += fracstep;\r
+//              if (height > MAXSCALEHEIGHT)\r
+//                      height = MAXSCALEHEIGHT;\r
+//              wallheight[x] = zbuffer[x] = height;\r
+\r
+               //\r
+               // texture map\r
+               //\r
+               angle = pixelangle[x]+traceangle;\r
+               if (angle<0)\r
+                       angle+=FINEANGLES;\r
+\r
+               slope = finetangent[angle];\r
+\r
+//\r
+// distance is an unsigned 6.6 bit number (12 pixel bits)\r
+// slope is a signed 5.10 bit number\r
+// result is a signed 11.16 bit number\r
+//\r
+\r
+#if 0\r
+               source = distance*slope;\r
+               source >>=20;\r
+\r
+               source += mapadd;\r
+               source &= 63;                           // mask off the unused units\r
+               source = 63-source;\r
+               source <<= 6;                           // multiply by 64 for offset into pic\r
+#endif\r
+               asm     mov     ax,[distance]\r
+               asm     imul    [slope]                 // ax is the source pixel\r
+               asm     mov     al,ah\r
+               asm     shr     al,1\r
+               asm     shr     al,1                            // low 6 bits is now pixel number\r
+               asm     add     ax,[mapadd]\r
+               asm     and ax,63\r
+               asm     mov     dx,63\r
+               asm     sub     dx,ax                           // otherwise it is backwards\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1\r
+               asm     shl     dx,1                            // *64 to index into shape\r
+               asm     mov     [source],dx\r
+\r
+               if (source != lastsource)\r
+               {\r
+                       if (lastpix != (unsigned)-1)\r
+                       {\r
+                               wallofs[lastpix] = lastsource;\r
+                               wallseg[lastpix] = wallpicseg;\r
+                               wallwidth[lastpix] = lastwidth;\r
+                       }\r
+                       lastpix = x;\r
+                       lastsource = source;\r
+                       lastwidth = 1;\r
+               }\r
+               else\r
+                       lastwidth++;                    // optimized draw, same map as last one\r
+       }\r
+       wallofs[lastpix] = lastsource;\r
+       wallseg[lastpix] = wallpicseg;\r
+       wallwidth[lastpix] = lastwidth;\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= TraceRay\r
+=\r
+= Used to find the left and rightmost tile in the view area to be traced from\r
+= Follows a ray of the given angle from viewx,viewy in the global map until\r
+= it hits a solid tile\r
+= sets:\r
+=   tile.x,tile.y       : tile coordinates of contacted tile\r
+=   tilecolor   : solid tile's color\r
+=\r
+==================\r
+*/\r
+\r
+int tilecolor;\r
+\r
+void TraceRay (unsigned angle)\r
+{\r
+  long tracex,tracey,tracexstep,traceystep,searchx,searchy;\r
+  fixed fixtemp;\r
+  int otx,oty,searchsteps;\r
+\r
+  tracexstep = costable[angle];\r
+  traceystep = sintable[angle];\r
+\r
+//\r
+// advance point so it is even with the view plane before we start checking\r
+//\r
+  fixtemp = FixedByFrac(prestep,tracexstep);\r
+  tracex = viewx+fixtemp;\r
+  fixtemp = FixedByFrac(prestep,traceystep);\r
+  tracey = viewy-fixtemp;\r
+\r
+  tile.x = tracex>>TILESHIFT;   // starting point in tiles\r
+  tile.y = tracey>>TILESHIFT;\r
+\r
+\r
+  if (tracexstep<0)                     // use 2's complement, not signed magnitude\r
+       tracexstep = -(tracexstep&0x7fffffff);\r
+\r
+  if (traceystep<0)                     // use 2's complement, not signed magnitude\r
+       traceystep = -(traceystep&0x7fffffff);\r
+\r
+//\r
+// we assume viewx,viewy is not inside a solid tile, so go ahead one step\r
+//\r
+\r
+  do    // until a solid tile is hit\r
+  {\r
+    otx = tile.x;\r
+       oty = tile.y;\r
+       spotvis[otx][oty] = true;\r
+       tracex += tracexstep;\r
+    tracey -= traceystep;\r
+    tile.x = tracex>>TILESHIFT;\r
+       tile.y = tracey>>TILESHIFT;\r
+\r
+       if (tile.x!=otx && tile.y!=oty && (tilemap[otx][tile.y] || tilemap[tile.x][oty]) )\r
+    {\r
+      //\r
+         // trace crossed two solid tiles, so do a binary search along the line\r
+         // to find a spot where only one tile edge is crossed\r
+      //\r
+      searchsteps = 0;\r
+      searchx = tracexstep;\r
+      searchy = traceystep;\r
+      do\r
+      {\r
+       searchx/=2;\r
+       searchy/=2;\r
+       if (tile.x!=otx && tile.y!=oty)\r
+       {\r
+        // still too far\r
+         tracex -= searchx;\r
+         tracey += searchy;\r
+       }\r
+       else\r
+       {\r
+        // not far enough, no tiles crossed\r
+         tracex += searchx;\r
+         tracey -= searchy;\r
+       }\r
+\r
+       //\r
+       // if it is REAL close, go for the most clockwise intersection\r
+       //\r
+       if (++searchsteps == 16)\r
+       {\r
+         tracex = (long)otx<<TILESHIFT;\r
+         tracey = (long)oty<<TILESHIFT;\r
+         if (tracexstep>0)\r
+         {\r
+               if (traceystep<0)\r
+               {\r
+                 tracex += TILEGLOBAL-1;\r
+                 tracey += TILEGLOBAL;\r
+               }\r
+               else\r
+               {\r
+                 tracex += TILEGLOBAL;\r
+               }\r
+         }\r
+         else\r
+         {\r
+               if (traceystep<0)\r
+               {\r
+                 tracex --;\r
+                 tracey += TILEGLOBAL-1;\r
+               }\r
+               else\r
+               {\r
+                 tracey --;\r
+               }\r
+         }\r
+       }\r
+\r
+       tile.x = tracex>>TILESHIFT;\r
+       tile.y = tracey>>TILESHIFT;\r
+\r
+         } while (( tile.x!=otx && tile.y!=oty) || (tile.x==otx && tile.y==oty) );\r
+       }\r
+  } while (!(tilecolor = tilemap[tile.x][tile.y]) );\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
+  fixed value;\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     not     ax\r
+asm     not     cx\r
+asm     add     ax,1\r
+asm     adc     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     not     ax\r
+asm     not     dx\r
+asm     add     ax,1\r
+asm     adc     dx,0\r
+\r
+ansok:;\r
+\r
+}\r
+\r
+#pragma warn +rvl\r
+\r
+#if 0\r
+/*\r
+=========================\r
+=\r
+= FixedAdd\r
+=\r
+= add two 16 bit fixed point numbers\r
+= to subtract, invert the sign of B before invoking\r
+=\r
+=========================\r
+*/\r
+\r
+fixed FixedAdd (fixed a, fixed b)\r
+{\r
+  fixed value;\r
+\r
+asm     mov     ax,[WORD PTR a]\r
+asm     mov     dx,[WORD PTR a+2]\r
+\r
+asm     mov     bx,[WORD PTR b]\r
+asm     mov     cx,[WORD PTR b+2]\r
+\r
+asm     or      dx,dx\r
+asm     jns     aok:            // negative?\r
+asm     and     dx,0x7fff\r
+asm     not     ax              // convert a from signed magnitude to 2's compl\r
+asm     not     dx\r
+asm     add     ax,1\r
+asm     adc     dx,0\r
+aok:\r
+\r
+asm     or      cx,cx\r
+asm     jns     bok:            // negative?\r
+asm     and     cx,0x7fff\r
+asm     not     bx              // convert b from signed magnitude to 2's compl\r
+asm     not     cx\r
+asm     add     bx,1\r
+asm     adc     cx,0\r
+bok:\r
+\r
+asm     add     ax,bx           // perform the addition\r
+asm     adc     dx,cx\r
+asm     jns     done\r
+\r
+asm     and     dx,0x7fff       // value was negative\r
+asm     not     ax              // back to signed magnitude\r
+asm     not     dx\r
+asm     add     ax,1\r
+asm     adc     dx,0\r
+\r
+done:\r
+\r
+asm     mov     [WORD PTR value],ax\r
+asm     mov     [WORD PTR value+2],dx\r
+\r
+  return value;\r
+}\r
+#endif\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= TransformPoint\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
+=\r
+=\r
+= defines:\r
+=   CENTERX             : pixel location of center of view window\r
+=   TILEGLOBAL          : size of one\r
+=   FOCALLENGTH         : distance behind viewx/y for center of projection\r
+=   scale               : conversion from global value to screen value\r
+=\r
+= returns:\r
+=   screenx,screenheight: projected edge location and size\r
+=\r
+========================\r
+*/\r
+\r
+void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight)\r
+{\r
+  int ratio;\r
+  fixed gxt,gyt,nx,ny;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+  gx = gx-viewx;\r
+  gy = gy-viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+  gxt = FixedByFrac(gx,viewcos);\r
+  gyt = FixedByFrac(gy,viewsin);\r
+  nx = gxt-gyt;\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
+  if (nx<0)\r
+       nx = 0;\r
+\r
+  ratio = nx*scale/FOCALLENGTH;\r
+\r
+  if (ratio<=MINRATIO)\r
+       ratio = MINRATIO;\r
+\r
+  *screenx = CENTERX + ny/ratio;\r
+\r
+  *screenheight = TILEGLOBAL/ratio;\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
+\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-ob->size;\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
+  if (nx<0)\r
+       nx = 0;\r
+\r
+  ratio = nx*scale/FOCALLENGTH;\r
+\r
+  if (ratio<=MINRATIO)\r
+       ratio = MINRATIO;\r
+\r
+  ob->viewx = CENTERX + ny/ratio;\r
+\r
+  ob->viewheight = TILEGLOBAL/ratio;\r
+}\r
+\r
+//==========================================================================\r
+\r
+fixed TransformX (fixed gx, fixed gy)\r
+{\r
+  int ratio;\r
+  fixed gxt,gyt,nx,ny;\r
+\r
+//\r
+// translate point to view centered coordinates\r
+//\r
+  gx = gx-viewx;\r
+  gy = gy-viewy;\r
+\r
+//\r
+// calculate newx\r
+//\r
+  gxt = FixedByFrac(gx,viewcos);\r
+  gyt = FixedByFrac(gy,viewsin);\r
+\r
+  return gxt-gyt;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= BuildTables\r
+=\r
+= Calculates:\r
+=\r
+= scale                 projection constant\r
+= sintable/costable     overlapping fractional tables\r
+= firstangle/lastangle  angles from focalpoint to left/right view edges\r
+= prestep               distance from focal point before checking for tiles\r
+=\r
+==================\r
+*/\r
+\r
+void BuildTables (void)\r
+{\r
+  int           i;\r
+  long          intang;\r
+  long          x;\r
+  float         angle,anglestep,radtoint;\r
+  double        tang;\r
+  fixed         value;\r
+\r
+//\r
+// calculate the angle offset from view angle of each pixel's ray\r
+//\r
+       radtoint = (float)FINEANGLES/2/PI;\r
+       for (i=0;i<VIEWWIDTH/2;i++)\r
+       {\r
+       // start 1/2 pixel over, so viewangle bisects two middle pixels\r
+               x = (TILEGLOBAL*i+TILEGLOBAL/2)/VIEWWIDTH;\r
+               tang = (float)x/(FOCALLENGTH+MINDIST);\r
+               angle = atan(tang);\r
+               intang = angle*radtoint;\r
+               pixelangle[VIEWWIDTH/2-1-i] = intang;\r
+               pixelangle[VIEWWIDTH/2+i] = -intang;\r
+       }\r
+\r
+//\r
+// calculate fine tangents\r
+// 1 sign bit, 5 units (clipped to), 10 fracs\r
+//\r
+#define MININT  (-MAXINT)\r
+\r
+       for (i=0;i<FINEANGLES/4;i++)\r
+       {\r
+               intang = tan(i/radtoint)*(1l<<10);\r
+\r
+               //\r
+               // if the tangent is not reprentable in this many bits, bound the\r
+               // units part ONLY\r
+               //\r
+               if (intang>MAXINT)\r
+                       intang = 0x8f00 | (intang & 0xff);\r
+               else if (intang<MININT)\r
+                       intang = 0xff00 | (intang & 0xff);\r
+\r
+               finetangent[i] = intang;\r
+//              finetangent[FINEANGLES/2+i] = intang;\r
+//              finetangent[FINEANGLES/2-i-1] = -intang;\r
+               finetangent[FINEANGLES-i-1] = -intang;\r
+       }\r
+\r
+//\r
+// calculate scale value so one tile at mindist allmost fills the view horizontally\r
+//\r
+  scale = GLOBAL1/VIEWWIDTH;\r
+  scale *= focallength;\r
+  scale /= (focallength+mindist);\r
+\r
+//\r
+// costable overlays sintable with a quarter phase shift\r
+// ANGLES is assumed to be divisable by four\r
+//\r
+// The low word of the value is the fraction, the high bit is the sign bit,\r
+// bits 16-30 should be 0\r
+//\r
+\r
+  angle = 0;\r
+  anglestep = PI/2/ANGLEQUAD;\r
+  for (i=0;i<=ANGLEQUAD;i++)\r
+  {\r
+       value=GLOBAL1*sin(angle);\r
+       sintable[i]=\r
+         sintable[i+ANGLES]=\r
+         sintable[ANGLES/2-i] = value;\r
+       sintable[ANGLES-i]=\r
+         sintable[ANGLES/2+i] = value | 0x80000000l;\r
+       angle += anglestep;\r
+  }\r
+\r
+//\r
+// figure trace angles for first and last pixel on screen\r
+//\r
+  angle = atan((float)VIEWWIDTH/2*scale/FOCALLENGTH);\r
+  angle *= ANGLES/(PI*2);\r
+\r
+  intang = (int)angle+1;\r
+  firstangle = intang;\r
+  lastangle = -intang;\r
+\r
+  prestep = GLOBAL1*((float)FOCALLENGTH/costable[firstangle]);\r
+\r
+//\r
+// misc stuff\r
+//\r
+  walls[0].x2 = VIEWX-1;\r
+  walls[0].height2 = 32000;\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= ClearScreen\r
+=\r
+=====================\r
+*/\r
+\r
+void ClearScreen (void)\r
+{\r
+       unsigned topcolor=*skycolor, bottomcolor=*groundcolor;\r
+       unsigned topimage=topcolor&0xf0,bottomimage=bottomcolor&0xf0;\r
+       unsigned pfoffset=0;\r
+\r
+\r
+#if USE_STRIPS\r
+       if (topimage == 0x20)           // special code for lightning\r
+               topimage = topcolor = 0;\r
+\r
+// Manually wipe screen with solid color.\r
+// If BOTH sky and ground are 'images' don't manually clear it!\r
+//\r
+       if ((!topimage) || (!bottomimage))\r
+       {\r
+#endif\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-VIEWWIDTH/8                                    // dx = modulo\r
+asm     mov     bl,VIEWWIDTH/16\r
+asm     mov     bh,CENTERY+1\r
+\r
+asm     mov     ax,topcolor\r
+asm     mov     es,[screenseg]\r
+asm     mov     di,[bufferofs]\r
+asm     add     di,((SCREENWIDTH*VIEWY)+(VIEWX/8))\r
+\r
+toploop:\r
+asm     mov     cl,bl\r
+asm     rep     stosw\r
+asm     stosb\r
+//asm     add     di,dx                                        // no need to add "0" modulo\r
+asm     dec     bh\r
+asm     jnz     toploop\r
+\r
+asm     mov     bh,CENTERY+1\r
+asm     mov     ax,bottomcolor\r
+\r
+bottomloop:\r
+asm     mov     cl,bl\r
+asm     rep     stosw\r
+asm     stosb\r
+//asm     add     di,dx                                        // no need to add "0" modulo\r
+asm     dec     bh\r
+asm     jnz     bottomloop\r
+\r
+#if USE_STRIPS\r
+       }\r
+\r
+\r
+//\r
+// code to test parallax turning\r
+//\r
+\r
+       if (topimage)\r
+       {\r
+               topimage -= 16;\r
+               pfoffset = LONG_PERCENTAGE(3200,359,(359-player->angle),12);\r
+               while (pfoffset >= 640)\r
+                       pfoffset -= 640;\r
+               LatchDrawPicStrip(0,0,SKY1PIC+topimage,pfoffset+8);\r
+       }\r
+\r
+       if (bottomimage)\r
+       {\r
+////           pfoffset = LONG_PERCENTAGE(3200,359,(359-player->angle),12)+320;\r
+//             pfoffset += 320;\r
+//             while (pfoffset >= 640)\r
+//                     pfoffset -= 640;\r
+//             LatchDrawPicStrip(0,64,SKY1PIC+topimage,pfoffset+8);\r
+               bottomimage -= 16;\r
+               LatchDrawPic(0,64,GND1PIC+bottomimage);\r
+       }\r
+#endif\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
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= DrawWallList\r
+=\r
+= Clips and draws all the walls traced this refresh\r
+=\r
+=====================\r
+*/\r
+\r
+void DrawWallList (void)\r
+{\r
+       int i,leftx,newleft,rightclip;\r
+       walltype *wall, *check;\r
+\r
+asm     mov     ax,ds\r
+asm     mov     es,ax\r
+asm     mov     di,OFFSET wallwidth\r
+asm     xor     ax,ax\r
+asm     mov     cx,VIEWWIDTH/2\r
+asm     rep     stosw\r
+\r
+       ClearScreen ();\r
+\r
+       rightwall->x1 = VIEWXH+1;\r
+       rightwall->height1 = 32000;\r
+       (rightwall+1)->x1 = 32000;\r
+\r
+       leftx = -1;\r
+\r
+       for (wall=&walls[1];wall<rightwall && leftx<=VIEWXH ;wall++)\r
+       {\r
+         if (leftx >= wall->x2)\r
+               continue;\r
+\r
+         rightclip = wall->x2;\r
+\r
+         check = wall+1;\r
+         while (check->x1 <= rightclip && check->height1 >= wall->height2)\r
+         {\r
+               rightclip = check->x1-1;\r
+               check++;\r
+         }\r
+\r
+         if (rightclip>VIEWXH)\r
+               rightclip=VIEWXH;\r
+\r
+         if (leftx < wall->x1 - 1)\r
+               newleft = wall->x1-1;           // there was black space between walls\r
+         else\r
+               newleft = leftx;\r
+\r
+         if (rightclip > newleft)\r
+         {\r
+               wall->leftclip = newleft+1;\r
+               wall->rightclip = rightclip;\r
+               DrawVWall (wall);\r
+               leftx = rightclip;\r
+         }\r
+       }\r
+\r
+#ifndef DRAWEACH\r
+       ScaleWalls ();                                  // draw all the walls\r
+#endif\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+=====================\r
+=\r
+= DrawScaleds\r
+=\r
+= Draws all objects that are visable\r
+=\r
+=====================\r
+*/\r
+\r
+objtype *depthsort[MAXACTORS];\r
+\r
+void DrawScaleds (void)\r
+{\r
+#if USE_INERT_LIST\r
+               extern inertobjtype inertobjlist[], *inert;\r
+\r
+               boolean inertlist=false;\r
+#endif\r
+       int             i,j,least,numvisable,height;\r
+       objtype         *obj,**vislist,*farthest;\r
+       memptr          shape;\r
+       byte            *tilespot,*visspot;\r
+\r
+       numvisable = 0;\r
+\r
+//\r
+// calculate base positions of all objects\r
+//\r
+       vislist = &depthsort[0];\r
+\r
+       obj = player->next;\r
+       while (obj)\r
+       {\r
+               tilespot = &tilemap[0][0]+(obj->tilex<<6)+obj->tiley;\r
+               visspot = &spotvis[0][0]+(obj->tilex<<6)+obj->tiley;\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
+#if USE_INERT_LIST\r
+                       if (!inertlist)\r
+#endif\r
+                               if ((obj->active == noalways) || (obj->active == always))\r
+                                       obj->active = always;\r
+                               else\r
+                                       obj->active = yes;\r
+                       TransformActor (obj);\r
+                       if (!obj->viewheight || obj->viewheight > VIEWWIDTH)\r
+                               goto cont;                       // too close or far away\r
+\r
+                       if (!obj->state->shapenum)\r
+                               goto cont;\r
+\r
+                       *vislist++ = obj;\r
+                       numvisable++;\r
+               }\r
+               else\r
+#if USE_INERT_LIST\r
+                       if (!inertlist)\r
+#endif\r
+                               if ((obj->active != always) && (obj->active != noalways))\r
+                                       obj->active = no;\r
+\r
+cont:;\r
+               obj = obj->next;\r
+#if USE_INERT_LIST\r
+               if ((!obj) && (!inertlist))\r
+               {\r
+                       if (inert != inertobjlist)\r
+                               obj = (objtype *)inertobjlist;\r
+                       inertlist = true;\r
+               }\r
+#endif\r
+       }\r
+\r
+       if (vislist == &depthsort[0])\r
+               return;                                         // no visable objects\r
+\r
+//\r
+// draw from back to front\r
+//\r
+       for (i = 0; i<numvisable; i++)\r
+       {\r
+               least = 32000;\r
+               for (j=0;j<numvisable;j++)\r
+               {\r
+                       height = depthsort[j]->viewheight;\r
+                       if (height < least)\r
+                       {\r
+                               least = height;\r
+                               farthest = depthsort[j];\r
+                       }\r
+               }\r
+               //\r
+               // draw farthest\r
+               //\r
+               shape = shapedirectory[farthest->state->shapenum-FIRSTSCALEPIC];\r
+               ScaleShape(farthest->viewx,shape,farthest->viewheight);\r
+               farthest->viewheight = 32000;\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
+#ifdef PROFILE\r
+       tics = 1;\r
+       return;\r
+#endif\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
+#if 0\r
+       if (DemoMode)                                   // demo recording and playback needs\r
+       {                                                               // to be constant\r
+//\r
+// take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
+//\r
+               oldtimecount = lasttimecount;\r
+               while (TimeCount<oldtimecount+DEMOTICS*2)\r
+               ;\r
+               lasttimecount = oldtimecount + DEMOTICS;\r
+               TimeCount = lasttimecount + DEMOTICS;\r
+               realtics = tics = DEMOTICS;\r
+       }\r
+       else\r
+#endif\r
+       {\r
+//\r
+// non demo, so report actual time\r
+//\r
+               newtime = TimeCount;\r
+               realtics = tics = newtime-lasttimecount;\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
+               if (realtics>MAXREALTICS)\r
+                       realtics = MAXREALTICS;\r
+       }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= DrawHand\r
+=\r
+========================\r
+*/\r
+\r
+void    DrawHand (void)\r
+{\r
+       #define HAND_X_POS      ((VIEWWIDTH/16)-(10/2))         // "10" = hand width in bytes\r
+\r
+       #define picnum HAND1PICM\r
+\r
+       memptr source;\r
+       unsigned dest,width,height;\r
+\r
+//      if (gamestate.shotpower || boltsleft)\r
+//              picnum += (((unsigned)TimeCount>>3)&1);\r
+\r
+       source = grsegs[picnum];\r
+       dest = ylookup[VIEWHEIGHT-handheight]+HAND_X_POS+bufferofs;                     // 12\r
+       width = picmtable[picnum-STARTPICM].width;\r
+       height = picmtable[picnum-STARTPICM].height;\r
+\r
+       VW_MaskBlock(source,0,dest,width,handheight,width*height);\r
+       EGAMAPMASK(15);\r
+}\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+========================\r
+=\r
+= ThreeDRefresh\r
+=\r
+========================\r
+*/\r
+\r
+void    ThreeDRefresh (void)\r
+{\r
+       int tracedir;\r
+\r
+restart:\r
+       aborttrace = false;\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,[mapwidth]           // mapheight*32 words\r
+asm     shl     cx,1\r
+asm     shl     cx,1\r
+asm     shl     cx,1\r
+asm     shl     cx,1\r
+asm     shl     cx,1\r
+asm     rep stosw\r
+\r
+\r
+//\r
+// set up variables for this view\r
+//\r
+\r
+       viewangle = player->angle;\r
+       fineviewangle = 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
+       viewx &= 0xfffffc00;            // stop on a pixel boundary\r
+       viewy &= 0xfffffc00;\r
+       viewx += 0x180;\r
+       viewy += 0x180;\r
+       viewxpix = viewx>>10;\r
+       viewypix = viewy>>10;\r
+\r
+       focal.x = viewx>>TILESHIFT;\r
+       focal.y = viewy>>TILESHIFT;\r
+\r
+//\r
+// find the rightmost visable tile in view\r
+//\r
+       tracedir = viewangle + lastangle;\r
+       if (tracedir<0)\r
+         tracedir+=ANGLES;\r
+       else if (tracedir>=ANGLES)\r
+         tracedir-=ANGLES;\r
+       TraceRay( tracedir );\r
+       right.x = tile.x;\r
+       right.y = tile.y;\r
+\r
+//\r
+// find the leftmost visable tile in view\r
+//\r
+       tracedir = viewangle + firstangle;\r
+       if (tracedir<0)\r
+         tracedir+=ANGLES;\r
+       else if (tracedir>=ANGLES)\r
+         tracedir-=ANGLES;\r
+       TraceRay( tracedir );\r
+\r
+//\r
+// follow the walls from there to the right\r
+//\r
+       rightwall = &walls[1];\r
+       FollowWalls ();\r
+\r
+       if (aborttrace)\r
+               goto restart;\r
+\r
+//\r
+// actually draw stuff\r
+//\r
+       if (++screenpage == 3)\r
+               screenpage = 0;\r
+\r
+       bufferofs = screenloc[screenpage];\r
+\r
+       EGAWRITEMODE(2);\r
+       EGAMAPMASK(15);\r
+\r
+//\r
+// draw the wall list saved be FollowWalls ()\r
+//\r
+//      animframe = (TimeCount&8)>>3;\r
+\r
+//\r
+// draw all the scaled images\r
+//\r
+       asm     mov     dx,GC_INDEX\r
+\r
+       asm     mov     ax,GC_COLORDONTCARE\r
+       asm     out     dx,ax                                           // don't look at any of the planes\r
+\r
+       asm     mov     ax,GC_MODE + 256*(10)           // read mode 1, write mode 2\r
+       asm     out     dx,ax\r
+\r
+       asm     mov     al,GC_BITMASK\r
+       asm     out     dx,al\r
+\r
+       AnimateWallList();\r
+       DrawWallList();\r
+       DrawScaleds();\r
+\r
+       EGAWRITEMODE(0);\r
+       EGABITMASK(0xff);\r
+\r
+//\r
+// draw hand\r
+//\r
+       if (handheight)\r
+               DrawHand ();\r
+\r
+//\r
+// show screen and time last cycle\r
+//\r
+       if (fizzlein)\r
+       {\r
+               fizzlein = false;\r
+               FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,true);\r
+               lasttimecount = TimeCount;\r
+               if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
+       }\r
+\r
+asm     cli\r
+asm     mov     cx,[bufferofs]\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     dec     dx\r
+asm     mov     al,0dh          // start address low register\r
+asm     out     dx,al\r
+asm     inc     dx\r
+asm     mov     al,cl\r
+asm     out     dx,al           // set the low byte\r
+asm     sti\r
+\r
+       displayofs = bufferofs;\r
+\r
+       CalcTics ();\r
+\r
+}\r
+\r