SRB2/src/hardware/hw_bsp.c

1032 lines
26 KiB
C
Raw Normal View History

2014-03-15 16:59:03 +00:00
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright (C) 1998-2000 by DooM Legacy Team.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//-----------------------------------------------------------------------------
/// \file
/// \brief convert SRB2 map
#include "../doomdef.h"
#include "../doomstat.h"
#ifdef HWRENDER
#include "hw_glob.h"
#include "../r_local.h"
#include "../z_zone.h"
#include "../console.h"
#include "../v_video.h"
#include "../m_menu.h"
#include "../i_system.h"
#include "../m_argv.h"
#include "../i_video.h"
#include "../w_wad.h"
#include "../p_setup.h" // levelfadecol
2014-03-15 16:59:03 +00:00
// --------------------------------------------------------------------------
// This is global data for planes rendering
// --------------------------------------------------------------------------
extrasubsector_t *extrasubsectors = NULL;
// newsubsectors are subsectors without segs, added for the plane polygons
#define NEWSUBSECTORS 50
static size_t totsubsectors;
size_t addsubsector;
typedef struct
{
float x, y;
float dx, dy;
} fdivline_t;
// ==========================================================================
// FLOOR & CEILING CONVEX POLYS GENERATION
// ==========================================================================
//debug counters
static INT32 nobackpoly = 0;
static INT32 skipcut = 0;
static INT32 totalsubsecpolys = 0;
// --------------------------------------------------------------------------
// Polygon fast alloc / free
// --------------------------------------------------------------------------
//hurdler: quick fix for those who wants to play with larger wad
#define ZPLANALLOC
#ifndef ZPLANALLOC
//#define POLYPOOLSIZE 1024000 // may be much over what is needed
/// \todo check out how much is used
static size_t POLYPOOLSIZE = 1024000;
static UINT8 *gr_polypool = NULL;
static UINT8 *gr_ppcurrent;
static size_t gr_ppfree;
#endif
// only between levels, clear poly pool
static void HWR_ClearPolys(void)
{
#ifndef ZPLANALLOC
gr_ppcurrent = gr_polypool;
gr_ppfree = POLYPOOLSIZE;
#endif
}
// allocate pool for fast alloc of polys
void HWR_InitPolyPool(void)
{
#ifndef ZPLANALLOC
INT32 pnum;
//hurdler: quick fix for those who wants to play with larger wad
if ((pnum = M_CheckParm("-polypoolsize")))
POLYPOOLSIZE = atoi(myargv[pnum+1])*1024; // (in kb)
CONS_Debug(DBG_RENDER, "HWR_InitPolyPool(): allocating %d bytes\n", POLYPOOLSIZE);
gr_polypool = malloc(POLYPOOLSIZE);
if (!gr_polypool)
I_Error("HWR_InitPolyPool(): couldn't malloc polypool\n");
HWR_ClearPolys();
#endif
}
void HWR_FreePolyPool(void)
{
#ifndef ZPLANALLOC
if (gr_polypool)
free(gr_polypool);
gr_polypool = NULL;
#endif
}
static poly_t *HWR_AllocPoly(INT32 numpts)
{
poly_t *p;
size_t size = sizeof (poly_t) + sizeof (polyvertex_t) * numpts;
#ifdef ZPLANALLOC
p = Z_Malloc(size, PU_HWRPLANE, NULL);
#else
#ifdef PARANOIA
if (!gr_polypool)
I_Error("Used gr_polypool without init!\n");
if (!gr_ppcurrent)
I_Error("gr_ppcurrent == NULL!\n");
#endif
if (gr_ppfree < size)
I_Error("HWR_AllocPoly(): no more memory %u bytes left, %u bytes needed\n\n%s\n",
gr_ppfree, size, "You can try the param -polypoolsize 2048 (or higher if needed)");
p = (poly_t *)gr_ppcurrent;
gr_ppcurrent += size;
gr_ppfree -= size;
#endif
p->numpts = numpts;
return p;
}
static polyvertex_t *HWR_AllocVertex(void)
{
polyvertex_t *p;
size_t size = sizeof (polyvertex_t);
#ifdef ZPLANALLOC
p = Z_Malloc(size, PU_HWRPLANE, NULL);
#else
if (gr_ppfree < size)
I_Error("HWR_AllocVertex(): no more memory %u bytes left, %u bytes needed\n\n%s\n",
gr_ppfree, size, "You can try the param -polypoolsize 2048 (or higher if needed)");
p = (polyvertex_t *)gr_ppcurrent;
gr_ppcurrent += size;
gr_ppfree -= size;
#endif
return p;
}
/// \todo polygons should be freed in reverse order for efficiency,
/// for now don't free because it doesn't free in reverse order
static void HWR_FreePoly(poly_t *poly)
{
#ifdef ZPLANALLOC
Z_Free(poly);
#else
const size_t size = sizeof (poly_t) + sizeof (polyvertex_t) * poly->numpts;
memset(poly, 0x00, size);
//mempoly -= polysize;
#endif
}
// Return interception along bsp line,
// with the polygon segment
//
static float bspfrac;
static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1,
polyvertex_t *v2)
{
static polyvertex_t pt;
double frac;
double num;
double den;
double v1x,v1y,v1dx,v1dy;
double v2x,v2y,v2dx,v2dy;
// a segment of a polygon
v1x = v1->x;
v1y = v1->y;
v1dx = v2->x - v1->x;
v1dy = v2->y - v1->y;
// the bsp partition line
v2x = bsp->x;
v2y = bsp->y;
v2dx = bsp->dx;
v2dy = bsp->dy;
den = v2dy*v1dx - v2dx*v1dy;
2018-12-16 18:51:53 +00:00
if (fabsf((float)den) < 1.0E-36f) // avoid checking exactly for 0.0
2014-03-15 16:59:03 +00:00
return NULL; // parallel
// first check the frac along the polygon segment,
// (do not accept hit with the extensions)
num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx;
frac = num / den;
2019-03-02 23:56:44 +00:00
if (frac < 0.0l || frac > 1.0l)
2014-03-15 16:59:03 +00:00
return NULL;
// now get the frac along the BSP line
// which is useful to determine what is left, what is right
num = (v2x - v1x)*v1dy + (v1y - v2y)*v1dx;
frac = num / den;
bspfrac = (float)frac;
// find the interception point along the partition line
pt.x = (float)(v2x + v2dx*frac);
pt.y = (float)(v2y + v2dy*frac);
return &pt;
}
// if two vertice coords have a x and/or y difference
// of less or equal than 1 FRACUNIT, they are considered the same
// point. Note: hardcoded value, 1.0f could be anything else.
static boolean SameVertice (polyvertex_t *p1, polyvertex_t *p2)
{
#if 0
float diff;
diff = p2->x - p1->x;
if (diff < -1.5f || diff > 1.5f)
return false;
diff = p2->y - p1->y;
if (diff < -1.5f || diff > 1.5f)
return false;
2018-12-15 00:33:40 +00:00
#elif 0
2014-03-15 16:59:03 +00:00
if (p1->x != p2->x)
return false;
if (p1->y != p2->y)
return false;
2018-12-16 18:51:53 +00:00
#elif 0
2018-12-15 00:33:40 +00:00
if (fabsf( p2->x - p1->x ) > 1.0E-36f )
return false;
if (fabsf( p2->y - p1->y ) > 1.0E-36f )
return false;
#else
#define DIVLINE_VERTEX_DIFF 0.45f
float ep = DIVLINE_VERTEX_DIFF;
if (fabsf( p2->x - p1->x ) > ep )
return false;
if (fabsf( p2->y - p1->y ) > ep )
return false;
2014-03-15 16:59:03 +00:00
#endif
// p1 and p2 are considered the same vertex
return true;
}
// split a _CONVEX_ polygon in two convex polygons
// outputs:
// frontpoly : polygon on right side of bsp line
// backpoly : polygon on left side
//
static void SplitPoly (fdivline_t *bsp, //splitting parametric line
poly_t *poly, //the convex poly we split
poly_t **frontpoly, //return one poly here
poly_t **backpoly) //return the other here
{
INT32 i,j;
polyvertex_t *pv;
INT32 ps = -1,pe = -1;
INT32 nptfront,nptback;
polyvertex_t vs = {0,0,0};
polyvertex_t ve = {0,0,0};
polyvertex_t lastpv = {0,0,0};
float fracs = 0.0f,frace = 0.0f; //used to tell which poly is on
// the front side of the bsp partition line
INT32 psonline = 0, peonline = 0;
for (i = 0; i < poly->numpts; i++)
{
j = i + 1;
if (j == poly->numpts) j = 0;
// start & end points
pv = fracdivline(bsp, &poly->pts[i], &poly->pts[j]);
if (pv == NULL)
continue;
if (ps < 0)
2014-03-15 16:59:03 +00:00
{
// first point
ps = i;
vs = *pv;
fracs = bspfrac;
}
else
{
//the partition line traverse a junction between two segments
// or the two points are so close, they can be considered as one
// thus, don't accept, since split 2 must be another vertex
if (SameVertice(pv, &lastpv))
2014-03-15 16:59:03 +00:00
{
if (pe < 0)
{
ps = i;
psonline = 1;
}
else
{
pe = i;
peonline = 1;
}
2014-03-15 16:59:03 +00:00
}
else
{
if (pe < 0)
2014-03-15 16:59:03 +00:00
{
pe = i;
ve = *pv;
frace = bspfrac;
2014-03-15 16:59:03 +00:00
}
else
{
// a frac, not same vertice as last one
// we already got pt2 so pt 2 is not on the line,
// so we probably got back to the start point
// which is on the line
if (SameVertice(pv, &vs))
psonline = 1;
break;
2014-03-15 16:59:03 +00:00
}
}
}
// remember last point intercept to detect identical points
lastpv = *pv;
2014-03-15 16:59:03 +00:00
}
// no split: the partition line is either parallel and
// aligned with one of the poly segments, or the line is totally
// out of the polygon and doesn't traverse it (happens if the bsp
// is fooled by some trick where the sidedefs don't point to
// the right sectors)
if (ps < 0)
{
//I_Error("SplitPoly: did not split polygon (%d %d)\n"
// "debugpos %d",ps,pe,debugpos);
// this eventually happens with 'broken' BSP's that accept
// linedefs where each side point the same sector, that is:
// the deep water effect with the original Doom
/// \todo make sure front poly is to front of partition line?
*frontpoly = poly;
*backpoly = NULL;
return;
}
if (pe < 0)
2014-03-15 16:59:03 +00:00
{
//I_Error("SplitPoly: only one point for split line (%d %d)", ps, pe);
*frontpoly = poly;
*backpoly = NULL;
return;
}
if (pe <= ps)
I_Error("SplitPoly: invalid splitting line (%d %d)", ps, pe);
// number of points on each side, _not_ counting those
// that may lie just one the line
nptback = pe - ps - peonline;
nptfront = poly->numpts - peonline - psonline - nptback;
if (nptback > 0)
*backpoly = HWR_AllocPoly(2 + nptback);
else
*backpoly = NULL;
if (nptfront > 0)
2014-03-15 16:59:03 +00:00
*frontpoly = HWR_AllocPoly(2 + nptfront);
else
*frontpoly = NULL;
// generate FRONT poly
if (*frontpoly)
{
pv = (*frontpoly)->pts;
*pv++ = vs;
*pv++ = ve;
i = pe;
do
{
if (++i == poly->numpts)
i = 0;
*pv++ = poly->pts[i];
} while (i != ps && --nptfront);
}
// generate BACK poly
if (*backpoly)
{
pv = (*backpoly)->pts;
*pv++ = ve;
*pv++ = vs;
i = ps;
do
{
if (++i == poly->numpts)
i = 0;
*pv++ = poly->pts[i];
} while (i != pe && --nptback);
}
// make sure frontpoly is the one on the 'right' side
// of the partition line
if (fracs > frace)
{
poly_t *swappoly;
swappoly = *backpoly;
*backpoly = *frontpoly;
*frontpoly = swappoly;
}
HWR_FreePoly (poly);
}
// use each seg of the poly as a partition line, keep only the
// part of the convex poly to the front of the seg (that is,
// the part inside the sector), the part behind the seg, is
// the void space and is cut out
//
static poly_t *CutOutSubsecPoly(seg_t *lseg, INT32 count, poly_t *poly)
{
INT32 i, j;
polyvertex_t *pv;
INT32 nump = 0, ps, pe;
polyvertex_t vs = {0, 0, 0}, ve = {0, 0, 0},
p1 = {0, 0, 0}, p2 = {0, 0, 0};
float fracs = 0.0f;
fdivline_t cutseg; // x, y, dx, dy as start of node_t struct
poly_t *temppoly;
// for each seg of the subsector
for (; count--; lseg++)
{
//x,y,dx,dy (like a divline)
line_t *line = lseg->linedef;
p1.x = FIXED_TO_FLOAT(lseg->side ? line->v2->x : line->v1->x);
p1.y = FIXED_TO_FLOAT(lseg->side ? line->v2->y : line->v1->y);
p2.x = FIXED_TO_FLOAT(lseg->side ? line->v1->x : line->v2->x);
p2.y = FIXED_TO_FLOAT(lseg->side ? line->v1->y : line->v2->y);
cutseg.x = p1.x;
cutseg.y = p1.y;
cutseg.dx = p2.x - p1.x;
cutseg.dy = p2.y - p1.y;
// see if it cuts the convex poly
ps = -1;
pe = -1;
for (i = 0; i < poly->numpts; i++)
{
j = i + 1;
if (j == poly->numpts)
j = 0;
pv = fracdivline(&cutseg, &poly->pts[i], &poly->pts[j]);
if (pv == NULL)
continue;
if (ps < 0)
2014-03-15 16:59:03 +00:00
{
ps = i;
vs = *pv;
fracs = bspfrac;
}
else
2014-03-15 16:59:03 +00:00
{
//frac 1 on previous segment,
// 0 on the next,
//the split line goes through one of the convex poly
// vertices, happens quite often since the convex
// poly is already adjacent to the subsector segs
// on most borders
if (SameVertice(pv, &vs))
continue;
if (fracs <= bspfrac)
2014-03-15 16:59:03 +00:00
{
nump = 2 + poly->numpts - (i-ps);
pe = ps;
2014-03-15 16:59:03 +00:00
ps = i;
ve = *pv;
2014-03-15 16:59:03 +00:00
}
else
{
nump = 2 + (i-ps);
pe = i;
ve = vs;
vs = *pv;
2014-03-15 16:59:03 +00:00
}
//found 2nd point
break;
2014-03-15 16:59:03 +00:00
}
}
// there was a split
if (ps >= 0)
{
//need 2 points
if (pe >= 0)
{
// generate FRONT poly
temppoly = HWR_AllocPoly(nump);
pv = temppoly->pts;
*pv++ = vs;
*pv++ = ve;
do
{
if (++ps == poly->numpts)
ps = 0;
*pv++ = poly->pts[ps];
} while (ps != pe);
HWR_FreePoly(poly);
poly = temppoly;
}
//hmmm... maybe we should NOT accept this, but this happens
// only when the cut is not needed it seems (when the cut
// line is aligned to one of the borders of the poly, and
// only some times..)
else
skipcut++;
// I_Error("CutOutPoly: only one point for split line (%d %d) %d", ps, pe, debugpos);
}
}
return poly;
}
// At this point, the poly should be convex and the exact
// layout of the subsector, it is not always the case,
// so continue to cut off the poly into smaller parts with
// each seg of the subsector.
//
static inline void HWR_SubsecPoly(INT32 num, poly_t *poly)
{
INT16 count;
subsector_t *sub;
seg_t *lseg;
sub = &subsectors[num];
count = sub->numlines;
lseg = &segs[sub->firstline];
if (poly)
{
poly = CutOutSubsecPoly (lseg,count,poly);
totalsubsecpolys++;
//extra data for this subsector
extrasubsectors[num].planepoly = poly;
}
}
// the bsp divline have not enouth presition
// search for the segs source of this divline
static inline void SearchDivline(node_t *bsp, fdivline_t *divline)
{
divline->x = FIXED_TO_FLOAT(bsp->x);
divline->y = FIXED_TO_FLOAT(bsp->y);
divline->dx = FIXED_TO_FLOAT(bsp->dx);
divline->dy = FIXED_TO_FLOAT(bsp->dy);
}
#ifdef HWR_LOADING_SCREEN
2014-03-15 16:59:03 +00:00
//Hurdler: implement a loading status
static size_t ls_count = 0;
static UINT8 ls_percent = 0;
static void loading_status(void)
{
char s[16];
int x, y;
I_OsPolling();
CON_Drawer();
sprintf(s, "%d%%", (++ls_percent)<<1);
x = BASEVIDWIDTH/2;
y = BASEVIDHEIGHT/2;
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Black background to match fade in effect
//V_DrawPatchFill(W_CachePatchName("SRB2BACK",PU_CACHE)); // SRB2 background, ehhh too bright.
M_DrawTextBox(x-58, y-8, 13, 1);
V_DrawString(x-50, y, V_YELLOWMAP, "Loading...");
V_DrawRightAlignedString(x+50, y, V_YELLOWMAP, s);
// Is this really necessary at this point..?
V_DrawCenteredString(BASEVIDWIDTH/2, 40, V_YELLOWMAP, "OPENGL MODE IS INCOMPLETE AND MAY");
V_DrawCenteredString(BASEVIDWIDTH/2, 50, V_YELLOWMAP, "NOT DISPLAY SOME SURFACES.");
V_DrawCenteredString(BASEVIDWIDTH/2, 70, V_YELLOWMAP, "USE AT SONIC'S RISK.");
I_UpdateNoVsync();
}
#endif
2014-03-15 16:59:03 +00:00
// poly : the convex polygon that encloses all child subsectors
static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *bbox)
{
node_t *bsp;
poly_t *backpoly, *frontpoly;
fdivline_t fdivline;
polyvertex_t *pt;
INT32 i;
// Found a subsector?
if (bspnum & NF_SUBSECTOR)
{
if (bspnum == -1)
{
// BP: i think this code is useless and wrong because
// - bspnum==-1 happens only when numsubsectors == 0
// - it can't happens in bsp recursive call since bspnum is a INT32 and children is UINT16
// - the BSP is complet !! (there just can have subsector without segs) (i am not sure of this point)
// do we have a valid polygon ?
if (poly && poly->numpts > 2)
{
CONS_Debug(DBG_RENDER, "Adding a new subsector\n");
if (addsubsector == numsubsectors + NEWSUBSECTORS)
I_Error("WalkBSPNode: not enough addsubsectors\n");
else if (addsubsector > 0x7fff)
I_Error("WalkBSPNode: addsubsector > 0x7fff\n");
*leafnode = (UINT16)((UINT16)addsubsector | NF_SUBSECTOR);
extrasubsectors[addsubsector].planepoly = poly;
addsubsector++;
}
//add subsectors without segs here?
//HWR_SubsecPoly(0, NULL);
}
else
{
2018-12-14 21:00:53 +00:00
HWR_SubsecPoly(bspnum & ~NF_SUBSECTOR, poly);
2014-03-15 16:59:03 +00:00
//Hurdler: implement a loading status
#ifdef HWR_LOADING_SCREEN
2014-03-15 16:59:03 +00:00
if (ls_count-- <= 0)
{
ls_count = numsubsectors/50;
loading_status();
2014-03-15 16:59:03 +00:00
}
#endif
2014-03-15 16:59:03 +00:00
}
M_ClearBox(bbox);
2018-12-14 21:00:53 +00:00
poly = extrasubsectors[bspnum & ~NF_SUBSECTOR].planepoly;
2014-03-15 16:59:03 +00:00
for (i = 0, pt = poly->pts; i < poly->numpts; i++,pt++)
M_AddToBox(bbox, FLOAT_TO_FIXED(pt->x), FLOAT_TO_FIXED(pt->y));
return;
}
bsp = &nodes[bspnum];
SearchDivline(bsp, &fdivline);
SplitPoly(&fdivline, poly, &frontpoly, &backpoly);
poly = NULL;
//debug
if (!backpoly)
nobackpoly++;
// Recursively divide front space.
if (frontpoly)
{
WalkBSPNode(bsp->children[0], frontpoly, &bsp->children[0],bsp->bbox[0]);
// copy child bbox
M_Memcpy(bbox, bsp->bbox[0], 4*sizeof (fixed_t));
}
else
I_Error("WalkBSPNode: no front poly?");
// Recursively divide back space.
if (backpoly)
{
// Correct back bbox to include floor/ceiling convex polygon
2018-12-14 21:00:53 +00:00
WalkBSPNode(bsp->children[1], backpoly, &bsp->children[1], bsp->bbox[1]);
2014-03-15 16:59:03 +00:00
2018-12-14 21:00:53 +00:00
// enlarge bbox with second child
2014-03-15 16:59:03 +00:00
M_AddToBox(bbox, bsp->bbox[1][BOXLEFT ],
2018-12-14 21:00:53 +00:00
bsp->bbox[1][BOXTOP ]);
2014-03-15 16:59:03 +00:00
M_AddToBox(bbox, bsp->bbox[1][BOXRIGHT ],
2018-12-14 21:00:53 +00:00
bsp->bbox[1][BOXBOTTOM]);
2014-03-15 16:59:03 +00:00
}
}
// FIXME: use Z_Malloc() STATIC ?
void HWR_FreeExtraSubsectors(void)
{
if (extrasubsectors)
free(extrasubsectors);
extrasubsectors = NULL;
}
#define MAXDIST 1.5f
// BP: can't move vertex: DON'T change polygon geometry! (convex)
//#define MOVEVERTEX
static boolean PointInSeg(polyvertex_t *a,polyvertex_t *v1,polyvertex_t *v2)
{
register float ax,ay,bx,by,cx,cy,d,norm;
register polyvertex_t *p;
// check bbox of the seg first
if (v1->x > v2->x)
{
p = v1;
v1 = v2;
v2 = p;
}
if (a->x < v1->x-MAXDIST || a->x > v2->x+MAXDIST)
return false;
if (v1->y > v2->y)
{
p = v1;
v1 = v2;
v2 = p;
}
if (a->y < v1->y-MAXDIST || a->y > v2->y+MAXDIST)
return false;
// v1 = origine
ax= v2->x-v1->x;
ay= v2->y-v1->y;
norm = (float)hypot(ax, ay);
ax /= norm;
ay /= norm;
bx = a->x-v1->x;
by = a->y-v1->y;
//d = a.b
d =ax*bx+ay*by;
// bound of the seg
if (d < 0 || d > norm)
return false;
//c = d.1a-b
cx = ax*d-bx;
cy = ay*d-by;
#ifdef MOVEVERTEX
if (cx*cx+cy*cy <= MAXDIST*MAXDIST)
{
// ajust a little the point position
a->x = ax*d+v1->x;
a->y = ay*d+v1->y;
// anyway the correction is not enouth
return true;
}
return false;
#else
return cx*cx+cy*cy <= MAXDIST*MAXDIST;
#endif
}
static INT32 numsplitpoly;
static void SearchSegInBSP(INT32 bspnum,polyvertex_t *p,poly_t *poly)
{
poly_t *q;
INT32 j,k;
if (bspnum & NF_SUBSECTOR)
{
2018-12-14 21:00:53 +00:00
if (bspnum != -1)
2014-03-15 16:59:03 +00:00
{
2018-12-14 21:00:53 +00:00
bspnum &= ~NF_SUBSECTOR;
2014-03-15 16:59:03 +00:00
q = extrasubsectors[bspnum].planepoly;
if (poly == q || !q)
return;
for (j = 0; j < q->numpts; j++)
{
k = j+1;
if (k == q->numpts) k = 0;
if (!SameVertice(p, &q->pts[j])
&& !SameVertice(p, &q->pts[k])
&& PointInSeg(p, &q->pts[j],
&q->pts[k]))
{
poly_t *newpoly = HWR_AllocPoly(q->numpts+1);
INT32 n;
for (n = 0; n <= j; n++)
newpoly->pts[n] = q->pts[n];
newpoly->pts[k] = *p;
for (n = k+1; n < newpoly->numpts; n++)
newpoly->pts[n] = q->pts[n-1];
numsplitpoly++;
extrasubsectors[bspnum].planepoly =
newpoly;
HWR_FreePoly(q);
return;
}
}
}
return;
}
if ((FIXED_TO_FLOAT(nodes[bspnum].bbox[0][BOXBOTTOM])-MAXDIST <= p->y) &&
(FIXED_TO_FLOAT(nodes[bspnum].bbox[0][BOXTOP ])+MAXDIST >= p->y) &&
(FIXED_TO_FLOAT(nodes[bspnum].bbox[0][BOXLEFT ])-MAXDIST <= p->x) &&
(FIXED_TO_FLOAT(nodes[bspnum].bbox[0][BOXRIGHT ])+MAXDIST >= p->x))
SearchSegInBSP(nodes[bspnum].children[0],p,poly);
if ((FIXED_TO_FLOAT(nodes[bspnum].bbox[1][BOXBOTTOM])-MAXDIST <= p->y) &&
(FIXED_TO_FLOAT(nodes[bspnum].bbox[1][BOXTOP ])+MAXDIST >= p->y) &&
(FIXED_TO_FLOAT(nodes[bspnum].bbox[1][BOXLEFT ])-MAXDIST <= p->x) &&
(FIXED_TO_FLOAT(nodes[bspnum].bbox[1][BOXRIGHT ])+MAXDIST >= p->x))
SearchSegInBSP(nodes[bspnum].children[1],p,poly);
}
// search for T-intersection problem
// BP : It can be mush more faster doing this at the same time of the splitpoly
// but we must use a different structure : polygone pointing on segs
// segs pointing on polygone and on vertex (too mush complicated, well not
// realy but i am soo lasy), the methode discibed is also better for segs presition
static INT32 SolveTProblem(void)
{
poly_t *p;
INT32 i;
size_t l;
if (cv_grsolvetjoin.value == 0)
return 0;
CONS_Debug(DBG_RENDER, "Solving T-joins. This may take a while. Please wait...\n");
2019-09-09 00:37:24 +00:00
#ifdef HWR_LOADING_SCREEN
2014-03-15 16:59:03 +00:00
CON_Drawer(); //let the user know what we are doing
I_FinishUpdate(); // page flip or blit buffer
2019-09-09 00:37:24 +00:00
#endif
2014-03-15 16:59:03 +00:00
numsplitpoly = 0;
for (l = 0; l < addsubsector; l++)
{
p = extrasubsectors[l].planepoly;
if (p)
for (i = 0; i < p->numpts; i++)
SearchSegInBSP((INT32)numnodes-1, &p->pts[i], p);
}
//CONS_Debug(DBG_RENDER, "numsplitpoly %d\n", numsplitpoly);
return numsplitpoly;
}
#define NEARDIST (0.75f)
#define MYMAX (10000000000000.0f)
/* Adjust true segs (from the segs lump) to be exactely the same as
* plane polygone segs
* This also convert fixed_t point of segs in float (in moste case
* it share the same vertice
*/
static void AdjustSegs(void)
{
size_t i, count;
INT32 j;
seg_t *lseg;
poly_t *p;
INT32 v1found = 0, v2found = 0;
float nearv1, nearv2;
for (i = 0; i < numsubsectors; i++)
{
count = subsectors[i].numlines;
lseg = &segs[subsectors[i].firstline];
p = extrasubsectors[i].planepoly;
//if (!p)
//continue;
2014-03-15 16:59:03 +00:00
for (; count--; lseg++)
{
float distv1,distv2,tmp;
nearv1 = nearv2 = MYMAX;
#ifdef POLYOBJECTS
// Don't touch polyobject segs. We'll compensate
// for this when we go about drawing them.
if (lseg->polyseg)
continue;
#endif
if (p) {
for (j = 0; j < p->numpts; j++)
2014-03-15 16:59:03 +00:00
{
distv1 = p->pts[j].x - FIXED_TO_FLOAT(lseg->v1->x);
tmp = p->pts[j].y - FIXED_TO_FLOAT(lseg->v1->y);
distv1 = distv1*distv1+tmp*tmp;
if (distv1 <= nearv1)
{
v1found = j;
nearv1 = distv1;
}
// the same with v2
distv2 = p->pts[j].x - FIXED_TO_FLOAT(lseg->v2->x);
tmp = p->pts[j].y - FIXED_TO_FLOAT(lseg->v2->y);
distv2 = distv2*distv2+tmp*tmp;
if (distv2 <= nearv2)
{
v2found = j;
nearv2 = distv2;
}
2014-03-15 16:59:03 +00:00
}
}
if (p && nearv1 <= NEARDIST*NEARDIST)
2014-03-15 16:59:03 +00:00
// share vertice with segs
lseg->pv1 = &(p->pts[v1found]);
2014-03-15 16:59:03 +00:00
else
{
// BP: here we can do better, using PointInSeg and compute
// the right point position also split a polygone side to
// solve a T-intersection, but too mush work
// convert fixed vertex to float vertex
polyvertex_t *pv = HWR_AllocVertex();
pv->x = FIXED_TO_FLOAT(lseg->v1->x);
pv->y = FIXED_TO_FLOAT(lseg->v1->y);
lseg->pv1 = pv;
2014-03-15 16:59:03 +00:00
}
if (p && nearv2 <= NEARDIST*NEARDIST)
lseg->pv2 = &(p->pts[v2found]);
2014-03-15 16:59:03 +00:00
else
{
polyvertex_t *pv = HWR_AllocVertex();
pv->x = FIXED_TO_FLOAT(lseg->v2->x);
pv->y = FIXED_TO_FLOAT(lseg->v2->y);
lseg->pv2 = pv;
2014-03-15 16:59:03 +00:00
}
// recompute length
{
float x,y;
x = ((polyvertex_t *)lseg->pv2)->x - ((polyvertex_t *)lseg->pv1)->x
2014-03-15 16:59:03 +00:00
+ FIXED_TO_FLOAT(FRACUNIT/2);
y = ((polyvertex_t *)lseg->pv2)->y - ((polyvertex_t *)lseg->pv1)->y
2014-03-15 16:59:03 +00:00
+ FIXED_TO_FLOAT(FRACUNIT/2);
lseg->flength = (float)hypot(x, y);
// BP: debug see this kind of segs
//if (nearv2 > NEARDIST*NEARDIST || nearv1 > NEARDIST*NEARDIST)
// lseg->length = 1;
}
}
}
}
// call this routine after the BSP of a Doom wad file is loaded,
// and it will generate all the convex polys for the hardware renderer
void HWR_CreatePlanePolygons(INT32 bspnum)
{
poly_t *rootp;
polyvertex_t *rootpv;
size_t i;
fixed_t rootbbox[4];
CONS_Debug(DBG_RENDER, "Creating polygons, please wait...\n");
#ifdef HWR_LOADING_SCREEN
2014-03-15 16:59:03 +00:00
ls_count = ls_percent = 0; // reset the loading status
CON_Drawer(); //let the user know what we are doing
I_FinishUpdate(); // page flip or blit buffer
2019-09-09 00:37:24 +00:00
#endif
2014-03-15 16:59:03 +00:00
HWR_ClearPolys();
// find min/max boundaries of map
//CONS_Debug(DBG_RENDER, "Looking for boundaries of map...\n");
M_ClearBox(rootbbox);
for (i = 0;i < numvertexes; i++)
M_AddToBox(rootbbox, vertexes[i].x, vertexes[i].y);
//CONS_Debug(DBG_RENDER, "Generating subsector polygons... %d subsectors\n", numsubsectors);
HWR_FreeExtraSubsectors();
// allocate extra data for each subsector present in map
totsubsectors = numsubsectors + NEWSUBSECTORS;
extrasubsectors = calloc(totsubsectors, sizeof (*extrasubsectors));
if (extrasubsectors == NULL)
I_Error("couldn't malloc extrasubsectors totsubsectors %s\n", sizeu1(totsubsectors));
// allocate table for back to front drawing of subsectors
/*gr_drawsubsectors = (INT16 *)malloc(sizeof (*gr_drawsubsectors) * totsubsectors);
if (!gr_drawsubsectors)
I_Error("couldn't malloc gr_drawsubsectors\n");*/
// number of the first new subsector that might be added
addsubsector = numsubsectors;
// construct the initial convex poly that encloses the full map
rootp = HWR_AllocPoly(4);
rootpv = rootp->pts;
rootpv->x = FIXED_TO_FLOAT(rootbbox[BOXLEFT ]);
rootpv->y = FIXED_TO_FLOAT(rootbbox[BOXBOTTOM]); //lr
rootpv++;
rootpv->x = FIXED_TO_FLOAT(rootbbox[BOXLEFT ]);
rootpv->y = FIXED_TO_FLOAT(rootbbox[BOXTOP ]); //ur
rootpv++;
rootpv->x = FIXED_TO_FLOAT(rootbbox[BOXRIGHT ]);
rootpv->y = FIXED_TO_FLOAT(rootbbox[BOXTOP ]); //ul
rootpv++;
rootpv->x = FIXED_TO_FLOAT(rootbbox[BOXRIGHT ]);
rootpv->y = FIXED_TO_FLOAT(rootbbox[BOXBOTTOM]); //ll
rootpv++;
WalkBSPNode(bspnum, rootp, NULL,rootbbox);
i = SolveTProblem();
//CONS_Debug(DBG_RENDER, "%d point divides a polygon line\n",i);
AdjustSegs();
//debug debug..
//if (nobackpoly)
// CONS_Debug(DBG_RENDER, "no back polygon %u times\n",nobackpoly);
//"(should happen only with the deep water trick)"
//if (skipcut)
// CONS_Debug(DBG_RENDER, "%u cuts were skipped because of only one point\n",skipcut);
//CONS_Debug(DBG_RENDER, "done: %u total subsector convex polygons\n", totalsubsecpolys);
}
#endif //HWRENDER