ref: ef1ba7ed5da0ddfd59b1b6d828c44db598dcca4f
dir: /r_main.c/
//**************************************************************************
//**
//** r_main.c : Heretic 2 : Raven Software, Corp.
//**
//** $Revision: 373 $
//** $Date: 2009-05-19 21:14:28 +0300 (Tue, 19 May 2009) $
//**
//**************************************************************************
#include "h2stdinc.h"
#ifndef RENDER3D
#include "h2def.h"
#include "r_local.h"
int viewangleoffset;
int validcount = 1; // increment every time a check is made
lighttable_t *fixedcolormap;
extern lighttable_t **walllights;
int centerx, centery;
fixed_t centerxfrac, centeryfrac;
fixed_t projection;
int framecount; // just for profiling purposes
int sscount, linecount, loopcount;
fixed_t viewx, viewy, viewz;
angle_t viewangle;
fixed_t viewcos, viewsin;
player_t *viewplayer;
int detailshift; // 0 = high, 1 = low
//
// precalculated math tables
//
angle_t clipangle;
// 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.
int 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[SCREENWIDTH+1];
// the finetangentgent[angle+FINEANGLES/4] table holds the fixed_t tangent
// values for view angles, ranging from H2MININT to 0 to H2MAXINT.
// fixed_t finetangent[FINEANGLES/2];
// fixed_t finesine[5*FINEANGLES/4];
fixed_t *finecosine = &finesine[FINEANGLES/4];
lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
lighttable_t *scalelightfixed[MAXLIGHTSCALE];
lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
int extralight; // bumped light from gun blasts
void (*colfunc) (void);
void (*basecolfunc) (void);
void (*fuzzcolfunc) (void);
void (*transcolfunc) (void);
void (*spanfunc) (void);
/*
===================
=
= R_AddPointToBox
=
===================
*/
/*
void R_AddPointToBox (int x, int y, fixed_t *box)
{
if (x < box[BOXLEFT])
box[BOXLEFT] = x;
if (x > box[BOXRIGHT])
box[BOXRIGHT] = x;
if (y < box[BOXBOTTOM])
box[BOXBOTTOM] = y;
if (y > box[BOXTOP])
box[BOXTOP] = y;
}
*/
/*
===============================================================================
=
= R_PointOnSide
=
= Returns side 0 (front) or 1 (back)
===============================================================================
*/
int R_PointOnSide (fixed_t x, fixed_t y, node_t *node)
{
fixed_t dx, dy;
fixed_t left, right;
if (!node->dx)
{
if (x <= node->x)
return node->dy > 0;
return node->dy < 0;
}
if (!node->dy)
{
if (y <= node->y)
return node->dx < 0;
return node->dx > 0;
}
dx = (x - node->x);
dy = (y - node->y);
// try to quickly decide by looking at sign bits
if ((node->dy ^ node->dx ^ dx ^ dy) & 0x80000000)
{
if ((node->dy ^ dx) & 0x80000000)
return 1; // (left is negative)
return 0;
}
left = FixedMul (node->dy>>FRACBITS , dx);
right = FixedMul (dy , node->dx>>FRACBITS);
if (right < left)
return 0; // front side
return 1; // back side
}
int R_PointOnSegSide (fixed_t x, fixed_t y, seg_t *line)
{
fixed_t lx, ly;
fixed_t ldx, ldy;
fixed_t dx, dy;
fixed_t left, right;
lx = line->v1->x;
ly = line->v1->y;
ldx = line->v2->x - lx;
ldy = line->v2->y - ly;
if (!ldx)
{
if (x <= lx)
return ldy > 0;
return ldy < 0;
}
if (!ldy)
{
if (y <= ly)
return ldx < 0;
return ldx > 0;
}
dx = (x - lx);
dy = (y - ly);
// try to quickly decide by looking at sign bits
if ((ldy ^ ldx ^ dx ^ dy) & 0x80000000)
{
if ((ldy ^ dx) & 0x80000000)
return 1; // (left is negative)
return 0;
}
left = FixedMul (ldy>>FRACBITS, dx);
right = FixedMul (dy, ldx>>FRACBITS);
if (right < left)
return 0; // front side
return 1; // back side
}
/*
===============================================================================
=
= 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 is to handle
// the case when x==y without additional checking.
#define SLOPERANGE 2048
#define SLOPEBITS 11
#define DBITS (FRACBITS-SLOPEBITS)
extern int tantoangle[SLOPERANGE+1]; // get from tables.c
//int tantoangle[SLOPERANGE+1];
static int SlopeDiv (unsigned num, unsigned den)
{
unsigned ans;
if (den < 512)
return SLOPERANGE;
ans = (num<<3) / (den>>8);
return ans <= SLOPERANGE ? ans : SLOPERANGE;
}
angle_t R_PointToAngle (fixed_t x, fixed_t y)
{
x -= viewx;
y -= viewy;
if ( (!x) && (!y) )
return 0;
if (x >= 0)
{ // x >= 0
if (y >= 0)
{ // y >= 0
if (x > y)
return tantoangle[SlopeDiv(y,x)]; // octant 0
else
return ANG90 - 1 - tantoangle[SlopeDiv(x,y)]; // octant 1
}
else
{ // y < 0
y = -y;
if (x > y)
return -tantoangle[SlopeDiv(y,x)]; // octant 8
else
return ANG270 + tantoangle[SlopeDiv(x,y)]; // octant 7
}
}
else
{ // x < 0
x = -x;
if (y >= 0)
{ // y >= 0
if (x > y)
return ANG180 - 1 - tantoangle[SlopeDiv(y,x)]; // octant 3
else
return ANG90 + tantoangle[SlopeDiv(x,y)]; // octant 2
}
else
{ // y < 0
y = -y;
if (x > y)
return ANG180 + tantoangle[SlopeDiv(y,x)]; // octant 4
else
return ANG270 - 1 - tantoangle[SlopeDiv(x,y)]; // octant 5
}
}
return 0;
}
angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
{
viewx = x1;
viewy = y1;
return R_PointToAngle (x2, y2);
}
fixed_t R_PointToDist (fixed_t x, fixed_t y)
{
int angle;
fixed_t dx, dy, temp;
fixed_t dist;
dx = abs(x - viewx);
dy = abs(y - viewy);
if (dy > dx)
{
temp = dx;
dx = dy;
dy = temp;
}
angle = (tantoangle[ FixedDiv(dy,dx)>>DBITS ]+ANG90) >> ANGLETOFINESHIFT;
dist = FixedDiv (dx, finesine[angle]); // use as cosine
return dist;
}
/*
=================
=
= R_InitPointToAngle
=
=================
*/
void R_InitPointToAngle (void)
{
// now getting from tables.c
#if 0
int i;
int t; /* int32_t */
float f;
//
// slope (tangent) to angle lookup
//
for (i = 0; i <= SLOPERANGE; i++)
{
f = atan((float)i / SLOPERANGE) / (3.141592657*2);
t = 0xffffffff * f;
tantoangle[i] = t;
}
#endif
}
//=============================================================================
/*
================
=
= R_ScaleFromGlobalAngle
=
= Returns the texture mapping scale for the current line at the given angle
= rw_distance must be calculated first
================
*/
fixed_t R_ScaleFromGlobalAngle (angle_t visangle)
{
fixed_t scale;
int anglea, angleb;
int sinea, sineb;
fixed_t num, den;
#if 0
{
fixed_t dist, z;
fixed_t sinv, cosv;
sinv = finesine[(visangle - rw_normalangle)>>ANGLETOFINESHIFT];
dist = FixedDiv (rw_distance, sinv);
cosv = finecosine[(viewangle - visangle)>>ANGLETOFINESHIFT];
z = abs(FixedMul (dist, cosv));
scale = FixedDiv(projection, z);
return scale;
}
#endif
anglea = ANG90 + (visangle - viewangle);
angleb = ANG90 + (visangle - rw_normalangle);
// bothe sines are allways positive
sinea = finesine[anglea>>ANGLETOFINESHIFT];
sineb = finesine[angleb>>ANGLETOFINESHIFT];
num = FixedMul(projection, sineb)<<detailshift;
den = FixedMul(rw_distance, sinea);
if (den > num>>16)
{
scale = FixedDiv (num, den);
if (scale > 64*FRACUNIT)
scale = 64*FRACUNIT;
else if (scale < 256)
scale = 256;
}
else
scale = 64*FRACUNIT;
return scale;
}
/*
=================
=
= R_InitTables
=
=================
*/
void R_InitTables (void)
{
// now getting from tables.c
#if 0
int i;
float a, fv;
int t;
//
// viewangle tangent table
//
for (i = 0; i < FINEANGLES/2; i++)
{
a = (i - FINEANGLES/4 + 0.5) * PI * 2 / FINEANGLES;
fv = FRACUNIT * tan(a);
t = fv;
finetangent[i] = t;
}
//
// finesine table
//
for (i = 0; i < 5*FINEANGLES/4; i++)
{
// OPTIMIZE: mirror...
a = (i + 0.5) * PI * 2 / FINEANGLES;
t = FRACUNIT * sin(a);
finesine[i] = t;
}
#endif
}
/*
=================
=
= R_InitTextureMapping
=
=================
*/
void R_InitTextureMapping (void)
{
int i;
int x;
int 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 (centerxfrac, finetangent[FINEANGLES/4 + FIELDOFVIEW/2]);
for (i = 0; i < FINEANGLES/2; i++)
{
if (finetangent[i] > FRACUNIT*2)
t = -1;
else if (finetangent[i] < -FRACUNIT*2)
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 xtoviewangleangle[]
//
// 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) - ANG90;
}
//
// take out the fencepost cases from viewangletox
//
for (i = 0; i < FINEANGLES/2; i++)
{
t = FixedMul (finetangent[i], focallength);
t = centerx - t;
if (viewangletox[i] == -1)
viewangletox[i] = 0;
else if (viewangletox[i] == viewwidth + 1)
viewangletox[i] = viewwidth;
}
clipangle = xtoviewangle[0];
}
//=============================================================================
/*
====================
=
= R_InitLightTables
=
= Only inits the zlight table, because the scalelight table changes
= with view size
=
====================
*/
#define DISTMAP 2
void R_InitLightTables (void)
{
int i, j, level, start_map;
int scale;
//
// Calculate the light levels to use for each level / distance combination
//
for (i = 0; i < LIGHTLEVELS; i++)
{
start_map = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
for (j = 0; j < MAXLIGHTZ; j++)
{
scale = FixedDiv ((SCREENWIDTH/2*FRACUNIT), (j + 1)<<LIGHTZSHIFT);
scale >>= LIGHTSCALESHIFT;
level = start_map - scale/DISTMAP;
if (level < 0)
level = 0;
if (level >= NUMCOLORMAPS)
level = NUMCOLORMAPS-1;
zlight[i][j] = colormaps + level*256;
}
}
}
/*
==============
=
= R_SetViewSize
=
= Don't really change anything here, because i might be in the middle of
= a refresh. The change will take effect next refresh.
=
==============
*/
static int setblocks, setdetail;
boolean setsizeneeded;
void R_SetViewSize (int blocks, int detail)
{
setsizeneeded = true;
setblocks = blocks;
setdetail = detail;
}
/*
==============
=
= R_ExecuteSetViewSize
=
==============
*/
void R_ExecuteSetViewSize (void)
{
fixed_t cosadj, dy;
int i, j, level, start_map;
setsizeneeded = false;
if (setblocks == 11)
{
scaledviewwidth = SCREENWIDTH;
viewheight = SCREENHEIGHT;
}
else
{
scaledviewwidth = setblocks*32;
viewheight = (setblocks*161/10);
}
detailshift = setdetail;
viewwidth = scaledviewwidth>>detailshift;
centery = viewheight/2;
centerx = viewwidth/2;
centerxfrac = centerx<<FRACBITS;
centeryfrac = centery<<FRACBITS;
projection = centerxfrac;
if (!detailshift)
{
colfunc = basecolfunc = R_DrawColumn;
fuzzcolfunc = R_DrawFuzzColumn;
transcolfunc = R_DrawTranslatedColumn;
spanfunc = R_DrawSpan;
}
else
{
colfunc = basecolfunc = R_DrawColumnLow;
fuzzcolfunc = R_DrawFuzzColumn;
transcolfunc = R_DrawTranslatedColumn;
spanfunc = R_DrawSpanLow;
}
R_InitBuffer (scaledviewwidth, viewheight);
R_InitTextureMapping ();
//
// psprite scales
//
pspritescale = FRACUNIT*viewwidth/SCREENWIDTH;
pspriteiscale = FRACUNIT*SCREENWIDTH/viewwidth;
//
// thing clipping
//
for (i = 0; i < viewwidth; i++)
screenheightarray[i] = viewheight;
//
// planes
//
for (i = 0; i < viewheight; i++)
{
dy = ((i - viewheight/2)<<FRACBITS) + FRACUNIT/2;
dy = abs(dy);
yslope[i] = FixedDiv ((viewwidth<<detailshift)/2*FRACUNIT, dy);
}
for (i = 0; i < viewwidth; i++)
{
cosadj = abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
distscale[i] = FixedDiv (FRACUNIT, cosadj);
}
//
// Calculate the light levels to use for each level / scale combination
//
for (i = 0; i < LIGHTLEVELS; i++)
{
start_map = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
for (j = 0; j < MAXLIGHTSCALE; j++)
{
level = start_map - j*SCREENWIDTH/(viewwidth<<detailshift)/DISTMAP;
if (level < 0)
level = 0;
if (level >= NUMCOLORMAPS)
level = NUMCOLORMAPS-1;
scalelight[i][j] = colormaps + level*256;
}
}
//
// draw the border
//
R_DrawViewBorder (); // erase old menu stuff
}
/*
==============
=
= R_Init
=
==============
*/
int detailLevel;
int screenblocks;
void R_Init(void)
{
R_InitData();
R_InitPointToAngle();
R_InitTables();
// viewwidth / viewheight / detailLevel are set by the defaults
R_SetViewSize(screenblocks, detailLevel);
R_InitPlanes();
R_InitLightTables();
R_InitSkyMap();
R_InitTranslationTables();
framecount = 0;
}
/*
==============
=
= R_PointInSubsector
=
==============
*/
subsector_t *R_PointInSubsector (fixed_t x, fixed_t y)
{
node_t *node;
int side, nodenum;
if (!numnodes) // single subsector is a special case
return subsectors;
nodenum = numnodes - 1;
while (! (nodenum & NF_SUBSECTOR) )
{
node = &nodes[nodenum];
side = R_PointOnSide (x, y, node);
nodenum = node->children[side];
}
return &subsectors[nodenum & ~NF_SUBSECTOR];
}
//----------------------------------------------------------------------------
//
// PROC R_SetupFrame
//
//----------------------------------------------------------------------------
void R_SetupFrame(player_t *player)
{
int i;
int tableAngle;
int tempCentery;
int intensity;
viewplayer = player;
viewangle = player->mo->angle + viewangleoffset;
tableAngle = viewangle>>ANGLETOFINESHIFT;
viewx = player->mo->x;
viewy = player->mo->y;
if (localQuakeHappening[displayplayer] && !paused)
{
intensity = localQuakeHappening[displayplayer];
viewx += ((M_Random() % (intensity<<2)) - (intensity<<1)) << FRACBITS;
viewy += ((M_Random() % (intensity<<2)) - (intensity<<1)) << FRACBITS;
}
extralight = player->extralight;
viewz = player->viewz;
tempCentery = viewheight/2 + (player->lookdir)*screenblocks/10;
if (centery != tempCentery)
{
centery = tempCentery;
centeryfrac = centery<<FRACBITS;
for (i = 0; i < viewheight; i++)
{
yslope[i] = FixedDiv ( (viewwidth<<detailshift)/2*FRACUNIT,
abs(((i - centery)<<FRACBITS) + FRACUNIT/2) );
}
}
viewsin = finesine[tableAngle];
viewcos = finecosine[tableAngle];
sscount = 0;
if (player->fixedcolormap)
{
fixedcolormap = colormaps + player->fixedcolormap*256*sizeof(lighttable_t);
walllights = scalelightfixed;
for (i = 0; i < MAXLIGHTSCALE; i++)
{
scalelightfixed[i] = fixedcolormap;
}
}
else
{
fixedcolormap = 0;
}
framecount++;
validcount++;
if (BorderNeedRefresh)
{
if (setblocks < 10)
{
R_DrawViewBorder();
}
BorderNeedRefresh = false;
BorderTopRefresh = false;
UpdateState |= I_FULLSCRN;
}
if (BorderTopRefresh)
{
if (setblocks < 10)
{
R_DrawTopBorder();
}
BorderTopRefresh = false;
UpdateState |= I_MESSAGES;
}
}
/*
==============
=
= R_RenderView
=
==============
*/
void R_RenderPlayerView (player_t *player)
{
R_SetupFrame (player);
R_ClearClipSegs ();
R_ClearDrawSegs ();
R_ClearPlanes ();
R_ClearSprites ();
NetUpdate (); // check for new console commands
// Make displayed player invisible locally
if (localQuakeHappening[displayplayer] && gamestate == GS_LEVEL)
{
players[displayplayer].mo->flags2 |= MF2_DONTDRAW;
R_RenderBSPNode (numnodes - 1); // head node is the last node output
players[displayplayer].mo->flags2 &= ~MF2_DONTDRAW;
}
else
{
R_RenderBSPNode (numnodes - 1); // head node is the last node output
}
NetUpdate (); // check for new console commands
R_DrawPlanes ();
NetUpdate (); // check for new console commands
R_DrawMasked ();
NetUpdate (); // check for new console commands
}
#endif /* RENDER3D */