UltimateZoneBuilder/Source/Native/VPO/r_main.cpp
Magnus Norddahl 8eb522c873 Move vpo native code into BuilderNative as it is easier to manage. The plugins folder doesn't support including native dlls properly anyway.
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
2020-04-19 15:56:24 +02:00

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