Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
117 results
Select Git revision
Show changes
Commits on Source (4)
...@@ -69,6 +69,7 @@ r_patch.c ...@@ -69,6 +69,7 @@ r_patch.c
r_patchrotation.c r_patchrotation.c
r_picformats.c r_picformats.c
r_portal.c r_portal.c
nodebuilder.c
screen.c screen.c
taglist.c taglist.c
v_video.c v_video.c
......
...@@ -49,6 +49,20 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f) ...@@ -49,6 +49,20 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f)
return (fixed_t)(f * FRACUNIT); return (fixed_t)(f * FRACUNIT);
} }
/*!
\brief convert fixed_t into a double
*/
FUNCMATH FUNCINLINE static ATTRINLINE double FixedToDouble(fixed_t x)
{
return x / (double)FRACUNIT;
}
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DoubleToFixed(double f)
{
return (fixed_t)(f * FRACUNIT);
}
// for backwards compat // for backwards compat
#define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT)) #define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT))
#define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT)) #define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT))
......
#include "doomdef.h"
#include "doomdata.h"
#include "doomtype.h"
#include "nodebuilder.h"
#include "m_bbox.h"
#include "r_defs.h"
#include "r_main.h"
#include "r_state.h"
#include "z_zone.h"
static NodeBuilder *builder = NULL;
static UINT32 HackSeg; // Seg to force to back of splitter
static UINT32 HackMate; // Seg to use in front of hack seg
static INT32 SegsStuffed; // I love eating segs.
static const int MaxSegs = 64;
static const int SplitCost = 8;
static const int AAPreference = 16;
static UINT32 VertexMap_Insert(FPrivVert *vert)
{
UINT32 pos = (UINT32)builder->NumVertices;
builder->NumVertices++;
builder->Vertices = Z_Realloc(builder->Vertices, (pos+1) * sizeof(FPrivVert), PU_LEVEL, NULL);
memcpy(&builder->Vertices[pos], vert, sizeof(FPrivVert));
return pos;
}
static UINT32 VertexMap_SelectExact(FPrivVert *vert)
{
FPrivVert *verts = builder->Vertices;
UINT32 stop = builder->NumVertices;
UINT32 i;
for (i = 0; i < stop; ++i)
{
if (verts[i].x == vert->x && verts[i].y == vert->y)
return i;
}
// Not present: add it!
return VertexMap_Insert(vert);
}
// Vertices within this distance of each other will be considered as the same vertex.
#define VERTEX_EPSILON 6 // This is a fixed_t value
static UINT32 VertexMap_SelectClose(FPrivVert *vert)
{
FPrivVert *verts = builder->Vertices;
UINT32 stop = builder->NumVertices;
UINT32 i;
for (i = 0; i < stop; ++i)
{
#if VERTEX_EPSILON <= 1
if (verts[i].x == vert->x && verts[i]->y == y)
#else
if (abs(verts[i].x - vert->x) < VERTEX_EPSILON &&
abs(verts[i].y - vert->y) < VERTEX_EPSILON)
#endif
return i;
}
// Not present: add it!
return VertexMap_Insert(vert);
}
void NodeBuilder_Set(NodeBuilder *nb)
{
builder = nb;
}
void NodeBuilder_Clear(void)
{
if (builder == NULL)
return;
Z_Free(builder->Nodes);
Z_Free(builder->Subsectors);
Z_Free(builder->SubsectorSets);
Z_Free(builder->Segs);
Z_Free(builder->Vertices);
Z_Free(builder->SegList);
Z_Free(builder->PlaneChecked);
Z_Free(builder->Planes);
builder->Nodes = NULL;
builder->Subsectors = NULL;
builder->SubsectorSets = NULL;
builder->Segs = NULL;
builder->Vertices = NULL;
builder->SegList = NULL;
builder->PlaneChecked = NULL;
builder->Planes = NULL;
builder->NumNodes = 0;
builder->NumSubsectors = 0;
builder->NumSubsectorSets = 0;
builder->NumSegs = 0;
builder->NumVertices = 0;
builder->SegListSize = 0;
builder->NumPlaneChecked = 0;
builder->NumPlanes = 0;
SegsStuffed = 0;
}
static INT32 PushSeg(FPrivSeg *seg)
{
INT32 pos = builder->NumSegs;
builder->NumSegs++;
builder->Segs = Z_Realloc(builder->Segs, (pos+1) * sizeof(FPrivSeg), PU_LEVEL, NULL);
memcpy(&builder->Segs[pos], seg, sizeof(FPrivSeg));
return pos;
}
static INT32 PushSegPtr(USegPtr *src)
{
USegPtr *ptr;
INT32 pos = builder->SegListSize;
builder->SegListSize++;
builder->SegList = Z_Realloc(builder->SegList, (pos+1) * sizeof(USegPtr), PU_LEVEL, NULL);
ptr = &builder->SegList[pos];
ptr->SegPtr = src->SegPtr;
ptr->SegNum = src->SegNum;
return pos;
}
static INT32 PushNode(node_t *node)
{
INT32 pos = builder->NumNodes;
builder->NumNodes++;
builder->Nodes = Z_Realloc(builder->Nodes, (pos+1) * sizeof(node_t), PU_LEVEL, NULL);
memcpy(&builder->Nodes[pos], node, sizeof(node_t));
return pos;
}
static INT32 PushSubsector(subsector_t *node)
{
INT32 pos = builder->NumSubsectors;
builder->NumSubsectors++;
builder->Subsectors = Z_Realloc(builder->Subsectors, (pos+1) * sizeof(subsector_t), PU_LEVEL, NULL);
memcpy(&builder->Subsectors[pos], node, sizeof(subsector_t));
return pos;
}
static INT32 PushSubsectorSet(UINT32 set)
{
INT32 pos = builder->NumSubsectorSets;
builder->NumSubsectorSets++;
builder->SubsectorSets = Z_Realloc(builder->SubsectorSets, (pos+1) * sizeof(UINT32), PU_LEVEL, NULL);
builder->SubsectorSets[pos] = set;
return pos;
}
static void AddSegToBBox(fixed_t bbox[4], const FPrivSeg *seg)
{
FPrivVert *v1 = &builder->Vertices[seg->v1];
FPrivVert *v2 = &builder->Vertices[seg->v2];
if (v1->x < bbox[BOXLEFT]) bbox[BOXLEFT] = v1->x;
if (v1->x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v1->x;
if (v1->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v1->y;
if (v1->y > bbox[BOXTOP]) bbox[BOXTOP] = v1->y;
if (v2->x < bbox[BOXLEFT]) bbox[BOXLEFT] = v2->x;
if (v2->x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v2->x;
if (v2->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v2->y;
if (v2->y > bbox[BOXTOP]) bbox[BOXTOP] = v2->y;
}
static fixed_t CalcSegLength(FPrivSeg *seg)
{
FPrivVert *v1 = &builder->Vertices[seg->v1];
FPrivVert *v2 = &builder->Vertices[seg->v2];
INT64 dx = (v2->x - v1->x)>>1;
INT64 dy = (v2->y - v1->y)>>1;
return FixedHypot(dx, dy)<<1;
}
static angle_t CalcSegAngle(FPrivSeg *seg)
{
FPrivVert *v1 = &builder->Vertices[seg->v1];
FPrivVert *v2 = &builder->Vertices[seg->v2];
return R_PointToAngle2(v1->x, v1->y, v2->x, v2->y);
}
static fixed_t CalcSegOffset(FPrivSeg *seg)
{
FPrivVert *v1 = &builder->Vertices[seg->v1];
INT64 dx = (seg->side ? seg->linev2x : seg->linev1x) - v1->x;
INT64 dy = (seg->side ? seg->linev2y : seg->linev1y) - v1->y;
return FixedHypot(dx>>1, dy>>1)<<1;
}
static void SetNodeFromSeg(node_t *node, const FPrivSeg *pseg)
{
if (pseg->planenum >= 0)
{
FSimpleLine *pline = &builder->Planes[pseg->planenum];
node->x = pline->x;
node->y = pline->y;
node->dx = pline->dx;
node->dy = pline->dy;
}
else
{
node->x = builder->Vertices[pseg->v1].x;
node->y = builder->Vertices[pseg->v1].y;
node->dx = builder->Vertices[pseg->v2].x - node->x;
node->dy = builder->Vertices[pseg->v2].y - node->y;
}
}
static UINT32 SplitSeg(UINT32 segnum, INT32 splitvert, INT32 v1InFront)
{
FPrivSeg *seg = &builder->Segs[segnum];
FPrivSeg newseg;
memcpy(&newseg, seg, sizeof(FPrivSeg));
if (v1InFront > 0)
{
newseg.v1 = splitvert;
seg->v2 = splitvert;
}
else
{
seg->v1 = splitvert;
newseg.v2 = splitvert;
}
return PushSeg(&newseg);
}
static double InterceptVector(const node_t *splitter, const FPrivSeg *seg)
{
double v2x = FixedToDouble(builder->Vertices[seg->v1].x);
double v2y = FixedToDouble(builder->Vertices[seg->v1].y);
double v2dx = FixedToDouble(builder->Vertices[seg->v2].x) - v2x;
double v2dy = FixedToDouble(builder->Vertices[seg->v2].y) - v2y;
double v1dx = FixedToDouble(splitter->dx);
double v1dy = FixedToDouble(splitter->dy);
double den = v1dy*v2dx - v1dx*v2dy;
double v1x, v1y;
double num, frac;
if (fpclassify(den) == FP_ZERO)
return 0.0; // parallel
v1x = FixedToDouble(splitter->x);
v1y = FixedToDouble(splitter->y);
num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
frac = num / den;
return frac;
}
#define FAR_ENOUGH 17179869184.f // 4<<32
const double SIDE_EPSILON = 6.5536;
static INT32 ClassifyLine(node_t *node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2])
{
double d_x1 = FixedToDouble(node->x);
double d_y1 = FixedToDouble(node->y);
double d_dx = FixedToDouble(node->dx);
double d_dy = FixedToDouble(node->dy);
double d_xv1 = FixedToDouble(v1->x);
double d_xv2 = FixedToDouble(v2->x);
double d_yv1 = FixedToDouble(v1->y);
double d_yv2 = FixedToDouble(v2->y);
double s_num1 = (d_y1 - d_yv1) * d_dx - (d_x1 - d_xv1) * d_dy;
double s_num2 = (d_y1 - d_yv2) * d_dx - (d_x1 - d_xv2) * d_dy;
INT32 nears = 0;
if (s_num1 <= -FAR_ENOUGH)
{
if (s_num2 <= -FAR_ENOUGH)
{
sidev[0] = sidev[1] = 1;
return 1;
}
else if (s_num2 >= FAR_ENOUGH)
{
sidev[0] = 1;
sidev[1] = -1;
return -1;
}
nears = 1;
}
else if (s_num1 >= FAR_ENOUGH)
{
if (s_num2 >= FAR_ENOUGH)
{
sidev[0] = sidev[1] = -1;
return 0;
}
else if (s_num2 <= -FAR_ENOUGH)
{
sidev[0] = -1;
sidev[1] = 1;
return -1;
}
nears = 1;
}
else
nears = 2 | (INT32)(fabs(s_num2) < FAR_ENOUGH);
if (nears)
{
double l = 1.0 / (d_dx*d_dx + d_dy*d_dy);
if (nears & 2)
{
double dist = s_num1 * s_num1 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON)
sidev[0] = 0;
else
sidev[0] = s_num1 > 0.0 ? -1 : 1;
}
else
sidev[0] = s_num1 > 0.0 ? -1 : 1;
if (nears & 1)
{
double dist = s_num2 * s_num2 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON)
sidev[1] = 0;
else
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
else
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
if ((sidev[0] | sidev[1]) == 0)
{
// seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back.
if (node->dx != 0)
{
if ((node->dx > 0 && v2->x > v1->x) || (node->dx < 0 && v2->x < v1->x))
return 0;
else
return 1;
}
else
{
if ((node->dy > 0 && v2->y > v1->y) || (node->dy < 0 && v2->y < v1->y))
return 0;
else
return 1;
}
}
else if (sidev[0] <= 0 && sidev[1] <= 0)
return 0;
else if (sidev[0] >= 0 && sidev[1] >= 0)
return 1;
return -1;
}
// Given a splitter (node), returns a score based on how "good" the resulting
// split in a set of segs is. Higher scores are better. -1 means this splitter
// splits something it shouldn't and will only be returned if honorNoSplit is
// true. A score of 0 means that the splitter does not split any of the segs
// in the set.
static INT32 Heuristic(node_t *node, UINT32 set, boolean honorNoSplit)
{
// Set the initial score above 0 so that near vertex anti-weighting is less likely to produce a negative score.
INT32 score = 1000000;
INT32 segsInSet = 0;
INT32 counts[2] = { 0, 0 };
INT32 realSegs[2] = { 0, 0 };
INT32 specialSegs[2] = { 0, 0 };
UINT32 i = set;
INT32 sidev[2] = {0, 0};
INT32 side;
boolean splitter = false;
double frac;
while (i != UINT32_MAX)
{
const FPrivSeg *test = &builder->Segs[i];
if (HackSeg == i)
side = 1;
else
side = ClassifyLine(node, &builder->Vertices[test->v1], &builder->Vertices[test->v2], sidev);
switch (side)
{
case 0: // Seg is on only one side of the partition
/* FALLTHRU */
case 1:
counts[side]++;
realSegs[side]++;
if (test->frontsector == test->backsector)
specialSegs[side]++;
// Add some weight to the score for unsplit lines
score += SplitCost;
break;
default: // Seg is cut by the partition
// Splitters that are too close to a vertex are bad.
frac = InterceptVector(node, test);
if (frac < 0.001 || frac > 0.999)
{
FPrivVert *v1 = &builder->Vertices[test->v1];
FPrivVert *v2 = &builder->Vertices[test->v2];
INT32 penalty;
double x = FixedToDouble(v1->x), y = FixedToDouble(v1->y);
x += frac * (FixedToDouble(v2->x) - x);
y += frac * (FixedToDouble(v2->y) - y);
if (fabs(x - FixedToDouble(v1->x)) < VERTEX_EPSILON+1 && fabs(y - FixedToDouble(v1->y)) < VERTEX_EPSILON+1)
return -1;
else if (fabs(x - FixedToDouble(v2->x)) < VERTEX_EPSILON+1 && fabs(y - FixedToDouble(v2->y)) < VERTEX_EPSILON+1)
return -1;
if (frac > 0.999)
frac = 1.0f - frac;
penalty = (INT32)(1 / frac);
score = max(score - penalty, 1);
}
counts[0]++;
counts[1]++;
realSegs[0]++;
realSegs[1]++;
if (test->frontsector == test->backsector)
{
specialSegs[0]++;
specialSegs[1]++;
}
break;
}
segsInSet++;
i = test->next;
}
// If this line is outside all the others, return a special score
if (counts[0] == 0 || counts[1] == 0)
return 0;
// A splitter must have at least one real seg on each side.
// Otherwise, a subsector could be left without any way to easily
// determine which sector it lies inside.
if (realSegs[0] == 0 || realSegs[1] == 0)
return -1;
// Try to avoid splits that leave only "special" segs, so that the generated
// subsectors have a better chance of choosing the correct sector. This situation
// is not neccesarily bad, just undesirable.
if (honorNoSplit && (specialSegs[0] == realSegs[0] || specialSegs[1] == realSegs[1]))
return -1;
// Doom maps are primarily axis-aligned lines, so it's usually a good
// idea to prefer axis-aligned splitters over diagonal ones. Doom originally
// had special-casing for orthogonal lines, so they performed better. ZDoom
// does not care about the line's direction, so this is merely a choice to
// try and improve the final tree.
if ((node->dx == 0) || (node->dy == 0))
{
// If we have to split a seg we would prefer to keep unsplit, give
// extra precedence to orthogonal lines so that the polyobjects
// outside the entrance to MAP06 in Hexen MAP02 display properly.
if (splitter)
score += segsInSet*8;
else
score += segsInSet/AAPreference;
}
score += (counts[0] + counts[1]) - abs(counts[0] - counts[1]);
return score;
}
static void SplitSegs(UINT32 set, node_t *node, UINT32 *outset0, UINT32 *outset1, UINT32 *count0, UINT32 *count1)
{
UINT32 _count0 = 0;
UINT32 _count1 = 0;
(*outset0) = UINT32_MAX;
(*outset1) = UINT32_MAX;
while (set != UINT32_MAX)
{
FPrivSeg *seg = &builder->Segs[set];
INT32 next = seg->next;
INT32 sidev[2], side;
if (HackSeg == set)
{
HackSeg = UINT32_MAX;
side = 1;
sidev[0] = sidev[1] = 0;
}
else
side = ClassifyLine(node, &builder->Vertices[seg->v1], &builder->Vertices[seg->v2], sidev);
switch (side)
{
case 0: // seg is entirely in front
seg->next = (*outset0);
(*outset0) = set;
_count0++;
break;
case 1: // seg is entirely in back
seg->next = (*outset1);
(*outset1) = set;
_count1++;
break;
default: // seg needs to be split
{
FPrivVert newvert;
UINT32 vertnum;
INT32 seg2;
double frac = InterceptVector(node, seg);
newvert.x = builder->Vertices[seg->v1].x;
newvert.y = builder->Vertices[seg->v1].y;
newvert.x += DoubleToFixed(frac * FixedToDouble(builder->Vertices[seg->v2].x - newvert.x));
newvert.y += DoubleToFixed(frac * FixedToDouble(builder->Vertices[seg->v2].y - newvert.y));
vertnum = VertexMap_SelectClose(&newvert);
seg2 = SplitSeg(set, vertnum, sidev[0]);
builder->Segs[seg2].next = (*outset0);
(*outset0) = seg2;
builder->Segs[set].next = (*outset1);
(*outset1) = set;
_count0++;
_count1++;
break;
}
}
set = next;
}
*count0 = _count0;
*count1 = _count1;
}
// Splitters are chosen to coincide with segs in the given set. To reduce the
// number of segs that need to be considered as splitters, segs are grouped into
// according to the planes that they lie on. Because one seg on the plane is just
// as good as any other seg on the plane at defining a split, only one seg from
// each unique plane needs to be considered as a splitter. A result of 0 means
// this set is a convex region. A result of -1 means that there were possible
// splitters, but they all split segs we want to keep intact.
static INT32 SelectSplitter(UINT32 set, node_t *node, INT32 step, boolean nosplit)
{
INT32 stepleft;
INT32 bestvalue;
UINT32 bestseg;
UINT32 seg;
boolean nosplitters = false;
bestvalue = 0;
bestseg = UINT32_MAX;
seg = set;
stepleft = 0;
memset(builder->PlaneChecked, 0, builder->NumPlaneChecked);
while (seg != UINT32_MAX)
{
FPrivSeg *pseg = &builder->Segs[seg];
if (--stepleft <= 0)
{
INT32 l = pseg->planenum >> 3;
INT32 r = 1 << (pseg->planenum & 7);
if (l < 0 || (builder->PlaneChecked[l] & r) == 0)
{
INT32 value;
if (l >= 0)
builder->PlaneChecked[l] |= r;
stepleft = step;
SetNodeFromSeg(node, pseg);
value = Heuristic(node, set, nosplit);
if (value > bestvalue)
{
bestvalue = value;
bestseg = seg;
}
else if (value < 0)
nosplitters = true;
}
}
seg = pseg->next;
}
// No lines split any others into two sets, so this is a convex region.
if (bestseg == UINT32_MAX)
return nosplitters ? -1 : 0;
SetNodeFromSeg(node, &builder->Segs[bestseg]);
return 1;
}
// Just create one plane per seg. Should be good enough for mini BSPs.
static void GroupSegPlanesSimple(void)
{
INT32 segcount = builder->NumSegs, i;
builder->NumPlanes = segcount;
builder->Planes = Z_Malloc(segcount * sizeof(FSimpleLine), PU_LEVEL, NULL);
for (i = 0; i < segcount; ++i)
{
FPrivSeg *seg = &builder->Segs[i];
FSimpleLine *pline = &builder->Planes[i];
seg->next = i+1;
seg->planenum = i;
seg->planefront = true;
pline->x = builder->Vertices[seg->v1].x;
pline->y = builder->Vertices[seg->v1].y;
pline->dx = builder->Vertices[seg->v2].x - builder->Vertices[seg->v1].x;
pline->dy = builder->Vertices[seg->v2].y - builder->Vertices[seg->v1].y;
}
builder->Segs[segcount-1].next = UINT32_MAX;
builder->NumPlaneChecked = (segcount + 7) / 8;
builder->PlaneChecked = Z_Calloc(builder->NumPlaneChecked * sizeof(UINT8), PU_LEVEL, NULL);
}
static UINT16 CreateSubsector(UINT32 set, fixed_t bbox[4])
{
INT32 ssnum, count;
M_ClearBox(bbox);
// We cannot actually create the subsector now because the node building
// process might split a seg in this subsector (because all partner segs
// must use the same pair of vertices), adding a new seg that hasn't been
// created yet. After all the nodes are built, then we can create the
// actual subsectors using the CreateSubsectorsForReal function below.
ssnum = PushSubsectorSet(set);
count = 0;
while (set != UINT32_MAX)
{
AddSegToBBox(bbox, &builder->Segs[set]);
set = builder->Segs[set].next;
count++;
}
SegsStuffed += count;
return ssnum;
}
static boolean ShoveSegBehind(UINT32 set, node_t *node, UINT32 seg, UINT32 mate)
{
SetNodeFromSeg(node, &builder->Segs[seg]);
HackSeg = seg;
HackMate = mate;
if (!builder->Segs[seg].planefront)
{
node->x += node->dx;
node->y += node->dy;
node->dx = -node->dx;
node->dy = -node->dy;
}
return Heuristic(node, set, false) > 0;
}
static boolean CheckSubsector(UINT32 set, node_t *node)
{
sector_t *sec = NULL;
UINT32 seg = set;
do
{
if (builder->Segs[seg].frontsector != sec
// Segs with the same front and back sectors are allowed to reside
// in a subsector with segs from a different sector, because the
// only effect they can have on the display is to place masked
// mid textures in the scene. Since minisegs only mark subsector
// boundaries, their sector information is unimportant.
//
// Update: Lines with the same front and back sectors *can* affect
// the display if their subsector does not match their front sector.
/*&& Segs[seg].frontsector != Segs[seg].backsector*/)
{
if (sec == NULL)
sec = builder->Segs[seg].frontsector;
else
break;
}
seg = builder->Segs[seg].next;
} while (seg != UINT32_MAX);
if (seg == UINT32_MAX)
return false;
// This is a very simple and cheap "fix" for subsectors with segs
// from multiple sectors, and it seems ZenNode does something
// similar. It is the only technique I could find that makes the
// "transparent water" in nb_bmtrk.wad work properly.
return ShoveSegBehind(set, node, seg, UINT32_MAX);
}
static UINT16 CreateNode(UINT32 set, UINT32 count, fixed_t bbox[4])
{
node_t node;
INT32 selstat;
INT32 skip = (INT32)(count / MaxSegs);
// When building GL nodes, count may not be an exact count of the number of segs
// in the set. That's okay, because we just use it to get a skip count, so an
// estimate is fine.
if ((selstat = SelectSplitter(set, &node, skip, true)) > 0 ||
(skip > 0 && (selstat = SelectSplitter(set, &node, 1, true)) > 0) ||
(selstat < 0 && (SelectSplitter(set, &node, skip, false) > 0 ||
(skip > 0 && SelectSplitter(set, &node, 1, false)))) ||
CheckSubsector(set, &node))
{
// Create a normal node
UINT32 set1, set2;
UINT32 count1, count2;
SplitSegs(set, &node, &set1, &set2, &count1, &count2);
node.children[0] = CreateNode(set1, count1, node.bbox[0]);
node.children[1] = CreateNode(set2, count2, node.bbox[1]);
bbox[BOXTOP] = max(node.bbox[0][BOXTOP], node.bbox[1][BOXTOP]);
bbox[BOXBOTTOM] = min(node.bbox[0][BOXBOTTOM], node.bbox[1][BOXBOTTOM]);
bbox[BOXLEFT] = min(node.bbox[0][BOXLEFT], node.bbox[1][BOXLEFT]);
bbox[BOXRIGHT] = max(node.bbox[0][BOXRIGHT], node.bbox[1][BOXRIGHT]);
return PushNode(&node);
}
else
return NF_SUBSECTOR | CreateSubsector(set, bbox);
}
static int SortSegs(const void *a, const void *b)
{
const FPrivSeg *x = ((const USegPtr *)a)->SegPtr;
const FPrivSeg *y = ((const USegPtr *)b)->SegPtr;
// Segs are grouped into two categories in this order:
//
// 1. Segs with different front and back sectors (or no back at all).
// 2. Segs with the same front and back sectors.
//
INT32 xtype, ytype;
if (x->frontsector == x->backsector)
xtype = 1;
else
xtype = 0;
if (y->frontsector == y->backsector)
ytype = 1;
else
ytype = 0;
if (xtype != ytype)
return xtype - ytype;
else
return x->linedef - y->linedef;
return 0;
}
static void CreateSubsectorsForReal(void)
{
subsector_t sub;
UINT32 i, j;
sub.sector = NULL;
sub.polynodes = NULL;
sub.polyList = NULL;
sub.BSP = NULL;
sub.numlines = sub.firstline = 0;
sub.validcount = 0;
for (i = 0; i < (UINT32)builder->NumSubsectorSets; ++i)
{
UINT32 set = builder->SubsectorSets[i];
UINT32 firstline = (UINT32)builder->SegListSize;
while (set != UINT32_MAX)
{
USegPtr ptr;
ptr.SegPtr = &builder->Segs[set];
PushSegPtr(&ptr);
set = ptr.SegPtr->next;
}
sub.numlines = (UINT32)(builder->SegListSize - firstline);
sub.firstline = (UINT16)firstline;
// Sort segs by linedef for special effects
qsort(&builder->SegList[firstline], sub.numlines, sizeof(USegPtr), SortSegs);
// Convert seg pointers into indices
for (j = firstline; j < (UINT32)builder->SegListSize; ++j)
builder->SegList[j].SegNum = (UINT32)(builder->SegList[j].SegPtr - &builder->Segs[0]);
PushSubsector(&sub);
}
}
static void BuildTree(void)
{
fixed_t bbox[4];
HackSeg = UINT32_MAX;
HackMate = UINT32_MAX;
CreateNode(0, builder->NumSegs, bbox);
CreateSubsectorsForReal();
}
void NodeBuilder_BuildMini(void)
{
GroupSegPlanesSimple();
BuildTree();
}
#define TryRealloc(oldsize, newsize, dest, type) \
size = (size_t)builder->newsize; \
if (size != bsp->oldsize) { \
bsp->oldsize = size; \
bsp->dest = Z_Realloc(bsp->dest, size * sizeof(type), PU_LEVEL, NULL); \
} \
size *= sizeof(type);
void NodeBuilder_ExtractMini(minibsp_t *bsp)
{
UINT32 i;
size_t size;
TryRealloc(numverts, NumVertices, verts, vertex_t);
for (i = 0; i < bsp->numverts; ++i)
{
vertex_t *vert = &bsp->verts[i];
vert->x = builder->Vertices[i].x;
vert->y = builder->Vertices[i].y;
vert->floorzset = vert->ceilingzset = 0;
vert->floorz = vert->ceilingz = 0;
}
TryRealloc(numnodes, NumNodes, nodes, node_t);
memcpy(bsp->nodes, builder->Nodes, size);
TryRealloc(numsubsectors, NumSubsectors, subsectors, subsector_t);
memcpy(bsp->subsectors, builder->Subsectors, size);
TryRealloc(numsegs, NumSegs, segs, seg_t);
for (i = 0; i < bsp->numsegs; ++i)
{
FPrivSeg *org = &builder->Segs[builder->SegList[i].SegNum];
seg_t *out = &bsp->segs[i];
out->v1 = &bsp->verts[org->v1];
out->v2 = &bsp->verts[org->v2];
out->backsector = org->backsector;
out->frontsector = org->frontsector;
out->linedef = lines + org->linedef;
out->sidedef = sides + org->sidedef;
out->side = org->side;
out->length = CalcSegLength(org);
out->angle = CalcSegAngle(org);
out->offset = CalcSegOffset(org);
out->polyseg = org->polynode ? org->polynode->poly : NULL;
out->polysector = org->polysector;
out->polybackside = org->backside;
out->glseg = false;
}
bsp->dirty = false;
}
#undef TryRealloc
void NodeBuilder_AddSegs(seg_t *seglist, size_t segcount)
{
size_t i;
for (i = 0; i < segcount; ++i)
{
FPrivSeg seg;
FPrivVert vert;
seg.next = UINT32_MAX;
seg.planefront = false;
seg.planenum = UINT32_MAX;
seg.frontsector = seglist[i].frontsector;
seg.backsector = seglist[i].backsector;
seg.polysector = NULL;
vert.x = seglist[i].v1->x;
vert.y = seglist[i].v1->y;
seg.v1 = VertexMap_SelectExact(&vert);
seg.linev1x = seglist[i].linedef->v1->x;
seg.linev1y = seglist[i].linedef->v1->y;
vert.x = seglist[i].v2->x;
vert.y = seglist[i].v2->y;
seg.v2 = VertexMap_SelectExact(&vert);
seg.linev2x = seglist[i].linedef->v1->x;
seg.linev2y = seglist[i].linedef->v1->y;
seg.linedef = (INT32)(seglist[i].linedef - lines);
seg.sidedef = seglist[i].sidedef != NULL ? (INT32)(seglist[i].sidedef - sides) : 0xFFFF;
seg.polynode = NULL;
seg.side = seglist[i].side;
seg.length = seglist[i].length;
seg.angle = seglist[i].angle;
seg.offset = seglist[i].offset;
PushSeg(&seg);
}
}
void NodeBuilder_AddPolySegs(polynode_t *node)
{
size_t i;
for (i = 0; i < node->numsegs; ++i)
{
FPrivSeg seg;
FPrivVert vert;
polyseg_t *polyseg = &node->segs[i];
seg_t *wall = polyseg->wall;
seg.next = UINT32_MAX;
seg.planefront = false;
seg.planenum = UINT32_MAX;
seg.frontsector = wall->polybackside ? wall->frontsector : wall->backsector;
seg.backsector = node->subsector->sector;
seg.polysector = node->subsector->sector;
seg.backside = wall->polybackside;
vert.x = DoubleToFixed(polyseg->v1.x);
vert.y = DoubleToFixed(polyseg->v1.y);
seg.v1 = VertexMap_SelectExact(&vert);
seg.linev1x = wall->linedef->v1->x;
seg.linev1y = wall->linedef->v1->y;
vert.x = DoubleToFixed(polyseg->v2.x);
vert.y = DoubleToFixed(polyseg->v2.y);
seg.v2 = VertexMap_SelectExact(&vert);
seg.linev2x = wall->linedef->v2->x;
seg.linev2y = wall->linedef->v2->y;
seg.linedef = (INT32)(wall->linedef - lines);
seg.sidedef = (INT32)(wall->sidedef - sides);
seg.polynode = node;
seg.side = wall->side;
seg.length = wall->length;
seg.angle = wall->angle;
seg.offset = wall->offset;
PushSeg(&seg);
}
}
#ifndef __NODEBUILDER_H__
#define __NODEBUILDER_H__
#include "doomdef.h"
#include "doomdata.h"
#include "doomtype.h"
#include "r_defs.h"
typedef struct FPrivSeg_s
{
INT32 v1, v2;
fixed_t linev1x, linev1y;
fixed_t linev2x, linev2y;
INT32 sidedef;
INT32 linedef;
INT32 side;
fixed_t length;
fixed_t offset;
angle_t angle;
sector_t *frontsector;
sector_t *backsector;
polynode_t *polynode;
sector_t *polysector;
boolean backside;
UINT32 next;
INT32 planenum;
boolean planefront;
} FPrivSeg;
typedef struct FPrivVert_s
{
fixed_t x, y;
} FPrivVert;
typedef struct FSimpleLine_s
{
fixed_t x, y, dx, dy;
} FSimpleLine;
typedef union USegPtr_s
{
UINT32 SegNum;
FPrivSeg *SegPtr;
} USegPtr;
typedef struct
{
node_t *Nodes;
subsector_t *Subsectors;
UINT32 *SubsectorSets;
FPrivSeg *Segs;
FPrivVert *Vertices;
USegPtr *SegList;
UINT8 *PlaneChecked;
FSimpleLine *Planes;
INT32 NumNodes;
INT32 NumSubsectors;
INT32 NumSubsectorSets;
INT32 NumSegs;
INT32 NumVertices;
INT32 SegListSize;
INT32 NumPlaneChecked;
INT32 NumPlanes;
} NodeBuilder;
void NodeBuilder_Set(NodeBuilder *nb);
void NodeBuilder_Clear(void);
void NodeBuilder_AddSegs(seg_t *seglist, size_t segcount);
void NodeBuilder_AddPolySegs(polynode_t *node);
void NodeBuilder_BuildMini(void);
void NodeBuilder_ExtractMini(minibsp_t *bsp);
#endif // __NODEBUILDER_H__
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
/// \brief Movable segs like in Hexen, but more flexible /// \brief Movable segs like in Hexen, but more flexible
/// due to application of dynamic binary space partitioning theory. /// due to application of dynamic binary space partitioning theory.
// haleyjd: temporary define
#include "z_zone.h" #include "z_zone.h"
#include "doomstat.h" #include "doomstat.h"
...@@ -359,7 +357,7 @@ static void Polyobj_findSegs(polyobj_t *po, seg_t *seg) ...@@ -359,7 +357,7 @@ static void Polyobj_findSegs(polyobj_t *po, seg_t *seg)
if (!(po->flags & POF_ONESIDE)) if (!(po->flags & POF_ONESIDE))
{ {
// Find backfacings // Find backfacings
for (s = 0; s < numsegs; s++) for (s = 0; s < numsegs; s++)
{ {
size_t r; size_t r;
...@@ -381,7 +379,7 @@ static void Polyobj_findSegs(polyobj_t *po, seg_t *seg) ...@@ -381,7 +379,7 @@ static void Polyobj_findSegs(polyobj_t *po, seg_t *seg)
if (r != po->segCount) if (r != po->segCount)
continue; continue;
segs[s].dontrenderme = true; segs[s].polybackside = true;
Polyobj_addSeg(po, &segs[s]); Polyobj_addSeg(po, &segs[s]);
} }
...@@ -451,7 +449,7 @@ newseg: ...@@ -451,7 +449,7 @@ newseg:
if (r != po->segCount) if (r != po->segCount)
continue; continue;
segs[q].dontrenderme = true; segs[q].polybackside = true;
Polyobj_addSeg(po, &segs[q]); Polyobj_addSeg(po, &segs[q]);
} }
} }
...@@ -644,6 +642,459 @@ static void Polyobj_removeFromSubsec(polyobj_t *po) ...@@ -644,6 +642,459 @@ static void Polyobj_removeFromSubsec(polyobj_t *po)
} }
} }
//==========================================================================
//
// TArray for segs
//
//==========================================================================
typedef struct segarray_s
{
size_t size;
size_t alloc;
polyseg_t *elements;
} segarray_t;
static void SegArray_Clear(segarray_t *array)
{
array->size = 0;
array->alloc = 0;
Z_Free(array->elements);
array->elements = NULL;
}
static void SegArray_Push(segarray_t *array, polyseg_t *element)
{
array->size++;
if (array->size >= array->alloc)
{
array->alloc = array->alloc ? array->alloc*2 : 8;
array->elements = Z_Realloc(array->elements, array->alloc * sizeof(polyseg_t), PU_STATIC, NULL);
}
memcpy(&array->elements[array->size - 1], element, sizeof(polyseg_t));
}
static polyseg_t *SegArray_Last(segarray_t *array)
{
return &(array->elements[array->size - 1]);
}
static void SegArray_Copy(segarray_t *list, polynode_t *node)
{
size_t i;
node->numsegs = list->size;
node->segs = Z_Malloc(node->numsegs * sizeof(polyseg_t), PU_LEVEL, NULL);
for (i = 0; i < list->size; i++)
{
polyseg_t *src = &list->elements[i];
polyseg_t *pseg = &node->segs[i];
pseg->v1.x = src->v1.x;
pseg->v1.y = src->v1.y;
pseg->v2.x = src->v2.x;
pseg->v2.y = src->v2.y;
pseg->wall = src->wall;
}
}
//==========================================================================
//
// NewPolyNode
//
//==========================================================================
static polynode_t *FreePolyNodes;
static polynode_t *NewPolyNode(void)
{
polynode_t *node;
if (FreePolyNodes != NULL)
{
node = FreePolyNodes;
FreePolyNodes = node->pnext;
}
else
node = Z_Malloc(sizeof(polynode_t), PU_LEVEL, NULL);
node->poly = NULL;
node->pnext = NULL;
node->pprev = NULL;
node->subsector = NULL;
node->snext = NULL;
return node;
}
//==========================================================================
//
// FreePolyNode
//
//==========================================================================
static void FreePolyNode(polynode_t *node)
{
Z_Free(node->segs);
node->segs = NULL;
node->numsegs = 0;
node->pnext = FreePolyNodes;
FreePolyNodes = node;
}
//==========================================================================
//
// ReleaseAllPolyNodes
//
//==========================================================================
static void ReleaseAllPolyNodes(void)
{
polynode_t *node, *next;
for (node = FreePolyNodes; node != NULL; node = next)
{
next = node->pnext;
Z_Free(node);
}
FreePolyNodes = NULL;
}
//==========================================================================
//
// ClearSubsectorLinks
//
//==========================================================================
void Polyobj_ClearSubsectorLinks(polyobj_t *polyobj)
{
while (polyobj->subsectorlinks != NULL)
{
polynode_t *link = polyobj->subsectorlinks;
polynode_t *next = link->snext;
subsector_t *sub = link->subsector;
if (link->pnext != NULL)
link->pnext->pprev = link->pprev;
if (link->pprev != NULL)
link->pprev->pnext = link->pnext;
else
sub->polynodes = link->pnext;
if (sub->BSP != NULL)
sub->BSP->dirty = true;
FreePolyNode(link);
polyobj->subsectorlinks = next;
}
polyobj->subsectorlinks = NULL;
}
void Polyobj_ClearAllSubsectorLinks(void)
{
INT32 i;
for (i = 0; i < numPolyObjects; i++)
{
if (PolyObjects[i].subsectorlinks == NULL)
Polyobj_ClearSubsectorLinks(&PolyObjects[i]);
}
ReleaseAllPolyNodes();
}
//==========================================================================
//
// GetIntersection
//
// adapted from P_InterceptVector
//
//==========================================================================
static boolean GetIntersection(polyseg_t *seg, node_t *bsp, polyobjvertex_t *v)
{
double frac;
double num;
double den;
double v2x = seg->v1.x;
double v2y = seg->v1.y;
double v2dx = seg->v2.x - v2x;
double v2dy = seg->v2.y - v2y;
double v1x = FixedToDouble(bsp->x);
double v1y = FixedToDouble(bsp->y);
double v1dx = FixedToDouble(bsp->dx);
double v1dy = FixedToDouble(bsp->dy);
den = v1dy*v2dx - v1dx*v2dy;
if (fpclassify(den) == FP_ZERO)
return false; // parallel
num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
frac = num / den;
if (frac < 0.0 || frac > 1.0)
return false;
v->x = v2x + frac * v2dx;
v->y = v2y + frac * v2dy;
return true;
}
//==========================================================================
//
// PartitionDistance
//
// Determine the distance of a vertex to a node's partition line.
//
//==========================================================================
static double PartitionDistance(polyobjvertex_t *vt, node_t *node)
{
double a = FixedToDouble(-node->dy) * (vt->x - FixedToDouble(node->x));
double b = FixedToDouble(node->dx) * (vt->y - FixedToDouble(node->y));
double len = FixedToDouble(node->length);
return fabs(a + b) / len;
}
//==========================================================================
//
// AddToBBox
//
//==========================================================================
static void AddToBBox(fixed_t child[4], fixed_t parent[4])
{
if (child[BOXTOP] > parent[BOXTOP])
parent[BOXTOP] = child[BOXTOP];
if (child[BOXBOTTOM] < parent[BOXBOTTOM])
parent[BOXBOTTOM] = child[BOXBOTTOM];
if (child[BOXLEFT] < parent[BOXLEFT])
parent[BOXLEFT] = child[BOXLEFT];
if (child[BOXRIGHT] > parent[BOXRIGHT])
parent[BOXRIGHT] = child[BOXRIGHT];
}
//==========================================================================
//
// AddPolyVertexToBBox
//
//==========================================================================
static void AddPolyVertexToBBox(polyobjvertex_t *v, fixed_t bbox[4])
{
fixed_t x = DoubleToFixed(v->x);
fixed_t y = DoubleToFixed(v->y);
if (x < bbox[BOXLEFT])
bbox[BOXLEFT] = x;
if (x > bbox[BOXRIGHT])
bbox[BOXRIGHT] = x;
if (y < bbox[BOXBOTTOM])
bbox[BOXBOTTOM] = y;
if (y > bbox[BOXTOP])
bbox[BOXTOP] = y;
}
//==========================================================================
//
// SplitPoly
//
//==========================================================================
static void SplitPoly(polynode_t *pnode, INT32 bspnum, fixed_t bbox[4])
{
static segarray_t lists[2];
static const double POLY_EPSILON = 0.3125;
size_t i;
if (!(bspnum & NF_SUBSECTOR)) // Keep going until found a subsector
{
node_t *bsp = &nodes[bspnum];
INT32 centerside = R_PointOnSide(pnode->poly->centerPt.x, pnode->poly->centerPt.y, bsp);
SegArray_Clear(&lists[0]);
SegArray_Clear(&lists[1]);
for (i = 0; i < pnode->numsegs; i++)
{
polyseg_t *seg = &pnode->segs[i];
// Parts of the following code were taken from Eternity and are
// being used with permission.
// get distance of vertices from partition line
// If the distance is too small, we may decide to
// change our idea of sidedness.
double dist_v1 = PartitionDistance(&seg->v1, bsp);
double dist_v2 = PartitionDistance(&seg->v2, bsp);
// If the distances are less than epsilon, consider the points as being
// on the same side as the polyobj origin. Why? People like to build
// polyobject doors flush with their door tracks. This breaks using the
// usual assumptions.
// Addition to Eternity code: We must also check any seg with only one
// vertex inside the epsilon threshold. If not, these lines will get split but
// adjoining ones with both vertices inside the threshold won't thus messing up
// the order in which they get drawn.
if(dist_v1 <= POLY_EPSILON)
{
if (dist_v2 <= POLY_EPSILON)
SegArray_Push(&lists[centerside], seg);
else
{
INT32 side = R_PointOnSide(DoubleToFixed(seg->v2.x), DoubleToFixed(seg->v2.y), bsp);
SegArray_Push(&lists[side], seg);
}
}
else if (dist_v2 <= POLY_EPSILON)
{
INT32 side = R_PointOnSide(DoubleToFixed(seg->v1.x), DoubleToFixed(seg->v1.y), bsp);
SegArray_Push(&lists[side], seg);
}
else
{
INT32 side1 = R_PointOnSide(DoubleToFixed(seg->v1.x), DoubleToFixed(seg->v1.y), bsp);
INT32 side2 = R_PointOnSide(DoubleToFixed(seg->v2.x), DoubleToFixed(seg->v2.y), bsp);
if (side1 != side2)
{
// if the partition line crosses this seg, we must split it.
polyobjvertex_t vert;
if (GetIntersection(seg, bsp, &vert))
{
SegArray_Push(&lists[0], seg);
SegArray_Push(&lists[1], seg);
SegArray_Last(&lists[side1])->v2.x = vert.x;
SegArray_Last(&lists[side1])->v2.y = vert.y;
SegArray_Last(&lists[side2])->v1.x = vert.x;
SegArray_Last(&lists[side2])->v1.y = vert.y;
}
else
{
// should never happen
SegArray_Push(&lists[side1], seg);
}
}
else
{
// both points on the same side.
SegArray_Push(&lists[side1], seg);
}
}
}
if (lists[1].size == 0)
{
SplitPoly(pnode, bsp->children[0], bsp->bbox[0]);
AddToBBox(bsp->bbox[0], bbox);
}
else if (lists[0].size == 0)
{
SplitPoly(pnode, bsp->children[1], bsp->bbox[1]);
AddToBBox(bsp->bbox[1], bbox);
}
else
{
// create the new node
polynode_t *newnode = NewPolyNode();
newnode->poly = pnode->poly;
SegArray_Copy(&lists[1], newnode);
// set segs for original node
SegArray_Copy(&lists[0], pnode);
// recurse back side
SplitPoly(newnode, bsp->children[1], bsp->bbox[1]);
// recurse front side
SplitPoly(pnode, bsp->children[0], bsp->bbox[0]);
AddToBBox(bsp->bbox[0], bbox);
AddToBBox(bsp->bbox[1], bbox);
}
}
else
{
// we reached a subsector so we can link the node with this subsector
subsector_t *sub = &subsectors[bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR];
fixed_t subbbox[4] = { INT32_MIN, INT32_MAX, INT32_MAX, INT32_MIN };
// Link node to subsector
pnode->pnext = sub->polynodes;
if (pnode->pnext != NULL)
pnode->pnext->pprev = pnode;
pnode->pprev = NULL;
sub->polynodes = pnode;
// link node to polyobject
pnode->snext = pnode->poly->subsectorlinks;
pnode->poly->subsectorlinks = pnode;
pnode->subsector = sub;
// calculate bounding box for this polynode
for (i = 0; i < pnode->numsegs; ++i)
{
AddPolyVertexToBBox(&pnode->segs[i].v1, subbbox);
AddPolyVertexToBBox(&pnode->segs[i].v2, subbbox);
}
// Potentially expand the parent node's bounding box to contain these bits of polyobject.
AddToBBox(subbbox, bbox);
}
}
static void Polyobj_CreateSubsectorLinks(polyobj_t *polyobj)
{
polynode_t *node = NewPolyNode();
size_t i;
// Even though we don't care about it, we need to initialize this
// bounding box to something so that Valgrind won't complain about it
// when SplitPoly modifies it.
fixed_t dummybbox[4] = { 0, 0, 0, 0 };
node->poly = polyobj;
node->numsegs = polyobj->segCount;
node->segs = Z_Malloc(node->numsegs * sizeof(polyseg_t), PU_LEVEL, NULL);
for (i = 0; i < node->numsegs; i++)
{
polyseg_t *seg = &node->segs[i];
seg_t *line = polyobj->segs[i];
seg->v1.x = FixedToDouble(line->v1->x);
seg->v1.y = FixedToDouble(line->v1->y);
seg->v2.x = FixedToDouble(line->v2->x);
seg->v2.y = FixedToDouble(line->v2->y);
seg->wall = line;
}
SplitPoly(node, (INT32)numnodes - 1, dummybbox);
ReleaseAllPolyNodes();
}
void Polyobj_LinkToSubsectors(void)
{
INT32 i;
for (i = 0; i < numPolyObjects; i++)
{
if (PolyObjects[i].subsectorlinks == NULL)
Polyobj_CreateSubsectorLinks(&PolyObjects[i]);
}
}
// Blockmap Functions // Blockmap Functions
// Retrieves a polymaplink object from the free list or creates a new one. // Retrieves a polymaplink object from the free list or creates a new one.
...@@ -708,7 +1159,7 @@ static void Polyobj_linkToBlockmap(polyobj_t *po) ...@@ -708,7 +1159,7 @@ static void Polyobj_linkToBlockmap(polyobj_t *po)
{ {
if (!(x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)) if (!(x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight))
{ {
polymaplink_t *l = Polyobj_getLink(); polymaplink_t *l = Polyobj_getLink();
l->po = po; l->po = po;
...@@ -1028,6 +1479,7 @@ boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs) ...@@ -1028,6 +1479,7 @@ boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs)
Polyobj_removeFromSubsec(po); // unlink it from its subsector Polyobj_removeFromSubsec(po); // unlink it from its subsector
Polyobj_linkToBlockmap(po); // relink to blockmap Polyobj_linkToBlockmap(po); // relink to blockmap
Polyobj_attachToSubsec(po); // relink to subsector Polyobj_attachToSubsec(po); // relink to subsector
Polyobj_ClearSubsectorLinks(po);// clear its subsector links
} }
return !(hitflags & 2); return !(hitflags & 2);
...@@ -1227,9 +1679,10 @@ boolean Polyobj_rotate(polyobj_t *po, angle_t delta, boolean turnplayers, boolea ...@@ -1227,9 +1679,10 @@ boolean Polyobj_rotate(polyobj_t *po, angle_t delta, boolean turnplayers, boolea
po->angle += delta; po->angle += delta;
Polyobj_removeFromBlockmap(po); // unlink it from the blockmap Polyobj_removeFromBlockmap(po); // unlink it from the blockmap
Polyobj_removeFromSubsec(po); // remove from subsector Polyobj_removeFromSubsec(po); // unlink it from its subsector
Polyobj_linkToBlockmap(po); // relink to blockmap Polyobj_linkToBlockmap(po); // relink to blockmap
Polyobj_attachToSubsec(po); // relink to subsector Polyobj_attachToSubsec(po); // relink to subsector
Polyobj_ClearSubsectorLinks(po);// clear its subsector links
} }
return !(hitflags & 2); return !(hitflags & 2);
...@@ -2483,6 +2936,7 @@ void T_PolyObjFlag(polymove_t *th) ...@@ -2483,6 +2936,7 @@ void T_PolyObjFlag(polymove_t *th)
Polyobj_removeFromSubsec(po); // unlink it from its subsector Polyobj_removeFromSubsec(po); // unlink it from its subsector
Polyobj_linkToBlockmap(po); // relink to blockmap Polyobj_linkToBlockmap(po); // relink to blockmap
Polyobj_attachToSubsec(po); // relink to subsector Polyobj_attachToSubsec(po); // relink to subsector
Polyobj_ClearSubsectorLinks(po);// clear its subsector links
} }
boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata) boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata)
......
...@@ -66,6 +66,8 @@ typedef enum ...@@ -66,6 +66,8 @@ typedef enum
// Polyobject Structure // Polyobject Structure
// //
struct polynode_s;
typedef struct polyobj_s typedef struct polyobj_s
{ {
mdllistitem_t link; // for subsector links; must be first mdllistitem_t link; // for subsector links; must be first
...@@ -76,8 +78,8 @@ typedef struct polyobj_s ...@@ -76,8 +78,8 @@ typedef struct polyobj_s
INT32 parent; // numeric id of parent polyobject INT32 parent; // numeric id of parent polyobject
size_t segCount; // number of segs in polyobject size_t segCount; // number of segs in polyobject
size_t numSegsAlloc; // number of segs allocated size_t numSegsAlloc; // number of segs allocated
struct seg_s **segs; // the segs, a reallocating array. struct seg_s **segs; // the segs, a reallocating array.
size_t numVertices; // number of vertices (generally == segCount) size_t numVertices; // number of vertices (generally == segCount)
...@@ -86,18 +88,19 @@ typedef struct polyobj_s ...@@ -86,18 +88,19 @@ typedef struct polyobj_s
vertex_t *tmpVerts; // temporary vertex backups for rotation vertex_t *tmpVerts; // temporary vertex backups for rotation
vertex_t **vertices; // vertices this polyobject must move vertex_t **vertices; // vertices this polyobject must move
size_t numLines; // number of linedefs (generally <= segCount) size_t numLines; // number of linedefs (generally <= segCount)
size_t numLinesAlloc; // number of linedefs allocated size_t numLinesAlloc; // number of linedefs allocated
struct line_s **lines; // linedefs this polyobject must move struct line_s **lines; // linedefs this polyobject must move
degenmobj_t spawnSpot; // location of spawn spot degenmobj_t spawnSpot; // location of spawn spot
vertex_t centerPt; // center point vertex_t centerPt; // center point
fixed_t zdist; // viewz distance for sorting fixed_t zdist; // viewz distance for sorting
angle_t angle; // for rotation angle_t angle; // for rotation
UINT8 attached; // if true, is attached to a subsector UINT8 attached; // if true, is attached to a subsector
struct polynode_s *subsectorlinks;
fixed_t blockbox[4]; // bounding box for clipping fixed_t blockbox[4]; // bounding box for clipping
UINT8 linked; // is linked to blockmap UINT8 linked; // is linked to blockmap
size_t validcount; // for clipping: prevents multiple checks size_t validcount; // for clipping: prevents multiple checks
INT32 damage; // damage to inflict on stuck things INT32 damage; // damage to inflict on stuck things
fixed_t thrust; // amount of thrust to put on blocking objects fixed_t thrust; // amount of thrust to put on blocking objects
...@@ -105,17 +108,41 @@ typedef struct polyobj_s ...@@ -105,17 +108,41 @@ typedef struct polyobj_s
thinker_t *thinker; // pointer to a thinker affecting this polyobj thinker_t *thinker; // pointer to a thinker affecting this polyobj
UINT8 isBad; // a bad polyobject: should not be rendered/manipulated UINT8 isBad; // a bad polyobject: should not be rendered/manipulated
INT32 translucency; // index to translucency tables INT32 translucency; // index to translucency tables
INT16 triggertag; // Tag of linedef executor to trigger on touch INT16 triggertag; // Tag of linedef executor to trigger on touch
struct visplane_s *visplane; // polyobject's visplane, for ease of putting into the list later
// these are saved for netgames, so do not let Lua touch these! // these are saved for netgames, so do not let Lua touch these!
INT32 spawnflags; // Flags the polyobject originally spawned with INT32 spawnflags; // Flags the polyobject originally spawned with
INT32 spawntrans; // Translucency the polyobject originally spawned with INT32 spawntrans; // Translucency the polyobject originally spawned with
} polyobj_t; } polyobj_t;
typedef struct polyobjvertex_s
{
double x, y;
} polyobjvertex_t;
typedef struct polyseg_s
{
polyobjvertex_t v1;
polyobjvertex_t v2;
struct seg_s *wall;
} polyseg_t;
typedef struct polynode_s
{
polyobj_t *poly; // owning polyobject
struct polynode_s *pnext; // next polyobj in list
struct polynode_s *pprev; // previous polyobj
struct subsector_s *subsector; // containing subsector
struct polynode_s *snext; // next subsector
polyseg_t *segs; // segs for this node
size_t numsegs;
} polynode_t;
// //
// Polyobject Blockmap Link Structure // Polyobject Blockmap Link Structure
// //
...@@ -372,10 +399,14 @@ typedef struct polyfadedata_s ...@@ -372,10 +399,14 @@ typedef struct polyfadedata_s
// Functions // Functions
// //
void Polyobj_InitLevel(void);
void Polyobj_LinkToSubsectors(void);
void Polyobj_ClearSubsectorLinks(polyobj_t *polyobj);
void Polyobj_ClearAllSubsectorLinks(void);
boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs); boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs);
boolean Polyobj_rotate(polyobj_t *po, angle_t delta, boolean turnplayers, boolean turnothers, boolean checkmobjs); boolean Polyobj_rotate(polyobj_t *po, angle_t delta, boolean turnplayers, boolean turnothers, boolean checkmobjs);
polyobj_t *Polyobj_GetForNum(INT32 id); polyobj_t *Polyobj_GetForNum(INT32 id);
void Polyobj_InitLevel(void);
void Polyobj_MoveOnLoad(polyobj_t *po, angle_t angle, fixed_t x, fixed_t y); void Polyobj_MoveOnLoad(polyobj_t *po, angle_t angle, fixed_t x, fixed_t y);
boolean P_PointInsidePolyobj(polyobj_t *po, fixed_t x, fixed_t y); boolean P_PointInsidePolyobj(polyobj_t *po, fixed_t x, fixed_t y);
boolean P_MobjTouchingPolyobj(polyobj_t *po, mobj_t *mo); boolean P_MobjTouchingPolyobj(polyobj_t *po, mobj_t *mo);
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include "m_argv.h" #include "m_argv.h"
#include "p_polyobj.h" #include "p_polyobj.h"
#include "nodebuilder.h"
#include "v_video.h" #include "v_video.h"
...@@ -3058,6 +3059,7 @@ static void P_LoadNodes(UINT8 *data) ...@@ -3058,6 +3059,7 @@ static void P_LoadNodes(UINT8 *data)
no->y = SHORT(mn->y)<<FRACBITS; no->y = SHORT(mn->y)<<FRACBITS;
no->dx = SHORT(mn->dx)<<FRACBITS; no->dx = SHORT(mn->dx)<<FRACBITS;
no->dy = SHORT(mn->dy)<<FRACBITS; no->dy = SHORT(mn->dy)<<FRACBITS;
no->length = FixedHypot(no->dx>>1, no->dy>>1)<<1;
for (j = 0; j < 2; j++) for (j = 0; j < 2; j++)
{ {
no->children[j] = SHORT(mn->children[j]); no->children[j] = SHORT(mn->children[j]);
...@@ -3120,10 +3122,9 @@ static void P_InitializeSeg(seg_t *seg) ...@@ -3120,10 +3122,9 @@ static void P_InitializeSeg(seg_t *seg)
seg->lightmaps = NULL; // list of static lightmap for this seg seg->lightmaps = NULL; // list of static lightmap for this seg
#endif #endif
seg->numlights = 0;
seg->rlights = NULL;
seg->polyseg = NULL; seg->polyseg = NULL;
seg->dontrenderme = false; seg->polysector = NULL;
seg->polybackside = false;
} }
static void P_LoadSegs(UINT8 *data) static void P_LoadSegs(UINT8 *data)
...@@ -3387,6 +3388,7 @@ static void P_LoadExtendedNodes(UINT8 **data, nodetype_t nodetype) ...@@ -3387,6 +3388,7 @@ static void P_LoadExtendedNodes(UINT8 **data, nodetype_t nodetype)
mn->y = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS); mn->y = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS);
mn->dx = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS); mn->dx = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS);
mn->dy = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS); mn->dy = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS);
mn->length = FixedHypot(mn->dx>>1, mn->dy>>1)<<1;
// Bounding boxes // Bounding boxes
for (j = 0; j < 2; j++) for (j = 0; j < 2; j++)
...@@ -7692,6 +7694,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) ...@@ -7692,6 +7694,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
Z_Free(ss->attachedsolid); Z_Free(ss->attachedsolid);
} }
Polyobj_ClearAllSubsectorLinks();
NodeBuilder_Clear();
// Clear pointers that would be left dangling by the purge // Clear pointers that would be left dangling by the purge
R_FlushTranslationColormapCache(); R_FlushTranslationColormapCache();
......
...@@ -23,11 +23,16 @@ ...@@ -23,11 +23,16 @@
#include "z_zone.h" // Check R_Prep3DFloors #include "z_zone.h" // Check R_Prep3DFloors
#include "taglist.h" #include "taglist.h"
#include "nodebuilder.h"
seg_t *curline; seg_t *curline;
side_t *sidedef; side_t *sidedef;
line_t *linedef; line_t *linedef;
sector_t *frontsector; sector_t *frontsector;
sector_t *backsector; sector_t *backsector;
polynode_t *polynodes;
static minibsp_t *minibsp = NULL;
// very ugly realloc() of drawsegs at run-time, I upped it to 512 // very ugly realloc() of drawsegs at run-time, I upped it to 512
// instead of 256.. and someone managed to send me a level with // instead of 256.. and someone managed to send me a level with
...@@ -388,23 +393,17 @@ boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back) ...@@ -388,23 +393,17 @@ boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back)
// //
static void R_AddLine(seg_t *line) static void R_AddLine(seg_t *line)
{ {
INT32 x1, x2;
angle_t angle1, angle2, span, tspan;
static sector_t tempsec; static sector_t tempsec;
boolean bothceilingssky = false, bothfloorssky = false; boolean bothceilingssky = false, bothfloorssky = false;
portalline = false; angle_t angle1 = R_PointToAngle64(line->v1->x, line->v1->y);
angle_t angle2 = R_PointToAngle64(line->v2->x, line->v2->y);
if (line->polyseg && !(line->polyseg->flags & POF_RENDERSIDES))
return;
// big room fix
angle1 = R_PointToAngle64(line->v1->x, line->v1->y);
angle2 = R_PointToAngle64(line->v2->x, line->v2->y);
curline = line; curline = line;
portalline = false;
// Clip to view edges. // Clip to view edges.
span = angle1 - angle2; angle_t span = angle1 - angle2;
// Back side? i.e. backface culling? // Back side? i.e. backface culling?
if (span >= ANGLE_180) if (span >= ANGLE_180)
...@@ -415,7 +414,7 @@ static void R_AddLine(seg_t *line) ...@@ -415,7 +414,7 @@ static void R_AddLine(seg_t *line)
angle1 -= viewangle; angle1 -= viewangle;
angle2 -= viewangle; angle2 -= viewangle;
tspan = angle1 + clipangle; angle_t tspan = angle1 + clipangle;
if (tspan > doubleclipangle) if (tspan > doubleclipangle)
{ {
tspan -= doubleclipangle; tspan -= doubleclipangle;
...@@ -441,8 +440,9 @@ static void R_AddLine(seg_t *line) ...@@ -441,8 +440,9 @@ static void R_AddLine(seg_t *line)
// The seg is in the view range, but not necessarily visible. // The seg is in the view range, but not necessarily visible.
angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT; angle1 = (angle1+ANGLE_90)>>ANGLETOFINESHIFT;
angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT; angle2 = (angle2+ANGLE_90)>>ANGLETOFINESHIFT;
x1 = viewangletox[angle1];
x2 = viewangletox[angle2]; INT32 x1 = viewangletox[angle1];
INT32 x2 = viewangletox[angle2];
// Does not cross a pixel? // Does not cross a pixel?
if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness if (x1 >= x2) // killough 1/31/98 -- change == to >= for robustness
...@@ -655,6 +655,70 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) ...@@ -655,6 +655,70 @@ static boolean R_CheckBBox(const fixed_t *bspcoord)
return true; return true;
} }
static NodeBuilder *PolyNodeBuilder = NULL;
void R_BuildPolyBSP(subsector_t *sub)
{
polynode_t *pn;
UINT32 i;
if (PolyNodeBuilder == NULL)
PolyNodeBuilder = Z_Calloc(sizeof(NodeBuilder), PU_STATIC, NULL);
NodeBuilder_Set(PolyNodeBuilder);
NodeBuilder_Clear();
// Feed segs to the nodebuilder and build the nodes.
NodeBuilder_AddSegs(&segs[sub->firstline], sub->numlines);
for (pn = sub->polynodes; pn != NULL; pn = pn->pnext)
{
NodeBuilder_AddPolySegs(pn);
ps_numpolyobjects.value.i++; // for render stats
}
NodeBuilder_BuildMini();
if (sub->BSP == NULL)
sub->BSP = Z_Calloc(sizeof(minibsp_t), PU_LEVEL, NULL);
NodeBuilder_ExtractMini(sub->BSP);
for (i = 0; i < sub->BSP->numsubsectors; ++i)
{
subsector_t *minisub = &sub->BSP->subsectors[i];
seg_t *line = &sub->BSP->segs[minisub->firstline];
INT32 count = minisub->numlines;
while (count--)
{
if (line->polyseg)
{
minisub->polynodes = sub->polynodes;
break;
}
line++;
}
minisub->sector = sub->sector;
}
}
static void R_AddPolyobjs(subsector_t *sub)
{
INT32 nodecount;
if (sub->BSP == NULL || sub->BSP->dirty)
R_BuildPolyBSP(sub);
minibsp = sub->BSP;
nodecount = minibsp->numnodes - 1;
if (nodecount == 0)
R_Subsector(0);
else
R_RenderMiniBSPNode(nodecount);
minibsp = NULL;
}
size_t numpolys; // number of polyobjects in current subsector size_t numpolys; // number of polyobjects in current subsector
size_t num_po_ptrs; // number of polyobject pointers allocated size_t num_po_ptrs; // number of polyobject pointers allocated
polyobj_t **po_ptrs; // temp ptr array to sort polyobject pointers polyobj_t **po_ptrs; // temp ptr array to sort polyobject pointers
...@@ -719,109 +783,6 @@ void R_SortPolyObjects(subsector_t *sub) ...@@ -719,109 +783,6 @@ void R_SortPolyObjects(subsector_t *sub)
} }
} }
//
// R_PolysegCompare
//
// Callback for qsort to sort the segs of a polyobject. Returns such that the
// closer one is sorted first. I sure hope this doesn't break anything. -Red
//
static int R_PolysegCompare(const void *p1, const void *p2)
{
const seg_t *seg1 = *(const seg_t * const *)p1;
const seg_t *seg2 = *(const seg_t * const *)p2;
fixed_t dist1v1, dist1v2, dist2v1, dist2v2;
// TODO might be a better way to get distance?
#define pdist(x, y) (FixedMul(R_PointToDist(x, y), FINECOSINE((R_PointToAngle(x, y)-viewangle)>>ANGLETOFINESHIFT))+0xFFFFFFF)
#define vxdist(v) pdist(v->x, v->y)
dist1v1 = vxdist(seg1->v1);
dist1v2 = vxdist(seg1->v2);
dist2v1 = vxdist(seg2->v1);
dist2v2 = vxdist(seg2->v2);
if (min(dist1v1, dist1v2) != min(dist2v1, dist2v2))
return min(dist1v1, dist1v2) - min(dist2v1, dist2v2);
{ // That didn't work, so now let's try this.......
fixed_t delta1, delta2, x1, y1, x2, y2;
vertex_t *near1, *near2, *far1, *far2; // wherever you are~
delta1 = R_PointToDist2(seg1->v1->x, seg1->v1->y, seg1->v2->x, seg1->v2->y);
delta2 = R_PointToDist2(seg2->v1->x, seg2->v1->y, seg2->v2->x, seg2->v2->y);
delta1 = FixedDiv(128<<FRACBITS, delta1);
delta2 = FixedDiv(128<<FRACBITS, delta2);
if (dist1v1 < dist1v2)
{
near1 = seg1->v1;
far1 = seg1->v2;
}
else
{
near1 = seg1->v2;
far1 = seg1->v1;
}
if (dist2v1 < dist2v2)
{
near2 = seg2->v1;
far2 = seg2->v2;
}
else
{
near2 = seg2->v2;
far2 = seg2->v1;
}
x1 = near1->x + FixedMul(far1->x-near1->x, delta1);
y1 = near1->y + FixedMul(far1->y-near1->y, delta1);
x2 = near2->x + FixedMul(far2->x-near2->x, delta2);
y2 = near2->y + FixedMul(far2->y-near2->y, delta2);
return pdist(x1, y1)-pdist(x2, y2);
}
#undef vxdist
#undef pdist
}
//
// R_AddPolyObjects
//
// haleyjd 02/19/06
// Adds all segs in all polyobjects in the given subsector.
//
static void R_AddPolyObjects(subsector_t *sub)
{
polyobj_t *po = sub->polyList;
size_t i, j;
numpolys = 0;
// count polyobjects
while (po)
{
++numpolys;
po = (polyobj_t *)(po->link.next);
}
// for render stats
ps_numpolyobjects.value.i += numpolys;
// sort polyobjects
R_SortPolyObjects(sub);
// render polyobjects
for (i = 0; i < numpolys; ++i)
{
qsort(po_ptrs[i]->segs, po_ptrs[i]->segCount, sizeof(seg_t *), R_PolysegCompare);
for (j = 0; j < po_ptrs[i]->segCount; ++j)
R_AddLine(po_ptrs[i]->segs[j]);
}
}
// //
// R_Subsector // R_Subsector
// Determine floor/ceiling planes. // Determine floor/ceiling planes.
...@@ -831,7 +792,7 @@ static void R_AddPolyObjects(subsector_t *sub) ...@@ -831,7 +792,7 @@ static void R_AddPolyObjects(subsector_t *sub)
drawseg_t *firstseg; drawseg_t *firstseg;
static void R_Subsector(size_t num) void R_Subsector(size_t num)
{ {
INT32 count, floorlightlevel, ceilinglightlevel, light; INT32 count, floorlightlevel, ceilinglightlevel, light;
seg_t *line; seg_t *line;
...@@ -842,19 +803,45 @@ static void R_Subsector(size_t num) ...@@ -842,19 +803,45 @@ static void R_Subsector(size_t num)
fixed_t floorcenterz, ceilingcenterz; fixed_t floorcenterz, ceilingcenterz;
ffloor_t *rover; ffloor_t *rover;
if (minibsp)
{
size_t numsubsecs = minibsp->numsubsectors;
if (num >= numsubsecs)
{
#ifdef RANGECHECK #ifdef RANGECHECK
if (num >= numsubsectors) I_Error("R_Subsector: ss %s with numss = %s (miniBSP)\n", sizeu1(num), sizeu2(numsubsecs));
I_Error("R_Subsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
#endif #endif
return;
}
// subsectors added at run-time sub = &minibsp->subsectors[num];
if (num >= numsubsectors) line = &minibsp->segs[sub->firstline];
return; }
else
{
size_t numsubsecs = numsubsectors;
if (num >= numsubsecs) // subsectors added at run-time
{
#ifdef RANGECHECK
I_Error("R_Subsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsecs));
#endif
return;
}
sub = &subsectors[num];
// Render the minibsp instead
if (sub->polynodes)
{
R_AddPolyobjs(sub);
return;
}
line = &segs[sub->firstline];
}
sub = &subsectors[num];
frontsector = sub->sector; frontsector = sub->sector;
count = sub->numlines; count = sub->numlines;
line = &segs[sub->firstline];
// Deep water/fake ceiling effect. // Deep water/fake ceiling effect.
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, &ceilinglightlevel, false); frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, &ceilinglightlevel, false);
...@@ -1008,23 +995,19 @@ static void R_Subsector(size_t num) ...@@ -1008,23 +995,19 @@ static void R_Subsector(size_t num)
} }
// Polyobjects have planes, too! // Polyobjects have planes, too!
if (sub->polyList) polynodes = sub->polynodes;
if (minibsp && polynodes)
{ {
polyobj_t *po = sub->polyList; polynode_t *pn = polynodes;
sector_t *polysec;
while (po) for (; pn != NULL && numffloors < MAXFFLOORS; pn = pn->pnext)
{ {
if (numffloors >= MAXFFLOORS) polyobj_t *po = pn->poly;
break;
if (!(po->flags & POF_RENDERPLANES)) // Don't draw planes if (!(po->flags & POF_RENDERPLANES)) // Don't draw planes
{
po = (polyobj_t *)(po->link.next);
continue; continue;
}
polysec = po->lines[0]->backsector; sector_t *polysec = po->lines[0]->backsector;
ffloor[numffloors].plane = NULL; ffloor[numffloors].plane = NULL;
if (polysec->floorheight <= ceilingcenterz if (polysec->floorheight <= ceilingcenterz
...@@ -1036,13 +1019,11 @@ static void R_Subsector(size_t num) ...@@ -1036,13 +1019,11 @@ static void R_Subsector(size_t num)
(light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floor_xoffs, polysec->floor_yoffs, (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floor_xoffs, polysec->floor_yoffs,
polysec->floorpic_angle-po->angle, polysec->floorpic_angle-po->angle,
(light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po, (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po,
NULL); // will ffloors be slopable eventually? NULL); // will polyobjects be slopable eventually?
ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].height = polysec->floorheight;
ffloor[numffloors].polyobj = po; ffloor[numffloors].polyobj = po;
ffloor[numffloors].slope = NULL; ffloor[numffloors].slope = NULL;
//ffloor[numffloors].ffloor = rover;
po->visplane = ffloor[numffloors].plane;
numffloors++; numffloors++;
} }
...@@ -1059,48 +1040,41 @@ static void R_Subsector(size_t num) ...@@ -1059,48 +1040,41 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
(light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle-po->angle, (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle-po->angle,
(light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po, (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po,
NULL); // will ffloors be slopable eventually? NULL); // will polyobjects be slopable eventually?
ffloor[numffloors].polyobj = po; ffloor[numffloors].polyobj = po;
ffloor[numffloors].height = polysec->ceilingheight; ffloor[numffloors].height = polysec->ceilingheight;
ffloor[numffloors].slope = NULL; ffloor[numffloors].slope = NULL;
//ffloor[numffloors].ffloor = rover;
po->visplane = ffloor[numffloors].plane;
numffloors++; numffloors++;
} }
po = (polyobj_t *)(po->link.next);
} }
} }
// killough 9/18/98: Fix underwater slowdown, by passing real sector // killough 9/18/98: Fix underwater slowdown, by passing real sector
// instead of fake one. Improve sprite lighting by basing sprite // instead of fake one. Improve sprite lighting by basing sprite
// lightlevels on floor & ceiling lightlevels in the surrounding area. // lightlevels on floor & ceiling lightlevels in the surrounding area.
// //
// 10/98 killough: // 10/98 killough:
// //
// NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!! // NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!!
// That is part of the 242 effect!!! If you simply pass sub->sector to // That is part of the 242 effect!!! If you simply pass sub->sector to
// the old code you will not get correct lighting for underwater sprites!!! // the old code you will not get correct lighting for underwater sprites!!!
// Either you must pass the fake sector and handle validcount here, on the // Either you must pass the fake sector and handle validcount here, on the
// real sector, or you must account for the lighting in some other way, // real sector, or you must account for the lighting in some other way,
// like passing it as an argument. // like passing it as an argument.
R_AddSprites(sub->sector, (floorlightlevel+ceilinglightlevel)/2); R_AddSprites(sub->sector, (floorlightlevel+ceilinglightlevel)/2);
firstseg = NULL; firstseg = NULL;
// haleyjd 02/19/06: draw polyobjects before static lines
if (sub->polyList)
R_AddPolyObjects(sub);
while (count--) while (count--)
{ {
// CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime); if (!line->glseg && !(line->polyseg && !minibsp)) // ignore segs that belong to polyobjects
if (!line->glseg && !line->polyseg) // ignore segs that belong to polyobjects
R_AddLine(line); R_AddLine(line);
line++; line++;
curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */ curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */
} }
polynodes = NULL;
} }
// //
...@@ -1267,11 +1241,11 @@ void R_RenderBSPNode(INT32 bspnum) ...@@ -1267,11 +1241,11 @@ void R_RenderBSPNode(INT32 bspnum)
// Decide which side the view point is on. // Decide which side the view point is on.
side = R_PointOnSide(viewx, viewy, bsp); side = R_PointOnSide(viewx, viewy, bsp);
// Recursively divide front space. // Recursively divide front space.
R_RenderBSPNode(bsp->children[side]); R_RenderBSPNode(bsp->children[side]);
// Possibly divide back space. // Possibly divide back space.
if (!R_CheckBBox(bsp->bbox[side^1])) if (!R_CheckBBox(bsp->bbox[side^1]))
return; return;
...@@ -1288,3 +1262,30 @@ void R_RenderBSPNode(INT32 bspnum) ...@@ -1288,3 +1262,30 @@ void R_RenderBSPNode(INT32 bspnum)
R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
} }
void R_RenderMiniBSPNode(INT32 bspnum)
{
node_t *bsp;
INT32 side;
ps_numbspcalls.value.i++;
while (!(bspnum & NF_SUBSECTOR)) // Found a subsector?
{
bsp = &minibsp->nodes[bspnum];
// Decide which side the view point is on.
side = R_PointOnSide(viewx, viewy, bsp);
// Recursively divide front space.
R_RenderMiniBSPNode(bsp->children[side]);
// Possibly divide back space.
if (!R_CheckBBox(bsp->bbox[side^1]))
return;
bspnum = bsp->children[side^1];
}
R_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR);
}
...@@ -23,6 +23,7 @@ extern side_t *sidedef; ...@@ -23,6 +23,7 @@ extern side_t *sidedef;
extern line_t *linedef; extern line_t *linedef;
extern sector_t *frontsector; extern sector_t *frontsector;
extern sector_t *backsector; extern sector_t *backsector;
extern polynode_t *polynodes;
extern boolean portalline; // is curline a portal seg? extern boolean portalline; // is curline a portal seg?
// drawsegs are allocated on the fly... see r_segs.c // drawsegs are allocated on the fly... see r_segs.c
...@@ -38,7 +39,11 @@ extern INT32 doorclosed; ...@@ -38,7 +39,11 @@ extern INT32 doorclosed;
void R_ClearClipSegs(void); void R_ClearClipSegs(void);
void R_PortalClearClipSegs(INT32 start, INT32 end); void R_PortalClearClipSegs(INT32 start, INT32 end);
void R_ClearDrawSegs(void); void R_ClearDrawSegs(void);
void R_Subsector(size_t num);
void R_RenderBSPNode(INT32 bspnum); void R_RenderBSPNode(INT32 bspnum);
void R_RenderMiniBSPNode(INT32 bspnum);
void R_BuildPolyBSP(subsector_t *sub);
void R_SortPolyObjects(subsector_t *sub); void R_SortPolyObjects(subsector_t *sub);
......
...@@ -577,6 +577,8 @@ typedef struct ...@@ -577,6 +577,8 @@ typedef struct
extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors. extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors.
} side_t; } side_t;
struct minibsp_s;
// //
// A subsector. // A subsector.
// References a sector. // References a sector.
...@@ -588,8 +590,12 @@ typedef struct subsector_s ...@@ -588,8 +590,12 @@ typedef struct subsector_s
sector_t *sector; sector_t *sector;
INT16 numlines; INT16 numlines;
UINT32 firstline; UINT32 firstline;
struct polyobj_s *polyList; // haleyjd 02/19/06: list of polyobjects
size_t validcount; size_t validcount;
struct polyobj_s *polyList; // haleyjd 02/19/06: list of polyobjects
struct minibsp_s *BSP;
struct polynode_s *polynodes;
} subsector_t; } subsector_t;
// Sector list node showing all sectors an object appears in. // Sector list node showing all sectors an object appears in.
...@@ -663,6 +669,7 @@ typedef struct seg_s ...@@ -663,6 +669,7 @@ typedef struct seg_s
INT32 side; INT32 side;
fixed_t length; // precalculated seg length
fixed_t offset; fixed_t offset;
angle_t angle; angle_t angle;
...@@ -675,7 +682,6 @@ typedef struct seg_s ...@@ -675,7 +682,6 @@ typedef struct seg_s
sector_t *frontsector; sector_t *frontsector;
sector_t *backsector; sector_t *backsector;
fixed_t length; // precalculated seg length
#ifdef HWRENDER #ifdef HWRENDER
// new pointers so that AdjustSegs doesn't mess with v1/v2 // new pointers so that AdjustSegs doesn't mess with v1/v2
void *pv1; // polyvertex_t void *pv1; // polyvertex_t
...@@ -685,11 +691,10 @@ typedef struct seg_s ...@@ -685,11 +691,10 @@ typedef struct seg_s
lightmap_t *lightmaps; // for static lightmap lightmap_t *lightmaps; // for static lightmap
#endif #endif
// Why slow things down by calculating lightlists for every thick side?
size_t numlights;
r_lightlist_t *rlights;
polyobj_t *polyseg; polyobj_t *polyseg;
boolean dontrenderme; sector_t *polysector;
boolean polybackside;
boolean glseg; boolean glseg;
} seg_t; } seg_t;
...@@ -701,14 +706,31 @@ typedef struct ...@@ -701,14 +706,31 @@ typedef struct
// Partition line. // Partition line.
fixed_t x, y; fixed_t x, y;
fixed_t dx, dy; fixed_t dx, dy;
fixed_t length;
// Bounding box for each child. // Bounding box for each child.
fixed_t bbox[2][4]; fixed_t bbox[2][4];
// If NF_SUBSECTOR its a subsector. // If NF_SUBSECTOR, it's a subsector.
UINT16 children[2]; UINT16 children[2];
} node_t; } node_t;
// An entire BSP tree.
typedef struct minibsp_s
{
boolean dirty;
node_t *nodes;
seg_t *segs;
subsector_t *subsectors;
vertex_t *verts;
size_t numnodes;
size_t numsegs;
size_t numsubsectors;
size_t numverts;
} minibsp_t;
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)
#endif #endif
......
...@@ -1496,6 +1496,8 @@ void R_RenderPlayerView(player_t *player) ...@@ -1496,6 +1496,8 @@ void R_RenderPlayerView(player_t *player)
#endif #endif
ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0; ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0;
PS_START_TIMING(ps_bsptime); PS_START_TIMING(ps_bsptime);
// Link the polyobjects right before drawing the scene to reduce the amounts of calls to this function
Polyobj_LinkToSubsectors();
R_RenderBSPNode((INT32)numnodes - 1); R_RenderBSPNode((INT32)numnodes - 1);
PS_STOP_TIMING(ps_bsptime); PS_STOP_TIMING(ps_bsptime);
ps_numsprites.value.i = visspritecount; ps_numsprites.value.i = visspritecount;
......
...@@ -492,6 +492,42 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, ...@@ -492,6 +492,42 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
return check; return check;
} }
static visplane_t *R_CreateVisplane(visplane_t *pl, INT32 start, INT32 stop)
{
visplane_t *new_pl;
if (pl->ffloor || pl->polyobj)
{
new_pl = new_visplane(MAXVISPLANES - 1);
}
else
{
unsigned hash =
visplane_hash(pl->picnum, pl->lightlevel, pl->height);
new_pl = new_visplane(hash);
}
new_pl->height = pl->height;
new_pl->picnum = pl->picnum;
new_pl->lightlevel = pl->lightlevel;
new_pl->xoffs = pl->xoffs;
new_pl->yoffs = pl->yoffs;
new_pl->extra_colormap = pl->extra_colormap;
new_pl->ffloor = pl->ffloor;
new_pl->viewx = pl->viewx;
new_pl->viewy = pl->viewy;
new_pl->viewz = pl->viewz;
new_pl->viewangle = pl->viewangle;
new_pl->plangle = pl->plangle;
new_pl->polyobj = pl->polyobj;
new_pl->slope = pl->slope;
new_pl->minx = start;
new_pl->maxx = stop;
memset(new_pl->top, 0xff, sizeof new_pl->top);
memset(new_pl->bottom, 0x00, sizeof new_pl->bottom);
return new_pl;
}
// //
// R_CheckPlane: return same visplane or alloc a new one if needed // R_CheckPlane: return same visplane or alloc a new one if needed
// //
...@@ -501,6 +537,9 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) ...@@ -501,6 +537,9 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop)
INT32 unionl, unionh; INT32 unionl, unionh;
INT32 x; INT32 x;
if (pl->polyobj)
return R_CreateVisplane(pl, start, stop);
if (start < pl->minx) if (start < pl->minx)
{ {
intrl = pl->minx; intrl = pl->minx;
...@@ -532,45 +571,13 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) ...@@ -532,45 +571,13 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop)
{ {
pl->minx = unionl; pl->minx = unionl;
pl->maxx = unionh; pl->maxx = unionh;
return pl;
} }
else /* Cannot use existing plane; create a new one */
{
visplane_t *new_pl;
if (pl->ffloor)
{
new_pl = new_visplane(MAXVISPLANES - 1);
}
else
{
unsigned hash =
visplane_hash(pl->picnum, pl->lightlevel, pl->height);
new_pl = new_visplane(hash);
}
new_pl->height = pl->height; /* Cannot use existing plane; create a new one */
new_pl->picnum = pl->picnum; return R_CreateVisplane(pl, start, stop);
new_pl->lightlevel = pl->lightlevel;
new_pl->xoffs = pl->xoffs;
new_pl->yoffs = pl->yoffs;
new_pl->extra_colormap = pl->extra_colormap;
new_pl->ffloor = pl->ffloor;
new_pl->viewx = pl->viewx;
new_pl->viewy = pl->viewy;
new_pl->viewz = pl->viewz;
new_pl->viewangle = pl->viewangle;
new_pl->plangle = pl->plangle;
new_pl->polyobj = pl->polyobj;
new_pl->slope = pl->slope;
pl = new_pl;
pl->minx = start;
pl->maxx = stop;
memset(pl->top, 0xff, sizeof pl->top);
memset(pl->bottom, 0x00, sizeof pl->bottom);
}
return pl;
} }
// //
// R_ExpandPlane // R_ExpandPlane
// //
......
...@@ -136,17 +136,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -136,17 +136,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
void (*colfunc_2s)(column_t *); void (*colfunc_2s)(column_t *);
line_t *ldef; line_t *ldef;
sector_t *front, *back; sector_t *front, *back;
INT32 times, repeats; INT32 times, repeats = 1;
INT64 overflow_test; INT64 overflow_test;
INT32 range; INT32 range;
// Calculate light table.
// Use different light tables
// for horizontal / vertical / diagonal. Diagonal?
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
curline = ds->curline; curline = ds->curline;
frontsector = curline->frontsector; frontsector = curline->polyseg ? curline->polysector : curline->frontsector;
backsector = curline->backsector; backsector = curline->backsector;
texnum = R_GetTextureNum(curline->sidedef->midtexture); texnum = R_GetTextureNum(curline->sidedef->midtexture);
windowbottom = windowtop = sprbotscreen = INT32_MAX; windowbottom = windowtop = sprbotscreen = INT32_MAX;
...@@ -236,8 +232,6 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -236,8 +232,6 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rlight->height = (centeryfrac) - FixedMul(leftheight , ds->scale1); rlight->height = (centeryfrac) - FixedMul(leftheight , ds->scale1);
rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2); rlight->heightstep = (centeryfrac) - FixedMul(rightheight, ds->scale2);
rlight->heightstep = (rlight->heightstep-rlight->height)/(range); rlight->heightstep = (rlight->heightstep-rlight->height)/(range);
//if (x1 > ds->x1)
//rlight->height -= (x1 - ds->x1)*rlight->heightstep;
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
rlight->lightlevel = *light->lightlevel; rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = *light->extra_colormap; rlight->extra_colormap = *light->extra_colormap;
...@@ -262,6 +256,10 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -262,6 +256,10 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
} }
else else
{ {
// Calculate light table.
// Use different light tables
// for horizontal / vertical / diagonal. Diagonal?
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY]) if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))) || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
...@@ -299,28 +297,29 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -299,28 +297,29 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
else else
back = backsector; back = backsector;
if (ds->curline->sidedef->repeatcnt) if (!curline->polyseg)
repeats = 1 + ds->curline->sidedef->repeatcnt;
else if (ldef->flags & ML_WRAPMIDTEX)
{ {
fixed_t high, low; if (ds->curline->sidedef->repeatcnt)
repeats = 1 + ds->curline->sidedef->repeatcnt;
else if (ldef->flags & ML_WRAPMIDTEX)
{
fixed_t high, low;
if (front->ceilingheight > back->ceilingheight) if (front->ceilingheight > back->ceilingheight)
high = back->ceilingheight; high = back->ceilingheight;
else else
high = front->ceilingheight; high = front->ceilingheight;
if (front->floorheight > back->floorheight) if (front->floorheight > back->floorheight)
low = front->floorheight; low = front->floorheight;
else else
low = back->floorheight; low = back->floorheight;
repeats = (high - low)/textureheight[texnum]; repeats = (high - low)/textureheight[texnum];
if ((high-low)%textureheight[texnum]) if ((high-low)%textureheight[texnum])
repeats++; // tile an extra time to fill the gap -- Monster Iestyn repeats++; // tile an extra time to fill the gap -- Monster Iestyn
}
} }
else
repeats = 1;
for (times = 0; times < repeats; times++) for (times = 0; times < repeats; times++)
{ {
...@@ -459,7 +458,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -459,7 +458,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3);
#if 0 // Disabling this allows inside edges to render below the planes, for until the clipping is fixed to work right when POs are near the camera. -Red #if 0 // Disabling this allows inside edges to render below the planes, for until the clipping is fixed to work right when POs are near the camera. -Red
if (curline->dontrenderme && curline->polyseg && (curline->polyseg->flags & POF_RENDERPLANES)) if (curline->polybackside && curline->polyseg && (curline->polyseg->flags & POF_RENDERPLANES))
{ {
fixed_t my_topscreen; fixed_t my_topscreen;
fixed_t my_bottomscreen; fixed_t my_bottomscreen;
...@@ -1154,7 +1153,7 @@ static void R_RenderSegLoop (void) ...@@ -1154,7 +1153,7 @@ static void R_RenderSegLoop (void)
for (i = 0; i < numffloors; i++) for (i = 0; i < numffloors; i++)
{ {
if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg)) if (ffloor[i].polyobj && ffloor[i].polyobj != curline->polyseg)
continue; continue;
if (ffloor[i].height < viewz) if (ffloor[i].height < viewz)
...@@ -1174,33 +1173,30 @@ static void R_RenderSegLoop (void) ...@@ -1174,33 +1173,30 @@ static void R_RenderSegLoop (void)
ffloor[i].plane->top[rw_x] = 0xFFFF; ffloor[i].plane->top[rw_x] = 0xFFFF;
ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18 ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18
} }
else else if (top_w <= bottom_w)
{ {
if (top_w <= bottom_w) fftop = (INT16)top_w;
{ ffbottom = (INT16)bottom_w;
fftop = (INT16)top_w;
ffbottom = (INT16)bottom_w;
ffloor[i].plane->top[rw_x] = fftop; ffloor[i].plane->top[rw_x] = fftop;
ffloor[i].plane->bottom[rw_x] = ffbottom; ffloor[i].plane->bottom[rw_x] = ffbottom;
// Lactozilla: Cull part of the column by the 3D floor if it can't be seen // Lactozilla: Cull part of the column by the 3D floor if it can't be seen
// "bottom" is the top pixel of the floor column // "bottom" is the top pixel of the floor column
if (ffbottom >= bottom-1 && R_FFloorCanClip(&ffloor[i]) && !curline->polyseg) if (ffbottom >= bottom-1 && R_FFloorCanClip(&ffloor[i]) && !curline->polyseg)
{ {
rw_floormarked = true; rw_floormarked = true;
floorclip[rw_x] = fftop; floorclip[rw_x] = fftop;
if (yh > fftop) if (yh > fftop)
yh = fftop; yh = fftop;
if (markfloor && floorplane) if (markfloor && floorplane)
floorplane->top[rw_x] = bottom; floorplane->top[rw_x] = bottom;
if (rw_silhouette) if (rw_silhouette)
{ {
(*rw_silhouette) |= SIL_BOTTOM; (*rw_silhouette) |= SIL_BOTTOM;
(*rw_bsilheight) = INT32_MAX; (*rw_bsilheight) = INT32_MAX;
}
} }
} }
} }
...@@ -1222,33 +1218,30 @@ static void R_RenderSegLoop (void) ...@@ -1222,33 +1218,30 @@ static void R_RenderSegLoop (void)
ffloor[i].plane->top[rw_x] = 0xFFFF; ffloor[i].plane->top[rw_x] = 0xFFFF;
ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18 ffloor[i].plane->bottom[rw_x] = 0x0000; // fix for sky plane drawing crashes - Monster Iestyn 25/05/18
} }
else else if (top_w <= bottom_w)
{ {
if (top_w <= bottom_w) fftop = (INT16)top_w;
{ ffbottom = (INT16)bottom_w;
fftop = (INT16)top_w;
ffbottom = (INT16)bottom_w;
ffloor[i].plane->top[rw_x] = fftop; ffloor[i].plane->top[rw_x] = fftop;
ffloor[i].plane->bottom[rw_x] = ffbottom; ffloor[i].plane->bottom[rw_x] = ffbottom;
// Lactozilla: Cull part of the column by the 3D floor if it can't be seen // Lactozilla: Cull part of the column by the 3D floor if it can't be seen
// "top" is the height of the ceiling column // "top" is the height of the ceiling column
if (fftop <= top+1 && R_FFloorCanClip(&ffloor[i]) && !curline->polyseg) if (fftop <= top+1 && R_FFloorCanClip(&ffloor[i]) && !curline->polyseg)
{ {
rw_ceilingmarked = true; rw_ceilingmarked = true;
ceilingclip[rw_x] = ffbottom; ceilingclip[rw_x] = ffbottom;
if (yl < ffbottom) if (yl < ffbottom)
yl = ffbottom; yl = ffbottom;
if (markceiling && ceilingplane) if (markceiling && ceilingplane)
ceilingplane->bottom[rw_x] = top; ceilingplane->bottom[rw_x] = top;
if (rw_silhouette) if (rw_silhouette)
{ {
(*rw_silhouette) |= SIL_TOP; (*rw_silhouette) |= SIL_TOP;
(*rw_tsilheight) = INT32_MIN; (*rw_tsilheight) = INT32_MIN;
}
} }
} }
} }
...@@ -1277,7 +1270,7 @@ static void R_RenderSegLoop (void) ...@@ -1277,7 +1270,7 @@ static void R_RenderSegLoop (void)
// calculate lighting // calculate lighting
pindex = FixedMul(rw_scale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; pindex = FixedMul(rw_scale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT;
if (pindex >= MAXLIGHTSCALE) if (pindex >= MAXLIGHTSCALE)
pindex = MAXLIGHTSCALE-1; pindex = MAXLIGHTSCALE-1;
dc_colormap = walllights[pindex]; dc_colormap = walllights[pindex];
...@@ -1461,29 +1454,24 @@ static void R_RenderSegLoop (void) ...@@ -1461,29 +1454,24 @@ static void R_RenderSegLoop (void)
} }
} }
if (dc_numlights) for (i = 0; i < dc_numlights; i++)
{ {
for (i = 0; i < dc_numlights; i++) dc_lightlist[i].height += dc_lightlist[i].heightstep;
{ if (dc_lightlist[i].flags & FOF_CUTSOLIDS)
dc_lightlist[i].height += dc_lightlist[i].heightstep; dc_lightlist[i].botheight += dc_lightlist[i].botheightstep;
if (dc_lightlist[i].flags & FOF_CUTSOLIDS)
dc_lightlist[i].botheight += dc_lightlist[i].botheightstep;
}
} }
for (i = 0; i < numffloors; i++) for (i = 0; i < numffloors; i++)
{ {
if (curline->polyseg && (ffloor[i].polyobj != curline->polyseg)) if (ffloor[i].polyobj && ffloor[i].polyobj != curline->polyseg)
continue; continue;
ffloor[i].f_frac += ffloor[i].f_step; ffloor[i].f_frac += ffloor[i].f_step;
} }
for (i = 0; i < numbackffloors; i++) for (i = 0; i < numbackffloors; i++)
{ {
if (curline->polyseg && (ffloor[i].polyobj != curline->polyseg)) if (ffloor[i].polyobj && ffloor[i].polyobj != curline->polyseg)
continue; continue;
ffloor[i].f_clip[rw_x] = ffloor[i].c_clip[rw_x] = (INT16)((ffloor[i].b_frac >> HEIGHTBITS) & 0xFFFF); ffloor[i].f_clip[rw_x] = ffloor[i].c_clip[rw_x] = (INT16)((ffloor[i].b_frac >> HEIGHTBITS) & 0xFFFF);
ffloor[i].b_frac += ffloor[i].b_step; ffloor[i].b_frac += ffloor[i].b_step;
} }
...@@ -1726,16 +1714,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -1726,16 +1714,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
for (i = 0; i < MAXFFLOORS; i++) for (i = 0; i < MAXFFLOORS; i++)
ds_p->thicksides[i] = NULL; ds_p->thicksides[i] = NULL;
if (numffloors) for (i = 0; i < numffloors; i++)
{ {
for (i = 0; i < numffloors; i++) ffloor[i].f_pos = P_GetZAt(ffloor[i].slope, segleft .x, segleft .y, ffloor[i].height) - viewz;
{ ffloor[i].f_pos_slope = P_GetZAt(ffloor[i].slope, segright.x, segright.y, ffloor[i].height) - viewz;
if (ffloor[i].polyobj && (!ds_p->curline->polyseg || ffloor[i].polyobj != ds_p->curline->polyseg))
continue;
ffloor[i].f_pos = P_GetZAt(ffloor[i].slope, segleft .x, segleft .y, ffloor[i].height) - viewz;
ffloor[i].f_pos_slope = P_GetZAt(ffloor[i].slope, segright.x, segright.y, ffloor[i].height) - viewz;
}
} }
// Set up texture Y offset slides for sloped walls // Set up texture Y offset slides for sloped walls
...@@ -2026,17 +2008,16 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2026,17 +2008,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
rw_bottomtexturemid += sidedef->rowoffset; rw_bottomtexturemid += sidedef->rowoffset;
// allocate space for masked texture tables // allocate space for masked texture tables
if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors)) if (backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors))
{ {
ffloor_t *rover; ffloor_t *rover;
ffloor_t *r2; ffloor_t *r2;
fixed_t lowcut, highcut; fixed_t lowcut, highcut;
fixed_t lowcutslope, highcutslope; fixed_t lowcutslope, highcutslope;
// Used for height comparisons and etc across FOFs and slopes // Used for height comparisons and etc across FOFs and slopes
fixed_t high1, highslope1, low1, lowslope1, high2, highslope2, low2, lowslope2; fixed_t high1, highslope1, low1, lowslope1, high2, highslope2, low2, lowslope2;
//markceiling = markfloor = true;
maskedtexture = true; maskedtexture = true;
ds_p->thicksidecol = maskedtexturecol = lastopening - rw_x; ds_p->thicksidecol = maskedtexturecol = lastopening - rw_x;
...@@ -2218,7 +2199,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2218,7 +2199,9 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ds_p->numthicksides = numthicksides = i; ds_p->numthicksides = numthicksides = i;
} }
if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures
&& !(curline->polyseg && !(curline->polyseg->flags & POF_RENDERSIDES)))
{ {
// masked midtexture // masked midtexture
if (!ds_p->thicksidecol) if (!ds_p->thicksidecol)
...@@ -2229,10 +2212,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2229,10 +2212,11 @@ void R_StoreWallRange(INT32 start, INT32 stop)
else else
ds_p->maskedtexturecol = ds_p->thicksidecol; ds_p->maskedtexturecol = ds_p->thicksidecol;
maskedtextureheight = ds_p->maskedtextureheight; // note to red, this == &(ds_p->maskedtextureheight[0]) maskedtextureheight = ds_p->maskedtextureheight;
// use REAL front and back floors please, so midtexture rendering isn't mucked up
if (curline->polyseg) if (curline->polyseg)
{ // use REAL front and back floors please, so midtexture rendering isn't mucked up {
rw_midtextureslide = rw_midtexturebackslide = 0; rw_midtextureslide = rw_midtexturebackslide = 0;
if (linedef->flags & ML_MIDPEG) if (linedef->flags & ML_MIDPEG)
rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz; rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz;
...@@ -2445,23 +2429,20 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2445,23 +2429,20 @@ void R_StoreWallRange(INT32 start, INT32 stop)
dc_numlights = p; dc_numlights = p;
} }
if (numffloors) for (i = 0; i < numffloors; i++)
{ {
for (i = 0; i < numffloors; i++) ffloor[i].f_pos >>= 4;
ffloor[i].f_pos_slope >>= 4;
if (linedef->special == HORIZONSPECIAL) // Horizon lines extend FOFs in contact with them too.
{ {
ffloor[i].f_pos >>= 4; ffloor[i].f_step = 0;
ffloor[i].f_pos_slope >>= 4; ffloor[i].f_frac = (centeryfrac>>4);
if (linedef->special == HORIZONSPECIAL) // Horizon lines extend FOFs in contact with them too. topfrac++; // Prevent 1px HOM
{ }
ffloor[i].f_step = 0; else
ffloor[i].f_frac = (centeryfrac>>4); {
topfrac++; // Prevent 1px HOM ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
} ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range);
else
{
ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range);
}
} }
} }
...@@ -2493,11 +2474,13 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2493,11 +2474,13 @@ void R_StoreWallRange(INT32 start, INT32 stop)
} }
} }
i = 0;
if (backsector->ffloors || frontsector->ffloors)
{ {
ffloor_t * rover; ffloor_t *rover;
fixed_t roverleft, roverright; fixed_t roverleft, roverright;
fixed_t planevistest; fixed_t planevistest;
i = 0;
if (backsector->ffloors) if (backsector->ffloors)
{ {
...@@ -2521,7 +2504,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2521,7 +2504,6 @@ void R_StoreWallRange(INT32 start, INT32 stop)
((viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || ((viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) (viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{ {
//ffloor[i].slope = *rover->b_slope;
ffloor[i].b_pos = roverleft; ffloor[i].b_pos = roverleft;
ffloor[i].b_pos_slope = roverright; ffloor[i].b_pos_slope = roverright;
ffloor[i].b_pos >>= 4; ffloor[i].b_pos >>= 4;
...@@ -2544,7 +2526,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2544,7 +2526,6 @@ void R_StoreWallRange(INT32 start, INT32 stop)
((viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || ((viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) (viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{ {
//ffloor[i].slope = *rover->t_slope;
ffloor[i].b_pos = roverleft; ffloor[i].b_pos = roverleft;
ffloor[i].b_pos_slope = roverright; ffloor[i].b_pos_slope = roverright;
ffloor[i].b_pos >>= 4; ffloor[i].b_pos >>= 4;
...@@ -2556,7 +2537,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2556,7 +2537,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
} }
} }
} }
else if (frontsector && frontsector->ffloors) else if (frontsector->ffloors)
{ {
for (rover = frontsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next) for (rover = frontsector->ffloors; rover && i < MAXFFLOORS; rover = rover->next)
{ {
...@@ -2578,7 +2559,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2578,7 +2559,6 @@ void R_StoreWallRange(INT32 start, INT32 stop)
((viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || ((viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) (viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{ {
//ffloor[i].slope = *rover->b_slope;
ffloor[i].b_pos = roverleft; ffloor[i].b_pos = roverleft;
ffloor[i].b_pos_slope = roverright; ffloor[i].b_pos_slope = roverright;
ffloor[i].b_pos >>= 4; ffloor[i].b_pos >>= 4;
...@@ -2601,7 +2581,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2601,7 +2581,6 @@ void R_StoreWallRange(INT32 start, INT32 stop)
((viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) || ((viewz > planevistest && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES))) ||
(viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES)))) (viewz < planevistest && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{ {
//ffloor[i].slope = *rover->t_slope;
ffloor[i].b_pos = roverleft; ffloor[i].b_pos = roverleft;
ffloor[i].b_pos_slope = roverright; ffloor[i].b_pos_slope = roverright;
ffloor[i].b_pos >>= 4; ffloor[i].b_pos >>= 4;
...@@ -2613,46 +2592,49 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2613,46 +2592,49 @@ void R_StoreWallRange(INT32 start, INT32 stop)
} }
} }
} }
if (curline->polyseg && frontsector && (curline->polyseg->flags & POF_RENDERPLANES))
polyobj_t *po = curline->polyseg;
if (po && po->flags & POF_RENDERPLANES)
{ {
while (i < numffloors && ffloor[i].polyobj != curline->polyseg) i++; sector_t *polysec = po->lines[0]->backsector;
if (i < numffloors && backsector->floorheight <= frontsector->ceilingheight &&
backsector->floorheight >= frontsector->floorheight &&
(viewz < backsector->floorheight))
{
if (ffloor[i].plane->minx > ds_p->x1)
ffloor[i].plane->minx = ds_p->x1;
if (ffloor[i].plane->maxx < ds_p->x2) while (i < numffloors && ffloor[i].polyobj != po) i++;
ffloor[i].plane->maxx = ds_p->x2;
ffloor[i].slope = NULL; if (i < MAXFFLOORS && polysec->floorheight <= frontsector->ceilingheight &&
ffloor[i].b_pos = backsector->floorheight; polysec->floorheight >= frontsector->floorheight &&
(viewz < polysec->floorheight))
{
ffloor[i].b_pos = polysec->floorheight;
ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4;
ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos);
ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
i++; i++;
} }
if (i < numffloors && backsector->ceilingheight >= frontsector->floorheight &&
backsector->ceilingheight <= frontsector->ceilingheight &&
(viewz > backsector->ceilingheight))
{
if (ffloor[i].plane->minx > ds_p->x1)
ffloor[i].plane->minx = ds_p->x1;
if (ffloor[i].plane->maxx < ds_p->x2)
ffloor[i].plane->maxx = ds_p->x2;
ffloor[i].slope = NULL; if (i < MAXFFLOORS && polysec->ceilingheight >= frontsector->floorheight &&
ffloor[i].b_pos = backsector->ceilingheight; polysec->ceilingheight <= frontsector->ceilingheight &&
(viewz > polysec->ceilingheight))
{
ffloor[i].b_pos = polysec->ceilingheight;
ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4; ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4;
ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos); ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos);
ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale); ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
i++; i++;
} }
} }
}
numbackffloors = i;
}
numbackffloors = i; for (i = 0; i < numffloors; i++)
{
if (curline->polyseg == ffloor[i].polyobj)
{
if (ffloor[i].plane->minx > ds_p->x1)
ffloor[i].plane->minx = ds_p->x1;
if (ffloor[i].plane->maxx < ds_p->x2)
ffloor[i].plane->maxx = ds_p->x2;
} }
} }
...@@ -2704,20 +2686,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2704,20 +2686,6 @@ void R_StoreWallRange(INT32 start, INT32 stop)
for (i = 0; i < numffloors; i++) for (i = 0; i < numffloors; i++)
R_ExpandPlane(ffloor[i].plane, rw_x, rw_stopx - 1); R_ExpandPlane(ffloor[i].plane, rw_x, rw_stopx - 1);
} }
// FIXME hack to fix planes disappearing when a seg goes behind the camera. This NEEDS to be changed to be done properly. -Red
if (curline->polyseg)
{
for (i = 0; i < numffloors; i++)
{
if (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg)
continue;
if (ffloor[i].plane->minx > rw_x)
ffloor[i].plane->minx = rw_x;
if (ffloor[i].plane->maxx < rw_stopx - 1)
ffloor[i].plane->maxx = rw_stopx - 1;
}
}
} }
rw_silhouette = &(ds_p->silhouette); rw_silhouette = &(ds_p->silhouette);
......
...@@ -2588,7 +2588,7 @@ static drawnode_t *R_CreateDrawNode(drawnode_t *link); ...@@ -2588,7 +2588,7 @@ static drawnode_t *R_CreateDrawNode(drawnode_t *link);
static drawnode_t nodebankhead; static drawnode_t nodebankhead;
static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean tempskip) static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head)
{ {
drawnode_t *entry; drawnode_t *entry;
drawseg_t *ds; drawseg_t *ds;
...@@ -2613,21 +2613,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps ...@@ -2613,21 +2613,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
entry->ffloor = ds->thicksides[i]; entry->ffloor = ds->thicksides[i];
} }
} }
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
plane = ds->curline->polyseg->visplane;
R_PlaneBounds(plane);
if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low)
;
else {
// Put it in!
entry = R_CreateDrawNode(head);
entry->plane = plane;
entry->seg = ds;
}
ds->curline->polyseg->visplane = NULL;
}
if (ds->maskedtexturecol) if (ds->maskedtexturecol)
{ {
entry = R_CreateDrawNode(head); entry = R_CreateDrawNode(head);
...@@ -2646,7 +2631,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps ...@@ -2646,7 +2631,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
plane = ds->ffloorplanes[p]; plane = ds->ffloorplanes[p];
R_PlaneBounds(plane); R_PlaneBounds(plane);
if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low || plane->polyobj) if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low || (plane->polyobj && !ds->curline->side))
{ {
ds->ffloorplanes[p] = NULL; ds->ffloorplanes[p] = NULL;
continue; continue;
...@@ -2672,30 +2657,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps ...@@ -2672,30 +2657,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
} }
} }
if (tempskip)
return;
// find all the remaining polyobject planes and add them on the end of the list
// probably this is a terrible idea if we wanted them to be sorted properly
// but it works getting them in for now
for (i = 0; i < numPolyObjects; i++)
{
if (!PolyObjects[i].visplane)
continue;
plane = PolyObjects[i].visplane;
R_PlaneBounds(plane);
if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low)
{
PolyObjects[i].visplane = NULL;
continue;
}
entry = R_CreateDrawNode(head);
entry->plane = plane;
// note: no seg is set, for what should be obvious reasons
PolyObjects[i].visplane = NULL;
}
// No vissprites in this mask? // No vissprites in this mask?
if (mask->vissprites[1] - mask->vissprites[0] == 0) if (mask->vissprites[1] - mask->vissprites[0] == 0)
return; return;
...@@ -3354,7 +3315,7 @@ void R_DrawMasked(maskcount_t* masks, INT32 nummasks) ...@@ -3354,7 +3315,7 @@ void R_DrawMasked(maskcount_t* masks, INT32 nummasks)
viewz = masks[i].viewz; viewz = masks[i].viewz;
viewsector = masks[i].viewsector; viewsector = masks[i].viewsector;
R_CreateDrawNodes(&masks[i], &heads[i], false); R_CreateDrawNodes(&masks[i], &heads[i]);
} }
//for (i = 0; i < nummasks; i++) //for (i = 0; i < nummasks; i++)
......