mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-29 23:22:32 +00:00
8eb522c873
Fix visplane explorer busy looping when waiting for data and reduce the used core count to 75% of the total available Made vpo native code thread safe, removing the need for ungodly DLL patching hacks
609 lines
11 KiB
C++
609 lines
11 KiB
C++
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Copyright(C) 1993-1996 Id Software, Inc.
|
|
// Copyright(C) 2005 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.
|
|
//
|
|
// DESCRIPTION:
|
|
// Rendering main loop and setup functions,
|
|
// utility functions (BSP, geometry, trigonometry).
|
|
// See tables.c, too.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "Precomp.h"
|
|
#include "vpo_local.h"
|
|
|
|
// #include "r_sky.h"
|
|
|
|
namespace vpo
|
|
{
|
|
|
|
|
|
// Fineangles in the SCREENWIDTH wide window.
|
|
#define FIELDOFVIEW 2048
|
|
|
|
|
|
|
|
//
|
|
// R_AddPointToBox
|
|
// Expand a given bbox
|
|
// so that it encloses a given point.
|
|
//
|
|
void Context::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 Context::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 Context::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 Context::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
|
|
return -tantoangle[SlopeDiv(y,x)];
|
|
}
|
|
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 Context::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 Context::R_PointToDist ( fixed_t x, fixed_t y )
|
|
{
|
|
int angle;
|
|
fixed_t dx;
|
|
fixed_t dy;
|
|
fixed_t temp;
|
|
fixed_t dist;
|
|
fixed_t frac;
|
|
|
|
dx = abs(x - viewx);
|
|
dy = abs(y - viewy);
|
|
|
|
if (dy>dx)
|
|
{
|
|
temp = dx;
|
|
dx = dy;
|
|
dy = temp;
|
|
}
|
|
|
|
// Fix crashes in udm1.wad
|
|
|
|
if (dx != 0)
|
|
{
|
|
frac = FixedDiv(dy, dx);
|
|
}
|
|
else
|
|
{
|
|
frac = 0;
|
|
}
|
|
|
|
angle = (tantoangle[frac>>DBITS]+ANG90) >> ANGLETOFINESHIFT;
|
|
|
|
// use as cosine
|
|
dist = FixedDiv (dx, finesine[angle] );
|
|
|
|
return dist;
|
|
}
|
|
|
|
|
|
//
|
|
// 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 Context::R_ScaleFromGlobalAngle (angle_t visangle)
|
|
{
|
|
fixed_t scale;
|
|
angle_t anglea;
|
|
angle_t angleb;
|
|
int sinea;
|
|
int sineb;
|
|
fixed_t num;
|
|
int den;
|
|
|
|
// UNUSED
|
|
#if 0
|
|
{
|
|
fixed_t dist;
|
|
fixed_t z;
|
|
fixed_t sinv;
|
|
fixed_t 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);
|
|
|
|
// both sines are allways positive
|
|
sinea = finesine[anglea>>ANGLETOFINESHIFT];
|
|
sineb = finesine[angleb>>ANGLETOFINESHIFT];
|
|
num = FixedMul(projection,sineb)<<0;
|
|
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;
|
|
}
|
|
|
|
|
|
void Context::R_InitBuffer ( int width, int height )
|
|
{
|
|
int i;
|
|
|
|
// Handle resize,
|
|
// e.g. smaller view windows
|
|
// with border and/or status bar.
|
|
viewwindowx = (SCREENWIDTH-width) >> 1;
|
|
viewwindowy = 0;
|
|
|
|
// this was from R_InitSprites
|
|
for (i=0 ; i<SCREENWIDTH ; i++)
|
|
{
|
|
negonearray[i] = -1;
|
|
}
|
|
|
|
#if 0
|
|
// Column offset. For windows.
|
|
for (i=0 ; i<width ; i++)
|
|
columnofs[i] = viewwindowx + i;
|
|
|
|
// Samw with base row offset.
|
|
if (width == SCREENWIDTH)
|
|
viewwindowy = 0;
|
|
else
|
|
viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1;
|
|
|
|
// Preclaculate all row offsets.
|
|
for (i=0 ; i<height ; i++)
|
|
ylookup[i] = screens[0] + (i+viewwindowy)*SCREENWIDTH;
|
|
#endif
|
|
}
|
|
|
|
|
|
//
|
|
// R_InitTextureMapping
|
|
//
|
|
void Context::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_SetViewSize
|
|
//
|
|
void Context::R_SetViewSize ( int blocks, int detail )
|
|
{
|
|
fixed_t cosadj;
|
|
fixed_t dy;
|
|
int i;
|
|
|
|
if (blocks == 11)
|
|
{
|
|
scaledviewwidth = SCREENWIDTH;
|
|
viewheight = SCREENHEIGHT;
|
|
}
|
|
else
|
|
{
|
|
scaledviewwidth = blocks*32;
|
|
viewheight = (blocks*168/10)&~7;
|
|
}
|
|
|
|
viewwidth = scaledviewwidth >> 0;
|
|
|
|
centery = viewheight/2;
|
|
centerx = viewwidth/2;
|
|
centerxfrac = centerx<<FRACBITS;
|
|
centeryfrac = centery<<FRACBITS;
|
|
projection = centerxfrac;
|
|
|
|
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<<0)/2*FRACUNIT, dy);
|
|
}
|
|
|
|
for (i=0 ; i<viewwidth ; i++)
|
|
{
|
|
cosadj = abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
|
|
distscale[i] = FixedDiv (FRACUNIT,cosadj);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// R_Init
|
|
//
|
|
void Context::R_Init (void)
|
|
{
|
|
R_SetViewSize (11, 0);
|
|
|
|
framecount = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// R_PointInSubsector
|
|
//
|
|
subsector_t* Context::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 Context::R_SetupFrame (fixed_t x, fixed_t y, fixed_t z, angle_t angle)
|
|
{
|
|
viewx = x;
|
|
viewy = y;
|
|
viewz = z;
|
|
|
|
viewangle = angle;
|
|
|
|
viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
|
|
viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
|
|
|
|
sscount = 0;
|
|
|
|
framecount++;
|
|
validcount++;
|
|
}
|
|
|
|
|
|
//
|
|
// R_RenderView
|
|
//
|
|
void Context::R_RenderView (fixed_t x, fixed_t y, fixed_t z, angle_t angle)
|
|
{
|
|
R_SetupFrame (x, y, z, angle);
|
|
|
|
// Clear buffers.
|
|
R_ClearClipSegs ();
|
|
R_ClearDrawSegs ();
|
|
R_ClearPlanes ();
|
|
/// R_ClearSprites ();
|
|
|
|
// The head node is the last node output.
|
|
R_RenderBSPNode (numnodes - 1);
|
|
}
|
|
|
|
|
|
} // namespace vpo
|
|
|