summaryrefslogtreecommitdiff
path: root/src/hexen/r_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hexen/r_main.c')
-rw-r--r--src/hexen/r_main.c839
1 files changed, 839 insertions, 0 deletions
diff --git a/src/hexen/r_main.c b/src/hexen/r_main.c
new file mode 100644
index 00000000..48e21ab2
--- /dev/null
+++ b/src/hexen/r_main.c
@@ -0,0 +1,839 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <math.h>
+#include "m_random.h"
+#include "h2def.h"
+#include "m_bbox.h"
+#include "r_local.h"
+
+int viewangleoffset;
+
+// haleyjd: removed WATCOMC
+
+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];
+
+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 (*tlcolfunc) (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
+=
+===============================================================================
+*/
+
+#define DBITS (FRACBITS-SLOPEBITS)
+
+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;
+ long 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, startmap;
+ int scale;
+
+//
+// Calculate the light levels to use for each level / distance combination
+//
+ for (i = 0; i < LIGHTLEVELS; i++)
+ {
+ startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+ for (j = 0; j < MAXLIGHTZ; j++)
+ {
+ scale =
+ FixedDiv((SCREENWIDTH / 2 * FRACUNIT),
+ (j + 1) << LIGHTZSHIFT);
+ scale >>= LIGHTSCALESHIFT;
+ level = startmap - 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.
+=
+==============
+*/
+
+boolean setsizeneeded;
+int setblocks, setdetail;
+
+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, startmap;
+
+ 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;
+ tlcolfunc = R_DrawTLColumn;
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpan;
+ }
+ else
+ {
+ colfunc = basecolfunc = R_DrawColumnLow;
+ tlcolfunc = R_DrawTLColumn;
+ 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++)
+ {
+ startmap = ((LIGHTLEVELS - 1 - i) * 2) * NUMCOLORMAPS / LIGHTLEVELS;
+ for (j = 0; j < MAXLIGHTSCALE; j++)
+ {
+ level =
+ startmap -
+ 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 = 10;
+
+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;
+
+ //drawbsp = 1;
+ viewplayer = player;
+ // haleyjd: removed WATCOMC
+ // haleyjd FIXME: viewangleoffset handling?
+ 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;
+ }
+
+#if 0
+ {
+ static int frame;
+ memset(screen, frame, SCREENWIDTH * SCREENHEIGHT);
+ frame++;
+ }
+#endif
+}
+
+/*
+==============
+=
+= 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
+}