1#include "SceneReader.h"
8#include "EntityStore.h"
10#include "Foundation/Logging/Logger.h"
12#include "Utilities/Expressions.h"
13#include "Utilities/Parsing.h"
15#include "Components/Core/PropertiesComponent.h"
16#include "Components/Core/AssetComponent.h"
18#include "Resources/AssetManager.h"
20#include "EntityReader.h"
21#include "EntityCreator.h"
22#include "ResourceReader.h"
31 constexpr size_t PreAllocSize = 64ULL;
34 constexpr uint32_t NoIndex =
static_cast<uint32_t
>(-1);
40 if (entity.isAssetModelOrLodGroup() || ((entity.
type != NoString) && (Strings::get(entity.
type) != newTypeName))) {
41 LOG_WARNING(logger,
"Type already set to '%.*s', cannot set type to '%.*s'",
42 StringViewFormat(entity.getTypeName()),
43 StringViewFormat(newTypeName));
52 auto& val = ev->getValues()[i];
54 const uint32_t index = sceneDef.entities[entityId].index;
57 while (val.value <= val.max) {
59 for (
auto& c : v.GetArray()) {
60 uint32_t child = asset.scene.createEntity(index);
61 readSceneEntityDefinition(context, c, asset, asset.scene, child, ev);
62 asset.scene[index].numChildren++;
66 loopValues(context, v, asset, asset.scene, index, ev, i - 1);
69 val.value += val.step;
74 void replace(std::string& str,
const std::string& from,
const std::string& to)
76 size_t start_pos = str.find(from);
77 if (start_pos != std::string::npos) {
78 str.replace(start_pos, from.length(), to);
86 if (isTypeSomethingDifferent(asset, entity,
"Model")) {
92 entity.
model.part = NoIndex;
93 entity.
model.size = 0;
95 uint32_t lodDepth = 0;
96 uint32_t pIndex = entity.parentIndex;
97 while (pIndex != NoIndex) {
100 if (e.isLodGroup()) ++lodDepth;
102 pIndex = e.parentIndex;
104 entity.
model.depth = (uint16_t)lodDepth;
106 if (modelValue.IsObject()) {
107 for (
auto& mm : modelValue.GetObject()) {
113 if (mm.value.IsString()) {
115 if (!source.empty()) {
116 entity.
model.index = scene.properties.addProperty(
"model", source);
119 LOG_ERROR(logger,
"In 'model', value of 'source' is empty string");
123 else if (mm.value.IsUint()) {
125 entity.
model.index = scene.properties.addProperty(
"model", mm.value.GetUint());
128 LOG_ERROR(logger,
"In 'model', value of 'source' is neither string nor uint");
134 case
Cogs::hash(
"part"):
135 if (mm.value.IsUint()) {
136 entity.
model.part = mm.value.GetUint();
138 else if (mm.value.IsInt() && mm.value.GetInt() == -1) {
139 entity.
model.part = NoIndex;
142 LOG_ERROR(logger,
"In 'model', value of '%.*s' is not an uint", StringViewFormat(key));
148 if (mm.value.IsUint()) {
149 entity.
model.size = mm.value.GetUint();
152 LOG_ERROR(logger,
"In 'model', value of kb is not an uint");
158 LOG_WARNING(logger,
"In 'model', unrecognized key '%.*s'", StringViewFormat(key));
164 else if (modelValue.IsString()) {
166 if (!source.empty()) {
167 entity.
model.index = scene.properties.addProperty(
"asset", source);
174 else if (modelValue.IsUint()) {
175 entity.
model.index = scene.properties.addProperty(
"model", modelValue.GetUint());
180 LOG_ERROR(logger,
"Invalid model value.");
189 if (isTypeSomethingDifferent(asset, entity,
"Asset")) {
195 entity.
asset.material = NoIndex;
197 if (assetValue.IsObject()) {
198 for (
auto& mm : assetValue.GetObject()) {
204 if (mm.value.IsString()) {
205 entity.
asset.index = scene.properties.addProperty(
"asset", toKey(mm.value));
207 else if (mm.value.IsUint()) {
208 entity.
asset.index = scene.properties.addProperty(
"asset", mm.value.GetUint());
211 LOG_ERROR(logger,
"In 'asset', value of 'source' is neither a string nor an uint");
216 if (mm.value.IsString()) {
217 entity.
asset.
flags = uint32_t(parseEnumFlags(toView(mm.value), AssetFlags::None));
219 else if (mm.value.IsUint()) {
224 LOG_ERROR(logger,
"In 'asset', value of 'flags' is neither a string nor an uint");
229 if (mm.value.IsString()) {
230 entity.
asset.material = scene.properties.addProperty(
"material", toView(mm.value));
232 else if (mm.value.IsObject()) {
235 rc.context = context;
238 readMaterialInstanceDefinition(&rc, mm.value, resource);
242 LOG_ERROR(logger,
"In 'asset', value of 'material' is neither a string nor an object");
247 LOG_WARNING(logger,
"In 'asset', unrecognized key '%.*s'", StringViewFormat(key));
253 else if (assetValue.IsString()) {
255 if (!source.empty()) {
256 entity.
asset.index = scene.properties.addProperty(
"asset", source);
263 else if (assetValue.IsUint()) {
264 entity.
asset.index = scene.properties.addProperty(
"asset", assetValue.GetUint());
269 LOG_ERROR(logger,
"Invalid asset value.");
278 if (!jsonEntity.IsObject()) {
279 sceneDef[entityId].setError();
280 LOG_ERROR(logger,
"JSON parse Error in scene entity definition.");
286 if (jsonEntity.GetObject().ObjectEmpty()) {
287 sceneDef[entityId].setEmpty();
291 sceneDef[entityId].firstField = uint32_t(scene.fieldValues.size());
292 sceneDef[entityId].firstChild = uint32_t(scene.entities.size());
294 auto o = jsonEntity.GetObject();
300 std::string nameStr = m.value.GetString();
302 if (ec && nameStr.find(
'%') != std::string::npos) {
307 replace(nameStr,
"%" + value.name, std::to_string(value.sequenceNumber));
309 tec = tec->getParent();
310 }
while (tec !=
nullptr);
314 sceneDef[entityId].nameIndex = scene.properties.addProperty(
"name", nameStr);
316 else if (key ==
"objectId") {
317 sceneDef[entityId].objectId = m.value.GetUint();
319 else if (key ==
"type") {
321 if (isTypeSomethingDifferent(asset, sceneDef[entityId], type)) {
324 sceneDef[entityId].type = Strings::add(type);
326 else if (key ==
"model") {
327 parseModelItem(context, asset, sceneDef[entityId], m.value);
329 else if (key ==
"asset") {
330 parseAssetItem(context, asset, sceneDef[entityId], ec, m.value);
332 else if (key ==
"parent") {
333 uint32_t parentPropertyIndex = scene.properties.addProperty(
"parent", toKey(m.value));
334 sceneDef[entityId].parentIndex = parentPropertyIndex;
335 sceneDef[entityId].flags |= SceneEntityFlags::ParentIsName;
337 else if (key ==
"properties") {
341 entity.firstProperty = uint32_t(scene.properties.size());
343 for (
auto& c : m.value.GetObject()) {
345 ++entity.numProperties;
347 if (c.value.IsBool()) {
348 properties.addProperty(propName, c.value.GetBool());
350 else if (c.value.IsString()) {
351 properties.addProperty(propName, toKey(c.value));
353 else if (c.value.IsInt()) {
354 properties.addProperty(propName, c.value.GetInt());
356 else if (c.value.IsFloat()) {
357 properties.addProperty(propName, c.value.GetFloat());
359 else if (c.value.IsArray()) {
360 auto valueArray = c.value.GetArray();
362 if (valueArray.Empty()) {
363 LOG_WARNING(logger,
"Ignoring empty array in property \"%.*s\"", StringViewFormat(propName));
368 switch (toKey(c.name).
hash()) {
371 std::vector<uint32_t> uints(valueArray.Size());
372 for (uint32_t i = 0; i < valueArray.Size(); ++i) {
373 uints[i] = valueArray[i].GetUint();
375 properties.addProperty(propName, uints);
381 std::vector<float> floats(valueArray.Size());
382 for (uint32_t i = 0; i < valueArray.Size(); ++i) {
383 floats[i] = valueArray[i].GetFloat();
385 properties.addProperty(propName, floats);
398 LOG_WARNING(logger,
"Unsupported property type for key \"%.*s\".", StringViewFormat(name));
399 --entity.numProperties;
403 else if (key ==
"children" || key ==
"lods") {
406 else if (key ==
"sequence") {
407 sceneDef[entityId].setSequence();
411 expressionContext.inherit(ec);
413 for (
auto& v : m.value.GetObject()) {
414 if (v.name ==
"variables") {
415 for (
auto& vv : v.value.GetObject()) {
419 if (vv.value.IsObject()) {
420 if (!vv.value.HasMember(
"min") || !vv.value.HasMember(
"max") || !vv.value.HasMember(
"step")) {
421 LOG_ERROR(logger,
"Key variables: Invalid range specification.");
424 var.min = vv.value[
"min"].GetDouble();
425 var.max = vv.value[
"max"].GetDouble();
426 var.step = vv.value[
"step"].GetDouble();
428 else if (vv.value.IsArray()) {
429 if (vv.value.Size() != 3) {
430 LOG_ERROR(logger,
"Key variables: Invalid number of elements in array.");
433 var.min = vv.value[0].GetDouble();
434 var.max = vv.value[1].GetDouble();
435 var.step = vv.value[2].GetDouble();
441 for (
auto& v : m.value.GetObject()) {
442 if (v.name ==
"entities") {
443 loopValues(context, v.value, asset, sceneDef, entityId, &expressionContext, expressionContext.getValues().size() - 1);
448 if (scene.fieldValues.empty()) {
449 scene.fieldValues.reserve(PreAllocSize);
453 split(key,
".", tokens);
455 if (tokens.size() == 2) {
457 const Reflection::Type& type = Reflection::TypeDatabase::getType(tokens[0]);
459 if (readFieldValue(context, m.value, type, tokens[1], scene.fieldValues, ec)) {
460 ++sceneDef[entityId].numFields;
463 else if (tokens.size() == 1) {
464 size_t before = scene.fieldValues.size();
465 readFieldValues(context, m.value, key, scene.fieldValues, ec);
466 size_t after = scene.fieldValues.size();
468 sceneDef[entityId].numFields += uint32_t(after - before);
471 LOG_ERROR(logger,
"Unrecognized property name %.*s.", StringViewFormat(key));
476 uint32_t index = sceneDef[entityId].index;
481 if (key ==
"children") {
482 if (!m.value.IsArray()) {
483 LOG_ERROR(logger,
"children property must be array type.");
484 sceneDef[entityId].setError();
487 uint32_t prevChild = NoIndex;
488 if (m.value.GetArray().Empty()) {
491 for (
auto& c : m.value.GetArray()) {
492 uint32_t child = scene.createEntity(index);
493 if (prevChild != NoIndex) {
494 scene[prevChild].nextSibling = child;
497 ++scene[index].numChildren;
498 readSceneEntityDefinition(context, c, asset, scene, child, ec);
501 if (scene[index].numChildren) scene[index].setChildren();
503 else if (key ==
"lods") {
504 if (!m.value.IsArray()) {
505 LOG_ERROR(logger,
"lods property must be array type.");
506 sceneDef[entityId].setError();
510 if (isTypeSomethingDifferent(asset, scene[index],
"LodGroup")) {
511 scene[index].setError();
515 ++scene.numLodGroups;
516 scene[index].setLodGroup();
517 scene[index].lod.numLods = 0;
518 uint32_t prevChild = NoIndex;
520 for (
auto& c : m.value.GetArray()) {
522 if (c.IsObject() || (c.IsArray() && c.Empty())) {
523 uint32_t child = scene.createEntity(index);
524 if (prevChild != NoIndex) {
525 scene[prevChild].nextSibling = child;
528 ++scene[index].numChildren;
529 ++scene[index].lod.numLods;
531 readSceneEntityDefinition(context, c, asset, scene, child, ec);
536 scene[child].setEmpty();
540 else if (c.IsArray()) {
541 uint32_t prevLod = NoIndex;
542 for (
auto& cc : c.GetArray()) {
544 uint32_t child = scene.createEntity(index);
545 if (prevChild != NoIndex) {
546 scene[prevChild].nextSibling = child;
549 if (prevLod != NoIndex) {
550 scene[prevLod].nextLodSibling = child;
554 ++scene[index].numChildren;
555 readSceneEntityDefinition(context, cc, asset, scene, child, ec);
558 LOG_ERROR(logger,
"Invalid lod child - must be object.");
561 ++scene[index].lod.numLods;
565 if (scene[index].numChildren) scene[index].setChildren();
577 std::vector<ComponentModel::Entity*> entities(scene.entities.size());
580 Entity* parent =
nullptr;
581 if (definition.isParentedByName()) {
584 else if (definition.parentIndex == NoIndex) {
589 if (parentDef.isSequence()) {
594 parent = entities[definition.parentIndex];
598 entities[definition.index] = createEntity(context, scene, definition, parent);
606 if (!jsonScene.IsArray()) {
607 LOG_ERROR(logger,
"JSON Scene must be specified as an array.");
611 auto entityArray = jsonScene.GetArray();
614 scene.numTopLevelEntities = entityArray.Size();
616 if (scene.entities.empty()) {
617 scene.entities.reserve(std::max(
size_t(entityArray.Size()), PreAllocSize));
621 for (
auto& e : entityArray) {
622 uint32_t index = scene.createEntity(NoParentEntity);
623 readSceneEntityDefinition(context, e, asset, scene, index, &evaluationContext);
626 if (scene.entities.empty()) {
627 LOG_WARNING(logger,
"Read empty scene.");
Container for components, providing composition of dynamic entities.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Log implementation class.
Represents a discrete type definition, describing a native type class.
Provides a weakly referenced view over the contents of a string.
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....
void COGSCORE_DLL_API readSceneDefinition(class Context *context, const Value &jsonScene, AssetLoadFlags flags, AssetDefinition &asset)
Parse JSON description of Entities in Cogs Scene. Store contents in asset param.
void COGSCORE_DLL_API readScene(class Context *context, const Value &jsonScene, AssetLoadFlags flags, ComponentModel::Entity *root)
Parse JSON description of Entities in Cogs Scene file and create Entities defined in scene.
AssetLoadFlags
Asset and Scene loading flags. May be combined with resource loading flags.
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.
Provides a context for evaluation of expressions.
Defines a single named expression variable.
struct Cogs::Core::SceneEntityDefinition::@28::@31 model
SceneEntityFlags::Model is set.
uint32_t flags
Really enum of SceneEntityFlags.
StringRef type
Neither SceneEntityFlags::Asset, SceneEntityFlags::Model, nor SceneEntityFlags::LodGroup is set.
struct Cogs::Core::SceneEntityDefinition::@28::@30 asset
SceneEntityFlags::Asset is set.