BVB Source Codes

CRYENGINE Show 3DEngineRender.cpp Source code

Return Download CRYENGINE: download 3DEngineRender.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. // -------------------------------------------------------------------------
  4. //  File name:   3denginerender.cpp
  5. //  Version:     v1.00
  6. //  Created:     28/5/2001 by Vladimir Kajalin
  7. //  Compilers:   Visual Studio.NET
  8. //  Description: rendering
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15.  
  16. #include "3dEngine.h"
  17. #include "ObjMan.h"
  18. #include "VisAreas.h"
  19. #include "terrain_water.h"
  20. #include <CryParticleSystem/IParticles.h>
  21. #include "DecalManager.h"
  22. #include "SkyLightManager.h"
  23. #include "terrain.h"
  24. #include "PolygonClipContext.h"
  25. #include "LightEntity.h"
  26. #include "FogVolumeRenderNode.h"
  27. #include "ObjectsTree.h"
  28. #include "WaterWaveRenderNode.h"
  29. #include "CloudsManager.h"
  30. #include "MatMan.h"
  31. #include "VolumeObjectRenderNode.h"
  32. #include <CryString/CryPath.h>
  33. #include <CryMemory/ILocalMemoryUsage.h>
  34. #include <CryCore/BitFiddling.h>
  35. #include "ObjMan.h"
  36. #include "ParticleMemory.h"
  37. #include "ParticleSystem/ParticleSystem.h"
  38. #include "ObjManCullQueue.h"
  39. #include "MergedMeshRenderNode.h"
  40. #include "GeomCacheManager.h"
  41. #include "DeformableNode.h"
  42. #include "Brush.h"
  43. #include "ClipVolumeManager.h"
  44. #include <Cry3DEngine/ITimeOfDay.h>
  45. #include <CrySystem/Scaleform/IScaleformHelper.h>
  46. #include <CryGame/IGameFramework.h>
  47. #include <CryAnimation/ICryAnimation.h>
  48. #include <CryAISystem/IAISystem.h>
  49. #include <CryCore/Platform/IPlatformOS.h>
  50. #include "WaterRippleManager.h"
  51.  
  52. #if defined(FEATURE_SVO_GI)
  53.         #include "SVO/SceneTreeManager.h"
  54. #endif
  55.  
  56. #ifdef GetCharWidth
  57.         #undef GetCharWidth
  58. #endif //GetCharWidth
  59.  
  60. ////////////////////////////////////////////////////////////////////////////////////////
  61. // RenderScene
  62. ////////////////////////////////////////////////////////////////////////////////////////
  63. #define FREE_MEMORY_YELLOW_LIMIT (30)
  64. #define FREE_MEMORY_RED_LIMIT    (10)
  65. #define DISPLAY_INFO_SCALE       (1.25f)
  66. #define DISPLAY_INFO_SCALE_SMALL (1.1f)
  67. #define STEP_SMALL_DIFF          (2.f)
  68.  
  69. #if CRY_PLATFORM_WINDOWS
  70. // for panorama screenshots
  71. class CStitchedImage : public Cry3DEngineBase
  72. {
  73. public:
  74.         CStitchedImage(C3DEngine& rEngine,
  75.                        const uint32 dwWidth,
  76.                        const uint32 dwHeight,
  77.                        const uint32 dwVirtualWidth,
  78.                        const uint32 dwVirtualHeight,
  79.                        const uint32 dwSliceCount,
  80.                        const f32 fTransitionSize,
  81.                        const bool bMetaData = false) :
  82.                 m_rEngine(rEngine),
  83.                 m_dwWidth(dwWidth),
  84.                 m_dwHeight(dwHeight),
  85.                 m_fInvWidth(1.f / static_cast<f32>(dwWidth)),
  86.                 m_fInvHeight(1.f / static_cast<f32>(dwHeight)),
  87.                 m_dwVirtualWidth(dwVirtualWidth),
  88.                 m_dwVirtualHeight(dwVirtualHeight),
  89.                 m_fInvVirtualWidth(1.f / static_cast<f32>(dwVirtualWidth)),
  90.                 m_fInvVirtualHeight(1.f / static_cast<f32>(dwVirtualHeight)),
  91.                 m_nFileId(0),
  92.                 m_dwSliceCount(dwSliceCount),
  93.                 m_fHorizFOV(2 * gf_PI / dwSliceCount),
  94.                 m_bFlipY(true),
  95.                 m_fTransitionSize(fTransitionSize),
  96.                 m_bMetaData(bMetaData)
  97.         {
  98.                 assert(dwWidth);
  99.                 assert(dwHeight);
  100.  
  101.                 const char* szExtension = m_rEngine.GetCVars()->e_ScreenShotFileFormat->GetString();
  102.  
  103.                 m_bFlipY = (stricmp(szExtension, "tga") == 0);
  104.  
  105.                 m_RGB.resize(m_dwWidth * 3 * m_dwHeight);
  106.  
  107.                 // ratio between width and height defines angle 1 (angle from mid to cylinder edges)
  108.                 float fVert1Frac = (2 * gf_PI * m_dwHeight) / m_dwWidth;
  109.  
  110.                 // slice count defines angle 2
  111.                 float fHorizFrac = tanf(GetHorizFOVWithBorder() * 0.5f);
  112.                 float fVert2Frac = 2.0f * fHorizFrac / rEngine.GetRenderer()->GetWidth() * rEngine.GetRenderer()->GetHeight();
  113.                 //              float fVert2Frac = 2.0f * fHorizFrac / rEngine.GetRenderer()->GetWidth() * rEngine.GetRenderer()->GetHeight();
  114.  
  115.                 // the bigger one defines the needed angle
  116.                 float fVertFrac = max(fVert1Frac, fVert2Frac);
  117.  
  118.                 // planar image becomes a barrel after projection and we need to zoom in to only utilize the usable part (inner rect)
  119.                 // this is not always needed - for quality with low slice count we could be save some quality here
  120.                 fVertFrac /= cosf(GetHorizFOVWithBorder() * 0.5f);
  121.  
  122.                 // compute FOV from Frac
  123.                 float fVertFOV = 2 * atanf(0.5f * fVertFrac);
  124.  
  125.                 m_fPanoramaShotVertFOV = fVertFOV;
  126.  
  127.                 CryLog("RenderFov = %f degrees (%f = max(%f,%f)*fix)", RAD2DEG(m_fPanoramaShotVertFOV), fVertFrac, fVert1Frac, fVert2Frac);
  128.                 Clear();
  129.         }
  130.  
  131.         void Clear()
  132.         {
  133.                 memset(&m_RGB[0], 0, m_dwWidth * m_dwHeight * 3);
  134.         }
  135.  
  136.         // szDirectory + "/" + file_id + "." + extension
  137.         // logs errors in the case there are problems
  138.         bool SaveImage(const char* szDirectory)
  139.         {
  140.                 assert(szDirectory);
  141.  
  142.                 const char* szExtension = m_rEngine.GetCVars()->e_ScreenShotFileFormat->GetString();
  143.  
  144.                 if (stricmp(szExtension, "dds") != 0 &&
  145.                     stricmp(szExtension, "tga") != 0 &&
  146.                     stricmp(szExtension, "jpg") != 0)
  147.                 {
  148.                         gEnv->pLog->LogError("Format e_ScreenShotFileFormat='%s' not supported", szExtension);
  149.                         return false;
  150.                 }
  151.  
  152.                 char sFileName[_MAX_PATH];
  153.  
  154.                 cry_sprintf(sFileName, "%s/ScreenShots/%s", PathUtil::GetGameFolder().c_str(), szDirectory);
  155.                 CryCreateDirectory(sFileName);
  156.  
  157.                 // find free file id
  158.                 for (;; )
  159.                 {
  160.                         cry_sprintf(sFileName, "%s/ScreenShots/%s/%.5d.%s", PathUtil::GetGameFolder().c_str(), szDirectory, m_nFileId, szExtension);
  161.  
  162.                         FILE* fp = gEnv->pCryPak->FOpen(sFileName, "rb");
  163.  
  164.                         if (!fp)
  165.                                 break; // file doesn't exist
  166.  
  167.                         gEnv->pCryPak->FClose(fp);
  168.                         m_nFileId++;
  169.                 }
  170.  
  171.                 bool bOk;
  172.  
  173.                 if (stricmp(szExtension, "dds") == 0)
  174.                         bOk = gEnv->pRenderer->WriteDDS((byte*)&m_RGB[0], m_dwWidth, m_dwHeight, 4, sFileName, eTF_BC3, 1);
  175.                 else if (stricmp(szExtension, "tga") == 0)
  176.                         bOk = gEnv->pRenderer->WriteTGA((byte*)&m_RGB[0], m_dwWidth, m_dwHeight, sFileName, 24, 24);
  177.                 else
  178.                         bOk = gEnv->pRenderer->WriteJPG((byte*)&m_RGB[0], m_dwWidth, m_dwHeight, sFileName, 24);
  179.  
  180.                 if (!bOk)
  181.                         gEnv->pLog->LogError("Failed to write '%s' (not supported on this platform?)", sFileName);
  182.                 else //write meta data
  183.                 {
  184.                         if (m_bMetaData)
  185.                         {
  186.                                 const f32 nTSize = static_cast<f32>(gEnv->p3DEngine->GetTerrainSize());
  187.                                 const f32 fSizeX = GetCVars()->e_ScreenShotMapSizeX;
  188.                                 const f32 fSizeY = GetCVars()->e_ScreenShotMapSizeY;
  189.                                 const f32 fTLX = GetCVars()->e_ScreenShotMapCenterX - fSizeX;
  190.                                 const f32 fTLY = GetCVars()->e_ScreenShotMapCenterY - fSizeY;
  191.                                 const f32 fBRX = GetCVars()->e_ScreenShotMapCenterX + fSizeX;
  192.                                 const f32 fBRY = GetCVars()->e_ScreenShotMapCenterY + fSizeY;
  193.  
  194.                                 cry_sprintf(sFileName, "%s/ScreenShots/%s/%.5d.%s", PathUtil::GetGameFolder().c_str(), szDirectory, m_nFileId, "xml");
  195.  
  196.                                 FILE* metaFile = gEnv->pCryPak->FOpen(sFileName, "wt");
  197.                                 if (metaFile)
  198.                                 {
  199.                                         char sFileData[1024];
  200.                                         cry_sprintf(sFileData, "<MiniMap Filename=\"%.5d.%s\" startX=\"%f\" startY=\"%f\" endX=\"%f\" endY=\"%f\"/>",
  201.                                                     m_nFileId, szExtension, fTLX, fTLY, fBRX, fBRY);
  202.                                         string data(sFileData);
  203.                                         gEnv->pCryPak->FWrite(data.c_str(), data.size(), metaFile);
  204.                                         gEnv->pCryPak->FClose(metaFile);
  205.                                 }
  206.                         }
  207.                 }
  208.  
  209.                 return bOk;
  210.         }
  211.  
  212.         // rasterize rectangle
  213.         // Arguments:
  214.         //   x0 - <x1, including
  215.         //   y0 - <y1, including
  216.         //   x1 - >x0, excluding
  217.         //   y1 - >y0, excluding
  218.         void RasterizeRect(const uint32* pRGBAImage,
  219.                            const uint32 dwWidth,
  220.                            const uint32 dwHeight,
  221.                            const uint32 dwSliceX,
  222.                            const uint32 dwSliceY,
  223.                            const f32 fTransitionSize,
  224.                            const bool bFadeBordersX,
  225.                            const bool bFadeBordersY)
  226.         {
  227.                 //              if(bFadeBordersX|bFadeBordersY)
  228.                 {
  229.                         //calculate rect inside the whole image
  230.                         const int32 OrgX0 = static_cast<int32>(static_cast<f32>((dwSliceX * dwWidth) * m_dwWidth) * m_fInvVirtualWidth);
  231.                         const int32 OrgY0 = static_cast<int32>(static_cast<f32>((dwSliceY * dwHeight) * m_dwHeight) * m_fInvVirtualHeight);
  232.                         const int32 OrgX1 = min(static_cast<int32>(static_cast<f32>(((dwSliceX + 1) * dwWidth) * m_dwWidth) * m_fInvVirtualWidth), static_cast<int32>(m_dwWidth)) - (m_rEngine.GetCVars()->e_ScreenShotDebug == 1 ? 1 : 0);
  233.                         const int32 OrgY1 = min(static_cast<int32>(static_cast<f32>(((dwSliceY + 1) * dwHeight) * m_dwHeight) * m_fInvVirtualHeight), static_cast<int32>(m_dwHeight)) - (m_rEngine.GetCVars()->e_ScreenShotDebug == 1 ? 1 : 0);
  234.                         //expand bounds for borderblending
  235.                         const int32 CenterX = (OrgX0 + OrgX1) / 2;
  236.                         const int32 CenterY = (OrgY0 + OrgY1) / 2;
  237.                         const int32 X0 = static_cast<int32>(static_cast<f32>(OrgX0 - CenterX) * (1.f + fTransitionSize)) + CenterX;
  238.                         const int32 Y0 = static_cast<int32>(static_cast<f32>(OrgY0 - CenterY) * (1.f + fTransitionSize)) + CenterY;
  239.                         const int32 X1 = static_cast<int32>(static_cast<f32>(OrgX1 - CenterX) * (1.f + fTransitionSize)) + CenterX;
  240.                         const int32 Y1 = static_cast<int32>(static_cast<f32>(OrgY1 - CenterY) * (1.f + fTransitionSize)) + CenterY;
  241.                         //clip bounds -- disabled due to some artifacts on edges
  242.                         //X0    =       min(max(X0,0),static_cast<int32>(m_dwWidth-1));
  243.                         //Y0    =       min(max(Y0,0),static_cast<int32>(m_dwHeight-1));
  244.                         //X1    =       min(max(X1,0),static_cast<int32>(m_dwWidth-1));
  245.                         //Y1    =       min(max(Y1,0),static_cast<int32>(m_dwHeight-1));
  246.                         const f32 InvBlendX = 1.f / max(static_cast<f32>(X1 - OrgX1), 0.01f);//0.5 is here because the border is two times wider then the border of the single segment in total
  247.                         const f32 InvBlendY = 1.f / max(static_cast<f32>(Y1 - OrgY1), 0.01f);
  248.                         const int32 DebugScale = (m_rEngine.GetCVars()->e_ScreenShotDebug == 2) ? 65536 : 0;
  249.                         for (int32 y = max(Y0, 0); y < Y1 && y < (int)m_dwHeight; y++)
  250.                         {
  251.                                 const f32 WeightY = bFadeBordersY ? min(1.f, static_cast<f32>(min(y - Y0, Y1 - y)) * InvBlendY) : 1.f;
  252.                                 for (int32 x = max(X0, 0); x < X1 && x < (int)m_dwWidth; x++)
  253.                                 {
  254.                                         uint8* pDst = &m_RGB[m_bFlipY ? 3 * (x + (m_dwHeight - y - 1) * m_dwWidth) : 3 * (x + y * m_dwWidth)];
  255.                                         const f32 WeightX = bFadeBordersX ? min(1.f, static_cast<f32>(min(x - X0, X1 - x)) * InvBlendX) : 1.f;
  256.                                         GetBilinearFilteredBlend(static_cast<int32>(static_cast<f32>(x - X0) / static_cast<f32>(X1 - X0) * static_cast<f32>(dwWidth) * 16.f),
  257.                                                                  static_cast<int32>(static_cast<f32>(y - Y0) / static_cast<f32>(Y1 - Y0) * static_cast<f32>(dwHeight) * 16.f),
  258.                                                                  pRGBAImage, dwWidth, dwHeight,
  259.                                                                  max(static_cast<int32>(WeightX * WeightY * 65536.f), DebugScale), pDst);
  260.                                 }
  261.                         }
  262.                 }
  263.                 /*              else
  264.                    {
  265.                    const int32 X0       =       static_cast<int32>(static_cast<f32>((dwSliceX*dwWidth)*m_dwWidth)*m_fInvVirtualWidth);
  266.                    const int32 Y0       =       static_cast<int32>(static_cast<f32>((dwSliceY*dwHeight)*m_dwHeight)*m_fInvVirtualHeight);
  267.                    const int32 X1       =       min(static_cast<int32>(static_cast<f32>(((dwSliceX+1)*dwWidth)*m_dwWidth)*m_fInvVirtualWidth),static_cast<int32>(m_dwWidth))-(m_rEngine.GetCVars()->e_ScreenShotDebug==1?1:0);
  268.                    const int32 Y1       =       min(static_cast<int32>(static_cast<f32>(((dwSliceY+1)*dwHeight)*m_dwHeight)*m_fInvVirtualHeight),static_cast<int32>(m_dwHeight))-(m_rEngine.GetCVars()->e_ScreenShotDebug==1?1:0);
  269.                    for(int32 y=Y0;y<Y1;y++)
  270.                    for(int32 x=X0;x<X1;x++)
  271.                    {
  272.                    uint8 *pDst = &m_RGB[m_bFlipY?3*(x+(m_dwHeight-y-1)*m_dwWidth):3*(x+y*m_dwWidth)];
  273.                    GetBilinearFiltered(static_cast<int32>(static_cast<f32>(x*m_dwVirtualWidth*16)*m_fInvWidth)-((dwSliceX*dwWidth)*16),
  274.                    static_cast<int32>(static_cast<f32>(y*m_dwVirtualHeight*16)*m_fInvHeight)-((dwSliceY*dwHeight)*16),
  275.                    pRGBAImage,dwWidth,dwHeight,pDst);
  276.                    }
  277.                    }*/
  278.         }
  279.  
  280.         void RasterizeCylinder(const uint32* pRGBAImage,
  281.                                const uint32 dwWidth,
  282.                                const uint32 dwHeight,
  283.                                const uint32 dwSlice,
  284.                                const bool bFadeBorders)
  285.         {
  286.                 float fSrcAngleMin = GetSliceAngle(dwSlice - 1);
  287.                 float fFractionVert = tanf(m_fPanoramaShotVertFOV * 0.5f);
  288.                 float fFractionHoriz = fFractionVert * gEnv->pRenderer->GetCamera().GetProjRatio();
  289.                 float fInvFractionHoriz = 1.0f / fFractionHoriz;
  290.  
  291.                 // for soft transition
  292.                 float fFadeOutFov = GetHorizFOVWithBorder();
  293.                 float fFadeInFov = GetHorizFOV();
  294.  
  295.                 int x0 = 0, y0 = 0, x1 = m_dwWidth, y1 = m_dwHeight;
  296.  
  297.                 float fScaleX = 1.0f / m_dwWidth;
  298.                 float fScaleY = 0.5f * fInvFractionHoriz / (m_dwWidth / (2 * gf_PI)) / dwHeight * dwWidth;                // this value is not correctly computed yet - but using many slices reduced the problem
  299.  
  300.                 if (m_bFlipY)
  301.                         fScaleY = -fScaleY;
  302.  
  303.                 // it's more efficient to process colums than lines
  304.                 for (int x = x0; x < x1; ++x)
  305.                 {
  306.                         uint8* pDst = &m_RGB[3 * (x + y0 * m_dwWidth)];
  307.                         float fSrcX = x * fScaleX - 0.5f;   // -0.5 .. 0.5
  308.                         float fSrcAngleX = fSrcAngleMin + 2 * gf_PI * fSrcX;
  309.  
  310.                         if (fSrcAngleX > gf_PI)
  311.                                 fSrcAngleX -= 2 * gf_PI;
  312.                         if (fSrcAngleX < -gf_PI)
  313.                                 fSrcAngleX += 2 * gf_PI;
  314.  
  315.                         if (fabs(fSrcAngleX) > fFadeOutFov * 0.5f)
  316.                                 continue;                             // clip away curved parts of the barrel
  317.  
  318.                         float fScrPosX = (tanf(fSrcAngleX) * 0.5f * fInvFractionHoriz + 0.5f) * dwWidth;
  319.                         //                      float fInvCosSrcX = 1.0f / cos(fSrcAngleX);
  320.                         float fInvCosSrcX = 1.0f / cosf(fSrcAngleX);
  321.  
  322.                         if (fScrPosX >= 0 && fScrPosX <= (float)dwWidth)   // this is an optimization - but it could be done even more efficient
  323.                                 if (fInvCosSrcX > 0)                             // don't render the viewer opposing direction
  324.                                 {
  325.                                         int iSrcPosX16 = (int)(fScrPosX * 16.0f);
  326.  
  327.                                         float fYOffset = 16 * 0.5f * dwHeight - 16 * 0.5f * m_dwHeight * fScaleY * fInvCosSrcX * dwHeight;
  328.                                         float fYMul = 16 * fScaleY * fInvCosSrcX * dwHeight;
  329.  
  330.                                         float fSrcY = y0 * fYMul + fYOffset;
  331.  
  332.                                         uint32 dwLerp64k = 256 * 256 - 1;
  333.  
  334.                                         if (!bFadeBorders)
  335.                                         {
  336.                                                 // first pass - every second image without soft borders
  337.                                                 for (int y = y0; y < y1; ++y, fSrcY += fYMul, pDst += m_dwWidth * 3)
  338.                                                         GetBilinearFiltered(iSrcPosX16, (int)fSrcY, pRGBAImage, dwWidth, dwHeight, pDst);
  339.                                         }
  340.                                         else
  341.                                         {
  342.                                                 // second pass - do all the inbetween with soft borders
  343.                                                 float fOffSlice = fabs(fSrcAngleX / fFadeInFov) - 0.5f;
  344.  
  345.                                                 if (fOffSlice < 0)
  346.                                                         fOffSlice = 0;      // no transition in this area
  347.  
  348.                                                 float fBorder = (fFadeOutFov - fFadeInFov) * 0.5f;
  349.  
  350.                                                 if (fBorder < 0.001f)
  351.                                                         fBorder = 0.001f;   // we do not have border
  352.  
  353.                                                 float fFade = 1.0f - fOffSlice * fFadeInFov / fBorder;
  354.  
  355.                                                 if (fFade < 0.0f)
  356.                                                         fFade = 0.0f;       // don't use this slice here
  357.  
  358.                                                 dwLerp64k = (uint32)(fFade * (256.0f * 256.0f - 1.0f));   // 0..64k
  359.  
  360.                                                 if (dwLerp64k)                             // optimization
  361.                                                         for (int y = y0; y < y1; ++y, fSrcY += fYMul, pDst += m_dwWidth * 3)
  362.                                                                 GetBilinearFilteredBlend(iSrcPosX16, (int)fSrcY, pRGBAImage, dwWidth, dwHeight, dwLerp64k, pDst);
  363.                                         }
  364.                                 }
  365.                 }
  366.         }
  367.  
  368.         // fast, rgb only
  369.         static inline ColorB lerp(const ColorB x, const ColorB y, const uint32 a, const uint32 dwBase)
  370.         {
  371.                 const int32 b = dwBase - a;
  372.                 const int32 RC = dwBase / 2; //rounding correction
  373.  
  374.                 return ColorB(((int)x.r * b + (int)y.r * a + RC) / dwBase,
  375.                               ((int)x.g * b + (int)y.g * a + RC) / dwBase,
  376.                               ((int)x.b * b + (int)y.b * a + RC) / dwBase);
  377.         }
  378.  
  379.         static inline ColorB Mul(const ColorB x, const int32 a, const int32 dwBase)
  380.         {
  381.                 return ColorB(((int)x.r * (int)a) / dwBase,
  382.                               ((int)x.g * (int)a) / dwBase,
  383.                               ((int)x.b * (int)a) / dwBase);
  384.         }
  385.         static inline ColorB MadSaturate(const ColorB x, const int32 a, const int32 dwBase, const ColorB y)
  386.         {
  387.                 const int32 MAX_COLOR = 0xff;
  388.                 const ColorB PreMuled = Mul(x, a, dwBase);
  389.                 return ColorB(min((int)PreMuled.r + (int)y.r, MAX_COLOR),
  390.                               min((int)PreMuled.g + (int)y.g, MAX_COLOR),
  391.                               min((int)PreMuled.b + (int)y.b, MAX_COLOR));
  392.         }
  393.  
  394.         // bilinear filtering in fixpoint,
  395.         // 4bit fractional part -> multiplier 16
  396.         // --lookup outside of the image is not defined
  397.         //      lookups outside the image are now clamped, needed due to some float inaccuracy while rasterizing a rect-screenshot
  398.         // Arguments:
  399.         //   iX16 - fX mul 16
  400.         //   iY16 - fY mul 16
  401.         //   result - [0]=red, [1]=green, [2]=blue
  402.         static inline bool GetBilinearFilteredRaw(const int iX16, const int iY16,
  403.                                                   const uint32* pRGBAImage,
  404.                                                   const uint32 dwWidth, const uint32 dwHeight,
  405.                                                   ColorB& result)
  406.         {
  407.                 int iLocalX = min(max(iX16 / 16, 0), static_cast<int>(dwWidth - 1));
  408.                 int iLocalY = min(max(iY16 / 16, 0), static_cast<int>(dwHeight - 1));
  409.  
  410.                 int iLerpX = iX16 & 0xf;      // 0..15
  411.                 int iLerpY = iY16 & 0xf;      // 0..15
  412.  
  413.                 ColorB colS[4];
  414.  
  415.                 const uint32* pRGBA = &pRGBAImage[iLocalX + iLocalY * dwWidth];
  416.  
  417.                 colS[0] = pRGBA[0];
  418.                 colS[1] = pRGBA[1];
  419.                 colS[2] = pRGBA[iLocalY + 1uL < dwHeight ? dwWidth : 0];
  420.                 colS[3] = pRGBA[(iLocalX + 1uL < dwWidth ? 1 : 0) + (iLocalY + 1uL < dwHeight ? dwWidth : 0)];
  421.  
  422.                 ColorB colTop, colBottom;
  423.  
  424.                 colTop = lerp(colS[0], colS[1], iLerpX, 16);
  425.                 colBottom = lerp(colS[2], colS[3], iLerpX, 16);
  426.  
  427.                 result = lerp(colTop, colBottom, iLerpY, 16);
  428.                 return true;
  429.         }
  430.  
  431.         // blend with background
  432.         static inline bool GetBilinearFiltered(const int iX16, const int iY16,
  433.                                                const uint32* pRGBAImage,
  434.                                                const uint32 dwWidth, const uint32 dwHeight,
  435.                                                uint8 result[3])
  436.         {
  437.                 ColorB colFiltered;
  438.                 if (GetBilinearFilteredRaw(iX16, iY16, pRGBAImage, dwWidth, dwHeight, colFiltered))
  439.                 {
  440.                         result[0] = colFiltered.r;
  441.                         result[1] = colFiltered.g;
  442.                         result[2] = colFiltered.b;
  443.                         return true;
  444.                 }
  445.                 return false;
  446.         }
  447.  
  448.         static inline bool GetBilinearFilteredBlend(const int iX16, const int iY16,
  449.                                                     const uint32* pRGBAImage,
  450.                                                     const uint32 dwWidth, const uint32 dwHeight,
  451.                                                     const uint32 dwLerp64k,
  452.                                                     uint8 result[3])
  453.         {
  454.                 ColorB colFiltered;
  455.                 if (GetBilinearFilteredRaw(iX16, iY16, pRGBAImage, dwWidth, dwHeight, colFiltered))
  456.                 {
  457.                         ColorB colRet = lerp(ColorB(result[0], result[1], result[2]), colFiltered, dwLerp64k, 256 * 256);
  458.  
  459.                         result[0] = colRet.r;
  460.                         result[1] = colRet.g;
  461.                         result[2] = colRet.b;
  462.                         return true;
  463.                 }
  464.                 return false;
  465.         }
  466.  
  467.         static inline bool GetBilinearFilteredAdd(const int iX16, const int iY16,
  468.                                                   const uint32* pRGBAImage,
  469.                                                   const uint32 dwWidth, const uint32 dwHeight,
  470.                                                   const uint32 dwLerp64k,
  471.                                                   uint8 result[3])
  472.         {
  473.                 ColorB colFiltered;
  474.                 if (GetBilinearFilteredRaw(iX16, iY16, pRGBAImage, dwWidth, dwHeight, colFiltered))
  475.                 {
  476.                         ColorB colRet = MadSaturate(colFiltered, dwLerp64k, 256 * 256, ColorB(result[0], result[1], result[2]));
  477.  
  478.                         result[0] = colRet.r;
  479.                         result[1] = colRet.g;
  480.                         result[2] = colRet.b;
  481.                         return true;
  482.                 }
  483.                 return false;
  484.         }
  485.  
  486.         float GetSliceAngle(const uint32 dwSlice) const
  487.         {
  488.                 uint32 dwAlternatingSlice = (dwSlice * 2) % m_dwSliceCount;
  489.  
  490.                 float fAngleStep = m_fHorizFOV;
  491.  
  492.                 float fRet = fAngleStep * dwAlternatingSlice;
  493.  
  494.                 if (dwSlice * 2 >= m_dwSliceCount)
  495.                         fRet += fAngleStep;
  496.  
  497.                 return fRet;
  498.         }
  499.  
  500.         float GetHorizFOV() const
  501.         {
  502.                 return m_fHorizFOV;
  503.         }
  504.  
  505.         float GetHorizFOVWithBorder() const
  506.         {
  507.                 return m_fHorizFOV * (1.0f + m_fTransitionSize);
  508.         }
  509.  
  510.         void*  GetBuffer() { return &m_RGB[0]; }
  511.         uint32 GetWidth()  { return m_dwWidth; }
  512.         uint32 GetHeight() { return m_dwHeight; }
  513.  
  514.         //private: // -------------------------------------------------------------------
  515.  
  516.         uint32             m_dwWidth;                       // >0
  517.         uint32             m_dwHeight;                      // >0
  518.         f32                m_fInvWidth;                     // >0
  519.         f32                m_fInvHeight;                    // >0
  520.         uint32             m_dwVirtualWidth;                // >0
  521.         uint32             m_dwVirtualHeight;               // >0
  522.         f32                m_fInvVirtualWidth;              // >0
  523.         f32                m_fInvVirtualHeight;             // >0
  524.         std::vector<uint8> m_RGB;                           // [channel + x*3 + m_dwWidth*3*y], channel=0..2, x<m_dwWidth, y<m_dwHeight, no alpha channel to occupy less memory
  525.         uint32             m_nFileId;                       // counts up until it finds free file id
  526.         bool               m_bFlipY;                        // might be useful for some image formats
  527.         bool               m_bMetaData;                     // output additional metadata
  528.  
  529.         float              m_fPanoramaShotVertFOV;          // -1 means not set yet - in radians
  530.  
  531. private:
  532.  
  533.         uint32     m_dwSliceCount;                          //
  534.         C3DEngine& m_rEngine;                               //
  535.         float      m_fHorizFOV;                             // - in radians
  536.         float      m_fTransitionSize;                       // [0..1], 0=no transition, 1.0=full transition
  537. };
  538. #endif
  539.  
  540. enum EScreenShotType
  541. {
  542.         ESST_NONE    = 0,
  543.         ESST_HIGHRES = 1,
  544.         ESST_PANORAMA,
  545.         ESST_MAP_DELAYED,
  546.         ESST_MAP,
  547.         ESST_SWMAP,
  548.         ESST_SWMAP_DELAYED,
  549. };
  550.  
  551. void C3DEngine::ScreenshotDispatcher(const int nRenderFlags, const SRenderingPassInfo& passInfo)
  552. {
  553. #if CRY_PLATFORM_WINDOWS
  554.         CStitchedImage* pStitchedImage = 0;
  555.         const uint32 dwPanWidth = max(1, GetCVars()->e_ScreenShotWidth);
  556.         const uint32 dwPanHeight = max(1, GetCVars()->e_ScreenShotHeight);
  557.         const f32 fTransitionSize = min(1.f, abs(GetCVars()->e_ScreenShotQuality) * 0.01f);
  558.         const uint32 MinSlices = max(max(1, GetCVars()->e_ScreenShotMinSlices),
  559.                                      max(static_cast<int>((dwPanWidth + GetRenderer()->GetWidth() - 1) / GetRenderer()->GetWidth()),
  560.                                          static_cast<int>((dwPanHeight + GetRenderer()->GetHeight() - 1) / GetRenderer()->GetHeight())));
  561.         const uint32 dwVirtualWidth = GetRenderer()->GetWidth() * MinSlices;
  562.         const uint32 dwVirtualHeight = GetRenderer()->GetHeight() * MinSlices;
  563.  
  564.         switch (abs(GetCVars()->e_ScreenShot))
  565.         {
  566.         case ESST_HIGHRES:
  567.                 GetConsole()->ShowConsole(false);
  568.                 pStitchedImage = new CStitchedImage(*this, dwPanWidth, dwPanHeight, dwVirtualWidth, dwVirtualHeight, MinSlices, fTransitionSize);
  569.                 ScreenShotHighRes(pStitchedImage, nRenderFlags, passInfo, MinSlices, fTransitionSize);
  570.                 pStitchedImage->SaveImage("HiRes");
  571.                 pStitchedImage->Clear();    // good for debugging
  572.                 delete pStitchedImage;
  573.                 if (GetCVars()->e_ScreenShot > 0)      // <0 is used for multiple frames (videos)
  574.                         GetCVars()->e_ScreenShot = 0;
  575.                 break;
  576.         case ESST_PANORAMA:
  577.                 GetConsole()->ShowConsole(false);
  578.                 pStitchedImage = new CStitchedImage(*this, dwPanWidth, dwPanHeight, dwVirtualWidth, dwVirtualHeight, MinSlices, fTransitionSize);
  579.                 ScreenShotPanorama(pStitchedImage, nRenderFlags, passInfo, MinSlices, fTransitionSize);
  580.                 pStitchedImage->SaveImage("Panorama");
  581.                 pStitchedImage->Clear();    // good for debugging
  582.                 delete pStitchedImage;
  583.                 if (GetCVars()->e_ScreenShot > 0)      // <0 is used for multiple frames (videos)
  584.                         GetCVars()->e_ScreenShot = 0;
  585.                 break;
  586.         case ESST_MAP_DELAYED:
  587.                 {
  588.                         GetCVars()->e_ScreenShot = sgn(GetCVars()->e_ScreenShot) * ESST_MAP;   // sgn() to keep sign bit , <0 is used for multiple frames (videos)
  589.                         if (CTerrain* const pTerrain = GetTerrain())
  590.                         {
  591.                                 pTerrain->ResetTerrainVertBuffers(NULL, GetDefSID());
  592.                         }
  593.                 }
  594.                 break;
  595.         case ESST_SWMAP_DELAYED:
  596.                 {
  597.                         GetCVars()->e_ScreenShot = sgn(GetCVars()->e_ScreenShot) * ESST_SWMAP;   // sgn() to keep sign bit , <0 is used for multiple frames (videos)
  598.                         if (CTerrain* const pTerrain = GetTerrain())
  599.                         {
  600.                                 pTerrain->ResetTerrainVertBuffers(NULL, GetDefSID());
  601.                         }
  602.                 }
  603.                 break;
  604.         case ESST_SWMAP:
  605.         case ESST_MAP:
  606.                 {
  607.                         static const unsigned int nMipMapSnapshotSize = 512;
  608.                         GetRenderer()->ChangeViewport(0, 0, nMipMapSnapshotSize, nMipMapSnapshotSize);
  609.                         uint32 TmpHeight, TmpWidth, TmpVirtualHeight, TmpVirtualWidth;
  610.                         TmpHeight = TmpWidth = TmpVirtualHeight = TmpVirtualWidth = 1;
  611.  
  612.                         while ((TmpHeight << 1) <= dwPanHeight)
  613.                         {
  614.                                 TmpHeight <<= 1;
  615.                         }
  616.                         while ((TmpWidth << 1) <= dwPanWidth)
  617.                         {
  618.                                 TmpWidth <<= 1;
  619.                         }
  620.                         const uint32 TmpMinSlices = max(max(1, GetCVars()->e_ScreenShotMinSlices),
  621.                                                         max(static_cast<int>((TmpWidth + nMipMapSnapshotSize - 1) / nMipMapSnapshotSize),
  622.                                                             static_cast<int>((TmpHeight + nMipMapSnapshotSize - 1) / nMipMapSnapshotSize)));
  623.                         while ((TmpVirtualHeight << 1) <= TmpMinSlices * nMipMapSnapshotSize)
  624.                         {
  625.                                 TmpVirtualHeight <<= 1;
  626.                         }
  627.                         while ((TmpVirtualWidth << 1) <= TmpMinSlices * nMipMapSnapshotSize)
  628.                         {
  629.                                 TmpVirtualWidth <<= 1;
  630.                         }
  631.  
  632.                         GetConsole()->ShowConsole(false);
  633.                         pStitchedImage = new CStitchedImage(*this, TmpWidth, TmpHeight, TmpVirtualWidth, TmpVirtualHeight, TmpMinSlices, fTransitionSize, true);
  634.                         ScreenShotMap(pStitchedImage, nRenderFlags, passInfo, TmpMinSlices, fTransitionSize);
  635.                         if (abs(GetCVars()->e_ScreenShot) == ESST_MAP)
  636.                                 pStitchedImage->SaveImage("Map");
  637.  
  638.                         if (m_pScreenshotCallback)
  639.                         {
  640.                                 const f32 fSizeX = GetCVars()->e_ScreenShotMapSizeX;
  641.                                 const f32 fSizeY = GetCVars()->e_ScreenShotMapSizeY;
  642.                                 const f32 fTLX = GetCVars()->e_ScreenShotMapCenterX - fSizeX;
  643.                                 const f32 fTLY = GetCVars()->e_ScreenShotMapCenterY - fSizeY;
  644.                                 const f32 fBRX = GetCVars()->e_ScreenShotMapCenterX + fSizeX;
  645.                                 const f32 fBRY = GetCVars()->e_ScreenShotMapCenterY + fSizeY;
  646.  
  647.                                 m_pScreenshotCallback->SendParameters(pStitchedImage->GetBuffer(), pStitchedImage->GetWidth(), pStitchedImage->GetHeight(), fTLX, fTLY, fBRX, fBRY);
  648.                         }
  649.  
  650.                         pStitchedImage->Clear();    // good for debugging
  651.                         delete pStitchedImage;
  652.                 }
  653.                 if (GetCVars()->e_ScreenShot > 0)      // <0 is used for multiple frames (videos)
  654.                         GetCVars()->e_ScreenShot = 0;
  655.  
  656.                 if (CTerrain* const pTerrain = GetTerrain())
  657.                 {
  658.                         pTerrain->ResetTerrainVertBuffers(NULL, GetDefSID());
  659.                 }
  660.                 break;
  661.         default:
  662.                 GetCVars()->e_ScreenShot = 0;
  663.         }
  664. #endif //#if CRY_PLATFORM_WINDOWS
  665. }
  666.  
  667. struct SDebugFrustrum
  668. {
  669.         Vec3        m_vPos[8];
  670.         const char* m_szName;
  671.         CTimeValue  m_TimeStamp;
  672.         ColorB      m_Color;
  673.         float       m_fQuadDist;        // < 0 if not used
  674. };
  675.  
  676. static std::vector<SDebugFrustrum> g_DebugFrustrums;
  677.  
  678. void C3DEngine::DebugDraw_Draw()
  679. {
  680. #ifndef _RELEASE
  681.         if (!gEnv->pRenderer)
  682.         {
  683.                 return;
  684.         }
  685.  
  686.         if (m_DebugDrawListMgr.IsEnabled())
  687.                 m_DebugDrawListMgr.Update();
  688.  
  689.         CTimeValue CurrentTime = gEnv->pTimer->GetFrameStartTime();
  690.  
  691.         IRenderAuxGeom* pAux = gEnv->pAuxGeomRenderer;
  692.  
  693.         SAuxGeomRenderFlags oldFlags = pAux->GetRenderFlags();
  694.         SAuxGeomRenderFlags newFlags;
  695.         newFlags.SetAlphaBlendMode(e_AlphaBlended);
  696.         newFlags.SetCullMode(e_CullModeNone);
  697.         newFlags.SetDepthWriteFlag(e_DepthWriteOff);
  698.         pAux->SetRenderFlags(newFlags);
  699.         std::vector<SDebugFrustrum>::iterator it;
  700.  
  701.         for (it = g_DebugFrustrums.begin(); it != g_DebugFrustrums.end(); )
  702.         {
  703.                 SDebugFrustrum& ref = *it;
  704.  
  705.                 float fRatio = (CurrentTime - ref.m_TimeStamp).GetSeconds() * 2.0f;
  706.  
  707.                 if (fRatio > 1.0f)
  708.                 {
  709.                         it = g_DebugFrustrums.erase(it);
  710.                         continue;
  711.                 }
  712.  
  713.                 vtx_idx pnInd[8] = { 0, 4, 1, 5, 2, 6, 3, 7 };
  714.  
  715.                 float fRadius = ((ref.m_vPos[0] + ref.m_vPos[1] + ref.m_vPos[2] + ref.m_vPos[3]) - (ref.m_vPos[4] + ref.m_vPos[5] + ref.m_vPos[6] + ref.m_vPos[7])).GetLength() * 0.25f;
  716.                 float fDistance = min(fRadius, 33.0f);   // in meters
  717.  
  718.                 float fRenderRatio = fRatio * fDistance / fRadius;
  719.  
  720.                 if (ref.m_fQuadDist > 0)
  721.                         fRenderRatio = ref.m_fQuadDist / fRadius;
  722.  
  723.                 Vec3 vPos[4];
  724.  
  725.                 for (uint32 i = 0; i < 4; ++i)
  726.                         vPos[i] = ref.m_vPos[i] * fRenderRatio + ref.m_vPos[i + 4] * (1.0f - fRenderRatio);
  727.  
  728.                 Vec3 vMid = (vPos[0] + vPos[1] + vPos[2] + vPos[3]) * 0.25f;
  729.  
  730.                 ColorB col = ref.m_Color;
  731.  
  732.                 if (ref.m_fQuadDist <= 0)
  733.                 {
  734.                         for (uint32 i = 0; i < 4; ++i)
  735.                                 vPos[i] = vPos[i] * 0.95f + vMid * 0.05f;
  736.  
  737.                         // quad
  738.                         if (ref.m_fQuadDist != -999.f)
  739.                         {
  740.                                 pAux->DrawTriangle(vPos[0], col, vPos[2], col, vPos[1], col);
  741.                                 pAux->DrawTriangle(vPos[2], col, vPos[0], col, vPos[3], col);
  742.                         }
  743.                         // projection lines
  744.                         pAux->DrawLines(ref.m_vPos, 8, pnInd, 2, RGBA8(0xff, 0xff, 0x1f, 0xff));
  745.                         pAux->DrawLines(ref.m_vPos, 8, pnInd + 2, 2, RGBA8(0xff, 0xff, 0x1f, 0xff));
  746.                         pAux->DrawLines(ref.m_vPos, 8, pnInd + 4, 2, RGBA8(0xff, 0xff, 0x1f, 0xff));
  747.                         pAux->DrawLines(ref.m_vPos, 8, pnInd + 6, 2, RGBA8(0xff, 0xff, 0x1f, 0xff));
  748.                 }
  749.                 else
  750.                 {
  751.                         // rectangle
  752.                         pAux->DrawPolyline(vPos, 4, true, RGBA8(0xff, 0xff, 0x1f, 0xff));
  753.                 }
  754.  
  755.                 ++it;
  756.         }
  757.  
  758.         pAux->SetRenderFlags(oldFlags);
  759.  
  760.         if (GetCVars()->e_DebugDraw == 16)
  761.         {
  762.                 DebugDraw_UpdateDebugNode();
  763.         }
  764.         else if (GetRenderer())
  765.         {
  766.                 GetRenderer()->SetDebugRenderNode(NULL);
  767.         }
  768.  
  769. #endif //_RELEASE
  770. }
  771.  
  772. void C3DEngine::DebugDraw_UpdateDebugNode()
  773. {
  774. #ifndef _RELEASE
  775.  
  776.         ray_hit rayHit;
  777.  
  778.         // use cam, no need for firing pos/dir
  779.         CCamera& cam = GetISystem()->GetViewCamera();
  780.         const unsigned int flags = rwi_stop_at_pierceable | rwi_colltype_any;
  781.         const float hitRange = 2000.f;
  782.  
  783.         if (gEnv->pPhysicalWorld->RayWorldIntersection(cam.GetPosition() + cam.GetViewdir(), cam.GetViewdir() * hitRange, ent_all, flags, &rayHit, 1))
  784.         {
  785.                 int type = rayHit.pCollider->GetiForeignData();
  786.  
  787.                 if (type == PHYS_FOREIGN_ID_STATIC)
  788.                 {
  789.                         IRenderNode* pRenderNode = (IRenderNode*)rayHit.pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC);
  790.  
  791.                         if (pRenderNode)
  792.                         {
  793.                                 gEnv->pRenderer->SetDebugRenderNode(pRenderNode);
  794.  
  795.                                 //CryLogAlways( "Hit: %s, ipart: %d, partid: %d, surafce_idx: %d, iNode: %d, \n",
  796.                                 //pRenderNode->GetName(), rayHit.ipart, rayHit.partid, rayHit.surface_idx, rayHit.iNode);
  797.                         }
  798.                 }
  799.                 else if (type == PHYS_FOREIGN_ID_ENTITY)
  800.                 {
  801.                         IEntity* pEntity = (IEntity*)rayHit.pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY);
  802.  
  803.                         if (pEntity)
  804.                         {
  805.                                 IEntityRender* pIEntityRender = pEntity->GetRenderInterface();
  806.  
  807.                                
  808.                                 {
  809.                                         IRenderNode* pRenderNode = pIEntityRender->GetRenderNode();
  810.  
  811.                                         if (pRenderNode)
  812.                                         {
  813.                                                 gEnv->pRenderer->SetDebugRenderNode(pRenderNode);
  814.  
  815.                                                 //CryLogAlways( "Hit: %s(0x%p), ipart: %d, partid: %d, surafce_idx: %d, iNode: %d, \n",
  816.                                                 //pRenderNode->GetName(), pRenderNode, rayHit.ipart, rayHit.partid, rayHit.surface_idx, rayHit.iNode);
  817.                                         }
  818.                                 }
  819.                         }
  820.                 }
  821.         }
  822. #endif //_RELEASE
  823. }
  824.  
  825. void C3DEngine::RenderWorld(const int nRenderFlags, const SRenderingPassInfo& passInfo, const char* szDebugName)
  826. {
  827.         CRY_PROFILE_REGION(PROFILE_3DENGINE, "3DEngine: RenderWorld");
  828.         CRYPROFILE_SCOPE_PROFILE_MARKER("RenderWorld");
  829.  
  830. #if defined(FEATURE_SVO_GI)
  831.         if (passInfo.IsGeneralPass() && (nRenderFlags & SHDF_ALLOW_AO))
  832.                 CSvoManager::OnFrameStart(passInfo);
  833. #endif
  834.  
  835.         passInfo.GetIRenderView()->SetShaderRenderingFlags(nRenderFlags);
  836.  
  837.         if (passInfo.IsGeneralPass())
  838.         {
  839.                 if (m_szLevelFolder[0] != 0)
  840.                 {
  841.                         m_nFramesSinceLevelStart++;
  842.                 }
  843.         }
  844.  
  845.         assert(szDebugName);
  846.  
  847.         if (!GetCVars()->e_Render)
  848.                 return;
  849.  
  850.         IF (!m_bEditor && (m_bInShutDown || m_bInUnload) && !GetRenderer()->IsPost3DRendererEnabled(), 0)
  851.         {
  852.                 // Do not render during shutdown/unloading (should never reach here, unless something wrong with game/editor code)
  853.                 return;
  854.         }
  855.  
  856. #ifdef ENABLE_LW_PROFILERS
  857.         int64 renderStart = CryGetTicks();
  858. #endif
  859.  
  860.         if (passInfo.IsGeneralPass())
  861.         {
  862.                 if (GetCVars()->e_ScreenShot)
  863.                 {
  864.                         ScreenshotDispatcher(nRenderFlags, passInfo);
  865.                         // screenshots can mess up the frame ids, be safe and recreate the rendering passinfo object after a screenshot
  866.                         const_cast<SRenderingPassInfo&>(passInfo) = SRenderingPassInfo::CreateGeneralPassRenderingInfo(passInfo.GetCamera());
  867.                 }
  868.  
  869.                 if (GetCVars()->e_DefaultMaterial)
  870.                 {
  871.                         _smart_ptr<IMaterial> pMat = GetMaterialManager()->LoadMaterial("EngineAssets/Materials/material_default");
  872.                         _smart_ptr<IMaterial> pTerrainMat = GetMaterialManager()->LoadMaterial("EngineAssets/Materials/material_terrain_default");
  873.                         GetRenderer()->SetDefaultMaterials(pMat, pTerrainMat);
  874.                 }
  875.                 else
  876.                         GetRenderer()->SetDefaultMaterials(NULL, NULL);
  877.         }
  878.  
  879.         // skip rendering if camera is invalid
  880.         if (IsCameraAnd3DEngineInvalid(passInfo, szDebugName))
  881.                 return;
  882.  
  883.         // update camera 3d engine uses for rendering
  884.         if (passInfo.IsGeneralPass())
  885.         {
  886.                 // this will also set the camera in passInfo for the General Pass (done here to support e_camerafreeze)
  887.                 UpdateRenderingCamera(szDebugName, passInfo);
  888.         }
  889.  
  890.         if (passInfo.IsGeneralPass())
  891.         {
  892.                 // Update visible nodes, do it at the beginning of the rendering to avoid running in parallel with using visible nodes for rendering
  893.                 if (m_bResetRNTmpDataPool)
  894.                 {
  895.                         m_visibleNodesManager.InvalidateAll();
  896.                         m_bResetRNTmpDataPool = false;
  897.                 }
  898.                 m_visibleNodesManager.UpdateVisibleNodes(passInfo.GetFrameID());
  899.         }
  900.  
  901.         RenderInternal(nRenderFlags, passInfo, szDebugName);
  902.  
  903. #ifdef SEG_WORLD
  904.         if (GetISystem()->GetIConsole()->GetCVar("sw_debugInfo")->GetIVal() == 4)
  905.         {
  906.                 f32 fColor[4] = { 1, 1, 0, 1 };
  907.  
  908.                 float fYLine = 8.0f, fYStep = 20.0f;
  909.  
  910.                 GetRenderer()->Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "sw_debugInfo = 4\n"
  911.                                                                                         "Green are normal ones, Red are global ones, Blue are those cross different segs");
  912.         }
  913. #endif //SEG_WORLD
  914.  
  915.         IF (GetCVars()->e_DebugDraw, 0)
  916.         {
  917.                 f32 fColor[4] = { 1, 1, 0, 1 };
  918.  
  919.                 float fYLine = 8.0f, fYStep = 20.0f;
  920.  
  921.                 IRenderAuxText::Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "e_DebugDraw = %d", GetCVars()->e_DebugDraw);
  922.  
  923.                 char* szMode = "";
  924.  
  925.                 switch (GetCVars()->e_DebugDraw)
  926.                 {
  927.                 case  -1:
  928.                         szMode = "Showing bounding boxes";
  929.                         break;
  930.                 case  1:
  931.                         szMode = "bounding boxes, name of the used cgf, polycount, used LOD";
  932.                         break;
  933.                 case  -2:
  934.                 case  2:
  935.                         szMode = "color coded polygon count(red,yellow,green,turqoise, blue)";
  936.                         break;
  937.                 case  -3:
  938.                         szMode = "show color coded LODs count, flashing color indicates LOD.";
  939.                         break;
  940.                 case  3:
  941.                         szMode = "show color coded LODs count, flashing color indicates LOD.\nFormat: (Current LOD [Min LOD; Max LOD] (LOD Ratio / Distance to camera)";
  942.                         break;
  943.                 case  -4:
  944.                 case  4:
  945.                         szMode = "object texture memory usage in KB";
  946.                         break;
  947.                 case  -5:
  948.                 case  5:
  949.                         szMode = "number of render materials (color coded)";
  950.                         break;
  951.                 case  6:
  952.                         szMode = "ambient color (R,G,B,A)";
  953.                         break;
  954.                 case  7:
  955.                         szMode = "triangle count, number of render materials, texture memory in KB";
  956.                         break;
  957.                 case  8:
  958.                         szMode = "Free slot";
  959.                         break;
  960.                 case  9:
  961.                         szMode = "Free slot";
  962.                         break;
  963.                 case 10:
  964.                         szMode = "Deprecated option, use \"r_showlines 2\" instead";
  965.                         break;
  966.                 case 11:
  967.                         szMode = "Free slot";
  968.                         break;
  969.                 case 12:
  970.                         szMode = "Free slot";
  971.                         break;
  972.                 case 13:
  973.                         szMode = "occlusion amount (used during AO computations)";
  974.                         break;
  975.                 //                      case 14:        szMode="";break;
  976.                 case 15:
  977.                         szMode = "display helpers";
  978.                         break;
  979.                 case 16:
  980.                         szMode = "Debug Gun";
  981.                         break;
  982.                 case 17:
  983.                         szMode = "streaming: buffer sizes (black: geometry, blue: texture)";
  984.                         if (gEnv->pLocalMemoryUsage) gEnv->pLocalMemoryUsage->OnRender(GetRenderer(), &passInfo.GetCamera());
  985.                         break;
  986.                 case 18:
  987.                         szMode = "Free slot";
  988.                         break;
  989.                 case 19:
  990.                         szMode = "physics proxy triangle count";
  991.                         break;
  992.                 case 20:
  993.                         szMode = "Character attachments texture memory usage";
  994.                         break;
  995.                 case 21:
  996.                         szMode = "Display animated objects distance to camera";
  997.                         break;
  998.                 case -22:
  999.                 case 22:
  1000.                         szMode = "object's current LOD vertex count";
  1001.                         break;
  1002.  
  1003.                 default:
  1004.                         assert(0);
  1005.                 }
  1006.  
  1007.                 IRenderAuxText::Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "   %s", szMode);
  1008.  
  1009.                 if (GetCVars()->e_DebugDraw == 17)
  1010.                 {
  1011.                         IRenderAuxText::Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "   StatObj geometry used: %.2fMb / %dMb", CObjManager::s_nLastStreamingMemoryUsage / (1024.f * 1024.f), GetCVars()->e_StreamCgfPoolSize);
  1012.  
  1013.                         ICVar* cVar = GetConsole()->GetCVar("r_TexturesStreaming");
  1014.                         if (!cVar || !cVar->GetIVal())
  1015.                         {
  1016.                                 IRenderAuxText::Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "   You have to set r_TexturesStreaming = 1 to see texture information!");
  1017.                         }
  1018.                 }
  1019.         }
  1020.  
  1021. #if !defined(_RELEASE)
  1022.         PrintDebugInfo(passInfo);
  1023. #endif
  1024. }
  1025.  
  1026. void C3DEngine::PreWorldStreamUpdate(const CCamera& cam)
  1027. {
  1028.         const int nGlobalSystemState = gEnv->pSystem->GetSystemGlobalState();
  1029.         if (nGlobalSystemState == ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_END)
  1030.         {
  1031.                 ClearPrecacheInfo();
  1032.         }
  1033.  
  1034.         if (m_szLevelFolder[0] != 0 && (nGlobalSystemState > ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_END))
  1035.         {
  1036.                 m_nStreamingFramesSinceLevelStart++;
  1037.         }
  1038.  
  1039.         // force preload terrain data if camera was teleported more than 32 meters
  1040.         if (GetRenderer() && (!IsAreaActivationInUse() || m_bLayersActivated))
  1041.         {
  1042.                 float fDistance = m_vPrevMainFrameCamPos.GetDistance(cam.GetPosition());
  1043.  
  1044.                 if (m_vPrevMainFrameCamPos != Vec3(-1000000.f, -1000000.f, -1000000.f))
  1045.                 {
  1046.                         m_vAverageCameraMoveDir = m_vAverageCameraMoveDir * .75f + (cam.GetPosition() - m_vPrevMainFrameCamPos) / max(0.01f, GetTimer()->GetFrameTime()) * .25f;
  1047.                         if (m_vAverageCameraMoveDir.GetLength() > 10.f)
  1048.                                 m_vAverageCameraMoveDir.SetLength(10.f);
  1049.  
  1050.                         float fNewSpeed = fDistance / max(0.001f, gEnv->pTimer->GetFrameTime());
  1051.                         if (fNewSpeed > m_fAverageCameraSpeed)
  1052.                                 m_fAverageCameraSpeed = fNewSpeed * .20f + m_fAverageCameraSpeed * .80f;
  1053.                         else
  1054.                                 m_fAverageCameraSpeed = fNewSpeed * .02f + m_fAverageCameraSpeed * .98f;
  1055.                         m_fAverageCameraSpeed = CLAMP(m_fAverageCameraSpeed, 0, 10.f);
  1056.                 }
  1057.  
  1058.                 // Adjust streaming mip bias based on camera speed and depending on installed on HDD or not
  1059.                 bool bStreamingFromHDD = gEnv->pSystem->GetStreamEngine()->IsStreamDataOnHDD();
  1060.                 if (GetCVars()->e_StreamAutoMipFactorSpeedThreshold)
  1061.                 {
  1062.                         if (m_fAverageCameraSpeed > GetCVars()->e_StreamAutoMipFactorSpeedThreshold)
  1063.                                 GetRenderer()->SetTexturesStreamingGlobalMipFactor(bStreamingFromHDD ? GetCVars()->e_StreamAutoMipFactorMax * .5f : GetCVars()->e_StreamAutoMipFactorMax);
  1064.                         else
  1065.                                 GetRenderer()->SetTexturesStreamingGlobalMipFactor(bStreamingFromHDD ? GetCVars()->e_StreamAutoMipFactorMin * .5f : GetCVars()->e_StreamAutoMipFactorMin);
  1066.                 }
  1067.                 else
  1068.                 {
  1069.                         if (bStreamingFromHDD)
  1070.                                 GetRenderer()->SetTexturesStreamingGlobalMipFactor(0);
  1071.                         else
  1072.                                 GetRenderer()->SetTexturesStreamingGlobalMipFactor(GetCVars()->e_StreamAutoMipFactorMaxDVD);
  1073.                 }
  1074.  
  1075.                 if (GetCVars()->e_AutoPrecacheCameraJumpDist && fDistance > GetCVars()->e_AutoPrecacheCameraJumpDist)
  1076.                 {
  1077.                         m_bContentPrecacheRequested = true;
  1078.                         m_bResetRNTmpDataPool = true;
  1079.  
  1080.                         // Invalidate existing precache info
  1081.                         m_pObjManager->m_nUpdateStreamingPrioriryRoundIdFast += 8;
  1082.                         m_pObjManager->m_nUpdateStreamingPrioriryRoundId += 8;
  1083.                 }
  1084.  
  1085.                 m_vPrevMainFrameCamPos = cam.GetPosition();
  1086.         }
  1087. }
  1088.  
  1089. void C3DEngine::WorldStreamUpdate()
  1090. {
  1091. #if defined(STREAMENGINE_ENABLE_STATS)
  1092.         static uint32 nCurrentRequestCount = 0;
  1093.         static uint64 nCurrentBytesRead = 0;
  1094.         if (m_nStreamingFramesSinceLevelStart == 1)
  1095.         {
  1096.                 // store current streaming stats
  1097.                 SStreamEngineStatistics& fullStats = gEnv->pSystem->GetStreamEngine()->GetStreamingStatistics();
  1098.                 nCurrentBytesRead = fullStats.nTotalBytesRead;
  1099.                 nCurrentRequestCount = fullStats.nTotalRequestCount;
  1100.         }
  1101. #endif
  1102.  
  1103.         static float fTestStartTime = 0;
  1104.         if (m_nStreamingFramesSinceLevelStart == 1)
  1105.         {
  1106.                 fTestStartTime = GetCurAsyncTimeSec();
  1107.                 gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_FIRST_FRAME, 0, 0);
  1108.         }
  1109.  
  1110.         // Simple streaming performance test: Wait until all startup texture streaming jobs finish and print a message
  1111.         if (!m_bEditor)
  1112.         {
  1113.                 if (!m_bPreCacheEndEventSent)
  1114.                 {
  1115.                         IStreamEngine* pSE = gEnv->pSystem->GetStreamEngine();
  1116.                         SStreamEngineOpenStats openStats;
  1117.                         pSE->GetStreamingOpenStatistics(openStats);
  1118.                         bool bStarted =
  1119.                           (openStats.nOpenRequestCountByType[eStreamTaskTypeTexture] > 0) ||
  1120.                           (openStats.nOpenRequestCountByType[eStreamTaskTypeGeometry] > 0);
  1121.  
  1122.                         float fTime = GetCurAsyncTimeSec() - fTestStartTime;
  1123.  
  1124.                         switch (m_nStreamingFramesSinceLevelStart)
  1125.                         {
  1126.                         case 1:
  1127.                                 pSE->PauseStreaming(true, (1 << eStreamTaskTypeTexture) | (1 << eStreamTaskTypeGeometry));
  1128.                                 break;
  1129.                         case 4:
  1130.                                 pSE->PauseStreaming(false, (1 << eStreamTaskTypeGeometry));
  1131.                                 break;
  1132.                         case 8:
  1133.                                 pSE->PauseStreaming(false, (1 << eStreamTaskTypeTexture));
  1134.                                 break;
  1135.                         }
  1136.  
  1137.                         const int nGlobalSystemState = gEnv->pSystem->GetSystemGlobalState();
  1138.  
  1139.                         if (nGlobalSystemState == ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_END)
  1140.                         {
  1141.                                 gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_START, 0, 0);
  1142.  
  1143.                                 m_pSystem->SetThreadState(ESubsys_Physics, true);
  1144.  
  1145.                                 gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_ENDING);
  1146.                         }
  1147.  
  1148.                         if (nGlobalSystemState == ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_ENDING && (!bStarted || fTime >= 10.0f) && m_nStreamingFramesSinceLevelStart > 16)
  1149.                         {
  1150.                                 gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_COMPLETE);
  1151.  
  1152.                                 if (!bStarted)
  1153.                                         PrintMessage("Textures startup streaming finished in %.1f sec", fTime);
  1154.                                 else
  1155.                                         PrintMessage("Textures startup streaming timed out after %.1f sec", fTime);
  1156.  
  1157.                                 m_fTimeStateStarted = fTime;
  1158.                         }
  1159.  
  1160.                         if (nGlobalSystemState == ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_COMPLETE && (fTime - m_fTimeStateStarted) > 0.4f)
  1161.                         {
  1162.                                 pSE->PauseStreaming(false, (1 << eStreamTaskTypeTexture) | (1 << eStreamTaskTypeGeometry));
  1163.  
  1164.                                 m_bPreCacheEndEventSent = true;
  1165.                                 gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_RUNNING);
  1166.                                 gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_END, 0, 0);
  1167.  
  1168.                                 fTestStartTime = 0.f;
  1169.  
  1170. #if defined(STREAMENGINE_ENABLE_STATS)
  1171.                                 SStreamEngineStatistics& fullStats = pSE->GetStreamingStatistics();
  1172.                                 uint64 nBytesRead = fullStats.nTotalBytesRead - nCurrentBytesRead;
  1173.                                 uint32 nRequestCount = fullStats.nTotalRequestCount - nCurrentRequestCount;
  1174.  
  1175.                                 uint32 nOverallFileReadKB = (uint32)(nBytesRead / 1024);
  1176.                                 uint32 nOverallFileReadNum = nRequestCount;
  1177.                                 uint32 nBlockSize = (uint32)(nBytesRead / max((uint32)1, nRequestCount));
  1178.                                 float fReadBandwidthMB = (float)fullStats.nTotalSessionReadBandwidth / (1024 * 1024);
  1179.  
  1180.                                 PrintMessage("Average block size: %d KB, Average throughput: %.1f MB/sec, Jobs processed: %d (%.1f MB), File IO Bandwidth: %.2fMB/s",
  1181.                                              (nBlockSize) / 1024, (float)(nOverallFileReadKB / max(fTime, 1.f)) / 1024.f,
  1182.                                              nOverallFileReadNum, (float)nOverallFileReadKB / 1024.f,
  1183.                                              fReadBandwidthMB);
  1184.  
  1185.                                 if (GetCVars()->e_StreamSaveStartupResultsIntoXML)
  1186.                                 {
  1187.                                         const char* szTestResults = "%USER%/TestResults";
  1188.                                         char path[ICryPak::g_nMaxPath] = "";
  1189.                                         gEnv->pCryPak->AdjustFileName(string(string(szTestResults) + "\\" + "Streaming_Level_Start_Throughput.xml").c_str(), path, ICryPak::FLAGS_PATH_REAL | ICryPak::FLAGS_FOR_WRITING);
  1190.                                         gEnv->pCryPak->MakeDir(szTestResults);
  1191.  
  1192.                                         if (FILE* f = ::fopen(path, "wb"))
  1193.                                         {
  1194.                                                 fprintf(f,
  1195.                                                         "<phase name=\"Streaming_Level_Start_Throughput\">\n"
  1196.                                                         "<metrics name=\"Streaming\">\n"
  1197.                                                         "<metric name=\"Duration_Sec\"  value=\"%.1f\"/>\n"
  1198.                                                         "<metric name=\"BlockSize_KB\" value=\"%u\"/>\n"
  1199.                                                         "<metric name=\"Throughput_MB_Sec\" value=\"%.1f\"/>\n"
  1200.                                                         "<metric name=\"Jobs_Num\"      value=\"%u\"/>\n"
  1201.                                                         "<metric name=\"Read_MB\" value=\"%.1f\"/>\n"
  1202.                                                         "</metrics>\n"
  1203.                                                         "</phase>\n",
  1204.                                                         fTime,
  1205.                                                         (nOverallFileReadKB / nOverallFileReadNum),
  1206.                                                         (float)nOverallFileReadKB / max(fTime, 1.f) / 1024.f,
  1207.                                                         nOverallFileReadNum,
  1208.                                                         (float)nOverallFileReadKB / 1024.f);
  1209.  
  1210.                                                 ::fclose(f);
  1211.                                         }
  1212.                                 }
  1213. #endif
  1214.                                 // gEnv->pCryPak->GetFileReadSequencer()->EndSection(); // STREAMING
  1215.                         }
  1216.                 }
  1217.         }
  1218.         else
  1219.         {
  1220.                 if (!m_bPreCacheEndEventSent && m_nStreamingFramesSinceLevelStart == 4)
  1221.                 {
  1222.                         m_bPreCacheEndEventSent = true;
  1223.                         gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_RUNNING);
  1224.                         gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_END, 0, 0);
  1225.                 }
  1226.         }
  1227. }
  1228.  
  1229. void C3DEngine::PrintDebugInfo(const SRenderingPassInfo& passInfo)
  1230. {
  1231.         float fTextPosX = 10, fTextPosY = 10, fTextStepY = 12;
  1232.  
  1233.         // print list of streamed meshes
  1234.         if (m_pObjManager && GetCVars()->e_StreamCgf && GetCVars()->e_StreamCgfDebug >= 3)
  1235.         {
  1236.                 // overall status
  1237.                 {
  1238.                         static char szCGFStreaming[256];
  1239.                         static SObjectsStreamingStatus objectsStreamingStatus = { 0 };
  1240.  
  1241.                         {
  1242.                                 m_pObjManager->GetObjectsStreamingStatus(objectsStreamingStatus);
  1243.                                 cry_sprintf(szCGFStreaming, "CgfStrm: Loaded:%d InProg:%d All:%d Act:%d MemUsed:%2.2f MemReq:%2.2f Pool:%d",
  1244.                                             objectsStreamingStatus.nReady, objectsStreamingStatus.nInProgress, objectsStreamingStatus.nTotal, objectsStreamingStatus.nActive, float(objectsStreamingStatus.nAllocatedBytes) / 1024 / 1024, float(objectsStreamingStatus.nMemRequired) / 1024 / 1024, GetCVars()->e_StreamCgfPoolSize);
  1245.                         }
  1246.  
  1247.                         bool bOutOfMem((float(objectsStreamingStatus.nMemRequired) / 1024 / 1024) > GetCVars()->e_StreamCgfPoolSize);
  1248.                         bool bCloseToOutOfMem((float(objectsStreamingStatus.nMemRequired) / 1024 / 1024) > GetCVars()->e_StreamCgfPoolSize * 90 / 100);
  1249.  
  1250.                         ColorF color = Col_White;
  1251.                         if (bOutOfMem)
  1252.                                 color = Col_Red;
  1253.                         else if (bCloseToOutOfMem)
  1254.                                 color = Col_Orange;
  1255.                         //              if(bTooManyRequests)
  1256.                         //              color = Col_Magenta;
  1257.  
  1258.                         DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, color, "%s", szCGFStreaming);
  1259.                         fTextPosY += fTextStepY;
  1260.                 }
  1261.  
  1262.                 DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_White, "------------------- List of meshes bigger than %d KB -------------------", GetCVars()->e_StreamCgfDebugMinObjSize);
  1263.  
  1264.                 for (int nObjId = 0; nObjId < m_pObjManager->m_arrStreamableObjects.Count(); nObjId++)
  1265.                 {
  1266.                         CStatObj* pStatObj = (CStatObj*)m_pObjManager->m_arrStreamableObjects[nObjId].GetStreamAbleObject();
  1267.  
  1268.                         int nKB = pStatObj->GetStreamableContentMemoryUsage() >> 10;
  1269.                         int nSel = (pStatObj->m_nSelectedFrameId >= passInfo.GetMainFrameID() - 2);
  1270.  
  1271.                         string sName;
  1272.                         pStatObj->GetStreamableName(sName);
  1273.  
  1274.                         if ((nKB >= GetCVars()->e_StreamCgfDebugMinObjSize && strstr(sName.c_str(), GetCVars()->e_StreamCgfDebugFilter->GetString())) || nSel)
  1275.                         {
  1276.                                 char* pComment = 0;
  1277.  
  1278.                                 if (!pStatObj->m_bCanUnload)
  1279.                                         pComment = "NO_STRM";
  1280.                                 else if (pStatObj->m_pLod0)
  1281.                                         pComment = "  LOD_X";
  1282.                                 else if (!pStatObj->m_bLodsAreLoadedFromSeparateFile && pStatObj->m_nLoadedLodsNum > 1)
  1283.                                         pComment = " SINGLE";
  1284.                                 else if (pStatObj->m_nLoadedLodsNum > 1)
  1285.                                         pComment = "  LOD_0";
  1286.                                 else
  1287.                                         pComment = "NO_LODS";
  1288.  
  1289.                                 int nDiff = SATURATEB(int(float(nKB - GetCVars()->e_StreamCgfDebugMinObjSize) / max(1, (int)GetCVars()->e_StreamCgfDebugMinObjSize) * 255));
  1290.                                 ColorB col(nDiff, 255 - nDiff, 0, 255);
  1291.                                 if (nSel && (1 & (int)(GetCurTimeSec() * 5.f)))
  1292.                                         col = Col_Yellow;
  1293.                                 ColorF fColor(col[0] / 255.f, col[1] / 255.f, col[2] / 255.f, col[3] / 255.f);
  1294.  
  1295.                                 char* pStatusText = "Unload";
  1296.                                 if (pStatObj->m_eStreamingStatus == ecss_Ready)
  1297.                                         pStatusText = "Ready ";
  1298.                                 else if (pStatObj->m_eStreamingStatus == ecss_InProgress)
  1299.                                         pStatusText = "InProg";
  1300.  
  1301.                                 DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, fColor, "%1.2f mb, %s, %s, %s",
  1302.                                                     1.f / 1024.f * nKB, pComment, pStatusText, sName.c_str());
  1303.  
  1304.                                 if (fTextPosY > (float)gEnv->pRenderer->GetHeight())
  1305.                                         break;
  1306.                         }
  1307.                 }
  1308.         }
  1309.  
  1310.         if (m_arrProcessStreamingLatencyTestResults.Count())
  1311.         {
  1312.                 float fAverTime = 0;
  1313.                 for (int i = 0; i < m_arrProcessStreamingLatencyTestResults.Count(); i++)
  1314.                         fAverTime += m_arrProcessStreamingLatencyTestResults[i];
  1315.                 fAverTime /= m_arrProcessStreamingLatencyTestResults.Count();
  1316.  
  1317.                 int nAverTexNum = 0;
  1318.                 for (int i = 0; i < m_arrProcessStreamingLatencyTexNum.Count(); i++)
  1319.                         nAverTexNum += m_arrProcessStreamingLatencyTexNum[i];
  1320.                 nAverTexNum /= m_arrProcessStreamingLatencyTexNum.Count();
  1321.  
  1322.                 DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_Yellow, "------ SQT Average Time = %.1f, TexNum = %d ------", fAverTime, nAverTexNum);
  1323.  
  1324.                 for (int i = 0; i < m_arrProcessStreamingLatencyTestResults.Count(); i++)
  1325.                         DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_Yellow, "Run %d: Time = %.1f, TexNum = %d",
  1326.                                             i, m_arrProcessStreamingLatencyTestResults[i], m_arrProcessStreamingLatencyTexNum[i]);
  1327.         }
  1328.  
  1329. #if defined(USE_GEOM_CACHES)
  1330.         #ifndef _RELEASE
  1331.         if (GetCVars()->e_GeomCacheDebug)
  1332.         {
  1333.                 m_pGeomCacheManager->DrawDebugInfo();
  1334.         }
  1335.         else
  1336.         {
  1337.                 m_pGeomCacheManager->ResetDebugInfo();
  1338.         }
  1339.         #endif
  1340. #endif
  1341. }
  1342.  
  1343. void C3DEngine::OffsetPosition(Vec3& delta)
  1344. {
  1345. #ifdef SEG_WORLD
  1346.         m_vPrevMainFrameCamPos += delta;
  1347.  
  1348.         if (m_pGlobalIlluminationManager)
  1349.                 m_pGlobalIlluminationManager->OffsetPosition(delta);
  1350. #endif
  1351. }
  1352.  
  1353. void C3DEngine::DebugDrawStreaming(const SRenderingPassInfo& passInfo)
  1354. {
  1355. #ifndef CONSOLE_CONST_CVAR_MODE
  1356.         static Array2d<int> memUsage;
  1357.         int nArrayDim = 256;
  1358.  
  1359.         if (GetCVars()->e_StreamCgfDebugHeatMap == 1)
  1360.         {
  1361.                 memUsage.Allocate(nArrayDim);
  1362.                 CCamera camOld = passInfo.GetCamera();
  1363.  
  1364.                 int nStep = Get3DEngine()->GetTerrainSize() / nArrayDim;
  1365.  
  1366.                 PrintMessage("Computing mesh streaming heat map");
  1367.  
  1368.                 for (int x = 0; x < Get3DEngine()->GetTerrainSize(); x += nStep)
  1369.                 {
  1370.                         for (int y = 0; y < Get3DEngine()->GetTerrainSize(); y += nStep)
  1371.                         {
  1372.                                 CCamera camTmp = camOld;
  1373.                                 camTmp.SetPosition(Vec3((float)x + (float)nStep / 2.f, (float)y + (float)nStep / 2.f, Get3DEngine()->GetTerrainElevation((float)x, (float)y)));
  1374.                                 //SetCamera(camTmp);
  1375.                                 m_pObjManager->ProcessObjectsStreaming(passInfo);
  1376.  
  1377.                                 SObjectsStreamingStatus objectsStreamingStatus;
  1378.                                 m_pObjManager->GetObjectsStreamingStatus(objectsStreamingStatus);
  1379.  
  1380.                                 memUsage[x / nStep][y / nStep] = objectsStreamingStatus.nMemRequired;
  1381.                         }
  1382.  
  1383.                         if (!((x / nStep) & 31))
  1384.                                 PrintMessage(" working ...");
  1385.                 }
  1386.  
  1387.                 PrintMessage(" done");
  1388.  
  1389.                 GetCVars()->e_StreamCgfDebugHeatMap = 2;
  1390.                 //SetCamera(camOld);
  1391.         }
  1392.         else if (GetCVars()->e_StreamCgfDebugHeatMap == 2)
  1393.         {
  1394.                 float fStep = (float)Get3DEngine()->GetTerrainSize() / (float)nArrayDim;
  1395.  
  1396.                 for (int x = 0; x < memUsage.GetSize(); x++)
  1397.                 {
  1398.                         for (int y = 0; y < memUsage.GetSize(); y++)
  1399.                         {
  1400.                                 Vec3 v0((float)x * fStep, (float)y * fStep, Get3DEngine()->GetTerrainElevation((float)x * fStep, (float)y * fStep));
  1401.                                 Vec3 v1((float)x * fStep + fStep, (float)y * fStep + fStep, v0.z + fStep);
  1402.                                 v0 += Vec3(.25f, .25f, .25f);
  1403.                                 v1 -= Vec3(.25f, .25f, .25f);
  1404.                                 AABB box(v0, v1);
  1405.                                 if (!passInfo.GetCamera().IsAABBVisible_F(box))
  1406.                                         continue;
  1407.  
  1408.                                 int nMemUsageMB = memUsage[(int)(x)][(int)(y)] / 1024 / 1024;
  1409.  
  1410.                                 int nOverLoad = nMemUsageMB - GetCVars()->e_StreamCgfPoolSize;
  1411.  
  1412.                                 ColorB col = Col_Red;
  1413.  
  1414.                                 if (nOverLoad < GetCVars()->e_StreamCgfPoolSize / 2)
  1415.                                         col = Col_Yellow;
  1416.  
  1417.                                 if (nOverLoad < 0)
  1418.                                         col = Col_Green;
  1419.  
  1420.                                 DrawBBox(box, col);
  1421.                         }
  1422.                 }
  1423.         }
  1424. #endif //CONSOLE_CONST_CVAR_MODE
  1425. }
  1426.  
  1427. void C3DEngine::RenderInternal(const int nRenderFlags, const SRenderingPassInfo& passInfo, const char* szDebugName)
  1428. {
  1429.         m_bProfilerEnabled = gEnv->pFrameProfileSystem->IsProfiling();
  1430.  
  1431.         //Cache for later use
  1432.         if (m_pObjManager)
  1433.                 m_pObjManager->SetCurrentTime(gEnv->pTimer->GetCurrTime());
  1434.  
  1435.         // test if recursion causes problems
  1436.         if (passInfo.IsRecursivePass() && !GetCVars()->e_Recursion)
  1437.                 return;
  1438.  
  1439.         if (passInfo.IsGeneralPass())
  1440.         {
  1441.                 m_fGsmRange = GetCVars()->e_GsmRange;
  1442.                 m_fGsmRangeStep = GetCVars()->e_GsmRangeStep;
  1443.  
  1444.                 //!!!also formulas for computing biases per gsm needs to be changed
  1445.                 m_fShadowsConstBias = GetCVars()->e_ShadowsConstBias;
  1446.                 m_fShadowsSlopeBias = GetCVars()->e_ShadowsSlopeBias;
  1447.  
  1448.                 if (m_eShadowMode == ESM_HIGHQUALITY)
  1449.                 {
  1450.                         m_fGsmRange = min(0.15f, GetCVars()->e_GsmRange);
  1451.                         m_fGsmRangeStep = min(2.8f, GetCVars()->e_GsmRangeStep);
  1452.  
  1453.                         m_fShadowsConstBias = min(GetCVars()->e_ShadowsConstBiasHQ, GetCVars()->e_ShadowsConstBias);
  1454.                         m_fShadowsSlopeBias = min(GetCVars()->e_ShadowsSlopeBiasHQ, GetCVars()->e_ShadowsSlopeBias);
  1455.                 }
  1456.         }
  1457.  
  1458.         // Update particle system as late as possible, only renderer is dependent on it.
  1459.         m_pPartManager->GetLightProfileCounts().ResetFrameTicks();
  1460.         if (passInfo.IsGeneralPass() && m_pPartManager)
  1461.                 m_pPartManager->Update();
  1462.         if (passInfo.IsGeneralPass() && m_pParticleSystem)
  1463.                 m_pParticleSystem->Update();
  1464.  
  1465.         if (passInfo.IsGeneralPass() && passInfo.RenderClouds())
  1466.         {
  1467.                 if (m_pCloudsManager)
  1468.                         m_pCloudsManager->MoveClouds();
  1469.  
  1470.                 CVolumeObjectRenderNode::MoveVolumeObjects();
  1471.  
  1472.                 // move procedural volumetric clouds with global wind.
  1473.                 {
  1474.                         Vec3 cloudParams(0, 0, 0);
  1475.                         GetGlobalParameter(E3DPARAM_VOLCLOUD_WIND_ATMOSPHERIC, cloudParams);
  1476.                         const float windInfluence = cloudParams.x;
  1477.                         Vec3 wind = GetGlobalWind(false);
  1478.                         const float elapsedTime = windInfluence * gEnv->pTimer->GetFrameTime();
  1479.  
  1480.                         // move E3DPARAM_VOLCLOUD_TILING_OFFSET with global wind.
  1481.                         m_vVolCloudTilingOffset.x -= wind.x * elapsedTime;
  1482.                         m_vVolCloudTilingOffset.y -= wind.y * elapsedTime;
  1483.                 }
  1484.         }
  1485.  
  1486.         if (m_pObjManager)
  1487.         {
  1488.                 m_pObjManager->m_fMaxViewDistanceScale = 1.f;
  1489.  
  1490.                 const int nCascadeCount = Get3DEngine()->GetShadowsCascadeCount(NULL);
  1491.                 m_pObjManager->m_fGSMMaxDistance = Get3DEngine()->m_fGsmRange * powf(Get3DEngine()->m_fGsmRangeStep, (float)nCascadeCount);
  1492.         }
  1493.  
  1494.         if (passInfo.GetRecursiveLevel() >= MAX_RECURSION_LEVELS)
  1495.         {
  1496.                 assert(!"Recursion deeper than MAX_RECURSION_LEVELS is not supported");
  1497.                 return;
  1498.         }
  1499.  
  1500.         if (passInfo.IsGeneralPass())
  1501.                 UpdateScene(passInfo);
  1502.  
  1503.         CheckPhysicalized(passInfo.GetCamera().GetPosition() - Vec3(2, 2, 2), passInfo.GetCamera().GetPosition() + Vec3(2, 2, 2));
  1504.  
  1505.         RenderScene(nRenderFlags, passInfo);
  1506.  
  1507. #ifndef _RELEASE
  1508.         IF (GetCVars()->e_LightVolumesDebug, 0)
  1509.                 m_LightVolumesMgr.DrawDebug(passInfo);
  1510. #endif
  1511.  
  1512.         if (m_pObjManager && passInfo.IsGeneralPass())
  1513.         {
  1514.                 m_pObjManager->CheckTextureReadyFlag();
  1515.                 if (GetCVars()->e_StreamCgf)
  1516.                 {
  1517.                         DebugDrawStreaming(passInfo);
  1518.  
  1519.                         m_pObjManager->ProcessObjectsStreaming(passInfo);
  1520.                 }
  1521.                 else
  1522.                 {
  1523.                         m_pObjManager->m_vStreamPreCacheCameras[0].vPosition = passInfo.GetCamera().GetPosition();
  1524.                         if (Distance::Point_AABBSq(m_pObjManager->m_vStreamPreCacheCameras[0].vPosition, m_pObjManager->m_vStreamPreCacheCameras[0].bbox) > 0.0f)
  1525.                                 m_pObjManager->m_vStreamPreCacheCameras[0].bbox = AABB(m_pObjManager->m_vStreamPreCacheCameras[0].vPosition, GetCVars()->e_StreamPredictionBoxRadius);
  1526.                         m_pObjManager->UpdateObjectsStreamingPriority(false, passInfo);
  1527.                 }
  1528.  
  1529.                 // Unload old object instances
  1530.                 COctreeNode::StreamingCheckUnload(passInfo, GetObjManager()->m_vStreamPreCacheCameras);
  1531.         }
  1532.  
  1533.         if (passInfo.IsGeneralPass())
  1534.                 m_bContentPrecacheRequested = false;
  1535.  
  1536. }
  1537.  
  1538. int __cdecl C3DEngine__Cmp_SRNInfo(const void* v1, const void* v2)
  1539. {
  1540.         SRNInfo* p1 = (SRNInfo*)v1;
  1541.         SRNInfo* p2 = (SRNInfo*)v2;
  1542.  
  1543.         float fViewDist1 = p1->fMaxViewDist - p1->objSphere.radius;
  1544.         float fViewDist2 = p2->fMaxViewDist - p2->objSphere.radius;
  1545.  
  1546.         // if same - give closest sectors higher priority
  1547.         if (fViewDist1 > fViewDist2)
  1548.                 return 1;
  1549.         else if (fViewDist1 < fViewDist2)
  1550.                 return -1;
  1551.  
  1552.         return 0;
  1553. }
  1554.  
  1555. IMaterial* C3DEngine::GetSkyMaterial()
  1556. {
  1557.         IMaterial* pRes(0);
  1558.         if (GetCVars()->e_SkyType == 0)
  1559.         {
  1560.                 if (!m_pSkyLowSpecMat)
  1561.                 {
  1562.                         m_pSkyLowSpecMat = m_skyLowSpecMatName.empty() ? 0 : m_pMatMan->LoadMaterial(m_skyLowSpecMatName.c_str(), false);
  1563.                 }
  1564.                 pRes = m_pSkyLowSpecMat;
  1565.         }
  1566.         else
  1567.         {
  1568.                 if (!m_pSkyMat)
  1569.                 {
  1570.                         m_pSkyMat = m_skyMatName.empty() ? 0 : GetMatMan()->LoadMaterial(m_skyMatName.c_str(), false);
  1571.                 }
  1572.                 pRes = m_pSkyMat;
  1573.         }
  1574.         return pRes;
  1575. }
  1576.  
  1577. void C3DEngine::SetSkyMaterial(IMaterial* pSkyMat)
  1578. {
  1579.         m_pSkyMat = pSkyMat;
  1580. }
  1581.  
  1582. bool C3DEngine::IsHDRSkyMaterial(IMaterial* pMat) const
  1583. {
  1584.         return pMat && pMat->GetShaderItem().m_pShader && !stricmp(pMat->GetShaderItem().m_pShader->GetName(), "SkyHDR");
  1585. }
  1586.  
  1587. void C3DEngine::RenderScene(const int nRenderFlags, const SRenderingPassInfo& passInfo)
  1588. {
  1589.         FUNCTION_PROFILER_3DENGINE;
  1590.         assert(passInfo.GetRecursiveLevel() < MAX_RECURSION_LEVELS);
  1591.  
  1592.         ////////////////////////////////////////////////////////////////////////////////////////
  1593.         // Begin scene drawing
  1594.         ////////////////////////////////////////////////////////////////////////////////////////
  1595.         if (passInfo.IsGeneralPass())
  1596.                 GetObjManager()->m_CullThread.SetActive(true);
  1597.  
  1598.         ////////////////////////////////////////////////////////////////////////////////////////
  1599.         // Sync asynchronous cull queue processing if enabled
  1600.         ////////////////////////////////////////////////////////////////////////////////////////
  1601. #ifdef USE_CULL_QUEUE
  1602.         if (GetCVars()->e_CoverageBuffer)
  1603.                 GetObjManager()->CullQueue().Wait();
  1604. #endif
  1605.  
  1606.         ////////////////////////////////////////////////////////////////////////////////////////
  1607.         // Draw potential occluders into z-buffer
  1608.         ////////////////////////////////////////////////////////////////////////////////////////
  1609.  
  1610.         if (GetCVars()->e_Sleep > 0)
  1611.         {
  1612.                 CrySleep(GetCVars()->e_Sleep);
  1613.         }
  1614.  
  1615.         ////////////////////////////////////////////////////////////////////////////////////////
  1616.         // Output debug data from last frame
  1617.         ////////////////////////////////////////////////////////////////////////////////////////
  1618.         if (passInfo.IsGeneralPass())
  1619.                 m_pObjManager->RenderAllObjectDebugInfo();
  1620.  
  1621.         ////////////////////////////////////////////////////////////////////////////////////////
  1622.         // From here we add render elements of main scene
  1623.         ////////////////////////////////////////////////////////////////////////////////////////
  1624.  
  1625.         GetRenderer()->EF_StartEf(passInfo);
  1626.  
  1627.         ////////////////////////////////////////////////////////////////////////////////////////
  1628.         // Define indoor visibility
  1629.         ////////////////////////////////////////////////////////////////////////////////////////
  1630.  
  1631.         if (m_pVisAreaManager)
  1632.         {
  1633.                 m_pVisAreaManager->DrawOcclusionAreasIntoCBuffer(passInfo);
  1634.                 m_pVisAreaManager->CheckVis(passInfo);
  1635.         }
  1636.  
  1637.         ////////////////////////////////////////////////////////////////////////////////////////
  1638.         // Add clip volumes to renderer
  1639.         ////////////////////////////////////////////////////////////////////////////////////////
  1640.         if (m_pClipVolumeManager)
  1641.                 m_pClipVolumeManager->PrepareVolumesForRendering(passInfo);
  1642.  
  1643.         if (m_pPartManager)
  1644.                 m_pPartManager->PrepareForRender(passInfo);
  1645.  
  1646.         ////////////////////////////////////////////////////////////////////////////////////////
  1647.         // Make sure all async octree updates are done
  1648.         ////////////////////////////////////////////////////////////////////////////////////////
  1649.         if (passInfo.IsGeneralPass())
  1650.                 m_bIsInRenderScene = true;
  1651.  
  1652.         if (passInfo.IsGeneralPass())
  1653.                 COctreeNode::ReleaseEmptyNodes();
  1654.  
  1655.         ////////////////////////////////////////////////////////////////////////////////////////
  1656.         // Add lsources to the renderer and register into sectors
  1657.         ////////////////////////////////////////////////////////////////////////////////////////
  1658.         UpdateLightSources(passInfo);
  1659.         PrepareLightSourcesForRendering_0(passInfo);
  1660.         PrepareLightSourcesForRendering_1(passInfo);
  1661.  
  1662.         ////////////////////////////////////////////////////////////////////////////////////////
  1663.         // Add render elements for indoor
  1664.         ////////////////////////////////////////////////////////////////////////////////////////
  1665.         if (passInfo.IsGeneralPass() && GetCVars()->e_StatObjBufferRenderTasks && JobManager::InvokeAsJob("CheckOcclusion"))
  1666.                 m_pObjManager->BeginOcclusionCulling(passInfo);
  1667.  
  1668.         // draw objects inside visible vis areas
  1669.         if (m_pVisAreaManager)
  1670.                 m_pVisAreaManager->DrawVisibleSectors(passInfo);
  1671.  
  1672.         ////////////////////////////////////////////////////////////////////////////////////////
  1673.         // Clear current sprites list
  1674.         ////////////////////////////////////////////////////////////////////////////////////////
  1675.         for (int t = 0; t < nThreadsNum; t++)
  1676.         {
  1677.                 CThreadSafeRendererContainer<SVegetationSpriteInfo>& rList = m_pObjManager->m_arrVegetationSprites[passInfo.GetRecursiveLevel()][t];
  1678.                 rList.resize(0);
  1679.         }
  1680.  
  1681.         ////////////////////////////////////////////////////////////////////////////////////////
  1682.         // Add render elements for outdoor
  1683.         ////////////////////////////////////////////////////////////////////////////////////////
  1684.  
  1685.         // Reset ocean volume
  1686.         if (passInfo.IsGeneralPass())
  1687.                 m_nOceanRenderFlags &= ~OCR_OCEANVOLUME_VISIBLE;
  1688.  
  1689.         if (m_pTerrain)
  1690.                 m_pTerrain->ClearVisSectors();
  1691.  
  1692.         if (IsOutdoorVisible() || GetRenderer()->IsPost3DRendererEnabled())
  1693.         {
  1694.                 if (m_pVisAreaManager && m_pVisAreaManager->m_lstOutdoorPortalCameras.Count() &&
  1695.                     (m_pVisAreaManager->m_pCurArea || m_pVisAreaManager->m_pCurPortal))
  1696.                 {
  1697.                         // enable multi-camera culling
  1698.                         //const_cast<CCamera&>(passInfo.GetCamera()).m_pMultiCamera = &m_pVisAreaManager->m_lstOutdoorPortalCameras;
  1699.                 }
  1700.  
  1701.                 if (IsOutdoorVisible())
  1702.                 {
  1703.                         RenderSkyBox(GetSkyMaterial(), passInfo);
  1704.                 }
  1705.  
  1706.                 // start processing terrain
  1707.                 if (IsOutdoorVisible() && m_pTerrain && passInfo.RenderTerrain() && Get3DEngine()->m_bShowTerrainSurface && !gEnv->IsDedicated())
  1708.                         m_pTerrain->CheckVis(passInfo);
  1709.  
  1710.                 // process streaming and procedural vegetation distribution
  1711.                 if (passInfo.IsGeneralPass() && m_pTerrain)
  1712.                         m_pTerrain->UpdateNodesIncrementaly(passInfo);
  1713.  
  1714.                 for (int nSID = 0; nSID < Get3DEngine()->m_pObjectsTree.Count(); nSID++)
  1715.                 {
  1716.                         if (IsSegmentSafeToUse(nSID))
  1717.                         {
  1718.                                 passInfo.GetRendItemSorter().IncreaseOctreeCounter();
  1719.                                 FRAME_PROFILER("COctreeNode::Render_____", GetSystem(), PROFILE_3DENGINE);
  1720.                                 m_pObjectsTree[nSID]->Render_Object_Nodes(false, OCTREENODE_RENDER_FLAG_OBJECTS, GetSkyColor(), passInfo);
  1721.  
  1722.                                 if (GetCVars()->e_ObjectsTreeBBoxes >= 3)
  1723.                                         m_pObjectsTree[nSID]->RenderDebug();
  1724.                         }
  1725.                 }
  1726.                 passInfo.GetRendItemSorter().IncreaseGroupCounter();
  1727.         }
  1728.         else if (m_pVisAreaManager && m_pVisAreaManager->IsSkyVisible())
  1729.         {
  1730.                 __debugbreak();
  1731.                 RenderSkyBox(GetSkyMaterial(), passInfo);
  1732.         }
  1733.  
  1734. #if defined(FEATURE_SVO_GI)
  1735.         if (passInfo.IsGeneralPass() && (nRenderFlags & SHDF_ALLOW_AO))
  1736.                 CSvoManager::Render();
  1737. #endif
  1738.  
  1739.         if (GetCVars()->e_ObjectLayersActivation == 4)
  1740.         {
  1741.                 for (int l = 0; l < m_arrObjectLayersActivity.Count(); l++)
  1742.                         if (m_arrObjectLayersActivity[l].objectsBox.GetVolume())
  1743.                                 DrawBBoxLabeled(m_arrObjectLayersActivity[l].objectsBox, Matrix34::CreateIdentity(), Col_White, "id=%d, %s", l, m_arrObjectLayersActivity[l].bActive ? "ON" : "OFF");
  1744.         }
  1745.  
  1746.         // render outdoor entities very near of camera - fix for 1p vehicle entering into indoor
  1747.         for (int nSID = 0; nSID < Get3DEngine()->m_pObjectsTree.Count(); nSID++)
  1748.         {
  1749.                 FRAME_PROFILER("COctreeNode::Render_Object_Nodes_NEAR", GetSystem(), PROFILE_3DENGINE);
  1750.                 passInfo.GetRendItemSorter().IncreaseOctreeCounter();
  1751.                 if (GetCVars()->e_PortalsBigEntitiesFix)
  1752.                         if (IsSegmentSafeToUse(nSID) && !IsOutdoorVisible() && GetVisAreaManager() && GetVisAreaManager()->GetCurVisArea())
  1753.                                 if (GetVisAreaManager()->GetCurVisArea()->IsConnectedToOutdoor())
  1754.                                 {
  1755.                                         CCamera cam = passInfo.GetCamera();
  1756.                                         cam.SetFrustum(cam.GetViewSurfaceX(), cam.GetViewSurfaceZ(), cam.GetFov(), min(cam.GetNearPlane(), 1.f), 2.f, cam.GetPixelAspectRatio());
  1757.                                         m_pObjectsTree[nSID]->Render_Object_Nodes(false, OCTREENODE_RENDER_FLAG_OBJECTS | OCTREENODE_RENDER_FLAG_OBJECTS_ONLY_ENTITIES, GetSkyColor(), SRenderingPassInfo::CreateTempRenderingInfo(cam, passInfo));
  1758.                                 }
  1759.         }
  1760.         passInfo.GetRendItemSorter().IncreaseGroupCounter();
  1761.  
  1762.         // render special objects like laser beams intersecting entire level
  1763.         for (int i = 0; i < m_lstAlwaysVisible.Count(); i++)
  1764.         {
  1765.                 IRenderNode* pObj = m_lstAlwaysVisible[i];
  1766.                 const AABB& objBox = pObj->GetBBox();
  1767.                 // don't frustum cull the HUD. When e.g. zooming the FOV for this camera is very different to the
  1768.                 // fixed HUD FOV, and this can cull incorrectly.
  1769.                 auto dwRndFlags = pObj->GetRndFlags();
  1770.                 if (dwRndFlags & ERF_HUD || passInfo.GetCamera().IsAABBVisible_E(objBox))
  1771.                 {
  1772.                         FRAME_PROFILER("C3DEngine::RenderScene_DrawAlwaysVisible", GetSystem(), PROFILE_3DENGINE);
  1773.  
  1774.                         Vec3 vCamPos = passInfo.GetCamera().GetPosition();
  1775.                         float fEntDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
  1776.                         assert(fEntDistance >= 0 && _finite(fEntDistance));
  1777.                         if (fEntDistance < pObj->m_fWSMaxViewDist)
  1778.                         {
  1779.                                 GetObjManager()->RenderObject(pObj, NULL, GetSkyColor(), objBox, fEntDistance, false, pObj->GetRenderNodeType(), passInfo);
  1780.                         }
  1781.                 }
  1782.         }
  1783.         passInfo.GetRendItemSorter().IncreaseGroupCounter();
  1784.  
  1785.         ProcessOcean(passInfo);
  1786.  
  1787.         if (m_pWaterRippleManager)
  1788.         {
  1789.                 m_pWaterRippleManager->Render(passInfo);
  1790.         }
  1791.  
  1792.         if (m_pDecalManager && passInfo.RenderDecals())
  1793.                 m_pDecalManager->Render(passInfo);
  1794.  
  1795.         // tell the occlusion culler that no new work will be submitted
  1796.         if (GetCVars()->e_StatObjBufferRenderTasks == 1 && passInfo.IsGeneralPass() && JobManager::InvokeAsJob("CheckOcclusion"))
  1797.                 GetObjManager()->PushIntoCullQueue(SCheckOcclusionJobData::CreateQuitJobData());
  1798.  
  1799.         // fill shadow list here to allow more time between starting and waiting for the occlusion buffer
  1800.         InitShadowFrustums(passInfo);
  1801.  
  1802.         if (passInfo.IsGeneralPass())
  1803.                 gEnv->pSystem->DoWorkDuringOcclusionChecks();
  1804.  
  1805.         if (passInfo.IsGeneralPass() && GetCVars()->e_StatObjBufferRenderTasks && JobManager::InvokeAsJob("CheckOcclusion"))
  1806.                 m_pObjManager->RenderBufferedRenderMeshes(passInfo);
  1807.  
  1808.         // Call postrender on the meshes that require it.
  1809.         // Call it before InvokeShadowMapRenderJobs, otherwise render meshes are not constructed at the moment of shadow gen render calls
  1810.         if (passInfo.IsGeneralPass())
  1811.         {
  1812.                 m_pMergedMeshesManager->SortActiveInstances(passInfo);
  1813.                 m_pMergedMeshesManager->PostRenderMeshes(passInfo);
  1814.         }
  1815.  
  1816.         // start render jobs for shadow map
  1817.         if (!passInfo.IsShadowPass() && passInfo.RenderShadows() && !passInfo.IsRecursivePass())
  1818.         {
  1819.                 GetRenderer()->EF_InvokeShadowMapRenderJobs(passInfo.GetRenderView(), 0);
  1820.         }
  1821.  
  1822.         // add sprites render item
  1823.         if (passInfo.RenderFarSprites())
  1824.                 m_pObjManager->RenderFarObjects(passInfo);
  1825.  
  1826.         // render terrain ground
  1827.         if (m_pTerrain)
  1828.                 m_pTerrain->DrawVisibleSectors(passInfo);
  1829.  
  1830.         pfx2::CParticleSystem* pParticleSystem = static_cast<pfx2::CParticleSystem*>(m_pParticleSystem.get());
  1831.         if (pParticleSystem)
  1832.                 pParticleSystem->SyncronizeUpdateKernels();
  1833.         if (m_pPartManager)
  1834.                 m_pPartManager->FinishParticleRenderTasks(passInfo);
  1835.         if (pParticleSystem)
  1836.                 pParticleSystem->DeferredRender();
  1837.  
  1838.         if (passInfo.IsGeneralPass())
  1839.                 m_LightVolumesMgr.Update(passInfo);
  1840.  
  1841.         if (auto* pGame = gEnv->pGameFramework->GetIGame())
  1842.                 pGame->OnRenderScene(passInfo);
  1843.  
  1844.         ////////////////////////////////////////////////////////////////////////////////////////
  1845.         // Start asynchronous cull queue processing if enabled
  1846.         ////////////////////////////////////////////////////////////////////////////////////////
  1847.  
  1848.         //Tell the c-buffer that the item queue is ready. The render thread supplies the depth buffer to test against and this is prepared asynchronously
  1849.         GetObjManager()->CullQueue().FinishedFillingTestItemQueue();
  1850.  
  1851.         ////////////////////////////////////////////////////////////////////////////////////////
  1852.         // Finalize frame
  1853.         ////////////////////////////////////////////////////////////////////////////////////////
  1854.  
  1855.         SetupDistanceFog();
  1856.  
  1857.         if (passInfo.IsGeneralPass())
  1858.                 SetupClearColor();
  1859.  
  1860.         // Update the sector meshes
  1861.         if (m_pTerrain)
  1862.                 m_pTerrain->UpdateSectorMeshes(passInfo);
  1863.  
  1864.         ICharacterManager* pCharManager = gEnv->pCharacterManager;
  1865.         if (pCharManager)
  1866.         {
  1867.                 pCharManager->UpdateStreaming(GetObjManager()->m_nUpdateStreamingPrioriryRoundId, GetObjManager()->m_nUpdateStreamingPrioriryRoundIdFast);
  1868.         }
  1869.  
  1870.         FinishWindGridJob();
  1871.  
  1872.         {
  1873.                 FRAME_PROFILER("Renderer::EF_EndEf3D", GetSystem(), PROFILE_RENDERER);
  1874.                 // TODO: separate SHDF_NOASYNC and SHDF_STREAM_SYNC flags
  1875.                 GetRenderer()->EF_EndEf3D(IsShadersSyncLoad() ? (nRenderFlags | SHDF_NOASYNC | SHDF_STREAM_SYNC) : nRenderFlags, GetObjManager()->m_nUpdateStreamingPrioriryRoundId, GetObjManager()->m_nUpdateStreamingPrioriryRoundIdFast, passInfo);
  1876.         }
  1877.  
  1878.         if (passInfo.IsGeneralPass())
  1879.         {
  1880.                 GetRenderer()->EnableFog(false);
  1881.                 m_pMergedMeshesManager->Update(passInfo);
  1882.         }
  1883.  
  1884.         // unload old meshes
  1885.         if (passInfo.IsGeneralPass() && m_pTerrain)
  1886.                 for (int nSID = 0; nSID < Get3DEngine()->m_pObjectsTree.Count(); nSID++)
  1887.                         m_pTerrain->CheckNodesGeomUnload(nSID, passInfo);
  1888.  
  1889.         if (passInfo.IsGeneralPass())
  1890.         {
  1891.                 m_bIsInRenderScene = false;
  1892.         }
  1893. }
  1894.  
  1895. void C3DEngine::ResetCoverageBufferSignalVariables()
  1896. {
  1897.         GetObjManager()->CullQueue().ResetSignalVariables();
  1898. }
  1899.  
  1900. void C3DEngine::ProcessOcean(const SRenderingPassInfo& passInfo)
  1901. {
  1902.         FUNCTION_PROFILER_3DENGINE;
  1903.  
  1904.         if (GetOceanRenderFlags() & OCR_NO_DRAW || !GetVisAreaManager() || GetCVars()->e_DefaultMaterial || !GetTerrain())
  1905.                 return;
  1906.  
  1907.         bool bOceanIsForcedByVisAreaFlags = GetVisAreaManager()->IsOceanVisible();
  1908.  
  1909.         if (!IsOutdoorVisible() && !bOceanIsForcedByVisAreaFlags)
  1910.                 return;
  1911.  
  1912.         float fOceanLevel = GetTerrain()->GetWaterLevel();
  1913.  
  1914.         // check for case when no any visible terrain sectors has minz lower than ocean level
  1915.         bool bOceanVisible = !Get3DEngine()->m_bShowTerrainSurface;
  1916.         bOceanVisible |= m_pTerrain->GetDistanceToSectorWithWater() >= 0 && fOceanLevel && m_pTerrain->IsOceanVisible();
  1917.  
  1918.         if (bOceanVisible && passInfo.RenderWaterOcean() && m_bOcean)
  1919.         {
  1920.                 Vec3 vCamPos = passInfo.GetCamera().GetPosition();
  1921.                 float fWaterPlaneSize = passInfo.GetCamera().GetFarPlane();
  1922.  
  1923.                 AABB boxOcean(Vec3(vCamPos.x - fWaterPlaneSize, vCamPos.y - fWaterPlaneSize, 0),
  1924.                               Vec3(vCamPos.x + fWaterPlaneSize, vCamPos.y + fWaterPlaneSize, fOceanLevel + 0.5f));
  1925.  
  1926.                 if ((!bOceanIsForcedByVisAreaFlags && passInfo.GetCamera().IsAABBVisible_EM(boxOcean)) ||
  1927.                     (bOceanIsForcedByVisAreaFlags && passInfo.GetCamera().IsAABBVisible_E(boxOcean)))
  1928.                 {
  1929.                         bool bOceanIsVisibleFromIndoor = true;
  1930.                         if (class PodArray<CCamera>* pMultiCamera = passInfo.GetCamera().m_pMultiCamera)
  1931.                         {
  1932.                                 for (int i = 0; i < pMultiCamera->Count(); i++)
  1933.                                 {
  1934.                                         CVisArea* pExitPortal = (CVisArea*)(pMultiCamera->Get(i))->m_pPortal;
  1935.                                         float fMinZ = pExitPortal->GetAABBox()->min.z;
  1936.                                         float fMaxZ = pExitPortal->GetAABBox()->max.z;
  1937.  
  1938.                                         if (!bOceanIsForcedByVisAreaFlags)
  1939.                                         {
  1940.                                                 if (fMinZ > fOceanLevel && vCamPos.z < fMinZ)
  1941.                                                         bOceanIsVisibleFromIndoor = false;
  1942.  
  1943.                                                 if (fMaxZ < fOceanLevel && vCamPos.z > fMaxZ)
  1944.                                                         bOceanIsVisibleFromIndoor = false;
  1945.                                         }
  1946.                                 }
  1947.                         }
  1948.  
  1949.                         if (bOceanIsVisibleFromIndoor)
  1950.                         {
  1951.                                 m_pTerrain->UpdateOcean(passInfo);
  1952.  
  1953.                                 if ((GetOceanRenderFlags() & OCR_OCEANVOLUME_VISIBLE))
  1954.                                 {
  1955.                                         m_pTerrain->RenderOcean(passInfo);
  1956.  
  1957.                                         if (passInfo.RenderWaterWaves())
  1958.                                                 GetWaterWaveManager()->Update(passInfo);
  1959.                                 }
  1960.                         }
  1961.                 }
  1962.         }
  1963. }
  1964.  
  1965. void C3DEngine::RenderSkyBox(IMaterial* pMat, const SRenderingPassInfo& passInfo)
  1966. {
  1967.         FUNCTION_PROFILER_3DENGINE;
  1968.  
  1969.         const float fForceDrawLastSortOffset = 100000.0f;
  1970.  
  1971.         Vec3 vSkyLight(0.0f, 0.0f, 0.0f);
  1972.  
  1973.         // hdr sky dome
  1974.         // TODO: temporary workaround to force the right sky dome for the selected shader
  1975.         if (m_pREHDRSky && IsHDRSkyMaterial(pMat))
  1976.         {
  1977.                 if (GetCVars()->e_SkyBox)
  1978.                 {
  1979. #ifndef CONSOLE_CONST_CVAR_MODE
  1980.                         if (GetCVars()->e_SkyQuality < 1)
  1981.                                 GetCVars()->e_SkyQuality = 1;
  1982.                         else if (GetCVars()->e_SkyQuality > 2)
  1983.                                 GetCVars()->e_SkyQuality = 2;
  1984. #endif
  1985.                         m_pSkyLightManager->SetQuality(GetCVars()->e_SkyQuality);
  1986.  
  1987.                         // set sky light incremental update rate and perform update
  1988.                         if (GetCVars()->e_SkyUpdateRate <= 0.0f)
  1989.                                 GetCVars()->e_SkyUpdateRate = 0.01f;
  1990.                         m_pSkyLightManager->IncrementalUpdate(GetCVars()->e_SkyUpdateRate, passInfo);
  1991.  
  1992.                         // prepare render object
  1993.                         CRenderObject* pObj = GetRenderer()->EF_GetObject_Temp(passInfo.ThreadID());
  1994.                         if (!pObj)
  1995.                                 return;
  1996.                         pObj->m_II.m_Matrix.SetTranslationMat(passInfo.GetCamera().GetPosition());
  1997.                         pObj->m_ObjFlags |= FOB_TRANS_TRANSLATE;
  1998.                         pObj->m_pRenderNode = 0;//m_pREHDRSky;
  1999.                         pObj->m_fSort = fForceDrawLastSortOffset; // force sky to draw last
  2000.  
  2001.                         /*                      if( 0 == m_nRenderStackLevel )
  2002.                            {
  2003.                            // set scissor rect
  2004.                            pObj->m_nScissorX1 = GetCamera().m_ScissorInfo.x1;
  2005.                            pObj->m_nScissorY1 = GetCamera().m_ScissorInfo.y1;
  2006.                            pObj->m_nScissorX2 = GetCamera().m_ScissorInfo.x2;
  2007.                            pObj->m_nScissorY2 = GetCamera().m_ScissorInfo.y2;
  2008.                            }*/
  2009.  
  2010.                         m_pREHDRSky->m_pRenderParams = m_pSkyLightManager->GetRenderParams();
  2011.                         m_pREHDRSky->m_moonTexId = m_nNightMoonTexId;
  2012.  
  2013.                         // add sky dome to render list
  2014.                         GetRenderer()->EF_AddEf(m_pREHDRSky, pMat->GetShaderItem(), pObj, passInfo, EFSLIST_GENERAL, 1);
  2015.  
  2016.                         // get sky lighting parameter.
  2017.                         const SSkyLightRenderParams* pSkyParams = m_pSkyLightManager->GetRenderParams();
  2018.                         if (pSkyParams)
  2019.                         {
  2020.                                 Vec4 skylightRayleighInScatter;
  2021.                                 skylightRayleighInScatter = pSkyParams->m_hazeColorRayleighNoPremul * pSkyParams->m_partialRayleighInScatteringConst;
  2022.                                 vSkyLight = Vec3(skylightRayleighInScatter);
  2023.                         }
  2024.                 }
  2025.         }
  2026.         // skybox
  2027.         else
  2028.         {
  2029.                 if (pMat && m_pRESky && GetCVars()->e_SkyBox)
  2030.                 {
  2031.                         CRenderObject* pObj = GetRenderer()->EF_GetObject_Temp(passInfo.ThreadID());
  2032.                         if (!pObj)
  2033.                                 return;
  2034.                         pObj->m_II.m_Matrix.SetTranslationMat(passInfo.GetCamera().GetPosition());
  2035.                         pObj->m_II.m_Matrix = pObj->m_II.m_Matrix * Matrix33::CreateRotationZ(DEG2RAD(m_fSkyBoxAngle));
  2036.                         pObj->m_ObjFlags |= FOB_TRANS_TRANSLATE | FOB_TRANS_ROTATE;
  2037.                         pObj->m_fSort = fForceDrawLastSortOffset; // force sky to draw last
  2038.  
  2039.                         m_pRESky->m_fTerrainWaterLevel = max(0.0f, m_pTerrain->GetWaterLevel());
  2040.                         m_pRESky->m_fSkyBoxStretching = m_fSkyBoxStretching;
  2041.  
  2042.                         GetRenderer()->EF_AddEf(m_pRESky, pMat->GetShaderItem(), pObj, passInfo, EFSLIST_GENERAL, 1);
  2043.                 }
  2044.         }
  2045.  
  2046.         SetGlobalParameter(E3DPARAM_SKYLIGHT_RAYLEIGH_INSCATTER, vSkyLight);
  2047. }
  2048.  
  2049. void C3DEngine::DrawTextRightAligned(const float x, const float y, const char* format, ...)
  2050. {
  2051.         va_list args;
  2052.         va_start(args, format);
  2053.         IRenderAuxText::DrawText(Vec3(x, y, 1.0f), DISPLAY_INFO_SCALE, NULL, eDrawText_FixedSize | eDrawText_Right | eDrawText_2D | eDrawText_Monospace, format, args);
  2054.         va_end(args);
  2055. }
  2056.  
  2057. void C3DEngine::DrawTextAligned(int flags, const float x, const float y, const float scale, const ColorF& color, const char* format, ...)
  2058. {
  2059.         va_list args;
  2060.         va_start(args, format);
  2061.         IRenderAuxText::DrawText(Vec3(x, y, 1.0f), scale, color, flags, format, args);
  2062.  
  2063.         va_end(args);
  2064. }
  2065.  
  2066. void C3DEngine::DrawTextLeftAligned(const float x, const float y, const float scale, const ColorF& color, const char* format, ...)
  2067. {
  2068.         va_list args;
  2069.         va_start(args, format);
  2070.         IRenderAuxText::DrawText(Vec3(x, y, 1.0f), scale, color, eDrawText_FixedSize | eDrawText_2D | eDrawText_Monospace, format, args);
  2071.         va_end(args);
  2072.  
  2073. }
  2074.  
  2075. void C3DEngine::DrawTextRightAligned(const float x, const float y, const float scale, const ColorF& color, const char* format, ...)
  2076. {
  2077.         va_list args;
  2078.         va_start(args, format);
  2079.         IRenderAuxText::DrawText(Vec3(x, y, 1.0f), scale, color, eDrawText_FixedSize | eDrawText_Right | eDrawText_2D | eDrawText_Monospace, format, args);
  2080.         va_end(args);
  2081. }
  2082.  
  2083. int __cdecl C3DEngine__Cmp_FPS(const void* v1, const void* v2)
  2084. {
  2085.         float f1 = *(float*)v1;
  2086.         float f2 = *(float*)v2;
  2087.  
  2088.         if (f1 > f2)
  2089.                 return 1;
  2090.         else if (f1 < f2)
  2091.                 return -1;
  2092.  
  2093.         return 0;
  2094. }
  2095.  
  2096. inline void Blend(float& Stat, float StatCur, float fBlendCur)
  2097. {
  2098.         Stat = Stat * (1.f - fBlendCur) + StatCur * fBlendCur;
  2099. }
  2100.  
  2101. inline void Blend(float& Stat, int& StatCur, float fBlendCur)
  2102. {
  2103.         Blend(Stat, float(StatCur), fBlendCur);
  2104.         StatCur = int_round(Stat);
  2105. }
  2106.  
  2107. static void AppendString(char*& szEnd, const char* szToAppend)
  2108. {
  2109.         assert(szToAppend);
  2110.  
  2111.         while (*szToAppend)
  2112.                 *szEnd++ = *szToAppend++;
  2113.  
  2114.         *szEnd++ = ' ';
  2115.         *szEnd = 0;
  2116. }
  2117.  
  2118. void C3DEngine::DisplayInfo(float& fTextPosX, float& fTextPosY, float& fTextStepY, const bool bEnhanced)
  2119. {
  2120.  
  2121. #ifdef ENABLE_LW_PROFILERS
  2122.         //  FUNCTION_PROFILER_3DENGINE; causes 0 fps in stats
  2123.         static ICVar* pDisplayInfo = GetConsole()->GetCVar("r_DisplayInfo");
  2124.         int displayInfoVal = pDisplayInfo->GetIVal();
  2125.         if (displayInfoVal <= 0 || gEnv->IsDedicated())
  2126.         {
  2127.                 return;
  2128.         }
  2129.  
  2130.         const SAuxGeomRenderFlags flags = GetRenderer()->GetIRenderAuxGeom()->GetRenderFlags();
  2131.         SAuxGeomRenderFlags newFlags(flags);
  2132.         newFlags.SetAlphaBlendMode(e_AlphaNone);
  2133.         newFlags.SetMode2D3DFlag(e_Mode2D);
  2134.         newFlags.SetCullMode(e_CullModeNone);
  2135.         newFlags.SetDepthWriteFlag(e_DepthWriteOff);
  2136.         newFlags.SetDepthTestFlag(e_DepthTestOff);
  2137.         newFlags.SetFillMode(e_FillModeSolid);
  2138.  
  2139.         GetRenderer()->GetIRenderAuxGeom()->SetRenderFlags(newFlags);
  2140.  
  2141.         const int iDisplayResolutionX = GetRenderer()->GetOverlayWidth();
  2142.         const int iDisplayResolutionY = GetRenderer()->GetOverlayHeight();
  2143.         const float fDisplayMarginRes = 5.0f;
  2144.         const float fDisplayMarginNormX = (float)fDisplayMarginRes / (float)iDisplayResolutionX;
  2145.         const float fDisplayMarginNormY = (float)fDisplayMarginRes / (float)iDisplayResolutionY;
  2146.         Vec2 overscanBorderNorm = Vec2(0.0f, 0.0f);
  2147.         gEnv->pRenderer->EF_Query(EFQ_OverscanBorders, overscanBorderNorm);
  2148.  
  2149.         #if defined(INFO_FRAME_COUNTER)
  2150.         static int frameCounter = 0;
  2151.         #endif
  2152.  
  2153.         // If stat averaging is on, compute blend amount for current stats.
  2154.         float fFPS = GetTimer()->GetFrameRate();
  2155.  
  2156.         arrFPSforSaveLevelStats.push_back(SATURATEB((int)fFPS));
  2157.  
  2158.         float fBlendTime = GetTimer()->GetCurrTime();
  2159.         int iBlendMode = 0;
  2160.         float fBlendCur = GetTimer()->GetProfileFrameBlending(&fBlendTime, &iBlendMode);
  2161.  
  2162.         fTextPosY = -10;
  2163.         fTextStepY = 13;
  2164.         fTextPosX = iDisplayResolutionX - fDisplayMarginRes;
  2165.  
  2166.         if (displayInfoVal == 3 || displayInfoVal == 4)
  2167.         {
  2168.                 static float fCurrentFPS, fCurrentFrameTime;
  2169.                 Blend(fCurrentFPS, fFPS, fBlendCur);
  2170.                 Blend(fCurrentFrameTime, GetTimer()->GetRealFrameTime() * 1000.0f, fBlendCur);
  2171.                 DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 1.5f, ColorF(1.0f, 1.0f, 0.5f, 1.0f),
  2172.                                      "FPS %.1f - %.1fms", fCurrentFPS, fCurrentFrameTime);
  2173.  
  2174.                 if (displayInfoVal == 4)
  2175.                 {
  2176.                         const float fBarBottomYRes = fTextPosY + UIDRAW_TEXTSIZEFACTOR;
  2177.                         const float fBarYNorm = (fBarBottomYRes / iDisplayResolutionY) + overscanBorderNorm.y;
  2178.                         const float fBarMarkersTopYNorm = ((fBarBottomYRes - 10) / iDisplayResolutionY) + overscanBorderNorm.y;
  2179.                         const float fBarMarkersBottomYNorm = ((fBarBottomYRes + 10) / iDisplayResolutionY) + overscanBorderNorm.y;
  2180.                         const float fBarMarkersTextYRes = fBarBottomYRes + 10;
  2181.  
  2182.                         const float barMinNorm = fDisplayMarginNormX + overscanBorderNorm.x;
  2183.                         const float barMaxNorm = 0.85f - overscanBorderNorm.x;
  2184.                         const float barSizeNorm = barMaxNorm - barMinNorm;
  2185.                         const float barSizeRes = barSizeNorm * iDisplayResolutionX;
  2186.  
  2187.                         float targetFPS = gEnv->pConsole->GetCVar("r_displayinfoTargetFPS")->GetFVal();
  2188.                         if (targetFPS <= 0)
  2189.                         {
  2190.                                 targetFPS = 30;
  2191.                         }
  2192.                         float millisecTarget = (1000.0f / targetFPS);
  2193.                         float millisecMin = max((millisecTarget - 10), 0.0f);
  2194.                         float millisecMax = millisecTarget + (millisecTarget - millisecMin);
  2195.  
  2196.                         float barPercentFilled = max(min(((fCurrentFrameTime - millisecMin) / (millisecMax - millisecMin)), 1.0f), 0.0f); // clamping bar to +-10ms from target
  2197.  
  2198.                         // bar
  2199.                         ColorB barColor = (fCurrentFrameTime > millisecTarget) ? ColorB(255, 0, 0) : ColorB(0, 255, 0);
  2200.                         GetRenderer()->GetIRenderAuxGeom()->DrawLine(
  2201.                           Vec3(barMinNorm, fBarYNorm, 0), barColor,
  2202.                           Vec3(barMinNorm + (barPercentFilled * barSizeNorm), fBarYNorm, 0), barColor, (5760.0f / iDisplayResolutionY)); // 5760 = 8*720
  2203.  
  2204.                         // markers
  2205.                         GetRenderer()->GetIRenderAuxGeom()->DrawLine(Vec3(barMinNorm, fBarMarkersBottomYNorm, 0), Col_White, Vec3(barMinNorm, fBarMarkersTopYNorm, 0), Col_White, 1.0f);
  2206.                         if (millisecMin == 0)
  2207.                         {
  2208.                                 DrawTextLeftAligned(fDisplayMarginRes, fBarMarkersTextYRes, DISPLAY_INFO_SCALE_SMALL, Col_White, "%.1fms (inf FPS)", millisecMin);
  2209.                         }
  2210.                         else
  2211.                         {
  2212.                                 DrawTextLeftAligned(fDisplayMarginRes, fBarMarkersTextYRes, DISPLAY_INFO_SCALE_SMALL, Col_White, "%.1fms (%.1f FPS)", millisecMin, (1000.0f / millisecMin));
  2213.                         }
  2214.  
  2215.                         float xPos = (0.5f * barSizeNorm + barMinNorm);
  2216.                         GetRenderer()->GetIRenderAuxGeom()->DrawLine(Vec3(xPos, fBarMarkersBottomYNorm, 0), Col_White, Vec3(xPos, fBarMarkersTopYNorm, 0), Col_White, 1.0f);
  2217.                         DrawTextLeftAligned(fDisplayMarginRes + (0.5f * barSizeRes), fBarMarkersTextYRes, DISPLAY_INFO_SCALE_SMALL, Col_White, "%.1fms (%.1f FPS)", millisecTarget, targetFPS);
  2218.  
  2219.                         GetRenderer()->GetIRenderAuxGeom()->DrawLine(Vec3(barMaxNorm, fBarMarkersBottomYNorm, 0), Col_White, Vec3(barMaxNorm, fBarMarkersTopYNorm, 0), Col_White, 1.0f);
  2220.                         DrawTextLeftAligned(fDisplayMarginRes + barSizeRes, fBarMarkersTextYRes, DISPLAY_INFO_SCALE_SMALL, Col_White, "%.1fms (%.1f FPS)", millisecMax, (1000.0f / millisecMax));
  2221.                 }
  2222.  
  2223.                 GetRenderer()->GetIRenderAuxGeom()->SetRenderFlags(flags);
  2224.                 return;
  2225.         }
  2226.  
  2227.         // make level name
  2228.         char szLevelName[128];
  2229.  
  2230.         *szLevelName = 0;
  2231.         {
  2232.                 int ii;
  2233.                 for (ii = strlen(m_szLevelFolder) - 2; ii > 0; ii--)
  2234.                         if (m_szLevelFolder[ii] == '\\' || m_szLevelFolder[ii] == '/')
  2235.                                 break;
  2236.  
  2237.                 if (ii >= 0)
  2238.                 {
  2239.                         cry_strcpy(szLevelName, &m_szLevelFolder[ii + 1]);
  2240.  
  2241.                         for (int i = strlen(szLevelName) - 1; i > 0; i--)
  2242.                                 if (szLevelName[i] == '\\' || szLevelName[i] == '/')
  2243.                                         szLevelName[i] = 0;
  2244.                 }
  2245.         }
  2246.  
  2247.         Matrix33 m = Matrix33(GetRenderingCamera().GetMatrix());
  2248.         //m.OrthonormalizeFast();               // why is that needed? is it?
  2249.         Ang3 aAng = RAD2DEG(Ang3::GetAnglesXYZ(m));
  2250.         Vec3 vPos = GetRenderingCamera().GetPosition();
  2251.  
  2252.         // display out of memory message if an allocation failed
  2253.         IF (gEnv->bIsOutOfMemory, 0)
  2254.         {
  2255.                 ColorF fColor(1.0f, 0.0f, 0.0f, 1.0f);
  2256.                 DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 4.0f, fColor, "**** Out of Memory ****");
  2257.                 fTextPosY += 40.0f;
  2258.         }
  2259.         // display out of memory message if an allocation failed
  2260.         IF (gEnv->bIsOutOfVideoMemory, 0)
  2261.         {
  2262.                 ColorF fColor(1.0f, 0.0f, 0.0f, 1.0f);
  2263.                 DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 4.0f, fColor, "**** Out of Video Memory ****");
  2264.                 fTextPosY += 40.0f;
  2265.         }
  2266.  
  2267.         float fogCullDist = 0.0f;
  2268.         Vec2 vViewportScale = Vec2(0.0f, 0.0f);
  2269.         m_pRenderer->EF_Query(EFQ_GetFogCullDistance, fogCullDist);
  2270.         m_pRenderer->EF_Query(EFQ_GetViewportDownscaleFactor, vViewportScale);
  2271.  
  2272.         DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "CamPos=%.2f %.2f %.2f Angl=%3d %2d %3d ZN=%.2f ZF=%d FC=%.2f VS=%.2f,%.2f Zoom=%.2f Speed=%1.2f",
  2273.                              vPos.x, vPos.y, vPos.z, (int)aAng.x, (int)aAng.y, (int)aAng.z,
  2274.                              GetRenderingCamera().GetNearPlane(), (int)GetRenderingCamera().GetFarPlane(), fogCullDist,
  2275.                              vViewportScale.x, vViewportScale.y,
  2276.                              GetZoomFactor(), GetAverageCameraSpeed());
  2277.  
  2278.         // get version
  2279.         const SFileVersion& ver = GetSystem()->GetFileVersion();
  2280.         //char sVersion[128];
  2281.         //ver.ToString(sVersion);
  2282.  
  2283.         // Get memory usage.
  2284.         static IMemoryManager::SProcessMemInfo processMemInfo;
  2285.         {
  2286.                 static int nGetMemInfoCount = 0;
  2287.                 if ((nGetMemInfoCount & 0x1F) == 0 && GetISystem()->GetIMemoryManager())
  2288.                 {
  2289.                         // Only get mem stats every 32 frames.
  2290.                         GetISystem()->GetIMemoryManager()->GetProcessMemInfo(processMemInfo);
  2291.                 }
  2292.                 nGetMemInfoCount++;
  2293.         }
  2294.  
  2295.         bool bMultiGPU;
  2296.         m_pRenderer->EF_Query(EFQ_MultiGPUEnabled, bMultiGPU);
  2297.  
  2298.         const char* pRenderType(0);
  2299.  
  2300.         switch (gEnv->pRenderer->GetRenderType())
  2301.         {
  2302.         case eRT_OpenGL:
  2303.                 pRenderType = "GL";
  2304.                 break;
  2305.         case eRT_DX11:
  2306.                 pRenderType = "DX11";
  2307.                 break;
  2308.         case eRT_DX12:
  2309.                 pRenderType = "DX12";
  2310.                 break;
  2311.         case eRT_XboxOne:
  2312.                 pRenderType = "XboxOne";
  2313.                 break;
  2314.         case eRT_PS4:
  2315.                 pRenderType = "PS4";
  2316.                 break;
  2317.         case eRT_Null:
  2318.                 pRenderType = "Null";
  2319.                 break;
  2320.         case eRT_Undefined:
  2321.         default:
  2322.                 assert(0);
  2323.                 pRenderType = "Undefined";
  2324.                 break;
  2325.         }
  2326.  
  2327.         assert(gEnv->pSystem);
  2328.         bool bTextureStreamingEnabled = false;
  2329.         m_pRenderer->EF_Query(EFQ_TextureStreamingEnabled, bTextureStreamingEnabled);
  2330.         const bool bCGFStreaming = GetCVars()->e_StreamCgf && m_pObjManager;
  2331.         const bool bTexStreaming = gEnv->pSystem->GetStreamEngine() && bTextureStreamingEnabled;
  2332.         char szFlags[128], * szFlagsEnd = szFlags;
  2333.  
  2334.         #ifndef _RELEASE
  2335.         ESystemConfigSpec spec = GetISystem()->GetConfigSpec();
  2336.         switch (spec)
  2337.         {
  2338.         case CONFIG_CUSTOM:
  2339.                 AppendString(szFlagsEnd, "Custom");
  2340.                 break;
  2341.         case CONFIG_LOW_SPEC:
  2342.                 AppendString(szFlagsEnd, "LowSpec");
  2343.                 break;
  2344.         case CONFIG_MEDIUM_SPEC:
  2345.                 AppendString(szFlagsEnd, "MedSpec");
  2346.                 break;
  2347.         case CONFIG_HIGH_SPEC:
  2348.                 AppendString(szFlagsEnd, "HighSpec");
  2349.                 break;
  2350.         case CONFIG_VERYHIGH_SPEC:
  2351.                 AppendString(szFlagsEnd, "VeryHighSpec");
  2352.                 break;
  2353.         case CONFIG_DURANGO:
  2354.                 AppendString(szFlagsEnd, "XboxOneSpec");
  2355.                 break;
  2356.         case CONFIG_ORBIS:
  2357.                 AppendString(szFlagsEnd, "PS4Spec");
  2358.                 break;
  2359.         default:
  2360.                 assert(0);
  2361.         }
  2362.         #endif
  2363.         #ifndef CONSOLE_CONST_CVAR_MODE
  2364.         static ICVar* pMultiThreaded = GetConsole()->GetCVar("r_MultiThreaded");
  2365.         if (pMultiThreaded && pMultiThreaded->GetIVal() > 0)
  2366.         #endif
  2367.         AppendString(szFlagsEnd, "MT");
  2368.  
  2369.         char* sAAMode = NULL;
  2370.         m_pRenderer->EF_Query(EFQ_AAMode, sAAMode);
  2371.         AppendString(szFlagsEnd, sAAMode);
  2372.  
  2373.         #if defined(FEATURE_SVO_GI)
  2374.         if (GetCVars()->e_svoTI_Apply)
  2375.                 AppendString(szFlagsEnd, "SVOGI");
  2376.         #endif
  2377.  
  2378.         if (IsAreaActivationInUse())
  2379.                 AppendString(szFlagsEnd, "LA");
  2380.  
  2381.         if (bMultiGPU)
  2382.                 AppendString(szFlagsEnd, "MGPU");
  2383.  
  2384.         if (gEnv->pCryPak->GetLvlResStatus())
  2385.                 AppendString(szFlagsEnd, "LvlRes");
  2386.  
  2387.         if (gEnv->pSystem->IsDevMode())
  2388.                 AppendString(szFlagsEnd, gEnv->IsEditor() ? "DevMode (Editor)" : "DevMode");
  2389.  
  2390.         if (bCGFStreaming || bTexStreaming)
  2391.         {
  2392.                 if (bCGFStreaming && !bTexStreaming)
  2393.                         AppendString(szFlagsEnd, "StG");
  2394.                 if (bTexStreaming && !bCGFStreaming)
  2395.                         AppendString(szFlagsEnd, "StT");
  2396.                 if (bTexStreaming && bCGFStreaming)
  2397.                         AppendString(szFlagsEnd, "StGT");
  2398.         }
  2399.  
  2400.         // remove last space
  2401.         if (szFlags != szFlagsEnd)
  2402.                 *(szFlagsEnd - 1) = 0;
  2403.         #ifdef _RELEASE
  2404.         const char* mode = "Release";
  2405.         #else
  2406.         const char* mode = "Profile";
  2407.         #endif
  2408.  
  2409.         DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "%s %s %dbit %s %s [%d.%d]",
  2410.                              pRenderType, mode, (int)sizeof(char*) * 8, szFlags, szLevelName, ver.v[1], ver.v[0]);
  2411.  
  2412.         // Polys in scene
  2413.         int nPolygons, nShadowPolygons;
  2414.         GetRenderer()->GetPolyCount(nPolygons, nShadowPolygons);
  2415.         int nDrawCalls, nShadowGenDrawCalls;
  2416.         GetRenderer()->GetCurrentNumberOfDrawCalls(nDrawCalls, nShadowGenDrawCalls);
  2417.  
  2418.         int nGeomInstances = GetRenderer()->GetNumGeomInstances();
  2419.         int nGeomInstanceDrawCalls = GetRenderer()->GetNumGeomInstanceDrawCalls();
  2420.  
  2421.         if (fBlendCur != 1.f)
  2422.         {
  2423.                 // Smooth over time.
  2424.                 static float fPolygons, fShadowVolPolys, fDrawCalls, fShadowGenDrawCalls, fGeomInstances, fGeomInstanceDrawCalls;
  2425.                 Blend(fPolygons, nPolygons, fBlendCur);
  2426.                 Blend(fShadowVolPolys, nShadowPolygons, fBlendCur);
  2427.                 Blend(fDrawCalls, nDrawCalls, fBlendCur);
  2428.                 Blend(fShadowGenDrawCalls, nShadowGenDrawCalls, fBlendCur);
  2429.                 Blend(fGeomInstances, nGeomInstances, fBlendCur);
  2430.                 Blend(fGeomInstanceDrawCalls, nGeomInstanceDrawCalls, fBlendCur);
  2431.         }
  2432.  
  2433.         //
  2434.         static float m_lastAverageDPTime = -FLT_MAX;
  2435.         float curTime = gEnv->pTimer->GetAsyncCurTime();
  2436.         static int lastDrawCalls = 0;
  2437.         static int lastShadowGenDrawCalls = 0;
  2438.         static int avgPolys = 0;
  2439.         static int avgShadowPolys = 0;
  2440.         static int sumPolys = 0;
  2441.         static int sumShadowPolys = 0;
  2442.         static int nPolysFrames = 0;
  2443.         if (curTime < m_lastAverageDPTime)
  2444.         {
  2445.                 m_lastAverageDPTime = curTime;
  2446.         }
  2447.         if (curTime - m_lastAverageDPTime > 1.0f)
  2448.         {
  2449.                 lastDrawCalls = nDrawCalls;
  2450.                 lastShadowGenDrawCalls = nShadowGenDrawCalls;
  2451.                 m_lastAverageDPTime = curTime;
  2452.                 avgPolys = nPolysFrames ? sumPolys / nPolysFrames : 0;
  2453.                 avgShadowPolys = nPolysFrames ? sumShadowPolys / nPolysFrames : 0;
  2454.                 sumPolys = nPolygons;
  2455.                 sumShadowPolys = nShadowPolygons;
  2456.                 nPolysFrames = 1;
  2457.         }
  2458.         else
  2459.         {
  2460.                 nPolysFrames++;
  2461.                 sumPolys += nPolygons;
  2462.                 sumShadowPolys += nShadowPolygons;
  2463.         }
  2464.         //
  2465.  
  2466.         int nMaxDrawCalls = GetCVars()->e_MaxDrawCalls <= 0 ? 2000 : GetCVars()->e_MaxDrawCalls;
  2467.         bool bInRed = (nDrawCalls + nShadowGenDrawCalls) > nMaxDrawCalls;
  2468.  
  2469.         DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, bInRed ? Col_Red : Col_White, "DP: %04d (%04d) ShadowGen:%04d (%04d) - Total: %04d Instanced: %04d",
  2470.                              nDrawCalls, lastDrawCalls, nShadowGenDrawCalls, lastShadowGenDrawCalls, nDrawCalls + nShadowGenDrawCalls, nDrawCalls + nShadowGenDrawCalls - nGeomInstances + nGeomInstanceDrawCalls);
  2471.         #if CRY_PLATFORM_MOBILE
  2472.         bInRed = nPolygons > 500000;
  2473.         #else
  2474.         bInRed = nPolygons > 1500000;
  2475.         #endif
  2476.  
  2477.         DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, bInRed ? Col_Red : Col_White, "Polys: %03d,%03d (%03d,%03d) Shadow:%03d,%03d (%03d,%03d)",
  2478.                              nPolygons / 1000, nPolygons % 1000, avgPolys / 1000, avgPolys % 1000,
  2479.                              nShadowPolygons / 1000, nShadowPolygons % 1000, avgShadowPolys / 1000, avgShadowPolys % 1000);
  2480.  
  2481.         {
  2482.                 SShaderCacheStatistics stats;
  2483.                 m_pRenderer->EF_Query(EFQ_GetShaderCacheInfo, stats);
  2484.                 {
  2485.  
  2486.                         DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_White, "ShaderCache: %d GCM | %d Async Reqs | Compile: %s",
  2487.                                              (int)stats.m_nGlobalShaderCacheMisses, (int)stats.m_nNumShaderAsyncCompiles, stats.m_bShaderCompileActive ? "On" : "Off");
  2488.                 }
  2489.