TDME2  1.9.200
SceneConnector.cpp
Go to the documentation of this file.
2 
3 #if defined(_WIN32) && defined(_MSC_VER)
4  #pragma warning(disable:4503)
5 #endif
6 
7 #include <memory>
8 #include <string>
9 #include <unordered_map>
10 #include <vector>
11 
12 #include <tdme/tdme.h>
13 #include <tdme/audio/Audio.h>
14 #include <tdme/audio/Sound.h>
18 #include <tdme/engine/Color4.h>
60 #include <tdme/engine/Decal.h>
61 #include <tdme/engine/Engine.h>
62 #include <tdme/engine/Entity.h>
66 #include <tdme/engine/Light.h>
67 #include <tdme/engine/LODObject.h>
69 #include <tdme/engine/Object.h>
76 #include <tdme/engine/Transform.h>
77 #include <tdme/math/Math.h>
78 #include <tdme/math/Vector3.h>
79 #include <tdme/math/Vector4.h>
81 #include <tdme/utilities/Console.h>
86 #include <tdme/utilities/Terrain.h>
87 
88 using std::make_unique;
89 using std::string;
90 using std::to_string;
91 using std::unique_ptr;
92 using std::unordered_map;
93 using std::vector;
94 
96 
97 using tdme::audio::Audio;
98 using tdme::audio::Sound;
143 using tdme::engine::Decal;
149 using tdme::engine::Light;
160 using tdme::math::Math;
161 using tdme::math::Vector3;
162 using tdme::math::Vector4;
170 
171 Model* SceneConnector::emptyModel = nullptr;
172 float SceneConnector::renderGroupsPartitionWidth = 64.0f;
173 float SceneConnector::renderGroupsPartitionHeight = 64.0f;
174 float SceneConnector::renderGroupsPartitionDepth = 64.0f;
175 int SceneConnector::renderGroupsReduceBy = 1;
176 int SceneConnector::renderGroupsLODLevels = 3;
177 float SceneConnector::renderGroupsLOD2MinDistance = 25.0;
178 float SceneConnector::renderGroupsLOD3MinDistance = 50.0;
179 int SceneConnector::renderGroupsLOD2ReduceBy = 4;
180 int SceneConnector::renderGroupsLOD3ReduceBy = 16;
181 
182 void SceneConnector::setNaturalLights(Engine* engine, float t) {
183  // disable all lights
184  for (auto light: engine->getLights()) light->setEnabled(false);
185  // sun
186  auto sunLight = engine->getLightAt(Engine::LIGHTIDX_SUN);
187  auto sunColor = Vector3(1.0f, 1.0f, 1.0f); // engine->getShaderParameter("sky", "sun_color").getVector3Value();
188  auto sunAmbientColor = sunColor * 0.5;
189  auto sunDiffuseColor = sunColor * 0.3;
190  sunLight->setupSun(t);
191  sunLight->setAmbient(Color4(sunAmbientColor[0], sunAmbientColor[1], sunAmbientColor[2], 1.0f));
192  sunLight->setDiffuse(Color4(sunDiffuseColor[0], sunDiffuseColor[1], sunDiffuseColor[2], 1.0f));
193  sunLight->setSpecular(Color4(1.0f, 1.0f, 1.0f, 1.0f));
194  sunLight->setEnabled(true);
195  // moon
196  auto moonLight = engine->getLightAt(Engine::LIGHTIDX_MOON);
197  auto moonColor = Vector3(1.0f, 1.0f, 1.0f); // engine->getShaderParameter("sky", "moon_color").getVector3Value();
198  auto moonAmbientColor = moonColor * 0.5 * 0.5;
199  auto moonDiffuseColor = moonColor * 0.3 * 0.5;
200  moonLight->setupMoon(t);
201  moonLight->setAmbient(Color4(moonAmbientColor[0], moonAmbientColor[1], moonAmbientColor[2], 1.0f));
202  moonLight->setDiffuse(Color4(moonDiffuseColor[0], moonDiffuseColor[1], moonDiffuseColor[2], 1.0f));
203  moonLight->setSpecular(Color4(1.0f, 1.0f, 1.0f, 1.0f));
204  moonLight->setEnabled(true);
205 }
206 
207 void SceneConnector::setLights(Engine* engine, Scene* scene, float t, const Vector3& translation)
208 {
209  //
210  setNaturalLights(engine);
211  // additional lights
212  auto engineLightIdx = static_cast<int>(Engine::LIGHTIDX_OTHERS);
213  for (auto sceneLight: scene->getLights()) {
214  //
215  if (engineLightIdx >= Engine::LIGHTS_MAX) break;
216  //
217  engine->getLightAt(engineLightIdx)->setAmbient(Color4(sceneLight->getAmbient()));
218  engine->getLightAt(engineLightIdx)->setDiffuse(Color4(sceneLight->getDiffuse()));
219  engine->getLightAt(engineLightIdx)->setSpecular(Color4(sceneLight->getSpecular()));
220  engine->getLightAt(engineLightIdx)->setSpotDirection(sceneLight->getSpotDirection());
221  engine->getLightAt(engineLightIdx)->setSpotExponent(sceneLight->getSpotExponent());
222  engine->getLightAt(engineLightIdx)->setSpotCutOff(sceneLight->getSpotCutOff());
223  engine->getLightAt(engineLightIdx)->setConstantAttenuation(sceneLight->getConstantAttenuation());
224  engine->getLightAt(engineLightIdx)->setLinearAttenuation(sceneLight->getLinearAttenuation());
225  engine->getLightAt(engineLightIdx)->setQuadraticAttenuation(sceneLight->getQuadraticAttenuation());
226  engine->getLightAt(engineLightIdx)->setPosition(
227  Vector4(
228  sceneLight->getPosition().getX() + translation.getX(),
229  sceneLight->getPosition().getY() + translation.getY(),
230  sceneLight->getPosition().getZ() + translation.getZ(),
231  sceneLight->getPosition().getW()
232  )
233  );
234  engine->getLightAt(engineLightIdx)->setEnabled(sceneLight->isEnabled());
235  engineLightIdx++;
236  }
237 }
238 
239 Entity* SceneConnector::createParticleSystem(PrototypeParticleSystem* particleSystem, const string& id, bool enableDynamicShadows)
240 {
241  unique_ptr<ParticleEmitter> engineEmitter;
242  {
243  auto emitterType = particleSystem->getEmitter();
244  if (emitterType == PrototypeParticleSystem_Emitter::NONE) {
245  return nullptr;
246  } else
247  if (emitterType == PrototypeParticleSystem_Emitter::POINT_PARTICLE_EMITTER) {
248  auto emitter = particleSystem->getPointParticleEmitter();
249  engineEmitter = make_unique<PointParticleEmitter>(emitter->getCount(), emitter->getLifeTime(), emitter->getLifeTimeRnd(), emitter->getMass(), emitter->getMassRnd(), emitter->getPosition(), emitter->getVelocity(), emitter->getVelocityRnd(), emitter->getColorStart(), emitter->getColorEnd());
250  } else
251  if (emitterType == PrototypeParticleSystem_Emitter::BOUNDINGBOX_PARTICLE_EMITTER) {
252  auto emitter = particleSystem->getBoundingBoxParticleEmitters();
253  engineEmitter = make_unique<BoundingBoxParticleEmitter>(emitter->getCount(), emitter->getLifeTime(), emitter->getLifeTimeRnd(), emitter->getMass(), emitter->getMassRnd(), new OrientedBoundingBox(emitter->getObbCenter(), emitter->getObbAxis0(), emitter->getObbAxis1(), emitter->getObbAxis2(), emitter->getObbHalfextension()), emitter->getVelocity(), emitter->getVelocityRnd(), emitter->getColorStart(), emitter->getColorEnd());
254  } else
255  if (emitterType == PrototypeParticleSystem_Emitter::CIRCLE_PARTICLE_EMITTER) {
256  auto emitter = particleSystem->getCircleParticleEmitter();
257  engineEmitter = make_unique<CircleParticleEmitter>(emitter->getCount(), emitter->getLifeTime(), emitter->getLifeTimeRnd(), emitter->getAxis0(), emitter->getAxis1(), emitter->getCenter(), emitter->getRadius(), emitter->getMass(), emitter->getMassRnd(), emitter->getVelocity(), emitter->getVelocityRnd(), emitter->getColorStart(), emitter->getColorEnd());
258  } else
259  if (emitterType == PrototypeParticleSystem_Emitter::CIRCLE_PARTICLE_EMITTER_PLANE_VELOCITY) {
260  auto emitter = particleSystem->getCircleParticleEmitterPlaneVelocity();
261  engineEmitter = make_unique<CircleParticleEmitterPlaneVelocity>(emitter->getCount(), emitter->getLifeTime(), emitter->getLifeTimeRnd(), emitter->getAxis0(), emitter->getAxis1(), emitter->getCenter(), emitter->getRadius(), emitter->getMass(), emitter->getMassRnd(), emitter->getVelocity(), emitter->getVelocityRnd(), emitter->getColorStart(), emitter->getColorEnd());
262  } else
263  if (emitterType == PrototypeParticleSystem_Emitter::SPHERE_PARTICLE_EMITTER) {
264  auto emitter = particleSystem->getSphereParticleEmitter();
265  engineEmitter = make_unique<SphereParticleEmitter>(emitter->getCount(), emitter->getLifeTime(), emitter->getLifeTimeRnd(), emitter->getMass(), emitter->getMassRnd(), new Sphere(emitter->getCenter(), emitter->getRadius()), emitter->getVelocity(), emitter->getVelocityRnd(), emitter->getColorStart(), emitter->getColorEnd());
266  } else {
267  Console::println(
268  string(
269  "SceneConnector::createParticleSystem(): unknown particle system emitter '" +
270  particleSystem->getEmitter()->getName() +
271  "'"
272  )
273  );
274  return nullptr;
275  }
276  }
277 
278  {
279  auto particleSystemType = particleSystem->getType();
280  if (particleSystemType == PrototypeParticleSystem_Type::NONE) {
281  return nullptr;
282  } else
283  if (particleSystemType == PrototypeParticleSystem_Type::OBJECT_PARTICLE_SYSTEM) {
284  auto objectParticleSystem = particleSystem->getObjectParticleSystem();
285  if (objectParticleSystem->getModel() == nullptr) return nullptr;
286  return
287  make_unique<ObjectParticleSystem>(
288  id,
289  objectParticleSystem->getModel(),
290  objectParticleSystem->getScale(),
291  objectParticleSystem->isAutoEmit(),
292  enableDynamicShadows,
293  enableDynamicShadows,
294  objectParticleSystem->getMaxCount(),
295  engineEmitter.release()
296  ).release();
297  } else
298  if (particleSystemType == PrototypeParticleSystem_Type::POINT_PARTICLE_SYSTEM) {
299  auto pointParticleSystem = particleSystem->getPointParticleSystem();
300  return
301  make_unique<PointsParticleSystem>(
302  id,
303  engineEmitter.release(),
304  pointParticleSystem->getMaxPoints(),
305  pointParticleSystem->getPointSize(),
306  pointParticleSystem->isAutoEmit(),
307  pointParticleSystem->getTextureReference(),
308  pointParticleSystem->getTextureHorizontalSprites(),
309  pointParticleSystem->getTextureVerticalSprites(),
310  pointParticleSystem->getTextureSpritesFPS()
311  ).release();
312  } else
313  if (particleSystemType == PrototypeParticleSystem_Type::FOG_PARTICLE_SYSTEM) {
314  auto fogParticleSystem = particleSystem->getFogParticleSystem();
315  return
316  make_unique<FogParticleSystem>(
317  id,
318  engineEmitter.release(),
319  fogParticleSystem->getMaxPoints(),
320  fogParticleSystem->getPointSize(),
321  fogParticleSystem->getTextureReference(),
322  fogParticleSystem->getTextureHorizontalSprites(),
323  fogParticleSystem->getTextureVerticalSprites(),
324  fogParticleSystem->getTextureSpritesFPS()
325  ).release();
326  } else {
327  Console::println(
328  string(
329  "SceneConnector::createParticleSystem(): unknown particle system type '" +
330  particleSystem->getType()->getName() +
331  "'"
332  )
333  );
334  return nullptr;
335  }
336  }
337 }
338 
339 Entity* SceneConnector::createEmpty(const string& id, const Transform& transform) {
340  if (emptyModel == nullptr) {
341  emptyModel = ModelReader::read("resources/engine/models", "empty.tm");
342  }
343  auto entity = new Object(
344  id,
346  );
347  entity->setTransform(transform);
348  return entity;
349 }
350 
351 Entity* SceneConnector::createEditorDecalEntity(Prototype* prototype, const string& id, const Transform& transform, int instances) {
352  // decals only here :D
353  if (prototype->getType() != Prototype_Type::DECAL) return nullptr;
354 
355  //
356  Entity* entity = nullptr;
357 
358  // add decal OBB
359  auto entityHierarchy = make_unique<EntityHierarchy>(id);
360  {
361  auto i = 0;
362  for (auto prototypeBoundingVolume: prototype->getBoundingVolumes()) {
363  if (prototypeBoundingVolume->getModel() != nullptr) {
364  auto bvObject = new Object("tdme.prototype.bv." + to_string(i), prototypeBoundingVolume->getModel());
365  bvObject->setRenderPass(Entity::RENDERPASS_POST_POSTPROCESSING);
366  entityHierarchy->addEntity(bvObject);
367  }
368  i++;
369  }
370  }
371  // add decal itself
372  if (prototype->getBoundingVolumeCount() == 1 &&
373  dynamic_cast<OrientedBoundingBox*>(prototype->getBoundingVolume(0)->getBoundingVolume()) != nullptr) {
374  entityHierarchy->addEntity(
375  new Decal(
376  "decal",
377  dynamic_cast<OrientedBoundingBox*>(prototype->getBoundingVolume(0)->getBoundingVolume()),
378  prototype->getDecal()->getTextureReference(),
379  prototype->getDecal()->getTextureHorizontalSprites(),
380  prototype->getDecal()->getTextureVerticalSprites(),
381  prototype->getDecal()->getTextureSpritesFPS()
382  )
383  );
384  }
385 
386  //
387  entityHierarchy->setTransform(transform);
388  entityHierarchy->update();
389  if (entityHierarchy->getEntities().size() == 0) {
390  entityHierarchy->dispose();
391  } else {
392  entity = entityHierarchy.release();
393  }
394 
395  // done
396  return entity;
397 }
398 
399 Entity* SceneConnector::createEntity(Prototype* prototype, const string& id, const Transform& transform, int instances, bool noEntityHierarchy) {
400  Entity* entity = nullptr;
401 
402  // objects
403  if (prototype->getModel() != nullptr) {
404  auto imposterLOD = prototype->getImposterLOD();
405  auto lodLevel2 = prototype->getLODLevel2();
406  auto lodLevel3 = prototype->getLODLevel3();
407  // with LOD
408  if (imposterLOD != nullptr) {
409  entity = new LODObjectImposter(
410  id,
411  prototype->getModel(),
412  imposterLOD->getModels(),
413  imposterLOD->getMinDistance()
414  );
415  auto imposterLodObject = dynamic_cast<LODObjectImposter*>(entity);
416  imposterLodObject->setEffectColorAddLOD2(imposterLOD->getColorAdd());
417  imposterLodObject->setEffectColorMulLOD2(imposterLOD->getColorMul());
418  if (prototype->getShader() == "water" || prototype->getShader() == "pbr-water") imposterLodObject->setRenderPass(Entity::RENDERPASS_WATER);
419  imposterLodObject->setShader(prototype->getShader());
420  for (const auto& parameterName: Engine::getShaderParameterNames(prototype->getShader())) {
421  auto parameterValue = prototype->getShaderParameters().getShaderParameter(parameterName);
422  imposterLodObject->setShaderParameter(parameterName, parameterValue);
423  }
424  } else
425  if (lodLevel2 != nullptr) {
426  entity = new LODObject(
427  id,
428  prototype->getModel(),
429  lodLevel2->getType(),
430  lodLevel2->getMinDistance(),
431  lodLevel2->getModel(),
432  lodLevel3 != nullptr?lodLevel3->getType():LODObject::LODLEVELTYPE_NONE,
433  lodLevel3 != nullptr?lodLevel3->getMinDistance():0.0f,
434  lodLevel3 != nullptr?lodLevel3->getModel():nullptr
435  );
436  auto lodObject = dynamic_cast<LODObject*>(entity);
437  lodObject->setEffectColorAddLOD2(lodLevel2->getColorAdd());
438  lodObject->setEffectColorMulLOD2(lodLevel2->getColorMul());
439  if (lodLevel3 != nullptr) {
440  lodObject->setEffectColorAddLOD3(lodLevel3->getColorAdd());
441  lodObject->setEffectColorMulLOD3(lodLevel3->getColorMul());
442  }
443  if (prototype->getShader() == "water" || prototype->getShader() == "pbr-water") lodObject->setRenderPass(Entity::RENDERPASS_WATER);
444  lodObject->setShader(prototype->getShader());
445  for (const auto& parameterName: Engine::getShaderParameterNames(prototype->getShader())) {
446  auto parameterValue = prototype->getShaderParameters().getShaderParameter(parameterName);
447  lodObject->setShaderParameter(parameterName, parameterValue);
448  }
449  } else {
450  // single
451  entity = new Object(
452  id,
453  prototype->getModel(),
454  instances
455  );
456  auto object = dynamic_cast<Object*>(entity);
457  object->setAnimationComputationLODEnabled(true);
458  if (prototype->getShader() == "water" || prototype->getShader() == "pbr-water") object->setRenderPass(Entity::RENDERPASS_WATER);
459  object->setShader(prototype->getShader());
460  for (const auto& parameterName: Engine::getShaderParameterNames(prototype->getShader())) {
461  auto parameterValue = prototype->getShaderParameters().getShaderParameter(parameterName);
462  object->setShaderParameter(parameterName, parameterValue);
463  }
464  }
465  } else
466  // particle system
467  if (prototype->getType() == Prototype_Type::PARTICLESYSTEM) {
468  vector<ParticleSystem*> particleSystems;
469  auto i = 0;
470  for (auto prototypeParticleSystem: prototype->getParticleSystems()) {
471  auto particleSystem = createParticleSystem(
472  prototypeParticleSystem,
473  id + (i == 0?"":"." + to_string(i)),
474  true
475  );
476  if (particleSystem != nullptr) particleSystems.push_back(dynamic_cast<ParticleSystem*>(particleSystem));
477  i++;
478  }
479  if (particleSystems.size() == 1) {
480  entity = dynamic_cast<Entity*>(particleSystems[0]);
481  } else
482  if (particleSystems.size() > 1) {
483  entity = new ParticleSystemGroup(
484  id,
485  true,
486  true,
487  true,
488  particleSystems
489  );
490  }
491  } else
492  // decal
493  if (prototype->getType() == Prototype_Type::DECAL) {
494  entity =
495  new Decal(
496  id,
497  dynamic_cast<OrientedBoundingBox*>(prototype->getBoundingVolume(0)->getBoundingVolume()),
498  prototype->getDecal()->getTextureReference(),
499  prototype->getDecal()->getTextureHorizontalSprites(),
500  prototype->getDecal()->getTextureVerticalSprites(),
501  prototype->getDecal()->getTextureSpritesFPS()
502  );
503  } else
504  // trigger/environment mapping
505  if (prototype->getType() == Prototype_Type::TRIGGER ||
506  prototype->getType() == Prototype_Type::ENVIRONMENTMAPPING) {
507  // bounding volumes
508  auto entityHierarchy = make_unique<EntityHierarchy>(id);
509  {
510  auto i = 0;
511  for (auto prototypeBoundingVolume: prototype->getBoundingVolumes()) {
512  if (prototypeBoundingVolume->getModel() != nullptr) {
513  auto bvObject = new Object("tdme.prototype.bv." + to_string(i), prototypeBoundingVolume->getModel());
514  bvObject->setRenderPass(Entity::RENDERPASS_POST_POSTPROCESSING);
515  entityHierarchy->addEntity(bvObject);
516  }
517  i++;
518  }
519  }
520  if (prototype->getType() == Prototype_Type::ENVIRONMENTMAPPING &&
521  prototype->getBoundingVolumeCount() == 1 &&
522  dynamic_cast<OrientedBoundingBox*>(prototype->getBoundingVolume(0)->getBoundingVolume()) != nullptr) {
523  BoundingBox aabb(dynamic_cast<OrientedBoundingBox*>(prototype->getBoundingVolume(0)->getBoundingVolume()));
524  auto environmentMapping = new EnvironmentMapping("environmentmapping", Engine::getEnvironmentMappingWidth(), Engine::getEnvironmentMappingHeight(), aabb);
525  environmentMapping->setRenderPassMask(prototype->getEnvironmentMapRenderPassMask());
526  environmentMapping->setTimeRenderUpdateFrequency(prototype->getEnvironmentMapTimeRenderUpdateFrequency());
527  entityHierarchy->addEntity(environmentMapping);
528  }
529  entityHierarchy->update();
530  if (entityHierarchy->getEntities().size() == 0) {
531  entityHierarchy->dispose();
532  } else {
533  entity = entityHierarchy.release();
534  }
535  }
536 
537  //
538  if (noEntityHierarchy == false && prototype->isEntityHierarchy() == true && dynamic_cast<EntityHierarchy*>(entity) == nullptr) {
539  auto entityHierarchy = new EntityHierarchy(id);
540  entityHierarchy->addEntity(entity);
541  // pass on entity hierarchy as entity
542  entity = entityHierarchy;
543  }
544 
545  //
546  if (entity != nullptr) {
547  if (prototype->isTerrainMesh() == true) entity->setRenderPass(Entity::RENDERPASS_TERRAIN);
548  entity->setContributesShadows(prototype->isContributesShadows());
549  entity->setReceivesShadows(prototype->isReceivesShadows());
550  entity->setTransform(transform);
551  }
552 
553  // done
554  return entity;
555 }
556 
557 Entity* SceneConnector::createEditorDecalEntity(SceneEntity* sceneEntity, const Vector3& translation, int instances) {
558  Transform transform;
559  transform.setTransform(sceneEntity->getTransform());
560  if (translation.equals(Vector3()) == false) {
561  transform.setTranslation(transform.getTranslation().clone().add(translation));
562  transform.update();
563  }
564  return createEditorDecalEntity(sceneEntity->getPrototype(), sceneEntity->getId(), transform, instances);
565 }
566 
567 Entity* SceneConnector::createEntity(SceneEntity* sceneEntity, const Vector3& translation, int instances, bool noEntityHierarchy) {
568  Transform transform;
569  transform.setTransform(sceneEntity->getTransform());
570  if (translation.equals(Vector3()) == false) {
571  transform.setTranslation(transform.getTranslation().clone().add(translation));
572  transform.update();
573  }
574  return createEntity(sceneEntity->getPrototype(), sceneEntity->getId(), transform, instances, noEntityHierarchy);
575 }
576 
577 void SceneConnector::addScene(Engine* engine, Scene* scene, bool addEmpties, bool addTrigger, bool addEnvironmentMapping, bool useEditorDecals, bool pickable, bool enable, const Vector3& translation, ProgressCallback* progressCallback)
578 {
579  auto progressCallbackPtr = unique_ptr<ProgressCallback>(progressCallback);
580  if (progressCallbackPtr != nullptr) progressCallbackPtr->progress(0.0f);
581  // TODO: progress callbacks for terrain
582 
583  // scene library
584  auto sceneLibrary = scene->getLibrary();
585 
586  // terrain
587  {
588  auto prototype = sceneLibrary->getTerrainPrototype();
589  if (prototype != nullptr) {
590  //
591  auto terrain = prototype->getTerrain();
592  auto width = terrain->getWidth();
593  auto depth = terrain->getDepth();
594  // terrain
595  BoundingBox terrainBoundingBox;
596  vector<Model*> terrainModels;
597  Terrain::createTerrainModels(width, depth, 0.0f, terrain->getHeightVector(), terrainBoundingBox, terrainModels/*, true*/); // TODO: finish LOD
598  if (terrainModels.empty() == false) {
599  auto idx = 0;
600  for (auto terrainModel: terrainModels) {
601  auto terrainObject = new Object("tdme.terrain." + to_string(idx++), terrainModel);
602  terrainObject->setRenderPass(Entity::RENDERPASS_TERRAIN);
603  terrainObject->setShader("terrain");
604  terrainObject->setContributesShadows(true);
605  terrainObject->setReceivesShadows(true);
606  terrainObject->setPickable(pickable);
607  terrainObject->setEnabled(enable);
608  terrainObject->setTranslation(translation);
609  terrainObject->update();
610  engine->addEntity(terrainObject);
611  }
612  }
613  // water
614  {
615  auto idx = 0;
616  auto waterPositionMapsIndices = terrain->getWaterPositionMapsIndices();
617  for (auto waterPositionMapIdx: waterPositionMapsIndices) {
618  vector<Model*> waterModels;
619  Terrain::createWaterModels(
620  terrainBoundingBox,
621  prototype->getTerrain()->getWaterPositionMap(waterPositionMapIdx),
622  prototype->getTerrain()->getWaterPositionMapHeight(waterPositionMapIdx),
623  waterPositionMapIdx,
624  waterModels
625  );
626  for (auto waterModel: waterModels) {
627  auto waterObject = new Object("tdme.water." + to_string(idx++), waterModel);
628  waterObject->setRenderPass(Entity::RENDERPASS_WATER);
629  waterObject->setShader("water");
630 
631  waterObject->setContributesShadows(false);
632  waterObject->setReceivesShadows(false);
633  waterObject->setReflectionEnvironmentMappingId("sky_environment_mapping");
634  waterObject->setReflectionEnvironmentMappingPosition(
635  Terrain::computeWaterReflectionEnvironmentMappingPosition(
636  terrain->getWaterPositionMap(waterPositionMapIdx),
637  terrain->getWaterPositionMapHeight(waterPositionMapIdx)
638  )
639  );
640  waterObject->setPickable(pickable);
641  waterObject->setEnabled(enable);
642  waterObject->setTranslation(translation);
643  waterObject->update();
644  engine->addEntity(waterObject);
645  }
646  }
647  }
648  // foliage
649  {
650  //
651  const auto& foliageMaps = terrain->getFoliageMaps();
652 
653  //
654  auto foliageRenderGroupIdx = 0;
655  auto partitionIdx = 0;
656  unordered_map<int, int> prototypeEntityIdx;
657  for (auto& foliageMapPartition: foliageMaps) {
658  auto partitionPrototypeInstanceCount = 0;
659  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
660  partitionPrototypeInstanceCount+= transformVector.size();
661  }
662  if (partitionPrototypeInstanceCount > 0) {
663  unordered_map<string, ObjectRenderGroup*> objectRenderGroupByShaderParameters;
664  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
665  if (transformVector.empty() == true) continue;
666  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
667  if (foliagePrototype->isRenderGroups() == false) {
668  for (auto& transform: transformVector) {
669  auto entity = createEntity(foliagePrototype, "tdme.foliage." + to_string(prototypeIdx) + "." + to_string(prototypeEntityIdx[prototypeIdx]++), transform);
670  if (entity == nullptr) continue;
671  entity->setTranslation(entity->getTranslation().clone().add(translation));
672  entity->setPickable(pickable);
673  entity->setEnabled(enable);
674  entity->update();
675  engine->addEntity(entity);
676  }
677  } else {
678  ObjectRenderGroup* foliagePartitionObjectRenderGroup = nullptr;
679  auto contributesShadows = foliagePrototype->isContributesShadows();
680  auto receivesShadows = foliagePrototype->isReceivesShadows();
681  auto hash = foliagePrototype->getShaderParameters().getShaderParametersHash() + "|" + to_string(contributesShadows) + "|" + to_string(receivesShadows);
682  auto foliagePartitionObjectRenderGroupIt = objectRenderGroupByShaderParameters.find(hash);
683  if (foliagePartitionObjectRenderGroupIt != objectRenderGroupByShaderParameters.end()) {
684  foliagePartitionObjectRenderGroup = foliagePartitionObjectRenderGroupIt->second;
685  }
686  if (foliagePartitionObjectRenderGroup == nullptr) {
687  foliagePartitionObjectRenderGroup =
688  new ObjectRenderGroup(
689  "tdme.fo3rg." + to_string(foliageRenderGroupIdx++),
695  );
696  foliagePartitionObjectRenderGroup->setContributesShadows(contributesShadows);
697  foliagePartitionObjectRenderGroup->setReceivesShadows(receivesShadows);
698  foliagePartitionObjectRenderGroup->setShader(foliagePrototype->getShader());
699  for (const auto& parameterName: Engine::getShaderParameterNames(foliagePrototype->getShader())) {
700  auto parameterValue = foliagePrototype->getShaderParameters().getShaderParameter(parameterName);
701  foliagePartitionObjectRenderGroup->setShaderParameter(parameterName, parameterValue);
702  }
703  foliagePartitionObjectRenderGroup->setPickable(false);
704  foliagePartitionObjectRenderGroup->setEnabled(enable);
705  objectRenderGroupByShaderParameters[hash] = foliagePartitionObjectRenderGroup;
706  }
707 
708  //
709  auto objectIdx = -1;
710  for (auto& transform: transformVector) {
711  objectIdx++;
712  if (objectIdx % renderGroupsReduceBy != 0) continue;
713  foliagePartitionObjectRenderGroup->addObject(foliagePrototype->getModel(), transform);
714  }
715  }
716  }
717  for (const auto& [shaderHashId, foliagePartitionObjectRenderGroup]: objectRenderGroupByShaderParameters) {
718  foliagePartitionObjectRenderGroup->updateRenderGroup();
719  foliagePartitionObjectRenderGroup->setTranslation(translation);
720  foliagePartitionObjectRenderGroup->update();
721  engine->addEntity(foliagePartitionObjectRenderGroup);
722  }
723  }
724  partitionIdx++;
725  }
726  }
727  }
728  }
729 
730  // scene entities
731  unordered_map<string, unordered_map<string, unordered_map<Model*, vector<Transform*>>>> renderGroupEntitiesByShaderPartitionModel;
732  unordered_map<Model*, Prototype*> renderGroupSceneEditorEntities;
733  auto progressStepCurrent = 0;
734  for (auto sceneEntity: scene->getEntities()) {
735  if (progressCallbackPtr != nullptr && progressStepCurrent % 1000 == 0) progressCallbackPtr->progress(0.0f + static_cast<float>(progressStepCurrent) / static_cast<float>(scene->getEntityCount()) * 0.5f);
736  progressStepCurrent++;
737 
738  if (addEmpties == false && sceneEntity->getPrototype()->getType() == Prototype_Type::EMPTY) continue;
739  if (addTrigger == false && sceneEntity->getPrototype()->getType() == Prototype_Type::TRIGGER) continue;
740 
741  if (sceneEntity->getPrototype()->isRenderGroups() == true) {
742  auto minX = sceneEntity->getTransform().getTranslation().getX();
743  auto minY = sceneEntity->getTransform().getTranslation().getY();
744  auto minZ = sceneEntity->getTransform().getTranslation().getZ();
745  auto partitionX = (int)(minX / renderGroupsPartitionWidth);
746  auto partitionY = (int)(minY / renderGroupsPartitionHeight);
747  auto partitionZ = (int)(minZ / renderGroupsPartitionDepth);
748  renderGroupSceneEditorEntities[sceneEntity->getPrototype()->getModel()] = sceneEntity->getPrototype();
749  renderGroupEntitiesByShaderPartitionModel[sceneEntity->getPrototype()->getShader()][to_string(partitionX) + "," + to_string(partitionY) + "," + to_string(partitionZ)][sceneEntity->getPrototype()->getModel()].push_back(&sceneEntity->getTransform());
750  } else {
751  auto entity = sceneEntity->getPrototype()->getType() == Prototype_Type::DECAL && useEditorDecals == true?createEditorDecalEntity(sceneEntity):createEntity(sceneEntity);
752  if (entity == nullptr) continue;
753 
754  entity->setTranslation(entity->getTranslation().clone().add(translation));
755  entity->setPickable(pickable);
756  entity->setContributesShadows(sceneEntity->getPrototype()->isContributesShadows());
757  entity->setReceivesShadows(sceneEntity->getPrototype()->isReceivesShadows());
758  if (sceneEntity->getPrototype()->getType() == Prototype_Type::EMPTY) {
759  entity->setScale(Vector3(Math::sign(entity->getScale().getX()), Math::sign(entity->getScale().getY()), Math::sign(entity->getScale().getZ())));
760  }
761  if (sceneEntity->getPrototype()->getType()->hasNonEditScaleDownMode() == true) {
762  entity->setScale(
763  sceneEntity->getPrototype()->getType()->getNonEditScaleDownModeDimension().
764  clone().
765  scale(
766  Vector3(
767  1.0f / (sceneEntity->getTransform().getScale().getX() * entity->getBoundingBox()->getDimensions().getX()),
768  1.0f / (sceneEntity->getTransform().getScale().getY() * entity->getBoundingBox()->getDimensions().getY()),
769  1.0f / (sceneEntity->getTransform().getScale().getZ() * entity->getBoundingBox()->getDimensions().getZ())
770  )
771  )
772  );
773  }
774  entity->update();
775  entity->setEnabled(enable);
776 
777  auto object = dynamic_cast<Object*>(entity);
778  if (object != nullptr) object->setReflectionEnvironmentMappingId(sceneEntity->getReflectionEnvironmentMappingId());
779 
780  engine->addEntity(entity);
781  }
782  }
783 
784  // do render groups
785  {
786  auto idx = 0;
787  progressStepCurrent = 0;
788  auto progressStepMax = 0;
789  if (progressCallbackPtr != nullptr) {
790  for (const auto& [shaderId, shaderPartitionModelTranformsMap]: renderGroupEntitiesByShaderPartitionModel) {
791  for (const auto& [partitionId, modelTranformsMap]: shaderPartitionModelTranformsMap) {
792  for (const auto& [model, transformVector]: modelTranformsMap) {
793  progressStepMax++;
794  }
795  }
796  }
797  }
798  for (const auto& [shaderId, shaderPartitionModelTranformsMap]: renderGroupEntitiesByShaderPartitionModel) {
799  for (const auto& [partitionId, modelTranformsMap]: shaderPartitionModelTranformsMap) {
800  unordered_map<string, ObjectRenderGroup*> objectRenderGroupsByShaderParameters;
801  for (const auto& [model, transformVector]: modelTranformsMap) {
802  if (progressCallbackPtr != nullptr) {
803  progressCallbackPtr->progress(0.5f + static_cast<float>(progressStepCurrent) / static_cast<float>(progressStepMax) * 0.5f);
804  }
805  progressStepCurrent++;
806  auto prototype = renderGroupSceneEditorEntities[model];
807  auto contributesShadows = prototype->isContributesShadows();
808  auto receivesShadows = prototype->isReceivesShadows();
809  auto hash = prototype->getShaderParameters().getShaderParametersHash() + "|" + to_string(contributesShadows) + "|" + to_string(receivesShadows);
810  if (objectRenderGroupsByShaderParameters.find(hash) == objectRenderGroupsByShaderParameters.end()) {
811  auto objectRenderNode =
812  new ObjectRenderGroup(
813  "tdme.o3rg." + to_string(idx++),
819  );
820  objectRenderNode->setContributesShadows(contributesShadows);
821  objectRenderNode->setReceivesShadows(receivesShadows);
822  objectRenderNode->setShader(prototype->getShader());
823  for (const auto& parameterName: Engine::getShaderParameterNames(prototype->getShader())) {
824  auto parameterValue = prototype->getShaderParameters().getShaderParameter(parameterName);
825  objectRenderNode->setShaderParameter(parameterName, parameterValue);
826  }
827  objectRenderGroupsByShaderParameters[hash] = objectRenderNode;
828  }
829  auto objectRenderNode = objectRenderGroupsByShaderParameters[hash];
830  auto objectIdx = -1;
831  for (const auto& transform: transformVector) {
832  objectIdx++;
833  if (objectIdx % renderGroupsReduceBy != 0) continue;
834  objectRenderNode->addObject(prototype->getModel(), *transform);
835  }
836  }
837  for (const auto& [hash, objectRenderNode]: objectRenderGroupsByShaderParameters) {
838  objectRenderNode->updateRenderGroup();
839  engine->addEntity(objectRenderNode);
840  }
841  }
842  }
843  }
844 
845  //
846  if (progressCallbackPtr != nullptr) {
847  progressCallbackPtr->progress(1.0f);
848  }
849 }
850 
851 Body* SceneConnector::createBody(World* world, Prototype* prototype, const string& id, const Transform& transform, uint16_t collisionTypeId, bool hierarchy, int index, PrototypePhysics_BodyType* overrideType) {
852  //
853  if (prototype->getType() == Prototype_Type::EMPTY) return nullptr;
854  // no physics, no fun with bodies
855  if (prototype->getPhysics() == nullptr) return nullptr;
856  //
857  auto physicsType = overrideType != nullptr?overrideType:prototype->getPhysics()->getType();
858  // trigger
859  if (prototype->getType() == Prototype_Type::TRIGGER) {
860  vector<BoundingVolume*> boundingVolumes;
861  auto j = 0;
862  for (auto prototypeBoundingVolume: prototype->getBoundingVolumes()) {
863  if (index == -1 || index == j) boundingVolumes.push_back(prototypeBoundingVolume->getBoundingVolume());
864  j++;
865  }
866  if (boundingVolumes.size() == 0) return nullptr;
867  return world->addStaticCollisionBody(
868  id,
869  collisionTypeId == 0?BODY_TYPEID_TRIGGER:collisionTypeId,
870  true,
871  transform,
872  boundingVolumes,
873  hierarchy == true || prototype->isEntityHierarchy() == true
874  );
875  } else
876  // model as terrain mesh
877  if (prototype->getType() == Prototype_Type::MODEL &&
878  prototype->isTerrainMesh() == true) {
879  ObjectModel terrainModel(prototype->getModel());
880  auto terrainMesh = new TerrainMesh(&terrainModel, transform);
881  if (physicsType == PrototypePhysics_BodyType::COLLISION_BODY) {
882  return world->addStaticCollisionBody(
883  id,
884  collisionTypeId == 0?BODY_TYPEID_COLLISION:collisionTypeId,
885  true,
886  Transform(),
887  {terrainMesh},
888  hierarchy == true || prototype->isEntityHierarchy() == true
889  );
890  } else
891  if (physicsType == PrototypePhysics_BodyType::STATIC_RIGIDBODY) {
892  return world->addStaticRigidBody(
893  id,
894  collisionTypeId == 0?BODY_TYPEID_STATIC:collisionTypeId,
895  true,
896  Transform(),
897  prototype->getPhysics()->getFriction(),
898  {terrainMesh},
899  hierarchy == true || prototype->isEntityHierarchy() == true
900  );
901  } else
902  if (physicsType == PrototypePhysics_BodyType::DYNAMIC_RIGIDBODY) {
903  return world->addRigidBody(
904  id,
905  collisionTypeId == 0?BODY_TYPEID_DYNAMIC:collisionTypeId,
906  true,
907  Transform(),
908  prototype->getPhysics()->getRestitution(),
909  prototype->getPhysics()->getFriction(),
910  prototype->getPhysics()->getMass(),
911  prototype->getPhysics()->getInertiaTensor(),
912  {terrainMesh},
913  hierarchy == true || prototype->isEntityHierarchy() == true
914  );
915  }
916  } else {
917  // normal body
918  vector<BoundingVolume*> boundingVolumes;
919  for (auto j = 0; j < prototype->getBoundingVolumeCount(); j++) {
920  auto entityBv = prototype->getBoundingVolume(j);
921  if (index == -1 || index == j) boundingVolumes.push_back(entityBv->getBoundingVolume());
922  }
923  if (boundingVolumes.size() == 0) return nullptr;
924  if (physicsType == PrototypePhysics_BodyType::COLLISION_BODY) {
925  return world->addStaticCollisionBody(
926  id,
927  collisionTypeId == 0?BODY_TYPEID_COLLISION:collisionTypeId,
928  true,
929  transform,
930  boundingVolumes,
931  hierarchy == true || prototype->isEntityHierarchy() == true
932  );
933  } else
934  if (physicsType == PrototypePhysics_BodyType::STATIC_RIGIDBODY) {
935  return world->addStaticRigidBody(
936  id,
937  true,
938  collisionTypeId == 0?BODY_TYPEID_STATIC:collisionTypeId,
939  transform,
940  prototype->getPhysics()->getFriction(),
941  boundingVolumes,
942  hierarchy == true || prototype->isEntityHierarchy() == true
943  );
944  } else
945  if (physicsType == PrototypePhysics_BodyType::DYNAMIC_RIGIDBODY) {
946  return world->addRigidBody(
947  id,
948  collisionTypeId == 0?BODY_TYPEID_DYNAMIC:collisionTypeId,
949  true,
950  transform,
951  prototype->getPhysics()->getRestitution(),
952  prototype->getPhysics()->getFriction(),
953  prototype->getPhysics()->getMass(),
954  prototype->getPhysics()->getInertiaTensor(),
955  boundingVolumes,
956  hierarchy == true || prototype->isEntityHierarchy() == true
957  );
958  }
959  }
960  return nullptr;
961 }
962 
963 Body* SceneConnector::createBody(World* world, SceneEntity* sceneEntity, const Vector3& translation, uint16_t collisionTypeId, bool hierarchy, int index, PrototypePhysics_BodyType* overrideType) {
964  auto transform = sceneEntity->getTransform();
965  if (translation.equals(Vector3()) == false) {
966  transform.setTranslation(transform.getTranslation().clone().add(translation));
967  transform.update();
968  }
969  return createBody(world, sceneEntity->getPrototype(), sceneEntity->getId(), transform, collisionTypeId, hierarchy, index, overrideType);
970 }
971 
972 BodyHierarchy* SceneConnector::createSubBody(World* world, Prototype* prototype, const string& id, const Transform& transform, const string& bodyHierarchyId, const string& bodyHierarchyParentId) {
973  auto bodyHierarchy = world->getBodyHierarchy(bodyHierarchyId);
974  if (bodyHierarchy == nullptr) {
975  Console::println("SceneConnector::createSubBody(): body hierarchy not found: " + bodyHierarchyId);
976  return nullptr;
977  }
978  bodyHierarchy->addBody(id, transform, prototype->getBoundingVolumesPrimitives(), bodyHierarchyParentId);
979  bodyHierarchy->update();
980  return bodyHierarchy;
981 }
982 
983 void SceneConnector::addScene(World* world, Scene* scene, bool enable, const Vector3& translation, ProgressCallback* progressCallback)
984 {
985  auto progressCallbackPtr = unique_ptr<ProgressCallback>(progressCallback);
986  if (progressCallbackPtr != nullptr) progressCallbackPtr->progress(0.0f);
987  auto progressStepCurrent = 0;
988 
989  // scene library
990  auto sceneLibrary = scene->getLibrary();
991 
992  // terrain + foliage
993  {
994  auto prototype = sceneLibrary->getTerrainPrototype();
995  if (prototype != nullptr) {
996  //
997  auto terrain = prototype->getTerrain();
998  auto width = terrain->getWidth();
999  auto depth = terrain->getDepth();
1000  auto terrainHeightVectorVerticesPerX = static_cast<int>(Math::ceil(width / Terrain::STEP_SIZE));
1001  auto terreinHeightVectorVerticesPerZ = static_cast<int>(Math::ceil(depth / Terrain::STEP_SIZE));
1002  // terrain
1003  auto minHeight = terrain->getHeightVector()[0];
1004  auto maxHeight = terrain->getHeightVector()[0];
1005  for (auto heightValue: terrain->getHeightVector()) {
1006  if (heightValue < minHeight) minHeight = heightValue;
1007  if (heightValue > maxHeight) maxHeight = heightValue;
1008  }
1009  {
1010  // create temporary heightmap, will be cloned by Body::Body()
1011  auto heightMap = make_unique<HeightMap>(
1012  terrainHeightVectorVerticesPerX,
1013  terreinHeightVectorVerticesPerZ,
1014  minHeight,
1015  maxHeight,
1016  terrain->getHeightVector().data()
1017  );
1018  //
1019  Transform transform;
1020  transform.setTranslation(Vector3(width / 2.0f, (minHeight + maxHeight) / 2.0f, depth / 2.0f));
1021  transform.update();
1022  auto rigidBody = world->addStaticRigidBody(
1023  "tdme.terrain",
1025  true,
1026  transform,
1027  0.5f,
1028  {
1029  heightMap.get()
1030  }
1031  );
1032  rigidBody->setEnabled(enable);
1033  }
1034  // single foliage
1035  {
1036  //
1037  const auto& foliageMaps = terrain->getFoliageMaps();
1038 
1039  //
1040  unordered_map<int, int> prototypeBodyIdx;
1041  for (const auto& foliageMapPartition: foliageMaps) {
1042  for (const auto& [prototypeIdx, transformVector]: foliageMapPartition) {
1043  if (transformVector.empty() == true) continue;
1044  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
1045  if (foliagePrototype->isRenderGroups() == true) continue;
1046  for (const auto& foliageTransform: transformVector) {
1047  auto body = createBody(world, foliagePrototype, "tdme.foliage." + to_string(prototypeIdx) + "." + to_string(prototypeBodyIdx[prototypeIdx]++), foliageTransform);
1048  if (body == nullptr) continue;
1049  if (translation.equals(Vector3()) == false) {
1050  auto transform = foliageTransform;
1051  transform.setTranslation(transform.getTranslation().clone().add(translation));
1052  transform.update();
1053  body->setTransform(transform);
1054  }
1055  body->setEnabled(enable);
1056  }
1057  }
1058  }
1059  }
1060  }
1061  }
1062 
1063  //
1064  for (auto sceneEntity: scene->getEntities()) {
1065  //
1066  if (progressCallbackPtr != nullptr && progressStepCurrent % 1000 == 0) progressCallbackPtr->progress(0.0f + static_cast<float>(progressStepCurrent) / static_cast<float>(scene->getEntityCount()) * 1.0f);
1067  progressStepCurrent++;
1068 
1069  //
1070  auto rigidBody = createBody(world, sceneEntity);
1071  if (rigidBody == nullptr) continue;
1072  if (translation.equals(Vector3()) == false) {
1073  auto transform = sceneEntity->getTransform();
1074  transform.setTranslation(transform.getTranslation().clone().add(translation));
1075  transform.update();
1076  rigidBody->setTransform(transform);
1077  }
1078  rigidBody->setEnabled(enable);
1079  }
1080 
1081  //
1082  if (progressCallbackPtr != nullptr) {
1083  progressCallbackPtr->progress(1.0f);
1084  }
1085 }
1086 
1088 {
1089  // terrain + water + foliage render groups + render groups
1090  {
1091  auto idx = 0;
1092  Entity* entity = nullptr;
1093  while ((entity = engine->getEntity("tdme.terrain." + to_string(idx++))) != nullptr) {
1094  entity->setEnabled(false);
1095  }
1096  }
1097  {
1098  auto idx = 0;
1099  Entity* entity = nullptr;
1100  while ((entity = engine->getEntity("tdme.water." + to_string(idx++))) != nullptr) {
1101  entity->setEnabled(false);
1102  }
1103  }
1104  {
1105  auto idx = 0;
1106  Entity* entity = nullptr;
1107  while ((entity = engine->getEntity("tdme.fo3rg." + to_string(idx++))) != nullptr) {
1108  entity->setEnabled(false);
1109  }
1110  }
1111  {
1112  auto idx = 0;
1113  Entity* entity = nullptr;
1114  while ((entity = engine->getEntity("tdme.o3rg." + to_string(idx++))) != nullptr) {
1115  entity->setEnabled(false);
1116  }
1117  }
1118 
1119  // scene library
1120  auto sceneLibrary = scene->getLibrary();
1121 
1122  // single foliage
1123  {
1124  auto prototype = sceneLibrary->getTerrainPrototype();
1125  if (prototype != nullptr) {
1126  //
1127  auto terrain = prototype->getTerrain();
1128  //
1129  for (auto prototypeIdx: terrain->getFoliagePrototypeIndices()) {
1130  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
1131  if (foliagePrototype->isRenderGroups() == true) continue;
1132  for (auto& entityId: terrain->getFoliagePrototypeEntityIds(prototypeIdx)) {
1133  auto entity = engine->getEntity(entityId);
1134  if (entity != nullptr) entity->setEnabled(false);
1135  }
1136  }
1137  }
1138  }
1139 
1140  // scene entities
1141  for (auto sceneEntity: scene->getEntities()) {
1142  auto entity = engine->getEntity(sceneEntity->getId());
1143  if (entity == nullptr)
1144  continue;
1145 
1146  entity->setEnabled(false);
1147  }
1148 }
1149 
1151 {
1152  // terrain
1153  {
1154  auto body = world->getBody("tdme.terrain");
1155  if (body != nullptr) body->setEnabled(false);
1156  }
1157 
1158  // scene library
1159  auto sceneLibrary = scene->getLibrary();
1160 
1161  // single foliage
1162  {
1163  auto prototype = sceneLibrary->getTerrainPrototype();
1164  if (prototype != nullptr) {
1165  //
1166  auto terrain = prototype->getTerrain();
1167  //
1168  for (auto prototypeIdx: terrain->getFoliagePrototypeIndices()) {
1169  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
1170  if (foliagePrototype->isRenderGroups() == true) continue;
1171  for (auto& bodyId: terrain->getFoliagePrototypeEntityIds(prototypeIdx)) {
1172  auto body = world->getBody(bodyId);
1173  if (body != nullptr) body->setEnabled(false);
1174  }
1175  }
1176  }
1177  }
1178 
1179  // scene entities
1180  for (auto sceneEntity: scene->getEntities()) {
1181  auto body = world->getBody(sceneEntity->getId());
1182  if (body == nullptr) continue;
1183  body->setEnabled(false);
1184  }
1185 }
1186 
1187 void SceneConnector::enableScene(Engine* engine, Scene* scene, const Vector3& translation)
1188 {
1189  // terrain + water + foliage render groups + render groups
1190  {
1191  auto idx = 0;
1192  Entity* entity = nullptr;
1193  while ((entity = engine->getEntity("tdme.terrain." + to_string(idx++))) != nullptr) {
1194  entity->setEnabled(true);
1195  }
1196  }
1197  {
1198  auto idx = 0;
1199  Entity* entity = nullptr;
1200  while ((entity = engine->getEntity("tdme.water." + to_string(idx++))) != nullptr) {
1201  entity->setEnabled(true);
1202  }
1203  }
1204  {
1205  auto idx = 0;
1206  Entity* entity = nullptr;
1207  while ((entity = engine->getEntity("tdme.fo3rg." + to_string(idx++))) != nullptr) {
1208  entity->setEnabled(true);
1209  }
1210  }
1211  {
1212  auto idx = 0;
1213  Entity* entity = nullptr;
1214  while ((entity = engine->getEntity("tdme.o3rg." + to_string(idx++))) != nullptr) {
1215  entity->setEnabled(true);
1216  }
1217  }
1218 
1219  // scene library
1220  auto sceneLibrary = scene->getLibrary();
1221 
1222  // single foliage
1223  {
1224  auto prototype = sceneLibrary->getTerrainPrototype();
1225  if (prototype != nullptr) {
1226  //
1227  auto terrain = prototype->getTerrain();
1228  //
1229  for (auto prototypeIdx: terrain->getFoliagePrototypeIndices()) {
1230  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
1231  if (foliagePrototype->isRenderGroups() == true) continue;
1232  for (auto& entityId: terrain->getFoliagePrototypeEntityIds(prototypeIdx)) {
1233  auto entity = engine->getEntity(entityId);
1234  if (entity != nullptr) entity->setEnabled(true);
1235  }
1236  }
1237  }
1238  }
1239 
1240  // scene entities
1241  for (auto sceneEntity: scene->getEntities()) {
1242  auto entity = engine->getEntity(sceneEntity->getId());
1243  if (entity == nullptr)
1244  continue;
1245 
1246  entity->setTransform(sceneEntity->getTransform());
1247  entity->setTranslation(entity->getTranslation().clone().add(translation));
1248  if (sceneEntity->getPrototype()->getType() == Prototype_Type::EMPTY) {
1249  entity->setScale(Vector3(Math::sign(entity->getScale().getX()), Math::sign(entity->getScale().getY()), Math::sign(entity->getScale().getZ())));
1250  }
1251  entity->update();
1252  entity->setEnabled(true);
1253  }
1254 }
1255 
1256 void SceneConnector::enableScene(World* world, Scene* scene, const Vector3& translation)
1257 {
1258  // terrain
1259  {
1260  auto body = world->getBody("tdme.terrain");
1261  if (body != nullptr) {
1262  body->setEnabled(true);
1263  // TODO: translate
1264  }
1265  }
1266 
1267  // scene library
1268  auto sceneLibrary = scene->getLibrary();
1269 
1270  // single foliage
1271  {
1272  auto prototype = sceneLibrary->getTerrainPrototype();
1273  if (prototype != nullptr) {
1274  //
1275  auto terrain = prototype->getTerrain();
1276  //
1277  for (auto prototypeIdx: terrain->getFoliagePrototypeIndices()) {
1278  auto foliagePrototype = prototype->getTerrain()->getFoliagePrototype(prototypeIdx);
1279  if (foliagePrototype->isRenderGroups() == true) continue;
1280  for (auto& bodyId: terrain->getFoliagePrototypeEntityIds(prototypeIdx)) {
1281  auto body = world->getBody(bodyId);
1282  if (body != nullptr) body->setEnabled(true);
1283  }
1284  }
1285  }
1286  }
1287 
1288  // scene entities
1289  Transform transform;
1290  for (auto sceneEntity: scene->getEntities()) {
1291  auto rigidBody = world->getBody(sceneEntity->getId());
1292  if (rigidBody == nullptr) continue;
1293  transform.setTransform(sceneEntity->getTransform());
1294  transform.setTranslation(transform.getTranslation().clone().add(translation));
1295  transform.update();
1296  rigidBody->setTransform(transform);
1297  rigidBody->setEnabled(true);
1298  }
1299 }
1300 
1302  {
1303  auto idx = 0;
1304  Entity* entity = nullptr;
1305  while ((entity = engine->getEntity("tdme.terrain." + to_string(idx++))) != nullptr) {
1306  auto model = unique_ptr<Model>(entity->getEntityType() == Entity::ENTITYTYPE_OBJECT?static_cast<Object*>(entity)->getModel():nullptr);
1307  engine->removeEntity(entity->getId());
1308  }
1309  }
1310  {
1311  auto idx = 0;
1312  Entity* entity = nullptr;
1313  while ((entity = engine->getEntity("tdme.water." + to_string(idx++))) != nullptr) {
1314  auto model = unique_ptr<Model>(entity->getEntityType() == Entity::ENTITYTYPE_OBJECT?static_cast<Object*>(entity)->getModel():nullptr);
1315  engine->removeEntity(entity->getId());
1316  }
1317  }
1318  //
1319  engine->reset();
1320 }
1321 
1322 void SceneConnector::addSounds(Audio* audio, Prototype* prototype, const string& id, int poolSize) {
1323  for (auto soundDefinition: prototype->getSounds()) {
1324  if (soundDefinition->getFileName().length() > 0) {
1325  for (auto poolIdx = 0; poolIdx < poolSize; poolIdx++) {
1326  string pathName = PrototypeReader::getResourcePathName(
1327  Tools::getPathName(prototype->getFileName()),
1328  soundDefinition->getFileName()
1329  );
1330  string fileName = Tools::getFileName(soundDefinition->getFileName());
1331  auto sound = new Sound(
1332  id + "." + soundDefinition->getId() + (poolSize > 1?"." + to_string(poolIdx):""),
1333  pathName,
1334  fileName
1335  );
1336  sound->setGain(soundDefinition->getGain());
1337  sound->setPitch(soundDefinition->getPitch());
1338  sound->setLooping(soundDefinition->isLooping());
1339  sound->setFixed(soundDefinition->isFixed());
1340  audio->addEntity(sound);
1341  }
1342  }
1343  }
1344 }
1345 
Interface to audio module.
Definition: Audio.h:29
void addEntity(AudioEntity *entity)
Adds a audio entity.
Definition: Audio.cpp:67
Sound audio entity implementation.
Definition: Sound.h:19
Color 4 definition class.
Definition: Color4.h:18
Decal entity to be used with engine class.
Definition: Decal.h:36
Engine main class.
Definition: Engine.h:131
bool removeEntity(const string &id)
Removes an entity.
Definition: Engine.cpp:502
Light * getLightAt(int32_t idx)
Returns light at idx (0 <= idx < 8)
Definition: Engine.h:1143
UniquePtrSequenceIterator< Light > getLights()
Definition: Engine.h:1127
void addEntity(Entity *entity)
Adds an entity by id.
Definition: Engine.cpp:357
Entity * getEntity(const string &id)
Returns a entity by given id.
Definition: Engine.h:1175
void reset()
Removes all entities and caches.
Definition: Engine.cpp:716
static int32_t getEnvironmentMappingWidth()
Definition: Engine.h:769
static int32_t getEnvironmentMappingHeight()
Definition: Engine.h:776
static const vector< string > getShaderParameterNames(const string &shaderId)
Returns shader parameter names of shader with given id.
Definition: Engine.h:896
Entity hierarchy to be used with engine class.
const ShaderParameter getShaderParameter(const string &parameterName) const
Returns shader parameter for given parameter name, if the value does not exist, the default will be r...
Engine entity.
Definition: Entity.h:30
@ RENDERPASS_POST_POSTPROCESSING
Definition: Entity.h:85
virtual const string & getId()=0
virtual void setRenderPass(RenderPass renderPass)=0
Set render pass.
virtual EntityType getEntityType()=0
virtual void setTransform(const Transform &transform)=0
Set transform.
virtual void setContributesShadows(bool contributesShadows)=0
Enable/disable contributes shadows.
virtual void setReceivesShadows(bool receivesShadows)=0
Enable/disable receives shadows.
virtual void setEnabled(bool enabled)=0
Enable/disable rendering.
Environment mapping entity.
Fog particle system entity to be used with engine class.
LOD object + imposter to be used with engine class.
void setEffectColorAddLOD2(const Color4 &effectColorAddLOD2)
Set effect color add for LOD2 level.
LOD object to be used with engine class.
Definition: LODObject.h:49
void setEffectColorAddLOD2(const Color4 &effectColorAddLOD2)
Set effect color add for LOD2 level.
Definition: LODObject.h:258
Light representation.
Definition: Light.h:33
void setEnabled(bool enabled)
Set enabled.
Definition: Light.h:87
void setSpecular(const Color4 &specular)
Set specular light component.
Definition: Light.h:132
void setConstantAttenuation(float constantAttenuation)
Set up constant attenuation.
Definition: Light.h:207
void setSpotDirection(const Vector3 &spotDirection)
Set spot direction.
Definition: Light.h:162
void setAmbient(const Color4 &ambient)
Set ambient light component.
Definition: Light.h:102
void setQuadraticAttenuation(float quadraticAttenuation)
Set up quadratic attenuation.
Definition: Light.h:237
void setSpotCutOff(float spotCutOff)
Set spot cut off.
Definition: Light.h:192
void setPosition(const Vector4 &position)
Set light position.
Definition: Light.h:147
void setDiffuse(const Color4 &diffuse)
Set diffuse light component.
Definition: Light.h:117
void setLinearAttenuation(float linearAttenuation)
Set up linear attenuation.
Definition: Light.h:222
void setSpotExponent(float spotExponent)
Set up spot exponent.
Definition: Light.h:177
Object particle system entity to be used with engine class.
Object render group for static objects that might be animated by shaders.
void setShader(const string &id)
Set shader id.
void setReceivesShadows(bool receivesShadows) override
Enable/disable receives shadows.
void setPickable(bool pickable) override
Set this entity pickable.
void setShaderParameter(const string &parameterName, const ShaderParameter &parameterValue)
Set shader parameter for given parameter name.
void addObject(Model *model, const Transform &transform)
Adds a instance to this render group.
void setEnabled(bool enabled) override
Enable/disable rendering.
void setContributesShadows(bool contributesShadows) override
Enable/disable contributes shadows.
Object to be used with engine class.
Definition: Object.h:60
void setReflectionEnvironmentMappingId(const string &reflectionEnvironmentMappingId)
Definition: Object.h:387
void setAnimationComputationLODEnabled(bool animationComputationLODEnabled)
Set transform computing LOD enabled.
Definition: Object.h:483
Particle system group, which combines several particle systems into a group, to be used with engine c...
Point particle system entity to be used with engine class.
Scene engine/physics connector.
static STATIC_DLL_IMPEXT int renderGroupsLODLevels
static Entity * createEditorDecalEntity(Prototype *prototype, const string &id, const Transform &transform, int instances=1)
Create editor decal engine entity.
static BodyHierarchy * createSubBody(World *world, Prototype *prototype, const string &id, const Transform &transform, const string &bodyHierarchyId, const string &bodyHierarchyParentId)
Create sub body in body hierarchy.
static constexpr uint16_t BODY_TYPEID_DYNAMIC
static Entity * createEmpty(const string &id, const Transform &transform)
Create engine entity.
static STATIC_DLL_IMPEXT int renderGroupsReduceBy
static constexpr uint16_t BODY_TYPEID_TRIGGER
static STATIC_DLL_IMPEXT Model * emptyModel
static STATIC_DLL_IMPEXT float renderGroupsPartitionHeight
static void enableScene(Engine *engine, Scene *scene, const Vector3 &translation=Vector3(0.0f, 0.0f, 0.0f))
Enable disabled scene in engine.
static STATIC_DLL_IMPEXT int renderGroupsLOD3ReduceBy
static constexpr uint16_t BODY_TYPEID_COLLISION
static STATIC_DLL_IMPEXT int renderGroupsLOD2ReduceBy
static void setNaturalLights(Engine *engine, float t=0.15f)
Set sun/moon lights.
static void disableScene(Engine *engine, Scene *scene)
Disable scene in engine.
static Entity * createEntity(Prototype *prototype, const string &id, const Transform &transform, int instances=1, bool noEntityHierarchy=false)
Create engine entity.
static constexpr uint16_t BODY_TYPEID_STATIC
static void addScene(Engine *engine, Scene *scene, bool addEmpties, bool addTrigger, bool addEnvironmentMapping, bool useEditorDecals, bool pickable, bool enable=true, const Vector3 &translation=Vector3(0.0f, 0.0f, 0.0f), ProgressCallback *progressCallback=nullptr)
Add scene to engine.
static STATIC_DLL_IMPEXT float renderGroupsPartitionDepth
static Entity * createParticleSystem(PrototypeParticleSystem *particleSystem, const string &id, bool enableDynamicShadows=true)
Create particle system.
static void resetEngine(Engine *engine, Scene *scene)
Reset engine regarding given scene.
static STATIC_DLL_IMPEXT float renderGroupsPartitionWidth
static STATIC_DLL_IMPEXT float renderGroupsLOD3MinDistance
static void setLights(Engine *engine, Scene *scene, float t=0.15f, const Vector3 &translation=Vector3(0.0f, 0.0f, 0.0f))
Set lights from scene.
static STATIC_DLL_IMPEXT float renderGroupsLOD2MinDistance
static Body * createBody(World *world, Prototype *prototype, const string &id, const Transform &transform, uint16_t collisionTypeId=BODY_TYPEID_STANDARD, bool hierarchy=false, int index=BOUNDINGVOLUME_INDEX_NONE, PrototypePhysics_BodyType *overrideType=nullptr)
Create body.
static void addSounds(Audio *audio, Prototype *prototype, const string &id, int poolSize=1)
Add scene entity sounds into given audio instance associated with given id.
Transform which contain scale, rotations and translation.
Definition: Transform.h:29
virtual void setTransform(const Transform &transform)
Set transform.
Definition: Transform.h:177
void setTranslation(const Vector3 &translation)
Set translation.
Definition: Transform.h:64
virtual void update()
Computes transform matrix.
Definition: Transform.cpp:33
const Vector3 & getTranslation() const
Definition: Transform.h:56
Representation of a 3D model.
Definition: Model.h:35
Rigid body class.
Definition: Body.h:41
void setEnabled(bool enabled)
Set up if rigid body is enabled.
Definition: Body.h:215
Dynamic physics world class.
Definition: World.h:38
BodyHierarchy * getBodyHierarchy(const string &id)
Returns body hierarchy identified by id.
Definition: World.cpp:205
Body * getBody(const string &id)
Returns body identified by id.
Definition: World.h:151
Body * addStaticRigidBody(const string &id, uint16_t collisionTypeId, bool enabled, const Transform &transform, float friction, const vector< BoundingVolume * > &boundingVolumes, bool hierarchy=false)
Add a static rigid body.
Definition: World.cpp:181
Body * addStaticCollisionBody(const string &id, uint16_t collisionTypeId, bool enabled, const Transform &transform, const vector< BoundingVolume * > &boundingVolumes, bool hierarchy=false)
Add a static collision body.
Definition: World.cpp:135
Body * addRigidBody(const string &id, uint16_t collisionTypeId, bool enabled, const Transform &transform, float restitution, float friction, float mass, const Vector3 &inertiaTensor, const vector< BoundingVolume * > &boundingVolumes, bool hierarchy=false)
Add a rigid body.
Definition: World.cpp:110
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:26
Convex mesh physics primitive.
Definition: ConvexMesh.h:37
Height map physics primitive.
Definition: HeightMap.h:19
Oriented bounding box physics primitive.
Sphere physics primitive.
Definition: Sphere.h:19
Terrain mesh physics primitive.
Definition: TerrainMesh.h:31
Base property model class.
Definition: BaseProperty.h:15
Prototype audio definition.
Prototype LOD level definition.
PrototypeParticleSystem_PointParticleSystem * getPointParticleSystem()
PrototypeParticleSystem_SphereParticleEmitter * getSphereParticleEmitter()
PrototypeParticleSystem_CircleParticleEmitterPlaneVelocity * getCircleParticleEmitterPlaneVelocity()
PrototypeParticleSystem_PointParticleEmitter * getPointParticleEmitter()
PrototypeParticleSystem_CircleParticleEmitter * getCircleParticleEmitter()
PrototypeParticleSystem_BoundingBoxParticleEmitter * getBoundingBoxParticleEmitters()
PrototypeParticleSystem_ObjectParticleSystem * getObjectParticleSystem()
PrototypeParticleSystem_FogParticleSystem * getFogParticleSystem()
Prototype physics body definitions.
PrototypePhysics_BodyType * getType() const
Prototype * getFoliagePrototype(int prototypeIdx)
Get foliage prototype by given index.
Prototype definition.
Definition: Prototype.h:55
const vector< BoundingVolume * > getBoundingVolumesPrimitives()
Get bounding volumes primitibves to be added to physics engine.
Definition: Prototype.h:308
PrototypeLODLevel * getLODLevel3()
Definition: Prototype.h:341
PrototypeImposterLOD * getImposterLOD()
Definition: Prototype.h:360
PrototypeTerrain * getTerrain()
Definition: Prototype.h:613
const string & getShader()
Get shader.
Definition: Prototype.h:480
PrototypeBoundingVolume * getBoundingVolume(int idx)
Get bounding volume at given index.
Definition: Prototype.h:288
UniquePtrSequenceIterator< PrototypeParticleSystem > getParticleSystems()
Definition: Prototype.h:373
UniquePtrSequenceIterator< PrototypeAudio > getSounds()
Definition: Prototype.h:512
bool isTerrainMesh()
Is terrain mesh.
Definition: Prototype.h:448
UniquePtrSequenceIterator< PrototypeBoundingVolume > getBoundingVolumes()
Definition: Prototype.h:272
PrototypeLODLevel * getLODLevel2()
Definition: Prototype.h:328
int64_t getEnvironmentMapTimeRenderUpdateFrequency()
Definition: Prototype.h:598
PrototypePhysics * getPhysics()
Definition: Prototype.h:321
const EntityShaderParameters & getShaderParameters()
Get shader parameters.
Definition: Prototype.h:497
Scene entity definition.
Definition: SceneEntity.h:23
Scene prototype library definition.
Definition: SceneLibrary.h:32
Prototype * getTerrainPrototype()
Get a terrain prototype.
Definition: SceneLibrary.h:122
Scene light definition.
Definition: SceneLight.h:20
Scene definition.
Definition: Scene.h:50
UniquePtrSequenceIterator< SceneLight > getLights()
Definition: Scene.h:141
UniquePtrSequenceIterator< SceneEntity > getEntities()
Definition: Scene.h:267
SceneLibrary * getLibrary()
Definition: Scene.h:185
Standard math functions.
Definition: Math.h:19
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
float getY() const
Definition: Vector3.h:117
float getX() const
Definition: Vector3.h:100
float getZ() const
Definition: Vector3.h:134
Vector3 & add(float scalar)
Adds a scalar.
Definition: Vector3.h:153
Vector3 clone() const
Clones this vector3.
Definition: Vector3.h:374
bool equals(const Vector3 &vector3, float tolerance=Math::EPSILON) const
Compares this vector3 with given vector3.
Definition: Vector3.h:226
Vector4 class representing vector4 mathematical structure and operations with x, y,...
Definition: Vector4.h:22
Console class.
Definition: Console.h:29
const string & getName() const
Definition: Enum.h:37
Model tools functions class.
Definition: ModelTools.h:42
Mutable utf8 aware string class.
Definition: MutableString.h:23
Helper class to create models from physics primitive bounding volumes.
Definition: Primitives.h:33
String tools class.
Definition: StringTools.h:22
Terrain utility.
Definition: Terrain.h:33
Particle system entity interface.