Cogs.Core
ClipmapRenderer.cpp
1#include "ClipmapRenderer.h"
2
3#include "ClipmapLevel.h"
4#include "ClipmapGeometry.h"
5#include "ClipmapState.h"
6#include "ClipmapParameterCalculation.h"
7
8#include "RenderBlock.h"
9#include "RenderBlockCulling.h"
10
11#include "Rendering/IRenderTargets.h"
12#include "Rendering/IContext.h"
13#include "Rendering/ITextures.h"
14#include "Rendering/IEffects.h"
15
16#include <cassert>
17
18namespace
19{
20 std::vector<Cogs::Vector3> colors = {
21 Cogs::Vector3(1, 0, 0),
22 Cogs::Vector3(0, 1, 0),
23 Cogs::Vector3(0, 0, 1),
24 Cogs::Vector3(1, 1, 0),
25 Cogs::Vector3(0, 1, 1),
26 Cogs::Vector3(1, 0, 1),
27 Cogs::Vector3(1, 0, 0),
28 Cogs::Vector3(0, 1, 0),
29 Cogs::Vector3(0, 0, 1),
30 Cogs::Vector3(1, 0, 0),
31 Cogs::Vector3(0, 1, 0),
32 Cogs::Vector3(0, 0, 1),
33 Cogs::Vector3(1, 0, 0),
34 Cogs::Vector3(0, 1, 0),
35 Cogs::Vector3(0, 0, 1),
36 Cogs::Vector3(1, 0, 0),
37 Cogs::Vector3(0, 1, 0),
38 Cogs::Vector3(0, 0, 1),
39 Cogs::Vector3(1, 0, 0),
40 Cogs::Vector3(0, 1, 0),
41 };
42}
43
44void Cogs::DepthRenderData::initialize(IGraphicsDevice * device, int width, int height)
45{
46 this->width = width;
47 this->height = height;
48 auto textures = device->getTextures();
49 auto renderTargets = device->getRenderTargets();
50
51 depthTextureHandle = textures->loadTexture(nullptr, width, height, TextureFormat::R32_FLOAT, TextureFlags::RenderTarget);
52
53 depthRenderHandle = renderTargets->createRenderTarget(depthTextureHandle);
54 depthTargetHandle = renderTargets->createDepthStencilTarget(depthRenderHandle);
55
56 const size_t bufferSize = width * height * sizeof(float);
57 readbackBufferHandle = device->getBuffers()->loadBuffer(nullptr, bufferSize, Usage::Staging, AccessMode::Read, 0);
58}
59
60void Cogs::DepthRenderData::cleanup(IGraphicsDevice * device)
61{
62 auto textures = device->getTextures();
63 auto renderTargets = device->getRenderTargets();
64
65 renderTargets->releaseDepthStencilTarget(depthTargetHandle);
66 renderTargets->releaseRenderTarget(depthRenderHandle);
67
68 textures->releaseTexture(depthTextureHandle);
69
70 device->getBuffers()->releaseBuffer(readbackBufferHandle);
71}
72
73void Cogs::ClipmapRenderer::initializeTextures(ITextures * textures)
74{
75 SamplerState pointSampler = {
80 SamplerState::ComparisonFunction::Never,
81 0,
82 { 0.0f, 0.0f, 0.0f, 0.0f },
83 };
84
85 pointSamplerState = textures->loadSamplerState(pointSampler);
86
87 SamplerState linearSampler = {
92 SamplerState::ComparisonFunction::Never,
93 16,
94 { 0.0f, 0.0f, 0.0f, 0.0f },
95 };
96
97 linearSamplerState = textures->loadSamplerState(linearSampler);
98
99 depthQuerySize = 8;
100 depthQueryTextureHandle = textures->loadTexture(nullptr, depthQuerySize, depthQuerySize, TextureFormat::R32G32B32A32_FLOAT, TextureFlags::RenderTarget);
101}
102
103void Cogs::ClipmapRenderer::initializeEffects(IBuffers * buffers, IEffects * effects, const size_t numImagery, size_t permutation)
104{
105 auto & permutationRendererData = getPermutationDependentClipmapRendererData(permutation);
106 if (!permutationRendererData.initialized) {
107 // First time, create and initialize constant buffers.
108 initializeConstantBuffers(buffers, permutationRendererData.effectVariables);
109 initializeConstantBuffers(buffers, permutationRendererData.depthEffectVariables);
110 }
111
112 initializeEffectVariables(effects, permutationRendererData.clipmapEffect, permutationRendererData.effectVariables, numImagery, false);
113 initializeEffectVariables(effects, permutationRendererData.clipmapDepthEffect, permutationRendererData.depthEffectVariables, numImagery, true);
114
115 initializeEffectBindings(effects, permutationRendererData.clipmapEffect, permutationRendererData.effectBindings, numImagery, false);
116 initializeEffectBindings(effects, permutationRendererData.clipmapDepthEffect, permutationRendererData.depthEffectBindings, numImagery, true);
117
118 VertexElement element = { 0, DataFormat::X32Y32_FLOAT, ElementSemantic::Position, 0, InputType::VertexData, 0 };
119 VertexFormatHandle meshFormat = buffers->createVertexFormat(&element, 1);
120 inputLayout = buffers->loadInputLayout(&meshFormat, 1, permutationRendererData.clipmapEffect);
121
122 permutationRendererData.initialized = true;
123}
124
125void Cogs::ClipmapRenderer::initializeConstantBuffers(IBuffers * buffers, ClipmapEffectVariables & variables)
126{
127 variables.globalBuffer = buffers->loadBuffer(nullptr, sizeof(GlobalParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
128 variables.levelBuffer = buffers->loadBuffer(nullptr, sizeof(LevelParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
129 variables.imageryBuffer = buffers->loadBuffer(nullptr, sizeof(ImageryParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
130
131 variables.patchBuffer = buffers->loadBuffer(nullptr, sizeof(PatchParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
132
133 variables.renderBuffer = buffers->loadBuffer(nullptr, sizeof(RenderParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
134 variables.levelRenderBuffer = buffers->loadBuffer(nullptr, sizeof(LevelRenderParameters), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
135 customParametersBuffer = BufferHandle::NoHandle;
136}
137
138void Cogs::ClipmapRenderer::initializeEffectVariables(IEffects * effects, EffectHandle effectHandle, ClipmapEffectVariables & variables, const size_t /*numImagery*/, bool isDepth)
139{
140 variables.globalBufferBinding = effects->getConstantBufferBinding(effectHandle, "GlobalParameters");
141 variables.levelBufferBinding = effects->getConstantBufferBinding(effectHandle, "LevelParameters");
142
143 variables.patchBufferBinding = effects->getConstantBufferBinding(effectHandle, "PatchParameters");
144 variables.imageryBufferBinding = effects->getConstantBufferBinding(effectHandle, "ImageryParameters");
145
146 if (!isDepth) {
147
148 variables.renderBufferBinding = effects->getConstantBufferBinding(effectHandle, "RenderParameters");
149 variables.levelRenderBufferBinding = effects->getConstantBufferBinding(effectHandle, "LevelRenderParameters");
150 }
151
152 variables.customParametersBufferBinding = effects->getConstantBufferBinding(effectHandle, "CustomParameters");
153}
154
155namespace
156{
157 const char * imagerySemantics[] = {
158 "imageryTexture[0]",
159 "imageryTexture[1]",
160 "imageryTexture[2]",
161 "imageryTexture[3]",
162 };
163
164 const char * coarseImagerySemantics[] = {
165 "coarseImageryTexture[0]",
166 "coarseImageryTexture[1]",
167 "coarseImageryTexture[2]",
168 "coarseImageryTexture[3]",
169 };
170}
171
172void Cogs::ClipmapRenderer::initializeEffectBindings(IEffects * effects, EffectHandle effect, ClipmapTextureBindings & bindings, const size_t numImagery, bool isDepth)
173{
174 int unit = 0;
175
176 bindings.heightMapBinding = effects->getTextureBinding(effect, "heightTexture", unit);
177 bindings.heightMapSamplerBinding = effects->getSamplerStateBinding(effect, "heightSampler", unit++);
178
179 bindings.coarseHeightMapBinding = effects->getTextureBinding(effect, "coarseHeightTexture", unit);
180 bindings.coarseHeightMapSamplerBinding = effects->getSamplerStateBinding(effect, "coarseHeightSampler", unit++);
181
182 if (!isDepth || true) {
183 bindings.normalMapBinding = effects->getTextureBinding(effect, "normalTexture", unit);
184 bindings.normalMapSamplerBinding = effects->getSamplerStateBinding(effect, "normalSampler", unit++);
185
186 bindings.coarseNormalMapBinding = effects->getTextureBinding(effect, "coarseNormalTexture", unit);
187 bindings.coarseNormalMapSamplerBinding = effects->getSamplerStateBinding(effect, "normalSampler", unit++);
188
189 if (numImagery > 1) {
190 for (size_t i = 0; i < numImagery; ++i) {
191 auto & perImageBindings = bindings.getImageryBindingHandles(i);
192 perImageBindings.imageryBinding = effects->getTextureBinding(effect, imagerySemantics[i], unit);
193 perImageBindings.imagerySamplerBinding = effects->getSamplerStateBinding(effect, "imagerySampler", unit++);
194
195 perImageBindings.coarseImageryBinding = effects->getTextureBinding(effect, coarseImagerySemantics[i], unit);
196 perImageBindings.coarseImagerySamplerBinding = effects->getSamplerStateBinding(effect, "imagerySampler", unit++);
197 }
198 } else {
199 auto & perImageBindings = bindings.getImageryBindingHandles(0);
200 perImageBindings.imageryBinding = effects->getTextureBinding(effect, "imageryTexture[0]", unit);
201 perImageBindings.imagerySamplerBinding = effects->getSamplerStateBinding(effect, "imagerySampler", unit++);
202
203 perImageBindings.coarseImageryBinding = effects->getTextureBinding(effect, "coarseImageryTexture[0]", unit);
204 perImageBindings.coarseImagerySamplerBinding = perImageBindings.imagerySamplerBinding;
205 }
206 }
207}
208
209void Cogs::ClipmapRenderer::initializeRasterizerStates(IRenderTargets * renderTargets)
210{
211 float offset = reverseDepth ? -1.0f : 1.0f;
214
215 RasterizerState solid = { false, RasterizerState::CullMode::None, true, true, 0.0f, 0.0f, 0.0f, false, false };
216 solidRasterizerState = renderTargets->loadRasterizerState(solid);
217
218 RasterizerState solidNoDepthClip = { false, RasterizerState::CullMode::None, true, true, 0.0f, 0.0f, 0.0f, false, false };
219 solidNoDepthClip.noDepthClip = true;
220 solidNoDepthClipRasterizerState = renderTargets->loadRasterizerState(solidNoDepthClip);
221
222 RasterizerState solidOffset = { false, RasterizerState::CullMode::None, true, true, offset, 0.0f, 0.0f, false, false };
223 solidOffsetRasterizerState = renderTargets->loadRasterizerState(solidOffset);
224
225 RasterizerState wireFrame = { true, RasterizerState::CullMode::None, true, true, 0.0f, 0.0f, 0.0f, false, false };
226 wireframeRasterizerState = renderTargets->loadRasterizerState(wireFrame);
227
228 DepthStencilState solidDepth = { true, true, cmp };
229 solidDepthState = renderTargets->loadDepthStencilState(solidDepth);
230
231 DepthStencilState wireDepth = { true, true, cmpOrEqual };
232 wireframeDepthState = renderTargets->loadDepthStencilState(wireDepth);
233
234 DepthStencilState transparentDepth = { true, false, cmp };
235 transparentDepthState = renderTargets->loadDepthStencilState(transparentDepth);
236
237 DepthStencilState transparentWireDepth = { true, false, cmpOrEqual };
238 transparentWireframeDepthState = renderTargets->loadDepthStencilState(transparentWireDepth);
239}
240
241void Cogs::ClipmapRenderer::initializeRenderTargets(IRenderTargets * renderTargets)
242{
243 depthQueryRenderHandle = renderTargets->createRenderTarget(depthQueryTextureHandle);
244 depthQueryTargetHandle = renderTargets->createDepthStencilTarget(depthQueryRenderHandle);
245}
246
247namespace Cogs
248{
249 template<typename Parameters>
250 void applyParameters(IContext * context, const Parameters & parameters, BufferHandle bufferHandle)
251 {
252 MappedBuffer<Parameters> out(context, bufferHandle, MapMode::WriteDiscard);
253
254 if (out) {
255 ::memcpy(out, &parameters, sizeof(Parameters));
256 }
257 }
258}
259
260void Cogs::ClipmapRenderer::updateGlobalParameters(const RenderContext & renderContext, const RenderOptions & renderOptions, const ClipmapState & /*clipmapState*/, const GlobalParameters & globalParameters)
261{
262 IContext * context = renderContext.context;
263
264 const auto & permutationRendererData = getPermutationDependentClipmapRendererData(renderContext.permutation);
265 const auto & variables = this->depthPass ? permutationRendererData.depthEffectVariables : permutationRendererData.effectVariables;
266
267 if (!this->depthPass) {
268 RenderParameters renderParameters;
269 renderParameters.blendRegionColor = renderOptions.blendRegionColor;
270 renderParameters.showBlendRegions = renderOptions.showBlendRegions;
271 renderParameters.showImagery = renderOptions.showImagery;
272 renderParameters.showLevelColors = renderOptions.showLevelColors;
273
274 applyParameters(context, renderParameters, variables.renderBuffer);
275 }
276
277 applyParameters(context, globalParameters, variables.globalBuffer);
278}
279
280void Cogs::ClipmapRenderer::updateLevelParameters(IContext * context, const RenderOptions & options, const LevelParameters & parameters, const ImageryParameters & imageryParameters, size_t permutation)
281{
282 const auto & permutationRendererData = getPermutationDependentClipmapRendererData(permutation);
283 const auto & variables = this->depthPass ? permutationRendererData.depthEffectVariables : permutationRendererData.effectVariables;
284
285 applyParameters(context, parameters, variables.levelBuffer);
286 applyParameters(context, imageryParameters, variables.imageryBuffer);
287
288 if (options.showLevelColors && !this->depthPass) {
289 Vector4 diffuseColor = pad3to4(colors[parameters.levelIndex & colors.size()]);
290 applyParameters(context, diffuseColor, variables.levelRenderBuffer);
291 } else if (!this->depthPass) {
292 applyParameters(context, options.diffuseColor, variables.levelRenderBuffer);
293 }
294}
295
296void Cogs::ClipmapRenderer::updateLevelTextures(IContext * context,
297 const RenderLevel * renderLevel,
298 size_t permutation)
299{
300 auto & permutationRendererData = getPermutationDependentClipmapRendererData(permutation);
301 auto & bindings = this->depthPass ? permutationRendererData.depthEffectBindings : permutationRendererData.effectBindings;
302
303 context->setTexture(bindings.heightMapBinding, renderLevel->terrainLevel->renderTexture.handle);
304 context->setSamplerState(bindings.heightMapSamplerBinding, pointSamplerState);
305
306 context->setTexture(bindings.coarseHeightMapBinding, renderLevel->coarserTerrainLevel->renderTexture.handle);
307 context->setSamplerState(bindings.coarseHeightMapSamplerBinding, linearSamplerState);
308
309 if (!this->depthPass || true) {
310 if (renderLevel->normalLevel) {
311 context->setTexture(bindings.normalMapBinding, renderLevel->normalLevel->renderTexture.handle);
312 context->setSamplerState(bindings.normalMapSamplerBinding, linearSamplerState);
313
314 context->setTexture(bindings.coarseNormalMapBinding, renderLevel->coarserNormalLevel->renderTexture.handle);
315 context->setSamplerState(bindings.coarseNormalMapSamplerBinding, linearSamplerState);
316 }
317
318 const size_t levelIndex = renderLevel->terrainLevel->index;
319
320 for (size_t i = 0; i < renderLevel->imagery->size(); ++i) {
321 const ClipmapLevel & imageryLevel = (*renderLevel->imagery)[i][levelIndex];
322 const auto & perImageBindings = bindings.getImageryBindingHandles(i);
323
324 context->setTexture(perImageBindings.imageryBinding, imageryLevel.renderTexture.handle);
325 context->setSamplerState(perImageBindings.imagerySamplerBinding, linearSamplerState);
326
327 context->setTexture(perImageBindings.coarseImageryBinding, imageryLevel.coarserLevel->renderTexture.handle);
328 context->setSamplerState(perImageBindings.coarseImagerySamplerBinding, linearSamplerState);
329 }
330 }
331}
332
333void Cogs::ClipmapRenderer::initLevels()
334{
335 levelIndex = 0;
336}
337
338bool Cogs::ClipmapRenderer::createRenderLevel(ClipmapGeometry & geometry,
339 ClipmapState & clipmapState,
340 ClipmapLevel & terrainLevel,
341 std::vector<std::vector<ClipmapLevel>> & imagery,
342 ClipmapLevel * normalLevel,
343 const GlobalParameters & globalParameters,
344 const LevelParameters & parameters,
345 const ImageryParameters & imageryParameters,
346 bool fillRing,
347 bool select)
348{
349 this->geometry = &geometry;
350
351 const int west = terrainLevel.currentExtent.west;
352 const int south = terrainLevel.currentExtent.south;
353 const int east = terrainLevel.currentExtent.east;
354 const int north = terrainLevel.currentExtent.north;
355
356 const int fillPatchSegments = static_cast<int>(clipmapState.fillPatchSegments);
357 const int fillPatchPosts = static_cast<int>(clipmapState.fillPatchPosts);
358
359 RenderLevel & renderLevel = levels[levelIndex++];
360
361 renderLevel.globalParameters = &globalParameters;
362 renderLevel.levelParameters = &parameters;
363 renderLevel.imageryParameters = &imageryParameters;
364
365 renderLevel.terrainLevel = &terrainLevel;
366 renderLevel.coarserTerrainLevel = terrainLevel.coarserLevel;
367
368 renderLevel.imagery = &imagery;
369
370 renderLevel.normalLevel = normalLevel;
371 renderLevel.coarserNormalLevel = normalLevel ? normalLevel->coarserLevel : nullptr;
372
373 renderLevel.blockCount = 0;
374
375 createBlock(geometry.fieldBlockMesh, west, south, west, south, renderLevel, select);
376
377 createBlock(geometry.fieldBlockMesh, west, south, west + fillPatchSegments, south, renderLevel, select);
378 createBlock(geometry.fieldBlockMesh, west, south, east - 2 * fillPatchSegments, south, renderLevel, select);
379 createBlock(geometry.fieldBlockMesh, west, south, east - fillPatchSegments, south, renderLevel, select);
380
381 createBlock(geometry.fieldBlockMesh, west, south, west, south + fillPatchSegments, renderLevel, select);
382 createBlock(geometry.fieldBlockMesh, west, south, east - fillPatchSegments, south + fillPatchSegments, renderLevel, select);
383
384 createBlock(geometry.fieldBlockMesh, west, south, west, north - 2 * fillPatchSegments, renderLevel, select);
385 createBlock(geometry.fieldBlockMesh, west, south, east - fillPatchSegments, north - 2 * fillPatchSegments, renderLevel, select);
386
387 createBlock(geometry.fieldBlockMesh, west, south, west, north - fillPatchSegments, renderLevel, select);
388 createBlock(geometry.fieldBlockMesh, west, south, west + fillPatchSegments, north - fillPatchSegments, renderLevel, select);
389 createBlock(geometry.fieldBlockMesh, west, south, east - 2 * fillPatchSegments, north - fillPatchSegments, renderLevel, select);
390 createBlock(geometry.fieldBlockMesh, west, south, east - fillPatchSegments, north - fillPatchSegments, renderLevel, select);
391
392 createBlock(geometry.ringFixupHorizontalMesh, west, south, west, south + 2 * fillPatchSegments, renderLevel);
393 createBlock(geometry.ringFixupHorizontalMesh, west, south, east - fillPatchSegments, south + 2 * fillPatchSegments, renderLevel);
394
395 createBlock(geometry.ringFixupVerticalMesh, west, south, west + 2 * fillPatchSegments, south, renderLevel);
396 createBlock(geometry.ringFixupVerticalMesh, west, south, west + 2 * fillPatchSegments, north - fillPatchSegments, renderLevel);
397
398 createBlock(geometry.degenerateTriangleMesh, west, south, west, south, renderLevel);
399
400 // Fill the center of the highest-detail ring
401 if (fillRing) {
402 createBlock(geometry.fieldBlockMesh, west, south, west + fillPatchSegments, south + fillPatchSegments, renderLevel);
403 createBlock(geometry.fieldBlockMesh, west, south, west + 2 * fillPatchPosts, south + fillPatchSegments, renderLevel);
404 createBlock(geometry.fieldBlockMesh, west, south, west + fillPatchSegments, south + 2 * fillPatchPosts, renderLevel);
405 createBlock(geometry.fieldBlockMesh, west, south, west + 2 * fillPatchPosts, south + 2 * fillPatchPosts, renderLevel);
406
407 createBlock(geometry.ringFixupHorizontalMesh, west, south, west + fillPatchSegments, south + 2 * fillPatchSegments, renderLevel);
408 createBlock(geometry.ringFixupHorizontalMesh, west, south, west + 2 * fillPatchPosts, south + 2 * fillPatchSegments, renderLevel);
409
410 createBlock(geometry.ringFixupVerticalMesh, west, south, west + 2 * fillPatchSegments, south + fillPatchSegments, renderLevel);
411 createBlock(geometry.ringFixupVerticalMesh, west, south, west + 2 * fillPatchSegments, south + 2 * fillPatchPosts, renderLevel);
412
413 createBlock(geometry.centerMesh, west, south, west + 2 * fillPatchSegments, south + 2 * fillPatchSegments, renderLevel);
414 } else {
415 int offset = terrainLevel.offsetStripOnNorth ? north - fillPatchPosts : south + fillPatchSegments;
416
417 createBlock(geometry.offsetStripHorizontalMesh, west, south, west + fillPatchSegments, offset, renderLevel);
418
419 int southOffset = terrainLevel.offsetStripOnNorth ? 0 : 1;
420 offset = terrainLevel.offsetStripOnEast ? east - fillPatchPosts : west + fillPatchSegments;
421
422 createBlock(geometry.offsetStripVerticalMesh, west, south, offset, south + fillPatchSegments + southOffset, renderLevel);
423 }
424
425 return true;
426}
427
428bool Cogs::ClipmapRenderer::createBackgroundRenderLevel(ClipmapGeometry & geometry,
429 ClipmapState & /*clipmapState*/,
430 ClipmapLevel & terrainLevel,
431 std::vector<std::vector<ClipmapLevel>> & imagery,
432 ClipmapLevel * normalLevel,
433 const GlobalParameters & globalParameters,
434 const LevelParameters & levelParameters,
435 const ImageryParameters & imageryParameters,
436 bool useSimplifiedMesh)
437{
438 const int west = terrainLevel.currentExtent.west;
439 const int south = terrainLevel.currentExtent.south;
440
441 RenderLevel & renderLevel = levels[levelIndex++];
442
443 renderLevel.globalParameters = &globalParameters;
444 renderLevel.levelParameters = &levelParameters;
445 renderLevel.imageryParameters = &imageryParameters;
446
447 renderLevel.terrainLevel = &terrainLevel;
448 renderLevel.coarserTerrainLevel = terrainLevel.coarserLevel;
449
450 renderLevel.imagery = &imagery;
451
452 renderLevel.normalLevel = normalLevel;
453 renderLevel.coarserNormalLevel = normalLevel ? normalLevel->coarserLevel : nullptr;
454
455 renderLevel.blockCount = 0;
456
457 const int width = terrainLevel.renderTexture.width;
458 const int height = terrainLevel.renderTexture.height;
459
460 const int blockSize = 64;
461
462 const int numDivisionsX = (width + blockSize - 1) / blockSize;
463 const int numDivisionsY = (height + blockSize - 1) / blockSize;
464
465 const int widthIncrement = blockSize * terrainLevel.currentExtent.getWidth() / terrainLevel.renderTexture.width;
466 const int heightIncrement = blockSize * terrainLevel.currentExtent.getHeight() / terrainLevel.renderTexture.height;
467
468 if (!HandleIsValid(geometry.worldMesh.vertexBuffer)) {
469 geometry.worldMesh = createMesh(geometry.buffers, 0, 0, widthIncrement, heightIncrement, blockSize, blockSize, geometry.meshFormat);
470 geometry.simpleWorldMesh = createMesh(geometry.buffers, 0, 0, widthIncrement, heightIncrement, 1, 1, geometry.meshFormat);
471 };
472
473 for (int x = 0; x < numDivisionsX; ++x) {
474 for (int y = 0; y < numDivisionsY; ++y) {
475 assert(renderLevel.blockCount < kMaxNumBlocks - 1 && "Number of blocks too large.");
476 createBlock(geometry.worldMesh, west, south, west + widthIncrement * x, south + heightIncrement * y, renderLevel, useSimplifiedMesh);
477 }
478 }
479
480 return true;
481}
482
483void Cogs::ClipmapRenderer::setupDepthPass(RenderContext & renderContext, size_t depthDataIndex)
484{
485 depthPass = true;
486
487 auto context = renderContext.context;
488 const auto & permutationRendererData = getPermutationDependentClipmapRendererData(renderContext.permutation);
489 auto & variables = permutationRendererData.depthEffectVariables;
490
491 auto & depthData = raypickDepthData[depthDataIndex];
492
493 context->setRenderTarget(depthData.depthRenderHandle, depthData.depthTargetHandle);
494
495 context->setRasterizerState(solidRasterizerState);
496 context->setDepthStencilState(solidDepthState);
497
498 float color[] = { 1.0f, 0.0f, 0.0f, 1.0f };
499 if(reverseDepth) color[0] = 0.0f;
500
501 context->clearRenderTarget(color);
502 if(reverseDepth)
503 context->clearDepth(0.0f);
504 else
505 context->clearDepth();
506 depthData.depthRenderInitialized = true;
507
508 context->setViewport(0, 0, static_cast<float>(depthData.width), static_cast<float>(depthData.height));
509
510 context->setEffect(permutationRendererData.clipmapDepthEffect);
511 context->setInputLayout(inputLayout);
512
513 renderContext.callback(permutationRendererData.clipmapDepthEffect);
514
515 context->setConstantBuffer(variables.globalBufferBinding, variables.globalBuffer);
516 context->setConstantBuffer(variables.levelBufferBinding, variables.levelBuffer);
517 context->setConstantBuffer(variables.imageryBufferBinding, variables.imageryBuffer);
518 context->setConstantBuffer(variables.patchBufferBinding, variables.patchBuffer);
519
520 if (customParameters.size()) {
521 auto buffers = renderContext.device->getBuffers();
522
523 if (HandleIsValid(customParametersBuffer)) {
524 buffers->releaseBuffer(customParametersBuffer);
525 }
526
527 customParametersBuffer = buffers->loadBuffer(customParameters.data(), customParameters.size(), Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
528
529 customParameters.clear();
530 }
531
532 if (HandleIsValid(customParametersBuffer) && HandleIsValid(variables.customParametersBufferBinding)) {
533 context->setConstantBuffer(variables.customParametersBufferBinding, customParametersBuffer);
534 }
535}
536
537void Cogs::ClipmapRenderer::setupDepthQueryPass(RenderContext & renderContext)
538{
539 depthPass = true;
540
541 auto context = renderContext.context;
542 const auto & permutationRendererData = getPermutationDependentClipmapRendererData(renderContext.permutation);
543 auto & variables = permutationRendererData.depthEffectVariables;
544
545 context->setRenderTarget(depthQueryRenderHandle, depthQueryTargetHandle);
546
547 context->setRasterizerState(solidNoDepthClipRasterizerState);
548 context->setDepthStencilState(solidDepthState);
549
550 float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
551 if(reverseDepth){
552 color[0] = 0.0f;
553 color[1] = 0.0f;
554 color[2] = 0.0f;
555 }
556
557 context->clearRenderTarget(color);
558 if(reverseDepth)
559 context->clearDepth(0.0f);
560 else
561 context->clearDepth();
562 depthQueryRenderInitialized = true;
563
564 context->setViewport(0, 0, static_cast<float>(depthQuerySize), static_cast<float>(depthQuerySize));
565
566 context->setEffect(permutationRendererData.clipmapDepthEffect);
567 context->setInputLayout(inputLayout);
568
569 renderContext.callback(permutationRendererData.clipmapDepthEffect);
570
571 context->setConstantBuffer(variables.globalBufferBinding, variables.globalBuffer);
572 context->setConstantBuffer(variables.levelBufferBinding, variables.levelBuffer);
573 context->setConstantBuffer(variables.imageryBufferBinding, variables.imageryBuffer);
574 context->setConstantBuffer(variables.patchBufferBinding, variables.patchBuffer);
575}
576
577void Cogs::ClipmapRenderer::setupRegularPass(RenderContext & renderContext)
578{
579 depthPass = false;
580
581 const auto & permutationRendererData = getPermutationDependentClipmapRendererData(renderContext.permutation);
582 auto context = renderContext.context;
583 auto & variables = permutationRendererData.effectVariables;
584
585 context->setRenderTarget(renderContext.renderTarget, renderContext.depthStencilTarget);
586 context->setViewport(renderContext.viewportX, renderContext.viewportY, renderContext.width, renderContext.height);
587
588 context->setEffect(permutationRendererData.clipmapEffect);
589 context->setInputLayout(inputLayout);
590
591 renderContext.callback(permutationRendererData.clipmapEffect);
592
593 if (renderContext.wireframe) {
594 context->setRasterizerState(wireframeRasterizerState);
595 } else {
596 context->setRasterizerState(renderContext.offsetEnabled ? solidOffsetRasterizerState : solidRasterizerState);
597 }
598
599 context->setDepthStencilState(renderContext.wireframe ? wireframeDepthState : solidDepthState);
600
601 context->setConstantBuffer(variables.globalBufferBinding, variables.globalBuffer);
602 context->setConstantBuffer(variables.levelBufferBinding, variables.levelBuffer);
603 context->setConstantBuffer(variables.imageryBufferBinding, variables.imageryBuffer);
604
605 context->setConstantBuffer(variables.patchBufferBinding, variables.patchBuffer);
606
607 if (HandleIsValid(variables.renderBufferBinding)) {
608 context->setConstantBuffer(variables.renderBufferBinding, variables.renderBuffer);
609 }
610
611 if (HandleIsValid(variables.levelRenderBufferBinding)) {
612 context->setConstantBuffer(variables.levelRenderBufferBinding, variables.levelRenderBuffer);
613 }
614
615 if (HandleIsValid(customParametersBuffer) && HandleIsValid(variables.customParametersBufferBinding)) {
616 context->setConstantBuffer(variables.customParametersBufferBinding, customParametersBuffer);
617 }
618}
619
620void Cogs::ClipmapRenderer::render(RenderContext & renderContext, const RenderOptions & renderOptions, const WorldOptions & worldOptions, bool usePreviousCullingResults)
621{
622 if (!usePreviousCullingResults) {
623 for (size_t i = 0; i < levelIndex; ++i) {
624 const RenderLevel & renderLevel = levels[i];
625
626 updateLevelTextures(renderContext.context, &renderLevel, renderContext.permutation);
627
628 updateLevelParameters(renderContext.context, renderOptions, *renderLevel.levelParameters, *renderLevel.imageryParameters, renderContext.permutation);
629
630 cullRenderBlocks(renderLevel.renderBlocks,
631 visibleBlocks + i * kMaxNumBlocks,
632 renderLevel.blockCount,
633 renderLevel,
634 renderContext.cullVolume,
635 renderContext.center - renderContext.cullOrigin + renderContext.offset,
636 worldOptions.heightExaggeration,
637 static_cast<float>(worldOptions.worldScale.x),
638 static_cast<float>(worldOptions.worldScale.y));
639
640 for (size_t j = 0; j < renderLevel.blockCount; ++j) {
641 bool draw = visibleBlocks[j + i * kMaxNumBlocks] || !renderOptions.enableCulling;
642
643 if (draw) {
644 drawBlock(renderLevel.renderBlocks[j], renderContext);
645 }
646 }
647 }
648 } else {
649 for (size_t i = 0; i < levelIndex; ++i) {
650 const RenderLevel & renderLevel = levels[i];
651
652 updateLevelTextures(renderContext.context, &renderLevel, renderContext.permutation);
653
654 updateLevelParameters(renderContext.context, renderOptions, *renderLevel.levelParameters, *renderLevel.imageryParameters, renderContext.permutation);
655
656 for (size_t j = 0; j < renderLevel.blockCount; ++j) {
657 if (visibleBlocks[j + i * kMaxNumBlocks] || !renderOptions.enableCulling) {
658 drawBlock(renderLevel.renderBlocks[j], renderContext);
659 }
660 }
661 }
662 }
663}
664
665void Cogs::ClipmapRenderer::createBlock(ClipmapMesh & mesh, int overallWest, int overallSouth, int blockWest, int blockSouth, RenderLevel & renderLevel, bool useSimplifiedMesh)
666{
667 auto & renderBlock = renderLevel.renderBlocks[renderLevel.blockCount++];
668
669 renderBlock.mesh = &mesh;
670
671 const int textureWest = blockWest - overallWest;
672 const int textureSouth = blockSouth - overallSouth;
673
674 renderBlock.patchOriginInClippedLevel = Vector2(static_cast<float>(textureWest), static_cast<float>(textureSouth));
675
676 // Calculate raster coordinates in terrain coordinate space (pre world scale and origin transform).
677 const auto levelOffset = renderLevel.levelParameters->levelOffsetFromClipmapCenter;
678 const auto scaleFactor = renderLevel.levelParameters->levelScaleFactor * renderLevel.globalParameters->levelZeroWorldScaleFactor;
679
680 renderBlock.min = Vector2(renderBlock.patchOriginInClippedLevel + levelOffset) * scaleFactor;
681 renderBlock.max = Vector2(renderBlock.patchOriginInClippedLevel + levelOffset + Vector2(mesh.width, mesh.height)) * scaleFactor;
682
683 if (useSimplifiedMesh && renderBlock.mesh == &geometry->fieldBlockMesh) {
684 renderBlock.mesh = &geometry->simpleMesh;
685 } else if (useSimplifiedMesh && renderBlock.mesh == &geometry->worldMesh) {
686 renderBlock.mesh = &geometry->simpleWorldMesh;
687 }
688}
689
690void Cogs::ClipmapRenderer::drawBlock(const RenderBlock & renderBlock, RenderContext & renderContext)
691{
692 IContext * context = renderContext.context;
693
694 auto & permutationRendererData = getPermutationDependentClipmapRendererData(renderContext.permutation);
695 const auto & effectVariables = this->depthPass ? permutationRendererData.depthEffectVariables : permutationRendererData.effectVariables;
696
697 applyParameters(context, renderBlock.patchOriginInClippedLevel, effectVariables.patchBuffer);
698
699 context->setVertexBuffers(&renderBlock.mesh->vertexBuffer, 1, &renderBlock.mesh->stride, nullptr);
700 context->setIndexBuffer(renderBlock.mesh->indexBuffer, sizeof(unsigned short), 0);
701
702 context->drawIndexed(PrimitiveType::TriangleList, 0, 0);
703}
704
705void Cogs::ClipmapRenderer::setCustomParameters(const unsigned char * data, int count)
706{
707 customParameters.assign(data, data + count);
708}
709
710void Cogs::ClipmapRenderer::cleanup(IGraphicsDevice * device)
711{
712 if (HandleIsValid(depthQueryRenderHandle)) {
713 device->getRenderTargets()->releaseRenderTarget(depthQueryRenderHandle);
714 }
715
716 if (HandleIsValid(depthQueryTargetHandle)) {
717 device->getRenderTargets()->releaseDepthStencilTarget(depthQueryTargetHandle);
718 }
719
720 if (HandleIsValid(depthQueryTextureHandle)) {
721 device->getTextures()->releaseTexture(depthQueryTextureHandle);
722 }
723
724 for (auto & data : raypickDepthData)
725 {
726 data.cleanup(device);
727 }
728}
729
730Cogs::RenderTexture Cogs::createClipmapTexture(IGraphicsDevice * device, int width, int height, TextureFormat textureFormat, bool mipmap, glm::vec4 clearColor)
731{
732 unsigned int flags = TextureFlags::RenderTarget | (mipmap ? TextureFlags::GenerateMipMaps : 0);
733 TextureHandle textureHandle = device->getTextures()->loadTexture(nullptr, width, height, textureFormat, flags);
734 RenderTargetHandle renderTarget = device->getRenderTargets()->createRenderTarget(textureHandle);
735
736 RenderTexture texture = {
737 textureHandle,
738 Cogs::getTextureSize(width, height, textureFormat),
739 width,
740 height,
741 renderTarget,
742 clearColor
743 };
744
745 assert(HandleIsValid(texture.handle) && "Texture handle not valid.");
746 assert(HandleIsValid(texture.renderTarget) && "Render target handle not valid.");
747
748 clearClipmapTexture(device, texture);
749
750 return texture;
751}
752
753void Cogs::releaseClipmapTexture(IGraphicsDevice * device, RenderTexture & texture)
754{
755 if (HandleIsValid(texture.renderTarget)) {
756 device->getRenderTargets()->releaseRenderTarget(texture.renderTarget);
757 }
758
759 device->getTextures()->releaseTexture(texture.handle);
760}
761
762void Cogs::clearClipmapTexture(IGraphicsDevice * device, RenderTexture & texture)
763{
764 auto context = device->getImmediateContext();
765
766 context->setRenderTarget(texture.renderTarget, DepthStencilHandle::InvalidHandle);
767
768 context->clearRenderTarget(reinterpret_cast<float *>(&texture.clearColor));
769
771}
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
@ VertexData
Per vertex data.
@ Position
Position semantic.
@ Read
The buffer can be mapped and read from by the CPU after creation.
Definition: Flags.h:48
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
DepthFunction
Depth functions to apply when determining object visibility based on its depth test.
@ GreaterOrEqual
Greater or equal depth.
@ LessOrEqual
Less or equal depth.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:77
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103
@ TriangleList
List of triangles.
Definition: Common.h:116
@ None
Do not perform any face culling.
@ Wrap
Texture coordinates automatically wrap around to [0, 1] range.
Definition: SamplerState.h:19
@ MinMagMipPoint
Point sampling for both minification and magnification.
Definition: SamplerState.h:33
@ MinMagMipLinear
Linear sampling for both minification and magnification.
Definition: SamplerState.h:35
@ RenderTarget
The texture can be used as a render target and drawn into.
Definition: Flags.h:120
@ GenerateMipMaps
The texture supports automatic mipmap generation performed by the graphics device.
Definition: Flags.h:124
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30
@ Staging
Definition: Flags.h:33