1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 // -------------------------------------------------------------------------
4 // File name: statobjconstr.cpp
6 // Created: 28/5/2001 by Vladimir Kajalin
7 // Compilers: Visual Studio.NET
8 // Description: creation
9 // -------------------------------------------------------------------------
12 ////////////////////////////////////////////////////////////////////////////
18 #include "IndexedMesh.h"
19 #include "../RenderDll/Common/Shadow_Renderer.h"
20 #include <CryRenderer/IRenderer.h>
21 #include <CryMemory/CrySizer.h>
23 #include "PolygonClipContext.h"
25 #include "RenderMeshMerger.h"
26 #include "MergedMeshGeometry.h"
28 #define MAX_VERTICES_MERGABLE 15000
29 #define MAX_TRIS_IN_LOD_0 512
30 #define TRIS_IN_LOD_WARNING_RAIO (1.5f)
31 // Minimal ratio of Lod(n-1)/Lod(n) polygons to consider LOD for sub-object merging.
32 #define MIN_TRIS_IN_MERGED_LOD_RAIO (1.5f)
34 DEFINE_INTRUSIVE_LINKED_LIST(CStatObj
)
36 //////////////////////////////////////////////////////////////////////////
39 m_pAsyncUpdateContext
= 0;
41 m_nMergedMemoryUsage
= 0;
42 m_nUsers
= 0; // reference counter
43 m_nLastDrawMainFrameId
= 0;
46 m_lastBooleanOpScale
= 1.f
;
47 m_fGeometricMeanFaceArea
= 0.f
;
48 m_fLodDistance
= 0.0f
;
53 //////////////////////////////////////////////////////////////////////////
56 m_pAsyncUpdateContext
= 0;
59 m_nRenderTrisCount
= m_nLoadedTrisCount
= m_nLoadedVertexCount
= 0;
64 m_pClonedSourceObject
= 0;
65 m_bVehicleOnlyPhysics
= 0;
66 m_bBreakableByGame
= 0;
67 m_idmatBreakable
= -1;
75 m_aiVegetationRadius
= -1.0f
;
77 m_phys_density
= -1.0f
;
80 m_vVegCenter
.Set(0, 0, 0);
82 m_fGeometricMeanFaceArea
= 0.f
;
83 m_fLodDistance
= 0.0f
;
84 m_depthSortOffset
.Set(0, 0, 0);
88 m_bDefaultObject
= false;
91 for (int i
= 0; i
< MAX_STATOBJ_LODS_NUM
; i
++)
96 m_nModificationId
= 0;
97 m_nSubObjectMeshCount
= 0;
99 m_nRenderMeshMemoryUsage
= 0;
100 m_arrRenderMeshesPotentialMemoryUsage
[0] = m_arrRenderMeshesPotentialMemoryUsage
[1] = -1;
102 m_bCanUnload
= false;
103 m_bLodsLoaded
= false;
104 m_bDefaultObject
= false;
105 m_bOpenEdgesTested
= false;
106 m_bSubObject
= false;
107 m_bSharesChildren
= false;
108 m_bHasDeformationMorphs
= false;
109 m_bTmpIndexedMesh
= false;
111 m_bMergedLODs
= false;
112 m_bUnmergable
= false;
113 m_bLowSpecLod0Set
= false;
114 m_bHaveOcclusionProxy
= false;
115 m_bCheckGarbage
= false;
116 m_bLodsAreLoadedFromSeparateFile
= false;
117 m_bNoHitRefinement
= false;
118 m_bDontOccludeExplosions
= false;
119 m_isDeformable
= false;
120 m_isProxyTooBig
= false;
121 m_bHasStreamOnlyCGF
= true;
123 // Assign default material originally.
124 m_pMaterial
= GetMatMan()->GetDefaultMaterial();
130 m_pLastBooleanOp
= 0;
131 m_pMapFaceToFace0
= 0;
132 m_pClothTangentsData
= 0;
134 m_hasClothTangentsData
= m_hasSkinInfo
= 0;
135 m_pDelayedSkinParams
= 0;
136 m_arrPhysGeomInfo
.m_array
.clear();
138 m_nInitialSubObjHideMask
= 0;
140 #if !defined (_RELEASE)
141 m_fStreamingStart
= 0.0f
;
144 #ifdef OBJMAN_STREAM_STATS
145 m_nStatoscopeState
= 0;
149 //////////////////////////////////////////////////////////////////////////
150 CStatObj::~CStatObj()
155 void CStatObj::ShutDown()
159 // We don't need this stream anymore.
160 m_pReadStream
->Abort();
161 m_pReadStream
= NULL
;
164 SAFE_DELETE(m_pAsyncUpdateContext
);
166 // assert (IsHeapValid());
168 SAFE_DELETE(m_pIndexedMesh
);
169 // assert (IsHeapValid());
171 for (int n
= 0; n
< m_arrPhysGeomInfo
.GetGeomCount(); n
++)
172 if (m_arrPhysGeomInfo
[n
])
174 if (m_arrPhysGeomInfo
[n
]->pGeom
->GetForeignData() == (void*)this)
175 m_arrPhysGeomInfo
[n
]->pGeom
->SetForeignData(0, 0);
176 GetPhysicalWorld()->GetGeomManager()->UnregisterGeometry(m_arrPhysGeomInfo
[n
]);
178 m_arrPhysGeomInfo
.m_array
.clear();
180 _smart_ptr
<IRenderMesh
> pNullMesh
= nullptr;
181 m_pStreamedRenderMesh
= pNullMesh
;
182 m_pMergedRenderMesh
= pNullMesh
;
183 SetRenderMesh(pNullMesh
);
185 // assert (IsHeapValid());
187 /* // SDynTexture is not accessible for 3dengine
189 for(int i=0; i<FAR_TEX_COUNT; i++)
190 if(m_arrSpriteTexPtr[i])
191 m_arrSpriteTexPtr[i]->ReleaseDynamicRT(true);
193 for(int i=0; i<FAR_TEX_COUNT_60; i++)
194 if(m_arrSpriteTexPtr_60[i])
195 m_arrSpriteTexPtr_60[i]->ReleaseDynamicRT(true);
198 SAFE_RELEASE(m_pLattice
);
201 for (int i
= 0; i
< MAX_STATOBJ_LODS_NUM
; i
++)
204 if (m_pLODs
[i
]->m_pParentObject
)
205 GetObjManager()->UnregisterForStreaming(m_pLODs
[i
]->m_pParentObject
);
207 GetObjManager()->UnregisterForStreaming(m_pLODs
[i
]);
209 // Sub objects do not own the LODs, so they should not delete them.
213 //////////////////////////////////////////////////////////////////////////
214 // Handle sub-objects and parents.
215 //////////////////////////////////////////////////////////////////////////
216 for (size_t i
= 0; i
< m_subObjects
.size(); i
++)
218 CStatObj
* pChildObj
= (CStatObj
*)m_subObjects
[i
].pStatObj
;
221 if (!m_bSharesChildren
)
222 pChildObj
->m_pParentObject
= NULL
;
223 GetObjManager()->UnregisterForStreaming(pChildObj
);
224 pChildObj
->Release();
227 m_subObjects
.clear();
229 if (m_pParentObject
&& !m_pParentObject
->m_subObjects
.empty())
231 // Remove this StatObject from sub-objects of the parent.
232 SSubObject
* pSubObjects
= &m_pParentObject
->m_subObjects
[0];
233 for (int i
= 0, num
= m_pParentObject
->m_subObjects
.size(); i
< num
; i
++)
235 if (pSubObjects
[i
].pStatObj
== this)
237 m_pParentObject
->m_subObjects
.erase(m_pParentObject
->m_subObjects
.begin() + i
);
243 //////////////////////////////////////////////////////////////////////////
247 if (m_pMapFaceToFace0
)
248 delete[] m_pMapFaceToFace0
;
249 m_pMapFaceToFace0
= 0;
250 if (m_hasClothTangentsData
&& !m_pClonedSourceObject
)
251 delete[] m_pClothTangentsData
;
252 if (m_hasSkinInfo
&& !m_pClonedSourceObject
)
253 delete[] m_pSkinInfo
;
254 m_pClothTangentsData
= 0;
255 m_hasClothTangentsData
= 0;
259 SAFE_DELETE(m_pDelayedSkinParams
);
261 SAFE_RELEASE(m_pClonedSourceObject
);
263 GetObjManager()->UnregisterForStreaming(this);
265 SAFE_DELETE_ARRAY(m_pLODs
);
268 //////////////////////////////////////////////////////////////////////////
269 int CStatObj::Release()
271 // Has to be thread safe, as it can be called by a worker thread for deferred plane breaks
272 int newRef
= CryInterlockedDecrement(&m_nUsers
);
275 if (m_pParentObject
&& m_pParentObject
->m_nUsers
<= 0)
277 GetObjManager()->CheckForGarbage(m_pParentObject
);
281 GetObjManager()->CheckForGarbage(this);
287 //////////////////////////////////////////////////////////////////////////
288 void* CStatObj::operator new(size_t size
)
290 CObjManager
* pObjManager
= GetObjManager();
291 assert(size
== sizeof(CStatObj
));
292 return pObjManager
->AllocateStatObj();
295 void CStatObj::operator delete(void* pToFree
)
297 CObjManager
* pObjManager
= GetObjManager();
298 pObjManager
->FreeStatObj((CStatObj
*)pToFree
);
301 //////////////////////////////////////////////////////////////////////////
302 void CStatObj::FreeIndexedMesh()
306 WriteLock
lock(m_lockIdxMesh
);
307 delete m_pIndexedMesh
;
312 //////////////////////////////////////////////////////////////////////////
313 void CStatObj::CalcRadiuses()
315 if (!m_AABB
.min
.IsValid() || !m_AABB
.max
.IsValid())
317 Error("CStatObj::CalcRadiuses: Invalid bbox, File name: %s", m_szFileName
.c_str());
322 float dxh
= (float)max(fabs(GetBoxMax().x
), fabs(GetBoxMin().x
));
323 float dyh
= (float)max(fabs(GetBoxMax().y
), fabs(GetBoxMin().y
));
324 m_fRadiusHors
= (float)sqrt_tpl(dxh
* dxh
+ dyh
* dyh
);
325 m_fRadiusVert
= (GetBoxMax().z
- 0) * 0.5f
;// never change this
326 m_vVegCenter
= m_AABB
.GetCenter();
327 m_vVegCenter
.z
= m_fRadiusVert
;
330 void CStatObj::MakeRenderMesh()
332 if (gEnv
->IsDedicated())
335 FUNCTION_PROFILER_3DENGINE
;
337 _smart_ptr
<IRenderMesh
> pNullMesh
= nullptr;
338 SetRenderMesh(pNullMesh
);
340 if (!m_pIndexedMesh
|| m_pIndexedMesh
->GetSubSetCount() == 0)
343 CMesh
* pMesh
= m_pIndexedMesh
->GetMesh();
345 m_nRenderTrisCount
= 0;
346 //////////////////////////////////////////////////////////////////////////
347 // Initialize Mesh subset material flags.
348 //////////////////////////////////////////////////////////////////////////
349 for (int i
= 0; i
< pMesh
->GetSubSetCount(); i
++)
351 SMeshSubset
& subset
= pMesh
->m_subsets
[i
];
352 if (!(subset
.nMatFlags
& MTL_FLAG_NODRAW
))
354 m_nRenderTrisCount
+= subset
.nNumIndices
/ 3;
357 //////////////////////////////////////////////////////////////////////////
358 if (!m_nRenderTrisCount
)
361 if (!(GetFlags() & STATIC_OBJECT_DYNAMIC
))
362 m_pRenderMesh
= GetRenderer()->CreateRenderMesh("StatObj_Static", GetFilePath(), NULL
, eRMT_Static
);
365 m_pRenderMesh
= GetRenderer()->CreateRenderMesh("StatObj_Dynamic", GetFilePath(), NULL
, eRMT_Dynamic
);
366 m_pRenderMesh
->KeepSysMesh(true);
369 SMeshBoneMapping_uint16
* const pBoneMap
= pMesh
->m_pBoneMapping
;
370 pMesh
->m_pBoneMapping
= 0;
372 nFlags
|= (!GetCVars()->e_StreamCgf
&& Get3DEngine()->m_bInLoad
) ? FSM_SETMESH_ASYNC
: 0;
373 m_pRenderMesh
->SetMesh(*pMesh
, 0, nFlags
, NULL
, false);
374 pMesh
->m_pBoneMapping
= pBoneMap
;
377 //////////////////////////////////////////////////////////////////////////
378 void CStatObj::SetMaterial(IMaterial
* pMaterial
)
380 m_pMaterial
= pMaterial
;
383 ///////////////////////////////////////////////////////////////////////////////////////
384 Vec3
CStatObj::GetHelperPos(const char* szHelperName
)
386 SSubObject
* pSubObj
= FindSubObject(szHelperName
);
388 return Vec3(0, 0, 0);
390 return Vec3(pSubObj
->tm
.m03
, pSubObj
->tm
.m13
, pSubObj
->tm
.m23
);
393 ///////////////////////////////////////////////////////////////////////////////////////
394 const Matrix34
& CStatObj::GetHelperTM(const char* szHelperName
)
396 SSubObject
* pSubObj
= FindSubObject(szHelperName
);
400 static Matrix34
identity(IDENTITY
);
407 bool CStatObj::IsSameObject(const char* szFileName
, const char* szGeomName
)
412 if (stricmp(szGeomName
, m_szGeomName
) != 0)
416 // Normilize file name
417 char szFileNameNorm
[MAX_PATH_LENGTH
] = "";
418 char* pszDest
= szFileNameNorm
;
419 const char* pszSource
= szFileName
;
422 if (*pszSource
== '\\')
425 *pszDest
++ = *pszSource
;
431 if (stricmp(szFileNameNorm
, m_szFileName
) != 0)
437 void CStatObj::GetMemoryUsage(ICrySizer
* pSizer
) const
440 SIZER_COMPONENT_NAME(pSizer
, "Self");
441 pSizer
->AddObject(this, sizeof(*this));
445 SIZER_COMPONENT_NAME(pSizer
, "subObjects");
446 pSizer
->AddObject(m_subObjects
);
450 SIZER_COMPONENT_NAME(pSizer
, "Strings");
451 pSizer
->AddObject(m_szFileName
);
452 pSizer
->AddObject(m_szGeomName
);
453 pSizer
->AddObject(m_szProperties
);
457 SIZER_COMPONENT_NAME(pSizer
, "Material");
458 pSizer
->AddObject(m_pMaterial
);
462 SIZER_COMPONENT_NAME(pSizer
, "PhysGeomInfo");
463 pSizer
->AddObject(m_arrPhysGeomInfo
);
467 for (int i
= 1; i
< MAX_STATOBJ_LODS_NUM
; i
++)
469 SIZER_COMPONENT_NAME(pSizer
, "StatObjLods");
470 pSizer
->AddObject(m_pLODs
[i
]);
475 SIZER_COMPONENT_NAME(pSizer
, "Mesh");
476 pSizer
->AddObject(m_pIndexedMesh
);
481 nVtx
= m_pIndexedMesh
->GetVertexCount();
482 else if (m_pRenderMesh
)
483 nVtx
= m_pRenderMesh
->GetVerticesCount();
487 SIZER_COMPONENT_NAME(pSizer
, "StatObj Foliage Data");
488 pSizer
->AddObject(m_pSpines
, sizeof(m_pSpines
[0]), m_nSpines
);
490 pSizer
->AddObject(m_pBoneMapping
, sizeof(m_pBoneMapping
[0]), nVtx
);
491 for (int i
= 0; i
< m_nSpines
; i
++)
492 pSizer
->AddObject(m_pSpines
[i
].pVtx
, sizeof(Vec3
) * 2 + sizeof(Vec4
), m_pSpines
[i
].nVtx
);
495 if (m_hasClothTangentsData
&& (!m_pClonedSourceObject
|| m_pClonedSourceObject
== this))
497 SIZER_COMPONENT_NAME(pSizer
, "Deformable StatObj ClothTangents");
498 pSizer
->AddObject(m_pClothTangentsData
, nVtx
* sizeof(m_pClothTangentsData
[0]));
501 if (m_hasSkinInfo
&& (!m_pClonedSourceObject
|| m_pClonedSourceObject
== this))
503 SIZER_COMPONENT_NAME(pSizer
, "Deformable StatObj SkinData");
504 pSizer
->AddObject(m_pSkinInfo
, (nVtx
+ 1) * sizeof(m_pSkinInfo
[0]));
507 if (m_pMapFaceToFace0
)
509 SIZER_COMPONENT_NAME(pSizer
, "Deformable StatObj Mesh");
510 pSizer
->AddObject(m_pMapFaceToFace0
, sizeof(m_pMapFaceToFace0
[0]) * max(m_nLoadedTrisCount
, m_nRenderTrisCount
));
514 //////////////////////////////////////////////////////////////////////////
515 void CStatObj::SetLodObject(int nLod
, IStatObj
* pObj
)
517 assert(nLod
> 0 && nLod
< MAX_STATOBJ_LODS_NUM
);
518 if (nLod
<= 0 || nLod
>= MAX_STATOBJ_LODS_NUM
)
521 CStatObj
* pLod
= (CStatObj
*)pObj
;
522 if (strstr(m_szProperties
, "lowspeclod0"))
523 m_bLowSpecLod0Set
= true;
525 bool bLodCompound
= pLod
&& (pLod
->GetFlags() & STATIC_OBJECT_COMPOUND
) != 0;
527 if (pLod
&& !bLodCompound
)
529 // Check if low lod decrease amount of used materials.
530 int nPrevLodMatIds
= m_nRenderMatIds
;
531 int nPrevLodTris
= m_nLoadedTrisCount
;
532 if (nLod
> 1 && m_pLODs
&& m_pLODs
[nLod
- 1])
534 nPrevLodMatIds
= m_pLODs
[nLod
- 1]->m_nRenderMatIds
;
535 nPrevLodTris
= m_pLODs
[nLod
- 1]->m_nLoadedTrisCount
;
538 if (GetCVars()->e_LodsForceUse
)
540 if ((int)m_nMaxUsableLod
< nLod
)
541 m_nMaxUsableLod
= nLod
;
545 int min_tris
= GetCVars()->e_LodMinTtris
;
546 if (((pLod
->m_nLoadedTrisCount
>= min_tris
|| nPrevLodTris
>= (3 * min_tris
) / 2)
547 || pLod
->m_nRenderMatIds
< nPrevLodMatIds
) && nLod
> (int)m_nMaxUsableLod
)
549 m_nMaxUsableLod
= nLod
;
553 if (m_pParentObject
&& (m_pParentObject
->m_nMaxUsableLod
< m_nMaxUsableLod
))
554 m_pParentObject
->m_nMaxUsableLod
= m_nMaxUsableLod
;
556 pLod
->m_pLod0
= this;
557 pLod
->m_pMaterial
= m_pMaterial
; // Lod must use same material as parent.
559 if (pLod
->m_nLoadedTrisCount
> MAX_TRIS_IN_LOD_0
)
561 if ((strstr(pLod
->GetProperties(), "lowspeclod0") != 0) && !m_bLowSpecLod0Set
)
563 m_bLowSpecLod0Set
= true;
564 m_nMaxUsableLod0
= nLod
;
566 if (!m_bLowSpecLod0Set
)
567 m_nMaxUsableLod0
= nLod
;
569 if (nLod
+ 1 > (int)m_nLoadedLodsNum
)
570 m_nLoadedLodsNum
= nLod
+ 1;
572 // When assigning lod to child object.
575 if (nLod
+ 1 > (int)m_pParentObject
->m_nLoadedLodsNum
)
576 m_pParentObject
->m_nLoadedLodsNum
= nLod
+ 1;
580 if (pLod
&& bLodCompound
)
582 m_nMaxUsableLod
= nLod
;
583 pLod
->m_bUnmergable
= m_bUnmergable
;
586 if (!m_pLODs
&& pLod
)
587 m_pLODs
= new _smart_ptr
<CStatObj
>[MAX_STATOBJ_LODS_NUM
];
590 m_pLODs
[nLod
] = pLod
;
593 //////////////////////////////////////////////////////////////////////////
594 IStatObj
* CStatObj::GetLodObject(int nLodLevel
, bool bReturnNearest
)
610 nLodLevel
= min(nLodLevel
, MAX_STATOBJ_LODS_NUM
- 1);
613 if (nLodLevel
< MAX_STATOBJ_LODS_NUM
)
615 pLod
= m_pLODs
[nLodLevel
];
617 if (bReturnNearest
&& !pLod
)
619 for (int deltaLod
= 1; deltaLod
< MAX_STATOBJ_LODS_NUM
; ++deltaLod
)
621 int lower
= nLodLevel
- deltaLod
;
622 if (0 < lower
&& m_pLODs
[lower
])
623 return m_pLODs
[lower
];
627 int upper
= nLodLevel
+ deltaLod
;
628 if (upper
< MAX_STATOBJ_LODS_NUM
&& m_pLODs
[upper
])
629 return m_pLODs
[upper
];
637 bool CStatObj::IsPhysicsExist() const
639 return m_arrPhysGeomInfo
.GetGeomCount() > 0;
642 bool CStatObj::IsSphereOverlap(const Sphere
& sSphere
)
644 if (m_pRenderMesh
&& Overlap::Sphere_AABB(sSphere
, m_AABB
))
648 int nInds
= m_pRenderMesh
->GetIndicesCount();
649 const byte
* pPos
= m_pRenderMesh
->GetPosPtr(nPosStride
, FSL_READ
);
650 vtx_idx
* pInds
= m_pRenderMesh
->GetIndexPtr(FSL_READ
);
653 for (int i
= 0; (i
+ 2) < nInds
; i
+= 3)
655 // test all triangles of water surface strip
656 Vec3 v0
= (*(Vec3
*)&pPos
[nPosStride
* pInds
[i
+ 0]]);
657 Vec3 v1
= (*(Vec3
*)&pPos
[nPosStride
* pInds
[i
+ 1]]);
658 Vec3 v2
= (*(Vec3
*)&pPos
[nPosStride
* pInds
[i
+ 2]]);
660 vBoxMin
.CheckMin(v1
);
661 vBoxMin
.CheckMin(v2
);
663 vBoxMax
.CheckMax(v1
);
664 vBoxMax
.CheckMax(v2
);
666 if (Overlap::Sphere_AABB(sSphere
, AABB(vBoxMin
, vBoxMax
)))
674 //////////////////////////////////////////////////////////////////////////
675 void CStatObj::Invalidate(bool bPhysics
, float tolerance
)
679 m_pIndexedMesh
->CalcBBox();
681 m_AABB
= m_pIndexedMesh
->m_bbox
;
684 m_nLoadedVertexCount
= m_pIndexedMesh
->GetVertexCount();
685 m_nLoadedTrisCount
= m_pIndexedMesh
->GetFaceCount();
686 if (!m_nLoadedTrisCount
)
688 m_nLoadedTrisCount
= m_pIndexedMesh
->GetIndexCount() / 3;
694 PhysicalizeGeomType(PHYS_GEOM_TYPE_DEFAULT
, *m_pIndexedMesh
->GetMesh(), tolerance
, 0);
697 ReleaseIndexedMesh(true);
700 //////////////////////////////////////////////////////////////////////////
701 // Iterate through sub objects and update hide mask and sub obj mesh count.
702 //////////////////////////////////////////////////////////////////////////
703 m_nSubObjectMeshCount
= 0;
704 for (size_t i
= 0, numsub
= m_subObjects
.size(); i
< numsub
; i
++)
706 SSubObject
& subObj
= m_subObjects
[i
];
707 if (subObj
.pStatObj
&& subObj
.nType
== STATIC_SUB_OBJECT_MESH
)
709 m_nSubObjectMeshCount
++;
713 UnMergeSubObjectsRenderMeshes();
716 //////////////////////////////////////////////////////////////////////////
717 IStatObj
* CStatObj::Clone(bool bCloneGeometry
, bool bCloneChildren
, bool bMeshesOnly
)
719 if (m_bDefaultObject
)
722 CStatObj
* pNewObj
= new CStatObj
;
724 pNewObj
->m_pClonedSourceObject
= m_pClonedSourceObject
? m_pClonedSourceObject
: this;
725 pNewObj
->m_pClonedSourceObject
->AddRef(); // Cloned object will keep a reference to this.
727 pNewObj
->m_nLoadedTrisCount
= m_nLoadedTrisCount
;
728 pNewObj
->m_nLoadedVertexCount
= m_nLoadedVertexCount
;
729 pNewObj
->m_nRenderTrisCount
= m_nRenderTrisCount
;
735 UnMergeSubObjectsRenderMeshes();
737 if (m_pIndexedMesh
&& !m_bMerged
)
739 pNewObj
->m_pIndexedMesh
= new CIndexedMesh
;
740 pNewObj
->m_pIndexedMesh
->CopyFrom(*m_pIndexedMesh
->GetMesh());
742 if (m_pRenderMesh
&& !m_bMerged
)
744 _smart_ptr
<IRenderMesh
> pRenderMesh
= GetRenderer()->CreateRenderMesh(
746 pNewObj
->GetFilePath(),
748 ((GetFlags() & STATIC_OBJECT_DYNAMIC
) ? eRMT_Dynamic
: eRMT_Static
));
750 m_pRenderMesh
->CopyTo(pRenderMesh
);
751 pNewObj
->SetRenderMesh(pRenderMesh
);
757 if (m_pMergedRenderMesh
!= m_pRenderMesh
)
758 pNewObj
->SetRenderMesh(m_pRenderMesh
);
760 pNewObj
->m_pRenderMesh
= m_pRenderMesh
;
761 pNewObj
->m_pMergedRenderMesh
= m_pMergedRenderMesh
;
762 pNewObj
->m_bMerged
= m_pMergedRenderMesh
!= NULL
;
765 pNewObj
->m_szFileName
= m_szFileName
;
766 pNewObj
->m_szGeomName
= m_szGeomName
;
769 pNewObj
->m_pMaterial
= m_pMaterial
;
771 for (int i
= 0; i
< m_arrPhysGeomInfo
.GetGeomCount(); i
++)
773 pNewObj
->m_arrPhysGeomInfo
.SetPhysGeom(m_arrPhysGeomInfo
[i
], i
, m_arrPhysGeomInfo
.GetGeomType(i
));
774 if (pNewObj
->m_arrPhysGeomInfo
[i
])
775 GetPhysicalWorld()->GetGeomManager()->AddRefGeometry(pNewObj
->m_arrPhysGeomInfo
[i
]);
777 pNewObj
->m_phys_mass
= m_phys_mass
;
778 pNewObj
->m_phys_density
= m_phys_density
;
779 pNewObj
->m_AABB
= m_AABB
;
780 pNewObj
->m_vVegCenter
= m_vVegCenter
;
782 pNewObj
->m_fRadiusHors
= m_fRadiusHors
;
783 pNewObj
->m_fRadiusVert
= m_fRadiusVert
;
785 pNewObj
->m_nFlags
= m_nFlags
| STATIC_OBJECT_CLONE
;
787 pNewObj
->m_fGeometricMeanFaceArea
= m_fGeometricMeanFaceArea
;
788 pNewObj
->m_fLodDistance
= m_fLodDistance
;
789 pNewObj
->m_depthSortOffset
= m_depthSortOffset
;
791 //////////////////////////////////////////////////////////////////////////
793 //////////////////////////////////////////////////////////////////////////
794 pNewObj
->m_bCanUnload
= false;
795 pNewObj
->m_bDefaultObject
= m_bDefaultObject
;
796 pNewObj
->m_bOpenEdgesTested
= m_bOpenEdgesTested
;
797 pNewObj
->m_bSubObject
= false; // [anton] since parent is not copied anyway
798 pNewObj
->m_bVehicleOnlyPhysics
= m_bVehicleOnlyPhysics
;
799 pNewObj
->m_idmatBreakable
= m_idmatBreakable
;
800 pNewObj
->m_bBreakableByGame
= m_bBreakableByGame
;
801 pNewObj
->m_bHasDeformationMorphs
= m_bHasDeformationMorphs
;
802 pNewObj
->m_bTmpIndexedMesh
= m_bTmpIndexedMesh
;
803 pNewObj
->m_bHaveOcclusionProxy
= m_bHaveOcclusionProxy
;
804 pNewObj
->m_bHasStreamOnlyCGF
= m_bHasStreamOnlyCGF
;
805 pNewObj
->m_eStreamingStatus
= m_eStreamingStatus
;
806 //////////////////////////////////////////////////////////////////////////
808 int numSubObj
= (int)m_subObjects
.size();
812 for (size_t i
= 0; i
< m_subObjects
.size(); i
++)
814 if (m_subObjects
[i
].nType
== STATIC_SUB_OBJECT_MESH
)
820 pNewObj
->m_subObjects
.reserve(numSubObj
);
821 for (int i
= 0; i
< numSubObj
; i
++)
823 pNewObj
->m_subObjects
.push_back(m_subObjects
[i
]);
824 pNewObj
->m_subObjects
[i
].pFoliage
= 0;
825 if (m_subObjects
[i
].pStatObj
)
829 pNewObj
->m_subObjects
[i
].pStatObj
= m_subObjects
[i
].pStatObj
->Clone(bCloneGeometry
, bCloneChildren
, bMeshesOnly
);
830 pNewObj
->m_subObjects
[i
].pStatObj
->AddRef();
831 ((CStatObj
*)(pNewObj
->m_subObjects
[i
].pStatObj
))->m_pParentObject
= this;
835 m_subObjects
[i
].pStatObj
->AddRef();
836 ((CStatObj
*)(m_subObjects
[i
].pStatObj
))->m_nFlags
|= STATIC_OBJECT_MULTIPLE_PARENTS
;
840 pNewObj
->m_nSubObjectMeshCount
= m_nSubObjectMeshCount
;
842 pNewObj
->m_bSharesChildren
= true;
844 if (pNewObj
->m_hasClothTangentsData
= m_hasClothTangentsData
)
845 pNewObj
->m_pClothTangentsData
= m_pClothTangentsData
;
846 if (pNewObj
->m_hasSkinInfo
= m_hasSkinInfo
)
847 pNewObj
->m_pSkinInfo
= m_pSkinInfo
;
851 //////////////////////////////////////////////////////////////////////////
853 IIndexedMesh
* CStatObj::GetIndexedMesh(bool bCreateIfNone
)
855 WriteLock
lock(m_lockIdxMesh
);
857 return m_pIndexedMesh
;
858 else if (m_pRenderMesh
&& bCreateIfNone
)
861 if (m_pRenderMesh
->GetIndexedMesh(m_pIndexedMesh
= new CIndexedMesh
) == NULL
)
863 // GetIndexMesh will free the IndexedMesh object if an allocation failed
864 m_pIndexedMesh
= NULL
;
868 CMesh
* pMesh
= m_pIndexedMesh
->GetMesh();
869 if (!pMesh
|| pMesh
->m_subsets
.size() <= 0)
871 m_pIndexedMesh
->Release();
875 m_bTmpIndexedMesh
= true;
877 int i
, j
, i0
= pMesh
->m_subsets
[0].nFirstVertId
+ pMesh
->m_subsets
[0].nNumVerts
;
878 for (i
= j
= 1; i
< pMesh
->m_subsets
.size(); i
++)
879 if (pMesh
->m_subsets
[i
].nFirstVertId
- i0
< pMesh
->m_subsets
[j
].nFirstVertId
- i0
)
881 if (j
< pMesh
->m_subsets
.size() && pMesh
->m_subsets
[0].nPhysicalizeType
== PHYS_GEOM_TYPE_DEFAULT
&&
882 pMesh
->m_subsets
[j
].nPhysicalizeType
!= PHYS_GEOM_TYPE_DEFAULT
&& pMesh
->m_subsets
[j
].nFirstVertId
> i0
)
884 pMesh
->m_subsets
[j
].nNumVerts
+= pMesh
->m_subsets
[j
].nFirstVertId
- i0
;
885 pMesh
->m_subsets
[j
].nFirstVertId
= i0
;
887 return m_pIndexedMesh
;
892 IIndexedMesh
* CStatObj::CreateIndexedMesh()
895 m_pIndexedMesh
= new CIndexedMesh();
897 return m_pIndexedMesh
;
900 void CStatObj::ReleaseIndexedMesh(bool bRenderMeshUpdated
)
902 WriteLock
lock(m_lockIdxMesh
);
903 if (m_bTmpIndexedMesh
&& m_pIndexedMesh
)
906 CMesh
* pMesh
= m_pIndexedMesh
->GetMesh();
907 if (m_pRenderMesh
&& !bRenderMeshUpdated
)
909 TRenderChunkArray
& Chunks
= m_pRenderMesh
->GetChunks();
910 for (int i
= 0; i
< pMesh
->m_subsets
.size(); i
++)
911 Chunks
[i
].m_nMatFlags
|= pMesh
->m_subsets
[i
].nMatFlags
& 1 << 30;
913 if (bRenderMeshUpdated
&& m_pBoneMapping
)
915 for (int i
= iend
= 0; i
< (int)pMesh
->m_subsets
.size(); i
++)
916 if ((pMesh
->m_subsets
[i
].nMatFlags
& (MTL_FLAG_NOPHYSICALIZE
| MTL_FLAG_NODRAW
)) == MTL_FLAG_NOPHYSICALIZE
)
918 for (istart
= iend
++; iend
< (int)m_chunkBoneIds
.size() && m_chunkBoneIds
[iend
]; iend
++)
920 if (!pMesh
->m_subsets
[i
].nNumIndices
)
922 m_chunkBoneIds
.erase(m_chunkBoneIds
.begin() + istart
, m_chunkBoneIds
.begin() + iend
);
927 m_pIndexedMesh
->Release();
929 m_bTmpIndexedMesh
= false;
933 //////////////////////////////////////////////////////////////////////////
934 static bool SubObjectsOfCompoundHaveLOD(const CStatObj
* pStatObj
, int nLod
)
936 int numSubObjects
= pStatObj
->GetSubObjectCount();
937 for (int i
= 0; i
< numSubObjects
; ++i
)
939 const IStatObj::SSubObject
* pSubObject
= const_cast<CStatObj
*>(pStatObj
)->GetSubObject(i
);
942 const CStatObj
* pChildObj
= (const CStatObj
*)pSubObject
->pStatObj
;
945 if (!pChildObj
->m_pLODs
)
947 const CStatObj
* pLod
= pChildObj
->m_pLODs
[nLod
];
954 //////////////////////////////////////////////////////////////////////////
955 void CStatObj::TryMergeSubObjects(bool bFromStreaming
)
957 // sub meshes merging
958 if (GetCVars()->e_StatObjMerge
)
960 if (!m_bUnmergable
&& !IsDeformable())
962 MergeSubObjectsRenderMeshes(bFromStreaming
, this, 0);
964 if (!bFromStreaming
&& !m_pLODs
&& m_nFlags
& STATIC_OBJECT_COMPOUND
)
966 // Check if LODs were not split (production mode)
967 for (int i
= 1; i
< MAX_STATOBJ_LODS_NUM
; ++i
)
969 if (!SubObjectsOfCompoundHaveLOD(this, i
))
972 CStatObj
* pStatObj
= new CStatObj();
973 pStatObj
->m_szFileName
= m_szFileName
;
974 static_assert(MAX_STATOBJ_LODS_NUM
< 10, "Increase size of lodName buffer");
975 char lodName
[] = "-mlod?"; // '?' is a placeholder for the number
976 ltoa(i
, &lodName
[5], 10);
977 pStatObj
->m_szFileName
.append(lodName
);
978 pStatObj
->m_szGeomName
= m_szGeomName
;
979 pStatObj
->m_bSubObject
= true;
981 SetLodObject(i
, pStatObj
);
982 m_bMergedLODs
= true;
988 for (int i
= 1; i
< MAX_STATOBJ_LODS_NUM
; i
++)
992 m_pLODs
[i
]->MergeSubObjectsRenderMeshes(bFromStreaming
, this, i
);
1000 //////////////////////////////////////////////////////////////////////////
1001 void CStatObj::MergeSubObjectsRenderMeshes(bool bFromStreaming
, CStatObj
* pLod0
, int nLod
)
1006 MEMSTAT_CONTEXT(EMemStatContextType::Other
, "Merged StatObj");
1007 FUNCTION_PROFILER_3DENGINE
;
1010 m_pMergedRenderMesh
= 0;
1012 int nSubObjCount
= (int)pLod0
->m_subObjects
.size();
1014 std::vector
<SRenderMeshInfoInput
> lstRMI
;
1016 SRenderMeshInfoInput rmi
;
1018 rmi
.pMat
= m_pMaterial
;
1019 rmi
.mat
.SetIdentity();
1021 rmi
.pSrcRndNode
= 0;
1023 for (int s
= 0; s
< nSubObjCount
; s
++)
1025 CStatObj::SSubObject
* pSubObj
= &pLod0
->m_subObjects
[s
];
1026 if (pSubObj
->pStatObj
&& pSubObj
->nType
== STATIC_SUB_OBJECT_MESH
)
1028 CStatObj
* pStatObj
= (CStatObj
*)pSubObj
->pStatObj
->GetLodObject(nLod
, true); // Get lod, if not exist get lowest existing.
1031 CryAutoCriticalSection
lock(pStatObj
->m_streamingMeshLock
);
1032 if (pStatObj
->m_pRenderMesh
|| pStatObj
->m_pStreamedRenderMesh
)
1034 rmi
.pMesh
= pStatObj
->m_pRenderMesh
? pStatObj
->m_pRenderMesh
: pStatObj
->m_pStreamedRenderMesh
;
1035 rmi
.mat
= pSubObj
->tm
;
1036 rmi
.bIdentityMatrix
= pSubObj
->bIdentityMatrix
;
1037 rmi
.nSubObjectIndex
= s
;
1038 lstRMI
.push_back(rmi
);
1044 _smart_ptr
<IRenderMesh
> pMergedMesh
= 0;
1045 if (lstRMI
.size() == 1 && lstRMI
[0].bIdentityMatrix
)
1047 // If identity matrix and only mesh-subobject use it as a merged render mesh.
1048 pMergedMesh
= rmi
.pMesh
;
1050 else if (!lstRMI
.empty())
1053 info
.sMeshName
= GetFilePath();
1054 info
.sMeshType
= "StatObj_Merged";
1055 info
.bMergeToOneRenderMesh
= true;
1056 info
.pUseMaterial
= m_pMaterial
;
1057 pMergedMesh
= GetSharedRenderMeshMerger()->MergeRenderMeshes(&lstRMI
[0], lstRMI
.size(), info
);
1064 CryAutoCriticalSection
lock(m_streamingMeshLock
);
1065 m_pMergedRenderMesh
= pMergedMesh
;
1066 m_pStreamedRenderMesh
= pMergedMesh
;
1070 m_pMergedRenderMesh
= pMergedMesh
;
1071 SetRenderMesh(pMergedMesh
);
1077 // Make sure upmost lod is also marked to be merged.
1078 m_pLod0
->m_bMerged
= true;
1083 bool CStatObj::IsMatIDReferencedByObj(uint16 matID
)
1086 if (IRenderMesh
* pRenderMesh
= GetRenderMesh())
1088 TRenderChunkArray
& Chunks
= pRenderMesh
->GetChunks();
1090 for (int nChunkId
= 0; nChunkId
< Chunks
.size(); nChunkId
++)
1092 if (Chunks
[nChunkId
].m_nMatID
== matID
)
1100 int nSubObjCount
= (int)m_subObjects
.size();
1101 for (int s
= 0; s
< nSubObjCount
; s
++)
1103 CStatObj::SSubObject
* pSubObj
= &m_subObjects
[s
];
1105 if (pSubObj
->pStatObj
)
1107 CStatObj
* pSubStatObj
= (CStatObj
*)pSubObj
->pStatObj
;
1109 if (IRenderMesh
* pSubRenderMesh
= pSubStatObj
->GetRenderMesh())
1111 TRenderChunkArray
& Chunks
= pSubRenderMesh
->GetChunks();
1113 for (int nChunkId
= 0; nChunkId
< Chunks
.size(); nChunkId
++)
1115 if (Chunks
[nChunkId
].m_nMatID
== matID
)
1127 //////////////////////////////////////////////////////////////////////////
1128 bool CStatObj::CanMergeSubObjects()
1130 if (gEnv
->IsDedicated())
1134 int nTotalVertexCount
= 0;
1135 int nTotalTriCount
= 0;
1136 int nTotalRenderChunksCount
= 0;
1138 int nSubObjCount
= (int)m_subObjects
.size();
1139 for (int s
= 0; s
< nSubObjCount
; s
++)
1141 CStatObj::SSubObject
* pSubObj
= &m_subObjects
[s
];
1142 if (pSubObj
->pStatObj
&& pSubObj
->nType
== STATIC_SUB_OBJECT_MESH
&& !pSubObj
->bHidden
)
1144 CStatObj
* pStatObj
= (CStatObj
*)pSubObj
->pStatObj
;
1145 if (pStatObj
->m_pMaterial
!= m_pMaterial
|| pStatObj
->m_nSpines
) // All materials must be same, and no bendable foliage
1150 nTotalVertexCount
+= pStatObj
->m_nLoadedVertexCount
;
1151 nTotalTriCount
+= pStatObj
->m_nLoadedTrisCount
;
1152 nTotalRenderChunksCount
+= pStatObj
->m_nRenderMatIds
;
1156 // Check for mat_breakable surface type in material
1159 int nSubMtls
= m_pMaterial
->GetSubMtlCount();
1162 for (int i
= 0; i
< nSubMtls
; ++i
)
1164 IMaterial
* pSubMtl
= m_pMaterial
->GetSafeSubMtl(i
);
1167 ISurfaceType
* pSFType
= pSubMtl
->GetSurfaceType();
1169 // This is breakable glass.
1170 // Do not merge meshes that have procedural physics breakability in them.
1171 if (pSFType
&& pSFType
->GetBreakability() != 0)
1173 //if mesh is streamed, we must assume the material is referenced
1174 if (m_bMeshStrippedCGF
)
1178 else if (IsMatIDReferencedByObj((uint16
)i
))
1188 ISurfaceType
* pSFType
= m_pMaterial
->GetSurfaceType();
1190 // This is breakable glass.
1191 // Do not merge meshes that have procedural physics breakability in them.
1192 if (pSFType
&& pSFType
->GetBreakability() != 0)
1199 if (nTotalVertexCount
> MAX_VERTICES_MERGABLE
|| nSubMeshes
<= 1 || nTotalRenderChunksCount
<= 1)
1203 if ((nTotalTriCount
/ nTotalRenderChunksCount
) > GetCVars()->e_StatObjMergeMaxTrisPerDrawCall
)
1205 return false; // tris to draw calls ratio is already not so bad
1210 //////////////////////////////////////////////////////////////////////////
1211 void CStatObj::UnMergeSubObjectsRenderMeshes()
1213 _smart_ptr
<IRenderMesh
> pNullMesh
= nullptr;
1217 m_pMergedRenderMesh
= 0;
1218 SetRenderMesh(pNullMesh
);
1227 //------------------------------------------------------------------------------
1228 // This function is recovered from previous FindSubObject function which was then
1229 // changed and creating many CGA model issues (some joints never move).
1230 CStatObj::SSubObject
* CStatObj::FindSubObject_CGA(const char* sNodeName
)
1232 uint32 numSubObjects
= m_subObjects
.size();
1233 for (uint32 i
= 0; i
< numSubObjects
; i
++)
1235 if (stricmp(m_subObjects
[i
].name
.c_str(), sNodeName
) == 0)
1237 return &m_subObjects
[i
];
1243 //////////////////////////////////////////////////////////////////////////
1244 CStatObj::SSubObject
* CStatObj::FindSubObject(const char* sNodeName
)
1246 uint32 numSubObjects
= m_subObjects
.size();
1247 int len
= 1; // some objects has ' ' in the beginning
1248 for (; sNodeName
[len
] > ' ' && sNodeName
[len
] != ',' && sNodeName
[len
] != ';'; len
++)
1250 for (uint32 i
= 0; i
< numSubObjects
; i
++)
1252 if (strnicmp(m_subObjects
[i
].name
.c_str(), sNodeName
, len
) == 0 && m_subObjects
[i
].name
[len
] == 0)
1254 return &m_subObjects
[i
];
1260 //////////////////////////////////////////////////////////////////////////
1261 CStatObj::SSubObject
* CStatObj::FindSubObject_StrStr(const char* sNodeName
)
1263 uint32 numSubObjects
= m_subObjects
.size();
1264 for (uint32 i
= 0; i
< numSubObjects
; i
++)
1266 if (stristr(m_subObjects
[i
].name
.c_str(), sNodeName
))
1268 return &m_subObjects
[i
];
1274 //////////////////////////////////////////////////////////////////////////
1275 inline void InitializeSubObject(IStatObj::SSubObject
& so
)
1277 so
.localTM
.SetIdentity();
1280 so
.nType
= STATIC_SUB_OBJECT_MESH
;
1284 so
.tm
.SetIdentity();
1285 so
.bIdentityMatrix
= true;
1287 so
.helperSize
= Vec3(0, 0, 0);
1289 so
.bShadowProxy
= 0;
1292 //////////////////////////////////////////////////////////////////////////
1293 IStatObj::SSubObject
& CStatObj::AddSubObject(IStatObj
* pSubObj
)
1296 SetSubObjectCount(m_subObjects
.size() + 1);
1297 InitializeSubObject(m_subObjects
[m_subObjects
.size() - 1]);
1298 m_subObjects
[m_subObjects
.size() - 1].pStatObj
= pSubObj
;
1300 return m_subObjects
[m_subObjects
.size() - 1];
1303 //////////////////////////////////////////////////////////////////////////
1304 bool CStatObj::RemoveSubObject(int nIndex
)
1306 if (nIndex
>= 0 && nIndex
< (int)m_subObjects
.size())
1308 SSubObject
* pSubObj
= &m_subObjects
[nIndex
];
1309 CStatObj
* pChildObj
= (CStatObj
*)pSubObj
->pStatObj
;
1312 if (!m_bSharesChildren
)
1313 pChildObj
->m_pParentObject
= NULL
;
1314 pChildObj
->Release();
1316 m_subObjects
.erase(m_subObjects
.begin() + nIndex
);
1323 //////////////////////////////////////////////////////////////////////////
1324 void CStatObj::SetSubObjectCount(int nCount
)
1326 // remove sub objects.
1327 while ((int)m_subObjects
.size() > nCount
)
1329 RemoveSubObject(m_subObjects
.size() - 1);
1333 InitializeSubObject(subobj
);
1334 m_subObjects
.resize(nCount
, subobj
);
1338 m_nFlags
|= STATIC_OBJECT_COMPOUND
;
1342 m_nFlags
&= ~STATIC_OBJECT_COMPOUND
;
1345 UnMergeSubObjectsRenderMeshes();
1348 //////////////////////////////////////////////////////////////////////////
1349 bool CStatObj::CopySubObject(int nToIndex
, IStatObj
* pFromObj
, int nFromIndex
)
1351 SSubObject
* pSrcSubObj
= pFromObj
->GetSubObject(nFromIndex
);
1355 if (nToIndex
>= (int)m_subObjects
.size())
1357 SetSubObjectCount(nToIndex
+ 1);
1358 if (pFromObj
== this)
1359 pSrcSubObj
= pFromObj
->GetSubObject(nFromIndex
);
1362 m_subObjects
[nToIndex
] = *pSrcSubObj
;
1363 if (pSrcSubObj
->pStatObj
)
1364 pSrcSubObj
->pStatObj
->AddRef();
1365 m_subObjects
[nToIndex
].pFoliage
= 0;
1372 //////////////////////////////////////////////////////////////////////////
1373 bool CStatObj::GetPhysicalProperties(float& mass
, float& density
)
1376 density
= m_phys_density
;
1377 if (mass
< 0 && density
< 0)
1382 //////////////////////////////////////////////////////////////////////////
1383 bool CStatObj::RayIntersection(SRayHitInfo
& hitInfo
, IMaterial
* pCustomMtl
)
1387 bool bNonDirectionalTest
= hitInfo
.inRay
.direction
.IsZero();
1389 // First check if ray intersect objects bounding box.
1390 if (!bNonDirectionalTest
&& !Intersect::Ray_AABB(hitInfo
.inRay
, m_AABB
, vOut
))
1393 if (bNonDirectionalTest
&& !Overlap::AABB_AABB(
1394 AABB(hitInfo
.inRay
.origin
- Vec3(hitInfo
.fMaxHitDistance
), hitInfo
.inRay
.origin
+ Vec3(hitInfo
.fMaxHitDistance
)),
1398 _smart_ptr
<IRenderMesh
> pRenderMesh
= m_pRenderMesh
;
1400 // Sometimes, object has no base lod mesh. So need to hit test with low level mesh.
1401 // If the distance from camera is larger then a base lod distance, then base lod mesh is not loaded yet.
1402 assert(m_nMaxUsableLod
< MAX_STATOBJ_LODS_NUM
&& (m_nMaxUsableLod
== 0 || (m_pLODs
&& m_pLODs
[m_nMaxUsableLod
])));
1403 if (!pRenderMesh
&& m_nMaxUsableLod
> 0 && m_pLODs
&& m_pLODs
[m_nMaxUsableLod
])
1404 pRenderMesh
= m_pLODs
[m_nMaxUsableLod
]->GetRenderMesh();
1406 if ((m_nFlags
& STATIC_OBJECT_COMPOUND
) && !m_bMerged
)
1409 bool bAnyHit
= false;
1410 float fMinDistance
= FLT_MAX
;
1411 for (int i
= 0, num
= m_subObjects
.size(); i
< num
; i
++)
1413 if (m_subObjects
[i
].pStatObj
&& m_subObjects
[i
].nType
== STATIC_SUB_OBJECT_MESH
&& !m_subObjects
[i
].bHidden
)
1415 if (((CStatObj
*)(m_subObjects
[i
].pStatObj
))->m_nFlags
& STATIC_OBJECT_HIDDEN
)
1418 Matrix34 invertedTM
= m_subObjects
[i
].tm
.GetInverted();
1420 SRayHitInfo hit
= hitInfo
;
1422 // Transform ray into sub-object local space.
1423 hit
.inReferencePoint
= invertedTM
.TransformPoint(hit
.inReferencePoint
);
1424 hit
.inRay
.origin
= invertedTM
.TransformPoint(hit
.inRay
.origin
);
1425 hit
.inRay
.direction
= invertedTM
.TransformVector(hit
.inRay
.direction
);
1427 #if defined(FEATURE_SVO_GI)
1428 int nFirstTriangleId
= hit
.pHitTris
? hit
.pHitTris
->Count() : 0;
1431 if (((CStatObj
*)m_subObjects
[i
].pStatObj
)->RayIntersection(hit
, pCustomMtl
))
1433 if (hit
.fDistance
< fMinDistance
)
1440 #if defined(FEATURE_SVO_GI)
1441 // transform collected triangles from sub-object space into object space
1444 for (int t
= nFirstTriangleId
; t
< hit
.pHitTris
->Count(); t
++)
1446 SRayHitTriangle
& ht
= hit
.pHitTris
->GetAt(t
);
1447 for (int c
= 0; c
< 3; c
++)
1448 ht
.v
[c
] = m_subObjects
[i
].tm
.TransformPoint(ht
.v
[c
]);
1456 // Restore input ray/reference point.
1457 hitOut
.inReferencePoint
= hitInfo
.inReferencePoint
;
1458 hitOut
.inRay
= hitInfo
.inRay
;
1468 bool bRes
= CRenderMeshUtils::RayIntersection(pRenderMesh
, hitInfo
, pCustomMtl
);
1475 bool CStatObj::LineSegIntersection(const Lineseg
& lineSeg
, Vec3
& hitPos
, int& surfaceTypeId
)
1477 bool intersects
= false;
1480 m_pRenderMesh
->LockForThreadAccess();
1481 int numIndices
= m_pRenderMesh
->GetIndicesCount();
1482 int numVertices
= m_pRenderMesh
->GetVerticesCount();
1483 if (numIndices
&& numVertices
)
1486 uint8
* pPositions
= (uint8
*)m_pRenderMesh
->GetPosPtr(posStride
, FSL_READ
);
1487 vtx_idx
* pIndices
= m_pRenderMesh
->GetIndexPtr(FSL_READ
);
1489 TRenderChunkArray
& Chunks
= m_pRenderMesh
->GetChunks();
1490 int nChunkCount
= Chunks
.size();
1491 for (int nChunkId
= 0; nChunkId
< nChunkCount
; nChunkId
++)
1493 CRenderChunk
* pChunk
= &Chunks
[nChunkId
];
1494 if (!(pChunk
->m_nMatFlags
& MTL_FLAG_NODRAW
))
1496 int lastIndex
= pChunk
->nFirstIndexId
+ pChunk
->nNumIndices
;
1497 for (int i
= pChunk
->nFirstIndexId
; i
< lastIndex
; )
1499 const Vec3
& v0
= *(Vec3
*)(pPositions
+ pIndices
[i
++] * posStride
);
1500 const Vec3
& v1
= *(Vec3
*)(pPositions
+ pIndices
[i
++] * posStride
);
1501 const Vec3
& v2
= *(Vec3
*)(pPositions
+ pIndices
[i
++] * posStride
);
1503 if (Intersect::Lineseg_Triangle(lineSeg
, v0
, v2
, v1
, hitPos
) || // Front face
1504 Intersect::Lineseg_Triangle(lineSeg
, v0
, v1
, v2
, hitPos
)) // Back face
1506 IMaterial
* pMtl
= m_pMaterial
->GetSafeSubMtl(pChunk
->m_nMatID
);
1507 surfaceTypeId
= pMtl
->GetSurfaceTypeId();
1515 m_pRenderMesh
->UnlockStream(VSF_GENERAL
);
1516 m_pRenderMesh
->UnlockIndexStream();
1517 m_pRenderMesh
->UnLockForThreadAccess();
1522 void CStatObj::SetRenderMesh(_smart_ptr
<IRenderMesh
>& pRM
)
1524 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY
);
1526 if (pRM
.get() == m_pRenderMesh
.get())
1530 CryAutoCriticalSection
lock(m_streamingMeshLock
);
1531 m_pRenderMesh
= pRM
;
1533 IncrementModificationId();
1538 m_nRenderTrisCount
= 0;
1539 m_nRenderMatIds
= 0;
1541 TRenderChunkArray
& Chunks
= m_pRenderMesh
->GetChunks();
1542 for (int nChunkId
= 0; nChunkId
< Chunks
.size(); nChunkId
++)
1544 CRenderChunk
* pChunk
= &Chunks
[nChunkId
];
1545 if (pChunk
->m_nMatFlags
& MTL_FLAG_NODRAW
|| !pChunk
->pRE
)
1548 if (pChunk
->nNumIndices
> 0)
1551 m_nRenderTrisCount
+= pChunk
->nNumIndices
/ 3;
1554 m_nLoadedTrisCount
= pRM
->GetIndicesCount() / 3;
1555 m_nLoadedVertexCount
= pRM
->GetVerticesCount();
1558 // this will prepare all deformable object during loading instead when needed.
1559 // Thus is will prevent runtime stalls (300ms when shooting a taxi with 6000 vertices)
1560 // but will incrase memory since every deformable information needs to be loaded(500kb for the taxi)
1561 // So this is more a workaround, the real solution would precompute the data in the RC and load
1562 // the data only when needed into memory
1563 if (GetCVars()->e_PrepareDeformableObjectsAtLoadTime
&& m_pRenderMesh
&& m_pDelayedSkinParams
)
1565 PrepareSkinData(m_pDelayedSkinParams
->mtxSkelToMesh
, m_pDelayedSkinParams
->pPhysSkel
, m_pDelayedSkinParams
->r
);
1569 //////////////////////////////////////////////////////////////////////////
1570 int CStatObj::CountChildReferences()
1572 // Check if it must be released.
1574 int numChilds
= (int)m_subObjects
.size();
1575 for (int i
= 0; i
< numChilds
; i
++)
1577 IStatObj::SSubObject
& so
= m_subObjects
[i
];
1578 CStatObj
* pChildStatObj
= (CStatObj
*)so
.pStatObj
;
1579 if (!pChildStatObj
) // All stat objects must be at the begining of the array//
1582 // 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
1583 if (pChildStatObj
->m_pParentObject
== this)
1585 bool bIgnoreSharedStatObj
= false;
1586 for (int k
= 0; k
< i
; k
++)
1588 if (pChildStatObj
== m_subObjects
[k
].pStatObj
)
1590 // If we share pointer to this stat obj then do not count it again.
1591 bIgnoreSharedStatObj
= true;
1592 nChildRefs
-= 1; // 1 reference from current object should be ignored.
1596 if (!bIgnoreSharedStatObj
)
1598 nChildRefs
+= pChildStatObj
->m_nUsers
- 1; // 1 reference from parent should be ignored.
1602 assert(nChildRefs
>= 0);
1606 IStatObj
* CStatObj::GetLowestLod()
1608 if (int nLowestLod
= CStatObj::GetMinUsableLod())
1609 return m_pLODs
? (CStatObj
*)m_pLODs
[nLowestLod
] : (CStatObj
*)NULL
;
1613 //////////////////////////////////////////////////////////////////////////
1614 int CStatObj::FindHighestLOD(int nBias
)
1616 int nLowestLod
= CStatObj::GetMinUsableLod();
1618 // if requested lod is not ready - find nearest ready one
1619 int nLod
= CLAMP((int)m_nMaxUsableLod
+ nBias
, nLowestLod
, (int)m_nMaxUsableLod
);
1621 while (nLod
&& nLod
>= nLowestLod
&& (!m_pLODs
|| !m_pLODs
[nLod
] || !m_pLODs
[nLod
]->GetRenderMesh()))
1624 if (nLod
== 0 && !GetRenderMesh())
1630 //////////////////////////////////////////////////////////////////////////
1631 void CStatObj::GetStatisticsNonRecursive(SStatistics
& si
)
1633 CStatObj
* pStatObj
= this;
1635 for (int lod
= 0; lod
< MAX_STATOBJ_LODS_NUM
; lod
++)
1637 CStatObj
* pLod
= (CStatObj
*)pStatObj
->GetLodObject(lod
);
1640 //if (!pLod0 && pLod->GetRenderMesh())
1643 if (lod
> 0 && lod
+ 1 > si
.nLods
) // Assign last existing lod.
1646 si
.nVerticesPerLod
[lod
] += pLod
->m_nLoadedVertexCount
;
1647 si
.nIndicesPerLod
[lod
] += pLod
->m_nLoadedTrisCount
* 3;
1648 si
.nMeshSize
+= pLod
->m_nRenderMeshMemoryUsage
;
1650 IRenderMesh
* pRenderMesh
= pLod
->GetRenderMesh();
1653 si
.nMeshSizeLoaded
+= pRenderMesh
->GetMemoryUsage(0, IRenderMesh::MEM_USAGE_ONLY_STREAMS
);
1654 //if (si.pTextureSizer)
1655 //pRenderMesh->GetTextureMemoryUsage(0,si.pTextureSizer);
1656 //if (si.pTextureSizer2)
1657 //pRenderMesh->GetTextureMemoryUsage(0,si.pTextureSizer2);
1662 si
.nIndices
+= m_nLoadedTrisCount
* 3;
1663 si
.nVertices
+= m_nLoadedVertexCount
;
1665 for (int j
= 0; j
< pStatObj
->m_arrPhysGeomInfo
.GetGeomCount(); j
++)
1667 if (pStatObj
->GetPhysGeom(j
) && pStatObj
->GetPhysGeom(j
)->pGeom
)
1669 ICrySizer
* pPhysSizer
= GetISystem()->CreateSizer();
1670 pStatObj
->GetPhysGeom(j
)->pGeom
->GetMemoryStatistics(pPhysSizer
);
1671 int sz
= pPhysSizer
->GetTotalSize();
1672 si
.nPhysProxySize
+= sz
;
1673 si
.nPhysProxySizeMax
= max(si
.nPhysProxySizeMax
, sz
);
1674 si
.nPhysPrimitives
+= pStatObj
->GetPhysGeom(j
)->pGeom
->GetPrimitiveCount();
1675 pPhysSizer
->Release();
1680 //////////////////////////////////////////////////////////////////////////
1681 void CStatObj::GetStatistics(SStatistics
& si
)
1683 si
.bSplitLods
= m_bLodsAreLoadedFromSeparateFile
;
1685 bool bMultiSubObj
= (GetFlags() & STATIC_OBJECT_COMPOUND
) != 0;
1688 GetStatisticsNonRecursive(si
);
1689 si
.nSubMeshCount
= 0;
1690 si
.nNumRefs
= GetRefCount();
1691 si
.nDrawCalls
= m_nRenderMatIds
;
1695 si
.nNumRefs
= GetRefCount();
1697 std::vector
<void*> addedObjects
;
1698 for (int k
= 0; k
< GetSubObjectCount(); k
++)
1700 if (!GetSubObject(k
))
1702 CStatObj
* pSubObj
= (CStatObj
*)GetSubObject(k
)->pStatObj
;
1704 int nSubObjectType
= GetSubObject(k
)->nType
;
1705 if (nSubObjectType
!= STATIC_SUB_OBJECT_MESH
&& nSubObjectType
!= STATIC_SUB_OBJECT_HELPER_MESH
)
1708 if (stl::find(addedObjects
, pSubObj
))
1710 addedObjects
.push_back(pSubObj
);
1714 pSubObj
->GetStatisticsNonRecursive(si
);
1717 if (nSubObjectType
== STATIC_SUB_OBJECT_MESH
)
1719 si
.nDrawCalls
+= pSubObj
->m_nRenderMatIds
;
1722 if (pSubObj
->GetRefCount() > si
.nNumRefs
)
1723 si
.nNumRefs
= pSubObj
->GetRefCount();
1728 // Only do rough estimation based on the material
1729 // This is more consistent when streaming is enabled and render mesh may no exist
1732 if (si
.pTextureSizer
)
1733 m_pMaterial
->GetTextureMemoryUsage(si
.pTextureSizer
);
1734 if (si
.pTextureSizer2
)
1735 m_pMaterial
->GetTextureMemoryUsage(si
.pTextureSizer2
);