2#include "Foundation/Logging/Logger.h"
4#include "Rendering/ICapabilities.h"
6#include "Utilities/Math.h"
7#include "Systems/Core/CameraSystem.h"
8#include "Systems/Core/TransformSystem.h"
9#include "Resources/Material.h"
10#include "Resources/MaterialInstance.h"
11#include "Resources/TextureManager.h"
12#include "Services/Time.h"
13#include "TexAtlasSystem.h"
14#include "TexAtlasRenderer.h"
16using namespace Cogs::Core::TexAtlas;
26 const size_t slotCount = 4;
28 Layout getLayout(
const glm::dvec2& domainMin,
const glm::dvec2& domainMax,
const uint32_t minLevel,
const uint32_t maxLevel)
31 double domainSize = std::max(domainMax.x - domainMin.x,
32 domainMax.y - domainMax.y);
33 uint32_t level =
static_cast<uint32_t
>(std::max(0.0, std::round(-std::log2(domainSize))));
34 if (level < minLevel) level = minLevel;
35 if (maxLevel < level) level = maxLevel;
37 const uint32_t tileScale = 1<<level;
42 glm::ivec2 maxGridSizeAtLevel = glm::ivec2(1 << level);
43 glm::ivec2 minGridCell = glm::ivec2(glm::floor(
static_cast<float>(tileScale) * glm::vec2(domainMin)));
44 glm::ivec2 maxGridCell = glm::ivec2(glm::floor(
static_cast<float>(tileScale) * glm::vec2(domainMax))) + glm::ivec2(1);
45 glm::uvec2 size = glm::max(glm::ivec2(0), glm::min(maxGridSizeAtLevel, maxGridCell - minGridCell));
50 .tileScale = tileScale,
61 materialKeys.resize(slotCount);
62 for (
size_t slot = 0; slot < slotCount; slot++) {
63 const std::string indexString = std::to_string(slot);
64 materialKeys[slot].level =
"TexAtlasLevels" + indexString;
65 materialKeys[slot].floatCoeffs =
"texAtlasFloatCoeffs" + indexString;
66 materialKeys[slot].intCoeffs =
"texAtlasIntCoeffs" + indexString;
67 materialKeys[slot].tile =
"texAtlasTiles" + indexString;
68 materialKeys[slot].tree =
"texAtlasTree" + indexString;
74 if (pool.size() == 0) {
75 LOG_DEBUG(logger,
"Creating first component, creating renderer.");
76 assert(renderer ==
nullptr);
78 context->renderer->registerExtension(renderer);
80 return base::createComponent();
85 base::destroyComponent(component);
86 if (pool.size() == 0) {
87 LOG_DEBUG(logger,
"Destroying last component, destroying renderer.");
88 trackedMaterials.clear();
90 context->renderer->unregisterExtension(renderer);
99 if (pool.size() == 0)
return;
103 const uint32_t currentFrame = context->
time->getFrame();
104 const uint32_t
currentTime =
static_cast<uint32_t
>(std::floor(context->
time->getAnimationTime()));
107 bool lodFreeze = context->
variables->getOrAdd(lodFreezeName,
false);
108 renderer->renderFrustum = lodFreeze;
110 bool atlasLayoutLog = context->
variables->getOrAdd(atlasLayoutLogName,
false);
113 const glm::vec3 p[8] = {
114 glm::vec3(-1.f, -1.f, -1.f),
115 glm::vec3( 1.f, -1.f, -1.f),
116 glm::vec3( 1.f, 1.f, -1.f),
117 glm::vec3(-1.f, 1.f, -1.f),
118 glm::vec3(-1.f, -1.f, 1.f),
119 glm::vec3( 1.f, -1.f, 1.f),
120 glm::vec3( 1.f, 1.f, 1.f),
121 glm::vec3(-1.f, 1.f, 1.f)
124 const CameraData& mainCamData = context->cameraSystem->getMainCameraData();
125 glm::mat4 PVinv = glm::inverse(mainCamData.rawViewProjection);
126 for (
size_t i = 0; i < 8; i++) {
127 renderer->frustumCorners[i] = glm::vec4(euclidean(PVinv * glm::vec4(p[i], 1.f)), 1.f);
131 for (
auto& item : trackedMaterials) {
143 texAtlasData.levels = 0;
145 if (texAtlasData.inUse) {
146 texAtlasData.inUse =
false;
148 else if (texAtlasComp.materials.empty())
continue;
150 if (4 <= texAtlasComp.index)
continue;
151 if ((texAtlasComp.domainMax.x <= texAtlasComp.domainMin.x) ||
152 (texAtlasComp.domainMax.y <= texAtlasComp.domainMin.y))
continue;
156 texAtlasComp.maxLevel = std::min(28u, texAtlasComp.maxLevel);
157 texAtlasComp.minLevel = std::min(texAtlasComp.minLevel, texAtlasComp.maxLevel);
159 geo.domain[0] = texAtlasComp.domainMin;
160 geo.domain[1] = texAtlasComp.domainMax;
161 geo.invDomainMapShift = -glm::vec2(geo.domain[0]);
162 geo.invDomainMapScale = glm::vec2(1.f) / glm::vec2(geo.domain[1] - geo.domain[0]);
165 texAtlasData.layout = getLayout(texAtlasData.geometry.domain[0],
166 texAtlasData.geometry.domain[1],
167 texAtlasComp.minLevel,
168 texAtlasComp.maxLevel);
170 texAtlasData.fetcher.datasetExtentMin = texAtlasComp.domainExtentsMin;
171 texAtlasData.fetcher.datasetExtentMax = texAtlasComp.domainExtentsMax;
173 texAtlasData.fetcher.
update(context, currentFrame,
currentTime, texAtlasComp.timeout, texAtlasComp.path);
174 texAtlasData.cache.update(currentFrame,
currentTime, texAtlasComp.minRetryDelay, std::min(texAtlasComp.maxItemCount, maxItemCount));
175 texAtlasData.tree.update(context, texAtlasData.geometry, texAtlasData.cache, texAtlasData.fetcher, texAtlasData.layout, std::max(1.f / 8192.f, texAtlasComp.tolerance), texAtlasComp.restrictBetweenNearAndFar, lodFreeze);
180 std::vector<uint16_t>& encoded = texAtlasData.tree.encoded;
181 size_t treeHashValue =
Cogs::hash(encoded.data(),
sizeof(encoded[0]) * encoded.size());
182 if (!texAtlasData.treeTex ||
183 (texAtlasData.treeTex->description.width != encoded.size()) ||
184 (texAtlasData.treeHashValue != treeHashValue))
186 texAtlasData.treeTex = context->textureManager->loadTexture(texAtlasData.tree.encoded.data(),
187 ResourceDimensions::Texture2D,
188 static_cast<int>(texAtlasData.tree.encoded.size()), 1, 1, 1,
189 TextureFormat::R16_UINT, 0, texAtlasData.treeTex,
191 texAtlasData.treeHashValue = treeHashValue;
196 if (texAtlasData.fetcher.tileWidth != 0 && texAtlasData.fetcher.tileHeight != 0) {
198 uint32_t currentSlotCount = texAtlasData.tilesTex ? texAtlasData.tilesTex->description.layers : 0;
199 uint32_t newSlotCount = currentSlotCount;
201 if (currentSlotCount < texAtlasData.cache.slots.size()) {
202 newSlotCount = std::min(texAtlasData.cache.
maxItemCount, std::max(
static_cast<uint32_t
>(texAtlasData.cache.slots.size()), (currentSlotCount * 3 + 1) / 2));
203 if (atlasLayoutLog) {
204 LOG_DEBUG(logger,
"Growing to %u tiles", newSlotCount);
208 if (texAtlasData.cache.slots.size() < currentSlotCount / 2) {
209 newSlotCount = std::max(
static_cast<uint32_t
>(1), currentSlotCount / 2);
210 if (atlasLayoutLog) {
211 LOG_DEBUG(logger,
"Shrinking to %u tiles", newSlotCount);
215 if (currentSlotCount != newSlotCount) {
217 if (texAtlasData.tilesOldTex) {
223 texAtlasData.tilesOldTex = texAtlasData.tilesTex;
225 texAtlasData.tilesTex = context->textureManager->loadTexture(
nullptr,
226 ResourceDimensions::Texture2DArray,
227 texAtlasData.fetcher.tileWidth, texAtlasData.fetcher.tileHeight, 1, newSlotCount,
233 switch (texAtlasComp.projection) {
235 if (texAtlasComp.coefficients.size() != 4)
continue;
237 for (
size_t i = 0; i < 4; i++) {
238 texAtlasData.geometry.
coefficients[i] = transformSystem->engineFromWorldCoords(glm::dvec3(texAtlasComp.coefficients[i], 0.f));
240 texAtlasData.geometry.elevationMin = transformSystem->engineFromWorldCoords(glm::dvec3(0.0, 0.0,
double(texAtlasComp.elevation))).z;
241 texAtlasData.geometry.elevationMax = transformSystem->engineFromWorldCoords(glm::dvec3(0.0, 0.0,
double(texAtlasComp.elevation))).z;
249 uint32_t tileScale = (1 << texAtlasData.layout.
level);
250 glm::vec2 gridFromUnitScale = glm::vec2(
double(tileScale) * (texAtlasData.geometry.domain[1] - texAtlasData.geometry.domain[0]));
251 glm::vec2 gridFromUnitOffset = glm::vec2(
double(tileScale) * texAtlasData.geometry.domain[0] - glm::dvec2(texAtlasData.layout.
offset));
252 texAtlasData.floatCoefficients = glm::mat4(glm::vec4(texAtlasData.geometry.
coefficients[0], texAtlasData.geometry.
coefficients[1]),
254 glm::vec4(gridFromUnitScale, gridFromUnitOffset),
255 glm::vec4(tileScale, 0.f, 0.f, 0.f));
256 texAtlasData.intCoefficients = glm::ivec4(
int(tileScale - 1u), texAtlasData.layout.
size.x, 0, 0);
257 texAtlasData.levels =
static_cast<int>(texAtlasData.layout.
maxLevel + 1 - texAtlasData.layout.
level);
259 const std::string indexString = std::to_string(texAtlasComp.index);
261 if (!handle)
continue;
263 if (texAtlasComp.index < slotCount) {
265 tracked.material = handle;
266 tracked.lastSeen = currentFrame;
267 tracked.slots[texAtlasComp.index] = &texAtlasComp;
271 if (texAtlasComp.index == 0) {
272 LOG_DEBUG(logger,
"level=%u off=[%d %d], size=[%d %d]",
273 texAtlasData.layout.
level,
274 texAtlasData.layout.
offset.x,
275 texAtlasData.layout.
offset.y,
276 texAtlasData.layout.
size.x,
277 texAtlasData.layout.
size.y);
285 for (
auto& item : trackedMaterials) {
290 for (
size_t slotIndex = 0; slotIndex < slotCount; slotIndex++) {
293 if (
TexAtlasComponent* texAtlasComp = trackedMaterial.slots[slotIndex]; texAtlasComp) {
296 mat->setVariant(keys.level, texAtlasData.levels);
298 if (
VariableKey transformKey = mat->getMat4Key(keys.floatCoeffs); transformKey != NoProperty) {
302 if (
VariableKey key = mat->getInt4Key(keys.intCoeffs); key != NoProperty) {
306 if (
VariableKey key = mat->getTextureKey(keys.tile); key != NoProperty) {
312 if (
VariableKey key = mat->getTextureKey(keys.tree); key != NoProperty) {
320 mat->setVariant(keys.level, 0);
326 std::erase_if(trackedMaterials, [currentFrame](
auto& item) {
return item.second.lastSeen != currentFrame; });
Context * context
Pointer to the Context instance the system lives in.
virtual void initialize(Context *context)
Initialize the system.
void update()
Updates the system state to that of the current frame.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class IRenderer * renderer
Renderer.
std::unique_ptr< class Variables > variables
Variables service instance.
std::unique_ptr< class Time > time
Time service instance.
virtual IGraphicsDevice * getDevice()=0
Get the graphics device used by the renderer.
virtual ICapabilities * getCapabilities()=0
Get a pointer to the capability management interface used to query the graphics device capability fla...
Log implementation class.
Provides a weakly referenced view over the contents of a string.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
@ RenderTarget
Set the usage flag of the texture to RenderTarget.
@ NoMipMaps
Do not generate mipmaps.
@ ForceSynchronous
Force loading the resource synchronously.
uint16_t VariableKey
Used to lookup material properties.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
COGSFOUNDATION_API Time currentTime()
High resolution clock time (NTP / UTC time). Returns an implementation defined absolute timestamp,...
Handle to a Component instance.
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
Material resources define the how of geometry rendering (the what is defined by Mesh and Texture reso...
void setMat4Property(const VariableKey key, glm::mat4 value)
Set the mat4 property with the given key to value.
void setTextureFilterMode(const VariableKey key, SamplerState::FilterMode filterMode)
Set filtermode used for the texture property.
void setInt4Property(const VariableKey key, glm::ivec4 value)
Set the ivec4 property with the given key to value.
void setTextureProperty(const VariableKey key, TextureHandle value)
Set the texture property with the given key to the texture resource held by value.
void setTextureAddressMode(const VariableKey key, SamplerState::AddressMode mode)
Set the address mode used for the texture property with the given key to mode.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
void destroyComponent(ComponentHandle component) override
void initialize(Context *context) override
Initialize the system.
ComponentHandle createComponent() override
uint32_t maxItemCount
Number of tiles in cache.
void update(Context *context, uint32_t currentFrame, uint32_t currentTime, uint32_t timeout, std::string_view urlTemplate)
void processLoadQueue(Context *context, Cache &cache)
glm::vec2 coefficients[4]
Coefficients wrt engine origin.
uint32_t level
Base level.
uint32_t maxLevel
Maximum level.
glm::uvec2 size
Size of grid.
glm::ivec2 offset
Indices of the grid cell with smallest indices.
uint32_t MaxTextureArrayLayers
Using D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION as default.
virtual const GraphicsDeviceCapabilities & getDeviceCapabilities() const
Gets the device capabilities in a structure.
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
@ MinMagMipPoint
Point sampling for both minification and magnification.
@ MinMagMipLinear
Linear sampling for both minification and magnification.