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