OSDN Git Service

going to start wolf3d core core (loop with input only) work soon. I was mostly brains...
[proj16/16.git] / src / lib / hb / draw / c3_draw.c
1 /* Catacomb 3-D Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // C3_DRAW.C\r
20 \r
21 #include "C3_DEF.H"\r
22 #pragma hdrstop\r
23 \r
24 //#define DRAWEACH                              // draw walls one at a time for debugging\r
25 \r
26 unsigned        highest;\r
27 unsigned        mostwalls,numwalls;\r
28 \r
29 /*\r
30 =============================================================================\r
31 \r
32                                                  LOCAL CONSTANTS\r
33 \r
34 =============================================================================\r
35 */\r
36 \r
37 #define PI      3.141592657\r
38 #define ANGLEQUAD       (ANGLES/4)\r
39 \r
40 unsigned        oldend;\r
41 \r
42 #define FINEANGLES      3600\r
43 \r
44 #define MINRATIO        16\r
45 \r
46 \r
47 const   unsigned        MAXSCALEHEIGHT  = (VIEWWIDTH/2);\r
48 const   unsigned        MAXVISHEIGHT    = (VIEWHEIGHT/2);\r
49 const   unsigned        BASESCALE               = 32;\r
50 \r
51 /*\r
52 =============================================================================\r
53 \r
54                                                  GLOBAL VARIABLES\r
55 \r
56 =============================================================================\r
57 */\r
58 \r
59 //\r
60 // calculate location of screens in video memory so they have the\r
61 // maximum possible distance seperating them (for scaling overflow)\r
62 //\r
63 \r
64 unsigned screenloc[3]= {0x900,0x2000,0x3700};\r
65 unsigned freelatch = 0x4e00;\r
66 \r
67 boolean         fizzlein;\r
68 \r
69 long    scaleshapecalll;\r
70 long    scaletablecall;\r
71 \r
72 /*\r
73 =============================================================================\r
74 \r
75                                                  LOCAL VARIABLES\r
76 \r
77 =============================================================================\r
78 */\r
79 \r
80 long    bytecount,endcount;             // for profiling\r
81 int             animframe;\r
82 int             pixelangle[VIEWWIDTH];\r
83 int             far finetangent[FINEANGLES+1];\r
84 int             fineviewangle;\r
85 unsigned        viewxpix,viewypix;\r
86 \r
87 /*\r
88 ============================================================================\r
89 \r
90                            3 - D  DEFINITIONS\r
91 \r
92 ============================================================================\r
93 */\r
94 \r
95 fixed   tileglobal      = TILEGLOBAL;\r
96 fixed   focallength     = FOCALLENGTH;\r
97 fixed   mindist         = MINDIST;\r
98 int             viewheight      = VIEWHEIGHT;\r
99 fixed scale;\r
100 \r
101 \r
102 tilept  tile,lasttile,          // tile of wall being followed\r
103         focal,                  // focal point in tiles\r
104         left,mid,right;         // rightmost tile in view\r
105 \r
106 globpt edge,view;\r
107 \r
108 int     segstart[VIEWHEIGHT],   // addline tracks line segment and draws\r
109         segend[VIEWHEIGHT],\r
110         segcolor[VIEWHEIGHT];   // only when the color changes\r
111 \r
112 \r
113 walltype        walls[MAXWALLS],*leftwall,*rightwall;\r
114 \r
115 \r
116 //==========================================================================\r
117 \r
118 //\r
119 // refresh stuff\r
120 //\r
121 \r
122 int screenpage;\r
123 \r
124 long lasttimecount;\r
125 \r
126 //\r
127 // rendering stuff\r
128 //\r
129 \r
130 int firstangle,lastangle;\r
131 \r
132 fixed prestep;\r
133 \r
134 fixed sintable[ANGLES+ANGLES/4],*costable = sintable+(ANGLES/4);\r
135 \r
136 fixed   viewx,viewy;                    // the focal point\r
137 int     viewangle;\r
138 fixed   viewsin,viewcos;\r
139 \r
140 int     zbuffer[VIEWXH+1];      // holds the height of the wall at that point\r
141 \r
142 //==========================================================================\r
143 \r
144 void    DrawLine (int xl, int xh, int y,int color);\r
145 void    DrawWall (walltype *wallptr);\r
146 void    TraceRay (unsigned angle);\r
147 fixed   FixedByFrac (fixed a, fixed b);\r
148 fixed   FixedAdd (void);\r
149 fixed   TransformX (fixed gx, fixed gy);\r
150 int             FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max);\r
151 int             BackTrace (int finish);\r
152 void    ForwardTrace (void);\r
153 int             TurnClockwise (void);\r
154 int             TurnCounterClockwise (void);\r
155 void    FollowWall (void);\r
156 \r
157 void    NewScene (void);\r
158 void    BuildTables (void);\r
159 \r
160 //==========================================================================\r
161 \r
162 \r
163 /*\r
164 ==================\r
165 =\r
166 = DrawLine\r
167 =\r
168 = Must be in write mode 2 with all planes enabled\r
169 = The bit mask is left set to the end value, so clear it after all lines are\r
170 = drawn\r
171 =\r
172 = draws a black dot at the left edge of the line\r
173 =\r
174 ==================\r
175 */\r
176 \r
177 unsigned static char dotmask[8] = {0x80,0x40,0x20,0x10,8,4,2,1};\r
178 unsigned static char leftmask[8] = {0xff,0x7f,0x3f,0x1f,0xf,7,3,1};\r
179 unsigned static char rightmask[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};\r
180 \r
181 void DrawLine (int xl, int xh, int y,int color)\r
182 {\r
183   unsigned dest,xlp,xlb,xhb,maskleft,maskright,maskdot,mid;\r
184 \r
185   xlb=xl/8;\r
186   xhb=xh/8;\r
187 \r
188   if (xh<xl)\r
189         Quit("DrawLine: xh<xl");\r
190   if (y<VIEWY)\r
191         Quit("DrawLine: y<VIEWY");\r
192   if (y>VIEWYH)\r
193         Quit("DrawLine: y>VIEWYH");\r
194 \r
195         xlp = xl&7;\r
196         maskleft = leftmask[xlp];\r
197         maskright = rightmask[xh&7];\r
198 \r
199   mid = xhb-xlb-1;\r
200   dest = bufferofs+ylookup[y]+xlb;\r
201 \r
202         //\r
203         // set the GC index register to point to the bit mask register\r
204         //\r
205         asm     mov     al,GC_BITMASK\r
206         asm     mov     dx,GC_INDEX\r
207         asm     out     dx,al\r
208 \r
209   if (xlb==xhb)\r
210   {\r
211   //\r
212   // entire line is in one byte\r
213   //\r
214 \r
215         maskleft&=maskright;\r
216 \r
217         asm     mov     es,[screenseg]\r
218         asm     mov     di,[dest]\r
219         asm     mov     dx,GC_INDEX+1\r
220 \r
221         asm     mov     al,[BYTE PTR maskleft]\r
222         asm     out     dx,al           // mask off pixels\r
223 \r
224         asm     mov     al,[BYTE PTR color]\r
225         asm     xchg    al,[es:di]      // load latches and write pixels\r
226 \r
227         return;\r
228   }\r
229 \r
230 asm     mov     es,[screenseg]\r
231 asm     mov     di,[dest]\r
232 asm     mov     dx,GC_INDEX+1\r
233 asm     mov     bh,[BYTE PTR color]\r
234 \r
235 //\r
236 // draw left side\r
237 //\r
238 asm     mov     al,[BYTE PTR maskleft]\r
239 asm     out     dx,al           // mask off pixels\r
240 \r
241 asm     mov     al,bh\r
242 asm     xchg    al,[es:di]      // load latches and write pixels\r
243 asm     inc     di\r
244 \r
245 //\r
246 // draw middle\r
247 //\r
248 asm     mov     al,255\r
249 asm     out     dx,al           // no masking\r
250 \r
251 asm     mov     al,bh\r
252 asm     mov     cx,[mid]\r
253 asm     rep     stosb\r
254 \r
255 //\r
256 // draw right side\r
257 //\r
258 asm     mov     al,[BYTE PTR maskright]\r
259 asm     out     dx,al           // mask off pixels\r
260 asm     xchg    bh,[es:di]      // load latches and write pixels\r
261 \r
262 }\r
263 \r
264 //==========================================================================\r
265 \r
266 void DrawLineDot (int xl, int xh, int y,int color)\r
267 {\r
268   unsigned dest,xlp,xlb,xhb,maskleft,maskright,maskdot,mid;\r
269 \r
270   xlb=xl/8;\r
271   xhb=xh/8;\r
272 \r
273   if (xh<xl)\r
274         Quit("DrawLine: xh<xl");\r
275   if (y<VIEWY)\r
276         Quit("DrawLine: y<VIEWY");\r
277   if (y>VIEWYH)\r
278         Quit("DrawLine: y>VIEWYH");\r
279 \r
280         xlp = xl&7;\r
281         maskdot = dotmask[xlp];\r
282         maskleft = leftmask[xlp];\r
283         maskright = rightmask[xh&7];\r
284 \r
285   mid = xhb-xlb-1;\r
286   dest = bufferofs+ylookup[y]+xlb;\r
287 \r
288         //\r
289         // set the GC index register to point to the bit mask register\r
290         //\r
291         asm     mov     al,GC_BITMASK\r
292         asm     mov     dx,GC_INDEX\r
293         asm     out     dx,al\r
294 \r
295   if (xlb==xhb)\r
296   {\r
297   //\r
298   // entire line is in one byte\r
299   //\r
300 \r
301         maskleft&=maskright;\r
302 \r
303         asm     mov     es,[screenseg]\r
304         asm     mov     di,[dest]\r
305         asm     mov     dx,GC_INDEX+1\r
306 \r
307         asm     mov     al,[BYTE PTR maskleft]\r
308         asm     out     dx,al           // mask off pixels\r
309 \r
310         asm     mov     al,[BYTE PTR color]\r
311         asm     xchg    al,[es:di]      // load latches and write pixels\r
312 \r
313 \r
314         //\r
315         // write the black dot at the start\r
316         //\r
317         asm     mov     al,[BYTE PTR maskdot]\r
318         asm     out     dx,al           // mask off pixels\r
319 \r
320         asm     xor     al,al\r
321         asm     xchg    al,[es:di]      // load latches and write pixels\r
322 \r
323 \r
324         return;\r
325   }\r
326 \r
327 asm     mov     es,[screenseg]\r
328 asm     mov     di,[dest]\r
329 asm     mov     dx,GC_INDEX+1\r
330 asm     mov     bh,[BYTE PTR color]\r
331 \r
332 //\r
333 // draw left side\r
334 //\r
335 asm     mov     al,[BYTE PTR maskleft]\r
336 asm     out     dx,al           // mask off pixels\r
337 \r
338 asm     mov     al,bh\r
339 asm     xchg    al,[es:di]      // load latches and write pixels\r
340 \r
341 //\r
342 // write the black dot at the start\r
343 //\r
344 asm     mov     al,[BYTE PTR maskdot]\r
345 asm     out     dx,al           // mask off pixels\r
346 asm     xor     al,al\r
347 asm     xchg    al,[es:di]      // load latches and write pixels\r
348 asm     inc     di\r
349 \r
350 //\r
351 // draw middle\r
352 //\r
353 asm     mov     al,255\r
354 asm     out     dx,al           // no masking\r
355 \r
356 asm     mov     al,bh\r
357 asm     mov     cx,[mid]\r
358 asm     rep     stosb\r
359 \r
360 //\r
361 // draw right side\r
362 //\r
363 asm     mov     al,[BYTE PTR maskright]\r
364 asm     out     dx,al           // mask off pixels\r
365 asm     xchg    bh,[es:di]      // load latches and write pixels\r
366 \r
367 }\r
368 \r
369 //==========================================================================\r
370 \r
371 \r
372 long            wallscalesource;\r
373 \r
374 #ifdef DRAWEACH\r
375 /*\r
376 ====================\r
377 =\r
378 = ScaleOneWall\r
379 =\r
380 ====================\r
381 */\r
382 \r
383 void near ScaleOneWall (int xl, int xh)\r
384 {\r
385         int     x,pixwidth,height;\r
386 \r
387         *(((unsigned *)&wallscalesource)+1) = wallseg[xl];\r
388 \r
389         for (x=xl;x<=xh;x+=pixwidth)\r
390         {\r
391                 height = wallheight[x];\r
392                 pixwidth = wallwidth[x];\r
393                 (unsigned)wallscalesource = wallofs[x];\r
394 \r
395                 *(((unsigned *)&scaletablecall)+1) = (unsigned)scaledirectory[height];\r
396                 (unsigned)scaletablecall = scaledirectory[height]->codeofs[0];\r
397 \r
398                 //\r
399                 // scale a byte wide strip of wall\r
400                 //\r
401                 asm     mov     bx,[x]\r
402                 asm     mov     di,bx\r
403                 asm     shr     di,1\r
404                 asm     shr     di,1\r
405                 asm     shr     di,1                                            // X in bytes\r
406                 asm     add     di,[bufferofs]\r
407                 asm     and     bx,7\r
408                 asm     shl     bx,1\r
409                 asm     shl     bx,1\r
410                 asm     shl     bx,1\r
411                 asm     add     bx,[pixwidth]                           // bx = pixel*8+pixwidth-1\r
412                 asm     dec     bx\r
413                 asm     mov     al,BYTE PTR [bitmasks1+bx]\r
414                 asm     mov     dx,GC_INDEX+1\r
415                 asm     out     dx,al                                           // set bit mask register\r
416                 asm     mov     es,[screenseg]\r
417                 asm     lds     si,[wallscalesource]\r
418                 asm     call [DWORD PTR ss:scaletablecall]              // scale the line of pixels\r
419 \r
420                 asm     mov     al,BYTE PTR [ss:bitmasks2+bx]\r
421                 asm     or      al,al\r
422                 asm     jz      nosecond\r
423 \r
424                 //\r
425                 // draw a second byte for vertical strips that cross two bytes\r
426                 //\r
427                 asm     inc     di\r
428                 asm     out     dx,al                                           // set bit mask register\r
429                 asm     call [DWORD PTR ss:scaletablecall]      // scale the line of pixels\r
430         nosecond:\r
431                 asm     mov     ax,ss\r
432                 asm     mov     ds,ax\r
433         }\r
434 }\r
435 \r
436 #endif\r
437 \r
438 int     walllight1[NUMFLOORS] = {0,\r
439         WALL1LPIC,WALL2LPIC,WALL3LPIC,WALL4LPIC,WALL5LPIC,WALL6LPIC,WALL7LPIC,\r
440         WALL1LPIC,WALL2LPIC,WALL3LPIC,WALL4LPIC,WALL5LPIC,WALL6LPIC,WALL7LPIC,\r
441         EXPWALL1PIC,EXPWALL2PIC,EXPWALL3PIC,\r
442         RDOOR1PIC,RDOOR2PIC,RDOOR1PIC,RDOOR2PIC,\r
443         YDOOR1PIC,YDOOR2PIC,YDOOR1PIC,YDOOR2PIC,\r
444         GDOOR1PIC,GDOOR2PIC,GDOOR1PIC,GDOOR2PIC,\r
445         BDOOR1PIC,BDOOR2PIC,BDOOR1PIC,BDOOR2PIC};\r
446 \r
447 int     walldark1[NUMFLOORS] = {0,\r
448         WALL1DPIC,WALL2DPIC,WALL3DPIC,WALL4DPIC,WALL5DPIC,WALL6DPIC,WALL7DPIC,\r
449         WALL1DPIC,WALL2DPIC,WALL3DPIC,WALL4DPIC,WALL5DPIC,WALL6DPIC,WALL7DPIC,\r
450         EXPWALL1PIC,EXPWALL2PIC,EXPWALL3PIC,\r
451         RDOOR1PIC,RDOOR2PIC,RDOOR1PIC,RDOOR2PIC,\r
452         YDOOR1PIC,YDOOR2PIC,YDOOR1PIC,YDOOR2PIC,\r
453         GDOOR1PIC,GDOOR2PIC,GDOOR1PIC,GDOOR2PIC,\r
454         BDOOR1PIC,BDOOR2PIC,BDOOR1PIC,BDOOR2PIC};\r
455 \r
456 int     walllight2[NUMFLOORS] = {0,\r
457         WALL1LPIC,WALL2LPIC,WALL3LPIC,WALL4LPIC,WALL5LPIC,WALL6LPIC,WALL7LPIC,\r
458         WALL1LPIC,WALL2LPIC,WALL3LPIC,WALL4LPIC,WALL5LPIC,WALL6LPIC,WALL7LPIC,\r
459         EXPWALL1PIC,EXPWALL2PIC,EXPWALL3PIC,\r
460         RDOOR2PIC,RDOOR1PIC,RDOOR2PIC,RDOOR1PIC,\r
461         YDOOR2PIC,YDOOR1PIC,YDOOR2PIC,YDOOR1PIC,\r
462         GDOOR2PIC,GDOOR1PIC,GDOOR2PIC,GDOOR1PIC,\r
463         BDOOR2PIC,BDOOR1PIC,BDOOR2PIC,BDOOR1PIC};\r
464 \r
465 int     walldark2[NUMFLOORS] = {0,\r
466         WALL1DPIC,WALL2DPIC,WALL3DPIC,WALL4DPIC,WALL5DPIC,WALL6DPIC,WALL7DPIC,\r
467         WALL1DPIC,WALL2DPIC,WALL3DPIC,WALL4DPIC,WALL5DPIC,WALL6DPIC,WALL7DPIC,\r
468         EXPWALL1PIC,EXPWALL2PIC,EXPWALL3PIC,\r
469         RDOOR2PIC,RDOOR1PIC,RDOOR2PIC,RDOOR1PIC,\r
470         YDOOR2PIC,YDOOR1PIC,YDOOR2PIC,YDOOR1PIC,\r
471         GDOOR2PIC,GDOOR1PIC,GDOOR2PIC,GDOOR1PIC,\r
472         BDOOR2PIC,BDOOR1PIC,BDOOR2PIC,BDOOR1PIC};\r
473 \r
474 /*\r
475 =====================\r
476 =\r
477 = DrawVWall\r
478 =\r
479 = Draws a wall by vertical segments, for texture mapping!\r
480 =\r
481 = wallptr->side is true for east/west walls (constant x)\r
482 =\r
483 = fracheight and fracstep are 16.16 bit fractions\r
484 =\r
485 =====================\r
486 */\r
487 \r
488 void DrawVWall (walltype *wallptr)\r
489 {\r
490         int                     x,i;\r
491         unsigned        source;\r
492         unsigned        width,sourceint;\r
493         unsigned        wallpic,wallpicseg;\r
494         unsigned        skip;\r
495         long            fracheight,fracstep,longheightchange;\r
496         unsigned        height;\r
497         int                     heightchange;\r
498         unsigned        slope,distance;\r
499         int                     traceangle,angle;\r
500         int                     mapadd;\r
501         unsigned        lastpix,lastsource,lastwidth;\r
502 \r
503 \r
504         if (wallptr->rightclip < wallptr->leftclip)\r
505                 Quit ("DrawVWall: Right < Left");\r
506 \r
507 //\r
508 // setup for height calculation\r
509 //\r
510         wallptr->height1 >>= 1;\r
511         wallptr->height2 >>= 1;\r
512         wallptr->planecoord>>=10;                       // remove non significant bits\r
513 \r
514         width = wallptr->x2 - wallptr->x1;\r
515         if (width)\r
516         {\r
517                 heightchange = wallptr->height2 - wallptr->height1;\r
518                 asm     mov     ax,[heightchange]\r
519                 asm     mov     WORD PTR [longheightchange+2],ax\r
520                 asm     mov     WORD PTR [longheightchange],0   // avoid long shift by 16\r
521                 fracstep = longheightchange/width;\r
522         }\r
523 \r
524         fracheight = ((long)wallptr->height1<<16)+0x8000;\r
525         skip = wallptr->leftclip - wallptr->x1;\r
526         if (skip)\r
527                 fracheight += fracstep*skip;\r
528 \r
529 //\r
530 // setup for texture mapping\r
531 //\r
532 // mapadd is 64*64 (to keep source positive) + the origin wall intercept\r
533 // distance has 6 unit bits, and 6 frac bits\r
534 // traceangle is the center view angle in FINEANGLES, moved to be in\r
535 // the +-90 degree range (to thew right of origin)\r
536 //\r
537         traceangle = fineviewangle;\r
538         //\r
539         // find wall picture to map from\r
540         //\r
541         if (wallptr->side)\r
542         {       // east or west wall\r
543                 if (animframe)\r
544                         wallpic = walllight2[wallptr->color];\r
545                 else\r
546                         wallpic = walllight1[wallptr->color];\r
547 \r
548                 if (wallptr->planecoord < viewxpix)\r
549                 {\r
550                         distance = viewxpix-wallptr->planecoord;\r
551                         traceangle -= FINEANGLES/2;\r
552                         mapadd = (64-viewypix&63);              // the pixel spot of the origin\r
553                 }\r
554                 else\r
555                 {\r
556                         distance = wallptr->planecoord-viewxpix;\r
557                         // traceangle is correct\r
558                         mapadd = viewypix&63;           // the pixel spot of the origin\r
559                 }\r
560         }\r
561         else\r
562         {       // north or south wall\r
563                 if (animframe)\r
564                         wallpic = walldark2[wallptr->color];\r
565                 else\r
566                         wallpic = walldark1[wallptr->color];\r
567 \r
568                 if (wallptr->planecoord < viewypix)\r
569                 {\r
570                         distance = viewypix-wallptr->planecoord;\r
571                         traceangle -= FINEANGLES/4;\r
572                         mapadd = viewxpix&63;           // the pixel spot of the origin\r
573                 }\r
574                 else\r
575                 {\r
576                         distance = wallptr->planecoord-viewypix;\r
577                         traceangle -= FINEANGLES*3/4;\r
578                         mapadd = (64-viewxpix&63);              // the pixel spot of the origin\r
579                 }\r
580         }\r
581 \r
582         mapadd = 64*64-mapadd;                          // make sure it stays positive\r
583 \r
584         wallpicseg = (unsigned)walldirectory[wallpic-FIRSTWALLPIC];\r
585         if (traceangle > FINEANGLES/2)\r
586                 traceangle -= FINEANGLES;\r
587 \r
588 //\r
589 // calculate everything\r
590 //\r
591 // IMPORTANT!  This loop is executed around 5000 times / second!\r
592 //\r
593         lastpix = lastsource = (unsigned)-1;\r
594 \r
595         for (x = wallptr->leftclip ; x <= wallptr->rightclip ; x++)\r
596         {\r
597                 //\r
598                 // height\r
599                 //\r
600                 asm     mov     ax,WORD PTR [fracheight]\r
601                 asm     mov     dx,WORD PTR [fracheight+2]\r
602                 asm     mov     cx,dx\r
603                 asm     add     ax,WORD PTR [fracstep]\r
604                 asm     adc     dx,WORD PTR [fracstep+2]\r
605                 asm     mov     WORD PTR [fracheight],ax\r
606                 asm     mov     WORD PTR [fracheight+2],dx\r
607                 asm     mov     bx,[x]\r
608                 asm     shl     bx,1\r
609                 asm     cmp     cx,MAXSCALEHEIGHT\r
610                 asm     jbe     storeheight\r
611                 asm     mov     cx,MAXSCALEHEIGHT\r
612 storeheight:\r
613                 asm     mov WORD PTR [wallheight+bx],cx\r
614                 asm     mov WORD PTR [zbuffer+bx],cx\r
615 \r
616 //              height = fracheight>>16;\r
617 //              fracheight += fracstep;\r
618 //              if (height > MAXSCALEHEIGHT)\r
619 //                      height = MAXSCALEHEIGHT;\r
620 //              wallheight[x] = zbuffer[x] = height;\r
621 \r
622                 //\r
623                 // texture map\r
624                 //\r
625                 angle = pixelangle[x]+traceangle;\r
626                 if (angle<0)\r
627                         angle+=FINEANGLES;\r
628 \r
629                 slope = finetangent[angle];\r
630 \r
631 //\r
632 // distance is an unsigned 6.6 bit number (12 pixel bits)\r
633 // slope is a signed 5.10 bit number\r
634 // result is a signed 11.16 bit number\r
635 //\r
636 \r
637 #if 0\r
638                 source = distance*slope;\r
639                 source >>=20;\r
640 \r
641                 source += mapadd;\r
642                 source &= 63;                           // mask off the unused units\r
643                 source = 63-source;\r
644                 source <<= 6;                           // multiply by 64 for offset into pic\r
645 #endif\r
646                 asm     mov     ax,[distance]\r
647                 asm     imul    [slope]                 // ax is the source pixel\r
648                 asm     mov     al,ah\r
649                 asm     shr     al,1\r
650                 asm     shr     al,1                            // low 6 bits is now pixel number\r
651                 asm     add     ax,[mapadd]\r
652                 asm     and ax,63\r
653                 asm     mov     dx,63\r
654                 asm     sub     dx,ax                           // otherwise it is backwards\r
655                 asm     shl     dx,1\r
656                 asm     shl     dx,1\r
657                 asm     shl     dx,1\r
658                 asm     shl     dx,1\r
659                 asm     shl     dx,1\r
660                 asm     shl     dx,1                            // *64 to index into shape\r
661                 asm     mov     [source],dx\r
662 \r
663                 if (source != lastsource)\r
664                 {\r
665                         if (lastpix != (unsigned)-1)\r
666                         {\r
667                                 wallofs[lastpix] = lastsource;\r
668                                 wallseg[lastpix] = wallpicseg;\r
669                                 wallwidth[lastpix] = lastwidth;\r
670                         }\r
671                         lastpix = x;\r
672                         lastsource = source;\r
673                         lastwidth = 1;\r
674                 }\r
675                 else\r
676                         lastwidth++;                    // optimized draw, same map as last one\r
677         }\r
678         wallofs[lastpix] = lastsource;\r
679         wallseg[lastpix] = wallpicseg;\r
680         wallwidth[lastpix] = lastwidth;\r
681 }\r
682 \r
683 \r
684 //==========================================================================\r
685 \r
686 \r
687 /*\r
688 =================\r
689 =\r
690 = TraceRay\r
691 =\r
692 = Used to find the left and rightmost tile in the view area to be traced from\r
693 = Follows a ray of the given angle from viewx,viewy in the global map until\r
694 = it hits a solid tile\r
695 = sets:\r
696 =   tile.x,tile.y       : tile coordinates of contacted tile\r
697 =   tilecolor   : solid tile's color\r
698 =\r
699 ==================\r
700 */\r
701 \r
702 int tilecolor;\r
703 \r
704 void TraceRay (unsigned angle)\r
705 {\r
706   long tracex,tracey,tracexstep,traceystep,searchx,searchy;\r
707   fixed fixtemp;\r
708   int otx,oty,searchsteps;\r
709 \r
710   tracexstep = costable[angle];\r
711   traceystep = sintable[angle];\r
712 \r
713 //\r
714 // advance point so it is even with the view plane before we start checking\r
715 //\r
716   fixtemp = FixedByFrac(prestep,tracexstep);\r
717   tracex = viewx+fixtemp;\r
718   fixtemp = FixedByFrac(prestep,traceystep);\r
719   tracey = viewy-fixtemp;\r
720 \r
721   tile.x = tracex>>TILESHIFT;   // starting point in tiles\r
722   tile.y = tracey>>TILESHIFT;\r
723 \r
724 \r
725   if (tracexstep<0)                     // use 2's complement, not signed magnitude\r
726         tracexstep = -(tracexstep&0x7fffffff);\r
727 \r
728   if (traceystep<0)                     // use 2's complement, not signed magnitude\r
729         traceystep = -(traceystep&0x7fffffff);\r
730 \r
731 //\r
732 // we assume viewx,viewy is not inside a solid tile, so go ahead one step\r
733 //\r
734 \r
735   do    // until a solid tile is hit\r
736   {\r
737     otx = tile.x;\r
738         oty = tile.y;\r
739         spotvis[otx][oty] = true;\r
740         tracex += tracexstep;\r
741     tracey -= traceystep;\r
742     tile.x = tracex>>TILESHIFT;\r
743         tile.y = tracey>>TILESHIFT;\r
744 \r
745         if (tile.x!=otx && tile.y!=oty && (tilemap[otx][tile.y] || tilemap[tile.x][oty]) )\r
746     {\r
747       //\r
748           // trace crossed two solid tiles, so do a binary search along the line\r
749           // to find a spot where only one tile edge is crossed\r
750       //\r
751       searchsteps = 0;\r
752       searchx = tracexstep;\r
753       searchy = traceystep;\r
754       do\r
755       {\r
756         searchx/=2;\r
757         searchy/=2;\r
758         if (tile.x!=otx && tile.y!=oty)\r
759         {\r
760          // still too far\r
761           tracex -= searchx;\r
762           tracey += searchy;\r
763         }\r
764         else\r
765         {\r
766          // not far enough, no tiles crossed\r
767           tracex += searchx;\r
768           tracey -= searchy;\r
769         }\r
770 \r
771         //\r
772         // if it is REAL close, go for the most clockwise intersection\r
773         //\r
774         if (++searchsteps == 16)\r
775         {\r
776           tracex = (long)otx<<TILESHIFT;\r
777           tracey = (long)oty<<TILESHIFT;\r
778           if (tracexstep>0)\r
779           {\r
780                 if (traceystep<0)\r
781                 {\r
782                   tracex += TILEGLOBAL-1;\r
783                   tracey += TILEGLOBAL;\r
784                 }\r
785                 else\r
786                 {\r
787                   tracex += TILEGLOBAL;\r
788                 }\r
789           }\r
790           else\r
791           {\r
792                 if (traceystep<0)\r
793                 {\r
794                   tracex --;\r
795                   tracey += TILEGLOBAL-1;\r
796                 }\r
797                 else\r
798                 {\r
799                   tracey --;\r
800                 }\r
801           }\r
802         }\r
803 \r
804         tile.x = tracex>>TILESHIFT;\r
805         tile.y = tracey>>TILESHIFT;\r
806 \r
807           } while (( tile.x!=otx && tile.y!=oty) || (tile.x==otx && tile.y==oty) );\r
808         }\r
809   } while (!(tilecolor = tilemap[tile.x][tile.y]) );\r
810 \r
811 }\r
812 \r
813 //==========================================================================\r
814 \r
815 \r
816 /*\r
817 ========================\r
818 =\r
819 = FixedByFrac\r
820 =\r
821 = multiply a 16/16 bit, 2's complement fixed point number by a 16 bit\r
822 = fraction, passed as a signed magnitude 32 bit number\r
823 =\r
824 ========================\r
825 */\r
826 \r
827 #pragma warn -rvl                       // I stick the return value in with ASMs\r
828 \r
829 fixed FixedByFrac (fixed a, fixed b)\r
830 {\r
831   fixed value;\r
832 \r
833 //\r
834 // setup\r
835 //\r
836 asm     mov     si,[WORD PTR b+2]       // sign of result = sign of fraction\r
837 \r
838 asm     mov     ax,[WORD PTR a]\r
839 asm     mov     cx,[WORD PTR a+2]\r
840 \r
841 asm     or      cx,cx\r
842 asm     jns     aok:                            // negative?\r
843 asm     not     ax\r
844 asm     not     cx\r
845 asm     add     ax,1\r
846 asm     adc     cx,0\r
847 asm     xor     si,0x8000                       // toggle sign of result\r
848 aok:\r
849 \r
850 //\r
851 // multiply  cx:ax by bx\r
852 //\r
853 asm     mov     bx,[WORD PTR b]\r
854 asm     mul     bx                                      // fraction*fraction\r
855 asm     mov     di,dx                           // di is low word of result\r
856 asm     mov     ax,cx                           //\r
857 asm     mul     bx                                      // units*fraction\r
858 asm add ax,di\r
859 asm     adc     dx,0\r
860 \r
861 //\r
862 // put result dx:ax in 2's complement\r
863 //\r
864 asm     test    si,0x8000               // is the result negative?\r
865 asm     jz      ansok:\r
866 asm     not     ax\r
867 asm     not     dx\r
868 asm     add     ax,1\r
869 asm     adc     dx,0\r
870 \r
871 ansok:;\r
872 \r
873 }\r
874 \r
875 #pragma warn +rvl\r
876 \r
877 //==========================================================================\r
878 \r
879 \r
880 /*\r
881 ========================\r
882 =\r
883 = TransformPoint\r
884 =\r
885 = Takes paramaters:\r
886 =   gx,gy               : globalx/globaly of point\r
887 =\r
888 = globals:\r
889 =   viewx,viewy         : point of view\r
890 =   viewcos,viewsin     : sin/cos of viewangle\r
891 =\r
892 =\r
893 = defines:\r
894 =   CENTERX             : pixel location of center of view window\r
895 =   TILEGLOBAL          : size of one\r
896 =   FOCALLENGTH         : distance behind viewx/y for center of projection\r
897 =   scale               : conversion from global value to screen value\r
898 =\r
899 = returns:\r
900 =   screenx,screenheight: projected edge location and size\r
901 =\r
902 ========================\r
903 */\r
904 \r
905 void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight)\r
906 {\r
907   int ratio;\r
908   fixed gxt,gyt,nx,ny;\r
909 \r
910 //\r
911 // translate point to view centered coordinates\r
912 //\r
913   gx = gx-viewx;\r
914   gy = gy-viewy;\r
915 \r
916 //\r
917 // calculate newx\r
918 //\r
919   gxt = FixedByFrac(gx,viewcos);\r
920   gyt = FixedByFrac(gy,viewsin);\r
921   nx = gxt-gyt;\r
922 \r
923 //\r
924 // calculate newy\r
925 //\r
926   gxt = FixedByFrac(gx,viewsin);\r
927   gyt = FixedByFrac(gy,viewcos);\r
928   ny = gyt+gxt;\r
929 \r
930 //\r
931 // calculate perspective ratio\r
932 //\r
933   if (nx<0)\r
934         nx = 0;\r
935 \r
936   ratio = nx*scale/FOCALLENGTH;\r
937 \r
938   if (ratio<=MINRATIO)\r
939         ratio = MINRATIO;\r
940 \r
941   *screenx = CENTERX + ny/ratio;\r
942 \r
943   *screenheight = TILEGLOBAL/ratio;\r
944 \r
945 }\r
946 \r
947 \r
948 //\r
949 // transform actor\r
950 //\r
951 void TransformActor (objtype *ob)\r
952 {\r
953   int ratio;\r
954   fixed gx,gy,gxt,gyt,nx,ny;\r
955 \r
956 //\r
957 // translate point to view centered coordinates\r
958 //\r
959   gx = ob->x-viewx;\r
960   gy = ob->y-viewy;\r
961 \r
962 //\r
963 // calculate newx\r
964 //\r
965   gxt = FixedByFrac(gx,viewcos);\r
966   gyt = FixedByFrac(gy,viewsin);\r
967   nx = gxt-gyt-ob->size;\r
968 \r
969 //\r
970 // calculate newy\r
971 //\r
972   gxt = FixedByFrac(gx,viewsin);\r
973   gyt = FixedByFrac(gy,viewcos);\r
974   ny = gyt+gxt;\r
975 \r
976 //\r
977 // calculate perspective ratio\r
978 //\r
979   if (nx<0)\r
980         nx = 0;\r
981 \r
982   ratio = nx*scale/FOCALLENGTH;\r
983 \r
984   if (ratio<=MINRATIO)\r
985         ratio = MINRATIO;\r
986 \r
987   ob->viewx = CENTERX + ny/ratio;\r
988 \r
989   ob->viewheight = TILEGLOBAL/ratio;\r
990 }\r
991 \r
992 //==========================================================================\r
993 \r
994 fixed TransformX (fixed gx, fixed gy)\r
995 {\r
996   int ratio;\r
997   fixed gxt,gyt,nx,ny;\r
998 \r
999 //\r
1000 // translate point to view centered coordinates\r
1001 //\r
1002   gx = gx-viewx;\r
1003   gy = gy-viewy;\r
1004 \r
1005 //\r
1006 // calculate newx\r
1007 //\r
1008   gxt = FixedByFrac(gx,viewcos);\r
1009   gyt = FixedByFrac(gy,viewsin);\r
1010 \r
1011   return gxt-gyt;\r
1012 }\r
1013 \r
1014 //==========================================================================\r
1015 \r
1016 /*\r
1017 ==================\r
1018 =\r
1019 = BuildTables\r
1020 =\r
1021 = Calculates:\r
1022 =\r
1023 = scale                 projection constant\r
1024 = sintable/costable     overlapping fractional tables\r
1025 = firstangle/lastangle  angles from focalpoint to left/right view edges\r
1026 = prestep               distance from focal point before checking for tiles\r
1027 =\r
1028 ==================\r
1029 */\r
1030 \r
1031 void BuildTables (void)\r
1032 {\r
1033   int           i;\r
1034   long          intang;\r
1035   long          x;\r
1036   float         angle,anglestep,radtoint;\r
1037   double        tang;\r
1038   fixed         value;\r
1039 \r
1040 //\r
1041 // calculate the angle offset from view angle of each pixel's ray\r
1042 //\r
1043         radtoint = (float)FINEANGLES/2/PI;\r
1044         for (i=0;i<VIEWWIDTH/2;i++)\r
1045         {\r
1046         // start 1/2 pixel over, so viewangle bisects two middle pixels\r
1047                 x = (TILEGLOBAL*i+TILEGLOBAL/2)/VIEWWIDTH;\r
1048                 tang = (float)x/(FOCALLENGTH+MINDIST);\r
1049                 angle = atan(tang);\r
1050                 intang = angle*radtoint;\r
1051                 pixelangle[VIEWWIDTH/2-1-i] = intang;\r
1052                 pixelangle[VIEWWIDTH/2+i] = -intang;\r
1053         }\r
1054 \r
1055 //\r
1056 // calculate fine tangents\r
1057 // 1 sign bit, 5 units (clipped to), 10 fracs\r
1058 //\r
1059 #define MININT  (-MAXINT)\r
1060 \r
1061         for (i=0;i<FINEANGLES/4;i++)\r
1062         {\r
1063                 intang = tan(i/radtoint)*(1l<<10);\r
1064 \r
1065                 //\r
1066                 // if the tangent is not reprentable in this many bits, bound the\r
1067                 // units part ONLY\r
1068                 //\r
1069                 if (intang>MAXINT)\r
1070                         intang = 0x8f00 | (intang & 0xff);\r
1071                 else if (intang<MININT)\r
1072                         intang = 0xff00 | (intang & 0xff);\r
1073 \r
1074                 finetangent[i] = intang;\r
1075 //              finetangent[FINEANGLES/2+i] = intang;\r
1076 //              finetangent[FINEANGLES/2-i-1] = -intang;\r
1077                 finetangent[FINEANGLES-i-1] = -intang;\r
1078         }\r
1079 \r
1080 //\r
1081 // calculate scale value so one tile at mindist allmost fills the view horizontally\r
1082 //\r
1083   scale = GLOBAL1/VIEWWIDTH;\r
1084   scale *= focallength;\r
1085   scale /= (focallength+mindist);\r
1086 \r
1087 //\r
1088 // costable overlays sintable with a quarter phase shift\r
1089 // ANGLES is assumed to be divisable by four\r
1090 //\r
1091 // The low word of the value is the fraction, the high bit is the sign bit,\r
1092 // bits 16-30 should be 0\r
1093 //\r
1094 \r
1095   angle = 0;\r
1096   anglestep = PI/2/ANGLEQUAD;\r
1097   for (i=0;i<=ANGLEQUAD;i++)\r
1098   {\r
1099         value=GLOBAL1*sin(angle);\r
1100         sintable[i]=\r
1101           sintable[i+ANGLES]=\r
1102           sintable[ANGLES/2-i] = value;\r
1103         sintable[ANGLES-i]=\r
1104           sintable[ANGLES/2+i] = value | 0x80000000l;\r
1105         angle += anglestep;\r
1106   }\r
1107 \r
1108 //\r
1109 // figure trace angles for first and last pixel on screen\r
1110 //\r
1111   angle = atan((float)VIEWWIDTH/2*scale/FOCALLENGTH);\r
1112   angle *= ANGLES/(PI*2);\r
1113 \r
1114   intang = (int)angle+1;\r
1115   firstangle = intang;\r
1116   lastangle = -intang;\r
1117 \r
1118   prestep = GLOBAL1*((float)FOCALLENGTH/costable[firstangle]);\r
1119 \r
1120 //\r
1121 // misc stuff\r
1122 //\r
1123   walls[0].x2 = VIEWX-1;\r
1124   walls[0].height2 = 32000;\r
1125 }\r
1126 \r
1127 \r
1128 //==========================================================================\r
1129 \r
1130 /*\r
1131 =====================\r
1132 =\r
1133 = ClearScreen\r
1134 =\r
1135 =====================\r
1136 */\r
1137 \r
1138 void ClearScreen (void)\r
1139 {\r
1140   //\r
1141   // clear the screen\r
1142   //\r
1143 asm     mov     dx,GC_INDEX\r
1144 asm     mov     ax,GC_MODE + 256*2              // read mode 0, write mode 2\r
1145 asm     out     dx,ax\r
1146 asm     mov     ax,GC_BITMASK + 255*256\r
1147 asm     out     dx,ax\r
1148 \r
1149 asm     mov     dx,40-VIEWWIDTH/8\r
1150 asm     mov     bl,VIEWWIDTH/16\r
1151 asm     mov     bh,CENTERY+1\r
1152 \r
1153 asm     xor     ax,ax\r
1154 asm     mov     es,[screenseg]\r
1155 asm     mov     di,[bufferofs]\r
1156 \r
1157 toploop:\r
1158 asm     mov     cl,bl\r
1159 asm     rep     stosw\r
1160 asm     stosb\r
1161 asm     add     di,dx\r
1162 asm     dec     bh\r
1163 asm     jnz     toploop\r
1164 \r
1165 asm     mov     bh,CENTERY+1\r
1166 asm     mov     ax,0x0808\r
1167 \r
1168 bottomloop:\r
1169 asm     mov     cl,bl\r
1170 asm     rep     stosw\r
1171 asm     stosb\r
1172 asm     add     di,dx\r
1173 asm     dec     bh\r
1174 asm     jnz     bottomloop\r
1175 \r
1176 \r
1177 asm     mov     dx,GC_INDEX\r
1178 asm     mov     ax,GC_MODE + 256*10             // read mode 1, write mode 2\r
1179 asm     out     dx,ax\r
1180 asm     mov     al,GC_BITMASK\r
1181 asm     out     dx,al\r
1182 \r
1183 }\r
1184 \r
1185 //==========================================================================\r
1186 \r
1187 /*\r
1188 =====================\r
1189 =\r
1190 = DrawWallList\r
1191 =\r
1192 = Clips and draws all the walls traced this refresh\r
1193 =\r
1194 =====================\r
1195 */\r
1196 \r
1197 void DrawWallList (void)\r
1198 {\r
1199         int i,leftx,newleft,rightclip;\r
1200         walltype *wall, *check;\r
1201 \r
1202 asm     mov     ax,ds\r
1203 asm     mov     es,ax\r
1204 asm     mov     di,OFFSET wallwidth\r
1205 asm     xor     ax,ax\r
1206 asm     mov     cx,VIEWWIDTH/2\r
1207 asm     rep     stosw\r
1208 \r
1209         ClearScreen ();\r
1210 \r
1211         rightwall->x1 = VIEWXH+1;\r
1212         rightwall->height1 = 32000;\r
1213         (rightwall+1)->x1 = 32000;\r
1214 \r
1215         leftx = -1;\r
1216 \r
1217         for (wall=&walls[1];wall<rightwall && leftx<=VIEWXH ;wall++)\r
1218         {\r
1219           if (leftx >= wall->x2)\r
1220                 continue;\r
1221 \r
1222           rightclip = wall->x2;\r
1223 \r
1224           check = wall+1;\r
1225           while (check->x1 <= rightclip && check->height1 >= wall->height2)\r
1226           {\r
1227                 rightclip = check->x1-1;\r
1228                 check++;\r
1229           }\r
1230 \r
1231           if (rightclip>VIEWXH)\r
1232                 rightclip=VIEWXH;\r
1233 \r
1234           if (leftx < wall->x1 - 1)\r
1235                 newleft = wall->x1-1;           // there was black space between walls\r
1236           else\r
1237                 newleft = leftx;\r
1238 \r
1239           if (rightclip > newleft)\r
1240           {\r
1241                 wall->leftclip = newleft+1;\r
1242                 wall->rightclip = rightclip;\r
1243                 DrawVWall (wall);\r
1244                 leftx = rightclip;\r
1245           }\r
1246         }\r
1247 \r
1248 #ifndef DRAWEACH\r
1249         ScaleWalls ();                                  // draw all the walls\r
1250 #endif\r
1251 }\r
1252 \r
1253 //==========================================================================\r
1254 \r
1255 /*\r
1256 =====================\r
1257 =\r
1258 = DrawScaleds\r
1259 =\r
1260 = Draws all objects that are visable\r
1261 =\r
1262 =====================\r
1263 */\r
1264 \r
1265 objtype *depthsort[MAXACTORS];\r
1266 \r
1267 void DrawScaleds (void)\r
1268 {\r
1269         int             i,j,least,numvisable,height;\r
1270         objtype         *obj,**vislist,*farthest;\r
1271         memptr          shape;\r
1272         byte            *tilespot,*visspot;\r
1273 \r
1274         numvisable = 0;\r
1275 \r
1276 //\r
1277 // calculate base positions of all objects\r
1278 //\r
1279         vislist = &depthsort[0];\r
1280 \r
1281         for (obj = player->next;obj;obj=obj->next)\r
1282         {\r
1283                 if (!obj->state->shapenum)\r
1284                         continue;\r
1285 \r
1286                 tilespot = &tilemap[0][0]+(obj->tilex<<6)+obj->tiley;\r
1287                 visspot = &spotvis[0][0]+(obj->tilex<<6)+obj->tiley;\r
1288                 //\r
1289                 // could be in any of the nine surrounding tiles\r
1290                 //\r
1291                 if (*visspot\r
1292                 || ( *(visspot-1) && !*(tilespot-1) )\r
1293                 || ( *(visspot+1) && !*(tilespot+1) )\r
1294                 || ( *(visspot-65) && !*(tilespot-65) )\r
1295                 || ( *(visspot-64) && !*(tilespot-64) )\r
1296                 || ( *(visspot-63) && !*(tilespot-63) )\r
1297                 || ( *(visspot+65) && !*(tilespot+65) )\r
1298                 || ( *(visspot+64) && !*(tilespot+64) )\r
1299                 || ( *(visspot+63) && !*(tilespot+63) ) )\r
1300                 {\r
1301                         obj->active = true;\r
1302                         TransformActor (obj);\r
1303                         if (!obj->viewheight || obj->viewheight > VIEWWIDTH)\r
1304                                 continue;                       // too close or far away\r
1305 \r
1306                         *vislist++ = obj;\r
1307                         numvisable++;\r
1308                 }\r
1309         }\r
1310 \r
1311         if (vislist == &depthsort[0])\r
1312                 return;                                         // no visable objects\r
1313 \r
1314 //\r
1315 // draw from back to front\r
1316 //\r
1317         for (i = 0; i<numvisable; i++)\r
1318         {\r
1319                 least = 32000;\r
1320                 for (j=0;j<numvisable;j++)\r
1321                 {\r
1322                         height = depthsort[j]->viewheight;\r
1323                         if (height < least)\r
1324                         {\r
1325                                 least = height;\r
1326                                 farthest = depthsort[j];\r
1327                         }\r
1328                 }\r
1329                 //\r
1330                 // draw farthest\r
1331                 //\r
1332                 shape = shapedirectory[farthest->state->shapenum-FIRSTSCALEPIC];\r
1333                 ScaleShape(farthest->viewx,shape,farthest->viewheight);\r
1334                 farthest->viewheight = 32000;\r
1335         }\r
1336 }\r
1337 \r
1338 //==========================================================================\r
1339 \r
1340 \r
1341 /*\r
1342 =====================\r
1343 =\r
1344 = CalcTics\r
1345 =\r
1346 =====================\r
1347 */\r
1348 \r
1349 void CalcTics (void)\r
1350 {\r
1351         long    newtime,oldtimecount;\r
1352 \r
1353 \r
1354 #ifdef PROFILE\r
1355         tics = 1;\r
1356         return;\r
1357 #endif\r
1358 \r
1359 //\r
1360 // calculate tics since last refresh for adaptive timing\r
1361 //\r
1362         if (lasttimecount > TimeCount)\r
1363                 TimeCount = lasttimecount;              // if the game was paused a LONG time\r
1364 \r
1365         if (DemoMode)                                   // demo recording and playback needs\r
1366         {                                                               // to be constant\r
1367 //\r
1368 // take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
1369 //\r
1370                 oldtimecount = lasttimecount;\r
1371                 while (TimeCount<oldtimecount+DEMOTICS*2)\r
1372                 ;\r
1373                 lasttimecount = oldtimecount + DEMOTICS;\r
1374                 TimeCount = lasttimecount + DEMOTICS;\r
1375                 tics = DEMOTICS;\r
1376         }\r
1377         else\r
1378         {\r
1379 //\r
1380 // non demo, so report actual time\r
1381 //\r
1382                 newtime = TimeCount;\r
1383                 tics = newtime-lasttimecount;\r
1384                 lasttimecount = newtime;\r
1385 \r
1386 #ifdef FILEPROFILE\r
1387                         strcpy (scratch,"\tTics:");\r
1388                         itoa (tics,str,10);\r
1389                         strcat (scratch,str);\r
1390                         strcat (scratch,"\n");\r
1391                         write (profilehandle,scratch,strlen(scratch));\r
1392 #endif\r
1393 \r
1394                 if (tics>MAXTICS)\r
1395                 {\r
1396                         TimeCount -= (tics-MAXTICS);\r
1397                         tics = MAXTICS;\r
1398                 }\r
1399         }\r
1400 }\r
1401 \r
1402 \r
1403 //==========================================================================\r
1404 \r
1405 \r
1406 /*\r
1407 ========================\r
1408 =\r
1409 = DrawHand\r
1410 =\r
1411 ========================\r
1412 */\r
1413 \r
1414 void    DrawHand (void)\r
1415 {\r
1416         int     picnum;\r
1417         memptr source;\r
1418         unsigned dest,width,height;\r
1419 \r
1420         picnum = HAND1PICM;\r
1421         if (gamestate.shotpower || boltsleft)\r
1422                 picnum += (((unsigned)TimeCount>>3)&1);\r
1423 \r
1424         source = grsegs[picnum];\r
1425         dest = ylookup[VIEWHEIGHT-handheight]+12+bufferofs;\r
1426         width = picmtable[picnum-STARTPICM].width;\r
1427         height = picmtable[picnum-STARTPICM].height;\r
1428 \r
1429         VW_MaskBlock(source,0,dest,width,handheight,width*height);\r
1430         EGAMAPMASK(15);\r
1431 }\r
1432 \r
1433 //==========================================================================\r
1434 \r
1435 \r
1436 /*\r
1437 ========================\r
1438 =\r
1439 = ThreeDRefresh\r
1440 =\r
1441 ========================\r
1442 */\r
1443 \r
1444 void    ThreeDRefresh (void)\r
1445 {\r
1446         int tracedir;\r
1447 \r
1448 restart:\r
1449         aborttrace = false;\r
1450 \r
1451 //\r
1452 // clear out the traced array\r
1453 //\r
1454 asm     mov     ax,ds\r
1455 asm     mov     es,ax\r
1456 asm     mov     di,OFFSET spotvis\r
1457 asm     xor     ax,ax\r
1458 asm     mov     cx,[mapwidth]           // mapheight*32 words\r
1459 asm     shl     cx,1\r
1460 asm     shl     cx,1\r
1461 asm     shl     cx,1\r
1462 asm     shl     cx,1\r
1463 asm     shl     cx,1\r
1464 asm     rep stosw\r
1465 \r
1466 \r
1467 //\r
1468 // set up variables for this view\r
1469 //\r
1470 \r
1471         viewangle = player->angle;\r
1472         fineviewangle = viewangle*(FINEANGLES/ANGLES);\r
1473         viewsin = sintable[viewangle];\r
1474         viewcos = costable[viewangle];\r
1475         viewx = player->x - FixedByFrac(FOCALLENGTH,viewcos);\r
1476         viewy = player->y + FixedByFrac(FOCALLENGTH,viewsin);\r
1477         viewx &= 0xfffffc00;            // stop on a pixel boundary\r
1478         viewy &= 0xfffffc00;\r
1479         viewx += 0x180;\r
1480         viewy += 0x180;\r
1481         viewxpix = viewx>>10;\r
1482         viewypix = viewy>>10;\r
1483 \r
1484         focal.x = viewx>>TILESHIFT;\r
1485         focal.y = viewy>>TILESHIFT;\r
1486 \r
1487 //\r
1488 // find the rightmost visable tile in view\r
1489 //\r
1490         tracedir = viewangle + lastangle;\r
1491         if (tracedir<0)\r
1492           tracedir+=ANGLES;\r
1493         else if (tracedir>=ANGLES)\r
1494           tracedir-=ANGLES;\r
1495         TraceRay( tracedir );\r
1496         right.x = tile.x;\r
1497         right.y = tile.y;\r
1498 \r
1499 //\r
1500 // find the leftmost visable tile in view\r
1501 //\r
1502         tracedir = viewangle + firstangle;\r
1503         if (tracedir<0)\r
1504           tracedir+=ANGLES;\r
1505         else if (tracedir>=ANGLES)\r
1506           tracedir-=ANGLES;\r
1507         TraceRay( tracedir );\r
1508 \r
1509 //\r
1510 // follow the walls from there to the right\r
1511 //\r
1512         rightwall = &walls[1];\r
1513         FollowWalls ();\r
1514 \r
1515         if (aborttrace)\r
1516                 goto restart;\r
1517 \r
1518 //\r
1519 // actually draw stuff\r
1520 //\r
1521         if (++screenpage == 3)\r
1522                 screenpage = 0;\r
1523 \r
1524         bufferofs = screenloc[screenpage];\r
1525 \r
1526         EGAWRITEMODE(2);\r
1527         EGAMAPMASK(15);\r
1528 \r
1529 //\r
1530 // draw the wall list saved be FollowWalls ()\r
1531 //\r
1532         animframe = (TimeCount&8)>>3;\r
1533 \r
1534 //\r
1535 // draw all the scaled images\r
1536 //\r
1537         asm     mov     dx,GC_INDEX\r
1538 \r
1539         asm     mov     ax,GC_COLORDONTCARE\r
1540         asm     out     dx,ax                                           // don't look at any of the planes\r
1541 \r
1542         asm     mov     ax,GC_MODE + 256*(10)           // read mode 1, write mode 2\r
1543         asm     out     dx,ax\r
1544 \r
1545         asm     mov     al,GC_BITMASK\r
1546         asm     out     dx,al\r
1547 \r
1548         DrawWallList();\r
1549         DrawScaleds();\r
1550 \r
1551         EGAWRITEMODE(0);\r
1552         EGABITMASK(0xff);\r
1553 \r
1554 //\r
1555 // draw hand\r
1556 //\r
1557         if (handheight)\r
1558                 DrawHand ();\r
1559 \r
1560 //\r
1561 // show screen and time last cycle\r
1562 //\r
1563         if (fizzlein)\r
1564         {\r
1565                 fizzlein = false;\r
1566                 FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,true);\r
1567                 lasttimecount = TimeCount;\r
1568                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
1569         }\r
1570 \r
1571 asm     cli\r
1572 asm     mov     cx,[bufferofs]\r
1573 asm     mov     dx,3d4h         // CRTC address register\r
1574 asm     mov     al,0ch          // start address high register\r
1575 asm     out     dx,al\r
1576 asm     inc     dx\r
1577 asm     mov     al,ch\r
1578 asm     out     dx,al           // set the high byte\r
1579 asm     dec     dx\r
1580 asm     mov     al,0dh          // start address low register\r
1581 asm     out     dx,al\r
1582 asm     inc     dx\r
1583 asm     mov     al,cl\r
1584 asm     out     dx,al           // set the low byte\r
1585 asm     sti\r
1586 \r
1587         displayofs = bufferofs;\r
1588 \r
1589         CalcTics ();\r
1590 \r
1591 }\r
1592 \r