vhlt/hlbsp/portals.cpp
2016-09-21 00:07:53 +03:00

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);
}
}