/* * 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 "StdAfx.h" #include "Brush.h" #include "RoadRenderNode.h" #include "DecalRenderNode.h" #include "WaterVolumeRenderNode.h" #include "DistanceCloudRenderNode.h" #include "MergedMeshRenderNode.h" #include "MergedMeshGeometry.h" #include "VisAreas.h" #include "Brush.h" #include #include #pragma pack(push,4) // common node data struct SRenderNodeChunk { AABB m_WSBBox = AABB(); uint16 m_nLayerId = 0; int8 m_cShadowLodBias = 0; uint8 m_ucDummy = 0; uint32 m_dwRndFlags = 0; uint16 m_nObjectTypeIndex = 0; uint16 m_pad16 = 0; float m_fViewDistanceMultiplier = 0.0f; uint8 m_ucLodRatio = 0; // Can't guarantee alignment for derived structs across different compilers // http://stackoverflow.com/questions/22404423/c-pod-struct-inheritance-are-there-any-guarantees-about-the-memory-layout-of uint8 m_pad8 = 0; uint16 m_pad16B = 0; AUTO_STRUCT_INFO_LOCAL }; struct SVegetationChunkOld : public SRenderNodeChunk { Vec3 m_vPos; float m_fScale; uint8 m_ucBright; uint8 m_ucAngle; AUTO_STRUCT_INFO_LOCAL }; struct SVegetationChunk : public SRenderNodeChunk { Vec3 m_vPos = Vec3(0.0f); float m_fScale = 0.0f; uint8 m_ucBright = 0; // Note: Brightness is unused, it's a deprecated field. uint8 m_ucAngle = 0; uint8 m_ucAngleX = 0; uint8 m_ucAngleY = 0; AUTO_STRUCT_INFO_LOCAL }; struct SMergedMeshChunk : public SRenderNodeChunk { uint32 m_nGroups = 0; AABB m_Extents = AABB(); AUTO_STRUCT_INFO_LOCAL }; struct SMergedMeshGroupChunk { uint32 m_StatInstGroupID = 0; uint32 m_nSamples = 0; AUTO_STRUCT_INFO_LOCAL }; struct SBrushChunk : public SRenderNodeChunk { Matrix34 m_Matrix = Matrix34(); int16 m_collisionClassIdx = 0; uint16 m_flags = 0; int32 m_nMaterialId = 0; int32 m_nMaterialLayers = 0; AUTO_STRUCT_INFO_LOCAL }; #define ROADCHUNKFLAG_IGNORE_TERRAIN_HOLES 1 #define ROADCHUNKFLAG_PHYSICALIZE 2 struct SRoadChunk : public SRenderNodeChunk { int32 m_nVertsNum = 0; int16 m_nSortPriority = 0; int16 m_nFlags = 0; int32 m_nMaterialId = 0; float m_arrTexCoors[2] = { 0.0f, 0.0f }; float m_arrTexCoorsGlobal[2] = { 0.0f, 0.0f }; AUTO_STRUCT_INFO_LOCAL }; struct SDecalChunk : public SRenderNodeChunk { int16 m_projectionType = 0; uint8 m_deferred = 0; uint8 m_pad8 = 0; f32 m_depth = 0.0f; Vec3 m_pos = Vec3(0.0f); Vec3 m_normal = Vec3(0.0f); Matrix33 m_explicitRightUpFront = Matrix33(); f32 m_radius = 0.0f; int32 m_nMaterialId = 0; int32 m_nSortPriority = 0; AUTO_STRUCT_INFO_LOCAL }; struct SWaterVolumeChunk : public SRenderNodeChunk { // volume type and id int32 m_volumeTypeAndMiscBits = 0; uint64 m_volumeID = 0; // material int32 m_materialID = 0; // fog properties f32 m_fogDensity = 0.0f; Vec3 m_fogColor = Vec3(0.0f); Plane m_fogPlane = Plane(); f32 m_fogShadowing = 0.0f; // caustic propeties uint8 m_caustics = 0; uint8 m_pad8 = 0; uint16 m_pad16 = 0; f32 m_causticIntensity = 0.0f; f32 m_causticTiling = 0.0f; f32 m_causticHeight = 0.0f; // render geometry f32 m_uTexCoordBegin = 0.0f; f32 m_uTexCoordEnd = 0.0f; f32 m_surfUScale = 0.0f; f32 m_surfVScale = 0.0f; uint32 m_numVertices = 0; // physics properties f32 m_volumeDepth = 0.0f; f32 m_streamSpeed = 0.0f; uint32 m_numVerticesPhysAreaContour = 0; AUTO_STRUCT_INFO_LOCAL }; struct SWaterVolumeVertex { Vec3 m_xyz; AUTO_STRUCT_INFO_LOCAL }; struct SDistanceCloudChunk : public SRenderNodeChunk { Vec3 m_pos = Vec3(0.0f); f32 m_sizeX = 0.0f; f32 m_sizeY = 0.0f; f32 m_rotationZ = 0.0f; int32 m_materialID = 0; AUTO_STRUCT_INFO_LOCAL }; #pragma pack(pop) AUTO_TYPE_INFO(EERType) #include "TypeInfo_impl.h" #include "ObjectsTree_Serialize_info.h" inline void CopyCommonData(SRenderNodeChunk* pChunk, IRenderNode* pObj) { pChunk->m_WSBBox = pObj->GetBBox(); //COPY_MEMBER_SAVE(pChunk,pObj,m_fWSMaxViewDist); COPY_MEMBER_SAVE(pChunk, pObj, m_dwRndFlags); COPY_MEMBER_SAVE(pChunk, pObj, m_fViewDistanceMultiplier); COPY_MEMBER_SAVE(pChunk, pObj, m_ucLodRatio); COPY_MEMBER_SAVE(pChunk, pObj, m_cShadowLodBias); pChunk->m_nLayerId = pObj->GetLayerId(); } inline void LoadCommonData(SRenderNodeChunk* pChunk, IRenderNode* pObj, const SLayerVisibility* pLayerVisibility) { //COPY_MEMBER_LOAD(pObj,pChunk,m_fWSMaxViewDist); COPY_MEMBER_LOAD(pObj, pChunk, m_dwRndFlags); COPY_MEMBER_LOAD(pObj, pChunk, m_fViewDistanceMultiplier); COPY_MEMBER_LOAD(pObj, pChunk, m_ucLodRatio); COPY_MEMBER_LOAD(pObj, pChunk, m_cShadowLodBias); pObj->m_dwRndFlags &= ~(ERF_HIDDEN | ERF_SELECTED); if (pObj->m_dwRndFlags & ERF_CASTSHADOWMAPS) { pObj->m_dwRndFlags |= ERF_HAS_CASTSHADOWMAPS; } if (NULL != pLayerVisibility) { const uint16 newLayerId = pLayerVisibility->pLayerIdTranslation[pChunk->m_nLayerId]; pObj->SetLayerId(newLayerId); } else { pObj->SetLayerId(pChunk->m_nLayerId); } } ////////////////////////////////////////////////////////////////////////// inline static uint8 CheckLayerVisibility(const uint16 layerId, const SLayerVisibility* pLayerVisibility) { return pLayerVisibility->pLayerVisibilityMask[layerId >> 3] & (1 << (layerId & 7)); } ////////////////////////////////////////////////////////////////////////// int COctreeNode::SaveObjects(CMemoryBlock* pMemBlock, std::vector* pStatObjTable, std::vector<_smart_ptr >* pMatTable, std::vector* pStatInstGroupTable, EEndian eEndian, const SHotUpdateInfo* pExportInfo) { # if !ENGINE_ENABLE_COMPILATION CryFatalError("serialization code removed, please enable ENGINE_ENABLE_COMPILATION in Cry3DEngine/StdAfx.h"); return 0; # else uint32 nObjTypeMask = pExportInfo ? pExportInfo->nObjTypeMask : (uint32) ~0; int nBlockSize = 0; // FreeAreaBrushes(); for (int l = 0; l < eRNListType_ListsNum; l++) { for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext) { IRenderNode* pRenderNode = pObj; EERType eType = pRenderNode->GetRenderNodeType(); if (!(nObjTypeMask & (1 << eType))) { continue; } if ((pRenderNode->GetRndFlags() & ERF_COMPONENT_ENTITY) != 0) { continue; } nBlockSize += GetSingleObjectSize(pObj, pExportInfo); } } if (!pMemBlock || !nBlockSize) { return nBlockSize; } pMemBlock->Allocate(nBlockSize); byte* pPtr = (byte*)pMemBlock->GetData(); int nDatanSize = nBlockSize; for (int l = 0; l < eRNListType_ListsNum; l++) { for (IRenderNode* pRenderNode = m_arrObjects[l].m_pFirstNode; pRenderNode; pRenderNode = pRenderNode->m_pNext) { EERType eType = pRenderNode->GetRenderNodeType(); if (!(nObjTypeMask & (1 << eType))) { continue; } if ((pRenderNode->GetRndFlags() & ERF_COMPONENT_ENTITY) != 0) { continue; } SaveSingleObject(pPtr, nDatanSize, pRenderNode, pStatObjTable, pMatTable, pStatInstGroupTable, eEndian, pExportInfo); } } assert(pPtr == (byte*)pMemBlock->GetData() + nBlockSize); assert(nDatanSize == 0); return nBlockSize; # endif } ////////////////////////////////////////////////////////////////////////// int COctreeNode::LoadObjects(byte* pPtr, byte* pEndPtr, std::vector* pStatObjTable, std::vector<_smart_ptr >* pMatTable, EEndian eEndian, int nChunkVersion, const SLayerVisibility* pLayerVisibility) { while (pPtr < pEndPtr) { LoadSingleObject(pPtr, pStatObjTable, pMatTable, eEndian, nChunkVersion, pLayerVisibility, m_nSID); } return 0; } int COctreeNode::GetSingleObjectSize(IRenderNode* pObj, const SHotUpdateInfo* pExportInfo) { IRenderNode* pRenderNode = pObj; EERType eType = pRenderNode->GetRenderNodeType(); int nBlockSize = 0; if (eType == eERType_Vegetation && !(pRenderNode->GetRndFlags() & ERF_PROCEDURAL)) { nBlockSize += sizeof(eType); nBlockSize += sizeof(SVegetationChunk); } else if (eType == eERType_MergedMesh) { if (NULL == pExportInfo) { nBlockSize += sizeof(eType); nBlockSize += sizeof(SMergedMeshChunk); nBlockSize += ((CMergedMeshRenderNode*)pRenderNode)->NumGroups() * sizeof(SMergedMeshGroupChunk); } } else if (eType == eERType_Brush && !(pRenderNode->GetRndFlags() & ERF_PROCEDURAL)) { nBlockSize += sizeof(eType); nBlockSize += sizeof(SBrushChunk); } else if (eType == eERType_Decal && !(pRenderNode->GetRndFlags() & ERF_PROCEDURAL)) { nBlockSize += sizeof(eType); nBlockSize += sizeof(SDecalChunk); } else if (eType == eERType_WaterVolume) { CWaterVolumeRenderNode* pWVRN(static_cast< CWaterVolumeRenderNode* >(pRenderNode)); const SWaterVolumeSerialize* pSerParams(pWVRN->GetSerializationParams()); if (pSerParams && pWVRN->m_hasToBeSerialised) { nBlockSize += sizeof(eType); nBlockSize += sizeof(SWaterVolumeChunk); nBlockSize += (pSerParams->m_vertices.size() + pSerParams->m_physicsAreaContour.size()) * sizeof(SWaterVolumeVertex); int cntAux; pWVRN->GetAuxSerializationDataPtr(cntAux); nBlockSize += cntAux * sizeof(float); } } else if (eType == eERType_Road) { auto roadRenderNode = static_cast(pRenderNode); if (roadRenderNode->m_hasToBeSerialised) { nBlockSize += sizeof(eType); nBlockSize += sizeof(SRoadChunk); nBlockSize += roadRenderNode->m_arrVerts.GetDataSize(); } } else if (eType == eERType_DistanceCloud) { nBlockSize += sizeof(eType); nBlockSize += sizeof(SDistanceCloudChunk); } // align to 4 while (UINT_PTR(nBlockSize) & 3) { nBlockSize++; } return nBlockSize; } void COctreeNode::SaveSingleObject(byte*& pPtr, int& nDatanSize, IRenderNode* pEnt, std::vector* pStatObjTable, std::vector<_smart_ptr >* pMatTable, std::vector* pStatInstGroupTable, EEndian eEndian, const SHotUpdateInfo* pExportInfo) { EERType eType = pEnt->GetRenderNodeType(); if (eType == eERType_Brush && !(pEnt->GetRndFlags() & ERF_PROCEDURAL)) { AddToPtr(pPtr, nDatanSize, eType, eEndian); CBrush* pObj = (CBrush*)pEnt; SBrushChunk chunk; CopyCommonData(&chunk, pObj); COPY_MEMBER_SAVE(&chunk, pObj, m_nMaterialLayers); // brush data COPY_MEMBER_SAVE(&chunk, pObj, m_Matrix); chunk.m_Matrix.SetTranslation(chunk.m_Matrix.GetTranslation()); chunk.m_nMaterialId = CObjManager::GetItemId(pMatTable, pObj->GetMaterial()); COPY_MEMBER_SAVE(&chunk, pObj, m_collisionClassIdx); { // find StatObj Id int nItemId = CObjManager::GetItemId(pStatObjTable, pObj->GetEntityStatObj()); if (nItemId < 0) { assert(!"StatObj not found in BrushTable on exporting"); } chunk.m_nObjectTypeIndex = nItemId; } chunk.m_flags |= pObj->GetDrawLast() ? 1 : 0; AddToPtr(pPtr, nDatanSize, chunk, eEndian); } else if (eType == eERType_Vegetation && !(pEnt->GetRndFlags() & ERF_PROCEDURAL)) { AddToPtr(pPtr, nDatanSize, eType, eEndian); CVegetation* pObj = (CVegetation*)pEnt; SVegetationChunk chunk; CopyCommonData(&chunk, pObj); // vegetation data COPY_MEMBER_SAVE(&chunk, pObj, m_vPos); chunk.m_fScale = pObj->GetScale(); COPY_MEMBER_SAVE(&chunk, pObj, m_nObjectTypeIndex); COPY_MEMBER_SAVE(&chunk, pObj, m_ucAngle); COPY_MEMBER_SAVE(&chunk, pObj, m_ucAngleX); COPY_MEMBER_SAVE(&chunk, pObj, m_ucAngleY); { // find StatInstGroup Id StatInstGroup& group = pObj->GetStatObjGroup(); int nItemId = CObjManager::GetItemId(pStatInstGroupTable, &group); if (nItemId < 0) { assert(!"StatObj not found in StatInstGroupTable on exporting"); } chunk.m_nObjectTypeIndex = nItemId; } AddToPtr(pPtr, nDatanSize, chunk, eEndian); } else if (eType == eERType_MergedMesh) { if (NULL == pExportInfo) { SMergedMeshChunk chunk; CMergedMeshRenderNode* pObj = (CMergedMeshRenderNode*)pEnt; AddToPtr(pPtr, nDatanSize, eType, eEndian); CopyCommonData(&chunk, pObj); chunk.m_nGroups = pObj->NumGroups(); chunk.m_Extents = pObj->GetInternalBBox(); AddToPtr(pPtr, nDatanSize, chunk, eEndian); for (size_t i = 0; i < pObj->NumGroups(); ++i) { SMergedMeshGroupChunk groupChunk; int grpid = pObj->Group(i)->instGroupId; StatInstGroup& group = pObj->GetStatObjGroup(grpid); int nItemId = CObjManager::GetItemId(pStatInstGroupTable, &group); if (nItemId < 0) { assert(!"StatObj not found in StatInstGroupTable on exporting"); } groupChunk.m_StatInstGroupID = nItemId; groupChunk.m_nSamples = pObj->Group(i)->numSamples; AddToPtr(pPtr, nDatanSize, groupChunk, eEndian); } } } else if (eType == eERType_Road) { CRoadRenderNode* pObj = static_cast(pEnt); if (pObj->m_hasToBeSerialised) { AddToPtr(pPtr, nDatanSize, eType, eEndian); SRoadChunk chunk; CopyCommonData(&chunk, pObj); // road data chunk.m_nMaterialId = CObjManager::GetItemId(pMatTable, pObj->GetMaterial()); chunk.m_nSortPriority = pObj->m_sortPrio; chunk.m_nFlags = pObj->m_bIgnoreTerrainHoles ? ROADCHUNKFLAG_IGNORE_TERRAIN_HOLES : 0; chunk.m_nFlags |= pObj->m_bPhysicalize ? ROADCHUNKFLAG_PHYSICALIZE : 0; chunk.m_nVertsNum = pObj->m_arrVerts.Count(); for (int i = 0; i < 2; i++) { COPY_MEMBER_SAVE(&chunk, pObj, m_arrTexCoors[i]); } for (int i = 0; i < 2; i++) { COPY_MEMBER_SAVE(&chunk, pObj, m_arrTexCoorsGlobal[i]); } AddToPtr(pPtr, nDatanSize, chunk, eEndian); for (int i = 0; i < pObj->m_arrVerts.Count(); i++) { Vec3 vPos(pObj->m_arrVerts[i]); AddToPtr(pPtr, nDatanSize, vPos, eEndian); } } } else if (eERType_Decal == eType && !(pEnt->GetRndFlags() & ERF_PROCEDURAL)) { AddToPtr(pPtr, nDatanSize, eType, eEndian); CDecalRenderNode* pObj((CDecalRenderNode*)pEnt); SDecalChunk chunk; CopyCommonData(&chunk, pObj); // decal properties const SDecalProperties* pDecalProperties(pObj->GetDecalProperties()); assert(pDecalProperties); chunk.m_projectionType = pDecalProperties->m_projectionType; chunk.m_deferred = pDecalProperties->m_deferred; chunk.m_pos = pDecalProperties->m_pos; chunk.m_normal = pDecalProperties->m_normal; chunk.m_explicitRightUpFront = pDecalProperties->m_explicitRightUpFront; chunk.m_radius = pDecalProperties->m_radius; chunk.m_depth = pDecalProperties->m_depth; chunk.m_nMaterialId = CObjManager::GetItemId(pMatTable, pObj->GetMaterial()); chunk.m_nSortPriority = pDecalProperties->m_sortPrio; AddToPtr(pPtr, nDatanSize, chunk, eEndian); } else if (eERType_WaterVolume == eType) { CWaterVolumeRenderNode* pObj((CWaterVolumeRenderNode*)pEnt); if (pObj->m_hasToBeSerialised) { // get access to serialization parameters const SWaterVolumeSerialize* pSerData(pObj->GetSerializationParams()); if (pSerData) { //assert( pSerData ); // trying to save level outside the editor? // save type AddToPtr(pPtr, nDatanSize, eType, eEndian); // save node data SWaterVolumeChunk chunk; int cntAux; float* pAuxData = pObj->GetAuxSerializationDataPtr(cntAux); CopyCommonData(&chunk, pObj); chunk.m_volumeTypeAndMiscBits = (pSerData->m_volumeType & 0xFFFF) | ((pSerData->m_capFogAtVolumeDepth ? 1 : 0) << 16) | ((pSerData->m_fogColorAffectedBySun ? 0 : 1) << 17) | (cntAux << 24); chunk.m_volumeID = pSerData->m_volumeID; chunk.m_materialID = CObjManager::GetItemId(pMatTable, pSerData->m_pMaterial); chunk.m_fogDensity = pSerData->m_fogDensity; chunk.m_fogColor = pSerData->m_fogColor; chunk.m_fogPlane = pSerData->m_fogPlane; chunk.m_fogShadowing = pSerData->m_fogShadowing; chunk.m_caustics = pSerData->m_caustics; chunk.m_causticIntensity = pSerData->m_causticIntensity; chunk.m_causticTiling = pSerData->m_causticTiling; chunk.m_causticHeight = pSerData->m_causticHeight; chunk.m_uTexCoordBegin = pSerData->m_uTexCoordBegin; chunk.m_uTexCoordEnd = pSerData->m_uTexCoordEnd; chunk.m_surfUScale = pSerData->m_surfUScale; chunk.m_surfVScale = pSerData->m_surfVScale; chunk.m_numVertices = pSerData->m_vertices.size(); chunk.m_volumeDepth = pSerData->m_volumeDepth; chunk.m_streamSpeed = pSerData->m_streamSpeed; chunk.m_numVerticesPhysAreaContour = pSerData->m_physicsAreaContour.size(); AddToPtr(pPtr, nDatanSize, chunk, eEndian); AddToPtr(pPtr, pAuxData, cntAux, eEndian); nDatanSize -= cntAux * sizeof(pAuxData[0]); // save vertices for (size_t i(0); i < pSerData->m_vertices.size(); ++i) { SWaterVolumeVertex v; v.m_xyz = pSerData->m_vertices[i]; AddToPtr(pPtr, nDatanSize, v, eEndian); } // save physics area contour vertices for (size_t i(0); i < pSerData->m_physicsAreaContour.size(); ++i) { SWaterVolumeVertex v; v.m_xyz = pSerData->m_physicsAreaContour[i]; AddToPtr(pPtr, nDatanSize, v, eEndian); } } } } else if (eERType_DistanceCloud == eType) { AddToPtr(pPtr, nDatanSize, eType, eEndian); CDistanceCloudRenderNode* pObj((CDistanceCloudRenderNode*)pEnt); SDistanceCloudChunk chunk; CopyCommonData(&chunk, pObj); // distance cloud properties SDistanceCloudProperties properties(pObj->GetProperties()); chunk.m_pos = properties.m_pos; chunk.m_sizeX = properties.m_sizeX; chunk.m_sizeY = properties.m_sizeY; chunk.m_rotationZ = properties.m_rotationZ; chunk.m_materialID = CObjManager::GetItemId(pMatTable, pObj->GetMaterial()); AddToPtr(pPtr, nDatanSize, chunk, eEndian); } // align to 4 while (UINT_PTR(pPtr) & 3) { byte emptyByte = 222; memcpy(pPtr, &emptyByte, sizeof(emptyByte)); pPtr += sizeof(emptyByte); nDatanSize -= sizeof(emptyByte); } } void COctreeNode::LoadSingleObject(byte*& pPtr, std::vector* pStatObjTable, std::vector<_smart_ptr >* pMatTable, EEndian eEndian, int nChunkVersion, const SLayerVisibility* pLayerVisibility, int nSID) { EERType eType = *StepData(pPtr, eEndian); // For these structures, our Endian swapping is built in to the member copy. if (eType == eERType_Brush) { SBrushChunk* pChunk = StepData(pPtr, eEndian); if (!CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags)) { return; } if (Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId)) { return; } CBrush* pObj = new CBrush(); // common node data COPY_MEMBER_LOAD(pObj, pChunk, m_WSBBox); LoadCommonData(pChunk, pObj, pLayerVisibility); // brush data COPY_MEMBER_LOAD(pObj, pChunk, m_nMaterialLayers); COPY_MEMBER_LOAD(pObj, pChunk, m_Matrix); COPY_MEMBER_LOAD(pObj, pChunk, m_collisionClassIdx); pObj->SetStatObj(CObjManager::GetItemPtr(pStatObjTable, (int)pChunk->m_nObjectTypeIndex)); // set material pObj->SetMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_nMaterialId)); // to get correct indirect lighting the registration must be done before checking if this object is inside a VisArea Get3DEngine()->RegisterEntity(pObj, nSID, nSID); if (NULL != pLayerVisibility) { if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility)) { pObj->SetRndFlags(ERF_HIDDEN, true); } } else if (Get3DEngine()->IsAreaActivationInUse()) { // keep everything deactivated, game will activate it later pObj->SetRndFlags(ERF_HIDDEN, true); } if (!(Get3DEngine()->IsAreaActivationInUse() && GetCVars()->e_ObjectLayersActivationPhysics == 1) && !(pChunk->m_dwRndFlags & ERF_NO_PHYSICS)) { pObj->Physicalize(); } pObj->SetDrawLast((pChunk->m_flags & 1) != 0); } else if (eType == eERType_Vegetation && nChunkVersion == OCTREENODE_CHUNK_VERSION_OLD) { SVegetationChunkOld* pChunk = StepData(pPtr, eEndian); if (!CheckRenderFlagsMinSpec(GetObjManager()->GetListStaticTypes()[nSID][pChunk->m_nObjectTypeIndex].m_dwRndFlags)) { return; } StatInstGroup* pGroup = &GetObjManager()->GetListStaticTypes()[nSID][pChunk->m_nObjectTypeIndex]; if (!pGroup->GetStatObj() || (pGroup->GetStatObj()->GetRadius() * pChunk->m_fScale < GetCVars()->e_VegetationMinSize)) { return; // skip creation of very small objects } CVegetation* pObj = new CVegetation(); // common node data LoadCommonData(pChunk, pObj, pLayerVisibility); // vegetation data COPY_MEMBER_LOAD(pObj, pChunk, m_vPos); pObj->SetScale(pChunk->m_fScale); COPY_MEMBER_LOAD(pObj, pChunk, m_nObjectTypeIndex); COPY_MEMBER_LOAD(pObj, pChunk, m_ucAngle); pObj->SetBBox(pChunk->m_WSBBox); pObj->Physicalize(); Get3DEngine()->RegisterEntity(pObj, nSID, nSID); pObj->CheckCreateDeformable(); assert(!(pObj->GetRndFlags() & ERF_PROCEDURAL)); } else if (eType == eERType_Vegetation) { SVegetationChunk* pChunk = StepData(pPtr, eEndian); if (!CheckRenderFlagsMinSpec(GetObjManager()->GetListStaticTypes()[nSID][pChunk->m_nObjectTypeIndex].m_dwRndFlags)) { return; } StatInstGroup* pGroup = &GetObjManager()->GetListStaticTypes()[nSID][pChunk->m_nObjectTypeIndex]; if (!pGroup->GetStatObj() || (pGroup->GetStatObj()->GetRadius() * pChunk->m_fScale < GetCVars()->e_VegetationMinSize)) { return; // skip creation of very small objects } CVegetation* pObj = new CVegetation(); // common node data LoadCommonData(pChunk, pObj, pLayerVisibility); // vegetation data COPY_MEMBER_LOAD(pObj, pChunk, m_vPos); pObj->SetScale(pChunk->m_fScale); COPY_MEMBER_LOAD(pObj, pChunk, m_nObjectTypeIndex); COPY_MEMBER_LOAD(pObj, pChunk, m_ucAngle); COPY_MEMBER_LOAD(pObj, pChunk, m_ucAngleX); COPY_MEMBER_LOAD(pObj, pChunk, m_ucAngleY); pObj->SetBBox(pChunk->m_WSBBox); pObj->Physicalize(); Get3DEngine()->RegisterEntity(pObj, nSID, nSID); pObj->CheckCreateDeformable(); Vegetation::StaticVegetationNotificationBus::Broadcast(&Vegetation::StaticVegetationNotificationBus::Events::InstanceAdded, pObj, LyAABBToAZAabb(pObj->CalcBBox())); assert(!(pObj->GetRndFlags() & ERF_PROCEDURAL)); } else if (eType == eERType_MergedMesh) { SMergedMeshChunk* pChunk = StepData(pPtr, eEndian); CMergedMeshRenderNode* pObj = m_pMergedMeshesManager->GetNode((pChunk->m_Extents.max + pChunk->m_Extents.min) * 0.5f); LoadCommonData(pChunk, pObj, pLayerVisibility); pObj->Setup(pChunk->m_Extents, pChunk->m_WSBBox, NULL); bool bHasValidData = false; for (size_t i = 0; i < pChunk->m_nGroups; ++i) { SMergedMeshGroupChunk* pGroupChunk = StepData(pPtr, eEndian); if (!gEnv->IsDedicated()) { bHasValidData |= pObj->AddGroup(pGroupChunk->m_StatInstGroupID, pGroupChunk->m_nSamples); } } if (bHasValidData) { Get3DEngine()->RegisterEntity(pObj, nSID, nSID); } else { delete pObj; } } else if (eType == eERType_Road) { SRoadChunk* pChunk = StepData(pPtr, eEndian); if (!CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags) || Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId)) { for (int j = 0; j < pChunk->m_nVertsNum; j++) { StepData(pPtr, eEndian); } return; } CRoadRenderNode* pObj = new CRoadRenderNode(); // common node data COPY_MEMBER_LOAD(pObj, pChunk, m_WSBBox); LoadCommonData(pChunk, pObj, pLayerVisibility); // road data pObj->SetMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_nMaterialId)); pObj->m_sortPrio = aznumeric_caster(pChunk->m_nSortPriority); pObj->m_bIgnoreTerrainHoles = (pChunk->m_nFlags & ROADCHUNKFLAG_IGNORE_TERRAIN_HOLES) != 0; pObj->m_bPhysicalize = (pChunk->m_nFlags & ROADCHUNKFLAG_PHYSICALIZE) != 0; for (int i = 0; i < 2; i++) { COPY_MEMBER_LOAD(pObj, pChunk, m_arrTexCoors[i]); } for (int i = 0; i < 2; i++) { COPY_MEMBER_LOAD(pObj, pChunk, m_arrTexCoorsGlobal[i]); } pObj->m_arrVerts.PreAllocate(pChunk->m_nVertsNum); for (int j = 0; j < pChunk->m_nVertsNum; j++) { Vec3* pVert = StepData(pPtr, eEndian); pObj->m_arrVerts.Add(*pVert); } pObj->SetVertices(pObj->m_arrVerts.GetElements(), pObj->m_arrVerts.Count(), pObj->m_arrTexCoors[0], pObj->m_arrTexCoors[1], pObj->m_arrTexCoorsGlobal[0], pObj->m_arrTexCoorsGlobal[1]); // set object visibility if (NULL != pLayerVisibility) { CRY_ASSERT(pChunk->m_nLayerId != 0); if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility)) { pObj->SetRndFlags(ERF_HIDDEN, true); } } else if (Get3DEngine()->IsAreaActivationInUse()) { // keep everything deactivated, game will activate it later pObj->SetRndFlags(ERF_HIDDEN, true); } Get3DEngine()->RegisterEntity(pObj, nSID, nSID); } else if (eERType_Decal == eType) { SDecalChunk* pChunk(StepData(pPtr, eEndian)); if (!CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags)) { return; } if (Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId)) { return; } CDecalRenderNode* pObj(new CDecalRenderNode()); // common node data pObj->SetBBox(pChunk->m_WSBBox); LoadCommonData(pChunk, pObj, pLayerVisibility); // decal properties SDecalProperties properties; switch (pChunk->m_projectionType) { case SDecalProperties::eProjectOnTerrainAndStaticObjects: { properties.m_projectionType = SDecalProperties::eProjectOnTerrainAndStaticObjects; break; } case SDecalProperties::eProjectOnTerrain: { properties.m_projectionType = SDecalProperties::eProjectOnTerrain; break; } case SDecalProperties::ePlanar: default: { properties.m_projectionType = SDecalProperties::ePlanar; break; } } memcpy(&properties.m_pos, &pChunk->m_pos, sizeof (pChunk->m_pos)); memcpy(&properties.m_normal, &pChunk->m_normal, sizeof (pChunk->m_normal)); memcpy(&properties.m_explicitRightUpFront, &pChunk->m_explicitRightUpFront, sizeof (pChunk->m_explicitRightUpFront)); memcpy(&properties.m_radius, &pChunk->m_radius, sizeof(pChunk->m_radius)); memcpy(&properties.m_depth, &pChunk->m_depth, sizeof(pChunk->m_depth)); _smart_ptr pMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_nMaterialId)); assert(pMaterial); properties.m_pMaterialName = pMaterial ? pMaterial->GetName() : ""; properties.m_sortPrio = pChunk->m_nSortPriority; properties.m_deferred = pChunk->m_deferred; pObj->SetDecalProperties(properties); // set object visibility if (NULL != pLayerVisibility) { CRY_ASSERT(pChunk->m_nLayerId != 0); if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility)) { pObj->SetRndFlags(ERF_HIDDEN, true); } } else if (Get3DEngine()->IsAreaActivationInUse()) { // keep everything deactivated, game will activate it later pObj->SetRndFlags(ERF_HIDDEN, true); } //if( pObj->GetMaterialID() != pChunk->m_materialID ) if (pObj->GetMaterial() != pMaterial) { const char* pMatName("_can't_resolve_material_name_"); int32 matID(pChunk->m_nMaterialId); if (matID >= 0 && matID < (int)pMatTable->size()) { pMatName = pMaterial ? pMaterial->GetName() : ""; } Warning("Warning: Removed placement decal at (%4.2f, %4.2f, %4.2f) with invalid material \"%s\"!\n", pChunk->m_pos.x, pChunk->m_pos.y, pChunk->m_pos.z, pMatName); pObj->ReleaseNode(); } else { Get3DEngine()->RegisterEntity(pObj, nSID, nSID); GetObjManager()->GetDecalsToPrecreate().push_back(pObj); } } else if (eERType_WaterVolume == eType) { // read common info SWaterVolumeChunk* pChunk(StepData(pPtr, eEndian)); if (!CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags) || Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId)) { for (uint32 j(0); j < pChunk->m_numVertices; ++j) { SWaterVolumeVertex* pVertex(StepData(pPtr, eEndian)); } for (uint32 j(0); j < pChunk->m_numVerticesPhysAreaContour; ++j) { SWaterVolumeVertex* pVertex(StepData(pPtr, eEndian)); } return; } CWaterVolumeRenderNode* pObj(new CWaterVolumeRenderNode()); int auxCntSrc = pChunk->m_volumeTypeAndMiscBits >> 24, auxCntDst; float* pAuxDataDst = pObj->GetAuxSerializationDataPtr(auxCntDst); const float* pAuxDataSrc = StepData(pPtr, auxCntSrc, eEndian); memcpy(pAuxDataDst, pAuxDataDst, min(auxCntSrc, auxCntDst) * sizeof(float)); // read common node data pObj->SetBBox(pChunk->m_WSBBox); LoadCommonData(pChunk, pObj, pLayerVisibility); // read vertices std::vector vertices; vertices.reserve(pChunk->m_numVertices); for (uint32 j(0); j < pChunk->m_numVertices; ++j) { SWaterVolumeVertex* pVertex(StepData(pPtr, eEndian)); vertices.push_back(pVertex->m_xyz); } // read physics area contour vertices std::vector physicsAreaContour; physicsAreaContour.reserve(pChunk->m_numVerticesPhysAreaContour); for (uint32 j(0); j < pChunk->m_numVerticesPhysAreaContour; ++j) { SWaterVolumeVertex* pVertex(StepData(pPtr, eEndian)); physicsAreaContour.push_back(pVertex->m_xyz); } const int volumeType = pChunk->m_volumeTypeAndMiscBits & 0xFFFF; const bool capFogAtVolumeDepth = ((pChunk->m_volumeTypeAndMiscBits & 0x10000) != 0) ? true : false; const bool fogColorAffectedBySun = ((pChunk->m_volumeTypeAndMiscBits & 0x20000) == 0) ? true : false; const bool enableCaustics = (pChunk->m_caustics != 0) ? true : false; // create volume switch (volumeType) { case IWaterVolumeRenderNode::eWVT_River: { pObj->CreateRiver(pChunk->m_volumeID, &vertices[0], pChunk->m_numVertices, pChunk->m_uTexCoordBegin, pChunk->m_uTexCoordEnd, Vec2(pChunk->m_surfUScale, pChunk->m_surfVScale), pChunk->m_fogPlane, false, nSID); break; } case IWaterVolumeRenderNode::eWVT_Area: { pObj->CreateArea(pChunk->m_volumeID, &vertices[0], pChunk->m_numVertices, Vec2(pChunk->m_surfUScale, pChunk->m_surfVScale), pChunk->m_fogPlane, false, nSID); break; } case IWaterVolumeRenderNode::eWVT_Ocean: { assert(!"COctreeNode::SerializeObjects( ... ) -- Water volume of type \"Ocean\" not supported yet!"); break; } default: { assert(!"COctreeNode::SerializeObjects( ... ) -- Invalid water volume type!"); break; } } // set material _smart_ptr pMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_materialID)); // set properties pObj->SetFogDensity(pChunk->m_fogDensity); pObj->SetFogColor(pChunk->m_fogColor); pObj->SetFogColorAffectedBySun(fogColorAffectedBySun); pObj->SetFogShadowing(pChunk->m_fogShadowing); pObj->SetVolumeDepth(pChunk->m_volumeDepth); pObj->SetStreamSpeed(pChunk->m_streamSpeed); pObj->SetCapFogAtVolumeDepth(capFogAtVolumeDepth); pObj->SetCaustics(enableCaustics); pObj->SetCausticIntensity(pChunk->m_causticIntensity); pObj->SetCausticTiling(pChunk->m_causticTiling); pObj->SetCausticHeight(pChunk->m_causticHeight); // set object visibility if (NULL != pLayerVisibility) { CRY_ASSERT(pChunk->m_nLayerId != 0); if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility)) { pObj->SetRndFlags(ERF_HIDDEN, true); } } else if (Get3DEngine()->IsAreaActivationInUse()) { // keep everything deactivated, game will activate it later pObj->SetRndFlags(ERF_HIDDEN, true); } // set physics if (!physicsAreaContour.empty()) { switch (volumeType) { case IWaterVolumeRenderNode::eWVT_River: { pObj->SetRiverPhysicsArea(&physicsAreaContour[0], physicsAreaContour.size()); break; } case IWaterVolumeRenderNode::eWVT_Area: { pObj->SetAreaPhysicsArea(&physicsAreaContour[0], physicsAreaContour.size()); break; } case IWaterVolumeRenderNode::eWVT_Ocean: { assert(!"COctreeNode::SerializeObjects( ... ) -- Water volume of type \"Ocean\" not supported yet!"); break; } default: { assert(!"COctreeNode::SerializeObjects( ... ) -- Invalid water volume type!"); break; } } if (!(Get3DEngine()->IsAreaActivationInUse() && GetCVars()->e_ObjectLayersActivationPhysics) && !(pChunk->m_dwRndFlags & ERF_NO_PHYSICS)) { pObj->Physicalize(); } } // set material pObj->SetMaterial(pMaterial); Get3DEngine()->RegisterEntity(pObj, nSID, nSID); } else if (eERType_DistanceCloud == eType) { SDistanceCloudChunk* pChunk(StepData(pPtr, eEndian)); if (!CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags)) { return; } if (Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId)) { return; } CDistanceCloudRenderNode* pObj(new CDistanceCloudRenderNode()); // common node data AABB box; memcpy(&box, &pChunk->m_WSBBox, sizeof(AABB)); pObj->SetBBox(box); LoadCommonData(pChunk, pObj, pLayerVisibility); // distance cloud properties SDistanceCloudProperties properties; properties.m_pos = pChunk->m_pos; properties.m_sizeX = pChunk->m_sizeX; properties.m_sizeY = pChunk->m_sizeY; properties.m_rotationZ = pChunk->m_rotationZ; _smart_ptr pMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_materialID)); assert(pMaterial); properties.m_pMaterialName = pMaterial ? pMaterial->GetName() : ""; pObj->SetProperties(properties); // set object visibility if (NULL != pLayerVisibility) { CRY_ASSERT(pChunk->m_nLayerId != 0); if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility)) { pObj->SetRndFlags(ERF_HIDDEN, true); } } else if (Get3DEngine()->IsAreaActivationInUse()) { // keep everything deactivated, game will activate it later pObj->SetRndFlags(ERF_HIDDEN, true); } if (pObj->GetMaterial() != pMaterial) { const char* pMatName("_can't_resolve_material_name_"); int32 matID(pChunk->m_materialID); if (matID >= 0 && matID < (int32)(*pMatTable).size()) { pMatName = pMaterial ? pMaterial->GetName() : ""; } Warning("Warning: Removed distance cloud at (%4.2f, %4.2f, %4.2f) with invalid material \"%s\"!\n", pChunk->m_pos.x, pChunk->m_pos.y, pChunk->m_pos.z, pMatName); pObj->ReleaseNode(); } else { Get3DEngine()->RegisterEntity(pObj, nSID, nSID); } } else { assert(!"Unsupported object type"); } // align to 4 while (UINT_PTR(pPtr) & 3) { assert(*pPtr == 222); pPtr++; } }