1#include "OGC3DTilesTileset.h"
6#include <Foundation/Logging/Logger.h>
7#include <Serialization/JsonParser.h>
9#include <glm/gtc/type_ptr.hpp>
20using namespace Cogs::Core::OGC3DTilesTileset;
23parseBoundingVolumeJSON(
const Value& value)
26 bv.type = OGC3DTiles::BoundingVolumeType::UNKNOWN;
28 if (!value.IsObject()) {
29 LOG_ERROR(logger,
"The 'BoundingVolume' object cannot be an array.");
33 for (Value::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
34 std::string key = std::string(itr->name.GetString());
36 if (key !=
"extensions" && !itr->value.IsArray()) {
37 LOG_ERROR(logger,
"Value of boundingVolume box/region/sphere is not an array (key=%s)", key.c_str());
43 auto array = itr->value.GetArray();
44 if (array.Size() != 12) {
45 LOG_ERROR(logger,
"Bounding volume box array does not contain 12 elements");
48 bv.type = OGC3DTiles::BoundingVolumeType::BOX;
49 for (
auto& v : array) {
50 bv.values[i++] = v.GetDouble();
53 else if (key ==
"region") {
54 bv.type = OGC3DTiles::BoundingVolumeType::REGION;
55 auto array = itr->value.GetArray();
56 if (array.Size() != 6) {
57 LOG_ERROR(logger,
"Bounding volume region array does not contain 6 elements");
60 for (
auto& v : array) {
61 bv.values[i++] = v.GetDouble();
64 else if (key ==
"sphere") {
65 bv.type = OGC3DTiles::BoundingVolumeType::SPHERE;
66 auto array = itr->value.GetArray();
67 if (array.Size() != 4) {
68 LOG_ERROR(logger,
"Bounding volume sphere array does not contain 4 elements");
71 for (
auto& v : array) {
72 bv.values[i++] = v.GetDouble();
75 else if (key ==
"extensions" || key ==
"extras") {
80 LOG_WARNING(logger,
"Unknown BoundingVolume type: '%s'", key.c_str());
88parseContentJSON(
const Value& value)
91 if (!value.IsObject()) {
92 LOG_ERROR(logger,
"The 'Content' object cannot be an array.");
96 for (Value::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
97 std::string key = std::string(itr->name.GetString());
99 if (!itr->value.IsString()) {
100 LOG_ERROR(logger,
"The member 'uri' is not a string");
103 content.URI = std::string(itr->value.GetString());
105 else if (key ==
"group") {
106 if (!itr->value.IsString()) {
107 LOG_ERROR(logger,
"The member 'group' is not an integer");
110 content.group = itr->value.GetInt();
125parseImplicitTilingJSON(
const Value& value)
128 if (!value.IsObject()) {
129 LOG_ERROR(logger,
"The 'ImplicitTiling' object cannot be an array.");
130 return implicitTiling;
133 for (Value::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
134 std::string key = std::string(itr->name.GetString());
135 if (key ==
"subdivisionScheme") {
136 if (!itr->value.IsString()) {
137 LOG_ERROR(logger,
"The member 'subdivisionScheme' is not a string");
140 implicitTiling.isOctTree = std::string(itr->value.GetString()) ==
"OCTREE";
142 else if (key ==
"availableLevels") {
143 if (!itr->value.IsInt()) {
144 LOG_ERROR(logger,
"The member 'availableLevels' is not an integer");
147 implicitTiling.availableLevels = (uint8_t)itr->value.GetInt();
151 if (implicitTiling.availableLevels > 15) {
156 LOG_WARNING(logger,
"The number of levels is %d. When the depth exceeds 15 there might be issues with the indexing.",
157 implicitTiling.availableLevels);
160 else if (key ==
"subtreeLevels") {
161 if (!itr->value.IsInt()) {
162 LOG_ERROR(logger,
"The member 'subtreeLevels' is not an integer");
165 implicitTiling.subtreeLevels = (uint8_t)itr->value.GetInt();
167 else if (key ==
"subtrees") {
168 if (!itr->value[
"uri"].IsString()) {
169 LOG_ERROR(logger,
"The member 'uri' is not a string");
172 implicitTiling.subTreeURLScheme = itr->value[
"uri"].GetString();
176 return implicitTiling;
183parseContentsJSON(
const Value& value)
185 std::vector<Content> contents;
187 if (!value.IsArray()) {
188 LOG_ERROR(logger,
"The 'Contents' object must be an array.");
192 auto array = value.GetArray();
193 contents.reserve(array.Size());
195 for (
auto& c : array) {
196 contents.emplace_back(parseContentJSON(c));
203parseTileJSON(
const Value& value)
206 tile.transform = glm::identity<glm::dmat4>();
207 tile.useImplicitTiling =
false;
209 if (!value.IsObject()) {
210 LOG_ERROR(logger,
"The 'Tile' object cannot be an array.");
214 for (Value::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
215 std::string key = std::string(itr->name.GetString());
216 if (key ==
"geometricError") {
217 tile.geometricError =
static_cast<float>(itr->value.GetDouble());
219 else if (key ==
"refine") {
220 tile.refine = std::string(itr->value.GetString()) ==
"ADD" ? RefineType::ADD : RefineType::REPLACE;
222 else if (key ==
"transform") {
223 auto array = itr->value.GetArray();
225 if (array.Size() != 16) {
226 LOG_ERROR(logger,
"Transform matrix array does not contain 16 elements");
232 for (
auto& v : array) {
233 tmp[i++] = v.GetDouble();
236 tile.transform = glm::make_mat4(tmp);
238 else if (key ==
"boundingVolume") {
239 tile.boundingVolume = parseBoundingVolumeJSON(value[
"boundingVolume"]);
241 else if (key ==
"content") {
242 tile.contents.emplace_back(parseContentJSON(value[
"content"]));
244 else if (key ==
"contents") {
246 std::vector<Content> contents = parseContentsJSON(value[
"contents"]);
247 tile.contents.reserve(tile.contents.size() + contents.size());
249 tile.contents.emplace_back(c);
252 else if (key ==
"children") {
253 if (!itr->value.IsArray()) {
254 LOG_ERROR(logger,
"The 'children' object must be an array.");
258 auto array = itr->value.GetArray();
259 tile.children.reserve(array.Size());
260 for (Value::ConstValueIterator itr2 = array.Begin(); itr2 != array.End(); ++itr2) {
261 Tile childTile = parseTileJSON(*itr2);
262 if (childTile.refine == RefineType::DEFAULT) {
263 childTile.refine = tile.refine;
265 tile.children.emplace_back(childTile);
268 else if (key ==
"implicitTiling") {
269 tile.useImplicitTiling =
true;
270 tile.implicitTiling = parseImplicitTilingJSON(value[
"implicitTiling"]);
271 LOG_DEBUG(logger,
"Tileset uses implicit tiling (%s)", tile.implicitTiling.isOctTree ?
"octtree" :
"quadtree");
283parseJSON(std::string_view json,
Tileset* tileset)
285 Document doc = parseJson(json, JsonParseFlags::None);
287 if (doc.HasMember(
"asset")) {
288 GenericObject asset = doc[
"asset"].GetObject();
289 tileset->version = asset[
"version"].GetString();
291 if (tileset->version ==
"1.0") {
292 LOG_WARNING(logger,
"Tileset is version 1.0 which is not fully tested. Upgrade to 1.1 if possible");
295 if (asset.HasMember(
"gltfUpAxis")) {
296 LOG_WARNING(logger,
"Tileset is using the unofficial/unsupported 'gltfUpAxis' setting ('gltfUpAxis'=%s).", asset[
"gltfUpAxis"].GetString());
300 LOG_ERROR(logger,
"No geometricError asset in tileset");
304 if (doc.HasMember(
"root")) {
305 tileset->root = parseTileJSON(doc[
"root"].GetObject());
308 LOG_ERROR(logger,
"No root attribute in tileset");
312 tileset->geometricError = 0.0;
313 if (doc.HasMember(
"geometricError")) {
314 tileset->geometricError = doc[
"geometricError"].GetFloat();
324Cogs::Core::DataFetcherManager::FetchId
325OGC3DTilesTileset::fetch(
Context* context,
const std::string& URL, FetchCallback callback)
327 LOG_INFO(logger,
"Fetching tileset: '%s'", URL.c_str());
328 Cogs::Core::DataFetcherManager::FetchId fetchId = DataFetcherManager::fetchAsync(context, URL,
329 [context, callback, URL](std::unique_ptr<Cogs::FileContents> data) {
333 Cogs::Memory::MemoryBuffer contentsBuff = data->take();
334 std::string_view jsonStr = std::string_view(static_cast<const char*>(contentsBuff.data()), contentsBuff.size());
336 tileset = new Tileset;
337 bool ok = parseJSON(jsonStr, tileset);
339 LOG_ERROR(logger,
"Error parsing tileset");
345 LOG_ERROR(logger,
"Error fetching tileset from '%s'", URL.c_str());
348 auto finishTask = [callback, tileset]() {
352#if defined(EMSCRIPTEN)
357 context->
engine->runTaskInMainThread(std::move(finishTask));
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class Engine > engine
Engine instance.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept