mirror of
https://github.com/nzp-team/vhlt.git
synced 2024-11-24 21:02:22 +00:00
1167 lines
30 KiB
C++
1167 lines
30 KiB
C++
#include "bsp5.h"
|
|
|
|
// WriteClipNodes_r
|
|
// WriteClipNodes
|
|
// WriteDrawLeaf
|
|
// WriteFace
|
|
// WriteDrawNodes_r
|
|
// FreeDrawNodes_r
|
|
// WriteDrawNodes
|
|
// BeginBSPFile
|
|
// FinishBSPFile
|
|
|
|
#include <map>
|
|
|
|
typedef std::map< int, int > PlaneMap;
|
|
static PlaneMap gPlaneMap;
|
|
static int gNumMappedPlanes;
|
|
static dplane_t gMappedPlanes[MAX_MAP_PLANES];
|
|
extern bool g_noopt;
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
typedef std::map< int, int > texinfomap_t;
|
|
static int g_nummappedtexinfo;
|
|
static texinfo_t g_mappedtexinfo[MAX_MAP_TEXINFO];
|
|
static texinfomap_t g_texinfomap;
|
|
#endif
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
int count_mergedclipnodes;
|
|
typedef std::map< std::pair< int, std::pair< int, int > >, int > clipnodemap_t;
|
|
inline clipnodemap_t::key_type MakeKey (const dclipnode_t &c)
|
|
{
|
|
return std::make_pair (c.planenum, std::make_pair (c.children[0], c.children[1]));
|
|
}
|
|
#endif
|
|
|
|
// =====================================================================================
|
|
// WritePlane
|
|
// hook for plane optimization
|
|
// =====================================================================================
|
|
static int WritePlane(int planenum)
|
|
{
|
|
planenum = planenum & (~1);
|
|
|
|
if(g_noopt)
|
|
{
|
|
return planenum;
|
|
}
|
|
|
|
PlaneMap::iterator item = gPlaneMap.find(planenum);
|
|
if(item != gPlaneMap.end())
|
|
{
|
|
return item->second;
|
|
}
|
|
//add plane to BSP
|
|
hlassume(gNumMappedPlanes < MAX_MAP_PLANES, assume_MAX_MAP_PLANES);
|
|
gMappedPlanes[gNumMappedPlanes] = g_dplanes[planenum];
|
|
gPlaneMap.insert(PlaneMap::value_type(planenum,gNumMappedPlanes));
|
|
|
|
return gNumMappedPlanes++;
|
|
}
|
|
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
|
|
// =====================================================================================
|
|
// WriteTexinfo
|
|
// =====================================================================================
|
|
static int WriteTexinfo (int texinfo)
|
|
{
|
|
if (texinfo < 0 || texinfo >= g_numtexinfo)
|
|
{
|
|
Error ("Bad texinfo number %d.\n", texinfo);
|
|
}
|
|
|
|
if (g_noopt)
|
|
{
|
|
return texinfo;
|
|
}
|
|
|
|
texinfomap_t::iterator it;
|
|
it = g_texinfomap.find (texinfo);
|
|
if (it != g_texinfomap.end ())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
int c;
|
|
hlassume (g_nummappedtexinfo < MAX_MAP_TEXINFO, assume_MAX_MAP_TEXINFO);
|
|
c = g_nummappedtexinfo;
|
|
g_mappedtexinfo[g_nummappedtexinfo] = g_texinfo[texinfo];
|
|
g_texinfomap.insert (texinfomap_t::value_type (texinfo, g_nummappedtexinfo));
|
|
g_nummappedtexinfo++;
|
|
return c;
|
|
}
|
|
|
|
#endif
|
|
// =====================================================================================
|
|
// WriteClipNodes_r
|
|
// =====================================================================================
|
|
static int WriteClipNodes_r(node_t* node
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
, const node_t *portalleaf
|
|
#endif
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
, clipnodemap_t *outputmap
|
|
#endif
|
|
)
|
|
{
|
|
int i, c;
|
|
dclipnode_t* cn;
|
|
int num;
|
|
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
if (node->isportalleaf)
|
|
{
|
|
if (node->contents == CONTENTS_SOLID)
|
|
{
|
|
free (node);
|
|
return CONTENTS_SOLID;
|
|
}
|
|
else
|
|
{
|
|
portalleaf = node;
|
|
}
|
|
}
|
|
if (node->planenum == -1)
|
|
{
|
|
if (node->iscontentsdetail)
|
|
{
|
|
num = CONTENTS_SOLID;
|
|
}
|
|
else
|
|
{
|
|
num = portalleaf->contents;
|
|
}
|
|
free (node->markfaces);
|
|
free (node);
|
|
return num;
|
|
}
|
|
#else
|
|
if (node->planenum == -1)
|
|
{
|
|
num = node->contents;
|
|
free(node->markfaces);
|
|
free(node);
|
|
return num;
|
|
}
|
|
#endif
|
|
|
|
#ifdef ZHLT_XASH2
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
dclipnode_t tmpclipnode; // this clipnode will be inserted into g_dclipnodes[c] if it can't be merged
|
|
cn = &tmpclipnode;
|
|
c = g_numclipnodes[g_hullnum - 1];
|
|
g_numclipnodes[g_hullnum - 1]++;
|
|
#else
|
|
// emit a clipnode
|
|
hlassume(g_numclipnodes[g_hullnum - 1] < MAX_MAP_CLIPNODES, assume_MAX_MAP_CLIPNODES);
|
|
|
|
c = g_numclipnodes[g_hullnum - 1];
|
|
cn = &g_dclipnodes[g_hullnum - 1][g_numclipnodes];
|
|
g_numclipnodes[g_hullnum - 1]++;
|
|
#endif
|
|
#else
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
dclipnode_t tmpclipnode; // this clipnode will be inserted into g_dclipnodes[c] if it can't be merged
|
|
cn = &tmpclipnode;
|
|
c = g_numclipnodes;
|
|
g_numclipnodes++;
|
|
#else
|
|
// emit a clipnode
|
|
hlassume(g_numclipnodes < MAX_MAP_CLIPNODES, assume_MAX_MAP_CLIPNODES);
|
|
|
|
c = g_numclipnodes;
|
|
cn = &g_dclipnodes[g_numclipnodes];
|
|
g_numclipnodes++;
|
|
#endif
|
|
#endif
|
|
if (node->planenum & 1)
|
|
{
|
|
Error("WriteClipNodes_r: odd planenum");
|
|
}
|
|
cn->planenum = WritePlane(node->planenum);
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
cn->children[i] = WriteClipNodes_r(node->children[i]
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
, portalleaf
|
|
#endif
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
, outputmap
|
|
#endif
|
|
);
|
|
}
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
clipnodemap_t::iterator output;
|
|
output = outputmap->find (MakeKey (*cn));
|
|
if (g_noclipnodemerge || output == outputmap->end ())
|
|
{
|
|
hlassume (c < MAX_MAP_CLIPNODES, assume_MAX_MAP_CLIPNODES);
|
|
#ifdef ZHLT_XASH2
|
|
g_dclipnodes[g_hullnum - 1][c] = *cn;
|
|
#else
|
|
g_dclipnodes[c] = *cn;
|
|
#endif
|
|
(*outputmap)[MakeKey (*cn)] = c;
|
|
}
|
|
else
|
|
{
|
|
count_mergedclipnodes++;
|
|
#ifdef ZHLT_XASH2
|
|
if (g_numclipnodes[g_hullnum - 1] != c + 1)
|
|
{
|
|
Error ("Merge clipnodes: internal error");
|
|
}
|
|
g_numclipnodes[g_hullnum - 1] = c;
|
|
#else
|
|
if (g_numclipnodes != c + 1)
|
|
{
|
|
Error ("Merge clipnodes: internal error");
|
|
}
|
|
g_numclipnodes = c;
|
|
#endif
|
|
c = output->second; // use existing clipnode
|
|
}
|
|
#endif
|
|
|
|
free(node);
|
|
return c;
|
|
}
|
|
|
|
// =====================================================================================
|
|
// WriteClipNodes
|
|
// Called after the clipping hull is completed. Generates a disk format
|
|
// representation and frees the original memory.
|
|
// =====================================================================================
|
|
void WriteClipNodes(node_t* nodes)
|
|
{
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
// we only merge among the clipnodes of the same hull of the same model
|
|
clipnodemap_t outputmap;
|
|
#endif
|
|
WriteClipNodes_r(nodes
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
, NULL
|
|
#endif
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
, &outputmap
|
|
#endif
|
|
);
|
|
}
|
|
|
|
// =====================================================================================
|
|
// WriteDrawLeaf
|
|
// =====================================================================================
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
static int WriteDrawLeaf (node_t *node, const node_t *portalleaf)
|
|
#else
|
|
static void WriteDrawLeaf(const node_t* const node)
|
|
#endif
|
|
{
|
|
face_t** fp;
|
|
face_t* f;
|
|
dleaf_t* leaf_p;
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
int leafnum = g_numleafs;
|
|
#endif
|
|
|
|
// emit a leaf
|
|
#ifdef ZHLT_MAX_MAP_LEAFS
|
|
hlassume (g_numleafs < MAX_MAP_LEAFS, assume_MAX_MAP_LEAFS);
|
|
#endif
|
|
leaf_p = &g_dleafs[g_numleafs];
|
|
g_numleafs++;
|
|
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
leaf_p->contents = portalleaf->contents;
|
|
#else
|
|
leaf_p->contents = node->contents;
|
|
#endif
|
|
|
|
//
|
|
// write bounding box info
|
|
//
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
#ifdef HLBSP_DETAILBRUSH_CULL
|
|
vec3_t mins, maxs;
|
|
#if 0
|
|
printf ("leaf isdetail = %d loosebound = (%f,%f,%f)-(%f,%f,%f) portalleaf = (%f,%f,%f)-(%f,%f,%f)\n", node->isdetail,
|
|
node->loosemins[0], node->loosemins[1], node->loosemins[2], node->loosemaxs[0], node->loosemaxs[1], node->loosemaxs[2],
|
|
portalleaf->mins[0], portalleaf->mins[1], portalleaf->mins[2], portalleaf->maxs[0], portalleaf->maxs[1], portalleaf->maxs[2]);
|
|
#endif
|
|
if (node->isdetail)
|
|
{
|
|
// intersect its loose bounds with the strict bounds of its parent portalleaf
|
|
VectorCompareMaximum (portalleaf->mins, node->loosemins, mins);
|
|
VectorCompareMinimum (portalleaf->maxs, node->loosemaxs, maxs);
|
|
}
|
|
else
|
|
{
|
|
VectorCopy (node->mins, mins);
|
|
VectorCopy (node->maxs, maxs);
|
|
}
|
|
#ifdef ZHLT_LARGERANGE
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
leaf_p->mins[k] = (short)qmax (-32767, qmin ((int)mins[k], 32767));
|
|
leaf_p->maxs[k] = (short)qmax (-32767, qmin ((int)maxs[k], 32767));
|
|
}
|
|
#else
|
|
VectorCopy (mins, leaf_p->mins);
|
|
VectorCopy (maxs, leaf_p->maxs);
|
|
#endif
|
|
#else
|
|
#ifdef ZHLT_LARGERANGE
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
leaf_p->mins[k] = (short)qmax (-32767, qmin ((int)portalleaf->mins[k], 32767));
|
|
leaf_p->maxs[k] = (short)qmax (-32767, qmin ((int)portalleaf->maxs[k], 32767));
|
|
}
|
|
#else
|
|
VectorCopy (portalleaf->mins, leaf_p->mins);
|
|
VectorCopy (portalleaf->maxs, leaf_p->maxs);
|
|
#endif
|
|
#endif
|
|
#else
|
|
#ifdef ZHLT_LARGERANGE
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
leaf_p->mins[k] = (short)qmax (-32767, qmin ((int)node->mins[k], 32767));
|
|
leaf_p->maxs[k] = (short)qmax (-32767, qmin ((int)node->maxs[k], 32767));
|
|
}
|
|
#else
|
|
VectorCopy(node->mins, leaf_p->mins);
|
|
VectorCopy(node->maxs, leaf_p->maxs);
|
|
#endif
|
|
#endif
|
|
|
|
leaf_p->visofs = -1; // no vis info yet
|
|
|
|
//
|
|
// write the marksurfaces
|
|
//
|
|
leaf_p->firstmarksurface = g_nummarksurfaces;
|
|
|
|
hlassume(node->markfaces != NULL, assume_EmptySolid);
|
|
|
|
for (fp = node->markfaces; *fp; fp++)
|
|
{
|
|
// emit a marksurface
|
|
f = *fp;
|
|
do
|
|
{
|
|
#ifdef HLBSP_NULLFACEOUTPUT_FIX
|
|
// fix face 0 being seen everywhere
|
|
if (f->outputnumber == -1)
|
|
{
|
|
f = f->original;
|
|
continue;
|
|
}
|
|
#endif
|
|
#if defined(HLBSP_HIDDENFACE) || defined(ZHLT_HIDDENSOUNDTEXTURE)
|
|
bool ishidden = false;
|
|
{
|
|
const char *name = GetTextureByNumber (f->texturenum);
|
|
if (strlen (name) >= 7 && !strcasecmp (&name[strlen (name) - 7], "_HIDDEN"))
|
|
{
|
|
ishidden = true;
|
|
}
|
|
#ifdef ZHLT_HIDDENSOUNDTEXTURE
|
|
if (f->texturenum >= 0 && (g_texinfo[f->texturenum].flags & TEX_SHOULDHIDE))
|
|
{
|
|
ishidden = true;
|
|
}
|
|
#endif
|
|
}
|
|
if (ishidden)
|
|
{
|
|
f = f->original;
|
|
continue;
|
|
}
|
|
#endif
|
|
g_dmarksurfaces[g_nummarksurfaces] = f->outputnumber;
|
|
hlassume(g_nummarksurfaces < MAX_MAP_MARKSURFACES, assume_MAX_MAP_MARKSURFACES);
|
|
g_nummarksurfaces++;
|
|
f = f->original; // grab tjunction split faces
|
|
}
|
|
while (f);
|
|
}
|
|
free(node->markfaces);
|
|
|
|
leaf_p->nummarksurfaces = g_nummarksurfaces - leaf_p->firstmarksurface;
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
return leafnum;
|
|
#endif
|
|
}
|
|
|
|
// =====================================================================================
|
|
// WriteFace
|
|
// =====================================================================================
|
|
static void WriteFace(face_t* f)
|
|
{
|
|
dface_t* df;
|
|
int i;
|
|
int e;
|
|
|
|
if ( CheckFaceForHint(f)
|
|
|| CheckFaceForSkip(f)
|
|
#ifdef ZHLT_NULLTEX
|
|
|| CheckFaceForNull(f) // AJM
|
|
#endif
|
|
#ifdef HLCSG_HLBSP_SOLIDHINT
|
|
|| CheckFaceForDiscardable (f)
|
|
#endif
|
|
#ifdef HLCSG_HLBSP_VOIDTEXINFO
|
|
|| f->texturenum == -1
|
|
#endif
|
|
#ifdef HLBSP_REMOVECOVEREDFACES
|
|
|| f->referenced == 0 // this face is not referenced by any nonsolid leaf because it is completely covered by func_details
|
|
#endif
|
|
|
|
// =====================================================================================
|
|
//Cpt_Andrew - Env_Sky Check
|
|
// =====================================================================================
|
|
|| CheckFaceForEnv_Sky(f)
|
|
// =====================================================================================
|
|
|
|
)
|
|
{
|
|
#ifdef HLBSP_NULLFACEOUTPUT_FIX
|
|
f->outputnumber = -1;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
f->outputnumber = g_numfaces;
|
|
|
|
df = &g_dfaces[g_numfaces];
|
|
hlassume(g_numfaces < MAX_MAP_FACES, assume_MAX_MAP_FACES);
|
|
g_numfaces++;
|
|
|
|
df->planenum = WritePlane(f->planenum);
|
|
df->side = f->planenum & 1;
|
|
df->firstedge = g_numsurfedges;
|
|
df->numedges = f->numpoints;
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
df->texinfo = WriteTexinfo (f->texturenum);
|
|
#else
|
|
df->texinfo = f->texturenum;
|
|
#endif
|
|
for (i = 0; i < f->numpoints; i++)
|
|
{
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
e = f->outputedges[i];
|
|
#else
|
|
e = GetEdge(f->pts[i], f->pts[(i + 1) % f->numpoints], f);
|
|
#endif
|
|
hlassume(g_numsurfedges < MAX_MAP_SURFEDGES, assume_MAX_MAP_SURFEDGES);
|
|
g_dsurfedges[g_numsurfedges] = e;
|
|
g_numsurfedges++;
|
|
}
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
free (f->outputedges);
|
|
f->outputedges = NULL;
|
|
#endif
|
|
}
|
|
|
|
// =====================================================================================
|
|
// WriteDrawNodes_r
|
|
// =====================================================================================
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
static int WriteDrawNodes_r (node_t *node, const node_t *portalleaf)
|
|
#else
|
|
static void WriteDrawNodes_r(const node_t* const node)
|
|
#endif
|
|
{
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
if (node->isportalleaf)
|
|
{
|
|
if (node->contents == CONTENTS_SOLID)
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
portalleaf = node;
|
|
// Warning: make sure parent data have not been freed when writing children.
|
|
}
|
|
}
|
|
if (node->planenum == -1)
|
|
{
|
|
if (node->iscontentsdetail)
|
|
{
|
|
free(node->markfaces);
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int leafnum = WriteDrawLeaf (node, portalleaf);
|
|
return -1 - leafnum;
|
|
}
|
|
}
|
|
#endif
|
|
dnode_t* n;
|
|
int i;
|
|
face_t* f;
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
int nodenum = g_numnodes;
|
|
#endif
|
|
|
|
// emit a node
|
|
hlassume(g_numnodes < MAX_MAP_NODES, assume_MAX_MAP_NODES);
|
|
n = &g_dnodes[g_numnodes];
|
|
g_numnodes++;
|
|
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
vec3_t mins, maxs;
|
|
#if 0
|
|
if (node->isdetail || node->isportalleaf)
|
|
printf ("node isdetail = %d loosebound = (%f,%f,%f)-(%f,%f,%f) portalleaf = (%f,%f,%f)-(%f,%f,%f)\n", node->isdetail,
|
|
node->loosemins[0], node->loosemins[1], node->loosemins[2], node->loosemaxs[0], node->loosemaxs[1], node->loosemaxs[2],
|
|
portalleaf->mins[0], portalleaf->mins[1], portalleaf->mins[2], portalleaf->maxs[0], portalleaf->maxs[1], portalleaf->maxs[2]);
|
|
#endif
|
|
if (node->isdetail)
|
|
{
|
|
#ifdef HLBSP_DETAILBRUSH_CULL
|
|
// intersect its loose bounds with the strict bounds of its parent portalleaf
|
|
VectorCompareMaximum (portalleaf->mins, node->loosemins, mins);
|
|
VectorCompareMinimum (portalleaf->maxs, node->loosemaxs, maxs);
|
|
#else
|
|
VectorCopy (portalleaf->mins, mins);
|
|
VectorCopy (portalleaf->maxs, maxs);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
VectorCopy (node->mins, mins);
|
|
VectorCopy (node->maxs, maxs);
|
|
}
|
|
#ifdef ZHLT_LARGERANGE
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
n->mins[k] = (short)qmax (-32767, qmin ((int)mins[k], 32767));
|
|
n->maxs[k] = (short)qmax (-32767, qmin ((int)maxs[k], 32767));
|
|
}
|
|
#else
|
|
VectorCopy (mins, n->mins);
|
|
VectorCopy (maxs, n->maxs);
|
|
#endif
|
|
#else
|
|
#ifdef ZHLT_LARGERANGE
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
n->mins[k] = (short)qmax (-32767, qmin ((int)node->mins[k], 32767));
|
|
n->maxs[k] = (short)qmax (-32767, qmin ((int)node->maxs[k], 32767));
|
|
}
|
|
#else
|
|
VectorCopy(node->mins, n->mins);
|
|
VectorCopy(node->maxs, n->maxs);
|
|
#endif
|
|
#endif
|
|
|
|
if (node->planenum & 1)
|
|
{
|
|
Error("WriteDrawNodes_r: odd planenum");
|
|
}
|
|
n->planenum = WritePlane(node->planenum);
|
|
n->firstface = g_numfaces;
|
|
|
|
for (f = node->faces; f; f = f->next)
|
|
{
|
|
WriteFace(f);
|
|
}
|
|
|
|
n->numfaces = g_numfaces - n->firstface;
|
|
|
|
//
|
|
// recursively output the other nodes
|
|
//
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
n->children[i] = WriteDrawNodes_r (node->children[i], portalleaf);
|
|
#else
|
|
if (node->children[i]->planenum == -1)
|
|
{
|
|
if (node->children[i]->contents == CONTENTS_SOLID)
|
|
{
|
|
n->children[i] = -1;
|
|
}
|
|
else
|
|
{
|
|
n->children[i] = -(g_numleafs + 1);
|
|
WriteDrawLeaf(node->children[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
n->children[i] = g_numnodes;
|
|
WriteDrawNodes_r(node->children[i]);
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
return nodenum;
|
|
#endif
|
|
}
|
|
|
|
// =====================================================================================
|
|
// FreeDrawNodes_r
|
|
// =====================================================================================
|
|
static void FreeDrawNodes_r(node_t* node)
|
|
{
|
|
int i;
|
|
face_t* f;
|
|
face_t* next;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
if (node->children[i]->planenum != -1)
|
|
{
|
|
FreeDrawNodes_r(node->children[i]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// free the faces on the node
|
|
//
|
|
for (f = node->faces; f; f = next)
|
|
{
|
|
next = f->next;
|
|
FreeFace(f);
|
|
}
|
|
|
|
free(node);
|
|
}
|
|
|
|
// =====================================================================================
|
|
// WriteDrawNodes
|
|
// Called after a drawing hull is completed
|
|
// Frees all nodes and faces
|
|
// =====================================================================================
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
void OutputEdges_face (face_t *f)
|
|
{
|
|
if (CheckFaceForHint(f)
|
|
|| CheckFaceForSkip(f)
|
|
#ifdef ZHLT_NULLTEX
|
|
|| CheckFaceForNull(f) // AJM
|
|
#endif
|
|
#ifdef HLCSG_HLBSP_SOLIDHINT
|
|
|| CheckFaceForDiscardable (f)
|
|
#endif
|
|
#ifdef HLCSG_HLBSP_VOIDTEXINFO
|
|
|| f->texturenum == -1
|
|
#endif
|
|
#ifdef HLBSP_REMOVECOVEREDFACES
|
|
|| f->referenced == 0
|
|
#endif
|
|
|| CheckFaceForEnv_Sky(f)//Cpt_Andrew - Env_Sky Check
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
f->outputedges = (int *)malloc (f->numpoints * sizeof (int));
|
|
hlassume (f->outputedges != NULL, assume_NoMemory);
|
|
int i;
|
|
for (i = 0; i < f->numpoints; i++)
|
|
{
|
|
int e = GetEdge (f->pts[i], f->pts[(i + 1) % f->numpoints], f);
|
|
f->outputedges[i] = e;
|
|
}
|
|
}
|
|
int OutputEdges_r (node_t *node, int detaillevel)
|
|
{
|
|
int next = -1;
|
|
if (node->planenum == -1)
|
|
{
|
|
return next;
|
|
}
|
|
face_t *f;
|
|
for (f = node->faces; f; f = f->next)
|
|
{
|
|
if (f->detaillevel > detaillevel)
|
|
{
|
|
if (next == -1? true: f->detaillevel < next)
|
|
{
|
|
next = f->detaillevel;
|
|
}
|
|
}
|
|
if (f->detaillevel == detaillevel)
|
|
{
|
|
OutputEdges_face (f);
|
|
}
|
|
}
|
|
int i;
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
int r = OutputEdges_r (node->children[i], detaillevel);
|
|
if (r == -1? false: next == -1? true: r < next)
|
|
{
|
|
next = r;
|
|
}
|
|
}
|
|
return next;
|
|
}
|
|
#endif
|
|
#ifdef HLBSP_REMOVECOVEREDFACES
|
|
static void RemoveCoveredFaces_r (node_t *node)
|
|
{
|
|
if (node->isportalleaf)
|
|
{
|
|
if (node->contents == CONTENTS_SOLID)
|
|
{
|
|
return; // stop here, don't go deeper into children
|
|
}
|
|
}
|
|
if (node->planenum == -1)
|
|
{
|
|
// this is a leaf
|
|
if (node->iscontentsdetail)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
face_t **fp;
|
|
for (fp = node->markfaces; *fp; fp++)
|
|
{
|
|
for (face_t *f = *fp; f; f = f->original) // for each tjunc subface
|
|
{
|
|
f->referenced++; // mark the face as referenced
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// this is a node
|
|
for (face_t *f = node->faces; f; f = f->next)
|
|
{
|
|
f->referenced = 0; // clear the mark
|
|
}
|
|
|
|
RemoveCoveredFaces_r (node->children[0]);
|
|
RemoveCoveredFaces_r (node->children[1]);
|
|
}
|
|
#endif
|
|
void WriteDrawNodes(node_t* headnode)
|
|
{
|
|
#ifdef ZHLT_DETAILBRUSH
|
|
#ifdef HLBSP_REMOVECOVEREDFACES
|
|
RemoveCoveredFaces_r (headnode); // fill "referenced" value
|
|
#endif
|
|
// higher detail level should not compete for edge pairing with lower detail level.
|
|
int detaillevel, nextdetaillevel;
|
|
for (detaillevel = 0; detaillevel != -1; detaillevel = nextdetaillevel)
|
|
{
|
|
nextdetaillevel = OutputEdges_r (headnode, detaillevel);
|
|
}
|
|
WriteDrawNodes_r (headnode, NULL);
|
|
#else
|
|
if (headnode->contents < 0)
|
|
{
|
|
WriteDrawLeaf(headnode);
|
|
}
|
|
else
|
|
{
|
|
WriteDrawNodes_r(headnode);
|
|
FreeDrawNodes_r(headnode);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// =====================================================================================
|
|
// BeginBSPFile
|
|
// =====================================================================================
|
|
void BeginBSPFile()
|
|
{
|
|
// these values may actually be initialized
|
|
// if the file existed when loaded, so clear them explicitly
|
|
gNumMappedPlanes = 0;
|
|
gPlaneMap.clear();
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
g_nummappedtexinfo = 0;
|
|
g_texinfomap.clear ();
|
|
#endif
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
count_mergedclipnodes = 0;
|
|
#endif
|
|
g_nummodels = 0;
|
|
g_numfaces = 0;
|
|
g_numnodes = 0;
|
|
#ifdef ZHLT_XASH2
|
|
for (int hull = 1; hull < MAX_MAP_HULLS; hull++)
|
|
{
|
|
g_numclipnodes[hull - 1] = 0;
|
|
}
|
|
#else
|
|
g_numclipnodes = 0;
|
|
#endif
|
|
g_numvertexes = 0;
|
|
g_nummarksurfaces = 0;
|
|
g_numsurfedges = 0;
|
|
|
|
// edge 0 is not used, because 0 can't be negated
|
|
g_numedges = 1;
|
|
|
|
// leaf 0 is common solid with no faces
|
|
g_numleafs = 1;
|
|
g_dleafs[0].contents = CONTENTS_SOLID;
|
|
}
|
|
|
|
// =====================================================================================
|
|
// FinishBSPFile
|
|
// =====================================================================================
|
|
void FinishBSPFile()
|
|
{
|
|
Verbose("--- FinishBSPFile ---\n");
|
|
|
|
#ifdef ZHLT_MAX_MAP_LEAFS
|
|
if (g_dmodels[0].visleafs > MAX_MAP_LEAFS_ENGINE)
|
|
{
|
|
Warning ("Number of world leaves(%d) exceeded MAX_MAP_LEAFS(%d)\nIf you encounter problems when running your map, consider this the most likely cause.\n", g_dmodels[0].visleafs, MAX_MAP_LEAFS_ENGINE);
|
|
}
|
|
#endif
|
|
#ifdef ZHLT_WARNWORLDFACES
|
|
if (g_dmodels[0].numfaces > MAX_MAP_WORLDFACES)
|
|
{
|
|
Warning ("Number of world faces(%d) exceeded %d. Some faces will disappear in game.\nTo reduce world faces, change some world brushes (including func_details) to func_walls.\n", g_dmodels[0].numfaces, MAX_MAP_WORLDFACES);
|
|
}
|
|
#endif
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
Developer (DEVELOPER_LEVEL_MESSAGE, "count_mergedclipnodes = %d\n", count_mergedclipnodes);
|
|
if (!g_noclipnodemerge)
|
|
{
|
|
#ifdef ZHLT_XASH2
|
|
int total = 0;
|
|
for (int hull = 1; hull < MAX_MAP_HULLS; hull++)
|
|
{
|
|
total += g_numclipnodes[hull - 1];
|
|
}
|
|
Log ("Reduced %d clipnodes to %d\n", total + count_mergedclipnodes, total);
|
|
#else
|
|
Log ("Reduced %d clipnodes to %d\n", g_numclipnodes + count_mergedclipnodes, g_numclipnodes);
|
|
#endif
|
|
}
|
|
#endif
|
|
if(!g_noopt)
|
|
{
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
{
|
|
Log ("Reduced %d texinfos to %d\n", g_numtexinfo, g_nummappedtexinfo);
|
|
for (int i = 0; i < g_nummappedtexinfo; i++)
|
|
{
|
|
g_texinfo[i] = g_mappedtexinfo[i];
|
|
}
|
|
g_numtexinfo = g_nummappedtexinfo;
|
|
}
|
|
{
|
|
dmiptexlump_t *l = (dmiptexlump_t *)g_dtexdata;
|
|
int &g_nummiptex = l->nummiptex;
|
|
bool *Used = (bool *)calloc (g_nummiptex, sizeof(bool));
|
|
int Num = 0, Size = 0;
|
|
int *Map = (int *)malloc (g_nummiptex * sizeof(int));
|
|
int i;
|
|
hlassume (Used != NULL && Map != NULL, assume_NoMemory);
|
|
int *lumpsizes = (int *)malloc (g_nummiptex * sizeof (int));
|
|
const int newdatasizemax = g_texdatasize - ((byte *)&l->dataofs[g_nummiptex] - (byte *)l);
|
|
byte *newdata = (byte *)malloc (newdatasizemax);
|
|
int newdatasize = 0;
|
|
hlassume (lumpsizes != NULL && newdata != NULL, assume_NoMemory);
|
|
int total = 0;
|
|
for (i = 0; i < g_nummiptex; i++)
|
|
{
|
|
if (l->dataofs[i] == -1)
|
|
{
|
|
lumpsizes[i] = -1;
|
|
continue;
|
|
}
|
|
lumpsizes[i] = g_texdatasize - l->dataofs[i];
|
|
for (int j = 0; j < g_nummiptex; j++)
|
|
{
|
|
int lumpsize = l->dataofs[j] - l->dataofs[i];
|
|
if (l->dataofs[j] == -1 || lumpsize < 0 || lumpsize == 0 && j <= i)
|
|
continue;
|
|
if (lumpsize < lumpsizes[i])
|
|
lumpsizes[i] = lumpsize;
|
|
}
|
|
total += lumpsizes[i];
|
|
}
|
|
if (total != newdatasizemax)
|
|
{
|
|
Warning ("Bad texdata structure.\n");
|
|
goto skipReduceTexdata;
|
|
}
|
|
for (i = 0; i < g_numtexinfo; i++)
|
|
{
|
|
texinfo_t *t = &g_texinfo[i];
|
|
if (t->miptex < 0 || t->miptex >= g_nummiptex)
|
|
{
|
|
Warning ("Bad miptex number %d.\n", t->miptex);
|
|
goto skipReduceTexdata;
|
|
}
|
|
Used[t->miptex] = true;
|
|
}
|
|
for (i = 0; i < g_nummiptex; i++)
|
|
{
|
|
const int MAXWADNAME = 16;
|
|
char name[MAXWADNAME];
|
|
int j, k;
|
|
if (l->dataofs[i] < 0)
|
|
continue;
|
|
if (Used[i] == true)
|
|
{
|
|
miptex_t *m = (miptex_t *)((byte *)l + l->dataofs[i]);
|
|
if (m->name[0] != '+' && m->name[0] != '-')
|
|
continue;
|
|
safe_strncpy (name, m->name, MAXWADNAME);
|
|
if (name[1] == '\0')
|
|
continue;
|
|
for (j = 0; j < 20; j++)
|
|
{
|
|
if (j < 10)
|
|
name[1] = '0' + j;
|
|
else
|
|
name[1] = 'A' + j - 10;
|
|
for (k = 0; k < g_nummiptex; k++)
|
|
{
|
|
if (l->dataofs[k] < 0)
|
|
continue;
|
|
miptex_t *m2 = (miptex_t *)((byte *)l + l->dataofs[k]);
|
|
if (!strcasecmp (name, m2->name))
|
|
Used[k] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < g_nummiptex; i++)
|
|
{
|
|
if (Used[i])
|
|
{
|
|
Map[i] = Num;
|
|
Num++;
|
|
}
|
|
else
|
|
{
|
|
Map[i] = -1;
|
|
}
|
|
}
|
|
for (i = 0; i < g_numtexinfo; i++)
|
|
{
|
|
texinfo_t *t = &g_texinfo[i];
|
|
t->miptex = Map[t->miptex];
|
|
}
|
|
Size += (byte *)&l->dataofs[Num] - (byte *)l;
|
|
for (i = 0; i < g_nummiptex; i++)
|
|
{
|
|
if (Used[i])
|
|
{
|
|
if (lumpsizes[i] == -1)
|
|
{
|
|
l->dataofs[Map[i]] = -1;
|
|
}
|
|
else
|
|
{
|
|
memcpy ((byte *)newdata + newdatasize, (byte *)l + l->dataofs[i], lumpsizes[i]);
|
|
l->dataofs[Map[i]] = Size;
|
|
newdatasize += lumpsizes[i];
|
|
Size += lumpsizes[i];
|
|
}
|
|
}
|
|
}
|
|
memcpy (&l->dataofs[Num], newdata, newdatasize);
|
|
Log ("Reduced %d texdatas to %d (%d bytes to %d)\n", g_nummiptex, Num, g_texdatasize, Size);
|
|
g_nummiptex = Num;
|
|
g_texdatasize = Size;
|
|
skipReduceTexdata:;
|
|
free (lumpsizes);
|
|
free (newdata);
|
|
free (Used);
|
|
free (Map);
|
|
}
|
|
Log ("Reduced %d planes to %d\n", g_numplanes, gNumMappedPlanes);
|
|
#endif
|
|
for(int counter = 0; counter < gNumMappedPlanes; counter++)
|
|
{
|
|
g_dplanes[counter] = gMappedPlanes[counter];
|
|
}
|
|
g_numplanes = gNumMappedPlanes;
|
|
}
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
else
|
|
{
|
|
hlassume (g_numtexinfo < MAX_MAP_TEXINFO, assume_MAX_MAP_TEXINFO);
|
|
hlassume (g_numplanes < MAX_MAP_PLANES, assume_MAX_MAP_PLANES);
|
|
}
|
|
#endif
|
|
#ifdef HLBSP_BRINKHACK
|
|
if (!g_nobrink)
|
|
{
|
|
Log ("FixBrinks:\n");
|
|
#ifdef ZHLT_XASH2
|
|
dclipnode_t *clipnodes[MAX_MAP_HULLS - 1];
|
|
int numclipnodes[MAX_MAP_HULLS - 1];
|
|
for (int hull = 1; hull < MAX_MAP_HULLS; hull++)
|
|
{
|
|
clipnodes[hull - 1] = (dclipnode_t *)malloc (MAX_MAP_CLIPNODES * sizeof (dclipnode_t));
|
|
hlassume (clipnodes[hull - 1] != NULL, assume_NoMemory);
|
|
}
|
|
#else
|
|
dclipnode_t *clipnodes; //[MAX_MAP_CLIPNODES]
|
|
int numclipnodes;
|
|
clipnodes = (dclipnode_t *)malloc (MAX_MAP_CLIPNODES * sizeof (dclipnode_t));
|
|
hlassume (clipnodes != NULL, assume_NoMemory);
|
|
#endif
|
|
void *(*brinkinfo)[NUM_HULLS]; //[MAX_MAP_MODELS]
|
|
int (*headnode)[NUM_HULLS]; //[MAX_MAP_MODELS]
|
|
brinkinfo = (void *(*)[NUM_HULLS])malloc (MAX_MAP_MODELS * sizeof (void *[NUM_HULLS]));
|
|
hlassume (brinkinfo != NULL, assume_NoMemory);
|
|
headnode = (int (*)[NUM_HULLS])malloc (MAX_MAP_MODELS * sizeof (int [NUM_HULLS]));
|
|
hlassume (headnode != NULL, assume_NoMemory);
|
|
|
|
int i, j, level;
|
|
for (i = 0; i < g_nummodels; i++)
|
|
{
|
|
dmodel_t *m = &g_dmodels[i];
|
|
Developer (DEVELOPER_LEVEL_MESSAGE, " model %d\n", i);
|
|
for (j = 1; j < NUM_HULLS; j++)
|
|
{
|
|
#ifdef ZHLT_XASH2
|
|
brinkinfo[i][j] = CreateBrinkinfo (g_dclipnodes[j - 1], m->headnode[j]);
|
|
#else
|
|
brinkinfo[i][j] = CreateBrinkinfo (g_dclipnodes, m->headnode[j]);
|
|
#endif
|
|
}
|
|
}
|
|
for (level = BrinkAny; level > BrinkNone; level--)
|
|
{
|
|
#ifdef ZHLT_XASH2
|
|
for (int hull = 1; hull < MAX_MAP_HULLS; hull++)
|
|
{
|
|
numclipnodes[hull - 1] = 0;
|
|
}
|
|
#else
|
|
numclipnodes = 0;
|
|
#endif
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
count_mergedclipnodes = 0;
|
|
#endif
|
|
for (i = 0; i < g_nummodels; i++)
|
|
{
|
|
for (j = 1; j < NUM_HULLS; j++)
|
|
{
|
|
#ifdef ZHLT_XASH2
|
|
if (!FixBrinks (brinkinfo[i][j], (bbrinklevel_e) level, headnode[i][j], clipnodes[j - 1], MAX_MAP_CLIPNODES, numclipnodes[j - 1], numclipnodes[j - 1]))
|
|
#else
|
|
if (!FixBrinks (brinkinfo[i][j], (bbrinklevel_e) level, headnode[i][j], clipnodes, MAX_MAP_CLIPNODES, numclipnodes, numclipnodes))
|
|
#endif
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (j < NUM_HULLS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == g_nummodels)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
for (i = 0; i < g_nummodels; i++)
|
|
{
|
|
for (j = 1; j < NUM_HULLS; j++)
|
|
{
|
|
DeleteBrinkinfo (brinkinfo[i][j]);
|
|
}
|
|
}
|
|
if (level == BrinkNone)
|
|
{
|
|
Warning ("No brinks have been fixed because clipnode data is almost full.");
|
|
}
|
|
else
|
|
{
|
|
if (level != BrinkAny)
|
|
{
|
|
Warning ("Not all brinks have been fixed because clipnode data is almost full.");
|
|
}
|
|
#ifdef HLBSP_MERGECLIPNODE
|
|
Developer (DEVELOPER_LEVEL_MESSAGE, "count_mergedclipnodes = %d\n", count_mergedclipnodes);
|
|
#endif
|
|
#ifdef ZHLT_XASH2
|
|
int g_numclipnodes_total = 0;
|
|
int numclipnodes_total = 0;
|
|
for (int hull = 1; hull < MAX_MAP_HULLS; hull++)
|
|
{
|
|
g_numclipnodes_total += g_numclipnodes[hull - 1];
|
|
numclipnodes_total += numclipnodes[hull - 1];
|
|
}
|
|
Log ("Increased %d clipnodes to %d.\n", g_numclipnodes_total, numclipnodes_total);
|
|
for (int hull = 1; hull < MAX_MAP_HULLS; hull++)
|
|
{
|
|
g_numclipnodes[hull - 1] = numclipnodes[hull - 1];
|
|
memcpy (g_dclipnodes[hull - 1], clipnodes[hull - 1], numclipnodes[hull - 1] * sizeof (dclipnode_t));
|
|
}
|
|
#else
|
|
Log ("Increased %d clipnodes to %d.\n", g_numclipnodes, numclipnodes);
|
|
g_numclipnodes = numclipnodes;
|
|
memcpy (g_dclipnodes, clipnodes, numclipnodes * sizeof (dclipnode_t));
|
|
#endif
|
|
for (i = 0; i < g_nummodels; i++)
|
|
{
|
|
dmodel_t *m = &g_dmodels[i];
|
|
for (j = 1; j < NUM_HULLS; j++)
|
|
{
|
|
m->headnode[j] = headnode[i][j];
|
|
}
|
|
}
|
|
}
|
|
free (brinkinfo);
|
|
free (headnode);
|
|
#ifdef ZHLT_XASH2
|
|
for (int hull = 1; hull < MAX_MAP_HULLS; hull++)
|
|
{
|
|
free (clipnodes[hull - 1]);
|
|
}
|
|
#else
|
|
free (clipnodes);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef ZHLT_HIDDENSOUNDTEXTURE
|
|
for (int i = 0; i < g_numtexinfo; i++)
|
|
{
|
|
g_texinfo[i].flags &= ~TEX_SHOULDHIDE;
|
|
}
|
|
#endif
|
|
#ifdef ZHLT_64BIT_FIX
|
|
#ifdef PLATFORM_CAN_CALC_EXTENT
|
|
WriteExtentFile (g_extentfilename);
|
|
#else
|
|
Warning ("The " PLATFORM_VERSIONSTRING " version of hlbsp couldn't create extent file. The lack of extent file may cause hlrad error.");
|
|
#endif
|
|
#endif
|
|
if (g_chart)
|
|
{
|
|
PrintBSPFileSizes();
|
|
}
|
|
|
|
#ifdef HLCSG_HLBSP_DOUBLEPLANE
|
|
#undef dplane_t // this allow us to temporarily access the raw data directly without the layer of indirection
|
|
#undef g_dplanes
|
|
for (int i = 0; i < g_numplanes; i++)
|
|
{
|
|
plane_t *mp = &g_mapplanes[i];
|
|
dplane_t *dp = &g_dplanes[i];
|
|
VectorCopy (mp->normal, dp->normal);
|
|
dp->dist = mp->dist;
|
|
dp->type = mp->type;
|
|
}
|
|
#define dplane_t plane_t
|
|
#define g_dplanes g_mapplanes
|
|
#endif
|
|
WriteBSPFile(g_bspfilename);
|
|
}
|