UltimateZoneBuilder/Source/Native/VPO/r_segs.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

561 lines
14 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:
// All the clipping: columns, horizontal spans, sky columns.
//
//-----------------------------------------------------------------------------
#include "Precomp.h"
#include "vpo_local.h"
namespace vpo
{
//
// R_RenderSegLoop
// Draws zero, one, or two textures (and possibly a masked
// texture) for walls.
// Can draw or mark the starting pixel of floor and ceiling
// textures.
// CALLED: CORE LOOPING ROUTINE.
//
#define HEIGHTBITS 12
#define HEIGHTUNIT (1<<HEIGHTBITS)
void Context::R_RenderSegLoop (void)
{
angle_t angle;
int yl;
int yh;
int mid;
fixed_t texturecolumn;
int top;
int bottom;
for ( ; rw_x < rw_stopx ; rw_x++)
{
// mark floor / ceiling areas
yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
// no space above wall?
if (yl < ceilingclip[rw_x]+1)
yl = ceilingclip[rw_x]+1;
if (markceiling)
{
top = ceilingclip[rw_x]+1;
bottom = yl-1;
if (bottom >= floorclip[rw_x])
bottom = floorclip[rw_x]-1;
if (top <= bottom)
{
ceilingplane->top[rw_x] = top;
ceilingplane->bottom[rw_x] = bottom;
}
}
yh = bottomfrac>>HEIGHTBITS;
if (yh >= floorclip[rw_x])
yh = floorclip[rw_x]-1;
if (markfloor)
{
top = yh+1;
bottom = floorclip[rw_x]-1;
if (top <= ceilingclip[rw_x])
top = ceilingclip[rw_x]+1;
if (top <= bottom)
{
floorplane->top[rw_x] = top;
floorplane->bottom[rw_x] = bottom;
}
}
// texturecolumn and lighting are independent of wall tiers
if (segtextured)
{
// calculate texture offset
angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance);
texturecolumn >>= FRACBITS;
dc_x = rw_x;
dc_iscale = 0xffffffffu / (unsigned)rw_scale;
}
else
{
// purely to shut up the compiler
texturecolumn = 0;
}
// draw the wall tiers
if (midtexture)
{
// single sided line
dc_yl = yl;
dc_yh = yh;
dc_texturemid = rw_midtexturemid;
///--- dc_source = R_GetColumn(midtexture,texturecolumn);
///--- colfunc ();
ceilingclip[rw_x] = viewheight;
floorclip[rw_x] = -1;
}
else
{
// two sided line
if (toptexture)
{
// top wall
mid = pixhigh>>HEIGHTBITS;
pixhigh += pixhighstep;
if (mid >= floorclip[rw_x])
mid = floorclip[rw_x]-1;
if (mid >= yl)
{
dc_yl = yl;
dc_yh = mid;
dc_texturemid = rw_toptexturemid;
///--- dc_source = R_GetColumn(toptexture,texturecolumn);
///--- colfunc ();
ceilingclip[rw_x] = mid;
}
else
ceilingclip[rw_x] = yl-1;
}
else
{
// no top wall
if (markceiling)
ceilingclip[rw_x] = yl-1;
}
if (bottomtexture)
{
// bottom wall
mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
pixlow += pixlowstep;
// no space above wall?
if (mid <= ceilingclip[rw_x])
mid = ceilingclip[rw_x]+1;
if (mid <= yh)
{
dc_yl = mid;
dc_yh = yh;
dc_texturemid = rw_bottomtexturemid;
///--- dc_source = R_GetColumn(bottomtexture, texturecolumn);
///--- colfunc ();
floorclip[rw_x] = mid;
}
else
floorclip[rw_x] = yh+1;
}
else
{
// no bottom wall
if (markfloor)
floorclip[rw_x] = yh+1;
}
if (maskedtexture)
{
// save texturecol
// for backdrawing of masked mid texture
maskedtexturecol[rw_x] = texturecolumn;
}
}
rw_scale += rw_scalestep;
topfrac += topstep;
bottomfrac += bottomstep;
}
}
//
// R_StoreWallRange
// A wall segment will be drawn
// between start and stop pixels (inclusive).
//
void Context::R_StoreWallRange ( int start, int stop )
{
fixed_t hyp;
fixed_t sineval;
angle_t distangle, offsetangle;
fixed_t vtop;
// don't overflow and crash
total_drawsegs++;
if (total_drawsegs >= MAXDRAWSEGS)
throw overflow_exception();
#ifdef RANGECHECK
if (start >=viewwidth || start > stop)
I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
#endif
sidedef = curline->sidedef;
linedef = curline->linedef;
// mark the segment as visible for auto map
linedef->flags |= ML_MAPPED;
// calculate rw_distance for scale calculation
rw_normalangle = curline->angle + ANG90;
offsetangle = abs((int)rw_normalangle-rw_angle1);
if (offsetangle > ANG90)
offsetangle = ANG90;
distangle = ANG90 - offsetangle;
hyp = R_PointToDist (curline->v1->x, curline->v1->y);
sineval = finesine[distangle>>ANGLETOFINESHIFT];
rw_distance = FixedMul (hyp, sineval);
ds_p->x1 = rw_x = start;
ds_p->x2 = stop;
ds_p->curline = curline;
rw_stopx = stop+1;
// calculate scale at both ends and step
ds_p->scale1 = rw_scale =
R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
if (stop > start )
{
ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
ds_p->scalestep = rw_scalestep =
(ds_p->scale2 - rw_scale) / (stop-start);
}
else
{
ds_p->scale2 = ds_p->scale1;
}
// calculate texture boundaries
// and decide if floor / ceiling marks are needed
worldtop = frontsector->ceilingheight - viewz;
worldbottom = frontsector->floorheight - viewz;
midtexture = toptexture = bottomtexture = maskedtexture = 0;
ds_p->maskedtexturecol = NULL;
if (!backsector)
{
// single sided line
midtexture = sidedef->midtexture;
// a single sided line is terminal, so it must mark ends
markfloor = markceiling = true;
if (linedef->flags & ML_DONTPEGBOTTOM)
{
vtop = frontsector->floorheight
+ 128; ///??? textureheight[sidedef->midtexture];
// bottom of texture at bottom
rw_midtexturemid = vtop - viewz;
}
else
{
// top of texture at top
rw_midtexturemid = worldtop;
}
rw_midtexturemid += sidedef->rowoffset;
ds_p->silhouette = SIL_BOTH;
ds_p->sprtopclip = screenheightarray;
ds_p->sprbottomclip = negonearray;
ds_p->bsilheight = INT_MAX;
ds_p->tsilheight = INT_MIN;
}
else
{
// two sided line
ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
ds_p->silhouette = 0;
if (frontsector->floorheight > backsector->floorheight)
{
ds_p->silhouette = SIL_BOTTOM;
ds_p->bsilheight = frontsector->floorheight;
}
else if (backsector->floorheight > viewz)
{
ds_p->silhouette = SIL_BOTTOM;
ds_p->bsilheight = INT_MAX;
// ds_p->sprbottomclip = negonearray;
}
if (frontsector->ceilingheight < backsector->ceilingheight)
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = frontsector->ceilingheight;
}
else if (backsector->ceilingheight < viewz)
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = INT_MIN;
// ds_p->sprtopclip = screenheightarray;
}
if (backsector->ceilingheight <= frontsector->floorheight)
{
ds_p->sprbottomclip = negonearray;
ds_p->bsilheight = INT_MAX;
ds_p->silhouette |= SIL_BOTTOM;
}
if (backsector->floorheight >= frontsector->ceilingheight)
{
ds_p->sprtopclip = screenheightarray;
ds_p->tsilheight = INT_MIN;
ds_p->silhouette |= SIL_TOP;
}
worldhigh = backsector->ceilingheight - viewz;
worldlow = backsector->floorheight - viewz;
// hack to allow height changes in outdoor areas
if (frontsector->ceilingpic == skyflatnum
&& backsector->ceilingpic == skyflatnum)
{
worldtop = worldhigh;
}
if (worldlow != worldbottom
|| backsector->floorpic != frontsector->floorpic
|| backsector->lightlevel != frontsector->lightlevel)
{
markfloor = true;
}
else
{
// same plane on both sides
markfloor = false;
}
if (worldhigh != worldtop
|| backsector->ceilingpic != frontsector->ceilingpic
|| backsector->lightlevel != frontsector->lightlevel)
{
markceiling = true;
}
else
{
// same plane on both sides
markceiling = false;
}
if (backsector->ceilingheight <= frontsector->floorheight
|| backsector->floorheight >= frontsector->ceilingheight)
{
// closed door
markceiling = markfloor = true;
}
if (worldhigh < worldtop)
{
// top texture
toptexture = sidedef->toptexture;
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
}
else
{
vtop = backsector->ceilingheight
+ 128; ///??? textureheight[sidedef->toptexture];
// bottom of texture
rw_toptexturemid = vtop - viewz;
}
}
if (worldlow > worldbottom)
{
// bottom texture
bottomtexture = sidedef->bottomtexture;
if (linedef->flags & ML_DONTPEGBOTTOM )
{
// bottom of texture at bottom
// top of texture at top
rw_bottomtexturemid = worldtop;
}
else // top of texture at top
rw_bottomtexturemid = worldlow;
}
rw_toptexturemid += sidedef->rowoffset;
rw_bottomtexturemid += sidedef->rowoffset;
// allocate space for masked texture tables
if (sidedef->midtexture)
{
// masked midtexture
maskedtexture = true;
ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
lastopening += rw_stopx - rw_x;
total_openings += (rw_stopx - rw_x);
if (total_openings >= MAXOPENINGS)
throw overflow_exception();
}
}
// calculate rw_offset (only needed for textured lines)
segtextured = midtexture | toptexture | bottomtexture | (int)maskedtexture;
if (segtextured)
{
offsetangle = rw_normalangle-rw_angle1;
if (offsetangle > ANG180)
offsetangle = -offsetangle;
if (offsetangle > ANG90)
offsetangle = ANG90;
sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
rw_offset = FixedMul (hyp, sineval);
if (rw_normalangle-rw_angle1 < ANG180)
rw_offset = -rw_offset;
rw_offset += sidedef->textureoffset + curline->offset;
rw_centerangle = ANG90 + viewangle - rw_normalangle;
}
// if a floor / ceiling plane is on the wrong side
// of the view plane, it is definitely invisible
// and doesn't need to be marked.
if (frontsector->floorheight >= viewz)
{
// above view plane
markfloor = false;
}
if (frontsector->ceilingheight <= viewz
&& frontsector->ceilingpic != skyflatnum)
{
// below view plane
markceiling = false;
}
// calculate incremental stepping values for texture edges
worldtop >>= 4;
worldbottom >>= 4;
topstep = -FixedMul (rw_scalestep, worldtop);
topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
bottomstep = -FixedMul (rw_scalestep,worldbottom);
bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
if (backsector)
{
worldhigh >>= 4;
worldlow >>= 4;
if (worldhigh < worldtop)
{
pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
pixhighstep = -FixedMul (rw_scalestep,worldhigh);
}
if (worldlow > worldbottom)
{
pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
pixlowstep = -FixedMul (rw_scalestep,worldlow);
}
}
// andrewj: make sure floorplane/ceilingplane are not NULL (prevent a crash)
if (! floorplane) markfloor = false;
if (! ceilingplane) markceiling = false;
// render it
if (markceiling)
ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
if (markfloor)
floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
R_RenderSegLoop ();
// save sprite clipping info
if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture)
&& !ds_p->sprtopclip)
{
memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start));
ds_p->sprtopclip = lastopening - start;
lastopening += rw_stopx - start;
total_openings += (rw_stopx - start);
if (total_openings >= MAXOPENINGS)
throw overflow_exception();
}
if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture)
&& !ds_p->sprbottomclip)
{
memcpy (lastopening, floorclip+start, 2*(rw_stopx-start));
ds_p->sprbottomclip = lastopening - start;
lastopening += rw_stopx - start;
total_openings += (rw_stopx - start);
if (total_openings >= MAXOPENINGS)
throw overflow_exception();
}
if (maskedtexture && !(ds_p->silhouette&SIL_TOP))
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = INT_MIN;
}
if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM))
{
ds_p->silhouette |= SIL_BOTTOM;
ds_p->bsilheight = INT_MAX;
}
ds_p++;
}
} // namespace vpo