csgo-2018-source/utils/vbsp/physlevelhavok.cpp
2021-07-24 21:11:47 -07:00

229 lines
6.5 KiB
C++

//========= Copyright c 1996-2008, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "physlevelhavok.h"
#include "alignedarray.h"
#include "bsplib.h"
#include "physdll.h"
#include "vbsp.h"
CPhysLevelHavokEmitter::CPhysLevelHavokEmitter()
{
m_numModels = nummodels;
m_pModels = dmodels;
m_pNodes = dnodes;
m_numBrushes = numbrushes;
m_pLeafs = dleafs;
m_pLeafBrushes = dleafbrushes;
m_pBrushes = dbrushes;
m_pBrushSides = dbrushsides;
m_pPlanes = dplanes;
m_bConvertBrushesToMopp = !g_bPhysNoMopp;
m_buildInertia = false;
m_exportObjMopp = !!g_bPhysExportMoppObj;
m_physics = NULL;
CreateInterfaceFn physicsFactory = GetPhysicsFactory();
if ( physicsFactory )
{
m_physics = (IPhysics2*)physicsFactory( VPHYSICS2_INTERFACE_VERSION, NULL );
}
if ( !m_physics )
Warning("!!! WARNING: Can't build collision2 data!\n" );
m_cook = m_physics->GetCook();
}
CPhysLevelHavokEmitter::~CPhysLevelHavokEmitter()
{
}
// TODO: move this to Cook interface
void CPhysLevelHavokEmitter::Emit()
{
CVarBitVec useBrush(m_numBrushes);
for ( int i = 0; i < m_numModels; ++i )
{
dmodel_t *pModel = &m_pModels[i];
AddBrushes(pModel->headnode, useBrush);
}
CUtlVector<IPhysics2CookedPolytope *> arrPolytopes;
ConvertBrushesToPolytopes(useBrush, arrPolytopes);
dphyslevelV0_t *pRoot = Write<dphyslevelV0_t>();
pRoot->toolVersion = 2;
pRoot->dataVersion = m_physics->GetSerializeVersion();
pRoot->sizeofDiskPhysics2Polytope = sizeof(DiskPhysics2Polytope_t);
pRoot->buildTime = (int)time(NULL);
bool outputIndividualPolytopes = true;
// having the number of polytopes, we need to generate MOPP
if(m_bConvertBrushesToMopp)
{
int numPolytopes = arrPolytopes.Count();
CUtlVector<IPhysics2CookedMeshBase*>arrMeshes(0,numPolytopes);
for(int i = 0; i < numPolytopes; ++i)
arrMeshes[i] = arrPolytopes[i]; // conver the pointers
if(m_exportObjMopp)m_cook->ExportObj("d:\\mopp.obj", arrMeshes.Base(), numPolytopes);
IPhysics2CookedMopp *pMopp = m_cook->CookMopp(arrMeshes.Base(), numPolytopes);
if(pMopp)
{
Msg("Physics2Mopp cooked, mem size: %.1f\n", pMopp->GetSizeOf()/1024.);
void *pSerializedMopp = m_cook->Serialize(pMopp->GetMopp(), this);
IStream::Link(&pRoot->mopp, pSerializedMopp);
outputIndividualPolytopes = false; // we don't need to output individual polytopes, because MOPP will contain them separately
m_cook->Destroy(pMopp);
}
else
Warning("Could not build polysoup from brushes\n");
}
if(false)
{
int numPolytopes = arrPolytopes.Count();
CUtlVector<IPhysics2CookedMeshBase*>arrMeshes(0,numPolytopes);
for(int i = 0; i < numPolytopes; ++i)
arrMeshes[i] = arrPolytopes[i]; // conver the pointers
IPhysics2CookedPolysoup *polysoup = m_cook->CookPolysoupFromMeshes(arrMeshes.Base(), numPolytopes);
if(polysoup)
{
//polysoup->ExportObj("d:\\test.obj");
m_cook->Destroy(polysoup);
}
}
int numPolytopes = arrPolytopes.Count();
DiskPhysics2Polytope_t *pDiskPolytopes = NULL;
if(outputIndividualPolytopes)
pDiskPolytopes = WriteAndLinkArray(&pRoot->polytopes,numPolytopes);
for(int nPolytope = 0; nPolytope < numPolytopes; ++nPolytope)
{
IPhysics2CookedPolytope *pPolytope = arrPolytopes[nPolytope];
if(outputIndividualPolytopes)
{
void *pSerializedPolytope = m_cook->Serialize(pPolytope->GetPolytope(), this);
Link(&pDiskPolytopes[nPolytope].offsetPolytope, pSerializedPolytope);
if(m_buildInertia)
{
IPhysics2CookedInertia *pInertia = m_cook->CookInertia(pPolytope->GetPolytope());
void* pSerializedInertia = m_cook->Serialize(pInertia->GetInertia(), this);
Link(&pDiskPolytopes[nPolytope].offsetInertia, pSerializedInertia);
m_cook->Destroy(pInertia);
}
}
m_cook->Destroy(pPolytope);
}
}
void CPhysLevelHavokEmitter::ConvertBrushesToPolytopes(CVarBitVec &useBrushIn, CUtlVector<IPhysics2CookedPolytope*> &arrPolytopesOut)
{
uint numCouldntCreate = 0;
for( int nBrush = 0; nBrush < m_numBrushes; ++nBrush )
{
if(useBrushIn[nBrush])
{
int numBrushSides = m_pBrushes[nBrush].numsides;
CUtlVector_Vector4DAligned arrSides(numBrushSides);
dbrushside_t *pThisBrushSides = m_pBrushSides + m_pBrushes[nBrush].firstside;
for(int nSide = 0; nSide < numBrushSides; ++nSide)
{
dbrushside_t *pSide = pThisBrushSides + nSide;
if(!pSide->bevel)
{
dplane_t &plane = m_pPlanes[pSide->planenum];
Vector4DAligned side;
side.Init(plane.normal.x,plane.normal.y,plane.normal.z, -plane.dist);
arrSides.AddToTail(side);
}
}
IPhysics2CookedPolytope *pPolytope = m_cook->CookPolytopeFromPlanes((Vector4DAligned*)arrSides.Base(), arrSides.Size());
if(pPolytope)
{
arrPolytopesOut.AddToTail(pPolytope);
}
else
{
//Warning("Couldn't create a convex out of brush #%d\n", nBrush);
++numCouldntCreate;
}
}
}
if(numCouldntCreate)
Warning("Couldn't create %u/%u brushes\n", numCouldntCreate, m_numBrushes);
else
Msg("Created %u brushes\n", m_numBrushes);
}
void CPhysLevelHavokEmitter::AddBrushes(int nNode, CVarBitVec &isBrushAdded)
{
if(nNode < 0)
{
int leafIndex = -1 - nNode;
for ( int i = 0; i < m_pLeafs[leafIndex].numleafbrushes; ++i )
{
int brushIndex = m_pLeafBrushes[m_pLeafs[leafIndex].firstleafbrush + i];
isBrushAdded.Set(brushIndex);
}
}
else
{
dnode_t *pNode = m_pNodes + nNode;
AddBrushes( pNode->children[0] , isBrushAdded );
AddBrushes( pNode->children[1] , isBrushAdded );
}
}
// This is the only public entry to this file.
// The global data touched in the file is:
// from bsplib.h:
// g_pPhysLevel : This is an output from this file.
// g_PhysLevelSize : This is set in this file.
// g_dispinfo : This is an input to this file.
// int nummodels;
// dmodel_t dmodels[MAX_MAP_MODELS];
// numnodewaterdata : This is an input to this file from EmitPhysCollision()
// dleafwaterdata : This is an input to this file from EmitPhysCollision()
// from vbsp.h:
// g_SurfaceProperties : This is an input to this file.
void EmitPhysLevel()
{
if(g_pPhysLevel)
MemAlloc_FreeAligned(g_pPhysLevel);
CPhysLevelHavokEmitter emitter;
emitter.Emit();
g_PhysLevelSize = emitter.GetTotalSize();
g_pPhysLevel = (byte*)MemAlloc_AllocAligned(g_PhysLevelSize, 16);
if(!emitter.Compile(g_pPhysLevel))
{
free(g_pPhysLevel);
g_pPhysLevel = NULL;
g_PhysLevelSize = 0;
}
else
{// Msg("Compiled PhysLevel: %.1fk\n", g_PhysLevelSize / 1024.0);
emitter.PrintStats();
}
}