/* * 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. // Description : Level loading #include "StdAfx.h" #include "3dEngine.h" #include "ObjMan.h" #include "VisAreas.h" #include "Ocean.h" #include "IParticles.h" #include "DecalManager.h" #include "Vegetation.h" #include "Brush.h" #include "MatMan.h" #include "IndexedMesh.h" #include "SkyLightManager.h" #include "ObjectsTree.h" #include "LightEntity.h" #include "RoadRenderNode.h" #include "PhysCallbacks.h" #include "TimeOfDay.h" #include "LightEntity.h" #include "RenderMeshMerger.h" #include "FogVolumeRenderNode.h" #include "RopeRenderNode.h" #include "MergedMeshRenderNode.h" #if ENABLE_CRY_PHYSICS #include "BreezeGenerator.h" #endif #include #include #include "ClipVolumeManager.h" #include "Environment/OceanEnvironmentBus.h" #include #include #include #include #include "AzCore/Component/TickBus.h" //------------------------------------------------------------------------------ #define LEVEL_DATA_FILE "LevelData.xml" #define CUSTOM_MATERIALS_FILE "Materials.xml" #define PARTICLES_FILE "LevelParticles.xml" #define SHADER_LIST_FILE "ShadersList.txt" #define LEVEL_CONFIG_FILE "Level.cfg" #define LEVEL_EDITOR_CONFIG_FILE "Editor.cfg" //------------------------------------------------------------------------------ const uint32 MAX_ACTIVE_BREEZE_POINTS = 99; //------------------------------------------------------------------------------ inline Vec3 StringToVector(const char* str) { Vec3 vTemp(0, 0, 0); float x, y, z; if (azsscanf(str, "%f,%f,%f", &x, &y, &z) == 3) { vTemp(x, y, z); } else { vTemp(0, 0, 0); } return vTemp; } ////////////////////////////////////////////////////////////////////////// void C3DEngine::LoadEmptyLevel() { CreateOctree(0.0f); LoadDefaultAssets(); } ////////////////////////////////////////////////////////////////////////// void C3DEngine::SetLevelPath(const char* szFolderName) { // make folder path assert(strlen(szFolderName) < 1024); azstrcpy(m_szLevelFolder, AZ_ARRAY_SIZE(m_szLevelFolder), szFolderName); if (strlen(m_szLevelFolder) > 0) { if (m_szLevelFolder[strlen(m_szLevelFolder) - 1] != '/') { azstrcat(m_szLevelFolder, AZ_ARRAY_SIZE (m_szLevelFolder), "/"); } } } ////////////////////////////////////////////////////////////////////////// void C3DEngine::LoadDefaultAssets() { GetRenderer()->InitSystemResources(FRR_SYSTEM_RESOURCES); //Add a call to refresh the loading screen and call the loading tick functions to ensure that no big gaps in coverage occur. SYNCHRONOUS_LOADING_TICK(); #if !defined(SYS_ENV_AS_STRUCT) PREFAST_ASSUME(gEnv); #endif GetMatMan()->InitDefaults(); m_nBlackTexID = GetRenderer()->EF_LoadTexture("EngineAssets/Textures/black.dds", FT_DONT_STREAM)->GetTextureID(); m_nBlackCMTexID = GetRenderer()->EF_LoadTexture("EngineAssets/Textures/BlackCM.dds", FT_DONT_RELEASE | FT_DONT_STREAM)->GetTextureID(); m_pMatFogVolEllipsoid = GetMatMan()->LoadMaterial("EngineAssets/Materials/Fog/FogVolumeEllipsoid", false); m_pMatFogVolBox = GetMatMan()->LoadMaterial("EngineAssets/Materials/Fog/FogVolumeBox", false); if (!m_pRESky) { m_pRESky = (CRESky*)GetRenderer()->EF_CreateRE(eDATA_Sky); //m_pRESky->m_fAlpha = 1.f; } if (!m_pREHDRSky) { m_pREHDRSky = (CREHDRSky*)GetRenderer()->EF_CreateRE(eDATA_HDRSky); } if (!m_ptexIconLowMemoryUsage) { m_ptexIconLowMemoryUsage = gEnv->pRenderer->EF_LoadDefaultTexture("LowMemoryUsage"); } if (!m_ptexIconAverageMemoryUsage) { m_ptexIconAverageMemoryUsage = gEnv->pRenderer->EF_LoadDefaultTexture("AverageMemoryUsage"); } if (!m_ptexIconHighMemoryUsage) { m_ptexIconHighMemoryUsage = gEnv->pRenderer->EF_LoadDefaultTexture("HighMemoryUsage"); } if (!m_ptexIconEditorConnectedToConsole) { m_ptexIconEditorConnectedToConsole = gEnv->pRenderer->EF_LoadDefaultTexture("LivePreview"); } } ////////////////////////////////////////////////////////////////////////// bool C3DEngine::InitLevelForEditor(const char* szFolderName, const char* szMissionName) { #if defined(CONSOLE) CRY_ASSERT_MESSAGE(0, "InitLevelForEditor not supported on consoles yet"); return false; #else LOADING_TIME_PROFILE_SECTION; m_bEditor = true; m_bAreaActivationInUse = false; m_bLayersActivated = true; ClearDebugFPSInfo(); #if ENABLE_CRY_PHYSICS gEnv->pPhysicalWorld->DeactivateOnDemandGrid(); if (gEnv->pEntitySystem) { gEnv->pEntitySystem->RegisterPhysicCallbacks(); } #endif if (!szFolderName || !szFolderName[0]) { Warning("C3DEngine::LoadLevel: Level name is not specified"); return 0; } if (!szMissionName || !szMissionName[0]) { Warning("C3DEngine::LoadLevel: Mission name is not specified"); } char szMissionNameBody[256] = "NoMission"; if (!szMissionName) { szMissionName = szMissionNameBody; } SetLevelPath(szFolderName); // Load console vars specific to this level. if (GetPak()->IsFileExist(GetLevelFilePath(LEVEL_CONFIG_FILE))) { GetISystem()->LoadConfiguration(GetLevelFilePath(LEVEL_CONFIG_FILE)); } if (GetPak()->IsFileExist(GetLevelFilePath(LEVEL_EDITOR_CONFIG_FILE))) { GetISystem()->LoadConfiguration(GetLevelFilePath(LEVEL_EDITOR_CONFIG_FILE)); } if (!m_pObjManager) { m_pObjManager = CryAlignedNew(); } if (!m_pVisAreaManager) { m_pVisAreaManager = new CVisAreaManager(); } CRY_ASSERT(m_pClipVolumeManager->GetClipVolumeCount() == 0); ////////////////////////////////////////////////////////////////////////// CryComment("initializing merged mesh manager"); m_pMergedMeshesManager->Init(); #if ENABLE_CRY_PHYSICS m_pBreezeGenerator->Initialize(); #endif if (m_pSkyLightManager) { m_pSkyLightManager->InitSkyDomeMesh(); } // recreate particles and decals if (m_pPartManager) { m_pPartManager->Reset(false); } // recreate decals SAFE_DELETE(m_pDecalManager); m_pDecalManager = new CDecalManager(); // restore game state EnableOceanRendering(true); m_pObjManager->SetLockCGFResources(0); LoadDefaultAssets(); LoadParticleEffects(szFolderName); { string SettingsFileName = GetLevelFilePath("ScreenshotMap.Settings"); AZ::IO::HandleType metaFileHandle = gEnv->pCryPak->FOpen(SettingsFileName, "r"); if (metaFileHandle != AZ::IO::InvalidHandle) { char Data[1024 * 8]; gEnv->pCryPak->FRead(Data, sizeof(Data), metaFileHandle); azsscanf(Data, "", &GetCVars()->e_ScreenShotMapCenterX, &GetCVars()->e_ScreenShotMapCenterY, &GetCVars()->e_ScreenShotMapSizeX, &GetCVars()->e_ScreenShotMapSizeY, &GetCVars()->e_ScreenShotMapCamHeight, &GetCVars()->e_ScreenShotQuality, &GetCVars()->e_ScreenShotMapOrientation); gEnv->pCryPak->FClose(metaFileHandle); } } #if ENABLE_CRY_PHYSICS LoadPhysicsData(); #endif GetObjManager()->LoadOcclusionMesh(szFolderName); // delete m_pObjectsTree[nSID]; // m_pObjectsTree[nSID] = NULL; return (true); #endif } bool C3DEngine::LevelLoadingInProgress() { return Cry3DEngineBase::m_bLevelLoadingInProgress; } int C3DEngine::GetLegacyTerrainLevelData(AZ::IO::HandleType& fileHandle, STerrainInfo& terrainInfo , bool& bSectorPalettes, EEndian& eEndian , XmlNodeRef& surfaceTypesXmlNode) { // Load LevelData.xml File. XmlNodeRef xmlLevelData = GetSystem()->LoadXmlFromFile(GetLevelFilePath(LEVEL_DATA_FILE)); if (xmlLevelData == nullptr) { AZ_Error("LegacyTerrain", false, "C3DEngine::GetLegacyTerrainLevelData: xml level file '%s' not found (files missing?)", GetLevelFilePath(LEVEL_DATA_FILE)); // files missing ? return false; } surfaceTypesXmlNode = xmlLevelData->findChild("SurfaceTypes"); return GetLegacyTerrainDataFromCompiledOctreeFile(fileHandle, terrainInfo, bSectorPalettes, eEndian); } int C3DEngine::GetLegacyTerrainLevelData(uint8*& octreeData, STerrainInfo& terrainInfo , bool& bSectorPalettes, EEndian& eEndian) { return GetLegacyTerrainDataFromOctreeBuffer(octreeData, terrainInfo, bSectorPalettes, eEndian); } bool C3DEngine::LoadCompiledOctreeForEditor() { // Load LevelData.xml File. XmlNodeRef xmlLevelData = GetSystem()->LoadXmlFromFile(GetLevelFilePath(LEVEL_DATA_FILE)); if (xmlLevelData == 0) { Error("C3DEngine::LoadLevel: xml file not found (files missing?)"); // files missing ? return false; } std::vector* pStatObjTable = NULL; std::vector<_smart_ptr >* pMatTable = NULL; int nSID = 0; XmlNodeRef nodeRef = xmlLevelData->findChild("SurfaceTypes"); LoadCollisionClasses(xmlLevelData->findChild("CollisionClasses")); if (!LoadOctree(nodeRef, &pStatObjTable, &pMatTable, nSID)) { Error("Octree file (%s) not found or file version error, please try to re-export the level", COMPILED_OCTREE_FILE_NAME); return false; } SAFE_DELETE(pStatObjTable); SAFE_DELETE(pMatTable); return true; } bool C3DEngine::LoadVisAreas(std::vector** ppStatObjTable, std::vector<_smart_ptr >** ppMatTable) { LOADING_TIME_PROFILE_SECTION; PrintMessage("===== Loading %s =====", COMPILED_VISAREA_MAP_FILE_NAME); // open file AZ::IO::HandleType fileHandle = GetPak()->FOpen(GetLevelFilePath(COMPILED_VISAREA_MAP_FILE_NAME), "rbx"); if (fileHandle == AZ::IO::InvalidHandle) { return false; } // read header SVisAreaManChunkHeader header; if (!GetPak()->FRead(&header, 1, fileHandle, false)) { GetPak()->FClose(fileHandle); return 0; } SwapEndian(header, (header.nFlags & SERIALIZATION_FLAG_BIG_ENDIAN) ? eBigEndian : eLittleEndian); if (header.nChunkSize) { assert(!m_pVisAreaManager); m_pVisAreaManager = new CVisAreaManager(); if (!m_pVisAreaManager->Load(fileHandle, header.nChunkSize, &header, *ppStatObjTable, *ppMatTable)) { delete m_pVisAreaManager; m_pVisAreaManager = NULL; } } assert(GetPak()->FEof(fileHandle)); GetPak()->FClose(fileHandle); return m_pVisAreaManager != NULL; } ////////////////////////////////////////////////////////////////////////// void C3DEngine::UnloadLevel() { if (!m_levelLoaded) { return; } GetRenderer()->EnableLevelUnloading(true); GetISystem()->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_UNLOAD, 0, 0); // Run any events that were queued against the system tick bus before we start tearing down systems and deleting things // This should prevent any stale events from running when the next level is loaded AZ::SystemTickBus::ExecuteQueuedEvents(); GetRenderer()->EnableLevelUnloading(false); m_bInUnload = true; m_szLevelFolder[0] = 0; GetRenderer()->FlushRTCommands(true, true, true); SVOGILegacyRequestBus::Broadcast(&SVOGILegacyRequests::ReleaseData); InstanceStatObjEventBus::Broadcast(&InstanceStatObjEventBus::Events::ReleaseData); FreeRNTmpDataPool(); FreeFoliages(); if (m_pSkyLightManager) { m_pSkyLightManager->ReleaseSkyDomeMesh(); } // free vegetation and brush CGF's m_lstKilledVegetations.Reset(); ResetPostEffects(); if (m_pPartManager) { // Force clear of all deferred release operations m_pPartManager->ClearDeferredReleaseResources(); } if (gEnv->pCharacterManager) { CryComment("Deleting Characters"); gEnv->pCharacterManager->ClearResources(false); CryComment("done"); } // delete decal manager if (m_pDecalManager) { CryComment("Deleting Decals"); SAFE_DELETE(m_pDecalManager); CryComment("done"); } if (m_pOcean) { CryComment("Deleting Ocean"); SAFE_DELETE(m_pOcean); CryComment("done"); } // delete outdoor objects CryComment("Deleting Octree"); DestroyOctree(); SAFE_DELETE(m_pObjectsTree); m_pObjectsTree = nullptr; // delete indoors if (m_pVisAreaManager) { CryComment("Deleting VisAreas"); SAFE_DELETE(m_pVisAreaManager); CryComment("done"); } CRY_ASSERT(m_pClipVolumeManager->GetClipVolumeCount() == 0); m_LightVolumesMgr.Reset(); m_pTerrainWaterMat = 0; m_nWaterBottomTexId = 0; ////////////////////////////////////////////////////////////////////////// CryComment("Removing Lights ..."); DeleteAllStaticLightSources(); SAFE_DELETE(m_pSun); CryComment("done"); ////////////////////////////////////////////////////////////////////////// CleanLevelShaders(); if (m_pRESky) { m_pRESky->Release(true); } if (m_pREHDRSky) { m_pREHDRSky->Release(true); } m_pRESky = 0; m_pREHDRSky = 0; stl::free_container(m_skyMatName); stl::free_container(m_skyLowSpecMatName); m_previousSkyType = -1; if (m_nCloudShadowTexId) { ITexture* tex = GetRenderer()->EF_GetTextureByID(m_nCloudShadowTexId); if (tex) { tex->Release(); } m_nCloudShadowTexId = 0; GetRenderer()->SetCloudShadowsParams(0, Vec3(0, 0, 0), 1, false, 1); SetGlobalParameter(E3DPARAM_VOLFOG_SHADOW_ENABLE, Vec3(0, 0, 0)); } if (m_nNightMoonTexId) { ITexture* tex = GetRenderer()->EF_GetTextureByID(m_nNightMoonTexId); if (tex) { tex->Release(); } m_nNightMoonTexId = 0; } ////////////////////////////////////////////////////////////////////////// if (m_pPartManager) { CryComment("Purge particles"); // Force to clean all particles that are left, even if still referenced. m_pPartManager->ClearRenderResources(true); CryComment("done"); } ////////////////////////////////////////////////////////////////////////// if (gEnv->pCharacterManager) { // Moved here as the particles need to be torn down before the char instances CryComment("Purge Characters"); // Delete all character instances and models. gEnv->pCharacterManager->ClearResources(true); CryComment("done"); } ////////////////////////////////////////////////////////////////////////// if (m_pObjManager) { bool bDeleteAll = !m_bEditor || m_bInShutDown; CryComment("Deleting Static Objects"); m_pObjManager->UnloadObjects(bDeleteAll); m_pObjManager->GetCullThread().UnloadLevel(); CryComment("done"); } AZ_Assert(m_pObjectsTree == nullptr, "m_pObjectsTree == nullptr"); COctreeNode::StaticReset(); ////////////////////////////////////////////////////////////////////////// // Force delete all materials. ////////////////////////////////////////////////////////////////////////// if (GetMatMan() && !m_bEditor) { // Should be after deleting all meshes. // We force delete all materials. CryComment("Deleting Materials"); GetMatMan()->ShutDown(); CryComment("done"); } //Set default icons to nullptr here, texture manager will take care of the memory release m_ptexIconAverageMemoryUsage = nullptr; m_ptexIconLowMemoryUsage = nullptr; m_ptexIconHighMemoryUsage = nullptr; m_ptexIconEditorConnectedToConsole = nullptr; if (m_pOpticsManager && !gEnv->IsEditor()) { m_pOpticsManager->Reset(); } ////////////////////////////////////////////////////////////////////////// #if ENABLE_CRY_PHYSICS m_pBreezeGenerator->Shutdown(); #endif ////////////////////////////////////////////////////////////////////////// // Delete physics related things. ////////////////////////////////////////////////////////////////////////// #if ENABLE_CRY_PHYSICS if (gEnv->pEntitySystem) { gEnv->pEntitySystem->UnregisterPhysicCallbacks(); } UnloadPhysicsData(); #endif // ENABLE_CRY_PHYSICS stl::free_container(m_lstRoadRenderNodesForUpdate); stl::free_container(m_lstAlwaysVisible); if (m_decalRenderNodes.empty()) { stl::free_container(m_decalRenderNodes); } stl::free_container(m_lstPerObjectShadows); m_nCustomShadowFrustumCount = 0; Cry3DEngineBase::m_pRenderMeshMerger->Reset(); SAFE_DELETE(m_pTimeOfDay); CLightEntity::StaticReset(); CVisArea::StaticReset(); CFogVolumeRenderNode::StaticReset(); #if ENABLE_CRY_PHYSICS CRopeRenderNode::StaticReset(); #endif GetRenderer()->FlushRTCommands(true, true, true); IDeferredPhysicsEventManager* pPhysEventManager = GetDeferredPhysicsEventManager(); if (pPhysEventManager) { pPhysEventManager->ClearDeferredEvents(); } m_PhysicsAreaUpdates.Reset(); for (size_t i = 0; i < NUM_BENDING_POOLS; stl::free_container(m_bendingPool[i++])) { ; } ////////////////////////////////////////////////////////////////////////// CryComment("Shutting down merged mesh manager"); m_pMergedMeshesManager->Shutdown(); ////////////////////////////////////////////////////////////////////////// // clear data used for SRenderingPass stl::free_container(m_RenderingPassCameras[0]); stl::free_container(m_RenderingPassCameras[1]); stl::free_container(m_deferredRenderComponentStreamingPriorityUpdates); stl::free_container(m_lstCustomShadowFrustums); m_nWindSamplePositions = 0; if (m_pWindSamplePositions) { CryModuleMemalignFree(m_pWindSamplePositions); m_pWindSamplePositions = NULL; } stl::free_container(m_collisionClasses); m_levelLoaded = false; } ////////////////////////////////////////////////////////////////////////// void C3DEngine::LoadFlaresData() { string flareExportListPath = gEnv->p3DEngine->GetLevelFilePath(FLARE_EXPORT_FILE); XmlNodeRef pFlareRootNode = gEnv->pSystem->LoadXmlFromFile(flareExportListPath); if (pFlareRootNode == NULL) { return; } int nFlareExportFileVer = 0; pFlareRootNode->getAttr("Version", nFlareExportFileVer); for (int i = 0, iCount(pFlareRootNode->getChildCount()); i < iCount; ++i) { XmlNodeRef pFlareNode = pFlareRootNode->getChild(i); if (pFlareNode == NULL) { continue; } const char* flareName = NULL; if (!pFlareNode->getAttr("name", &flareName)) { continue; } int nOutIndex(-1); if (nFlareExportFileVer == 0) { gEnv->pOpticsManager->Load(flareName, nOutIndex); } else if (nFlareExportFileVer == 1) { if (pFlareNode->getChildCount() == 0) { gEnv->pOpticsManager->Load(flareName, nOutIndex); } else if (pFlareNode->getChildCount() > 0) { gEnv->pOpticsManager->Load(pFlareNode, nOutIndex); } } } } ////////////////////////////////////////////////////////////////////////// bool C3DEngine::LoadLevel(const char* szFolderName, const char* szMissionName) { LOADING_TIME_PROFILE_SECTION; CRY_ASSERT(m_levelLoaded == false); PREFAST_ASSUME(gEnv); stl::scoped_set setInLoad(m_bInLoad, true); m_bInUnload = false; m_bAreaActivationInUse = false; m_bLayersActivated = false; m_eShadowMode = ESM_NORMAL; m_vPrevMainFrameCamPos.Set(-1000000.f, -1000000.f, -1000000.f); m_vAverageCameraMoveDir = Vec3(0); m_fAverageCameraSpeed = 0; ClearDebugFPSInfo(); #if !defined(CONSOLE) m_bEditor = false; #endif #if ENABLE_CRY_PHYSICS if (gEnv->pEntitySystem) { gEnv->pEntitySystem->RegisterPhysicCallbacks(); } #endif assert(!m_bEditor); ////////////////////////////////////////////////////////////////////////// CryComment("initializing merged mesh manager"); m_pMergedMeshesManager->Init(); ////////////////////////////////////////////////////////////////////////// #if ENABLE_CRY_PHYSICS m_pBreezeGenerator->Initialize(); #endif if (!szFolderName || !szFolderName[0]) { Warning("C3DEngine::LoadLevel: Level name is not specified"); return 0; } if (!szMissionName || !szMissionName[0]) { Warning("C3DEngine::LoadLevel: Mission name is not specified"); } char szMissionNameBody[256] = "NoMission"; if (!szMissionName) { szMissionName = szMissionNameBody; } SetLevelPath(szFolderName); if (GetPak()->IsFileExist(GetLevelFilePath(LEVEL_CONFIG_FILE))) { GetISystem()->LoadConfiguration(GetLevelFilePath(LEVEL_CONFIG_FILE)); } { // check is LevelData.xml file exist char sMapFileName[_MAX_PATH]; cry_strcpy(sMapFileName, m_szLevelFolder); cry_strcat(sMapFileName, LEVEL_DATA_FILE); if (!IsValidFile(sMapFileName)) { PrintMessage("Error: Level not found: %s", sMapFileName); return 0; } } if (!m_pObjManager) { m_pObjManager = CryAlignedNew(); } CRY_ASSERT(m_pClipVolumeManager->GetClipVolumeCount() == 0); // Load and activate all shaders used by the level before activating any shaders if (!m_bEditor) { LoadUsedShadersList(); } #if AZ_LOADSCREENCOMPONENT_ENABLED // Make sure system resources are inited before displaying a load screen GetRenderer()->InitSystemResources(FRR_SYSTEM_RESOURCES); // IMPORTANT: This MUST be done AFTER the LoadConfiguration() above. EBUS_EVENT(LoadScreenBus, LevelStart); #endif // if AZ_LOADSCREENCOMPONENT_ENABLED LoadDefaultAssets(); if (m_pSkyLightManager) { m_pSkyLightManager->InitSkyDomeMesh(); // set default render parameters. // for some reason this is not done later??? m_pSkyLightManager->UpdateRenderParams(); } // Load LevelData.xml File. XmlNodeRef xmlLevelData = GetSystem()->LoadXmlFromFile(GetLevelFilePath(LEVEL_DATA_FILE)); if (xmlLevelData == 0) { Error("C3DEngine::LoadLevel: xml file not found (files missing?)"); // files missing ? return false; } // re-create decal manager SAFE_DELETE(m_pDecalManager); m_pDecalManager = new CDecalManager(); gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_MATERIALS); if (GetCVars()->e_PreloadMaterials) { // Preload materials. GetMatMan()->PreloadLevelMaterials(); } if (GetCVars()->e_PreloadDecals) { // Preload materials. GetMatMan()->PreloadDecalMaterials(); } // Preload any geometry used by merged meshes m_pMergedMeshesManager->PreloadMeshes(); gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_OBJECTS); // preload level cgfs if (GetCVars()->e_StatObjPreload && !gEnv->IsEditor()) { if (GetCVars()->e_StatObjPreload == 2) { GetSystem()->OutputLoadingTimeStats(); } m_pObjManager->PreloadLevelObjects(); if (GetCVars()->e_StatObjPreload == 2) { GetSystem()->OutputLoadingTimeStats(); } gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_CHARACTERS); if (gEnv->pCharacterManager) { PrintMessage("Starting loading level characters ..."); INDENT_LOG_DURING_SCOPE(); float fStartTime = GetCurAsyncTimeSec(); gEnv->pCharacterManager->PreloadLevelModels(); float dt = GetCurAsyncTimeSec() - fStartTime; PrintMessage("Finished loading level characters (%.1f sec)", dt); } } std::vector* pStatObjTable = NULL; std::vector<_smart_ptr >* pMatTable = NULL; int nSID = 0; // load terrain XmlNodeRef nodeRef = xmlLevelData->findChild("SurfaceTypes"); LoadCollisionClasses(xmlLevelData->findChild("CollisionClasses")); gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_STATIC_WORLD); #if defined(FEATURE_SVO_GI) if (gEnv->pConsole->GetCVar("e_GI")->GetIVal()) { // Load SVOGI settings (must be called before loading of brushes, vegetation and textures) char szFileName[256]; azsprintf(szFileName, "mission_%s.xml", szMissionName); XmlNodeRef xmlMission = GetSystem()->LoadXmlFromFile(Get3DEngine()->GetLevelFilePath(szFileName)); if (xmlMission) { LoadTISettings(xmlMission->findChild("Environment")); } } #endif if (!LoadOctree(nodeRef, &pStatObjTable, &pMatTable, nSID)) { Warning("Octree file (%s) not found or file version error, please try to re-export the level", COMPILED_OCTREE_FILE_NAME); } // load indoors if (!LoadVisAreas(&pStatObjTable, &pMatTable)) { Error("VisAreas file (%s) not found or file version error, please try to re-export the level", COMPILED_VISAREA_MAP_FILE_NAME); return false; } SAFE_DELETE(pStatObjTable); SAFE_DELETE(pMatTable); // Preload any geometry used by merged meshes if (m_pMergedMeshesManager->SyncPreparationStep() == false) { Error("some merged meshes failed to prepare properly (missing cgfs, re-export?!)"); } // re-create particles and decals if (m_pPartManager) { m_pPartManager->Reset(false); } //Update loading screen and important tick functions SYNCHRONOUS_LOADING_TICK(); LoadParticleEffects(szFolderName); PrintMessage("===== Loading mission settings from XML ====="); //Update loading screen and important tick functions SYNCHRONOUS_LOADING_TICK(); // load leveldata.xml m_pTerrainWaterMat = 0; m_nWaterBottomTexId = 0; LoadMissionDataFromXMLNode(szMissionName); //Update loading screen and important tick functions SYNCHRONOUS_LOADING_TICK(); #if ENABLE_CRY_PHYSICS if (!LegacyTerrain::LegacyTerrainDataRequestBus::HasHandlers()) { gEnv->pPhysicalWorld->SetHeightfieldData(nullptr); } #endif // init water if not initialized already (if no mission was found) if (!GetOcean()) { PrintMessage("===== Creating Ocean ====="); CreateOcean(m_pTerrainWaterMat, COcean::GetWaterLevelInfo()); } PrintMessage("===== Load level physics data ====="); #if ENABLE_CRY_PHYSICS LoadPhysicsData(); #endif LoadFlaresData(); // restore game state EnableOceanRendering(true); m_pObjManager->SetLockCGFResources(false); PrintMessage("===== loading occlusion mesh ====="); GetObjManager()->LoadOcclusionMesh(szFolderName); PrintMessage("===== Finished loading static world ====="); m_skipedLayers.clear(); if (gEnv->pMaterialEffects) { gEnv->pMaterialEffects->CompleteInit(); } return (true); } ////////////////////////////////////////////////////////////////////////// #if ENABLE_CRY_PHYSICS void C3DEngine::LoadPhysicsData() { CPhysCallbacks::Init(); } #endif // ENABLE_CRY_PHYSICS static void OnReleaseGeom(IGeometry* pGeom) { if (IStatObj* pStatObj = (IStatObj*)pGeom->GetForeignData()) { pStatObj->Release(); } } #if ENABLE_CRY_PHYSICS void C3DEngine::UnloadPhysicsData() { #if ENABLE_CRY_PHYSICS if (m_pGlobalWind != 0) { gEnv->pPhysicalWorld->DestroyPhysicalEntity(m_pGlobalWind); m_pGlobalWind = 0; } #endif if (gEnv->pPhysicalWorld) { // Pause and wait for the physics gEnv->pSystem->SetThreadState(ESubsys_Physics, false); gEnv->pPhysicalWorld->RemoveAllExplosionShapes(OnReleaseGeom); gEnv->pPhysicalWorld->GetGeomManager()->UnregisterAllCracks(OnReleaseGeom); CryComment("Physics PurgeDeletedEntities..."); gEnv->pPhysicalWorld->DeactivateOnDemandGrid(); gEnv->pPhysicalWorld->PurgeDeletedEntities(); CryComment("done"); CPhysCallbacks::Done(); if (!gEnv->IsEditor()) { CryComment("Physics Cleanup..."); gEnv->pPhysicalWorld->Cleanup(); CryComment("Physics Cleanup done"); } } ////////////////////////////////////////////////////////////////////////// } #endif // ENABLE_CRY_PHYSICS ////////////////////////////////////////////////////////////////////////// void C3DEngine::LoadCollisionClasses(XmlNodeRef node) { m_collisionClasses.clear(); if (node) { int count = node->getChildCount(); m_collisionClasses.reserve(count); for (int i = 0; i < count; i++) { SCollisionClass cc(0, 0); XmlNodeRef xmlCC = node->getChild(i); xmlCC->getAttr("type", cc.type); xmlCC->getAttr("ignore", cc.ignore); m_collisionClasses.push_back(cc); } } } void C3DEngine::FreeFoliages() { if (m_pFirstFoliage) { CryComment("Removing physicalized foliages ..."); CStatObjFoliage* pFoliage, * pFoliageNext; for (pFoliage = m_pFirstFoliage; &pFoliage->m_next != &m_pFirstFoliage; pFoliage = pFoliageNext) { pFoliageNext = pFoliage->m_next; delete pFoliage; } CryComment("done"); } m_arrEntsInFoliage.Reset(); } void C3DEngine::LoadMissionDataFromXMLNode(const char* szMissionName) { LOADING_TIME_PROFILE_SECTION; GetRenderer()->MakeMainContextActive(); // set default values m_vFogColor(1, 1, 1); m_fMaxViewDistHighSpec = 8000; m_fMaxViewDistLowSpec = 1000; m_fTerrainDetailMaterialsViewDistRatio = 1; m_vDefFogColor = m_vFogColor; // mission environment if (szMissionName && szMissionName[0]) { char szFileName[256]; sprintf_s(szFileName, "mission_%s.xml", szMissionName); XmlNodeRef xmlMission = GetSystem()->LoadXmlFromFile(Get3DEngine()->GetLevelFilePath(szFileName)); if (xmlMission) { LoadEnvironmentSettingsFromXML(xmlMission->findChild("Environment"), GetDefSID()); LoadTimeOfDaySettingsFromXML(xmlMission->findChild("TimeOfDay")); } else { Error("C3DEngine::LoadMissionDataFromXMLNode: Mission file not found: %s", szFileName); } } else { Error("C3DEngine::LoadMissionDataFromXMLNode: Mission name is not defined"); } } char* C3DEngine::GetXMLAttribText(XmlNodeRef pInputNode, const char* szLevel1, const char* szLevel2, const char* szDefaultValue) { static char szResText[128]; cry_strcpy(szResText, szDefaultValue); XmlNodeRef nodeLevel = pInputNode->findChild(szLevel1); if (nodeLevel && nodeLevel->haveAttr(szLevel2)) { cry_strcpy(szResText, nodeLevel->getAttr(szLevel2)); } return szResText; } char* C3DEngine::GetXMLAttribText(XmlNodeRef pInputNode, const char* szLevel1, const char* szLevel2, const char* szLevel3, const char* szDefaultValue) { static char szResText[128]; cry_strcpy(szResText, szDefaultValue); XmlNodeRef nodeLevel = pInputNode->findChild(szLevel1); if (nodeLevel) { nodeLevel = nodeLevel->findChild(szLevel2); if (nodeLevel) { cry_strcpy(szResText, nodeLevel->getAttr(szLevel3)); } } return szResText; } void C3DEngine::UpdateMoonDirection() { float moonLati(-gf_PI + gf_PI* m_moonRotationLatitude / 180.0f); float moonLong(0.5f * gf_PI - gf_PI* m_moonRotationLongitude / 180.0f); float sinLon(sinf(moonLong)); float cosLon(cosf(moonLong)); float sinLat(sinf(moonLati)); float cosLat(cosf(moonLati)); m_moonDirection = Vec3(sinLon * cosLat, sinLon * sinLat, cosLon); } void C3DEngine::LoadEnvironmentSettingsFromXML(XmlNodeRef pInputNode, int nSID) { PrintComment("Loading environment settings from XML ..."); // set start and end time for dawn/dusk (to fade moon/sun light in and out) float dawnTime = (float)atof(GetXMLAttribText(pInputNode, "Lighting", "DawnTime", "355")); float dawnDuration = (float)atof(GetXMLAttribText(pInputNode, "Lighting", "DawnDuration", "10")); float duskTime = (float)atof(GetXMLAttribText(pInputNode, "Lighting", "DuskTime", "365")); float duskDuration = (float)atof(GetXMLAttribText(pInputNode, "Lighting", "DuskDuration", "10")); m_dawnStart = (dawnTime - dawnDuration * 0.5f) / 60.0f; m_dawnEnd = (dawnTime + dawnDuration * 0.5f) / 60.0f; m_duskStart = 12.0f + (duskTime - duskDuration * 0.5f) / 60.0f; m_duskEnd = 12.0f + (duskTime + duskDuration * 0.5f) / 60.0f; if (m_dawnEnd > m_duskStart) { m_duskEnd += m_dawnEnd - m_duskStart; m_duskStart = m_dawnEnd; } // get moon info m_moonRotationLatitude = (float)atof(GetXMLAttribText(pInputNode, "Moon", "Latitude", "240")); m_moonRotationLongitude = (float)atof(GetXMLAttribText(pInputNode, "Moon", "Longitude", "45")); UpdateMoonDirection(); m_nightMoonSize = (float)atof(GetXMLAttribText(pInputNode, "Moon", "Size", "0.5")); { char moonTexture[256]; cry_strcpy(moonTexture, GetXMLAttribText(pInputNode, "Moon", "Texture", "")); ITexture* pTex(0); if (moonTexture[0] != '\0') { pTex = GetRenderer()->EF_LoadTexture(moonTexture, FT_DONT_STREAM); } m_nNightMoonTexId = pTex ? pTex->GetTextureID() : 0; } // max view distance m_fMaxViewDistHighSpec = (float)atol(GetXMLAttribText(pInputNode, "Fog", "ViewDistance", "8000")); m_fMaxViewDistLowSpec = (float)atol(GetXMLAttribText(pInputNode, "Fog", "ViewDistanceLowSpec", "1000")); m_fMaxViewDistScale = 1.f; m_volFogGlobalDensityMultiplierLDR = (float)max(atof(GetXMLAttribText(pInputNode, "Fog", "LDRGlobalDensMult", "1.0")), 0.0); float fTerrainDetailMaterialsViewDistRatio = (float)atof(GetXMLAttribText(pInputNode, "Terrain", "DetailLayersViewDistRatio", "1.0")); if (m_fTerrainDetailMaterialsViewDistRatio != fTerrainDetailMaterialsViewDistRatio) { LegacyTerrain::LegacyTerrainDataRequestBus::Broadcast(&LegacyTerrain::LegacyTerrainDataRequests::ResetTerrainVertBuffers); } m_fTerrainDetailMaterialsViewDistRatio = fTerrainDetailMaterialsViewDistRatio; // SkyBox const string skyMaterialName = GetXMLAttribText(pInputNode, "SkyBox", "Material", "Materials/Sky/Sky"); const string skyLowSpecMaterialName = GetXMLAttribText(pInputNode, "SkyBox", "MaterialLowSpec", "Materials/Sky/Sky"); SetSkyMaterialPath(skyMaterialName); SetSkyLowSpecMaterialPath(skyLowSpecMaterialName); LoadSkyMaterial(); m_fSkyBoxAngle = (float)atof(GetXMLAttribText(pInputNode, "SkyBox", "Angle", "0.0")); m_fSkyBoxStretching = (float)atof(GetXMLAttribText(pInputNode, "SkyBox", "Stretching", "1.0")); // set terrain water (aka the infinite ocean), sun road and bottom shaders if (OceanToggle::IsActive()) { AZStd::string szOceanMatName = OceanRequest::GetOceanMaterialName(); m_pTerrainWaterMat = GetMatMan()->LoadMaterial(szOceanMatName.c_str(), false); } else { char szTerrainWaterMatName[256]; cry_strcpy(szTerrainWaterMatName, GetXMLAttribText(pInputNode, "Ocean", "Material", "EngineAssets/Materials/Water/Ocean_default")); m_pTerrainWaterMat = szTerrainWaterMatName[0] ? GetMatMan()->LoadMaterial(szTerrainWaterMatName, false) : nullptr; } CreateOcean(m_pTerrainWaterMat, COcean::GetWaterLevelInfo()); m_oceanWindDirection = (float) atof(GetXMLAttribText(pInputNode, "OceanAnimation", "WindDirection", "1.0")); m_oceanWindSpeed = (float) atof(GetXMLAttribText(pInputNode, "OceanAnimation", "WindSpeed", "4.0")); m_oceanWavesSpeed = (float) atof(GetXMLAttribText(pInputNode, "OceanAnimation", "WavesSpeed", "1.0")); m_oceanWavesAmount = (float) atof(GetXMLAttribText(pInputNode, "OceanAnimation", "WavesAmount", "1.5")); m_oceanWavesSize = (float) atof(GetXMLAttribText(pInputNode, "OceanAnimation", "WavesSize", "0.75")); // re-scale speed based on size - the smaller the faster waves move m_oceanWavesSpeed /= m_oceanWavesSize; m_oceanCausticsDistanceAtten = (float)atof(GetXMLAttribText(pInputNode, "Ocean", "CausticsDistanceAtten", "100.0")); m_oceanCausticsTiling = (float)atof(GetXMLAttribText(pInputNode, "Ocean", "CausticsTilling", "1.0")); m_oceanCausticDepth = (float)atof(GetXMLAttribText(pInputNode, "Ocean", "CausticDepth", "8.0")); m_oceanCausticIntensity = (float)atof(GetXMLAttribText(pInputNode, "Ocean", "CausticIntensity", "1.0")); #if ENABLE_CRY_PHYSICS // get wind Vec3 vWindSpeed = StringToVector(GetXMLAttribText(pInputNode, "EnvState", "WindVector", "1,0,0")); SetWind(vWindSpeed); // Define breeze generation if (m_pBreezeGenerator) { m_pBreezeGenerator->Shutdown(); const char* pText = GetXMLAttribText(pInputNode, "EnvState", "BreezeGeneration", "false"); m_pBreezeGenerator->m_enabled = !strcmp(pText, "true") || !strcmp(pText, "1"); m_pBreezeGenerator->m_strength = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "BreezeStrength", "1.f")); m_pBreezeGenerator->m_variance = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "BreezeVariation", "1.f")); m_pBreezeGenerator->m_lifetime = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "BreezeLifeTime", "15.f")); m_pBreezeGenerator->m_count = min((uint32) max(0, atoi(GetXMLAttribText(pInputNode, "EnvState", "BreezeCount", "4"))), MAX_ACTIVE_BREEZE_POINTS); m_pBreezeGenerator->m_radius = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "BreezeRadius", "5.f")); m_pBreezeGenerator->m_spawn_radius = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "BreezeSpawnRadius", "25.f")); m_pBreezeGenerator->m_spread = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "BreezeSpread", "0.f")); m_pBreezeGenerator->m_movement_speed = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "BreezeMovementSpeed", "8.f")); m_pBreezeGenerator->m_wind_speed = vWindSpeed; m_pBreezeGenerator->m_fixed_height = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "BreezeFixedHeight", "-1.f")); m_pBreezeGenerator->Initialize(); } #endif // Per-level mergedmeshes pool size (on consoles) Cry3DEngineBase::m_mergedMeshesPoolSize = atoi(GetXMLAttribText(pInputNode, "EnvState", "ConsoleMergedMeshesPool", MMRM_DEFAULT_POOLSIZE_STR)); // update relevant time of day settings ITimeOfDay* pTimeOfDay(GetTimeOfDay()); if (pTimeOfDay) { CTimeOfDay::SEnvironmentInfo envTODInfo; { const char* pText = GetXMLAttribText(pInputNode, "EnvState", "SunLinkedToTOD", "true"); envTODInfo.bSunLinkedToTOD = !strcmp(pText, "true") || !strcmp(pText, "1"); } // get rotation of sun around z axis (needed to define an arbitrary path over zenit for day/night cycle position calculations) envTODInfo.sunRotationLatitude = (float) atof(GetXMLAttribText(pInputNode, "Lighting", "SunRotation", "240")); envTODInfo.sunRotationLongitude = (float) atof(GetXMLAttribText(pInputNode, "Lighting", "Longitude", "90")); pTimeOfDay->SetEnvironmentSettings(envTODInfo); pTimeOfDay->Update(true, true); } { const char* pText = GetXMLAttribText(pInputNode, "EnvState", "SunShadowsMinSpec", "1"); int nMinSpec = atoi(pText); if (nMinSpec > 0 && CheckMinSpec(nMinSpec)) { m_bSunShadows = true; } else { m_bSunShadows = false; } } { const char* pText = GetXMLAttribText(pInputNode, "EnvState", "SunShadowsAdditionalCascadeMinSpec", "0"); int nMinSpec = atoi(pText); if (nMinSpec > 0 && CheckMinSpec(nMinSpec)) { m_nSunAdditionalCascades = 1; } else { m_nSunAdditionalCascades = 0; } } { m_nGsmCache = m_pConsole->GetCVar("r_ShadowsCache")->GetIVal(); } { const char* pText = GetXMLAttribText(pInputNode, "Terrain", "HeightMapAO", "false"); m_bHeightMapAoEnabled = !strcmp(pText, "true") || !strcmp(pText, "1"); } { int nMinSpec = 3;//atoi(pText); m_fSunClipPlaneRange = 256.0; m_fSunClipPlaneRangeShift = 0.0f; if (nMinSpec > 0 && CheckMinSpec(nMinSpec)) { m_fSunClipPlaneRange = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "SunShadowsClipPlaneRange", "256.0")); float fSunClipPlaneRangeShift = (float)atof(GetXMLAttribText(pInputNode, "EnvState", "SunShadowsClipPlaneRangeShift", "0.0")); m_fSunClipPlaneRangeShift = clamp_tpl(fSunClipPlaneRangeShift / 100.0f, 0.0f, 1.0f); } } { const char* pText = GetXMLAttribText(pInputNode, "EnvState", "UseLayersActivation", "false"); Get3DEngine()->m_bAreaActivationInUse = !strcmp(pText, "true") || !strcmp(pText, "1"); } // load cloud shadow parameters { char cloudShadowTexture[256]; cry_strcpy(cloudShadowTexture, GetXMLAttribText(pInputNode, "CloudShadows", "CloudShadowTexture", "")); ITexture* pTex = 0; if (cloudShadowTexture[0] != '\0') { pTex = GetRenderer()->EF_LoadTexture(cloudShadowTexture, FT_DONT_STREAM); } m_nCloudShadowTexId = pTex ? pTex->GetTextureID() : 0; // Get animation parameters const Vec3 cloudShadowSpeed = StringToVector(GetXMLAttribText(pInputNode, "CloudShadows", "CloudShadowSpeed", "0,0,0")); const float cloudShadowTiling = (float)atof(GetXMLAttribText(pInputNode, "CloudShadows", "CloudShadowTiling", "1.0")); const float cloudShadowBrightness = (float)atof(GetXMLAttribText(pInputNode, "CloudShadows", "CloudShadowBrightness", "1.0")); const char* pText = GetXMLAttribText(pInputNode, "CloudShadows", "CloudShadowInvert", "false"); const bool cloudShadowInvert = !strcmp(pText, "true") || !strcmp(pText, "1"); GetRenderer()->SetCloudShadowsParams(m_nCloudShadowTexId, cloudShadowSpeed, cloudShadowTiling, cloudShadowInvert, cloudShadowBrightness); } // Particle lighting params. Remove for projects post C3, should be no particle lighting multipliers - have assets tweaked from start { m_fParticlesAmbientMultiplier = (float)atof(GetXMLAttribText(pInputNode, "ParticleLighting", "AmbientMul", "1.0")); m_fParticlesLightMultiplier = (float)atof(GetXMLAttribText(pInputNode, "ParticleLighting", "LightsMul", "1.0")); } { const char* pText = GetXMLAttribText(pInputNode, "VolFogShadows", "Enable", "false"); const bool enable = !strcmp(pText, "true") || !strcmp(pText, "1"); pText = GetXMLAttribText(pInputNode, "VolFogShadows", "EnableForClouds", "false"); const bool enableForClouds = !strcmp(pText, "true") || !strcmp(pText, "1"); SetGlobalParameter(E3DPARAM_VOLFOG_SHADOW_ENABLE, Vec3(enable ? 1.0f : 0.0f, enableForClouds ? 1.0f : 0.0f, 0.0f)); } #if defined(FEATURE_SVO_GI) if (gEnv->pConsole->GetCVar("e_GI")->GetIVal()) { LoadTISettings(pInputNode); } #endif } ////////////////////////////////////////////////////////////////////////// void C3DEngine::LoadTimeOfDaySettingsFromXML(XmlNodeRef node) { if (node) { GetTimeOfDay()->Serialize(node, true); ITimeOfDay::SAdvancedInfo info; GetTimeOfDay()->GetAdvancedInfo(info); GetTimeOfDay()->SetTime(info.fStartTime, true); } } ////////////////////////////////////////////////////////////////////////// void C3DEngine::LoadParticleEffects(const char* szFolderName) { LOADING_TIME_PROFILE_SECTION; if (m_pPartManager) { PrintMessage("===== Loading Particle Effects ====="); m_pPartManager->LoadLibrary("Level", GetLevelFilePath(PARTICLES_FILE), true); if (GetCVars()->e_ParticlesPreload) { // Force loading all effects and assets, to ensure no runtime stalls. CTimeValue t0 = GetTimer()->GetAsyncTime(); PrintMessage("Preloading Particle Effects..."); m_pPartManager->LoadLibrary("*", NULL, true); CTimeValue t1 = GetTimer()->GetAsyncTime(); float dt = (t1 - t0).GetSeconds(); PrintMessage("Particle Effects Loaded in %.2f seconds", dt); } else { // Load just specified libraries. m_pPartManager->LoadLibrary("@PreloadLibs", szFolderName, true); } } } //! create static object containing empty IndexedMesh IStatObj* C3DEngine::CreateStatObj() { CStatObj* pStatObj = new CStatObj(); pStatObj->m_pIndexedMesh = new CIndexedMesh(); return pStatObj; } IStatObj* C3DEngine::CreateStatObjOptionalIndexedMesh(bool createIndexedMesh) { CStatObj* pStatObj = new CStatObj(); if (createIndexedMesh) { pStatObj->m_pIndexedMesh = new CIndexedMesh(); } return pStatObj; } bool C3DEngine::RestoreTerrainFromDisk(int nSID) { ResetParticlesAndDecals(); // update roads if (m_pObjectsTree != nullptr && GetCVars()->e_TerrainDeformations) { PodArray lstRoads; m_pObjectsTree->GetObjectsByType(lstRoads, eERType_Road, NULL); for (int i = 0; i < lstRoads.Count(); i++) { CRoadRenderNode* pRoad = (CRoadRenderNode*)lstRoads[i]; pRoad->OnTerrainChanged(); } } ReRegisterKilledVegetationInstances(); return true; } void C3DEngine::ReRegisterKilledVegetationInstances() { for (int i = 0; i < m_lstKilledVegetations.Count(); i++) { IRenderNode* pObj = m_lstKilledVegetations[i]; pObj->Physicalize(); Get3DEngine()->RegisterEntity(pObj); } m_lstKilledVegetations.Clear(); } ////////////////////////////////////////////////////////////////////////// bool C3DEngine::LoadUsedShadersList() { LOADING_TIME_PROFILE_SECTION; gEnv->pRenderer->EF_Query(EFQ_SetShaderCombinations); return true; } ////////////////////////////////////////////////////////////////////////// bool C3DEngine::PrecreateDecals() { LOADING_TIME_PROFILE_SECTION; CObjManager::DecalsToPrecreate& decals(GetObjManager()->GetDecalsToPrecreate()); // pre-create ... if (GetCVars()->e_DecalsPreCreate) { CryLog("Pre-creating %d decals...", (int)decals.size()); CObjManager::DecalsToPrecreate::iterator it(decals.begin()); CObjManager::DecalsToPrecreate::iterator itEnd(decals.end()); for (; it != itEnd; ++it) { IDecalRenderNode* pDecalRenderNode(*it); pDecalRenderNode->Precache(); } CryLog(" done.\n"); } else { CryLog("Skipped pre-creation of decals.\n"); } // ... and discard list (even if pre-creation was skipped!) decals.resize(0); return true; } ////////////////////////////////////////////////////////////////////////// // Called by game when everything needed for level is loaded. ////////////////////////////////////////////////////////////////////////// void C3DEngine::PostLoadLevel() { LOADING_TIME_PROFILE_SECTION; CRY_ASSERT(m_levelLoaded == false); ////////////////////////////////////////////////////////////////////////// // Submit water material to physics if the ocean exists ////////////////////////////////////////////////////////////////////////// #if ENABLE_CRY_PHYSICS if (!OceanToggle::IsActive() || OceanRequest::OceanIsEnabled()) { IMaterialManager* pMatMan = GetMaterialManager(); IPhysicalWorld* pPhysicalWorld = gEnv->pPhysicalWorld; IPhysicalEntity* pGlobalArea = pPhysicalWorld->AddGlobalArea(); pe_params_buoyancy pb; pb.waterPlane.n.Set(0, 0, 1); pb.waterPlane.origin.Set(0, 0, OceanToggle::IsActive() ? OceanRequest::GetOceanLevel() : GetWaterLevel()); pGlobalArea->SetParams(&pb); ISurfaceType* pSrfType = pMatMan->GetSurfaceTypeByName("mat_water"); if (pSrfType) { pPhysicalWorld->SetWaterMat(pSrfType->GetId()); } } #endif // ENABLE_CRY_PHYSICS if (GetCVars()->e_PrecacheLevel) { // pre-create decals PrecreateDecals(); } gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_TEXTURES); GetRenderer()->PostLevelLoading(); // refresh material constants pulled in from resources (such as textures) GetMatMan()->RefreshShaderResourceConstants(); if (m_nGsmCache > 0) { m_CachedShadowsBounds.Reset(); SetRecomputeCachedShadows(m_nCachedShadowsUpdateStrategy = ShadowMapFrustum::ShadowCacheData::eFullUpdate); } m_levelLoaded = true; } int C3DEngine::SaveStatObj(IStatObj* pStatObj, TSerialize ser) { if (!(pStatObj->GetFlags() & STATIC_OBJECT_GENERATED)) { bool bVal = false; ser.Value("altered", bVal); ser.Value("file", pStatObj->GetFilePath()); ser.Value("geom", pStatObj->GetGeoName()); } else { bool bVal = true; ser.Value("altered", bVal); ser.Value("CloneSource", pStatObj->GetCloneSourceObject() ? pStatObj->GetCloneSourceObject()->GetFilePath() : "0"); pStatObj->Serialize(ser); } return 1; } IStatObj* C3DEngine::LoadStatObj(TSerialize ser) { bool bVal; IStatObj* pStatObj; ser.Value("altered", bVal); if (!bVal) { string fileName, geomName; ser.Value("file", fileName); ser.Value("geom", geomName); pStatObj = LoadStatObjUnsafeManualRef(fileName, geomName); } else { string srcObjName; ser.Value("CloneSource", srcObjName); if (*(const unsigned short*)(const char*)srcObjName != '0') { pStatObj = LoadStatObjUnsafeManualRef(srcObjName)->Clone(false, false, true); } else { pStatObj = CreateStatObj(); } pStatObj->Serialize(ser); } return pStatObj; }