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 // HEADER FILES ------------------------------------------------------------
27 
28 #include <stdlib.h>
29 #include <math.h>
30 
31 #include "templates.h"
32 #include "doomdef.h"
33 #include "d_net.h"
34 #include "doomstat.h"
35 #include "m_random.h"
36 #include "m_bbox.h"
37 #include "p_local.h"
38 #include "r_sky.h"
39 #include "st_stuff.h"
40 #include "c_cvars.h"
41 #include "c_dispatch.h"
42 #include "v_video.h"
43 #include "stats.h"
44 #include "i_video.h"
45 #include "i_system.h"
46 #include "a_sharedglobal.h"
47 #include "r_data/r_translate.h"
48 #include "p_3dmidtex.h"
49 #include "r_data/r_interpolate.h"
50 #include "v_palette.h"
51 #include "po_man.h"
52 #include "p_effect.h"
53 #include "st_start.h"
54 #include "v_font.h"
55 #include "r_renderer.h"
56 #include "r_data/colormaps.h"
57 #include "farchive.h"
58 
59 
60 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
61 
62 extern bool DrawFSHUD;		// [RH] Defined in d_main.cpp
63 EXTERN_CVAR (Bool, cl_capfps)
64 
65 // TYPES -------------------------------------------------------------------
66 
67 struct InterpolationViewer
68 {
69 	AActor *ViewActor;
70 	int otic;
71 	fixed_t oviewx, oviewy, oviewz;
72 	fixed_t nviewx, nviewy, nviewz;
73 	int oviewpitch, nviewpitch;
74 	angle_t oviewangle, nviewangle;
75 };
76 
77 // PRIVATE DATA DECLARATIONS -----------------------------------------------
78 static TArray<InterpolationViewer> PastViewers;
79 static FRandom pr_torchflicker ("TorchFlicker");
80 static FRandom pr_hom;
81 static bool NoInterpolateView;
82 
83 // PUBLIC DATA DEFINITIONS -------------------------------------------------
84 
CVAR(Bool,r_deathcamera,false,CVAR_ARCHIVE)85 CVAR (Bool, r_deathcamera, false, CVAR_ARCHIVE)
86 CVAR (Int, r_clearbuffer, 0, 0)
87 CVAR (Bool, r_drawvoxels, true, 0)
88 CVAR (Bool, r_drawplayersprites, true, 0)	// [RH] Draw player sprites?
89 CUSTOM_CVAR(Float, r_quakeintensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
90 {
91 	if (self < 0.f) self = 0.f;
92 	else if (self > 1.f) self = 1.f;
93 }
94 
95 DCanvas			*RenderTarget;		// [RH] canvas to render to
96 
97 int 			viewwindowx;
98 int 			viewwindowy;
99 
100 fixed_t 		viewx;
101 fixed_t 		viewy;
102 fixed_t 		viewz;
103 int				viewpitch;
104 
105 extern "C"
106 {
107 		int 	viewwidth;
108 		int 	viewheight;
109 		int		centerx;
110 		int		centery;
111 		int		centerxwide;
112 }
113 
114 int				otic;
115 
116 angle_t 		viewangle;
117 sector_t		*viewsector;
118 
119 fixed_t 		viewcos, viewtancos;
120 fixed_t 		viewsin, viewtansin;
121 
122 AActor			*camera;	// [RH] camera to draw from. doesn't have to be a player
123 
124 fixed_t			r_TicFrac;			// [RH] Fractional tic to render
125 DWORD			r_FrameTime;		// [RH] Time this frame started drawing (in ms)
126 bool			r_NoInterpolate;
127 bool			r_showviewer;
128 
129 angle_t			LocalViewAngle;
130 int				LocalViewPitch;
131 bool			LocalKeyboardTurner;
132 
133 float			LastFOV;
134 int				WidescreenRatio;
135 int				setblocks;
136 int				extralight;
137 bool			setsizeneeded;
138 fixed_t			FocalTangent;
139 
140 unsigned int	R_OldBlend = ~0;
141 int 			validcount = 1; 	// increment every time a check is made
142 int				FieldOfView = 2048;		// Fineangles in the SCREENWIDTH wide window
143 
144 FCanvasTextureInfo *FCanvasTextureInfo::List;
145 
146 
147 // CODE --------------------------------------------------------------------
148 static void R_Shutdown ();
149 
150 //==========================================================================
151 //
152 // SlopeDiv
153 //
154 // Utility function, called by R_PointToAngle.
155 //
156 //==========================================================================
157 
SlopeDiv(unsigned int num,unsigned den)158 angle_t SlopeDiv (unsigned int num, unsigned den)
159 {
160 	unsigned int ans;
161 
162 	if (den < 512)
163 		return (ANG45 - 1); //tantoangle[SLOPERANGE]
164 
165 	ans = (num << 3) / (den >> 8);
166 
167 	return ans <= SLOPERANGE ? tantoangle[ans] : (ANG45 - 1);
168 }
169 
170 
171 //==========================================================================
172 //
173 // R_PointToAngle
174 //
175 // To get a global angle from cartesian coordinates, the coordinates are
176 // flipped until they are in the first octant of the coordinate system,
177 // then the y (<=x) is scaled and divided by x to get a tangent (slope)
178 // value which is looked up in the tantoangle[] table.
179 //
180 //==========================================================================
181 
R_PointToAngle2(fixed_t x1,fixed_t y1,fixed_t x,fixed_t y)182 angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x, fixed_t y)
183 {
184 	x -= x1;
185 	y -= y1;
186 
187 	if ((x | y) == 0)
188 	{
189 		return 0;
190 	}
191 
192 	// We need to be aware of overflows here. If the values get larger than INT_MAX/4
193 	// this code won't work anymore.
194 
195 	if (x < INT_MAX/4 && x > -INT_MAX/4 && y < INT_MAX/4 && y > -INT_MAX/4)
196 	{
197 		if (x >= 0)
198 		{
199 			if (y >= 0)
200 			{
201 				if (x > y)
202 				{ // octant 0
203 					return SlopeDiv(y, x);
204 				}
205 				else
206 				{ // octant 1
207 					return ANG90 - 1 - SlopeDiv(x, y);
208 				}
209 			}
210 			else // y < 0
211 			{
212 				y = -y;
213 				if (x > y)
214 				{ // octant 8
215 					return 0 - SlopeDiv(y, x);
216 				}
217 				else
218 				{ // octant 7
219 					return ANG270 + SlopeDiv(x, y);
220 				}
221 			}
222 		}
223 		else // x < 0
224 		{
225 			x = -x;
226 			if (y >= 0)
227 			{
228 				if (x > y)
229 				{ // octant 3
230 					return ANG180 - 1 - SlopeDiv(y, x);
231 				}
232 				else
233 				{ // octant 2
234 					return ANG90 + SlopeDiv(x, y);
235 				}
236 			}
237 			else // y < 0
238 			{
239 				y = -y;
240 				if (x > y)
241 				{ // octant 4
242 					return ANG180 + SlopeDiv(y, x);
243 				}
244 				else
245 				{ // octant 5
246 					return ANG270 - 1 - SlopeDiv(x, y);
247 				}
248 			}
249 		}
250 	}
251 	else
252 	{
253 		// we have to use the slower but more precise floating point atan2 function here.
254 		return xs_RoundToUInt(atan2(double(y), double(x)) * (ANGLE_180/M_PI));
255 	}
256 }
257 
258 //==========================================================================
259 //
260 // R_InitPointToAngle
261 //
262 //==========================================================================
263 
R_InitPointToAngle(void)264 void R_InitPointToAngle (void)
265 {
266 	double f;
267 	int i;
268 //
269 // slope (tangent) to angle lookup
270 //
271 	for (i = 0; i <= SLOPERANGE; i++)
272 	{
273 		f = atan2 ((double)i, (double)SLOPERANGE) / (6.28318530718 /* 2*pi */);
274 		tantoangle[i] = (angle_t)(0xffffffff*f);
275 	}
276 }
277 
278 //==========================================================================
279 //
280 // R_PointToDist2
281 //
282 // Returns the distance from (0,0) to some other point. In a
283 // floating point environment, we'd probably be better off using the
284 // Pythagorean Theorem to determine the result.
285 //
286 // killough 5/2/98: simplified
287 // [RH] Simplified further [sin (t + 90 deg) == cos (t)]
288 // Not used. Should it go away?
289 //
290 //==========================================================================
291 
R_PointToDist2(fixed_t dx,fixed_t dy)292 fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy)
293 {
294 	dx = abs (dx);
295 	dy = abs (dy);
296 
297 	if ((dx | dy) == 0)
298 	{
299 		return 0;
300 	}
301 
302 	if (dy > dx)
303 	{
304 		swapvalues (dx, dy);
305 	}
306 
307 	return FixedDiv (dx, finecosine[tantoangle[FixedDiv (dy, dx) >> DBITS] >> ANGLETOFINESHIFT]);
308 }
309 
310 //==========================================================================
311 //
312 // R_InitTables
313 //
314 //==========================================================================
315 
R_InitTables(void)316 void R_InitTables (void)
317 {
318 	int i;
319 	const double pimul = PI*2/FINEANGLES;
320 
321 	// viewangle tangent table
322 	finetangent[0] = (fixed_t)(FRACUNIT*tan ((0.5-FINEANGLES/4)*pimul)+0.5);
323 	for (i = 1; i < FINEANGLES/2; i++)
324 	{
325 		finetangent[i] = (fixed_t)(FRACUNIT*tan ((i-FINEANGLES/4)*pimul)+0.5);
326 	}
327 
328 	// finesine table
329 	for (i = 0; i < FINEANGLES/4; i++)
330 	{
331 		finesine[i] = (fixed_t)(FRACUNIT * sin (i*pimul));
332 	}
333 	for (i = 0; i < FINEANGLES/4; i++)
334 	{
335 		finesine[i+FINEANGLES/4] = finesine[FINEANGLES/4-1-i];
336 	}
337 	for (i = 0; i < FINEANGLES/2; i++)
338 	{
339 		finesine[i+FINEANGLES/2] = -finesine[i];
340 	}
341 	finesine[FINEANGLES/4] = FRACUNIT;
342 	finesine[FINEANGLES*3/4] = -FRACUNIT;
343 	memcpy (&finesine[FINEANGLES], &finesine[0], sizeof(angle_t)*FINEANGLES/4);
344 }
345 
346 //==========================================================================
347 //
348 // R_SetFOV
349 //
350 // Changes the field of view in degrees
351 //
352 //==========================================================================
353 
R_SetFOV(float fov)354 void R_SetFOV (float fov)
355 {
356 	if (fov < 5.f)
357 		fov = 5.f;
358 	else if (fov > 170.f)
359 		fov = 170.f;
360 	if (fov != LastFOV)
361 	{
362 		LastFOV = fov;
363 		FieldOfView = (int)(fov * (float)FINEANGLES / 360.f);
364 		setsizeneeded = true;
365 	}
366 }
367 
368 //==========================================================================
369 //
370 // R_GetFOV
371 //
372 // Returns the current field of view in degrees
373 //
374 //==========================================================================
375 
R_GetFOV()376 float R_GetFOV ()
377 {
378 	return LastFOV;
379 }
380 
381 //==========================================================================
382 //
383 // R_SetViewSize
384 //
385 // Do not really change anything here, because it might be in the middle
386 // of a refresh. The change will take effect next refresh.
387 //
388 //==========================================================================
389 
R_SetViewSize(int blocks)390 void R_SetViewSize (int blocks)
391 {
392 	setsizeneeded = true;
393 	setblocks = blocks;
394 }
395 
396 //==========================================================================
397 //
398 // R_SetWindow
399 //
400 //==========================================================================
401 
R_SetWindow(int windowSize,int fullWidth,int fullHeight,int stHeight)402 void R_SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight)
403 {
404 	int trueratio;
405 
406 	if (windowSize >= 11)
407 	{
408 		viewwidth = fullWidth;
409 		freelookviewheight = viewheight = fullHeight;
410 	}
411 	else if (windowSize == 10)
412 	{
413 		viewwidth = fullWidth;
414 		viewheight = stHeight;
415 		freelookviewheight = fullHeight;
416 	}
417 	else
418 	{
419 		viewwidth = ((setblocks*fullWidth)/10) & (~15);
420 		viewheight = ((setblocks*stHeight)/10)&~7;
421 		freelookviewheight = ((setblocks*fullHeight)/10)&~7;
422 	}
423 
424 	// If the screen is approximately 16:9 or 16:10, consider it widescreen.
425 	WidescreenRatio = CheckRatio (fullWidth, fullHeight, &trueratio);
426 
427 	DrawFSHUD = (windowSize == 11);
428 
429 	// [RH] Sky height fix for screens not 200 (or 240) pixels tall
430 	R_InitSkyMap ();
431 
432 	centery = viewheight/2;
433 	centerx = viewwidth/2;
434 	if (WidescreenRatio & 4)
435 	{
436 		centerxwide = centerx;
437 	}
438 	else
439 	{
440 		centerxwide = centerx * BaseRatioSizes[WidescreenRatio][3] / 48;
441 	}
442 
443 
444 	int fov = FieldOfView;
445 
446 	// For widescreen displays, increase the FOV so that the middle part of the
447 	// screen that would be visible on a 4:3 display has the requested FOV.
448 	if (centerxwide != centerx)
449 	{ // centerxwide is what centerx would be if the display was not widescreen
450 		fov = int(atan(double(centerx)*tan(double(fov)*M_PI/(FINEANGLES))/double(centerxwide))*(FINEANGLES)/M_PI);
451 		if (fov > 170*FINEANGLES/360)
452 			fov = 170*FINEANGLES/360;
453 	}
454 
455 	FocalTangent = finetangent[FINEANGLES/4+fov/2];
456 	Renderer->SetWindow(windowSize, fullWidth, fullHeight, stHeight, trueratio);
457 }
458 
459 //==========================================================================
460 //
461 // R_ExecuteSetViewSize
462 //
463 //==========================================================================
464 
R_ExecuteSetViewSize()465 void R_ExecuteSetViewSize ()
466 {
467 	setsizeneeded = false;
468 	V_SetBorderNeedRefresh();
469 
470 	R_SetWindow (setblocks, SCREENWIDTH, SCREENHEIGHT, ST_Y);
471 
472 	// Handle resize, e.g. smaller view windows with border and/or status bar.
473 	viewwindowx = (screen->GetWidth() - viewwidth) >> 1;
474 
475 	// Same with base row offset.
476 	viewwindowy = (viewwidth == screen->GetWidth()) ? 0 : (ST_Y - viewheight) >> 1;
477 }
478 
479 //==========================================================================
480 //
481 // CVAR screenblocks
482 //
483 // Selects the size of the visible window
484 //
485 //==========================================================================
486 
487 CUSTOM_CVAR (Int, screenblocks, 10, CVAR_ARCHIVE)
488 {
489 	if (self > 12)
490 		self = 12;
491 	else if (self < 3)
492 		self = 3;
493 	else
494 		R_SetViewSize (self);
495 }
496 
497 //==========================================================================
498 //
499 // R_PointInSubsector
500 //
501 //==========================================================================
502 
R_PointInSubsector(fixed_t x,fixed_t y)503 subsector_t *R_PointInSubsector (fixed_t x, fixed_t y)
504 {
505 	node_t *node;
506 	int side;
507 
508 	// single subsector is a special case
509 	if (numnodes == 0)
510 		return subsectors;
511 
512 	node = nodes + numnodes - 1;
513 
514 	do
515 	{
516 		side = R_PointOnSide (x, y, node);
517 		node = (node_t *)node->children[side];
518 	}
519 	while (!((size_t)node & 1));
520 
521 	return (subsector_t *)((BYTE *)node - 1);
522 }
523 
524 //==========================================================================
525 //
526 // R_Init
527 //
528 //==========================================================================
529 
R_Init()530 void R_Init ()
531 {
532 	atterm (R_Shutdown);
533 
534 	StartScreen->Progress();
535 	V_InitFonts();
536 	StartScreen->Progress();
537 	// Colormap init moved back to InitPalette()
538 	//R_InitColormaps ();
539 	//StartScreen->Progress();
540 
541 	R_InitPointToAngle ();
542 	R_InitTables ();
543 	R_InitTranslationTables ();
544 	R_SetViewSize (screenblocks);
545 	Renderer->Init();
546 }
547 
548 //==========================================================================
549 //
550 // R_Shutdown
551 //
552 //==========================================================================
553 
R_Shutdown()554 static void R_Shutdown ()
555 {
556 	R_DeinitTranslationTables();
557 	R_DeinitColormaps ();
558 	FCanvasTextureInfo::EmptyList();
559 }
560 
561 //==========================================================================
562 //
563 // R_InterpolateView
564 //
565 //==========================================================================
566 
567 //CVAR (Int, tf, 0, 0)
EXTERN_CVAR(Bool,cl_noprediction)568 EXTERN_CVAR (Bool, cl_noprediction)
569 
570 void R_InterpolateView (player_t *player, fixed_t frac, InterpolationViewer *iview)
571 {
572 //	frac = tf;
573 	if (NoInterpolateView)
574 	{
575 		NoInterpolateView = false;
576 		iview->oviewx = iview->nviewx;
577 		iview->oviewy = iview->nviewy;
578 		iview->oviewz = iview->nviewz;
579 		iview->oviewpitch = iview->nviewpitch;
580 		iview->oviewangle = iview->nviewangle;
581 	}
582 	viewx = iview->oviewx + FixedMul (frac, iview->nviewx - iview->oviewx);
583 	viewy = iview->oviewy + FixedMul (frac, iview->nviewy - iview->oviewy);
584 	viewz = iview->oviewz + FixedMul (frac, iview->nviewz - iview->oviewz);
585 	if (player != NULL &&
586 		!(player->cheats & CF_INTERPVIEW) &&
587 		player - players == consoleplayer &&
588 		camera == player->mo &&
589 		!demoplayback &&
590 		iview->nviewx == camera->X() &&
591 		iview->nviewy == camera->Y() &&
592 		!(player->cheats & (CF_TOTALLYFROZEN|CF_FROZEN)) &&
593 		player->playerstate == PST_LIVE &&
594 		player->mo->reactiontime == 0 &&
595 		!NoInterpolateView &&
596 		!paused &&
597 		(!netgame || !cl_noprediction) &&
598 		!LocalKeyboardTurner)
599 	{
600 		viewangle = iview->nviewangle + (LocalViewAngle & 0xFFFF0000);
601 
602 		fixed_t delta = player->centering ? 0 : -(signed)(LocalViewPitch & 0xFFFF0000);
603 
604 		viewpitch = iview->nviewpitch;
605 		if (delta > 0)
606 		{
607 			// Avoid overflowing viewpitch (can happen when a netgame is stalled)
608 			if (viewpitch > INT_MAX - delta)
609 			{
610 				viewpitch = player->MaxPitch;
611 			}
612 			else
613 			{
614 				viewpitch = MIN(viewpitch + delta, player->MaxPitch);
615 			}
616 		}
617 		else if (delta < 0)
618 		{
619 			// Avoid overflowing viewpitch (can happen when a netgame is stalled)
620 			if (viewpitch < INT_MIN - delta)
621 			{
622 				viewpitch = player->MinPitch;
623 			}
624 			else
625 			{
626 				viewpitch = MAX(viewpitch + delta, player->MinPitch);
627 			}
628 		}
629 	}
630 	else
631 	{
632 		viewpitch = iview->oviewpitch + FixedMul (frac, iview->nviewpitch - iview->oviewpitch);
633 		viewangle = iview->oviewangle + FixedMul (frac, iview->nviewangle - iview->oviewangle);
634 	}
635 
636 	// Due to interpolation this is not necessarily the same as the sector the camera is in.
637 	viewsector = R_PointInSubsector(viewx, viewy)->sector;
638 }
639 
640 //==========================================================================
641 //
642 // R_ResetViewInterpolation
643 //
644 //==========================================================================
645 
R_ResetViewInterpolation()646 void R_ResetViewInterpolation ()
647 {
648 	NoInterpolateView = true;
649 }
650 
651 //==========================================================================
652 //
653 // R_SetViewAngle
654 //
655 //==========================================================================
656 
R_SetViewAngle()657 void R_SetViewAngle ()
658 {
659 	angle_t ang = viewangle >> ANGLETOFINESHIFT;
660 
661 	viewsin = finesine[ang];
662 	viewcos = finecosine[ang];
663 
664 	viewtansin = FixedMul (FocalTangent, viewsin);
665 	viewtancos = FixedMul (FocalTangent, viewcos);
666 }
667 
668 //==========================================================================
669 //
670 // FindPastViewer
671 //
672 //==========================================================================
673 
FindPastViewer(AActor * actor)674 static InterpolationViewer *FindPastViewer (AActor *actor)
675 {
676 	for (unsigned int i = 0; i < PastViewers.Size(); ++i)
677 	{
678 		if (PastViewers[i].ViewActor == actor)
679 		{
680 			return &PastViewers[i];
681 		}
682 	}
683 
684 	// Not found, so make a new one
685 	InterpolationViewer iview = { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
686 	iview.ViewActor = actor;
687 	iview.otic = -1;
688 	return &PastViewers[PastViewers.Push (iview)];
689 }
690 
691 //==========================================================================
692 //
693 // R_FreePastViewers
694 //
695 //==========================================================================
696 
R_FreePastViewers()697 void R_FreePastViewers ()
698 {
699 	PastViewers.Clear ();
700 }
701 
702 //==========================================================================
703 //
704 // R_ClearPastViewer
705 //
706 // If the actor changed in a non-interpolatable way, remove it.
707 //
708 //==========================================================================
709 
R_ClearPastViewer(AActor * actor)710 void R_ClearPastViewer (AActor *actor)
711 {
712 	for (unsigned int i = 0; i < PastViewers.Size(); ++i)
713 	{
714 		if (PastViewers[i].ViewActor == actor)
715 		{
716 			// Found it, so remove it.
717 			if (i == PastViewers.Size())
718 			{
719 				PastViewers.Delete (i);
720 			}
721 			else
722 			{
723 				PastViewers.Pop (PastViewers[i]);
724 			}
725 		}
726 	}
727 }
728 
729 //==========================================================================
730 //
731 // R_RebuildViewInterpolation
732 //
733 //==========================================================================
734 
R_RebuildViewInterpolation(player_t * player)735 void R_RebuildViewInterpolation(player_t *player)
736 {
737 	if (player == NULL || player->camera == NULL)
738 		return;
739 
740 	if (!NoInterpolateView)
741 		return;
742 	NoInterpolateView = false;
743 
744 	InterpolationViewer *iview = FindPastViewer(player->camera);
745 
746 	iview->oviewx = iview->nviewx;
747 	iview->oviewy = iview->nviewy;
748 	iview->oviewz = iview->nviewz;
749 	iview->oviewpitch = iview->nviewpitch;
750 	iview->oviewangle = iview->nviewangle;
751 }
752 
753 //==========================================================================
754 //
755 // R_GetViewInterpolationStatus
756 //
757 //==========================================================================
758 
R_GetViewInterpolationStatus()759 bool R_GetViewInterpolationStatus()
760 {
761 	return NoInterpolateView;
762 }
763 
764 //==========================================================================
765 //
766 // QuakePower
767 //
768 //==========================================================================
769 
QuakePower(fixed_t factor,fixed_t intensity,fixed_t offset)770 static fixed_t QuakePower(fixed_t factor, fixed_t intensity, fixed_t offset)
771 {
772 	fixed_t randumb;
773 
774 	if (intensity == 0)
775 	{
776 		randumb = 0;
777 	}
778 	else
779 	{
780 		randumb = pr_torchflicker(intensity * 2) - intensity;
781 	}
782 	return FixedMul(factor, randumb + offset);
783 }
784 
785 //==========================================================================
786 //
787 // R_SetupFrame
788 //
789 //==========================================================================
790 
R_SetupFrame(AActor * actor)791 void R_SetupFrame (AActor *actor)
792 {
793 	if (actor == NULL)
794 	{
795 		I_Error ("Tried to render from a NULL actor.");
796 	}
797 
798 	player_t *player = actor->player;
799 	unsigned int newblend;
800 	InterpolationViewer *iview;
801 
802 	if (player != NULL && player->mo == actor)
803 	{	// [RH] Use camera instead of viewplayer
804 		camera = player->camera;
805 		if (camera == NULL)
806 		{
807 			camera = player->camera = player->mo;
808 		}
809 	}
810 	else
811 	{
812 		camera = actor;
813 	}
814 
815 	if (camera == NULL)
816 	{
817 		I_Error ("You lost your body. Bad dehacked work is likely to blame.");
818 	}
819 
820 	iview = FindPastViewer (camera);
821 
822 	int nowtic = I_GetTime (false);
823 	if (iview->otic != -1 && nowtic > iview->otic)
824 	{
825 		iview->otic = nowtic;
826 		iview->oviewx = iview->nviewx;
827 		iview->oviewy = iview->nviewy;
828 		iview->oviewz = iview->nviewz;
829 		iview->oviewpitch = iview->nviewpitch;
830 		iview->oviewangle = iview->nviewangle;
831 	}
832 
833 	if (player != NULL && gamestate != GS_TITLELEVEL &&
834 		((player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)))
835 	{
836 		// [RH] Use chasecam view
837 		P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector);
838 		r_showviewer = true;
839 	}
840 	else
841 	{
842 		iview->nviewx = camera->X();
843 		iview->nviewy = camera->Y();
844 		iview->nviewz = camera->player ? camera->player->viewz : camera->Z() + camera->GetClass()->Meta.GetMetaFixed(AMETA_CameraHeight);
845 		viewsector = camera->Sector;
846 		r_showviewer = false;
847 	}
848 	iview->nviewpitch = camera->pitch;
849 	if (camera->player != 0)
850 	{
851 		player = camera->player;
852 	}
853 
854 	iview->nviewangle = camera->angle;
855 	if (iview->otic == -1 || r_NoInterpolate)
856 	{
857 		R_ResetViewInterpolation ();
858 		iview->otic = nowtic;
859 	}
860 
861 	r_TicFrac = I_GetTimeFrac (&r_FrameTime);
862 	if (cl_capfps || r_NoInterpolate)
863 	{
864 		r_TicFrac = FRACUNIT;
865 	}
866 
867 	R_InterpolateView (player, r_TicFrac, iview);
868 
869 #ifdef TEST_X
870 	viewx = TEST_X;
871 	viewy = TEST_Y;
872 	viewz = TEST_Z;
873 	viewangle = TEST_ANGLE;
874 #endif
875 
876 	R_SetViewAngle ();
877 
878 	interpolator.DoInterpolations (r_TicFrac);
879 
880 	// Keep the view within the sector's floor and ceiling
881 	fixed_t theZ = viewsector->ceilingplane.ZatPoint (viewx, viewy) - 4*FRACUNIT;
882 	if (viewz > theZ)
883 	{
884 		viewz = theZ;
885 	}
886 
887 	theZ = viewsector->floorplane.ZatPoint (viewx, viewy) + 4*FRACUNIT;
888 	if (viewz < theZ)
889 	{
890 		viewz = theZ;
891 	}
892 
893 	if (!paused)
894 	{
895 		FQuakeJiggers jiggers = { 0, };
896 
897 		if (DEarthquake::StaticGetQuakeIntensities(camera, jiggers) > 0)
898 		{
899 			fixed_t quakefactor = FLOAT2FIXED(r_quakeintensity);
900 
901 			if ((jiggers.RelIntensityX | jiggers.RelOffsetX) != 0)
902 			{
903 				int ang = (camera->angle) >> ANGLETOFINESHIFT;
904 				fixed_t power = QuakePower(quakefactor, jiggers.RelIntensityX, jiggers.RelOffsetX);
905 				viewx += FixedMul(finecosine[ang], power);
906 				viewy += FixedMul(finesine[ang], power);
907 			}
908 			if ((jiggers.RelIntensityY | jiggers.RelOffsetY) != 0)
909 			{
910 				int ang = (camera->angle + ANG90) >> ANGLETOFINESHIFT;
911 				fixed_t power = QuakePower(quakefactor, jiggers.RelIntensityY, jiggers.RelOffsetY);
912 				viewx += FixedMul(finecosine[ang], power);
913 				viewy += FixedMul(finesine[ang], power);
914 			}
915 			// FIXME: Relative Z is not relative
916 			// [MC]On it! Will be introducing pitch after QF_WAVE.
917 			if ((jiggers.RelIntensityZ | jiggers.RelOffsetZ) != 0)
918 			{
919 				viewz += QuakePower(quakefactor, jiggers.RelIntensityZ, jiggers.RelOffsetZ);
920 			}
921 			if ((jiggers.IntensityX | jiggers.OffsetX) != 0)
922 			{
923 				viewx += QuakePower(quakefactor, jiggers.IntensityX, jiggers.OffsetX);
924 			}
925 			if ((jiggers.IntensityY | jiggers.OffsetY) != 0)
926 			{
927 				viewy += QuakePower(quakefactor, jiggers.IntensityY, jiggers.OffsetY);
928 			}
929 			if ((jiggers.IntensityZ | jiggers.OffsetZ) != 0)
930 			{
931 				viewz += QuakePower(quakefactor, jiggers.IntensityZ, jiggers.OffsetZ);
932 			}
933 		}
934 	}
935 
936 	extralight = camera->player ? camera->player->extralight : 0;
937 
938 	// killough 3/20/98, 4/4/98: select colormap based on player status
939 	// [RH] Can also select a blend
940 	newblend = 0;
941 
942 	TArray<lightlist_t> &lightlist = viewsector->e->XFloor.lightlist;
943 	if (lightlist.Size() > 0)
944 	{
945 		for(unsigned int i = 0; i < lightlist.Size(); i++)
946 		{
947 			secplane_t *plane;
948 			int viewside;
949 			plane = (i < lightlist.Size()-1) ? &lightlist[i+1].plane : &viewsector->floorplane;
950 			viewside = plane->PointOnSide(viewx, viewy, viewz);
951 			// Reverse the direction of the test if the plane was downward facing.
952 			// We want to know if the view is above it, whatever its orientation may be.
953 			if (plane->c < 0)
954 				viewside = -viewside;
955 			if (viewside > 0)
956 			{
957 				// 3d floor 'fog' is rendered as a blending value
958 				PalEntry blendv = lightlist[i].blend;
959 
960 				// If no alpha is set, use 50%
961 				if (blendv.a==0 && blendv!=0) blendv.a=128;
962 				newblend = blendv.d;
963 				break;
964 			}
965 		}
966 	}
967 	else
968 	{
969 		const sector_t *s = viewsector->GetHeightSec();
970 		if (s != NULL)
971 		{
972 			newblend = s->floorplane.PointOnSide(viewx, viewy, viewz) < 0
973 				? s->bottommap
974 				: s->ceilingplane.PointOnSide(viewx, viewy, viewz) < 0
975 				? s->topmap
976 				: s->midmap;
977 			if (APART(newblend) == 0 && newblend >= numfakecmaps)
978 				newblend = 0;
979 		}
980 	}
981 
982 	// [RH] Don't override testblend unless entering a sector with a
983 	//		blend different from the previous sector's. Same goes with
984 	//		NormalLight's maps pointer.
985 	if (R_OldBlend != newblend)
986 	{
987 		R_OldBlend = newblend;
988 		if (APART(newblend))
989 		{
990 			BaseBlendR = RPART(newblend);
991 			BaseBlendG = GPART(newblend);
992 			BaseBlendB = BPART(newblend);
993 			BaseBlendA = APART(newblend) / 255.f;
994 			NormalLight.Maps = realcolormaps;
995 		}
996 		else
997 		{
998 			NormalLight.Maps = realcolormaps + NUMCOLORMAPS*256*newblend;
999 			BaseBlendR = BaseBlendG = BaseBlendB = 0;
1000 			BaseBlendA = 0.f;
1001 		}
1002 	}
1003 
1004 	Renderer->CopyStackedViewParameters();
1005 	Renderer->SetupFrame(player);
1006 
1007 	validcount++;
1008 
1009 	if (RenderTarget == screen && r_clearbuffer != 0)
1010 	{
1011 		int color;
1012 		int hom = r_clearbuffer;
1013 
1014 		if (hom == 3)
1015 		{
1016 			hom = ((I_FPSTime() / 128) & 1) + 1;
1017 		}
1018 		if (hom == 1)
1019 		{
1020 			color = GPalette.BlackIndex;
1021 		}
1022 		else if (hom == 2)
1023 		{
1024 			color = GPalette.WhiteIndex;
1025 		}
1026 		else if (hom == 4)
1027 		{
1028 			color = (I_FPSTime() / 32) & 255;
1029 		}
1030 		else
1031 		{
1032 			color = pr_hom();
1033 		}
1034 		Renderer->ClearBuffer(color);
1035 	}
1036 }
1037 
1038 
1039 //==========================================================================
1040 //
1041 // FCanvasTextureInfo :: Add
1042 //
1043 // Assigns a camera to a canvas texture.
1044 //
1045 //==========================================================================
1046 
Add(AActor * viewpoint,FTextureID picnum,int fov)1047 void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, int fov)
1048 {
1049 	FCanvasTextureInfo *probe;
1050 	FCanvasTexture *texture;
1051 
1052 	if (!picnum.isValid())
1053 	{
1054 		return;
1055 	}
1056 	texture = static_cast<FCanvasTexture *>(TexMan[picnum]);
1057 	if (!texture->bHasCanvas)
1058 	{
1059 		Printf ("%s is not a valid target for a camera\n", texture->Name.GetChars());
1060 		return;
1061 	}
1062 
1063 	// Is this texture already assigned to a camera?
1064 	for (probe = List; probe != NULL; probe = probe->Next)
1065 	{
1066 		if (probe->Texture == texture)
1067 		{
1068 			// Yes, change its assignment to this new camera
1069 			if (probe->Viewpoint != viewpoint || probe->FOV != fov)
1070 			{
1071 				texture->bFirstUpdate = true;
1072 			}
1073 			probe->Viewpoint = viewpoint;
1074 			probe->FOV = fov;
1075 			return;
1076 		}
1077 	}
1078 	// No, create a new assignment
1079 	probe = new FCanvasTextureInfo;
1080 	probe->Viewpoint = viewpoint;
1081 	probe->Texture = texture;
1082 	probe->PicNum = picnum;
1083 	probe->FOV = fov;
1084 	probe->Next = List;
1085 	texture->bFirstUpdate = true;
1086 	List = probe;
1087 }
1088 
1089 //==========================================================================
1090 //
1091 // FCanvasTextureInfo :: UpdateAll
1092 //
1093 // Updates all canvas textures that were visible in the last frame.
1094 //
1095 //==========================================================================
1096 
UpdateAll()1097 void FCanvasTextureInfo::UpdateAll ()
1098 {
1099 	FCanvasTextureInfo *probe;
1100 
1101 	for (probe = List; probe != NULL; probe = probe->Next)
1102 	{
1103 		if (probe->Viewpoint != NULL && probe->Texture->bNeedsUpdate)
1104 		{
1105 			Renderer->RenderTextureView(probe->Texture, probe->Viewpoint, probe->FOV);
1106 		}
1107 	}
1108 }
1109 
1110 //==========================================================================
1111 //
1112 // FCanvasTextureInfo :: EmptyList
1113 //
1114 // Removes all camera->texture assignments.
1115 //
1116 //==========================================================================
1117 
EmptyList()1118 void FCanvasTextureInfo::EmptyList ()
1119 {
1120 	FCanvasTextureInfo *probe, *next;
1121 
1122 	for (probe = List; probe != NULL; probe = next)
1123 	{
1124 		next = probe->Next;
1125 		probe->Texture->Unload();
1126 		delete probe;
1127 	}
1128 	List = NULL;
1129 }
1130 
1131 //==========================================================================
1132 //
1133 // FCanvasTextureInfo :: Serialize
1134 //
1135 // Reads or writes the current set of mappings in an archive.
1136 //
1137 //==========================================================================
1138 
Serialize(FArchive & arc)1139 void FCanvasTextureInfo::Serialize (FArchive &arc)
1140 {
1141 	if (arc.IsStoring ())
1142 	{
1143 		FCanvasTextureInfo *probe;
1144 
1145 		for (probe = List; probe != NULL; probe = probe->Next)
1146 		{
1147 			if (probe->Texture != NULL && probe->Viewpoint != NULL)
1148 			{
1149 				arc << probe->Viewpoint << probe->FOV << probe->PicNum;
1150 			}
1151 		}
1152 		AActor *nullactor = NULL;
1153 		arc << nullactor;
1154 	}
1155 	else
1156 	{
1157 		AActor *viewpoint;
1158 		int fov;
1159 		FTextureID picnum;
1160 
1161 		EmptyList ();
1162 		while (arc << viewpoint, viewpoint != NULL)
1163 		{
1164 			arc << fov << picnum;
1165 			Add (viewpoint, picnum, fov);
1166 		}
1167 	}
1168 }
1169 
1170 //==========================================================================
1171 //
1172 // FCanvasTextureInfo :: Mark
1173 //
1174 // Marks all viewpoints in the list for the collector.
1175 //
1176 //==========================================================================
1177 
Mark()1178 void FCanvasTextureInfo::Mark()
1179 {
1180 	for (FCanvasTextureInfo *probe = List; probe != NULL; probe = probe->Next)
1181 	{
1182 		GC::Mark(probe->Viewpoint);
1183 	}
1184 }
1185 
1186