mirror of
https://github.com/nzp-team/vhlt.git
synced 2024-11-14 00:11:03 +00:00
433 lines
10 KiB
C++
433 lines
10 KiB
C++
//#pragma warning(disable: 4018) // '<' : signed/unsigned mismatch
|
|
|
|
#include "bsp5.h"
|
|
|
|
node_t g_outside_node; // portals outside the world face this
|
|
|
|
//=============================================================================
|
|
|
|
/*
|
|
* =============
|
|
* AddPortalToNodes
|
|
* =============
|
|
*/
|
|
void AddPortalToNodes(portal_t* p, node_t* front, node_t* back)
|
|
{
|
|
if (p->nodes[0] || p->nodes[1])
|
|
{
|
|
Error("AddPortalToNode: allready included");
|
|
}
|
|
|
|
p->nodes[0] = front;
|
|
p->next[0] = front->portals;
|
|
front->portals = p;
|
|
|
|
p->nodes[1] = back;
|
|
p->next[1] = back->portals;
|
|
back->portals = p;
|
|
}
|
|
|
|
/*
|
|
* =============
|
|
* RemovePortalFromNode
|
|
* =============
|
|
*/
|
|
void RemovePortalFromNode(portal_t* portal, node_t* l)
|
|
{
|
|
portal_t** pp;
|
|
portal_t* t;
|
|
|
|
// remove reference to the current portal
|
|
pp = &l->portals;
|
|
while (1)
|
|
{
|
|
t = *pp;
|
|
if (!t)
|
|
{
|
|
Error("RemovePortalFromNode: portal not in leaf");
|
|
}
|
|
|
|
if (t == portal)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (t->nodes[0] == l)
|
|
{
|
|
pp = &t->next[0];
|
|
}
|
|
else if (t->nodes[1] == l)
|
|
{
|
|
pp = &t->next[1];
|
|
}
|
|
else
|
|
{
|
|
Error("RemovePortalFromNode: portal not bounding leaf");
|
|
}
|
|
}
|
|
|
|
if (portal->nodes[0] == l)
|
|
{
|
|
*pp = portal->next[0];
|
|
portal->nodes[0] = NULL;
|
|
}
|
|
else if (portal->nodes[1] == l)
|
|
{
|
|
*pp = portal->next[1];
|
|
portal->nodes[1] = NULL;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
|
|
/*
|
|
* ================
|
|
* MakeHeadnodePortals
|
|
*
|
|
* The created portals will face the global g_outside_node
|
|
* ================
|
|
*/
|
|
void MakeHeadnodePortals(node_t* node, const vec3_t mins, const vec3_t maxs)
|
|
{
|
|
vec3_t bounds[2];
|
|
int i, j, n;
|
|
portal_t* p;
|
|
portal_t* portals[6];
|
|
dplane_t bplanes[6];
|
|
dplane_t* pl;
|
|
|
|
// pad with some space so there will never be null volume leafs
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
bounds[0][i] = mins[i] - SIDESPACE;
|
|
bounds[1][i] = maxs[i] + SIDESPACE;
|
|
}
|
|
|
|
g_outside_node.contents = CONTENTS_SOLID;
|
|
g_outside_node.portals = NULL;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
n = j * 3 + i;
|
|
|
|
p = AllocPortal();
|
|
portals[n] = p;
|
|
|
|
pl = &bplanes[n];
|
|
memset(pl, 0, sizeof(*pl));
|
|
if (j)
|
|
{
|
|
pl->normal[i] = -1;
|
|
pl->dist = -bounds[j][i];
|
|
}
|
|
else
|
|
{
|
|
pl->normal[i] = 1;
|
|
pl->dist = bounds[j][i];
|
|
}
|
|
p->plane = *pl;
|
|
p->winding = new Winding(*pl);
|
|
AddPortalToNodes(p, node, &g_outside_node);
|
|
}
|
|
}
|
|
|
|
// clip the basewindings by all the other planes
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
for (j = 0; j < 6; j++)
|
|
{
|
|
if (j == i)
|
|
{
|
|
continue;
|
|
}
|
|
portals[i]->winding->Clip(bplanes[j], true);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ==============================================================================
|
|
*
|
|
* PORTAL FILE GENERATION
|
|
*
|
|
* ==============================================================================
|
|
*/
|
|
|
|
static FILE* pf;
|
|
#ifdef HLBSP_VIEWPORTAL
|
|
static FILE *pf_view;
|
|
extern bool g_viewportal;
|
|
#endif
|
|
static int num_visleafs; // leafs the player can be in
|
|
static int num_visportals;
|
|
|
|
static void WritePortalFile_r(const node_t* const node)
|
|
{
|
|
int i;
|
|
portal_t* p;
|
|
Winding* w;
|
|
dplane_t plane2;
|
|
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
if (!node->isportalleaf)
|
|
#else
|
|
if (!node->contents)
|
|
#endif
|
|
{
|
|
WritePortalFile_r(node->children[0]);
|
|
WritePortalFile_r(node->children[1]);
|
|
return;
|
|
}
|
|
|
|
if (node->contents == CONTENTS_SOLID)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (p = node->portals; p;)
|
|
{
|
|
w = p->winding;
|
|
if (w && p->nodes[0] == node)
|
|
{
|
|
if (p->nodes[0]->contents == p->nodes[1]->contents)
|
|
{
|
|
// write out to the file
|
|
|
|
// sometimes planes get turned around when they are very near
|
|
// the changeover point between different axis. interpret the
|
|
// plane the same way vis will, and flip the side orders if needed
|
|
w->getPlane(plane2);
|
|
if (DotProduct(p->plane.normal, plane2.normal) < 1.0 - ON_EPSILON)
|
|
{ // backwards...
|
|
#ifdef ZHLT_WINDING_FIX
|
|
if (DotProduct(p->plane.normal, plane2.normal) > -1.0 + ON_EPSILON)
|
|
{
|
|
Warning ("Colinear portal @");
|
|
w->Print ();
|
|
}
|
|
else
|
|
{
|
|
Warning ("Backward portal @");
|
|
w->Print ();
|
|
}
|
|
#endif
|
|
fprintf(pf, "%u %i %i ", w->m_NumPoints, p->nodes[1]->visleafnum, p->nodes[0]->visleafnum);
|
|
}
|
|
else
|
|
{
|
|
fprintf(pf, "%u %i %i ", w->m_NumPoints, p->nodes[0]->visleafnum, p->nodes[1]->visleafnum);
|
|
}
|
|
|
|
for (i = 0; i < w->m_NumPoints; i++)
|
|
{
|
|
fprintf(pf, "(%f %f %f) ", w->m_Points[i][0], w->m_Points[i][1], w->m_Points[i][2]);
|
|
}
|
|
fprintf(pf, "\n");
|
|
#ifdef HLBSP_VIEWPORTAL
|
|
if (g_viewportal)
|
|
{
|
|
vec3_t center, center1, center2;
|
|
vec3_t from = {0.0, 0.0, -65536};
|
|
w->getCenter (center);
|
|
VectorMA (center, 0.5, p->plane.normal, center1);
|
|
VectorMA (center, -0.5, p->plane.normal, center2);
|
|
fprintf (pf_view, "%5.2f %5.2f %5.2f\n", from[0], from[1], from[2]);
|
|
fprintf (pf_view, "%5.2f %5.2f %5.2f\n", center1[0], center1[1], center1[2]);
|
|
for (i = 0; i < w->m_NumPoints; i++)
|
|
{
|
|
vec_t *p1, *p2;
|
|
p1 = w->m_Points[i];
|
|
p2 = w->m_Points[(i+1)%w->m_NumPoints];
|
|
fprintf (pf_view, "%5.2f %5.2f %5.2f\n", p1[0], p1[1], p1[2]);
|
|
fprintf (pf_view, "%5.2f %5.2f %5.2f\n", p2[0], p2[1], p2[2]);
|
|
fprintf (pf_view, "%5.2f %5.2f %5.2f\n", center2[0], center2[1], center2[2]);
|
|
fprintf (pf_view, "%5.2f %5.2f %5.2f\n", center1[0], center1[1], center1[2]);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (p->nodes[0] == node)
|
|
{
|
|
p = p->next[0];
|
|
}
|
|
else
|
|
{
|
|
p = p->next[1];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* ================
|
|
* NumberLeafs_r
|
|
* ================
|
|
*/
|
|
static void NumberLeafs_r(node_t* node)
|
|
{
|
|
portal_t* p;
|
|
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
if (!node->isportalleaf)
|
|
#else
|
|
if (!node->contents)
|
|
#endif
|
|
{ // decision node
|
|
node->visleafnum = -99;
|
|
NumberLeafs_r(node->children[0]);
|
|
NumberLeafs_r(node->children[1]);
|
|
return;
|
|
}
|
|
|
|
if (node->contents == CONTENTS_SOLID)
|
|
{ // solid block, viewpoint never inside
|
|
node->visleafnum = -1;
|
|
return;
|
|
}
|
|
|
|
node->visleafnum = num_visleafs++;
|
|
|
|
for (p = node->portals; p;)
|
|
{
|
|
if (p->nodes[0] == node) // only write out from first leaf
|
|
{
|
|
if (p->nodes[0]->contents == p->nodes[1]->contents)
|
|
{
|
|
num_visportals++;
|
|
}
|
|
p = p->next[0];
|
|
}
|
|
else
|
|
{
|
|
p = p->next[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
static int CountChildLeafs_r (node_t *node)
|
|
{
|
|
if (node->planenum == -1)
|
|
{ // dleaf
|
|
if (node->iscontentsdetail)
|
|
{ // solid
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{ // node
|
|
int count = 0;
|
|
count += CountChildLeafs_r (node->children[0]);
|
|
count += CountChildLeafs_r (node->children[1]);
|
|
return count;
|
|
}
|
|
}
|
|
static void WriteLeafCount_r (node_t *node)
|
|
{
|
|
if (!node->isportalleaf)
|
|
{
|
|
WriteLeafCount_r (node->children[0]);
|
|
WriteLeafCount_r (node->children[1]);
|
|
}
|
|
else
|
|
{
|
|
if (node->contents == CONTENTS_SOLID)
|
|
{
|
|
return;
|
|
}
|
|
int count = CountChildLeafs_r (node);
|
|
fprintf (pf, "%i\n", count);
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
* ================
|
|
* WritePortalfile
|
|
* ================
|
|
*/
|
|
void WritePortalfile(node_t* headnode)
|
|
{
|
|
// set the visleafnum field in every leaf and count the total number of portals
|
|
num_visleafs = 0;
|
|
num_visportals = 0;
|
|
NumberLeafs_r(headnode);
|
|
|
|
// write the file
|
|
pf = fopen(g_portfilename, "w");
|
|
if (!pf)
|
|
{
|
|
Error("Error writing portal file %s", g_portfilename);
|
|
}
|
|
#ifdef HLBSP_VIEWPORTAL
|
|
if (g_viewportal)
|
|
{
|
|
char filename[_MAX_PATH];
|
|
safe_snprintf(filename, _MAX_PATH, "%s_portal.pts", g_Mapname);
|
|
pf_view = fopen (filename, "w");
|
|
if (!pf_view)
|
|
{
|
|
Error ("Couldn't open %s", filename);
|
|
}
|
|
Log ("Writing '%s' ...\n", filename);
|
|
}
|
|
#endif
|
|
|
|
fprintf(pf, "%i\n", num_visleafs);
|
|
fprintf(pf, "%i\n", num_visportals);
|
|
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
WriteLeafCount_r (headnode);
|
|
#endif
|
|
WritePortalFile_r(headnode);
|
|
fclose(pf);
|
|
#ifdef HLBSP_VIEWPORTAL
|
|
if (g_viewportal)
|
|
{
|
|
fclose (pf_view);
|
|
}
|
|
#endif
|
|
Log("BSP generation successful, writing portal file '%s'\n", g_portfilename);
|
|
}
|
|
|
|
//===================================================
|
|
|
|
void FreePortals(node_t* node)
|
|
{
|
|
portal_t* p;
|
|
portal_t* nextp;
|
|
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
if (!node->isportalleaf)
|
|
#else
|
|
if (node->planenum != -1)
|
|
#endif
|
|
{
|
|
FreePortals(node->children[0]);
|
|
FreePortals(node->children[1]);
|
|
return;
|
|
}
|
|
|
|
for (p = node->portals; p; p = nextp)
|
|
{
|
|
if (p->nodes[0] == node)
|
|
{
|
|
nextp = p->next[0];
|
|
}
|
|
else
|
|
{
|
|
nextp = p->next[1];
|
|
}
|
|
RemovePortalFromNode(p, p->nodes[0]);
|
|
RemovePortalFromNode(p, p->nodes[1]);
|
|
delete p->winding;
|
|
FreePortal(p);
|
|
}
|
|
}
|