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