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