diff --git a/source/graphics/Camera.cpp b/source/graphics/Camera.cpp index 0862317479..aae4832fd2 100644 --- a/source/graphics/Camera.cpp +++ b/source/graphics/Camera.cpp @@ -15,11 +15,6 @@ * along with 0 A.D. If not, see . */ -/* - * CCamera holds a view and a projection matrix. It also has a frustum - * which can be used to cull objects for rendering. - */ - #include "precompiled.h" #include "Camera.h" @@ -32,6 +27,7 @@ #include "ps/Game.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" CCamera::CCamera() @@ -275,7 +271,7 @@ CVector3D CCamera::GetWorldCoordinates(int px, int py, bool aboveWater) const CPlane plane; plane.Set(CVector3D(0.f, 1.f, 0.f), // upwards normal - CVector3D(0.f, g_Renderer.GetWaterManager().m_WaterHeight, 0.f)); // passes through water plane + CVector3D(0.f, g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight, 0.f)); // passes through water plane bool gotWater = plane.FindRayIntersection( origin, dir, &waterPoint ); @@ -353,7 +349,7 @@ CVector3D CCamera::GetFocus() const CPlane plane; plane.Set(CVector3D(0.f, 1.f, 0.f), // upwards normal - CVector3D(0.f, g_Renderer.GetWaterManager().m_WaterHeight, 0.f)); // passes through water plane + CVector3D(0.f, g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight, 0.f)); // passes through water plane bool gotWater = plane.FindRayIntersection( origin, dir, &waterPoint ); diff --git a/source/graphics/CameraController.cpp b/source/graphics/CameraController.cpp index f29729f3fb..459fb6a2f6 100644 --- a/source/graphics/CameraController.cpp +++ b/source/graphics/CameraController.cpp @@ -36,6 +36,7 @@ #include "ps/TouchInput.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpPosition.h" @@ -578,7 +579,7 @@ void CCameraController::FocusHeight(bool smooth) const float ground = std::max( g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel(nearPoint.X, nearPoint.Z), - g_Renderer.GetWaterManager().m_WaterHeight); + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight); // filter ground levels for smooth camera movement const float filtered_near_ground = g_Game->GetWorld()->GetTerrain()->GetFilteredGroundLevel(nearPoint.X, nearPoint.Z, near_radius); @@ -587,7 +588,7 @@ void CCameraController::FocusHeight(bool smooth) // filtered maximum visible ground level in view const float filtered_ground = std::max( std::max(filtered_near_ground, filtered_pivot_ground), - g_Renderer.GetWaterManager().m_WaterHeight); + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight); // target camera height above pivot point const float pivot_height = -forwards.Y * (m_Zoom.GetSmoothedValue() - m_ViewNear); diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 1fdac9082d..f9ebae8483 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -55,6 +55,7 @@ #include "ps/TouchInput.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpPosition.h" @@ -167,7 +168,7 @@ CGameView::CGameView(CGame *pGame): m(new CGameViewImpl(pGame)) { m->CullCamera = m->ViewCamera; - g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera); + g_Renderer.GetSceneRenderer().SetSceneCamera(m->ViewCamera, m->CullCamera); } CGameView::~CGameView() @@ -233,7 +234,7 @@ void CGameView::BeginFrame() // Set up cull camera m->CullCamera = m->ViewCamera; } - g_Renderer.SetSceneCamera(m->ViewCamera, m->CullCamera); + g_Renderer.GetSceneRenderer().SetSceneCamera(m->ViewCamera, m->CullCamera); CheckLightEnv(); @@ -242,7 +243,7 @@ void CGameView::BeginFrame() void CGameView::Render() { - g_Renderer.RenderScene(*this); + g_Renderer.GetSceneRenderer().RenderScene(*this); } /////////////////////////////////////////////////////////// @@ -254,7 +255,7 @@ void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c) PROFILE3("submit terrain"); CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain(); - float waterHeight = g_Renderer.GetWaterManager().m_WaterHeight + 0.001f; + float waterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight + 0.001f; const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide(); // find out which patches will be drawn @@ -302,7 +303,7 @@ void CGameView::CheckLightEnv() void CGameView::UnloadResources() { g_TexMan.UnloadTerrainTextures(); - g_Renderer.GetWaterManager().UnloadWaterTextures(); + g_Renderer.GetSceneRenderer().GetWaterManager().UnloadWaterTextures(); } void CGameView::Update(const float deltaRealTime) @@ -387,30 +388,31 @@ InReaction CGameView::HandleEvent(const SDL_Event_* ev) case SDL_HOTKEYPRESS: { std::string hotkey = static_cast(ev->ev.user.data1); + CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); if (hotkey == "wireframe") { if (g_XmppClient && g_rankedGame == true) break; - else if (g_Renderer.GetModelRenderMode() == SOLID) + else if (sceneRenderer.GetModelRenderMode() == SOLID) { - g_Renderer.SetTerrainRenderMode(EDGED_FACES); - g_Renderer.SetWaterRenderMode(EDGED_FACES); - g_Renderer.SetModelRenderMode(EDGED_FACES); - g_Renderer.SetOverlayRenderMode(EDGED_FACES); + sceneRenderer.SetTerrainRenderMode(EDGED_FACES); + sceneRenderer.SetWaterRenderMode(EDGED_FACES); + sceneRenderer.SetModelRenderMode(EDGED_FACES); + sceneRenderer.SetOverlayRenderMode(EDGED_FACES); } - else if (g_Renderer.GetModelRenderMode() == EDGED_FACES) + else if (sceneRenderer.GetModelRenderMode() == EDGED_FACES) { - g_Renderer.SetTerrainRenderMode(WIREFRAME); - g_Renderer.SetWaterRenderMode(WIREFRAME); - g_Renderer.SetModelRenderMode(WIREFRAME); - g_Renderer.SetOverlayRenderMode(WIREFRAME); + sceneRenderer.SetTerrainRenderMode(WIREFRAME); + sceneRenderer.SetWaterRenderMode(WIREFRAME); + sceneRenderer.SetModelRenderMode(WIREFRAME); + sceneRenderer.SetOverlayRenderMode(WIREFRAME); } else { - g_Renderer.SetTerrainRenderMode(SOLID); - g_Renderer.SetWaterRenderMode(SOLID); - g_Renderer.SetModelRenderMode(SOLID); - g_Renderer.SetOverlayRenderMode(SOLID); + sceneRenderer.SetTerrainRenderMode(SOLID); + sceneRenderer.SetWaterRenderMode(SOLID); + sceneRenderer.SetModelRenderMode(SOLID); + sceneRenderer.SetOverlayRenderMode(SOLID); } return IN_HANDLED; } diff --git a/source/graphics/MiniMapTexture.cpp b/source/graphics/MiniMapTexture.cpp index a1aaa384de..7d8466e51c 100644 --- a/source/graphics/MiniMapTexture.cpp +++ b/source/graphics/MiniMapTexture.cpp @@ -38,6 +38,7 @@ #include "ps/XML/Xeromyces.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "scriptinterface/Object.h" #include "simulation2/Simulation2.h" @@ -180,7 +181,7 @@ CMiniMapTexture::~CMiniMapTexture() void CMiniMapTexture::Update(const float UNUSED(deltaRealTime)) { - if (m_WaterHeight != g_Renderer.GetWaterManager().m_WaterHeight) + if (m_WaterHeight != g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight) { m_TerrainTextureDirty = true; m_FinalTextureDirty = true; @@ -263,7 +264,7 @@ void CMiniMapTexture::RebuildTerrainTexture(const CTerrain* terrain) const u32 width = m_MapSize - 1; const u32 height = m_MapSize - 1; - m_WaterHeight = g_Renderer.GetWaterManager().m_WaterHeight; + m_WaterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight; m_TerrainTextureDirty = false; for (u32 j = 0; j < height; ++j) diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index 41340a36d2..a7802e1904 100644 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -36,6 +36,7 @@ #include "ps/Game.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "simulation2/Simulation2.h" #include @@ -80,7 +81,7 @@ bool CObjectEntry::BuildVariation(const std::vector*>& comp if (variation.decal.m_SizeX && variation.decal.m_SizeZ) { - CMaterial material = g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material); + CMaterial material = g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(m_Base->m_Material); for (const CObjectBase::Samp& samp : m_Samplers) { @@ -103,7 +104,7 @@ bool CObjectEntry::BuildVariation(const std::vector*>& comp if (!variation.particles.empty()) { - m_Model = new CModelParticleEmitter(g_Renderer.GetParticleManager().LoadEmitterType(variation.particles)); + m_Model = new CModelParticleEmitter(g_Renderer.GetSceneRenderer().GetParticleManager().LoadEmitterType(variation.particles)); return true; } @@ -132,7 +133,7 @@ bool CObjectEntry::BuildVariation(const std::vector*>& comp CModel* model = new CModel(objectManager.GetSkeletonAnimManager(), m_Simulation); delete m_Model; m_Model = model; - model->SetMaterial(g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material)); + model->SetMaterial(g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(m_Base->m_Material)); model->GetMaterial().AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a)); model->InitModel(modeldef); diff --git a/source/graphics/ParticleEmitter.cpp b/source/graphics/ParticleEmitter.cpp index 640c9455d8..cd3c596417 100644 --- a/source/graphics/ParticleEmitter.cpp +++ b/source/graphics/ParticleEmitter.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,8 +26,8 @@ #include "graphics/ShaderProgram.h" #include "graphics/TextureManager.h" #include "ps/CStrInternStatic.h" - #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) : m_Type(type), m_Active(true), m_NextParticleIdx(0), m_EmissionRoundingError(0.f), @@ -179,11 +179,11 @@ void CParticleEmitter::PrepareForRendering() void CParticleEmitter::Bind(const CShaderProgramPtr& shader) { - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); + CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); shader->BindTexture(str_losTex, los.GetTextureSmooth()); shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); + const CLightEnv& lightEnv = g_Renderer.GetSceneRenderer().GetLightEnv(); shader->Uniform(str_sunColor, lightEnv.m_SunColor); shader->Uniform(str_fogColor, lightEnv.m_FogColor); shader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); diff --git a/source/graphics/TerrainTextureEntry.cpp b/source/graphics/TerrainTextureEntry.cpp index d84e28a4fc..03a81eae11 100644 --- a/source/graphics/TerrainTextureEntry.cpp +++ b/source/graphics/TerrainTextureEntry.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -34,6 +34,7 @@ #include "ps/Filesystem.h" #include "ps/XML/Xeromyces.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include @@ -106,7 +107,7 @@ CTerrainTextureEntry::CTerrainTextureEntry(CTerrainPropertiesPtr properties, con { VfsPath mat = VfsPath("art/materials") / child.GetText().FromUTF8(); if (CRenderer::IsInitialised()) - m_Material = g_Renderer.GetMaterialManager().LoadMaterial(mat); + m_Material = g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(mat); } else if (child_name == el_alphamap) { diff --git a/source/gui/ObjectTypes/CMiniMap.cpp b/source/gui/ObjectTypes/CMiniMap.cpp index a91a45dafa..c69b082a3c 100644 --- a/source/gui/ObjectTypes/CMiniMap.cpp +++ b/source/gui/ObjectTypes/CMiniMap.cpp @@ -47,6 +47,7 @@ #include "ps/World.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "scriptinterface/Object.h" #include "simulation2/Simulation2.h" @@ -307,7 +308,7 @@ void CMiniMap::DrawViewRect(CCanvas2D& canvas) const { // Compute the camera frustum intersected with a fixed-height plane. // Use the water height as a fixed base height, which should be the lowest we can go - const float sampleHeight = g_Renderer.GetWaterManager().m_WaterHeight; + const float sampleHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight; const CCamera* camera = g_Game->GetView()->GetCamera(); const std::array hitPoints = { diff --git a/source/ps/Game.cpp b/source/ps/Game.cpp index 46c7f5d88e..2d6ae68fbe 100644 --- a/source/ps/Game.cpp +++ b/source/ps/Game.cpp @@ -39,6 +39,7 @@ #include "ps/World.h" #include "ps/GameSetup/GameSetup.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TimeManager.h" #include "renderer/WaterManager.h" #include "scriptinterface/FunctionWrapper.h" @@ -49,7 +50,6 @@ #include "simulation2/components/ICmpPlayerManager.h" #include "simulation2/system/ReplayTurnManager.h" #include "soundmanager/ISoundManager.h" - #include "tools/atlas/GameInterface/GameLoop.h" #include @@ -262,7 +262,7 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved m_World->RegisterInit(mapFile, *scriptInterface.GetContext(), settings, m_PlayerID); } if (m_GameView) - RegMemFun(&g_Renderer.GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80); + RegMemFun(&g_Renderer.GetSceneRenderer().GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80); if (m_IsSavedGame) RegMemFun(this, &CGame::LoadInitialState, L"Loading game", 1000); diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index fbd3b6f448..b2d87422a2 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -76,6 +76,7 @@ #include "ps/World.h" #include "renderer/ModelRenderer.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/VertexBufferManager.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/JSON.h" @@ -205,7 +206,7 @@ void Render() g_Game->GetView()->BeginFrame(); if (g_Game) - g_Renderer.SetSimulation(g_Game->GetSimulation2()); + g_Renderer.GetSceneRenderer().SetSimulation(g_Game->GetSimulation2()); // start new frame g_Renderer.BeginFrame(); @@ -218,7 +219,7 @@ void Render() ogl_WarnIfError(); } - g_Renderer.RenderTextOverlays(); + g_Renderer.GetSceneRenderer().RenderTextOverlays(); // If we're in Atlas game view, render special tools if (g_AtlasGameLoop && g_AtlasGameLoop->view) @@ -490,7 +491,7 @@ static void InitRenderer() // Setup lighting environment. Since the Renderer accesses the // lighting environment through a pointer, this has to be done before // the first Frame. - g_Renderer.SetLightEnv(&g_LightEnv); + g_Renderer.GetSceneRenderer().SetLightEnv(&g_LightEnv); // I haven't seen the camera affecting GUI rendering and such, but the // viewport has to be updated according to the video mode @@ -564,7 +565,7 @@ void EndGame() if (CRenderer::IsInitialised()) { ISoundManager::CloseGame(); - g_Renderer.ResetState(); + g_Renderer.GetSceneRenderer().ResetState(); } } diff --git a/source/ps/World.cpp b/source/ps/World.cpp index bbe5bab42a..5e6dd6e4e4 100644 --- a/source/ps/World.cpp +++ b/source/ps/World.cpp @@ -33,6 +33,7 @@ #include "ps/LoaderThunks.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "simulation2/Simulation2.h" /** @@ -70,8 +71,8 @@ void CWorld::RegisterInit(const CStrW& mapFile, const ScriptContext& cx, JS::Han { CTriggerManager* pTriggerManager = NULL; m_MapReader->LoadMap(mapfilename, cx, settings, m_Terrain, - CRenderer::IsInitialised() ? &g_Renderer.GetWaterManager() : NULL, - CRenderer::IsInitialised() ? &g_Renderer.GetSkyManager() : NULL, + CRenderer::IsInitialised() ? &g_Renderer.GetSceneRenderer().GetWaterManager() : NULL, + CRenderer::IsInitialised() ? &g_Renderer.GetSceneRenderer().GetSkyManager() : NULL, &g_LightEnv, m_pGame->GetView(), m_pGame->GetView() ? m_pGame->GetView()->GetCinema() : NULL, pTriggerManager, CRenderer::IsInitialised() ? &g_Renderer.GetPostprocManager() : NULL, @@ -93,8 +94,8 @@ void CWorld::RegisterInitRMS(const CStrW& scriptFile, const ScriptContext& cx, J // If scriptFile is empty, a blank map will be generated using settings (no RMS run) CTriggerManager* pTriggerManager = NULL; m_MapReader->LoadRandomMap(scriptFile, cx, settings, m_Terrain, - CRenderer::IsInitialised() ? &g_Renderer.GetWaterManager() : NULL, - CRenderer::IsInitialised() ? &g_Renderer.GetSkyManager() : NULL, + CRenderer::IsInitialised() ? &g_Renderer.GetSceneRenderer().GetWaterManager() : NULL, + CRenderer::IsInitialised() ? &g_Renderer.GetSceneRenderer().GetSkyManager() : NULL, &g_LightEnv, m_pGame->GetView(), m_pGame->GetView() ? m_pGame->GetView()->GetCinema() : NULL, pTriggerManager, CRenderer::IsInitialised() ? &g_Renderer.GetPostprocManager() : NULL, diff --git a/source/renderer/DebugRenderer.cpp b/source/renderer/DebugRenderer.cpp index 89458398fa..5499547e2d 100644 --- a/source/renderer/DebugRenderer.cpp +++ b/source/renderer/DebugRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,6 +30,7 @@ #include "maths/Vector3D.h" #include "ps/CStrInternStatic.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include @@ -50,11 +51,13 @@ void CDebugRenderer::DrawLine(const std::vector& line, const CColor& g_Renderer.GetShaderManager().LoadEffect(str_debug_line); debugLineTech->BeginPass(); + const CCamera& viewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); + CShaderProgramPtr debugLineShader = debugLineTech->GetShader(); - debugLineShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + debugLineShader->Uniform(str_transform, viewCamera.GetViewProjection()); debugLineShader->Uniform(str_color, color); - const CVector3D cameraIn = g_Renderer.GetViewCamera().GetOrientation().GetIn(); + const CVector3D cameraIn = viewCamera.GetOrientation().GetIn(); std::vector vertices; vertices.reserve(line.size() * 6 * 3); @@ -100,7 +103,7 @@ void CDebugRenderer::DrawCircle(const CVector3D& origin, const float radius, con g_Renderer.GetShaderManager().LoadEffect(str_debug_line); debugCircleTech->BeginPass(); - const CCamera& camera = g_Renderer.GetViewCamera(); + const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); CShaderProgramPtr debugCircleShader = debugCircleTech->GetShader(); debugCircleShader->Uniform(str_transform, camera.GetViewProjection()); @@ -156,7 +159,7 @@ void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& colo overlayTech->BeginPass(); CShaderProgramPtr overlayShader = overlayTech->GetShader(); - overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); overlayShader->Uniform(str_color, color); std::vector vertices; @@ -221,7 +224,7 @@ void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& colo void CDebugRenderer::DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CColor& color) { - DrawBoundingBox(boundingBox, color, g_Renderer.GetViewCamera().GetViewProjection()); + DrawBoundingBox(boundingBox, color, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); } void CDebugRenderer::DrawBoundingBox(const CBoundingBoxAligned& boundingBox, const CColor& color, const CMatrix3D& transform) @@ -267,7 +270,7 @@ void CDebugRenderer::DrawBoundingBox(const CBoundingBoxAligned& boundingBox, con void CDebugRenderer::DrawBoundingBoxOutline(const CBoundingBoxAligned& boundingBox, const CColor& color) { - DrawBoundingBoxOutline(boundingBox, color, g_Renderer.GetViewCamera().GetViewProjection()); + DrawBoundingBoxOutline(boundingBox, color, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); } void CDebugRenderer::DrawBoundingBoxOutline(const CBoundingBoxAligned& boundingBox, const CColor& color, const CMatrix3D& transform) @@ -320,7 +323,7 @@ void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color) CShaderProgramPtr shader = shaderTech->GetShader(); shader->Uniform(str_color, color); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); std::vector data; @@ -367,7 +370,7 @@ void CDebugRenderer::DrawBrushOutline(const CBrush& brush, const CColor& color) CShaderProgramPtr shader = shaderTech->GetShader(); shader->Uniform(str_color, color); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); std::vector data; diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp index 5b081a502d..d850f9fbe1 100644 --- a/source/renderer/ModelRenderer.cpp +++ b/source/renderer/ModelRenderer.cpp @@ -38,6 +38,7 @@ #include "renderer/ModelVertexRenderer.h" #include "renderer/Renderer.h" #include "renderer/RenderModifiers.h" +#include "renderer/SceneRenderer.h" #include "renderer/SkyManager.h" #include "renderer/TimeManager.h" #include "renderer/WaterManager.h" @@ -114,7 +115,7 @@ void ModelRenderer::BuildColor4ub( CModelDefPtr mdef = model->GetModelDef(); size_t numVertices = mdef->GetNumVertices(); - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); + const CLightEnv& lightEnv = g_Renderer.GetSceneRenderer().GetLightEnv(); CColor shadingColor = model->GetShadingColor(); for (size_t j = 0; j < numVertices; ++j) @@ -193,7 +194,7 @@ struct ShaderModelRenderer::ShaderModelRendererInternals ModelVertexRendererPtr vertexRenderer; /// List of submitted models for rendering in this frame - std::vector submissions[CRenderer::CULL_MAX]; + std::vector submissions[CSceneRenderer::CULL_MAX]; }; @@ -230,7 +231,7 @@ void ShaderModelRenderer::Submit(int cullGroup, CModel* model) // Call update for all submitted models and enter the rendering phase void ShaderModelRenderer::PrepareModels() { - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) { for (size_t i = 0; i < m->submissions[cullGroup].size(); ++i) { @@ -251,7 +252,7 @@ void ShaderModelRenderer::PrepareModels() // Clear the submissions list void ShaderModelRenderer::EndFrame() { - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) m->submissions[cullGroup].clear(); } @@ -350,7 +351,7 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade return; CMatrix3D worldToCam; - g_Renderer.GetViewCamera().GetOrientation().GetInverse(worldToCam); + g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse(worldToCam); /* * Rendering approach: @@ -726,7 +727,7 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade else if (rq.first == RQUERY_WATER_TEX) { const double period = 1.6; - const WaterManager& waterManager = g_Renderer.GetWaterManager(); + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); if (waterManager.m_RenderWater && waterManager.WillRenderFancyWater()) shader->BindTexture(str_waterTex, waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]); else @@ -734,7 +735,7 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade } else if (rq.first == RQUERY_SKY_CUBE) { - shader->BindTexture(str_skyCube, g_Renderer.GetSkyManager().GetSkyCube()); + shader->BindTexture(str_skyCube, g_Renderer.GetSceneRenderer().GetSkyManager().GetSkyCube()); } } diff --git a/source/renderer/OverlayRenderer.cpp b/source/renderer/OverlayRenderer.cpp index be885cb4d8..53c88094f2 100644 --- a/source/renderer/OverlayRenderer.cpp +++ b/source/renderer/OverlayRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -34,6 +34,7 @@ #include "ps/Profile.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TexturedLineRData.h" #include "renderer/VertexArray.h" #include "renderer/VertexBuffer.h" @@ -419,7 +420,7 @@ void OverlayRenderer::RenderTexturedOverlayLines() glEnable(GL_BLEND); glDepthMask(0); - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); + CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); // ---------------------------------------------------------------------------------------- @@ -434,7 +435,7 @@ void OverlayRenderer::RenderTexturedOverlayLines() shaderTexLineNormal->BindTexture(str_losTex, los.GetTexture()); shaderTexLineNormal->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - shaderTexLineNormal->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shaderTexLineNormal->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); // batch render only the non-always-visible overlay lines using the normal shader RenderTexturedOverlayLines(shaderTexLineNormal, false); @@ -456,7 +457,7 @@ void OverlayRenderer::RenderTexturedOverlayLines() shaderTexLineAlwaysVisible->BindTexture(str_losTex, los.GetTexture()); shaderTexLineAlwaysVisible->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - shaderTexLineAlwaysVisible->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shaderTexLineAlwaysVisible->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); // batch render only the always-visible overlay lines using the LoS-ignored shader RenderTexturedOverlayLines(shaderTexLineAlwaysVisible, true); @@ -479,7 +480,7 @@ void OverlayRenderer::RenderTexturedOverlayLines() void OverlayRenderer::RenderTexturedOverlayLines(CShaderProgramPtr shader, bool alwaysVisible) { #if !CONFIG2_GLES - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); #endif for (size_t i = 0; i < m->texlines.size(); ++i) @@ -494,7 +495,7 @@ void OverlayRenderer::RenderTexturedOverlayLines(CShaderProgramPtr shader, bool line->m_RenderData->Render(*line, shader); } #if !CONFIG2_GLES - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } @@ -518,7 +519,7 @@ void OverlayRenderer::RenderQuadOverlays() CShaderProgramPtr shader = shaderTech->GetShader(); #if !CONFIG2_GLES - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); #endif @@ -526,13 +527,13 @@ void OverlayRenderer::RenderQuadOverlays() glEnable(GL_BLEND); glDepthMask(0); - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); + CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); shader->Bind(); shader->BindTexture(str_losTex, los.GetTexture()); shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); // Base offsets (in bytes) of the two backing stores relative to their owner VBO u8* indexBase = m->quadIndices.Bind(); @@ -587,7 +588,7 @@ void OverlayRenderer::RenderQuadOverlays() glDisable(GL_BLEND); #if !CONFIG2_GLES - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } @@ -599,7 +600,7 @@ void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera) #if CONFIG2_GLES #warning TODO: implement OverlayRenderer::RenderForegroundOverlays for GLES #else - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glActiveTextureARB(GL_TEXTURE0); @@ -613,7 +614,7 @@ void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera) tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); float uvs[8] = { 0,1, 1,1, 1,0, 0,0 }; @@ -647,7 +648,7 @@ void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera) glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); - if (g_Renderer.GetOverlayRenderMode() == WIREFRAME) + if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } @@ -746,7 +747,7 @@ void OverlayRenderer::RenderSphereOverlays() transform.Scale(sphere->m_Radius, sphere->m_Radius, sphere->m_Radius); transform.Translate(sphere->m_Center); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); shader->Uniform(str_instancingTransform, transform); shader->Uniform(str_color, sphere->m_Color); diff --git a/source/renderer/ParticleRenderer.cpp b/source/renderer/ParticleRenderer.cpp index 5189943603..3cbe75abf4 100644 --- a/source/renderer/ParticleRenderer.cpp +++ b/source/renderer/ParticleRenderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,13 +27,14 @@ #include "ps/Profile.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" struct ParticleRendererInternals { int frameNumber; CShaderTechniquePtr shader; CShaderTechniquePtr shaderSolid; - std::vector emitters[CRenderer::CULL_MAX]; + std::vector emitters[CSceneRenderer::CULL_MAX]; }; ParticleRenderer::ParticleRenderer() @@ -54,7 +55,7 @@ void ParticleRenderer::Submit(int cullGroup, CParticleEmitter* emitter) void ParticleRenderer::EndFrame() { - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) m->emitters[cullGroup].clear(); // this should leave the capacity unchanged, which is okay since it // won't be very large or very variable @@ -94,7 +95,7 @@ void ParticleRenderer::PrepareForRendering(const CShaderDefines& context) ++m->frameNumber; - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) { PROFILE("update emitters"); for (size_t i = 0; i < m->emitters[cullGroup].size(); ++i) @@ -105,12 +106,12 @@ void ParticleRenderer::PrepareForRendering(const CShaderDefines& context) } } - for (int cullGroup = 0; cullGroup < CRenderer::CULL_MAX; ++cullGroup) + for (int cullGroup = 0; cullGroup < CSceneRenderer::CULL_MAX; ++cullGroup) { // Sort back-to-front by distance from camera PROFILE("sort emitters"); CMatrix3D worldToCam; - g_Renderer.GetViewCamera().GetOrientation().GetInverse(worldToCam); + g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse(worldToCam); std::stable_sort(m->emitters[cullGroup].begin(), m->emitters[cullGroup].end(), SortEmitterDistance(worldToCam)); } @@ -125,8 +126,8 @@ void ParticleRenderer::RenderParticles(int cullGroup, bool solidColor) shader->BeginPass(); - shader->GetShader()->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - shader->GetShader()->Uniform(str_modelViewMatrix, g_Renderer.GetViewCamera().GetOrientation().GetInverse()); + shader->GetShader()->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + shader->GetShader()->Uniform(str_modelViewMatrix, g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse()); if (!solidColor) glEnable(GL_BLEND); diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp index 41da4d31d4..836af4b8c0 100644 --- a/source/renderer/PatchRData.cpp +++ b/source/renderer/PatchRData.cpp @@ -41,6 +41,7 @@ #include "renderer/AlphaMapCalculator.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TerrainRenderer.h" #include "renderer/WaterManager.h" #include "simulation2/components/ICmpWaterManager.h" @@ -1222,7 +1223,7 @@ void CPatchRData::BuildWater() u16 water_shore_index_map[PATCH_SIZE+1][PATCH_SIZE+1]; memset(water_shore_index_map, 0xFF, sizeof(water_shore_index_map)); - const WaterManager& waterManager = g_Renderer.GetWaterManager(); + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); CPatch* patch = m_Patch; CTerrain* terrain = patch->m_Parent; @@ -1381,7 +1382,7 @@ void CPatchRData::RenderWater(CShaderProgramPtr& shader, bool onlyShore, bool fi return; #if !CONFIG2_GLES - if (g_Renderer.GetWaterRenderMode() == WIREFRAME) + if (g_Renderer.GetSceneRenderer().GetWaterRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); #endif @@ -1406,8 +1407,8 @@ void CPatchRData::RenderWater(CShaderProgramPtr& shader, bool onlyShore, bool fi } if (m_VBWaterShore && g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB && - g_Renderer.GetWaterManager().m_WaterEffects && - g_Renderer.GetWaterManager().m_WaterFancyEffects) + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterEffects && + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterFancyEffects) { SWaterVertex *base=(SWaterVertex *)m_VBWaterShore->m_Owner->Bind(); @@ -1429,7 +1430,7 @@ void CPatchRData::RenderWater(CShaderProgramPtr& shader, bool onlyShore, bool fi CVertexBuffer::Unbind(); #if !CONFIG2_GLES - if (g_Renderer.GetWaterRenderMode() == WIREFRAME) + if (g_Renderer.GetSceneRenderer().GetWaterRenderMode() == WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } diff --git a/source/renderer/PostprocManager.cpp b/source/renderer/PostprocManager.cpp index 05f3da133b..d97e415608 100644 --- a/source/renderer/PostprocManager.cpp +++ b/source/renderer/PostprocManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -759,11 +759,17 @@ void CPostprocManager::ResolveMultisampleFramebuffer() #warning TODO: implement PostprocManager for GLES -void ApplyBlurDownscale2x(GLuint UNUSED(inTex), GLuint UNUSED(outTex), int UNUSED(inWidth), int UNUSED(inHeight)) +void ApplyBlurDownscale2x( + Renderer::Backend::GL::CTexture* UNUSED(inTex), + Renderer::Backend::GL::CTexture* UNUSED(outTex), + int UNUSED(inWidth), int UNUSED(inHeight)) { } -void CPostprocManager::ApplyBlurGauss(GLuint UNUSED(inOutTex), GLuint UNUSED(tempTex), int UNUSED(inWidth), int UNUSED(inHeight)) +void CPostprocManager::ApplyBlurGauss( + Renderer::Backend::GL::CTexture* UNUSED(inOutTex), + Renderer::Backend::GL::CTexture* UNUSED(tempTex), + int UNUSED(inWidth), int UNUSED(inHeight)) { } diff --git a/source/renderer/RenderModifiers.cpp b/source/renderer/RenderModifiers.cpp index 2f115d96f3..c00aeee409 100644 --- a/source/renderer/RenderModifiers.cpp +++ b/source/renderer/RenderModifiers.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,28 +15,23 @@ * along with 0 A.D. If not, see . */ -/* - * Implementation of common RenderModifiers - */ - #include "precompiled.h" -#include "lib/ogl.h" -#include "maths/Vector3D.h" -#include "maths/Vector4D.h" -#include "maths/Matrix3D.h" - -#include "ps/CStrInternStatic.h" -#include "ps/Game.h" +#include "renderer/RenderModifiers.h" #include "graphics/GameView.h" #include "graphics/LightEnv.h" #include "graphics/LOSTexture.h" #include "graphics/Model.h" #include "graphics/TextureManager.h" - -#include "renderer/RenderModifiers.h" +#include "lib/ogl.h" +#include "maths/Vector3D.h" +#include "maths/Vector4D.h" +#include "maths/Matrix3D.h" +#include "ps/CStrInternStatic.h" +#include "ps/Game.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/ShadowMap.h" #include @@ -74,8 +69,8 @@ ShaderRenderModifier::ShaderRenderModifier() void ShaderRenderModifier::BeginPass(const CShaderProgramPtr& shader) { - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - shader->Uniform(str_cameraPos, g_Renderer.GetViewCamera().GetOrientation().GetTranslation()); + shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + shader->Uniform(str_cameraPos, g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetTranslation()); if (GetShadowMap()) GetShadowMap()->BindTo(shader); @@ -92,7 +87,7 @@ void ShaderRenderModifier::BeginPass(const CShaderProgramPtr& shader) if (shader->GetTextureBinding(str_losTex).Active()) { - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); + CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); shader->BindTexture(str_losTex, los.GetTextureSmooth()); // Don't bother sending the whole matrix, we just need two floats (scale and translation) shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index c6425d8ee7..e86e6295ad 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,11 +24,7 @@ #include "Renderer.h" -#include "lib/bits.h" // is_pow2 #include "lib/res/graphics/ogl_tex.h" -#include "lib/allocators/shared_ptr.h" -#include "maths/Matrix3D.h" -#include "maths/MathUtil.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStrInternStatic.h" @@ -39,48 +35,21 @@ #include "ps/Loader.h" #include "ps/ProfileViewer.h" #include "graphics/Camera.h" -#include "graphics/Decal.h" #include "graphics/FontManager.h" -#include "graphics/GameView.h" -#include "graphics/LightEnv.h" -#include "graphics/LOSTexture.h" -#include "graphics/MaterialManager.h" -#include "graphics/MiniMapTexture.h" -#include "graphics/Model.h" -#include "graphics/ModelDef.h" -#include "graphics/ParticleManager.h" -#include "graphics/Patch.h" #include "graphics/ShaderManager.h" #include "graphics/Terrain.h" #include "graphics/Texture.h" #include "graphics/TextureManager.h" #include "ps/VideoMode.h" #include "renderer/DebugRenderer.h" -#include "renderer/HWLightingModelRenderer.h" -#include "renderer/InstancingModelRenderer.h" -#include "renderer/ModelRenderer.h" -#include "renderer/OverlayRenderer.h" -#include "renderer/ParticleRenderer.h" #include "renderer/PostprocManager.h" #include "renderer/RenderingOptions.h" #include "renderer/RenderModifiers.h" -#include "renderer/ShadowMap.h" -#include "renderer/SilhouetteRenderer.h" -#include "renderer/SkyManager.h" -#include "renderer/TerrainOverlay.h" -#include "renderer/TerrainRenderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TimeManager.h" #include "renderer/VertexBufferManager.h" -#include "renderer/WaterManager.h" #include -#include -#include - -struct SScreenRect -{ - GLint x1, y1, x2, y2; -}; /////////////////////////////////////////////////////////////////////////////////// // CRendererStatsTable - Profile display of rendering stats @@ -113,7 +82,8 @@ private: /// Column descriptions std::vector columnDescriptions; - enum { + enum + { Row_DrawCalls = 0, Row_TerrainTris, Row_WaterTris, @@ -242,7 +212,6 @@ AbstractProfileTable* CRendererStatsTable::GetChild(size_t UNUSED(row)) return 0; } - /////////////////////////////////////////////////////////////////////////////////// // CRenderer implementation @@ -266,129 +235,27 @@ public: /// Shader manager CShaderManager shaderManager; - /// Water manager - WaterManager waterManager; - - /// Sky manager - SkyManager skyManager; - /// Texture manager CTextureManager textureManager; - /// Terrain renderer - TerrainRenderer terrainRenderer; - - /// Overlay renderer - OverlayRenderer overlayRenderer; - - /// Particle manager - CParticleManager particleManager; - - /// Particle renderer - ParticleRenderer particleRenderer; - - /// Material manager - CMaterialManager materialManager; - /// Time manager CTimeManager timeManager; - /// Shadow map - ShadowMap shadow; - /// Postprocessing effect manager CPostprocManager postprocManager; + CSceneRenderer sceneRenderer; + CDebugRenderer debugRenderer; CFontManager fontManager; - SilhouetteRenderer silhouetteRenderer; - - /// Various model renderers - struct Models - { - // NOTE: The current renderer design (with ModelRenderer, ModelVertexRenderer, - // RenderModifier, etc) is mostly a relic of an older design that implemented - // the different materials and rendering modes through extensive subclassing - // and hooking objects together in various combinations. - // The new design uses the CShaderManager API to abstract away the details - // of rendering, and uses a data-driven approach to materials, so there are - // now a small number of generic subclasses instead of many specialised subclasses, - // but most of the old infrastructure hasn't been refactored out yet and leads to - // some unwanted complexity. - - // Submitted models are split on two axes: - // - Normal vs Transp[arent] - alpha-blended models are stored in a separate - // list so we can draw them above/below the alpha-blended water plane correctly - // - Skinned vs Unskinned - with hardware lighting we don't need to - // duplicate mesh data per model instance (except for skinned models), - // so non-skinned models get different ModelVertexRenderers - - ModelRendererPtr NormalSkinned; - ModelRendererPtr NormalUnskinned; // == NormalSkinned if unskinned shader instancing not supported - ModelRendererPtr TranspSkinned; - ModelRendererPtr TranspUnskinned; // == TranspSkinned if unskinned shader instancing not supported - - ModelVertexRendererPtr VertexRendererShader; - ModelVertexRendererPtr VertexInstancingShader; - ModelVertexRendererPtr VertexGPUSkinningShader; - - LitRenderModifierPtr ModShader; - } Model; - - CShaderDefines globalContext; - Internals() : IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats), textureManager(g_VFS, false, false) { } - - /** - * Renders all non-alpha-blended models with the given context. - */ - void CallModelRenderers(const CShaderDefines& context, int cullGroup, int flags) - { - CShaderDefines contextSkinned = context; - if (g_RenderingOptions.GetGPUSkinning()) - { - contextSkinned.Add(str_USE_INSTANCING, str_1); - contextSkinned.Add(str_USE_GPU_SKINNING, str_1); - } - Model.NormalSkinned->Render(Model.ModShader, contextSkinned, cullGroup, flags); - - if (Model.NormalUnskinned != Model.NormalSkinned) - { - CShaderDefines contextUnskinned = context; - contextUnskinned.Add(str_USE_INSTANCING, str_1); - Model.NormalUnskinned->Render(Model.ModShader, contextUnskinned, cullGroup, flags); - } - } - - /** - * Renders all alpha-blended models with the given context. - */ - void CallTranspModelRenderers(const CShaderDefines& context, int cullGroup, int flags) - { - CShaderDefines contextSkinned = context; - if (g_RenderingOptions.GetGPUSkinning()) - { - contextSkinned.Add(str_USE_INSTANCING, str_1); - contextSkinned.Add(str_USE_GPU_SKINNING, str_1); - } - Model.TranspSkinned->Render(Model.ModShader, contextSkinned, cullGroup, flags); - - if (Model.TranspUnskinned != Model.TranspSkinned) - { - CShaderDefines contextUnskinned = context; - contextUnskinned.Add(str_USE_INSTANCING, str_1); - Model.TranspUnskinned->Render(Model.ModShader, contextUnskinned, cullGroup, flags); - } - } }; -/////////////////////////////////////////////////////////////////////////////////// -// CRenderer constructor CRenderer::CRenderer() { m = std::make_unique(); @@ -397,34 +264,10 @@ CRenderer::CRenderer() m_Width = 0; m_Height = 0; - m_TerrainRenderMode = SOLID; - m_WaterRenderMode = SOLID; - m_ModelRenderMode = SOLID; - m_OverlayRenderMode = SOLID; - m_ClearColor[0] = m_ClearColor[1] = m_ClearColor[2] = m_ClearColor[3] = 0; - - m_DisplayTerrainPriorities = false; - - CStr skystring = "0 0 0"; - CColor skycolor; - CFG_GET_VAL("skycolor", skystring); - if (skycolor.ParseString(skystring, 255.f)) - { - m_ClearColor[0] = skycolor.r; - m_ClearColor[1] = skycolor.g; - m_ClearColor[2] = skycolor.b; - m_ClearColor[3] = skycolor.a; - } - - m_LightEnv = nullptr; - - m_CurrentScene = nullptr; m_Stats.Reset(); } -/////////////////////////////////////////////////////////////////////////////////// -// CRenderer destructor CRenderer::~CRenderer() { // We no longer UnloadWaterTextures here - @@ -433,9 +276,6 @@ CRenderer::~CRenderer() m.reset(); } - -/////////////////////////////////////////////////////////////////////////////////// -// EnumCaps: build card cap bits void CRenderer::EnumCaps() { // assume support for nothing @@ -484,52 +324,7 @@ void CRenderer::ReloadShaders() { ENSURE(m->IsOpen); - m->globalContext = CShaderDefines(); - - if (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) - { - m->globalContext.Add(str_USE_SHADOW, str_1); - if (m_Caps.m_ARBProgramShadow && g_RenderingOptions.GetARBProgramShadow()) - m->globalContext.Add(str_USE_FP_SHADOW, str_1); - if (g_RenderingOptions.GetShadowPCF()) - m->globalContext.Add(str_USE_SHADOW_PCF, str_1); - const int cascadeCount = m->shadow.GetCascadeCount(); - ENSURE(1 <= cascadeCount && cascadeCount <= 4); - const CStrIntern cascadeCountStr[5] = {str_0, str_1, str_2, str_3, str_4}; - m->globalContext.Add(str_SHADOWS_CASCADE_COUNT, cascadeCountStr[cascadeCount]); -#if !CONFIG2_GLES - m->globalContext.Add(str_USE_SHADOW_SAMPLER, str_1); -#endif - } - - m->globalContext.Add(str_RENDER_DEBUG_MODE, - RenderDebugModeEnum::ToString(g_RenderingOptions.GetRenderDebugMode())); - - if (g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB && g_RenderingOptions.GetFog()) - m->globalContext.Add(str_USE_FOG, str_1); - - m->Model.ModShader = LitRenderModifierPtr(new ShaderRenderModifier()); - - ENSURE(g_RenderingOptions.GetRenderPath() != RenderPath::FIXED); - m->Model.VertexRendererShader = ModelVertexRendererPtr(new ShaderModelVertexRenderer()); - m->Model.VertexInstancingShader = ModelVertexRendererPtr(new InstancingModelRenderer(false, g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB)); - - if (g_RenderingOptions.GetGPUSkinning()) // TODO: should check caps and GLSL etc too - { - m->Model.VertexGPUSkinningShader = ModelVertexRendererPtr(new InstancingModelRenderer(true, g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB)); - m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); - m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); - } - else - { - m->Model.VertexGPUSkinningShader.reset(); - m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader)); - m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader)); - } - - m->Model.NormalUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader)); - m->Model.TranspUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader)); - + m->sceneRenderer.ReloadShaders(); m->ShadersDirty = false; } @@ -559,34 +354,24 @@ bool CRenderer::Open(int width, int height) // Validate the currently selected render path SetRenderPath(g_RenderingOptions.GetRenderPath()); - // Let component renderers perform one-time initialization after graphics capabilities and - // the shader path have been determined. - m->overlayRenderer.Initialize(); - if (g_RenderingOptions.GetPostProc()) m->postprocManager.Initialize(); + m->sceneRenderer.Initialize(); + return true; } -// resize renderer view void CRenderer::Resize(int width, int height) { - // need to recreate the shadow map object to resize the shadow texture - m->shadow.RecreateTexture(); - m_Width = width; m_Height = height; m->postprocManager.Resize(); - m->waterManager.Resize(); + m->sceneRenderer.Resize(width, height); } -////////////////////////////////////////////////////////////////////////////////////////// -// SetRenderPath: Select the preferred render path. -// This may only be called before Open(), because the layout of vertex arrays and other -// data may depend on the chosen render path. void CRenderer::SetRenderPath(RenderPath rp) { if (!m->IsOpen) @@ -623,815 +408,28 @@ void CRenderer::SetRenderPath(RenderPath rp) g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_COLOR); } -////////////////////////////////////////////////////////////////////////////////////////// -// BeginFrame: signal frame start void CRenderer::BeginFrame() { PROFILE("begin frame"); - // zero out all the per-frame stats + // Zero out all the per-frame stats. m_Stats.Reset(); - // choose model renderers for this frame - if (m->ShadersDirty) ReloadShaders(); - m->Model.ModShader->SetShadowMap(&m->shadow); - m->Model.ModShader->SetLightEnv(m_LightEnv); + m->sceneRenderer.BeginFrame(); } -////////////////////////////////////////////////////////////////////////////////////////// -void CRenderer::SetSimulation(CSimulation2* simulation) -{ - // set current simulation context for terrain renderer - m->terrainRenderer.SetSimulation(simulation); -} - -void CRenderer::RenderShadowMap(const CShaderDefines& context) -{ - PROFILE3_GPU("shadow map"); - OGL_SCOPED_DEBUG_GROUP("Render shadow map"); - - CShaderDefines contextCast = context; - contextCast.Add(str_MODE_SHADOWCAST, str_1); - - m->shadow.BeginRender(); - - const int cascadeCount = m->shadow.GetCascadeCount(); - ENSURE(0 <= cascadeCount && cascadeCount <= 4); - for (int cascade = 0; cascade < cascadeCount; ++cascade) - { - m->shadow.PrepareCamera(cascade); - - const int cullGroup = CULL_SHADOWS_CASCADE_0 + cascade; - { - PROFILE("render patches"); - glCullFace(GL_FRONT); - glEnable(GL_CULL_FACE); - m->terrainRenderer.RenderPatches(cullGroup); - glCullFace(GL_BACK); - } - - { - PROFILE("render models"); - m->CallModelRenderers(contextCast, cullGroup, MODELFLAG_CASTSHADOWS); - } - - { - PROFILE("render transparent models"); - // disable face-culling for two-sided models - glDisable(GL_CULL_FACE); - m->CallTranspModelRenderers(contextCast, cullGroup, MODELFLAG_CASTSHADOWS); - glEnable(GL_CULL_FACE); - } - } - - m->shadow.EndRender(); - - SetViewport(m_ViewCamera.GetViewPort()); -} - -void CRenderer::RenderPatches(const CShaderDefines& context, int cullGroup) -{ - PROFILE3_GPU("patches"); - OGL_SCOPED_DEBUG_GROUP("Render patches"); - -#if CONFIG2_GLES -#warning TODO: implement wireface/edged rendering mode GLES -#else - // switch on wireframe if we need it - if (m_TerrainRenderMode == WIREFRAME) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } -#endif - - // render all the patches, including blend pass - ENSURE(g_RenderingOptions.GetRenderPath() != RenderPath::FIXED); - m->terrainRenderer.RenderTerrainShader(context, cullGroup, (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) ? &m->shadow : 0); - -#if !CONFIG2_GLES - if (m_TerrainRenderMode == WIREFRAME) - { - // switch wireframe off again - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - else if (m_TerrainRenderMode == EDGED_FACES) - { - // edged faces: need to make a second pass over the data: - // first switch on wireframe - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - // setup some renderstate .. - glActiveTextureARB(GL_TEXTURE0); - glLineWidth(2.0f); - - // render tiles edges - m->terrainRenderer.RenderPatches(cullGroup, CColor(0.5f, 0.5f, 1.0f, 1.0f)); - - glLineWidth(4.0f); - - // render outline of each patch - m->terrainRenderer.RenderOutlines(cullGroup); - - // .. and restore the renderstates - glLineWidth(1.0f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -#endif -} - -void CRenderer::RenderModels(const CShaderDefines& context, int cullGroup) -{ - PROFILE3_GPU("models"); - OGL_SCOPED_DEBUG_GROUP("Render models"); - - int flags = 0; - -#if !CONFIG2_GLES - if (m_ModelRenderMode == WIREFRAME) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } -#endif - - m->CallModelRenderers(context, cullGroup, flags); - -#if !CONFIG2_GLES - if (m_ModelRenderMode == WIREFRAME) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - else if (m_ModelRenderMode == EDGED_FACES) - { - CShaderDefines contextWireframe = context; - contextWireframe.Add(str_MODE_WIREFRAME, str_1); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - m->CallModelRenderers(contextWireframe, cullGroup, flags); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -#endif -} - -void CRenderer::RenderTransparentModels(const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode, bool disableFaceCulling) -{ - PROFILE3_GPU("transparent models"); - OGL_SCOPED_DEBUG_GROUP("Render transparent models"); - - int flags = 0; - -#if !CONFIG2_GLES - // switch on wireframe if we need it - if (m_ModelRenderMode == WIREFRAME) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } -#endif - - // disable face culling for two-sided models in sub-renders - if (disableFaceCulling) - glDisable(GL_CULL_FACE); - - CShaderDefines contextOpaque = context; - contextOpaque.Add(str_ALPHABLEND_PASS_OPAQUE, str_1); - - CShaderDefines contextBlend = context; - contextBlend.Add(str_ALPHABLEND_PASS_BLEND, str_1); - - if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_OPAQUE) - m->CallTranspModelRenderers(contextOpaque, cullGroup, flags); - - if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_BLEND) - m->CallTranspModelRenderers(contextBlend, cullGroup, flags); - - if (disableFaceCulling) - glEnable(GL_CULL_FACE); - -#if !CONFIG2_GLES - if (m_ModelRenderMode == WIREFRAME) - { - // switch wireframe off again - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - else if (m_ModelRenderMode == EDGED_FACES) - { - CShaderDefines contextWireframe = contextOpaque; - contextWireframe.Add(str_MODE_WIREFRAME, str_1); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - m->CallTranspModelRenderers(contextWireframe, cullGroup, flags); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -#endif -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space) -// Based on code from Game Programming Gems 5, from http://www.terathon.com/code/oblique.html -// - worldPlane is a clip plane in world space (worldPlane.Dot(v) >= 0 for any vector v passing the clipping test) -void CRenderer::SetObliqueFrustumClipping(CCamera& camera, const CVector4D& worldPlane) const -{ - // First, we'll convert the given clip plane to camera space, then we'll - // Get the view matrix and normal matrix (top 3x3 part of view matrix) - CMatrix3D normalMatrix = camera.GetOrientation().GetTranspose(); - CVector4D camPlane = normalMatrix.Transform(worldPlane); - - CMatrix3D matrix = camera.GetProjection(); - - // Calculate the clip-space corner point opposite the clipping plane - // as (sgn(camPlane.x), sgn(camPlane.y), 1, 1) and - // transform it into camera space by multiplying it - // by the inverse of the projection matrix - - CVector4D q; - q.X = (sgn(camPlane.X) - matrix[8]/matrix[11]) / matrix[0]; - q.Y = (sgn(camPlane.Y) - matrix[9]/matrix[11]) / matrix[5]; - q.Z = 1.0f/matrix[11]; - q.W = (1.0f - matrix[10]/matrix[11]) / matrix[14]; - - // Calculate the scaled plane vector - CVector4D c = camPlane * (2.0f * matrix[11] / camPlane.Dot(q)); - - // Replace the third row of the projection matrix - matrix[2] = c.X; - matrix[6] = c.Y; - matrix[10] = c.Z - matrix[11]; - matrix[14] = c.W; - - // Load it back into the camera - camera.SetProjection(matrix); -} - -void CRenderer::ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const -{ - WaterManager& wm = m->waterManager; - - CMatrix3D projection; - if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) - { - const float aspectRatio = 1.0f; - // Expand fov slightly since ripples can reflect parts of the scene that - // are slightly outside the normal camera view, and we want to avoid any - // noticeable edge-filtering artifacts - projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane()); - } - else - projection = m_ViewCamera.GetProjection(); - - camera = m_ViewCamera; - - // Temporarily change the camera to one that is reflected. - // Also, for texturing purposes, make it render to a view port the size of the - // water texture, stretch the image according to our aspect ratio so it covers - // the whole screen despite being rendered into a square, and cover slightly more - // of the view so we can see wavy reflections of slightly off-screen objects. - camera.m_Orientation.Scale(1, -1, 1); - camera.m_Orientation.Translate(0, 2 * wm.m_WaterHeight, 0); - camera.UpdateFrustum(scissor); - // Clip slightly above the water to improve reflections of objects on the water - // when the reflections are distorted. - camera.ClipFrustum(CVector4D(0, 1, 0, -wm.m_WaterHeight + 2.0f)); - - SViewPort vp; - vp.m_Height = wm.m_RefTextureSize; - vp.m_Width = wm.m_RefTextureSize; - vp.m_X = 0; - vp.m_Y = 0; - camera.SetViewPort(vp); - camera.SetProjection(projection); - CMatrix3D scaleMat; - scaleMat.SetScaling(m_Height / static_cast(std::max(1, m_Width)), 1.0f, 1.0f); - camera.SetProjection(scaleMat * camera.GetProjection()); - - CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight + 0.5f); - SetObliqueFrustumClipping(camera, camPlane); -} - -void CRenderer::ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const -{ - WaterManager& wm = m->waterManager; - - CMatrix3D projection; - if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) - { - const float aspectRatio = 1.0f; - // Expand fov slightly since ripples can reflect parts of the scene that - // are slightly outside the normal camera view, and we want to avoid any - // noticeable edge-filtering artifacts - projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane()); - } - else - projection = m_ViewCamera.GetProjection(); - - camera = m_ViewCamera; - - // Temporarily change the camera to make it render to a view port the size of the - // water texture, stretch the image according to our aspect ratio so it covers - // the whole screen despite being rendered into a square, and cover slightly more - // of the view so we can see wavy refractions of slightly off-screen objects. - camera.UpdateFrustum(scissor); - camera.ClipFrustum(CVector4D(0, -1, 0, wm.m_WaterHeight + 0.5f)); // add some to avoid artifacts near steep shores. - - SViewPort vp; - vp.m_Height = wm.m_RefTextureSize; - vp.m_Width = wm.m_RefTextureSize; - vp.m_X = 0; - vp.m_Y = 0; - camera.SetViewPort(vp); - camera.SetProjection(projection); - CMatrix3D scaleMat; - scaleMat.SetScaling(m_Height / static_cast(std::max(1, m_Width)), 1.0f, 1.0f); - camera.SetProjection(scaleMat * camera.GetProjection()); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// RenderReflections: render the water reflections to the reflection texture -void CRenderer::RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor) -{ - PROFILE3_GPU("water reflections"); - OGL_SCOPED_DEBUG_GROUP("Render water reflections"); - - WaterManager& wm = m->waterManager; - - // Remember old camera - CCamera normalCamera = m_ViewCamera; - - ComputeReflectionCamera(m_ViewCamera, scissor); - const CBoundingBoxAligned reflectionScissor = - m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); - - SetViewport(m_ViewCamera.GetViewPort()); - - // Save the model-view-projection matrix so the shaders can use it for projective texturing - wm.m_ReflectionMatrix = m_ViewCamera.GetViewProjection(); - - float vpHeight = wm.m_RefTextureSize; - float vpWidth = wm.m_RefTextureSize; - - SScreenRect screenScissor; - screenScissor.x1 = (GLint)floor((reflectionScissor[0].X*0.5f+0.5f)*vpWidth); - screenScissor.y1 = (GLint)floor((reflectionScissor[0].Y*0.5f+0.5f)*vpHeight); - screenScissor.x2 = (GLint)ceil((reflectionScissor[1].X*0.5f+0.5f)*vpWidth); - screenScissor.y2 = (GLint)ceil((reflectionScissor[1].Y*0.5f+0.5f)*vpHeight); - - glEnable(GL_SCISSOR_TEST); - glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1); - - // try binding the framebuffer - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, wm.m_ReflectionFbo); - - glClearColor(0.5f, 0.5f, 1.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glFrontFace(GL_CW); - - if (!g_RenderingOptions.GetWaterReflection()) - { - m->skyManager.RenderSky(); - ogl_WarnIfError(); - } - else - { - // Render terrain and models - RenderPatches(context, CULL_REFLECTIONS); - ogl_WarnIfError(); - RenderModels(context, CULL_REFLECTIONS); - ogl_WarnIfError(); - RenderTransparentModels(context, CULL_REFLECTIONS, TRANSPARENT, true); - ogl_WarnIfError(); - } - glFrontFace(GL_CCW); - - // Particles are always oriented to face the camera in the vertex shader, - // so they don't need the inverted glFrontFace - if (g_RenderingOptions.GetParticles()) - { - RenderParticles(CULL_REFLECTIONS); - ogl_WarnIfError(); - } - - glDisable(GL_SCISSOR_TEST); - - // Reset old camera - m_ViewCamera = normalCamera; - SetViewport(m_ViewCamera.GetViewPort()); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// RenderRefractions: render the water refractions to the refraction texture -void CRenderer::RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned &scissor) -{ - PROFILE3_GPU("water refractions"); - OGL_SCOPED_DEBUG_GROUP("Render water refractions"); - - WaterManager& wm = m->waterManager; - - // Remember old camera - CCamera normalCamera = m_ViewCamera; - - ComputeRefractionCamera(m_ViewCamera, scissor); - const CBoundingBoxAligned refractionScissor = - m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); - - CVector4D camPlane(0, -1, 0, wm.m_WaterHeight + 2.0f); - SetObliqueFrustumClipping(m_ViewCamera, camPlane); - - SetViewport(m_ViewCamera.GetViewPort()); - - // Save the model-view-projection matrix so the shaders can use it for projective texturing - wm.m_RefractionMatrix = m_ViewCamera.GetViewProjection(); - wm.m_RefractionProjInvMatrix = m_ViewCamera.GetProjection().GetInverse(); - wm.m_RefractionViewInvMatrix = m_ViewCamera.GetOrientation(); - - float vpHeight = wm.m_RefTextureSize; - float vpWidth = wm.m_RefTextureSize; - - SScreenRect screenScissor; - screenScissor.x1 = (GLint)floor((refractionScissor[0].X*0.5f+0.5f)*vpWidth); - screenScissor.y1 = (GLint)floor((refractionScissor[0].Y*0.5f+0.5f)*vpHeight); - screenScissor.x2 = (GLint)ceil((refractionScissor[1].X*0.5f+0.5f)*vpWidth); - screenScissor.y2 = (GLint)ceil((refractionScissor[1].Y*0.5f+0.5f)*vpHeight); - - glEnable(GL_SCISSOR_TEST); - glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1); - - // try binding the framebuffer - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, wm.m_RefractionFbo); - - glClearColor(1.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Render terrain and models - RenderPatches(context, CULL_REFRACTIONS); - ogl_WarnIfError(); - RenderModels(context, CULL_REFRACTIONS); - ogl_WarnIfError(); - RenderTransparentModels(context, CULL_REFRACTIONS, TRANSPARENT_OPAQUE, false); - ogl_WarnIfError(); - - glDisable(GL_SCISSOR_TEST); - - // Reset old camera - m_ViewCamera = normalCamera; - SetViewport(m_ViewCamera.GetViewPort()); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); -} - -void CRenderer::RenderSilhouettes(const CShaderDefines& context) -{ - PROFILE3_GPU("silhouettes"); - OGL_SCOPED_DEBUG_GROUP("Render water silhouettes"); - - CShaderDefines contextOccluder = context; - contextOccluder.Add(str_MODE_SILHOUETTEOCCLUDER, str_1); - - CShaderDefines contextDisplay = context; - contextDisplay.Add(str_MODE_SILHOUETTEDISPLAY, str_1); - - // Render silhouettes of units hidden behind terrain or occluders. - // To avoid breaking the standard rendering of alpha-blended objects, this - // has to be done in a separate pass. - // First we render all occluders into depth, then render all units with - // inverted depth test so any behind an occluder will get drawn in a constant - // color. - - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - glColorMask(0, 0, 0, 0); - - // Render occluders: - - { - PROFILE("render patches"); - - // To prevent units displaying silhouettes when parts of their model - // protrude into the ground, only occlude with the back faces of the - // terrain (so silhouettes will still display when behind hills) - glCullFace(GL_FRONT); - m->terrainRenderer.RenderPatches(CULL_SILHOUETTE_OCCLUDER); - glCullFace(GL_BACK); - } - - { - PROFILE("render model occluders"); - m->CallModelRenderers(contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0); - } - - { - PROFILE("render transparent occluders"); - m->CallTranspModelRenderers(contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0); - } - - glDepthFunc(GL_GEQUAL); - glColorMask(1, 1, 1, 1); - - // Since we can't sort, we'll use the stencil buffer to ensure we only draw - // a pixel once (using the color of whatever model happens to be drawn first). - glEnable(GL_BLEND); - glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); - const float silhouetteAlpha = 0.75f; - glBlendColorEXT(0, 0, 0, silhouetteAlpha); - - glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_NOTEQUAL, 1, (GLuint)-1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - { - PROFILE("render model casters"); - m->CallModelRenderers(contextDisplay, CULL_SILHOUETTE_CASTER, 0); - } - - { - PROFILE("render transparent casters"); - m->CallTranspModelRenderers(contextDisplay, CULL_SILHOUETTE_CASTER, 0); - } - - // Restore state - glDepthFunc(GL_LEQUAL); - glDisable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendColorEXT(0, 0, 0, 0); - glDisable(GL_STENCIL_TEST); -} - -void CRenderer::RenderParticles(int cullGroup) -{ - PROFILE3_GPU("particles"); - OGL_SCOPED_DEBUG_GROUP("Render particles"); - - m->particleRenderer.RenderParticles(cullGroup); - -#if !CONFIG2_GLES - if (m_ModelRenderMode == EDGED_FACES) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - m->particleRenderer.RenderParticles(true); - m->particleRenderer.RenderBounds(cullGroup); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } -#endif -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// RenderSubmissions: force rendering of any batched objects -void CRenderer::RenderSubmissions(const CBoundingBoxAligned& waterScissor) -{ - PROFILE3("render submissions"); - OGL_SCOPED_DEBUG_GROUP("Render submissions"); - - GetScene().GetLOSTexture().InterpolateLOS(); - - GetScene().GetMiniMapTexture().Render(); - - CShaderDefines context = m->globalContext; - - int cullGroup = CULL_DEFAULT; - - ogl_WarnIfError(); - - // Set the camera - SetViewport(m_ViewCamera.GetViewPort()); - - // Prepare model renderers - { - PROFILE3("prepare models"); - m->Model.NormalSkinned->PrepareModels(); - m->Model.TranspSkinned->PrepareModels(); - if (m->Model.NormalUnskinned != m->Model.NormalSkinned) - m->Model.NormalUnskinned->PrepareModels(); - if (m->Model.TranspUnskinned != m->Model.TranspSkinned) - m->Model.TranspUnskinned->PrepareModels(); - } - - m->terrainRenderer.PrepareForRendering(); - - m->overlayRenderer.PrepareForRendering(); - - m->particleRenderer.PrepareForRendering(context); - - if (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) - { - RenderShadowMap(context); - } - - ogl_WarnIfError(); - - if (m->waterManager.m_RenderWater) - { - if (waterScissor.GetVolume() > 0 && m->waterManager.WillRenderFancyWater()) - { - PROFILE3_GPU("water scissor"); - RenderReflections(context, waterScissor); - - if (g_RenderingOptions.GetWaterRefraction()) - RenderRefractions(context, waterScissor); - } - } - - if (g_RenderingOptions.GetPostProc()) - { - // We have to update the post process manager with real near/far planes - // that we use for the scene rendering. - m->postprocManager.SetDepthBufferClipPlanes( - m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane() - ); - m->postprocManager.Initialize(); - m->postprocManager.CaptureRenderOutput(); - } - - { - PROFILE3_GPU("clear buffers"); - glClearColor(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - - m->skyManager.RenderSky(); - - // render submitted patches and models - RenderPatches(context, cullGroup); - ogl_WarnIfError(); - - // render debug-related terrain overlays - ITerrainOverlay::RenderOverlaysBeforeWater(); - ogl_WarnIfError(); - - // render other debug-related overlays before water (so they can be seen when underwater) - m->overlayRenderer.RenderOverlaysBeforeWater(); - ogl_WarnIfError(); - - RenderModels(context, cullGroup); - ogl_WarnIfError(); - - // render water - if (m->waterManager.m_RenderWater && g_Game && waterScissor.GetVolume() > 0) - { - if (m->waterManager.WillRenderFancyWater()) - { - // Render transparent stuff, but only the solid parts that can occlude block water. - RenderTransparentModels(context, cullGroup, TRANSPARENT_OPAQUE, false); - ogl_WarnIfError(); - - m->terrainRenderer.RenderWater(context, cullGroup, &m->shadow); - ogl_WarnIfError(); - - // Render transparent stuff again, but only the blended parts that overlap water. - RenderTransparentModels(context, cullGroup, TRANSPARENT_BLEND, false); - ogl_WarnIfError(); - } - else - { - m->terrainRenderer.RenderWater(context, cullGroup, &m->shadow); - ogl_WarnIfError(); - - // Render transparent stuff, so it can overlap models/terrain. - RenderTransparentModels(context, cullGroup, TRANSPARENT, false); - ogl_WarnIfError(); - } - } - else - { - // render transparent stuff, so it can overlap models/terrain - RenderTransparentModels(context, cullGroup, TRANSPARENT, false); - ogl_WarnIfError(); - } - - // render debug-related terrain overlays - ITerrainOverlay::RenderOverlaysAfterWater(cullGroup); - ogl_WarnIfError(); - - // render some other overlays after water (so they can be displayed on top of water) - m->overlayRenderer.RenderOverlaysAfterWater(); - ogl_WarnIfError(); - - // particles are transparent so render after water - if (g_RenderingOptions.GetParticles()) - { - RenderParticles(cullGroup); - ogl_WarnIfError(); - } - - if (g_RenderingOptions.GetPostProc()) - { - if (g_Renderer.GetPostprocManager().IsMultisampleEnabled()) - g_Renderer.GetPostprocManager().ResolveMultisampleFramebuffer(); - - m->postprocManager.ApplyPostproc(); - m->postprocManager.ReleaseRenderOutput(); - } - - if (g_RenderingOptions.GetSilhouettes()) - { - RenderSilhouettes(context); - } - - // render debug lines - if (g_RenderingOptions.GetDisplayFrustum()) - DisplayFrustum(); - - if (g_RenderingOptions.GetDisplayShadowsFrustum()) - { - m->shadow.RenderDebugBounds(); - m->shadow.RenderDebugTexture(); - } - - m->silhouetteRenderer.RenderDebugOverlays(m_ViewCamera); - - // render overlays that should appear on top of all other objects - m->overlayRenderer.RenderForegroundOverlays(m_ViewCamera); - ogl_WarnIfError(); - -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// EndFrame: signal frame end void CRenderer::EndFrame() { PROFILE3("end frame"); - // empty lists - m->terrainRenderer.EndFrame(); - m->overlayRenderer.EndFrame(); - m->particleRenderer.EndFrame(); - m->silhouetteRenderer.EndFrame(); - - // Finish model renderers - m->Model.NormalSkinned->EndFrame(); - m->Model.TranspSkinned->EndFrame(); - if (m->Model.NormalUnskinned != m->Model.NormalSkinned) - m->Model.NormalUnskinned->EndFrame(); - if (m->Model.TranspUnskinned != m->Model.TranspSkinned) - m->Model.TranspUnskinned->EndFrame(); + m->sceneRenderer.EndFrame(); ogl_tex_bind(0, 0); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// DisplayFrustum: debug displays -// - white: cull camera frustum -// - red: bounds of shadow casting objects -void CRenderer::DisplayFrustum() -{ -#if CONFIG2_GLES -#warning TODO: implement CRenderer::DisplayFrustum for GLES -#else - glDepthMask(0); - glDisable(GL_CULL_FACE); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - GetDebugRenderer().DrawCameraFrustum(m_CullCamera, CColor(1.0f, 1.0f, 1.0f, 0.25f), 2); - glDisable(GL_BLEND); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - GetDebugRenderer().DrawCameraFrustum(m_CullCamera, CColor(1.0f, 1.0f, 1.0f, 1.0f), 2); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glEnable(GL_CULL_FACE); - glDepthMask(1); -#endif - - ogl_WarnIfError(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Text overlay rendering -void CRenderer::RenderTextOverlays() -{ - PROFILE3_GPU("text overlays"); - - if (m_DisplayTerrainPriorities) - m->terrainRenderer.RenderPriorities(CULL_DEFAULT); - - ogl_WarnIfError(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// SetSceneCamera: setup projection and transform of camera and adjust viewport to current view -// The camera always represents the actual camera used to render a scene, not any virtual camera -// used for shadow rendering or reflections. -void CRenderer::SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera) -{ - m_ViewCamera = viewCamera; - m_CullCamera = cullCamera; - - if (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) - m->shadow.SetupFrame(m_CullCamera, m_LightEnv->GetSunDir()); -} - - void CRenderer::SetViewport(const SViewPort &vp) { m_Viewport = vp; @@ -1443,197 +441,6 @@ SViewPort CRenderer::GetViewport() return m_Viewport; } -void CRenderer::Submit(CPatch* patch) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - { - m->shadow.AddShadowReceiverBound(patch->GetWorldBounds()); - m->silhouetteRenderer.AddOccluder(patch); - } - - if (CULL_SHADOWS_CASCADE_0 <= m_CurrentCullGroup && m_CurrentCullGroup <= CULL_SHADOWS_CASCADE_3) - { - const int cascade = m_CurrentCullGroup - CULL_SHADOWS_CASCADE_0; - m->shadow.AddShadowCasterBound(cascade, patch->GetWorldBounds()); - } - - m->terrainRenderer.Submit(m_CurrentCullGroup, patch); -} - -void CRenderer::Submit(SOverlayLine* overlay) -{ - // Overlays are only needed in the default cull group for now, - // so just ignore submissions to any other group - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(SOverlayTexturedLine* overlay) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(SOverlaySprite* overlay) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(SOverlayQuad* overlay) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(SOverlaySphere* overlay) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - m->overlayRenderer.Submit(overlay); -} - -void CRenderer::Submit(CModelDecal* decal) -{ - // Decals can't cast shadows since they're flat on the terrain. - // They can receive shadows, but the terrain under them will have - // already been passed to AddShadowCasterBound, so don't bother - // doing it again here. - - m->terrainRenderer.Submit(m_CurrentCullGroup, decal); -} - -void CRenderer::Submit(CParticleEmitter* emitter) -{ - m->particleRenderer.Submit(m_CurrentCullGroup, emitter); -} - -void CRenderer::SubmitNonRecursive(CModel* model) -{ - if (m_CurrentCullGroup == CULL_DEFAULT) - { - m->shadow.AddShadowReceiverBound(model->GetWorldBounds()); - - if (model->GetFlags() & MODELFLAG_SILHOUETTE_OCCLUDER) - m->silhouetteRenderer.AddOccluder(model); - if (model->GetFlags() & MODELFLAG_SILHOUETTE_DISPLAY) - m->silhouetteRenderer.AddCaster(model); - } - - if (CULL_SHADOWS_CASCADE_0 <= m_CurrentCullGroup && m_CurrentCullGroup <= CULL_SHADOWS_CASCADE_3) - { - if (!(model->GetFlags() & MODELFLAG_CASTSHADOWS)) - return; - - const int cascade = m_CurrentCullGroup - CULL_SHADOWS_CASCADE_0; - m->shadow.AddShadowCasterBound(cascade, model->GetWorldBounds()); - } - - bool requiresSkinning = (model->GetModelDef()->GetNumBones() != 0); - - if (model->GetMaterial().UsesAlphaBlending()) - { - if (requiresSkinning) - m->Model.TranspSkinned->Submit(m_CurrentCullGroup, model); - else - m->Model.TranspUnskinned->Submit(m_CurrentCullGroup, model); - } - else - { - if (requiresSkinning) - m->Model.NormalSkinned->Submit(m_CurrentCullGroup, model); - else - m->Model.NormalUnskinned->Submit(m_CurrentCullGroup, model); - } -} - - -/////////////////////////////////////////////////////////// -// Render the given scene -void CRenderer::RenderScene(Scene& scene) -{ - m_CurrentScene = &scene; - - CFrustum frustum = m_CullCamera.GetFrustum(); - - m_CurrentCullGroup = CULL_DEFAULT; - - scene.EnumerateObjects(frustum, this); - - m->particleManager.RenderSubmit(*this, frustum); - - if (g_RenderingOptions.GetSilhouettes()) - { - m->silhouetteRenderer.ComputeSubmissions(m_ViewCamera); - - m_CurrentCullGroup = CULL_DEFAULT; - m->silhouetteRenderer.RenderSubmitOverlays(*this); - - m_CurrentCullGroup = CULL_SILHOUETTE_OCCLUDER; - m->silhouetteRenderer.RenderSubmitOccluders(*this); - - m_CurrentCullGroup = CULL_SILHOUETTE_CASTER; - m->silhouetteRenderer.RenderSubmitCasters(*this); - } - - if (m_Caps.m_Shadows && g_RenderingOptions.GetShadows()) - { - for (int cascade = 0; cascade <= m->shadow.GetCascadeCount(); ++cascade) - { - m_CurrentCullGroup = CULL_SHADOWS_CASCADE_0 + cascade; - const CFrustum shadowFrustum = m->shadow.GetShadowCasterCullFrustum(cascade); - scene.EnumerateObjects(shadowFrustum, this); - } - } - - CBoundingBoxAligned waterScissor; - if (m->waterManager.m_RenderWater) - { - waterScissor = m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); - - if (waterScissor.GetVolume() > 0 && m->waterManager.WillRenderFancyWater()) - { - if (g_RenderingOptions.GetWaterReflection()) - { - m_CurrentCullGroup = CULL_REFLECTIONS; - - CCamera reflectionCamera; - ComputeReflectionCamera(reflectionCamera, waterScissor); - - scene.EnumerateObjects(reflectionCamera.GetFrustum(), this); - } - - if (g_RenderingOptions.GetWaterRefraction()) - { - m_CurrentCullGroup = CULL_REFRACTIONS; - - CCamera refractionCamera; - ComputeRefractionCamera(refractionCamera, waterScissor); - - scene.EnumerateObjects(refractionCamera.GetFrustum(), this); - } - - // Render the waves to the Fancy effects texture - m->waterManager.RenderWaves(frustum); - } - } - - m_CurrentCullGroup = -1; - - ogl_WarnIfError(); - - RenderSubmissions(waterScissor); - - m_CurrentScene = NULL; -} - -Scene& CRenderer::GetScene() -{ - ENSURE(m_CurrentScene); - return *m_CurrentScene; -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// BindTexture: bind a GL texture object to current active unit void CRenderer::BindTexture(int unit, GLuint tex) { glActiveTextureARB(GL_TEXTURE0+unit); @@ -1644,17 +451,7 @@ void CRenderer::BindTexture(int unit, GLuint tex) void CRenderer::MakeShadersDirty() { m->ShadersDirty = true; - m->waterManager.m_NeedsReloading = true; -} - -WaterManager& CRenderer::GetWaterManager() -{ - return m->waterManager; -} - -SkyManager& CRenderer::GetSkyManager() -{ - return m->skyManager; + m->sceneRenderer.MakeShadersDirty(); } CTextureManager& CRenderer::GetTextureManager() @@ -1667,31 +464,21 @@ CShaderManager& CRenderer::GetShaderManager() return m->shaderManager; } -CParticleManager& CRenderer::GetParticleManager() -{ - return m->particleManager; -} - -TerrainRenderer& CRenderer::GetTerrainRenderer() -{ - return m->terrainRenderer; -} - CTimeManager& CRenderer::GetTimeManager() { return m->timeManager; } -CMaterialManager& CRenderer::GetMaterialManager() -{ - return m->materialManager; -} - CPostprocManager& CRenderer::GetPostprocManager() { return m->postprocManager; } +CSceneRenderer& CRenderer::GetSceneRenderer() +{ + return m->sceneRenderer; +} + CDebugRenderer& CRenderer::GetDebugRenderer() { return m->debugRenderer; @@ -1701,14 +488,3 @@ CFontManager& CRenderer::GetFontManager() { return m->fontManager; } - -ShadowMap& CRenderer::GetShadowMap() -{ - return m->shadow; -} - -void CRenderer::ResetState() -{ - // Clear all emitters, that were created in previous games - GetParticleManager().ClearUnattachedEmitters(); -} diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index 2f701356e6..51e6076865 100644 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -15,11 +15,6 @@ * along with 0 A.D. If not, see . */ -/* - * higher level interface on top of OpenGL to render basic objects: - * terrain, models, sprites, particles etc. - */ - #ifndef INCLUDED_RENDERER #define INCLUDED_RENDERER @@ -34,51 +29,22 @@ class CDebugRenderer; class CFontManager; -class CLightEnv; -class CMaterial; -class CMaterialManager; -class CModel; -class CParticleManager; -class CPatch; class CPostprocManager; +class CSceneRenderer; class CShaderManager; -class CSimulation2; class CTextureManager; class CTimeManager; -class RenderPathVertexShader; -class ShadowMap; -class SkyManager; -class TerrainRenderer; -class WaterManager; -// rendering modes -enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES }; - -// transparency modes -enum ETransparentMode { TRANSPARENT, TRANSPARENT_OPAQUE, TRANSPARENT_BLEND }; - -// access to sole renderer object #define g_Renderer CRenderer::GetSingleton() -class CRenderer : - public Singleton, - private SceneCollector +/** + * Higher level interface on top of the whole frame rendering. It does know + * what should be rendered and via which renderer but shouldn't know how to + * render a particular area, like UI or scene. + */ +class CRenderer : public Singleton { public: - enum CullGroup - { - CULL_DEFAULT, - CULL_SHADOWS_CASCADE_0, - CULL_SHADOWS_CASCADE_1, - CULL_SHADOWS_CASCADE_2, - CULL_SHADOWS_CASCADE_3, - CULL_REFLECTIONS, - CULL_REFRACTIONS, - CULL_SILHOUETTE_OCCLUDER, - CULL_SILHOUETTE_CASTER, - CULL_MAX - }; - // stats class - per frame counts of number of draw calls, poly counts etc struct Stats { @@ -111,150 +77,52 @@ public: }; public: - // constructor, destructor CRenderer(); ~CRenderer(); // open up the renderer: performs any necessary initialisation - bool Open(int width,int height); + bool Open(int width, int height); // resize renderer view - void Resize(int width,int height); + void Resize(int width, int height); // return view width int GetWidth() const { return m_Width; } // return view height int GetHeight() const { return m_Height; } - // return view aspect ratio - float GetAspect() const { return float(m_Width)/float(m_Height); } // signal frame start void BeginFrame(); // signal frame end void EndFrame(); - /** - * Set simulation context for rendering purposes. - * Must be called at least once when the game has started and before - * frames are rendered. - */ - void SetSimulation(CSimulation2* simulation); - // trigger a reload of shaders (when parameters they depend on have changed) void MakeShadersDirty(); - /** - * Set up the camera used for rendering the next scene; this includes - * setting OpenGL state like viewport, projection and modelview matrices. - * - * @param viewCamera this camera determines the eye position for rendering - * @param cullCamera this camera determines the frustum for culling in the renderer and - * for shadow calculations - */ - void SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera); - // set the viewport void SetViewport(const SViewPort &); // get the last viewport SViewPort GetViewport(); - /** - * Render the given scene immediately. - * @param scene a Scene object describing what should be rendered. - */ - void RenderScene(Scene& scene); - - /** - * Return the scene that is currently being rendered. - * Only valid when the renderer is in a RenderScene call. - */ - Scene& GetScene(); - - /** - * Render text overlays on top of the scene. - * Assumes the caller has set up the GL environment for orthographic rendering - * with texturing and blending. - */ - void RenderTextOverlays(); - - // set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer, - // so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering) - void SetLightEnv(CLightEnv* lightenv) - { - m_LightEnv = lightenv; - } - - // set the mode to render subsequent terrain patches - void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode = mode; } - // get the mode to render subsequent terrain patches - ERenderMode GetTerrainRenderMode() const { return m_TerrainRenderMode; } - - // set the mode to render subsequent water patches - void SetWaterRenderMode(ERenderMode mode) { m_WaterRenderMode = mode; } - // get the mode to render subsequent water patches - ERenderMode GetWaterRenderMode() const { return m_WaterRenderMode; } - - // set the mode to render subsequent models - void SetModelRenderMode(ERenderMode mode) { m_ModelRenderMode = mode; } - // get the mode to render subsequent models - ERenderMode GetModelRenderMode() const { return m_ModelRenderMode; } - - // Get the mode to render subsequent overlays. - ERenderMode GetOverlayRenderMode() const { return m_OverlayRenderMode; } - // Set the mode to render subsequent overlays. - void SetOverlayRenderMode(ERenderMode mode) { m_OverlayRenderMode = mode; } - - // debugging - void SetDisplayTerrainPriorities(bool enabled) { m_DisplayTerrainPriorities = enabled; } - // bind a GL texture object to active unit void BindTexture(int unit, unsigned int tex); // return stats accumulated for current frame Stats& GetStats() { return m_Stats; } - // return the current light environment - const CLightEnv &GetLightEnv() { return *m_LightEnv; } - - // return the current view camera - const CCamera& GetViewCamera() const { return m_ViewCamera; } - // replace the current view camera - void SetViewCamera(const CCamera& camera) { m_ViewCamera = camera; } - - // return the current cull camera - const CCamera& GetCullCamera() const { return m_CullCamera; } - - /** - * GetWaterManager: Return the renderer's water manager. - * - * @return the WaterManager object used by the renderer - */ - WaterManager& GetWaterManager(); - - /** - * GetSkyManager: Return the renderer's sky manager. - * - * @return the SkyManager object used by the renderer - */ - SkyManager& GetSkyManager(); - CTextureManager& GetTextureManager(); CShaderManager& GetShaderManager(); - CParticleManager& GetParticleManager(); - - TerrainRenderer& GetTerrainRenderer(); - - CMaterialManager& GetMaterialManager(); - CFontManager& GetFontManager(); CTimeManager& GetTimeManager(); CPostprocManager& GetPostprocManager(); + CSceneRenderer& GetSceneRenderer(); + CDebugRenderer& GetDebugRenderer(); /** @@ -264,13 +132,6 @@ public: */ const Caps& GetCapabilities() const { return m_Caps; } - ShadowMap& GetShadowMap(); - - /** - * Resets the render state to default, that was before a game started - */ - void ResetState(); - protected: friend class CPatchRData; friend class CDecalRData; @@ -279,54 +140,14 @@ protected: friend class InstancingModelRenderer; friend class CRenderingOptions; - //BEGIN: Implementation of SceneCollector - void Submit(CPatch* patch); - void Submit(SOverlayLine* overlay); - void Submit(SOverlayTexturedLine* overlay); - void Submit(SOverlaySprite* overlay); - void Submit(SOverlayQuad* overlay); - void Submit(CModelDecal* decal); - void Submit(CParticleEmitter* emitter); - void Submit(SOverlaySphere* overlay); - void SubmitNonRecursive(CModel* model); - //END: Implementation of SceneCollector - - // render any batched objects - void RenderSubmissions(const CBoundingBoxAligned& waterScissor); - - // patch rendering stuff - void RenderPatches(const CShaderDefines& context, int cullGroup); - - // model rendering stuff - void RenderModels(const CShaderDefines& context, int cullGroup); - void RenderTransparentModels(const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode, bool disableFaceCulling); - - void RenderSilhouettes(const CShaderDefines& context); - - void RenderParticles(int cullGroup); - - // shadow rendering stuff - void RenderShadowMap(const CShaderDefines& context); - - // render water reflection and refraction textures - void RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor); - void RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned& scissor); - - void ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const; - void ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const; - - // debugging - void DisplayFrustum(); - - // enable oblique frustum clipping with the given clip plane - void SetObliqueFrustumClipping(CCamera& camera, const CVector4D& clipPlane) const; - + // SetRenderPath: Select the preferred render path. + // This may only be called before Open(), because the layout of vertex arrays and other + // data may depend on the chosen render path. void SetRenderPath(RenderPath rp); void ReloadShaders(); - // RENDERER DATA: - /// Private data that is not needed by inline functions + // Private data that is not needed by inline functions. class Internals; std::unique_ptr m; // view width @@ -334,50 +155,14 @@ protected: // view height int m_Height; - // Current terrain rendering mode. - ERenderMode m_TerrainRenderMode; - // Current water rendering mode. - ERenderMode m_WaterRenderMode; - // Current model rendering mode. - ERenderMode m_ModelRenderMode; - // Current overlay rendering mode. - ERenderMode m_OverlayRenderMode; - SViewPort m_Viewport; - /** - * m_ViewCamera: determines the eye position for rendering - * - * @see CGameView::m_ViewCamera - */ - CCamera m_ViewCamera; - - /** - * m_CullCamera: determines the frustum for culling and shadowmap calculations - * - * @see CGameView::m_ViewCamera - */ - CCamera m_CullCamera; - - // only valid inside a call to RenderScene - Scene* m_CurrentScene; - int m_CurrentCullGroup; - - // color used to clear screen in BeginFrame - float m_ClearColor[4]; - // current lighting setup - CLightEnv* m_LightEnv; // card capabilities Caps m_Caps; // build card cap bits void EnumCaps(); // per-frame renderer stats Stats m_Stats; - - /** - * Enable rendering of terrain tile priority text overlay, for debugging. - */ - bool m_DisplayTerrainPriorities; }; #endif // INCLUDED_RENDERER diff --git a/source/renderer/RenderingOptions.cpp b/source/renderer/RenderingOptions.cpp index b63a2d6d75..680ac93cf7 100644 --- a/source/renderer/RenderingOptions.cpp +++ b/source/renderer/RenderingOptions.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include "ps/VideoMode.h" #include "renderer/Renderer.h" #include "renderer/PostprocManager.h" +#include "renderer/SceneRenderer.h" #include "renderer/ShadowMap.h" CRenderingOptions g_RenderingOptions; @@ -146,25 +147,25 @@ void CRenderingOptions::ReadConfigAndSetupHooks() m_ConfigHooks->Setup("shadowquality", []() { if (CRenderer::IsInitialised()) - g_Renderer.GetShadowMap().RecreateTexture(); + g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadowscascadecount", []() { if (CRenderer::IsInitialised()) { - g_Renderer.GetShadowMap().RecreateTexture(); + g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); g_Renderer.MakeShadersDirty(); } }); m_ConfigHooks->Setup("shadowscovermap", []() { if (CRenderer::IsInitialised()) { - g_Renderer.GetShadowMap().RecreateTexture(); + g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); g_Renderer.MakeShadersDirty(); } }); m_ConfigHooks->Setup("shadowscutoffdistance", []() { if (CRenderer::IsInitialised()) - g_Renderer.GetShadowMap().RecreateTexture(); + g_Renderer.GetSceneRenderer().GetShadowMap().RecreateTexture(); }); m_ConfigHooks->Setup("shadows", [this]() { diff --git a/source/renderer/SceneRenderer.cpp b/source/renderer/SceneRenderer.cpp new file mode 100644 index 0000000000..aef25c2beb --- /dev/null +++ b/source/renderer/SceneRenderer.cpp @@ -0,0 +1,1298 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "SceneRenderer.h" + +#include "maths/Matrix3D.h" +#include "maths/MathUtil.h" +#include "ps/CLogger.h" +#include "ps/ConfigDB.h" +#include "ps/CStrInternStatic.h" +#include "ps/Game.h" +#include "ps/Profile.h" +#include "ps/World.h" +#include "graphics/Camera.h" +#include "graphics/Decal.h" +#include "graphics/GameView.h" +#include "graphics/LightEnv.h" +#include "graphics/LOSTexture.h" +#include "graphics/MaterialManager.h" +#include "graphics/MiniMapTexture.h" +#include "graphics/Model.h" +#include "graphics/ModelDef.h" +#include "graphics/ParticleManager.h" +#include "graphics/Patch.h" +#include "graphics/ShaderManager.h" +#include "graphics/Terrain.h" +#include "graphics/Texture.h" +#include "graphics/TextureManager.h" +#include "ps/VideoMode.h" +#include "renderer/DebugRenderer.h" +#include "renderer/HWLightingModelRenderer.h" +#include "renderer/InstancingModelRenderer.h" +#include "renderer/ModelRenderer.h" +#include "renderer/OverlayRenderer.h" +#include "renderer/ParticleRenderer.h" +#include "renderer/PostprocManager.h" +#include "renderer/Renderer.h" +#include "renderer/RenderingOptions.h" +#include "renderer/RenderModifiers.h" +#include "renderer/ShadowMap.h" +#include "renderer/SilhouetteRenderer.h" +#include "renderer/SkyManager.h" +#include "renderer/TerrainOverlay.h" +#include "renderer/TerrainRenderer.h" +#include "renderer/WaterManager.h" + +#include + +struct SScreenRect +{ + GLint x1, y1, x2, y2; +}; + +/** + * Struct CSceneRendererInternals: Truly hide data that is supposed to be hidden + * in this structure so it won't even appear in header files. + */ +class CSceneRenderer::Internals +{ + NONCOPYABLE(Internals); +public: + Internals() = default; + ~Internals() = default; + + /// Water manager + WaterManager waterManager; + + /// Sky manager + SkyManager skyManager; + + /// Terrain renderer + TerrainRenderer terrainRenderer; + + /// Overlay renderer + OverlayRenderer overlayRenderer; + + /// Particle manager + CParticleManager particleManager; + + /// Particle renderer + ParticleRenderer particleRenderer; + + /// Material manager + CMaterialManager materialManager; + + /// Shadow map + ShadowMap shadow; + + SilhouetteRenderer silhouetteRenderer; + + /// Various model renderers + struct Models + { + // NOTE: The current renderer design (with ModelRenderer, ModelVertexRenderer, + // RenderModifier, etc) is mostly a relic of an older design that implemented + // the different materials and rendering modes through extensive subclassing + // and hooking objects together in various combinations. + // The new design uses the CShaderManager API to abstract away the details + // of rendering, and uses a data-driven approach to materials, so there are + // now a small number of generic subclasses instead of many specialised subclasses, + // but most of the old infrastructure hasn't been refactored out yet and leads to + // some unwanted complexity. + + // Submitted models are split on two axes: + // - Normal vs Transp[arent] - alpha-blended models are stored in a separate + // list so we can draw them above/below the alpha-blended water plane correctly + // - Skinned vs Unskinned - with hardware lighting we don't need to + // duplicate mesh data per model instance (except for skinned models), + // so non-skinned models get different ModelVertexRenderers + + ModelRendererPtr NormalSkinned; + ModelRendererPtr NormalUnskinned; // == NormalSkinned if unskinned shader instancing not supported + ModelRendererPtr TranspSkinned; + ModelRendererPtr TranspUnskinned; // == TranspSkinned if unskinned shader instancing not supported + + ModelVertexRendererPtr VertexRendererShader; + ModelVertexRendererPtr VertexInstancingShader; + ModelVertexRendererPtr VertexGPUSkinningShader; + + LitRenderModifierPtr ModShader; + } Model; + + CShaderDefines globalContext; + + /** + * Renders all non-alpha-blended models with the given context. + */ + void CallModelRenderers(const CShaderDefines& context, int cullGroup, int flags) + { + CShaderDefines contextSkinned = context; + if (g_RenderingOptions.GetGPUSkinning()) + { + contextSkinned.Add(str_USE_INSTANCING, str_1); + contextSkinned.Add(str_USE_GPU_SKINNING, str_1); + } + Model.NormalSkinned->Render(Model.ModShader, contextSkinned, cullGroup, flags); + + if (Model.NormalUnskinned != Model.NormalSkinned) + { + CShaderDefines contextUnskinned = context; + contextUnskinned.Add(str_USE_INSTANCING, str_1); + Model.NormalUnskinned->Render(Model.ModShader, contextUnskinned, cullGroup, flags); + } + } + + /** + * Renders all alpha-blended models with the given context. + */ + void CallTranspModelRenderers(const CShaderDefines& context, int cullGroup, int flags) + { + CShaderDefines contextSkinned = context; + if (g_RenderingOptions.GetGPUSkinning()) + { + contextSkinned.Add(str_USE_INSTANCING, str_1); + contextSkinned.Add(str_USE_GPU_SKINNING, str_1); + } + Model.TranspSkinned->Render(Model.ModShader, contextSkinned, cullGroup, flags); + + if (Model.TranspUnskinned != Model.TranspSkinned) + { + CShaderDefines contextUnskinned = context; + contextUnskinned.Add(str_USE_INSTANCING, str_1); + Model.TranspUnskinned->Render(Model.ModShader, contextUnskinned, cullGroup, flags); + } + } +}; + +CSceneRenderer::CSceneRenderer() +{ + m = std::make_unique(); + + m_TerrainRenderMode = SOLID; + m_WaterRenderMode = SOLID; + m_ModelRenderMode = SOLID; + m_OverlayRenderMode = SOLID; + m_ClearColor[0] = m_ClearColor[1] = m_ClearColor[2] = m_ClearColor[3] = 0; + + m_DisplayTerrainPriorities = false; + + CStr skystring = "0 0 0"; + CColor skycolor; + CFG_GET_VAL("skycolor", skystring); + if (skycolor.ParseString(skystring, 255.f)) + { + m_ClearColor[0] = skycolor.r; + m_ClearColor[1] = skycolor.g; + m_ClearColor[2] = skycolor.b; + m_ClearColor[3] = skycolor.a; + } + + m_LightEnv = nullptr; + + m_CurrentScene = nullptr; +} + +CSceneRenderer::~CSceneRenderer() +{ + // We no longer UnloadWaterTextures here - + // that is the responsibility of the module that asked for + // them to be loaded (i.e. CGameView). + m.reset(); +} + +void CSceneRenderer::ReloadShaders() +{ + m->globalContext = CShaderDefines(); + + const CRenderer::Caps& capabilities = g_Renderer.GetCapabilities(); + if (capabilities.m_Shadows && g_RenderingOptions.GetShadows()) + { + m->globalContext.Add(str_USE_SHADOW, str_1); + if (capabilities.m_ARBProgramShadow && g_RenderingOptions.GetARBProgramShadow()) + m->globalContext.Add(str_USE_FP_SHADOW, str_1); + if (g_RenderingOptions.GetShadowPCF()) + m->globalContext.Add(str_USE_SHADOW_PCF, str_1); + const int cascadeCount = m->shadow.GetCascadeCount(); + ENSURE(1 <= cascadeCount && cascadeCount <= 4); + const CStrIntern cascadeCountStr[5] = {str_0, str_1, str_2, str_3, str_4}; + m->globalContext.Add(str_SHADOWS_CASCADE_COUNT, cascadeCountStr[cascadeCount]); +#if !CONFIG2_GLES + m->globalContext.Add(str_USE_SHADOW_SAMPLER, str_1); +#endif + } + + m->globalContext.Add(str_RENDER_DEBUG_MODE, + RenderDebugModeEnum::ToString(g_RenderingOptions.GetRenderDebugMode())); + + if (g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB && g_RenderingOptions.GetFog()) + m->globalContext.Add(str_USE_FOG, str_1); + + m->Model.ModShader = LitRenderModifierPtr(new ShaderRenderModifier()); + + ENSURE(g_RenderingOptions.GetRenderPath() != RenderPath::FIXED); + m->Model.VertexRendererShader = ModelVertexRendererPtr(new ShaderModelVertexRenderer()); + m->Model.VertexInstancingShader = ModelVertexRendererPtr(new InstancingModelRenderer(false, g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB)); + + if (g_RenderingOptions.GetGPUSkinning()) // TODO: should check caps and GLSL etc too + { + m->Model.VertexGPUSkinningShader = ModelVertexRendererPtr(new InstancingModelRenderer(true, g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB)); + m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); + m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); + } + else + { + m->Model.VertexGPUSkinningShader.reset(); + m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader)); + m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexRendererShader)); + } + + m->Model.NormalUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader)); + m->Model.TranspUnskinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexInstancingShader)); +} + +void CSceneRenderer::Initialize() +{ + // Let component renderers perform one-time initialization after graphics capabilities and + // the shader path have been determined. + m->overlayRenderer.Initialize(); +} + +// resize renderer view +void CSceneRenderer::Resize(int UNUSED(width), int UNUSED(height)) +{ + // need to recreate the shadow map object to resize the shadow texture + m->shadow.RecreateTexture(); + + m->waterManager.Resize(); +} + +void CSceneRenderer::BeginFrame() +{ + // choose model renderers for this frame + m->Model.ModShader->SetShadowMap(&m->shadow); + m->Model.ModShader->SetLightEnv(m_LightEnv); +} + +void CSceneRenderer::SetSimulation(CSimulation2* simulation) +{ + // set current simulation context for terrain renderer + m->terrainRenderer.SetSimulation(simulation); +} + +void CSceneRenderer::RenderShadowMap(const CShaderDefines& context) +{ + PROFILE3_GPU("shadow map"); + OGL_SCOPED_DEBUG_GROUP("Render shadow map"); + + CShaderDefines contextCast = context; + contextCast.Add(str_MODE_SHADOWCAST, str_1); + + m->shadow.BeginRender(); + + const int cascadeCount = m->shadow.GetCascadeCount(); + ENSURE(0 <= cascadeCount && cascadeCount <= 4); + for (int cascade = 0; cascade < cascadeCount; ++cascade) + { + m->shadow.PrepareCamera(cascade); + + const int cullGroup = CULL_SHADOWS_CASCADE_0 + cascade; + { + PROFILE("render patches"); + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + m->terrainRenderer.RenderPatches(cullGroup); + glCullFace(GL_BACK); + } + + { + PROFILE("render models"); + m->CallModelRenderers(contextCast, cullGroup, MODELFLAG_CASTSHADOWS); + } + + { + PROFILE("render transparent models"); + // disable face-culling for two-sided models + glDisable(GL_CULL_FACE); + m->CallTranspModelRenderers(contextCast, cullGroup, MODELFLAG_CASTSHADOWS); + glEnable(GL_CULL_FACE); + } + } + + m->shadow.EndRender(); + + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); +} + +void CSceneRenderer::RenderPatches(const CShaderDefines& context, int cullGroup) +{ + PROFILE3_GPU("patches"); + OGL_SCOPED_DEBUG_GROUP("Render patches"); + +#if CONFIG2_GLES +#warning TODO: implement wireface/edged rendering mode GLES +#else + // switch on wireframe if we need it + if (m_TerrainRenderMode == WIREFRAME) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } +#endif + + // render all the patches, including blend pass + const CRenderer::Caps& capabilities = g_Renderer.GetCapabilities(); + m->terrainRenderer.RenderTerrainShader(context, cullGroup, + (capabilities.m_Shadows && g_RenderingOptions.GetShadows()) ? &m->shadow : 0); + +#if !CONFIG2_GLES + if (m_TerrainRenderMode == WIREFRAME) + { + // switch wireframe off again + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + else if (m_TerrainRenderMode == EDGED_FACES) + { + // edged faces: need to make a second pass over the data: + // first switch on wireframe + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // setup some renderstate .. + glActiveTextureARB(GL_TEXTURE0); + glLineWidth(2.0f); + + // render tiles edges + m->terrainRenderer.RenderPatches(cullGroup, CColor(0.5f, 0.5f, 1.0f, 1.0f)); + + glLineWidth(4.0f); + + // render outline of each patch + m->terrainRenderer.RenderOutlines(cullGroup); + + // .. and restore the renderstates + glLineWidth(1.0f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +#endif +} + +void CSceneRenderer::RenderModels(const CShaderDefines& context, int cullGroup) +{ + PROFILE3_GPU("models"); + OGL_SCOPED_DEBUG_GROUP("Render models"); + + int flags = 0; + +#if !CONFIG2_GLES + if (m_ModelRenderMode == WIREFRAME) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } +#endif + + m->CallModelRenderers(context, cullGroup, flags); + +#if !CONFIG2_GLES + if (m_ModelRenderMode == WIREFRAME) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + else if (m_ModelRenderMode == EDGED_FACES) + { + CShaderDefines contextWireframe = context; + contextWireframe.Add(str_MODE_WIREFRAME, str_1); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + m->CallModelRenderers(contextWireframe, cullGroup, flags); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +#endif +} + +void CSceneRenderer::RenderTransparentModels(const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode, bool disableFaceCulling) +{ + PROFILE3_GPU("transparent models"); + OGL_SCOPED_DEBUG_GROUP("Render transparent models"); + + int flags = 0; + +#if !CONFIG2_GLES + // switch on wireframe if we need it + if (m_ModelRenderMode == WIREFRAME) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } +#endif + + // disable face culling for two-sided models in sub-renders + if (disableFaceCulling) + glDisable(GL_CULL_FACE); + + CShaderDefines contextOpaque = context; + contextOpaque.Add(str_ALPHABLEND_PASS_OPAQUE, str_1); + + CShaderDefines contextBlend = context; + contextBlend.Add(str_ALPHABLEND_PASS_BLEND, str_1); + + if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_OPAQUE) + m->CallTranspModelRenderers(contextOpaque, cullGroup, flags); + + if (transparentMode == TRANSPARENT || transparentMode == TRANSPARENT_BLEND) + m->CallTranspModelRenderers(contextBlend, cullGroup, flags); + + if (disableFaceCulling) + glEnable(GL_CULL_FACE); + +#if !CONFIG2_GLES + if (m_ModelRenderMode == WIREFRAME) + { + // switch wireframe off again + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + else if (m_ModelRenderMode == EDGED_FACES) + { + CShaderDefines contextWireframe = contextOpaque; + contextWireframe.Add(str_MODE_WIREFRAME, str_1); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + m->CallTranspModelRenderers(contextWireframe, cullGroup, flags); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +#endif +} + +// SetObliqueFrustumClipping: change the near plane to the given clip plane (in world space) +// Based on code from Game Programming Gems 5, from http://www.terathon.com/code/oblique.html +// - worldPlane is a clip plane in world space (worldPlane.Dot(v) >= 0 for any vector v passing the clipping test) +void CSceneRenderer::SetObliqueFrustumClipping(CCamera& camera, const CVector4D& worldPlane) const +{ + // First, we'll convert the given clip plane to camera space, then we'll + // Get the view matrix and normal matrix (top 3x3 part of view matrix) + CMatrix3D normalMatrix = camera.GetOrientation().GetTranspose(); + CVector4D camPlane = normalMatrix.Transform(worldPlane); + + CMatrix3D matrix = camera.GetProjection(); + + // Calculate the clip-space corner point opposite the clipping plane + // as (sgn(camPlane.x), sgn(camPlane.y), 1, 1) and + // transform it into camera space by multiplying it + // by the inverse of the projection matrix + + CVector4D q; + q.X = (sgn(camPlane.X) - matrix[8]/matrix[11]) / matrix[0]; + q.Y = (sgn(camPlane.Y) - matrix[9]/matrix[11]) / matrix[5]; + q.Z = 1.0f/matrix[11]; + q.W = (1.0f - matrix[10]/matrix[11]) / matrix[14]; + + // Calculate the scaled plane vector + CVector4D c = camPlane * (2.0f * matrix[11] / camPlane.Dot(q)); + + // Replace the third row of the projection matrix + matrix[2] = c.X; + matrix[6] = c.Y; + matrix[10] = c.Z - matrix[11]; + matrix[14] = c.W; + + // Load it back into the camera + camera.SetProjection(matrix); +} + +void CSceneRenderer::ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const +{ + WaterManager& wm = m->waterManager; + + CMatrix3D projection; + if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) + { + const float aspectRatio = 1.0f; + // Expand fov slightly since ripples can reflect parts of the scene that + // are slightly outside the normal camera view, and we want to avoid any + // noticeable edge-filtering artifacts + projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane()); + } + else + projection = m_ViewCamera.GetProjection(); + + camera = m_ViewCamera; + + // Temporarily change the camera to one that is reflected. + // Also, for texturing purposes, make it render to a view port the size of the + // water texture, stretch the image according to our aspect ratio so it covers + // the whole screen despite being rendered into a square, and cover slightly more + // of the view so we can see wavy reflections of slightly off-screen objects. + camera.m_Orientation.Scale(1, -1, 1); + camera.m_Orientation.Translate(0, 2 * wm.m_WaterHeight, 0); + camera.UpdateFrustum(scissor); + // Clip slightly above the water to improve reflections of objects on the water + // when the reflections are distorted. + camera.ClipFrustum(CVector4D(0, 1, 0, -wm.m_WaterHeight + 2.0f)); + + SViewPort vp; + vp.m_Height = wm.m_RefTextureSize; + vp.m_Width = wm.m_RefTextureSize; + vp.m_X = 0; + vp.m_Y = 0; + camera.SetViewPort(vp); + camera.SetProjection(projection); + CMatrix3D scaleMat; + scaleMat.SetScaling(g_Renderer.GetHeight() / static_cast(std::max(1, g_Renderer.GetWidth())), 1.0f, 1.0f); + camera.SetProjection(scaleMat * camera.GetProjection()); + + CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight + 0.5f); + SetObliqueFrustumClipping(camera, camPlane); +} + +void CSceneRenderer::ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const +{ + WaterManager& wm = m->waterManager; + + CMatrix3D projection; + if (m_ViewCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE) + { + const float aspectRatio = 1.0f; + // Expand fov slightly since ripples can reflect parts of the scene that + // are slightly outside the normal camera view, and we want to avoid any + // noticeable edge-filtering artifacts + projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane()); + } + else + projection = m_ViewCamera.GetProjection(); + + camera = m_ViewCamera; + + // Temporarily change the camera to make it render to a view port the size of the + // water texture, stretch the image according to our aspect ratio so it covers + // the whole screen despite being rendered into a square, and cover slightly more + // of the view so we can see wavy refractions of slightly off-screen objects. + camera.UpdateFrustum(scissor); + camera.ClipFrustum(CVector4D(0, -1, 0, wm.m_WaterHeight + 0.5f)); // add some to avoid artifacts near steep shores. + + SViewPort vp; + vp.m_Height = wm.m_RefTextureSize; + vp.m_Width = wm.m_RefTextureSize; + vp.m_X = 0; + vp.m_Y = 0; + camera.SetViewPort(vp); + camera.SetProjection(projection); + CMatrix3D scaleMat; + scaleMat.SetScaling(g_Renderer.GetHeight() / static_cast(std::max(1, g_Renderer.GetWidth())), 1.0f, 1.0f); + camera.SetProjection(scaleMat * camera.GetProjection()); +} + +// RenderReflections: render the water reflections to the reflection texture +void CSceneRenderer::RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor) +{ + PROFILE3_GPU("water reflections"); + OGL_SCOPED_DEBUG_GROUP("Render water reflections"); + + WaterManager& wm = m->waterManager; + + // Remember old camera + CCamera normalCamera = m_ViewCamera; + + ComputeReflectionCamera(m_ViewCamera, scissor); + const CBoundingBoxAligned reflectionScissor = + m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); + + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); + + // Save the model-view-projection matrix so the shaders can use it for projective texturing + wm.m_ReflectionMatrix = m_ViewCamera.GetViewProjection(); + + float vpHeight = wm.m_RefTextureSize; + float vpWidth = wm.m_RefTextureSize; + + SScreenRect screenScissor; + screenScissor.x1 = (GLint)floor((reflectionScissor[0].X*0.5f+0.5f)*vpWidth); + screenScissor.y1 = (GLint)floor((reflectionScissor[0].Y*0.5f+0.5f)*vpHeight); + screenScissor.x2 = (GLint)ceil((reflectionScissor[1].X*0.5f+0.5f)*vpWidth); + screenScissor.y2 = (GLint)ceil((reflectionScissor[1].Y*0.5f+0.5f)*vpHeight); + + glEnable(GL_SCISSOR_TEST); + glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1); + + // try binding the framebuffer + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, wm.m_ReflectionFbo); + + glClearColor(0.5f, 0.5f, 1.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glFrontFace(GL_CW); + + if (!g_RenderingOptions.GetWaterReflection()) + { + m->skyManager.RenderSky(); + ogl_WarnIfError(); + } + else + { + // Render terrain and models + RenderPatches(context, CULL_REFLECTIONS); + ogl_WarnIfError(); + RenderModels(context, CULL_REFLECTIONS); + ogl_WarnIfError(); + RenderTransparentModels(context, CULL_REFLECTIONS, TRANSPARENT, true); + ogl_WarnIfError(); + } + glFrontFace(GL_CCW); + + // Particles are always oriented to face the camera in the vertex shader, + // so they don't need the inverted glFrontFace + if (g_RenderingOptions.GetParticles()) + { + RenderParticles(CULL_REFLECTIONS); + ogl_WarnIfError(); + } + + glDisable(GL_SCISSOR_TEST); + + // Reset old camera + m_ViewCamera = normalCamera; + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +} + +// RenderRefractions: render the water refractions to the refraction texture +void CSceneRenderer::RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned &scissor) +{ + PROFILE3_GPU("water refractions"); + OGL_SCOPED_DEBUG_GROUP("Render water refractions"); + + WaterManager& wm = m->waterManager; + + // Remember old camera + CCamera normalCamera = m_ViewCamera; + + ComputeRefractionCamera(m_ViewCamera, scissor); + const CBoundingBoxAligned refractionScissor = + m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); + + CVector4D camPlane(0, -1, 0, wm.m_WaterHeight + 2.0f); + SetObliqueFrustumClipping(m_ViewCamera, camPlane); + + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); + + // Save the model-view-projection matrix so the shaders can use it for projective texturing + wm.m_RefractionMatrix = m_ViewCamera.GetViewProjection(); + wm.m_RefractionProjInvMatrix = m_ViewCamera.GetProjection().GetInverse(); + wm.m_RefractionViewInvMatrix = m_ViewCamera.GetOrientation(); + + float vpHeight = wm.m_RefTextureSize; + float vpWidth = wm.m_RefTextureSize; + + SScreenRect screenScissor; + screenScissor.x1 = (GLint)floor((refractionScissor[0].X*0.5f+0.5f)*vpWidth); + screenScissor.y1 = (GLint)floor((refractionScissor[0].Y*0.5f+0.5f)*vpHeight); + screenScissor.x2 = (GLint)ceil((refractionScissor[1].X*0.5f+0.5f)*vpWidth); + screenScissor.y2 = (GLint)ceil((refractionScissor[1].Y*0.5f+0.5f)*vpHeight); + + glEnable(GL_SCISSOR_TEST); + glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1); + + // try binding the framebuffer + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, wm.m_RefractionFbo); + + glClearColor(1.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Render terrain and models + RenderPatches(context, CULL_REFRACTIONS); + ogl_WarnIfError(); + RenderModels(context, CULL_REFRACTIONS); + ogl_WarnIfError(); + RenderTransparentModels(context, CULL_REFRACTIONS, TRANSPARENT_OPAQUE, false); + ogl_WarnIfError(); + + glDisable(GL_SCISSOR_TEST); + + // Reset old camera + m_ViewCamera = normalCamera; + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +} + +void CSceneRenderer::RenderSilhouettes(const CShaderDefines& context) +{ + PROFILE3_GPU("silhouettes"); + OGL_SCOPED_DEBUG_GROUP("Render water silhouettes"); + + CShaderDefines contextOccluder = context; + contextOccluder.Add(str_MODE_SILHOUETTEOCCLUDER, str_1); + + CShaderDefines contextDisplay = context; + contextDisplay.Add(str_MODE_SILHOUETTEDISPLAY, str_1); + + // Render silhouettes of units hidden behind terrain or occluders. + // To avoid breaking the standard rendering of alpha-blended objects, this + // has to be done in a separate pass. + // First we render all occluders into depth, then render all units with + // inverted depth test so any behind an occluder will get drawn in a constant + // color. + + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + glColorMask(0, 0, 0, 0); + + // Render occluders: + + { + PROFILE("render patches"); + + // To prevent units displaying silhouettes when parts of their model + // protrude into the ground, only occlude with the back faces of the + // terrain (so silhouettes will still display when behind hills) + glCullFace(GL_FRONT); + m->terrainRenderer.RenderPatches(CULL_SILHOUETTE_OCCLUDER); + glCullFace(GL_BACK); + } + + { + PROFILE("render model occluders"); + m->CallModelRenderers(contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0); + } + + { + PROFILE("render transparent occluders"); + m->CallTranspModelRenderers(contextOccluder, CULL_SILHOUETTE_OCCLUDER, 0); + } + + glDepthFunc(GL_GEQUAL); + glColorMask(1, 1, 1, 1); + + // Since we can't sort, we'll use the stencil buffer to ensure we only draw + // a pixel once (using the color of whatever model happens to be drawn first). + glEnable(GL_BLEND); + glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); + const float silhouetteAlpha = 0.75f; + glBlendColorEXT(0, 0, 0, silhouetteAlpha); + + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_NOTEQUAL, 1, (GLuint)-1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + { + PROFILE("render model casters"); + m->CallModelRenderers(contextDisplay, CULL_SILHOUETTE_CASTER, 0); + } + + { + PROFILE("render transparent casters"); + m->CallTranspModelRenderers(contextDisplay, CULL_SILHOUETTE_CASTER, 0); + } + + // Restore state + glDepthFunc(GL_LEQUAL); + glDisable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendColorEXT(0, 0, 0, 0); + glDisable(GL_STENCIL_TEST); +} + +void CSceneRenderer::RenderParticles(int cullGroup) +{ + PROFILE3_GPU("particles"); + OGL_SCOPED_DEBUG_GROUP("Render particles"); + + m->particleRenderer.RenderParticles(cullGroup); + +#if !CONFIG2_GLES + if (m_ModelRenderMode == EDGED_FACES) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + m->particleRenderer.RenderParticles(true); + m->particleRenderer.RenderBounds(cullGroup); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +#endif +} + +// RenderSubmissions: force rendering of any batched objects +void CSceneRenderer::RenderSubmissions(const CBoundingBoxAligned& waterScissor) +{ + PROFILE3("render submissions"); + OGL_SCOPED_DEBUG_GROUP("Render submissions"); + + GetScene().GetLOSTexture().InterpolateLOS(); + + GetScene().GetMiniMapTexture().Render(); + + CShaderDefines context = m->globalContext; + + int cullGroup = CULL_DEFAULT; + + ogl_WarnIfError(); + + // Set the camera + g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); + + // Prepare model renderers + { + PROFILE3("prepare models"); + m->Model.NormalSkinned->PrepareModels(); + m->Model.TranspSkinned->PrepareModels(); + if (m->Model.NormalUnskinned != m->Model.NormalSkinned) + m->Model.NormalUnskinned->PrepareModels(); + if (m->Model.TranspUnskinned != m->Model.TranspSkinned) + m->Model.TranspUnskinned->PrepareModels(); + } + + m->terrainRenderer.PrepareForRendering(); + + m->overlayRenderer.PrepareForRendering(); + + m->particleRenderer.PrepareForRendering(context); + + const CRenderer::Caps& capabilities = g_Renderer.GetCapabilities(); + if (capabilities.m_Shadows && g_RenderingOptions.GetShadows()) + { + RenderShadowMap(context); + } + + ogl_WarnIfError(); + + if (m->waterManager.m_RenderWater) + { + if (waterScissor.GetVolume() > 0 && m->waterManager.WillRenderFancyWater()) + { + PROFILE3_GPU("water scissor"); + RenderReflections(context, waterScissor); + + if (g_RenderingOptions.GetWaterRefraction()) + RenderRefractions(context, waterScissor); + } + } + + CPostprocManager& postprocManager = g_Renderer.GetPostprocManager(); + if (g_RenderingOptions.GetPostProc()) + { + // We have to update the post process manager with real near/far planes + // that we use for the scene rendering. + postprocManager.SetDepthBufferClipPlanes( + m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane() + ); + postprocManager.Initialize(); + postprocManager.CaptureRenderOutput(); + } + + { + PROFILE3_GPU("clear buffers"); + glClearColor(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + + m->skyManager.RenderSky(); + + // render submitted patches and models + RenderPatches(context, cullGroup); + ogl_WarnIfError(); + + // render debug-related terrain overlays + ITerrainOverlay::RenderOverlaysBeforeWater(); + ogl_WarnIfError(); + + // render other debug-related overlays before water (so they can be seen when underwater) + m->overlayRenderer.RenderOverlaysBeforeWater(); + ogl_WarnIfError(); + + RenderModels(context, cullGroup); + ogl_WarnIfError(); + + // render water + if (m->waterManager.m_RenderWater && g_Game && waterScissor.GetVolume() > 0) + { + if (m->waterManager.WillRenderFancyWater()) + { + // Render transparent stuff, but only the solid parts that can occlude block water. + RenderTransparentModels(context, cullGroup, TRANSPARENT_OPAQUE, false); + ogl_WarnIfError(); + + m->terrainRenderer.RenderWater(context, cullGroup, &m->shadow); + ogl_WarnIfError(); + + // Render transparent stuff again, but only the blended parts that overlap water. + RenderTransparentModels(context, cullGroup, TRANSPARENT_BLEND, false); + ogl_WarnIfError(); + } + else + { + m->terrainRenderer.RenderWater(context, cullGroup, &m->shadow); + ogl_WarnIfError(); + + // Render transparent stuff, so it can overlap models/terrain. + RenderTransparentModels(context, cullGroup, TRANSPARENT, false); + ogl_WarnIfError(); + } + } + else + { + // render transparent stuff, so it can overlap models/terrain + RenderTransparentModels(context, cullGroup, TRANSPARENT, false); + ogl_WarnIfError(); + } + + // render debug-related terrain overlays + ITerrainOverlay::RenderOverlaysAfterWater(cullGroup); + ogl_WarnIfError(); + + // render some other overlays after water (so they can be displayed on top of water) + m->overlayRenderer.RenderOverlaysAfterWater(); + ogl_WarnIfError(); + + // particles are transparent so render after water + if (g_RenderingOptions.GetParticles()) + { + RenderParticles(cullGroup); + ogl_WarnIfError(); + } + + if (g_RenderingOptions.GetPostProc()) + { + if (g_Renderer.GetPostprocManager().IsMultisampleEnabled()) + g_Renderer.GetPostprocManager().ResolveMultisampleFramebuffer(); + + postprocManager.ApplyPostproc(); + postprocManager.ReleaseRenderOutput(); + } + + if (g_RenderingOptions.GetSilhouettes()) + { + RenderSilhouettes(context); + } + + // render debug lines + if (g_RenderingOptions.GetDisplayFrustum()) + DisplayFrustum(); + + if (g_RenderingOptions.GetDisplayShadowsFrustum()) + { + m->shadow.RenderDebugBounds(); + m->shadow.RenderDebugTexture(); + } + + m->silhouetteRenderer.RenderDebugOverlays(m_ViewCamera); + + // render overlays that should appear on top of all other objects + m->overlayRenderer.RenderForegroundOverlays(m_ViewCamera); + ogl_WarnIfError(); + +} + +void CSceneRenderer::EndFrame() +{ + // empty lists + m->terrainRenderer.EndFrame(); + m->overlayRenderer.EndFrame(); + m->particleRenderer.EndFrame(); + m->silhouetteRenderer.EndFrame(); + + // Finish model renderers + m->Model.NormalSkinned->EndFrame(); + m->Model.TranspSkinned->EndFrame(); + if (m->Model.NormalUnskinned != m->Model.NormalSkinned) + m->Model.NormalUnskinned->EndFrame(); + if (m->Model.TranspUnskinned != m->Model.TranspSkinned) + m->Model.TranspUnskinned->EndFrame(); +} + +// DisplayFrustum: debug displays +// - white: cull camera frustum +// - red: bounds of shadow casting objects +void CSceneRenderer::DisplayFrustum() +{ +#if CONFIG2_GLES +#warning TODO: implement CSceneRenderer::DisplayFrustum for GLES +#else + glDepthMask(0); + glDisable(GL_CULL_FACE); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_Renderer.GetDebugRenderer().DrawCameraFrustum(m_CullCamera, CColor(1.0f, 1.0f, 1.0f, 0.25f), 2); + glDisable(GL_BLEND); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + g_Renderer.GetDebugRenderer().DrawCameraFrustum(m_CullCamera, CColor(1.0f, 1.0f, 1.0f, 1.0f), 2); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glEnable(GL_CULL_FACE); + glDepthMask(1); +#endif + + ogl_WarnIfError(); +} + +// Text overlay rendering +void CSceneRenderer::RenderTextOverlays() +{ + PROFILE3_GPU("text overlays"); + + if (m_DisplayTerrainPriorities) + m->terrainRenderer.RenderPriorities(CULL_DEFAULT); + + ogl_WarnIfError(); +} + +// SetSceneCamera: setup projection and transform of camera and adjust viewport to current view +// The camera always represents the actual camera used to render a scene, not any virtual camera +// used for shadow rendering or reflections. +void CSceneRenderer::SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera) +{ + m_ViewCamera = viewCamera; + m_CullCamera = cullCamera; + + const CRenderer::Caps& capabilities = g_Renderer.GetCapabilities(); + if (capabilities.m_Shadows && g_RenderingOptions.GetShadows()) + m->shadow.SetupFrame(m_CullCamera, m_LightEnv->GetSunDir()); +} + +void CSceneRenderer::Submit(CPatch* patch) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + { + m->shadow.AddShadowReceiverBound(patch->GetWorldBounds()); + m->silhouetteRenderer.AddOccluder(patch); + } + + if (CULL_SHADOWS_CASCADE_0 <= m_CurrentCullGroup && m_CurrentCullGroup <= CULL_SHADOWS_CASCADE_3) + { + const int cascade = m_CurrentCullGroup - CULL_SHADOWS_CASCADE_0; + m->shadow.AddShadowCasterBound(cascade, patch->GetWorldBounds()); + } + + m->terrainRenderer.Submit(m_CurrentCullGroup, patch); +} + +void CSceneRenderer::Submit(SOverlayLine* overlay) +{ + // Overlays are only needed in the default cull group for now, + // so just ignore submissions to any other group + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(SOverlayTexturedLine* overlay) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(SOverlaySprite* overlay) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(SOverlayQuad* overlay) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(SOverlaySphere* overlay) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + m->overlayRenderer.Submit(overlay); +} + +void CSceneRenderer::Submit(CModelDecal* decal) +{ + // Decals can't cast shadows since they're flat on the terrain. + // They can receive shadows, but the terrain under them will have + // already been passed to AddShadowCasterBound, so don't bother + // doing it again here. + + m->terrainRenderer.Submit(m_CurrentCullGroup, decal); +} + +void CSceneRenderer::Submit(CParticleEmitter* emitter) +{ + m->particleRenderer.Submit(m_CurrentCullGroup, emitter); +} + +void CSceneRenderer::SubmitNonRecursive(CModel* model) +{ + if (m_CurrentCullGroup == CULL_DEFAULT) + { + m->shadow.AddShadowReceiverBound(model->GetWorldBounds()); + + if (model->GetFlags() & MODELFLAG_SILHOUETTE_OCCLUDER) + m->silhouetteRenderer.AddOccluder(model); + if (model->GetFlags() & MODELFLAG_SILHOUETTE_DISPLAY) + m->silhouetteRenderer.AddCaster(model); + } + + if (CULL_SHADOWS_CASCADE_0 <= m_CurrentCullGroup && m_CurrentCullGroup <= CULL_SHADOWS_CASCADE_3) + { + if (!(model->GetFlags() & MODELFLAG_CASTSHADOWS)) + return; + + const int cascade = m_CurrentCullGroup - CULL_SHADOWS_CASCADE_0; + m->shadow.AddShadowCasterBound(cascade, model->GetWorldBounds()); + } + + bool requiresSkinning = (model->GetModelDef()->GetNumBones() != 0); + + if (model->GetMaterial().UsesAlphaBlending()) + { + if (requiresSkinning) + m->Model.TranspSkinned->Submit(m_CurrentCullGroup, model); + else + m->Model.TranspUnskinned->Submit(m_CurrentCullGroup, model); + } + else + { + if (requiresSkinning) + m->Model.NormalSkinned->Submit(m_CurrentCullGroup, model); + else + m->Model.NormalUnskinned->Submit(m_CurrentCullGroup, model); + } +} + +// Render the given scene +void CSceneRenderer::RenderScene(Scene& scene) +{ + m_CurrentScene = &scene; + + CFrustum frustum = m_CullCamera.GetFrustum(); + + m_CurrentCullGroup = CULL_DEFAULT; + + scene.EnumerateObjects(frustum, this); + + m->particleManager.RenderSubmit(*this, frustum); + + if (g_RenderingOptions.GetSilhouettes()) + { + m->silhouetteRenderer.ComputeSubmissions(m_ViewCamera); + + m_CurrentCullGroup = CULL_DEFAULT; + m->silhouetteRenderer.RenderSubmitOverlays(*this); + + m_CurrentCullGroup = CULL_SILHOUETTE_OCCLUDER; + m->silhouetteRenderer.RenderSubmitOccluders(*this); + + m_CurrentCullGroup = CULL_SILHOUETTE_CASTER; + m->silhouetteRenderer.RenderSubmitCasters(*this); + } + + const CRenderer::Caps& capabilities = g_Renderer.GetCapabilities(); + if (capabilities.m_Shadows && g_RenderingOptions.GetShadows()) + { + for (int cascade = 0; cascade <= m->shadow.GetCascadeCount(); ++cascade) + { + m_CurrentCullGroup = CULL_SHADOWS_CASCADE_0 + cascade; + const CFrustum shadowFrustum = m->shadow.GetShadowCasterCullFrustum(cascade); + scene.EnumerateObjects(shadowFrustum, this); + } + } + + CBoundingBoxAligned waterScissor; + if (m->waterManager.m_RenderWater) + { + waterScissor = m->terrainRenderer.ScissorWater(CULL_DEFAULT, m_ViewCamera); + + if (waterScissor.GetVolume() > 0 && m->waterManager.WillRenderFancyWater()) + { + if (g_RenderingOptions.GetWaterReflection()) + { + m_CurrentCullGroup = CULL_REFLECTIONS; + + CCamera reflectionCamera; + ComputeReflectionCamera(reflectionCamera, waterScissor); + + scene.EnumerateObjects(reflectionCamera.GetFrustum(), this); + } + + if (g_RenderingOptions.GetWaterRefraction()) + { + m_CurrentCullGroup = CULL_REFRACTIONS; + + CCamera refractionCamera; + ComputeRefractionCamera(refractionCamera, waterScissor); + + scene.EnumerateObjects(refractionCamera.GetFrustum(), this); + } + + // Render the waves to the Fancy effects texture + m->waterManager.RenderWaves(frustum); + } + } + + m_CurrentCullGroup = -1; + + ogl_WarnIfError(); + + RenderSubmissions(waterScissor); + + m_CurrentScene = NULL; +} + +Scene& CSceneRenderer::GetScene() +{ + ENSURE(m_CurrentScene); + return *m_CurrentScene; +} + +void CSceneRenderer::MakeShadersDirty() +{ + m->waterManager.m_NeedsReloading = true; +} + +WaterManager& CSceneRenderer::GetWaterManager() +{ + return m->waterManager; +} + +SkyManager& CSceneRenderer::GetSkyManager() +{ + return m->skyManager; +} + +CParticleManager& CSceneRenderer::GetParticleManager() +{ + return m->particleManager; +} + +TerrainRenderer& CSceneRenderer::GetTerrainRenderer() +{ + return m->terrainRenderer; +} + +CMaterialManager& CSceneRenderer::GetMaterialManager() +{ + return m->materialManager; +} + +ShadowMap& CSceneRenderer::GetShadowMap() +{ + return m->shadow; +} + +void CSceneRenderer::ResetState() +{ + // Clear all emitters, that were created in previous games + GetParticleManager().ClearUnattachedEmitters(); +} diff --git a/source/renderer/SceneRenderer.h b/source/renderer/SceneRenderer.h new file mode 100644 index 0000000000..9d356e3188 --- /dev/null +++ b/source/renderer/SceneRenderer.h @@ -0,0 +1,266 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_SCENERENDERER +#define INCLUDED_RENDERER_SCENERENDERER + +#include "graphics/Camera.h" +#include "graphics/ShaderDefines.h" +#include "graphics/ShaderProgramPtr.h" +#include "ps/Singleton.h" +#include "renderer/RenderingOptions.h" +#include "renderer/Scene.h" + +#include + +class CLightEnv; +class CMaterial; +class CMaterialManager; +class CModel; +class CParticleManager; +class CPatch; +class CSimulation2; +class ShadowMap; +class SkyManager; +class TerrainRenderer; +class WaterManager; + +// rendering modes +enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES }; + +// transparency modes +enum ETransparentMode { TRANSPARENT, TRANSPARENT_OPAQUE, TRANSPARENT_BLEND }; + +class CSceneRenderer : public SceneCollector +{ +public: + enum CullGroup + { + CULL_DEFAULT, + CULL_SHADOWS_CASCADE_0, + CULL_SHADOWS_CASCADE_1, + CULL_SHADOWS_CASCADE_2, + CULL_SHADOWS_CASCADE_3, + CULL_REFLECTIONS, + CULL_REFRACTIONS, + CULL_SILHOUETTE_OCCLUDER, + CULL_SILHOUETTE_CASTER, + CULL_MAX + }; + + CSceneRenderer(); + ~CSceneRenderer(); + + void Initialize(); + void Resize(int width, int height); + + void BeginFrame(); + void EndFrame(); + + /** + * Set simulation context for rendering purposes. + * Must be called at least once when the game has started and before + * frames are rendered. + */ + void SetSimulation(CSimulation2* simulation); + + // trigger a reload of shaders (when parameters they depend on have changed) + void MakeShadersDirty(); + + /** + * Set up the camera used for rendering the next scene; this includes + * setting OpenGL state like viewport, projection and modelview matrices. + * + * @param viewCamera this camera determines the eye position for rendering + * @param cullCamera this camera determines the frustum for culling in the renderer and + * for shadow calculations + */ + void SetSceneCamera(const CCamera& viewCamera, const CCamera& cullCamera); + + /** + * Render the given scene immediately. + * @param scene a Scene object describing what should be rendered. + */ + void RenderScene(Scene& scene); + + /** + * Return the scene that is currently being rendered. + * Only valid when the renderer is in a RenderScene call. + */ + Scene& GetScene(); + + /** + * Render text overlays on top of the scene. + * Assumes the caller has set up the GL environment for orthographic rendering + * with texturing and blending. + */ + void RenderTextOverlays(); + + // set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer, + // so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering) + void SetLightEnv(CLightEnv* lightenv) + { + m_LightEnv = lightenv; + } + + // set the mode to render subsequent terrain patches + void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode = mode; } + // get the mode to render subsequent terrain patches + ERenderMode GetTerrainRenderMode() const { return m_TerrainRenderMode; } + + // set the mode to render subsequent water patches + void SetWaterRenderMode(ERenderMode mode) { m_WaterRenderMode = mode; } + // get the mode to render subsequent water patches + ERenderMode GetWaterRenderMode() const { return m_WaterRenderMode; } + + // set the mode to render subsequent models + void SetModelRenderMode(ERenderMode mode) { m_ModelRenderMode = mode; } + // get the mode to render subsequent models + ERenderMode GetModelRenderMode() const { return m_ModelRenderMode; } + + // Get the mode to render subsequent overlays. + ERenderMode GetOverlayRenderMode() const { return m_OverlayRenderMode; } + // Set the mode to render subsequent overlays. + void SetOverlayRenderMode(ERenderMode mode) { m_OverlayRenderMode = mode; } + + // debugging + void SetDisplayTerrainPriorities(bool enabled) { m_DisplayTerrainPriorities = enabled; } + + // return the current light environment + const CLightEnv &GetLightEnv() { return *m_LightEnv; } + + // return the current view camera + const CCamera& GetViewCamera() const { return m_ViewCamera; } + // replace the current view camera + void SetViewCamera(const CCamera& camera) { m_ViewCamera = camera; } + + // return the current cull camera + const CCamera& GetCullCamera() const { return m_CullCamera; } + + /** + * GetWaterManager: Return the renderer's water manager. + * + * @return the WaterManager object used by the renderer + */ + WaterManager& GetWaterManager(); + + /** + * GetSkyManager: Return the renderer's sky manager. + * + * @return the SkyManager object used by the renderer + */ + SkyManager& GetSkyManager(); + + CParticleManager& GetParticleManager(); + + TerrainRenderer& GetTerrainRenderer(); + + CMaterialManager& GetMaterialManager(); + + ShadowMap& GetShadowMap(); + + /** + * Resets the render state to default, that was before a game started + */ + void ResetState(); + + void ReloadShaders(); + +protected: + void Submit(CPatch* patch) override; + void Submit(SOverlayLine* overlay) override; + void Submit(SOverlayTexturedLine* overlay) override; + void Submit(SOverlaySprite* overlay) override; + void Submit(SOverlayQuad* overlay) override; + void Submit(CModelDecal* decal) override; + void Submit(CParticleEmitter* emitter) override; + void Submit(SOverlaySphere* overlay) override; + void SubmitNonRecursive(CModel* model) override; + + // render any batched objects + void RenderSubmissions(const CBoundingBoxAligned& waterScissor); + + // patch rendering stuff + void RenderPatches(const CShaderDefines& context, int cullGroup); + + // model rendering stuff + void RenderModels(const CShaderDefines& context, int cullGroup); + void RenderTransparentModels(const CShaderDefines& context, int cullGroup, ETransparentMode transparentMode, bool disableFaceCulling); + + void RenderSilhouettes(const CShaderDefines& context); + + void RenderParticles(int cullGroup); + + // shadow rendering stuff + void RenderShadowMap(const CShaderDefines& context); + + // render water reflection and refraction textures + void RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor); + void RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned& scissor); + + void ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const; + void ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const; + + // debugging + void DisplayFrustum(); + + // enable oblique frustum clipping with the given clip plane + void SetObliqueFrustumClipping(CCamera& camera, const CVector4D& clipPlane) const; + + // Private data that is not needed by inline functions. + class Internals; + std::unique_ptr m; + + // Current terrain rendering mode. + ERenderMode m_TerrainRenderMode; + // Current water rendering mode. + ERenderMode m_WaterRenderMode; + // Current model rendering mode. + ERenderMode m_ModelRenderMode; + // Current overlay rendering mode. + ERenderMode m_OverlayRenderMode; + + /** + * m_ViewCamera: determines the eye position for rendering + * + * @see CGameView::m_ViewCamera + */ + CCamera m_ViewCamera; + + /** + * m_CullCamera: determines the frustum for culling and shadowmap calculations + * + * @see CGameView::m_ViewCamera + */ + CCamera m_CullCamera; + + // only valid inside a call to RenderScene + Scene* m_CurrentScene; + int m_CurrentCullGroup; + + // color used to clear screen in BeginFrame + float m_ClearColor[4]; + // current lighting setup + CLightEnv* m_LightEnv; + + /** + * Enable rendering of terrain tile priority text overlay, for debugging. + */ + bool m_DisplayTerrainPriorities; +}; + +#endif // INCLUDED_RENDERER_SCENERENDERER diff --git a/source/renderer/ShadowMap.cpp b/source/renderer/ShadowMap.cpp index 68d8b77f2e..578d3d3cdb 100644 --- a/source/renderer/ShadowMap.cpp +++ b/source/renderer/ShadowMap.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -39,6 +39,7 @@ #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include @@ -646,7 +647,7 @@ void ShadowMap::BeginRender() glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } - m->SavedViewCamera = g_Renderer.GetViewCamera(); + m->SavedViewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); glEnable(GL_SCISSOR_TEST); } @@ -661,7 +662,7 @@ void ShadowMap::PrepareCamera(const int cascade) CCamera camera = m->SavedViewCamera; camera.SetProjection(m->Cascades[cascade].LightProjection); camera.GetOrientation() = m->InvLightTransform; - g_Renderer.SetViewCamera(camera); + g_Renderer.GetSceneRenderer().SetViewCamera(camera); const SViewPort& cascadeViewPort = m->Cascades[cascade].ViewPort; glScissor( @@ -674,7 +675,7 @@ void ShadowMap::EndRender() { glDisable(GL_SCISSOR_TEST); - g_Renderer.SetViewCamera(m->SavedViewCamera); + g_Renderer.GetSceneRenderer().SetViewCamera(m->SavedViewCamera); { PROFILE("unbind framebuffer"); @@ -695,9 +696,9 @@ void ShadowMap::BindTo(const CShaderProgramPtr& shader) const shader->BindTexture(str_shadowTex, m->Texture.get()); shader->Uniform(str_shadowScale, m->Width, m->Height, 1.0f / m->Width, 1.0f / m->Height); - const CVector3D cameraForward = g_Renderer.GetCullCamera().GetOrientation().GetIn(); + const CVector3D cameraForward = g_Renderer.GetSceneRenderer().GetCullCamera().GetOrientation().GetIn(); shader->Uniform(str_cameraForward, cameraForward.X, cameraForward.Y, cameraForward.Z, - cameraForward.Dot(g_Renderer.GetCullCamera().GetOrientation().GetTranslation())); + cameraForward.Dot(g_Renderer.GetSceneRenderer().GetCullCamera().GetOrientation().GetTranslation())); if (GetCascadeCount() == 1) { shader->Uniform(str_shadowTransform, m->Cascades[0].TextureMatrix); @@ -746,7 +747,7 @@ void ShadowMap::RenderDebugBounds() // Red = culling frustum used to find potential shadow casters // Blue = frustum used for rendering the shadow map - const CMatrix3D transform = g_Renderer.GetViewCamera().GetViewProjection() * m->InvLightTransform; + const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection() * m->InvLightTransform; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp index ba373f7b22..7e56ca5223 100644 --- a/source/renderer/SkyManager.cpp +++ b/source/renderer/SkyManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,10 +15,6 @@ * along with 0 A.D. If not, see . */ -/* - * Sky settings, texture management and rendering. - */ - #include "precompiled.h" #include "renderer/SkyManager.h" @@ -41,6 +37,7 @@ #include "ps/Loader.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/RenderingOptions.h" #include @@ -226,7 +223,7 @@ void SkyManager::RenderSky() glDepthMask(GL_FALSE); - const CCamera& camera = g_Renderer.GetViewCamera(); + const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); CShaderTechniquePtr skytech = g_Renderer.GetShaderManager().LoadEffect(str_sky_simple); @@ -246,7 +243,7 @@ void SkyManager::RenderSky() // each skymap, is in the direction of the sun from our light // environment. CMatrix3D rotate; - rotate.SetYRotation(M_PI + g_Renderer.GetLightEnv().GetRotation()); + rotate.SetYRotation(M_PI + g_Renderer.GetSceneRenderer().GetLightEnv().GetRotation()); shader->Uniform( str_transform, diff --git a/source/renderer/TerrainOverlay.cpp b/source/renderer/TerrainOverlay.cpp index 0e82d633b1..af5a7945dd 100644 --- a/source/renderer/TerrainOverlay.cpp +++ b/source/renderer/TerrainOverlay.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,6 +31,7 @@ #include "ps/Profile.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/TerrainRenderer.h" #include "simulation2/system/SimContext.h" @@ -223,7 +224,7 @@ void TerrainOverlay::RenderTile(const CColor& color, bool draw_hidden, ssize_t i CShaderProgramPtr overlayShader = overlayTech->GetShader(); overlayShader->Bind(); - overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); overlayShader->Uniform(str_color, color); overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); @@ -284,7 +285,7 @@ void TerrainOverlay::RenderTileOutline(const CColor& color, int line_width, bool CShaderProgramPtr overlayShader = overlayTech->GetShader(); overlayShader->Bind(); - overlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); overlayShader->Uniform(str_color, color); overlayShader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); @@ -348,7 +349,7 @@ void TerrainTextureOverlay::RenderAfterWater(int cullGroup) matrix._23 = m_TexelsPerTile / (m_Texture->GetHeight() * TERRAIN_TILE_SIZE); matrix._44 = 1; - g_Renderer.GetTerrainRenderer().RenderTerrainOverlayTexture(cullGroup, matrix, m_Texture.get()); + g_Renderer.GetSceneRenderer().GetTerrainRenderer().RenderTerrainOverlayTexture(cullGroup, matrix, m_Texture.get()); } SColor4ub TerrainTextureOverlay::GetColor(size_t idx, u8 alpha) const diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 91248ad535..cb46cd185c 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -41,6 +41,7 @@ #include "renderer/PatchRData.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include "renderer/ShadowMap.h" #include "renderer/SkyManager.h" #include "renderer/VertexArray.h" @@ -65,10 +66,10 @@ struct TerrainRendererInternals Phase phase; /// Patches that were submitted for this frame - std::vector visiblePatches[CRenderer::CULL_MAX]; + std::vector visiblePatches[CSceneRenderer::CULL_MAX]; /// Decals that were submitted for this frame - std::vector visibleDecals[CRenderer::CULL_MAX]; + std::vector visibleDecals[CSceneRenderer::CULL_MAX]; /// Fancy water shader CShaderTechniquePtr fancyWaterTech; @@ -147,7 +148,7 @@ void TerrainRenderer::EndFrame() { ENSURE(m->phase == Phase_Render || m->phase == Phase_Submit); - for (int i = 0; i < CRenderer::CULL_MAX; ++i) + for (int i = 0; i < CSceneRenderer::CULL_MAX; ++i) { m->visiblePatches[i].clear(); m->visibleDecals[i].clear(); @@ -181,7 +182,7 @@ void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& text debugOverlayShader->Bind(); debugOverlayShader->BindTexture(str_baseTex, texture); - debugOverlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + debugOverlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); debugOverlayShader->Uniform(str_textureTransform, textureMatrix); CPatchRData::RenderStreams(visiblePatches, debugOverlayShader, STREAM_POS | STREAM_POSTOUV0); @@ -195,7 +196,7 @@ void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& text if (!waterBounds.IsEmpty()) { // Add a delta to avoid z-fighting. - const float height = g_Renderer.GetWaterManager().m_WaterHeight + 0.05f; + const float height = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight + 0.05f; const float waterPos[] = { waterBounds[0].X, height, waterBounds[0].Z, waterBounds[1].X, height, waterBounds[0].Z, @@ -227,15 +228,17 @@ void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& text */ void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow) { - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - shader->Uniform(str_cameraPos, g_Renderer.GetViewCamera().GetOrientation().GetTranslation()); + CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); + shader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); + shader->Uniform(str_cameraPos, sceneRenderer.GetViewCamera().GetOrientation().GetTranslation()); + + const CLightEnv& lightEnv = sceneRenderer.GetLightEnv(); if (shadow) shadow->BindTo(shader); - CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); + CLOSTexture& los = sceneRenderer.GetScene().GetLOSTexture(); shader->BindTexture(str_losTex, los.GetTextureSmooth()); shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); @@ -260,7 +263,7 @@ void TerrainRenderer::RenderTerrainShader(const CShaderDefines& context, int cul CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect(str_solid); techSolid->BeginPass(); CShaderProgramPtr shaderSolid = techSolid->GetShader(); - shaderSolid->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shaderSolid->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); shaderSolid->Uniform(str_color, 0.0f, 0.0f, 0.0f, 1.0f); CPatchRData::RenderSides(visiblePatches, shaderSolid); @@ -305,7 +308,7 @@ void TerrainRenderer::RenderPatches(int cullGroup, const CColor& color) CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_dummy); dummyTech->BeginPass(); CShaderProgramPtr dummyShader = dummyTech->GetShader(); - dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + dummyShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); dummyShader->Uniform(str_color, color); CPatchRData::RenderStreams(visiblePatches, dummyShader, STREAM_POS); @@ -356,7 +359,9 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr PROFILE3_GPU("fancy water"); OGL_SCOPED_DEBUG_GROUP("Render Fancy Water"); - WaterManager& waterManager = g_Renderer.GetWaterManager(); + CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); + + WaterManager& waterManager = sceneRenderer.GetWaterManager(); CShaderDefines defines = context; // If we're using fancy water, make sure its shader is loaded @@ -382,7 +387,7 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr waterManager.m_NeedsReloading = false; } - CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture(); + CLOSTexture& losTexture = sceneRenderer.GetScene().GetLOSTexture(); // Calculating the advanced informations about Foam and all if the quality calls for it. /*if (WaterMgr->m_NeedInfoUpdate && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves)) @@ -413,7 +418,7 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr dummyTech->BeginPass(); CShaderProgramPtr dummyShader = dummyTech->GetShader(); - dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + dummyShader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) @@ -434,7 +439,7 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr m->fancyWaterTech->BeginPass(); CShaderProgramPtr fancyWaterShader = m->fancyWaterTech->GetShader(); - const CCamera& camera = g_Renderer.GetViewCamera(); + const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); const double period = 8.0; fancyWaterShader->BindTexture(str_normalMap, waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]); @@ -458,11 +463,11 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr fancyWaterShader->BindTexture(str_reflectionMap, waterManager.m_ReflectionTexture.get()); fancyWaterShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); - const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); + const CLightEnv& lightEnv = sceneRenderer.GetLightEnv(); - fancyWaterShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + fancyWaterShader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); - fancyWaterShader->BindTexture(str_skyCube, g_Renderer.GetSkyManager().GetSkyCube()); + fancyWaterShader->BindTexture(str_skyCube, sceneRenderer.GetSkyManager().GetSkyCube()); // TODO: check that this rotates in the right direction. CMatrix3D skyBoxRotation; skyBoxRotation.SetIdentity(); @@ -533,7 +538,7 @@ void TerrainRenderer::RenderSimpleWater(int cullGroup) PROFILE3_GPU("simple water"); OGL_SCOPED_DEBUG_GROUP("Render Simple Water"); - const WaterManager& waterManager = g_Renderer.GetWaterManager(); + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); glEnable(GL_DEPTH_TEST); @@ -549,7 +554,7 @@ void TerrainRenderer::RenderSimpleWater(int cullGroup) waterSimpleShader->Bind(); waterSimpleShader->BindTexture(str_baseTex, waterManager.m_WaterTexture[waterManager.GetCurrentTextureIndex(1.6)]); waterSimpleShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); - waterSimpleShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + waterSimpleShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); waterSimpleShader->Uniform(str_losTransform, losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12], 0.f, 0.f); waterSimpleShader->Uniform(str_time, static_cast(time)); waterSimpleShader->Uniform(str_color, waterManager.m_WaterColor); @@ -574,7 +579,7 @@ void TerrainRenderer::RenderSimpleWater(int cullGroup) // Render water that is part of the terrain void TerrainRenderer::RenderWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { - WaterManager& waterManager = g_Renderer.GetWaterManager(); + WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); waterManager.UpdateQuality(); diff --git a/source/renderer/WaterManager.cpp b/source/renderer/WaterManager.cpp index 0f490c1fbd..8493000081 100644 --- a/source/renderer/WaterManager.cpp +++ b/source/renderer/WaterManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,6 +35,7 @@ #include "renderer/WaterManager.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" +#include "renderer/SceneRenderer.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpWaterManager.h" #include "simulation2/components/ICmpRangeManager.h" @@ -866,7 +867,7 @@ void WaterManager::RenderWaves(const CFrustum& frustrum) shader->BindTexture(str_foamTex, m_FoamTex); shader->Uniform(str_time, (float)m_WaterTexTimer); - shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); + shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); for (size_t a = 0; a < m_ShoreWaves.size(); ++a) { diff --git a/source/simulation2/components/CCmpParticleManager.cpp b/source/simulation2/components/CCmpParticleManager.cpp index a41294ac56..663643cdab 100644 --- a/source/simulation2/components/CCmpParticleManager.cpp +++ b/source/simulation2/components/CCmpParticleManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,10 +20,10 @@ #include "simulation2/system/Component.h" #include "ICmpParticleManager.h" -#include "simulation2/MessageTypes.h" - #include "graphics/ParticleManager.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" +#include "simulation2/MessageTypes.h" class CCmpParticleManager : public ICmpParticleManager { @@ -70,7 +70,7 @@ public: if (CRenderer::IsInitialised()) { float time = useSimTime ? msgData.deltaSimTime : msgData.deltaRealTime; - g_Renderer.GetParticleManager().Interpolate(time); + g_Renderer.GetSceneRenderer().GetParticleManager().Interpolate(time); } break; } diff --git a/source/simulation2/components/CCmpTerrain.cpp b/source/simulation2/components/CCmpTerrain.cpp index 591b0efb78..eaeac350c6 100644 --- a/source/simulation2/components/CCmpTerrain.cpp +++ b/source/simulation2/components/CCmpTerrain.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,14 +20,14 @@ #include "simulation2/system/Component.h" #include "ICmpTerrain.h" -#include "ICmpObstructionManager.h" -#include "ICmpRangeManager.h" -#include "simulation2/MessageTypes.h" - #include "graphics/Terrain.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "maths/Vector3D.h" +#include "simulation2/components/ICmpObstructionManager.h" +#include "simulation2/components/ICmpRangeManager.h" +#include "simulation2/MessageTypes.h" class CCmpTerrain : public ICmpTerrain { @@ -144,8 +144,8 @@ public: if (ReloadWater && CRenderer::IsInitialised()) { - g_Renderer.GetWaterManager().SetMapSize(vertices); - g_Renderer.GetWaterManager().RecomputeWaterData(); + g_Renderer.GetSceneRenderer().GetWaterManager().SetMapSize(vertices); + g_Renderer.GetSceneRenderer().GetWaterManager().RecomputeWaterData(); } MakeDirty(0, 0, tiles+1, tiles+1); } diff --git a/source/simulation2/components/CCmpWaterManager.cpp b/source/simulation2/components/CCmpWaterManager.cpp index 3cb0aef2d4..c92ed872b5 100644 --- a/source/simulation2/components/CCmpWaterManager.cpp +++ b/source/simulation2/components/CCmpWaterManager.cpp @@ -23,9 +23,9 @@ #include "graphics/RenderableObject.h" #include "graphics/Terrain.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "simulation2/MessageTypes.h" - #include "tools/atlas/GameInterface/GameLoop.h" class CCmpWaterManager : public ICmpWaterManager @@ -57,7 +57,7 @@ public: { // Clear the map size & data. if (CRenderer::IsInitialised()) - g_Renderer.GetWaterManager().SetMapSize(0); + g_Renderer.GetSceneRenderer().GetWaterManager().SetMapSize(0); } virtual void Serialize(ISerializer& serialize) @@ -72,7 +72,7 @@ public: deserialize.NumberFixed_Unbounded("height", m_WaterHeight); if (CRenderer::IsInitialised()) - g_Renderer.GetWaterManager().SetMapSize(GetSimContext().GetTerrain().GetVerticesPerSide()); + g_Renderer.GetSceneRenderer().GetWaterManager().SetMapSize(GetSimContext().GetTerrain().GetVerticesPerSide()); RecomputeWaterData(); } @@ -85,7 +85,7 @@ public: { const CMessageInterpolate& msgData = static_cast (msg); if (CRenderer::IsInitialised()) - g_Renderer.GetWaterManager().m_WaterTexTimer += msgData.deltaSimTime; + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterTexTimer += msgData.deltaSimTime; break; } case MT_TerrainChanged: @@ -105,8 +105,8 @@ public: { if (CRenderer::IsInitialised()) { - g_Renderer.GetWaterManager().RecomputeWaterData(); - g_Renderer.GetWaterManager().m_WaterHeight = m_WaterHeight.ToFloat(); + g_Renderer.GetSceneRenderer().GetWaterManager().RecomputeWaterData(); + g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight = m_WaterHeight.ToFloat(); } // Tell the terrain it'll need to recompute its cached render data diff --git a/source/tools/atlas/GameInterface/ActorViewer.cpp b/source/tools/atlas/GameInterface/ActorViewer.cpp index 93b4bc9640..210c7f37cc 100644 --- a/source/tools/atlas/GameInterface/ActorViewer.cpp +++ b/source/tools/atlas/GameInterface/ActorViewer.cpp @@ -45,6 +45,7 @@ #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "renderer/Scene.h" +#include "renderer/SceneRenderer.h" #include "renderer/SkyManager.h" #include "renderer/WaterManager.h" #include "scriptinterface/ScriptContext.h" @@ -353,7 +354,7 @@ void ActorViewer::SetActor(const CStrW& name, const CStr& animation, player_id_t } // Clear particles associated with deleted entity - g_Renderer.GetParticleManager().ClearUnattachedEmitters(); + g_Renderer.GetSceneRenderer().GetParticleManager().ClearUnattachedEmitters(); // If there's no actor to display, return with nothing loaded if (id.empty()) @@ -445,18 +446,18 @@ void ActorViewer::SetEnabled(bool enabled) m.OldShadows = g_RenderingOptions.GetShadows(); SetShadowsEnabled(m.ShadowsEnabled); - m.OldSky = g_Renderer.GetSkyManager().GetRenderSky(); - g_Renderer.GetSkyManager().SetRenderSky(false); + m.OldSky = g_Renderer.GetSceneRenderer().GetSkyManager().GetRenderSky(); + g_Renderer.GetSceneRenderer().GetSkyManager().SetRenderSky(false); - m.OldWater = g_Renderer.GetWaterManager().m_RenderWater; - g_Renderer.GetWaterManager().m_RenderWater = m.WaterEnabled; + m.OldWater = g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater; + g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater = m.WaterEnabled; } else { // Restore the old renderer state SetShadowsEnabled(m.OldShadows); - g_Renderer.GetSkyManager().SetRenderSky(m.OldSky); - g_Renderer.GetWaterManager().m_RenderWater = m.OldWater; + g_Renderer.GetSceneRenderer().GetSkyManager().SetRenderSky(m.OldSky); + g_Renderer.GetSceneRenderer().GetWaterManager().m_RenderWater = m.OldWater; } } @@ -501,7 +502,7 @@ void ActorViewer::Render() m.Terrain.MakeDirty(RENDERDATA_UPDATE_COLOR); // Set simulation context for rendering purposes - g_Renderer.SetSimulation(&m.Simulation2); + g_Renderer.GetSceneRenderer().SetSimulation(&m.Simulation2); g_Renderer.BeginFrame(); @@ -519,9 +520,9 @@ void ActorViewer::Render() camera.m_Orientation.Translate(centre.X, centre.Y, centre.Z); camera.UpdateFrustum(); - g_Renderer.SetSceneCamera(camera, camera); + g_Renderer.GetSceneRenderer().SetSceneCamera(camera, camera); - g_Renderer.RenderScene(m); + g_Renderer.GetSceneRenderer().RenderScene(m); glDisable(GL_DEPTH_TEST); g_Logger->Render(); diff --git a/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp index 979f71a3c8..a35b19484f 100644 --- a/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp @@ -29,6 +29,7 @@ #include "ps/World.h" #include "renderer/PostprocManager.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/SkyManager.h" #include "renderer/WaterManager.h" #include "simulation2/Simulation2.h" @@ -45,7 +46,7 @@ sEnvironmentSettings GetSettings() s.waterheight = cmpWaterManager->GetExactWaterLevel(0, 0) / (65536.f * HEIGHT_SCALE); - const WaterManager& waterManager = g_Renderer.GetWaterManager(); + const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); s.watertype = waterManager.m_WaterType; s.waterwaviness = waterManager.m_Waviness; s.watermurkiness = waterManager.m_Murkiness; @@ -65,7 +66,7 @@ sEnvironmentSettings GetSettings() s.posteffect = g_Renderer.GetPostprocManager().GetPostEffect(); - s.skyset = g_Renderer.GetSkyManager().GetSkySet(); + s.skyset = g_Renderer.GetSceneRenderer().GetSkyManager().GetSkySet(); s.fogfactor = g_LightEnv.m_FogFactor; s.fogmax = g_LightEnv.m_FogMax; @@ -99,7 +100,7 @@ void SetSettings(const sEnvironmentSettings& s) cmpWaterManager->SetWaterLevel(entity_pos_t::FromFloat(s.waterheight * (65536.f * HEIGHT_SCALE))); - WaterManager& waterManager = g_Renderer.GetWaterManager(); + WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); waterManager.m_Waviness = s.waterwaviness; waterManager.m_Murkiness = s.watermurkiness; waterManager.m_WindAngle = s.windangle; @@ -125,7 +126,7 @@ void SetSettings(const sEnvironmentSettings& s) CStrW skySet = *s.skyset; if (skySet.length() == 0) skySet = L"default"; - g_Renderer.GetSkyManager().SetSkySet(skySet); + g_Renderer.GetSceneRenderer().GetSkyManager().SetSkySet(skySet); g_LightEnv.m_FogFactor = s.fogfactor; g_LightEnv.m_FogMax = s.fogmax; @@ -241,7 +242,7 @@ QUERYHANDLER(GetEnvironmentSettings) QUERYHANDLER(GetSkySets) { - std::vector skies = g_Renderer.GetSkyManager().GetSkySets(); + std::vector skies = g_Renderer.GetSceneRenderer().GetSkyManager().GetSkySets(); msg->skysets = std::vector(skies.begin(), skies.end()); } diff --git a/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp index 6e8f96613e..8bd3879a8d 100644 --- a/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -41,6 +41,7 @@ #include "ps/GameSetup/Config.h" #include "ps/GameSetup/GameSetup.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #if OS_WIN // We don't include wutil header directly to prevent including Windows headers. @@ -261,10 +262,10 @@ QUERYHANDLER(RenderLoop) MESSAGEHANDLER(RenderStyle) { - g_Renderer.SetTerrainRenderMode(msg->wireframe ? EDGED_FACES : SOLID); - g_Renderer.SetWaterRenderMode(msg->wireframe ? EDGED_FACES : SOLID); - g_Renderer.SetModelRenderMode(msg->wireframe ? EDGED_FACES : SOLID); - g_Renderer.SetOverlayRenderMode(msg->wireframe ? EDGED_FACES : SOLID); + g_Renderer.GetSceneRenderer().SetTerrainRenderMode(msg->wireframe ? EDGED_FACES : SOLID); + g_Renderer.GetSceneRenderer().SetWaterRenderMode(msg->wireframe ? EDGED_FACES : SOLID); + g_Renderer.GetSceneRenderer().SetModelRenderMode(msg->wireframe ? EDGED_FACES : SOLID); + g_Renderer.GetSceneRenderer().SetOverlayRenderMode(msg->wireframe ? EDGED_FACES : SOLID); } } // namespace AtlasMessage diff --git a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp index 0da190750b..86d3516621 100644 --- a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp @@ -42,6 +42,7 @@ #include "ps/Loader.h" #include "ps/World.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "renderer/WaterManager.h" #include "scriptinterface/Object.h" #include "scriptinterface/JSON.h" @@ -225,7 +226,7 @@ MESSAGEHANDLER(SaveMap) VfsPath pathname = VfsPath(*msg->filename).ChangeExtension(L".pmp"); writer.SaveMap(pathname, g_Game->GetWorld()->GetTerrain(), - &g_Renderer.GetWaterManager(), &g_Renderer.GetSkyManager(), + &g_Renderer.GetSceneRenderer().GetWaterManager(), &g_Renderer.GetSceneRenderer().GetSkyManager(), &g_LightEnv, g_Game->GetView()->GetCamera(), g_Game->GetView()->GetCinema(), &g_Renderer.GetPostprocManager(), g_Game->GetSimulation2()); @@ -297,7 +298,7 @@ QUERYHANDLER(RasterizeMinimap) ssize_t w = dimension; ssize_t h = dimension; - const float waterHeight = g_Renderer.GetWaterManager().m_WaterHeight; + const float waterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight; for (ssize_t j = 0; j < h; ++j) { diff --git a/source/tools/atlas/GameInterface/View.cpp b/source/tools/atlas/GameInterface/View.cpp index dcae2ccb7e..e44ee50354 100644 --- a/source/tools/atlas/GameInterface/View.cpp +++ b/source/tools/atlas/GameInterface/View.cpp @@ -39,6 +39,7 @@ #include "renderer/backend/gl/Device.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" +#include "renderer/SceneRenderer.h" #include "simulation2/components/ICmpObstructionManager.h" #include "simulation2/components/ICmpParticleManager.h" #include "simulation2/components/ICmpPathfinder.h" @@ -137,7 +138,7 @@ ActorViewer& AtlasViewActor::GetActorViewer() void AtlasViewActor::SetParam(const std::wstring& name, bool value) { if (name == L"wireframe") - g_Renderer.SetModelRenderMode(value ? WIREFRAME : SOLID); + g_Renderer.GetSceneRenderer().SetModelRenderMode(value ? WIREFRAME : SOLID); else if (name == L"walk") m_ActorViewer->SetWalkEnabled(value); else if (name == L"ground") @@ -280,7 +281,7 @@ void AtlasViewGame::DrawOverlays(CCanvas2D& canvas) void AtlasViewGame::SetParam(const std::wstring& name, bool value) { if (name == L"priorities") - g_Renderer.SetDisplayTerrainPriorities(value); + g_Renderer.GetSceneRenderer().SetDisplayTerrainPriorities(value); else if (name == L"movetool") m_DrawMoveTool = value; }