40 #include <ext/rapidjson/document.h>
48 using std::make_unique;
51 using std::unique_ptr;
87 using rapidjson::Document;
88 using rapidjson::Value;
92 return read(pathName, fileName,
"", progressCallback, prototypeTransformFilter);
97 if (progressCallback !=
nullptr) progressCallback->
progress(0.0f);
100 auto jsonContent = FileSystem::getInstance()->getContentAsString(pathName, fileName);
101 if (progressCallback !=
nullptr) progressCallback->
progress(0.165f);
105 jRoot.Parse(jsonContent.c_str());
106 if (progressCallback !=
nullptr) progressCallback->
progress(0.33f);
109 auto progressCallbackUniquePtr = unique_ptr<ProgressCallback>(progressCallback);
110 auto scene = make_unique<Scene>(fileName,
"");
112 scene->setApplicationRootPathName(Tools::getApplicationRootPathName(pathName));
114 scene->setRotationOrder(jRoot.FindMember(
"ro") != jRoot.MemberEnd()?RotationOrder::valueOf(jRoot[
"ro"].GetString()):RotationOrder::XYZ);
115 for (
auto i = 0; i < jRoot[
"properties"].GetArray().Size(); i++) {
116 const auto& jSceneProperty = jRoot[
"properties"].GetArray()[i];
118 jSceneProperty[
"name"].GetString(),
119 jSceneProperty[
"value"].GetString()
122 if (jRoot.FindMember(
"lights") != jRoot.MemberEnd()) {
124 auto jLights = jRoot[
"lights"].GetArray();
125 for (
auto i = 0; i < jLights.Size(); i++) {
126 const auto& jLight = jLights[i];
127 if (jLight[
"e"].GetBool() ==
false)
continue;
128 auto light = lightIdx < scene->getLightCount()?(scene->getLightAt(jLight.FindMember(
"id") != jLight.MemberEnd()?jLight[
"id"].GetInt():lightIdx)):scene->addLight();
131 jLight[
"ar"].GetFloat(),
132 jLight[
"ag"].GetFloat(),
133 jLight[
"ab"].GetFloat(),
134 jLight[
"aa"].GetFloat()
139 jLight[
"dr"].GetFloat(),
140 jLight[
"dg"].GetFloat(),
141 jLight[
"db"].GetFloat(),
142 jLight[
"da"].GetFloat()
147 jLight[
"sr"].GetFloat(),
148 jLight[
"sg"].GetFloat(),
149 jLight[
"sb"].GetFloat(),
150 jLight[
"sa"].GetFloat()
155 jLight[
"px"].GetFloat(),
156 jLight[
"py"].GetFloat(),
157 jLight[
"pz"].GetFloat(),
158 jLight[
"pw"].GetFloat()
161 light->setConstantAttenuation(jLight[
"ca"].GetFloat());
162 light->setLinearAttenuation(jLight[
"la"].GetFloat());
163 light->setQuadraticAttenuation(jLight[
"qa"].GetFloat());
164 light->setSpotDirection(
166 jLight[
"sdx"].GetFloat(),
167 jLight[
"sdy"].GetFloat(),
168 jLight[
"sdz"].GetFloat()
171 light->setSpotExponent(jLight[
"se"].GetFloat());
172 light->setSpotCutOff(jLight[
"sco"].GetFloat());
173 light->setEnabled(jLight[
"e"].GetBool());
178 auto progressStepCurrent = 0;
179 auto jPrototypes = jRoot[
"models"].GetArray();
180 for (
auto i = 0; i < jPrototypes.Size(); i++) {
181 const auto& jPrototype = jPrototypes[i];
182 unique_ptr<Prototype> prototype;
184 auto embedded = jPrototype.FindMember(
"e") != jPrototype.MemberEnd()?jPrototype[
"e"].GetBool():
true;
185 if (embedded ==
true) {
186 prototype = unique_ptr<Prototype>(
187 PrototypeReader::read(
188 jPrototype[
"id"].GetInt(),
190 jPrototype[
"entity"],
191 prototypeTransformFilter
194 prototype->setEmbedded(
true);
196 auto externalPrototypePathName = PrototypeReader::getResourcePathName(pathName, jPrototype[
"pf"].GetString());
197 auto externalPrototypeFileName = FileSystem::getInstance()->getFileName(jPrototype[
"pf"].GetString());
198 prototype = unique_ptr<Prototype>(
199 PrototypeReader::read(
200 jPrototype[
"id"].GetInt(),
201 externalPrototypePathName,
202 externalPrototypeFileName,
203 prototypeTransformFilter
206 prototype->setEmbedded(
false);
209 Console::println(
string() +
"SceneReader::read(): An error occurred: " + exception.what() +
": Using empty prototype");
211 string prototypeName =
"Missing-Prototype-" + to_string(jPrototype[
"id"].GetInt());
213 prototype = make_unique<Prototype>(
214 jPrototype[
"id"].GetInt(),
215 Prototype_Type::EMPTY,
218 prototypeName +
".tempty",
219 "resources/engine/models/empty.tm",
221 ModelReader::read(
"resources/engine/models",
"empty.tm")
224 if (prototype ==
nullptr) {
225 Console::println(
"SceneReader::read(): Invalid prototype = " + to_string(jPrototype[
"id"].GetInt()));
228 if (jPrototype.FindMember(
"properties") != jPrototype.MemberEnd()) {
229 for (
auto j = 0; j < jPrototype[
"properties"].GetArray().Size(); j++) {
230 const auto& jPrototypeProperty = jPrototype[
"properties"].GetArray()[j];
231 prototype->addProperty(
232 jPrototypeProperty[
"name"].GetString(),
233 jPrototypeProperty[
"value"].GetString()
237 scene->getLibrary()->addPrototype(prototype.release());
239 if (progressCallback !=
nullptr) progressCallback->
progress(0.33f +
static_cast<float>(progressStepCurrent) /
static_cast<float>(jRoot[
"models"].GetArray().Size()) * 0.33f);
240 progressStepCurrent++;
243 auto jEntities = jRoot[
"objects"].GetArray();
244 for (
auto i = 0; i < jEntities.Size(); i++) {
245 const auto& jSceneEntity = jEntities[i];
246 auto prototype = scene->getLibrary()->getPrototype(jSceneEntity[
"mid"].GetInt());
247 if (prototype ==
nullptr) {
248 Console::println(
"SceneReader::read(): No prototype found with id = " + to_string(jSceneEntity[
"mid"].GetInt()));
250 if (progressCallback !=
nullptr && progressStepCurrent % 1000 == 0) progressCallback->
progress(0.66f +
static_cast<float>(progressStepCurrent) /
static_cast<float>(jRoot[
"objects"].GetArray().Size()) * 0.33f);
251 progressStepCurrent++;
259 jSceneEntity[
"tx"].GetFloat(),
260 jSceneEntity[
"ty"].GetFloat(),
261 jSceneEntity[
"tz"].GetFloat()
266 jSceneEntity[
"sx"].GetFloat(),
267 jSceneEntity[
"sy"].GetFloat(),
268 jSceneEntity[
"sz"].GetFloat()
272 jSceneEntity[
"rx"].GetFloat(),
273 jSceneEntity[
"ry"].GetFloat(),
274 jSceneEntity[
"rz"].GetFloat()
276 transform.
addRotation(scene->getRotationOrder()->getAxis0(), rotation.
getArray()[scene->getRotationOrder()->getAxis0VectorIndex()]);
277 transform.
addRotation(scene->getRotationOrder()->getAxis1(), rotation.
getArray()[scene->getRotationOrder()->getAxis1VectorIndex()]);
278 transform.
addRotation(scene->getRotationOrder()->getAxis2(), rotation.
getArray()[scene->getRotationOrder()->getAxis2VectorIndex()]);
280 auto sceneEntity = make_unique<SceneEntity>(
281 objectIdPrefix !=
"" ?
282 objectIdPrefix + jSceneEntity[
"id"].GetString() :
283 (jSceneEntity[
"id"].GetString()),
284 jSceneEntity.FindMember(
"descr") != jSceneEntity.MemberEnd()?jSceneEntity[
"descr"].GetString() :
"",
288 if (jSceneEntity.FindMember(
"properties") != jSceneEntity.MemberEnd()) {
289 auto jSceneEntities = jSceneEntity[
"properties"].GetArray();
290 for (
auto j = 0; j < jSceneEntities.Size(); j++) {
291 const auto& jSceneEntityProperty = jSceneEntity[
"properties"].GetArray()[j];
292 sceneEntity->addProperty(
293 jSceneEntityProperty[
"name"].GetString(),
294 jSceneEntityProperty[
"value"].GetString()
298 sceneEntity->setReflectionEnvironmentMappingId(jSceneEntity.FindMember(
"r") != jSceneEntity.MemberEnd()?jSceneEntity[
"r"].GetString():
"");
299 scene->addEntity(sceneEntity.release());
301 if (progressCallback !=
nullptr && progressStepCurrent % 1000 == 0) progressCallback->
progress(0.66f +
static_cast<float>(progressStepCurrent) /
static_cast<float>(jRoot[
"objects"].GetArray().Size()) * 0.33f);
302 progressStepCurrent++;
304 scene->setEntityIdx(jRoot[
"objects_eidx"].GetInt());
305 scene->setFileName((pathName.empty() ==
false?pathName +
"/":
"") + fileName);
309 if (jRoot.FindMember(
"skyshader") != jRoot.MemberEnd()) {
310 const auto& jSkyShaderParameters = jRoot[
"skyshader"];
313 for (
auto jShaderParameterIt = jSkyShaderParameters.MemberBegin(); jShaderParameterIt != jSkyShaderParameters.MemberEnd(); ++jShaderParameterIt) {
314 skyShaderParameters.
setShaderParameter(jShaderParameterIt->name.GetString(),
string(jShaderParameterIt->value.GetString()));
316 scene->setSkyShaderParameters(skyShaderParameters);
320 if (jRoot.FindMember(
"postprocessingshaders") != jRoot.MemberEnd()) {
322 const auto& jPostProcessingShaders = jRoot[
"postprocessingshaders"];
324 const auto& jEnabledPostProcessingShaders = jPostProcessingShaders[
"enabled"].GetArray();
325 for (
auto i = 0; i < jEnabledPostProcessingShaders.Size(); i++) {
326 scene->enablePostProcessingShader(jEnabledPostProcessingShaders[i].GetString());
329 const auto& jAllPostProcessingShaderParameters = jPostProcessingShaders[
"parameters"].GetObject();
330 for (
auto jAllPostProcessingShaderParameterIt = jAllPostProcessingShaderParameters.MemberBegin(); jAllPostProcessingShaderParameterIt != jAllPostProcessingShaderParameters.MemberEnd(); ++jAllPostProcessingShaderParameterIt) {
331 const auto& jShaderId = jAllPostProcessingShaderParameterIt->name.GetString();
332 const auto& jShaderParameters = jAllPostProcessingShaderParameterIt->value.GetObject();
336 for (
auto jShaderParameterIt = jShaderParameters.MemberBegin(); jShaderParameterIt != jShaderParameters.MemberEnd(); ++jShaderParameterIt) {
337 shaderParameters.
setShaderParameter(jShaderParameterIt->name.GetString(),
string(jShaderParameterIt->value.GetString()));
340 scene->setPostProcessingShaderParameters(jShaderId, shaderParameters);
345 if (jRoot.FindMember(
"gui") != jRoot.MemberEnd()) {
346 auto guiFileName = jRoot[
"gui"].GetString();
347 auto externalPrototypePathName = PrototypeReader::getResourcePathName(pathName, guiFileName);
348 auto externalPrototypeFileName = FileSystem::getInstance()->getFileName(guiFileName);
349 scene->setGUIFileName(guiFileName);
353 if (progressCallback !=
nullptr) {
358 return scene.release();
363 auto nodeId = node->
getId();
364 if (parentName.length() > 0) nodeId = parentName +
"." + nodeId;
365 auto modelName = nodeId;
366 modelName = StringTools::regexReplace(modelName,
"[-_]{1}[0-9]+$",
"");
367 modelName = StringTools::regexReplace(modelName,
"[0-9]+$",
"");
368 auto haveName = sceneLibrary->getPrototypeCount() == 0;
369 if (haveName ==
false) {
370 for (
auto i = 0; i < 10000; i++) {
372 auto modelNameTry = modelName;
373 if (i > 0) modelNameTry+= to_string(i);
374 for (
auto entity: sceneLibrary->getPrototypes()) {
375 if (entity->getName() == modelNameTry) {
380 if (haveName ==
true) {
381 modelName = modelNameTry;
386 if (haveName ==
false) {
389 "SceneReader::doImportFromModel(): Skipping model '" +
391 "' as no name could be created for it."
399 if (animation !=
nullptr) {
401 transformMatrix.
set(animationMatrices[0 % animationMatrices.size()]);
408 transformMatrix.
multiply(parentTransformMatrix);
413 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
419 prototypeMeshNode.
id = nodeId;
420 prototypeMeshNode.
name = modelName;
421 prototypeMeshNode.
node = node;
423 meshNodes.push_back(prototypeMeshNode);
429 if (progressCallback !=
nullptr) progressCallback->
progress(0.0f);
431 string modelPathName = pathName +
"/" + fileName +
"-models";
432 if (FileSystem::getInstance()->exists(modelPathName)) {
433 FileSystem::getInstance()->removePath(modelPathName,
true);
435 FileSystem::getInstance()->createPath(modelPathName);
437 unique_ptr<Model> sceneModel(ModelReader::read(pathName, fileName));
439 if (progressCallback !=
nullptr) progressCallback->
progress(0.1f);
441 auto upVector = sceneModel->getUpVector();
442 RotationOrder* rotationOrder = sceneModel->getRotationOrder();
445 auto scene = make_unique<Scene>(fileName,
"");
446 scene->setRotationOrder(rotationOrder);
448 auto sceneLibrary = scene->getLibrary();
451 Matrix4x4 sceneModelImportRotationMatrix;
453 sceneModelImportRotationMatrix.
set(sceneModel->getImportTransformMatrix());
454 sceneModelImportRotationMatrix.
getScale(sceneModelScale);
455 sceneModelImportRotationMatrix.
scale(
Vector3(1.0f / sceneModelScale.
getX(), 1.0f / sceneModelScale.
getY(), 1.0f / sceneModelScale.
getZ()));
456 auto progressTotal = sceneModel->getSubNodes().size();
457 auto progressIdx = 0;
458 for (
const auto& [subNodeId, subNode]: sceneModel->getSubNodes()) {
459 if (progressCallback !=
nullptr) progressCallback->
progress(0.1f +
static_cast<float>(progressIdx) /
static_cast<float>(progressTotal) * 0.8f);
460 vector<PrototypeMeshNode> meshNodes;
462 for (
const auto& meshNode: meshNodes) {
463 auto model = make_unique<Model>(
464 meshNode.name +
".tm",
465 fileName +
"-" + meshNode.name,
470 model->setImportTransformMatrix(sceneModel->getImportTransformMatrix());
471 float importFixScale = 1.0f;
475 nodeTransformMatrix.
set(meshNode.transformMatrix);
476 nodeTransformMatrix.
getAxes(xAxis, yAxis, zAxis);
478 nodeTransformMatrix.
getScale(scale);
482 nodeTransformMatrix.
setAxes(xAxis, yAxis, zAxis);
483 if ((upVector == UpVector::Y_UP && Vector3::computeDotProduct(Vector3::computeCrossProduct(xAxis, yAxis), zAxis) < 0.0f) ||
484 (upVector == UpVector::Z_UP && Vector3::computeDotProduct(Vector3::computeCrossProduct(xAxis, zAxis), yAxis) < 0.0f)) {
488 nodeTransformMatrix.
setAxes(xAxis, yAxis, zAxis);
492 scale = sceneModelImportRotationMatrix.
multiply(scale);
493 rotation = sceneModelImportRotationMatrix.
multiply(rotation);
494 translation = model->getImportTransformMatrix().multiply(translation);
496 ModelTools::cloneNode(meshNode.node, model.get());
497 if (model->getSubNodes().begin() != model->getSubNodes().end()) {
498 model->getSubNodes().begin()->second->setTransformMatrix(
Matrix4x4().identity());
500 model->addAnimationSetup(Model::ANIMATIONSETUP_DEFAULT, 0, 0,
true);
501 ModelTools::prepareForIndexedRendering(model.get());
505 auto width = model->getBoundingBox()->getDimensions().getX();
506 auto height = model->getBoundingBox()->getDimensions().getY();
507 auto depth = model->getBoundingBox()->getDimensions().getZ();
508 if (width < 0.2f && height < 0.2f && depth < 0.2f) {
509 if (width > Math::EPSILON && width < height && width < depth) {
510 importFixScale = 1.0f / width / 5.0f;
512 if (height > Math::EPSILON && height < width && height < depth) {
513 importFixScale = 1.0f / height / 5.0f;
515 if (depth > Math::EPSILON) {
516 importFixScale = 1.0f / depth / 5.0f;
519 model->setImportTransformMatrix(model->getImportTransformMatrix().clone().scale(importFixScale));
520 model->getBoundingBox()->getMin().scale(importFixScale);
521 model->getBoundingBox()->getMax().scale(importFixScale);
522 model->getBoundingBox()->update();
523 scale.
scale(1.0f / importFixScale);
525 auto prototypeType = Prototype_Type::MODEL;
526 if (meshNode.node->getVertices().size() == 0) {
527 prototypeType = Prototype_Type::EMPTY;
531 if (prototypeType == Prototype_Type::MODEL && model !=
nullptr) {
532 for (
auto prototypeCompare: scene->getLibrary()->getPrototypes()) {
533 if (prototypeCompare->getType() != Prototype_Type::MODEL)
537 prototype = prototypeCompare;
542 if (prototype ==
nullptr && model !=
nullptr) {
543 auto modelFileName = meshNode.
name +
".tm";
553 auto newPrototype = make_unique<Prototype>(
555 Prototype_Type::MODEL,
556 Tools::removeFileExtension(fileName),
557 Tools::removeFileExtension(fileName),
558 modelPathName +
"/" + modelFileName,
559 "resources/engine/models/empty.tm",
563 sceneLibrary->addPrototype(newPrototype.get());
564 prototype = newPrototype.release();
567 if (prototypeType == Prototype_Type::EMPTY) {
568 if (emptyPrototype ==
nullptr) {
569 auto newEmptyPrototype = make_unique<Prototype>(
571 Prototype_Type::EMPTY,
575 "resources/engine/models/empty.tm",
577 ModelReader::read(
"resources/engine/models",
"empty.tm")
579 sceneLibrary->addPrototype(newEmptyPrototype.get());
580 emptyPrototype = newEmptyPrototype.release();
582 prototype = emptyPrototype;
584 Console::println(
string(
"SceneReader::readFromModel(): unknown entity type. Skipping"));
592 sceneEntityTransform.
setScale(scale);
593 sceneEntityTransform.
update();
594 auto sceneEntity = make_unique<SceneEntity>(
597 sceneEntityTransform,
600 scene->addEntity(sceneEntity.release());
606 if (progressCallback !=
nullptr) progressCallback->
progress(0.9f);
612 Tools::removeFileExtension(fileName) +
".tscene",
616 Console::println(
"SceneReader::readFromModel(): An error occurred: " +
string(exception.what()));
621 if (progressCallback !=
nullptr) progressCallback->
progress(1.0f);
624 return scene.release();
Color 4 definition class.
TDME2 engine entity shader parameters.
void setShaderParameter(const string ¶meterName, const ShaderParameter ¶meterValue)
Set shader parameter for given parameter name.
void setShader(const string &shaderId)
Set shader.
static Scene * read(const string &pathName, const string &fileName, ProgressCallback *progressCallback=nullptr, PrototypeTransformFilter *prototypeTransformFilter=nullptr)
Reads a scene.
static Scene * readFromModel(const string &pathName, const string &fileName, ProgressCallback *progressCallback=nullptr)
Reads a scene.
static void determineMeshNodes(Scene *scene, Node *node, const string &parentName, const Matrix4x4 &parentTransformMatrix, vector< PrototypeMeshNode > &meshNodes)
Determine mesh nodes in node hierarchy.
static void write(const string &pathName, const string &fileName, Scene *scene)
Writes a scene.
const vector< Matrix4x4 > & getTransformMatrices() const
Returns transform matrices.
Representation of a 3D model.
unordered_map< string, Node * > & getSubNodes()
Animation * getAnimation()
const vector< Vector3 > & getVertices() const
const string & getId()
Returns id.
const Matrix4x4 & getTransformMatrix() const
Represents rotation orders of a model.
const Vector3 & getAxis1() const
const Vector3 & getAxis0() const
int getAxis2VectorIndex() const
const Vector3 & getAxis2() const
int getAxis1VectorIndex() const
int getAxis0VectorIndex() const
Scene prototype library definition.
SceneLibrary * getLibrary()
static bool equals(Model *model1, Model *model2)
Compute if model 1 equals model 2.
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Matrix4x4 clone() const
Clones this matrix.
Matrix4x4 & scale(float scalar)
Scales by scalar.
Vector3 multiply(const Vector3 &vector3) const
Multiplies this matrix with vector3.
void getAxes(Vector3 &xAxis, Vector3 &yAxis, Vector3 &zAxis) const
Get coordinate system axes.
Matrix4x4 & set(float r0c0, float r0c1, float r0c2, float r0c3, float r1c0, float r1c1, float r1c2, float r1c3, float r2c0, float r2c1, float r2c2, float r2c3, float r3c0, float r3c1, float r3c2, float r3c3)
Sets this matrix by its components.
Vector3 computeEulerAngles() const
Compute Euler angles (rotation around x, y, z axes)
void getScale(Vector3 &scale) const
Get scale.
void getTranslation(Vector3 &translation) const
Get translation.
Matrix4x4 & setAxes(const Vector3 &xAxis, const Vector3 &yAxis, const Vector3 &zAxis)
Set coordinate system axes.
Vector3 class representing vector3 mathematical structure and operations with x, y,...
const array< float, 3 > & getArray() const
Vector3 & scale(float scalar)
Scales by scalar.
Vector3 & normalize()
Normalizes this vector3.
Vector4 class representing vector4 mathematical structure and operations with x, y,...
File system singleton class.
std::exception Exception
Exception base class.
virtual void progress(float value)=0
Perform action.
Matrix4x4 transformMatrix