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