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

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