Newer
Older
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file r_main.c
/// \brief Rendering main loop and setup functions,
/// utility functions (BSP, geometry, trigonometry).
/// See tables.c, too.
#include "doomdef.h"
#include "g_game.h"
#include "g_input.h"
#include "r_local.h"
#include "r_splats.h" // faB(21jan): testing
#include "r_sky.h"
#include "st_stuff.h"
#include "p_local.h"
#include "keys.h"
#include "i_video.h"
#include "m_menu.h"
#include "am_map.h"
#include "d_main.h"
#include "v_video.h"
#include "p_spec.h" // skyboxmo
#include "z_zone.h"
#include "m_random.h" // quake camera shake
#include "r_portal.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
#endif
//profile stuff ---------------------------------------------------------
//#define TIMING
#ifdef TIMING
#include "p5prof.h"
INT64 mycount;
INT64 mytotal = 0;
//unsigned long nombre = 100000;
#endif
//profile stuff ---------------------------------------------------------
// Fineangles in the SCREENWIDTH wide window.
#define FIELDOFVIEW 2048
// increment every time a check is made
size_t validcount = 1;
INT32 centerx, centery;
fixed_t centerxfrac, centeryfrac;
fixed_t projection;
fixed_t projectiony; // aspect ratio
// just for profiling purposes
size_t framecount;
size_t loopcount;
fixed_t viewx, viewy, viewz;
angle_t viewangle, aimingangle;
fixed_t viewcos, viewsin;
sector_t *viewsector;
player_t *viewplayer;
//
// precalculated math tables
//
angle_t clipangle;
angle_t doubleclipangle;
// The viewangletox[viewangle + FINEANGLES/4] lookup
// maps the visible view angles to screen X coordinates,
// flattening the arc to a flat projection plane.
// There will be many angles mapped to the same X.
INT32 viewangletox[FINEANGLES/2];
// The xtoviewangleangle[] table maps a screen pixel
// to the lowest viewangle that maps back to x ranges
// from clipangle to -clipangle.
angle_t xtoviewangle[MAXVIDWIDTH+1];
lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
lighttable_t *scalelightfixed[MAXLIGHTSCALE];
lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
// Hack to support extra boom colormaps.
extracolormap_t *extra_colormaps = NULL;

Hannu Hanhi
committed
// Render stats
precise_t ps_prevframetime = 0;
precise_t ps_rendercalltime = 0;
precise_t ps_uitime = 0;
precise_t ps_swaptime = 0;

Hannu Hanhi
committed

Hannu Hanhi
committed
precise_t ps_sw_spritecliptime = 0;
precise_t ps_sw_portaltime = 0;
precise_t ps_sw_planetime = 0;
precise_t ps_sw_maskedtime = 0;

Hannu Hanhi
committed
int ps_numbspcalls = 0;
int ps_numsprites = 0;
int ps_numdrawnodes = 0;
int ps_numpolyobjects = 0;

