PageRenderTime 55ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/Code/GameSDK/GameDll/UI/Menu3dModels/MenuRender3DModelMgr.cpp

https://gitlab.com/blackbird91/CS188_AI_Game
C++ | 1301 lines | 972 code | 156 blank | 173 comment | 185 complexity | f3dbce8ddbbd624e16c0132e99a5d24e MD5 | raw file
  1. /*
  2. * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
  3. * its licensors.
  4. *
  5. * For complete copyright and license terms please see the LICENSE at the root of this
  6. * distribution (the "License"). All use of this software is governed by the License,
  7. * or, if provided, by the license below or the license accompanying this file. Do not
  8. * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
  9. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. *
  11. */
  12. // Original file Copyright Crytek GMBH or its affiliates, used under license.
  13. // Description : Rendering of 3d models in menus
  14. #include "StdAfx.h"
  15. #include "MenuRender3DModelMgr.h"
  16. #include "FrontEndModelCache.h"
  17. #include "Graphics/2DRenderUtils.h"
  18. #include "Utility/CryWatch.h"
  19. #include "Utility/StringUtils.h"
  20. #include "GameCVars.h"
  21. #include "UI/UIManager.h"
  22. // Defines
  23. #if MP_FE_CACHE_LOG_FILE_ACCESSES
  24. #define CACHE_LOG_FILE_ACCESSES_START CFrontEndModelCache::SetReasonForLoggingFileOpens("CMenuRender3DModelMgr::AddModel");
  25. #define CACHE_LOG_FILE_ACCESSES_END CFrontEndModelCache::SetReasonForLoggingFileOpens(NULL);
  26. #else
  27. #define CACHE_LOG_FILE_ACCESSES_START
  28. #define CACHE_LOG_FILE_ACCESSES_END
  29. #endif
  30. #define MENU_LIGHT_COLOR_SCALE 1.0f
  31. #define MENU_LIGHT_AMBIENT_ALPHA_SCALE 1.0f
  32. // Statics
  33. CMenuRender3DModelMgr* CMenuRender3DModelMgr::s_pInstance = NULL;
  34. CMenuRender3DModelMgr* CMenuRender3DModelMgr::s_pFirstNonFreedModelMgr = NULL;
  35. uint8 CMenuRender3DModelMgr::s_instanceCount = 0;
  36. #if DEBUG_MENU_RENDER_3D_MODEL_MGR
  37. float CMenuRender3DModelMgr::s_menuLightColorScale = MENU_LIGHT_COLOR_SCALE;
  38. #endif
  39. //#define MR3MM_TRACE(...) CryLogAlways(__VA_ARGS__)
  40. #define MR3MM_TRACE(...)
  41. //#pragma optimize("",off)
  42. //--------------------------------------------------------------------------------------------------
  43. // Name: CMenuRender3DModelMgr
  44. // Desc: Constructor
  45. //--------------------------------------------------------------------------------------------------
  46. CMenuRender3DModelMgr::CMenuRender3DModelMgr()
  47. {
  48. CRY_ASSERT_MESSAGE( IsMenu3dModelEngineSupportActive(),
  49. "No 3d model engine support - Must have a FrontEndModelCache in the front end, check FrontEndModelCache.xml");
  50. CMenuRender3DModelMgr::Release();
  51. s_instanceCount++;
  52. if(s_instanceCount == 1)
  53. {
  54. gEnv->p3DEngine->SetPostEffectParam("Post3DRenderer_Active",1.0f);
  55. }
  56. CRY_ASSERT_MESSAGE(s_pInstance==NULL,"Some how there's still an instance of CMenuRender3DModelMgr");
  57. s_pInstance = this;
  58. m_groupCount = 0;
  59. m_bReleaseMe = false;
  60. m_framesUntilDestroy = 3;
  61. m_pNextNonFreedModelMgr = NULL;
  62. m_pPrevNonFreedModelMgr = NULL;
  63. m_bUserRotation = false;
  64. gEnv->pGame->GetIGameFramework()->RegisterListener(this, "MenuRender3DModelMgr", FRAMEWORKLISTENERPRIORITY_MENU);
  65. }//-------------------------------------------------------------------------------------------------
  66. //--------------------------------------------------------------------------------------------------
  67. // Name: ~CMenuRender3DModelMgr
  68. // Desc: Destructor
  69. //--------------------------------------------------------------------------------------------------
  70. CMenuRender3DModelMgr::~CMenuRender3DModelMgr()
  71. {
  72. CRY_ASSERT_MESSAGE(s_instanceCount,"No instances left to delete in destructor");
  73. CRY_ASSERT_MESSAGE(m_bReleaseMe,"Deleting an instance which isn't marked for release");
  74. s_instanceCount--;
  75. if(s_instanceCount == 0)
  76. {
  77. CRY_ASSERT(m_pPrevNonFreedModelMgr == NULL);
  78. CRY_ASSERT(m_pNextNonFreedModelMgr == NULL);
  79. gEnv->p3DEngine->SetPostEffectParam("Post3DRenderer_Active",0.0f);
  80. }
  81. const uint renderEntityCount = m_renderEntityData.size();
  82. FE_LOG("[MenuRender3DModelMgr] Destroying instance %p (%d entities) THREAD=%u", this, renderEntityCount, CryGetCurrentThreadId());
  83. // Fix up linked list of instances
  84. if(m_pNextNonFreedModelMgr)
  85. {
  86. CRY_ASSERT(m_pNextNonFreedModelMgr->m_pPrevNonFreedModelMgr == this);
  87. m_pNextNonFreedModelMgr->m_pPrevNonFreedModelMgr = m_pPrevNonFreedModelMgr;
  88. }
  89. if (m_pPrevNonFreedModelMgr == NULL)
  90. {
  91. CRY_ASSERT(s_pFirstNonFreedModelMgr == this);
  92. s_pFirstNonFreedModelMgr = m_pNextNonFreedModelMgr;
  93. }
  94. else
  95. {
  96. CRY_ASSERT(s_pFirstNonFreedModelMgr != this);
  97. CRY_ASSERT(m_pPrevNonFreedModelMgr->m_pNextNonFreedModelMgr == this);
  98. m_pPrevNonFreedModelMgr->m_pNextNonFreedModelMgr = m_pNextNonFreedModelMgr;
  99. }
  100. // Remove entities
  101. const bool bForceRemoveNow = true;
  102. for(uint8 i=0; i<renderEntityCount; i++)
  103. {
  104. gEnv->pEntitySystem->RemoveEntity(m_renderEntityData[i].entityId, bForceRemoveNow);
  105. }
  106. // Release lights
  107. ReleaseLights();
  108. // Free containers
  109. stl::free_container(m_sceneSettings.lights);
  110. // Unregister listeners
  111. gEnv->pGame->GetIGameFramework()->UnregisterListener(this);
  112. }//-------------------------------------------------------------------------------------------------
  113. //--------------------------------------------------------------------------------------------------
  114. // Name: Release
  115. // Desc: Releases CMenuRender3DModelMgr
  116. //--------------------------------------------------------------------------------------------------
  117. void CMenuRender3DModelMgr::Release(bool bImmediateDelete)
  118. {
  119. FE_LOG("[MenuRender3DModelMgr] Release s_pInstance:%p immediateDelete:%d", s_pInstance, bImmediateDelete);
  120. if(s_pInstance)
  121. {
  122. s_pInstance->m_bUserRotation = false;
  123. CRY_ASSERT(!s_pInstance->m_bReleaseMe);
  124. s_pInstance->m_bReleaseMe = true;
  125. // Release lights
  126. s_pInstance->ReleaseLights();
  127. CRY_ASSERT(s_pInstance->m_pNextNonFreedModelMgr == NULL);
  128. CRY_ASSERT(s_pInstance->m_pPrevNonFreedModelMgr == NULL);
  129. s_pInstance->SetVisibilityOfAllEntities(false);
  130. // Linked list ptr management
  131. if(s_pFirstNonFreedModelMgr)
  132. {
  133. CRY_ASSERT(s_pFirstNonFreedModelMgr->m_pPrevNonFreedModelMgr == NULL);
  134. s_pFirstNonFreedModelMgr->m_pPrevNonFreedModelMgr = s_pInstance;
  135. }
  136. s_pInstance->m_pNextNonFreedModelMgr = s_pFirstNonFreedModelMgr;
  137. s_pFirstNonFreedModelMgr = s_pInstance;
  138. s_pInstance = NULL;
  139. }
  140. if(bImmediateDelete)
  141. {
  142. PREFAST_SUPPRESS_WARNING(6001);
  143. while(s_pFirstNonFreedModelMgr)
  144. {
  145. CRY_ASSERT(s_pFirstNonFreedModelMgr->m_pPrevNonFreedModelMgr == NULL);
  146. delete s_pFirstNonFreedModelMgr;
  147. }
  148. }
  149. }//-------------------------------------------------------------------------------------------------
  150. //--------------------------------------------------------------------------------------------------
  151. // Name: ReleaseLights
  152. // Desc: Releases lights
  153. //--------------------------------------------------------------------------------------------------
  154. void CMenuRender3DModelMgr::ReleaseLights()
  155. {
  156. const int lightCount = m_sceneSettings.lights.size();
  157. for(int i=0; i<lightCount; i++)
  158. {
  159. SLightData& lightData = m_sceneSettings.lights[i];
  160. if(lightData.pLightSource)
  161. {
  162. gEnv->p3DEngine->UnRegisterEntityDirect(lightData.pLightSource);
  163. gEnv->p3DEngine->DeleteLightSource(lightData.pLightSource);
  164. lightData.pLightSource = NULL;
  165. }
  166. }
  167. }//-------------------------------------------------------------------------------------------------
  168. //--------------------------------------------------------------------------------------------------
  169. // Name: AddModel
  170. // Desc: Adds a model to the manager
  171. //--------------------------------------------------------------------------------------------------
  172. CMenuRender3DModelMgr::TAddedModelIndex CMenuRender3DModelMgr::AddModel(const SModelParams& modelParams)
  173. {
  174. TAddedModelIndex modelIndex = kAddedModelIndex_Invalid;
  175. if(IsMenu3dModelEngineSupportActive())
  176. {
  177. CACHE_LOG_FILE_ACCESSES_START;
  178. const uint renderEntityCount = m_renderEntityData.size();
  179. CRY_ASSERT(modelParams.pFilename);
  180. CRY_ASSERT_MESSAGE((renderEntityCount < kAddedModelIndex_MaxEntities),"CMenuRender3DModelMgr has no free slots left for new models, failed to add one");
  181. if((CFrontEndModelCache::Exists()==false) && (g_pGame->GetGameRules()==NULL))
  182. {
  183. GameWarning("Can't add '%s' over menu as game currently has no model cache and no game rules", modelParams.pFilename);
  184. }
  185. else if(!CFrontEndModelCache::IsAllowed3dFrontEndAssets())
  186. {
  187. GameWarning ("Not allowed to load 3d front end assets [g_pGame->IsAllowed3dFrontEndAssets==false], aborting");
  188. }
  189. else if(renderEntityCount < kAddedModelIndex_MaxEntities && g_pGameCVars->menu3D_enabled)
  190. {
  191. // Add model
  192. const bool bIsCharacter = IsCharacterFile(modelParams.pFilename);
  193. FE_LOG("[MenuRender3DModelMgr] Adding %s model='%s' material='%s' THREAD=%u",
  194. bIsCharacter ? "character" : "prop",
  195. modelParams.pFilename,
  196. modelParams.pMaterialOverrideFilename,
  197. CryGetCurrentThreadId());
  198. Quat rotQuat;
  199. rotQuat.SetRotationXYZ(modelParams.rot);
  200. char uniqueEntityName[64];
  201. cry_sprintf(uniqueEntityName,sizeof(uniqueEntityName),"MenuObj[%s %d]",modelParams.pName,renderEntityCount);
  202. // Spawn entity
  203. SEntitySpawnParams entitySpawnParams;
  204. entitySpawnParams.pClass = gEnv->pEntitySystem->GetClassRegistry()->GetDefaultClass();
  205. entitySpawnParams.sName = uniqueEntityName;
  206. entitySpawnParams.nFlags = ENTITY_FLAG_NO_PROXIMITY | ENTITY_FLAG_CLIENT_ONLY | ENTITY_FLAG_NO_SAVE | ENTITY_FLAG_UPDATE_HIDDEN;
  207. entitySpawnParams.vPosition = ZERO;
  208. entitySpawnParams.qRotation = rotQuat;
  209. IEntity* pNewEntity = gEnv->pEntitySystem->SpawnEntity(entitySpawnParams);
  210. CRY_ASSERT_MESSAGE(pNewEntity,"Failed to create entity");
  211. if(pNewEntity)
  212. {
  213. // Attempt to add model to entity
  214. bool bHasModel = false;
  215. if(modelParams.pFilename && modelParams.pFilename[0])
  216. {
  217. bHasModel = true;
  218. const int slotIndex = 0;
  219. if(bIsCharacter)
  220. {
  221. pNewEntity->LoadCharacter(slotIndex,modelParams.pFilename,IEntity::EF_NO_STREAMING);
  222. SetCharacterFlags(pNewEntity);
  223. }
  224. else
  225. {
  226. pNewEntity->LoadGeometry(slotIndex,modelParams.pFilename,NULL,IEntity::EF_NO_STREAMING);
  227. }
  228. }
  229. ApplyMaterialOverride(pNewEntity,modelParams.pMaterialOverrideFilename);
  230. // Fill out SRenderSingleEntityData
  231. SRenderSingleEntityData renderEntityData;
  232. renderEntityData.entityId = pNewEntity->GetId();
  233. renderEntityData.flags |= (bIsCharacter) ? eRSE_IsCharacter : 0;
  234. renderEntityData.pos = ZERO;
  235. renderEntityData.rot = modelParams.rot;
  236. renderEntityData.secondRot = modelParams.secondRot;
  237. renderEntityData.continuousRot = modelParams.continuousRot;
  238. renderEntityData.userRotScale = modelParams.userRotScale;
  239. renderEntityData.topParentIndex = renderEntityCount;
  240. renderEntityData.parentIndex = kAddedModelIndex_Invalid;
  241. renderEntityData.name = modelParams.pName;
  242. renderEntityData.flags |= (bHasModel) ? eRSE_HasModel : 0;
  243. renderEntityData.groupId = m_groupCount;
  244. renderEntityData.posOffset = modelParams.posOffset;
  245. renderEntityData.posSecondOffset = modelParams.posSecondOffset;
  246. renderEntityData.scale = max(modelParams.scale,0.0f);
  247. renderEntityData.secondScale = max(modelParams.secondScale,0.0f);
  248. renderEntityData.silhouetteColor.x = clamp_tpl<float>(modelParams.silhouetteColor.x,0.0f,1.0f);
  249. renderEntityData.silhouetteColor.y = clamp_tpl<float>(modelParams.silhouetteColor.y,0.0f,1.0f);
  250. renderEntityData.silhouetteColor.z = clamp_tpl<float>(modelParams.silhouetteColor.z,0.0f,1.0f);
  251. memcpy(renderEntityData.screenRect,modelParams.screenRect,sizeof(float)*4);
  252. PreCacheMaterial(renderEntityData, pNewEntity,bIsCharacter);
  253. CalcWorldPosFromScreenRect(renderEntityData);
  254. int nIdx = m_renderEntityData.size();
  255. m_renderEntityData.push_back(renderEntityData);
  256. // Start of hidden, then show when has fully streamed in
  257. HideModel(true,nIdx);
  258. SetAsPost3dRenderObject(pNewEntity,renderEntityData.groupId,renderEntityData.screenRect);
  259. m_groupCount++;
  260. modelIndex = renderEntityCount;
  261. }
  262. m_bUserRotation |= (modelParams.userRotScale > 0.f);
  263. }
  264. CACHE_LOG_FILE_ACCESSES_END;
  265. }
  266. return modelIndex;
  267. }//-------------------------------------------------------------------------------------------------
  268. //--------------------------------------------------------------------------------------------------
  269. // Name: HideModel
  270. // Desc: Hides model
  271. //--------------------------------------------------------------------------------------------------
  272. void CMenuRender3DModelMgr::HideModel(bool bHide,int nEntityIdx,bool bUpdateModelPos)
  273. {
  274. SRenderSingleEntityData& renderEntityData = m_renderEntityData[nEntityIdx];
  275. IEntity* pEntity = gEnv->pEntitySystem->GetEntity(renderEntityData.entityId);
  276. if(pEntity)
  277. {
  278. // Set hidden status
  279. if(pEntity->IsHidden() != bHide)
  280. {
  281. pEntity->Hide(bHide);
  282. }
  283. // Reset alpha
  284. if(bHide)
  285. {
  286. IComponentRender* pRenderProxy = static_cast<IComponentRender*>(pEntity->GetComponent<IComponentRender>().get());
  287. if(pRenderProxy)
  288. {
  289. pRenderProxy->SetOpacity(0.0f);
  290. renderEntityData.alpha=0.0f;
  291. }
  292. }
  293. else if((renderEntityData.flags & eRSE_HasModel) && bUpdateModelPos)
  294. {
  295. CalcWorldPosFromScreenRect(renderEntityData);
  296. }
  297. }
  298. // Recurse through children
  299. for (int i = 0, c = m_renderEntityData.size(); i != c; ++ i)
  300. {
  301. SRenderSingleEntityData& child = m_renderEntityData[i];
  302. if (child.parentIndex == nEntityIdx)
  303. {
  304. HideModel(bHide, i, false);
  305. }
  306. }
  307. }//-------------------------------------------------------------------------------------------------
  308. //--------------------------------------------------------------------------------------------------
  309. // Name: ForceAnimationUpdate
  310. // Desc: Forces the animation to update so it is correct for the 1st frame
  311. //--------------------------------------------------------------------------------------------------
  312. void CMenuRender3DModelMgr::ForceAnimationUpdate(IEntity* pEntity)
  313. {
  314. // Force update on animation, so it will be correct on the 1st frame
  315. if(pEntity)
  316. {
  317. ICharacterInstance* pCharInst = pEntity->GetCharacter(0);
  318. if(pCharInst)
  319. {
  320. const QuatTS pose = (QuatTS)pEntity->GetWorldTM();
  321. const float fZoomAdjustedDistanceFromCamera = (GetISystem()->GetViewCamera().GetPosition()-pose.t).GetLength();
  322. SAnimationProcessParams animProcessParams;
  323. animProcessParams.locationAnimation = pose;
  324. animProcessParams.bOnRender = false;
  325. animProcessParams.zoomAdjustedDistanceFromCamera = fZoomAdjustedDistanceFromCamera;
  326. pCharInst->StartAnimationProcessing(animProcessParams);
  327. pCharInst->FinishAnimationComputations();
  328. IComponentRender* pRenderProxy = static_cast<IComponentRender*>(pEntity->GetComponent<IComponentRender>().get());
  329. if(pRenderProxy)
  330. {
  331. pRenderProxy->InvalidateLocalBounds();
  332. }
  333. }
  334. }
  335. }//-------------------------------------------------------------------------------------------------
  336. //--------------------------------------------------------------------------------------------------
  337. // Name: IsCharacterFile
  338. // Desc: Returns true if pFilename is a character file
  339. //--------------------------------------------------------------------------------------------------
  340. bool CMenuRender3DModelMgr::IsCharacterFile(const char* pFilename)
  341. {
  342. bool bIsCharacter = false;
  343. if(pFilename)
  344. {
  345. const char* pFilenameExtension = PathUtil::GetExt(pFilename);
  346. bIsCharacter = (strcmp(pFilenameExtension,"cdf")==0);
  347. }
  348. return bIsCharacter;
  349. }//-------------------------------------------------------------------------------------------------
  350. //--------------------------------------------------------------------------------------------------
  351. // Name: SwapIfMinBiggerThanMax
  352. // Desc: Swaps values if min is bigger than max
  353. //--------------------------------------------------------------------------------------------------
  354. void CMenuRender3DModelMgr::SwapIfMinBiggerThanMax(float& minValue,float& maxValue)
  355. {
  356. const float minValueCopy = minValue;
  357. const float maxValueCopy = maxValue;
  358. minValue = min(minValueCopy,maxValueCopy);
  359. maxValue = max(minValueCopy,maxValueCopy);
  360. }//-------------------------------------------------------------------------------------------------
  361. //--------------------------------------------------------------------------------------------------
  362. // Name: GetPostRenderCamera
  363. // Desc: Gets post render camera
  364. //--------------------------------------------------------------------------------------------------
  365. void CMenuRender3DModelMgr::GetPostRenderCamera(CCamera& postRenderCamera)
  366. {
  367. CRY_ASSERT_MESSAGE(m_sceneSettings.fovScale!=0.0f,"Scene Settings FOV hasn't been set yet - must SetSceneSettings before adding models");
  368. Matrix34 newCameraMatrix;
  369. newCameraMatrix.SetIdentity();
  370. postRenderCamera = gEnv->pSystem->GetViewCamera();
  371. const float newFov = DEFAULT_FOV * clamp_tpl<float>( m_sceneSettings.fovScale, 0.05f, 1.0f);
  372. const int viewSurfaceX = postRenderCamera.GetViewSurfaceX();
  373. const int viewSurfaceZ = postRenderCamera.GetViewSurfaceZ();
  374. const float pixelAspectRatio = postRenderCamera.GetPixelAspectRatio();
  375. postRenderCamera.SetMatrix(newCameraMatrix);
  376. postRenderCamera.SetFrustum(viewSurfaceX,viewSurfaceZ,newFov,DEFAULT_NEAR,DEFAULT_FAR,pixelAspectRatio);
  377. }//-------------------------------------------------------------------------------------------------
  378. //--------------------------------------------------------------------------------------------------
  379. // Name: CalcWorldPosFromScreenRect
  380. // Desc: Calculates model world position so that it will render within the screen rect provided
  381. //--------------------------------------------------------------------------------------------------
  382. void CMenuRender3DModelMgr::CalcWorldPosFromScreenRect(SRenderSingleEntityData& renderEntityData)
  383. {
  384. if(!(renderEntityData.flags & eRSE_Attached)) // Only position non-attached entities
  385. {
  386. IEntity* pEntity = gEnv->pEntitySystem->GetEntity(renderEntityData.entityId);
  387. if(pEntity)
  388. {
  389. float scaleToUse = (renderEntityData.bUseSecondOffset)? renderEntityData.secondScale : renderEntityData.scale;
  390. // Use local AABB and then rotate to same as model, this will then be in "post render camera space",
  391. // rather than are default camera space (which would then be wrong if in-game)
  392. AABB localAabb;
  393. pEntity->GetLocalBounds(localAabb);
  394. // Rotate local aabb so that it has the same rot as the model
  395. Quat rotQuatInv;
  396. rotQuatInv.SetRotationXYZ((renderEntityData.bUseSecondOffset)? renderEntityData.secondRot : renderEntityData.rot);
  397. rotQuatInv.Invert();
  398. const Vec3 localAabbCentre = localAabb.GetCenter();
  399. localAabb.min = localAabb.min * rotQuatInv;
  400. localAabb.max = localAabb.max * rotQuatInv;
  401. // Update min's and max's to be correct
  402. AABB aabbCopy = localAabb;
  403. SwapIfMinBiggerThanMax(localAabb.min.x,localAabb.max.x);
  404. SwapIfMinBiggerThanMax(localAabb.min.y,localAabb.max.y);
  405. SwapIfMinBiggerThanMax(localAabb.min.z,localAabb.max.z);
  406. Vec3 aabbSize = localAabb.GetSize();
  407. // Get post render camera
  408. CCamera postRenderCamera;
  409. GetPostRenderCamera(postRenderCamera);
  410. // Calc destination width and height
  411. const float doubleScale = scaleToUse * 2.0f;
  412. float destScreenWidth = (renderEntityData.screenRect[2] - renderEntityData.screenRect[0]) * doubleScale;
  413. float destScreenHeight = (renderEntityData.screenRect[3] - renderEntityData.screenRect[1]) * doubleScale;
  414. if((destScreenWidth>0.0f) && (destScreenHeight>0.0f))
  415. {
  416. if((destScreenWidth > scaleToUse) || (destScreenHeight > scaleToUse))
  417. {
  418. if(destScreenWidth >= destScreenHeight)
  419. {
  420. destScreenHeight *= (scaleToUse / destScreenWidth);
  421. destScreenWidth = scaleToUse;
  422. }
  423. else
  424. {
  425. destScreenWidth *= (scaleToUse / destScreenHeight);
  426. destScreenHeight = scaleToUse;
  427. }
  428. }
  429. // Calc depth model needs to render at
  430. const float horizontalSize = tan(0.5f*postRenderCamera.GetHorizontalFov());
  431. const float verticalSize = tan(0.5f*postRenderCamera.GetFov());
  432. const float horizontalDepth = ((aabbSize.x*0.5f)/destScreenWidth) / horizontalSize;
  433. const float verticalDepth = ((aabbSize.z*0.5f)/destScreenHeight) / verticalSize;
  434. const float maxDepth = max(horizontalDepth,verticalDepth);
  435. renderEntityData.pos = Vec3(0.0f,maxDepth+(aabbSize.y*0.5f),0.0f);
  436. // Character pivot points are at their feet, not centre, so remove offset
  437. if(renderEntityData.flags & eRSE_IsCharacter)
  438. {
  439. const Vec3 centreOffset = localAabbCentre * rotQuatInv;
  440. renderEntityData.pos -= centreOffset;
  441. }
  442. // Override depth if less than near plane
  443. renderEntityData.pos.y = max(DEFAULT_NEAR + aabbSize.y,renderEntityData.pos.y);
  444. }
  445. }
  446. }
  447. }//-------------------------------------------------------------------------------------------------
  448. bool CMenuRender3DModelMgr::HasAttachmentStreamedIn(SRenderSingleEntityData& rd, IAttachment* pAttachment)
  449. {
  450. bool bHasStreamed = true;
  451. IAttachmentObject* pAttachmentObj = pAttachment->GetIAttachmentObject();
  452. if(pAttachmentObj)
  453. {
  454. if (IStatObj* pStatObj = pAttachmentObj->GetIStatObj())
  455. {
  456. if (!HasStatObjStreamedIn(rd, pStatObj))
  457. {
  458. MR3MM_TRACE("[MR3MM] (%p) Missing stat obj '%s'", &rd, pStatObj->GetFilePath());
  459. bHasStreamed = false;
  460. }
  461. }
  462. if (pAttachmentObj->GetAttachmentType() == IAttachmentObject::eAttachment_Entity)
  463. {
  464. CEntityAttachment* pEntAttachment = static_cast<CEntityAttachment*>(pAttachmentObj);
  465. if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(pEntAttachment->GetEntityId()))
  466. {
  467. if (!HasEntityStreamedIn(rd, pEntity))
  468. {
  469. MR3MM_TRACE("[MR3MM] (%p) Missing entity attachment '%s'", &rd, pEntity->GetName());
  470. bHasStreamed = false;
  471. }
  472. }
  473. }
  474. if (ICharacterInstance* pCharInst = pAttachmentObj->GetICharacterInstance())
  475. {
  476. if (!HasCharacterStreamedIn(rd, pCharInst))
  477. {
  478. MR3MM_TRACE("[MR3MM] (%p) Missing character attachment", &rd);
  479. bHasStreamed = false;
  480. }
  481. }
  482. if (IAttachmentSkin* pASkin = pAttachmentObj->GetIAttachmentSkin())
  483. {
  484. if (ISkin* pSkin = pASkin->GetISkin())
  485. {
  486. if (!pSkin->GetIRenderMesh(0))
  487. {
  488. MR3MM_TRACE("[MR3MM] (%p) Missing skin attachment '%s'", &rd, pSkin->GetModelFilePath());
  489. bHasStreamed = false;
  490. if (IMaterial* pMaterial = pSkin->GetIMaterial(0))
  491. {
  492. if (!pMaterial->IsStreamedIn(rd.firstPrecacheRoundIds, pSkin->GetIRenderMesh(0)))
  493. {
  494. MR3MM_TRACE("[MR3MM] (%p) Missing skin attachment '%s' material '%s'", &rd, pSkin->GetModelFilePath(), pMaterial->GetName());
  495. bHasStreamed = false;
  496. }
  497. }
  498. }
  499. }
  500. }
  501. }
  502. return bHasStreamed;
  503. }
  504. bool CMenuRender3DModelMgr::HasCharacterStreamedIn(SRenderSingleEntityData& rd, ICharacterInstance* pCharacter)
  505. {
  506. bool bHasStreamed = true;
  507. IDefaultSkeleton& rIDefaultSkeleton = pCharacter->GetIDefaultSkeleton();
  508. {
  509. if (!rIDefaultSkeleton.GetIRenderMesh())
  510. {
  511. MR3MM_TRACE("[MR3MM] (%p) Missing character model render mesh '%s'", &rd, rIDefaultSkeleton.GetModelFilePath());
  512. bHasStreamed = false;
  513. }
  514. }
  515. if (IMaterial* pMat = pCharacter->GetIMaterial())
  516. {
  517. if (!pMat->IsStreamedIn(rd.firstPrecacheRoundIds, NULL))
  518. {
  519. MR3MM_TRACE("[MR3MM] (%p) Missing character material '%s'", &rd, pMat->GetName());
  520. bHasStreamed = false;
  521. }
  522. }
  523. if(IAttachmentManager* pAttachmentMgr = pCharacter->GetIAttachmentManager())
  524. {
  525. const int32 attachmentCount = pAttachmentMgr->GetAttachmentCount();
  526. for(int32 i=0; i<attachmentCount; i++)
  527. {
  528. IAttachment* pAttachment = pAttachmentMgr->GetInterfaceByIndex(i);
  529. if(pAttachment)
  530. {
  531. if (!HasAttachmentStreamedIn(rd, pAttachment))
  532. {
  533. MR3MM_TRACE("[MR3MM] (%p) Missing attachment", &rd);
  534. bHasStreamed = false;
  535. break;
  536. }
  537. }
  538. }
  539. }
  540. return bHasStreamed;
  541. }
  542. bool CMenuRender3DModelMgr::HasStatObjStreamedIn(SRenderSingleEntityData& rd, IStatObj* pStatObj)
  543. {
  544. int nFlags = pStatObj->GetFlags();
  545. if ((nFlags & STATIC_OBJECT_COMPOUND) && pStatObj->GetSubObjectCount())
  546. {
  547. for(int s=0,num = pStatObj->GetSubObjectCount(); s<num; s++)
  548. {
  549. IStatObj::SSubObject &subObj = *pStatObj->GetSubObject(s);
  550. if (subObj.pStatObj && subObj.nType == STATIC_SUB_OBJECT_MESH && !subObj.bShadowProxy)
  551. {
  552. IStatObj *pSubStatObj = subObj.pStatObj;
  553. if (IStatObj * pLod = (IStatObj *)pSubStatObj->GetLodObject(0, true))
  554. {
  555. if (!HasStatObjStreamedIn(rd, pLod))
  556. {
  557. MR3MM_TRACE("[MR3MM] (%p) Missing rendermesh for '%s'", &rd, pLod->GetFilePath());
  558. return false;
  559. }
  560. if (IMaterial* pMat = pLod->GetMaterial())
  561. {
  562. if (!pMat->IsStreamedIn(rd.firstPrecacheRoundIds, pLod->GetRenderMesh()))
  563. {
  564. MR3MM_TRACE("[MR3MM] (%p) Missing material '%s' for '%s'", &rd, pMat->GetName(), pLod->GetFilePath());
  565. return false;
  566. }
  567. }
  568. }
  569. }
  570. }
  571. }
  572. else
  573. {
  574. if(IStatObj * pLod = pStatObj->GetLodObject(0, true))
  575. {
  576. if (!pLod->GetRenderMesh())
  577. {
  578. MR3MM_TRACE("[MR3MM] (%p) Missing rendermesh for '%s'", &rd, pLod->GetFilePath());
  579. return false;
  580. }
  581. if (IMaterial* pMat = pLod->GetMaterial())
  582. {
  583. if (!pMat->IsStreamedIn(rd.firstPrecacheRoundIds, pLod->GetRenderMesh()))
  584. {
  585. MR3MM_TRACE("[MR3MM] (%p) Missing material '%s' for '%s'", &rd, pMat->GetName(), pLod->GetFilePath());
  586. return false;
  587. }
  588. }
  589. }
  590. }
  591. return true;
  592. }
  593. //--------------------------------------------------------------------------------------------------
  594. // Name: HasEntityStreamedIn
  595. // Desc: Returns true if entity has streamed in
  596. //--------------------------------------------------------------------------------------------------
  597. bool CMenuRender3DModelMgr::HasEntityStreamedIn(SRenderSingleEntityData& rd, IEntity* pEntity)
  598. {
  599. bool bHasStreamed = true;
  600. if(pEntity)
  601. {
  602. SEntitySlotInfo slotInfo;
  603. const int slotIndex = 0;
  604. bool bGotSlotInfo = pEntity->GetSlotInfo(slotIndex,slotInfo);
  605. if(bGotSlotInfo)
  606. {
  607. if(!slotInfo.pCharacter && !slotInfo.pStatObj)
  608. {
  609. // No char or statObj yet
  610. MR3MM_TRACE("[MR3MM] (%p) Slot is empty on entity '%s'", &rd, pEntity->GetName());
  611. bHasStreamed = false;
  612. }
  613. else if(slotInfo.pCharacter)
  614. {
  615. if (!HasCharacterStreamedIn(rd, slotInfo.pCharacter))
  616. {
  617. MR3MM_TRACE("[MR3MM] (%p) Character missing on entity '%s'", &rd, pEntity->GetName());
  618. bHasStreamed = false;
  619. }
  620. }
  621. else
  622. {
  623. // Stat obj
  624. if (!HasStatObjStreamedIn(rd, slotInfo.pStatObj))
  625. {
  626. MR3MM_TRACE("[MR3MM] (%p) Stat obj missing on entity '%s'", &rd, pEntity->GetName());
  627. bHasStreamed = false;
  628. }
  629. }
  630. }
  631. }
  632. else
  633. {
  634. // No entity, so not streamed in
  635. bHasStreamed = false;
  636. }
  637. return bHasStreamed;
  638. }//-------------------------------------------------------------------------------------------------
  639. //--------------------------------------------------------------------------------------------------
  640. // Name: PreCacheMaterial
  641. // Desc: Pre-caches material
  642. //--------------------------------------------------------------------------------------------------
  643. void CMenuRender3DModelMgr::PreCacheMaterial(SRenderSingleEntityData& rd, IEntity* pEntity,bool bIsCharacter)
  644. {
  645. // Precache material -> This forces the material to have a high streaming priority
  646. const float distance = 0.0f;
  647. IRenderMesh* pRenderMesh = NULL;
  648. const bool bFullUpdate = true;
  649. const bool bDrawNear = true;
  650. IComponentRender* pRenderProxy = static_cast<IComponentRender*>(pEntity->GetComponent<IComponentRender>().get());
  651. if (pRenderProxy)
  652. gEnv->p3DEngine->PrecacheRenderNode(pRenderProxy->GetRenderNode(), 0.0f);
  653. if (!rd.firstPrecacheRoundIds[0])
  654. {
  655. gEnv->p3DEngine->GetPrecacheRoundIds(rd.firstPrecacheRoundIds);
  656. // We only precached the near zone, so we don't care about when the far zone was last precached.
  657. rd.firstPrecacheRoundIds[1] = -1;
  658. }
  659. }//-------------------------------------------------------------------------------------------------
  660. //--------------------------------------------------------------------------------------------------
  661. // Name: AddModelData
  662. // Desc: Adds model data
  663. //--------------------------------------------------------------------------------------------------
  664. void CMenuRender3DModelMgr::AddModelData(const PodArray<CMenuRender3DModelMgr::SModelData>& modelData)
  665. {
  666. if(IsMenu3dModelEngineSupportActive())
  667. {
  668. const uint modelCount = modelData.Size();
  669. for(uint i=0; i<modelCount; i++)
  670. {
  671. const SModelData& currentModelData = modelData[i];
  672. SModelParams modelParams;
  673. modelParams.pName = currentModelData.name.c_str();
  674. modelParams.pFilename = currentModelData.filename.c_str();
  675. modelParams.pMaterialOverrideFilename = currentModelData.materialOverrideFilename.c_str();
  676. modelParams.rot = currentModelData.rot;
  677. modelParams.secondRot = currentModelData.secondRot;
  678. modelParams.userRotScale = currentModelData.userRotScale;
  679. modelParams.posOffset = currentModelData.posOffset;
  680. modelParams.posSecondOffset = currentModelData.posSecondOffset;
  681. modelParams.scale = currentModelData.scale;
  682. modelParams.secondScale = currentModelData.secondScale;
  683. modelParams.silhouetteColor = currentModelData.silhouetteColor;
  684. memcpy(modelParams.screenRect,currentModelData.screenRect,sizeof(float)*4);
  685. // Add model
  686. const TAddedModelIndex modelIndex = AddModel( modelParams );
  687. if(modelIndex != kAddedModelIndex_Invalid)
  688. {
  689. SRenderSingleEntityData& renderEntityData = m_renderEntityData[modelIndex];
  690. IEntity* pEntity = gEnv->pEntitySystem->GetEntity(renderEntityData.entityId);
  691. if(pEntity)
  692. {
  693. SetAsPost3dRenderObject(pEntity,renderEntityData.groupId,renderEntityData.screenRect);
  694. }
  695. // Set animation
  696. const char* pAnimName = currentModelData.animName.c_str();
  697. if(pAnimName && pAnimName[0])
  698. {
  699. UpdateAnim(modelIndex,pAnimName,currentModelData.animSpeed);
  700. }
  701. // Set attachment
  702. const char* pAttachmentParent = currentModelData.attachmentParent.c_str();
  703. if(pAttachmentParent && pAttachmentParent[0])
  704. {
  705. CMenuRender3DModelMgr::TAddedModelIndex parentModelIndex = 0;
  706. if(GetModelIndexFromName(pAttachmentParent,parentModelIndex))
  707. {
  708. AttachChildToParent(modelIndex,parentModelIndex,currentModelData.attachmentLocation.c_str());
  709. }
  710. }
  711. }
  712. }
  713. }
  714. }//-------------------------------------------------------------------------------------------------
  715. //--------------------------------------------------------------------------------------------------
  716. // Name: SetSilhouette
  717. // Desc: Sets model silhouette
  718. //--------------------------------------------------------------------------------------------------
  719. void CMenuRender3DModelMgr::SetSilhouette(TAddedModelIndex modelIndex, const Vec3& silhouetteColor)
  720. {
  721. const uint renderEntityCount = m_renderEntityData.size();
  722. if(modelIndex < renderEntityCount)
  723. {
  724. SRenderSingleEntityData& renderEntityData = m_renderEntityData[modelIndex];
  725. renderEntityData.silhouetteColor.x = clamp_tpl<float>(silhouetteColor.x,0.0f,1.0f);
  726. renderEntityData.silhouetteColor.y = clamp_tpl<float>(silhouetteColor.y,0.0f,1.0f);
  727. renderEntityData.silhouetteColor.z = clamp_tpl<float>(silhouetteColor.z,0.0f,1.0f);
  728. }
  729. }//-------------------------------------------------------------------------------------------------
  730. //--------------------------------------------------------------------------------------------------
  731. // Name: SetAlpha
  732. // Desc: Sets model alpha
  733. //--------------------------------------------------------------------------------------------------
  734. void CMenuRender3DModelMgr::SetAlpha(TAddedModelIndex modelIndex,float alpha)
  735. {
  736. const uint renderEntityCount = m_renderEntityData.size();
  737. if(modelIndex < renderEntityCount)
  738. {
  739. SRenderSingleEntityData& renderEntityData = m_renderEntityData[modelIndex];
  740. renderEntityData.maxAlpha = clamp_tpl<float>(alpha,0.0f,1.0f);
  741. }
  742. }//-------------------------------------------------------------------------------------------------
  743. //--------------------------------------------------------------------------------------------------
  744. // Name: UseSecondOffset
  745. // Desc: Enables or disabled usage of the second offset values
  746. //--------------------------------------------------------------------------------------------------
  747. void CMenuRender3DModelMgr::UseSecondOffset(TAddedModelIndex modelIndex, bool enabled)
  748. {
  749. const uint renderEntityCount = m_renderEntityData.size();
  750. if(modelIndex < renderEntityCount)
  751. {
  752. SRenderSingleEntityData& renderEntityData = m_renderEntityData[modelIndex];
  753. renderEntityData.bUseSecondOffset = enabled;
  754. }
  755. }//-------------------------------------------------------------------------------------------------
  756. //--------------------------------------------------------------------------------------------------
  757. // Name: GetModelIndexFromName
  758. // Desc: Gets a model index from name, returns true if found model
  759. //--------------------------------------------------------------------------------------------------
  760. bool CMenuRender3DModelMgr::GetModelIndexFromName(const char* pName,TAddedModelIndex& outModelIndex) const
  761. {
  762. const uint renderEntityCount = m_renderEntityData.size();
  763. for(uint i=0; i<renderEntityCount; i++)
  764. {
  765. if(strcmp(m_renderEntityData[i].name.c_str(),pName)==0)
  766. {
  767. outModelIndex = i;
  768. return true;
  769. }
  770. }
  771. return false;
  772. }//-------------------------------------------------------------------------------------------------
  773. //--------------------------------------------------------------------------------------------------
  774. // Name: UpdateModel
  775. // Desc: Updates model with new data
  776. //--------------------------------------------------------------------------------------------------
  777. void CMenuRender3DModelMgr::UpdateModel(TAddedModelIndex modelIndex,const char* pFilename, const char* pMaterialOverrideFilename, bool bUpdateModelPos)
  778. {
  779. if(IsMenu3dModelEngineSupportActive())
  780. {
  781. const uint renderEntityCount = m_renderEntityData.size();
  782. if(modelIndex < renderEntityCount)
  783. {
  784. const bool bIsNewModelCharacter = IsCharacterFile(pFilename);
  785. SRenderSingleEntityData& renderEntityData = m_renderEntityData[modelIndex];
  786. IEntitySystem* pEntitySystem = gEnv->pEntitySystem;
  787. if(pEntitySystem)
  788. {
  789. IEntity* pEntity = pEntitySystem->GetEntity(renderEntityData.entityId);
  790. if(pEntity)
  791. {
  792. const int slotIndex = 0;
  793. float animNormalizedTime = 0.0f;
  794. const bool bHasNewModel = (pFilename && pFilename[0]) ? true : false;
  795. const bool bIsOldModelCharacter = (renderEntityData.flags & eRSE_IsCharacter) ? true : false;
  796. // If previous model wasn't streamed in, then it can't rely on previous model pos
  797. if(!(renderEntityData.flags & eRSE_StreamedIn) && !(renderEntityData.flags & eRSE_Attached))
  798. {
  799. bUpdateModelPos = true;
  800. }
  801. if(bIsNewModelCharacter)
  802. {
  803. renderEntityData.flags |= eRSE_IsCharacter;
  804. }
  805. else
  806. {
  807. renderEntityData.flags &=~ eRSE_IsCharacter;
  808. }
  809. // UnHide model, then reHide after loading new model, otherwise will get out of sync
  810. const bool bPrevHidden = pEntity->IsHidden();
  811. HideModel(false,modelIndex,bUpdateModelPos);
  812. if(bIsNewModelCharacter)
  813. {
  814. // Get animNormaizedTime so we can resume animation playback from same place for new char
  815. ICharacterInstance *pCharInst = pEntity->GetCharacter(slotIndex);
  816. if(pCharInst)
  817. {
  818. const uint32 animationLayer = 0;
  819. ISkeletonAnim* pSkelAnim = pCharInst->GetISkeletonAnim();
  820. if(pSkelAnim)
  821. {
  822. const int animationsInLayer = pSkelAnim->GetNumAnimsInFIFO(animationLayer);
  823. const int lastAnimationIndex = animationsInLayer - 1;
  824. CAnimation& animation = pSkelAnim->GetAnimFromFIFO(animationLayer,lastAnimationIndex);
  825. animNormalizedTime = pSkelAnim->GetAnimationNormalizedTime(&animation);
  826. }
  827. }
  828. // Free old char and load new char
  829. pEntity->FreeSlot(slotIndex);
  830. if(bHasNewModel)
  831. {
  832. pEntity->LoadCharacter(slotIndex, pFilename,IEntity::EF_NO_STREAMING);
  833. SetCharacterFlags(pEntity);
  834. }
  835. }
  836. else
  837. {
  838. // Free old obj and load new obj
  839. pEntity->FreeSlot(slotIndex);
  840. if(bHasNewModel)
  841. {
  842. pEntity->LoadGeometry(0, pFilename,NULL,IEntity::EF_NO_STREAMING);
  843. }
  844. }
  845. if(bHasNewModel)
  846. {
  847. renderEntityData.flags |= eRSE_HasModel;
  848. }
  849. else
  850. {
  851. renderEntityData.flags &=~ eRSE_HasModel;
  852. }
  853. ApplyMaterialOverride(pEntity,pMaterialOverrideFilename);
  854. PreCacheMaterial(renderEntityData, pEntity,bIsNewModelCharacter);
  855. SetAsPost3dRenderObject(pEntity,renderEntityData.groupId,renderEntityData.screenRect);
  856. // Apply existing animation
  857. if(bHasNewModel)
  858. {
  859. const char* pAnimName = renderEntityData.animName.c_str();
  860. if(pAnimName && pAnimName[0])
  861. {
  862. float speedMultiplier = 0.5f;
  863. int layer = 0;
  864. ICharacterInstance *pCharInst = pEntity->GetCharacter(slotIndex);
  865. if(pCharInst)
  866. {
  867. CryCharAnimationParams animParams;
  868. animParams.m_nLayerID = layer;
  869. animParams.m_nFlags |= CA_LOOP_ANIMATION | CA_FORCE_SKELETON_UPDATE;
  870. animParams.m_fPlaybackSpeed = speedMultiplier;
  871. animParams.m_fTransTime = 0.0f;
  872. ISkeletonAnim* pSkelAnim = pCharInst->GetISkeletonAnim();
  873. if(pSkelAnim)
  874. {
  875. pSkelAnim->StartAnimation(pAnimName,animParams);
  876. const uint32 animationLayer = 0;
  877. const int animationsInLayer = pSkelAnim->GetNumAnimsInFIFO(animationLayer);
  878. const int lastAnimationIndex = animationsInLayer - 1;
  879. CAnimation& animation = pSkelAnim->GetAnimFromFIFO(animationLayer,lastAnimationIndex);
  880. pSkelAnim->SetAnimationNormalizedTime(&animation,animNormalizedTime);
  881. }
  882. }
  883. }
  884. }
  885. // If model is already streamed in then calc new world pos
  886. if(!pEntity->IsHidden() && bUpdateModelPos)
  887. {
  888. CalcWorldPosFromScreenRect(renderEntityData);
  889. }
  890. // Fix attachments
  891. for(uint8 i=0; i<renderEntityCount; i++)
  892. {
  893. SRenderSingleEntityData& childRenderEntityData = m_renderEntityData[i];
  894. if(childRenderEntityData.parentIndex == modelIndex)
  895. {
  896. AttachChildToParent(i,modelIndex,childRenderEntityData.attachmentLocation.c_str());
  897. }
  898. }
  899. renderEntityData.flags |= eRSE_Invalid;
  900. // If attached then don't fade in, but set alpha the same as parent
  901. if(renderEntityData.flags & eRSE_Attached)
  902. {
  903. SRenderSingleEntityData& parentRenderEntityData = m_renderEntityData[renderEntityData.parentIndex];
  904. renderEntityData.alpha = parentRenderEntityData.alpha;
  905. parentRenderEntityData.flags |= eRSE_Invalid;
  906. }
  907. HideModel(bPrevHidden,modelIndex,bUpdateModelPos);
  908. }
  909. }
  910. }
  911. }
  912. }//-------------------------------------------------------------------------------------------------
  913. //--------------------------------------------------------------------------------------------------
  914. // Name: SetAsPost3dRenderObject
  915. // Desc: Sets model to render as post 3d render object
  916. //--------------------------------------------------------------------------------------------------
  917. void CMenuRender3DModelMgr::SetAsPost3dRenderObject(IEntity* pEntity,uint8 groupId,float* pScreenRect)
  918. {
  919. if(pEntity)
  920. {
  921. IComponentRender* pRenderProxy = static_cast<IComponentRender*>(pEntity->GetComponent<IComponentRender>().get());
  922. if(pRenderProxy)
  923. {
  924. pRenderProxy->SetAsPost3dRenderObject(true,groupId,pScreenRect);
  925. IRenderNode* pRenderNode = pRenderProxy->GetRenderNode();
  926. if(pRenderNode)
  927. {
  928. pRenderNode->SetRndFlags(ERF_RENDER_ALWAYS|ERF_HUD,true); // Set render node to always render
  929. pRenderNode->SetLodRatio(0); // Ignore LODs
  930. }
  931. }
  932. }
  933. }//-------------------------------------------------------------------------------------------------
  934. //--------------------------------------------------------------------------------------------------
  935. // Name: ApplyMaterialOverride
  936. // Desc: Applies an override material to a model
  937. //--------------------------------------------------------------------------------------------------
  938. void CMenuRender3DModelMgr::ApplyMaterialOverride(IEntity* pEntity,const char* pOverrideMaterialFilename)
  939. {
  940. if(pEntity && pOverrideMaterialFilename && pOverrideMaterialFilename[0])
  941. {
  942. IMaterialManager* pMaterialManager = gEnv->p3DEngine->GetMaterialManager();
  943. if(pMaterialManager)
  944. {
  945. IMaterial* pMaterialOverride = pMaterialManager->FindMaterial(pOverrideMaterialFilename);
  946. if(!pMaterialOverride)
  947. {
  948. const bool bMakeIfNotFound = false;
  949. pMaterialOverride = pMaterialManager->LoadMaterial(pOverrideMaterialFilename,bMakeIfNotFound);
  950. if(!pMaterialOverride)
  951. {
  952. FE_LOG("Material not found '%s'", pOverrideMaterialFilename);
  953. }
  954. }
  955. if(pMaterialOverride)
  956. {
  957. pEntity->SetSlotMaterial(0,pMaterialOverride);
  958. }
  959. }
  960. }
  961. }//-------------------------------------------------------------------------------------------------
  962. //--------------------------------------------------------------------------------------------------
  963. // Name: SetCharacterFlags
  964. // Desc: Sets character flags
  965. //--------------------------------------------------------------------------------------------------
  966. void CMenuRender3DModelMgr::SetCharacterFlags(IEntity* pEntity)
  967. {
  968. if(pEntity)
  969. {
  970. const int slotIndex = 0;
  971. SEntitySlotInfo slotInfo;
  972. const bool bGotSlotInfo = pEntity->GetSlotInfo(slotIndex, slotInfo);
  973. if(bGotSlotInfo && slotInfo.pCharacter)
  974. {
  975. slotInfo.pCharacter->SetFlags(slotInfo.pCharacter->GetFlags()|CS_FLAG_UPDATE|CS_FLAG_UPDATE_ALWAYS);
  976. }
  977. }
  978. }//-------------------------------------------------------------------------------------------------
  979. //--------------------------------------------------------------------------------------------------
  980. // Name: SetSceneSettings
  981. // Desc: Sets scene settings
  982. //--------------------------------------------------------------------------------------------------
  983. void CMenuRender3DModelMgr::SetSceneSettings(const SSceneSettings& sceneSettings)
  984. {
  985. // Set scene settings
  986. m_sceneSettings.ambientLight = sceneSettings.ambientLight;
  987. m_sceneSettings.ambientLight.w *= MENU_LIGHT_AMBIENT_ALPHA_SCALE;
  988. m_sceneSettings.fadeInSpeed = sceneSettings.fadeInSpeed;
  989. m_sceneSettings.fovScale = sceneSettings.fovScale;
  990. m_sceneSettings.flashEdgeFadeScale = sceneSettings.flashEdgeFadeScale;
  991. ReleaseLights();
  992. const int lightCount = sceneSettings.lights.size();
  993. m_sceneSettings.lights.resize(lightCount);
  994. for(int i=0; i<lightCount; i++)
  995. {
  996. // Copy light settings
  997. SLightData& lightData = m_sceneSettings.lights[i];
  998. memcpy(&lightData,&sceneSettings.lights[i],sizeof(CMenuRender3DModelMgr::SLightData));
  999. #if !DEBUG_MENU_RENDER_3D_MODEL_MGR
  1000. lightData.color *= MENU_LIGHT_COLOR_SCALE;
  1001. #endif
  1002. // Create light source
  1003. lightData.pLightSource = gEnv->p3DEngine->CreateLightSource();
  1004. if(lightData.pLightSource)
  1005. {
  1006. const float frameTime = 0.0f;
  1007. UpdateLight(i,frameTime); //Needs to update before Register so it has a valid AABB
  1008. gEnv->p3DEngine->RegisterEntity(lightData.pLightSource);
  1009. lightData.pLightSource->SetRndFlags(ERF_RENDER_ALWAYS,true);
  1010. }
  1011. }
  1012. }//-------------------------------------------------------------------------------------------------
  1013. //--------------------------------------------------------------------------------------------------
  1014. // Name: UpdateAnim
  1015. // Desc: Updates animation with new data
  1016. //--------------------------------------------------------------------------------------------------
  1017. void CMenuRender3DModelMgr::UpdateAnim(TAddedModelIndex modelIndex, const char* animName,float speedMultiplier,int layer)
  1018. {
  1019. if(IsMenu3dModelEngineSupportActive())
  1020. {
  1021. if(animName && animName[0])
  1022. {
  1023. CACHE_LOG_FILE_ACCESSES_START;
  1024. const uint renderEntityCount = m_renderEntityData.size();
  1025. if(modelIndex < renderEntityCount)
  1026. {
  1027. SRenderSingleEntityData& renderEntityData = m_renderEntityData[modelIndex];
  1028. IEntity* pEntity = gEnv->pEntitySystem->GetEntity(renderEntityData.entityId);
  1029. if(pEntity)
  1030. {
  1031. renderEntityData.animName = animName;
  1032. const int slotIndex = 0;
  1033. ICharacterInstance* pCharInst = pEntity->GetCharacter(slotIndex);
  1034. if(pCharInst)
  1035. {
  1036. CryCharAnimationParams animParams;
  1037. animParams.m_nLayerID = layer;
  1038. animParams.m_nFlags |= CA_LOOP_ANIMATION | CA_FORCE_SKELETON_UPDATE;
  1039. animParams.m_fPlaybackSpeed = speedMultiplier;
  1040. animParams.m_fTransTime = 0.0f;
  1041. pCharInst->GetISkeletonAnim()->StartAnimation(animName,animParams);
  1042. }
  1043. }
  1044. }
  1045. CACHE_LOG_FILE_ACCESSES_END;
  1046. }
  1047. }
  1048. }//-------------------------------------------------------------------------------------------------
  1049. bool CMenuRender3DModelMgr::IsModelStreamed(TAddedModelIndex modelIndex) const
  1050. {
  1051. if (!(m_renderEntityData[modelIndex].flags & eRSE_HasModel))
  1052. return true;
  1053. if (m_renderEntityData[modelIndex].flags & eRSE_Invalid)
  1054. return false;
  1055. if (!(m_renderEntityData[modelIndex].flags & eRSE_StreamedIn))
  1056. return false;
  1057. return true;
  1058. }
  1059. //--------------------------------------------------------------------------------------------------
  1060. // Name: AttachChildToParent
  1061. // Desc: Attaches child to parent
  1062. //--------------------------------------------------------------------------------------------------
  1063. void CMenuRender3DModelMgr::AttachChildToParent(TAddedModelIndex childIndex,TAddedModelIndex parentIndex, const char* pAttachPointName)
  1064. {
  1065. if(pAttachPointName && pAttachPointName[0])
  1066. {
  1067. const uint renderEntityCount = m_renderEntityData.size();
  1068. if(parentIndex < renderEntityCount && childIndex < renderEntityCount)
  1069. {
  1070. SRenderSingleEntityData& parentRenderData = m_renderEntityData[parentIndex];
  1071. SRenderSingleEntityData& childRenderData = m_renderEntityData[childIndex];
  1072. // Store top level parent index, so all linked models can have a common piece of data
  1073. TAddedModelIndex topParentIndex = parentIndex;
  1074. SRenderSingleEntityData* pTopParentRenderData = &m_renderEntityData[topParentIndex];
  1075. while(pTopParentRenderData->topParentIndex != topParentIndex)
  1076. {
  1077. topParentIndex = pTopParentRenderData->topParentIndex;
  1078. pTopParentRenderData = &m_renderEntityData[topParentIndex];
  1079. }
  1080. if(parentRenderData.flags & eRSE_IsCharacter)
  1081. {
  1082. AttachToCharacter(childIndex,parentIndex,pAttachPointName);
  1083. }
  1084. else
  1085. {
  1086. AttachToStaticObject(childIndex,parentIndex,pAttachPointName);
  1087. }
  1088. // Copy data after attachment change, so can release previous attachment
  1089. childRenderData.topParentIndex = topParentIndex;
  1090. childRenderData.parentIndex = parentIndex;
  1091. childRenderData.attachmentLocation = pAttachPointName;
  1092. memcpy(childRenderData.screenRect,pTopParentRenderData->screenRect,sizeof(float)*4);
  1093. childRenderData.pos = ZERO;
  1094. IEntity* pChildEntity = gEnv->pEntitySystem->GetEntity(childRenderData.entityId);
  1095. if(pChildEntity)
  1096. {
  1097. const uint8 topParentGroupId = pTopParentRenderData->groupId;
  1098. const uint8 groupIdToFree = childRenderData.groupId;
  1099. childRenderData.groupId = topParentGroupId;
  1100. SetAsPost3dRenderObject(pChildEntity,topParentGroupId,pTopParentRenderData->screenRect);
  1101. if(groupIdToFree != topParentGroupId)
  1102. {
  1103. FreeUnusedGroup(groupIdToFree);
  1104. }
  1105. }
  1106. }
  1107. }
  1108. }//-------------------------------------------------------------------------------------------------
  1109. //--------------------------------------------------------------------------------------------------
  1110. // Name: FreeUnusedGroup
  1111. // Desc: Frees an unused group
  1112. //--------------------------------------------------------------------------------------------------
  1113. void CMenuRender3DModelMgr::FreeUnusedGroup(uint8 unusedGroupId)
  1114. {
  1115. const uint8 endGroupIndex = m_groupCount-1;
  1116. if(unusedGroupId < endGroupIndex)
  1117. {
  1118. // Not last group, so swap with last group
  1119. const uint renderEntityCount = m_renderEntityData.size();
  1120. for(uint8 i=0; i<renderEntityCount; i++)
  1121. {
  1122. SRenderSingleEntityData& renderEntityData = m_renderEntityData[i];
  1123. if(renderEntityData.groupId == endGroupIndex)
  1124. {
  1125. renderEntityData.groupId = unusedGroupId;
  1126. IEntity* pEntity = gEnv->pEntitySystem->GetEntity(renderEntityData.entityId);
  1127. if(pEntity)
  1128. {
  1129. SRenderSingleEntityData& topParentRenderEntityData = m_renderEntityData[renderEntityData.topParentIndex];
  1130. SetAsPost3dRenderObject(pEntity,unusedGroupId,topParentRenderEntityData.screenRect);
  1131. }
  1132. }
  1133. }
  1134. }
  1135. m_groupCount--;
  1136. }//-------------------------------------------------------------------------------------------------
  1137. //--------------------------------------------------------------------------------------------------
  1138. // Name: AttachToStaticObject
  1139. // Desc: Attaches a model to a static object
  1140. //--------------------------------------------------------------------------------------------------
  1141. void CMenuRender3DModelMgr::AttachToStaticObject(TAddedModelIndex childIndex, TAddedModelIndex parentIndex, const char* pMountPointName)
  1142. {
  1143. if(pMountPointName && pMountPointName[0])
  1144. {
  1145. const uint rend