]> 4ch.mooo.com Git - 16.git/blob - 16/cawat/C5_DRAW.C
wwww
[16.git] / 16 / cawat / C5_DRAW.C
1 /* Catacomb Armageddon 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 "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]= {PAGE1START,PAGE2START,PAGE3START};\r
65 unsigned freelatch = FREESTART;\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 #if 0\r
164 /*\r
165 ==================\r
166 =\r
167 = DrawLine\r
168 =\r
169 = Must be in write mode 2 with all planes enabled\r
170 = The bit mask is left set to the end value, so clear it after all lines are\r
171 = drawn\r
172 =\r
173 = draws a black dot at the left edge of the line\r
174 =\r
175 ==================\r
176 */\r
177 \r
178 unsigned static char dotmask[8] = {0x80,0x40,0x20,0x10,8,4,2,1};\r
179 unsigned static char leftmask[8] = {0xff,0x7f,0x3f,0x1f,0xf,7,3,1};\r
180 unsigned static char rightmask[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};\r
181 \r
182 void DrawLine (int xl, int xh, int y,int color)\r
183 {\r
184   unsigned dest,xlp,xlb,xhb,maskleft,maskright,maskdot,mid;\r
185 \r
186   xlb=xl/8;\r
187   xhb=xh/8;\r
188 \r
189   if (xh<xl)\r
190         Quit("DrawLine: xh<xl");\r
191   if (y<VIEWY)\r
192         Quit("DrawLine: y<VIEWY");\r
193   if (y>VIEWYH)\r
194         Quit("DrawLine: y>VIEWYH");\r
195 \r
196         xlp = xl&7;\r
197         maskleft = leftmask[xlp];\r
198         maskright = rightmask[xh&7];\r
199 \r
200   mid = xhb-xlb-1;\r
201   dest = bufferofs+ylookup[y]+xlb;\r
202 \r
203         //\r
204         // set the GC index register to point to the bit mask register\r
205         //\r
206         asm     mov     al,GC_BITMASK\r
207         asm     mov     dx,GC_INDEX\r
208         asm     out     dx,al\r
209 \r
210   if (xlb==xhb)\r
211   {\r
212   //\r
213   // entire line is in one byte\r
214   //\r
215 \r
216         maskleft&=maskright;\r
217 \r
218         asm     mov     es,[screenseg]\r
219         asm     mov     di,[dest]\r
220         asm     mov     dx,GC_INDEX+1\r
221 \r
222         asm     mov     al,[BYTE PTR maskleft]\r
223         asm     out     dx,al           // mask off pixels\r
224 \r
225         asm     mov     al,[BYTE PTR color]\r
226         asm     xchg    al,[es:di]      // load latches and write pixels\r
227 \r
228         return;\r
229   }\r
230 \r
231 asm     mov     es,[screenseg]\r
232 asm     mov     di,[dest]\r
233 asm     mov     dx,GC_INDEX+1\r
234 asm     mov     bh,[BYTE PTR color]\r
235 \r
236 //\r
237 // draw left side\r
238 //\r
239 asm     mov     al,[BYTE PTR maskleft]\r
240 asm     out     dx,al           // mask off pixels\r
241 \r
242 asm     mov     al,bh\r
243 asm     xchg    al,[es:di]      // load latches and write pixels\r
244 asm     inc     di\r
245 \r
246 //\r
247 // draw middle\r
248 //\r
249 asm     mov     al,255\r
250 asm     out     dx,al           // no masking\r
251 \r
252 asm     mov     al,bh\r
253 asm     mov     cx,[mid]\r
254 asm     rep     stosb\r
255 \r
256 //\r
257 // draw right side\r
258 //\r
259 asm     mov     al,[BYTE PTR maskright]\r
260 asm     out     dx,al           // mask off pixels\r
261 asm     xchg    bh,[es:di]      // load latches and write pixels\r
262 \r
263 }\r
264 \r
265 //==========================================================================\r
266 \r
267 void DrawLineDot (int xl, int xh, int y,int color)\r
268 {\r
269   unsigned dest,xlp,xlb,xhb,maskleft,maskright,maskdot,mid;\r
270 \r
271   xlb=xl/8;\r
272   xhb=xh/8;\r
273 \r
274   if (xh<xl)\r
275         Quit("DrawLine: xh<xl");\r
276   if (y<VIEWY)\r
277         Quit("DrawLine: y<VIEWY");\r
278   if (y>VIEWYH)\r
279         Quit("DrawLine: y>VIEWYH");\r
280 \r
281         xlp = xl&7;\r
282         maskdot = dotmask[xlp];\r
283         maskleft = leftmask[xlp];\r
284         maskright = rightmask[xh&7];\r
285 \r
286   mid = xhb-xlb-1;\r
287   dest = bufferofs+ylookup[y]+xlb;\r
288 \r
289         //\r
290         // set the GC index register to point to the bit mask register\r
291         //\r
292         asm     mov     al,GC_BITMASK\r
293         asm     mov     dx,GC_INDEX\r
294         asm     out     dx,al\r
295 \r
296   if (xlb==xhb)\r
297   {\r
298   //\r
299   // entire line is in one byte\r
300   //\r
301 \r
302         maskleft&=maskright;\r
303 \r
304         asm     mov     es,[screenseg]\r
305         asm     mov     di,[dest]\r
306         asm     mov     dx,GC_INDEX+1\r
307 \r
308         asm     mov     al,[BYTE PTR maskleft]\r
309         asm     out     dx,al           // mask off pixels\r
310 \r
311         asm     mov     al,[BYTE PTR color]\r
312         asm     xchg    al,[es:di]      // load latches and write pixels\r
313 \r
314 \r
315         //\r
316         // write the black dot at the start\r
317         //\r
318         asm     mov     al,[BYTE PTR maskdot]\r
319         asm     out     dx,al           // mask off pixels\r
320 \r
321         asm     xor     al,al\r
322         asm     xchg    al,[es:di]      // load latches and write pixels\r
323 \r
324 \r
325         return;\r
326   }\r
327 \r
328 asm     mov     es,[screenseg]\r
329 asm     mov     di,[dest]\r
330 asm     mov     dx,GC_INDEX+1\r
331 asm     mov     bh,[BYTE PTR color]\r
332 \r
333 //\r
334 // draw left side\r
335 //\r
336 asm     mov     al,[BYTE PTR maskleft]\r
337 asm     out     dx,al           // mask off pixels\r
338 \r
339 asm     mov     al,bh\r
340 asm     xchg    al,[es:di]      // load latches and write pixels\r
341 \r
342 //\r
343 // write the black dot at the start\r
344 //\r
345 asm     mov     al,[BYTE PTR maskdot]\r
346 asm     out     dx,al           // mask off pixels\r
347 asm     xor     al,al\r
348 asm     xchg    al,[es:di]      // load latches and write pixels\r
349 asm     inc     di\r
350 \r
351 //\r
352 // draw middle\r
353 //\r
354 asm     mov     al,255\r
355 asm     out     dx,al           // no masking\r
356 \r
357 asm     mov     al,bh\r
358 asm     mov     cx,[mid]\r
359 asm     rep     stosb\r
360 \r
361 //\r
362 // draw right side\r
363 //\r
364 asm     mov     al,[BYTE PTR maskright]\r
365 asm     out     dx,al           // mask off pixels\r
366 asm     xchg    bh,[es:di]      // load latches and write pixels\r
367 \r
368 }\r
369 \r
370 #endif\r
371 \r
372 //==========================================================================\r
373 \r
374 \r
375 long            wallscalesource;\r
376 \r
377 #ifdef DRAWEACH\r
378 /*\r
379 ====================\r
380 =\r
381 = ScaleOneWall\r
382 =\r
383 ====================\r
384 */\r
385 \r
386 void near ScaleOneWall (int xl, int xh)\r
387 {\r
388         int     x,pixwidth,height;\r
389 \r
390         *(((unsigned *)&wallscalesource)+1) = wallseg[xl];\r
391 \r
392         for (x=xl;x<=xh;x+=pixwidth)\r
393         {\r
394                 height = wallheight[x];\r
395                 pixwidth = wallwidth[x];\r
396                 (unsigned)wallscalesource = wallofs[x];\r
397 \r
398                 *(((unsigned *)&scaletablecall)+1) = (unsigned)scaledirectory[height];\r
399                 (unsigned)scaletablecall = scaledirectory[height]->codeofs[0];\r
400 \r
401                 //\r
402                 // scale a byte wide strip of wall\r
403                 //\r
404                 asm     mov     bx,[x]\r
405                 asm     mov     di,bx\r
406                 asm     shr     di,1\r
407                 asm     shr     di,1\r
408                 asm     shr     di,1                                            // X in bytes\r
409                 asm     add     di,[bufferofs]\r
410                 asm     and     bx,7\r
411                 asm     shl     bx,1\r
412                 asm     shl     bx,1\r
413                 asm     shl     bx,1\r
414                 asm     add     bx,[pixwidth]                           // bx = pixel*8+pixwidth-1\r
415                 asm     dec     bx\r
416                 asm     mov     al,BYTE PTR [bitmasks1+bx]\r
417                 asm     mov     dx,GC_INDEX+1\r
418                 asm     out     dx,al                                           // set bit mask register\r
419                 asm     mov     es,[screenseg]\r
420                 asm     lds     si,[wallscalesource]\r
421                 asm     call [DWORD PTR ss:scaletablecall]              // scale the line of pixels\r
422 \r
423                 asm     mov     al,BYTE PTR [ss:bitmasks2+bx]\r
424                 asm     or      al,al\r
425                 asm     jz      nosecond\r
426 \r
427                 //\r
428                 // draw a second byte for vertical strips that cross two bytes\r
429                 //\r
430                 asm     inc     di\r
431                 asm     out     dx,al                                           // set bit mask register\r
432                 asm     call [DWORD PTR ss:scaletablecall]      // scale the line of pixels\r
433         nosecond:\r
434                 asm     mov     ax,ss\r
435                 asm     mov     ds,ax\r
436         }\r
437 }\r
438 \r
439 #endif\r
440 \r
441 char wall_anim_pos[NUMFLOORS];\r
442 \r
443 // EAST / WEST WALLS\r
444 //\r
445 int     far walllight1[NUMFLOORS] = {0,\r
446 \r
447         CRYSTAL_LIGHT_1PIC,\r
448         CRYSTAL_LIGHT_2PIC,\r
449         CRYSTAL_LIGHT_3PIC,\r
450         CRYSTAL_LIGHT_4PIC,                     //4\r
451 \r
452         FIRE_WALL_1PIC,\r
453         FIRE_WALL_2PIC,\r
454         FIRE_WALL_3PIC,\r
455         FIRE_WALL_4PIC,                         //8\r
456 \r
457         BRN_STONE_GATEPIC,\r
458         BRN_STONE_WALL_1PIC,\r
459         KUDZU_WEAK_LIGHTPIC,\r
460         KUDZU_LIGHT_WALLPIC,\r
461         HEDGE_WALLPIC,\r
462         HEDGE_EYESPIC,                          //14\r
463 \r
464         W_GEN_DOOR1PIC,                                 //15\r
465         BRN_WINDOW_LIGHTPIC,\r
466 \r
467         ALTAR_LEFTPIC,\r
468         ALTAR_RIGHTPIC,\r
469         GRAY_LIGHT_WALLPIC,\r
470         GRAY_LIGHT_SIGNPIC,                     //20\r
471 \r
472         MANICLE_LIGHT_WALLPIC,\r
473         MANICLE_LIGHT_BLOODYPIC,\r
474 \r
475         LIGHT_CURTAIN_WINDOWPIC,\r
476         LIGHT_CURTAIN_WALLPIC,\r
477         BRN_LIGHT_SIGNPIC,                      //25\r
478 \r
479         LIGHT_STONE_WALLPIC,\r
480 \r
481         W_GEN_DOOR2PIC,                                 //27\r
482 \r
483         TROLL_LIGHT_STONEPIC,\r
484 \r
485         BRN_FLAGSTONE_LIGHT_2PIC,\r
486 \r
487         W_CRYSTAL_DOORPIC,\r
488 \r
489         DMG_BRN_FSTN_LTPIC,\r
490 \r
491         RUST_METAL_LIGHTPIC,\r
492         GRAY_METAL_LIGHTPIC,                    //33\r
493 \r
494         WEAK_STONE_LIGHTPIC,\r
495 \r
496         DMG_FIN_FSTN_LTPIC,\r
497 \r
498         WEAK_GRAY_RFGSTN_LIGHTPIC,\r
499         0,\r
500 \r
501         WEAK_CRYSTAL_LIGHTPIC,\r
502 \r
503         RED_MUD_LIGHTPIC,\r
504 \r
505         STEEL_DOOR1PIC,                         //40\r
506 \r
507         RED_MUD_WEAK_LIGHTPIC,\r
508 \r
509         STEEL_DOOR2PIC,                         //42\r
510 \r
511         HORN_DOORPIC,\r
512         TROLL_BLOODY_LT_STONEPIC,\r
513         CLOSED_DOOR_1PIC,\r
514 \r
515         GRY_DOOR_LTPIC,                         //46\r
516 \r
517         BRN_DOOR_LTPIC,                         //47\r
518 \r
519         GRY_FGSTN_LTPIC,                           //48\r
520         DOOR_2PIC,\r
521 \r
522         WATER_LIGHT_WEAK_1PIC,\r
523         WATER_LIGHT_WEAK_2PIC,\r
524         WATER_LIGHT_WEAK_3PIC,                  //52\r
525 \r
526         WATER_LIGHT_1PIC,\r
527         WATER_LIGHT_2PIC,\r
528         WATER_LIGHT_3PIC,\r
529 \r
530         LIGHT_BREATH_1PIC,\r
531         LIGHT_BREATH_2PIC,\r
532         LIGHT_BREATH_3PIC,                      //58\r
533 \r
534         EXP_WALL_1PIC,\r
535         EXP_WALL_2PIC,\r
536         EXP_WALL_3PIC,\r
537 \r
538         WATER_EXP_WALL_1PIC,\r
539         WATER_EXP_WALL_2PIC,\r
540         WATER_EXP_WALL_3PIC,                    //64\r
541 \r
542         FINALWALLPIC,\r
543 \r
544         LT_SKEL1PIC,\r
545         DK_SKEL1PIC,\r
546         LT_SKEL2PIC,\r
547         DK_SKEL2PIC,\r
548 \r
549         0,\r
550 \r
551         TAP_1PIC,\r
552         TAP_2PIC,\r
553         TAP_3PIC,\r
554         TAP_4PIC,\r
555         TAP_5PIC,\r
556 \r
557         WATER_DOOR1_PIC,\r
558         WATER_DOOR2_PIC,\r
559         };\r
560 \r
561 // NORTH / SOUTH WALLS\r
562 //\r
563 int     far walldark1[NUMFLOORS] = {0,\r
564 \r
565         CRYSTAL_DARK_1PIC,\r
566         CRYSTAL_DARK_2PIC,\r
567         CRYSTAL_DARK_3PIC,\r
568         CRYSTAL_DARK_4PIC,                      //4\r
569 \r
570         FIRE_WALL_1PIC,\r
571         FIRE_WALL_2PIC,\r
572         FIRE_WALL_3PIC,\r
573         FIRE_WALL_4PIC,                         //8\r
574 \r
575         BRN_STONE_GATEPIC,\r
576         BRN_STONE_WALL_2PIC,\r
577         KUDZU_WEAK_DARKPIC,\r
578         KUDZU_DARK_WALLPIC,\r
579         HEDGE_WALLPIC,\r
580         HEDGE_EYESPIC,                          //14\r
581 \r
582         W_GEN_DOOR1PIC,                         //15\r
583         BRN_WINDOW_DARKPIC,\r
584 \r
585         ALTAR_LEFTPIC,\r
586         ALTAR_RIGHTPIC,\r
587         GRAY_DARK_WALLPIC,\r
588         GRAY_DARK_SIGNPIC,                      //20\r
589 \r
590         MANICLE_DARK_WALLPIC,\r
591         MANICLE_DARK_BLOODYPIC,\r
592 \r
593         DARK_CURTAIN_WINDOWPIC,\r
594         DARK_CURTAIN_WALLPIC,\r
595         BRN_DARK_SIGNPIC,\r
596 \r
597         DARK_STONE_WALLPIC,\r
598 \r
599         W_GEN_DOOR2PIC,                         //27\r
600 \r
601         TROLL_DARK_STONEPIC,\r
602 \r
603         BRN_FLAGSTONE_DARK_2PIC,\r
604 \r
605         W_CRYSTAL_DOORPIC,                              //30\r
606 \r
607         DMG_BRN_FSTN_DKPIC,\r
608 \r
609         RUST_METAL_DARKPIC,\r
610         GRAY_METAL_DARKPIC,\r
611 \r
612         WEAK_STONE_DARKPIC,\r
613 \r
614         DMG_FIN_FSTN_DKPIC,                     //35\r
615 \r
616         WEAK_GRAY_RFGSTN_DARKPIC,\r
617         0,\r
618 \r
619         WEAK_CRYSTAL_DARKPIC,\r
620 \r
621         BRN_MUD_DARKPIC,\r
622 \r
623         STEEL_DOOR1PIC,                         //40\r
624 \r
625         BRN_MUD_WEAK_DARKPIC,\r
626 \r
627         STEEL_DOOR2PIC,\r
628 \r
629         HORN_DOORPIC,\r
630         TROLL_BLOODY_DK_STONEPIC,\r
631 \r
632         CLOSED_DOOR_1PIC,\r
633 \r
634         GRY_DOOR_DKPIC,                         //46\r
635         BRN_DOOR_DKPIC,                         //47\r
636         GRY_FGSTN_DKPIC,                                //48\r
637         DOOR_2PIC,\r
638 \r
639         WATER_DARK_WEAK_1PIC,\r
640         WATER_DARK_WEAK_2PIC,\r
641         WATER_DARK_WEAK_3PIC,\r
642 \r
643         WATER_DARK_1PIC,\r
644         WATER_DARK_2PIC,\r
645         WATER_DARK_3PIC,\r
646 \r
647         DARK_BREATH_1PIC,\r
648         DARK_BREATH_2PIC,\r
649         DARK_BREATH_3PIC,\r
650 \r
651         EXP_WALL_1PIC,\r
652         EXP_WALL_2PIC,\r
653         EXP_WALL_3PIC,\r
654 \r
655         WATER_EXP_WALL_1PIC,\r
656         WATER_EXP_WALL_2PIC,\r
657         WATER_EXP_WALL_3PIC,\r
658 \r
659         FINALWALLPIC,\r
660 \r
661         LT_SKEL1PIC,\r
662         DK_SKEL1PIC,\r
663         LT_SKEL2PIC,\r
664         DK_SKEL2PIC,\r
665 \r
666         0,\r
667 \r
668         TAP_1PIC,\r
669         TAP_2PIC,\r
670         TAP_3PIC,\r
671         TAP_4PIC,\r
672         TAP_5PIC,\r
673 \r
674         WATER_DOOR1_PIC,\r
675         WATER_DOOR2_PIC,\r
676         };\r
677 \r
678 \r
679 /*\r
680 =====================\r
681 =\r
682 = DrawVWall\r
683 =\r
684 = Draws a wall by vertical segments, for texture mapping!\r
685 =\r
686 = wallptr->side is true for east/west walls (constant x)\r
687 =\r
688 = fracheight and fracstep are 16.16 bit fractions\r
689 =\r
690 =====================\r
691 */\r
692 \r
693 void DrawVWall (walltype *wallptr)\r
694 {\r
695         int                     x,i;\r
696         unsigned        source;\r
697         unsigned        width,sourceint;\r
698         unsigned        wallpic,wallpicseg;\r
699         unsigned        skip;\r
700         long            fracheight,fracstep,longheightchange;\r
701         unsigned        height;\r
702         int                     heightchange;\r
703         unsigned        slope,distance;\r
704         int                     traceangle,angle;\r
705         int                     mapadd;\r
706         unsigned        lastpix,lastsource,lastwidth;\r
707 \r
708         if (wallptr->rightclip < wallptr->leftclip)\r
709                 Quit ("DrawVWall: Right < Left");\r
710 \r
711 //\r
712 // setup for height calculation\r
713 //\r
714         wallptr->height1 >>= 1;\r
715         wallptr->height2 >>= 1;\r
716         wallptr->planecoord>>=10;                       // remove non significant bits\r
717 \r
718         width = wallptr->x2 - wallptr->x1;\r
719         if (width)\r
720         {\r
721                 heightchange = wallptr->height2 - wallptr->height1;\r
722                 asm     mov     ax,[heightchange]\r
723                 asm     mov     WORD PTR [longheightchange+2],ax\r
724                 asm     mov     WORD PTR [longheightchange],0   // avoid long shift by 16\r
725                 fracstep = longheightchange/width;\r
726         }\r
727 \r
728         fracheight = ((long)wallptr->height1<<16)+0x8000;\r
729         skip = wallptr->leftclip - wallptr->x1;\r
730         if (skip)\r
731                 fracheight += fracstep*skip;\r
732 \r
733 //\r
734 // setup for texture mapping\r
735 //\r
736 // mapadd is 64*64 (to keep source positive) + the origin wall intercept\r
737 // distance has 6 unit bits, and 6 frac bits\r
738 // traceangle is the center view angle in FINEANGLES, moved to be in\r
739 // the +-90 degree range (to thew right of origin)\r
740 //\r
741         traceangle = fineviewangle;\r
742         //\r
743         // find wall picture to map from\r
744         //\r
745         if (wallptr->side)\r
746         {       // east or west wall\r
747 \r
748                 wallpic = walllight1[wallptr->color+wall_anim_pos[wallptr->color]];\r
749                 if (wallptr->planecoord < viewxpix)\r
750                 {\r
751                         distance = viewxpix-wallptr->planecoord;\r
752                         traceangle -= FINEANGLES/2;\r
753                         mapadd = (64-viewypix&63);              // the pixel spot of the origin\r
754                 }\r
755                 else\r
756                 {\r
757                         distance = wallptr->planecoord-viewxpix;\r
758                         // traceangle is correct\r
759                         mapadd = viewypix&63;           // the pixel spot of the origin\r
760                 }\r
761         }\r
762         else\r
763         {       // north or south wall\r
764 \r
765                 wallpic = walldark1[wallptr->color+wall_anim_pos[wallptr->color]];\r
766                 if (wallptr->planecoord < viewypix)\r
767                 {\r
768                         distance = viewypix-wallptr->planecoord;\r
769                         traceangle -= FINEANGLES/4;\r
770                         mapadd = viewxpix&63;           // the pixel spot of the origin\r
771                 }\r
772                 else\r
773                 {\r
774                         distance = wallptr->planecoord-viewypix;\r
775                         traceangle -= FINEANGLES*3/4;\r
776                         mapadd = (64-viewxpix&63);              // the pixel spot of the origin\r
777                 }\r
778         }\r
779 \r
780         mapadd = 64*64-mapadd;                          // make sure it stays positive\r
781 \r
782         wallpicseg = (unsigned)walldirectory[wallpic-FIRSTWALLPIC];\r
783         if (traceangle > FINEANGLES/2)\r
784                 traceangle -= FINEANGLES;\r
785 \r
786 //\r
787 // calculate everything\r
788 //\r
789 // IMPORTANT!  This loop is executed around 5000 times / second!\r
790 //\r
791         lastpix = lastsource = (unsigned)-1;\r
792 \r
793         for (x = wallptr->leftclip ; x <= wallptr->rightclip ; x++)\r
794         {\r
795                 //\r
796                 // height\r
797                 //\r
798                 asm     mov     ax,WORD PTR [fracheight]\r
799                 asm     mov     dx,WORD PTR [fracheight+2]\r
800                 asm     mov     cx,dx\r
801                 asm     add     ax,WORD PTR [fracstep]\r
802                 asm     adc     dx,WORD PTR [fracstep+2]\r
803                 asm     mov     WORD PTR [fracheight],ax\r
804                 asm     mov     WORD PTR [fracheight+2],dx\r
805                 asm     mov     bx,[x]\r
806                 asm     shl     bx,1\r
807                 asm     cmp     cx,MAXSCALEHEIGHT\r
808                 asm     jbe     storeheight\r
809                 asm     mov     cx,MAXSCALEHEIGHT\r
810 storeheight:\r
811                 asm     mov WORD PTR [wallheight+bx],cx\r
812                 asm     mov WORD PTR [zbuffer+bx],cx\r
813 \r
814 //              height = fracheight>>16;\r
815 //              fracheight += fracstep;\r
816 //              if (height > MAXSCALEHEIGHT)\r
817 //                      height = MAXSCALEHEIGHT;\r
818 //              wallheight[x] = zbuffer[x] = height;\r
819 \r
820                 //\r
821                 // texture map\r
822                 //\r
823                 angle = pixelangle[x]+traceangle;\r
824                 if (angle<0)\r
825                         angle+=FINEANGLES;\r
826 \r
827                 slope = finetangent[angle];\r
828 \r
829 //\r
830 // distance is an unsigned 6.6 bit number (12 pixel bits)\r
831 // slope is a signed 5.10 bit number\r
832 // result is a signed 11.16 bit number\r
833 //\r
834 \r
835 #if 0\r
836                 source = distance*slope;\r
837                 source >>=20;\r
838 \r
839                 source += mapadd;\r
840                 source &= 63;                           // mask off the unused units\r
841                 source = 63-source;\r
842                 source <<= 6;                           // multiply by 64 for offset into pic\r
843 #endif\r
844                 asm     mov     ax,[distance]\r
845                 asm     imul    [slope]                 // ax is the source pixel\r
846                 asm     mov     al,ah\r
847                 asm     shr     al,1\r
848                 asm     shr     al,1                            // low 6 bits is now pixel number\r
849                 asm     add     ax,[mapadd]\r
850                 asm     and ax,63\r
851                 asm     mov     dx,63\r
852                 asm     sub     dx,ax                           // otherwise it is backwards\r
853                 asm     shl     dx,1\r
854                 asm     shl     dx,1\r
855                 asm     shl     dx,1\r
856                 asm     shl     dx,1\r
857                 asm     shl     dx,1\r
858                 asm     shl     dx,1                            // *64 to index into shape\r
859                 asm     mov     [source],dx\r
860 \r
861                 if (source != lastsource)\r
862                 {\r
863                         if (lastpix != (unsigned)-1)\r
864                         {\r
865                                 wallofs[lastpix] = lastsource;\r
866                                 wallseg[lastpix] = wallpicseg;\r
867                                 wallwidth[lastpix] = lastwidth;\r
868                         }\r
869                         lastpix = x;\r
870                         lastsource = source;\r
871                         lastwidth = 1;\r
872                 }\r
873                 else\r
874                         lastwidth++;                    // optimized draw, same map as last one\r
875         }\r
876         wallofs[lastpix] = lastsource;\r
877         wallseg[lastpix] = wallpicseg;\r
878         wallwidth[lastpix] = lastwidth;\r
879 }\r
880 \r
881 \r
882 //==========================================================================\r
883 \r
884 \r
885 /*\r
886 =================\r
887 =\r
888 = TraceRay\r
889 =\r
890 = Used to find the left and rightmost tile in the view area to be traced from\r
891 = Follows a ray of the given angle from viewx,viewy in the global map until\r
892 = it hits a solid tile\r
893 = sets:\r
894 =   tile.x,tile.y       : tile coordinates of contacted tile\r
895 =   tilecolor   : solid tile's color\r
896 =\r
897 ==================\r
898 */\r
899 \r
900 int tilecolor;\r
901 \r
902 void TraceRay (unsigned angle)\r
903 {\r
904   long tracex,tracey,tracexstep,traceystep,searchx,searchy;\r
905   fixed fixtemp;\r
906   int otx,oty,searchsteps;\r
907 \r
908   tracexstep = costable[angle];\r
909   traceystep = sintable[angle];\r
910 \r
911 //\r
912 // advance point so it is even with the view plane before we start checking\r
913 //\r
914   fixtemp = FixedByFrac(prestep,tracexstep);\r
915   tracex = viewx+fixtemp;\r
916   fixtemp = FixedByFrac(prestep,traceystep);\r
917   tracey = viewy-fixtemp;\r
918 \r
919   tile.x = tracex>>TILESHIFT;   // starting point in tiles\r
920   tile.y = tracey>>TILESHIFT;\r
921 \r
922 \r
923   if (tracexstep<0)                     // use 2's complement, not signed magnitude\r
924         tracexstep = -(tracexstep&0x7fffffff);\r
925 \r
926   if (traceystep<0)                     // use 2's complement, not signed magnitude\r
927         traceystep = -(traceystep&0x7fffffff);\r
928 \r
929 //\r
930 // we assume viewx,viewy is not inside a solid tile, so go ahead one step\r
931 //\r
932 \r
933   do    // until a solid tile is hit\r
934   {\r
935     otx = tile.x;\r
936         oty = tile.y;\r
937         spotvis[otx][oty] = true;\r
938         tracex += tracexstep;\r
939     tracey -= traceystep;\r
940     tile.x = tracex>>TILESHIFT;\r
941         tile.y = tracey>>TILESHIFT;\r
942 \r
943         if (tile.x!=otx && tile.y!=oty && (tilemap[otx][tile.y] || tilemap[tile.x][oty]) )\r
944     {\r
945       //\r
946           // trace crossed two solid tiles, so do a binary search along the line\r
947           // to find a spot where only one tile edge is crossed\r
948       //\r
949       searchsteps = 0;\r
950       searchx = tracexstep;\r
951       searchy = traceystep;\r
952       do\r
953       {\r
954         searchx/=2;\r
955         searchy/=2;\r
956         if (tile.x!=otx && tile.y!=oty)\r
957         {\r
958          // still too far\r
959           tracex -= searchx;\r
960           tracey += searchy;\r
961         }\r
962         else\r
963         {\r
964          // not far enough, no tiles crossed\r
965           tracex += searchx;\r
966           tracey -= searchy;\r
967         }\r
968 \r
969         //\r
970         // if it is REAL close, go for the most clockwise intersection\r
971         //\r
972         if (++searchsteps == 16)\r
973         {\r
974           tracex = (long)otx<<TILESHIFT;\r
975           tracey = (long)oty<<TILESHIFT;\r
976           if (tracexstep>0)\r
977           {\r
978                 if (traceystep<0)\r
979                 {\r
980                   tracex += TILEGLOBAL-1;\r
981                   tracey += TILEGLOBAL;\r
982                 }\r
983                 else\r
984                 {\r
985                   tracex += TILEGLOBAL;\r
986                 }\r
987           }\r
988           else\r
989           {\r
990                 if (traceystep<0)\r
991                 {\r
992                   tracex --;\r
993                   tracey += TILEGLOBAL-1;\r
994                 }\r
995                 else\r
996                 {\r
997                   tracey --;\r
998                 }\r
999           }\r
1000         }\r
1001 \r
1002         tile.x = tracex>>TILESHIFT;\r
1003         tile.y = tracey>>TILESHIFT;\r
1004 \r
1005           } while (( tile.x!=otx && tile.y!=oty) || (tile.x==otx && tile.y==oty) );\r
1006         }\r
1007   } while (!(tilecolor = tilemap[tile.x][tile.y]) );\r
1008 \r
1009 }\r
1010 \r
1011 //==========================================================================\r
1012 \r
1013 \r
1014 /*\r
1015 ========================\r
1016 =\r
1017 = FixedByFrac\r
1018 =\r
1019 = multiply a 16/16 bit, 2's complement fixed point number by a 16 bit\r
1020 = fraction, passed as a signed magnitude 32 bit number\r
1021 =\r
1022 ========================\r
1023 */\r
1024 \r
1025 #pragma warn -rvl                       // I stick the return value in with ASMs\r
1026 \r
1027 fixed FixedByFrac (fixed a, fixed b)\r
1028 {\r
1029   fixed value;\r
1030 \r
1031 //\r
1032 // setup\r
1033 //\r
1034 asm     mov     si,[WORD PTR b+2]       // sign of result = sign of fraction\r
1035 \r
1036 asm     mov     ax,[WORD PTR a]\r
1037 asm     mov     cx,[WORD PTR a+2]\r
1038 \r
1039 asm     or      cx,cx\r
1040 asm     jns     aok:                            // negative?\r
1041 asm     not     ax\r
1042 asm     not     cx\r
1043 asm     add     ax,1\r
1044 asm     adc     cx,0\r
1045 asm     xor     si,0x8000                       // toggle sign of result\r
1046 aok:\r
1047 \r
1048 //\r
1049 // multiply  cx:ax by bx\r
1050 //\r
1051 asm     mov     bx,[WORD PTR b]\r
1052 asm     mul     bx                                      // fraction*fraction\r
1053 asm     mov     di,dx                           // di is low word of result\r
1054 asm     mov     ax,cx                           //\r
1055 asm     mul     bx                                      // units*fraction\r
1056 asm add ax,di\r
1057 asm     adc     dx,0\r
1058 \r
1059 //\r
1060 // put result dx:ax in 2's complement\r
1061 //\r
1062 asm     test    si,0x8000               // is the result negative?\r
1063 asm     jz      ansok:\r
1064 asm     not     ax\r
1065 asm     not     dx\r
1066 asm     add     ax,1\r
1067 asm     adc     dx,0\r
1068 \r
1069 ansok:;\r
1070 \r
1071 }\r
1072 \r
1073 #pragma warn +rvl\r
1074 \r
1075 #if 0\r
1076 /*\r
1077 =========================\r
1078 =\r
1079 = FixedAdd\r
1080 =\r
1081 = add two 16 bit fixed point numbers\r
1082 = to subtract, invert the sign of B before invoking\r
1083 =\r
1084 =========================\r
1085 */\r
1086 \r
1087 fixed FixedAdd (fixed a, fixed b)\r
1088 {\r
1089   fixed value;\r
1090 \r
1091 asm     mov     ax,[WORD PTR a]\r
1092 asm     mov     dx,[WORD PTR a+2]\r
1093 \r
1094 asm     mov     bx,[WORD PTR b]\r
1095 asm     mov     cx,[WORD PTR b+2]\r
1096 \r
1097 asm     or      dx,dx\r
1098 asm     jns     aok:            // negative?\r
1099 asm     and     dx,0x7fff\r
1100 asm     not     ax              // convert a from signed magnitude to 2's compl\r
1101 asm     not     dx\r
1102 asm     add     ax,1\r
1103 asm     adc     dx,0\r
1104 aok:\r
1105 \r
1106 asm     or      cx,cx\r
1107 asm     jns     bok:            // negative?\r
1108 asm     and     cx,0x7fff\r
1109 asm     not     bx              // convert b from signed magnitude to 2's compl\r
1110 asm     not     cx\r
1111 asm     add     bx,1\r
1112 asm     adc     cx,0\r
1113 bok:\r
1114 \r
1115 asm     add     ax,bx           // perform the addition\r
1116 asm     adc     dx,cx\r
1117 asm     jns     done\r
1118 \r
1119 asm     and     dx,0x7fff       // value was negative\r
1120 asm     not     ax              // back to signed magnitude\r
1121 asm     not     dx\r
1122 asm     add     ax,1\r
1123 asm     adc     dx,0\r
1124 \r
1125 done:\r
1126 \r
1127 asm     mov     [WORD PTR value],ax\r
1128 asm     mov     [WORD PTR value+2],dx\r
1129 \r
1130   return value;\r
1131 }\r
1132 #endif\r
1133 \r
1134 //==========================================================================\r
1135 \r
1136 \r
1137 /*\r
1138 ========================\r
1139 =\r
1140 = TransformPoint\r
1141 =\r
1142 = Takes paramaters:\r
1143 =   gx,gy               : globalx/globaly of point\r
1144 =\r
1145 = globals:\r
1146 =   viewx,viewy         : point of view\r
1147 =   viewcos,viewsin     : sin/cos of viewangle\r
1148 =\r
1149 =\r
1150 = defines:\r
1151 =   CENTERX             : pixel location of center of view window\r
1152 =   TILEGLOBAL          : size of one\r
1153 =   FOCALLENGTH         : distance behind viewx/y for center of projection\r
1154 =   scale               : conversion from global value to screen value\r
1155 =\r
1156 = returns:\r
1157 =   screenx,screenheight: projected edge location and size\r
1158 =\r
1159 ========================\r
1160 */\r
1161 \r
1162 void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight)\r
1163 {\r
1164   int ratio;\r
1165   fixed gxt,gyt,nx,ny;\r
1166 \r
1167 //\r
1168 // translate point to view centered coordinates\r
1169 //\r
1170   gx = gx-viewx;\r
1171   gy = gy-viewy;\r
1172 \r
1173 //\r
1174 // calculate newx\r
1175 //\r
1176   gxt = FixedByFrac(gx,viewcos);\r
1177   gyt = FixedByFrac(gy,viewsin);\r
1178   nx = gxt-gyt;\r
1179 \r
1180 //\r
1181 // calculate newy\r
1182 //\r
1183   gxt = FixedByFrac(gx,viewsin);\r
1184   gyt = FixedByFrac(gy,viewcos);\r
1185   ny = gyt+gxt;\r
1186 \r
1187 //\r
1188 // calculate perspective ratio\r
1189 //\r
1190   if (nx<0)\r
1191         nx = 0;\r
1192 \r
1193   ratio = nx*scale/FOCALLENGTH;\r
1194 \r
1195   if (ratio<=MINRATIO)\r
1196         ratio = MINRATIO;\r
1197 \r
1198   *screenx = CENTERX + ny/ratio;\r
1199 \r
1200   *screenheight = TILEGLOBAL/ratio;\r
1201 \r
1202 }\r
1203 \r
1204 \r
1205 //\r
1206 // transform actor\r
1207 //\r
1208 void TransformActor (objtype *ob)\r
1209 {\r
1210   int ratio;\r
1211   fixed gx,gy,gxt,gyt,nx,ny;\r
1212 \r
1213 //\r
1214 // translate point to view centered coordinates\r
1215 //\r
1216   gx = ob->x-viewx;\r
1217   gy = ob->y-viewy;\r
1218 \r
1219 //\r
1220 // calculate newx\r
1221 //\r
1222   gxt = FixedByFrac(gx,viewcos);\r
1223   gyt = FixedByFrac(gy,viewsin);\r
1224   nx = gxt-gyt-ob->size;\r
1225 \r
1226 //\r
1227 // calculate newy\r
1228 //\r
1229   gxt = FixedByFrac(gx,viewsin);\r
1230   gyt = FixedByFrac(gy,viewcos);\r
1231   ny = gyt+gxt;\r
1232 \r
1233 //\r
1234 // calculate perspective ratio\r
1235 //\r
1236   if (nx<0)\r
1237         nx = 0;\r
1238 \r
1239   ratio = nx*scale/FOCALLENGTH;\r
1240 \r
1241   if (ratio<=MINRATIO)\r
1242         ratio = MINRATIO;\r
1243 \r
1244   ob->viewx = CENTERX + ny/ratio;\r
1245 \r
1246   ob->viewheight = TILEGLOBAL/ratio;\r
1247 }\r
1248 \r
1249 //==========================================================================\r
1250 \r
1251 fixed TransformX (fixed gx, fixed gy)\r
1252 {\r
1253   int ratio;\r
1254   fixed gxt,gyt,nx,ny;\r
1255 \r
1256 //\r
1257 // translate point to view centered coordinates\r
1258 //\r
1259   gx = gx-viewx;\r
1260   gy = gy-viewy;\r
1261 \r
1262 //\r
1263 // calculate newx\r
1264 //\r
1265   gxt = FixedByFrac(gx,viewcos);\r
1266   gyt = FixedByFrac(gy,viewsin);\r
1267 \r
1268   return gxt-gyt;\r
1269 }\r
1270 \r
1271 //==========================================================================\r
1272 \r
1273 /*\r
1274 ==================\r
1275 =\r
1276 = BuildTables\r
1277 =\r
1278 = Calculates:\r
1279 =\r
1280 = scale                 projection constant\r
1281 = sintable/costable     overlapping fractional tables\r
1282 = firstangle/lastangle  angles from focalpoint to left/right view edges\r
1283 = prestep               distance from focal point before checking for tiles\r
1284 =\r
1285 ==================\r
1286 */\r
1287 \r
1288 void BuildTables (void)\r
1289 {\r
1290   int           i;\r
1291   long          intang;\r
1292   long          x;\r
1293   float         angle,anglestep,radtoint;\r
1294   double        tang;\r
1295   fixed         value;\r
1296 \r
1297 //\r
1298 // calculate the angle offset from view angle of each pixel's ray\r
1299 //\r
1300         radtoint = (float)FINEANGLES/2/PI;\r
1301         for (i=0;i<VIEWWIDTH/2;i++)\r
1302         {\r
1303         // start 1/2 pixel over, so viewangle bisects two middle pixels\r
1304                 x = (TILEGLOBAL*i+TILEGLOBAL/2)/VIEWWIDTH;\r
1305                 tang = (float)x/(FOCALLENGTH+MINDIST);\r
1306                 angle = atan(tang);\r
1307                 intang = angle*radtoint;\r
1308                 pixelangle[VIEWWIDTH/2-1-i] = intang;\r
1309                 pixelangle[VIEWWIDTH/2+i] = -intang;\r
1310         }\r
1311 \r
1312 //\r
1313 // calculate fine tangents\r
1314 // 1 sign bit, 5 units (clipped to), 10 fracs\r
1315 //\r
1316 #define MININT  (-MAXINT)\r
1317 \r
1318         for (i=0;i<FINEANGLES/4;i++)\r
1319         {\r
1320                 intang = tan(i/radtoint)*(1l<<10);\r
1321 \r
1322                 //\r
1323                 // if the tangent is not reprentable in this many bits, bound the\r
1324                 // units part ONLY\r
1325                 //\r
1326                 if (intang>MAXINT)\r
1327                         intang = 0x8f00 | (intang & 0xff);\r
1328                 else if (intang<MININT)\r
1329                         intang = 0xff00 | (intang & 0xff);\r
1330 \r
1331                 finetangent[i] = intang;\r
1332 //              finetangent[FINEANGLES/2+i] = intang;\r
1333 //              finetangent[FINEANGLES/2-i-1] = -intang;\r
1334                 finetangent[FINEANGLES-i-1] = -intang;\r
1335         }\r
1336 \r
1337 //\r
1338 // calculate scale value so one tile at mindist allmost fills the view horizontally\r
1339 //\r
1340   scale = GLOBAL1/VIEWWIDTH;\r
1341   scale *= focallength;\r
1342   scale /= (focallength+mindist);\r
1343 \r
1344 //\r
1345 // costable overlays sintable with a quarter phase shift\r
1346 // ANGLES is assumed to be divisable by four\r
1347 //\r
1348 // The low word of the value is the fraction, the high bit is the sign bit,\r
1349 // bits 16-30 should be 0\r
1350 //\r
1351 \r
1352   angle = 0;\r
1353   anglestep = PI/2/ANGLEQUAD;\r
1354   for (i=0;i<=ANGLEQUAD;i++)\r
1355   {\r
1356         value=GLOBAL1*sin(angle);\r
1357         sintable[i]=\r
1358           sintable[i+ANGLES]=\r
1359           sintable[ANGLES/2-i] = value;\r
1360         sintable[ANGLES-i]=\r
1361           sintable[ANGLES/2+i] = value | 0x80000000l;\r
1362         angle += anglestep;\r
1363   }\r
1364 \r
1365 //\r
1366 // figure trace angles for first and last pixel on screen\r
1367 //\r
1368   angle = atan((float)VIEWWIDTH/2*scale/FOCALLENGTH);\r
1369   angle *= ANGLES/(PI*2);\r
1370 \r
1371   intang = (int)angle+1;\r
1372   firstangle = intang;\r
1373   lastangle = -intang;\r
1374 \r
1375   prestep = GLOBAL1*((float)FOCALLENGTH/costable[firstangle]);\r
1376 \r
1377 //\r
1378 // misc stuff\r
1379 //\r
1380   walls[0].x2 = VIEWX-1;\r
1381   walls[0].height2 = 32000;\r
1382 }\r
1383 \r
1384 \r
1385 //==========================================================================\r
1386 \r
1387 /*\r
1388 =====================\r
1389 =\r
1390 = ClearScreen\r
1391 =\r
1392 =====================\r
1393 */\r
1394 \r
1395 void ClearScreen (void)\r
1396 {\r
1397         unsigned topcolor=*skycolor, bottomcolor=*groundcolor;\r
1398         unsigned topimage=topcolor&0xf0,bottomimage=bottomcolor&0xf0;\r
1399         unsigned pfoffset=0;\r
1400 \r
1401 \r
1402 #if USE_STRIPS\r
1403         if (topimage == 0x20)           // special code for lightning\r
1404                 topimage = topcolor = 0;\r
1405 \r
1406 // Manually wipe screen with solid color.\r
1407 // If BOTH sky and ground are 'images' don't manually clear it!\r
1408 //\r
1409         if ((!topimage) || (!bottomimage))\r
1410         {\r
1411 #endif\r
1412 \r
1413   //\r
1414   // clear the screen\r
1415   //\r
1416 asm     mov     dx,GC_INDEX\r
1417 asm     mov     ax,GC_MODE + 256*2              // read mode 0, write mode 2\r
1418 asm     out     dx,ax\r
1419 asm     mov     ax,GC_BITMASK + 255*256\r
1420 asm     out     dx,ax\r
1421 \r
1422 //asm     mov     dx,40-VIEWWIDTH/8                                     // dx = modulo\r
1423 asm     mov     bl,VIEWWIDTH/16\r
1424 asm     mov     bh,CENTERY+1\r
1425 \r
1426 asm     mov     ax,topcolor\r
1427 asm     mov     es,[screenseg]\r
1428 asm     mov     di,[bufferofs]\r
1429 asm     add     di,((SCREENWIDTH*VIEWY)+(VIEWX/8))\r
1430 \r
1431 toploop:\r
1432 asm     mov     cl,bl\r
1433 asm     rep     stosw\r
1434 asm     stosb\r
1435 //asm     add     di,dx                                 // no need to add "0" modulo\r
1436 asm     dec     bh\r
1437 asm     jnz     toploop\r
1438 \r
1439 asm     mov     bh,CENTERY+1\r
1440 asm     mov     ax,bottomcolor\r
1441 \r
1442 bottomloop:\r
1443 asm     mov     cl,bl\r
1444 asm     rep     stosw\r
1445 asm     stosb\r
1446 //asm     add     di,dx                                 // no need to add "0" modulo\r
1447 asm     dec     bh\r
1448 asm     jnz     bottomloop\r
1449 \r
1450 #if USE_STRIPS\r
1451         }\r
1452 \r
1453 \r
1454 //\r
1455 // code to test parallax turning\r
1456 //\r
1457 \r
1458         if (topimage)\r
1459         {\r
1460                 topimage -= 16;\r
1461                 pfoffset = LONG_PERCENTAGE(3200,359,(359-player->angle),12);\r
1462                 while (pfoffset >= 640)\r
1463                         pfoffset -= 640;\r
1464                 LatchDrawPicStrip(0,0,SKY1PIC+topimage,pfoffset+8);\r
1465         }\r
1466 \r
1467         if (bottomimage)\r
1468         {\r
1469 ////            pfoffset = LONG_PERCENTAGE(3200,359,(359-player->angle),12)+320;\r
1470 //              pfoffset += 320;\r
1471 //              while (pfoffset >= 640)\r
1472 //                      pfoffset -= 640;\r
1473 //              LatchDrawPicStrip(0,64,SKY1PIC+topimage,pfoffset+8);\r
1474                 bottomimage -= 16;\r
1475                 LatchDrawPic(0,64,GND1PIC+bottomimage);\r
1476         }\r
1477 #endif\r
1478 \r
1479 \r
1480 asm     mov     dx,GC_INDEX\r
1481 asm     mov     ax,GC_MODE + 256*10             // read mode 1, write mode 2\r
1482 asm     out     dx,ax\r
1483 asm     mov     al,GC_BITMASK\r
1484 asm     out     dx,al\r
1485 \r
1486 }\r
1487 \r
1488 //==========================================================================\r
1489 \r
1490 /*\r
1491 =====================\r
1492 =\r
1493 = DrawWallList\r
1494 =\r
1495 = Clips and draws all the walls traced this refresh\r
1496 =\r
1497 =====================\r
1498 */\r
1499 \r
1500 void DrawWallList (void)\r
1501 {\r
1502         int i,leftx,newleft,rightclip;\r
1503         walltype *wall, *check;\r
1504 \r
1505 asm     mov     ax,ds\r
1506 asm     mov     es,ax\r
1507 asm     mov     di,OFFSET wallwidth\r
1508 asm     xor     ax,ax\r
1509 asm     mov     cx,VIEWWIDTH/2\r
1510 asm     rep     stosw\r
1511 \r
1512         ClearScreen ();\r
1513 \r
1514         rightwall->x1 = VIEWXH+1;\r
1515         rightwall->height1 = 32000;\r
1516         (rightwall+1)->x1 = 32000;\r
1517 \r
1518         leftx = -1;\r
1519 \r
1520         for (wall=&walls[1];wall<rightwall && leftx<=VIEWXH ;wall++)\r
1521         {\r
1522           if (leftx >= wall->x2)\r
1523                 continue;\r
1524 \r
1525           rightclip = wall->x2;\r
1526 \r
1527           check = wall+1;\r
1528           while (check->x1 <= rightclip && check->height1 >= wall->height2)\r
1529           {\r
1530                 rightclip = check->x1-1;\r
1531                 check++;\r
1532           }\r
1533 \r
1534           if (rightclip>VIEWXH)\r
1535                 rightclip=VIEWXH;\r
1536 \r
1537           if (leftx < wall->x1 - 1)\r
1538                 newleft = wall->x1-1;           // there was black space between walls\r
1539           else\r
1540                 newleft = leftx;\r
1541 \r
1542           if (rightclip > newleft)\r
1543           {\r
1544                 wall->leftclip = newleft+1;\r
1545                 wall->rightclip = rightclip;\r
1546                 DrawVWall (wall);\r
1547                 leftx = rightclip;\r
1548           }\r
1549         }\r
1550 \r
1551 #ifndef DRAWEACH\r
1552         ScaleWalls ();                                  // draw all the walls\r
1553 #endif\r
1554 }\r
1555 \r
1556 //==========================================================================\r
1557 \r
1558 /*\r
1559 =====================\r
1560 =\r
1561 = DrawScaleds\r
1562 =\r
1563 = Draws all objects that are visable\r
1564 =\r
1565 =====================\r
1566 */\r
1567 \r
1568 objtype *depthsort[MAXACTORS];\r
1569 \r
1570 void DrawScaleds (void)\r
1571 {\r
1572 #if USE_INERT_LIST\r
1573                 extern inertobjtype inertobjlist[], *inert;\r
1574 \r
1575                 boolean inertlist=false;\r
1576 #endif\r
1577         int             i,j,least,numvisable,height;\r
1578         objtype         *obj,**vislist,*farthest;\r
1579         memptr          shape;\r
1580         byte            *tilespot,*visspot;\r
1581 \r
1582         numvisable = 0;\r
1583 \r
1584 //\r
1585 // calculate base positions of all objects\r
1586 //\r
1587         vislist = &depthsort[0];\r
1588 \r
1589         obj = player->next;\r
1590         while (obj)\r
1591         {\r
1592                 tilespot = &tilemap[0][0]+(obj->tilex<<6)+obj->tiley;\r
1593                 visspot = &spotvis[0][0]+(obj->tilex<<6)+obj->tiley;\r
1594                 //\r
1595                 // could be in any of the nine surrounding tiles\r
1596                 //\r
1597                 if (*visspot\r
1598                 || ( *(visspot-1) && !*(tilespot-1) )\r
1599                 || ( *(visspot+1) && !*(tilespot+1) )\r
1600                 || ( *(visspot-65) && !*(tilespot-65) )\r
1601                 || ( *(visspot-64) && !*(tilespot-64) )\r
1602                 || ( *(visspot-63) && !*(tilespot-63) )\r
1603                 || ( *(visspot+65) && !*(tilespot+65) )\r
1604                 || ( *(visspot+64) && !*(tilespot+64) )\r
1605                 || ( *(visspot+63) && !*(tilespot+63) ) )\r
1606                 {\r
1607 #if USE_INERT_LIST\r
1608                         if (!inertlist)\r
1609 #endif\r
1610                                 if ((obj->active == noalways) || (obj->active == always))\r
1611                                         obj->active = always;\r
1612                                 else\r
1613                                         obj->active = yes;\r
1614                         TransformActor (obj);\r
1615                         if (!obj->viewheight || obj->viewheight > VIEWWIDTH)\r
1616                                 goto cont;                       // too close or far away\r
1617 \r
1618                         if (!obj->state->shapenum)\r
1619                                 goto cont;\r
1620 \r
1621                         *vislist++ = obj;\r
1622                         numvisable++;\r
1623                 }\r
1624                 else\r
1625 #if USE_INERT_LIST\r
1626                         if (!inertlist)\r
1627 #endif\r
1628                                 if ((obj->active != always) && (obj->active != noalways))\r
1629                                         obj->active = no;\r
1630 \r
1631 cont:;\r
1632                 obj = obj->next;\r
1633 #if USE_INERT_LIST\r
1634                 if ((!obj) && (!inertlist))\r
1635                 {\r
1636                         if (inert != inertobjlist)\r
1637                                 obj = (objtype *)inertobjlist;\r
1638                         inertlist = true;\r
1639                 }\r
1640 #endif\r
1641         }\r
1642 \r
1643         if (vislist == &depthsort[0])\r
1644                 return;                                         // no visable objects\r
1645 \r
1646 //\r
1647 // draw from back to front\r
1648 //\r
1649         for (i = 0; i<numvisable; i++)\r
1650         {\r
1651                 least = 32000;\r
1652                 for (j=0;j<numvisable;j++)\r
1653                 {\r
1654                         height = depthsort[j]->viewheight;\r
1655                         if (height < least)\r
1656                         {\r
1657                                 least = height;\r
1658                                 farthest = depthsort[j];\r
1659                         }\r
1660                 }\r
1661                 //\r
1662                 // draw farthest\r
1663                 //\r
1664                 shape = shapedirectory[farthest->state->shapenum-FIRSTSCALEPIC];\r
1665                 ScaleShape(farthest->viewx,shape,farthest->viewheight);\r
1666                 farthest->viewheight = 32000;\r
1667         }\r
1668 }\r
1669 \r
1670 //==========================================================================\r
1671 \r
1672 \r
1673 /*\r
1674 =====================\r
1675 =\r
1676 = CalcTics\r
1677 =\r
1678 =====================\r
1679 */\r
1680 \r
1681 void CalcTics (void)\r
1682 {\r
1683         long    newtime,oldtimecount;\r
1684 \r
1685 \r
1686 #ifdef PROFILE\r
1687         tics = 1;\r
1688         return;\r
1689 #endif\r
1690 \r
1691 //\r
1692 // calculate tics since last refresh for adaptive timing\r
1693 //\r
1694         if (lasttimecount > TimeCount)\r
1695                 TimeCount = lasttimecount;              // if the game was paused a LONG time\r
1696 \r
1697 #if 0\r
1698         if (DemoMode)                                   // demo recording and playback needs\r
1699         {                                                               // to be constant\r
1700 //\r
1701 // take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
1702 //\r
1703                 oldtimecount = lasttimecount;\r
1704                 while (TimeCount<oldtimecount+DEMOTICS*2)\r
1705                 ;\r
1706                 lasttimecount = oldtimecount + DEMOTICS;\r
1707                 TimeCount = lasttimecount + DEMOTICS;\r
1708                 realtics = tics = DEMOTICS;\r
1709         }\r
1710         else\r
1711 #endif\r
1712         {\r
1713 //\r
1714 // non demo, so report actual time\r
1715 //\r
1716                 newtime = TimeCount;\r
1717                 realtics = tics = newtime-lasttimecount;\r
1718                 lasttimecount = newtime;\r
1719 \r
1720 #ifdef FILEPROFILE\r
1721                         strcpy (scratch,"\tTics:");\r
1722                         itoa (tics,str,10);\r
1723                         strcat (scratch,str);\r
1724                         strcat (scratch,"\n");\r
1725                         write (profilehandle,scratch,strlen(scratch));\r
1726 #endif\r
1727 \r
1728                 if (tics>MAXTICS)\r
1729                 {\r
1730                         TimeCount -= (tics-MAXTICS);\r
1731                         tics = MAXTICS;\r
1732                 }\r
1733 \r
1734                 if (realtics>MAXREALTICS)\r
1735                         realtics = MAXREALTICS;\r
1736         }\r
1737 }\r
1738 \r
1739 \r
1740 //==========================================================================\r
1741 \r
1742 \r
1743 /*\r
1744 ========================\r
1745 =\r
1746 = DrawHand\r
1747 =\r
1748 ========================\r
1749 */\r
1750 \r
1751 void    DrawHand (void)\r
1752 {\r
1753         #define HAND_X_POS      ((VIEWWIDTH/16)-(10/2))         // "10" = hand width in bytes\r
1754 \r
1755         #define picnum HAND1PICM\r
1756 \r
1757         memptr source;\r
1758         unsigned dest,width,height;\r
1759 \r
1760 //      if (gamestate.shotpower || boltsleft)\r
1761 //              picnum += (((unsigned)TimeCount>>3)&1);\r
1762 \r
1763         source = grsegs[picnum];\r
1764         dest = ylookup[VIEWHEIGHT-handheight]+HAND_X_POS+bufferofs;                     // 12\r
1765         width = picmtable[picnum-STARTPICM].width;\r
1766         height = picmtable[picnum-STARTPICM].height;\r
1767 \r
1768         VW_MaskBlock(source,0,dest,width,handheight,width*height);\r
1769         EGAMAPMASK(15);\r
1770 }\r
1771 \r
1772 //==========================================================================\r
1773 \r
1774 \r
1775 /*\r
1776 ========================\r
1777 =\r
1778 = ThreeDRefresh\r
1779 =\r
1780 ========================\r
1781 */\r
1782 \r
1783 void    ThreeDRefresh (void)\r
1784 {\r
1785         int tracedir;\r
1786 \r
1787 restart:\r
1788         aborttrace = false;\r
1789 \r
1790 //\r
1791 // clear out the traced array\r
1792 //\r
1793 asm     mov     ax,ds\r
1794 asm     mov     es,ax\r
1795 asm     mov     di,OFFSET spotvis\r
1796 asm     xor     ax,ax\r
1797 asm     mov     cx,[mapwidth]           // mapheight*32 words\r
1798 asm     shl     cx,1\r
1799 asm     shl     cx,1\r
1800 asm     shl     cx,1\r
1801 asm     shl     cx,1\r
1802 asm     shl     cx,1\r
1803 asm     rep stosw\r
1804 \r
1805 \r
1806 //\r
1807 // set up variables for this view\r
1808 //\r
1809 \r
1810         viewangle = player->angle;\r
1811         fineviewangle = viewangle*(FINEANGLES/ANGLES);\r
1812         viewsin = sintable[viewangle];\r
1813         viewcos = costable[viewangle];\r
1814         viewx = player->x - FixedByFrac(FOCALLENGTH,viewcos);\r
1815         viewy = player->y + FixedByFrac(FOCALLENGTH,viewsin);\r
1816         viewx &= 0xfffffc00;            // stop on a pixel boundary\r
1817         viewy &= 0xfffffc00;\r
1818         viewx += 0x180;\r
1819         viewy += 0x180;\r
1820         viewxpix = viewx>>10;\r
1821         viewypix = viewy>>10;\r
1822 \r
1823         focal.x = viewx>>TILESHIFT;\r
1824         focal.y = viewy>>TILESHIFT;\r
1825 \r
1826 //\r
1827 // find the rightmost visable tile in view\r
1828 //\r
1829         tracedir = viewangle + lastangle;\r
1830         if (tracedir<0)\r
1831           tracedir+=ANGLES;\r
1832         else if (tracedir>=ANGLES)\r
1833           tracedir-=ANGLES;\r
1834         TraceRay( tracedir );\r
1835         right.x = tile.x;\r
1836         right.y = tile.y;\r
1837 \r
1838 //\r
1839 // find the leftmost visable tile in view\r
1840 //\r
1841         tracedir = viewangle + firstangle;\r
1842         if (tracedir<0)\r
1843           tracedir+=ANGLES;\r
1844         else if (tracedir>=ANGLES)\r
1845           tracedir-=ANGLES;\r
1846         TraceRay( tracedir );\r
1847 \r
1848 //\r
1849 // follow the walls from there to the right\r
1850 //\r
1851         rightwall = &walls[1];\r
1852         FollowWalls ();\r
1853 \r
1854         if (aborttrace)\r
1855                 goto restart;\r
1856 \r
1857 //\r
1858 // actually draw stuff\r
1859 //\r
1860         if (++screenpage == 3)\r
1861                 screenpage = 0;\r
1862 \r
1863         bufferofs = screenloc[screenpage];\r
1864 \r
1865         EGAWRITEMODE(2);\r
1866         EGAMAPMASK(15);\r
1867 \r
1868 //\r
1869 // draw the wall list saved be FollowWalls ()\r
1870 //\r
1871 //      animframe = (TimeCount&8)>>3;\r
1872 \r
1873 //\r
1874 // draw all the scaled images\r
1875 //\r
1876         asm     mov     dx,GC_INDEX\r
1877 \r
1878         asm     mov     ax,GC_COLORDONTCARE\r
1879         asm     out     dx,ax                                           // don't look at any of the planes\r
1880 \r
1881         asm     mov     ax,GC_MODE + 256*(10)           // read mode 1, write mode 2\r
1882         asm     out     dx,ax\r
1883 \r
1884         asm     mov     al,GC_BITMASK\r
1885         asm     out     dx,al\r
1886 \r
1887         AnimateWallList();\r
1888         DrawWallList();\r
1889         DrawScaleds();\r
1890 \r
1891         EGAWRITEMODE(0);\r
1892         EGABITMASK(0xff);\r
1893 \r
1894 //\r
1895 // draw hand\r
1896 //\r
1897         if (handheight)\r
1898                 DrawHand ();\r
1899 \r
1900 //\r
1901 // show screen and time last cycle\r
1902 //\r
1903         if (fizzlein)\r
1904         {\r
1905                 fizzlein = false;\r
1906                 FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,true);\r
1907                 lasttimecount = TimeCount;\r
1908                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
1909         }\r
1910 \r
1911 asm     cli\r
1912 asm     mov     cx,[bufferofs]\r
1913 asm     mov     dx,3d4h         // CRTC address register\r
1914 asm     mov     al,0ch          // start address high register\r
1915 asm     out     dx,al\r
1916 asm     inc     dx\r
1917 asm     mov     al,ch\r
1918 asm     out     dx,al           // set the high byte\r
1919 asm     dec     dx\r
1920 asm     mov     al,0dh          // start address low register\r
1921 asm     out     dx,al\r
1922 asm     inc     dx\r
1923 asm     mov     al,cl\r
1924 asm     out     dx,al           // set the low byte\r
1925 asm     sti\r
1926 \r
1927         displayofs = bufferofs;\r
1928 \r
1929         CalcTics ();\r
1930 \r
1931 }\r
1932 \r