1612 lines
50 KiB
C++
1612 lines
50 KiB
C++
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crytek Engine Source File.
|
|
// Copyright (C), Crytek Studios, 2002.
|
|
// -------------------------------------------------------------------------
|
|
// File name: 3denginerender.cpp
|
|
// Version: v1.00
|
|
// Created: 28/5/2001 by Vladimir Kajalin
|
|
// Compilers: Visual Studio.NET
|
|
// Description: rendering
|
|
// -------------------------------------------------------------------------
|
|
// History:
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "3dEngine.h"
|
|
#include "objman.h"
|
|
#include "visareas.h"
|
|
#include "terrain_water.h"
|
|
#include "partman.h"
|
|
#include "DecalManager.h"
|
|
#include "bflyes.h"
|
|
#include "rain.h"
|
|
#include "../RenderDll/Common/RendElements/CREScreenCommon.h"
|
|
|
|
#include "cbuffer.h"
|
|
|
|
#include "watervolumes.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// RenderScene
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void C3DEngine::Draw()
|
|
{
|
|
m_bProfilerEnabled = GetISystem()->GetIProfileSystem()->IsProfiling();
|
|
|
|
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
|
|
|
|
if (!m_bEnabled)
|
|
{
|
|
return;
|
|
}
|
|
#if !defined(LINUX)
|
|
if(GetCVars()->e_sleep)
|
|
Sleep(GetCVars()->e_sleep);
|
|
#endif
|
|
GetTimer()->MeasureTime("EnterDraw");
|
|
|
|
m_nRenderFrameID = GetRenderer()->GetFrameID();
|
|
|
|
if(IsCameraAnd3DEngineInvalid(GetViewCamera(), "C3DEngine::Draw"))
|
|
return;
|
|
|
|
UpdateScene();
|
|
|
|
Get3DEngine()->CheckPhysicalized(GetViewCamera().GetPos()-Vec3d(2,2,2),GetViewCamera().GetPos()+Vec3d(2,2,2));
|
|
|
|
if(GetCVars()->e_hires_screenshoot)
|
|
{
|
|
if(GetRenderer()->GetType()==R_GL_RENDERER)
|
|
MakeHiResScreenShot();
|
|
else
|
|
{
|
|
GetLog()->Log("\003e_hires_screenshoot is suported only in OpenGL");
|
|
GetCVars()->e_hires_screenshoot=0;
|
|
}
|
|
}
|
|
|
|
m_pObjManager->m_fMaxViewDistanceScale = 1.f;
|
|
|
|
if (GetSystem()->IsDedicated())
|
|
RenderScene(0);
|
|
else
|
|
{
|
|
// bad solution - only to get CryVision working properly
|
|
if(*((bool*)m_pREScreenProcess->mfGetParameter(SCREENPROCESS_NIGHTVISION, SCREENPROCESS_ACTIVE)))
|
|
{
|
|
static ICVar *pCVVolFog=GetConsole()->GetCVar("r_VolumetricFog");
|
|
int e_shadow_maps=GetCVars()->e_shadow_maps; GetCVars()->e_shadow_maps=0;
|
|
int e_stencil_shadows=GetCVars()->e_stencil_shadows; GetCVars()->e_stencil_shadows=0;
|
|
int r_VolumetricFog=pCVVolFog->GetIVal(); pCVVolFog->Set(0);
|
|
|
|
RenderScene(-1);
|
|
|
|
GetCVars()->e_shadow_maps=e_shadow_maps;
|
|
GetCVars()->e_stencil_shadows=e_stencil_shadows;
|
|
pCVVolFog->Set(r_VolumetricFog);
|
|
}
|
|
else
|
|
{
|
|
RenderScene(-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CaptureFrameBufferToFile();
|
|
|
|
GetRenderer()->EF_ClearLightsList();
|
|
|
|
// fog addons
|
|
//GetRenderer()->ResetToDefault();
|
|
/* m_pTerrain->m_pWater->DrawUnderWaterFog(
|
|
m_arrUnderWaterPlaneColor[0],
|
|
m_arrUnderWaterPlaneColor[1],
|
|
m_arrUnderWaterPlaneColor[2],
|
|
m_arrUnderWaterPlaneColor[3]);*/
|
|
|
|
// streaming state
|
|
if(GetCVars()->e_terrain_debug)
|
|
if (CStatObj::m_fStreamingTimePerFrame>0 ||
|
|
(IsOutdoorVisible() && m_pTerrain && m_pTerrain->IsStreamingNow() && GetCVars()->e_terrain && !GetCVars()->e_hires_screenshoot))
|
|
{
|
|
//GetRenderer()->ResetToDefault();
|
|
GetRenderer()->Draw2dImage(800-8,0,8,8,m_nStreamingIconTexID);
|
|
}
|
|
|
|
// black quad for simple shadow volumes
|
|
// if(GetCVars()->e_stencil_shadows)
|
|
//{
|
|
// GetRenderer()->ResetToDefault();
|
|
// GetRenderer()->DrawTransparentQuad2D(0.5);
|
|
// }
|
|
|
|
// c-buffer debug info
|
|
if(m_pObjManager && m_pObjManager->m_pCoverageBuffer && GetCVars()->e_cbuffer>=2)
|
|
{
|
|
m_pObjManager->m_pCoverageBuffer->DrawDebug(GetCVars()->e_cbuffer-1);
|
|
GetTimer()->MeasureTime("3CBDebug");
|
|
}
|
|
|
|
GetTimer()->MeasureTime("3DrawEnd");
|
|
/*
|
|
#ifdef _DEBUG
|
|
#ifdef WIN32
|
|
if(GetCVars()->e_portals>1)
|
|
{
|
|
Sleep(20);
|
|
GetTimer()->MeasureTime("3Sleep(20)");
|
|
}
|
|
#endif
|
|
#endif
|
|
*/
|
|
// Unload old stuff
|
|
if(GetCVars()->e_stream_areas)
|
|
{
|
|
if(m_pTerrain)
|
|
m_pTerrain->CheckUnload();
|
|
if(m_pVisAreaManager)
|
|
m_pVisAreaManager->CheckUnload();
|
|
}
|
|
|
|
if(m_pObjManager && GetCVars()->e_stream_cgf)
|
|
m_pObjManager->CheckUnload();
|
|
/*
|
|
CSectorInfo * pSectorInfo = m_pTerrain ? m_pTerrain->GetSecInfo(GetViewCamera().GetPos()) : 0;
|
|
uchar * pImage = new uchar[256*256*4];
|
|
if(pSectorInfo)
|
|
MakeSectorLightMap(pSectorInfo->m_nOriginX, pSectorInfo->m_nOriginY, pImage, 256);
|
|
delete [] pImage;*/
|
|
}
|
|
|
|
void C3DEngine::RenderScene(unsigned int dwDrawFlags)
|
|
{
|
|
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
|
|
if (!m_pTerrain)
|
|
return;
|
|
|
|
#ifdef WIN64
|
|
#pragma warning( push ) //AMD Port
|
|
#pragma warning( disable : 4311 )
|
|
#endif
|
|
|
|
// it's correct only before StartEf()
|
|
int nRecursionLevel = (int)GetRenderer()->EF_Query(EFQ_RecurseLevel);
|
|
assert(nRecursionLevel>=0);
|
|
m_pObjManager->m_nRenderStackLevel = m_pTerrain->m_nRenderStackLevel = nRecursionLevel;
|
|
if(m_pObjManager->m_nRenderStackLevel<0 || m_pObjManager->m_nRenderStackLevel>1)
|
|
return;
|
|
|
|
#ifdef WIN64
|
|
#pragma warning( pop ) //AMD Port
|
|
#endif
|
|
|
|
GetRenderer()->EF_StartEf();
|
|
GetTimer()->MeasureTime("3StartEf");
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// Add lsources to the renderer and register into sectors
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//if(dwDrawFlags & DLD_ADD_LIGHTSOURCES)
|
|
{ // Add lsources to the renderer and register into sectors
|
|
GetRenderer()->EF_ClearLightsList();
|
|
UpdateLightSources();
|
|
PrepareLightSourcesForRendering();
|
|
GetTimer()->MeasureTime("3LSources");
|
|
}
|
|
|
|
// prepare coverage buffer
|
|
m_pObjManager->m_pCoverageBuffer->BeginFrame(GetViewCamera());
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// Add render elements for indoor
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CCamera InitialCam = GetViewCamera();
|
|
// m_lstPortalCamera.Clear();
|
|
// m_bCameraInsideBuilding = false;
|
|
|
|
m_pDecalManager->SubmitLightHolesToRenderer();
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
// Add render elements for outdoor
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
{
|
|
for(int i=0; i<MAX_LIGHTS_NUM; i++)
|
|
m_pObjManager->m_lstLightEntities[i].Clear();
|
|
}
|
|
|
|
// for(int i=0; i<MAX_LIGHTS_NUM; i++)
|
|
// m_pObjManager->m_lstShadowEntities[i].Clear();
|
|
|
|
CStatObj::m_fStreamingTimePerFrame-=CGF_STREAMING_MAX_TIME_PER_FRAME;
|
|
if(CStatObj::m_fStreamingTimePerFrame<0)
|
|
CStatObj::m_fStreamingTimePerFrame=0;
|
|
if(CStatObj::m_fStreamingTimePerFrame>0.25f)
|
|
CStatObj::m_fStreamingTimePerFrame=0.25f;
|
|
|
|
assert(Cry3DEngineBase::m_nRenderStackLevel>=0 && Cry3DEngineBase::m_nRenderStackLevel<=1);
|
|
m_pObjManager->m_dwRecursionDrawFlags[Cry3DEngineBase::m_nRenderStackLevel] = dwDrawFlags;
|
|
|
|
m_pVisAreaManager->DrawOcclusionAreasIntoCBuffer(m_pObjManager->m_pCoverageBuffer);
|
|
GetTimer()->MeasureTime("3OcclAreas");
|
|
|
|
// draw entities inside vis areas
|
|
m_pVisAreaManager->Render(m_pObjManager);
|
|
GetTimer()->MeasureTime("3VisAreas");
|
|
|
|
if(m_pObjManager)
|
|
m_pObjManager->PreloadNearObjects();
|
|
|
|
if(GetCVars()->e_stream_preload_textures && Cry3DEngineBase::m_nRenderStackLevel==0)
|
|
{
|
|
m_fPreloadStartTime = GetCurTimeSec();
|
|
bool bPreloadOutdoor = m_pVisAreaManager->PreloadResources();
|
|
GetTimer()->MeasureTime("3TexPrelInd");
|
|
|
|
// for(int p=0; p<16; p++)
|
|
if(bPreloadOutdoor && m_pTerrain->PreloadResources() && m_pSHSky)
|
|
{
|
|
FRAME_PROFILER( "Renderer::EF_PrecacheResource", GetSystem(), PROFILE_RENDERER );
|
|
GetRenderer()->EF_PrecacheResource(m_pSHSky, 0, 1.f, 0);
|
|
}
|
|
GetTimer()->MeasureTime("3TexPrelOut");
|
|
}
|
|
|
|
/*
|
|
// precache tarrain data if camera was teleported more than 32 meters
|
|
if(m_pTerrain->m_nRenderStackLevel==0)
|
|
{
|
|
if(GetDistance(m_pTerrain->m_vPrevCameraPos, GetViewCamera().GetPos()) > 32)
|
|
m_pTerrain->PreCacheArea(GetViewCamera().GetPos(), GetViewCamera().GetZMax()*1.5f);
|
|
m_pTerrain->m_vPrevCameraPos = GetViewCamera().GetPos();
|
|
}
|
|
*/
|
|
|
|
// clear sprites list
|
|
if(m_nRenderStackLevel>=0 && m_nRenderStackLevel<=1)
|
|
{
|
|
list2<CStatObjInst*> * pList = &m_pObjManager->m_lstFarObjects[m_nRenderStackLevel];
|
|
pList->Clear();
|
|
}
|
|
else
|
|
assert(0);
|
|
|
|
CCamera prevCam = GetViewCamera();
|
|
if (IsOutdoorVisible())
|
|
{
|
|
if (m_pVisAreaManager->m_lstOutdoorPortalCameras.Count() &&
|
|
(m_pVisAreaManager->m_pCurArea || m_pVisAreaManager->m_pCurPortal))
|
|
GetViewCamera() = m_pVisAreaManager->m_lstOutdoorPortalCameras[0];
|
|
|
|
if(m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
{
|
|
if(GetCVars()->e_out_space)
|
|
RenderOutSpace();
|
|
else
|
|
RenderSkyBox(m_pSHSky);
|
|
}
|
|
|
|
// terrain and tree sprites
|
|
m_pTerrain->m_bCameraInsideBuilding = (m_pVisAreaManager->m_pCurArea || m_pVisAreaManager->m_pCurPortal);
|
|
|
|
if(m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
m_pTerrain->RenderTerrain(m_pObjManager, dwDrawFlags);
|
|
GetTimer()->MeasureTime("3Terrain");
|
|
|
|
// m_pObjManager->m_lstStatShadowsBuffer.Clear();
|
|
m_pObjManager->m_fWindForce = m_vWindForce.Length()/53.33f;
|
|
// if(m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
// m_pTerrain->RenderStaticObjects(m_pObjManager);
|
|
//GetTimer()->MeasureTime("3statobj");
|
|
|
|
// draw terrain water and beach
|
|
if( m_pVisAreaManager->IsOutdoorAreasVisible() &&
|
|
( dwDrawFlags & DLD_TERRAIN_WATER) &&
|
|
m_pTerrain->m_fDistanceToSectorWithWater>=0 &&
|
|
m_pTerrain->GetWaterLevel() && m_pTerrain->m_bOceanIsVisibe &&
|
|
m_bOcean)
|
|
{
|
|
Vec3d vBoxMin(-2048.f,-2048.f,-2048.f);
|
|
Vec3d vBoxMax(GetTerrainSize()+2048.f,GetTerrainSize()+2048.f,m_pTerrain->GetWaterLevel());
|
|
if(GetViewCamera().IsAABBVisible_exact(AABB(vBoxMin,vBoxMax)))
|
|
m_pTerrain->RenderTerrainWater(m_bShore);
|
|
}
|
|
|
|
if(m_pTerrain && m_pTerrain->m_pWater)
|
|
m_pTerrain->m_pWater->SetLastFov(GetViewCamera().GetFov());
|
|
|
|
GetTimer()->MeasureTime("3Wtr&Bch");
|
|
|
|
// if(m_pObjManager->m_pCWaterVolumes && m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
// m_pObjManager->m_pCWaterVolumes->RenderWaterVolumes();
|
|
// GetTimer()->MeasureTime("3WaterVol");
|
|
|
|
// draw sprites at far distance
|
|
if(dwDrawFlags & DLD_FAR_SPRITES)
|
|
m_pObjManager->RenderFarObjects();
|
|
GetTimer()->MeasureTime("3Far");
|
|
|
|
// render entities not registered in sectors
|
|
m_pTerrain->RenderEntitiesOutOfTheMap(m_pObjManager);
|
|
GetTimer()->MeasureTime("3EntOut");
|
|
|
|
// render terrain ground
|
|
if(dwDrawFlags & DLD_TERRAIN_FULLRES)// && !m_pTerrain->m_nRenderStackLevel)
|
|
m_pTerrain->DrawVisibleSectors();
|
|
else
|
|
m_pTerrain->RenderReflectedTerrain();
|
|
GetTimer()->MeasureTime("3TerVisSec");
|
|
|
|
// unload far and old sectors
|
|
if(!m_pTerrain->m_nRenderStackLevel)
|
|
m_pTerrain->UnloadOldSectors(m_fMaxViewDist);
|
|
GetTimer()->MeasureTime("3UnlOldSecs");
|
|
|
|
if((dwDrawFlags & DLD_TERRAIN_LIGHT) && m_pTerrain &&
|
|
m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
{ // render terrain light passes
|
|
FRAME_PROFILER( "TerrainLightPasses", GetSystem(), PROFILE_RENDERER );
|
|
for (int nLightId=0; nLightId<MAX_LIGHTS_NUM && nLightId<m_nRealLightsNum/*m_lstDynLights.Count()*/; nLightId++)
|
|
{
|
|
if(m_lstDynLights[nLightId].m_Id>=0 && !(m_lstDynLights[nLightId].m_Flags & DLF_DIRECTIONAL))
|
|
{
|
|
if(m_lstDynLights[nLightId].m_Flags & DLF_CASTSHADOW_VOLUME)
|
|
m_pObjManager->m_lstLightEntities[nLightId].Add((IEntityRender*)-1);
|
|
else if(m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
{
|
|
if( (!(m_lstDynLights[nLightId].m_Flags & DLF_DIRECTIONAL)) &&
|
|
IsSphereVisibleOnTheScreen(m_lstDynLights[nLightId].m_Origin, m_lstDynLights[nLightId].m_fRadius, 0))
|
|
m_pTerrain->RenderDLightOnHeightMap(&m_lstDynLights[nLightId]);
|
|
}
|
|
}
|
|
}
|
|
GetTimer()->MeasureTime("3TerLSrc");
|
|
}
|
|
}
|
|
else if(m_pVisAreaManager->IsSkyVisible())
|
|
RenderSkyBox(m_pSHSky);
|
|
|
|
GetViewCamera() = prevCam;
|
|
|
|
// water volumes
|
|
if(m_pObjManager->m_pCWaterVolumes && !m_pObjManager->m_nRenderStackLevel)
|
|
m_pObjManager->m_pCWaterVolumes->RenderWaterVolumes(m_pVisAreaManager->IsOutdoorAreasVisible());
|
|
GetTimer()->MeasureTime("3WaterVol");
|
|
|
|
// render/generate shadow maps from entities
|
|
m_pObjManager->RenderEntitiesShadowMapsOnTerrain(false, m_pREShadowMapGenerator);
|
|
GetTimer()->MeasureTime("3EntSMaps");
|
|
|
|
if(GetCVars()->e_stencil_shadows)
|
|
{
|
|
m_pObjManager->DrawEntitiesLightPass();
|
|
GetTimer()->MeasureTime("3EntLPass");
|
|
}
|
|
|
|
// render terrain detail textures
|
|
if(m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
if(dwDrawFlags & DLD_DETAIL_TEXTURES)
|
|
m_pTerrain->RenderDetailTextures(m_fFogNearDist,m_fFogFarDist);
|
|
GetTimer()->MeasureTime("3TerDetTex");
|
|
|
|
GetViewCamera() = InitialCam;
|
|
|
|
m_pDecalManager->Render();
|
|
GetTimer()->MeasureTime("3Decals");
|
|
|
|
if(dwDrawFlags & DLD_PARTICLES)
|
|
{
|
|
RenderTerrainParticles();
|
|
m_pPartManager->Render(m_pObjManager, m_pTerrain);
|
|
GetTimer()->MeasureTime("3Part3d");
|
|
}
|
|
|
|
if (m_pRenderCallbackFunc && GetCVars()->e_entities && !m_pObjManager->m_nRenderStackLevel)
|
|
if(m_pObjManager && m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
{
|
|
FRAME_PROFILER( "RenderScene::m_pRenderCallbackFunc", GetSystem(), PROFILE_EDITOR );
|
|
m_pRenderCallbackFunc(m_pRenderCallbackParams);
|
|
GetTimer()->MeasureTime("3RendCB");
|
|
}
|
|
|
|
RenderVolumeFogTopPlane();
|
|
GetTimer()->MeasureTime("3UW&FP");
|
|
|
|
if(m_pSHFullScreenQuad && !m_pObjManager->m_nRenderStackLevel)
|
|
{
|
|
DrawFullScreenQuad(m_pSHFullScreenQuad, false, eS_HeatVision);
|
|
GetTimer()->MeasureTime("32dquad");
|
|
}
|
|
|
|
if(GetCVars()->e_rain_amount>1)
|
|
GetCVars()->e_rain_amount=1;
|
|
else if(GetCVars()->e_rain_amount<0)
|
|
GetCVars()->e_rain_amount=0;
|
|
|
|
if(GetCVars()->e_rain_amount && (m_pVisAreaManager->IsOutdoorAreasVisible()))
|
|
{
|
|
bool bCameraInOutdoors = !m_pVisAreaManager->m_pCurArea && !(m_pVisAreaManager->m_pCurPortal && m_pVisAreaManager->m_pCurPortal->m_lstConnections.Count()>1);
|
|
if(bCameraInOutdoors)
|
|
DrawFullScreenQuad(m_pSHRainMap, false);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
ProcessScreenEffects();
|
|
|
|
SetupDistanceFog();
|
|
|
|
if(!m_pTerrain->m_nRenderStackLevel)
|
|
SetupClearColor();
|
|
|
|
IRenderer * ppp = GetRenderer();
|
|
{
|
|
FRAME_PROFILER( "Renderer::EF_EndEf3D", GetSystem(), PROFILE_RENDERER );
|
|
|
|
if(!m_nRenderStackLevel)
|
|
{
|
|
if(GetCVars()->e_widescreen)
|
|
{ // set view port to 16/9 mode
|
|
int nVPSizeX = GetRenderer()->GetWidth();
|
|
int nVPSizeY = GetRenderer()->GetWidth()*9/16;
|
|
int nOffsetY = (GetRenderer()->GetHeight()-nVPSizeY)/2;
|
|
int nOffsetX = 0;
|
|
if(nOffsetY<0)
|
|
{
|
|
nOffsetY = 0;
|
|
nVPSizeX = GetRenderer()->GetHeight()*16/9;
|
|
nVPSizeY = GetRenderer()->GetHeight();
|
|
nOffsetX = (GetRenderer()->GetWidth()-nVPSizeX)/2;
|
|
}
|
|
|
|
// draw2 black textures
|
|
GetRenderer()->SetViewport(0,0,GetRenderer()->GetWidth(),GetRenderer()->GetHeight());
|
|
GetRenderer()->SetState(GS_NODEPTHTEST);
|
|
|
|
float fRatioX = 800.f/GetRenderer()->GetWidth();
|
|
float fRatioY = 600.f/GetRenderer()->GetHeight();
|
|
if(nOffsetY>0)
|
|
{
|
|
GetRenderer()->Draw2dImage(0,0,nVPSizeX*fRatioX,(600-(nVPSizeY*fRatioY))/2,m_nBlackTexID);
|
|
GetRenderer()->Draw2dImage(0,(nOffsetY+nVPSizeY)*fRatioY,nVPSizeX*fRatioX,(600-(nVPSizeY*fRatioY))/2,m_nBlackTexID);
|
|
}
|
|
else if(nOffsetX>0)
|
|
{
|
|
GetRenderer()->Draw2dImage(0,0,(800-(nVPSizeX*fRatioX))/2,nVPSizeY*fRatioY,m_nBlackTexID);
|
|
GetRenderer()->Draw2dImage((nOffsetX+nVPSizeX)*fRatioX,0,(800-(nVPSizeX*fRatioX))/2,nVPSizeY*fRatioY,m_nBlackTexID);
|
|
}
|
|
|
|
// set viewport
|
|
GetRenderer()->SetViewport(nOffsetX,nOffsetY,nVPSizeX,nVPSizeY);
|
|
}
|
|
else
|
|
GetRenderer()->SetViewport(0,0,GetRenderer()->GetWidth(),GetRenderer()->GetHeight());
|
|
}
|
|
|
|
GetRenderer()->EF_EndEf3D(SHDF_ALLOWHDR | SHDF_SORT);
|
|
}
|
|
GetRenderer()->EnableFog(false);
|
|
//GetRenderer()->EF_ClearLightsList();
|
|
if(!m_pObjManager->m_nRenderStackLevel)
|
|
GetTimer()->MeasureTime("3EndEf");
|
|
/*
|
|
// example for wemade
|
|
// setup vertices
|
|
SColorVert arrVerts[4];
|
|
Vec3d vPos(142,46,20);
|
|
Vec3d right(1,0,0);
|
|
Vec3d up(0,1,0);
|
|
UCol ucResCol;
|
|
ucResCol.dcolor= (DWORD)-1;
|
|
arrVerts[0].vert = (-right-up) + vPos;
|
|
arrVerts[0].dTC[0] = 1;
|
|
arrVerts[0].dTC[1] = 0;
|
|
arrVerts[0].color = ucResCol;
|
|
arrVerts[1].vert = ( right-up) + vPos;
|
|
arrVerts[1].dTC[0] = 1;
|
|
arrVerts[1].dTC[1] = 1;
|
|
arrVerts[1].color = ucResCol;
|
|
arrVerts[2].vert = ( right+up) + vPos;
|
|
arrVerts[2].dTC[0] = 0;
|
|
arrVerts[2].dTC[1] = 1;
|
|
arrVerts[2].color = ucResCol;
|
|
arrVerts[3].vert = (-right+up) + vPos;
|
|
arrVerts[3].dTC[0] = 0;
|
|
arrVerts[3].dTC[1] = 0;
|
|
arrVerts[3].color = ucResCol;
|
|
|
|
// make indices
|
|
byte arrIndices[6] = {0,1,2,0,2,3};
|
|
|
|
// get shader
|
|
IShader * pShader = GetRenderer()->EF_LoadShader("ParticleLight", eSH_World);
|
|
int nTexId = GetRenderer()->LoadTexture("detail");
|
|
|
|
// now render
|
|
// make object
|
|
CCObject * pOb = GetRenderer()->EF_GetObject(true);
|
|
pOb->m_Trans(0,0,0);
|
|
pOb->m_Angs(0,0,0);
|
|
pOb->m_AmbColor = Col_White;
|
|
pOb->m_RenderState = GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
|
|
pOb->m_NumCM = nTexId;
|
|
|
|
GetRenderer()->EF_StartEf();
|
|
GetRenderer()->EF_AddSpriteToScene(pShader->GetID(), 4, arrVerts, pOb, arrIndices, 6);
|
|
GetRenderer()->EF_EndEf3D(true);
|
|
|
|
*/
|
|
/* {
|
|
// i use static in this example only allow to have initialization and rendering in one place
|
|
static CLeafBuffer * pLeafBuffer = 0;
|
|
if(!pLeafBuffer)
|
|
{
|
|
const int nChunksNum = 16;
|
|
struct_VERTEX_FORMAT_P3F tmp;
|
|
list2<struct_VERTEX_FORMAT_P3F> lstVertices;
|
|
list2<ushort> lstIndices;
|
|
list2<ushort> lstChunkFirstIdxId;
|
|
|
|
// contruct some geometry
|
|
for(float r1=0, r2=1.f; r2<=nChunksNum; r1+=1.f, r2+=1.f)
|
|
{
|
|
lstChunkFirstIdxId.Add(lstIndices.Count());
|
|
|
|
for(int i=0; i<=360; i+=30)
|
|
{
|
|
float rad = (i) * (gf_PI/180);
|
|
|
|
tmp.x = Fsin(rad)*(r2);
|
|
tmp.y = Fcos(rad)*(r2);
|
|
tmp.z = 0;
|
|
|
|
lstIndices.Add(lstVertices.Count());
|
|
lstVertices.Add(tmp);
|
|
|
|
tmp.x = Fsin(rad)*(r1);
|
|
tmp.y = Fcos(rad)*(r1);
|
|
tmp.z = 0;
|
|
|
|
lstIndices.Add(lstVertices.Count());
|
|
lstVertices.Add(tmp);
|
|
}
|
|
}
|
|
|
|
lstChunkFirstIdxId.Add(lstIndices.Count());
|
|
|
|
// make leaf buffer
|
|
pLeafBuffer = GetRenderer()->CreateLeafBufferInitialized(
|
|
lstVertices.GetElements(), lstVertices.Count(), VERTEX_FORMAT_P3F,
|
|
lstIndices.GetElements(), lstIndices.Count(), R_PRIMV_MULTI_STRIPS,
|
|
"VolFogTopCircle", eBT_Dynamic,nChunksNum, 0x1000);
|
|
|
|
// make shader
|
|
IShader * pShader = GetRenderer()->EF_LoadShader("WaterVolume",eSH_World);
|
|
|
|
// define chunks
|
|
for(int i=0; i<nChunksNum; i++)
|
|
{
|
|
pLeafBuffer->SetChunk(pShader,
|
|
lstIndices[lstChunkFirstIdxId[i]],lstVertices.Count()/(lstChunkFirstIdxId.Count()-1),
|
|
lstChunkFirstIdxId[i],lstChunkFirstIdxId[i+1]-lstChunkFirstIdxId[i], i);
|
|
}
|
|
}
|
|
|
|
// render
|
|
CCObject * pObject = GetRenderer()->EF_GetObject(true);
|
|
Vec3d vPos(142,46,20);
|
|
pObject->m_Trans = vPos;
|
|
pObject->m_Scale = Vec3d(0.1f,0.1f,0.1f);
|
|
|
|
GetRenderer()->EF_StartEf();
|
|
pLeafBuffer->AddRenderElements(pObject);
|
|
GetRenderer()->EF_EndEf3D(true);
|
|
} */
|
|
|
|
/*
|
|
list2<struct_VERTEX_FORMAT_P3F_COL4UB> lstVert;
|
|
list2<unsigned short> lstIdx;
|
|
static CLeafBuffer * pLeafBuffer = NULL;
|
|
static IShader* pTempShader = NULL;
|
|
|
|
int offset = 2;
|
|
struct_VERTEX_FORMAT_P3F_COL4UB center;
|
|
center.x = 142;
|
|
center.y = 46;
|
|
center.z = 20;
|
|
center.r = 255;
|
|
center.g = 255;
|
|
center.b = 255;
|
|
center.a = 255;
|
|
struct_VERTEX_FORMAT_P3F_COL4UB temp[3];
|
|
|
|
temp[0] = center;
|
|
temp[0].x -= offset;
|
|
temp[0].z -= offset;
|
|
|
|
temp[1] = center;
|
|
temp[1].z += offset;
|
|
|
|
temp[2] = center;
|
|
temp[2].x += offset;
|
|
temp[2].z -= offset;
|
|
|
|
lstVert.Add( temp[0]);
|
|
lstVert.Add( temp[1]);
|
|
lstVert.Add( temp[2]);
|
|
|
|
lstIdx.Add(0);
|
|
lstIdx.Add(1);
|
|
lstIdx.Add(2);
|
|
|
|
static int minit=1;
|
|
if(minit)
|
|
{
|
|
minit=0;
|
|
pTempShader= GetSystem()->GetIRenderer()->EF_LoadShader("WaterVolume", eSH_World, 0);
|
|
|
|
pLeafBuffer = GetSystem()->GetIRenderer()->CreateLeafBufferInitialized(
|
|
&temp[0], lstVert.Count(), VERTEX_FORMAT_P3F_COL4UB,
|
|
lstIdx.GetElements(), lstIdx.Count(),
|
|
R_PRIMV_TRIANGLES,"TerrainSector");
|
|
|
|
pLeafBuffer->SetChunk(pTempShader,0,3,0,3);
|
|
pLeafBuffer->SetShader(pTempShader);
|
|
}
|
|
|
|
//In Rendering part
|
|
{
|
|
|
|
//In this position, want to change some vertex pos.
|
|
|
|
//and want to render. Below is Possible?
|
|
|
|
CCObject * pObject = GetRenderer()->EF_GetObject(true);
|
|
// Vec3d vPos(142,46,20);
|
|
//pObject->m_Trans = vPos;
|
|
//pObject->m_Scale = Vec3d(0.1f,0.1f,0.1f);
|
|
// pObject->m_NumCM = 4096;
|
|
|
|
// pLeafBuffer->UpdateVertices()
|
|
|
|
GetSystem()->GetIRenderer()->EF_StartEf();
|
|
pLeafBuffer->AddRenderElements();
|
|
GetSystem()->GetIRenderer()->EF_EndEf3D(true);
|
|
}
|
|
*/
|
|
|
|
m_pObjManager->m_nRenderStackLevel = m_pTerrain->m_nRenderStackLevel = 0;
|
|
|
|
// Light info is not valid after C3Dengine::Render()
|
|
// m_lstDynLights.Clear();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void C3DEngine::RenderSkyBox(IShader *pSH)
|
|
{
|
|
// skybox
|
|
if (pSH && m_pRESky && GetCVars()->e_sky_box)
|
|
{
|
|
CCObject * pObj = GetRenderer()->EF_GetObject(true, -1);
|
|
pObj->m_Matrix.SetTranslationMat(GetViewCamera().GetPos());
|
|
pObj->m_Matrix = Matrix33::CreateRotationZ(gf_DEGTORAD*m_fSkyBoxAngle)*pObj->m_Matrix;
|
|
pObj->m_ObjFlags |= FOB_TRANS_TRANSLATE | FOB_TRANS_ROTATE;
|
|
if(!m_pObjManager->m_nRenderStackLevel)
|
|
{
|
|
pObj->m_nScissorX1 = GetViewCamera().m_ScissorInfo.x1;
|
|
pObj->m_nScissorY1 = GetViewCamera().m_ScissorInfo.y1;
|
|
pObj->m_nScissorX2 = GetViewCamera().m_ScissorInfo.x2;
|
|
pObj->m_nScissorY2 = GetViewCamera().m_ScissorInfo.y2;
|
|
|
|
if(m_pVisAreaManager->m_lstIndoorActiveOcclVolumes.Count())
|
|
{
|
|
Matrix44 matInv = pObj->m_Matrix;
|
|
matInv.Invert44();
|
|
Vec3d vPos;
|
|
|
|
for(int i=0; i<MAX_SKY_OCCLAREAS_NUM; i++)
|
|
{
|
|
if(i<m_pVisAreaManager->m_lstIndoorActiveOcclVolumes.Count())
|
|
{
|
|
vPos = matInv.TransformPointOLD(m_pVisAreaManager->m_lstIndoorActiveOcclVolumes[i]->m_arrvActiveVerts[0]);
|
|
m_pRESky->m_arrvPortalVerts[i][0].xyz = vPos;
|
|
m_pRESky->m_arrvPortalVerts[i][0].color.bcolor[3] = 255;
|
|
|
|
vPos = matInv.TransformPointOLD(m_pVisAreaManager->m_lstIndoorActiveOcclVolumes[i]->m_arrvActiveVerts[1]);
|
|
m_pRESky->m_arrvPortalVerts[i][1].xyz = vPos;
|
|
m_pRESky->m_arrvPortalVerts[i][1].color.bcolor[3] = 255;
|
|
|
|
vPos = matInv.TransformPointOLD(m_pVisAreaManager->m_lstIndoorActiveOcclVolumes[i]->m_arrvActiveVerts[3]);
|
|
m_pRESky->m_arrvPortalVerts[i][2].xyz = vPos;
|
|
m_pRESky->m_arrvPortalVerts[i][2].color.bcolor[3] = 255;
|
|
|
|
vPos = matInv.TransformPointOLD(m_pVisAreaManager->m_lstIndoorActiveOcclVolumes[i]->m_arrvActiveVerts[2]);
|
|
m_pRESky->m_arrvPortalVerts[i][3].xyz = vPos;
|
|
m_pRESky->m_arrvPortalVerts[i][3].color.bcolor[3] = 255;
|
|
}
|
|
else
|
|
memset(m_pRESky->m_arrvPortalVerts[i],0,sizeof(m_pRESky->m_arrvPortalVerts[i]));
|
|
}
|
|
}
|
|
else
|
|
memset(m_pRESky->m_arrvPortalVerts,0,sizeof(m_pRESky->m_arrvPortalVerts));
|
|
}
|
|
else
|
|
memset(m_pRESky->m_arrvPortalVerts,0,sizeof(m_pRESky->m_arrvPortalVerts));
|
|
|
|
m_pRESky->m_fTerrainWaterLevel = max(0,m_pTerrain->GetWaterLevel());
|
|
m_pRESky->m_fSkyBoxStretching = m_fSkyBoxStretching;
|
|
|
|
GetRenderer()->EF_AddEf(0, m_pRESky, pSH, NULL, pObj, 0, NULL,EFSLIST_PREPROCESS);
|
|
}
|
|
|
|
// sun lensflares
|
|
if(m_pSHLensFlares && GetCVars()->e_sun==1 )//&&
|
|
// GetViewCamera().GetPos().z > GetWaterLevel(&GetViewCamera().GetPos()))
|
|
{ // no sun flare under water because of conflict with vol fog
|
|
if (m_pSHLensFlares->GetREs()->Num())
|
|
{
|
|
//get the object
|
|
if (!m_SunObject[m_pTerrain->m_nRenderStackLevel])
|
|
m_SunObject[m_pTerrain->m_nRenderStackLevel] = GetRenderer()->EF_GetObject(false, -1);
|
|
else
|
|
GetRenderer()->EF_GetObject(false, m_SunObject[m_pTerrain->m_nRenderStackLevel]->m_Id);
|
|
|
|
Vec3d vTrans = GetSunPosition(false);
|
|
vTrans.z *= m_fSunHeightScale;
|
|
Vec3d vCamDir = -GetViewCamera().GetVCMatrixD3D9().GetOrtZ();
|
|
if(vTrans.Dot(vCamDir)<0)
|
|
return; // sun is behind the camera
|
|
|
|
float fDist = vTrans.GetDistance(GetViewCamera().GetPos());
|
|
if(fDist > GetViewCamera().GetZMax()) // sun is behind far cliping plane - move it closer
|
|
{
|
|
float t = GetViewCamera().GetZMax() / fDist;
|
|
vTrans = GetViewCamera().GetPos() + 0.9f*t*(vTrans-GetViewCamera().GetPos());
|
|
}
|
|
|
|
m_SunObject[m_pTerrain->m_nRenderStackLevel]->m_Matrix = GetTranslationMat(vTrans);
|
|
m_SunObject[m_pTerrain->m_nRenderStackLevel]->m_ObjFlags |= FOB_DRSUN | FOB_TRANS_TRANSLATE;
|
|
m_SunObject[m_pTerrain->m_nRenderStackLevel]->m_TempVars[2] = 1.0f;
|
|
float fWaterLevel = GetWaterLevel();
|
|
float fCamZ = GetViewCamera().GetPos().z;
|
|
if((fCamZ-fWaterLevel)*(vTrans.z-fWaterLevel)>0)
|
|
m_SunObject[m_pTerrain->m_nRenderStackLevel]->m_SortId = -1000000;
|
|
else
|
|
m_SunObject[m_pTerrain->m_nRenderStackLevel]->m_SortId = 1000000;
|
|
GetRenderer()->EF_AddEf(0, m_pSHLensFlares->GetREs()->Get(0), m_pSHLensFlares, NULL, m_SunObject[m_pTerrain->m_nRenderStackLevel], -1, NULL, EFSLIST_DISTSORT);
|
|
}
|
|
}
|
|
}
|
|
|
|
void C3DEngine::DrawText(float x, float y, const char * format, ...)
|
|
{
|
|
char buffer[512];
|
|
va_list args;
|
|
va_start(args, format);
|
|
vsprintf(buffer, format, args);
|
|
va_end(args);
|
|
|
|
ICryFont *pCryFont = GetSystem()->GetICryFont();
|
|
if (!pCryFont)
|
|
return;
|
|
|
|
IFFont *pFont = pCryFont->GetFont("console");
|
|
if (!pFont)
|
|
return;
|
|
|
|
pFont->UseRealPixels(false);
|
|
pFont->SetSameSize(true);
|
|
pFont->SetCharWidthScale(1);
|
|
pFont->SetSize(vector2f(16, 16));
|
|
pFont->SetColor(color4f(1,1,1,1));
|
|
pFont->SetCharWidthScale(.65f);
|
|
pFont->DrawString( x-pFont->GetCharWidth() * strlen(buffer) * pFont->GetCharWidthScale(), y, buffer );
|
|
}
|
|
|
|
void C3DEngine::DisplayInfo(float & fTextPosX, float & fTextPosY, float & fTextStepY)
|
|
{
|
|
//GetRenderer()->ResetToDefault();
|
|
//GetRenderer()->EnableDepthTest(false);
|
|
GetRenderer()->SetState(GS_NODEPTHTEST);
|
|
|
|
static float fCurrentFPS = 0;
|
|
static float fFrameRateSecMin=GetTimer()->GetFrameRate();
|
|
static float fFrameRateSecMax=GetTimer()->GetFrameRate();
|
|
|
|
|
|
float fFrameRate = 0;
|
|
float fFrameTimeInSec=GetTimer()->GetFrameTime();
|
|
|
|
if(fFrameTimeInSec>0.0f) // to prevent divide by zero
|
|
fFrameRate = 1.0f / fFrameTimeInSec;
|
|
|
|
if(fFrameRate>999.0f) // to ensure number is <=999 (for nice printout)
|
|
fFrameRate=999.0f;
|
|
|
|
{ // current fps
|
|
static float START_TIME = GetCurAsyncTimeSec()*1000;
|
|
static int iFrameRateCount=0;
|
|
static float fFrameRateSum=0;
|
|
static float fFrameRateMin=0;
|
|
static float fFrameRateMax=0;
|
|
|
|
float time = GetCurAsyncTimeSec()*1000;
|
|
|
|
iFrameRateCount++;
|
|
|
|
fFrameRateSum += fFrameRate;
|
|
|
|
if (fFrameRateMin > fFrameRate) fFrameRateMin = fFrameRate;
|
|
if (fFrameRateMax < fFrameRate) fFrameRateMax = fFrameRate;
|
|
|
|
|
|
float diff = (time-START_TIME);
|
|
|
|
if(diff>500) // every second
|
|
{
|
|
if(iFrameRateCount)
|
|
fCurrentFPS = (float)(fFrameRateSum/(float)iFrameRateCount);
|
|
else
|
|
fCurrentFPS=0.0f;
|
|
|
|
fFrameRateSecMin = fFrameRateMin;
|
|
fFrameRateSecMax = fFrameRateMax;
|
|
|
|
fFrameRateMin = fFrameRate;
|
|
fFrameRateMax = fFrameRate;
|
|
fFrameRateSum = 0;
|
|
iFrameRateCount = 0;
|
|
START_TIME = time;
|
|
}
|
|
else
|
|
if(diff<0) // timer was reseted
|
|
{
|
|
START_TIME = GetCurAsyncTimeSec()*1000;
|
|
iFrameRateCount=0;
|
|
fFrameRateSum=0;
|
|
fFrameRateMin=0;
|
|
fFrameRateMax=0;
|
|
}
|
|
}
|
|
|
|
int nPolygons,nShadowVolPolys;
|
|
|
|
GetRenderer()->GetPolyCount(nPolygons,nShadowVolPolys);
|
|
|
|
// Cam pos
|
|
Vec3d vPos = GetViewCamera().GetPos();
|
|
|
|
// make level name
|
|
char szLevelName[16];
|
|
|
|
*szLevelName=0;
|
|
{
|
|
int i;
|
|
for(i=strlen(m_szLevelFolder)-2; i>0; i--)
|
|
if(m_szLevelFolder[i] == '\\' || m_szLevelFolder[i] == '/')
|
|
break;
|
|
|
|
if(i>=0)
|
|
{
|
|
strncpy(szLevelName,&m_szLevelFolder[i+1],sizeof(szLevelName));
|
|
szLevelName[sizeof(szLevelName)-1] = 0;
|
|
|
|
for(int i=strlen(szLevelName)-1; i>0; i--)
|
|
if(szLevelName[i] == '\\' || szLevelName[i] == '/')
|
|
szLevelName[i]=0;
|
|
}
|
|
}
|
|
|
|
fTextPosX = 800-5;
|
|
fTextPosY = -10;
|
|
fTextStepY = 16;
|
|
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY,
|
|
"CamPos=%3d %3d %3d Angl=%3d %2d %3d",
|
|
(int)vPos.x,(int)vPos.y,(int)vPos.z,
|
|
(int)GetViewCamera().GetAngles().x,
|
|
(int)GetViewCamera().GetAngles().y,
|
|
(int)GetViewCamera().GetAngles().z);
|
|
|
|
// get verson
|
|
const SFileVersion & ver = GetSystem()->GetFileVersion();
|
|
char sVersion[128];
|
|
ver.ToString(sVersion);
|
|
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY, "Ver=%s Lev=%s", sVersion,szLevelName);
|
|
|
|
// Polys in scene
|
|
if (nShadowVolPolys>0)
|
|
DrawText(fTextPosX, fTextPosY+=fTextStepY,"Polygons %d(SV=%d)", nPolygons,nShadowVolPolys);
|
|
else
|
|
DrawText(fTextPosX, fTextPosY+=fTextStepY,"Polygons %2d,%003d", nPolygons/1000, nPolygons-nPolygons/1000*1000);
|
|
|
|
{ // Polys per sec
|
|
int per_sec = (int)(nPolygons*fCurrentFPS);
|
|
int m = per_sec /1000000;
|
|
int t = (per_sec - m*1000000)/1000;
|
|
int n = per_sec - m*1000000 - t*1000;
|
|
DrawText(fTextPosX, fTextPosY+=fTextStepY,"P/Sec %003d,%003d,%003d", m,t,n);
|
|
}
|
|
|
|
if(GetCVars()->e_stream_cgf && m_pObjManager)
|
|
{
|
|
int nReady=0, nTotalInStreaming=0, nTotal=0;
|
|
m_pObjManager->GetObjectsStreamingStatus(nReady,nTotalInStreaming,nTotal);
|
|
DrawText(fTextPosX, fTextPosY+=fTextStepY,"Objects streaming: %d/%d/%d", nReady, nTotalInStreaming, nTotal);
|
|
}
|
|
|
|
if(GetCVars()->e_stream_areas && m_pTerrain)
|
|
{
|
|
int nReady=0, nTotal=0;
|
|
|
|
m_pTerrain->GetStreamingStatus(nReady,nTotal);
|
|
DrawText(fTextPosX, fTextPosY+=fTextStepY,"Terrain streaming: %d/%d", nReady, nTotal);
|
|
|
|
m_pVisAreaManager->GetStreamingStatus(nReady,nTotal);
|
|
DrawText(fTextPosX, fTextPosY+=fTextStepY,"Indoor streaming: %d/%d", nReady, nTotal);
|
|
}
|
|
|
|
// fps
|
|
const int nStartFrame = -50;
|
|
static int nFrames = nStartFrame;
|
|
static float fStartTime = GetTimer()->gfGetTime();
|
|
|
|
float fCurrentTime = GetTimer()->gfGetTime();
|
|
|
|
if(fCurrentTime<fStartTime) // timer was reseted
|
|
fStartTime=fCurrentTime;
|
|
|
|
if(GetCVars()->e_timedemo_frames && nFrames>=0)
|
|
{ // print current and average fps
|
|
if(fStartTime != GetTimer()->gfGetTime())
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY, "FPS %3d (%3d..%3d) / %3.2f / %3.2f",
|
|
(int)fCurrentFPS, (int)fFrameRateSecMin, (int)fFrameRateSecMax, fFrameRate,
|
|
float(nFrames)/(GetTimer()->gfGetTime()-fStartTime) );
|
|
}
|
|
else
|
|
{ // print current fps
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY, "FPS %3d (%3d..%3d) / %5.1f",
|
|
(int)fCurrentFPS, (int)fFrameRateSecMin, (int)fFrameRateSecMax, fFrameRate );
|
|
}
|
|
|
|
// exit when x frames rendered
|
|
if(nFrames > GetCVars()->e_timedemo_frames && GetCVars()->e_timedemo_frames)
|
|
{
|
|
char buffer[256];
|
|
snprintf(buffer, sizeof(buffer), "Average FPS = %3.2f", float(nFrames)/(GetTimer()->gfGetTime()-fStartTime));
|
|
|
|
#ifdef GAMECUBE
|
|
OSReport("- Timedemo result -\n");
|
|
#elif (defined (PS2) || defined (_XBOX) || defined(LINUX))
|
|
snprintf(buffer, sizeof(buffer),"- Timedemo result -");
|
|
OutputDebugString(buffer);
|
|
#else
|
|
if(GetCVars()->e_timedemo_frames>10)
|
|
MessageBox(0, buffer, "- Timedemo result -", MB_OK);
|
|
#endif
|
|
|
|
GetLog()->Log ("\001Timedemo quit");
|
|
GetConsole()->Exit("Timedemo quit 1");
|
|
}
|
|
|
|
// Exit unconditionally when x seconds of game passed
|
|
// THis is used for automatic multipass profiling with VTune 6.x
|
|
if (GetCVars()->e_timedemo_milliseconds)
|
|
{
|
|
if (int((GetTimer()->gfGetTime() - fStartTime)*1000) > GetCVars()->e_timedemo_milliseconds)
|
|
{
|
|
GetLog()->Log ("\001Timedemo quit in %dms (started at %g sec, stopped at %g sec) Average %3.2f FPS", GetCVars()->e_timedemo_milliseconds, fStartTime, GetTimer()->gfGetTime(), float(nFrames - nStartFrame)/(GetTimer()->gfGetTime()-fStartTime));
|
|
GetSystem()->Quit();
|
|
}
|
|
}
|
|
|
|
nFrames++;
|
|
|
|
/* if(GetCVars()->e_video_buffer_stats)
|
|
{
|
|
char * szRendererStatus = GetRenderer()->GetStatusText(eRS_VidBuffer);
|
|
GetRenderer()->TextToScreen( fTextPosX-44, fTextPosY+=fTextStepY, szRendererStatus );
|
|
}*/
|
|
|
|
if(GetCVars()->e_particles_debug)
|
|
{
|
|
int nSprites = 0, nFree = 0, nEmitters = 0;
|
|
int nParts = m_pPartManager->Count(&nSprites, &nFree, &nEmitters);
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY,
|
|
"Parts=%4d/%4d Emit=%d Sprites=%4d", nParts, nFree, nEmitters, nSprites );
|
|
}
|
|
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY, "ViewDist=%d/%.1f", (int)m_fMaxViewDist, m_pObjManager ? m_pObjManager->m_fMaxViewDistanceScale : 0);
|
|
|
|
{
|
|
int nActive=0;
|
|
char sLightsList[512]="";
|
|
for(int i=0; i<m_lstDynLights.Count(); i++)
|
|
{
|
|
if(m_lstDynLights[i].m_Id>=0 && m_lstDynLights[i].m_fRadius >= 0.5f )
|
|
if(!(m_lstDynLights[i].m_Flags & DLF_FAKE))
|
|
{
|
|
nActive++;
|
|
|
|
if(i<4)
|
|
{
|
|
strcat(sLightsList, m_lstDynLights[i].m_sDebugName);
|
|
if(i<m_lstDynLights.Count()-1)
|
|
strcat(sLightsList,",");
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef WIN64
|
|
#pragma warning( push ) //AMD Port
|
|
#pragma warning( disable : 4267 )
|
|
#endif
|
|
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY, "DynLights=%s(%d/%d/%d)", sLightsList, nActive, m_nRealLightsNum, m_lstDynLights.Count() );
|
|
}
|
|
|
|
#ifdef WIN64
|
|
#pragma warning( pop ) //AMD Port
|
|
#endif
|
|
|
|
if(GetCVars()->e_terrain_debug>1)
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY, m_pTerrain->m_pTexturePool->GetStatusText(m_pTerrain));
|
|
|
|
// Render path info
|
|
char * pRenderPath;
|
|
static ICVar *p_r_SM30PATH = GetConsole()->GetCVar("r_SM30PATH");
|
|
static ICVar *p_r_SM2XPATH = GetConsole()->GetCVar("r_SM2XPATH");
|
|
static ICVar *p_r_Quality_BumpMapping = GetConsole()->GetCVar("r_Quality_BumpMapping");
|
|
if(p_r_SM30PATH->GetIVal())
|
|
pRenderPath = "SM3.0 Path";
|
|
else
|
|
if(p_r_SM2XPATH->GetIVal())
|
|
pRenderPath = "SM2.X path";
|
|
else
|
|
if(p_r_Quality_BumpMapping->GetIVal() == 3)
|
|
pRenderPath = "SM2.0 Path";
|
|
else
|
|
if(p_r_Quality_BumpMapping->GetIVal() > 0)
|
|
pRenderPath = "SM1.1 Path";
|
|
else
|
|
pRenderPath = "FP Path";
|
|
|
|
DrawText( fTextPosX, fTextPosY+=fTextStepY, "Render path = %s", pRenderPath );
|
|
}
|
|
|
|
#define DLD_SET_CVAR(VarName,FlagName)\
|
|
int VarName = GetCVars()->VarName;\
|
|
if(!(DrawFlags & FlagName))\
|
|
GetCVars()->VarName = 0;\
|
|
|
|
#define DLD_RESTORE_CVAR(VarName) \
|
|
GetCVars()->VarName = VarName; \
|
|
|
|
void C3DEngine::DrawLowDetail(const int & DrawFlags)
|
|
{
|
|
if(m_pObjManager)
|
|
m_pObjManager->m_fMaxViewDistanceScale = 1.f;
|
|
m_nRenderFrameID = GetRenderer()->GetFrameID();
|
|
|
|
DLD_SET_CVAR(e_shadow_maps,DLD_SHADOW_MAPS);
|
|
DLD_SET_CVAR(e_stencil_shadows,DLD_STENCIL_SHADOWS);
|
|
DLD_SET_CVAR(e_brushes,DLD_STATIC_OBJECTS);
|
|
DLD_SET_CVAR(e_vegetation,DLD_STATIC_OBJECTS);
|
|
DLD_SET_CVAR(e_entities,DLD_ENTITIES);
|
|
DLD_SET_CVAR(e_terrain,DLD_TERRAIN);
|
|
DLD_SET_CVAR(e_player,DLD_FIRST_PERSON_CAMERA_OWNER);
|
|
|
|
RenderScene(DrawFlags);
|
|
|
|
DLD_RESTORE_CVAR(e_shadow_maps);
|
|
DLD_RESTORE_CVAR(e_stencil_shadows);
|
|
DLD_RESTORE_CVAR(e_brushes);
|
|
DLD_RESTORE_CVAR(e_vegetation);
|
|
DLD_RESTORE_CVAR(e_entities);
|
|
DLD_RESTORE_CVAR(e_terrain);
|
|
DLD_RESTORE_CVAR(e_player);
|
|
}
|
|
|
|
void C3DEngine::DrawTerrainDetailTextureLayers()
|
|
{
|
|
GetRenderer()->EnableFog(false);
|
|
|
|
// float fRainFactor = 1.f;// - 0.75f*GetCVars()->e_rain_amount;
|
|
//float fFogDistance = (m_fFogNearDist*fRainFactor + m_fFogFarDist *fRainFactor)*0.5f;
|
|
|
|
// m_pTerrain->DrawDetailTextures(m_fFogNearDist,m_fFogFarDist,true);
|
|
SetupDistanceFog();
|
|
|
|
// m_pObjManager->DrawShadows(0); // draw tree shadows
|
|
m_pObjManager->DrawEntitiesShadowSpotsOnTerrain();
|
|
}
|
|
|
|
void C3DEngine::DrawFarTrees()
|
|
{
|
|
m_pObjManager->DrawFarObjects(m_fMaxViewDist);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Particles, decals above the water
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void C3DEngine::DrawTerrainParticles(IShader * pShader)
|
|
{
|
|
if(pShader == m_pSHTerrainParticles)
|
|
{
|
|
m_pDecalManager->DrawBigDecalsOnTerrain();
|
|
/* if(!(m_pVisAreaManager->m_pCurArea || m_pVisAreaManager->m_pCurPortal)
|
|
&& IsOutdoorVisible() && m_pVisAreaManager->IsOutdoorAreasVisible())
|
|
m_pBFManager->Render(m_pTerrain);*/
|
|
}
|
|
// else
|
|
// assert(0);
|
|
}
|
|
|
|
void C3DEngine::RenderTerrainParticles()
|
|
{
|
|
if (m_pRETerrainParticles && GetCVars()->e_decals)
|
|
{
|
|
CCObject * pObj = GetRenderer()->EF_GetObject(true, -1);
|
|
pObj->m_Matrix.SetIdentity();
|
|
GetRenderer()->EF_AddEf(0, m_pRETerrainParticles, m_pSHTerrainParticles, NULL, pObj, 0, NULL, EFSLIST_STENCIL | eS_TerrainDetailTextures);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void C3DEngine::SetupDistanceFog()
|
|
{
|
|
if(!m_pTerrain)
|
|
return;
|
|
|
|
VolumeInfo * pFogVolume = NULL;
|
|
if(GetCVars()->e_use_global_fog_in_fog_volumes && !m_nRenderStackLevel)
|
|
{ // find camera fog volume
|
|
CVisArea * pCurVisArea = m_pVisAreaManager->m_pCurArea ? m_pVisAreaManager->m_pCurArea : m_pVisAreaManager->m_pCurPortal;
|
|
if(pCurVisArea)
|
|
{ // find indoor fog volume with this id
|
|
/*for(int f=0; f<m_pTerrain->m_lstFogVolumes.Count(); f++)
|
|
if(m_pTerrain->m_lstFogVolumes[f].bOcean)
|
|
if(m_pTerrain->m_lstFogVolumes[f].nRendererVolumeID == pCurVisArea->m_nFogVolumeId)
|
|
break;
|
|
|
|
if(f<m_pTerrain->m_lstFogVolumes.Count() && m_pTerrain->m_lstFogVolumes[f].vBoxMax.z>GetViewCamera().GetPos().z)
|
|
pFogVolume = &m_pTerrain->m_lstFogVolumes[f];*/
|
|
}
|
|
else
|
|
{ // find outdoor fog volume
|
|
int f;
|
|
for(f=0; f<m_pTerrain->m_lstFogVolumes.Count(); f++)
|
|
if(m_pTerrain->m_lstFogVolumes[f].bOcean)
|
|
if(m_pTerrain->m_lstFogVolumes[f].InsideBBox(GetViewCamera().GetPos()))
|
|
break;
|
|
|
|
if(f<m_pTerrain->m_lstFogVolumes.Count())
|
|
pFogVolume = &m_pTerrain->m_lstFogVolumes[f];
|
|
}
|
|
}
|
|
|
|
GetRenderer()->SetFog(0,
|
|
pFogVolume ? pFogVolume->fMaxViewDist*0.01f : m_fFogNearDist,
|
|
pFogVolume ? pFogVolume->fMaxViewDist : m_fFogFarDist ,
|
|
GetRenderer()->EF_GetHeatVision() ? Vec3d(0,0,0) :
|
|
pFogVolume ? pFogVolume->vColor : m_vFogColor,
|
|
R_FOGMODE_LINEAR);
|
|
GetRenderer()->EnableFog(GetCVars()->e_fog>0);
|
|
}
|
|
|
|
void C3DEngine::RenderOutSpace()
|
|
{
|
|
/* if (m_pREOutSpace && GetCVars()->e_out_space)
|
|
{
|
|
CCObject * pObj = GetRenderer()->EF_GetObject(true, -1);
|
|
pObj->m_Matrix.SetTranslationMat(GetViewCamera().GetPos());
|
|
GetRenderer()->EF_AddEf(0, m_pREOutSpace, m_pSHOutSpace, NULL, pObj, 0, NULL);
|
|
}*/
|
|
}
|
|
|
|
void C3DEngine::DrawFullScreenQuad(IShader *pShader, bool bRectangle, EF_Sort eSort)
|
|
{
|
|
if(m_pRE2DQuad)
|
|
{
|
|
CCObject * pObj = GetRenderer()->EF_GetObject(true, -1);
|
|
pObj->m_Matrix.SetIdentity();
|
|
pObj->m_Color = m_vFogColor;
|
|
pObj->m_Color.a = 1.f;
|
|
pObj->m_nTemplId = bRectangle;
|
|
GetRenderer()->EF_AddEf(0, m_pRE2DQuad, pShader, NULL, pObj, 0, NULL, eSort);
|
|
}
|
|
}
|
|
/*
|
|
void C3DEngine::RenderTerrainShadowMaps()
|
|
{
|
|
if(!GetCVars()->e_shadow_maps)
|
|
return;
|
|
|
|
CCObject * pRendObject = GetRenderer()->EF_GetObject(true, -1);
|
|
pRendObject->m_Trans.Clear();
|
|
pRendObject->m_Angs.Clear();
|
|
/// m_pRETerrainShadowMap->m_pShadowFrustum = 0;
|
|
// m_pRETerrainShadowMap->m_fAlpha = -1;
|
|
// GetRenderer()->EF_AddEf(0, m_pRETerrainShadowMap, "TerrainShadowMaps", pRendObject, 0, NULL, eS_TerrainDetailTextures);
|
|
} */
|
|
|
|
// render fog plane circle if camera is inside volume
|
|
void C3DEngine::RenderVolumeFogTopPlane()
|
|
{
|
|
FUNCTION_PROFILER( GetSystem(),PROFILE_3DENGINE );
|
|
if(m_pObjManager->m_nRenderStackLevel)
|
|
return;
|
|
|
|
Vec3d vCamPos = GetViewCamera().GetPos();
|
|
|
|
CSectorInfo * pSectorInfo = m_pTerrain ? m_pTerrain->GetSectorFromPoint((int)vCamPos.x,(int)vCamPos.y) : 0;
|
|
VolumeInfo * pFogVolume = 0;
|
|
if(!pSectorInfo || !pSectorInfo->m_pFogVolume || vCamPos.z>pSectorInfo->m_pFogVolume->vBoxMax.z)
|
|
{
|
|
}
|
|
else
|
|
pFogVolume = pSectorInfo->m_pFogVolume;
|
|
|
|
CVisArea * pCurVisArea = m_pVisAreaManager->m_pCurArea ? m_pVisAreaManager->m_pCurArea : m_pVisAreaManager->m_pCurPortal;
|
|
|
|
if(pCurVisArea && pCurVisArea->m_nFogVolumeId)
|
|
{
|
|
int f;
|
|
for(f=0; f<m_pTerrain->m_lstFogVolumes.Count(); f++)
|
|
if(m_pTerrain->m_lstFogVolumes[f].nRendererVolumeID == pCurVisArea->m_nFogVolumeId)
|
|
break;
|
|
|
|
if(f<m_pTerrain->m_lstFogVolumes.Count())
|
|
pFogVolume = &m_pTerrain->m_lstFogVolumes[f];
|
|
}
|
|
|
|
if(!pFogVolume)
|
|
return;
|
|
|
|
if( vCamPos.z<GetWaterLevel() && pSectorInfo && pFogVolume->bOcean )
|
|
return;
|
|
|
|
// do not render fog top plane if it is higher than current visarea
|
|
if( pCurVisArea && pFogVolume->vBoxMax.z>pCurVisArea->m_vBoxMax.z )
|
|
return;
|
|
|
|
const int nChunksNum = 16;
|
|
|
|
if(!m_pFogTopPlane)
|
|
{
|
|
struct_VERTEX_FORMAT_P3F tmp;
|
|
list2<struct_VERTEX_FORMAT_P3F> lstVertices;
|
|
list2<ushort> lstIndices;
|
|
list2<ushort> lstFirstIdxId;
|
|
|
|
for(float r1=0, r2=1.f; r2<=nChunksNum; r1+=1.f, r2+=1.f)
|
|
{
|
|
lstFirstIdxId.Add(lstIndices.Count());
|
|
|
|
for(int i=0; i<=360; i+=30)
|
|
{
|
|
float rad = (i) * (gf_PI/180);
|
|
|
|
tmp.xyz.x = cry_sinf(rad)*(r2);
|
|
tmp.xyz.y = cry_cosf(rad)*(r2);
|
|
tmp.xyz.z = 0;
|
|
|
|
lstIndices.Add(lstVertices.Count());
|
|
lstVertices.Add(tmp);
|
|
|
|
tmp.xyz.x = cry_sinf(rad)*(r1);
|
|
tmp.xyz.y = cry_cosf(rad)*(r1);
|
|
tmp.xyz.z = 0;
|
|
|
|
lstIndices.Add(lstVertices.Count());
|
|
lstVertices.Add(tmp);
|
|
}
|
|
}
|
|
|
|
lstFirstIdxId.Add(lstIndices.Count());
|
|
|
|
m_pFogTopPlane = GetRenderer()->CreateLeafBufferInitialized(
|
|
lstVertices.GetElements(), lstVertices.Count(), VERTEX_FORMAT_P3F,
|
|
lstIndices.GetElements(), lstIndices.Count(), R_PRIMV_MULTI_STRIPS,
|
|
"VolFogTopCircle", eBT_Dynamic,nChunksNum, 0x1000);
|
|
|
|
for(int i=0; i<nChunksNum; i++)
|
|
{
|
|
m_pFogTopPlane->SetChunk(pFogVolume->pShader,
|
|
lstIndices[lstFirstIdxId[i]],lstVertices.Count()/(lstFirstIdxId.Count()-1),
|
|
lstFirstIdxId[i],lstFirstIdxId[i+1]-lstFirstIdxId[i], i);
|
|
}
|
|
}
|
|
|
|
CCObject * pObj = GetRenderer()->EF_GetObject(true);
|
|
pObj->m_Matrix.SetTranslationMat(Vec3d(vCamPos.x, vCamPos.y, pFogVolume->vBoxMax.z+0.0125f));
|
|
|
|
float fSize = (pFogVolume->vBoxMax-pFogVolume->vBoxMin).Length();
|
|
float s= (1.f/nChunksNum*fSize)*2;
|
|
pObj->m_Matrix = Matrix33::CreateScale(Vec3d(s,s,s))*pObj->m_Matrix;
|
|
pObj->m_ObjFlags |= FOB_TRANS_TRANSLATE | FOB_TRANS_SCALE;
|
|
|
|
if(pFogVolume->nRendererVolumeID)
|
|
m_pFogTopPlane->AddRenderElements(pObj, 0, -1, pFogVolume->nRendererVolumeID);
|
|
}
|
|
|
|
void C3DEngine::MakeHiResScreenShot()
|
|
{
|
|
#if !defined(LINUX)
|
|
static int nFileId = 0;
|
|
static int nHiResShootCounter = -1;
|
|
static list2<unsigned char*> lstSubImages;
|
|
|
|
if(nHiResShootCounter<0)
|
|
{ // start loop
|
|
lstSubImages.Clear();
|
|
nHiResShootCounter = GetCVars()->e_hires_screenshoot*GetCVars()->e_hires_screenshoot;
|
|
GetConsole()->SetScrollMax(0);
|
|
GetTimer()->Enable(false);
|
|
|
|
// find free group id
|
|
while(1)
|
|
{
|
|
char sFileName[256];
|
|
snprintf(sFileName, sizeof(sFileName), "HiResScreenShoots\\%dx%d_%d.tga",
|
|
nFileId,
|
|
GetRenderer()->GetWidth()*GetCVars()->e_hires_screenshoot,
|
|
GetRenderer()->GetHeight()*GetCVars()->e_hires_screenshoot);
|
|
|
|
FILE * fp = GetSystem()->GetIPak()->FOpen(sFileName,"rb");
|
|
if (!fp)
|
|
break; // file doesn't exist
|
|
GetSystem()->GetIPak()->FClose(fp);
|
|
nFileId++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//IVO: I have a special solution for HiResScreenShoots on GameCube!
|
|
#ifndef GAMECUBE
|
|
CreateDirectory("HiResScreenShoots",0);
|
|
lstSubImages.Add(0);
|
|
lstSubImages.Last() = new unsigned char [GetRenderer()->GetWidth()*GetRenderer()->GetHeight()*4];
|
|
GetRenderer()->ReadFrameBuffer(lstSubImages.Last(),
|
|
GetRenderer()->GetWidth(), GetRenderer()->GetHeight(), false, true);
|
|
#endif
|
|
|
|
}
|
|
|
|
nHiResShootCounter--;
|
|
|
|
if(nHiResShootCounter<0)
|
|
{ // end loop
|
|
// restore initial state
|
|
GetRenderer()->SetViewport(0,0,GetRenderer()->GetWidth(),GetRenderer()->GetHeight());
|
|
GetConsole()->SetScrollMax(300);
|
|
GetTimer()->Enable(true);
|
|
|
|
char sFileName[256];
|
|
snprintf(sFileName, sizeof(sFileName), "HiResScreenShoots\\%dx%d_%d.tga",
|
|
nFileId,
|
|
GetRenderer()->GetWidth()*GetCVars()->e_hires_screenshoot,
|
|
GetRenderer()->GetHeight()*GetCVars()->e_hires_screenshoot);
|
|
GetLog()->UpdateLoadingScreen("Writing %s ...", sFileName);
|
|
|
|
int nFinSize = lstSubImages.Count()*
|
|
GetRenderer()->GetWidth()*GetRenderer()->GetHeight()*4;
|
|
|
|
unsigned char * pFinalImage = NULL;
|
|
|
|
#ifdef WIN32
|
|
pFinalImage = (unsigned char * )VirtualAlloc(NULL,nFinSize,MEM_COMMIT,PAGE_READWRITE);
|
|
#endif // WIN32
|
|
|
|
if(pFinalImage)
|
|
{
|
|
// Save final image
|
|
for(int nImageId=0; nImageId<lstSubImages.Count(); nImageId++)
|
|
{
|
|
int pos_X = (lstSubImages.Count()-nImageId-1)%GetCVars()->e_hires_screenshoot*GetRenderer()->GetWidth();
|
|
int pos_Y = (lstSubImages.Count()-nImageId-1)/GetCVars()->e_hires_screenshoot*GetRenderer()->GetHeight();
|
|
|
|
for(int x=0; x<GetRenderer()->GetWidth(); x++)
|
|
for(int y=0; y<GetRenderer()->GetHeight(); y++)
|
|
{
|
|
int nFin = ((pos_X+x) + (pos_Y+y)*GetRenderer()->GetWidth()*GetCVars()->e_hires_screenshoot);
|
|
int nSub = (( x) + ( y)*GetRenderer()->GetWidth());
|
|
|
|
for(int c=0; c<4; c++)
|
|
pFinalImage[nFin*4+c] = lstSubImages[nImageId][nSub*4+c];
|
|
}
|
|
|
|
delete [] lstSubImages[nImageId];
|
|
lstSubImages[nImageId]=0;
|
|
}
|
|
|
|
GetRenderer()->WriteTGA(pFinalImage,
|
|
GetRenderer()->GetWidth()*GetCVars()->e_hires_screenshoot,
|
|
GetRenderer()->GetHeight()*GetCVars()->e_hires_screenshoot,
|
|
sFileName, 32);
|
|
|
|
#ifdef WIN32
|
|
VirtualFree( pFinalImage,0,MEM_RELEASE );
|
|
#endif // WIN32
|
|
|
|
GetLog()->LogPlus(" done");
|
|
}
|
|
else
|
|
GetLog()->Log("Error making screenshot: memory allocation error (%d MB)", nFinSize/1024/1024);
|
|
|
|
GetCVars()->e_hires_screenshoot = 0;
|
|
}
|
|
else
|
|
{
|
|
GetRenderer()->SetViewport(
|
|
-nHiResShootCounter%GetCVars()->e_hires_screenshoot*GetRenderer()->GetWidth(),
|
|
-nHiResShootCounter/GetCVars()->e_hires_screenshoot*GetRenderer()->GetHeight(),
|
|
GetRenderer()->GetWidth()*GetCVars()->e_hires_screenshoot,
|
|
GetRenderer()->GetHeight()*GetCVars()->e_hires_screenshoot);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void C3DEngine::CaptureFrameBufferToFile()
|
|
{
|
|
#if !defined(LINUX)
|
|
if(GetCVars()->e_capture_frames>0)
|
|
{
|
|
char * pFolderName = GetCVars()->e_capture_folder->GetString();
|
|
CreateDirectory(pFolderName,0);
|
|
|
|
char * pFileFormat = GetCVars()->e_capture_file_format->GetString();
|
|
strlwr(pFileFormat);
|
|
|
|
// get image
|
|
unsigned char * pImage = new unsigned char [GetRenderer()->GetWidth()*GetRenderer()->GetHeight()*4];
|
|
GetRenderer()->ReadFrameBuffer(pImage, GetRenderer()->GetWidth(), GetRenderer()->GetHeight(), true, true);
|
|
|
|
|
|
{ // flip up side down
|
|
unsigned char * pImageFlip = new unsigned char [GetRenderer()->GetWidth()*GetRenderer()->GetHeight()*4];
|
|
int nSizeY = GetRenderer()->GetHeight();
|
|
int nSizeX = GetRenderer()->GetWidth();
|
|
for (int i=0; i<nSizeY; i++)
|
|
{
|
|
for (int j=0; j<nSizeX; j++)
|
|
{
|
|
pImageFlip[(i*nSizeX+j)*4+0] = pImage[((nSizeY-1-i)*nSizeX+j)*4+0];
|
|
pImageFlip[(i*nSizeX+j)*4+1] = pImage[((nSizeY-1-i)*nSizeX+j)*4+1];
|
|
pImageFlip[(i*nSizeX+j)*4+2] = pImage[((nSizeY-1-i)*nSizeX+j)*4+2];
|
|
pImageFlip[(i*nSizeX+j)*4+3] = pImage[((nSizeY-1-i)*nSizeX+j)*4+3];
|
|
}
|
|
}
|
|
delete [] pImage;
|
|
pImage = pImageFlip;
|
|
}
|
|
|
|
// save to file
|
|
char sFileName[256];
|
|
if(!strcmp(pFileFormat,"jpg"))
|
|
{
|
|
snprintf(sFileName, sizeof(sFileName), "%s\\Frame%06d.jpg", pFolderName, GetCVars()->e_capture_frames-1);
|
|
GetLog()->UpdateLoadingScreen("Writing %s ...", sFileName);
|
|
GetRenderer()->WriteJPG(pImage,GetRenderer()->GetWidth(), GetRenderer()->GetHeight(), sFileName);
|
|
}
|
|
else if(!strcmp(pFileFormat,"tga"))
|
|
{
|
|
snprintf(sFileName, sizeof(sFileName), "%s\\Frame%06d.tga", pFolderName, GetCVars()->e_capture_frames-1);
|
|
GetLog()->UpdateLoadingScreen("Writing %s ...", sFileName);
|
|
GetRenderer()->WriteTGA(pImage,GetRenderer()->GetWidth(), GetRenderer()->GetHeight(), sFileName, 32);
|
|
}
|
|
else
|
|
Warning(0,0,"C3DEngine::CaptureFrameBuffer: Unsupported image file format specified: %s", pFileFormat);
|
|
|
|
delete [] pImage;
|
|
|
|
GetCVars()->e_capture_frames++;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void C3DEngine::DrawShadowSpotOnTerrain(Vec3d vPos, float fRadius)
|
|
{
|
|
// calc area
|
|
int x1=int(vPos.x-fRadius*0.75)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
|
|
int y1=int(vPos.y-fRadius*0.75)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
|
|
int x2=int(vPos.x+CTerrain::GetHeightMapUnitSize()+fRadius*0.75)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
|
|
int y2=int(vPos.y+CTerrain::GetHeightMapUnitSize()+fRadius*0.75)/CTerrain::GetHeightMapUnitSize()*CTerrain::GetHeightMapUnitSize();
|
|
|
|
// limits
|
|
if(x1<0) x1=0;
|
|
if(y1<0) y1=0;
|
|
if(x2>=CTerrain::GetTerrainSize()) x2=CTerrain::GetTerrainSize();
|
|
if(y2>=CTerrain::GetTerrainSize()) y2=CTerrain::GetTerrainSize();
|
|
|
|
// fill buffer and draw
|
|
list2<struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F> verts;
|
|
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F tmp;
|
|
tmp.color.dcolor = -1;
|
|
|
|
float fAlpha = (1.f-(
|
|
m_pObjManager->m_vOutdoorAmbientColor.x+
|
|
m_pObjManager->m_vOutdoorAmbientColor.y+
|
|
m_pObjManager->m_vOutdoorAmbientColor.z)*0.3333f*0.5f);
|
|
|
|
float fHeight = vPos.z - GetTerrainElevation(vPos.x,vPos.y) - fRadius;
|
|
|
|
if(fHeight>=fRadius)
|
|
return;
|
|
|
|
if(fHeight<0)
|
|
fHeight=0;
|
|
|
|
fHeight = 1.f-fHeight/(fRadius);
|
|
|
|
tmp.color.bcolor[3] = uchar(min(255.f,fAlpha*fHeight*255.f));
|
|
|
|
GetRenderer()->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
|
|
GetRenderer()->SetColorOp(eCO_MODULATE, eCO_MODULATE, eCA_Texture|(eCA_Constant<<3), eCA_Texture|(eCA_Constant<<3));
|
|
GetRenderer()->SetCullMode(R_CULL_DISABLE);
|
|
GetRenderer()->SetTexture(m_nShadowSpotTexId);
|
|
ITexPic * pTexPic = GetRenderer()->EF_GetTextureByID(m_nShadowSpotTexId);
|
|
if(pTexPic)
|
|
pTexPic->SetFilter(FILTER_LINEAR);
|
|
GetRenderer()->SetTexClampMode(true);
|
|
|
|
for(int x=x1; x<x2; x+=CTerrain::GetHeightMapUnitSize())
|
|
{
|
|
verts.Clear();
|
|
for(int y=y1; y<=y2; y+=CTerrain::GetHeightMapUnitSize())
|
|
{
|
|
tmp.xyz.x = (float)x;
|
|
tmp.xyz.y = (float)y;
|
|
tmp.xyz.z = Get3DEngine()->GetTerrainZ(x,y)+0.07f;
|
|
tmp.st[0] = (((float)x)-vPos.x)/fRadius+0.5f;
|
|
tmp.st[1] = 1.f-((((float)y)-vPos.y)/fRadius+0.5f);
|
|
verts.Add(tmp);
|
|
|
|
tmp.xyz.x = (float)(x+CTerrain::GetHeightMapUnitSize());
|
|
tmp.xyz.y = (float)y;
|
|
tmp.xyz.z = Get3DEngine()->GetTerrainZ((x+CTerrain::GetHeightMapUnitSize()),y)+0.07f;
|
|
tmp.st[0] = (((float)(x+CTerrain::GetHeightMapUnitSize()))-vPos.x)/fRadius+0.5f;
|
|
tmp.st[1] = 1.f-((((float)y)-vPos.y)/fRadius+0.5f);
|
|
verts.Add(tmp);
|
|
}
|
|
|
|
if(verts.Count())
|
|
GetRenderer()->DrawTriStrip(&(CVertexBuffer (&verts[0].xyz.x,VERTEX_FORMAT_P3F_COL4UB_TEX2F)),verts.Count());
|
|
}
|
|
}
|
|
|
|
void C3DEngine::SetupClearColor()
|
|
{
|
|
bool bCameraInOutdoors = !m_pVisAreaManager->m_pCurArea && !(m_pVisAreaManager->m_pCurPortal && m_pVisAreaManager->m_pCurPortal->m_lstConnections.Count()>1);
|
|
GetRenderer()->SetClearColor(bCameraInOutdoors ? m_vFogColor : Vec3d(0,0,0));
|
|
|
|
if(bCameraInOutdoors)
|
|
if(GetViewCamera().GetPos().z<GetWaterLevel() && m_pTerrain)
|
|
{
|
|
CSectorInfo * pSectorInfo = m_pTerrain ? m_pTerrain->GetSectorFromPoint((int)GetViewCamera().GetPos().x,(int)GetViewCamera().GetPos().y) : 0;
|
|
if(!pSectorInfo || !pSectorInfo->m_pFogVolume || GetViewCamera().GetPos().z>pSectorInfo->m_pFogVolume->vBoxMax.z)
|
|
{
|
|
if(GetViewCamera().GetPos().z<GetWaterLevel() && m_pTerrain &&
|
|
m_pTerrain->m_lstFogVolumes.Count() &&
|
|
m_pTerrain->m_lstFogVolumes[0].bOcean)
|
|
GetRenderer()->SetClearColor( m_pTerrain->m_lstFogVolumes[0].vColor );
|
|
}
|
|
//else if( pSectorInfo->m_pFogVolume->bOcean ) // makes problems if there is no skybox
|
|
//GetRenderer()->SetClearColor( pSectorInfo->m_pFogVolume->vColor );
|
|
}
|
|
}
|