1#include "Serialization/JsonParser.h"
2#include "PotreeSystem.h"
4#include "Foundation/Logging/Logger.h"
5#include "Foundation/Platform/IO.h"
11 bool parseStringMemberNoLog(
const char*& value, rapidjson::Value& item,
const char* name)
13 if (
auto it = item.FindMember(name); it != item.MemberEnd() && it->value.IsString()) {
14 value = it->value.GetString();
20 bool parseUIntMemberNoLog(
unsigned& value, rapidjson::Value& item,
const char* name)
22 if (
auto it = item.FindMember(name); it != item.MemberEnd() && it->value.IsUint()) {
23 value = it->value.GetUint();
29 bool parseFloatMemberNoLog(
float& value, rapidjson::Value& item,
const char* name)
31 if (
auto it = item.FindMember(name); it != item.MemberEnd() && it->value.IsNumber()) {
32 value = it->value.GetFloat();
38 bool parseVec3NoLog(glm::vec3& value, rapidjson::Value& item,
const char* name)
40 if (
auto kt = item.FindMember(name); kt != item.MemberEnd()) {
41 if (!kt->value.IsArray()) {
return false; }
42 auto arr = kt->value.GetArray();
43 if (arr.Size() != 3) {
return false; }
44 for (
int i = 0; i < 3; i++) {
45 if (!arr[i].IsNumber()) {
return false; }
46 value[i] = arr[i].GetFloat();
53 bool parseVec3NoLog(glm::dvec3& value, rapidjson::Value& item,
const char* name)
55 if (
auto kt = item.FindMember(name); kt != item.MemberEnd()) {
56 if (!kt->value.IsArray()) {
return false; }
57 auto arr = kt->value.GetArray();
58 if (arr.Size() != 3) {
return false; }
59 for (
int i = 0; i < 3; i++) {
60 if (!arr[i].IsNumber()) {
return false; }
61 value[i] = arr[i].GetDouble();
68 bool parseBBox(
PotreeData* poData, glm::dvec3& bbmin, glm::dvec3& bbmax, Document& doc,
const std::string& name, uint32_t instanceId)
70 if (
auto jt = doc.FindMember(name.c_str()); jt != doc.MemberEnd()) {
71 if (jt->value.IsObject()) {
72 auto& parent = jt->value;
73 if (poData->versionMajor == 1) {
74 struct {
double* dst;
const char* name; }
76 {&bbmin.x,
"lx"}, {&bbmin.y,
"ly"},{&bbmin.z,
"lz"},
77 {&bbmax.x,
"ux"}, {&bbmax.y,
"uy"},{&bbmax.z,
"uz"},
79 for (
auto& component : components) {
80 if (
auto it = parent.FindMember(component.name); it != parent.MemberEnd() && it->value.IsNumber()) {
81 *component.dst = it->value.GetDouble();
84 LOG_ERROR(logger,
"[instance=%u] metadata file: %s element of %s is missing or not a numbers.", instanceId, component.name, name.c_str());
90 if (!parseVec3NoLog(bbmin, parent,
"min")) {
91 LOG_ERROR(logger,
"[instance=%u] metadata file: min element of %s is missing or not an array of three numbers.", instanceId, name.c_str());
94 if (!parseVec3NoLog(bbmax, parent,
"max")) {
95 LOG_ERROR(logger,
"[instance=%u] metadata file: min element of %s is missing or not an array of three numbers.", instanceId, name.c_str());
103 LOG_ERROR(logger,
"[instance=%u] metadata file: %s is not an object", instanceId, name.c_str());
108 LOG_ERROR(logger,
"[instance=%u] metadata file: missing %s", instanceId, name.c_str());
113 bool parsePointAttributeName(PotreeAttributes& attribute,
const char* str, uint32_t instanceId)
117 attribute = PotreeAttributes::POSITION_CARTESIAN;
120 case
Cogs::hash(
"RGBA_PACKED"):
121 case
Cogs::hash(
"COLOR_PACKED"):
122 attribute = PotreeAttributes::RGBA_PACKED;
125 attribute = PotreeAttributes::RGB_U8_PACKED;
128 case
Cogs::hash(
"NORMAL_FLOATS"):
129 attribute = PotreeAttributes::NORMAL;
132 attribute = PotreeAttributes::NORMAL_SPHEREMAPPED;
135 attribute = PotreeAttributes::NORMAL_OCT16;
138 case
Cogs::hash(
"intensity"):
139 attribute = PotreeAttributes::INTENSITY_U16;
142 attribute = PotreeAttributes::CLASSIFICATION;
145 attribute = PotreeAttributes::FILLER_1B;
148 LOG_WARNING(logger,
"[instance=%u] metadata file: unrecoginzed element name %s", instanceId, str);
154 bool parseAttributeItem17(
PotreeData* poData, PotreeAttributes& attribute,
unsigned& skipbytes, rapidjson::Value& item, uint32_t instanceId)
156 assert(poData->versionMajor == 1 && poData->versionMinor < 8);
158 attribute = PotreeAttributes::COUNT;
159 if (!item.IsString()) {
160 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttributes element is not a string", instanceId);
163 if (!parsePointAttributeName(attribute, item.GetString(), instanceId))
return false;
164 assert(attribute < PotreeAttributes::COUNT);
168 bool parseAttributeItem18(
PotreeData* poData, PotreeAttributes& attribute,
unsigned& skipbytes, rapidjson::Value& item, uint32_t instanceId)
170 assert(poData->versionMajor == 1 && 8 <= poData->versionMinor);
172 attribute = PotreeAttributes::COUNT;
174 if (!item.IsObject()) {
175 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttributes element is not an object", instanceId);
179 const char* name =
nullptr;
180 if (
auto nn = item.FindMember(
"name"); nn != item.MemberEnd()) {
181 if (nn->value.IsString()) {
182 name = nn->value.GetString();
183 if (!parsePointAttributeName(attribute, name, instanceId)) {
186 if (
auto it = item.FindMember(
"size"); it != item.MemberEnd()) {
187 if (it->value.IsUint()) {
188 skipbytes = it->value.GetUint();
196 LOG_ERROR(logger,
"[instance=%u] metadata file: attribute name field is not a string", instanceId);
201 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttribute element missing name", instanceId);
212 {
"elements", 0,
false},
213 {
"elementSize", 0,
false},
217 case PotreeAttributes::POSITION_CARTESIAN: expected[1].value = 3; expected[2].value = 4; expected[3].value =
Cogs::hash(
"int32");
break;
218 case PotreeAttributes::RGBA_PACKED: expected[1].value = 4; expected[2].value = 1; expected[3].value =
Cogs::hash(
"uint8");
break;
219 case PotreeAttributes::RGB_U8_PACKED: expected[1].value = 3; expected[2].value = 1; expected[3].value =
Cogs::hash(
"uint8");
break;
220 case PotreeAttributes::NORMAL: expected[1].value = 3; expected[2].value = 4; expected[3].value =
Cogs::hash(
"float");
break;
221 case PotreeAttributes::NORMAL_SPHEREMAPPED: expected[1].value = 2; expected[2].value = 1; expected[3].value =
Cogs::hash(
"uint8");
break;
222 case PotreeAttributes::NORMAL_OCT16: expected[1].value = 2; expected[2].value = 1; expected[3].value =
Cogs::hash(
"uint8");
break;
223 case PotreeAttributes::INTENSITY_U16: expected[1].value = 1; expected[2].value = 2; expected[3].value =
Cogs::hash(
"uint16");
break;
224 case PotreeAttributes::CLASSIFICATION: expected[1].value = 1; expected[2].value = 1; expected[3].value =
Cogs::hash(
"uint8");
break;
225 case PotreeAttributes::FILLER_1B: expected[1].value = 1; expected[2].value = 1; expected[3].value =
Cogs::hash(
"uint8");
break;
227 assert(
false &&
"Unhandled attribute enum value");
230 expected[0].value = expected[1].value * expected[2].value;
231 for (
const auto& e : expected) {
232 if (
auto spec = item.FindMember(e.key); spec != item.MemberEnd()) {
234 if (spec->value.IsString()) {
236 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttribute %s %s: unexpected type %s", instanceId, name, e.key, spec->value.GetString());
241 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttribute %s %s is not a string", instanceId, name, e.key);
246 if (spec->value.IsUint()) {
247 if (spec->value.GetUint() != e.value) {
248 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttribute %s %s: expected %u, got %u", instanceId, name, e.key,
unsigned(e.value), spec->value.GetUint());
253 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttribute %s %s is not an unsigned number", instanceId, name, e.key);
259 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttribute %s missing %s", instanceId, name, e.key);
264 assert(attribute < PotreeAttributes::COUNT);
269 bool parseAttributeItem20(
PotreeData* poData, PotreeAttributes& attribute,
unsigned& skipbytes, rapidjson::Value& item, uint32_t instanceId)
271 assert(poData->versionMajor == 2);
274 attribute = PotreeAttributes::COUNT;
275 if (!item.IsObject()) {
276 LOG_ERROR(logger,
"[instance=%u] metadata file: pointAttributes element is not an object", instanceId);
280 const char* name =
nullptr;
281 if (!parseStringMemberNoLog(name, item,
"name")) {
282 LOG_ERROR(logger,
"[instance=%u] metadata file: missing or malformed name element in attribute list", instanceId);
287 if (!parseUIntMemberNoLog(size, item,
"size")) {
288 LOG_ERROR(logger,
"[instance=%u] metadata file: missing or malformed size element in attribute %s", instanceId, name);
292 unsigned numElements = 0;
293 if (!parseUIntMemberNoLog(numElements, item,
"numElements")) {
294 LOG_ERROR(logger,
"[instance=%u] metadata file: missing or malformed numElements element in attribute %s", instanceId, name);
297 if (4 < numElements) {
298 LOG_ERROR(logger,
"[instance=%u] metadata file: attribute %s has %u elements, more than max supported of 4", instanceId, name, numElements);
302 PotreeeType type = PotreeeType::None;
303 unsigned typeSize = 0;
304 if (
auto it = item.FindMember(
"type"); it != item.MemberEnd() && it->value.IsString()) {
306 case Cogs::hash(
"double"): type = PotreeeType::Double; typeSize = 8;
break;
307 case Cogs::hash(
"float"): type = PotreeeType::Float; typeSize = 4;
break;
308 case Cogs::hash(
"int8"): type = PotreeeType::Int8; typeSize = 1;
break;
309 case Cogs::hash(
"uint8"): type = PotreeeType::UInt8; typeSize = 1;
break;
310 case Cogs::hash(
"int16"): type = PotreeeType::Int16; typeSize = 2;
break;
311 case Cogs::hash(
"uint16"): type = PotreeeType::UInt16; typeSize = 2;
break;
312 case Cogs::hash(
"int32"): type = PotreeeType::Int32; typeSize = 4;
break;
313 case Cogs::hash(
"uint32"): type = PotreeeType::UInt32; typeSize = 4;
break;
314 case Cogs::hash(
"int64"): type = PotreeeType::Int64; typeSize = 8;
break;
315 case Cogs::hash(
"uint64"): type = PotreeeType::UInt64; typeSize = 8;
break;
317 LOG_ERROR(logger,
"[instance=%u] metadata file: unrecognized attribute type '%s' attribute %s", instanceId, it->value.GetString(), name);
322 LOG_ERROR(logger,
"[instance=%u] metadata file: missing or malformed type element in attribute %s", instanceId, name);
326 unsigned elementSize = 0;
327 if (!parseUIntMemberNoLog(elementSize, item,
"elementSize")) {
328 LOG_ERROR(logger,
"[instance=%u] metadata file: missing or malformed elementSize element in attribute %s", instanceId, name);
331 if (typeSize != elementSize) {
332 LOG_ERROR(logger,
"[instance=%u] metadata file: mismatch type size in attribute %s, expected %u, but got %u", instanceId, name, typeSize, elementSize);
335 if (typeSize * numElements != size) {
336 LOG_ERROR(logger,
"[instance=%u] metadata file: attribute %s: unexpected element size %u, expected %u", instanceId, name, size, typeSize * numElements);
340 double attributeMin[4] = {};
341 if (
auto it = item.FindMember(
"min"); it != item.MemberEnd() && it->value.IsArray() && it->value.GetArray().Size() == numElements) {
342 for (
unsigned i = 0; i < numElements; i++) {
343 if (
auto& element = it->value.GetArray()[i]; element.IsNumber()) {
344 attributeMin[i] = element.GetDouble();
347 LOG_ERROR(logger,
"[instance=%u] metadata file: item %u in min element in attribute %s is not a number", instanceId, i, name);
353 LOG_ERROR(logger,
"[instance=%u] metadata file: missing or malformed min element in attribute %s", instanceId, name);
357 double attributeMax[4] = {};
358 if (
auto it = item.FindMember(
"max"); it != item.MemberEnd() && it->value.IsArray() && it->value.GetArray().Size() == numElements) {
359 for (
unsigned i = 0; i < numElements; i++) {
360 if (
auto& element = it->value.GetArray()[i]; element.IsNumber()) {
361 attributeMax[i] = element.GetDouble();
364 LOG_ERROR(logger,
"[instance=%u] metadata file: item %u in max element in attribute %s is not a number", instanceId, i, name);
370 LOG_ERROR(logger,
"[instance=%u] metadata file: missing or malformed max element in attribute %s", instanceId, name);
376 if (type == PotreeeType::Int32 && numElements == 3) {
377 attribute = PotreeAttributes::POSITION_CARTESIAN;
378 for (
unsigned i = 0; i < 3; i++) { poData->metadata.tbmin[i] = attributeMin[i]; }
379 for (
unsigned i = 0; i < 3; i++) { poData->metadata.tbmax[i] = attributeMax[i]; }
383 if (type == PotreeeType::UInt16 && numElements == 1) {
384 attribute = PotreeAttributes::INTENSITY_U16;
388 if (type == PotreeeType::UInt8 && numElements == 3) {
389 attribute = PotreeAttributes::RGB_U8_PACKED;
391 else if (type == PotreeeType::UInt16 && numElements == 3) {
392 attribute = PotreeAttributes::RGB_U16_PACKED;
399 if(attribute == PotreeAttributes::COUNT) {
400 LOG_WARNING(logger,
"[instance=%u] metadata file: Unrecognized attribute %s, skipping %u bytes", instanceId, name, size);
408 bool parseAttributeItem(
PotreeData* poData, PotreeAttributes& attribute,
unsigned& skipbytes, rapidjson::Value& item, uint32_t instanceId)
410 if (poData->versionMajor == 1 && poData->versionMinor < 8) {
411 return parseAttributeItem17(poData, attribute, skipbytes, item, instanceId);
413 else if (poData->versionMajor == 1) {
414 return parseAttributeItem18(poData, attribute, skipbytes, item, instanceId);
417 return parseAttributeItem20(poData, attribute, skipbytes, item, instanceId);
421 bool parsePointAttributes(
PotreeData* poData, rapidjson::Document& doc, uint32_t instanceId)
423 const char* attributeName = poData->versionMajor == 1 ?
"pointAttributes" :
"attributes";
425 if (
auto it = doc.FindMember(attributeName); it != doc.MemberEnd()) {
427 if (!it->value.IsArray()) {
428 LOG_ERROR(logger,
"[instance=%u] metadata file: %s is not an array.", instanceId, attributeName);
432 bool hasPosition =
false;
433 poData->hasColor =
false;
434 poData->hasNormal =
false;
435 poData->hasIntensity =
false;
436 poData->hasClassification =
false;
437 for (
auto& subitem : it->value.GetArray()) {
438 unsigned skipbytes = 0;
439 PotreeAttributes attribute = PotreeAttributes::COUNT;
440 if (!parseAttributeItem(poData, attribute, skipbytes, subitem, instanceId)) {
443 LOG_WARNING(logger,
"[instance=%u] Failed to parse attribute, skipping %u bytes", instanceId, skipbytes);
444 for (
unsigned i = 0; i < skipbytes; i++) {
445 poData->attributes.push_back(PotreeAttributes::FILLER_1B);
449 LOG_ERROR(logger,
"[instance=%u] Failed to parse attribute", instanceId);
455 case PotreeAttributes::POSITION_CARTESIAN:
457 LOG_ERROR(logger,
"[instance=%u] metadata file: Multiple position sources", instanceId);
462 case PotreeAttributes::RGBA_PACKED:
463 case PotreeAttributes::RGB_U8_PACKED:
464 case PotreeAttributes::RGB_U16_PACKED:
465 if (poData->hasColor) {
466 LOG_ERROR(logger,
"[instance=%u] metadata file: Multiple color sources", instanceId);
469 poData->hasColor =
true;
471 case PotreeAttributes::NORMAL:
472 poData->hasNormal =
true;
474 case PotreeAttributes::NORMAL_SPHEREMAPPED:
475 poData->hasNormal =
true;
477 case PotreeAttributes::NORMAL_OCT16:
478 poData->hasNormal =
true;
480 case PotreeAttributes::INTENSITY_U16:
481 if (poData->hasIntensity) {
482 LOG_ERROR(logger,
"[instance=%u] metadata file: Multiple intensity sources", instanceId);
485 poData->hasIntensity =
true;
487 case PotreeAttributes::CLASSIFICATION:
488 poData->hasClassification =
true;
490 case PotreeAttributes::FILLER_1B:
493 assert(
false &&
"Unhandled attribute enum value");
496 poData->attributes.push_back(attribute);
501 LOG_ERROR(logger,
"[instance=%u] metadata file: %s does not contain a position element", instanceId, attributeName);
506 poData->layout =
static_cast<PotreeVertexLayout
>((poData->hasColor ? 1 : 0) |
507 (poData->hasNormal ? 2 : 0) |
508 (poData->hasIntensity ? 4 : 0) |
509 (poData->hasClassification ? 8 : 0));
512 if (info.stride != ~0u) {
513 poData->streamsLayout.
vertexFormats[0] = Cogs::VertexFormats::createVertexFormat(info.elements.data(), info.elements.size());
518 LOG_ERROR(logger,
"[instance=%u] metadata file: Unimplemented vertex format: color=%s normal=%s intensity=%s classification=%s",
520 poData->hasColor ?
"yes" :
"no",
521 poData->hasNormal ?
"yes" :
"no",
522 poData->hasIntensity ?
"yes" :
"no",
523 poData->hasClassification ?
"yes" :
"no");
528 LOG_ERROR(logger,
"[instance=%u] metadata file: Missing %s", instanceId, attributeName);
543 Document doc = parseJson(
StringView((
const char*)data->ptr, data->size), JsonParseFlags::None);
545 if (doc.HasParseError()) {
546 LOG_ERROR(logger,
"[instance=%u] metadata file: Failed to parse JSON", poData->instanceId);
550 if (!doc.IsObject()) {
551 LOG_ERROR(logger,
"[instance=%u] metadata file: JSON root is not an object", poData->instanceId);
555 if (
auto it = doc.FindMember(
"version"); it != doc.MemberEnd()) {
556 unsigned versionMajor = 0;
557 unsigned versionMinor = 0;
558 if (it->value.IsString()) {
560 auto str_N =
static_cast<size_t>(it->value.GetStringLength());
561 auto * str = it->value.GetString();
565 for (j = i; j < str_N; j++) {
566 if (
'0' <= str[j] && str[j] <=
'9') versionMajor = 10 * versionMajor + (str[j] -
'0');
570 LOG_ERROR(logger,
"[instance=%u] metadata file: version \"%s\": missing major version number", poData->instanceId, str);
573 if (j == str_N || str[j] !=
'.') {
574 LOG_ERROR(logger,
"[instance=%u] metadata file: version \"%s\": no dot after major version number", poData->instanceId, str);
577 for (j = i; j < str_N; j++) {
578 if (
'0' <= str[j] && str[j] <=
'9') versionMinor = 10 * versionMinor + (str[j] -
'0');
582 LOG_ERROR(logger,
"[instance=%u] metadata file: version \"%s\": missing minor version number", poData->instanceId, str);
586 LOG_DEBUG(logger,
"[instance=%u] metadata file: detected version %u.%u", poData->instanceId, versionMajor, versionMinor);
587 poData->versionMajor = versionMajor;
588 poData->versionMinor = versionMinor;
591 LOG_ERROR(logger,
"[instance=%u] metadata file: version is not a string", poData->instanceId);
596 LOG_ERROR(logger,
"[instance=%u] metadata file: version is missing", poData->instanceId);
600 if (poData->versionMajor == 1) {
601 if (
auto it = doc.FindMember(
"octreeDir"); it != doc.MemberEnd()) {
602 if (it->value.IsString()) {
603 std::string path = poData->
rootPath;
604 if (!path.empty() && path.back() !=
'/') { path.push_back(
'/'); }
605 path.append(it->value.GetString());
606 if (!path.empty() && path.back() !=
'/') { path.push_back(
'/'); }
610 LOG_ERROR(logger,
"metadata file: octreeDir is not a string");
615 LOG_ERROR(logger,
"metadata file: Missing octreeDir");
620 if (
auto it = doc.FindMember(
"suffix"); it != doc.MemberEnd()) {
621 if (it->value.IsString()) {
622 poData->suffix = it->value.GetString();
625 poData->encoding = PotreeEnconding::Default;
629 poData->encoding = PotreeEnconding::ZStd;
632 poData->encoding = PotreeEnconding::Default;
633 LOG_WARNING(logger,
"Unrecognized suffix '%s', assuming non-compressed data.", it->value.GetString());
638 LOG_ERROR(logger,
"metadata file: suffix is not a string");
643 if (!parseBBox(poData, poData->metadata.bbmin, poData->metadata.bbmax, doc,
"boundingBox", poData->instanceId))
return false;
644 if (poData->versionMajor == 1) {
645 if (!parseBBox(poData, poData->metadata.tbmin, poData->metadata.tbmax, doc,
"tightBoundingBox", poData->instanceId))
return false;
649 poData->attributes.clear();
650 if (!parsePointAttributes(poData, doc, poData->instanceId))
return false;
653 if (poData->versionMajor == 1) {
654 if (!parseUIntMemberNoLog(poData->hierarchyStepSize, doc,
"hierarchyStepSize")) {
655 LOG_ERROR(logger,
"metadata file: hierarchyStepSize is missing or not an unsigned integer");
659 if (!parseFloatMemberNoLog(scale, doc,
"scale")) {
660 LOG_ERROR(logger,
"metadata file: scale is missing or not a number");
663 poData->metadata.scale = glm::vec3(scale);
668 else if (poData->versionMajor == 2) {
671 if (
auto it = doc.FindMember(
"hierarchy"); it != doc.MemberEnd() && it->value.IsObject()) {
672 auto& item = it->value;
673 if (!parseUIntMemberNoLog(poData->firstChunkSize, item,
"firstChunkSize")) {
674 LOG_ERROR(logger,
"metadata file: missing or malformed firstChunkSize in hierarchy");
677 if (!parseUIntMemberNoLog(poData->hierarchyStepSize, item,
"stepSize")) {
678 LOG_ERROR(logger,
"metadata file: missing or malformed stepSize in hierarchy");
681 if (!parseUIntMemberNoLog(poData->hierarchyDepth, item,
"depth")) {
682 LOG_ERROR(logger,
"metadata file: missing or malformed depth in hierarchy");
687 LOG_ERROR(logger,
"metadata file: hierarchy is missing");
692 const char* encoding =
nullptr;
693 if (!parseStringMemberNoLog(encoding, doc,
"encoding")) {
694 LOG_ERROR(logger,
"metadata file: encoding is missing or not a string");
699 poData->encoding = PotreeEnconding::Default;
702 poData->encoding = PotreeEnconding::Brotli;
705 LOG_ERROR(logger,
"metadata file: unrecognized encodng '%s'", encoding);
709 if (!parseVec3NoLog(poData->metadata.offset, doc,
"offset")) {
710 LOG_ERROR(logger,
"metadata file: offset missing or not an array of 3 numbers");
713 if (!parseVec3NoLog(poData->metadata.scale, doc,
"scale")) {
714 LOG_ERROR(logger,
"metadata file: offset missing or not an array of 3 numbers");
721 assert(
false &&
"Unsupported version");
725 if (8 < poData->hierarchyStepSize) {
727 LOG_ERROR(logger,
"metadata file: hierarchyStepSize larger than 8 is not supported");
733 if (
auto it = doc.FindMember(
"spacing"); it != doc.MemberEnd()) {
735 if (it->value.IsNumber()) {
736 poData->spacing = it->value.GetFloat();
739 LOG_ERROR(logger,
"metadata file: spacing is not a number");
744 LOG_ERROR(logger,
"metadata file: spacing is missing");
749 poData->octtreeFrame.positionInEntityFrame = 0.5 * (poData->metadata.tbmin + poData->metadata.tbmax);
750 poData->octtreeFrame.toBBoxShift = glm::vec3(poData->metadata.bbmin - poData->octtreeFrame.positionInEntityFrame);
752 poData->octtreeFrame.fullBBoxSize = glm::vec3(poData->metadata.bbmax - poData->metadata.bbmin);
753 poData->octtreeFrame.fullBBoxDiagonal = glm::length(poData->octtreeFrame.fullBBoxSize);
755 poData->octtreeFrame.tightBBoxMin = glm::vec3(poData->metadata.tbmin - poData->octtreeFrame.positionInEntityFrame);
756 poData->octtreeFrame.tightBBoxMax = glm::vec3(poData->metadata.tbmax - poData->octtreeFrame.positionInEntityFrame);
758 poData->octtreeFrame.fullBBoxMin = glm::vec3(poData->metadata.bbmin - poData->octtreeFrame.positionInEntityFrame);
759 poData->octtreeFrame.fullBBoxMax = glm::vec3(poData->metadata.bbmax - poData->octtreeFrame.positionInEntityFrame);
762 if (poData->versionMajor == 1) {
763 poData->positionDecode.scale = poData->versionMinor <= 3 ? glm::vec3(1.f) : poData->metadata.scale;
764 poData->positionDecode.shift = glm::vec3(poData->metadata.bbmin - poData->octtreeFrame.positionInEntityFrame);
766 else if (poData->versionMajor == 2) {
767 poData->positionDecode.scale = poData->metadata.scale;
768 poData->positionDecode.shift = glm::vec3(poData->metadata.offset - poData->octtreeFrame.positionInEntityFrame);
771 LOG_FATAL(logger,
"Unsupported major version %d", poData->versionMajor);
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Log implementation class.
Provides a weakly referenced view over the contents of a string.
size_t hashLowercase(size_t hashValue=Cogs::hash()) const noexcept
Get the hash code of the string converted to lowercase.
constexpr size_t hash() const noexcept
Get the hash code of the string.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
VertexFormatHandle vertexFormats[maxStreams]
COGSCORE_DLL_API void updateHash()
std::string octreeDir
1.x only: subdir with data
std::string rootPath
URL to folder containing metadata file.
Abstract base class storing data read from a file.