home *** CD-ROM | disk | FTP | other *** search
/ 100 af Verdens Bedste Spil / 100Spil.iso / dos / wolf3d / source / wolfsrc.1 / WL_DRAW.C < prev    next >
C/C++ Source or Header  |  1993-02-04  |  28KB  |  1,404 lines

  1. // WL_DRAW.C
  2.  
  3. #include "WL_DEF.H"
  4. #include <DOS.H>
  5. #pragma hdrstop
  6.  
  7. //#define DEBUGWALLS
  8. //#define DEBUGTICS
  9.  
  10. /*
  11. =============================================================================
  12.  
  13.                          LOCAL CONSTANTS
  14.  
  15. =============================================================================
  16. */
  17.  
  18. // the door is the last picture before the sprites
  19. #define DOORWALL    (PMSpriteStart-8)
  20.  
  21. #define ACTORSIZE    0x4000
  22.  
  23. /*
  24. =============================================================================
  25.  
  26.                          GLOBAL VARIABLES
  27.  
  28. =============================================================================
  29. */
  30.  
  31.  
  32. #ifdef DEBUGWALLS
  33. unsigned screenloc[3]= {0,0,0};
  34. #else
  35. unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START};
  36. #endif
  37. unsigned freelatch = FREESTART;
  38.  
  39. long     lasttimecount;
  40. long     frameon;
  41.  
  42. unsigned    wallheight[MAXVIEWWIDTH];
  43.  
  44. fixed    tileglobal    = TILEGLOBAL;
  45. fixed    mindist        = MINDIST;
  46.  
  47.  
  48. //
  49. // math tables
  50. //
  51. int            pixelangle[MAXVIEWWIDTH];
  52. long        far finetangent[FINEANGLES/4];
  53. fixed         far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4);
  54.  
  55. //
  56. // refresh variables
  57. //
  58. fixed    viewx,viewy;            // the focal point
  59. int        viewangle;
  60. fixed    viewsin,viewcos;
  61.  
  62.  
  63.  
  64. fixed    FixedByFrac (fixed a, fixed b);
  65. void    TransformActor (objtype *ob);
  66. void    BuildTables (void);
  67. void    ClearScreen (void);
  68. int        CalcRotate (objtype *ob);
  69. void    DrawScaleds (void);
  70. void    CalcTics (void);
  71. void    FixOfs (void);
  72. void    ThreeDRefresh (void);
  73.  
  74.  
  75.  
  76. //
  77. // wall optimization variables
  78. //
  79. int        lastside;        // true for vertical
  80. long    lastintercept;
  81. int        lasttilehit;
  82.  
  83.  
  84. //
  85. // ray tracing variables
  86. //
  87. int            focaltx,focalty,viewtx,viewty;
  88.  
  89. int            midangle,angle;
  90. unsigned    xpartial,ypartial;
  91. unsigned    xpartialup,xpartialdown,ypartialup,ypartialdown;
  92. unsigned    xinttile,yinttile;
  93.  
  94. unsigned    tilehit;
  95. unsigned    pixx;
  96.  
  97. int        xtile,ytile;
  98. int        xtilestep,ytilestep;
  99. long    xintercept,yintercept;
  100. long    xstep,ystep;
  101.  
  102. int        horizwall[MAXWALLTILES],vertwall[MAXWALLTILES];
  103.  
  104.  
  105. /*
  106. =============================================================================
  107.  
  108.                          LOCAL VARIABLES
  109.  
  110. =============================================================================
  111. */
  112.  
  113.  
  114. void AsmRefresh (void);            // in WL_DR_A.ASM
  115.  
  116. /*
  117. ============================================================================
  118.  
  119.                3 - D  DEFINITIONS
  120.  
  121. ============================================================================
  122. */
  123.  
  124.  
  125. //==========================================================================
  126.  
  127.  
  128. /*
  129. ========================
  130. =
  131. = FixedByFrac
  132. =
  133. = multiply a 16/16 bit, 2's complement fixed point number by a 16 bit
  134. = fraction, passed as a signed magnitude 32 bit number
  135. =
  136. ========================
  137. */
  138.  
  139. #pragma warn -rvl            // I stick the return value in with ASMs
  140.  
  141. fixed FixedByFrac (fixed a, fixed b)
  142. {
  143. //
  144. // setup
  145. //
  146. asm    mov    si,[WORD PTR b+2]    // sign of result = sign of fraction
  147.  
  148. asm    mov    ax,[WORD PTR a]
  149. asm    mov    cx,[WORD PTR a+2]
  150.  
  151. asm    or    cx,cx
  152. asm    jns    aok:                // negative?
  153. asm    neg    cx
  154. asm    neg    ax
  155. asm    sbb    cx,0
  156. asm    xor    si,0x8000            // toggle sign of result
  157. aok:
  158.  
  159. //
  160. // multiply  cx:ax by bx
  161. //
  162. asm    mov    bx,[WORD PTR b]
  163. asm    mul    bx                    // fraction*fraction
  164. asm    mov    di,dx                // di is low word of result
  165. asm    mov    ax,cx                //
  166. asm    mul    bx                    // units*fraction
  167. asm add    ax,di
  168. asm    adc    dx,0
  169.  
  170. //
  171. // put result dx:ax in 2's complement
  172. //
  173. asm    test    si,0x8000        // is the result negative?
  174. asm    jz    ansok:
  175. asm    neg    dx
  176. asm    neg    ax
  177. asm    sbb    dx,0
  178.  
  179. ansok:;
  180.  
  181. }
  182.  
  183. #pragma warn +rvl
  184.  
  185. //==========================================================================
  186.  
  187. /*
  188. ========================
  189. =
  190. = TransformActor
  191. =
  192. = Takes paramaters:
  193. =   gx,gy        : globalx/globaly of point
  194. =
  195. = globals:
  196. =   viewx,viewy        : point of view
  197. =   viewcos,viewsin    : sin/cos of viewangle
  198. =   scale        : conversion from global value to screen value
  199. =
  200. = sets:
  201. =   screenx,transx,transy,screenheight: projected edge location and size
  202. =
  203. ========================
  204. */
  205.  
  206.  
  207. //
  208. // transform actor
  209. //
  210. void TransformActor (objtype *ob)
  211. {
  212.     int ratio;
  213.     fixed gx,gy,gxt,gyt,nx,ny;
  214.     long    temp;
  215.  
  216. //
  217. // translate point to view centered coordinates
  218. //
  219.     gx = ob->x-viewx;
  220.     gy = ob->y-viewy;
  221.  
  222. //
  223. // calculate newx
  224. //
  225.     gxt = FixedByFrac(gx,viewcos);
  226.     gyt = FixedByFrac(gy,viewsin);
  227.     nx = gxt-gyt-ACTORSIZE;        // fudge the shape forward a bit, because
  228.                                 // the midpoint could put parts of the shape
  229.                                 // into an adjacent wall
  230.  
  231. //
  232. // calculate newy
  233. //
  234.     gxt = FixedByFrac(gx,viewsin);
  235.     gyt = FixedByFrac(gy,viewcos);
  236.     ny = gyt+gxt;
  237.  
  238. //
  239. // calculate perspective ratio
  240. //
  241.     ob->transx = nx;
  242.     ob->transy = ny;
  243.  
  244.     if (nx<mindist)            // too close, don't overflow the divide
  245.     {
  246.       ob->viewheight = 0;
  247.       return;
  248.     }
  249.  
  250.     ob->viewx = centerx + ny*scale/nx;    // DEBUG: use assembly divide
  251.  
  252. //
  253. // calculate height (heightnumerator/(nx>>8))
  254. //
  255.     asm    mov    ax,[WORD PTR heightnumerator]
  256.     asm    mov    dx,[WORD PTR heightnumerator+2]
  257.     asm    idiv    [WORD PTR nx+1]            // nx>>8
  258.     asm    mov    [WORD PTR temp],ax
  259.     asm    mov    [WORD PTR temp+2],dx
  260.  
  261.     ob->viewheight = temp;
  262. }
  263.  
  264. //==========================================================================
  265.  
  266. /*
  267. ========================
  268. =
  269. = TransformTile
  270. =
  271. = Takes paramaters:
  272. =   tx,ty        : tile the object is centered in
  273. =
  274. = globals:
  275. =   viewx,viewy        : point of view
  276. =   viewcos,viewsin    : sin/cos of viewangle
  277. =   scale        : conversion from global value to screen value
  278. =
  279. = sets:
  280. =   screenx,transx,transy,screenheight: projected edge location and size
  281. =
  282. = Returns true if the tile is withing getting distance
  283. =
  284. ========================
  285. */
  286.  
  287. boolean TransformTile (int tx, int ty, int *dispx, int *dispheight)
  288. {
  289.     int ratio;
  290.     fixed gx,gy,gxt,gyt,nx,ny;
  291.     long    temp;
  292.  
  293. //
  294. // translate point to view centered coordinates
  295. //
  296.     gx = ((long)tx<<TILESHIFT)+0x8000-viewx;
  297.     gy = ((long)ty<<TILESHIFT)+0x8000-viewy;
  298.  
  299. //
  300. // calculate newx
  301. //
  302.     gxt = FixedByFrac(gx,viewcos);
  303.     gyt = FixedByFrac(gy,viewsin);
  304.     nx = gxt-gyt-0x2000;        // 0x2000 is size of object
  305.  
  306. //
  307. // calculate newy
  308. //
  309.     gxt = FixedByFrac(gx,viewsin);
  310.     gyt = FixedByFrac(gy,viewcos);
  311.     ny = gyt+gxt;
  312.  
  313.  
  314. //
  315. // calculate perspective ratio
  316. //
  317.     if (nx<mindist)            // too close, don't overflow the divide
  318.     {
  319.         *dispheight = 0;
  320.         return false;
  321.     }
  322.  
  323.     *dispx = centerx + ny*scale/nx;    // DEBUG: use assembly divide
  324.  
  325. //
  326. // calculate height (heightnumerator/(nx>>8))
  327. //
  328.     asm    mov    ax,[WORD PTR heightnumerator]
  329.     asm    mov    dx,[WORD PTR heightnumerator+2]
  330.     asm    idiv    [WORD PTR nx+1]            // nx>>8
  331.     asm    mov    [WORD PTR temp],ax
  332.     asm    mov    [WORD PTR temp+2],dx
  333.  
  334.     *dispheight = temp;
  335.  
  336. //
  337. // see if it should be grabbed
  338. //
  339.     if (nx<TILEGLOBAL && ny>-TILEGLOBAL/2 && ny<TILEGLOBAL/2)
  340.         return true;
  341.     else
  342.         return false;
  343. }
  344.  
  345. //==========================================================================
  346.  
  347. /*
  348. ====================
  349. =
  350. = CalcHeight
  351. =
  352. = Calculates the height of xintercept,yintercept from viewx,viewy
  353. =
  354. ====================
  355. */
  356.  
  357. #pragma warn -rvl            // I stick the return value in with ASMs
  358.  
  359. int    CalcHeight (void)
  360. {
  361.     int    transheight;
  362.     int ratio;
  363.     fixed gxt,gyt,nx,ny;
  364.     long    gx,gy;
  365.  
  366.     gx = xintercept-viewx;
  367.     gxt = FixedByFrac(gx,viewcos);
  368.  
  369.     gy = yintercept-viewy;
  370.     gyt = FixedByFrac(gy,viewsin);
  371.  
  372.     nx = gxt-gyt;
  373.  
  374.   //
  375.   // calculate perspective ratio (heightnumerator/(nx>>8))
  376.   //
  377.     if (nx<mindist)
  378.         nx=mindist;            // don't let divide overflow
  379.  
  380.     asm    mov    ax,[WORD PTR heightnumerator]
  381.     asm    mov    dx,[WORD PTR heightnumerator+2]
  382.     asm    idiv    [WORD PTR nx+1]            // nx>>8
  383. }
  384.  
  385.  
  386. //==========================================================================
  387.  
  388. /*
  389. ===================
  390. =
  391. = ScalePost
  392. =
  393. ===================
  394. */
  395.  
  396. long        postsource;
  397. unsigned    postx;
  398. unsigned    postwidth;
  399.  
  400. void    near ScalePost (void)        // VGA version
  401. {
  402.     asm    mov    ax,SCREENSEG
  403.     asm    mov    es,ax
  404.  
  405.     asm    mov    bx,[postx]
  406.     asm    shl    bx,1
  407.     asm    mov    bp,WORD PTR [wallheight+bx]        // fractional height (low 3 bits frac)
  408.     asm    and    bp,0xfff8                // bp = heightscaler*4
  409.     asm    shr    bp,1
  410.     asm    cmp    bp,[maxscaleshl2]
  411.     asm    jle    heightok
  412.     asm    mov    bp,[maxscaleshl2]
  413. heightok:
  414.     asm    add    bp,OFFSET fullscalefarcall
  415.     //
  416.     // scale a byte wide strip of wall
  417.     //
  418.     asm    mov    bx,[postx]
  419.     asm    mov    di,bx
  420.     asm    shr    di,2                        // X in bytes
  421.     asm    add    di,[bufferofs]
  422.  
  423.     asm    and    bx,3
  424.     asm    shl    bx,3                        // bx = pixel*8+pixwidth
  425.     asm    add    bx,[postwidth]
  426.  
  427.     asm    mov    al,BYTE PTR [mapmasks1-1+bx]    // -1 because no widths of 0
  428.     asm    mov    dx,SC_INDEX+1
  429.     asm    out    dx,al                        // set bit mask register
  430.     asm    lds    si,DWORD PTR [postsource]
  431.     asm    call DWORD PTR [bp]                // scale the line of pixels
  432.  
  433.     asm    mov    al,BYTE PTR [ss:mapmasks2-1+bx]   // -1 because no widths of 0
  434.     asm    or    al,al
  435.     asm    jz    nomore
  436.  
  437.     //
  438.     // draw a second byte for vertical strips that cross two bytes
  439.     //
  440.     asm    inc    di
  441.     asm    out    dx,al                        // set bit mask register
  442.     asm    call DWORD PTR [bp]                // scale the line of pixels
  443.  
  444.     asm    mov    al,BYTE PTR [ss:mapmasks3-1+bx]    // -1 because no widths of 0
  445.     asm    or    al,al
  446.     asm    jz    nomore
  447.     //
  448.     // draw a third byte for vertical strips that cross three bytes
  449.     //
  450.     asm    inc    di
  451.     asm    out    dx,al                        // set bit mask register
  452.     asm    call DWORD PTR [bp]                // scale the line of pixels
  453.  
  454.  
  455. nomore:
  456.     asm    mov    ax,ss
  457.     asm    mov    ds,ax
  458. }
  459.  
  460. void  FarScalePost (void)                // just so other files can call
  461. {
  462.     ScalePost ();
  463. }
  464.  
  465.  
  466. /*
  467. ====================
  468. =
  469. = HitVertWall
  470. =
  471. = tilehit bit 7 is 0, because it's not a door tile
  472. = if bit 6 is 1 and the adjacent tile is a door tile, use door side pic
  473. =
  474. ====================
  475. */
  476.  
  477. void HitVertWall (void)
  478. {
  479.     int            wallpic;
  480.     unsigned    texture;
  481.  
  482.     texture = (yintercept>>4)&0xfc0;
  483.     if (xtilestep == -1)
  484.     {
  485.         texture = 0xfc0-texture;
  486.         xintercept += TILEGLOBAL;
  487.     }
  488.     wallheight[pixx] = CalcHeight();
  489.  
  490.     if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit)
  491.     {
  492.         // in the same wall type as last time, so check for optimized draw
  493.         if (texture == (unsigned)postsource)
  494.         {
  495.         // wide scale
  496.             postwidth++;
  497.             wallheight[pixx] = wallheight[pixx-1];
  498.             return;
  499.         }
  500.         else
  501.         {
  502.             ScalePost ();
  503.             (unsigned)postsource = texture;
  504.             postwidth = 1;
  505.             postx = pixx;
  506.         }
  507.     }
  508.     else
  509.     {
  510.     // new wall
  511.         if (lastside != -1)                // if not the first scaled post
  512.             ScalePost ();
  513.  
  514.         lastside = true;
  515.         lastintercept = xtile;
  516.  
  517.         lasttilehit = tilehit;
  518.         postx = pixx;
  519.         postwidth = 1;
  520.  
  521.         if (tilehit & 0x40)
  522.         {                                // check for adjacent doors
  523.             ytile = yintercept>>TILESHIFT;
  524.             if ( tilemap[xtile-xtilestep][ytile]&0x80 )
  525.                 wallpic = DOORWALL+3;
  526.             else
  527.                 wallpic = vertwall[tilehit & ~0x40];
  528.         }
  529.         else
  530.             wallpic = vertwall[tilehit];
  531.  
  532.         *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);
  533.         (unsigned)postsource = texture;
  534.  
  535.     }
  536. }
  537.  
  538.  
  539. /*
  540. ====================
  541. =
  542. = HitHorizWall
  543. =
  544. = tilehit bit 7 is 0, because it's not a door tile
  545. = if bit 6 is 1 and the adjacent tile is a door tile, use door side pic
  546. =
  547. ====================
  548. */
  549.  
  550. void HitHorizWall (void)
  551. {
  552.     int            wallpic;
  553.     unsigned    texture;
  554.  
  555.     texture = (xintercept>>4)&0xfc0;
  556.     if (ytilestep == -1)
  557.         yintercept += TILEGLOBAL;
  558.     else
  559.         texture = 0xfc0-texture;
  560.     wallheight[pixx] = CalcHeight();
  561.  
  562.     if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit)
  563.     {
  564.         // in the same wall type as last time, so check for optimized draw
  565.         if (texture == (unsigned)postsource)
  566.         {
  567.         // wide scale
  568.             postwidth++;
  569.             wallheight[pixx] = wallheight[pixx-1];
  570.             return;
  571.         }
  572.         else
  573.         {
  574.             ScalePost ();
  575.             (unsigned)postsource = texture;
  576.             postwidth = 1;
  577.             postx = pixx;
  578.         }
  579.     }
  580.     else
  581.     {
  582.     // new wall
  583.         if (lastside != -1)                // if not the first scaled post
  584.             ScalePost ();
  585.  
  586.         lastside = 0;
  587.         lastintercept = ytile;
  588.  
  589.         lasttilehit = tilehit;
  590.         postx = pixx;
  591.         postwidth = 1;
  592.  
  593.         if (tilehit & 0x40)
  594.         {                                // check for adjacent doors
  595.             xtile = xintercept>>TILESHIFT;
  596.             if ( tilemap[xtile][ytile-ytilestep]&0x80 )
  597.                 wallpic = DOORWALL+2;
  598.             else
  599.                 wallpic = horizwall[tilehit & ~0x40];
  600.         }
  601.         else
  602.             wallpic = horizwall[tilehit];
  603.  
  604.         *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);
  605.         (unsigned)postsource = texture;
  606.     }
  607.  
  608. }
  609.  
  610. //==========================================================================
  611.  
  612. /*
  613. ====================
  614. =
  615. = HitHorizDoor
  616. =
  617. ====================
  618. */
  619.  
  620. void HitHorizDoor (void)
  621. {
  622.     unsigned    texture,doorpage,doornum;
  623.  
  624.     doornum = tilehit&0x7f;
  625.     texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0;
  626.  
  627.     wallheight[pixx] = CalcHeight();
  628.  
  629.     if (lasttilehit == tilehit)
  630.     {
  631.     // in the same door as last time, so check for optimized draw
  632.         if (texture == (unsigned)postsource)
  633.         {
  634.         // wide scale
  635.             postwidth++;
  636.             wallheight[pixx] = wallheight[pixx-1];
  637.             return;
  638.         }
  639.         else
  640.         {
  641.             ScalePost ();
  642.             (unsigned)postsource = texture;
  643.             postwidth = 1;
  644.             postx = pixx;
  645.         }
  646.     }
  647.     else
  648.     {
  649.         if (lastside != -1)                // if not the first scaled post
  650.             ScalePost ();            // draw last post
  651.     // first pixel in this door
  652.         lastside = 2;
  653.         lasttilehit = tilehit;
  654.         postx = pixx;
  655.         postwidth = 1;
  656.  
  657.         switch (doorobjlist[doornum].lock)
  658.         {
  659.         case dr_normal:
  660.             doorpage = DOORWALL;
  661.             break;
  662.         case dr_lock1:
  663.         case dr_lock2:
  664.         case dr_lock3:
  665.         case dr_lock4:
  666.             doorpage = DOORWALL+6;
  667.             break;
  668.         case dr_elevator:
  669.             doorpage = DOORWALL+4;
  670.             break;
  671.         }
  672.  
  673.         *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage);
  674.         (unsigned)postsource = texture;
  675.     }
  676. }
  677.  
  678. //==========================================================================
  679.  
  680. /*
  681. ====================
  682. =
  683. = HitVertDoor
  684. =
  685. ====================
  686. */
  687.  
  688. void HitVertDoor (void)
  689. {
  690.     unsigned    texture,doorpage,doornum;
  691.  
  692.     doornum = tilehit&0x7f;
  693.     texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0;
  694.  
  695.     wallheight[pixx] = CalcHeight();
  696.  
  697.     if (lasttilehit == tilehit)
  698.     {
  699.     // in the same door as last time, so check for optimized draw
  700.         if (texture == (unsigned)postsource)
  701.         {
  702.         // wide scale
  703.             postwidth++;
  704.             wallheight[pixx] = wallheight[pixx-1];
  705.             return;
  706.         }
  707.         else
  708.         {
  709.             ScalePost ();
  710.             (unsigned)postsource = texture;
  711.             postwidth = 1;
  712.             postx = pixx;
  713.         }
  714.     }
  715.     else
  716.     {
  717.         if (lastside != -1)                // if not the first scaled post
  718.             ScalePost ();            // draw last post
  719.     // first pixel in this door
  720.         lastside = 2;
  721.         lasttilehit = tilehit;
  722.         postx = pixx;
  723.         postwidth = 1;
  724.  
  725.         switch (doorobjlist[doornum].lock)
  726.         {
  727.         case dr_normal:
  728.             doorpage = DOORWALL;
  729.             break;
  730.         case dr_lock1:
  731.         case dr_lock2:
  732.         case dr_lock3:
  733.         case dr_lock4:
  734.             doorpage = DOORWALL+6;
  735.             break;
  736.         case dr_elevator:
  737.             doorpage = DOORWALL+4;
  738.             break;
  739.         }
  740.  
  741.         *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage+1);
  742.         (unsigned)postsource = texture;
  743.     }
  744. }
  745.  
  746. //==========================================================================
  747.  
  748.  
  749. /*
  750. ====================
  751. =
  752. = HitHorizPWall
  753. =
  754. = A pushable wall in action has been hit
  755. =
  756. ====================
  757. */
  758.  
  759. void HitHorizPWall (void)
  760. {
  761.     int            wallpic;
  762.     unsigned    texture,offset;
  763.  
  764.     texture = (xintercept>>4)&0xfc0;
  765.     offset = pwallpos<<10;
  766.     if (ytilestep == -1)
  767.         yintercept += TILEGLOBAL-offset;
  768.     else
  769.     {
  770.         texture = 0xfc0-texture;
  771.         yintercept += offset;
  772.     }
  773.  
  774.     wallheight[pixx] = CalcHeight();
  775.  
  776.     if (lasttilehit == tilehit)
  777.     {
  778.         // in the same wall type as last time, so check for optimized draw
  779.         if (texture == (unsigned)postsource)
  780.         {
  781.         // wide scale
  782.             postwidth++;
  783.             wallheight[pixx] = wallheight[pixx-1];
  784.             return;
  785.         }
  786.         else
  787.         {
  788.             ScalePost ();
  789.             (unsigned)postsource = texture;
  790.             postwidth = 1;
  791.             postx = pixx;
  792.         }
  793.     }
  794.     else
  795.     {
  796.     // new wall
  797.         if (lastside != -1)                // if not the first scaled post
  798.             ScalePost ();
  799.  
  800.         lasttilehit = tilehit;
  801.         postx = pixx;
  802.         postwidth = 1;
  803.  
  804.         wallpic = horizwall[tilehit&63];
  805.  
  806.         *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);
  807.         (unsigned)postsource = texture;
  808.     }
  809.  
  810. }
  811.  
  812.  
  813. /*
  814. ====================
  815. =
  816. = HitVertPWall
  817. =
  818. = A pushable wall in action has been hit
  819. =
  820. ====================
  821. */
  822.  
  823. void HitVertPWall (void)
  824. {
  825.     int            wallpic;
  826.     unsigned    texture,offset;
  827.  
  828.     texture = (yintercept>>4)&0xfc0;
  829.     offset = pwallpos<<10;
  830.     if (xtilestep == -1)
  831.     {
  832.         xintercept += TILEGLOBAL-offset;
  833.         texture = 0xfc0-texture;
  834.     }
  835.     else
  836.         xintercept += offset;
  837.  
  838.     wallheight[pixx] = CalcHeight();
  839.  
  840.     if (lasttilehit == tilehit)
  841.     {
  842.         // in the same wall type as last time, so check for optimized draw
  843.         if (texture == (unsigned)postsource)
  844.         {
  845.         // wide scale
  846.             postwidth++;
  847.             wallheight[pixx] = wallheight[pixx-1];
  848.             return;
  849.         }
  850.         else
  851.         {
  852.             ScalePost ();
  853.             (unsigned)postsource = texture;
  854.             postwidth = 1;
  855.             postx = pixx;
  856.         }
  857.     }
  858.     else
  859.     {
  860.     // new wall
  861.         if (lastside != -1)                // if not the first scaled post
  862.             ScalePost ();
  863.  
  864.         lasttilehit = tilehit;
  865.         postx = pixx;
  866.         postwidth = 1;
  867.  
  868.         wallpic = vertwall[tilehit&63];
  869.  
  870.         *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic);
  871.         (unsigned)postsource = texture;
  872.     }
  873.  
  874. }
  875.  
  876. //==========================================================================
  877.  
  878. //==========================================================================
  879.  
  880. #if 0
  881. /*
  882. =====================
  883. =
  884. = ClearScreen
  885. =
  886. =====================
  887. */
  888.  
  889. void ClearScreen (void)
  890. {
  891.  unsigned floor=egaFloor[gamestate.episode*10+mapon],
  892.       ceiling=egaCeiling[gamestate.episode*10+mapon];
  893.  
  894.   //
  895.   // clear the screen
  896.   //
  897. asm    mov    dx,GC_INDEX
  898. asm    mov    ax,GC_MODE + 256*2        // read mode 0, write mode 2
  899. asm    out    dx,ax
  900. asm    mov    ax,GC_BITMASK + 255*256
  901. asm    out    dx,ax
  902.  
  903. asm    mov    dx,40
  904. asm    mov    ax,[viewwidth]
  905. asm    shr    ax,3
  906. asm    sub    dx,ax                    // dx = 40-viewwidth/8
  907.  
  908. asm    mov    bx,[viewwidth]
  909. asm    shr    bx,4                    // bl = viewwidth/16
  910. asm    mov    bh,BYTE PTR [viewheight]
  911. asm    shr    bh,1                    // half height
  912.  
  913. asm    mov    ax,[ceiling]
  914. asm    mov    es,[screenseg]
  915. asm    mov    di,[bufferofs]
  916.  
  917. toploop:
  918. asm    mov    cl,bl
  919. asm    rep    stosw
  920. asm    add    di,dx
  921. asm    dec    bh
  922. asm    jnz    toploop
  923.  
  924. asm    mov    bh,BYTE PTR [viewheight]
  925. asm    shr    bh,1                    // half height
  926. asm    mov    ax,[floor]
  927.  
  928. bottomloop:
  929. asm    mov    cl,bl
  930. asm    rep    stosw
  931. asm    add    di,dx
  932. asm    dec    bh
  933. asm    jnz    bottomloop
  934.  
  935.  
  936. asm    mov    dx,GC_INDEX
  937. asm    mov    ax,GC_MODE + 256*10        // read mode 1, write mode 2
  938. asm    out    dx,ax
  939. asm    mov    al,GC_BITMASK
  940. asm    out    dx,al
  941.  
  942. }
  943. #endif
  944. //==========================================================================
  945.  
  946. unsigned vgaCeiling[]=
  947. {
  948. #ifndef SPEAR
  949.  0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf,
  950.  0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d,
  951.  0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898,
  952.  
  953.  0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd,
  954.  0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d,
  955.  0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd
  956. #else
  957.  0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f,
  958.  0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc
  959. #endif
  960. };
  961.  
  962. /*
  963. =====================
  964. =
  965. = VGAClearScreen
  966. =
  967. =====================
  968. */
  969.  
  970. void VGAClearScreen (void)
  971. {
  972.  unsigned ceiling=vgaCeiling[gamestate.episode*10+mapon];
  973.  
  974.   //
  975.   // clear the screen
  976.   //
  977. asm    mov    dx,SC_INDEX
  978. asm    mov    ax,SC_MAPMASK+15*256    // write through all planes
  979. asm    out    dx,ax
  980.  
  981. asm    mov    dx,80
  982. asm    mov    ax,[viewwidth]
  983. asm    shr    ax,2
  984. asm    sub    dx,ax                    // dx = 40-viewwidth/2
  985.  
  986. asm    mov    bx,[viewwidth]
  987. asm    shr    bx,3                    // bl = viewwidth/8
  988. asm    mov    bh,BYTE PTR [viewheight]
  989. asm    shr    bh,1                    // half height
  990.  
  991. asm    mov    es,[screenseg]
  992. asm    mov    di,[bufferofs]
  993. asm    mov    ax,[ceiling]
  994.  
  995. toploop:
  996. asm    mov    cl,bl
  997. asm    rep    stosw
  998. asm    add    di,dx
  999. asm    dec    bh
  1000. asm    jnz    toploop
  1001.  
  1002. asm    mov    bh,BYTE PTR [viewheight]
  1003. asm    shr    bh,1                    // half height
  1004. asm    mov    ax,0x1919
  1005.  
  1006. bottomloop:
  1007. asm    mov    cl,bl
  1008. asm    rep    stosw
  1009. asm    add    di,dx
  1010. asm    dec    bh
  1011. asm    jnz    bottomloop
  1012. }
  1013.  
  1014. //==========================================================================
  1015.  
  1016. /*
  1017. =====================
  1018. =
  1019. = CalcRotate
  1020. =
  1021. =====================
  1022. */
  1023.  
  1024. int    CalcRotate (objtype *ob)
  1025. {
  1026.     int    angle,viewangle;
  1027.  
  1028.     // this isn't exactly correct, as it should vary by a trig value,
  1029.     // but it is close enough with only eight rotations
  1030.  
  1031.     viewangle = player->angle + (centerx - ob->viewx)/8;
  1032.  
  1033.     if (ob->obclass == rocketobj || ob->obclass == hrocketobj)
  1034.         angle =  (viewangle-180)- ob->angle;
  1035.     else
  1036.         angle =  (viewangle-180)- dirangle[ob->dir];
  1037.  
  1038.     angle+=ANGLES/16;
  1039.     while (angle>=ANGLES)
  1040.         angle-=ANGLES;
  1041.     while (angle<0)
  1042.         angle+=ANGLES;
  1043.  
  1044.     if (ob->state->rotate == 2)             // 2 rotation pain frame
  1045.         return 4*(angle/(ANGLES/2));        // seperated by 3 (art layout...)
  1046.  
  1047.     return angle/(ANGLES/8);
  1048. }
  1049.  
  1050.  
  1051. /*
  1052. =====================
  1053. =
  1054. = DrawScaleds
  1055. =
  1056. = Draws all objects that are visable
  1057. =
  1058. =====================
  1059. */
  1060.  
  1061. #define MAXVISABLE    50
  1062.  
  1063. typedef struct
  1064. {
  1065.     int    viewx,
  1066.         viewheight,
  1067.         shapenum;
  1068. } visobj_t;
  1069.  
  1070. visobj_t    vislist[MAXVISABLE],*visptr,*visstep,*farthest;
  1071.  
  1072. void DrawScaleds (void)
  1073. {
  1074.     int         i,j,least,numvisable,height;
  1075.     memptr        shape;
  1076.     byte        *tilespot,*visspot;
  1077.     int            shapenum;
  1078.     unsigned    spotloc;
  1079.  
  1080.     statobj_t    *statptr;
  1081.     objtype        *obj;
  1082.  
  1083.     visptr = &vislist[0];
  1084.  
  1085. //
  1086. // place static objects
  1087. //
  1088.     for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++)
  1089.     {
  1090.         if ((visptr->shapenum = statptr->shapenum) == -1)
  1091.             continue;                        // object has been deleted
  1092.  
  1093.         if (!*statptr->visspot)
  1094.             continue;                        // not visable
  1095.  
  1096.         if (TransformTile (statptr->tilex,statptr->tiley
  1097.             ,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS)
  1098.         {
  1099.             GetBonus (statptr);
  1100.             continue;
  1101.         }
  1102.  
  1103.         if (!visptr->viewheight)
  1104.             continue;                        // to close to the object
  1105.  
  1106.         if (visptr < &vislist[MAXVISABLE-1])    // don't let it overflow
  1107.             visptr++;
  1108.     }
  1109.  
  1110. //
  1111. // place active objects
  1112. //
  1113.     for (obj = player->next;obj;obj=obj->next)
  1114.     {
  1115.         if (!(visptr->shapenum = obj->state->shapenum))
  1116.             continue;                        // no shape
  1117.  
  1118.         spotloc = (obj->tilex<<6)+obj->tiley;    // optimize: keep in struct?
  1119.         visspot = &spotvis[0][0]+spotloc;
  1120.         tilespot = &tilemap[0][0]+spotloc;
  1121.  
  1122.         //
  1123.         // could be in any of the nine surrounding tiles
  1124.         //
  1125.         if (*visspot
  1126.         || ( *(visspot-1) && !*(tilespot-1) )
  1127.         || ( *(visspot+1) && !*(tilespot+1) )
  1128.         || ( *(visspot-65) && !*(tilespot-65) )
  1129.         || ( *(visspot-64) && !*(tilespot-64) )
  1130.         || ( *(visspot-63) && !*(tilespot-63) )
  1131.         || ( *(visspot+65) && !*(tilespot+65) )
  1132.         || ( *(visspot+64) && !*(tilespot+64) )
  1133.         || ( *(visspot+63) && !*(tilespot+63) ) )
  1134.         {
  1135.             obj->active = true;
  1136.             TransformActor (obj);
  1137.             if (!obj->viewheight)
  1138.                 continue;                        // too close or far away
  1139.  
  1140.             visptr->viewx = obj->viewx;
  1141.             visptr->viewheight = obj->viewheight;
  1142.             if (visptr->shapenum == -1)
  1143.                 visptr->shapenum = obj->temp1;    // special shape
  1144.  
  1145.             if (obj->state->rotate)
  1146.                 visptr->shapenum += CalcRotate (obj);
  1147.  
  1148.             if (visptr < &vislist[MAXVISABLE-1])    // don't let it overflow
  1149.                 visptr++;
  1150.             obj->flags |= FL_VISABLE;
  1151.         }
  1152.         else
  1153.             obj->flags &= ~FL_VISABLE;
  1154.     }
  1155.  
  1156. //
  1157. // draw from back to front
  1158. //
  1159.     numvisable = visptr-&vislist[0];
  1160.  
  1161.     if (!numvisable)
  1162.         return;                                    // no visable objects
  1163.  
  1164.     for (i = 0; i<numvisable; i++)
  1165.     {
  1166.         least = 32000;
  1167.         for (visstep=&vislist[0] ; visstep<visptr ; visstep++)
  1168.         {
  1169.             height = visstep->viewheight;
  1170.             if (height < least)
  1171.             {
  1172.                 least = height;
  1173.                 farthest = visstep;
  1174.             }
  1175.         }
  1176.         //
  1177.         // draw farthest
  1178.         //
  1179.         ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight);
  1180.  
  1181.         farthest->viewheight = 32000;
  1182.     }
  1183.  
  1184. }
  1185.  
  1186. //==========================================================================
  1187.  
  1188. /*
  1189. ==============
  1190. =
  1191. = DrawPlayerWeapon
  1192. =
  1193. = Draw the player's hands
  1194. =
  1195. ==============
  1196. */
  1197.  
  1198. int    weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY
  1199.     ,SPR_MACHINEGUNREADY,SPR_CHAINREADY};
  1200.  
  1201. void DrawPlayerWeapon (void)
  1202. {
  1203.     int    shapenum;
  1204.  
  1205. #ifndef SPEAR
  1206.     if (gamestate.victoryflag)
  1207.     {
  1208.         if (player->state == &s_deathcam && (TimeCount&32) )
  1209.             SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1);
  1210.         return;
  1211.     }
  1212. #endif
  1213.  
  1214.     if (gamestate.weapon != -1)
  1215.     {
  1216.         shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe;
  1217.         SimpleScaleShape(viewwidth/2,shapenum,viewheight+1);
  1218.     }
  1219.  
  1220.     if (demorecord || demoplayback)
  1221.         SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1);
  1222. }
  1223.  
  1224.  
  1225. //==========================================================================
  1226.  
  1227.  
  1228. /*
  1229. =====================
  1230. =
  1231. = CalcTics
  1232. =
  1233. =====================
  1234. */
  1235.  
  1236. void CalcTics (void)
  1237. {
  1238.     long    newtime,oldtimecount;
  1239.  
  1240. //
  1241. // calculate tics since last refresh for adaptive timing
  1242. //
  1243.     if (lasttimecount > TimeCount)
  1244.         TimeCount = lasttimecount;        // if the game was paused a LONG time
  1245.  
  1246.     do
  1247.     {
  1248.         newtime = TimeCount;
  1249.         tics = newtime-lasttimecount;
  1250.     } while (!tics);            // make sure at least one tic passes
  1251.  
  1252.     lasttimecount = newtime;
  1253.  
  1254. #ifdef FILEPROFILE
  1255.         strcpy (scratch,"\tTics:");
  1256.         itoa (tics,str,10);
  1257.         strcat (scratch,str);
  1258.         strcat (scratch,"\n");
  1259.         write (profilehandle,scratch,strlen(scratch));
  1260. #endif
  1261.  
  1262.     if (tics>MAXTICS)
  1263.     {
  1264.         TimeCount -= (tics-MAXTICS);
  1265.         tics = MAXTICS;
  1266.     }
  1267. }
  1268.  
  1269.  
  1270. //==========================================================================
  1271.  
  1272.  
  1273. /*
  1274. ========================
  1275. =
  1276. = FixOfs
  1277. =
  1278. ========================
  1279. */
  1280.  
  1281. void    FixOfs (void)
  1282. {
  1283.     VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight);
  1284. }
  1285.  
  1286.  
  1287. //==========================================================================
  1288.  
  1289.  
  1290. /*
  1291. ====================
  1292. =
  1293. = WallRefresh
  1294. =
  1295. ====================
  1296. */
  1297.  
  1298. void WallRefresh (void)
  1299. {
  1300. //
  1301. // set up variables for this view
  1302. //
  1303.     viewangle = player->angle;
  1304.     midangle = viewangle*(FINEANGLES/ANGLES);
  1305.     viewsin = sintable[viewangle];
  1306.     viewcos = costable[viewangle];
  1307.     viewx = player->x - FixedByFrac(focallength,viewcos);
  1308.     viewy = player->y + FixedByFrac(focallength,viewsin);
  1309.  
  1310.     focaltx = viewx>>TILESHIFT;
  1311.     focalty = viewy>>TILESHIFT;
  1312.  
  1313.     viewtx = player->x >> TILESHIFT;
  1314.     viewty = player->y >> TILESHIFT;
  1315.  
  1316.     xpartialdown = viewx&(TILEGLOBAL-1);
  1317.     xpartialup = TILEGLOBAL-xpartialdown;
  1318.     ypartialdown = viewy&(TILEGLOBAL-1);
  1319.     ypartialup = TILEGLOBAL-ypartialdown;
  1320.  
  1321.     lastside = -1;            // the first pixel is on a new wall
  1322.     AsmRefresh ();
  1323.     ScalePost ();            // no more optimization on last post
  1324. }
  1325.  
  1326. //==========================================================================
  1327.  
  1328. /*
  1329. ========================
  1330. =
  1331. = ThreeDRefresh
  1332. =
  1333. ========================
  1334. */
  1335.  
  1336. void    ThreeDRefresh (void)
  1337. {
  1338.     int tracedir;
  1339.  
  1340. // this wouldn't need to be done except for my debugger/video wierdness
  1341.     outportb (SC_INDEX,SC_MAPMASK);
  1342.  
  1343. //
  1344. // clear out the traced array
  1345. //
  1346. asm    mov    ax,ds
  1347. asm    mov    es,ax
  1348. asm    mov    di,OFFSET spotvis
  1349. asm    xor    ax,ax
  1350. asm    mov    cx,2048                            // 64*64 / 2
  1351. asm    rep stosw
  1352.  
  1353.     bufferofs += screenofs;
  1354.  
  1355. //
  1356. // follow the walls from there to the right, drawwing as we go
  1357. //
  1358.     VGAClearScreen ();
  1359.  
  1360.     WallRefresh ();
  1361.  
  1362. //
  1363. // draw all the scaled images
  1364. //
  1365.     DrawScaleds();            // draw scaled stuff
  1366.     DrawPlayerWeapon ();    // draw player's hands
  1367.  
  1368. //
  1369. // show screen and time last cycle
  1370. //
  1371.     if (fizzlein)
  1372.     {
  1373.         FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false);
  1374.         fizzlein = false;
  1375.  
  1376.         lasttimecount = TimeCount = 0;        // don't make a big tic count
  1377.  
  1378.     }
  1379.  
  1380.     bufferofs -= screenofs;
  1381.     displayofs = bufferofs;
  1382.  
  1383.     asm    cli
  1384.     asm    mov    cx,[displayofs]
  1385.     asm    mov    dx,3d4h        // CRTC address register
  1386.     asm    mov    al,0ch        // start address high register
  1387.     asm    out    dx,al
  1388.     asm    inc    dx
  1389.     asm    mov    al,ch
  1390.     asm    out    dx,al       // set the high byte
  1391.     asm    sti
  1392.  
  1393.     bufferofs += SCREENSIZE;
  1394.     if (bufferofs > PAGE3START)
  1395.         bufferofs = PAGE1START;
  1396.  
  1397.     frameon++;
  1398.     PM_NextFrame();
  1399. }
  1400.  
  1401.  
  1402. //===========================================================================
  1403.  
  1404.