Index: ps/trunk/binaries/data/mods/public/shaders/glsl/debug_overlay.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/debug_overlay.vs (revision 27207) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/debug_overlay.vs (revision 27208) @@ -1,24 +1,25 @@ #version 110 #include "common/vertex.h" uniform mat4 transform; #if DEBUG_TEXTURED -uniform mat4 textureTransform; +uniform vec2 textureTransform; #endif -VERTEX_INPUT_ATTRIBUTE(0, vec3, a_vertex); +#if DEBUG_TEXTURED +varying vec2 v_tex; +#endif +VERTEX_INPUT_ATTRIBUTE(0, vec3, a_vertex); #if DEBUG_TEXTURED VERTEX_INPUT_ATTRIBUTE(1, vec3, a_uv0); - -varying vec2 v_tex; #endif void main() { #if DEBUG_TEXTURED - v_tex = (textureTransform * vec4(a_uv0, 1.0)).xy; + v_tex = textureTransform.xy * a_uv0.xz; #endif OUTPUT_VERTEX_POSITION(transform * vec4(a_vertex, 1.0)); } Index: ps/trunk/source/renderer/TerrainOverlay.cpp =================================================================== --- ps/trunk/source/renderer/TerrainOverlay.cpp (revision 27207) +++ ps/trunk/source/renderer/TerrainOverlay.cpp (revision 27208) @@ -1,389 +1,387 @@ /* 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 "TerrainOverlay.h" #include "graphics/Color.h" #include "graphics/ShaderManager.h" #include "graphics/ShaderProgram.h" #include "graphics/Terrain.h" #include "lib/bits.h" #include "maths/MathUtil.h" +#include "maths/Vector2D.h" #include "ps/CStrInternStatic.h" #include "ps/Game.h" #include "ps/Profile.h" #include "ps/World.h" #include "renderer/backend/IDevice.h" #include "renderer/backend/IDeviceCommandContext.h" #include "renderer/Renderer.h" #include "renderer/SceneRenderer.h" #include "renderer/TerrainRenderer.h" #include "simulation2/system/SimContext.h" #include // Global overlay list management: static std::vector > g_TerrainOverlayList; ITerrainOverlay::ITerrainOverlay(int priority) { // Add to global list of overlays g_TerrainOverlayList.emplace_back(this, priority); // Sort by overlays by priority. Do stable sort so that adding/removing // overlays doesn't randomly disturb all the existing ones (which would // be noticeable if they have the same priority and overlap). std::stable_sort(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(), [](const std::pair& a, const std::pair& b) { return a.second < b.second; }); } ITerrainOverlay::~ITerrainOverlay() { std::vector >::iterator newEnd = std::remove_if(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(), [this](const std::pair& a) { return a.first == this; }); g_TerrainOverlayList.erase(newEnd, g_TerrainOverlayList.end()); } void ITerrainOverlay::RenderOverlaysBeforeWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { if (g_TerrainOverlayList.empty()) return; PROFILE3_GPU("terrain overlays (before)"); GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain overlays before water"); for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i) g_TerrainOverlayList[i].first->RenderBeforeWater(deviceCommandContext); } void ITerrainOverlay::RenderOverlaysAfterWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup) { if (g_TerrainOverlayList.empty()) return; PROFILE3_GPU("terrain overlays (after)"); GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain overlays after water"); for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i) g_TerrainOverlayList[i].first->RenderAfterWater(deviceCommandContext, cullGroup); } ////////////////////////////////////////////////////////////////////////// TerrainOverlay::TerrainOverlay(const CSimContext& simContext, int priority /* = 100 */) : ITerrainOverlay(priority), m_Terrain(&simContext.GetTerrain()) { } void TerrainOverlay::StartRender() { } void TerrainOverlay::EndRender() { } void TerrainOverlay::GetTileExtents( ssize_t& min_i_inclusive, ssize_t& min_j_inclusive, ssize_t& max_i_inclusive, ssize_t& max_j_inclusive) { // Default to whole map min_i_inclusive = min_j_inclusive = 0; max_i_inclusive = max_j_inclusive = m_Terrain->GetTilesPerSide()-1; } void TerrainOverlay::RenderBeforeWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { if (!m_Terrain) return; // should never happen, but let's play it safe StartRender(); ssize_t min_i, min_j, max_i, max_j; GetTileExtents(min_i, min_j, max_i, max_j); // Clamp the min to 0, but the max to -1 - so tile -1 can never be rendered, // but if unclamped_max<0 then no tiles at all will be rendered. And the same // for the upper limit. min_i = Clamp(min_i, 0, m_Terrain->GetTilesPerSide()); min_j = Clamp(min_j, 0, m_Terrain->GetTilesPerSide()); max_i = Clamp(max_i, -1, m_Terrain->GetTilesPerSide()-1); max_j = Clamp(max_j, -1, m_Terrain->GetTilesPerSide()-1); for (m_j = min_j; m_j <= max_j; ++m_j) for (m_i = min_i; m_i <= max_i; ++m_i) ProcessTile(deviceCommandContext, m_i, m_j); EndRender(); } void TerrainOverlay::RenderTile( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CColor& color, bool drawHidden) { RenderTile(deviceCommandContext, color, drawHidden, m_i, m_j); } void TerrainOverlay::RenderTile( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CColor& color, bool drawHidden, ssize_t i, ssize_t j) { // TODO: unnecessary computation calls has been removed but we should use // a vertex buffer or a vertex shader with a texture. // Not sure if it's possible on old OpenGL. CVector3D pos[2][2]; for (int di = 0; di < 2; ++di) for (int dj = 0; dj < 2; ++dj) m_Terrain->CalcPosition(i + di, j + dj, pos[di][dj]); std::vector vertices; #define ADD(position) \ vertices.emplace_back((position).X); \ vertices.emplace_back((position).Y); \ vertices.emplace_back((position).Z); if (m_Terrain->GetTriangulationDir(i, j)) { ADD(pos[0][0]); ADD(pos[1][0]); ADD(pos[0][1]); ADD(pos[1][0]); ADD(pos[1][1]); ADD(pos[0][1]); } else { ADD(pos[0][0]); ADD(pos[1][0]); ADD(pos[1][1]); ADD(pos[1][1]); ADD(pos[0][1]); ADD(pos[0][0]); } #undef ADD CShaderTechniquePtr overlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = overlayTech->GetGraphicsPipelineStateDesc(); pipelineStateDesc.depthStencilState.depthTestEnabled = !drawHidden; pipelineStateDesc.blendState.enabled = true; pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = Renderer::Backend::BlendFactor::SRC_ALPHA; pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = Renderer::Backend::BlendOp::ADD; pipelineStateDesc.rasterizationState.cullMode = drawHidden ? Renderer::Backend::CullMode::NONE : Renderer::Backend::CullMode::BACK; // To ensure that outlines are drawn on top of the terrain correctly (and // don't Z-fight and flicker nastily), use detph bias to pull them towards // the camera. pipelineStateDesc.rasterizationState.depthBiasEnabled = true; pipelineStateDesc.rasterizationState.depthBiasConstantFactor = -1.0f; pipelineStateDesc.rasterizationState.depthBiasSlopeFactor = -1.0f; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBufferData( 0, vertices.data(), vertices.size() * sizeof(vertices[0])); deviceCommandContext->Draw(0, vertices.size() / 3); deviceCommandContext->EndPass(); } void TerrainOverlay::RenderTileOutline( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CColor& color, bool drawHidden) { RenderTileOutline(deviceCommandContext, color, drawHidden, m_i, m_j); } void TerrainOverlay::RenderTileOutline( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CColor& color, bool drawHidden, ssize_t i, ssize_t j) { std::vector vertices; #define ADD(i, j) \ m_Terrain->CalcPosition(i, j, position); \ vertices.emplace_back(position.X); \ vertices.emplace_back(position.Y); \ vertices.emplace_back(position.Z); CVector3D position; ADD(i, j); ADD(i + 1, j); ADD(i + 1, j + 1); ADD(i, j); ADD(i + 1, j + 1); ADD(i, j + 1); #undef ADD CShaderTechniquePtr overlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = overlayTech->GetGraphicsPipelineStateDesc(); pipelineStateDesc.depthStencilState.depthTestEnabled = !drawHidden; pipelineStateDesc.blendState.enabled = true; pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = Renderer::Backend::BlendFactor::SRC_ALPHA; pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = Renderer::Backend::BlendOp::ADD; pipelineStateDesc.rasterizationState.cullMode = drawHidden ? Renderer::Backend::CullMode::NONE : Renderer::Backend::CullMode::BACK; pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBufferData( 0, vertices.data(), vertices.size() * sizeof(vertices[0])); deviceCommandContext->Draw(0, vertices.size() / 3); deviceCommandContext->EndPass(); } ////////////////////////////////////////////////////////////////////////// TerrainTextureOverlay::TerrainTextureOverlay(float texelsPerTile, int priority) : ITerrainOverlay(priority), m_TexelsPerTile(texelsPerTile) { } TerrainTextureOverlay::~TerrainTextureOverlay() = default; void TerrainTextureOverlay::RenderAfterWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup) { CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); ssize_t w = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile); ssize_t h = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile); const uint32_t requiredWidth = round_up_to_pow2(w); const uint32_t requiredHeight = round_up_to_pow2(h); // Recreate the texture with new size if necessary if (!m_Texture || m_Texture->GetWidth() != requiredWidth || m_Texture->GetHeight() != requiredHeight) { m_Texture = deviceCommandContext->GetDevice()->CreateTexture2D("TerrainOverlayTexture", Renderer::Backend::ITexture::Usage::TRANSFER_DST | Renderer::Backend::ITexture::Usage::SAMPLED, Renderer::Backend::Format::R8G8B8A8_UNORM, requiredWidth, requiredHeight, Renderer::Backend::Sampler::MakeDefaultSampler( Renderer::Backend::Sampler::Filter::NEAREST, Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE)); } u8* data = (u8*)calloc(w * h, 4); BuildTextureRGBA(data, w, h); deviceCommandContext->UploadTextureRegion( m_Texture.get(), Renderer::Backend::Format::R8G8B8A8_UNORM, data, w * h * 4, 0, 0, w, h); free(data); - CMatrix3D matrix; - matrix.SetZero(); - matrix._11 = m_TexelsPerTile / (m_Texture->GetWidth() * TERRAIN_TILE_SIZE); - matrix._23 = m_TexelsPerTile / (m_Texture->GetHeight() * TERRAIN_TILE_SIZE); - matrix._44 = 1; - + const CVector2D textureTransform{ + m_TexelsPerTile / (m_Texture->GetWidth() * TERRAIN_TILE_SIZE), + m_TexelsPerTile / (m_Texture->GetHeight() * TERRAIN_TILE_SIZE)}; g_Renderer.GetSceneRenderer().GetTerrainRenderer().RenderTerrainOverlayTexture( - deviceCommandContext, cullGroup, matrix, m_Texture.get()); + deviceCommandContext, cullGroup, textureTransform, m_Texture.get()); } SColor4ub TerrainTextureOverlay::GetColor(size_t idx, u8 alpha) const { static u8 colors[][3] = { { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, { 255, 255, 0 }, { 255, 0, 255 }, { 0, 255, 255 }, { 255, 255, 255 }, { 127, 0, 0 }, { 0, 127, 0 }, { 0, 0, 127 }, { 127, 127, 0 }, { 127, 0, 127 }, { 0, 127, 127 }, { 127, 127, 127}, { 255, 127, 0 }, { 127, 255, 0 }, { 255, 0, 127 }, { 127, 0, 255}, { 0, 255, 127 }, { 0, 127, 255}, { 255, 127, 127}, { 127, 255, 127}, { 127, 127, 255}, { 127, 255, 255 }, { 255, 127, 255 }, { 255, 255, 127 }, }; size_t c = idx % ARRAY_SIZE(colors); return SColor4ub(colors[c][0], colors[c][1], colors[c][2], alpha); } Index: ps/trunk/source/renderer/TerrainRenderer.cpp =================================================================== --- ps/trunk/source/renderer/TerrainRenderer.cpp (revision 27207) +++ ps/trunk/source/renderer/TerrainRenderer.cpp (revision 27208) @@ -1,727 +1,728 @@ /* 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 "renderer/TerrainRenderer.h" #include "graphics/Camera.h" #include "graphics/Canvas2D.h" #include "graphics/Decal.h" #include "graphics/GameView.h" #include "graphics/LightEnv.h" #include "graphics/LOSTexture.h" #include "graphics/Patch.h" #include "graphics/Model.h" #include "graphics/ShaderManager.h" #include "graphics/TerritoryTexture.h" #include "graphics/TextRenderer.h" #include "graphics/TextureManager.h" #include "maths/MathUtil.h" +#include "maths/Vector2D.h" #include "ps/CLogger.h" #include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "ps/Game.h" #include "ps/Profile.h" #include "ps/World.h" #include "renderer/backend/IDevice.h" #include "renderer/DecalRData.h" #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" #include "renderer/WaterManager.h" /** * TerrainRenderer keeps track of which phase it is in, to detect * when Submit, PrepareForRendering etc. are called in the wrong order. */ enum Phase { Phase_Submit, Phase_Render }; /** * Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class. */ struct TerrainRendererInternals { /// Which phase (submitting or rendering patches) are we in right now? Phase phase; /// Patches that were submitted for this frame std::vector visiblePatches[CSceneRenderer::CULL_MAX]; /// Decals that were submitted for this frame std::vector visibleDecals[CSceneRenderer::CULL_MAX]; /// Fancy water shader CShaderTechniquePtr fancyWaterTech; CSimulation2* simulation; }; /////////////////////////////////////////////////////////////////// // Construction/Destruction TerrainRenderer::TerrainRenderer() { m = new TerrainRendererInternals(); m->phase = Phase_Submit; } TerrainRenderer::~TerrainRenderer() { delete m; } void TerrainRenderer::SetSimulation(CSimulation2* simulation) { m->simulation = simulation; } /////////////////////////////////////////////////////////////////// // Submit a patch for rendering void TerrainRenderer::Submit(int cullGroup, CPatch* patch) { ENSURE(m->phase == Phase_Submit); CPatchRData* data = (CPatchRData*)patch->GetRenderData(); if (data == 0) { // no renderdata for patch, create it now data = new CPatchRData(patch, m->simulation); patch->SetRenderData(data); } data->Update(m->simulation); m->visiblePatches[cullGroup].push_back(data); } /////////////////////////////////////////////////////////////////// // Submit a decal for rendering void TerrainRenderer::Submit(int cullGroup, CModelDecal* decal) { ENSURE(m->phase == Phase_Submit); CDecalRData* data = (CDecalRData*)decal->GetRenderData(); if (data == 0) { // no renderdata for decal, create it now data = new CDecalRData(decal, m->simulation); decal->SetRenderData(data); } data->Update(m->simulation); m->visibleDecals[cullGroup].push_back(data); } /////////////////////////////////////////////////////////////////// // Prepare for rendering void TerrainRenderer::PrepareForRendering() { ENSURE(m->phase == Phase_Submit); m->phase = Phase_Render; } /////////////////////////////////////////////////////////////////// // Clear submissions lists void TerrainRenderer::EndFrame() { ENSURE(m->phase == Phase_Render || m->phase == Phase_Submit); for (int i = 0; i < CSceneRenderer::CULL_MAX; ++i) { m->visiblePatches[i].clear(); m->visibleDecals[i].clear(); } m->phase = Phase_Submit; } void TerrainRenderer::RenderTerrainOverlayTexture( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - int cullGroup, CMatrix3D& textureMatrix, + int cullGroup, const CVector2D& textureTransform, Renderer::Backend::ITexture* texture) { ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; CShaderTechniquePtr debugOverlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_overlay); deviceCommandContext->SetGraphicsPipelineState( debugOverlayTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* debugOverlayShader = debugOverlayTech->GetShader(); deviceCommandContext->SetTexture( debugOverlayShader->GetBindingSlot(str_baseTex), texture); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( debugOverlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( - debugOverlayShader->GetBindingSlot(str_textureTransform), textureMatrix.AsFloatArray()); + debugOverlayShader->GetBindingSlot(str_textureTransform), textureTransform.AsFloatArray()); CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, true); // To make the overlay visible over water, render an additional map-sized // water-height patch. CBoundingBoxAligned waterBounds; for (CPatchRData* data : visiblePatches) waterBounds += data->GetWaterBounds(); if (!waterBounds.IsEmpty()) { // Add a delta to avoid z-fighting. 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, waterBounds[1].X, height, waterBounds[1].Z, waterBounds[0].X, height, waterBounds[0].Z, waterBounds[1].X, height, waterBounds[1].Z, waterBounds[0].X, height, waterBounds[1].Z }; deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::UV0, Renderer::Backend::Format::R32G32B32_SFLOAT, 0, 0, Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0); deviceCommandContext->SetVertexBufferData( 0, waterPos, std::size(waterPos) * sizeof(waterPos[0])); deviceCommandContext->Draw(0, 6); } deviceCommandContext->EndPass(); } /////////////////////////////////////////////////////////////////// /** * Set up all the uniforms for a shader pass. */ void TerrainRenderer::PrepareShader( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, Renderer::Backend::IShaderProgram* shader, ShadowMap* shadow) { CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_cameraPos), sceneRenderer.GetViewCamera().GetOrientation().GetTranslation().AsFloatArray()); const CLightEnv& lightEnv = sceneRenderer.GetLightEnv(); if (shadow) shadow->BindTo(deviceCommandContext, shader); CLOSTexture& los = sceneRenderer.GetScene().GetLOSTexture(); deviceCommandContext->SetTexture( shader->GetBindingSlot(str_losTex), los.GetTextureSmooth()); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_losTransform), los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_ambient), lightEnv.m_AmbientColor.AsFloatArray()); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_sunColor), lightEnv.m_SunColor.AsFloatArray()); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_sunDir), lightEnv.GetSunDir().AsFloatArray()); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_fogColor), lightEnv.m_FogColor.AsFloatArray()); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_fogParams), lightEnv.m_FogFactor, lightEnv.m_FogMax); } void TerrainRenderer::RenderTerrainShader( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; std::vector& visibleDecals = m->visibleDecals[cullGroup]; if (visiblePatches.empty() && visibleDecals.empty()) return; // render the solid black sides of the map first CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect(str_solid); Renderer::Backend::GraphicsPipelineStateDesc solidPipelineStateDesc = techSolid->GetGraphicsPipelineStateDesc(); solidPipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; deviceCommandContext->SetGraphicsPipelineState(solidPipelineStateDesc); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shaderSolid = techSolid->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( shaderSolid->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( shaderSolid->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 1.0f); CPatchRData::RenderSides(deviceCommandContext, visiblePatches); deviceCommandContext->EndPass(); CPatchRData::RenderBases(deviceCommandContext, visiblePatches, context, shadow); // render blend passes for each patch CPatchRData::RenderBlends(deviceCommandContext, visiblePatches, context, shadow); CDecalRData::RenderDecals(deviceCommandContext, visibleDecals, context, shadow); } /////////////////////////////////////////////////////////////////// // Render un-textured patches as polygons void TerrainRenderer::RenderPatches( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup, const CShaderDefines& defines, const CColor& color) { ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; if (visiblePatches.empty()) return; GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain patches"); CShaderTechniquePtr solidTech = g_Renderer.GetShaderManager().LoadEffect(str_terrain_solid, defines); deviceCommandContext->SetGraphicsPipelineState( solidTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* solidShader = solidTech->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( solidShader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( solidShader->GetBindingSlot(str_color), color.AsFloatArray()); CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, false); deviceCommandContext->EndPass(); } /////////////////////////////////////////////////////////////////// // Render outlines of submitted patches as lines void TerrainRenderer::RenderOutlines( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup) { ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; if (visiblePatches.empty()) return; GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain outlines"); for (size_t i = 0; i < visiblePatches.size(); ++i) visiblePatches[i]->RenderOutline(); } /////////////////////////////////////////////////////////////////// // Scissor rectangle of water patches CBoundingBoxAligned TerrainRenderer::ScissorWater(int cullGroup, const CCamera& camera) { CBoundingBoxAligned scissor; for (const CPatchRData* data : m->visiblePatches[cullGroup]) { const CBoundingBoxAligned& waterBounds = data->GetWaterBounds(); if (waterBounds.IsEmpty()) continue; const CBoundingBoxAligned waterBoundsInViewPort = camera.GetBoundsInViewPort(waterBounds); if (!waterBoundsInViewPort.IsEmpty()) scissor += waterBoundsInViewPort; } if (scissor.IsEmpty()) return scissor; return CBoundingBoxAligned( CVector3D(Clamp(scissor[0].X, -1.0f, 1.0f), Clamp(scissor[0].Y, -1.0f, 1.0f), -1.0f), CVector3D(Clamp(scissor[1].X, -1.0f, 1.0f), Clamp(scissor[1].Y, -1.0f, 1.0f), 1.0f)); } // Render fancy water bool TerrainRenderer::RenderFancyWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { PROFILE3_GPU("fancy water"); GPU_SCOPED_LABEL(deviceCommandContext, "Render fancy water"); CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); WaterManager& waterManager = sceneRenderer.GetWaterManager(); CShaderDefines defines = context; // If we're using fancy water, make sure its shader is loaded if (!m->fancyWaterTech || waterManager.m_NeedsReloading) { if (waterManager.m_WaterRealDepth) defines.Add(str_USE_REAL_DEPTH, str_1); if (waterManager.m_WaterFancyEffects) defines.Add(str_USE_FANCY_EFFECTS, str_1); if (waterManager.m_WaterRefraction) defines.Add(str_USE_REFRACTION, str_1); if (waterManager.m_WaterReflection) defines.Add(str_USE_REFLECTION, str_1); m->fancyWaterTech = g_Renderer.GetShaderManager().LoadEffect(str_water_high, defines); if (!m->fancyWaterTech) { LOGERROR("Failed to load water shader. Falling back to a simple water.\n"); waterManager.m_RenderWater = false; return false; } waterManager.m_NeedsReloading = false; } 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)) { WaterMgr->m_NeedInfoUpdate = false; WaterMgr->CreateSuperfancyInfo(); }*/ const double time = waterManager.m_WaterTexTimer; const float repeatPeriod = waterManager.m_RepeatPeriod; deviceCommandContext->SetGraphicsPipelineState( m->fancyWaterTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* fancyWaterShader = m->fancyWaterTech->GetShader(); const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); const double period = 8.0; // TODO: move uploading to a prepare function during loading. const CTexturePtr& currentNormalTexture = waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]; const CTexturePtr& nextNormalTexture = waterManager.m_NormalMap[waterManager.GetNextTextureIndex(period)]; currentNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext); nextNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext); deviceCommandContext->SetTexture( fancyWaterShader->GetBindingSlot(str_normalMap), currentNormalTexture->GetBackendTexture()); deviceCommandContext->SetTexture( fancyWaterShader->GetBindingSlot(str_normalMap2), nextNormalTexture->GetBackendTexture()); if (waterManager.m_WaterFancyEffects) { deviceCommandContext->SetTexture( fancyWaterShader->GetBindingSlot(str_waterEffectsTex), waterManager.m_FancyTexture.get()); } if (waterManager.m_WaterRefraction && waterManager.m_WaterRealDepth) { deviceCommandContext->SetTexture( fancyWaterShader->GetBindingSlot(str_depthTex), waterManager.m_RefrFboDepthTexture.get()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_projInvTransform), waterManager.m_RefractionProjInvMatrix.AsFloatArray()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_viewInvTransform), waterManager.m_RefractionViewInvMatrix.AsFloatArray()); } if (waterManager.m_WaterRefraction) { deviceCommandContext->SetTexture( fancyWaterShader->GetBindingSlot(str_refractionMap), waterManager.m_RefractionTexture.get()); } if (waterManager.m_WaterReflection) { deviceCommandContext->SetTexture( fancyWaterShader->GetBindingSlot(str_reflectionMap), waterManager.m_ReflectionTexture.get()); } deviceCommandContext->SetTexture( fancyWaterShader->GetBindingSlot(str_losTex), losTexture.GetTextureSmooth()); const CLightEnv& lightEnv = sceneRenderer.GetLightEnv(); const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetTexture( fancyWaterShader->GetBindingSlot(str_skyCube), sceneRenderer.GetSkyManager().GetSkyCube()); // TODO: check that this rotates in the right direction. CMatrix3D skyBoxRotation; skyBoxRotation.SetIdentity(); skyBoxRotation.RotateY(M_PI + lightEnv.GetRotation()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_skyBoxRot), skyBoxRotation.AsFloatArray()); if (waterManager.m_WaterRefraction) { deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_refractionMatrix), waterManager.m_RefractionMatrix.AsFloatArray()); } if (waterManager.m_WaterReflection) { deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_reflectionMatrix), waterManager.m_ReflectionMatrix.AsFloatArray()); } deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_ambient), lightEnv.m_AmbientColor.AsFloatArray()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_sunDir), lightEnv.GetSunDir().AsFloatArray()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_sunColor), lightEnv.m_SunColor.AsFloatArray()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_tint), waterManager.m_WaterTint.AsFloatArray()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_waviness), waterManager.m_Waviness); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_murkiness), waterManager.m_Murkiness); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_windAngle), waterManager.m_WindAngle); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_repeatScale), 1.0f / repeatPeriod); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_losTransform), losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12]); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_cameraPos), camera.GetOrientation().GetTranslation().AsFloatArray()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_fogColor), lightEnv.m_FogColor.AsFloatArray()); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_fogParams), lightEnv.m_FogFactor, lightEnv.m_FogMax); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_time), static_cast(time)); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_screenSize), static_cast(g_Renderer.GetWidth()), static_cast(g_Renderer.GetHeight())); if (waterManager.m_WaterType == L"clap") { deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_waveParams1), 30.0f, 1.5f, 20.0f, 0.03f); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_waveParams2), 0.5f, 0.0f, 0.0f, 0.0f); } else if (waterManager.m_WaterType == L"lake") { deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_waveParams1), 8.5f, 1.5f, 15.0f, 0.03f); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_waveParams2), 0.2f, 0.0f, 0.0f, 0.07f); } else { deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_waveParams1), 15.0f, 0.8f, 10.0f, 0.1f); deviceCommandContext->SetUniform( fancyWaterShader->GetBindingSlot(str_waveParams2), 0.3f, 0.0f, 0.1f, 0.3f); } if (shadow) shadow->BindTo(deviceCommandContext, fancyWaterShader); for (CPatchRData* data : m->visiblePatches[cullGroup]) { data->RenderWaterSurface(deviceCommandContext, true); if (waterManager.m_WaterFancyEffects) data->RenderWaterShore(deviceCommandContext); } deviceCommandContext->EndPass(); return true; } void TerrainRenderer::RenderSimpleWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup) { PROFILE3_GPU("simple water"); GPU_SCOPED_LABEL(deviceCommandContext, "Render Simple Water"); const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); CLOSTexture& losTexture = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); const double time = waterManager.m_WaterTexTimer; CShaderDefines context; if (g_Renderer.GetSceneRenderer().GetWaterRenderMode() == WIREFRAME) context.Add(str_MODE_WIREFRAME, str_1); CShaderTechniquePtr waterSimpleTech = g_Renderer.GetShaderManager().LoadEffect(str_water_simple, context); deviceCommandContext->SetGraphicsPipelineState( waterSimpleTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* waterSimpleShader = waterSimpleTech->GetShader(); const CTexturePtr& waterTexture = waterManager.m_WaterTexture[waterManager.GetCurrentTextureIndex(1.6)]; waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext); deviceCommandContext->SetTexture( waterSimpleShader->GetBindingSlot(str_baseTex), waterTexture->GetBackendTexture()); deviceCommandContext->SetTexture( waterSimpleShader->GetBindingSlot(str_losTex), losTexture.GetTextureSmooth()); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( waterSimpleShader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( waterSimpleShader->GetBindingSlot(str_losTransform), losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12]); deviceCommandContext->SetUniform( waterSimpleShader->GetBindingSlot(str_time), static_cast(time)); deviceCommandContext->SetUniform( waterSimpleShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray()); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; data->RenderWaterSurface(deviceCommandContext, false); } deviceCommandContext->EndPass(); } /////////////////////////////////////////////////////////////////// // Render water that is part of the terrain void TerrainRenderer::RenderWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager(); if (!waterManager.WillRenderFancyWater()) RenderSimpleWater(deviceCommandContext, cullGroup); else RenderFancyWater(deviceCommandContext, context, cullGroup, shadow); } void TerrainRenderer::RenderWaterFoamOccluders( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup) { CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); const WaterManager& waterManager = sceneRenderer.GetWaterManager(); if (!waterManager.WillRenderFancyWater()) return; GPU_SCOPED_LABEL(deviceCommandContext, "Render water foam occluders"); // Render normals and foam to a framebuffer if we're using fancy effects. deviceCommandContext->BeginFramebufferPass(waterManager.m_FancyEffectsFramebuffer.get()); // Overwrite waves that would be behind the ground. CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = dummyTech->GetGraphicsPipelineStateDesc(); pipelineStateDesc.depthStencilState.depthTestEnabled = true; pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* dummyShader = dummyTech->GetShader(); const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( dummyShader->GetBindingSlot(str_transform), transform.AsFloatArray()); deviceCommandContext->SetUniform( dummyShader->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 0.0f); for (CPatchRData* data : m->visiblePatches[cullGroup]) data->RenderWaterShore(deviceCommandContext); deviceCommandContext->EndPass(); deviceCommandContext->EndFramebufferPass(); } void TerrainRenderer::RenderPriorities(CCanvas2D& canvas, int cullGroup) { PROFILE("priorities"); ENSURE(m->phase == Phase_Render); CTextRenderer textRenderer; textRenderer.SetCurrentFont(CStrIntern("mono-stroke-10")); textRenderer.SetCurrentColor(CColor(1.0f, 1.0f, 0.0f, 1.0f)); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) visiblePatches[i]->RenderPriorities(textRenderer); canvas.DrawText(textRenderer); } Index: ps/trunk/source/renderer/TerrainRenderer.h =================================================================== --- ps/trunk/source/renderer/TerrainRenderer.h (revision 27207) +++ ps/trunk/source/renderer/TerrainRenderer.h (revision 27208) @@ -1,195 +1,195 @@ /* 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 . */ /* * Terrain rendering (everything related to patches and water) is * encapsulated in TerrainRenderer */ #ifndef INCLUDED_TERRAINRENDERER #define INCLUDED_TERRAINRENDERER #include "graphics/Color.h" #include "maths/BoundingBoxAligned.h" #include "renderer/backend/IDeviceCommandContext.h" #include "renderer/backend/ITexture.h" #include "renderer/backend/IShaderProgram.h" class CCamera; class CCanvas2D; -class CMatrix3D; class CModelDecal; class CPatch; class CShaderDefines; class CSimulation2; +class CVector2D; class ShadowMap; struct TerrainRendererInternals; /** * Class TerrainRenderer: Render everything related to the terrain, * especially patches and water. */ class TerrainRenderer { friend class CPatchRData; friend class CDecalRData; public: TerrainRenderer(); ~TerrainRenderer(); /** * Set the simulation context for this frame. * Call at start of frame, before any other Submits. */ void SetSimulation(CSimulation2* simulation); /** * Submit: Add a patch for rendering in this frame. * * preconditions : PrepareForRendering must not have been called * for this frame yet. * The patch must not have been submitted in this frame yet (i.e. you * can only submit a frame once). * * @param patch the patch */ void Submit(int cullGroup, CPatch* patch); /** * Submit: Add a terrain decal for rendering in this frame. */ void Submit(int cullGroup, CModelDecal* decal); /** * PrepareForRendering: Prepare internal data structures like vertex * buffers for rendering. * * All patches must have been submitted before the call to * PrepareForRendering. * PrepareForRendering must be called before any rendering calls. */ void PrepareForRendering(); /** * EndFrame: Remove all patches from the list of submitted patches. */ void EndFrame(); /** * Render textured terrain (including blends between * different terrain types). * * preconditions : PrepareForRendering must have been called this * frame before calling RenderTerrain. * * @param deviceCommandContext A context to submit commands. * @param shadow A prepared shadow map, in case rendering with shadows is enabled. */ void RenderTerrainShader( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CShaderDefines& context, int cullGroup, ShadowMap* shadow); /** * RenderPatches: Render all patches un-textured as polygons. * * preconditions : PrepareForRendering must have been called this * frame before calling RenderPatches. * * @param filtered If true then only render objects that passed CullPatches. * @param color Fill color of the patches. */ void RenderPatches( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup, const CShaderDefines& defines, const CColor& color = CColor(0.0f, 0.0f, 0.0f, 1.0f)); /** * RenderOutlines: Render the outline of patches as lines. * * preconditions : PrepareForRendering must have been called this * frame before calling RenderOutlines. * * @param filtered If true then only render objects that passed CullPatches. */ void RenderOutlines( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup); /** * RenderWater: Render water for all patches that have been submitted * this frame. * * preconditions : PrepareForRendering must have been called this * frame before calling RenderWater. */ void RenderWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CShaderDefines& context, int cullGroup, ShadowMap* shadow); /** * Renders terrain to a framebuffer to occlude shore foams. */ void RenderWaterFoamOccluders( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup); /** * Calculate a scissor rectangle for the visible water patches. */ CBoundingBoxAligned ScissorWater(int cullGroup, const CCamera& camera); /** * Render priority text for all submitted patches, for debugging. */ void RenderPriorities(CCanvas2D& canvas, int cullGroup); /** * Render texture unit 0 over the terrain mesh, with UV coords calculated * by the given texture matrix. * Intended for use by TerrainTextureOverlay. */ void RenderTerrainOverlayTexture( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - int cullGroup, CMatrix3D& textureMatrix, Renderer::Backend::ITexture* texture); + int cullGroup, const CVector2D& textureTransform, Renderer::Backend::ITexture* texture); private: TerrainRendererInternals* m; /** * RenderFancyWater: internal rendering method for fancy water. * Returns false if unable to render with fancy water. */ bool RenderFancyWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, const CShaderDefines& context, int cullGroup, ShadowMap* shadow); /** * RenderSimpleWater: internal rendering method for water */ void RenderSimpleWater( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, int cullGroup); static void PrepareShader( Renderer::Backend::IDeviceCommandContext* deviceCommandContext, Renderer::Backend::IShaderProgram* shader, ShadowMap* shadow); }; #endif // INCLUDED_TERRAINRENDERER