123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145 |
- /*
- * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
- * its licensors.
- *
- * For complete copyright and license terms please see the LICENSE at the root of this
- * distribution (the "License"). All use of this software is governed by the License,
- * or, if provided, by the license below or the license accompanying this file. Do not
- * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *
- */
- // Original file Copyright Crytek GMBH or its affiliates, used under license.
- #include "Cry3DEngine_precompiled.h"
- #include "StatObj.h"
- #include "IndexedMesh.h"
- #include "../RenderDll/Common/Shadow_Renderer.h"
- #include <IRenderer.h>
- #include <CrySizer.h>
- #include "ObjMan.h"
- #include "MatMan.h"
- #include "RenderMeshMerger.h"
- #include <CryPhysicsDeprecation.h>
- #define MAX_VERTICES_MERGABLE 15000
- #define MAX_TRIS_IN_LOD_0 512
- #define TRIS_IN_LOD_WARNING_RAIO (1.5f)
- // Minimal ratio of Lod(n-1)/Lod(n) polygons to consider LOD for sub-object merging.
- #define MIN_TRIS_IN_MERGED_LOD_RAIO (1.5f)
- DEFINE_INTRUSIVE_LINKED_LIST(CStatObj)
- //////////////////////////////////////////////////////////////////////////
- CStatObj::CStatObj()
- {
- m_pAsyncUpdateContext = 0;
- m_nNodeCount = 0;
- m_nMergedMemoryUsage = 0;
- m_nUsers = 0; // reference counter
- m_nLastDrawMainFrameId = 0;
- #ifdef SERVER_CHECKS
- m_pMesh = NULL;
- #endif
- m_nFlags = 0;
- #ifdef SUPPORT_TERRAIN_AO_PRE_COMPUTATIONS
- m_fOcclusionAmount = -1;
- m_pHeightmap = NULL;
- m_nHeightmapSize = 0;
- #endif
- m_pLODs = 0;
- m_lastBooleanOpScale = 1.f;
- m_fGeometricMeanFaceArea = 0.f;
- m_fLodDistance = 0.0f;
- Init();
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::Init()
- {
- m_pAsyncUpdateContext = 0;
- m_pIndexedMesh = 0;
- m_lockIdxMesh = 0;
- m_nRenderTrisCount = m_nLoadedTrisCount = m_nLoadedVertexCount = 0;
- m_nRenderMatIds = 0;
- m_fObjectRadius = 0;
- m_fRadiusHors = 0;
- m_fRadiusVert = 0;
- m_pParentObject = 0;
- m_pClonedSourceObject = 0;
- m_bVehicleOnlyPhysics = 0;
- m_bBreakableByGame = 0;
- m_idmatBreakable = -1;
- m_nLoadedLodsNum = 1;
- m_nMinUsableLod0 = 0;
- m_nMaxUsableLod0 = 0;
- m_nMaxUsableLod = 0;
- m_pLod0 = 0;
- m_aiVegetationRadius = -1.0f;
- m_phys_mass = -1.0f;
- m_phys_density = -1.0f;
- m_vBoxMin.Set(0, 0, 0);
- m_vBoxMax.Set(0, 0, 0);
- m_vVegCenter.Set(0, 0, 0);
- m_fGeometricMeanFaceArea = 0.f;
- m_fLodDistance = 0.0f;
- m_pRenderMesh = 0;
- m_bDefaultObject = false;
- if (m_pLODs)
- {
- for (int i = 0; i < MAX_STATOBJ_LODS_NUM; i++)
- {
- if (m_pLODs[i])
- {
- m_pLODs[i]->Init();
- }
- }
- }
- m_pReadStream = 0;
- m_nSubObjectMeshCount = 0;
- m_nRenderMeshMemoryUsage = 0;
- m_arrRenderMeshesPotentialMemoryUsage[0] = m_arrRenderMeshesPotentialMemoryUsage[1] = -1;
- m_bCanUnload = false;
- m_bLodsLoaded = false;
- m_bDefaultObject = false;
- m_bOpenEdgesTested = false;
- m_bSubObject = false;
- m_bSharesChildren = false;
- m_bHasDeformationMorphs = false;
- m_bTmpIndexedMesh = false;
- m_bMerged = false;
- m_bMergedLODs = false;
- m_bUnmergable = false;
- m_bLowSpecLod0Set = false;
- m_bHaveOcclusionProxy = false;
- m_bCheckGarbage = false;
- m_bLodsAreLoadedFromSeparateFile = false;
- m_bNoHitRefinement = false;
- m_bDontOccludeExplosions = false;
- m_isDeformable = false;
- m_isProxyTooBig = false;
- m_bHasStreamOnlyCGF = true;
- // Assign default material originally.
- m_pMaterial = GetMatMan()->GetDefaultMaterial();
- m_pLattice = 0;
- m_pSpines = 0;
- m_nSpines = 0;
- m_pBoneMapping = 0;
- m_pLastBooleanOp = 0;
- m_pMapFaceToFace0 = 0;
- m_pClothTangentsData = 0;
- m_pSkinInfo = 0;
- m_hasClothTangentsData = m_hasSkinInfo = 0;
- m_pDelayedSkinParams = 0;
- m_arrPhysGeomInfo.m_array.clear();
- m_nInitialSubObjHideMask = 0;
- #if !defined (_RELEASE)
- m_fStreamingStart = 0.0f;
- #endif
- }
- //////////////////////////////////////////////////////////////////////////
- CStatObj::~CStatObj()
- {
- ShutDown();
- }
- void CStatObj::ShutDown()
- {
- if (m_pReadStream)
- {
- // We don't need this stream anymore.
- m_pReadStream->Abort();
- m_pReadStream = NULL;
- }
- SAFE_DELETE(m_pAsyncUpdateContext);
- // assert (IsHeapValid());
- SAFE_DELETE(m_pIndexedMesh);
- // assert (IsHeapValid());
- for (int n = 0; n < m_arrPhysGeomInfo.GetGeomCount(); n++)
- {
- if (m_arrPhysGeomInfo[n])
- {
- if (m_arrPhysGeomInfo[n]->pGeom->GetForeignData() == (void*)this)
- {
- m_arrPhysGeomInfo[n]->pGeom->SetForeignData(0, 0);
- }
- // Unregister geometry
- CRY_PHYSICS_REPLACEMENT_ASSERT();
- }
- }
- m_arrPhysGeomInfo.m_array.clear();
- m_pStreamedRenderMesh = 0;
- m_pMergedRenderMesh = 0;
- SetRenderMesh(0);
- #ifdef SERVER_CHECKS
- SAFE_DELETE(m_pMesh);
- #endif
- // assert (IsHeapValid());
- /* // SDynTexture is not accessible for 3dengine
- for(int i=0; i<FAR_TEX_COUNT; i++)
- if(m_arrSpriteTexPtr[i])
- m_arrSpriteTexPtr[i]->ReleaseDynamicRT(true);
- for(int i=0; i<FAR_TEX_COUNT_60; i++)
- if(m_arrSpriteTexPtr_60[i])
- m_arrSpriteTexPtr_60[i]->ReleaseDynamicRT(true);
- */
- SAFE_RELEASE(m_pLattice);
- if (m_pLODs)
- {
- for (int i = 0; i < MAX_STATOBJ_LODS_NUM; i++)
- {
- if (m_pLODs[i])
- {
- if (m_pLODs[i]->m_pParentObject)
- {
- GetObjManager()->UnregisterForStreaming(m_pLODs[i]->m_pParentObject);
- }
- else
- {
- GetObjManager()->UnregisterForStreaming(m_pLODs[i]);
- }
- // Sub objects do not own the LODs, so they should not delete them.
- m_pLODs[i] = 0;
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // Handle sub-objects and parents.
- //////////////////////////////////////////////////////////////////////////
- for (size_t i = 0; i < m_subObjects.size(); i++)
- {
- CStatObj* pChildObj = (CStatObj*)m_subObjects[i].pStatObj;
- if (pChildObj)
- {
- if (!m_bSharesChildren)
- {
- pChildObj->m_pParentObject = NULL;
- }
- GetObjManager()->UnregisterForStreaming(pChildObj);
- pChildObj->Release();
- }
- }
- m_subObjects.clear();
- if (m_pParentObject && !m_pParentObject->m_subObjects.empty())
- {
- // Remove this StatObject from sub-objects of the parent.
- SSubObject* pSubObjects = &m_pParentObject->m_subObjects[0];
- for (int i = 0, num = m_pParentObject->m_subObjects.size(); i < num; i++)
- {
- if (pSubObjects[i].pStatObj == this)
- {
- m_pParentObject->m_subObjects.erase(m_pParentObject->m_subObjects.begin() + i);
- break;
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- if (m_pMapFaceToFace0)
- {
- delete[] m_pMapFaceToFace0;
- }
- m_pMapFaceToFace0 = 0;
- if (m_hasClothTangentsData && !m_pClonedSourceObject)
- {
- delete[] m_pClothTangentsData;
- }
- if (m_hasSkinInfo && !m_pClonedSourceObject)
- {
- delete[] m_pSkinInfo;
- }
- m_pClothTangentsData = 0;
- m_hasClothTangentsData = 0;
- m_pSkinInfo = 0;
- m_hasSkinInfo = 0;
- SAFE_DELETE(m_pDelayedSkinParams);
- SAFE_RELEASE(m_pClonedSourceObject);
- #ifdef SUPPORT_TERRAIN_AO_PRE_COMPUTATIONS
- m_fOcclusionAmount = -1;
- SAFE_DELETE_ARRAY(m_pHeightmap);
- m_pHeightmap = 0;
- #endif
- GetObjManager()->UnregisterForStreaming(this);
- SAFE_DELETE_ARRAY(m_pLODs);
- }
- //////////////////////////////////////////////////////////////////////////
- int CStatObj::Release()
- {
- // Has to be thread safe, as it can be called by a worker thread for deferred plane breaks
- int newRef = CryInterlockedDecrement(&m_nUsers);
- if (newRef <= 1)
- {
- if (m_pParentObject && m_pParentObject->m_nUsers <= 0)
- {
- GetObjManager()->CheckForGarbage(m_pParentObject);
- }
- if (newRef <= 0)
- {
- GetObjManager()->CheckForGarbage(this);
- }
- }
- return newRef;
- }
- //////////////////////////////////////////////////////////////////////////
- void* CStatObj::operator new ([[maybe_unused]] size_t size)
- {
- IObjManager* pObjManager = GetObjManager();
- assert(size == sizeof(CStatObj));
- return pObjManager->AllocateStatObj();
- }
- void CStatObj::operator delete (void* pToFree)
- {
- IObjManager* pObjManager = GetObjManager();
- pObjManager->FreeStatObj((CStatObj*)pToFree);
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::FreeIndexedMesh()
- {
- if (!m_lockIdxMesh)
- {
- WriteLock lock(m_lockIdxMesh);
- delete m_pIndexedMesh;
- m_pIndexedMesh = 0;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::CalcRadiuses()
- {
- if (!m_vBoxMin.IsValid() || !m_vBoxMax.IsValid())
- {
- Error("CStatObj::CalcRadiuses: Invalid bbox, File name: %s", m_szFileName.c_str());
- m_vBoxMin.zero();
- m_vBoxMax.zero();
- }
- m_fObjectRadius = m_vBoxMin.GetDistance(m_vBoxMax) * 0.5f;
- float dxh = (float)max(fabs(GetBoxMax().x), fabs(GetBoxMin().x));
- float dyh = (float)max(fabs(GetBoxMax().y), fabs(GetBoxMin().y));
- m_fRadiusHors = (float)sqrt_tpl(dxh * dxh + dyh * dyh);
- m_fRadiusVert = (GetBoxMax().z - 0) * 0.5f;// never change this
- m_vVegCenter = (m_vBoxMax + m_vBoxMin) * 0.5f;
- m_vVegCenter.z = m_fRadiusVert;
- }
- void CStatObj::MakeRenderMesh()
- {
- if (gEnv->IsDedicated())
- {
- return;
- }
- FUNCTION_PROFILER_3DENGINE;
- SetRenderMesh(0);
- if (!m_pIndexedMesh || m_pIndexedMesh->GetSubSetCount() == 0)
- {
- return;
- }
- CMesh* pMesh = m_pIndexedMesh->GetMesh();
- m_nRenderTrisCount = 0;
- //////////////////////////////////////////////////////////////////////////
- // Initialize Mesh subset material flags.
- //////////////////////////////////////////////////////////////////////////
- for (int i = 0; i < pMesh->GetSubSetCount(); i++)
- {
- SMeshSubset& subset = pMesh->m_subsets[i];
- if (!(subset.nMatFlags & MTL_FLAG_NODRAW))
- {
- m_nRenderTrisCount += subset.nNumIndices / 3;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- if (!m_nRenderTrisCount)
- {
- return;
- }
- if (!(GetFlags() & STATIC_OBJECT_DYNAMIC))
- {
- m_pRenderMesh = GetRenderer()->CreateRenderMesh("StatObj_Static", GetFilePath(), NULL, eRMT_Static);
- }
- else
- {
- m_pRenderMesh = GetRenderer()->CreateRenderMesh("StatObj_Dynamic", GetFilePath(), NULL, eRMT_Dynamic);
- m_pRenderMesh->KeepSysMesh(true);
- }
- SMeshBoneMapping_uint16* const pBoneMap = pMesh->m_pBoneMapping;
- pMesh->m_pBoneMapping = 0;
- uint32 nFlags = 0;
- nFlags |= (!GetCVars()->e_StreamCgf && Get3DEngine()->m_bInLoad) ? FSM_SETMESH_ASYNC : 0;
- m_pRenderMesh->SetMesh(*pMesh, 0, nFlags, false);
- pMesh->m_pBoneMapping = pBoneMap;
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::SetMaterial(_smart_ptr<IMaterial> pMaterial)
- {
- m_pMaterial = pMaterial;
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- Vec3 CStatObj::GetHelperPos(const char* szHelperName)
- {
- SSubObject* pSubObj = FindSubObject(szHelperName);
- if (!pSubObj)
- {
- return Vec3(0, 0, 0);
- }
- return Vec3(pSubObj->tm.m03, pSubObj->tm.m13, pSubObj->tm.m23);
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- const Matrix34& CStatObj::GetHelperTM(const char* szHelperName)
- {
- SSubObject* pSubObj = FindSubObject(szHelperName);
- if (!pSubObj)
- {
- static Matrix34 identity(IDENTITY);
- return identity;
- }
- return pSubObj->tm;
- }
- bool CStatObj::IsSameObject(const char* szFileName, const char* szGeomName)
- {
- // cmp object names
- if (szGeomName)
- {
- if (azstricmp(szGeomName, m_szGeomName) != 0)
- {
- return false;
- }
- }
- // Normalize file name
- char szFileNameNorm[MAX_PATH_LENGTH] = "";
- char* pszDest = szFileNameNorm;
- const char* pszSource = szFileName;
- while (*pszSource)
- {
- if (*pszSource == '\\')
- {
- *pszDest++ = '/';
- }
- else
- {
- *pszDest++ = *pszSource;
- }
- pszSource++;
- }
- *pszDest = 0;
- // cmp file names
- if (azstricmp(szFileNameNorm, m_szFileName) != 0)
- {
- return false;
- }
- return true;
- }
- void CStatObj::GetMemoryUsage(ICrySizer* pSizer) const
- {
- {
- SIZER_COMPONENT_NAME(pSizer, "Self");
- pSizer->AddObject(this, sizeof(*this));
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "subObjects");
- pSizer->AddObject(m_subObjects);
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "Strings");
- pSizer->AddObject(m_szFileName);
- pSizer->AddObject(m_szGeomName);
- pSizer->AddObject(m_szProperties);
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "Material");
- pSizer->AddObject(m_pMaterial);
- }
- {
- SIZER_COMPONENT_NAME(pSizer, "PhysGeomInfo");
- pSizer->AddObject(m_arrPhysGeomInfo);
- }
- if (m_pLODs)
- {
- for (int i = 1; i < MAX_STATOBJ_LODS_NUM; i++)
- {
- SIZER_COMPONENT_NAME(pSizer, "StatObjLods");
- pSizer->AddObject(m_pLODs[i]);
- }
- }
- if (m_pIndexedMesh)
- {
- SIZER_COMPONENT_NAME(pSizer, "Mesh");
- pSizer->AddObject(m_pIndexedMesh);
- }
- int nVtx = 0;
- if (m_pIndexedMesh)
- {
- nVtx = m_pIndexedMesh->GetVertexCount();
- }
- else if (m_pRenderMesh)
- {
- nVtx = m_pRenderMesh->GetVerticesCount();
- }
- if (m_pSpines)
- {
- SIZER_COMPONENT_NAME(pSizer, "StatObj Foliage Data");
- pSizer->AddObject(m_pSpines, sizeof(m_pSpines[0]), m_nSpines);
- if (m_pBoneMapping)
- {
- pSizer->AddObject(m_pBoneMapping, sizeof(m_pBoneMapping[0]), nVtx);
- }
- for (int i = 0; i < m_nSpines; i++)
- {
- pSizer->AddObject(m_pSpines[i].pVtx, sizeof(Vec3) * 2 + sizeof(Vec4), m_pSpines[i].nVtx);
- }
- }
- if (m_hasClothTangentsData && (!m_pClonedSourceObject || m_pClonedSourceObject == this))
- {
- SIZER_COMPONENT_NAME(pSizer, "Deformable StatObj ClothTangents");
- pSizer->AddObject(m_pClothTangentsData, nVtx * sizeof(m_pClothTangentsData[0]));
- }
- if (m_hasSkinInfo && (!m_pClonedSourceObject || m_pClonedSourceObject == this))
- {
- SIZER_COMPONENT_NAME(pSizer, "Deformable StatObj SkinData");
- pSizer->AddObject(m_pSkinInfo, (nVtx + 1) * sizeof(m_pSkinInfo[0]));
- }
- if (m_pMapFaceToFace0)
- {
- SIZER_COMPONENT_NAME(pSizer, "Deformable StatObj Mesh");
- pSizer->AddObject(m_pMapFaceToFace0, sizeof(m_pMapFaceToFace0[0]) * max(m_nLoadedTrisCount, m_nRenderTrisCount));
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::SetLodObject(int nLod, IStatObj* pLod)
- {
- assert(nLod > 0 && nLod < MAX_STATOBJ_LODS_NUM);
- if (nLod <= 0 || nLod >= MAX_STATOBJ_LODS_NUM)
- {
- return;
- }
- if (strstr(m_szProperties, "lowspeclod0"))
- {
- m_bLowSpecLod0Set = true;
- }
- bool bLodCompound = pLod && (pLod->GetFlags() & STATIC_OBJECT_COMPOUND) != 0;
- if (pLod && !bLodCompound)
- {
- // Check if low lod decrease amount of used materials.
- int nPrevLodMatIds = m_nRenderMatIds;
- int nPrevLodTris = m_nLoadedTrisCount;
- if (nLod > 1 && m_pLODs && m_pLODs[nLod - 1])
- {
- nPrevLodMatIds = m_pLODs[nLod - 1]->m_nRenderMatIds;
- nPrevLodTris = m_pLODs[nLod - 1]->m_nLoadedTrisCount;
- }
- if (GetCVars()->e_LodsForceUse)
- {
- if ((int)m_nMaxUsableLod < nLod)
- {
- m_nMaxUsableLod = nLod;
- }
- }
- else
- {
- int min_tris = GetCVars()->e_LodMinTtris;
- if (((pLod->GetLoadedTrisCount() >= min_tris || nPrevLodTris >= (3 * min_tris) / 2)
- || pLod->GetRenderMatIds() < nPrevLodMatIds) && nLod > (int)m_nMaxUsableLod)
- {
- m_nMaxUsableLod = nLod;
- }
- }
- if (m_pParentObject && (m_pParentObject->m_nMaxUsableLod < m_nMaxUsableLod))
- {
- m_pParentObject->m_nMaxUsableLod = m_nMaxUsableLod;
- }
- pLod->SetLodLevel0(this);
- pLod->SetMaterial(m_pMaterial); // Lod must use same material as parent.
- if (pLod->GetLoadedTrisCount() > MAX_TRIS_IN_LOD_0)
- {
- if ((strstr(pLod->GetProperties(), "lowspeclod0") != 0) && !m_bLowSpecLod0Set)
- {
- m_bLowSpecLod0Set = true;
- m_nMaxUsableLod0 = nLod;
- }
- if (!m_bLowSpecLod0Set)
- {
- m_nMaxUsableLod0 = nLod;
- }
- }
- if (nLod + 1 > (int)m_nLoadedLodsNum)
- {
- m_nLoadedLodsNum = nLod + 1;
- }
- // When assigning lod to child object.
- if (m_pParentObject)
- {
- if (nLod + 1 > (int)m_pParentObject->m_nLoadedLodsNum)
- {
- m_pParentObject->m_nLoadedLodsNum = nLod + 1;
- }
- }
- }
- if (pLod && bLodCompound)
- {
- m_nMaxUsableLod = nLod;
- pLod->SetUnmergable(m_bUnmergable);
- }
- if (!m_pLODs && pLod)
- {
- m_pLODs = new _smart_ptr<CStatObj>[MAX_STATOBJ_LODS_NUM];
- }
- if (m_pLODs)
- {
- m_pLODs[nLod] = (CStatObj*)pLod;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- IStatObj* CStatObj::GetLodObject(int nLodLevel, bool bReturnNearest)
- {
- if (nLodLevel < 1)
- {
- return this;
- }
- if (!m_pLODs)
- {
- if (bReturnNearest || nLodLevel == 0)
- {
- return this;
- }
- else
- {
- return NULL;
- }
- }
- if (bReturnNearest)
- {
- nLodLevel = CLAMP(nLodLevel, 0, MAX_STATOBJ_LODS_NUM - 1);
- }
- CStatObj* pLod = 0;
- if (nLodLevel < MAX_STATOBJ_LODS_NUM)
- {
- pLod = m_pLODs[nLodLevel];
- // Look up
- if (bReturnNearest && !pLod)
- {
- // Find highest existing lod looking up.
- int lod = nLodLevel;
- while (lod > 0 && m_pLODs[lod] == 0)
- {
- lod--;
- }
- if (lod > 0)
- {
- pLod = m_pLODs[lod];
- }
- else
- {
- pLod = this;
- }
- }
- // Look down
- if (bReturnNearest && !pLod)
- {
- // Find highest existing lod looking down.
- for (int lod = nLodLevel + 1; lod < MAX_STATOBJ_LODS_NUM; lod++)
- {
- if (m_pLODs[lod])
- {
- pLod = m_pLODs[lod];
- break;
- }
- }
- }
- }
- return pLod;
- }
- bool CStatObj::IsPhysicsExist()
- {
- return m_arrPhysGeomInfo.GetGeomCount() > 0;
- }
- bool CStatObj::IsSphereOverlap(const Sphere& sSphere)
- {
- if (m_pRenderMesh && Overlap::Sphere_AABB(sSphere, AABB(m_vBoxMin, m_vBoxMax)))
- { // if inside bbox
- int nPosStride = 0;
- int nInds = m_pRenderMesh->GetIndicesCount();
- const byte* pPos = m_pRenderMesh->GetPosPtr(nPosStride, FSL_READ);
- vtx_idx* pInds = m_pRenderMesh->GetIndexPtr(FSL_READ);
- if (pInds && pPos)
- {
- for (int i = 0; (i + 2) < nInds; i += 3)
- { // test all triangles of water surface strip
- Vec3 v0 = (*(Vec3*)&pPos[nPosStride * pInds[i + 0]]);
- Vec3 v1 = (*(Vec3*)&pPos[nPosStride * pInds[i + 1]]);
- Vec3 v2 = (*(Vec3*)&pPos[nPosStride * pInds[i + 2]]);
- Vec3 vBoxMin = v0;
- vBoxMin.CheckMin(v1);
- vBoxMin.CheckMin(v2);
- Vec3 vBoxMax = v0;
- vBoxMax.CheckMax(v1);
- vBoxMax.CheckMax(v2);
- if (Overlap::Sphere_AABB(sSphere, AABB(vBoxMin, vBoxMax)))
- {
- return true;
- }
- }
- }
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::Invalidate(bool bPhysics, float tolerance)
- {
- AZ_UNUSED(bPhysics);
- AZ_UNUSED(tolerance);
- if (m_pIndexedMesh)
- {
- if (m_pIndexedMesh->GetIndexCount() > 0)
- {
- m_pIndexedMesh->CalcBBox();
- m_vBoxMin = m_pIndexedMesh->m_bbox.min;
- m_vBoxMax = m_pIndexedMesh->m_bbox.max;
- MakeRenderMesh();
- m_nLoadedVertexCount = m_pIndexedMesh->GetVertexCount();
- m_nLoadedTrisCount = m_pIndexedMesh->GetFaceCount();
- if (!m_nLoadedTrisCount)
- {
- m_nLoadedTrisCount = m_pIndexedMesh->GetIndexCount() / 3;
- }
- CalcRadiuses();
- }
- ReleaseIndexedMesh(true);
- }
- //////////////////////////////////////////////////////////////////////////
- // Iterate through sub objects and update hide mask and sub obj mesh count.
- //////////////////////////////////////////////////////////////////////////
- m_nSubObjectMeshCount = 0;
- for (size_t i = 0, numsub = m_subObjects.size(); i < numsub; i++)
- {
- SSubObject& subObj = m_subObjects[i];
- if (subObj.pStatObj && subObj.nType == STATIC_SUB_OBJECT_MESH)
- {
- m_nSubObjectMeshCount++;
- }
- }
- UnMergeSubObjectsRenderMeshes();
- }
- //////////////////////////////////////////////////////////////////////////
- IStatObj* CStatObj::Clone(bool bCloneGeometry, bool bCloneChildren, bool bMeshesOnly)
- {
- if (m_bDefaultObject)
- {
- return this;
- }
- CStatObj* pNewObj = new CStatObj;
- pNewObj->m_pClonedSourceObject = m_pClonedSourceObject ? m_pClonedSourceObject : this;
- pNewObj->m_pClonedSourceObject->AddRef(); // Cloned object will keep a reference to this.
- pNewObj->m_nLoadedTrisCount = m_nLoadedTrisCount;
- pNewObj->m_nLoadedVertexCount = m_nLoadedVertexCount;
- pNewObj->m_nRenderTrisCount = m_nRenderTrisCount;
- if (bCloneGeometry)
- {
- if (m_bMerged)
- {
- UnMergeSubObjectsRenderMeshes();
- }
- if (m_pIndexedMesh && !m_bMerged)
- {
- pNewObj->m_pIndexedMesh = new CIndexedMesh;
- pNewObj->m_pIndexedMesh->Copy(*m_pIndexedMesh->GetMesh());
- }
- if (m_pRenderMesh && !m_bMerged)
- {
- _smart_ptr<IRenderMesh> pRenderMesh = GetRenderer()->CreateRenderMesh(
- "StatObj_Cloned",
- pNewObj->GetFilePath(),
- NULL,
- ((GetFlags() & STATIC_OBJECT_DYNAMIC) ? eRMT_Dynamic : eRMT_Static));
- m_pRenderMesh->CopyTo(pRenderMesh);
- pNewObj->SetRenderMesh(pRenderMesh);
- }
- }
- else
- {
- if (m_pRenderMesh)
- {
- if (m_pMergedRenderMesh != m_pRenderMesh)
- {
- pNewObj->SetRenderMesh(m_pRenderMesh);
- }
- else
- {
- pNewObj->m_pRenderMesh = m_pRenderMesh;
- }
- }
- pNewObj->m_pMergedRenderMesh = m_pMergedRenderMesh;
- pNewObj->m_bMerged = m_pMergedRenderMesh != NULL;
- }
- pNewObj->m_szFileName = m_szFileName;
- pNewObj->m_szGeomName = m_szGeomName;
- pNewObj->m_cgfNodeName = m_cgfNodeName;
- // Default material.
- pNewObj->m_pMaterial = m_pMaterial;
- //*pNewObj->m_arrSpriteTexID = *m_arrSpriteTexID;
- pNewObj->m_fObjectRadius = m_fObjectRadius;
- for (int i = 0; i < m_arrPhysGeomInfo.GetGeomCount(); i++)
- {
- pNewObj->m_arrPhysGeomInfo.SetPhysGeom(m_arrPhysGeomInfo[i], i, m_arrPhysGeomInfo.GetGeomType(i));
- if (pNewObj->m_arrPhysGeomInfo[i])
- {
- // Remove geometry
- CRY_PHYSICS_REPLACEMENT_ASSERT();
- }
- }
- pNewObj->m_vBoxMin = m_vBoxMin;
- pNewObj->m_vBoxMax = m_vBoxMax;
- pNewObj->m_vVegCenter = m_vVegCenter;
- pNewObj->m_fGeometricMeanFaceArea = m_fGeometricMeanFaceArea;
- pNewObj->m_fRadiusHors = m_fRadiusHors;
- pNewObj->m_fRadiusVert = m_fRadiusVert;
- pNewObj->m_nFlags = m_nFlags | STATIC_OBJECT_CLONE;
- pNewObj->m_fLodDistance = m_fLodDistance;
- //////////////////////////////////////////////////////////////////////////
- // Internal Flags.
- //////////////////////////////////////////////////////////////////////////
- pNewObj->m_bCanUnload = false;
- pNewObj->m_bDefaultObject = m_bDefaultObject;
- pNewObj->m_bOpenEdgesTested = m_bOpenEdgesTested;
- pNewObj->m_bSubObject = false; // [anton] since parent is not copied anyway
- pNewObj->m_bVehicleOnlyPhysics = m_bVehicleOnlyPhysics;
- pNewObj->m_idmatBreakable = m_idmatBreakable;
- pNewObj->m_bBreakableByGame = m_bBreakableByGame;
- pNewObj->m_bHasDeformationMorphs = m_bHasDeformationMorphs;
- pNewObj->m_bTmpIndexedMesh = m_bTmpIndexedMesh;
- pNewObj->m_bHaveOcclusionProxy = m_bHaveOcclusionProxy;
- pNewObj->m_bHasStreamOnlyCGF = m_bHasStreamOnlyCGF;
- pNewObj->m_eStreamingStatus = m_eStreamingStatus;
- //////////////////////////////////////////////////////////////////////////
- int numSubObj = (int)m_subObjects.size();
- if (bMeshesOnly)
- {
- numSubObj = 0;
- for (size_t i = 0; i < m_subObjects.size(); i++)
- {
- if (m_subObjects[i].nType == STATIC_SUB_OBJECT_MESH)
- {
- numSubObj++;
- }
- else
- {
- break;
- }
- }
- }
- pNewObj->m_subObjects.reserve(numSubObj);
- for (int i = 0; i < numSubObj; i++)
- {
- pNewObj->m_subObjects.push_back(m_subObjects[i]);
- if (m_subObjects[i].pStatObj)
- {
- if (bCloneChildren)
- {
- pNewObj->m_subObjects[i].pStatObj = m_subObjects[i].pStatObj->Clone(bCloneGeometry, bCloneChildren, bMeshesOnly);
- pNewObj->m_subObjects[i].pStatObj->AddRef();
- ((CStatObj*)(pNewObj->m_subObjects[i].pStatObj))->m_pParentObject = pNewObj;
- }
- else
- {
- m_subObjects[i].pStatObj->AddRef();
- ((CStatObj*)(m_subObjects[i].pStatObj))->m_nFlags |= STATIC_OBJECT_MULTIPLE_PARENTS;
- }
- }
- }
- pNewObj->m_nSubObjectMeshCount = m_nSubObjectMeshCount;
- if (!bCloneChildren)
- {
- pNewObj->m_bSharesChildren = true;
- }
- if (pNewObj->m_hasClothTangentsData = m_hasClothTangentsData)
- {
- pNewObj->m_pClothTangentsData = m_pClothTangentsData;
- }
- if (pNewObj->m_hasSkinInfo = m_hasSkinInfo)
- {
- pNewObj->m_pSkinInfo = m_pSkinInfo;
- }
- return pNewObj;
- }
- //////////////////////////////////////////////////////////////////////////
- IIndexedMesh* CStatObj::GetIndexedMesh(bool bCreateIfNone)
- {
- WriteLock lock(m_lockIdxMesh);
- if (m_pIndexedMesh)
- {
- return m_pIndexedMesh;
- }
- else if (m_pRenderMesh && bCreateIfNone)
- {
- if (m_pRenderMesh->GetIndexedMesh(m_pIndexedMesh = new CIndexedMesh) == NULL)
- {
- // GetIndexMesh will free the IndexedMesh object if an allocation failed
- m_pIndexedMesh = NULL;
- return NULL;
- }
- CMesh* pMesh = m_pIndexedMesh->GetMesh();
- if (!pMesh || pMesh->m_subsets.size() <= 0)
- {
- m_pIndexedMesh->Release();
- m_pIndexedMesh = 0;
- return 0;
- }
- m_bTmpIndexedMesh = true;
- int i, j, i0 = pMesh->m_subsets[0].nFirstVertId + pMesh->m_subsets[0].nNumVerts;
- for (i = j = 1; i < pMesh->m_subsets.size(); i++)
- {
- if (pMesh->m_subsets[i].nFirstVertId - i0 < pMesh->m_subsets[j].nFirstVertId - i0)
- {
- j = i;
- }
- }
- if (j < pMesh->m_subsets.size() && pMesh->m_subsets[0].nPhysicalizeType == PHYS_GEOM_TYPE_DEFAULT &&
- pMesh->m_subsets[j].nPhysicalizeType != PHYS_GEOM_TYPE_DEFAULT && pMesh->m_subsets[j].nFirstVertId > i0)
- {
- pMesh->m_subsets[j].nNumVerts += pMesh->m_subsets[j].nFirstVertId - i0;
- pMesh->m_subsets[j].nFirstVertId = i0;
- }
- return m_pIndexedMesh;
- }
- return 0;
- }
- IIndexedMesh* CStatObj::CreateIndexedMesh()
- {
- if (!m_pIndexedMesh)
- {
- m_pIndexedMesh = new CIndexedMesh();
- }
- return m_pIndexedMesh;
- }
- void CStatObj::ReleaseIndexedMesh(bool bRenderMeshUpdated)
- {
- WriteLock lock(m_lockIdxMesh);
- if (m_bTmpIndexedMesh && m_pIndexedMesh)
- {
- int istart, iend;
- CMesh* pMesh = m_pIndexedMesh->GetMesh();
- if (m_pRenderMesh && !bRenderMeshUpdated)
- {
- TRenderChunkArray& Chunks = m_pRenderMesh->GetChunks();
- for (int i = 0; i < pMesh->m_subsets.size(); i++)
- {
- Chunks[i].m_nMatFlags |= pMesh->m_subsets[i].nMatFlags & 1 << 30;
- }
- }
- if (bRenderMeshUpdated && m_pBoneMapping)
- {
- for (int i = iend = 0; i < (int)pMesh->m_subsets.size(); i++)
- {
- if ((pMesh->m_subsets[i].nMatFlags & (MTL_FLAG_NOPHYSICALIZE | MTL_FLAG_NODRAW)) == MTL_FLAG_NOPHYSICALIZE)
- {
- for (istart = iend++; iend < (int)m_chunkBoneIds.size() && m_chunkBoneIds[iend]; iend++)
- {
- ;
- }
- if (!pMesh->m_subsets[i].nNumIndices)
- {
- m_chunkBoneIds.erase(m_chunkBoneIds.begin() + istart, m_chunkBoneIds.begin() + iend);
- iend = istart;
- }
- }
- }
- }
- m_pIndexedMesh->Release();
- m_pIndexedMesh = 0;
- m_bTmpIndexedMesh = false;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- static bool SubObjectsOfCompoundHaveLOD(const CStatObj* pStatObj, int nLod)
- {
- int numSubObjects = pStatObj->GetSubObjectCount();
- for (int i = 0; i < numSubObjects; ++i)
- {
- const IStatObj::SSubObject* pSubObject = const_cast<CStatObj*>(pStatObj)->GetSubObject(i);
- if (!pSubObject)
- {
- continue;
- }
- const CStatObj* pChildObj = (const CStatObj*)pSubObject->pStatObj;
- if (!pChildObj)
- {
- continue;
- }
- if (!pChildObj->m_pLODs)
- {
- continue;
- }
- const CStatObj* pLod = pChildObj->m_pLODs[nLod];
- if (pLod)
- {
- return true;
- }
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::TryMergeSubObjects(bool bFromStreaming)
- {
- // sub meshes merging
- if (GetCVars()->e_StatObjMerge)
- {
- if (!m_bUnmergable && !IsDeformable())
- {
- MergeSubObjectsRenderMeshes(bFromStreaming, this, 0);
- if (!bFromStreaming && !m_pLODs && m_nFlags & STATIC_OBJECT_COMPOUND)
- {
- // Check if LODs were not split (production mode)
- for (int i = 1; i < MAX_STATOBJ_LODS_NUM; ++i)
- {
- if (!SubObjectsOfCompoundHaveLOD(this, i))
- {
- continue;
- }
- CStatObj* pStatObj = new CStatObj();
- pStatObj->m_szFileName = m_szFileName;
- char lodName[32];
- azstrcpy(lodName, 32, "-mlod");
- azltoa(i, lodName + 5, AZ_ARRAY_SIZE(lodName) - 5, 10);
- pStatObj->m_szFileName.append(lodName);
- pStatObj->m_szGeomName = m_szGeomName;
- pStatObj->m_bSubObject = true;
- SetLodObject(i, pStatObj);
- m_bMergedLODs = true;
- }
- }
- if (m_pLODs)
- {
- for (int i = 1; i < MAX_STATOBJ_LODS_NUM; i++)
- {
- if (m_pLODs[i])
- {
- m_pLODs[i]->MergeSubObjectsRenderMeshes(bFromStreaming, this, i);
- }
- }
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::MergeSubObjectsRenderMeshes(bool bFromStreaming, CStatObj* pLod0, int nLod)
- {
- if (m_bUnmergable)
- {
- return;
- }
- FUNCTION_PROFILER_3DENGINE;
- LOADING_TIME_PROFILE_SECTION;
- m_bMerged = false;
- m_pMergedRenderMesh = 0;
- int nSubObjCount = (int)pLod0->m_subObjects.size();
- std::vector<SRenderMeshInfoInput> lstRMI;
- SRenderMeshInfoInput rmi;
- rmi.pMat = m_pMaterial;
- rmi.mat.SetIdentity();
- rmi.pMesh = 0;
- rmi.pSrcRndNode = 0;
- for (int s = 0; s < nSubObjCount; s++)
- {
- CStatObj::SSubObject* pSubObj = &pLod0->m_subObjects[s];
- if (pSubObj->pStatObj && pSubObj->nType == STATIC_SUB_OBJECT_MESH)
- {
- CStatObj* pStatObj = (CStatObj*)pSubObj->pStatObj->GetLodObject(nLod, true); // Get lod, if not exist get lowest existing.
- if (pStatObj)
- {
- CryAutoCriticalSection lock(pStatObj->m_streamingMeshLock);
- if (pStatObj->m_pRenderMesh || pStatObj->m_pStreamedRenderMesh)
- {
- rmi.pMesh = pStatObj->m_pRenderMesh ? pStatObj->m_pRenderMesh : pStatObj->m_pStreamedRenderMesh;
- rmi.mat = pSubObj->tm;
- rmi.bIdentityMatrix = pSubObj->bIdentityMatrix;
- rmi.nSubObjectIndex = s;
- lstRMI.push_back(rmi);
- }
- }
- }
- }
- _smart_ptr<IRenderMesh> pMergedMesh = 0;
- if (lstRMI.size() == 1 && lstRMI[0].bIdentityMatrix)
- {
- // If identity matrix and only mesh-subobject use it as a merged render mesh.
- pMergedMesh = rmi.pMesh;
- }
- else if (!lstRMI.empty())
- {
- SMergeInfo info;
- info.sMeshName = GetFilePath();
- info.sMeshType = "StatObj_Merged";
- info.bMergeToOneRenderMesh = true;
- info.pUseMaterial = m_pMaterial;
- pMergedMesh = GetSharedRenderMeshMerger()->MergeRenderMeshes(&lstRMI[0], lstRMI.size(), info);
- }
- if (pMergedMesh)
- {
- if (bFromStreaming)
- {
- CryAutoCriticalSection lock(m_streamingMeshLock);
- m_pMergedRenderMesh = pMergedMesh;
- m_pStreamedRenderMesh = pMergedMesh;
- }
- else
- {
- m_pMergedRenderMesh = pMergedMesh;
- SetRenderMesh(pMergedMesh);
- }
- m_bMerged = true;
- if (m_pLod0)
- {
- // Make sure upmost lod is also marked to be merged.
- m_pLod0->SetMerged(true);
- }
- }
- }
- bool CStatObj::IsMatIDReferencedByObj(uint16 matID)
- {
- //Check root obj
- if (IRenderMesh* pRenderMesh = GetRenderMesh())
- {
- TRenderChunkArray& Chunks = pRenderMesh->GetChunks();
- for (int nChunkId = 0; nChunkId < Chunks.size(); nChunkId++)
- {
- if (Chunks[nChunkId].m_nMatID == matID)
- {
- return true;
- }
- }
- }
- //check children
- int nSubObjCount = (int)m_subObjects.size();
- for (int s = 0; s < nSubObjCount; s++)
- {
- CStatObj::SSubObject* pSubObj = &m_subObjects[s];
- if (pSubObj->pStatObj)
- {
- CStatObj* pSubStatObj = (CStatObj*)pSubObj->pStatObj;
- if (IRenderMesh* pSubRenderMesh = pSubStatObj->GetRenderMesh())
- {
- TRenderChunkArray& Chunks = pSubRenderMesh->GetChunks();
- for (int nChunkId = 0; nChunkId < Chunks.size(); nChunkId++)
- {
- if (Chunks[nChunkId].m_nMatID == matID)
- {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CStatObj::CanMergeSubObjects()
- {
- if (gEnv->IsDedicated())
- {
- return false;
- }
- if (!m_clothData.empty())
- {
- return false;
- }
- int nSubMeshes = 0;
- int nTotalVertexCount = 0;
- int nTotalTriCount = 0;
- int nTotalRenderChunksCount = 0;
- int nSubObjCount = (int)m_subObjects.size();
- for (int s = 0; s < nSubObjCount; s++)
- {
- CStatObj::SSubObject* pSubObj = &m_subObjects[s];
- if (pSubObj->pStatObj && pSubObj->nType == STATIC_SUB_OBJECT_MESH && !pSubObj->bHidden)
- {
- CStatObj* pStatObj = (CStatObj*)pSubObj->pStatObj;
- // Conditions to not merge subobjects
- if (pStatObj->m_pMaterial != m_pMaterial || // Different materials
- pStatObj->m_nSpines || // It's bendable foliage
- !pStatObj->m_clothData.empty()) // It's cloth
- {
- return false;
- }
- nSubMeshes++;
- nTotalVertexCount += pStatObj->m_nLoadedVertexCount;
- nTotalTriCount += pStatObj->m_nLoadedTrisCount;
- nTotalRenderChunksCount += pStatObj->m_nRenderMatIds;
- }
- }
- // Check for mat_breakable surface type in material
- if (m_pMaterial)
- {
- int nSubMtls = m_pMaterial->GetSubMtlCount();
- if (nSubMtls > 0)
- {
- for (int i = 0; i < nSubMtls; ++i)
- {
- _smart_ptr<IMaterial> pSubMtl = m_pMaterial->GetSafeSubMtl(i);
- if (pSubMtl)
- {
- ISurfaceType* pSFType = pSubMtl->GetSurfaceType();
- // This is breakable glass.
- // Do not merge meshes that have procedural physics breakability in them.
- if (pSFType && pSFType->GetBreakability() != 0)
- {
- //if mesh is streamed, we must assume the material is referenced
- if (m_bMeshStrippedCGF)
- {
- return false;
- }
- else if (IsMatIDReferencedByObj((uint16)i))
- {
- return false;
- }
- }
- }
- }
- }
- else // nSubMtls==0
- {
- ISurfaceType* pSFType = m_pMaterial->GetSurfaceType();
- // This is breakable glass.
- // Do not merge meshes that have procedural physics breakability in them.
- if (pSFType && pSFType->GetBreakability() != 0)
- {
- return false;
- }
- }
- }
- if (nTotalVertexCount > MAX_VERTICES_MERGABLE || nSubMeshes <= 1 || nTotalRenderChunksCount <= 1)
- {
- return false;
- }
- if ((nTotalTriCount / nTotalRenderChunksCount) > GetCVars()->e_StatObjMergeMaxTrisPerDrawCall)
- {
- return false; // tris to draw calls ratio is already not so bad
- }
- return true;
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::UnMergeSubObjectsRenderMeshes()
- {
- if (m_bMerged)
- {
- m_bMerged = false;
- m_pMergedRenderMesh = 0;
- SetRenderMesh(0);
- }
- if (m_bMergedLODs)
- {
- delete[] m_pLODs;
- m_pLODs = 0;
- }
- }
- //------------------------------------------------------------------------------
- // This function is recovered from previous FindSubObject function which was then
- // changed and creating many CGA model issues (some joints never move).
- CStatObj::SSubObject* CStatObj::FindSubObject_CGA(const char* sNodeName)
- {
- uint32 numSubObjects = m_subObjects.size();
- for (uint32 i = 0; i < numSubObjects; i++)
- {
- if (azstricmp(m_subObjects[i].name.c_str(), sNodeName) == 0)
- {
- return &m_subObjects[i];
- }
- }
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- CStatObj::SSubObject* CStatObj::FindSubObject(const char* sNodeName)
- {
- uint32 numSubObjects = m_subObjects.size();
- int len = 1; // some objects has ' ' in the beginning
- for (; sNodeName[len] > ' ' && sNodeName[len] != ',' && sNodeName[len] != ';'; len++)
- {
- ;
- }
- for (uint32 i = 0; i < numSubObjects; i++)
- {
- if (_strnicmp(m_subObjects[i].name.c_str(), sNodeName, len) == 0 && m_subObjects[i].name[len] == 0)
- {
- return &m_subObjects[i];
- }
- }
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- CStatObj::SSubObject* CStatObj::FindSubObject_StrStr(const char* sNodeName)
- {
- uint32 numSubObjects = m_subObjects.size();
- for (uint32 i = 0; i < numSubObjects; i++)
- {
- if (stristr(m_subObjects[i].name.c_str(), sNodeName))
- {
- return &m_subObjects[i];
- }
- }
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- IStatObj::SSubObject& CStatObj::AddSubObject(IStatObj* pSubObj)
- {
- assert(pSubObj);
- SetSubObjectCount(m_subObjects.size() + 1);
- InitializeSubObject(m_subObjects[m_subObjects.size() - 1]);
- m_subObjects[m_subObjects.size() - 1].pStatObj = pSubObj;
- pSubObj->AddRef();
- return m_subObjects[m_subObjects.size() - 1];
- }
- //////////////////////////////////////////////////////////////////////////
- bool CStatObj::RemoveSubObject(int nIndex)
- {
- if (nIndex >= 0 && nIndex < (int)m_subObjects.size())
- {
- SSubObject* pSubObj = &m_subObjects[nIndex];
- CStatObj* pChildObj = (CStatObj*)pSubObj->pStatObj;
- if (pChildObj)
- {
- if (!m_bSharesChildren)
- {
- pChildObj->m_pParentObject = NULL;
- }
- pChildObj->Release();
- }
- m_subObjects.erase(m_subObjects.begin() + nIndex);
- Invalidate(true);
- return true;
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::SetSubObjectCount(int nCount)
- {
- // remove sub objects.
- while ((int)m_subObjects.size() > nCount)
- {
- RemoveSubObject(m_subObjects.size() - 1);
- }
- SSubObject subobj;
- InitializeSubObject(subobj);
- m_subObjects.resize(nCount, subobj);
- if (nCount > 0)
- {
- m_nFlags |= STATIC_OBJECT_COMPOUND;
- }
- else
- {
- m_nFlags &= ~STATIC_OBJECT_COMPOUND;
- }
- Invalidate(true);
- UnMergeSubObjectsRenderMeshes();
- }
- //////////////////////////////////////////////////////////////////////////
- bool CStatObj::CopySubObject(int nToIndex, IStatObj* pFromObj, int nFromIndex)
- {
- SSubObject* pSrcSubObj = pFromObj->GetSubObject(nFromIndex);
- if (!pSrcSubObj)
- {
- return false;
- }
- if (nToIndex >= (int)m_subObjects.size())
- {
- SetSubObjectCount(nToIndex + 1);
- if (pFromObj == this)
- {
- pSrcSubObj = pFromObj->GetSubObject(nFromIndex);
- }
- }
- m_subObjects[nToIndex] = *pSrcSubObj;
- if (pSrcSubObj->pStatObj)
- {
- pSrcSubObj->pStatObj->AddRef();
- }
- Invalidate(true);
- return true;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CStatObj::GetPhysicalProperties(float& mass, float& density)
- {
- mass = m_phys_mass;
- density = m_phys_density;
- if (mass < 0 && density < 0)
- {
- return false;
- }
- return true;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CStatObj::RayIntersection(SRayHitInfo& hitInfo, _smart_ptr<IMaterial> pCustomMtl)
- {
- Vec3 vOut;
- bool bNonDirectionalTest = hitInfo.inRay.direction.IsZero();
- // First check if ray intersect objects bounding box.
- if (!bNonDirectionalTest && !Intersect::Ray_AABB(hitInfo.inRay, AABB(m_vBoxMin, m_vBoxMax), vOut))
- {
- return false;
- }
- if (bNonDirectionalTest && !Overlap::AABB_AABB(
- AABB(hitInfo.inRay.origin - Vec3(hitInfo.fMaxHitDistance), hitInfo.inRay.origin + Vec3(hitInfo.fMaxHitDistance)),
- AABB(m_vBoxMin, m_vBoxMax)))
- {
- return false;
- }
- if ((m_nFlags & STATIC_OBJECT_COMPOUND) && !m_bMerged)
- {
- SRayHitInfo hitOut;
- bool bAnyHit = false;
- float fMinDistance = FLT_MAX;
- for (int i = 0, num = m_subObjects.size(); i < num; i++)
- {
- if (m_subObjects[i].pStatObj && m_subObjects[i].nType == STATIC_SUB_OBJECT_MESH && !m_subObjects[i].bHidden)
- {
- if (((CStatObj*)(m_subObjects[i].pStatObj))->m_nFlags & STATIC_OBJECT_HIDDEN)
- {
- continue;
- }
- Matrix34 invertedTM = m_subObjects[i].tm.GetInverted();
- SRayHitInfo hit = hitInfo;
- // Transform ray into sub-object local space.
- hit.inReferencePoint = invertedTM.TransformPoint(hit.inReferencePoint);
- hit.inRay.origin = invertedTM.TransformPoint(hit.inRay.origin);
- hit.inRay.direction = invertedTM.TransformVector(hit.inRay.direction);
- int nFirstTriangleId = hit.pHitTris ? hit.pHitTris->Count() : 0;
- if (((CStatObj*)m_subObjects[i].pStatObj)->RayIntersection(hit, pCustomMtl))
- {
- if (hit.fDistance < fMinDistance)
- {
- hitInfo.pStatObj = m_subObjects[i].pStatObj;
- bAnyHit = true;
- hitOut = hit;
- }
- }
- // transform collected triangles from sub-object space into object space
- if (hit.pHitTris)
- {
- for (int t = nFirstTriangleId; t < hit.pHitTris->Count(); t++)
- {
- SRayHitTriangle& ht = hit.pHitTris->GetAt(t);
- for (int c = 0; c < 3; c++)
- {
- ht.v[c] = m_subObjects[i].tm.TransformPoint(ht.v[c]);
- }
- }
- }
- }
- }
- if (bAnyHit)
- {
- // Restore input ray/reference point.
- hitOut.inReferencePoint = hitInfo.inReferencePoint;
- hitOut.inRay = hitInfo.inRay;
- hitInfo = hitOut;
- return true;
- }
- }
- else
- {
- bool result = false;
- IRenderMesh* pRenderMesh = m_pRenderMesh;
- // Sometimes, object has no base lod mesh. So need to hit test with low level mesh.
- // If the distance from camera is larger then a base lod distance, then base lod mesh is not loaded yet.
- if (!pRenderMesh && m_nMaxUsableLod > 0 && m_pLODs && m_pLODs[m_nMaxUsableLod])
- {
- pRenderMesh = m_pLODs[m_nMaxUsableLod]->GetRenderMesh();
- }
- AZ_Warning("StatObj Ray Intersection",
- pRenderMesh,
- "No render mesh available for hit testing for statobj %s", m_szFileName.c_str());
- if (pRenderMesh)
- {
- result = CRenderMeshUtils::RayIntersection(pRenderMesh, hitInfo, pCustomMtl);
- if (result)
- {
- hitInfo.pStatObj = this;
- hitInfo.pRenderMesh = pRenderMesh;
- }
- }
- return result;
- }
- return false;
- }
- bool CStatObj::LineSegIntersection(const Lineseg& lineSeg, Vec3& hitPos, int& surfaceTypeId)
- {
- bool intersects = false;
- #ifdef SERVER_CHECKS
- if (m_pMesh)
- {
- int numVertices, numVerticesf16, numIndices;
- Vec3* pPositions = m_pMesh->GetStreamPtrAndElementCount<Vec3>(CMesh::POSITIONS, 0, &numVertices);
- Vec3f16* pPositionsf16 = m_pMesh->GetStreamPtrAndElementCount<Vec3f16>(CMesh::POSITIONSF16, 0, &numVerticesf16);
- uint16* pIndices = m_pMesh->GetStreamPtrAndElementCount<uint16>(CMesh::INDICES, 0, &numIndices);
- if (numIndices && numVerticesf16)
- {
- DynArray<SMeshSubset>::iterator itSubset;
- for (itSubset = m_pMesh->m_subsets.begin(); itSubset != m_pMesh->m_subsets.end(); ++itSubset)
- {
- if (!(itSubset->nMatFlags & MTL_FLAG_NODRAW))
- {
- int lastIndex = itSubset->nFirstIndexId + itSubset->nNumIndices;
- for (int i = itSubset->nFirstIndexId; i < lastIndex; )
- {
- const Vec3 v0 = pPositionsf16[pIndices[i++]].ToVec3();
- const Vec3 v1 = pPositionsf16[pIndices[i++]].ToVec3();
- const Vec3 v2 = pPositionsf16[pIndices[i++]].ToVec3();
- if (Intersect::Lineseg_Triangle(lineSeg, v0, v2, v1, hitPos) || // Front face
- Intersect::Lineseg_Triangle(lineSeg, v0, v1, v2, hitPos)) // Back face
- {
- _smart_ptr<IMaterial> pMtl = m_pMaterial->GetSafeSubMtl(itSubset->nMatID);
- surfaceTypeId = pMtl->GetSurfaceTypeId();
- intersects = true;
- break;
- }
- }
- }
- }
- }
- else if (numIndices && numVertices)
- {
- DynArray<SMeshSubset>::iterator itSubset;
- for (itSubset = m_pMesh->m_subsets.begin(); itSubset != m_pMesh->m_subsets.end(); ++itSubset)
- {
- if (!(itSubset->nMatFlags & MTL_FLAG_NODRAW))
- {
- int lastIndex = itSubset->nFirstIndexId + itSubset->nNumIndices;
- for (int i = itSubset->nFirstIndexId; i < lastIndex; )
- {
- const Vec3& v0 = pPositions[pIndices[i++]];
- const Vec3& v1 = pPositions[pIndices[i++]];
- const Vec3& v2 = pPositions[pIndices[i++]];
- if (Intersect::Lineseg_Triangle(lineSeg, v0, v2, v1, hitPos) || // Front face
- Intersect::Lineseg_Triangle(lineSeg, v0, v1, v2, hitPos)) // Back face
- {
- _smart_ptr<IMaterial> pMtl = m_pMaterial->GetSafeSubMtl(itSubset->nMatID);
- surfaceTypeId = pMtl->GetSurfaceTypeId();
- intersects = true;
- break;
- }
- }
- }
- }
- }
- }
- else
- #endif
- if (m_pRenderMesh)
- {
- m_pRenderMesh->LockForThreadAccess();
- int numIndices = m_pRenderMesh->GetIndicesCount();
- int numVertices = m_pRenderMesh->GetVerticesCount();
- if (numIndices && numVertices)
- {
- int posStride;
- uint8* pPositions = (uint8*)m_pRenderMesh->GetPosPtr(posStride, FSL_READ);
- vtx_idx* pIndices = m_pRenderMesh->GetIndexPtr(FSL_READ);
- TRenderChunkArray& Chunks = m_pRenderMesh->GetChunks();
- int nChunkCount = Chunks.size();
- for (int nChunkId = 0; nChunkId < nChunkCount; nChunkId++)
- {
- CRenderChunk* pChunk = &Chunks[nChunkId];
- if (!(pChunk->m_nMatFlags & MTL_FLAG_NODRAW))
- {
- int lastIndex = pChunk->nFirstIndexId + pChunk->nNumIndices;
- for (int i = pChunk->nFirstIndexId; i < lastIndex; )
- {
- const Vec3& v0 = *(Vec3*)(pPositions + pIndices[i++] * posStride);
- const Vec3& v1 = *(Vec3*)(pPositions + pIndices[i++] * posStride);
- const Vec3& v2 = *(Vec3*)(pPositions + pIndices[i++] * posStride);
- if (Intersect::Lineseg_Triangle(lineSeg, v0, v2, v1, hitPos) || // Front face
- Intersect::Lineseg_Triangle(lineSeg, v0, v1, v2, hitPos)) // Back face
- {
- _smart_ptr<IMaterial> pMtl = m_pMaterial->GetSafeSubMtl(pChunk->m_nMatID);
- surfaceTypeId = pMtl->GetSurfaceTypeId();
- intersects = true;
- break;
- }
- }
- }
- }
- }
- m_pRenderMesh->UnlockStream(VSF_GENERAL);
- m_pRenderMesh->UnlockIndexStream();
- m_pRenderMesh->UnLockForThreadAccess();
- }
- return intersects;
- }
- #ifdef SUPPORT_TERRAIN_AO_PRE_COMPUTATIONS
- float CStatObj::GetOcclusionAmount()
- {
- if (m_fOcclusionAmount < 0)
- {
- PrintMessage("Computing occlusion value for: %s ... ", GetFilePath());
- float fHits = 0;
- float fTests = 0;
- Matrix34 objMatrix;
- objMatrix.SetIdentity();
- Vec3 vStep = Vec3(0.5f, 0.5f, 0.5f);
- Vec3 vClosestHitPoint;
- float fClosestHitDistance = 1000;
- // y-rays
- for (float x = m_vBoxMin.x; x <= m_vBoxMax.x; x += vStep.x)
- {
- for (float z = m_vBoxMin.z; z <= m_vBoxMax.z; z += vStep.z)
- {
- Vec3 vStart (x, m_vBoxMin.y, z);
- Vec3 vEnd (x, m_vBoxMax.y, z);
- if (GetObjManager()->RayStatObjIntersection(this, objMatrix, GetMaterial(), vStart, vEnd, vClosestHitPoint, fClosestHitDistance, true))
- {
- fHits++;
- }
- fTests++;
- }
- }
- // x-rays
- for (float y = m_vBoxMin.y; y <= m_vBoxMax.y; y += vStep.y)
- {
- for (float z = m_vBoxMin.z; z <= m_vBoxMax.z; z += vStep.z)
- {
- Vec3 vStart (m_vBoxMin.x, y, z);
- Vec3 vEnd (m_vBoxMax.x, y, z);
- if (GetObjManager()->RayStatObjIntersection(this, objMatrix, GetMaterial(), vStart, vEnd, vClosestHitPoint, fClosestHitDistance, true))
- {
- fHits++;
- }
- fTests++;
- }
- }
- // z-rays
- for (float y = m_vBoxMin.y; y <= m_vBoxMax.y; y += vStep.y)
- {
- for (float x = m_vBoxMin.x; x <= m_vBoxMax.x; x += vStep.x)
- {
- Vec3 vStart (x, y, m_vBoxMax.z);
- Vec3 vEnd (x, y, m_vBoxMin.z);
- if (GetObjManager()->RayStatObjIntersection(this, objMatrix, GetMaterial(), vStart, vEnd, vClosestHitPoint, fClosestHitDistance, true))
- {
- fHits++;
- }
- fTests++;
- }
- }
- m_fOcclusionAmount = fTests ? (fHits / fTests) : 0;
- PrintMessagePlus("[%.2f]", m_fOcclusionAmount);
- }
- return m_fOcclusionAmount;
- }
- #endif
- void CStatObj::SetRenderMesh(IRenderMesh* pRM)
- {
- LOADING_TIME_PROFILE_SECTION;
- if (pRM == m_pRenderMesh)
- {
- return;
- }
- {
- CryAutoCriticalSection lock(m_streamingMeshLock);
- m_pRenderMesh = pRM;
- }
- if (m_pRenderMesh)
- {
- m_nRenderTrisCount = 0;
- m_nRenderMatIds = 0;
- TRenderChunkArray& Chunks = m_pRenderMesh->GetChunks();
- for (int nChunkId = 0; nChunkId < Chunks.size(); nChunkId++)
- {
- CRenderChunk* pChunk = &Chunks[nChunkId];
- if (pChunk->m_nMatFlags & MTL_FLAG_NODRAW || !pChunk->pRE)
- {
- continue;
- }
- if (pChunk->nNumIndices > 0)
- {
- m_nRenderMatIds++;
- m_nRenderTrisCount += pChunk->nNumIndices / 3;
- }
- }
- m_nLoadedTrisCount = pRM->GetIndicesCount() / 3;
- m_nLoadedVertexCount = pRM->GetVerticesCount();
- }
- // this will prepare all deformable object during loading instead when needed.
- // Thus is will prevent runtime stalls (300ms when shooting a taxi with 6000 vertices)
- // but will incrase memory since every deformable information needs to be loaded(500kb for the taxi)
- // So this is more a workaround, the real solution would precompute the data in the RC and load
- // the data only when needed into memory
- if (GetCVars()->e_PrepareDeformableObjectsAtLoadTime && m_pRenderMesh && m_pDelayedSkinParams)
- {
- PrepareSkinData(m_pDelayedSkinParams->mtxSkelToMesh, m_pDelayedSkinParams->pPhysSkel, m_pDelayedSkinParams->r);
- }
- }
- #ifdef SUPPORT_TERRAIN_AO_PRE_COMPUTATIONS
- void CStatObj::CheckUpdateObjectHeightmap()
- {
- if (m_pHeightmap)
- {
- return;
- }
- PrintMessage("Computing object heightmap for: %s ... ", GetFilePath());
- m_nHeightmapSize = (int)(CLAMP(max(m_vBoxMax.x - m_vBoxMin.x, m_vBoxMax.y - m_vBoxMin.y) * 16, 8, 256));
- m_pHeightmap = new float[m_nHeightmapSize * m_nHeightmapSize];
- memset(m_pHeightmap, 0, sizeof(float) * m_nHeightmapSize * m_nHeightmapSize);
- float dx = max(0.001f, (m_vBoxMax.x - m_vBoxMin.x) / m_nHeightmapSize);
- float dy = max(0.001f, (m_vBoxMax.y - m_vBoxMin.y) / m_nHeightmapSize);
- Matrix34 objMatrix;
- objMatrix.SetIdentity();
- for (float x = m_vBoxMin.x + dx; x < m_vBoxMax.x - dx; x += dx)
- {
- for (float y = m_vBoxMin.y + dy; y < m_vBoxMax.y - dy; y += dy)
- {
- Vec3 vStart (x, y, m_vBoxMax.z);
- Vec3 vEnd (x, y, m_vBoxMin.z);
- Vec3 vClosestHitPoint(0, 0, 0);
- float fClosestHitDistance = 1000000;
- if (GetObjManager()->RayStatObjIntersection(this, objMatrix, GetMaterial(),
- vStart, vEnd, vClosestHitPoint, fClosestHitDistance, false))
- {
- int nX = CLAMP(int((x - m_vBoxMin.x) / dx), 0, m_nHeightmapSize - 1);
- int nY = CLAMP(int((y - m_vBoxMin.y) / dy), 0, m_nHeightmapSize - 1);
- m_pHeightmap[nX * m_nHeightmapSize + nY] = vClosestHitPoint.z;
- }
- }
- }
- PrintMessagePlus("[%dx%d] done", m_nHeightmapSize, m_nHeightmapSize);
- }
- float CStatObj::GetObjectHeight(float x, float y)
- {
- CheckUpdateObjectHeightmap();
- float dx = max(0.001f, (m_vBoxMax.x - m_vBoxMin.x) / m_nHeightmapSize);
- float dy = max(0.001f, (m_vBoxMax.y - m_vBoxMin.y) / m_nHeightmapSize);
- int nX = CLAMP(int((x - m_vBoxMin.x) / dx), 0, m_nHeightmapSize - 1);
- int nY = CLAMP(int((y - m_vBoxMin.y) / dy), 0, m_nHeightmapSize - 1);
- return m_pHeightmap[nX * m_nHeightmapSize + nY];
- }
- #endif
- //////////////////////////////////////////////////////////////////////////
- int CStatObj::CountChildReferences() const
- {
- // Check if it must be released.
- int nChildRefs = 0;
- int numChilds = (int)m_subObjects.size();
- for (int i = 0; i < numChilds; i++)
- {
- const IStatObj::SSubObject& so = m_subObjects[i];
- CStatObj* pChildStatObj = (CStatObj*)so.pStatObj;
- if (!pChildStatObj) // All stat objects must be at the begining of the array//
- {
- break;
- }
- // if I'm the real parent of this child, check that no-one else is referencing it, otherwise it doesn't matter if I get deleted
- if (pChildStatObj->m_pParentObject == this)
- {
- bool bIgnoreSharedStatObj = false;
- for (int k = 0; k < i; k++)
- {
- if (pChildStatObj == m_subObjects[k].pStatObj)
- {
- // If we share pointer to this stat obj then do not count it again.
- bIgnoreSharedStatObj = true;
- nChildRefs -= 1; // 1 reference from current object should be ignored.
- break;
- }
- }
- if (!bIgnoreSharedStatObj)
- {
- nChildRefs += pChildStatObj->m_nUsers - 1; // 1 reference from parent should be ignored.
- }
- }
- }
- assert(nChildRefs >= 0);
- return nChildRefs;
- }
- IStatObj* CStatObj::GetLowestLod()
- {
- if (int nLowestLod = CStatObj::GetMinUsableLod())
- {
- return m_pLODs ? (CStatObj*)m_pLODs[CStatObj::GetMinUsableLod()] : (CStatObj*)NULL;
- }
- return this;
- }
- //////////////////////////////////////////////////////////////////////////
- int CStatObj::FindHighestLOD(int nBias)
- {
- int nLowestLod = CStatObj::GetMinUsableLod();
- // if requested lod is not ready - find nearest ready one
- int nLod = CLAMP((int)m_nMaxUsableLod + nBias, nLowestLod, (int)m_nMaxUsableLod);
- while (nLod && nLod >= nLowestLod && (!m_pLODs || !m_pLODs[nLod] || !m_pLODs[nLod]->GetRenderMesh()))
- {
- nLod--;
- }
- if (nLod == 0 && !GetRenderMesh())
- {
- nLod = -1;
- }
- return nLod;
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::GetStatisticsNonRecursive(SStatistics& si)
- {
- CStatObj* pStatObj = this;
- for (int lod = 0; lod < MAX_STATOBJ_LODS_NUM; lod++)
- {
- CStatObj* pLod = (CStatObj*)pStatObj->GetLodObject(lod);
- if (pLod)
- {
- //if (!pLod0 && pLod->GetRenderMesh())
- //pLod0 = pLod;
- if (lod > 0 && lod + 1 > si.nLods) // Assign last existing lod.
- {
- si.nLods = lod + 1;
- }
- si.nVerticesPerLod[lod] += pLod->m_nLoadedVertexCount;
- si.nIndicesPerLod[lod] += pLod->m_nLoadedTrisCount * 3;
- si.nMeshSize += pLod->m_nRenderMeshMemoryUsage;
- IRenderMesh* pRenderMesh = pLod->GetRenderMesh();
- if (pRenderMesh)
- {
- si.nMeshSizeLoaded += pRenderMesh->GetMemoryUsage(0, IRenderMesh::MEM_USAGE_ONLY_STREAMS);
- //if (si.pTextureSizer)
- //pRenderMesh->GetTextureMemoryUsage(0,si.pTextureSizer);
- //if (si.pTextureSizer2)
- //pRenderMesh->GetTextureMemoryUsage(0,si.pTextureSizer2);
- }
- }
- }
- si.nIndices += m_nLoadedTrisCount * 3;
- si.nVertices += m_nLoadedVertexCount;
- for (int j = 0; j < pStatObj->m_arrPhysGeomInfo.GetGeomCount(); j++)
- {
- if (pStatObj->GetPhysGeom(j))
- {
- ICrySizer* pPhysSizer = GetISystem()->CreateSizer();
- pStatObj->GetPhysGeom(j)->pGeom->GetMemoryStatistics(pPhysSizer);
- int sz = pPhysSizer->GetTotalSize();
- si.nPhysProxySize += sz;
- si.nPhysProxySizeMax = max(si.nPhysProxySizeMax, sz);
- si.nPhysPrimitives += pStatObj->GetPhysGeom(j)->pGeom->GetPrimitiveCount();
- pPhysSizer->Release();
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CStatObj::GetStatistics(SStatistics& si)
- {
- si.bSplitLods = m_bLodsAreLoadedFromSeparateFile;
- bool bMultiSubObj = (GetFlags() & STATIC_OBJECT_COMPOUND) != 0;
- if (!bMultiSubObj)
- {
- GetStatisticsNonRecursive(si);
- si.nSubMeshCount = 0;
- si.nNumRefs = GetNumRefs();
- si.nDrawCalls = m_nRenderMatIds;
- }
- else
- {
- si.nNumRefs = GetNumRefs();
- std::vector<void*> addedObjects;
- for (int k = 0; k < GetSubObjectCount(); k++)
- {
- if (!GetSubObject(k))
- {
- continue;
- }
- CStatObj* pSubObj = (CStatObj*)GetSubObject(k)->pStatObj;
- int nSubObjectType = GetSubObject(k)->nType;
- if (nSubObjectType != STATIC_SUB_OBJECT_MESH && nSubObjectType != STATIC_SUB_OBJECT_HELPER_MESH)
- {
- continue;
- }
- if (stl::find(addedObjects, pSubObj))
- {
- continue;
- }
- addedObjects.push_back(pSubObj);
- if (pSubObj)
- {
- pSubObj->GetStatisticsNonRecursive(si);
- si.nSubMeshCount++;
- if (nSubObjectType == STATIC_SUB_OBJECT_MESH)
- {
- si.nDrawCalls += pSubObj->m_nRenderMatIds;
- }
- if (pSubObj->GetNumRefs() > si.nNumRefs)
- {
- si.nNumRefs = pSubObj->GetNumRefs();
- }
- }
- }
- }
- // Only do rough estimation based on the material
- // This is more consistent when streaming is enabled and render mesh may no exist
- if (m_pMaterial)
- {
- if (si.pTextureSizer)
- {
- m_pMaterial->GetTextureMemoryUsage(si.pTextureSizer);
- }
- if (si.pTextureSizer2)
- {
- m_pMaterial->GetTextureMemoryUsage(si.pTextureSizer2);
- }
- }
- }
|