mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-04 18:09:53 +03:00
1
This commit is contained in:
374
utils/vbsp/prtfile.cpp
Normal file
374
utils/vbsp/prtfile.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "vbsp.h"
|
||||
#include "collisionutils.h"
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
PORTAL FILE GENERATION
|
||||
|
||||
Save out name.prt for qvis to read
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#define PORTALFILE "PRT1"
|
||||
|
||||
struct cluster_portals_t
|
||||
{
|
||||
CUtlVector<portal_t *> portals;
|
||||
};
|
||||
|
||||
int num_visclusters; // clusters the player can be in
|
||||
int num_visportals;
|
||||
|
||||
int g_SkyCluster = -1;
|
||||
|
||||
void WriteFloat (FILE *f, vec_t v)
|
||||
{
|
||||
if ( fabs(v - RoundInt(v)) < 0.001 )
|
||||
fprintf (f,"%i ",(int)RoundInt(v));
|
||||
else
|
||||
fprintf (f,"%f ",v);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
WritePortalFile_r
|
||||
=================
|
||||
*/
|
||||
void WritePortalFile(FILE *pFile, const CUtlVector<cluster_portals_t> &list)
|
||||
{
|
||||
portal_t *p;
|
||||
winding_t *w;
|
||||
Vector normal;
|
||||
vec_t dist;
|
||||
|
||||
for ( int clusterIndex = 0; clusterIndex < list.Count(); clusterIndex++ )
|
||||
{
|
||||
for ( int j = 0; j < list[clusterIndex].portals.Count(); j++ )
|
||||
{
|
||||
p = list[clusterIndex].portals[j];
|
||||
w = p->winding;
|
||||
// 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
|
||||
// FIXME: is this still relevent?
|
||||
WindingPlane (w, normal, &dist);
|
||||
if ( DotProduct (p->plane.normal, normal) < 0.99 )
|
||||
{ // backwards...
|
||||
fprintf (pFile,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (pFile,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
|
||||
}
|
||||
|
||||
for (int i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (pFile,"(");
|
||||
WriteFloat (pFile, w->p[i][0]);
|
||||
WriteFloat (pFile, w->p[i][1]);
|
||||
WriteFloat (pFile, w->p[i][2]);
|
||||
fprintf (pFile,") ");
|
||||
}
|
||||
fprintf (pFile,"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct viscluster_t
|
||||
{
|
||||
bspbrush_t *pBrushes;
|
||||
int clusterIndex;
|
||||
int leafCount;
|
||||
int leafStart;
|
||||
};
|
||||
|
||||
static CUtlVector<viscluster_t> g_VisClusters;
|
||||
|
||||
// add to the list of brushes the merge leaves into single vis clusters
|
||||
void AddVisCluster( entity_t *pFuncVisCluster )
|
||||
{
|
||||
viscluster_t tmp;
|
||||
Vector clipMins, clipMaxs;
|
||||
clipMins[0] = clipMins[1] = clipMins[2] = MIN_COORD_INTEGER;
|
||||
clipMaxs[0] = clipMaxs[1] = clipMaxs[2] = MAX_COORD_INTEGER;
|
||||
|
||||
// build the map brushes out into the minimum non-overlapping set of brushes
|
||||
bspbrush_t *pBSPBrush = MakeBspBrushList( pFuncVisCluster->firstbrush, pFuncVisCluster->firstbrush + pFuncVisCluster->numbrushes,
|
||||
clipMins, clipMaxs, NO_DETAIL);
|
||||
tmp.pBrushes = ChopBrushes( pBSPBrush );
|
||||
|
||||
// store the entry in the list
|
||||
tmp.clusterIndex = -1;
|
||||
tmp.leafCount = 0;
|
||||
tmp.leafStart = 0;
|
||||
|
||||
#if DEBUG_VISUALIZE_CLUSTERS
|
||||
int debug = atoi(ValueForKey(pFuncVisCluster,"debug"));
|
||||
if ( debug )
|
||||
{
|
||||
Msg("Debug vis cluster %d\n", g_VisClusters.Count() );
|
||||
}
|
||||
#endif
|
||||
|
||||
g_VisClusters.AddToTail( tmp );
|
||||
|
||||
// clear out this entity so it won't get written to the bsp
|
||||
pFuncVisCluster->epairs = NULL;
|
||||
pFuncVisCluster->numbrushes = 0;
|
||||
}
|
||||
|
||||
// returns the total overlapping volume of intersection between the node and the brush list
|
||||
float VolumeOfIntersection( bspbrush_t *pBrushList, node_t *pNode )
|
||||
{
|
||||
float volume = 0.0f;
|
||||
for ( bspbrush_t *pBrush = pBrushList; pBrush; pBrush = pBrush->next )
|
||||
{
|
||||
if ( IsBoxIntersectingBox( pNode->mins, pNode->maxs, pBrush->mins, pBrush->maxs ) )
|
||||
{
|
||||
bspbrush_t *pIntersect = IntersectBrush( pNode->volume, pBrush );
|
||||
if ( pIntersect )
|
||||
{
|
||||
volume += BrushVolume( pIntersect );
|
||||
FreeBrush( pIntersect );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
// Search for a forced cluster that this node is within
|
||||
// NOTE: Returns the first one found, these won't merge themselves together
|
||||
int GetVisCluster( node_t *pNode )
|
||||
{
|
||||
float maxVolume = BrushVolume(pNode->volume) * 0.10f; // needs to cover at least 10% of the volume to overlap
|
||||
int maxIndex = -1;
|
||||
// UNDONE: This could get slow
|
||||
for ( int i = g_VisClusters.Count(); --i >= 0; )
|
||||
{
|
||||
float volume = VolumeOfIntersection( g_VisClusters[i].pBrushes, pNode );
|
||||
if ( volume > maxVolume )
|
||||
{
|
||||
volume = maxVolume;
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
return maxIndex;
|
||||
}
|
||||
/*
|
||||
================
|
||||
NumberLeafs_r
|
||||
================
|
||||
*/
|
||||
void BuildVisLeafList_r (node_t *node, CUtlVector<node_t *> &leaves)
|
||||
{
|
||||
if (node->planenum != PLANENUM_LEAF)
|
||||
{ // decision node
|
||||
node->cluster = -99;
|
||||
BuildVisLeafList_r (node->children[0], leaves);
|
||||
BuildVisLeafList_r (node->children[1], leaves);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( node->contents & CONTENTS_SOLID )
|
||||
{ // solid block, viewpoint never inside
|
||||
node->cluster = -1;
|
||||
return;
|
||||
}
|
||||
leaves.AddToTail(node);
|
||||
}
|
||||
|
||||
// Give each leaf in the list of empty leaves a vis cluster number
|
||||
// some are within func_viscluster volumes and will be merged together
|
||||
// every other leaf gets its own unique number
|
||||
void NumberLeafs( const CUtlVector<node_t *> &leaves )
|
||||
{
|
||||
for ( int i = 0; i < leaves.Count(); i++ )
|
||||
{
|
||||
node_t *node = leaves[i];
|
||||
int visCluster = GetVisCluster( node );
|
||||
if ( visCluster >= 0 )
|
||||
{
|
||||
if ( g_VisClusters[visCluster].clusterIndex < 0 )
|
||||
{
|
||||
g_VisClusters[visCluster].clusterIndex = num_visclusters;
|
||||
num_visclusters++;
|
||||
}
|
||||
g_VisClusters[visCluster].leafCount++;
|
||||
node->cluster = g_VisClusters[visCluster].clusterIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !g_bSkyVis && Is3DSkyboxArea( node->area ) )
|
||||
{
|
||||
if ( g_SkyCluster < 0 )
|
||||
{
|
||||
// allocate a cluster for the sky
|
||||
g_SkyCluster = num_visclusters;
|
||||
num_visclusters++;
|
||||
}
|
||||
node->cluster = g_SkyCluster;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->cluster = num_visclusters;
|
||||
num_visclusters++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_VISUALIZE_CLUSTERS
|
||||
for ( int i = 0; i < g_VisClusters.Count(); i++ )
|
||||
{
|
||||
char name[256];
|
||||
sprintf(name, "u:\\main\\game\\ep2\\maps\\vis_%02d.gl", i );
|
||||
FileHandle_t fp = g_pFileSystem->Open( name, "w" );
|
||||
Msg("Writing %s\n", name );
|
||||
for ( bspbrush_t *pBrush = g_VisClusters[i].pBrushes; pBrush; pBrush = pBrush->next )
|
||||
{
|
||||
for (int i = 0; i < pBrush->numsides; i++ )
|
||||
OutputWindingColor( pBrush->sides[i].winding, fp, 0, 255, 0 );
|
||||
}
|
||||
for ( int j = 0; j < leaves.Count(); j++ )
|
||||
{
|
||||
if ( leaves[j]->cluster == g_VisClusters[i].clusterIndex )
|
||||
{
|
||||
bspbrush_t *pBrush = leaves[j]->volume;
|
||||
for (int k = 0; k < pBrush->numsides; k++ )
|
||||
OutputWindingColor( pBrush->sides[k].winding, fp, 64 + (j&31), 64, 64 - (j&31) );
|
||||
}
|
||||
}
|
||||
g_pFileSystem->Close(fp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// build a list of all vis portals that connect clusters
|
||||
int BuildPortalList( CUtlVector<cluster_portals_t> &portalList, const CUtlVector<node_t *> &leaves )
|
||||
{
|
||||
int portalCount = 0;
|
||||
for ( int i = 0; i < leaves.Count(); i++ )
|
||||
{
|
||||
node_t *node = leaves[i];
|
||||
// count the portals
|
||||
for (portal_t *p = node->portals ; p ; )
|
||||
{
|
||||
if (p->nodes[0] == node) // only write out from first leaf
|
||||
{
|
||||
if ( p->nodes[0]->cluster != p->nodes[1]->cluster )
|
||||
{
|
||||
if (Portal_VisFlood (p))
|
||||
{
|
||||
portalCount++;
|
||||
portalList[node->cluster].portals.AddToTail(p);
|
||||
}
|
||||
}
|
||||
p = p->next[0];
|
||||
}
|
||||
else
|
||||
p = p->next[1];
|
||||
}
|
||||
}
|
||||
return portalCount;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CreateVisPortals_r
|
||||
================
|
||||
*/
|
||||
void CreateVisPortals_r (node_t *node)
|
||||
{
|
||||
// stop as soon as we get to a leaf
|
||||
if (node->planenum == PLANENUM_LEAF )
|
||||
return;
|
||||
|
||||
MakeNodePortal (node);
|
||||
SplitNodePortals (node);
|
||||
|
||||
CreateVisPortals_r (node->children[0]);
|
||||
CreateVisPortals_r (node->children[1]);
|
||||
}
|
||||
|
||||
int clusterleaf;
|
||||
void SaveClusters_r (node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
{
|
||||
dleafs[clusterleaf++].cluster = node->cluster;
|
||||
return;
|
||||
}
|
||||
SaveClusters_r (node->children[0]);
|
||||
SaveClusters_r (node->children[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
WritePortalFile
|
||||
================
|
||||
*/
|
||||
void WritePortalFile (tree_t *tree)
|
||||
{
|
||||
char filename[1024];
|
||||
node_t *headnode;
|
||||
int start = Plat_FloatTime();
|
||||
|
||||
qprintf ("--- WritePortalFile ---\n");
|
||||
|
||||
sprintf (filename, "%s.prt", source);
|
||||
Msg ("writing %s...", filename);
|
||||
|
||||
headnode = tree->headnode;
|
||||
|
||||
FreeTreePortals_r (headnode);
|
||||
MakeHeadnodePortals (tree);
|
||||
|
||||
CreateVisPortals_r (headnode);
|
||||
|
||||
// set the cluster field in every leaf and count the total number of portals
|
||||
num_visclusters = 0;
|
||||
Msg("Building visibility clusters...\n");
|
||||
CUtlVector<node_t *> leaves;
|
||||
BuildVisLeafList_r( headnode, leaves );
|
||||
|
||||
NumberLeafs (leaves);
|
||||
CUtlVector<cluster_portals_t> portalList;
|
||||
portalList.SetCount( num_visclusters );
|
||||
num_visportals = BuildPortalList( portalList, leaves );
|
||||
// write the file
|
||||
FILE *pf = fopen (filename, "w");
|
||||
if (!pf)
|
||||
Error ("Error opening %s", filename);
|
||||
|
||||
fprintf (pf, "%s\n", PORTALFILE);
|
||||
fprintf (pf, "%i\n", num_visclusters);
|
||||
fprintf (pf, "%i\n", num_visportals);
|
||||
|
||||
qprintf ("%5i visclusters\n", num_visclusters);
|
||||
qprintf ("%5i visportals\n", num_visportals);
|
||||
|
||||
WritePortalFile(pf, portalList);
|
||||
|
||||
fclose (pf);
|
||||
|
||||
// we need to store the clusters out now because ordering
|
||||
// issues made us do this after writebsp...
|
||||
clusterleaf = 1;
|
||||
SaveClusters_r (headnode);
|
||||
|
||||
Msg("done (%d)\n", (int)(Plat_FloatTime() - start) );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user