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 / c6_draw.c
1 /* Catacomb Apocalypse 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         0,//CRYSTAL1LIGHTPIC,\r
448         0,//EGYPT1LIGHTPIC,\r
449         EGYPT2LIGHTPIC,\r
450         EGYPT3LIGHTPIC,\r
451 \r
452         FIREWALL1PIC,\r
453         FIREWALL2PIC,\r
454         FIREWALL3PIC,\r
455         FIREWALL4PIC,\r
456 \r
457 \r
458         NEMESISPIC,\r
459 \r
460         ALTARLEFTPIC,\r
461         ALTARRIGHTPIC,\r
462 \r
463         TEMPLEWALLLIGHTPIC,\r
464 \r
465         TORCHWALL1PIC,\r
466         TORCHWALL2PIC,\r
467 \r
468         BRNBRKLIGHTPIC,\r
469         BRNBRKEMLIGHTPIC,\r
470 \r
471         IRONGATEPIC,\r
472 \r
473         BRNFLGLIGHTPIC,\r
474         BRNFLGWINDOWLIGHTPIC,\r
475         BRNFLGVINELIGHTPIC,\r
476         BRNFLGDMGLIGHTPIC,\r
477 \r
478         SPACEDMG1LIGHTPIC,\r
479         SPACEDMG2LIGHTPIC,\r
480 \r
481         SPACE1LIGHTPIC,\r
482         SPACE2LIGHTPIC,\r
483         SPACE3LIGHTPIC,\r
484         SPACE4LIGHTPIC,\r
485 \r
486         SPACE5LIGHTPIC,\r
487         SPACE6LIGHTPIC,\r
488         SPACE7LIGHTPIC,\r
489         SPACE8LIGHTPIC,\r
490 \r
491         0,//SPACE9LIGHTPIC,\r
492         0,//SPACEDMG9LIGHTPIC,\r
493         SPACE10LIGHTPIC,\r
494         RUSTDOORLIGHTPIC,\r
495 \r
496         SPACE11LIGHTPIC,\r
497         SPACE12LIGHTPIC,\r
498         SPACE13LIGHTPIC,\r
499         SPACE14LIGHTPIC,\r
500 \r
501         SPACEDMG5LIGHTPIC,\r
502         SPACEDMG6LIGHTPIC,\r
503 \r
504         TAP1PIC,\r
505         TAP2PIC,\r
506         ENDPIC,\r
507         0,//SIRONLIGHTPIC,\r
508 \r
509         SPCDOOR1LIGHTPIC,\r
510         SPCDOOR2LIGHTPIC,\r
511         SPCDOOR3LIGHTPIC,\r
512         SPCDOOR4LIGHTPIC,\r
513 \r
514         COLUMNSLIGHTPIC,\r
515 \r
516         DEMONSTATUELIGHTPIC,\r
517 \r
518         0,//CRYSTALBWALL1LIGHTPIC,\r
519 \r
520         0,//SRUSTLIGHTPIC,\r
521 \r
522         TROLLSTATUELIGHTPIC,\r
523 \r
524         BRNDMGVINELIGHTPIC,\r
525         TAP3PIC,\r
526         HORNDOORPIC,\r
527         RUNEDOORPIC,\r
528 \r
529         EXP_WALL_1PIC,\r
530         EXP_WALL_2PIC,\r
531         EXP_WALL_3PIC,\r
532         WATER_EXP_WALL_1PIC,\r
533         WATER_EXP_WALL_2PIC,\r
534         WATER_EXP_WALL_3PIC,\r
535 \r
536         IRONDMGLIGHTPIC,\r
537         IRONLIGHTPIC,\r
538         0,\r
539         TROLLBLOODYLIGHTPIC,\r
540         TROLLLIGHTPIC,\r
541 \r
542         0,                                                                                              // INVISIBLE WALL\r
543 \r
544         STONEDOORLIGHTPIC,\r
545         0,\r
546 \r
547         IRONWTR1LIGHTPIC,\r
548         IRONWTR2LIGHTPIC,\r
549         IRONWTR3LIGHTPIC,\r
550 \r
551         RUSTWTR1LIGHTPIC,\r
552         RUSTWTR2LIGHTPIC,\r
553         RUSTWTR3LIGHTPIC,\r
554 \r
555         CEMETARYLIGHTPIC,\r
556         0,      //      STAIRDWNLIGHTPIC,\r
557 \r
558         WGRATE1LIGHTPIC,\r
559         WGRATE2LIGHTPIC,\r
560         WGRATE3LIGHTPIC,\r
561 \r
562         MAS_WIN_LIGHTPIC,\r
563         MAS_DOOR_LIGHTPIC,\r
564         MAS_VINE1_LIGHTPIC,\r
565         MAS_VINE2_LIGHTPIC,\r
566 \r
567   // Start of non-solid walls\r
568         0,\r
569         0,\r
570         0,\r
571         0,\r
572         0,\r
573         0,\r
574 \r
575   // solid walls\r
576         SGRATEPIC,\r
577 };\r
578 \r
579 // NORTH / SOUTH WALLS\r
580 //\r
581 int     far walldark1[NUMFLOORS] = {0,\r
582 \r
583         0,//CRYSTAL1DARKPIC,\r
584         0,//EGYPT1DARKPIC,\r
585         EGYPT2DARKPIC,\r
586         EGYPT3DARKPIC,\r
587 \r
588         FIREWALL1PIC,\r
589         FIREWALL2PIC,\r
590         FIREWALL3PIC,\r
591         FIREWALL4PIC,\r
592 \r
593         NEMESISPIC,\r
594 \r
595         ALTARLEFTPIC,\r
596         ALTARRIGHTPIC,\r
597 \r
598         TEMPLEWALLDARKPIC,\r
599 \r
600         TORCHWALL1PIC,\r
601         TORCHWALL2PIC,\r
602 \r
603         BRNBRKDARKPIC,\r
604         BRNBRKEMDARKPIC,\r
605 \r
606         IRONGATEPIC,\r
607 \r
608         BRNFLGDARKPIC,\r
609         BRNFLGWINDOWDARKPIC,\r
610         BRNFLGVINEDARKPIC,\r
611         BRNFLGDMGDARKPIC,\r
612 \r
613         SPACEDMG1DARKPIC,\r
614         SPACEDMG2DARKPIC,\r
615 \r
616         SPACE1DARKPIC,\r
617         SPACE2DARKPIC,\r
618         SPACE3DARKPIC,\r
619         SPACE4DARKPIC,\r
620 \r
621         SPACE5DARKPIC,\r
622         SPACE6DARKPIC,\r
623         SPACE7DARKPIC,\r
624         SPACE8DARKPIC,\r
625 \r
626         0,//SPACE9DARKPIC,\r
627         0,//SPACEDMG9DARKPIC,\r
628         SPACE10DARKPIC,\r
629         RUSTDOORDARKPIC,\r
630 \r
631         SPACE11DARKPIC,\r
632         SPACE12DARKPIC,\r
633         SPACE13DARKPIC,\r
634         SPACE14DARKPIC,\r
635 \r
636         SPACEDMG5DARKPIC,\r
637         SPACEDMG6DARKPIC,\r
638 \r
639         TAP1PIC,\r
640         TAP2PIC,\r
641         ENDPIC,\r
642         0,//SIRONDARKPIC,\r
643 \r
644         SPCDOOR1DARKPIC,\r
645         SPCDOOR2DARKPIC,\r
646         SPCDOOR3DARKPIC,\r
647         SPCDOOR4DARKPIC,\r
648 \r
649         COLUMNSDARKPIC,\r
650 \r
651         DEMONSTATUEDARKPIC,\r
652 \r
653         0,//CRYSTALBWALL1DARKPIC,\r
654 \r
655         0,//SRUSTDARKPIC,\r
656 \r
657         TROLLSTATUEDARKPIC,\r
658 \r
659         BRNDMGVINEDARKPIC,\r
660         TAP3PIC,\r
661         HORNDOORPIC,\r
662         RUNEDOORPIC,\r
663 \r
664         EXP_WALL_1PIC,\r
665         EXP_WALL_2PIC,\r
666         EXP_WALL_3PIC,\r
667 \r
668         WATER_EXP_WALL_1PIC,\r
669         WATER_EXP_WALL_2PIC,\r
670         WATER_EXP_WALL_3PIC,\r
671 \r
672         IRONDMGDARKPIC,\r
673         IRONDARKPIC,\r
674         0,\r
675         TROLLBLOODYDARKPIC,\r
676 \r
677         TROLLDARKPIC,\r
678 \r
679         0,                                                                                      // INVISIBLE WALL\r
680 \r
681         STONEDOORDARKPIC,\r
682         0,\r
683 \r
684         IRONWTR1DARKPIC,\r
685         IRONWTR2DARKPIC,\r
686         IRONWTR3DARKPIC,\r
687 \r
688         RUSTWTR1DARKPIC,\r
689         RUSTWTR2DARKPIC,\r
690         RUSTWTR3DARKPIC,\r
691 \r
692         CEMETARYDARKPIC,\r
693         0,\r
694 \r
695         WGRATE1DARKPIC,\r
696         WGRATE2DARKPIC,\r
697         WGRATE3DARKPIC,\r
698 \r
699         MAS_WIN_DARKPIC,\r
700         MAS_DOOR_DARKPIC,\r
701         MAS_VINE1_DARKPIC,\r
702         MAS_VINE2_DARKPIC,\r
703 \r
704   // Start of non-solid walls\r
705         0,\r
706         0,\r
707         0,\r
708         0,\r
709         0,\r
710         0,\r
711 \r
712   // solid walls\r
713         SGRATEPIC,\r
714 };\r
715 \r
716 \r
717 /*\r
718 =====================\r
719 =\r
720 = DrawVWall\r
721 =\r
722 = Draws a wall by vertical segments, for texture mapping!\r
723 =\r
724 = wallptr->side is true for east/west walls (constant x)\r
725 =\r
726 = fracheight and fracstep are 16.16 bit fractions\r
727 =\r
728 =====================\r
729 */\r
730 \r
731 void DrawVWall (walltype *wallptr)\r
732 {\r
733         int                     x,i;\r
734         unsigned        source;\r
735         unsigned        width,sourceint;\r
736         unsigned        wallpic,wallpicseg;\r
737         unsigned        skip;\r
738         long            fracheight,fracstep,longheightchange;\r
739         unsigned        height;\r
740         int                     heightchange;\r
741         unsigned        slope,distance;\r
742         int                     traceangle,angle;\r
743         int                     mapadd;\r
744         unsigned        lastpix,lastsource,lastwidth;\r
745 \r
746         if (wallptr->rightclip < wallptr->leftclip)\r
747                 Quit ("DrawVWall: Right < Left");\r
748 \r
749 //\r
750 // setup for height calculation\r
751 //\r
752         wallptr->height1 >>= 1;\r
753         wallptr->height2 >>= 1;\r
754         wallptr->planecoord>>=10;                       // remove non significant bits\r
755 \r
756         width = wallptr->x2 - wallptr->x1;\r
757         if (width)\r
758         {\r
759                 heightchange = wallptr->height2 - wallptr->height1;\r
760                 asm     mov     ax,[heightchange]\r
761                 asm     mov     WORD PTR [longheightchange+2],ax\r
762                 asm     mov     WORD PTR [longheightchange],0   // avoid long shift by 16\r
763                 fracstep = longheightchange/width;\r
764         }\r
765 \r
766         fracheight = ((long)wallptr->height1<<16)+0x8000;\r
767         skip = wallptr->leftclip - wallptr->x1;\r
768         if (skip)\r
769                 fracheight += fracstep*skip;\r
770 \r
771 //\r
772 // setup for texture mapping\r
773 //\r
774 // mapadd is 64*64 (to keep source positive) + the origin wall intercept\r
775 // distance has 6 unit bits, and 6 frac bits\r
776 // traceangle is the center view angle in FINEANGLES, moved to be in\r
777 // the +-90 degree range (to thew right of origin)\r
778 //\r
779         traceangle = fineviewangle;\r
780         //\r
781         // find wall picture to map from\r
782         //\r
783         if (wallptr->side)\r
784         {       // east or west wall\r
785 \r
786                 wallpic = walllight1[wallptr->color+wall_anim_pos[wallptr->color]];\r
787                 if (wallptr->planecoord < viewxpix)\r
788                 {\r
789                         distance = viewxpix-wallptr->planecoord;\r
790                         traceangle -= FINEANGLES/2;\r
791                         mapadd = (64-viewypix&63);              // the pixel spot of the origin\r
792                 }\r
793                 else\r
794                 {\r
795                         distance = wallptr->planecoord-viewxpix;\r
796                         // traceangle is correct\r
797                         mapadd = viewypix&63;           // the pixel spot of the origin\r
798                 }\r
799         }\r
800         else\r
801         {       // north or south wall\r
802 \r
803                 wallpic = walldark1[wallptr->color+wall_anim_pos[wallptr->color]];\r
804                 if (wallptr->planecoord < viewypix)\r
805                 {\r
806                         distance = viewypix-wallptr->planecoord;\r
807                         traceangle -= FINEANGLES/4;\r
808                         mapadd = viewxpix&63;           // the pixel spot of the origin\r
809                 }\r
810                 else\r
811                 {\r
812                         distance = wallptr->planecoord-viewypix;\r
813                         traceangle -= FINEANGLES*3/4;\r
814                         mapadd = (64-viewxpix&63);              // the pixel spot of the origin\r
815                 }\r
816         }\r
817 \r
818         mapadd = 64*64-mapadd;                          // make sure it stays positive\r
819 \r
820         wallpicseg = (unsigned)walldirectory[wallpic-FIRSTWALLPIC];\r
821         if (traceangle > FINEANGLES/2)\r
822                 traceangle -= FINEANGLES;\r
823 \r
824 //\r
825 // calculate everything\r
826 //\r
827 // IMPORTANT!  This loop is executed around 5000 times / second!\r
828 //\r
829         lastpix = lastsource = (unsigned)-1;\r
830 \r
831         for (x = wallptr->leftclip ; x <= wallptr->rightclip ; x++)\r
832         {\r
833                 //\r
834                 // height\r
835                 //\r
836                 asm     mov     ax,WORD PTR [fracheight]\r
837                 asm     mov     dx,WORD PTR [fracheight+2]\r
838                 asm     mov     cx,dx\r
839                 asm     add     ax,WORD PTR [fracstep]\r
840                 asm     adc     dx,WORD PTR [fracstep+2]\r
841                 asm     mov     WORD PTR [fracheight],ax\r
842                 asm     mov     WORD PTR [fracheight+2],dx\r
843                 asm     mov     bx,[x]\r
844                 asm     shl     bx,1\r
845                 asm     cmp     cx,MAXSCALEHEIGHT\r
846                 asm     jbe     storeheight\r
847                 asm     mov     cx,MAXSCALEHEIGHT\r
848 storeheight:\r
849                 asm     mov WORD PTR [wallheight+bx],cx\r
850                 asm     mov WORD PTR [zbuffer+bx],cx\r
851 \r
852 //              height = fracheight>>16;\r
853 //              fracheight += fracstep;\r
854 //              if (height > MAXSCALEHEIGHT)\r
855 //                      height = MAXSCALEHEIGHT;\r
856 //              wallheight[x] = zbuffer[x] = height;\r
857 \r
858                 //\r
859                 // texture map\r
860                 //\r
861                 angle = pixelangle[x]+traceangle;\r
862                 if (angle<0)\r
863                         angle+=FINEANGLES;\r
864 \r
865                 slope = finetangent[angle];\r
866 \r
867 //\r
868 // distance is an unsigned 6.6 bit number (12 pixel bits)\r
869 // slope is a signed 5.10 bit number\r
870 // result is a signed 11.16 bit number\r
871 //\r
872 \r
873 #if 0\r
874                 source = distance*slope;\r
875                 source >>=20;\r
876 \r
877                 source += mapadd;\r
878                 source &= 63;                           // mask off the unused units\r
879                 source = 63-source;\r
880                 source <<= 6;                           // multiply by 64 for offset into pic\r
881 #endif\r
882                 asm     mov     ax,[distance]\r
883                 asm     imul    [slope]                 // ax is the source pixel\r
884                 asm     mov     al,ah\r
885                 asm     shr     al,1\r
886                 asm     shr     al,1                            // low 6 bits is now pixel number\r
887                 asm     add     ax,[mapadd]\r
888                 asm     and ax,63\r
889                 asm     mov     dx,63\r
890                 asm     sub     dx,ax                           // otherwise it is backwards\r
891                 asm     shl     dx,1\r
892                 asm     shl     dx,1\r
893                 asm     shl     dx,1\r
894                 asm     shl     dx,1\r
895                 asm     shl     dx,1\r
896                 asm     shl     dx,1                            // *64 to index into shape\r
897                 asm     mov     [source],dx\r
898 \r
899                 if (source != lastsource)\r
900                 {\r
901                         if (lastpix != (unsigned)-1)\r
902                         {\r
903                                 wallofs[lastpix] = lastsource;\r
904                                 wallseg[lastpix] = wallpicseg;\r
905                                 wallwidth[lastpix] = lastwidth;\r
906                         }\r
907                         lastpix = x;\r
908                         lastsource = source;\r
909                         lastwidth = 1;\r
910                 }\r
911                 else\r
912                         lastwidth++;                    // optimized draw, same map as last one\r
913         }\r
914         wallofs[lastpix] = lastsource;\r
915         wallseg[lastpix] = wallpicseg;\r
916         wallwidth[lastpix] = lastwidth;\r
917 }\r
918 \r
919 \r
920 //==========================================================================\r
921 \r
922 \r
923 /*\r
924 =================\r
925 =\r
926 = TraceRay\r
927 =\r
928 = Used to find the left and rightmost tile in the view area to be traced from\r
929 = Follows a ray of the given angle from viewx,viewy in the global map until\r
930 = it hits a solid tile\r
931 = sets:\r
932 =   tile.x,tile.y       : tile coordinates of contacted tile\r
933 =   tilecolor   : solid tile's color\r
934 =\r
935 ==================\r
936 */\r
937 \r
938 int tilecolor;\r
939 \r
940 void TraceRay (unsigned angle)\r
941 {\r
942   long tracex,tracey,tracexstep,traceystep,searchx,searchy;\r
943   fixed fixtemp;\r
944   int otx,oty,searchsteps;\r
945 \r
946   tracexstep = costable[angle];\r
947   traceystep = sintable[angle];\r
948 \r
949 //\r
950 // advance point so it is even with the view plane before we start checking\r
951 //\r
952   fixtemp = FixedByFrac(prestep,tracexstep);\r
953   tracex = viewx+fixtemp;\r
954   fixtemp = FixedByFrac(prestep,traceystep);\r
955   tracey = viewy-fixtemp;\r
956 \r
957   tile.x = tracex>>TILESHIFT;   // starting point in tiles\r
958   tile.y = tracey>>TILESHIFT;\r
959 \r
960 \r
961   if (tracexstep<0)                     // use 2's complement, not signed magnitude\r
962         tracexstep = -(tracexstep&0x7fffffff);\r
963 \r
964   if (traceystep<0)                     // use 2's complement, not signed magnitude\r
965         traceystep = -(traceystep&0x7fffffff);\r
966 \r
967 //\r
968 // we assume viewx,viewy is not inside a solid tile, so go ahead one step\r
969 //\r
970 \r
971   do    // until a solid tile is hit\r
972   {\r
973     otx = tile.x;\r
974         oty = tile.y;\r
975         spotvis[otx][oty] = true;\r
976         tracex += tracexstep;\r
977     tracey -= traceystep;\r
978     tile.x = tracex>>TILESHIFT;\r
979         tile.y = tracey>>TILESHIFT;\r
980 \r
981         if (tile.x!=otx && tile.y!=oty && (tilemap[otx][tile.y] || tilemap[tile.x][oty]) )\r
982     {\r
983       //\r
984           // trace crossed two solid tiles, so do a binary search along the line\r
985           // to find a spot where only one tile edge is crossed\r
986       //\r
987       searchsteps = 0;\r
988       searchx = tracexstep;\r
989       searchy = traceystep;\r
990       do\r
991       {\r
992         searchx/=2;\r
993         searchy/=2;\r
994         if (tile.x!=otx && tile.y!=oty)\r
995         {\r
996          // still too far\r
997           tracex -= searchx;\r
998           tracey += searchy;\r
999         }\r
1000         else\r
1001         {\r
1002          // not far enough, no tiles crossed\r
1003           tracex += searchx;\r
1004           tracey -= searchy;\r
1005         }\r
1006 \r
1007         //\r
1008         // if it is REAL close, go for the most clockwise intersection\r
1009         //\r
1010         if (++searchsteps == 16)\r
1011         {\r
1012           tracex = (long)otx<<TILESHIFT;\r
1013           tracey = (long)oty<<TILESHIFT;\r
1014           if (tracexstep>0)\r
1015           {\r
1016                 if (traceystep<0)\r
1017                 {\r
1018                   tracex += TILEGLOBAL-1;\r
1019                   tracey += TILEGLOBAL;\r
1020                 }\r
1021                 else\r
1022                 {\r
1023                   tracex += TILEGLOBAL;\r
1024                 }\r
1025           }\r
1026           else\r
1027           {\r
1028                 if (traceystep<0)\r
1029                 {\r
1030                   tracex --;\r
1031                   tracey += TILEGLOBAL-1;\r
1032                 }\r
1033                 else\r
1034                 {\r
1035                   tracey --;\r
1036                 }\r
1037           }\r
1038         }\r
1039 \r
1040         tile.x = tracex>>TILESHIFT;\r
1041         tile.y = tracey>>TILESHIFT;\r
1042 \r
1043           } while (( tile.x!=otx && tile.y!=oty) || (tile.x==otx && tile.y==oty) );\r
1044         }\r
1045   } while (!(tilecolor = tilemap[tile.x][tile.y]) );\r
1046 \r
1047 }\r
1048 \r
1049 //==========================================================================\r
1050 \r
1051 \r
1052 /*\r
1053 ========================\r
1054 =\r
1055 = FixedByFrac\r
1056 =\r
1057 = multiply a 16/16 bit, 2's complement fixed point number by a 16 bit\r
1058 = fraction, passed as a signed magnitude 32 bit number\r
1059 =\r
1060 ========================\r
1061 */\r
1062 \r
1063 #pragma warn -rvl                       // I stick the return value in with ASMs\r
1064 \r
1065 fixed FixedByFrac (fixed a, fixed b)\r
1066 {\r
1067   fixed value;\r
1068 \r
1069 //\r
1070 // setup\r
1071 //\r
1072 asm     mov     si,[WORD PTR b+2]       // sign of result = sign of fraction\r
1073 \r
1074 asm     mov     ax,[WORD PTR a]\r
1075 asm     mov     cx,[WORD PTR a+2]\r
1076 \r
1077 asm     or      cx,cx\r
1078 asm     jns     aok:                            // negative?\r
1079 asm     not     ax\r
1080 asm     not     cx\r
1081 asm     add     ax,1\r
1082 asm     adc     cx,0\r
1083 asm     xor     si,0x8000                       // toggle sign of result\r
1084 aok:\r
1085 \r
1086 //\r
1087 // multiply  cx:ax by bx\r
1088 //\r
1089 asm     mov     bx,[WORD PTR b]\r
1090 asm     mul     bx                                      // fraction*fraction\r
1091 asm     mov     di,dx                           // di is low word of result\r
1092 asm     mov     ax,cx                           //\r
1093 asm     mul     bx                                      // units*fraction\r
1094 asm add ax,di\r
1095 asm     adc     dx,0\r
1096 \r
1097 //\r
1098 // put result dx:ax in 2's complement\r
1099 //\r
1100 asm     test    si,0x8000               // is the result negative?\r
1101 asm     jz      ansok:\r
1102 asm     not     ax\r
1103 asm     not     dx\r
1104 asm     add     ax,1\r
1105 asm     adc     dx,0\r
1106 \r
1107 ansok:;\r
1108 \r
1109 }\r
1110 \r
1111 #pragma warn +rvl\r
1112 \r
1113 #if 0\r
1114 /*\r
1115 =========================\r
1116 =\r
1117 = FixedAdd\r
1118 =\r
1119 = add two 16 bit fixed point numbers\r
1120 = to subtract, invert the sign of B before invoking\r
1121 =\r
1122 =========================\r
1123 */\r
1124 \r
1125 fixed FixedAdd (fixed a, fixed b)\r
1126 {\r
1127   fixed value;\r
1128 \r
1129 asm     mov     ax,[WORD PTR a]\r
1130 asm     mov     dx,[WORD PTR a+2]\r
1131 \r
1132 asm     mov     bx,[WORD PTR b]\r
1133 asm     mov     cx,[WORD PTR b+2]\r
1134 \r
1135 asm     or      dx,dx\r
1136 asm     jns     aok:            // negative?\r
1137 asm     and     dx,0x7fff\r
1138 asm     not     ax              // convert a from signed magnitude to 2's compl\r
1139 asm     not     dx\r
1140 asm     add     ax,1\r
1141 asm     adc     dx,0\r
1142 aok:\r
1143 \r
1144 asm     or      cx,cx\r
1145 asm     jns     bok:            // negative?\r
1146 asm     and     cx,0x7fff\r
1147 asm     not     bx              // convert b from signed magnitude to 2's compl\r
1148 asm     not     cx\r
1149 asm     add     bx,1\r
1150 asm     adc     cx,0\r
1151 bok:\r
1152 \r
1153 asm     add     ax,bx           // perform the addition\r
1154 asm     adc     dx,cx\r
1155 asm     jns     done\r
1156 \r
1157 asm     and     dx,0x7fff       // value was negative\r
1158 asm     not     ax              // back to signed magnitude\r
1159 asm     not     dx\r
1160 asm     add     ax,1\r
1161 asm     adc     dx,0\r
1162 \r
1163 done:\r
1164 \r
1165 asm     mov     [WORD PTR value],ax\r
1166 asm     mov     [WORD PTR value+2],dx\r
1167 \r
1168   return value;\r
1169 }\r
1170 #endif\r
1171 \r
1172 //==========================================================================\r
1173 \r
1174 \r
1175 /*\r
1176 ========================\r
1177 =\r
1178 = TransformPoint\r
1179 =\r
1180 = Takes paramaters:\r
1181 =   gx,gy               : globalx/globaly of point\r
1182 =\r
1183 = globals:\r
1184 =   viewx,viewy         : point of view\r
1185 =   viewcos,viewsin     : sin/cos of viewangle\r
1186 =\r
1187 =\r
1188 = defines:\r
1189 =   CENTERX             : pixel location of center of view window\r
1190 =   TILEGLOBAL          : size of one\r
1191 =   FOCALLENGTH         : distance behind viewx/y for center of projection\r
1192 =   scale               : conversion from global value to screen value\r
1193 =\r
1194 = returns:\r
1195 =   screenx,screenheight: projected edge location and size\r
1196 =\r
1197 ========================\r
1198 */\r
1199 \r
1200 void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight)\r
1201 {\r
1202   int ratio;\r
1203   fixed gxt,gyt,nx,ny;\r
1204 \r
1205 //\r
1206 // translate point to view centered coordinates\r
1207 //\r
1208   gx = gx-viewx;\r
1209   gy = gy-viewy;\r
1210 \r
1211 //\r
1212 // calculate newx\r
1213 //\r
1214   gxt = FixedByFrac(gx,viewcos);\r
1215   gyt = FixedByFrac(gy,viewsin);\r
1216   nx = gxt-gyt;\r
1217 \r
1218 //\r
1219 // calculate newy\r
1220 //\r
1221   gxt = FixedByFrac(gx,viewsin);\r
1222   gyt = FixedByFrac(gy,viewcos);\r
1223   ny = gyt+gxt;\r
1224 \r
1225 //\r
1226 // calculate perspective ratio\r
1227 //\r
1228   if (nx<0)\r
1229         nx = 0;\r
1230 \r
1231   ratio = nx*scale/FOCALLENGTH;\r
1232 \r
1233   if (ratio<=MINRATIO)\r
1234         ratio = MINRATIO;\r
1235 \r
1236   *screenx = CENTERX + ny/ratio;\r
1237 \r
1238   *screenheight = TILEGLOBAL/ratio;\r
1239 \r
1240 }\r
1241 \r
1242 \r
1243 //\r
1244 // transform actor\r
1245 //\r
1246 void TransformActor (objtype *ob)\r
1247 {\r
1248   int ratio;\r
1249   fixed gx,gy,gxt,gyt,nx,ny;\r
1250 \r
1251 //\r
1252 // translate point to view centered coordinates\r
1253 //\r
1254   gx = ob->x-viewx;\r
1255   gy = ob->y-viewy;\r
1256 \r
1257 //\r
1258 // calculate newx\r
1259 //\r
1260   gxt = FixedByFrac(gx,viewcos);\r
1261   gyt = FixedByFrac(gy,viewsin);\r
1262   nx = gxt-gyt-ob->size;\r
1263 \r
1264 //\r
1265 // calculate newy\r
1266 //\r
1267   gxt = FixedByFrac(gx,viewsin);\r
1268   gyt = FixedByFrac(gy,viewcos);\r
1269   ny = gyt+gxt;\r
1270 \r
1271 //\r
1272 // calculate perspective ratio\r
1273 //\r
1274   if (nx<0)\r
1275         nx = 0;\r
1276 \r
1277   ratio = nx*scale/FOCALLENGTH;\r
1278 \r
1279   if (ratio<=MINRATIO)\r
1280         ratio = MINRATIO;\r
1281 \r
1282   ob->viewx = CENTERX + ny/ratio;\r
1283 \r
1284   ob->viewheight = TILEGLOBAL/ratio;\r
1285 }\r
1286 \r
1287 //==========================================================================\r
1288 \r
1289 fixed TransformX (fixed gx, fixed gy)\r
1290 {\r
1291   int ratio;\r
1292   fixed gxt,gyt,nx,ny;\r
1293 \r
1294 //\r
1295 // translate point to view centered coordinates\r
1296 //\r
1297   gx = gx-viewx;\r
1298   gy = gy-viewy;\r
1299 \r
1300 //\r
1301 // calculate newx\r
1302 //\r
1303   gxt = FixedByFrac(gx,viewcos);\r
1304   gyt = FixedByFrac(gy,viewsin);\r
1305 \r
1306   return gxt-gyt;\r
1307 }\r
1308 \r
1309 //==========================================================================\r
1310 \r
1311 /*\r
1312 ==================\r
1313 =\r
1314 = BuildTables\r
1315 =\r
1316 = Calculates:\r
1317 =\r
1318 = scale                 projection constant\r
1319 = sintable/costable     overlapping fractional tables\r
1320 = firstangle/lastangle  angles from focalpoint to left/right view edges\r
1321 = prestep               distance from focal point before checking for tiles\r
1322 =\r
1323 ==================\r
1324 */\r
1325 \r
1326 void BuildTables (void)\r
1327 {\r
1328   int           i;\r
1329   long          intang;\r
1330   long          x;\r
1331   float         angle,anglestep,radtoint;\r
1332   double        tang;\r
1333   fixed         value;\r
1334 \r
1335 //\r
1336 // calculate the angle offset from view angle of each pixel's ray\r
1337 //\r
1338         radtoint = (float)FINEANGLES/2/PI;\r
1339         for (i=0;i<VIEWWIDTH/2;i++)\r
1340         {\r
1341         // start 1/2 pixel over, so viewangle bisects two middle pixels\r
1342                 x = (TILEGLOBAL*i+TILEGLOBAL/2)/VIEWWIDTH;\r
1343                 tang = (float)x/(FOCALLENGTH+MINDIST);\r
1344                 angle = atan(tang);\r
1345                 intang = angle*radtoint;\r
1346                 pixelangle[VIEWWIDTH/2-1-i] = intang;\r
1347                 pixelangle[VIEWWIDTH/2+i] = -intang;\r
1348         }\r
1349 \r
1350 //\r
1351 // calculate fine tangents\r
1352 // 1 sign bit, 5 units (clipped to), 10 fracs\r
1353 //\r
1354 #define MININT  (-MAXINT)\r
1355 \r
1356         for (i=0;i<FINEANGLES/4;i++)\r
1357         {\r
1358                 intang = tan(i/radtoint)*(1l<<10);\r
1359 \r
1360                 //\r
1361                 // if the tangent is not reprentable in this many bits, bound the\r
1362                 // units part ONLY\r
1363                 //\r
1364                 if (intang>MAXINT)\r
1365                         intang = 0x8f00 | (intang & 0xff);\r
1366                 else if (intang<MININT)\r
1367                         intang = 0xff00 | (intang & 0xff);\r
1368 \r
1369                 finetangent[i] = intang;\r
1370 //              finetangent[FINEANGLES/2+i] = intang;\r
1371 //              finetangent[FINEANGLES/2-i-1] = -intang;\r
1372                 finetangent[FINEANGLES-i-1] = -intang;\r
1373         }\r
1374 \r
1375 //\r
1376 // calculate scale value so one tile at mindist allmost fills the view horizontally\r
1377 //\r
1378   scale = GLOBAL1/VIEWWIDTH;\r
1379   scale *= focallength;\r
1380   scale /= (focallength+mindist);\r
1381 \r
1382 //\r
1383 // costable overlays sintable with a quarter phase shift\r
1384 // ANGLES is assumed to be divisable by four\r
1385 //\r
1386 // The low word of the value is the fraction, the high bit is the sign bit,\r
1387 // bits 16-30 should be 0\r
1388 //\r
1389 \r
1390   angle = 0;\r
1391   anglestep = PI/2/ANGLEQUAD;\r
1392   for (i=0;i<=ANGLEQUAD;i++)\r
1393   {\r
1394         value=GLOBAL1*sin(angle);\r
1395         sintable[i]=\r
1396           sintable[i+ANGLES]=\r
1397           sintable[ANGLES/2-i] = value;\r
1398         sintable[ANGLES-i]=\r
1399           sintable[ANGLES/2+i] = value | 0x80000000l;\r
1400         angle += anglestep;\r
1401   }\r
1402 \r
1403 //\r
1404 // figure trace angles for first and last pixel on screen\r
1405 //\r
1406   angle = atan((float)VIEWWIDTH/2*scale/FOCALLENGTH);\r
1407   angle *= ANGLES/(PI*2);\r
1408 \r
1409   intang = (int)angle+1;\r
1410   firstangle = intang;\r
1411   lastangle = -intang;\r
1412 \r
1413   prestep = GLOBAL1*((float)FOCALLENGTH/costable[firstangle]);\r
1414 \r
1415 //\r
1416 // misc stuff\r
1417 //\r
1418   walls[0].x2 = VIEWX-1;\r
1419   walls[0].height2 = 32000;\r
1420 }\r
1421 \r
1422 \r
1423 //==========================================================================\r
1424 \r
1425 /*\r
1426 =====================\r
1427 =\r
1428 = ClearScreen\r
1429 =\r
1430 =====================\r
1431 */\r
1432 \r
1433 void ClearScreen (void)\r
1434 {\r
1435         unsigned topcolor=*skycolor, bottomcolor=*groundcolor;\r
1436         unsigned topimage=topcolor&0xf0,bottomimage=bottomcolor&0xf0;\r
1437         unsigned pfoffset=0;\r
1438 \r
1439 \r
1440 #if USE_STRIPS\r
1441         if (topimage == 0x20)           // special code for lightning\r
1442                 topimage = topcolor = 0;\r
1443 \r
1444 // Manually wipe screen with solid color.\r
1445 // If BOTH sky and ground are 'images' don't manually clear it!\r
1446 //\r
1447         if ((!topimage) || (!bottomimage))\r
1448         {\r
1449 #endif\r
1450 \r
1451   //\r
1452   // clear the screen\r
1453   //\r
1454 asm     mov     dx,GC_INDEX\r
1455 asm     mov     ax,GC_MODE + 256*2              // read mode 0, write mode 2\r
1456 asm     out     dx,ax\r
1457 asm     mov     ax,GC_BITMASK + 255*256\r
1458 asm     out     dx,ax\r
1459 \r
1460 //asm     mov     dx,40-VIEWWIDTH/8                                     // dx = modulo\r
1461 asm     mov     bl,VIEWWIDTH/16\r
1462 asm     mov     bh,CENTERY+1\r
1463 \r
1464 asm     mov     ax,topcolor\r
1465 asm     mov     es,[screenseg]\r
1466 asm     mov     di,[bufferofs]\r
1467 asm     add     di,((SCREENWIDTH*VIEWY)+(VIEWX/8))\r
1468 \r
1469 toploop:\r
1470 asm     mov     cl,bl\r
1471 asm     rep     stosw\r
1472 asm     stosb\r
1473 //asm     add     di,dx                                 // no need to add "0" modulo\r
1474 asm     dec     bh\r
1475 asm     jnz     toploop\r
1476 \r
1477 asm     mov     bh,CENTERY+1\r
1478 asm     mov     ax,bottomcolor\r
1479 \r
1480 bottomloop:\r
1481 asm     mov     cl,bl\r
1482 asm     rep     stosw\r
1483 asm     stosb\r
1484 //asm     add     di,dx                                 // no need to add "0" modulo\r
1485 asm     dec     bh\r
1486 asm     jnz     bottomloop\r
1487 \r
1488 #if USE_STRIPS\r
1489         }\r
1490 \r
1491 \r
1492 //\r
1493 // code to test parallax turning\r
1494 //\r
1495 \r
1496         if (topimage)\r
1497         {\r
1498                 topimage -= 16;\r
1499                 pfoffset = LONG_PERCENTAGE(3200,359,(359-player->angle),12);\r
1500                 while (pfoffset >= 640)\r
1501                         pfoffset -= 640;\r
1502                 LatchDrawPicStrip(0,0,SKY1PIC+topimage,pfoffset+8);\r
1503         }\r
1504 \r
1505         if (bottomimage)\r
1506         {\r
1507 ////            pfoffset = LONG_PERCENTAGE(3200,359,(359-player->angle),12)+320;\r
1508 //              pfoffset += 320;\r
1509 //              while (pfoffset >= 640)\r
1510 //                      pfoffset -= 640;\r
1511 //              LatchDrawPicStrip(0,64,SKY1PIC+topimage,pfoffset+8);\r
1512                 bottomimage -= 16;\r
1513                 LatchDrawPic(0,64,GND1PIC+bottomimage);\r
1514         }\r
1515 #endif\r
1516 \r
1517 \r
1518 asm     mov     dx,GC_INDEX\r
1519 asm     mov     ax,GC_MODE + 256*10             // read mode 1, write mode 2\r
1520 asm     out     dx,ax\r
1521 asm     mov     al,GC_BITMASK\r
1522 asm     out     dx,al\r
1523 \r
1524 }\r
1525 \r
1526 //==========================================================================\r
1527 \r
1528 /*\r
1529 =====================\r
1530 =\r
1531 = DrawWallList\r
1532 =\r
1533 = Clips and draws all the walls traced this refresh\r
1534 =\r
1535 =====================\r
1536 */\r
1537 \r
1538 void DrawWallList (void)\r
1539 {\r
1540         int i,leftx,newleft,rightclip;\r
1541         walltype *wall, *check;\r
1542 \r
1543 asm     mov     ax,ds\r
1544 asm     mov     es,ax\r
1545 asm     mov     di,OFFSET wallwidth\r
1546 asm     xor     ax,ax\r
1547 asm     mov     cx,VIEWWIDTH/2\r
1548 asm     rep     stosw\r
1549 \r
1550         ClearScreen ();\r
1551 \r
1552         rightwall->x1 = VIEWXH+1;\r
1553         rightwall->height1 = 32000;\r
1554         (rightwall+1)->x1 = 32000;\r
1555 \r
1556         leftx = -1;\r
1557 \r
1558         for (wall=&walls[1];wall<rightwall && leftx<=VIEWXH ;wall++)\r
1559         {\r
1560           if (leftx >= wall->x2)\r
1561                 continue;\r
1562 \r
1563           rightclip = wall->x2;\r
1564 \r
1565           check = wall+1;\r
1566           while (check->x1 <= rightclip && check->height1 >= wall->height2)\r
1567           {\r
1568                 rightclip = check->x1-1;\r
1569                 check++;\r
1570           }\r
1571 \r
1572           if (rightclip>VIEWXH)\r
1573                 rightclip=VIEWXH;\r
1574 \r
1575           if (leftx < wall->x1 - 1)\r
1576                 newleft = wall->x1-1;           // there was black space between walls\r
1577           else\r
1578                 newleft = leftx;\r
1579 \r
1580           if (rightclip > newleft)\r
1581           {\r
1582                 wall->leftclip = newleft+1;\r
1583                 wall->rightclip = rightclip;\r
1584                 DrawVWall (wall);\r
1585                 leftx = rightclip;\r
1586           }\r
1587         }\r
1588 \r
1589 #ifndef DRAWEACH\r
1590         ScaleWalls ();                                  // draw all the walls\r
1591 #endif\r
1592 }\r
1593 \r
1594 //==========================================================================\r
1595 \r
1596 /*\r
1597 =====================\r
1598 =\r
1599 = DrawScaleds\r
1600 =\r
1601 = Draws all objects that are visable\r
1602 =\r
1603 =====================\r
1604 */\r
1605 \r
1606 objtype *depthsort[MAXACTORS];\r
1607 \r
1608 void DrawScaleds (void)\r
1609 {\r
1610 #if USE_INERT_LIST\r
1611                 extern inertobjtype inertobjlist[], *inert;\r
1612 \r
1613                 boolean inertlist=false;\r
1614 #endif\r
1615         int             i,j,least,numvisable,height;\r
1616         objtype         *obj,**vislist,*farthest;\r
1617         memptr          shape;\r
1618         byte            *tilespot,*visspot;\r
1619 \r
1620         numvisable = 0;\r
1621 \r
1622 //\r
1623 // calculate base positions of all objects\r
1624 //\r
1625         vislist = &depthsort[0];\r
1626 \r
1627         obj = player->next;\r
1628         while (obj)\r
1629         {\r
1630                 tilespot = &tilemap[0][0]+(obj->tilex<<6)+obj->tiley;\r
1631                 visspot = &spotvis[0][0]+(obj->tilex<<6)+obj->tiley;\r
1632                 //\r
1633                 // could be in any of the nine surrounding tiles\r
1634                 //\r
1635                 if (*visspot\r
1636                 || ( *(visspot-1) && !*(tilespot-1) )\r
1637                 || ( *(visspot+1) && !*(tilespot+1) )\r
1638                 || ( *(visspot-65) && !*(tilespot-65) )\r
1639                 || ( *(visspot-64) && !*(tilespot-64) )\r
1640                 || ( *(visspot-63) && !*(tilespot-63) )\r
1641                 || ( *(visspot+65) && !*(tilespot+65) )\r
1642                 || ( *(visspot+64) && !*(tilespot+64) )\r
1643                 || ( *(visspot+63) && !*(tilespot+63) ) )\r
1644                 {\r
1645 #if USE_INERT_LIST\r
1646                         if (!inertlist)\r
1647 #endif\r
1648                                 if ((obj->active == noalways) || (obj->active == always))\r
1649                                         obj->active = always;\r
1650                                 else\r
1651                                         obj->active = yes;\r
1652                         TransformActor (obj);\r
1653                         if (!obj->viewheight || obj->viewheight > VIEWWIDTH)\r
1654                                 goto cont;                       // too close or far away\r
1655 \r
1656                         if (!obj->state->shapenum)\r
1657                                 goto cont;\r
1658 \r
1659                         *vislist++ = obj;\r
1660                         numvisable++;\r
1661                 }\r
1662                 else\r
1663 #if USE_INERT_LIST\r
1664                         if (!inertlist)\r
1665 #endif\r
1666                                 if ((obj->active != always) && (obj->active != noalways))\r
1667                                         obj->active = no;\r
1668 \r
1669 cont:;\r
1670                 obj = obj->next;\r
1671 #if USE_INERT_LIST\r
1672                 if ((!obj) && (!inertlist))\r
1673                 {\r
1674                         if (inert != inertobjlist)\r
1675                                 obj = (objtype *)inertobjlist;\r
1676                         inertlist = true;\r
1677                 }\r
1678 #endif\r
1679         }\r
1680 \r
1681         if (vislist == &depthsort[0])\r
1682                 return;                                         // no visable objects\r
1683 \r
1684 //\r
1685 // draw from back to front\r
1686 //\r
1687         for (i = 0; i<numvisable; i++)\r
1688         {\r
1689                 least = 32000;\r
1690                 for (j=0;j<numvisable;j++)\r
1691                 {\r
1692                         height = depthsort[j]->viewheight;\r
1693                         if (height < least)\r
1694                         {\r
1695                                 least = height;\r
1696                                 farthest = depthsort[j];\r
1697                         }\r
1698                 }\r
1699                 //\r
1700                 // draw farthest\r
1701                 //\r
1702                 shape = shapedirectory[farthest->state->shapenum-FIRSTSCALEPIC];\r
1703                 ScaleShape(farthest->viewx,shape,farthest->viewheight);\r
1704                 farthest->viewheight = 32000;\r
1705         }\r
1706 }\r
1707 \r
1708 //==========================================================================\r
1709 \r
1710 \r
1711 /*\r
1712 =====================\r
1713 =\r
1714 = CalcTics\r
1715 =\r
1716 =====================\r
1717 */\r
1718 \r
1719 void CalcTics (void)\r
1720 {\r
1721         long    newtime,oldtimecount;\r
1722 \r
1723 \r
1724 #ifdef PROFILE\r
1725         tics = 1;\r
1726         return;\r
1727 #endif\r
1728 \r
1729 //\r
1730 // calculate tics since last refresh for adaptive timing\r
1731 //\r
1732         if (lasttimecount > TimeCount)\r
1733                 TimeCount = lasttimecount;              // if the game was paused a LONG time\r
1734 \r
1735 #if 0\r
1736         if (DemoMode)                                   // demo recording and playback needs\r
1737         {                                                               // to be constant\r
1738 //\r
1739 // take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
1740 //\r
1741                 oldtimecount = lasttimecount;\r
1742                 while (TimeCount<oldtimecount+DEMOTICS*2)\r
1743                 ;\r
1744                 lasttimecount = oldtimecount + DEMOTICS;\r
1745                 TimeCount = lasttimecount + DEMOTICS;\r
1746                 realtics = tics = DEMOTICS;\r
1747         }\r
1748         else\r
1749 #endif\r
1750         {\r
1751 //\r
1752 // non demo, so report actual time\r
1753 //\r
1754                 newtime = TimeCount;\r
1755                 realtics = tics = newtime-lasttimecount;\r
1756                 lasttimecount = newtime;\r
1757 \r
1758 #ifdef FILEPROFILE\r
1759                         strcpy (scratch,"\tTics:");\r
1760                         itoa (tics,str,10);\r
1761                         strcat (scratch,str);\r
1762                         strcat (scratch,"\n");\r
1763                         write (profilehandle,scratch,strlen(scratch));\r
1764 #endif\r
1765 \r
1766                 if (tics>MAXTICS)\r
1767                 {\r
1768                         TimeCount -= (tics-MAXTICS);\r
1769                         tics = MAXTICS;\r
1770                 }\r
1771 \r
1772                 if (realtics>MAXREALTICS)\r
1773                         realtics = MAXREALTICS;\r
1774         }\r
1775 }\r
1776 \r
1777 \r
1778 //==========================================================================\r
1779 \r
1780 \r
1781 /*\r
1782 ========================\r
1783 =\r
1784 = DrawHand\r
1785 =\r
1786 ========================\r
1787 */\r
1788 \r
1789 void    DrawHand (void)\r
1790 {\r
1791         #define HAND_X_POS      ((VIEWWIDTH/16)-(10/2))         // "10" = hand width in bytes\r
1792 \r
1793         #define picnum HAND1PICM\r
1794 \r
1795         memptr source;\r
1796         unsigned dest,width,height;\r
1797 \r
1798 //      if (gamestate.shotpower || boltsleft)\r
1799 //              picnum += (((unsigned)TimeCount>>3)&1);\r
1800 \r
1801         source = grsegs[picnum];\r
1802         dest = ylookup[VIEWHEIGHT-handheight]+HAND_X_POS+bufferofs;                     // 12\r
1803         width = picmtable[picnum-STARTPICM].width;\r
1804         height = picmtable[picnum-STARTPICM].height;\r
1805 \r
1806         VW_MaskBlock(source,0,dest,width,handheight,width*height);\r
1807         EGAMAPMASK(15);\r
1808 }\r
1809 \r
1810 //==========================================================================\r
1811 \r
1812 \r
1813 /*\r
1814 ========================\r
1815 =\r
1816 = ThreeDRefresh\r
1817 =\r
1818 ========================\r
1819 */\r
1820 \r
1821 void    ThreeDRefresh (void)\r
1822 {\r
1823         int tracedir;\r
1824 \r
1825 restart:\r
1826         aborttrace = false;\r
1827 \r
1828 //\r
1829 // clear out the traced array\r
1830 //\r
1831 asm     mov     ax,ds\r
1832 asm     mov     es,ax\r
1833 asm     mov     di,OFFSET spotvis\r
1834 asm     xor     ax,ax\r
1835 asm     mov     cx,[mapwidth]           // mapheight*32 words\r
1836 asm     shl     cx,1\r
1837 asm     shl     cx,1\r
1838 asm     shl     cx,1\r
1839 asm     shl     cx,1\r
1840 asm     shl     cx,1\r
1841 asm     rep stosw\r
1842 \r
1843 \r
1844 //\r
1845 // set up variables for this view\r
1846 //\r
1847 \r
1848         viewangle = player->angle;\r
1849         fineviewangle = viewangle*(FINEANGLES/ANGLES);\r
1850         viewsin = sintable[viewangle];\r
1851         viewcos = costable[viewangle];\r
1852         viewx = player->x - FixedByFrac(FOCALLENGTH,viewcos);\r
1853         viewy = player->y + FixedByFrac(FOCALLENGTH,viewsin);\r
1854         viewx &= 0xfffffc00;            // stop on a pixel boundary\r
1855         viewy &= 0xfffffc00;\r
1856         viewx += 0x180;\r
1857         viewy += 0x180;\r
1858         viewxpix = viewx>>10;\r
1859         viewypix = viewy>>10;\r
1860 \r
1861         focal.x = viewx>>TILESHIFT;\r
1862         focal.y = viewy>>TILESHIFT;\r
1863 \r
1864 //\r
1865 // find the rightmost visable tile in view\r
1866 //\r
1867         tracedir = viewangle + lastangle;\r
1868         if (tracedir<0)\r
1869           tracedir+=ANGLES;\r
1870         else if (tracedir>=ANGLES)\r
1871           tracedir-=ANGLES;\r
1872         TraceRay( tracedir );\r
1873         right.x = tile.x;\r
1874         right.y = tile.y;\r
1875 \r
1876 //\r
1877 // find the leftmost visable tile in view\r
1878 //\r
1879         tracedir = viewangle + firstangle;\r
1880         if (tracedir<0)\r
1881           tracedir+=ANGLES;\r
1882         else if (tracedir>=ANGLES)\r
1883           tracedir-=ANGLES;\r
1884         TraceRay( tracedir );\r
1885 \r
1886 //\r
1887 // follow the walls from there to the right\r
1888 //\r
1889         rightwall = &walls[1];\r
1890         FollowWalls ();\r
1891 \r
1892         if (aborttrace)\r
1893                 goto restart;\r
1894 \r
1895 //\r
1896 // actually draw stuff\r
1897 //\r
1898         if (++screenpage == 3)\r
1899                 screenpage = 0;\r
1900 \r
1901         bufferofs = screenloc[screenpage];\r
1902 \r
1903         EGAWRITEMODE(2);\r
1904         EGAMAPMASK(15);\r
1905 \r
1906 //\r
1907 // draw the wall list saved be FollowWalls ()\r
1908 //\r
1909 //      animframe = (TimeCount&8)>>3;\r
1910 \r
1911 //\r
1912 // draw all the scaled images\r
1913 //\r
1914         asm     mov     dx,GC_INDEX\r
1915 \r
1916         asm     mov     ax,GC_COLORDONTCARE\r
1917         asm     out     dx,ax                                           // don't look at any of the planes\r
1918 \r
1919         asm     mov     ax,GC_MODE + 256*(10)           // read mode 1, write mode 2\r
1920         asm     out     dx,ax\r
1921 \r
1922         asm     mov     al,GC_BITMASK\r
1923         asm     out     dx,al\r
1924 \r
1925         AnimateWallList();\r
1926         DrawWallList();\r
1927         DrawScaleds();\r
1928 \r
1929         EGAWRITEMODE(0);\r
1930         EGABITMASK(0xff);\r
1931 \r
1932 //\r
1933 // draw hand\r
1934 //\r
1935         if (handheight)\r
1936                 DrawHand ();\r
1937 \r
1938 //\r
1939 // show screen and time last cycle\r
1940 //\r
1941         if (fizzlein)\r
1942         {\r
1943                 fizzlein = false;\r
1944                 FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,true);\r
1945                 lasttimecount = TimeCount;\r
1946                 if (MousePresent) Mouse(MDelta);        // Clear accumulated mouse movement\r
1947         }\r
1948 \r
1949 asm     cli\r
1950 asm     mov     cx,[bufferofs]\r
1951 asm     mov     dx,3d4h         // CRTC address register\r
1952 asm     mov     al,0ch          // start address high register\r
1953 asm     out     dx,al\r
1954 asm     inc     dx\r
1955 asm     mov     al,ch\r
1956 asm     out     dx,al           // set the high byte\r
1957 asm     dec     dx\r
1958 asm     mov     al,0dh          // start address low register\r
1959 asm     out     dx,al\r
1960 asm     inc     dx\r
1961 asm     mov     al,cl\r
1962 asm     out     dx,al           // set the low byte\r
1963 asm     sti\r
1964 \r
1965         displayofs = bufferofs;\r
1966 \r
1967         CalcTics ();\r
1968 \r
1969 }\r
1970 \r