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