1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1993-1996 by id Software, Inc.
4 // Copyright (C) 1998-2000 by DooM Legacy Team.
5 // Copyright (C) 1999-2020 by Sonic Team Junior.
6 //
7 // This program is free software distributed under the
8 // terms of the GNU General Public License, version 2.
9 // See the 'LICENSE' file for more details.
10 //-----------------------------------------------------------------------------
11 /// \file  r_main.c
12 /// \brief Rendering main loop and setup functions,
13 ///        utility functions (BSP, geometry, trigonometry).
14 ///        See tables.c, too.
15 
16 #include "doomdef.h"
17 #include "g_game.h"
18 #include "g_input.h"
19 #include "r_local.h"
20 #include "r_splats.h" // faB(21jan): testing
21 #include "r_sky.h"
22 #include "hu_stuff.h"
23 #include "st_stuff.h"
24 #include "p_local.h"
25 #include "keys.h"
26 #include "i_video.h"
27 #include "m_menu.h"
28 #include "am_map.h"
29 #include "d_main.h"
30 #include "v_video.h"
31 #include "p_spec.h" // skyboxmo
32 #include "p_setup.h"
33 #include "z_zone.h"
34 #include "m_random.h" // quake camera shake
35 #include "r_portal.h"
36 #include "r_main.h"
37 #include "i_system.h" // I_GetPreciseTime
38 
39 #ifdef HWRENDER
40 #include "hardware/hw_main.h"
41 #endif
42 
43 //profile stuff ---------------------------------------------------------
44 //#define TIMING
45 #ifdef TIMING
46 #include "p5prof.h"
47 INT64 mycount;
48 INT64 mytotal = 0;
49 //unsigned long  nombre = 100000;
50 #endif
51 //profile stuff ---------------------------------------------------------
52 
53 // Fineangles in the SCREENWIDTH wide window.
54 #define FIELDOFVIEW 2048
55 
56 // increment every time a check is made
57 size_t validcount = 1;
58 
59 INT32 centerx, centery;
60 
61 fixed_t centerxfrac, centeryfrac;
62 fixed_t projection;
63 fixed_t projectiony; // aspect ratio
64 fixed_t fovtan; // field of view
65 
66 // just for profiling purposes
67 size_t framecount;
68 
69 size_t loopcount;
70 
71 fixed_t viewx, viewy, viewz;
72 angle_t viewangle, aimingangle;
73 fixed_t viewcos, viewsin;
74 sector_t *viewsector;
75 player_t *viewplayer;
76 mobj_t *r_viewmobj;
77 
78 //
79 // precalculated math tables
80 //
81 angle_t clipangle;
82 angle_t doubleclipangle;
83 
84 // The viewangletox[viewangle + FINEANGLES/4] lookup
85 // maps the visible view angles to screen X coordinates,
86 // flattening the arc to a flat projection plane.
87 // There will be many angles mapped to the same X.
88 INT32 viewangletox[FINEANGLES/2];
89 
90 // The xtoviewangleangle[] table maps a screen pixel
91 // to the lowest viewangle that maps back to x ranges
92 // from clipangle to -clipangle.
93 angle_t xtoviewangle[MAXVIDWIDTH+1];
94 
95 lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
96 lighttable_t *scalelightfixed[MAXLIGHTSCALE];
97 lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
98 
99 // Hack to support extra boom colormaps.
100 extracolormap_t *extra_colormaps = NULL;
101 
102 // Render stats
103 precise_t ps_prevframetime = 0;
104 precise_t ps_rendercalltime = 0;
105 precise_t ps_uitime = 0;
106 precise_t ps_swaptime = 0;
107 
108 precise_t ps_bsptime = 0;
109 
110 precise_t ps_sw_spritecliptime = 0;
111 precise_t ps_sw_portaltime = 0;
112 precise_t ps_sw_planetime = 0;
113 precise_t ps_sw_maskedtime = 0;
114 
115 int ps_numbspcalls = 0;
116 int ps_numsprites = 0;
117 int ps_numdrawnodes = 0;
118 int ps_numpolyobjects = 0;
119 
120 static CV_PossibleValue_t drawdist_cons_t[] = {
121 	{256, "256"},	{512, "512"},	{768, "768"},
122 	{1024, "1024"},	{1536, "1536"},	{2048, "2048"},
123 	{3072, "3072"},	{4096, "4096"},	{6144, "6144"},
124 	{8192, "8192"},	{0, "Infinite"},	{0, NULL}};
125 
126 //static CV_PossibleValue_t precipdensity_cons_t[] = {{0, "None"}, {1, "Light"}, {2, "Moderate"}, {4, "Heavy"}, {6, "Thick"}, {8, "V.Thick"}, {0, NULL}};
127 
128 static CV_PossibleValue_t drawdist_precip_cons_t[] = {
129 	{256, "256"},	{512, "512"},	{768, "768"},
130 	{1024, "1024"},	{1536, "1536"},	{2048, "2048"},
131 	{0, "None"},	{0, NULL}};
132 
133 static CV_PossibleValue_t fov_cons_t[] = {{60*FRACUNIT, "MIN"}, {179*FRACUNIT, "MAX"}, {0, NULL}};
134 static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
135 static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {12, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card
136 static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}};
137 
138 static void Fov_OnChange(void);
139 static void ChaseCam_OnChange(void);
140 static void ChaseCam2_OnChange(void);
141 static void FlipCam_OnChange(void);
142 static void FlipCam2_OnChange(void);
143 void SendWeaponPref(void);
144 void SendWeaponPref2(void);
145 
146 consvar_t cv_tailspickup = CVAR_INIT ("tailspickup", "On", CV_NETVAR, CV_OnOff, NULL);
147 consvar_t cv_chasecam = CVAR_INIT ("chasecam", "On", CV_CALL, CV_OnOff, ChaseCam_OnChange);
148 consvar_t cv_chasecam2 = CVAR_INIT ("chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChange);
149 consvar_t cv_flipcam = CVAR_INIT ("flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange);
150 consvar_t cv_flipcam2 = CVAR_INIT ("flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange);
151 
152 consvar_t cv_shadow = CVAR_INIT ("shadow", "On", CV_SAVE, CV_OnOff, NULL);
153 consvar_t cv_skybox = CVAR_INIT ("skybox", "On", CV_SAVE, CV_OnOff, NULL);
154 consvar_t cv_ffloorclip = CVAR_INIT ("ffloorclip", "On", CV_SAVE, CV_OnOff, NULL);
155 consvar_t cv_allowmlook = CVAR_INIT ("allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL);
156 consvar_t cv_showhud = CVAR_INIT ("showhud", "Yes", CV_CALL,  CV_YesNo, R_SetViewSize);
157 consvar_t cv_translucenthud = CVAR_INIT ("translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL);
158 
159 consvar_t cv_translucency = CVAR_INIT ("translucency", "On", CV_SAVE, CV_OnOff, NULL);
160 consvar_t cv_drawdist = CVAR_INIT ("drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL);
161 consvar_t cv_drawdist_nights = CVAR_INIT ("drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL);
162 consvar_t cv_drawdist_precip = CVAR_INIT ("drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL);
163 //consvar_t cv_precipdensity = CVAR_INIT ("precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL);
164 consvar_t cv_fov = CVAR_INIT ("fov", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange);
165 
166 // Okay, whoever said homremoval causes a performance hit should be shot.
167 consvar_t cv_homremoval = CVAR_INIT ("homremoval", "No", CV_SAVE, homremoval_cons_t, NULL);
168 
169 consvar_t cv_maxportals = CVAR_INIT ("maxportals", "2", CV_SAVE, maxportals_cons_t, NULL);
170 
171 consvar_t cv_renderstats = CVAR_INIT ("renderstats", "Off", 0, CV_OnOff, NULL);
172 
SplitScreen_OnChange(void)173 void SplitScreen_OnChange(void)
174 {
175 	if (!cv_debug && netgame)
176 	{
177 		if (splitscreen)
178 		{
179 			CONS_Alert(CONS_NOTICE, M_GetText("Splitscreen not supported in netplay, sorry!\n"));
180 			splitscreen = false;
181 		}
182 		return;
183 	}
184 
185 	// recompute screen size
186 	R_ExecuteSetViewSize();
187 
188 	if (!demoplayback && !botingame)
189 	{
190 		if (splitscreen)
191 			CL_AddSplitscreenPlayer();
192 		else
193 			CL_RemoveSplitscreenPlayer();
194 
195 		if (server && !netgame)
196 			multiplayer = splitscreen;
197 	}
198 	else
199 	{
200 		INT32 i;
201 		secondarydisplayplayer = consoleplayer;
202 		for (i = 0; i < MAXPLAYERS; i++)
203 			if (playeringame[i] && i != consoleplayer)
204 			{
205 				secondarydisplayplayer = i;
206 				break;
207 			}
208 	}
209 }
Fov_OnChange(void)210 static void Fov_OnChange(void)
211 {
212 	// Shouldn't be needed with render parity?
213 	//if ((netgame || multiplayer) && !cv_debug && cv_fov.value != 90*FRACUNIT)
214 	//	CV_Set(&cv_fov, cv_fov.defaultvalue);
215 
216 	R_SetViewSize();
217 }
218 
ChaseCam_OnChange(void)219 static void ChaseCam_OnChange(void)
220 {
221 	if (!cv_chasecam.value || !cv_useranalog[0].value)
222 		CV_SetValue(&cv_analog[0], 0);
223 	else
224 		CV_SetValue(&cv_analog[0], 1);
225 }
226 
ChaseCam2_OnChange(void)227 static void ChaseCam2_OnChange(void)
228 {
229 	if (botingame)
230 		return;
231 	if (!cv_chasecam2.value || !cv_useranalog[1].value)
232 		CV_SetValue(&cv_analog[1], 0);
233 	else
234 		CV_SetValue(&cv_analog[1], 1);
235 }
236 
FlipCam_OnChange(void)237 static void FlipCam_OnChange(void)
238 {
239 	SendWeaponPref();
240 }
241 
FlipCam2_OnChange(void)242 static void FlipCam2_OnChange(void)
243 {
244 	SendWeaponPref2();
245 }
246 
247 //
248 // R_PointOnSide
249 // Traverse BSP (sub) tree,
250 // check point against partition plane.
251 // Returns side 0 (front) or 1 (back).
252 //
253 // killough 5/2/98: reformatted
254 //
R_PointOnSide(fixed_t x,fixed_t y,node_t * node)255 INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node)
256 {
257 	if (!node->dx)
258 		return x <= node->x ? node->dy > 0 : node->dy < 0;
259 
260 	if (!node->dy)
261 		return y <= node->y ? node->dx < 0 : node->dx > 0;
262 
263 	x -= node->x;
264 	y -= node->y;
265 
266 	// Try to quickly decide by looking at sign bits.
267 	if ((node->dy ^ node->dx ^ x ^ y) < 0)
268 		return (node->dy ^ x) < 0;  // (left is negative)
269 	return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x);
270 }
271 
272 // killough 5/2/98: reformatted
R_PointOnSegSide(fixed_t x,fixed_t y,seg_t * line)273 INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line)
274 {
275 	fixed_t lx = line->v1->x;
276 	fixed_t ly = line->v1->y;
277 	fixed_t ldx = line->v2->x - lx;
278 	fixed_t ldy = line->v2->y - ly;
279 
280 	if (!ldx)
281 		return x <= lx ? ldy > 0 : ldy < 0;
282 
283 	if (!ldy)
284 		return y <= ly ? ldx < 0 : ldx > 0;
285 
286 	x -= lx;
287 	y -= ly;
288 
289 	// Try to quickly decide by looking at sign bits.
290 	if ((ldy ^ ldx ^ x ^ y) < 0)
291 		return (ldy ^ x) < 0;          // (left is negative)
292 	return FixedMul(y, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, x);
293 }
294 
295 //
296 // R_PointToAngle
297 // To get a global angle from cartesian coordinates,
298 //  the coordinates are flipped until they are in
299 //  the first octant of the coordinate system, then
300 //  the y (<=x) is scaled and divided by x to get a
301 //  tangent (slope) value which is looked up in the
302 //  tantoangle[] table. The +1 size of tantoangle[]
303 //  is to handle the case when x==y without additional
304 //  checking.
305 //
306 // killough 5/2/98: reformatted, cleaned up
307 
R_PointToAngle(fixed_t x,fixed_t y)308 angle_t R_PointToAngle(fixed_t x, fixed_t y)
309 {
310 	return (y -= viewy, (x -= viewx) || y) ?
311 	x >= 0 ?
312 	y >= 0 ?
313 		(x > y) ? tantoangle[SlopeDiv(y,x)] :                          // octant 0
314 		ANGLE_90-tantoangle[SlopeDiv(x,y)] :                           // octant 1
315 		x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] :                   // octant 8
316 		ANGLE_270+tantoangle[SlopeDiv(x,y)] :                          // octant 7
317 		y >= 0 ? (x = -x) > y ? ANGLE_180-tantoangle[SlopeDiv(y,x)] :  // octant 3
318 		ANGLE_90 + tantoangle[SlopeDiv(x,y)] :                         // octant 2
319 		(x = -x) > (y = -y) ? ANGLE_180+tantoangle[SlopeDiv(y,x)] :    // octant 4
320 		ANGLE_270-tantoangle[SlopeDiv(x,y)] :                          // octant 5
321 		0;
322 }
323 
324 // This version uses 64-bit variables to avoid overflows with large values.
325 // Currently used only by OpenGL rendering.
R_PointToAngle64(INT64 x,INT64 y)326 angle_t R_PointToAngle64(INT64 x, INT64 y)
327 {
328 	return (y -= viewy, (x -= viewx) || y) ?
329 	x >= 0 ?
330 	y >= 0 ?
331 		(x > y) ? tantoangle[SlopeDivEx(y,x)] :                            // octant 0
332 		ANGLE_90-tantoangle[SlopeDivEx(x,y)] :                               // octant 1
333 		x > (y = -y) ? 0-tantoangle[SlopeDivEx(y,x)] :                    // octant 8
334 		ANGLE_270+tantoangle[SlopeDivEx(x,y)] :                              // octant 7
335 		y >= 0 ? (x = -x) > y ? ANGLE_180-tantoangle[SlopeDivEx(y,x)] :  // octant 3
336 		ANGLE_90 + tantoangle[SlopeDivEx(x,y)] :                             // octant 2
337 		(x = -x) > (y = -y) ? ANGLE_180+tantoangle[SlopeDivEx(y,x)] :    // octant 4
338 		ANGLE_270-tantoangle[SlopeDivEx(x,y)] :                              // octant 5
339 		0;
340 }
341 
R_PointToAngle2(fixed_t pviewx,fixed_t pviewy,fixed_t x,fixed_t y)342 angle_t R_PointToAngle2(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y)
343 {
344 	return (y -= pviewy, (x -= pviewx) || y) ?
345 	x >= 0 ?
346 	y >= 0 ?
347 		(x > y) ? tantoangle[SlopeDiv(y,x)] :                          // octant 0
348 		ANGLE_90-tantoangle[SlopeDiv(x,y)] :                           // octant 1
349 		x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] :                   // octant 8
350 		ANGLE_270+tantoangle[SlopeDiv(x,y)] :                          // octant 7
351 		y >= 0 ? (x = -x) > y ? ANGLE_180-tantoangle[SlopeDiv(y,x)] :  // octant 3
352 		ANGLE_90 + tantoangle[SlopeDiv(x,y)] :                         // octant 2
353 		(x = -x) > (y = -y) ? ANGLE_180+tantoangle[SlopeDiv(y,x)] :    // octant 4
354 		ANGLE_270-tantoangle[SlopeDiv(x,y)] :                          // octant 5
355 		0;
356 }
357 
R_PointToDist2(fixed_t px2,fixed_t py2,fixed_t px1,fixed_t py1)358 fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1)
359 {
360 	angle_t angle;
361 	fixed_t dx, dy, dist;
362 
363 	dx = abs(px1 - px2);
364 	dy = abs(py1 - py2);
365 
366 	if (dy > dx)
367 	{
368 		fixed_t temp;
369 
370 		temp = dx;
371 		dx = dy;
372 		dy = temp;
373 	}
374 	if (!dy)
375 		return dx;
376 
377 	angle = (tantoangle[FixedDiv(dy, dx)>>DBITS] + ANGLE_90) >> ANGLETOFINESHIFT;
378 
379 	// use as cosine
380 	dist = FixedDiv(dx, FINESINE(angle));
381 
382 	return dist;
383 }
384 
385 // Little extra utility. Works in the same way as R_PointToAngle2
R_PointToDist(fixed_t x,fixed_t y)386 fixed_t R_PointToDist(fixed_t x, fixed_t y)
387 {
388 	return R_PointToDist2(viewx, viewy, x, y);
389 }
390 
R_PointToAngleEx(INT32 x2,INT32 y2,INT32 x1,INT32 y1)391 angle_t R_PointToAngleEx(INT32 x2, INT32 y2, INT32 x1, INT32 y1)
392 {
393 	INT64 dx = x1-x2;
394 	INT64 dy = y1-y2;
395 	if (dx < INT32_MIN || dx > INT32_MAX || dy < INT32_MIN || dy > INT32_MAX)
396 	{
397 		x1 = (int)(dx / 2 + x2);
398 		y1 = (int)(dy / 2 + y2);
399 	}
400 	return (y1 -= y2, (x1 -= x2) || y1) ?
401 	x1 >= 0 ?
402 	y1 >= 0 ?
403 		(x1 > y1) ? tantoangle[SlopeDivEx(y1,x1)] :                            // octant 0
404 		ANGLE_90-tantoangle[SlopeDivEx(x1,y1)] :                               // octant 1
405 		x1 > (y1 = -y1) ? 0-tantoangle[SlopeDivEx(y1,x1)] :                    // octant 8
406 		ANGLE_270+tantoangle[SlopeDivEx(x1,y1)] :                              // octant 7
407 		y1 >= 0 ? (x1 = -x1) > y1 ? ANGLE_180-tantoangle[SlopeDivEx(y1,x1)] :  // octant 3
408 		ANGLE_90 + tantoangle[SlopeDivEx(x1,y1)] :                             // octant 2
409 		(x1 = -x1) > (y1 = -y1) ? ANGLE_180+tantoangle[SlopeDivEx(y1,x1)] :    // octant 4
410 		ANGLE_270-tantoangle[SlopeDivEx(x1,y1)] :                              // octant 5
411 		0;
412 }
413 
414 //
415 // R_ScaleFromGlobalAngle
416 // Returns the texture mapping scale for the current line (horizontal span)
417 //  at the given angle.
418 // rw_distance must be calculated first.
419 //
420 // killough 5/2/98: reformatted, cleaned up
421 //
422 // note: THIS IS USED ONLY FOR WALLS!
R_ScaleFromGlobalAngle(angle_t visangle)423 fixed_t R_ScaleFromGlobalAngle(angle_t visangle)
424 {
425 	angle_t anglea = ANGLE_90 + (visangle-viewangle);
426 	angle_t angleb = ANGLE_90 + (visangle-rw_normalangle);
427 	fixed_t den = FixedMul(rw_distance, FINESINE(anglea>>ANGLETOFINESHIFT));
428 	// proff 11/06/98: Changed for high-res
429 	fixed_t num = FixedMul(projectiony, FINESINE(angleb>>ANGLETOFINESHIFT));
430 
431 	if (den > num>>16)
432 	{
433 		num = FixedDiv(num, den);
434 		if (num > 64*FRACUNIT)
435 			return 64*FRACUNIT;
436 		if (num < 256)
437 			return 256;
438 		return num;
439 	}
440 	return 64*FRACUNIT;
441 }
442 
443 //
444 // R_DoCulling
445 // Checks viewz and top/bottom heights of an item against culling planes
446 // Returns true if the item is to be culled, i.e it shouldn't be drawn!
447 // if ML_NOCLIMB is set, the camera view is required to be in the same area for culling to occur
R_DoCulling(line_t * cullheight,line_t * viewcullheight,fixed_t vz,fixed_t bottomh,fixed_t toph)448 boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph)
449 {
450 	fixed_t cullplane;
451 
452 	if (!cullheight)
453 		return false;
454 
455 	cullplane = cullheight->frontsector->floorheight;
456 	if (cullheight->flags & ML_NOCLIMB) // Group culling
457 	{
458 		if (!viewcullheight)
459 			return false;
460 
461 		// Make sure this is part of the same group
462 		if (viewcullheight->frontsector == cullheight->frontsector)
463 		{
464 			// OK, we can cull
465 			if (vz > cullplane && toph < cullplane) // Cull if below plane
466 				return true;
467 
468 			if (bottomh > cullplane && vz <= cullplane) // Cull if above plane
469 				return true;
470 		}
471 	}
472 	else // Quick culling
473 	{
474 		if (vz > cullplane && toph < cullplane) // Cull if below plane
475 			return true;
476 
477 		if (bottomh > cullplane && vz <= cullplane) // Cull if above plane
478 			return true;
479 	}
480 
481 	return false;
482 }
483 
484 //
485 // R_InitTextureMapping
486 //
R_InitTextureMapping(void)487 static void R_InitTextureMapping(void)
488 {
489 	INT32 i;
490 	INT32 x;
491 	INT32 t;
492 	fixed_t focallength;
493 
494 	// Use tangent table to generate viewangletox:
495 	//  viewangletox will give the next greatest x
496 	//  after the view angle.
497 	//
498 	// Calc focallength
499 	//  so FIELDOFVIEW angles covers SCREENWIDTH.
500 	focallength = FixedDiv(projection,
501 		FINETANGENT(FINEANGLES/4+FIELDOFVIEW/2));
502 
503 	focallengthf = FIXED_TO_FLOAT(focallength);
504 
505 	for (i = 0; i < FINEANGLES/2; i++)
506 	{
507 		if (FINETANGENT(i) > fovtan*2)
508 			t = -1;
509 		else if (FINETANGENT(i) < -fovtan*2)
510 			t = viewwidth+1;
511 		else
512 		{
513 			t = FixedMul(FINETANGENT(i), focallength);
514 			t = (centerxfrac - t+FRACUNIT-1)>>FRACBITS;
515 
516 			if (t < -1)
517 				t = -1;
518 			else if (t > viewwidth+1)
519 				t = viewwidth+1;
520 		}
521 		viewangletox[i] = t;
522 	}
523 
524 	// Scan viewangletox[] to generate xtoviewangle[]:
525 	//  xtoviewangle will give the smallest view angle
526 	//  that maps to x.
527 	for (x = 0; x <= viewwidth;x++)
528 	{
529 		i = 0;
530 		while (viewangletox[i] > x)
531 			i++;
532 		xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANGLE_90;
533 	}
534 
535 	// Take out the fencepost cases from viewangletox.
536 	for (i = 0; i < FINEANGLES/2; i++)
537 	{
538 		if (viewangletox[i] == -1)
539 			viewangletox[i] = 0;
540 		else if (viewangletox[i] == viewwidth+1)
541 			viewangletox[i]  = viewwidth;
542 	}
543 
544 	clipangle = xtoviewangle[0];
545 	doubleclipangle = clipangle*2;
546 }
547 
548 
549 
550 //
551 // R_InitLightTables
552 // Only inits the zlight table,
553 //  because the scalelight table changes with view size.
554 //
555 #define DISTMAP 2
556 
R_InitLightTables(void)557 static inline void R_InitLightTables(void)
558 {
559 	INT32 i;
560 	INT32 j;
561 	INT32 level;
562 	INT32 startmapl;
563 	INT32 scale;
564 
565 	// Calculate the light levels to use
566 	//  for each level / distance combination.
567 	for (i = 0; i < LIGHTLEVELS; i++)
568 	{
569 		startmapl = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
570 		for (j = 0; j < MAXLIGHTZ; j++)
571 		{
572 			//added : 02-02-98 : use BASEVIDWIDTH, vid.width is not set already,
573 			// and it seems it needs to be calculated only once.
574 			scale = FixedDiv((BASEVIDWIDTH/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
575 			scale >>= LIGHTSCALESHIFT;
576 			level = startmapl - scale/DISTMAP;
577 
578 			if (level < 0)
579 				level = 0;
580 
581 			if (level >= NUMCOLORMAPS)
582 				level = NUMCOLORMAPS-1;
583 
584 			zlight[i][j] = colormaps + level*256;
585 		}
586 	}
587 }
588 
589 //#define WOUGHMP_WOUGHMP // I got a fish-eye lens - I'll make a rap video with a couple of friends
590 // it's kinda laggy sometimes
591 
592 static struct {
593 	angle_t rollangle; // pre-shifted by fineshift
594 #ifdef WOUGHMP_WOUGHMP
595 	fixed_t fisheye;
596 #endif
597 
598 	fixed_t zoomneeded;
599 	INT32 *scrmap;
600 	INT32 scrmapsize;
601 
602 	INT32 x1; // clip rendering horizontally for efficiency
603 	INT16 ceilingclip[MAXVIDWIDTH], floorclip[MAXVIDWIDTH];
604 
605 	boolean use;
606 } viewmorph = {
607 	0,
608 #ifdef WOUGHMP_WOUGHMP
609 	0,
610 #endif
611 
612 	FRACUNIT,
613 	NULL,
614 	0,
615 
616 	0,
617 	{}, {},
618 
619 	false
620 };
621 
R_CheckViewMorph(void)622 void R_CheckViewMorph(void)
623 {
624 	float zoomfactor, rollcos, rollsin;
625 	float x1, y1, x2, y2;
626 	fixed_t temp;
627 	INT32 end, vx, vy, pos, usedpos;
628 	INT32 usedx, usedy, halfwidth = vid.width/2, halfheight = vid.height/2;
629 #ifdef WOUGHMP_WOUGHMP
630 	float fisheyemap[MAXVIDWIDTH/2 + 1];
631 #endif
632 
633 	angle_t rollangle = players[displayplayer].viewrollangle;
634 #ifdef WOUGHMP_WOUGHMP
635 	fixed_t fisheye = cv_cam2_turnmultiplier.value; // temporary test value
636 #endif
637 
638 	rollangle >>= ANGLETOFINESHIFT;
639 	rollangle = ((rollangle+2) & ~3) & FINEMASK; // Limit the distinct number of angles to reduce recalcs from angles changing a lot.
640 
641 #ifdef WOUGHMP_WOUGHMP
642 	fisheye &= ~0x7FF; // Same
643 #endif
644 
645 	if (rollangle == viewmorph.rollangle &&
646 #ifdef WOUGHMP_WOUGHMP
647 		fisheye == viewmorph.fisheye &&
648 #endif
649 		viewmorph.scrmapsize == vid.width*vid.height)
650 		return; // No change
651 
652 	viewmorph.rollangle = rollangle;
653 #ifdef WOUGHMP_WOUGHMP
654 	viewmorph.fisheye = fisheye;
655 #endif
656 
657 	if (viewmorph.rollangle == 0
658 #ifdef WOUGHMP_WOUGHMP
659 		 && viewmorph.fisheye == 0
660 #endif
661 	 )
662 	{
663 		viewmorph.use = false;
664 		viewmorph.x1 = 0;
665 		if (viewmorph.zoomneeded != FRACUNIT)
666 			R_SetViewSize();
667 		viewmorph.zoomneeded = FRACUNIT;
668 
669 		return;
670 	}
671 
672 	if (viewmorph.scrmapsize != vid.width*vid.height)
673 	{
674 		if (viewmorph.scrmap)
675 			free(viewmorph.scrmap);
676 		viewmorph.scrmap = malloc(vid.width*vid.height * sizeof(INT32));
677 		viewmorph.scrmapsize = vid.width*vid.height;
678 	}
679 
680 	temp = FINECOSINE(rollangle);
681 	rollcos = FIXED_TO_FLOAT(temp);
682 	temp = FINESINE(rollangle);
683 	rollsin = FIXED_TO_FLOAT(temp);
684 
685 	// Calculate maximum zoom needed
686 	x1 = (vid.width*fabsf(rollcos) + vid.height*fabsf(rollsin)) / vid.width;
687 	y1 = (vid.height*fabsf(rollcos) + vid.width*fabsf(rollsin)) / vid.height;
688 
689 #ifdef WOUGHMP_WOUGHMP
690 	if (fisheye)
691 	{
692 		float f = FIXED_TO_FLOAT(fisheye);
693 		for (vx = 0; vx <= halfwidth; vx++)
694 			fisheyemap[vx] = 1.0f / cos(atan(vx * f / halfwidth));
695 
696 		f = cos(atan(f));
697 		if (f < 1.0f)
698 		{
699 			x1 /= f;
700 			y1 /= f;
701 		}
702 	}
703 #endif
704 
705 	temp = max(x1, y1)*FRACUNIT;
706 	if (temp < FRACUNIT)
707 		temp = FRACUNIT;
708 	else
709 		temp |= 0x3FFF; // Limit how many times the viewport needs to be recalculated
710 
711 	//CONS_Printf("Setting zoom to %f\n", FIXED_TO_FLOAT(temp));
712 
713 	if (temp != viewmorph.zoomneeded)
714 	{
715 		viewmorph.zoomneeded = temp;
716 		R_SetViewSize();
717 	}
718 
719 	zoomfactor = FIXED_TO_FLOAT(viewmorph.zoomneeded);
720 
721 	end = vid.width * vid.height - 1;
722 
723 	pos = 0;
724 
725 	// Pre-multiply rollcos and rollsin to use for positional stuff
726 	rollcos /= zoomfactor;
727 	rollsin /= zoomfactor;
728 
729 	x1 = -(halfwidth * rollcos - halfheight * rollsin);
730 	y1 = -(halfheight * rollcos + halfwidth * rollsin);
731 
732 #ifdef WOUGHMP_WOUGHMP
733 	if (fisheye)
734 		viewmorph.x1 = (INT32)(halfwidth - (halfwidth * fabsf(rollcos) + halfheight * fabsf(rollsin)) * fisheyemap[halfwidth]);
735 	else
736 #endif
737 	viewmorph.x1 = (INT32)(halfwidth - (halfwidth * fabsf(rollcos) + halfheight * fabsf(rollsin)));
738 	//CONS_Printf("saving %d cols\n", viewmorph.x1);
739 
740 	// Set ceilingclip and floorclip
741 	for (vx = 0; vx < vid.width; vx++)
742 	{
743 		viewmorph.ceilingclip[vx] = vid.height;
744 		viewmorph.floorclip[vx] = -1;
745 	}
746 	x2 = x1;
747 	y2 = y1;
748 	for (vx = 0; vx < vid.width; vx++)
749 	{
750 		INT16 xa, ya, xb, yb;
751 		xa = x2+halfwidth;
752 		ya = y2+halfheight-1;
753 		xb = vid.width-1-xa;
754 		yb = vid.height-1-ya;
755 
756 		viewmorph.ceilingclip[xa] = min(viewmorph.ceilingclip[xa], ya);
757 		viewmorph.floorclip[xa] = max(viewmorph.floorclip[xa], ya);
758 		viewmorph.ceilingclip[xb] = min(viewmorph.ceilingclip[xb], yb);
759 		viewmorph.floorclip[xb] = max(viewmorph.floorclip[xb], yb);
760 		x2 += rollcos;
761 		y2 += rollsin;
762 	}
763 	x2 = x1;
764 	y2 = y1;
765 	for (vy = 0; vy < vid.height; vy++)
766 	{
767 		INT16 xa, ya, xb, yb;
768 		xa = x2+halfwidth;
769 		ya = y2+halfheight;
770 		xb = vid.width-1-xa;
771 		yb = vid.height-1-ya;
772 
773 		viewmorph.ceilingclip[xa] = min(viewmorph.ceilingclip[xa], ya);
774 		viewmorph.floorclip[xa] = max(viewmorph.floorclip[xa], ya);
775 		viewmorph.ceilingclip[xb] = min(viewmorph.ceilingclip[xb], yb);
776 		viewmorph.floorclip[xb] = max(viewmorph.floorclip[xb], yb);
777 		x2 -= rollsin;
778 		y2 += rollcos;
779 	}
780 
781 	//CONS_Printf("Top left corner is %f %f\n", x1, y1);
782 
783 #ifdef WOUGHMP_WOUGHMP
784 	if (fisheye)
785 	{
786 		for (vy = 0; vy < halfheight; vy++)
787 		{
788 			x2 = x1;
789 			y2 = y1;
790 			x1 -= rollsin;
791 			y1 += rollcos;
792 
793 			for (vx = 0; vx < vid.width; vx++)
794 			{
795 				usedx = halfwidth + x2*fisheyemap[(int) floorf(fabsf(y2*zoomfactor))];
796 				usedy = halfheight + y2*fisheyemap[(int) floorf(fabsf(x2*zoomfactor))];
797 
798 				usedpos = usedx + usedy*vid.width;
799 
800 				viewmorph.scrmap[pos] = usedpos;
801 				viewmorph.scrmap[end-pos] = end-usedpos;
802 
803 				x2 += rollcos;
804 				y2 += rollsin;
805 				pos++;
806 			}
807 		}
808 	}
809 	else
810 	{
811 #endif
812 	x1 += halfwidth;
813 	y1 += halfheight;
814 
815 	for (vy = 0; vy < halfheight; vy++)
816 	{
817 		x2 = x1;
818 		y2 = y1;
819 		x1 -= rollsin;
820 		y1 += rollcos;
821 
822 		for (vx = 0; vx < vid.width; vx++)
823 		{
824 			usedx = x2;
825 			usedy = y2;
826 
827 			usedpos = usedx + usedy*vid.width;
828 
829 			viewmorph.scrmap[pos] = usedpos;
830 			viewmorph.scrmap[end-pos] = end-usedpos;
831 
832 			x2 += rollcos;
833 			y2 += rollsin;
834 			pos++;
835 		}
836 	}
837 #ifdef WOUGHMP_WOUGHMP
838 	}
839 #endif
840 
841 	viewmorph.use = true;
842 }
843 
R_ApplyViewMorph(void)844 void R_ApplyViewMorph(void)
845 {
846 	UINT8 *tmpscr = screens[4];
847 	UINT8 *srcscr = screens[0];
848 	INT32 p, end = vid.width * vid.height;
849 
850 	if (!viewmorph.use)
851 		return;
852 
853 	if (cv_debug & DBG_VIEWMORPH)
854 	{
855 		UINT8 border = 32;
856 		UINT8 grid = 160;
857 		INT32 ws = vid.width / 4;
858 		INT32 hs = vid.width * (vid.height / 4);
859 
860 		memcpy(tmpscr, srcscr, vid.width*vid.height);
861 		for (p = 0; p < vid.width; p++)
862 		{
863 			tmpscr[viewmorph.scrmap[p]] = border;
864 			tmpscr[viewmorph.scrmap[p + hs]] = grid;
865 			tmpscr[viewmorph.scrmap[p + hs*2]] = grid;
866 			tmpscr[viewmorph.scrmap[p + hs*3]] = grid;
867 			tmpscr[viewmorph.scrmap[end - 1 - p]] = border;
868 		}
869 		for (p = vid.width; p < end; p += vid.width)
870 		{
871 			tmpscr[viewmorph.scrmap[p]] = border;
872 			tmpscr[viewmorph.scrmap[p + ws]] = grid;
873 			tmpscr[viewmorph.scrmap[p + ws*2]] = grid;
874 			tmpscr[viewmorph.scrmap[p + ws*3]] = grid;
875 			tmpscr[viewmorph.scrmap[end - 1 - p]] = border;
876 		}
877 	}
878 	else
879 		for (p = 0; p < end; p++)
880 			tmpscr[p] = srcscr[viewmorph.scrmap[p]];
881 
882 	VID_BlitLinearScreen(tmpscr, screens[0],
883 			vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.width);
884 }
885 
886 
887 //
888 // R_SetViewSize
889 // Do not really change anything here,
890 // because it might be in the middle of a refresh.
891 // The change will take effect next refresh.
892 //
893 boolean setsizeneeded;
894 
R_SetViewSize(void)895 void R_SetViewSize(void)
896 {
897 	setsizeneeded = true;
898 }
899 
900 //
901 // R_ExecuteSetViewSize
902 //
R_ExecuteSetViewSize(void)903 void R_ExecuteSetViewSize(void)
904 {
905 	fixed_t dy;
906 	INT32 i;
907 	INT32 j;
908 	INT32 level;
909 	INT32 startmapl;
910 	angle_t fov;
911 
912 	setsizeneeded = false;
913 
914 	if (rendermode == render_none)
915 		return;
916 
917 	// status bar overlay
918 	st_overlay = cv_showhud.value;
919 
920 	scaledviewwidth = vid.width;
921 	viewheight = vid.height;
922 
923 	if (splitscreen)
924 		viewheight >>= 1;
925 
926 	viewwidth = scaledviewwidth;
927 
928 	centerx = viewwidth/2;
929 	centery = viewheight/2;
930 	centerxfrac = centerx<<FRACBITS;
931 	centeryfrac = centery<<FRACBITS;
932 
933 	fov = FixedAngle(cv_fov.value/2) + ANGLE_90;
934 	fovtan = FixedMul(FINETANGENT(fov >> ANGLETOFINESHIFT), viewmorph.zoomneeded);
935 	if (splitscreen == 1) // Splitscreen FOV should be adjusted to maintain expected vertical view
936 		fovtan = 17*fovtan/10;
937 
938 	projection = projectiony = FixedDiv(centerxfrac, fovtan);
939 
940 	R_InitViewBuffer(scaledviewwidth, viewheight);
941 
942 	R_InitTextureMapping();
943 
944 	// thing clipping
945 	for (i = 0; i < viewwidth; i++)
946 		screenheightarray[i] = (INT16)viewheight;
947 
948 	// setup sky scaling
949 	R_SetSkyScale();
950 
951 	// planes
952 	if (rendermode == render_soft)
953 	{
954 		// this is only used for planes rendering in software mode
955 		j = viewheight*16;
956 		for (i = 0; i < j; i++)
957 		{
958 			dy = ((i - viewheight*8)<<FRACBITS) + FRACUNIT/2;
959 			dy = FixedMul(abs(dy), fovtan);
960 			yslopetab[i] = FixedDiv(centerx*FRACUNIT, dy);
961 		}
962 
963 		if (ds_su)
964 			Z_Free(ds_su);
965 		if (ds_sv)
966 			Z_Free(ds_sv);
967 		if (ds_sz)
968 			Z_Free(ds_sz);
969 
970 		ds_su = ds_sv = ds_sz = NULL;
971 		ds_sup = ds_svp = ds_szp = NULL;
972 	}
973 
974 	memset(scalelight, 0xFF, sizeof(scalelight));
975 
976 	// Calculate the light levels to use for each level/scale combination.
977 	for (i = 0; i< LIGHTLEVELS; i++)
978 	{
979 		startmapl = ((LIGHTLEVELS - 1 - i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
980 		for (j = 0; j < MAXLIGHTSCALE; j++)
981 		{
982 			level = startmapl - j*vid.width/(viewwidth)/DISTMAP;
983 
984 			if (level < 0)
985 				level = 0;
986 
987 			if (level >= NUMCOLORMAPS)
988 				level = NUMCOLORMAPS - 1;
989 
990 			scalelight[i][j] = colormaps + level*256;
991 		}
992 	}
993 
994 	// continue to do the software setviewsize as long as we use the reference software view
995 #ifdef HWRENDER
996 	if (rendermode != render_soft)
997 		HWR_SetViewSize();
998 #endif
999 
1000 	am_recalc = true;
1001 }
1002 
1003 //
1004 // R_Init
1005 //
1006 
R_Init(void)1007 void R_Init(void)
1008 {
1009 	// screensize independent
1010 	//I_OutputMsg("\nR_InitData");
1011 	R_InitData();
1012 
1013 	//I_OutputMsg("\nR_InitViewBorder");
1014 	R_InitViewBorder();
1015 	R_SetViewSize(); // setsizeneeded is set true
1016 
1017 	//I_OutputMsg("\nR_InitPlanes");
1018 	R_InitPlanes();
1019 
1020 	// this is now done by SCR_Recalc() at the first mode set
1021 	//I_OutputMsg("\nR_InitLightTables");
1022 	R_InitLightTables();
1023 
1024 	//I_OutputMsg("\nR_InitTranslucencyTables\n");
1025 	R_InitTranslucencyTables();
1026 
1027 	R_InitDrawNodes();
1028 
1029 	framecount = 0;
1030 }
1031 
1032 //
1033 // R_PointInSubsector
1034 //
R_PointInSubsector(fixed_t x,fixed_t y)1035 subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
1036 {
1037 	size_t nodenum = numnodes-1;
1038 
1039 	while (!(nodenum & NF_SUBSECTOR))
1040 		nodenum = nodes[nodenum].children[R_PointOnSide(x, y, nodes+nodenum)];
1041 
1042 	return &subsectors[nodenum & ~NF_SUBSECTOR];
1043 }
1044 
1045 //
1046 // R_PointInSubsectorOrNull, same as above but returns 0 if not in subsector
1047 //
R_PointInSubsectorOrNull(fixed_t x,fixed_t y)1048 subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
1049 {
1050 	node_t *node;
1051 	INT32 side, i;
1052 	size_t nodenum;
1053 	subsector_t *ret;
1054 	seg_t *seg;
1055 
1056 	// single subsector is a special case
1057 	if (numnodes == 0)
1058 		return subsectors;
1059 
1060 	nodenum = numnodes - 1;
1061 
1062 	while (!(nodenum & NF_SUBSECTOR))
1063 	{
1064 		node = &nodes[nodenum];
1065 		side = R_PointOnSide(x, y, node);
1066 		nodenum = node->children[side];
1067 	}
1068 
1069 	ret = &subsectors[nodenum & ~NF_SUBSECTOR];
1070 	for (i = 0, seg = &segs[ret->firstline]; i < ret->numlines; i++, seg++)
1071 	{
1072 		if (seg->glseg)
1073 			continue;
1074 
1075 		//if (R_PointOnSegSide(x, y, seg)) -- breaks in ogl because polyvertex_t cast over vertex pointers
1076 		if (P_PointOnLineSide(x, y, seg->linedef) != seg->side)
1077 			return 0;
1078 	}
1079 
1080 	return ret;
1081 }
1082 
1083 //
1084 // R_SetupFrame
1085 //
1086 
1087 // recalc necessary stuff for mouseaiming
1088 // slopes are already calculated for the full possible view (which is 4*viewheight).
1089 // 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out)
R_SetupFreelook(player_t * player,boolean skybox)1090 static void R_SetupFreelook(player_t *player, boolean skybox)
1091 {
1092 #ifndef HWRENDER
1093 	(void)player;
1094 	(void)skybox;
1095 #endif
1096 
1097 	// clip it in the case we are looking a hardware 90 degrees full aiming
1098 	// (lmps, network and use F12...)
1099 	if (rendermode == render_soft
1100 #ifdef HWRENDER
1101 		|| (rendermode == render_opengl
1102 			&& (cv_glshearing.value == 1
1103 			|| (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox))))
1104 #endif
1105 		)
1106 	{
1107 		G_SoftwareClipAimingPitch((INT32 *)&aimingangle);
1108 	}
1109 
1110 	centeryfrac = (viewheight/2)<<FRACBITS;
1111 
1112 	if (rendermode == render_soft)
1113 		centeryfrac += FixedMul(AIMINGTODY(aimingangle), FixedDiv(viewwidth<<FRACBITS, BASEVIDWIDTH<<FRACBITS));
1114 
1115 	centery = FixedInt(FixedRound(centeryfrac));
1116 
1117 	if (rendermode == render_soft)
1118 		yslope = &yslopetab[viewheight*8 - centery];
1119 }
1120 
R_SetupFrame(player_t * player)1121 void R_SetupFrame(player_t *player)
1122 {
1123 	camera_t *thiscam;
1124 	boolean chasecam = false;
1125 
1126 	if (splitscreen && player == &players[secondarydisplayplayer]
1127 		&& player != &players[consoleplayer])
1128 	{
1129 		thiscam = &camera2;
1130 		chasecam = (cv_chasecam2.value != 0);
1131 	}
1132 	else
1133 	{
1134 		thiscam = &camera;
1135 		chasecam = (cv_chasecam.value != 0);
1136 	}
1137 
1138 	if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
1139 		chasecam = true; // force chasecam on
1140 	else if (player->spectator) // no spectator chasecam
1141 		chasecam = false; // force chasecam off
1142 
1143 	if (chasecam && !thiscam->chase)
1144 	{
1145 		P_ResetCamera(player, thiscam);
1146 		thiscam->chase = true;
1147 	}
1148 	else if (!chasecam)
1149 		thiscam->chase = false;
1150 
1151 	if (player->awayviewtics)
1152 	{
1153 		// cut-away view stuff
1154 		r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN
1155 		I_Assert(r_viewmobj != NULL);
1156 		viewz = r_viewmobj->z + 20*FRACUNIT;
1157 		aimingangle = player->awayviewaiming;
1158 		viewangle = r_viewmobj->angle;
1159 	}
1160 	else if (!player->spectator && chasecam)
1161 	// use outside cam view
1162 	{
1163 		r_viewmobj = NULL;
1164 		viewz = thiscam->z + (thiscam->height>>1);
1165 		aimingangle = thiscam->aiming;
1166 		viewangle = thiscam->angle;
1167 	}
1168 	else
1169 	// use the player's eyes view
1170 	{
1171 		viewz = player->viewz;
1172 
1173 		r_viewmobj = player->mo;
1174 		I_Assert(r_viewmobj != NULL);
1175 
1176 		aimingangle = player->aiming;
1177 		viewangle = r_viewmobj->angle;
1178 
1179 		if (!demoplayback && player->playerstate != PST_DEAD)
1180 		{
1181 			if (player == &players[consoleplayer])
1182 			{
1183 				viewangle = localangle; // WARNING: camera uses this
1184 				aimingangle = localaiming;
1185 			}
1186 			else if (player == &players[secondarydisplayplayer])
1187 			{
1188 				viewangle = localangle2;
1189 				aimingangle = localaiming2;
1190 			}
1191 		}
1192 	}
1193 	viewz += quake.z;
1194 
1195 	viewplayer = player;
1196 
1197 	if (chasecam && !player->awayviewtics && !player->spectator)
1198 	{
1199 		viewx = thiscam->x;
1200 		viewy = thiscam->y;
1201 		viewx += quake.x;
1202 		viewy += quake.y;
1203 
1204 		if (thiscam->subsector)
1205 			viewsector = thiscam->subsector->sector;
1206 		else
1207 			viewsector = R_PointInSubsector(viewx, viewy)->sector;
1208 	}
1209 	else
1210 	{
1211 		viewx = r_viewmobj->x;
1212 		viewy = r_viewmobj->y;
1213 		viewx += quake.x;
1214 		viewy += quake.y;
1215 
1216 		if (r_viewmobj->subsector)
1217 			viewsector = r_viewmobj->subsector->sector;
1218 		else
1219 			viewsector = R_PointInSubsector(viewx, viewy)->sector;
1220 	}
1221 
1222 	viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
1223 	viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
1224 
1225 	R_SetupFreelook(player, false);
1226 }
1227 
R_SkyboxFrame(player_t * player)1228 void R_SkyboxFrame(player_t *player)
1229 {
1230 	camera_t *thiscam;
1231 
1232 	if (splitscreen && player == &players[secondarydisplayplayer]
1233 	&& player != &players[consoleplayer])
1234 		thiscam = &camera2;
1235 	else
1236 		thiscam = &camera;
1237 
1238 	// cut-away view stuff
1239 	r_viewmobj = skyboxmo[0];
1240 #ifdef PARANOIA
1241 	if (!r_viewmobj)
1242 	{
1243 		const size_t playeri = (size_t)(player - players);
1244 		I_Error("R_SkyboxFrame: r_viewmobj null (player %s)", sizeu1(playeri));
1245 	}
1246 #endif
1247 	if (player->awayviewtics)
1248 	{
1249 		aimingangle = player->awayviewaiming;
1250 		viewangle = player->awayviewmobj->angle;
1251 	}
1252 	else if (thiscam->chase)
1253 	{
1254 		aimingangle = thiscam->aiming;
1255 		viewangle = thiscam->angle;
1256 	}
1257 	else
1258 	{
1259 		aimingangle = player->aiming;
1260 		viewangle = player->mo->angle;
1261 		if (!demoplayback && player->playerstate != PST_DEAD)
1262 		{
1263 			if (player == &players[consoleplayer])
1264 			{
1265 				viewangle = localangle; // WARNING: camera uses this
1266 				aimingangle = localaiming;
1267 			}
1268 			else if (player == &players[secondarydisplayplayer])
1269 			{
1270 				viewangle = localangle2;
1271 				aimingangle = localaiming2;
1272 			}
1273 		}
1274 	}
1275 	viewangle += r_viewmobj->angle;
1276 
1277 	viewplayer = player;
1278 
1279 	viewx = r_viewmobj->x;
1280 	viewy = r_viewmobj->y;
1281 	viewz = r_viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle!
1282 
1283 	if (mapheaderinfo[gamemap-1])
1284 	{
1285 		mapheader_t *mh = mapheaderinfo[gamemap-1];
1286 		vector3_t campos = {0,0,0}; // Position of player's actual view point
1287 
1288 		if (player->awayviewtics) {
1289 			campos.x = player->awayviewmobj->x;
1290 			campos.y = player->awayviewmobj->y;
1291 			campos.z = player->awayviewmobj->z + 20*FRACUNIT;
1292 		} else if (thiscam->chase) {
1293 			campos.x = thiscam->x;
1294 			campos.y = thiscam->y;
1295 			campos.z = thiscam->z + (thiscam->height>>1);
1296 		} else {
1297 			campos.x = player->mo->x;
1298 			campos.y = player->mo->y;
1299 			campos.z = player->viewz;
1300 		}
1301 
1302 		// Earthquake effects should be scaled in the skybox
1303 		// (if an axis isn't used, the skybox won't shake in that direction)
1304 		campos.x += quake.x;
1305 		campos.y += quake.y;
1306 		campos.z += quake.z;
1307 
1308 		if (skyboxmo[1]) // Is there a viewpoint?
1309 		{
1310 			fixed_t x = 0, y = 0;
1311 			if (mh->skybox_scalex > 0)
1312 				x = (campos.x - skyboxmo[1]->x) / mh->skybox_scalex;
1313 			else if (mh->skybox_scalex < 0)
1314 				x = (campos.x - skyboxmo[1]->x) * -mh->skybox_scalex;
1315 
1316 			if (mh->skybox_scaley > 0)
1317 				y = (campos.y - skyboxmo[1]->y) / mh->skybox_scaley;
1318 			else if (mh->skybox_scaley < 0)
1319 				y = (campos.y - skyboxmo[1]->y) * -mh->skybox_scaley;
1320 
1321 			if (r_viewmobj->angle == 0)
1322 			{
1323 				viewx += x;
1324 				viewy += y;
1325 			}
1326 			else if (r_viewmobj->angle == ANGLE_90)
1327 			{
1328 				viewx -= y;
1329 				viewy += x;
1330 			}
1331 			else if (r_viewmobj->angle == ANGLE_180)
1332 			{
1333 				viewx -= x;
1334 				viewy -= y;
1335 			}
1336 			else if (r_viewmobj->angle == ANGLE_270)
1337 			{
1338 				viewx += y;
1339 				viewy -= x;
1340 			}
1341 			else
1342 			{
1343 				angle_t ang = r_viewmobj->angle>>ANGLETOFINESHIFT;
1344 				viewx += FixedMul(x,FINECOSINE(ang)) - FixedMul(y,  FINESINE(ang));
1345 				viewy += FixedMul(x,  FINESINE(ang)) + FixedMul(y,FINECOSINE(ang));
1346 			}
1347 		}
1348 		if (mh->skybox_scalez > 0)
1349 			viewz += campos.z / mh->skybox_scalez;
1350 		else if (mh->skybox_scalez < 0)
1351 			viewz += campos.z * -mh->skybox_scalez;
1352 	}
1353 
1354 	if (r_viewmobj->subsector)
1355 		viewsector = r_viewmobj->subsector->sector;
1356 	else
1357 		viewsector = R_PointInSubsector(viewx, viewy)->sector;
1358 
1359 	viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
1360 	viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
1361 
1362 	R_SetupFreelook(player, true);
1363 }
1364 
R_ViewpointHasChasecam(player_t * player)1365 boolean R_ViewpointHasChasecam(player_t *player)
1366 {
1367 	boolean chasecam = false;
1368 
1369 	if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer])
1370 		chasecam = (cv_chasecam2.value != 0);
1371 	else
1372 		chasecam = (cv_chasecam.value != 0);
1373 
1374 	if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
1375 		chasecam = true; // force chasecam on
1376 	else if (player->spectator) // no spectator chasecam
1377 		chasecam = false; // force chasecam off
1378 
1379 	return chasecam;
1380 }
1381 
R_IsViewpointThirdPerson(player_t * player,boolean skybox)1382 boolean R_IsViewpointThirdPerson(player_t *player, boolean skybox)
1383 {
1384 	boolean chasecam = R_ViewpointHasChasecam(player);
1385 
1386 	// cut-away view stuff
1387 	if (player->awayviewtics || skybox)
1388 		return chasecam;
1389 	// use outside cam view
1390 	else if (!player->spectator && chasecam)
1391 		return true;
1392 
1393 	// use the player's eyes view
1394 	return false;
1395 }
1396 
R_PortalFrame(portal_t * portal)1397 static void R_PortalFrame(portal_t *portal)
1398 {
1399 	viewx = portal->viewx;
1400 	viewy = portal->viewy;
1401 	viewz = portal->viewz;
1402 
1403 	viewangle = portal->viewangle;
1404 	viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
1405 	viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
1406 
1407 	portalclipstart = portal->start;
1408 	portalclipend = portal->end;
1409 
1410 	if (portal->clipline != -1)
1411 	{
1412 		portalclipline = &lines[portal->clipline];
1413 		portalcullsector = portalclipline->frontsector;
1414 		viewsector = portalclipline->frontsector;
1415 	}
1416 	else
1417 	{
1418 		portalclipline = NULL;
1419 		portalcullsector = NULL;
1420 		viewsector = R_PointInSubsector(viewx, viewy)->sector;
1421 	}
1422 }
1423 
Mask_Pre(maskcount_t * m)1424 static void Mask_Pre (maskcount_t* m)
1425 {
1426 	m->drawsegs[0] = ds_p - drawsegs;
1427 	m->vissprites[0] = visspritecount;
1428 	m->viewx = viewx;
1429 	m->viewy = viewy;
1430 	m->viewz = viewz;
1431 	m->viewsector = viewsector;
1432 }
1433 
Mask_Post(maskcount_t * m)1434 static void Mask_Post (maskcount_t* m)
1435 {
1436 	m->drawsegs[1] = ds_p - drawsegs;
1437 	m->vissprites[1] = visspritecount;
1438 }
1439 
1440 // ================
1441 // R_RenderView
1442 // ================
1443 
1444 //                     FAB NOTE FOR WIN32 PORT !! I'm not finished already,
1445 // but I suspect network may have problems with the video buffer being locked
1446 // for all duration of rendering, and being released only once at the end..
1447 // I mean, there is a win16lock() or something that lasts all the rendering,
1448 // so maybe we should release screen lock before each netupdate below..?
1449 
R_RenderPlayerView(player_t * player)1450 void R_RenderPlayerView(player_t *player)
1451 {
1452 	UINT8			nummasks	= 1;
1453 	maskcount_t*	masks		= malloc(sizeof(maskcount_t));
1454 
1455 	if (cv_homremoval.value && player == &players[displayplayer]) // if this is display player 1
1456 	{
1457 		if (cv_homremoval.value == 1)
1458 			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // No HOM effect!
1459 		else //'development' HOM removal -- makes it blindingly obvious if HOM is spotted.
1460 			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 32+(timeinmap&15));
1461 	}
1462 
1463 	R_SetupFrame(player);
1464 	framecount++;
1465 	validcount++;
1466 
1467 	// Clear buffers.
1468 	R_ClearPlanes();
1469 	if (viewmorph.use)
1470 	{
1471 		portalclipstart = viewmorph.x1;
1472 		portalclipend = viewwidth-viewmorph.x1-1;
1473 		R_PortalClearClipSegs(portalclipstart, portalclipend);
1474 		memcpy(ceilingclip, viewmorph.ceilingclip, sizeof(INT16)*vid.width);
1475 		memcpy(floorclip, viewmorph.floorclip, sizeof(INT16)*vid.width);
1476 	}
1477 	else
1478 	{
1479 		portalclipstart = 0;
1480 		portalclipend = viewwidth;
1481 		R_ClearClipSegs();
1482 	}
1483 	R_ClearDrawSegs();
1484 	R_ClearSprites();
1485 	Portal_InitList();
1486 
1487 	// check for new console commands.
1488 	NetUpdate();
1489 
1490 	// The head node is the last node output.
1491 
1492 	Mask_Pre(&masks[nummasks - 1]);
1493 	curdrawsegs = ds_p;
1494 //profile stuff ---------------------------------------------------------
1495 #ifdef TIMING
1496 	mytotal = 0;
1497 	ProfZeroTimer();
1498 #endif
1499 	ps_numbspcalls = ps_numpolyobjects = ps_numdrawnodes = 0;
1500 	ps_bsptime = I_GetPreciseTime();
1501 	R_RenderBSPNode((INT32)numnodes - 1);
1502 	ps_bsptime = I_GetPreciseTime() - ps_bsptime;
1503 	ps_numsprites = visspritecount;
1504 #ifdef TIMING
1505 	RDMSR(0x10, &mycount);
1506 	mytotal += mycount; // 64bit add
1507 
1508 	CONS_Debug(DBG_RENDER, "RenderBSPNode: 0x%d %d\n", *((INT32 *)&mytotal + 1), (INT32)mytotal);
1509 #endif
1510 //profile stuff ---------------------------------------------------------
1511 	Mask_Post(&masks[nummasks - 1]);
1512 
1513 	ps_sw_spritecliptime = I_GetPreciseTime();
1514 	R_ClipSprites(drawsegs, NULL);
1515 	ps_sw_spritecliptime = I_GetPreciseTime() - ps_sw_spritecliptime;
1516 
1517 
1518 	// Add skybox portals caused by sky visplanes.
1519 	if (cv_skybox.value && skyboxmo[0])
1520 		Portal_AddSkyboxPortals();
1521 
1522 	// Portal rendering. Hijacks the BSP traversal.
1523 	ps_sw_portaltime = I_GetPreciseTime();
1524 	if (portal_base)
1525 	{
1526 		portal_t *portal;
1527 
1528 		for(portal = portal_base; portal; portal = portal_base)
1529 		{
1530 			portalrender = portal->pass; // Recursiveness depth.
1531 
1532 			R_ClearFFloorClips();
1533 
1534 			// Apply the viewpoint stored for the portal.
1535 			R_PortalFrame(portal);
1536 
1537 			// Hack in the clipsegs to delimit the starting
1538 			// clipping for sprites and possibly other similar
1539 			// future items.
1540 			R_PortalClearClipSegs(portal->start, portal->end);
1541 
1542 			// Hack in the top/bottom clip values for the window
1543 			// that were previously stored.
1544 			Portal_ClipApply(portal);
1545 
1546 			validcount++;
1547 
1548 			masks = realloc(masks, (++nummasks)*sizeof(maskcount_t));
1549 
1550 			Mask_Pre(&masks[nummasks - 1]);
1551 			curdrawsegs = ds_p;
1552 
1553 			// Render the BSP from the new viewpoint, and clip
1554 			// any sprites with the new clipsegs and window.
1555 			R_RenderBSPNode((INT32)numnodes - 1);
1556 			Mask_Post(&masks[nummasks - 1]);
1557 
1558 			R_ClipSprites(ds_p - (masks[nummasks - 1].drawsegs[1] - masks[nummasks - 1].drawsegs[0]), portal);
1559 
1560 			Portal_Remove(portal);
1561 		}
1562 	}
1563 	ps_sw_portaltime = I_GetPreciseTime() - ps_sw_portaltime;
1564 
1565 	ps_sw_planetime = I_GetPreciseTime();
1566 	R_DrawPlanes();
1567 	ps_sw_planetime = I_GetPreciseTime() - ps_sw_planetime;
1568 
1569 	// draw mid texture and sprite
1570 	// And now 3D floors/sides!
1571 	ps_sw_maskedtime = I_GetPreciseTime();
1572 	R_DrawMasked(masks, nummasks);
1573 	ps_sw_maskedtime = I_GetPreciseTime() - ps_sw_maskedtime;
1574 
1575 	free(masks);
1576 }
1577 
1578 // =========================================================================
1579 //                    ENGINE COMMANDS & VARS
1580 // =========================================================================
1581 
R_RegisterEngineStuff(void)1582 void R_RegisterEngineStuff(void)
1583 {
1584 	CV_RegisterVar(&cv_gravity);
1585 	CV_RegisterVar(&cv_tailspickup);
1586 	CV_RegisterVar(&cv_allowmlook);
1587 	CV_RegisterVar(&cv_homremoval);
1588 	CV_RegisterVar(&cv_flipcam);
1589 	CV_RegisterVar(&cv_flipcam2);
1590 
1591 	// Enough for dedicated server
1592 	if (dedicated)
1593 		return;
1594 
1595 	CV_RegisterVar(&cv_translucency);
1596 	CV_RegisterVar(&cv_drawdist);
1597 	CV_RegisterVar(&cv_drawdist_nights);
1598 	CV_RegisterVar(&cv_drawdist_precip);
1599 	CV_RegisterVar(&cv_fov);
1600 
1601 	CV_RegisterVar(&cv_chasecam);
1602 	CV_RegisterVar(&cv_chasecam2);
1603 
1604 	CV_RegisterVar(&cv_shadow);
1605 	CV_RegisterVar(&cv_skybox);
1606 	CV_RegisterVar(&cv_ffloorclip);
1607 
1608 	CV_RegisterVar(&cv_cam_dist);
1609 	CV_RegisterVar(&cv_cam_still);
1610 	CV_RegisterVar(&cv_cam_height);
1611 	CV_RegisterVar(&cv_cam_speed);
1612 	CV_RegisterVar(&cv_cam_rotate);
1613 	CV_RegisterVar(&cv_cam_rotspeed);
1614 	CV_RegisterVar(&cv_cam_turnmultiplier);
1615 	CV_RegisterVar(&cv_cam_orbit);
1616 	CV_RegisterVar(&cv_cam_adjust);
1617 
1618 	CV_RegisterVar(&cv_cam2_dist);
1619 	CV_RegisterVar(&cv_cam2_still);
1620 	CV_RegisterVar(&cv_cam2_height);
1621 	CV_RegisterVar(&cv_cam2_speed);
1622 	CV_RegisterVar(&cv_cam2_rotate);
1623 	CV_RegisterVar(&cv_cam2_rotspeed);
1624 	CV_RegisterVar(&cv_cam2_turnmultiplier);
1625 	CV_RegisterVar(&cv_cam2_orbit);
1626 	CV_RegisterVar(&cv_cam2_adjust);
1627 
1628 	CV_RegisterVar(&cv_cam_savedist[0][0]);
1629 	CV_RegisterVar(&cv_cam_savedist[0][1]);
1630 	CV_RegisterVar(&cv_cam_savedist[1][0]);
1631 	CV_RegisterVar(&cv_cam_savedist[1][1]);
1632 
1633 	CV_RegisterVar(&cv_cam_saveheight[0][0]);
1634 	CV_RegisterVar(&cv_cam_saveheight[0][1]);
1635 	CV_RegisterVar(&cv_cam_saveheight[1][0]);
1636 	CV_RegisterVar(&cv_cam_saveheight[1][1]);
1637 
1638 	CV_RegisterVar(&cv_showhud);
1639 	CV_RegisterVar(&cv_translucenthud);
1640 
1641 	CV_RegisterVar(&cv_maxportals);
1642 
1643 	CV_RegisterVar(&cv_movebob);
1644 }
1645