Hannu Hanhi
committed
static CV_PossibleValue_t drawdist_cons_t[] = {
{256, "256"}, {512, "512"}, {768, "768"},
{1024, "1024"}, {1536, "1536"}, {2048, "2048"},
{3072, "3072"}, {4096, "4096"}, {6144, "6144"},
{8192, "8192"}, {0, "Infinite"}, {0, NULL}};
//static CV_PossibleValue_t precipdensity_cons_t[] = {{0, "None"}, {1, "Light"}, {2, "Moderate"}, {4, "Heavy"}, {6, "Thick"}, {8, "V.Thick"}, {0, NULL}};
static CV_PossibleValue_t drawdist_precip_cons_t[] = {
{256, "256"}, {512, "512"}, {768, "768"},
{1024, "1024"}, {1536, "1536"}, {2048, "2048"},
{0, "None"}, {0, NULL}};
static CV_PossibleValue_t fov_cons_t[] = {{60*FRACUNIT, "MIN"}, {179*FRACUNIT, "MAX"}, {0, NULL}};
static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {12, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card
static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}};
static void ChaseCam_OnChange(void);
static void ChaseCam2_OnChange(void);
static void FlipCam_OnChange(void);
static void FlipCam2_OnChange(void);
consvar_t cv_tailspickup = CVAR_INIT ("tailspickup", "On", CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_chasecam = CVAR_INIT ("chasecam", "On", CV_CALL, CV_OnOff, ChaseCam_OnChange);
consvar_t cv_chasecam2 = CVAR_INIT ("chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChange);
consvar_t cv_flipcam = CVAR_INIT ("flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange);
consvar_t cv_flipcam2 = CVAR_INIT ("flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange);
consvar_t cv_shadow = CVAR_INIT ("shadow", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_skybox = CVAR_INIT ("skybox", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_ffloorclip = CVAR_INIT ("ffloorclip", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_allowmlook = CVAR_INIT ("allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL);
consvar_t cv_showhud = CVAR_INIT ("showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize);
consvar_t cv_translucenthud = CVAR_INIT ("translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL);
consvar_t cv_translucency = CVAR_INIT ("translucency", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_drawdist = CVAR_INIT ("drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL);
consvar_t cv_drawdist_nights = CVAR_INIT ("drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL);
consvar_t cv_drawdist_precip = CVAR_INIT ("drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL);
//consvar_t cv_precipdensity = CVAR_INIT ("precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL);
consvar_t cv_fov = CVAR_INIT ("fov", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange);
// Okay, whoever said homremoval causes a performance hit should be shot.
consvar_t cv_homremoval = CVAR_INIT ("homremoval", "No", CV_SAVE, homremoval_cons_t, NULL);
consvar_t cv_maxportals = CVAR_INIT ("maxportals", "2", CV_SAVE, maxportals_cons_t, NULL);
consvar_t cv_renderstats = CVAR_INIT ("renderstats", "Off", 0, CV_OnOff, NULL);

Hannu Hanhi
committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
void SplitScreen_OnChange(void)
{
if (!cv_debug && netgame)
{
if (splitscreen)
{
CONS_Alert(CONS_NOTICE, M_GetText("Splitscreen not supported in netplay, sorry!\n"));
splitscreen = false;
}
return;
}
// recompute screen size
R_ExecuteSetViewSize();
if (!demoplayback && !botingame)
{
if (splitscreen)
CL_AddSplitscreenPlayer();
else
CL_RemoveSplitscreenPlayer();
if (server && !netgame)
multiplayer = splitscreen;
}
else
{
INT32 i;
secondarydisplayplayer = consoleplayer;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && i != consoleplayer)
{
secondarydisplayplayer = i;
break;
}
}
}
static void Fov_OnChange(void)
{
// Shouldn't be needed with render parity?
//if ((netgame || multiplayer) && !cv_debug && cv_fov.value != 90*FRACUNIT)
// CV_Set(&cv_fov, cv_fov.defaultvalue);
R_SetViewSize();
}
if (!cv_chasecam.value || !cv_useranalog[0].value)
CV_SetValue(&cv_analog[0], 0);
CV_SetValue(&cv_analog[0], 1);
}
static void ChaseCam2_OnChange(void)
{
if (botingame)
return;
if (!cv_chasecam2.value || !cv_useranalog[1].value)
CV_SetValue(&cv_analog[1], 0);
CV_SetValue(&cv_analog[1], 1);
static void FlipCam_OnChange(void)
{
SendWeaponPref();
}
static void FlipCam2_OnChange(void)
{
SendWeaponPref2();
}
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
//
// R_PointOnSide
// Traverse BSP (sub) tree,
// check point against partition plane.
// Returns side 0 (front) or 1 (back).
//
// killough 5/2/98: reformatted
//
INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node)
{
if (!node->dx)
return x <= node->x ? node->dy > 0 : node->dy < 0;
if (!node->dy)
return y <= node->y ? node->dx < 0 : node->dx > 0;
x -= node->x;
y -= node->y;
// Try to quickly decide by looking at sign bits.
if ((node->dy ^ node->dx ^ x ^ y) < 0)
return (node->dy ^ x) < 0; // (left is negative)
return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x);
}
// killough 5/2/98: reformatted
INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line)
{
fixed_t lx = line->v1->x;
fixed_t ly = line->v1->y;
fixed_t ldx = line->v2->x - lx;
fixed_t ldy = line->v2->y - ly;
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
if (!ldx)
return x <= lx ? ldy > 0 : ldy < 0;
if (!ldy)
return y <= ly ? ldx < 0 : ldx > 0;
x -= lx;
y -= ly;
// Try to quickly decide by looking at sign bits.
if ((ldy ^ ldx ^ x ^ y) < 0)
return (ldy ^ x) < 0; // (left is negative)
return FixedMul(y, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, x);
}
//
// R_PointToAngle
// To get a global angle from cartesian coordinates,
// the coordinates are flipped until they are in
// the first octant of the coordinate system, then
// the y (<=x) is scaled and divided by x to get a
// tangent (slope) value which is looked up in the
// tantoangle[] table. The +1 size of tantoangle[]
// is to handle the case when x==y without additional
// checking.
//
// killough 5/2/98: reformatted, cleaned up
angle_t R_PointToAngle(fixed_t x, fixed_t y)
{
return (y -= viewy, (x -= viewx) || y) ?
x >= 0 ?
y >= 0 ?
(x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0
Monster Iestyn
committed
ANGLE_90-tantoangle[SlopeDiv(x,y)] : // octant 1
x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8
ANGLE_270+tantoangle[SlopeDiv(x,y)] : // octant 7
Monster Iestyn
committed
y >= 0 ? (x = -x) > y ? ANGLE_180-tantoangle[SlopeDiv(y,x)] : // octant 3
Monster Iestyn
committed
(x = -x) > (y = -y) ? ANGLE_180+tantoangle[SlopeDiv(y,x)] : // octant 4
ANGLE_270-tantoangle[SlopeDiv(x,y)] : // octant 5
0;
}
// This version uses 64-bit variables to avoid overflows with large values.
// Currently used only by OpenGL rendering.
angle_t R_PointToAngle64(INT64 x, INT64 y)
{
return (y -= viewy, (x -= viewx) || y) ?
x >= 0 ?
y >= 0 ?
(x > y) ? tantoangle[SlopeDivEx(y,x)] : // octant 0
ANGLE_90-tantoangle[SlopeDivEx(x,y)] : // octant 1
x > (y = -y) ? 0-tantoangle[SlopeDivEx(y,x)] : // octant 8
ANGLE_270+tantoangle[SlopeDivEx(x,y)] : // octant 7
y >= 0 ? (x = -x) > y ? ANGLE_180-tantoangle[SlopeDivEx(y,x)] : // octant 3
ANGLE_90 + tantoangle[SlopeDivEx(x,y)] : // octant 2
(x = -x) > (y = -y) ? ANGLE_180+tantoangle[SlopeDivEx(y,x)] : // octant 4
ANGLE_270-tantoangle[SlopeDivEx(x,y)] : // octant 5
0;
}
angle_t R_PointToAngle2(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y)
{
return (y -= pviewy, (x -= pviewx) || y) ?
x >= 0 ?
y >= 0 ?
(x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0
Monster Iestyn
committed
ANGLE_90-tantoangle[SlopeDiv(x,y)] : // octant 1
x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8
ANGLE_270+tantoangle[SlopeDiv(x,y)] : // octant 7
Monster Iestyn
committed
y >= 0 ? (x = -x) > y ? ANGLE_180-tantoangle[SlopeDiv(y,x)] : // octant 3
Monster Iestyn
committed
(x = -x) > (y = -y) ? ANGLE_180+tantoangle[SlopeDiv(y,x)] : // octant 4
ANGLE_270-tantoangle[SlopeDiv(x,y)] : // octant 5
0;
}
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1)
{
angle_t angle;
fixed_t dx, dy, dist;
dx = abs(px1 - px2);
dy = abs(py1 - py2);
if (dy > dx)
{
fixed_t temp;
temp = dx;
dx = dy;
dy = temp;
}
if (!dy)
return dx;
angle = (tantoangle[FixedDiv(dy, dx)>>DBITS] + ANGLE_90) >> ANGLETOFINESHIFT;
// use as cosine
dist = FixedDiv(dx, FINESINE(angle));
return dist;
}
// Little extra utility. Works in the same way as R_PointToAngle2
fixed_t R_PointToDist(fixed_t x, fixed_t y)
{
return R_PointToDist2(viewx, viewy, x, y);
}
angle_t R_PointToAngleEx(INT32 x2, INT32 y2, INT32 x1, INT32 y1)
{
INT64 dx = x1-x2;
INT64 dy = y1-y2;
if (dx < INT32_MIN || dx > INT32_MAX || dy < INT32_MIN || dy > INT32_MAX)
{
x1 = (int)(dx / 2 + x2);
y1 = (int)(dy / 2 + y2);
}
return (y1 -= y2, (x1 -= x2) || y1) ?
x1 >= 0 ?
y1 >= 0 ?
(x1 > y1) ? tantoangle[SlopeDivEx(y1,x1)] : // octant 0
ANGLE_90-tantoangle[SlopeDivEx(x1,y1)] : // octant 1
x1 > (y1 = -y1) ? 0-tantoangle[SlopeDivEx(y1,x1)] : // octant 8
ANGLE_270+tantoangle[SlopeDivEx(x1,y1)] : // octant 7
y1 >= 0 ? (x1 = -x1) > y1 ? ANGLE_180-tantoangle[SlopeDivEx(y1,x1)] : // octant 3
ANGLE_90 + tantoangle[SlopeDivEx(x1,y1)] : // octant 2
(x1 = -x1) > (y1 = -y1) ? ANGLE_180+tantoangle[SlopeDivEx(y1,x1)] : // octant 4
ANGLE_270-tantoangle[SlopeDivEx(x1,y1)] : // octant 5
0;
}
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
//
// R_ScaleFromGlobalAngle
// Returns the texture mapping scale for the current line (horizontal span)
// at the given angle.
// rw_distance must be calculated first.
//
// killough 5/2/98: reformatted, cleaned up
//
// note: THIS IS USED ONLY FOR WALLS!
fixed_t R_ScaleFromGlobalAngle(angle_t visangle)
{
angle_t anglea = ANGLE_90 + (visangle-viewangle);
angle_t angleb = ANGLE_90 + (visangle-rw_normalangle);
fixed_t den = FixedMul(rw_distance, FINESINE(anglea>>ANGLETOFINESHIFT));
// proff 11/06/98: Changed for high-res
fixed_t num = FixedMul(projectiony, FINESINE(angleb>>ANGLETOFINESHIFT));
if (den > num>>16)
{
num = FixedDiv(num, den);
if (num > 64*FRACUNIT)
return 64*FRACUNIT;
if (num < 256)
return 256;
return num;
}
return 64*FRACUNIT;
}
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
//
// R_DoCulling
// Checks viewz and top/bottom heights of an item against culling planes
// Returns true if the item is to be culled, i.e it shouldn't be drawn!
// if ML_NOCLIMB is set, the camera view is required to be in the same area for culling to occur
boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph)
{
fixed_t cullplane;
if (!cullheight)
return false;
cullplane = cullheight->frontsector->floorheight;
if (cullheight->flags & ML_NOCLIMB) // Group culling
{
if (!viewcullheight)
return false;
// Make sure this is part of the same group
if (viewcullheight->frontsector == cullheight->frontsector)
{
// OK, we can cull
if (vz > cullplane && toph < cullplane) // Cull if below plane
return true;
if (bottomh > cullplane && vz <= cullplane) // Cull if above plane
return true;
}
}
else // Quick culling
{
if (vz > cullplane && toph < cullplane) // Cull if below plane
return true;
if (bottomh > cullplane && vz <= cullplane) // Cull if above plane
return true;
}
return false;
}
//
// R_InitTextureMapping
//
static void R_InitTextureMapping(void)
{
INT32 i;
INT32 x;
INT32 t;
fixed_t focallength;
// Use tangent table to generate viewangletox:
// viewangletox will give the next greatest x
// after the view angle.
//
// Calc focallength
// so FIELDOFVIEW angles covers SCREENWIDTH.
focallength = FixedDiv(projection,
FINETANGENT(FINEANGLES/4+FIELDOFVIEW/2));
focallengthf = FIXED_TO_FLOAT(focallength);
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
t = viewwidth+1;
else
{
t = FixedMul(FINETANGENT(i), focallength);
t = (centerxfrac - t+FRACUNIT-1)>>FRACBITS;
if (t < -1)
t = -1;
else if (t > viewwidth+1)
t = viewwidth+1;
}
viewangletox[i] = t;
}
// Scan viewangletox[] to generate xtoviewangle[]:
// xtoviewangle will give the smallest view angle
// that maps to x.
for (x = 0; x <= viewwidth;x++)
{
i = 0;
while (viewangletox[i] > x)
i++;
xtoviewangle[x] = (i<<ANGLETOFINESHIFT) - ANGLE_90;
}
// Take out the fencepost cases from viewangletox.
for (i = 0; i < FINEANGLES/2; i++)
{
if (viewangletox[i] == -1)
viewangletox[i] = 0;
else if (viewangletox[i] == viewwidth+1)
viewangletox[i] = viewwidth;
}
clipangle = xtoviewangle[0];
doubleclipangle = clipangle*2;
}
//
// R_InitLightTables
// Only inits the zlight table,
// because the scalelight table changes with view size.
//
#define DISTMAP 2
static inline void R_InitLightTables(void)
{
INT32 i;
INT32 j;
INT32 level;
INT32 startmapl;
INT32 scale;
// Calculate the light levels to use
// for each level / distance combination.
for (i = 0; i < LIGHTLEVELS; i++)
{
startmapl = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
for (j = 0; j < MAXLIGHTZ; j++)
{
//added : 02-02-98 : use BASEVIDWIDTH, vid.width is not set already,
// and it seems it needs to be calculated only once.
scale = FixedDiv((BASEVIDWIDTH/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
scale >>= LIGHTSCALESHIFT;
level = startmapl - scale/DISTMAP;
if (level < 0)
level = 0;
if (level >= NUMCOLORMAPS)
level = NUMCOLORMAPS-1;
zlight[i][j] = colormaps + level*256;
}
}
}
//#define WOUGHMP_WOUGHMP // I got a fish-eye lens - I'll make a rap video with a couple of friends
// it's kinda laggy sometimes
static struct {
angle_t rollangle; // pre-shifted by fineshift
#ifdef WOUGHMP_WOUGHMP
fixed_t fisheye;
#endif
INT32 x1; // clip rendering horizontally for efficiency
INT16 ceilingclip[MAXVIDWIDTH], floorclip[MAXVIDWIDTH];
} viewmorph = {
0,
#ifdef WOUGHMP_WOUGHMP
0,
#endif
void R_CheckViewMorph(void)
{
float zoomfactor, rollcos, rollsin;
INT32 usedx, usedy, halfwidth = vid.width/2, halfheight = vid.height/2;
#ifdef WOUGHMP_WOUGHMP
float fisheyemap[MAXVIDWIDTH/2 + 1];
#endif
angle_t rollangle = players[displayplayer].viewrollangle;
#ifdef WOUGHMP_WOUGHMP
fixed_t fisheye = cv_cam2_turnmultiplier.value; // temporary test value
#endif
rollangle = ((rollangle+2) & ~3) & FINEMASK; // Limit the distinct number of angles to reduce recalcs from angles changing a lot.
#ifdef WOUGHMP_WOUGHMP
fisheye &= ~0x7FF; // Same
#endif
if (rollangle == viewmorph.rollangle &&
#ifdef WOUGHMP_WOUGHMP
fisheye == viewmorph.fisheye &&
#endif
viewmorph.scrmapsize == vid.width*vid.height)
return; // No change
viewmorph.rollangle = rollangle;
#ifdef WOUGHMP_WOUGHMP
viewmorph.fisheye = fisheye;
#endif
if (viewmorph.rollangle == 0
#ifdef WOUGHMP_WOUGHMP
&& viewmorph.fisheye == 0
#endif
)
viewmorph.x1 = 0;
if (viewmorph.zoomneeded != FRACUNIT)
R_SetViewSize();
viewmorph.zoomneeded = FRACUNIT;
return;
}
if (viewmorph.scrmapsize != vid.width*vid.height)
{
if (viewmorph.scrmap)
free(viewmorph.scrmap);
viewmorph.scrmap = malloc(vid.width*vid.height * sizeof(INT32));
viewmorph.scrmapsize = vid.width*vid.height;
}
temp = FINECOSINE(rollangle);
rollcos = FIXED_TO_FLOAT(temp);
temp = FINESINE(rollangle);
rollsin = FIXED_TO_FLOAT(temp);
// Calculate maximum zoom needed
x1 = (vid.width*fabsf(rollcos) + vid.height*fabsf(rollsin)) / vid.width;
y1 = (vid.height*fabsf(rollcos) + vid.width*fabsf(rollsin)) / vid.height;
#ifdef WOUGHMP_WOUGHMP
if (fisheye)
{
float f = FIXED_TO_FLOAT(fisheye);
for (vx = 0; vx <= halfwidth; vx++)
fisheyemap[vx] = 1.0f / cos(atan(vx * f / halfwidth));
f = cos(atan(f));
if (f < 1.0f)
{
x1 /= f;
y1 /= f;
}
}
#endif
temp = max(x1, y1)*FRACUNIT;
if (temp < FRACUNIT)
temp = FRACUNIT;
else
temp |= 0x3FFF; // Limit how many times the viewport needs to be recalculated
//CONS_Printf("Setting zoom to %f\n", FIXED_TO_FLOAT(temp));
if (temp != viewmorph.zoomneeded)
{
viewmorph.zoomneeded = temp;
R_SetViewSize();
}
zoomfactor = FIXED_TO_FLOAT(viewmorph.zoomneeded);
end = vid.width * vid.height - 1;
pos = 0;
// Pre-multiply rollcos and rollsin to use for positional stuff
rollcos /= zoomfactor;
rollsin /= zoomfactor;
x1 = -(halfwidth * rollcos - halfheight * rollsin);
y1 = -(halfheight * rollcos + halfwidth * rollsin);
#ifdef WOUGHMP_WOUGHMP
if (fisheye)
viewmorph.x1 = (INT32)(halfwidth - (halfwidth * fabsf(rollcos) + halfheight * fabsf(rollsin)) * fisheyemap[halfwidth]);
else
#endif
viewmorph.x1 = (INT32)(halfwidth - (halfwidth * fabsf(rollcos) + halfheight * fabsf(rollsin)));
//CONS_Printf("saving %d cols\n", viewmorph.x1);
// Set ceilingclip and floorclip
for (vx = 0; vx < vid.width; vx++)
{
viewmorph.ceilingclip[vx] = vid.height;
viewmorph.floorclip[vx] = -1;
}
x2 = x1;
y2 = y1;
for (vx = 0; vx < vid.width; vx++)
{
INT16 xa, ya, xb, yb;
xa = x2+halfwidth;
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
xb = vid.width-1-xa;
yb = vid.height-1-ya;
viewmorph.ceilingclip[xa] = min(viewmorph.ceilingclip[xa], ya);
viewmorph.floorclip[xa] = max(viewmorph.floorclip[xa], ya);
viewmorph.ceilingclip[xb] = min(viewmorph.ceilingclip[xb], yb);
viewmorph.floorclip[xb] = max(viewmorph.floorclip[xb], yb);
x2 += rollcos;
y2 += rollsin;
}
x2 = x1;
y2 = y1;
for (vy = 0; vy < vid.height; vy++)
{
INT16 xa, ya, xb, yb;
xa = x2+halfwidth;
ya = y2+halfheight;
xb = vid.width-1-xa;
yb = vid.height-1-ya;
viewmorph.ceilingclip[xa] = min(viewmorph.ceilingclip[xa], ya);
viewmorph.floorclip[xa] = max(viewmorph.floorclip[xa], ya);
viewmorph.ceilingclip[xb] = min(viewmorph.ceilingclip[xb], yb);
viewmorph.floorclip[xb] = max(viewmorph.floorclip[xb], yb);
x2 -= rollsin;
y2 += rollcos;
}
//CONS_Printf("Top left corner is %f %f\n", x1, y1);
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
#ifdef WOUGHMP_WOUGHMP
if (fisheye)
{
for (vy = 0; vy < halfheight; vy++)
{
x2 = x1;
y2 = y1;
x1 -= rollsin;
y1 += rollcos;
for (vx = 0; vx < vid.width; vx++)
{
usedx = halfwidth + x2*fisheyemap[(int) floorf(fabsf(y2*zoomfactor))];
usedy = halfheight + y2*fisheyemap[(int) floorf(fabsf(x2*zoomfactor))];
usedpos = usedx + usedy*vid.width;
viewmorph.scrmap[pos] = usedpos;
viewmorph.scrmap[end-pos] = end-usedpos;
x2 += rollcos;
y2 += rollsin;
pos++;
}
}
}
else
x1 += halfwidth;
y1 += halfheight;
for (vy = 0; vy < halfheight; vy++)
{
x2 = x1;
y2 = y1;
x1 -= rollsin;
y1 += rollcos;
for (vx = 0; vx < vid.width; vx++)
{
usedx = x2;
usedy = y2;
usedpos = usedx + usedy*vid.width;
viewmorph.scrmap[pos] = usedpos;
viewmorph.scrmap[end-pos] = end-usedpos;
x2 += rollcos;
y2 += rollsin;
pos++;
}
}
#ifdef WOUGHMP_WOUGHMP
}
#endif
viewmorph.use = true;
}
void R_ApplyViewMorph(void)
{
UINT8 *tmpscr = screens[4];
UINT8 *srcscr = screens[0];
INT32 p, end = vid.width * vid.height;
if (!viewmorph.use)
return;
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
if (cv_debug & DBG_VIEWMORPH)
{
UINT8 border = 32;
UINT8 grid = 160;
INT32 ws = vid.width / 4;
INT32 hs = vid.width * (vid.height / 4);
memcpy(tmpscr, srcscr, vid.width*vid.height);
for (p = 0; p < vid.width; p++)
{
tmpscr[viewmorph.scrmap[p]] = border;
tmpscr[viewmorph.scrmap[p + hs]] = grid;
tmpscr[viewmorph.scrmap[p + hs*2]] = grid;
tmpscr[viewmorph.scrmap[p + hs*3]] = grid;
tmpscr[viewmorph.scrmap[end - 1 - p]] = border;
}
for (p = vid.width; p < end; p += vid.width)
{
tmpscr[viewmorph.scrmap[p]] = border;
tmpscr[viewmorph.scrmap[p + ws]] = grid;
tmpscr[viewmorph.scrmap[p + ws*2]] = grid;
tmpscr[viewmorph.scrmap[p + ws*3]] = grid;
tmpscr[viewmorph.scrmap[end - 1 - p]] = border;
}
}
else
for (p = 0; p < end; p++)
tmpscr[p] = srcscr[viewmorph.scrmap[p]];
VID_BlitLinearScreen(tmpscr, screens[0],
vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.width);
}
//
// R_SetViewSize
// Do not really change anything here,
// because it might be in the middle of a refresh.
// The change will take effect next refresh.
//
boolean setsizeneeded;
void R_SetViewSize(void)
{
setsizeneeded = true;
}
//
// R_ExecuteSetViewSize
//
void R_ExecuteSetViewSize(void)
{
fixed_t dy;
INT32 i;
INT32 j;
INT32 level;
INT32 startmapl;
setsizeneeded = false;
if (rendermode == render_none)
return;
// status bar overlay
st_overlay = cv_showhud.value;
scaledviewwidth = vid.width;
viewheight = vid.height;
if (splitscreen)
viewheight >>= 1;
viewwidth = scaledviewwidth;
centerx = viewwidth/2;
centery = viewheight/2;
centerxfrac = centerx<<FRACBITS;
centeryfrac = centery<<FRACBITS;
fov = FixedAngle(cv_fov.value/2) + ANGLE_90;
fovtan = FixedMul(FINETANGENT(fov >> ANGLETOFINESHIFT), viewmorph.zoomneeded);
if (splitscreen == 1) // Splitscreen FOV should be adjusted to maintain expected vertical view
fovtan = 17*fovtan/10;
projection = projectiony = FixedDiv(centerxfrac, fovtan);
R_InitViewBuffer(scaledviewwidth, viewheight);
R_InitTextureMapping();
// thing clipping
for (i = 0; i < viewwidth; i++)
screenheightarray[i] = (INT16)viewheight;
R_SetSkyScale();
// planes
if (rendermode == render_soft)
{
// this is only used for planes rendering in software mode
if (ds_su)
Z_Free(ds_su);
if (ds_sv)
Z_Free(ds_sv);
if (ds_sz)
Z_Free(ds_sz);
ds_su = ds_sv = ds_sz = NULL;
ds_sup = ds_svp = ds_szp = NULL;
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
}
memset(scalelight, 0xFF, sizeof(scalelight));
// Calculate the light levels to use for each level/scale combination.
for (i = 0; i< LIGHTLEVELS; i++)
{
startmapl = ((LIGHTLEVELS - 1 - i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
for (j = 0; j < MAXLIGHTSCALE; j++)
{
level = startmapl - j*vid.width/(viewwidth)/DISTMAP;
if (level < 0)
level = 0;
if (level >= NUMCOLORMAPS)
level = NUMCOLORMAPS - 1;
scalelight[i][j] = colormaps + level*256;
}
}
// continue to do the software setviewsize as long as we use the reference software view
#ifdef HWRENDER
if (rendermode != render_soft)
HWR_SetViewSize();
#endif
am_recalc = true;