]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/r_main.c
merge
[plan9front.git] / sys / src / games / doom / r_main.c
1 // Emacs style mode select   -*- C++ -*- 
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // $Log:$
18 //
19 // DESCRIPTION:
20 //      Rendering main loop and setup functions,
21 //       utility functions (BSP, geometry, trigonometry).
22 //      See tables.c, too.
23 //
24 //-----------------------------------------------------------------------------
25
26
27 static const char rcsid[] = "$Id: r_main.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
28
29
30 #include "doomdef.h"
31 #include "d_net.h"
32
33 #include "m_bbox.h"
34
35 #include "r_local.h"
36 #include "r_sky.h"
37
38
39
40
41
42 // Fineangles in the SCREENWIDTH wide window.
43 #define FIELDOFVIEW             2048    
44
45
46
47 int                     viewangleoffset;
48
49 // increment every time a check is made
50 int                     validcount = 1;         
51
52
53 lighttable_t*           fixedcolormap;
54 extern lighttable_t**   walllights;
55
56 int                     centerx;
57 int                     centery;
58
59 fixed_t                 centerxfrac;
60 fixed_t                 centeryfrac;
61 fixed_t                 projection;
62
63 // just for profiling purposes
64 int                     framecount;     
65
66 int                     sscount;
67 int                     linecount;
68 int                     loopcount;
69
70 fixed_t                 viewx;
71 fixed_t                 viewy;
72 fixed_t                 viewz;
73
74 angle_t                 viewangle;
75
76 fixed_t                 viewcos;
77 fixed_t                 viewsin;
78
79 player_t*               viewplayer;
80
81 // 0 = high, 1 = low
82 int                     detailshift;    
83
84 //
85 // precalculated math tables
86 //
87 angle_t                 clipangle;
88
89 // The viewangletox[viewangle + FINEANGLES/4] lookup
90 // maps the visible view angles to screen X coordinates,
91 // flattening the arc to a flat projection plane.
92 // There will be many angles mapped to the same X. 
93 int                     viewangletox[FINEANGLES/2];
94
95 // The xtoviewangleangle[] table maps a screen pixel
96 // to the lowest viewangle that maps back to x ranges
97 // from clipangle to -clipangle.
98 angle_t                 xtoviewangle[SCREENWIDTH+1];
99
100
101 // UNUSED.
102 // The finetangentgent[angle+FINEANGLES/4] table
103 // holds the fixed_t tangent values for view angles,
104 // ranging from MININT to 0 to MAXINT.
105 // fixed_t              finetangent[FINEANGLES/2];
106
107 // fixed_t              finesine[5*FINEANGLES/4];
108 fixed_t*                finecosine = &finesine[FINEANGLES/4];
109
110
111 lighttable_t*           scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
112 lighttable_t*           scalelightfixed[MAXLIGHTSCALE];
113 lighttable_t*           zlight[LIGHTLEVELS][MAXLIGHTZ];
114
115 // bumped light from gun blasts
116 int                     extralight;                     
117
118
119
120 void (*colfunc) (void);
121 void (*basecolfunc) (void);
122 void (*fuzzcolfunc) (void);
123 void (*transcolfunc) (void);
124 void (*spanfunc) (void);
125
126
127
128 //
129 // R_AddPointToBox
130 // Expand a given bbox
131 // so that it encloses a given point.
132 //
133 void
134 R_AddPointToBox
135 ( int           x,
136   int           y,
137   fixed_t*      box )
138 {
139     if (x< box[BOXLEFT])
140         box[BOXLEFT] = x;
141     if (x> box[BOXRIGHT])
142         box[BOXRIGHT] = x;
143     if (y< box[BOXBOTTOM])
144         box[BOXBOTTOM] = y;
145     if (y> box[BOXTOP])
146         box[BOXTOP] = y;
147 }
148
149
150 //
151 // R_PointOnSide
152 // Traverse BSP (sub) tree,
153 //  check point against partition plane.
154 // Returns side 0 (front) or 1 (back).
155 //
156 int
157 R_PointOnSide
158 ( fixed_t       x,
159   fixed_t       y,
160   node_t*       node )
161 {
162     fixed_t     dx;
163     fixed_t     dy;
164     fixed_t     left;
165     fixed_t     right;
166         
167     if (!node->dx)
168     {
169         if (x <= node->x)
170             return node->dy > 0;
171         
172         return node->dy < 0;
173     }
174     if (!node->dy)
175     {
176         if (y <= node->y)
177             return node->dx < 0;
178         
179         return node->dx > 0;
180     }
181         
182     dx = (x - node->x);
183     dy = (y - node->y);
184         
185     // Try to quickly decide by looking at sign bits.
186     if ( (node->dy ^ node->dx ^ dx ^ dy)&0x80000000 )
187     {
188         if  ( (node->dy ^ dx) & 0x80000000 )
189         {
190             // (left is negative)
191             return 1;
192         }
193         return 0;
194     }
195
196     left = FixedMul ( node->dy>>FRACBITS , dx );
197     right = FixedMul ( dy , node->dx>>FRACBITS );
198         
199     if (right < left)
200     {
201         // front side
202         return 0;
203     }
204     // back side
205     return 1;                   
206 }
207
208
209 int
210 R_PointOnSegSide
211 ( fixed_t       x,
212   fixed_t       y,
213   seg_t*        line )
214 {
215     fixed_t     lx;
216     fixed_t     ly;
217     fixed_t     ldx;
218     fixed_t     ldy;
219     fixed_t     dx;
220     fixed_t     dy;
221     fixed_t     left;
222     fixed_t     right;
223         
224     lx = line->v1->x;
225     ly = line->v1->y;
226         
227     ldx = line->v2->x - lx;
228     ldy = line->v2->y - ly;
229         
230     if (!ldx)
231     {
232         if (x <= lx)
233             return ldy > 0;
234         
235         return ldy < 0;
236     }
237     if (!ldy)
238     {
239         if (y <= ly)
240             return ldx < 0;
241         
242         return ldx > 0;
243     }
244         
245     dx = (x - lx);
246     dy = (y - ly);
247         
248     // Try to quickly decide by looking at sign bits.
249     if ( (ldy ^ ldx ^ dx ^ dy)&0x80000000 )
250     {
251         if  ( (ldy ^ dx) & 0x80000000 )
252         {
253             // (left is negative)
254             return 1;
255         }
256         return 0;
257     }
258
259     left = FixedMul ( ldy>>FRACBITS , dx );
260     right = FixedMul ( dy , ldx>>FRACBITS );
261         
262     if (right < left)
263     {
264         // front side
265         return 0;
266     }
267     // back side
268     return 1;                   
269 }
270
271
272 //
273 // R_PointToAngle
274 // To get a global angle from cartesian coordinates,
275 //  the coordinates are flipped until they are in
276 //  the first octant of the coordinate system, then
277 //  the y (<=x) is scaled and divided by x to get a
278 //  tangent (slope) value which is looked up in the
279 //  tantoangle[] table.
280
281 //
282
283
284
285
286 angle_t
287 R_PointToAngle
288 ( fixed_t       x,
289   fixed_t       y )
290 {       
291     x -= viewx;
292     y -= viewy;
293     
294     if ( (!x) && (!y) )
295         return 0;
296
297     if (x>= 0)
298     {
299         // x >=0
300         if (y>= 0)
301         {
302             // y>= 0
303
304             if (x>y)
305             {
306                 // octant 0
307                 return tantoangle[ SlopeDiv(y,x)];
308             }
309             else
310             {
311                 // octant 1
312                 return ANG90-1-tantoangle[ SlopeDiv(x,y)];
313             }
314         }
315         else
316         {
317             // y<0
318             y = -y;
319
320             if (x>y)
321             {
322                 // octant 8
323                 return -tantoangle[SlopeDiv(y,x)];
324             }
325             else
326             {
327                 // octant 7
328                 return ANG270+tantoangle[ SlopeDiv(x,y)];
329             }
330         }
331     }
332     else
333     {
334         // x<0
335         x = -x;
336
337         if (y>= 0)
338         {
339             // y>= 0
340             if (x>y)
341             {
342                 // octant 3
343                 return ANG180-1-tantoangle[ SlopeDiv(y,x)];
344             }
345             else
346             {
347                 // octant 2
348                 return ANG90+ tantoangle[ SlopeDiv(x,y)];
349             }
350         }
351         else
352         {
353             // y<0
354             y = -y;
355
356             if (x>y)
357             {
358                 // octant 4
359                 return ANG180+tantoangle[ SlopeDiv(y,x)];
360             }
361             else
362             {
363                  // octant 5
364                 return ANG270-1-tantoangle[ SlopeDiv(x,y)];
365             }
366         }
367     }
368 }
369
370
371 angle_t
372 R_PointToAngle2
373 ( fixed_t       x1,
374   fixed_t       y1,
375   fixed_t       x2,
376   fixed_t       y2 )
377 {       
378     viewx = x1;
379     viewy = y1;
380     
381     return R_PointToAngle (x2, y2);
382 }
383
384
385 fixed_t
386 R_PointToDist
387 ( fixed_t       x,
388   fixed_t       y )
389 {
390     int         angle;
391     fixed_t     dx;
392     fixed_t     dy;
393     fixed_t     temp;
394     fixed_t     dist;
395         
396     dx = abs(x - viewx);
397     dy = abs(y - viewy);
398         
399     if (dy>dx)
400     {
401         temp = dx;
402         dx = dy;
403         dy = temp;
404     }
405         
406     angle = (tantoangle[ FixedDiv(dy,dx)>>DBITS ]+ANG90) >> ANGLETOFINESHIFT;
407
408     // use as cosine
409     dist = FixedDiv (dx, finesine[angle] );     
410         
411     return dist;
412 }
413
414
415 //
416 // R_ScaleFromGlobalAngle
417 // Returns the texture mapping scale
418 //  for the current line (horizontal span)
419 //  at the given angle.
420 // rw_distance must be calculated first.
421 //
422 fixed_t R_ScaleFromGlobalAngle (angle_t visangle)
423 {
424     fixed_t             scale;
425     int                 anglea;
426     int                 angleb;
427     int                 sinea;
428     int                 sineb;
429     fixed_t             num;
430     int                 den;
431
432     anglea = ANG90 + (visangle-viewangle);
433     angleb = ANG90 + (visangle-rw_normalangle);
434
435     // both sines are allways positive
436     sinea = finesine[anglea>>ANGLETOFINESHIFT]; 
437     sineb = finesine[angleb>>ANGLETOFINESHIFT];
438     num = FixedMul(projection,sineb)<<detailshift;
439     den = FixedMul(rw_distance,sinea);
440
441     if (den > num>>16)
442     {
443         scale = FixedDiv (num, den);
444
445         if (scale > 64*FRACUNIT)
446             scale = 64*FRACUNIT;
447         else if (scale < 256)
448             scale = 256;
449     }
450     else
451         scale = 64*FRACUNIT;
452         
453     return scale;
454 }
455
456
457 //
458 // R_InitTextureMapping
459 //
460 void R_InitTextureMapping (void)
461 {
462     int                 i;
463     int                 x;
464     int                 t;
465     fixed_t             focallength;
466     
467     // Use tangent table to generate viewangletox:
468     //  viewangletox will give the next greatest x
469     //  after the view angle.
470     //
471     // Calc focallength
472     //  so FIELDOFVIEW angles covers SCREENWIDTH.
473     focallength = FixedDiv (centerxfrac,
474                             finetangent[FINEANGLES/4+FIELDOFVIEW/2] );
475         
476     for (i=0 ; i<FINEANGLES/2 ; i++)
477     {
478         if (finetangent[i] > FRACUNIT*2)
479             t = -1;
480         else if (finetangent[i] < -FRACUNIT*2)
481             t = viewwidth+1;
482         else
483         {
484             t = FixedMul (finetangent[i], focallength);
485             t = (centerxfrac - t+FRACUNIT-1)>>FRACBITS;
486
487             if (t < -1)
488                 t = -1;
489             else if (t>viewwidth+1)
490                 t = viewwidth+1;
491         }
492         viewangletox[i] = t;
493     }
494     
495     // Scan viewangletox[] to generate xtoviewangle[]:
496     //  xtoviewangle will give the smallest view angle
497     //  that maps to x. 
498     for (x=0;x<=viewwidth;x++)
499     {
500         i = 0;
501         while (viewangletox[i]>x)
502             i++;
503         xtoviewangle[x] = (i<<ANGLETOFINESHIFT)-ANG90;
504     }
505     
506     // Take out the fencepost cases from viewangletox.
507     for (i=0 ; i<FINEANGLES/2 ; i++)
508     {
509         if (viewangletox[i] == -1)
510             viewangletox[i] = 0;
511         else if (viewangletox[i] == viewwidth+1)
512             viewangletox[i]  = viewwidth;
513     }
514         
515     clipangle = xtoviewangle[0];
516 }
517
518
519
520 //
521 // R_InitLightTables
522 // Only inits the zlight table,
523 //  because the scalelight table changes with view size.
524 //
525 #define DISTMAP         2
526
527 void R_InitLightTables (void)
528 {
529     int         i;
530     int         j;
531     int         level;
532     int         startmap;       
533     int         scale;
534     
535     // Calculate the light levels to use
536     //  for each level / distance combination.
537     for (i=0 ; i< LIGHTLEVELS ; i++)
538     {
539         startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
540         for (j=0 ; j<MAXLIGHTZ ; j++)
541         {
542             scale = FixedDiv ((SCREENWIDTH/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
543             scale >>= LIGHTSCALESHIFT;
544             level = startmap - scale/DISTMAP;
545             
546             if (level < 0)
547                 level = 0;
548
549             if (level >= NUMCOLORMAPS)
550                 level = NUMCOLORMAPS-1;
551
552             zlight[i][j] = colormaps + level*256;
553         }
554     }
555 }
556
557
558
559 //
560 // R_SetViewSize
561 // Do not really change anything here,
562 //  because it might be in the middle of a refresh.
563 // The change will take effect next refresh.
564 //
565 boolean         setsizeneeded;
566 int             setblocks;
567 int             setdetail;
568
569
570 void
571 R_SetViewSize
572 ( int           blocks,
573   int           detail )
574 {
575     setsizeneeded = true;
576     setblocks = blocks;
577     setdetail = detail;
578 }
579
580
581 //
582 // R_ExecuteSetViewSize
583 //
584 void R_ExecuteSetViewSize (void)
585 {
586     fixed_t     cosadj;
587     fixed_t     dy;
588     int         i;
589     int         j;
590     int         level;
591     int         startmap;       
592
593     setsizeneeded = false;
594
595     if (setblocks == 11)
596     {
597         scaledviewwidth = SCREENWIDTH;
598         viewheight = SCREENHEIGHT;
599     }
600     else
601     {
602         scaledviewwidth = setblocks*32;
603         viewheight = (setblocks*168/10)&~7;
604     }
605     
606     detailshift = setdetail;
607     viewwidth = scaledviewwidth>>detailshift;
608         
609     centery = viewheight/2;
610     centerx = viewwidth/2;
611     centerxfrac = centerx<<FRACBITS;
612     centeryfrac = centery<<FRACBITS;
613     projection = centerxfrac;
614
615     if (!detailshift)
616     {
617         colfunc = basecolfunc = R_DrawColumn;
618         fuzzcolfunc = R_DrawFuzzColumn;
619         transcolfunc = R_DrawTranslatedColumn;
620         spanfunc = R_DrawSpan;
621     }
622     else
623     {
624         colfunc = basecolfunc = R_DrawColumnLow;
625         fuzzcolfunc = R_DrawFuzzColumn;
626         transcolfunc = R_DrawTranslatedColumn;
627         spanfunc = R_DrawSpanLow;
628     }
629
630     R_InitBuffer (scaledviewwidth, viewheight);
631         
632     R_InitTextureMapping ();
633     
634     // psprite scales
635     pspritescale = FRACUNIT*viewwidth/SCREENWIDTH;
636     pspriteiscale = FRACUNIT*SCREENWIDTH/viewwidth;
637     
638     // thing clipping
639     for (i=0 ; i<viewwidth ; i++)
640         screenheightarray[i] = viewheight;
641     
642     // planes
643     for (i=0 ; i<viewheight ; i++)
644     {
645         dy = ((i-viewheight/2)<<FRACBITS)+FRACUNIT/2;
646         dy = abs(dy);
647         yslope[i] = FixedDiv ( (viewwidth<<detailshift)/2*FRACUNIT, dy);
648     }
649         
650     for (i=0 ; i<viewwidth ; i++)
651     {
652         cosadj = abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
653         distscale[i] = FixedDiv (FRACUNIT,cosadj);
654     }
655     
656     // Calculate the light levels to use
657     //  for each level / scale combination.
658     for (i=0 ; i< LIGHTLEVELS ; i++)
659     {
660         startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
661         for (j=0 ; j<MAXLIGHTSCALE ; j++)
662         {
663             level = startmap - j*SCREENWIDTH/(viewwidth<<detailshift)/DISTMAP;
664             
665             if (level < 0)
666                 level = 0;
667
668             if (level >= NUMCOLORMAPS)
669                 level = NUMCOLORMAPS-1;
670
671             scalelight[i][j] = colormaps + level*256;
672         }
673     }
674 }
675
676
677
678 //
679 // R_Init
680 //
681 extern int      detailLevel;
682 extern int      screenblocks;
683
684
685
686 void R_Init (void)
687 {
688     R_InitData ();
689     printf ("\nR_InitData");
690
691     R_SetViewSize (screenblocks, detailLevel);
692     R_InitPlanes ();
693     printf ("\nR_InitPlanes");
694     R_InitLightTables ();
695     printf ("\nR_InitLightTables");
696     R_InitSkyMap ();
697     printf ("\nR_InitSkyMap");
698     R_InitTranslationTables ();
699     printf ("\nR_InitTranslationsTables");
700         
701     framecount = 0;
702 }
703
704
705 //
706 // R_PointInSubsector
707 //
708 subsector_t*
709 R_PointInSubsector
710 ( fixed_t       x,
711   fixed_t       y )
712 {
713     node_t*     node;
714     int         side;
715     int         nodenum;
716
717     // single subsector is a special case
718     if (!numnodes)                              
719         return subsectors;
720                 
721     nodenum = numnodes-1;
722
723     while (! (nodenum & NF_SUBSECTOR) )
724     {
725         node = &nodes[nodenum];
726         side = R_PointOnSide (x, y, node);
727         nodenum = node->children[side];
728     }
729         
730     return &subsectors[nodenum & ~NF_SUBSECTOR];
731 }
732
733
734
735 //
736 // R_SetupFrame
737 //
738 void R_SetupFrame (player_t* player)
739 {               
740     int         i;
741     
742     viewplayer = player;
743     viewx = player->mo->x;
744     viewy = player->mo->y;
745     viewangle = player->mo->angle + viewangleoffset;
746     extralight = player->extralight;
747
748     viewz = player->viewz;
749     
750     viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
751     viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
752         
753     sscount = 0;
754         
755     if (player->fixedcolormap)
756     {
757         fixedcolormap =
758             colormaps
759             + player->fixedcolormap*256*sizeof(lighttable_t);
760         
761         walllights = scalelightfixed;
762
763         for (i=0 ; i<MAXLIGHTSCALE ; i++)
764             scalelightfixed[i] = fixedcolormap;
765     }
766     else
767         fixedcolormap = 0;
768                 
769     framecount++;
770     validcount++;
771 }
772
773
774
775 //
776 // R_RenderView
777 //
778 void R_RenderPlayerView (player_t* player)
779 {       
780     R_SetupFrame (player);
781
782     // Clear buffers.
783     R_ClearClipSegs ();
784     R_ClearDrawSegs ();
785     R_ClearPlanes ();
786     R_ClearSprites ();
787     
788     // check for new console commands.
789     NetUpdate ();
790
791     // The head node is the last node output.
792     R_RenderBSPNode (numnodes-1);
793     
794     // Check for new console commands.
795     NetUpdate ();
796     
797     R_DrawPlanes ();
798     
799     // Check for new console commands.
800     NetUpdate ();
801     
802     R_DrawMasked ();
803
804     // Check for new console commands.
805     NetUpdate ();                               
806 }