|
|
//========= 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(); } }
|