v4k-git-backup/demos/ports/doom/src/r_main.c

778 lines
16 KiB
C

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Rendering main loop and setup functions,
// utility functions (BSP, geometry, trigonometry).
// See tables.c, too.
//
//-----------------------------------------------------------------------------
#include "doom_config.h"
#include "doomdef.h"
#include "d_net.h"
#include "m_bbox.h"
#include "r_local.h"
#include "r_sky.h"
#define FIELDOFVIEW 2048 // Fineangles in the SCREENWIDTH wide window.
#define DISTMAP 2
int viewangleoffset;
// increment every time a check is made
int validcount = 1;
lighttable_t* fixedcolormap;
int centerx;
int centery;
fixed_t centerxfrac;
fixed_t centeryfrac;
fixed_t projection;
// just for profiling purposes
int framecount;
int sscount;
int linecount;
int loopcount;
fixed_t viewx;
fixed_t viewy;
fixed_t viewz;
angle_t viewangle;
fixed_t viewcos;
fixed_t viewsin;
player_t* viewplayer;
// 0 = high, 1 = low
int detailshift;
//
// 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];
fixed_t* finecosine = &finesine[FINEANGLES / 4];
lighttable_t* scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
lighttable_t* scalelightfixed[MAXLIGHTSCALE];
lighttable_t* zlight[LIGHTLEVELS][MAXLIGHTZ];
// bumped light from gun blasts
int extralight;
doom_boolean setsizeneeded;
int setblocks;
int setdetail;
extern lighttable_t** walllights;
extern int detailLevel;
extern int screenblocks;
void (*colfunc) (void);
void (*basecolfunc) (void);
void (*fuzzcolfunc) (void);
void (*transcolfunc) (void);
void (*spanfunc) (void);
//
// R_AddPointToBox
// Expand a given bbox
// so that it encloses a given point.
//
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
// Traverse BSP (sub) tree,
// check point against partition plane.
// Returns side 0 (front) or 1 (back).
//
int R_PointOnSide(fixed_t x, fixed_t y, node_t* node)
{
fixed_t dx;
fixed_t dy;
fixed_t left;
fixed_t 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)
{
// (left is negative)
return 1;
}
return 0;
}
left = FixedMul(node->dy >> FRACBITS, dx);
right = FixedMul(dy, node->dx >> FRACBITS);
if (right < left)
{
// front side
return 0;
}
// back side
return 1;
}
int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t* line)
{
fixed_t lx;
fixed_t ly;
fixed_t ldx;
fixed_t ldy;
fixed_t dx;
fixed_t dy;
fixed_t left;
fixed_t 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)
{
// (left is negative)
return 1;
}
return 0;
}
left = FixedMul(ldy >> FRACBITS, dx);
right = FixedMul(dy, ldx >> FRACBITS);
if (right < left)
{
// front side
return 0;
}
// back side
return 1;
}
//
// 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.
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)
{
// octant 0
return tantoangle[SlopeDiv(y, x)];
}
else
{
// octant 1
return ANG90 - 1 - tantoangle[SlopeDiv(x, y)];
}
}
else
{
// y<0
y = -y;
if (x > y)
{
// octant 8
#pragma warning(push)
#pragma warning(disable : 4146)
return -tantoangle[SlopeDiv(y, x)];
#pragma warning(pop)
}
else
{
// octant 7
return ANG270 + tantoangle[SlopeDiv(x, y)];
}
}
}
else
{
// x<0
x = -x;
if (y >= 0)
{
// y>= 0
if (x > y)
{
// octant 3
return ANG180 - 1 - tantoangle[SlopeDiv(y, x)];
}
else
{
// octant 2
return ANG90 + tantoangle[SlopeDiv(x, y)];
}
}
else
{
// y<0
y = -y;
if (x > y)
{
// octant 4
return ANG180 + tantoangle[SlopeDiv(y, x)];
}
else
{
// octant 5
return ANG270 - 1 - tantoangle[SlopeDiv(x, y)];
}
}
}
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;
fixed_t dy;
fixed_t temp;
fixed_t dist;
dx = doom_abs(x - viewx);
dy = doom_abs(y - viewy);
if (dy > dx)
{
temp = dx;
dx = dy;
dy = temp;
}
angle = (tantoangle[FixedDiv(dy, dx) >> DBITS] + ANG90) >> ANGLETOFINESHIFT;
// use as cosine
dist = FixedDiv(dx, finesine[angle]);
return dist;
}
//
// R_InitPointToAngle
//
void R_InitPointToAngle(void)
{
}
//
// R_ScaleFromGlobalAngle
// Returns the texture mapping scale
// for the current line (horizontal span)
// at the given angle.
// rw_distance must be calculated first.
//
fixed_t R_ScaleFromGlobalAngle(angle_t visangle)
{
fixed_t scale;
int anglea;
int angleb;
int sinea;
int sineb;
fixed_t num;
int den;
anglea = ANG90 + (visangle - viewangle);
angleb = ANG90 + (visangle - rw_normalangle);
// both 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)
{
}
//
// 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 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) - 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.
//
void R_InitLightTables(void)
{
int i;
int j;
int level;
int 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
// Do not really change anything here,
// because it might be in the middle of a refresh.
// The change will take effect next refresh.
//
void R_SetViewSize(int blocks, int detail)
{
setsizeneeded = true;
setblocks = blocks;
setdetail = detail;
}
//
// R_ExecuteSetViewSize
//
void R_ExecuteSetViewSize(void)
{
fixed_t cosadj;
fixed_t dy;
int i;
int j;
int level;
int startmap;
setsizeneeded = false;
if (setblocks == 11)
{
scaledviewwidth = SCREENWIDTH;
viewheight = SCREENHEIGHT;
}
else
{
scaledviewwidth = setblocks * 32;
viewheight = (setblocks * 168 / 10) & ~7;
}
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 = doom_abs(dy);
yslope[i] = FixedDiv((viewwidth << detailshift) / 2 * FRACUNIT, dy);
}
for (i = 0; i < viewwidth; i++)
{
cosadj = doom_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;
}
}
}
//
// R_Init
//
void R_Init(void)
{
R_InitData();
doom_print("\nR_InitData");
R_InitPointToAngle();
doom_print("\nR_InitPointToAngle");
R_InitTables();
// viewwidth / viewheight / detailLevel are set by the defaults
doom_print("\nR_InitTables");
R_SetViewSize(screenblocks, detailLevel);
R_InitPlanes();
doom_print("\nR_InitPlanes");
R_InitLightTables();
doom_print("\nR_InitLightTables");
R_InitSkyMap();
doom_print("\nR_InitSkyMap");
R_InitTranslationTables();
doom_print("\nR_InitTranslationsTables");
framecount = 0;
}
//
// R_PointInSubsector
//
subsector_t* R_PointInSubsector(fixed_t x, fixed_t y)
{
node_t* node;
int side;
int nodenum;
// single subsector is a special case
if (!numnodes)
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];
}
//
// R_SetupFrame
//
void R_SetupFrame(player_t* player)
{
int i;
viewplayer = player;
viewx = player->mo->x;
viewy = player->mo->y;
viewangle = player->mo->angle + viewangleoffset;
extralight = player->extralight;
viewz = player->viewz;
viewsin = finesine[viewangle >> ANGLETOFINESHIFT];
viewcos = finecosine[viewangle >> ANGLETOFINESHIFT];
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++;
}
//
// R_RenderView
//
void R_RenderPlayerView(player_t* player)
{
R_SetupFrame(player);
// Clear buffers.
R_ClearClipSegs();
R_ClearDrawSegs();
R_ClearPlanes();
R_ClearSprites();
// check for new console commands.
NetUpdate();
// The head node is the last node output.
R_RenderBSPNode(numnodes - 1);
// Check for new console commands.
NetUpdate();
R_DrawPlanes();
// Check for new console commands.
NetUpdate();
R_DrawMasked();
// Check for new console commands.
NetUpdate();
}