You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/Cry3DEngine/ObjectsTree.h

452 lines
18 KiB
C++

/*
* 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.
#ifndef CRYINCLUDE_CRY3DENGINE_OBJECTSTREE_H
#define CRYINCLUDE_CRY3DENGINE_OBJECTSTREE_H
#pragma once
#define OCTREENODE_RENDER_FLAG_OBJECTS 1
#define OCTREENODE_RENDER_FLAG_OCCLUDERS 2
#define OCTREENODE_RENDER_FLAG_CASTERS 4
#define OCTREENODE_RENDER_FLAG_OBJECTS_ONLY_ENTITIES 8
#define OCTREENODE_CHUNK_VERSION_OLD 3
#define OCTREENODE_CHUNK_VERSION 5
#include <AzCore/Casting/numeric_cast.h>
#include <CryCommon/stl/STLAlignedAlloc.h>
class COctreeNode;
template <class T, size_t overAllocBytes>
class PodArray;
struct CLightEntity;
struct ILightSource;
///////////////////////////////////////////////////////////////////////////////
// data to be pushed to occlusion culler
_MS_ALIGN(16) struct SCheckOcclusionJobData
{
enum JobTypeT
{
QUIT,
OCTREE_NODE,
};
SCheckOcclusionJobData() {}
static SCheckOcclusionJobData CreateQuitJobData();
static SCheckOcclusionJobData CreateOctreeJobData(COctreeNode* pOctTreeNode, int nRenderMask, const SRendItemSorter& rendItemSorter, const CCamera* pCam);
JobTypeT type; // type to indicate with which data the union is filled
union
{
// data for octree nodes
struct
{
COctreeNode* pOctTreeNode;
int nRenderMask;
} octTreeData;
// data for terrain nodes
struct
{
float vAABBMin[3];
float vAABBMax[3];
float fDistance;
} terrainData;
};
// common data
SRendItemSorter rendItemSorter; // ensure order octree traversal oder even with parallel execution
const CCamera* pCam; // store camera to handle vis areas correctly
} _ALIGN(16);
///////////////////////////////////////////////////////////////////////////////
inline SCheckOcclusionJobData SCheckOcclusionJobData::CreateQuitJobData()
{
SCheckOcclusionJobData jobData;
jobData.type = QUIT;
return jobData;
}
///////////////////////////////////////////////////////////////////////////////
inline SCheckOcclusionJobData SCheckOcclusionJobData::CreateOctreeJobData(COctreeNode* pOctTreeNode, int nRenderMask, const SRendItemSorter& rendItemSorter, const CCamera* pCam)
{
SCheckOcclusionJobData jobData;
jobData.type = OCTREE_NODE;
jobData.octTreeData.pOctTreeNode = pOctTreeNode;
jobData.octTreeData.nRenderMask = nRenderMask;
jobData.rendItemSorter = rendItemSorter;
jobData.pCam = pCam;
return jobData;
}
///////////////////////////////////////////////////////////////////////////////
// data written by occlusion culler jobs, to control main thread 3dengine side rendering
_MS_ALIGN(16) struct SCheckOcclusionOutput
{
enum JobTypeT
{
ROAD_DECALS,
COMMON,
};
static SCheckOcclusionOutput CreateDecalsAndRoadsOutput(IRenderNode* pObj, const AABB& rObjBox, float fEntDistance, bool bCheckPerObjectOcclusion, const SRendItemSorter& rendItemSorter);
static SCheckOcclusionOutput CreateCommonObjectOutput(IRenderNode* pObj, const AABB& rObjBox, float fEntDistance, SSectorTextureSet* pTerrainTexInfo, const SRendItemSorter& rendItemSorter);
JobTypeT type;
union
{
//ROAD_DECALS,COMMON Data
struct
{
IRenderNode* pObj;
SSectorTextureSet* pTerrainTexInfo;
float fEntDistance;
bool bCheckPerObjectOcclusion;
} common;
};
AABB objBox;
SRendItemSorter rendItemSorter;
} _ALIGN(16);
///////////////////////////////////////////////////////////////////////////////
inline SCheckOcclusionOutput SCheckOcclusionOutput::CreateDecalsAndRoadsOutput(IRenderNode* pObj, const AABB& rObjBox, float fEntDistance, bool bCheckPerObjectOcclusion, const SRendItemSorter& rendItemSorter)
{
SCheckOcclusionOutput outputData;
outputData.type = ROAD_DECALS;
outputData.rendItemSorter = rendItemSorter;
outputData.objBox = rObjBox;
outputData.common.pObj = pObj;
outputData.common.pTerrainTexInfo = NULL;
outputData.common.fEntDistance = fEntDistance;
outputData.common.bCheckPerObjectOcclusion = bCheckPerObjectOcclusion;
return outputData;
}
///////////////////////////////////////////////////////////////////////////////
inline SCheckOcclusionOutput SCheckOcclusionOutput::CreateCommonObjectOutput(IRenderNode* pObj, const AABB& rObjBox, float fEntDistance, SSectorTextureSet* pTerrainTexInfo, const SRendItemSorter& rendItemSorter)
{
SCheckOcclusionOutput outputData;
outputData.type = COMMON;
outputData.rendItemSorter = rendItemSorter;
outputData.objBox = rObjBox;
outputData.common.pObj = pObj;
outputData.common.fEntDistance = fEntDistance;
outputData.common.pTerrainTexInfo = pTerrainTexInfo;
return outputData;
}
///////////////////////////////////////////////////////////////////////////////
enum EOcTeeNodeListType
{
eMain,
eCasters,
eSprites_deprecated,
eLights,
};
template <class T>
struct TDoublyLinkedList
{
T* m_pFirstNode, * m_pLastNode;
TDoublyLinkedList()
{
m_pFirstNode = m_pLastNode = NULL;
}
~TDoublyLinkedList()
{
assert(!m_pFirstNode && !m_pLastNode);
}
void insertAfter(T* pAfter, T* pObj)
{
pObj->m_pPrev = pAfter;
pObj->m_pNext = pAfter->m_pNext;
if (pAfter->m_pNext == NULL)
{
m_pLastNode = pObj;
}
else
{
pAfter->m_pNext->m_pPrev = pObj;
}
pAfter->m_pNext = pObj;
}
void insertBefore(T* pBefore, T* pObj)
{
pObj->m_pPrev = pBefore->m_pPrev;
pObj->m_pNext = pBefore;
if (pBefore->m_pPrev == NULL)
{
m_pFirstNode = pObj;
}
else
{
pBefore->m_pPrev->m_pNext = pObj;
}
pBefore->m_pPrev = pObj;
}
void insertBeginning(T* pObj)
{
if (m_pFirstNode == NULL)
{
m_pFirstNode = pObj;
m_pLastNode = pObj;
pObj->m_pPrev = NULL;
pObj->m_pNext = NULL;
}
else
{
insertBefore(m_pFirstNode, pObj);
}
}
void insertEnd(T* pObj)
{
if (m_pLastNode == NULL)
{
insertBeginning(pObj);
}
else
{
insertAfter(m_pLastNode, pObj);
}
}
void remove(T* pObj)
{
if (pObj->m_pPrev == NULL)
{
m_pFirstNode = pObj->m_pNext;
}
else
{
pObj->m_pPrev->m_pNext = pObj->m_pNext;
}
if (pObj->m_pNext == NULL)
{
m_pLastNode = pObj->m_pPrev;
}
else
{
pObj->m_pNext->m_pPrev = pObj->m_pPrev;
}
pObj->m_pPrev = pObj->m_pNext = NULL;
}
bool empty() const { return m_pFirstNode == NULL; }
};
struct SInstancingInfo
{
SInstancingInfo() { pStatInstGroup = 0; aabb.Reset(); fMinSpriteDistance = 10000.f; bInstancingInUse = 0; }
StatInstGroup* pStatInstGroup;
DynArray<CVegetation*> arrInstances;
stl::aligned_vector<CRenderObject::SInstanceData, 16> arrMats;
AABB aabb;
float fMinSpriteDistance;
bool bInstancingInUse;
};
struct SLayerVisibility
{
const uint8* pLayerVisibilityMask;
const uint16* pLayerIdTranslation;
};
struct SOctreeLoadObjectsData
{
COctreeNode* pNode;
ptrdiff_t offset;
size_t size;
_smart_ptr<IMemoryBlock> pMemBlock;
byte* pObjPtr;
byte* pEndObjPtr;
};
class COctreeNode
: Cry3DEngineBase
, public IOctreeNode
{
public:
struct ShadowMapFrustumParams
{
CDLight* pLight;
struct ShadowMapFrustum* pFr;
PodArray<SPlaneObject>* pShadowHull;
const SRenderingPassInfo* passInfo;
Vec3 vCamPos;
uint32 nRenderNodeFlags;
bool bSun;
};
~COctreeNode();
bool HasChildNodes();
int CountChildNodes();
void InsertObject(IRenderNode* pObj, const AABB& objBox, const float fObjRadiusSqr, const Vec3& vObjCenter);
bool DeleteObject(IRenderNode* pObj);
void Render_Object_Nodes(bool bNodeCompletelyInFrustum, int nRenderMask, const SRenderingPassInfo& passInfo, SRendItemSorter& rendItemSorter);
static void Shutdown();
static void WaitForContentJobCompletion();
void RenderContent(int nRenderMask, const SRenderingPassInfo& passInfo, const SRendItemSorter& rendItemSorter, const CCamera* pCam);
void RenderContentJobEntry(int nRenderMask, const SRenderingPassInfo& passInfo, SRendItemSorter rendItemSorter, const CCamera* pCam);
void RenderCommonObjects(TDoublyLinkedList<IRenderNode>* lstObjects, const CCamera& rCam, int nRenderMask, bool bNodeCompletelyInFrustum, SSectorTextureSet* pTerrainTexInfo, const SRenderingPassInfo& passInfo, SRendItemSorter& rendItemSorter);
void RenderDecalsAndRoads(TDoublyLinkedList<IRenderNode>* lstObjects, const CCamera& rCam, int nRenderMask, bool bNodeCompletelyInFrustum, SSectorTextureSet* pTerrainTexInfo, const SRenderingPassInfo& passInfo, SRendItemSorter& rendItemSorter);
void FillShadowCastersList(bool bNodeCompletellyInFrustum, CDLight* pLight, struct ShadowMapFrustum* pFr, PodArray<SPlaneObject>* pShadowHull, uint32 nRenderNodeFlags, const SRenderingPassInfo& passInfo);
void FillShadowMapCastersList(const ShadowMapFrustumParams& params, bool bNodeCompletellyInFrustum);
void FillDepthCubemapRenderList(const AABB& cubemapAABB, const SRenderingPassInfo& passInfo, PodArray<struct IShadowCaster*>* objectsList);
void ActivateObjectsLayer(uint16 nLayerId, bool bActivate, bool bPhys, IGeneralMemoryHeap* pHeap);
void GetLayerMemoryUsage(uint16 nLayerId, ICrySizer* pSizer, int* pNumBrushes, int* pNumDecals);
COctreeNode* FindNodeContainingBox(const AABB& objBox);
void MoveObjectsIntoList(PodArray<SRNInfo>* plstResultEntities, const AABB* pAreaBox, bool bRemoveObjects = false, bool bSkipDecals = false, bool bSkip_ERF_NO_DECALNODE_DECALS = false, bool bSkipDynamicObjects = false, EERType eRNType = eERType_TypesNum);
# if ENGINE_ENABLE_COMPILATION
int GetData(byte*& pData, int& nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, EEndian eEndian, SHotUpdateInfo* pExportInfo);
# endif
const AABB& GetObjectsBBox() { return m_objectsBox; }
AABB GetShadowCastersBox(const AABB* pBBox, const Matrix34* pShadowSpaceTransform);
void DeleteObjectsByFlag(int nRndFlag);
void UnregisterEngineObjectsInArea(const SHotUpdateInfo* pExportInfo, PodArray<IRenderNode*>& arrUnregisteredObjects, bool bOnlyEngineObjects);
uint32 GetLastVisFrameId() { return m_nLastVisFrameId; }
void GetObjectsByType(PodArray<IRenderNode*>& lstObjects, EERType objType, const AABB* pBBox, ObjectTreeQueryFilterCallback filterCallback = nullptr) override;
void GetObjectsByFlags(uint dwFlags, PodArray<IRenderNode*>& lstObjects);
void GetNearestCubeProbe(float& fMinDistance, int& nMaxPriority, CLightEntity*& pNearestLight, const AABB* pBBox);
void GetObjects(PodArray<IRenderNode*>& lstObjects, const AABB* pBBox);
bool GetShadowCastersTimeSliced(IRenderNode* pIgnoreNode, ShadowMapFrustum* pFrustum, int renderNodeExcludeFlags, int& totalRemainingNodes, int nCurLevel, const SRenderingPassInfo& passInfo);
bool IsObjectTypeInTheBox(EERType objType, const AABB& WSBBox);
bool CleanUpTree();
int GetObjectsCount(EOcTeeNodeListType eListType);
int SaveObjects(class CMemoryBlock* pMemBlock, std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, EEndian eEndian, const SHotUpdateInfo * pExportInfo);
int LoadObjects(byte* pPtr, byte* pEndPtr, std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, EEndian eEndian, int nChunkVersion, const SLayerVisibility* pLayerVisibility);
static int GetSingleObjectSize (IRenderNode* pObj, const SHotUpdateInfo* pExportInfo);
static void SaveSingleObject (byte*& pPtr, int& nDatanSize, IRenderNode* pObj, std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, EEndian eEndian, const SHotUpdateInfo* pExportInfo);
static void LoadSingleObject(byte*& pPtr, std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, EEndian eEndian, int nChunkVersion, const SLayerVisibility* pLayerVisibility, int nSID);
bool IsRightNode(const AABB& objBox, const float fObjRadius, float fObjMaxViewDist);
void GetMemoryUsage(ICrySizer* pSizer) const;
#ifdef SUPPORT_TERRAIN_AO_PRE_COMPUTATIONS
bool RayObjectsIntersection2D(Vec3 vStart, Vec3 vEnd, Vec3& vClosestHitPoint, float& fClosestHitDistance, EERType eERType);
#endif
template <class T>
int Load_T(T& f, int& nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, EEndian eEndian, AABB* pBox, const SLayerVisibility* pLayerVisibility);
int Load(AZ::IO::HandleType& fileHandle, int& nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, EEndian eEndian, AABB* pBox, const SLayerVisibility* pLayerVisibility);
int Load(uint8*& f, int& nDataSize, std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, EEndian eEndian, AABB* pBox, const SLayerVisibility* pLayerVisibility);
void GenerateStatObjAndMatTables(std::vector<IStatObj*>* pStatObjTable, std::vector<_smart_ptr<IMaterial>>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, SHotUpdateInfo* pExportInfo);
static void ReleaseEmptyNodes();
static void StaticReset();
bool IsEmpty();
bool HasObjects();
bool UpdateStreamingPriority(PodArray<COctreeNode*>& arrRecursion, float fMinDist, float fMaxDist, bool bFullUpdate, const SObjManPrecacheCamera* pPrecacheCams, size_t nPrecacheCams, const SRenderingPassInfo& passInfo);
AABB GetNodeBox() const
{
return AABB(
m_vNodeCenter - m_vNodeAxisRadius,
m_vNodeCenter + m_vNodeAxisRadius);
}
void OffsetObjects(const Vec3& offset);
void SetVisArea(CVisArea* pVisArea);
void UpdateVisAreaSID([[maybe_unused]] CVisArea* pVisArea, int nSID)
{
assert(pVisArea);
m_nSID = nSID;
}
static COctreeNode* Create(int nSID, const AABB& box, struct CVisArea* pVisArea, COctreeNode* pParent = NULL);
protected:
AABB GetChildBBox(int nChildId);
void CompileObjects();
void UpdateObjects(IRenderNode* pObj);
void CompileObjectsBrightness();
float GetNodeObjectsMaxViewDistance();
// Check if min spec specified in render node passes current server config spec.
static bool CheckRenderFlagsMinSpec(uint32 dwRndFlags);
void LinkObject(IRenderNode* pObj, EERType eERType, bool bPushFront = true);
void UnlinkObject(IRenderNode* pObj);
static int Cmp_OctreeNodeSize(const void* v1, const void* v2);
private:
COctreeNode(int nSID, const AABB& box, struct CVisArea* pVisArea, COctreeNode* pParent);
float GetNodeRadius2() const { return m_vNodeAxisRadius.Dot(m_vNodeAxisRadius); }
COctreeNode* FindChildFor(IRenderNode* pObj, const AABB& objBox, const float fObjRadius, const Vec3& vObjCenter);
bool HasAnyRenderableCandidates(const SRenderingPassInfo& passInfo) const;
uint32 m_nOccludedFrameId;
uint32 m_renderFlags;
uint32 m_errTypesBitField;
AABB m_objectsBox;
float m_fObjectsMaxViewDist;
uint32 m_nLastVisFrameId;
COctreeNode* m_arrChilds[8];
TDoublyLinkedList<IRenderNode> m_arrObjects[eRNListType_ListsNum];
PodArray<SCasterInfo> m_lstCasters;
Vec3 m_vNodeCenter;
Vec3 m_vNodeAxisRadius;
COctreeNode* m_pParent;
uint32 nFillShadowCastersSkipFrameId;
float m_fNodeDistance;
int m_nManageVegetationsFrameId;
int m_nSID;
struct CRNTmpData* m_pRNTmpData;
uint32 m_bHasLights : 1;
uint32 m_bNodeCompletelyInFrustum : 1;
uint32 m_fpSunDirX : 7;
uint32 m_fpSunDirZ : 7;
uint32 m_fpSunDirYs : 1;
uint32 m_bStaticInstancingIsDirty : 1;
struct SNodeInstancingInfo
{
SNodeInstancingInfo() { pRNode = 0; nodeMatrix.IsIdentity(); }
Matrix34 nodeMatrix;
class CVegetation * pRNode;
};
std::map<std::pair<IStatObj*, _smart_ptr<IMaterial>>, PodArray<SNodeInstancingInfo>*> * m_pStaticInstancingInfo;
static void* m_pRenderContentJobQueue;
static bool m_removeVegetationCastersOneByOne;
public:
static PodArray<COctreeNode*> m_arrEmptyNodes;
};
#endif // CRYINCLUDE_CRY3DENGINE_OBJECTSTREE_H