3#include "Foundation/Logging/Logger.h"
4#include "Foundation/Platform/IO.h"
6#include "Services/Variables.h"
8#include "Resources/TextureManager.h"
10#include "TexAtlasSystem.h"
14 using namespace Cogs::Core::TexAtlas;
23 fetcher.urlBuilder.clear();
24 const std::string_view url(fetcher.url);
29 next = fetcher.url.find(
'{', next);
30 if (next == std::string_view::npos) {
31 if (done < url.length()) {
32 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertChars, url.substr(done) });
37 if (next + 3 <= url.length()) {
38 const std::string_view token = url.substr(next + 1, 2);
41 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertChars, url.substr(done, next - done) });
43 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertX, std::string_view() });
44 done = next = next + 3;
47 else if (token ==
"y}") {
49 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertChars, url.substr(done, next - done) });
51 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertY, std::string_view() });
52 done = next = next + 3;
55 else if (token ==
"z}") {
57 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertChars, url.substr(done, next - done) });
59 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertZ, std::string_view() });
60 done = next = next + 3;
64 if (next + 6 <= url.length()) {
65 const std::string_view token = url.substr(next + 1, 5);
66 if (token ==
"xmin}") {
68 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertChars, url.substr(done, next - done) });
70 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertXMin, std::string_view() });
71 done = next = next + 6;
74 else if (token ==
"xmax}") {
76 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertChars, url.substr(done, next - done) });
78 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertXMax, std::string_view() });
79 done = next = next + 6;
82 else if (token ==
"ymin}") {
84 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertChars, url.substr(done, next - done) });
86 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertYMin, std::string_view() });
87 done = next = next + 6;
90 else if (token ==
"ymax}") {
92 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertChars, url.substr(done, next - done) });
94 fetcher.urlBuilder.push_back(
Fetcher::UrlBuilderOp{ Fetcher::UrlBuilderOp::Kind::InsertYMax, std::string_view() });
95 done = next = next + 6;
103 if (context->
variables->getOrAdd(urlTemplateLogName,
false)) {
104 LOG_DEBUG(logger,
"UrlBuilder has %zu steps:", fetcher.urlBuilder.size());
107 case Fetcher::UrlBuilderOp::Kind::InsertChars:
108 LOG_DEBUG(logger,
"-> Insert chars '%.*s'",
static_cast<int>(item.chars.size()), item.chars.data());
110 case Fetcher::UrlBuilderOp::Kind::InsertX:
111 LOG_DEBUG(logger,
"-> Insert X");
113 case Fetcher::UrlBuilderOp::Kind::InsertY:
114 LOG_DEBUG(logger,
"-> Insert Y");
116 case Fetcher::UrlBuilderOp::Kind::InsertZ:
117 LOG_DEBUG(logger,
"-> Insert Z");
119 case Fetcher::UrlBuilderOp::Kind::InsertXMin:
120 LOG_DEBUG(logger,
"-> Insert XMIN");
122 case Fetcher::UrlBuilderOp::Kind::InsertXMax:
123 LOG_DEBUG(logger,
"-> Insert XMAX");
125 case Fetcher::UrlBuilderOp::Kind::InsertYMin:
126 LOG_DEBUG(logger,
"-> Insert YMIN");
128 case Fetcher::UrlBuilderOp::Kind::InsertYMax:
129 LOG_DEBUG(logger,
"-> Insert YMAX");
139 std::string getExtentValueForTile(
Fetcher& fetcher,
const glm::uvec3& tileId, Fetcher::UrlBuilderOp::Kind kind)
141 double extentValue = -1;
145 case Fetcher::UrlBuilderOp::Kind::InsertXMin:
146 width = (fetcher.datasetExtentMax.x - fetcher.datasetExtentMin.x) / (1 << tileId.z);
147 extentValue = fetcher.datasetExtentMin.x + width * tileId.x;
149 case Fetcher::UrlBuilderOp::Kind::InsertXMax:
150 width = (fetcher.datasetExtentMax.x - fetcher.datasetExtentMin.x) / (1 << tileId.z);
151 extentValue = fetcher.datasetExtentMin.x + width * (tileId.x + 1);
153 case Fetcher::UrlBuilderOp::Kind::InsertYMin:
154 height = (fetcher.datasetExtentMax.y - fetcher.datasetExtentMin.y) / (1 << tileId.z);
155 extentValue = fetcher.datasetExtentMax.y - height * (tileId.y + 1);
157 case Fetcher::UrlBuilderOp::Kind::InsertYMax:
158 height = (fetcher.datasetExtentMax.y - fetcher.datasetExtentMin.y) / (1 << tileId.z);
159 extentValue = fetcher.datasetExtentMax.y - height * tileId.y;
166 return std::to_string(extentValue);
169 void interpretUrlTemplate(
Fetcher& fetcher, std::string& out,
const glm::uvec3& tileId)
174 case Fetcher::UrlBuilderOp::Kind::InsertChars:
175 out.append(item.chars);
177 case Fetcher::UrlBuilderOp::Kind::InsertX:
178 out.append(std::to_string(tileId.x));
180 case Fetcher::UrlBuilderOp::Kind::InsertY:
181 out.append(std::to_string(tileId.y));
183 case Fetcher::UrlBuilderOp::Kind::InsertZ:
184 out.append(std::to_string(tileId.z));
186 case Fetcher::UrlBuilderOp::Kind::InsertXMin:
187 out.append(getExtentValueForTile(fetcher, tileId, item.kind));
189 case Fetcher::UrlBuilderOp::Kind::InsertYMin:
190 out.append(getExtentValueForTile(fetcher, tileId, item.kind));
192 case Fetcher::UrlBuilderOp::Kind::InsertXMax:
193 out.append(getExtentValueForTile(fetcher, tileId, item.kind));
195 case Fetcher::UrlBuilderOp::Kind::InsertYMax:
196 out.append(getExtentValueForTile(fetcher, tileId, item.kind));
210 compileUrlTemplate(context, *
this);
213 currentFrame = currentFrame_;
214 currentTime = currentTime_;
223 for (
LoadItem& loadItem : loading) {
224 if (
auto it = cache.tree.find(loadItem.treeIx); it != cache.tree.end()) {
225 SlotIx slotIx = it->second;
226 if (loadItem.slotIx == slotIx) {
227 assert(slotIx < cache.slots.size());
231 if (slot.treePos != loadItem.treeIx) {
232 context->textureManager->cancelTextureLoad(loadItem.texture);
233 LOG_DEBUG(logger,
"Cancelling recycled load item");
238 if (loadItem.texture->isResident()) {
240 const uint32_t w = loadItem.texture->description.width;
241 const uint32_t h = loadItem.texture->description.height;
243 if (w == 0 || h == 0) {
244 cache.setStateFailed(slot);
245 LOG_DEBUG(logger,
"Invalid texture size [%u, %u]", w, h);
249 if (tileWidth == 0 || tileHeight == 0) {
252 if (context->
variables->getOrAdd(atlasLayoutLogName,
false)) {
253 LOG_DEBUG(logger,
"First tile received, setting tileSize=[%u,%u]", tileWidth, tileHeight);
257 if (tileWidth != w || tileHeight != h) {
258 LOG_DEBUG(logger,
"Invalid texture size [%u, %u], expected [%u, %u]", w, h, tileWidth, tileHeight);
262 cache.setStateLoaded(slot);
263 loaded.emplace_back(std::move(loadItem));
268 if (loadItem.texture->hasFailedLoad()) {
269 cache.setStateFailed(slot);
270 LOG_DEBUG(logger,
"Failed load item");
275 uint32_t framesSinceLastNeeded = currentFrame - slot.lastTouched;
276 if (10 < framesSinceLastNeeded) {
277 context->textureManager->cancelTextureLoad(loadItem.texture);
278 cache.setStateCancelled(slot);
284 uint32_t timeSinceIssue =
currentTime - slot.stateChangeTime;
285 if (timeout <= timeSinceIssue) {
286 context->textureManager->cancelTextureLoad(loadItem.texture);
287 cache.setStateFailed(slot);
288 LOG_DEBUG(logger,
"Fetch tiled out, set as failed.");
294 tmp.emplace_back(std::move(loadItem));
298 loading = std::move(tmp);
303 return (issuedThisFrame < maxIssuesPerFrame) && (loading.size() < maxQueueSize);
309 uint8_t digitGlyps[11][8][8] = {
311 { 0, 1, 1, 1, 1, 1, 0, 0 },
312 { 1, 1, 0, 0, 0, 1, 1, 0 },
313 { 1, 1, 0, 0, 0, 1, 1, 0 },
314 { 1, 1, 0, 0, 0, 1, 1, 0 },
315 { 1, 1, 0, 0, 0, 1, 1, 0 },
316 { 1, 1, 0, 0, 0, 1, 1, 0 },
317 { 0, 1, 1, 1, 1, 1, 0, 0 },
318 { 0, 0, 0, 0, 0, 0, 0, 0 }
321 { 0, 0, 0, 0, 1, 0, 0, 0 },
322 { 0, 0, 0, 1, 1, 0, 0, 0 },
323 { 0, 0, 1, 1, 1, 0, 0, 0 },
324 { 0, 0, 0, 1, 1, 0, 0, 0 },
325 { 0, 0, 0, 1, 1, 0, 0, 0 },
326 { 0, 0, 0, 1, 1, 0, 0, 0 },
327 { 0, 0, 1, 1, 1, 1, 0, 0 },
328 { 0, 0, 0, 0, 0, 0, 0, 0 }
331 { 0, 1, 1, 1, 1, 1, 0, 0 },
332 { 1, 1, 0, 0, 0, 1, 1, 0 },
333 { 0, 0, 0, 0, 0, 1, 1, 0 },
334 { 0, 1, 1, 1, 1, 1, 0, 0 },
335 { 1, 1, 0, 0, 0, 0, 0, 0 },
336 { 1, 1, 0, 0, 0, 1, 1, 0 },
337 { 1, 1, 1, 1, 1, 1, 1, 0 },
338 { 0, 0, 0, 0, 0, 0, 0, 0 }
341 { 0, 1, 1, 1, 1, 1, 0, 0 },
342 { 1, 1, 0, 0, 0, 1, 1, 0 },
343 { 0, 0, 0, 0, 0, 1, 1, 0 },
344 { 0, 1, 1, 1, 1, 1, 0, 0 },
345 { 0, 0, 0, 0, 0, 1, 1, 0 },
346 { 1, 1, 0, 0, 0, 1, 1, 0 },
347 { 0, 1, 1, 1, 1, 1, 0, 0 },
348 { 0, 0, 0, 0, 0, 0, 0, 0 }
351 { 1, 1, 0, 0, 0, 1, 1, 0 },
352 { 1, 1, 0, 0, 0, 1, 1, 0 },
353 { 1, 1, 0, 0, 0, 1, 1, 0 },
354 { 1, 1, 1, 1, 1, 1, 1, 0 },
355 { 0, 0, 0, 0, 0, 1, 1, 0 },
356 { 0, 0, 0, 0, 0, 1, 1, 0 },
357 { 0, 0, 0, 0, 0, 1, 1, 0 },
358 { 0, 0, 0, 0, 0, 0, 0, 0 }
361 { 1, 1, 1, 1, 1, 1, 1, 0 },
362 { 1, 1, 0, 0, 0, 1, 1, 0 },
363 { 1, 1, 0, 0, 0, 0, 0, 0 },
364 { 1, 1, 1, 1, 1, 1, 0, 0 },
365 { 0, 0, 0, 0, 0, 1, 1, 0 },
366 { 1, 1, 0, 0, 0, 1, 1, 0 },
367 { 0, 1, 1, 1, 1, 1, 0, 0 },
368 { 0, 0, 0, 0, 0, 0, 0, 0 }
371 { 0, 1, 1, 1, 1, 1, 0, 0 },
372 { 1, 1, 0, 0, 0, 1, 1, 0 },
373 { 1, 1, 0, 0, 0, 0, 0, 0 },
374 { 1, 1, 1, 1, 1, 1, 0, 0 },
375 { 1, 1, 0, 0, 0, 1, 1, 0 },
376 { 1, 1, 0, 0, 0, 1, 1, 0 },
377 { 0, 1, 1, 1, 1, 1, 0, 0 },
378 { 0, 0, 0, 0, 0, 0, 0, 0 }
381 { 1, 1, 1, 1, 1, 1, 1, 0 },
382 { 1, 1, 0, 0, 0, 1, 1, 0 },
383 { 0, 0, 0, 0, 0, 1, 1, 0 },
384 { 0, 0, 0, 0, 1, 1, 0, 0 },
385 { 0, 0, 0, 1, 1, 0, 0, 0 },
386 { 0, 0, 0, 1, 1, 0, 0, 0 },
387 { 0, 0, 0, 1, 1, 0, 0, 0 },
388 { 0, 0, 0, 0, 0, 0, 0, 0 }
391 { 0, 1, 1, 1, 1, 1, 0, 0 },
392 { 1, 1, 0, 0, 0, 1, 1, 0 },
393 { 1, 1, 0, 0, 0, 1, 1, 0 },
394 { 0, 1, 1, 1, 1, 1, 0, 0 },
395 { 1, 1, 0, 0, 0, 1, 1, 0 },
396 { 1, 1, 0, 0, 0, 1, 1, 0 },
397 { 0, 1, 1, 1, 1, 1, 0, 0 },
398 { 0, 0, 0, 0, 0, 0, 0, 0 }
401 { 0, 1, 1, 1, 1, 1, 0, 0 },
402 { 1, 1, 0, 0, 0, 1, 1, 0 },
403 { 1, 1, 0, 0, 0, 1, 1, 0 },
404 { 0, 1, 1, 1, 1, 1, 1, 0 },
405 { 0, 0, 0, 0, 0, 1, 1, 0 },
406 { 1, 1, 0, 0, 0, 1, 1, 0 },
407 { 0, 1, 1, 1, 1, 1, 0, 0 },
408 { 0, 0, 0, 0, 0, 0, 0, 0 }
411 { 0, 0, 0, 0, 0, 0, 0, 0 },
412 { 0, 0, 0, 0, 0, 0, 0, 0 },
413 { 0, 0, 0, 0, 0, 0, 0, 0 },
414 { 0, 1, 1, 1, 1, 1, 1, 0 },
415 { 0, 0, 0, 0, 0, 0, 0, 0 },
416 { 0, 0, 0, 0, 0, 0, 0, 0 },
417 { 0, 0, 0, 0, 0, 0, 0, 0 },
418 { 0, 0, 0, 0, 0, 0, 0, 0 }
422 void emitDigit(std::vector<uint8_t>& buf,
size_t& x,
size_t& y, uint32_t digit)
424 for (
size_t j = 0; j < 8; j++) {
425 for (
size_t i = 0; i < 8; i++) {
426 buf[4 * (256 * (y + j) + (x + i))] = digitGlyps[digit][j][i] ? 255 : 0;
432 void emitNumber(std::vector<uint8_t>& buf,
size_t& x,
size_t& y, uint32_t number)
435 std::vector<uint32_t> digits;
437 digits.push_back(number % 10);
438 number = number / 10;
441 for (
size_t i = digits.size(); i; i--) {
442 emitDigit(buf, x, y, digits[i - 1]);
451 const glm::uvec3& tileId,
455 assert(slotIx != NoSlotIx);
456 assert(treeIx != NoTreeIx);
460 interpretUrlTemplate(*
this, path, tileId);
464 for (
const LoadItem& item : loading) {
465 if (item.treeIx == treeIx) {
466 LOG_WARNING(logger,
"Tree index %" PRIu64
" lluu is already loading(%s)", treeIx, path.c_str());
472 LoadItem& loadItem = loading.emplace_back();
473 loadItem.pathHash = pathHash;
475 if (!path.starts_with(
"http") && !Cogs::IO::exists(path)) {
479 std::vector<uint8_t> moo(256 * 256 * 4, 0);
482 emitNumber(moo, x, y, tileId.z);
483 emitDigit(moo, x, y, 10);
484 emitNumber(moo, x, y, tileId.x);
485 emitDigit(moo, x, y, 10);
486 emitNumber(moo, x, y, tileId.y);
492 loadItem.treeIx = treeIx;
493 loadItem.slotIx = slotIx;
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class Variables > variables
Variables service instance.
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....
@ NoMipMaps
Do not generate mipmaps.
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,...
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
void issueFetch(Context *context, const glm::uvec3 &tileId, TreeIx treeIx, SlotIx slotIx)
void update(Context *context, uint32_t currentFrame, uint32_t currentTime, uint32_t timeout, std::string_view urlTemplate)
void processLoadQueue(Context *context, Cache &cache)