TDME2  1.9.200
Engine.cpp
Go to the documentation of this file.
1 #include <tdme/engine/Engine.h>
2 
3 #include <algorithm>
4 #include <list>
5 #include <memory>
6 #include <string>
7 
8 #include <tdme/tdme.h>
11 #include <tdme/engine/Texture.h>
13 #include <tdme/engine/Color4.h>
14 #include <tdme/engine/model/Node.h>
45 #include <tdme/engine/Camera.h>
46 #include <tdme/engine/Decal.h>
47 #include <tdme/engine/Entity.h>
55 #include <tdme/engine/Light.h>
56 #include <tdme/engine/Lines.h>
57 #include <tdme/engine/LODObject.h>
59 #include <tdme/engine/Object.h>
65 #include <tdme/engine/Partition.h>
68 #include <tdme/engine/Timing.h>
71 #include <tdme/gui/GUI.h>
72 #include <tdme/gui/GUIParser.h>
73 #include <tdme/math/Math.h>
74 #include <tdme/math/Matrix4x4.h>
75 #include <tdme/math/Vector2.h>
76 #include <tdme/math/Vector3.h>
77 #include <tdme/math/Vector4.h>
83 #include <tdme/utilities/Console.h>
84 #include <tdme/utilities/Float.h>
86 
87 using std::list;
88 using std::make_unique;
89 using std::move;
90 using std::remove;
91 using std::sort;
92 using std::string;
93 using std::to_string;
94 using std::unique_ptr;
95 
140 using tdme::engine::Light;
141 using tdme::engine::Lines;
156 using tdme::gui::GUI;
158 using tdme::math::Math;
160 using tdme::math::Vector2;
161 using tdme::math::Vector3;
162 using tdme::math::Vector4;
171 
172 Engine* Engine::instance = nullptr;
173 Renderer* Engine::renderer = nullptr;
174 unique_ptr<TextureManager> Engine::textureManager;
175 unique_ptr<VBOManager> Engine::vboManager;
176 unique_ptr<MeshManager> Engine::meshManager;
177 unique_ptr<GUIRenderer> Engine::guiRenderer;
178 unique_ptr<BRDFLUTShader> Engine::brdfLUTShader;
179 unique_ptr<FrameBufferRenderShader> Engine::frameBufferRenderShader;
180 unique_ptr<DeferredLightingRenderShader> Engine::deferredLightingRenderShader;
181 unique_ptr<SkyRenderShader> Engine::skyRenderShader;
182 unique_ptr<PostProcessing> Engine::postProcessing;
183 unique_ptr<PostProcessingShader> Engine::postProcessingShader;
184 unique_ptr<Texture2DRenderShader> Engine::texture2DRenderShader;
185 Engine::AnimationProcessingTarget Engine::animationProcessingTarget = Engine::AnimationProcessingTarget::CPU;
186 unique_ptr<ShadowMapCreationShader> Engine::shadowMappingShaderPre;
187 unique_ptr<ShadowMapRenderShader> Engine::shadowMappingShaderRender;
188 unique_ptr<LightingShader> Engine::lightingShader;
189 unique_ptr<ParticlesShader> Engine::particlesShader;
190 unique_ptr<LinesShader> Engine::linesShader;
191 unique_ptr<SkinningShader> Engine::skinningShader;
192 unique_ptr<GUIShader> Engine::guiShader;
193 Engine* Engine::currentEngine = nullptr;
194 bool Engine::skinningShaderEnabled = false;
195 int Engine::threadCount = 0;
196 bool Engine::have4K = false;
197 float Engine::animationBlendingTime = 250.0f;
198 int32_t Engine::shadowMapWidth = 0;
199 int32_t Engine::shadowMapHeight = 0;
200 int32_t Engine::shadowMapRenderLookUps = 0;
201 int32_t Engine::environmentMappingWidth = 1024;
202 int32_t Engine::environmentMappingHeight = 1024;
203 float Engine::animationComputationReduction1Distance = 25.0f;
204 float Engine::animationComputationReduction2Distance = 50.0f;
205 list<Engine::Shader> Engine::shaders;
206 unordered_map<string, Engine::Shader*> Engine::shadersById;
207 unordered_map<string, uint8_t> Engine::uniqueShaderIds;
208 
209 vector<unique_ptr<Engine::EngineThread>> Engine::engineThreads;
210 unique_ptr<Queue<Engine::EngineThreadQueueElement>> Engine::engineThreadsQueue;
211 Engine::EngineThreadQueueElementPool Engine::engineThreadQueueElementPool;
212 
213 Engine::EngineThread::EngineThread(int idx, Queue<EngineThreadQueueElement>* queue):
214  Thread("enginethread"),
215  idx(idx),
216  queue(queue) {
217  //
218  transparentRenderFacesPool = make_unique<TransparentRenderFacesPool>();
219 }
220 
222  Console::println("EngineThread::" + string(__FUNCTION__) + "()[" + to_string(idx) + "]: INIT");
223  while (isStopRequested() == false) {
224  auto element = queue->getElement();
225  if (element == nullptr) break;
226  switch(element->type) {
228  break;
230  element->engine->preRenderFunction(
231  element->objects,
232  idx
233  );
234  element->objects.clear();
235  elementsProcessed++;
236  break;
238  element->engine->computeAnimationsFunction(
239  element->objects,
240  idx
241  );
242  element->objects.clear();
243  elementsProcessed++;
244  break;
246  element->engine->entityRenderer->renderFunction(
247  idx,
248  element->rendering.renderPass,
249  element->objects,
250  objectsByModels,
251  element->rendering.collectTransparentFaces,
252  element->rendering.renderTypes,
253  transparentRenderFacesPool.get()
254  );
255  element->objects.clear();
256  elementsProcessed++;
257  break;
258  }
259  }
260  Console::println("EngineThread::" + string(__FUNCTION__) + "()[" + to_string(idx) + "]: DONE");
261 }
262 
264  if (instance == nullptr) return;
265  delete instance;
266  instance = nullptr;
267 }
268 
270  timing = make_unique<Timing>();
271  sceneColor.set(0.0f, 0.0f, 0.0f, 1.0f);
272  // shadow mapping
273  shadowMappingEnabled = false;
274  skyShaderEnabled = false;
275  //
276  initialized = false;
277  // post processing frame buffers
278  //
280  //
281  effectPassSkip.fill(false);
282 }
283 
285  // set current engine
286  if (currentEngine == this) currentEngine = nullptr;
287 }
288 
289 void Engine::loadTextures(const string& pathName) {
290  lightingShader->loadTextures(pathName);
291  postProcessingShader->loadTextures(pathName);
292  skyRenderShader->loadTextures(pathName);
293  if (shadowMappingShaderPre != nullptr) shadowMappingShaderPre->loadTextures(pathName);
294  if (shadowMappingShaderRender != nullptr) shadowMappingShaderRender->loadTextures(pathName);
295 }
296 
297 Engine* Engine::createOffScreenInstance(int32_t width, int32_t height, bool enableShadowMapping, bool enableDepthBuffer, bool enableGeometryBuffer)
298 {
299  if (instance == nullptr || instance->initialized == false) {
300  Console::println(string("Engine::createOffScreenInstance(): Engine not created or not initialized."));
301  return nullptr;
302  }
303  // create off screen engine
304  auto offScreenEngine = new Engine();
305  offScreenEngine->initialized = true;
306  // create GUI
307  offScreenEngine->gui = make_unique<GUI>(offScreenEngine, guiRenderer.get());
308  // create entity renderer
309  offScreenEngine->entityRenderer = make_unique<EntityRenderer>(offScreenEngine, renderer);
310  offScreenEngine->entityRenderer->initialize();
311  // create framebuffers
312  offScreenEngine->frameBuffer = make_unique<FrameBuffer>(width, height, (enableDepthBuffer == true?FrameBuffer::FRAMEBUFFER_DEPTHBUFFER:0) | FrameBuffer::FRAMEBUFFER_COLORBUFFER);
313  offScreenEngine->frameBuffer->initialize();
314  // create camera, frustum partition
315  offScreenEngine->camera = make_unique<Camera>(renderer);
316  offScreenEngine->gizmoCamera = make_unique<Camera>(renderer);
317  offScreenEngine->gizmoCamera->setFrustumMode(Camera::FRUSTUMMODE_ORTHOGRAPHIC);
318  offScreenEngine->gizmoCamera->setCameraMode(Camera::CAMERAMODE_NONE);
319  offScreenEngine->gizmoCamera->setForwardVector(Vector3(0.0f, 0.0f, -1.0f));
320  offScreenEngine->gizmoCamera->setSideVector(Vector3(1.0f, 0.0f, 0.0f));
321  offScreenEngine->gizmoCamera->setUpVector(Vector3(0.0f, 1.0f, 0.0f));
322  offScreenEngine->gizmoCamera->setZNear(1.0f);
323  offScreenEngine->gizmoCamera->setZFar(400.0f);
324  offScreenEngine->partition = make_unique<OctTreePartition>();
325  // create lights
326  for (auto i = 0; i < offScreenEngine->lights.size(); i++) {
327  offScreenEngine->lights[i] = make_unique<Light>(renderer, i);
328  offScreenEngine->lights[i]->setSourceTexture(TextureReader::read("resources/engine/textures", "sun.png"));
329  }
330  // create shadow mapping
331  if (instance->shadowMappingEnabled == true && enableShadowMapping == true) {
332  offScreenEngine->shadowMapping = make_unique<ShadowMapping>(offScreenEngine, renderer, offScreenEngine->entityRenderer.get());
333  }
334  // geometry buffer
335  if (renderer->isDeferredShadingAvailable() == true && enableGeometryBuffer == true) {
336  offScreenEngine->geometryBuffer = make_unique<GeometryBuffer>(width, height);
337  offScreenEngine->geometryBuffer->initialize();
338  }
339  //
340  offScreenEngine->reshape(width, height);
341  return offScreenEngine;
342 }
343 
345  return renderer->getVendor();
346 }
347 
349  return renderer->getRenderer();
350 }
351 
353 {
354  this->partition = unique_ptr<Partition>(partition);
355 }
356 
358 {
359  {
360  auto entityByIdIt = entitiesById.find(entity->getId());
361  if (entityByIdIt != entitiesById.end()) {
362  // check if we want to add this entity a second time
363  if (entity == entityByIdIt->second) {
364  Console::println("Engine::addEntity(): " + entity->getId() + ": entity already added!");
365  return;
366  }
367  // dispose old entity if any did exist in engine with same id
368  removeEntity(entity->getId());
369  }
370  }
371 
372  // init entity
373  entity->setEngine(this);
374  entity->setRenderer(renderer);
375  entity->initialize();
376  entitiesById[entity->getId()] = entity;
377 
378  // add to partition if enabled and frustum culling requested
379  if (entity->isFrustumCulling() == true && entity->isEnabled() == true) partition->addEntity(entity);
380 }
381 
383  //
384  noFrustumCullingEntities.erase(entity);
386  remove(
389  entity
390  ),
392  autoEmitParticleSystemEntities.erase(entity);
393  requireComputeAnimationEntities.erase(entity);
394  requirePreRenderEntities.erase(entity);
395 
396  // decompose and deregister decal and pps textures
397  DecomposedEntities decomposedEntities;
398  decomposeEntityType(entity, decomposedEntities, true);
399  // objects
400  array<vector<Object*>*, 5> objectsArray = {
401  &decomposedEntities.objects,
402  &decomposedEntities.objectsForwardShading,
403  &decomposedEntities.objectsNoDepthTest,
404  &decomposedEntities.objectsPostPostProcessing,
405  &decomposedEntities.objectsGizmo,
406  };
407  for (auto& objects: objectsArray) {
408  for (auto object: *objects) {
409  if (object->getUniqueModelId() != UNIQUEMODELID_NONE) {
410  deregisterModel(object->getModel());
411  object->setUniqueModelId(UNIQUEMODELID_NONE);
412  }
413  }
414  }
415  // decal textures
416  for (auto decalEntity: decomposedEntities.decalEntities) {
417  decalsTextureAtlas.removeTexture(decalEntity->getDecalTexture());
418  }
419  // remove pps/fps textures
420  for (auto ppsEntity: decomposedEntities.ppses) {
421  auto entityType = ppsEntity->getEntityType();
422  switch (entityType) {
424  ppsTextureAtlas.removeTexture(static_cast<FogParticleSystem*>(ppsEntity)->getTexture());
425  break;
427  ppsTextureAtlas.removeTexture(static_cast<PointsParticleSystem*>(ppsEntity)->getTexture());
428  break;
429  default:
430  break;
431  }
432  }
433  //
434  removeEntityFromLists(entity);
435 }
436 
438  //
439  noFrustumCullingEntities.erase(entity);
441  remove(
444  entity
445  ),
447  );
448  autoEmitParticleSystemEntities.erase(entity);
449 
450  // add to no frustum culling
451  if (entity->isFrustumCulling() == false && entity->getParentEntity() == nullptr) {
452  // otherwise add to no frustum culling entities
453  noFrustumCullingEntities.insert(entity);
455  }
456 
457  // add to auto emit particle system entities
458  auto particleSystemEntity = dynamic_cast<ParticleSystem*>(entity);
459  if (particleSystemEntity != nullptr && particleSystemEntity->isAutoEmit() == true) {
460  autoEmitParticleSystemEntities.insert(particleSystemEntity);
461  }
462 
463  // decompose to engine instances to do pre render
464  DecomposedEntities decomposedEntities;
465  decomposeEntityType(entity, decomposedEntities, true);
466  // objects
467  array<vector<Object*>*, 5> objectsArray = {
468  &decomposedEntities.objects,
469  &decomposedEntities.objectsForwardShading,
470  &decomposedEntities.objectsNoDepthTest,
471  &decomposedEntities.objectsPostPostProcessing,
472  &decomposedEntities.objectsGizmo,
473  };
474  for (auto& objects: objectsArray) {
475  for (auto object: *objects) {
476  object->preRender(renderer->CONTEXTINDEX_DEFAULT);
477  if (object->isRequiringPreRender() == true) requirePreRenderEntities.insert(object);
478  if (object->isRequiringAnimationComputation() == true) requireComputeAnimationEntities.insert(object);
479  if (object->getUniqueModelId() == UNIQUEMODELID_NONE) object->setUniqueModelId(registerModel(object->getModel()));
480  }
481  }
482  // decal textures
483  for (auto decalEntity: decomposedEntities.decalEntities) {
484  decalsTextureAtlas.addTexture(decalEntity->getDecalTexture());
485  }
486  // // remove pps/fps textures
487  for (auto ppsEntity: decomposedEntities.ppses) {
488  auto entityType = ppsEntity->getEntityType();
489  switch (entityType) {
491  ppsTextureAtlas.addTexture(static_cast<FogParticleSystem*>(ppsEntity)->getTexture());
492  break;
494  ppsTextureAtlas.addTexture(static_cast<PointsParticleSystem*>(ppsEntity)->getTexture());
495  break;
496  default:
497  break;
498  }
499  }
500 }
501 
502 bool Engine::removeEntity(const string& id)
503 {
504  // get entity and remove if we have any
505  auto entityByIdIt = entitiesById.find(id);
506  if (entityByIdIt == entitiesById.end()) return false;
507 
508  //
509  auto entity = entityByIdIt->second;
510 
511  //
512  entitiesById.erase(entityByIdIt);
513  autoEmitParticleSystemEntities.erase(entity);
514  noFrustumCullingEntities.erase(entity);
515  requirePreRenderEntities.erase(entity);
516  requireComputeAnimationEntities.erase(entity);
517 
518  // remove from partition if enabled and frustum culling requested
519  if (entity->isFrustumCulling() == true && entity->isEnabled() == true) partition->removeEntity(entity);
520 
521  //
522  removeEntityFromLists(entity);
523 
524  // dispose entity
525  entity->dispose();
526  entity->setEngine(nullptr);
527  entity->setRenderer(nullptr);
528  delete entity;
529 
530  //
531  return true;
532 }
533 
534 inline void Engine::removeFromDecomposedEntities(DecomposedEntities& decomposedEntities, Entity* entity) {
535  // delete from lists
536  decomposedEntities.objects.erase(
537  remove(
538  decomposedEntities.objects.begin(),
539  decomposedEntities.objects.end(),
540  entity
541  ),
542  decomposedEntities.objects.end()
543  );
544  decomposedEntities.objectsForwardShading.erase(
545  remove(
546  decomposedEntities.objectsForwardShading.begin(),
547  decomposedEntities.objectsForwardShading.end(),
548  entity
549  ),
550  decomposedEntities.objectsForwardShading.end()
551  );
552  decomposedEntities.objectsPostPostProcessing.erase(
553  remove(
554  decomposedEntities.objectsPostPostProcessing.begin(),
555  decomposedEntities.objectsPostPostProcessing.end(),
556  entity
557  ),
558  decomposedEntities.objectsPostPostProcessing.end()
559  );
560  decomposedEntities.objectsNoDepthTest.erase(
561  remove(
562  decomposedEntities.objectsNoDepthTest.begin(),
563  decomposedEntities.objectsNoDepthTest.end(),
564  entity
565  ),
566  decomposedEntities.objectsNoDepthTest.end()
567  );
568  decomposedEntities.objectsGizmo.erase(
569  remove(
570  decomposedEntities.objectsGizmo.begin(),
571  decomposedEntities.objectsGizmo.end(),
572  entity
573  ),
574  decomposedEntities.objectsGizmo.end()
575  );
576  decomposedEntities.lodObjects.erase(
577  remove(
578  decomposedEntities.lodObjects.begin(),
579  decomposedEntities.lodObjects.end(),
580  entity
581  ),
582  decomposedEntities.lodObjects.end()
583  );
584  decomposedEntities.opses.erase(
585  remove(
586  decomposedEntities.opses.begin(),
587  decomposedEntities.opses.end(),
588  entity
589  ),
590  decomposedEntities.opses.end()
591  );
592  decomposedEntities.ppses.erase(
593  remove(
594  decomposedEntities.ppses.begin(),
595  decomposedEntities.ppses.end(),
596  entity
597  ),
598  decomposedEntities.ppses.end()
599  );
600  decomposedEntities.psgs.erase(
601  remove(
602  decomposedEntities.psgs.begin(),
603  decomposedEntities.psgs.end(),
604  entity
605  ),
606  decomposedEntities.psgs.end()
607  );
608  decomposedEntities.linesEntities.erase(
609  remove(
610  decomposedEntities.linesEntities.begin(),
611  decomposedEntities.linesEntities.end(),
612  entity
613  ),
614  decomposedEntities.linesEntities.end()
615  );
616  decomposedEntities.decalEntities.erase(
617  remove(
618  decomposedEntities.decalEntities.begin(),
619  decomposedEntities.decalEntities.end(),
620  entity
621  ),
622  decomposedEntities.decalEntities.end()
623  );
624  decomposedEntities.objectRenderGroups.erase(
625  remove(
626  decomposedEntities.objectRenderGroups.begin(),
627  decomposedEntities.objectRenderGroups.end(),
628  entity
629  ),
630  decomposedEntities.objectRenderGroups.end()
631  );
632  decomposedEntities.entityHierarchies.erase(
633  remove(
634  decomposedEntities.entityHierarchies.begin(),
635  decomposedEntities.entityHierarchies.end(),
636  entity
637  ),
638  decomposedEntities.entityHierarchies.end()
639  );
640  decomposedEntities.noFrustumCullingEntities.erase(
641  remove(
642  decomposedEntities.noFrustumCullingEntities.begin(),
643  decomposedEntities.noFrustumCullingEntities.end(),
644  entity
645  ),
646  decomposedEntities.noFrustumCullingEntities.end()
647  );
648  decomposedEntities.environmentMappingEntities.erase(
649  remove(
650  decomposedEntities.environmentMappingEntities.begin(),
651  decomposedEntities.environmentMappingEntities.end(),
652  entity
653  ),
654  decomposedEntities.environmentMappingEntities.end()
655  );
656  decomposedEntities.requirePreRenderEntities.erase(
657  remove(
658  decomposedEntities.requirePreRenderEntities.begin(),
659  decomposedEntities.requirePreRenderEntities.end(),
660  entity
661  ),
662  decomposedEntities.requirePreRenderEntities.end()
663  );
664  decomposedEntities.requireComputeAnimationEntities.erase(
665  remove(
666  decomposedEntities.requireComputeAnimationEntities.begin(),
667  decomposedEntities.requireComputeAnimationEntities.end(),
668  entity
669  ),
670  decomposedEntities.requireComputeAnimationEntities.end()
671  );
672 }
673 
675 {
676  if (entity == nullptr) return;
677  //
679  //
681  removeEntityFromLists(static_cast<ObjectRenderGroup*>(entity)->getEntity());
682  } else
684  auto ops = static_cast<ObjectParticleSystem*>(entity);
685  for (auto subEntity: ops->getObjects()) {
686  removeEntityFromLists(subEntity);
687  }
688  } else
690  auto eh = static_cast<EntityHierarchy*>(entity);
691  for (auto subEntity: eh->getEntities()) {
692  removeEntityFromLists(subEntity);
693  }
694  } else
695  if (entity->getEntityType() == Entity::ENTITYTYPE_LODOBJECT) {
696  auto lo = static_cast<LODObject*>(entity);
697  removeEntityFromLists(lo->getLOD1Object());
698  removeEntityFromLists(lo->getLOD2Object());
699  removeEntityFromLists(lo->getLOD3Object());
700  } else
702  auto io = static_cast<ImposterObject*>(entity);
703  for (auto subEntity: io->getBillboardObjects()) removeEntityFromLists(subEntity);
704  } else
706  auto loi = static_cast<LODObjectImposter*>(entity);
707  removeEntityFromLists(loi->getLOD1Object());
708  for (auto subEntity: loi->getLOD2Object()->getBillboardObjects()) removeEntityFromLists(subEntity);
709  } else
711  auto psg = static_cast<ParticleSystemGroup*>(entity);
712  for (auto subEntity: psg->getParticleSystems()) removeEntityFromLists(subEntity);
713  }
714 }
715 
717 {
718  vector<string> entitiesToRemove;
719  for (const auto& [entityId, entity]: entitiesById) {
720  entitiesToRemove.push_back(entityId);
721  }
722  for (const auto& entityKey: entitiesToRemove) {
723  removeEntity(entityKey);
724  }
725  partition->reset();
726  entityRenderer->reset();
727  if (skinningShaderEnabled == true) skinningShader->reset();
730  // TODO: reset engine thread queue element pool
731 }
732 
734 {
735  // set current engine
736  currentEngine = this;
737 
738  // exit if already initialized like a offscreen engine instance
739  if (initialized == true)
740  return;
741 
742  //
743  renderer = Application::getRenderer();
744  if (renderer == nullptr) {
745  initialized = false;
746  Console::println("No renderer: Exiting!");
747  Application::exit(0);
748  return;
749  }
750 
751  //
752  shadowMappingEnabled = true;
753  if (shadowMappingEnabled == true) {
754  if (getShadowMapWidth() == 0 || getShadowMapHeight() == 0) setShadowMapSize(2048, 2048);
756  }
757  animationProcessingTarget = renderer->isGLCLAvailable() == true || renderer->isComputeShaderAvailable() == true?Engine::AnimationProcessingTarget::GPU:Engine::AnimationProcessingTarget::CPU;
758 
759  // determine if we have the skinning compute shader or OpenCL program
761  animationProcessingTarget = skinningShaderEnabled == true?Engine::AnimationProcessingTarget::GPU:Engine::AnimationProcessingTarget::CPU;
762 
763  // engine thread count
765  if (threadCount == 0) threadCount = Math::clamp(Thread::getHardwareThreadCount() == 0?3:Thread::getHardwareThreadCount() / 2, 2, 3);
766  } else {
767  threadCount = 1;
768  }
769 
770  Console::println(string("TDME2::Thread count: ") + to_string(threadCount));
771 
772  // initialize object buffers
773  ObjectBuffer::initialize();
774 
775  // create manager
776  textureManager = make_unique<TextureManager>(renderer);
777  vboManager = make_unique<VBOManager>(renderer);
778  meshManager = make_unique<MeshManager>();
779 
780  // init
781  initialized = true;
782  renderer->initialize();
784 
785  // graphics device
786  Console::println(string("TDME2::Renderer::Graphics Vendor: ") + renderer->getVendor());
787  Console::println(string("TDME2::Renderer::Graphics Renderer: ") + renderer->getRenderer());
788 
789  // create entity renderer
790  entityRenderer = make_unique<EntityRenderer>(this, renderer);
791  entityRenderer->initialize();
792  GUIParser::initialize();
793 
794  // create GUI
795  guiRenderer = make_unique<GUIRenderer>(renderer);
796  guiRenderer->initialize();
797  gui = make_unique<GUI>(this, guiRenderer.get());
798  gui->initialize();
799 
800  // create camera
801  camera = make_unique<Camera>(renderer);
802  gizmoCamera = make_unique<Camera>(renderer);
804  gizmoCamera->setCameraMode(Camera::CAMERAMODE_NONE);
805  gizmoCamera->setForwardVector(Vector3(0.0f, 0.0f, -1.0f));
806  gizmoCamera->setSideVector(Vector3(1.0f, 0.0f, 0.0f));
807  gizmoCamera->setUpVector(Vector3(0.0f, 1.0f, 0.0f));
808  gizmoCamera->setZNear(1.0f);
809  gizmoCamera->setZFar(400.0f);
810 
811  // create lights
812  for (auto i = 0; i < lights.size(); i++) {
813  lights[i] = make_unique<Light>(renderer, i);
814  lights[i]->setSourceTexture(TextureReader::read("resources/engine/textures", "sun.png"));
815  }
816 
817  // create partition
818  partition = make_unique<OctTreePartition>();
819 
820  // create frame buffer render shader
821  frameBufferRenderShader = make_unique<FrameBufferRenderShader>(renderer);
822  frameBufferRenderShader->initialize();
823 
824  // pbr brdf lut
825  if (renderer->isPBRAvailable() == true) {
826  // brdf lut render shader
827  brdfLUTShader = make_unique<BRDFLUTShader>(renderer);
828  brdfLUTShader->initialize();
829  }
830 
831  // deferred lighting render shader
832  if (renderer->isDeferredShadingAvailable() == true) {
833  deferredLightingRenderShader = make_unique<DeferredLightingRenderShader>(renderer);
834  deferredLightingRenderShader->initialize();
835  }
836 
837  // create frame buffer render shader
838  skyRenderShader = make_unique<SkyRenderShader>(renderer);
839  skyRenderShader->initialize();
840 
841  // create lighting shader
842  lightingShader = make_unique<LightingShader>(renderer);
843  lightingShader->initialize();
844 
845  // create particles shader
846  particlesShader = make_unique<ParticlesShader>(this, renderer);
847  particlesShader->initialize();
848 
849  // create particles shader
850  linesShader = make_unique<LinesShader>(this, renderer);
851  linesShader->initialize();
852 
853  // create gui shader
854  guiShader = make_unique<GUIShader>(renderer);
855  guiShader->initialize();
856 
857  // create post processing shader
858  postProcessingShader = make_unique<PostProcessingShader>(renderer);
859  postProcessingShader->initialize();
860 
861  // create post processing
862  postProcessing = make_unique<PostProcessing>();
863 
864  // create post processing shader
865  texture2DRenderShader = make_unique<Texture2DRenderShader>(renderer);
866  texture2DRenderShader->initialize();
867 
868  // check if texture compression is available
869  if (renderer->isTextureCompressionAvailable() == true) {
870  Console::println("TDME2::BC7 texture compression is available.");
871  } else {
872  Console::println("TDME2::BC7 texture compression is not available.");
873  }
874 
875  // initialize shadow mapping
876  if (shadowMappingEnabled == true) {
877  Console::println("TDME2::Using shadow mapping");
878  shadowMappingShaderPre = make_unique<ShadowMapCreationShader>(renderer);
879  shadowMappingShaderPre->initialize();
880  shadowMappingShaderRender = make_unique<ShadowMapRenderShader>(renderer);
881  shadowMappingShaderRender->initialize();
882  shadowMapping = make_unique<ShadowMapping>(this, renderer, entityRenderer.get());
883  } else {
884  Console::println("TDME2::Not using shadow mapping");
885  }
886 
887  // initialize skinning shader
888  if (skinningShaderEnabled == true) {
889  Console::println("TDME2::Using skinning compute shader");
890  skinningShader = make_unique<SkinningShader>(renderer);
891  skinningShader->initialize();
892  } else {
893  Console::println("TDME2::Not using skinning compute shader");
894  }
895 
896  #define CHECK_INITIALIZED(NAME, SHADER) if (SHADER != nullptr && SHADER->isInitialized() == false) Console::println(string("TDME: ") + NAME + ": Not initialized")
897 
898  CHECK_INITIALIZED("ShadowMapCreationShader", shadowMappingShaderPre);
899  CHECK_INITIALIZED("ShadowMappingShader", shadowMappingShaderRender);
900  CHECK_INITIALIZED("LightingShader", lightingShader);
901  CHECK_INITIALIZED("ParticlesShader", particlesShader);
902  CHECK_INITIALIZED("LinesShader", linesShader);
903  CHECK_INITIALIZED("GUIShader", guiShader);
904  CHECK_INITIALIZED("FrameBufferRenderShader", frameBufferRenderShader);
905  if (brdfLUTShader != nullptr) {
906  CHECK_INITIALIZED("BRDFLUTShader", brdfLUTShader);
907  }
908  CHECK_INITIALIZED("DeferredLightingRenderShader", deferredLightingRenderShader);
909  CHECK_INITIALIZED("SkyRenderShader", skyRenderShader);
910  CHECK_INITIALIZED("PostProcessingShader", postProcessingShader);
911  CHECK_INITIALIZED("Texture2DRenderShader", texture2DRenderShader);
912 
913  // check if initialized
914  // initialized &= objectsFrameBuffer->isInitialized();
915  initialized &= shadowMappingShaderPre == nullptr ? true : shadowMappingShaderPre->isInitialized();
916  initialized &= shadowMappingShaderRender == nullptr ? true : shadowMappingShaderRender->isInitialized();
917  initialized &= lightingShader->isInitialized();
918  initialized &= particlesShader->isInitialized();
919  initialized &= linesShader->isInitialized();
920  initialized &= guiShader->isInitialized();
921  initialized &= frameBufferRenderShader->isInitialized();
922  if (brdfLUTShader != nullptr) {
923  initialized &= brdfLUTShader->isInitialized();
924  }
925  initialized &= deferredLightingRenderShader != nullptr?deferredLightingRenderShader->isInitialized():true;
926  initialized &= skyRenderShader->isInitialized();
927  initialized &= postProcessingShader->isInitialized();
928  initialized &= texture2DRenderShader->isInitialized();
929 
930  // deferred shading
931  if (renderer->isDeferredShadingAvailable() == true) {
932  Console::println("TDME2::Using deferred shading");
933  } else {
934  Console::println("TDME2::Not using deferred shading");
935  }
936 
937  //
938  Console::println(string("TDME2::initialized & ready: ") + to_string(initialized));
939 
940  // shut down engine if not initialized
941  if (initialized == false) {
942  Console::println("Engine not initialized: Exiting!");
943  Application::exit(0);
944  return;
945  }
946 
947  // pbr
948  if (renderer->isPBRAvailable() == true) {
949  Console::println("TDME2::PBR shaders are enabled");
950  Console::println("TDME2::Generating brdf LUT texture");
951  // brdf lut render shader
952  brdfLUTShader->generate();
953  }
954 
955  //
957  engineThreadsQueue = make_unique<Queue<Engine::EngineThreadQueueElement>>(0);
958  engineThreads.resize(threadCount - 1);
959  for (auto i = 0; i < threadCount - 1; i++) {
960  engineThreads[i] = make_unique<EngineThread>(
961  i + 1,
962  engineThreadsQueue.get()
963  );
964  engineThreads[i]->start();
965  }
966  }
967 
968  // show registered shaders
969  dumpShaders();
970 }
971 
972 void Engine::reshape(int32_t width, int32_t height)
973 {
974  // apparently windows sends 0x0 dimension if windows gets minimized
975  if (width == 0 && height == 0) return;
976 
977  // set current engine
978  currentEngine = this;
979 
980  // update our width and height
981  this->width = width;
982  this->height = height;
983 
984  //
985  int _width = scaledWidth != -1?scaledWidth:width;
986  int _height = scaledHeight != -1?scaledHeight:height;
987 
988  // update frame buffer if we have one
989  if (frameBuffer != nullptr) frameBuffer->reshape(_width, _height);
990 
991  // update post processing frame buffer if we have one
992  if (postProcessingFrameBuffer1 != nullptr) postProcessingFrameBuffer1->reshape(_width, _height);
993  if (postProcessingFrameBuffer2 != nullptr) postProcessingFrameBuffer2->reshape(_width, _height);
994  if (postProcessingTemporaryFrameBuffer != nullptr) postProcessingTemporaryFrameBuffer->reshape(_width, _height);
995  if (postProcessingTemporaryFrameBuffer != nullptr) postProcessingTemporaryFrameBuffer->reshape(_width, _height);
996  if (postProcessingTemporaryFrameBuffer != nullptr) postProcessingTemporaryFrameBuffer->reshape(_width, _height);
997 
998  // update shadow mapping
999  if (shadowMapping != nullptr) shadowMapping->reshape(width, height);
1000 
1001  // unset scaling frame buffer if width and height matches scaling
1002  if (this == Engine::instance && scaledWidth != -1 && scaledHeight != -1) {
1003  if (this->width == scaledWidth && this->height == scaledHeight) {
1004  if (frameBuffer != nullptr) frameBuffer->dispose();
1005  frameBuffer = nullptr;
1006  } else {
1007  if (frameBuffer == nullptr) {
1008  frameBuffer = make_unique<FrameBuffer>(_width, _height, FrameBuffer::FRAMEBUFFER_DEPTHBUFFER | FrameBuffer::FRAMEBUFFER_COLORBUFFER);
1009  frameBuffer->initialize();
1010  } else {
1011  frameBuffer->reshape(_width, _height);
1012  }
1013  }
1014  }
1015 
1016  // create geometry buffer if available
1017  if (renderer->isDeferredShadingAvailable() == true) {
1018  if (geometryBuffer == nullptr) {
1019  geometryBuffer = make_unique<GeometryBuffer>(_width, _height);
1020  geometryBuffer->initialize();
1021  } else {
1022  geometryBuffer->reshape(_width, _height);
1023  }
1024  }
1025 
1026  // update GUI system
1027  gui->reshape(width, height);
1028 }
1029 
1030 void Engine::scale(int32_t width, int32_t height)
1031 {
1032  if (this != Engine::instance) return;
1033  scaledWidth = width;
1034  scaledHeight = height;
1035  if (frameBuffer != nullptr) frameBuffer->dispose();
1036  frameBuffer = nullptr;
1037  if (scaledWidth != this->width || scaledHeight != this->height) {
1039  frameBuffer->initialize();
1040  }
1041  reshape(this->width, this->height);
1042 }
1043 
1045 {
1046  scaledWidth = -1;
1047  scaledHeight = -1;
1048  if (frameBuffer != nullptr) frameBuffer->dispose();
1049  frameBuffer = nullptr;
1050  reshape(this->width, this->height);
1051 }
1052 
1054  if (this == Engine::instance && frameBuffer != nullptr) frameBuffer->renderToScreen(this);
1055 }
1056 
1057 void Engine::resetLists(DecomposedEntities& decomposedEntites) {
1058  // clear lists of visible objects
1059  decomposedEntites.objects.clear();
1060  decomposedEntites.objectsForwardShading.clear();
1061  decomposedEntites.objectsPostPostProcessing.clear();
1062  decomposedEntites.objectsNoDepthTest.clear();
1063  decomposedEntites.objectsGizmo.clear();
1064  decomposedEntites.lodObjects.clear();
1065  decomposedEntites.opses.clear();
1066  decomposedEntites.ppses.clear();
1067  decomposedEntites.psgs.clear();
1068  decomposedEntites.linesEntities.clear();
1069  decomposedEntites.decalEntities.clear();
1070  decomposedEntites.objectRenderGroups.clear();
1071  decomposedEntites.entityHierarchies.clear();
1072  decomposedEntites.noFrustumCullingEntities.clear();
1073  decomposedEntites.environmentMappingEntities.clear();
1074  decomposedEntites.requirePreRenderEntities.clear();
1075  decomposedEntites.requireComputeAnimationEntities.clear();
1076 }
1077 
1079 {
1080  // update timing
1081  timing->updateTiming();
1082 
1083  //
1085 }
1086 
1087 void Engine::preRenderFunction(vector<Object*>& objects, int threadIdx) {
1088  for (auto object: objects) object->preRender(threadIdx);
1089 }
1090 
1091 void Engine::computeAnimationsFunction(vector<Object*>& objects, int threadIdx) {
1092  for (auto object: objects) object->computeAnimations(threadIdx);
1093 }
1094 
1095 inline void Engine::decomposeEntityType(Entity* entity, DecomposedEntities& decomposedEntities, bool decomposeAllEntities) {
1096  switch (entity->getEntityType()) {
1098  {
1099  auto object = static_cast<Object*>(entity);
1100  if (object->isDisableDepthTest() == true) {
1101  decomposedEntities.objectsNoDepthTest.push_back(object);
1102  } else
1103  if (object->getRenderPass() == Entity::RENDERPASS_POST_POSTPROCESSING) {
1104  decomposedEntities.objectsPostPostProcessing.push_back(object);
1105  } else
1106  if (object->isRequiringForwardShading() == true &&
1107  (object->getRenderPass() == Entity::RENDERPASS_TERRAIN || object->getRenderPass() == Entity::RENDERPASS_STANDARD) &&
1108  renderer->isDeferredShadingAvailable() == true) {
1109  decomposedEntities.objectsForwardShading.push_back(object);
1110  } else
1111  if (object->getRenderPass() == Entity::RENDERPASS_GIZMO) {
1112  decomposedEntities.objectsGizmo.push_back(object);
1113  } else {
1114  decomposedEntities.objects.push_back(object);
1115  }
1116  }
1117  break;
1119  {
1120  auto lodObject = static_cast<LODObject*>(entity);
1121  if (decomposeAllEntities == true) {
1122  auto lod1Object = lodObject->getLOD1Object();
1123  auto lod2Object = lodObject->getLOD2Object();
1124  auto lod3Object = lodObject->getLOD3Object();
1125  if (lod1Object != nullptr) decomposeEntityType(lod1Object, decomposedEntities);
1126  if (lod2Object != nullptr) decomposeEntityType(lod2Object, decomposedEntities);
1127  if (lod3Object != nullptr) decomposeEntityType(lod3Object, decomposedEntities);
1128  } else {
1129  auto object = lodObject->determineLODObject(camera.get());
1130  if (object != nullptr) decomposeEntityType(object, decomposedEntities, decomposeAllEntities);
1131  }
1132  }
1133  break;
1135  {
1136  auto imposterObject = static_cast<ImposterObject*>(entity);
1137  if (decomposeAllEntities == true) {
1138  for (auto subEntity: imposterObject->getBillboardObjects()) decomposeEntityType(subEntity, decomposedEntities);
1139  } else {
1140  decomposeEntityType(imposterObject->determineBillboardObject(camera.get()), decomposedEntities, decomposeAllEntities);
1141  }
1142  }
1143  break;
1145  {
1146  auto lodObjectImposter = static_cast<LODObjectImposter*>(entity);
1147  if (decomposeAllEntities == true) {
1148  decomposeEntityType(lodObjectImposter->getLOD1Object(), decomposedEntities);
1149  for (auto subEntity: lodObjectImposter->getLOD2Object()->getBillboardObjects()) decomposeEntityType(subEntity, decomposedEntities);
1150  } else {
1151  auto object = lodObjectImposter->determineLODObject(camera.get());
1152  if (object != nullptr) decomposeEntityType(object, decomposedEntities, decomposeAllEntities);
1153  }
1154  }
1155  break;
1157  {
1158  auto opse = static_cast<ObjectParticleSystem*>(entity);
1159  if (decomposeAllEntities == true) {
1160  for (auto object: opse->getObjects()) decomposeEntityType(object, decomposedEntities, decomposeAllEntities);
1161  } else {
1162  for (auto object: opse->getEnabledObjects()) decomposeEntityType(object, decomposedEntities, decomposeAllEntities);
1163  }
1164  decomposedEntities.opses.push_back(opse);
1165  }
1166  break;
1168  {
1169  auto ppse = static_cast<PointsParticleSystem*>(entity);
1170  decomposedEntities.ppses.push_back(ppse);
1171  }
1172  break;
1174  {
1175  auto fpse = static_cast<FogParticleSystem*>(entity);
1176  decomposedEntities.ppses.push_back(fpse);
1177  }
1178  break;
1180  {
1181  auto l = static_cast<Lines*>(entity);
1182  decomposedEntities.linesEntities.push_back(l);
1183  }
1184  break;
1186  {
1187  auto d = static_cast<Decal*>(entity);
1188  decomposedEntities.decalEntities.push_back(d);
1189  }
1190  break;
1192  {
1193  auto eme = static_cast<EnvironmentMapping*>(entity);
1194  decomposedEntities.environmentMappingEntities.push_back(eme);
1195  }
1196  break;
1198  {
1199  auto org = static_cast<ObjectRenderGroup*>(entity);
1200  decomposedEntities.objectRenderGroups.push_back(org);
1201  auto subEntity = org->getEntity();
1202  if (subEntity != nullptr) decomposeEntityType(subEntity, decomposedEntities, decomposeAllEntities);
1203  }
1204  break;
1206  {
1207  auto psg = static_cast<ParticleSystemGroup*>(entity);
1208  decomposedEntities.psgs.push_back(psg); \
1209  for (auto ps: psg->getParticleSystems()) decomposeEntityType(ps, decomposedEntities, decomposeAllEntities);
1210  }
1211  break;
1213  {
1214  auto eh = static_cast<EntityHierarchy*>(entity);
1215  decomposedEntities.entityHierarchies.push_back(eh);
1216  for (auto entityEh: eh->getEntities()) {
1217  if (entityEh->isEnabled() == false && decomposeAllEntities == false) continue;
1218  decomposeEntityType(entityEh, decomposedEntities, decomposeAllEntities);
1219  }
1220  }
1221  break;
1222  default:
1223  break;
1224  }
1225 }
1226 
1227 inline void Engine::decomposeEntityTypes(const vector<Entity*>& entities, DecomposedEntities& decomposedEntities, bool decomposeAllEntities) {
1228  for (auto entity: entities) {
1229  decomposeEntityType(entity, decomposedEntities, decomposeAllEntities);
1230  }
1231 }
1232 
1233 void Engine::preRender(Camera* camera, DecomposedEntities& decomposedEntities, bool autoEmit, bool computeAnimations)
1234 {
1235  // do particle systems auto emit
1236  if (autoEmit == true) {
1237  for (auto entity: autoEmitParticleSystemEntities) {
1238  auto pse = static_cast<ParticleSystem*>(entity);
1239 
1240  // skip on disabled entities
1241  if (pse->isEnabled() == false) continue;
1242 
1243  // do auto emit
1244  pse->emitParticles();
1245  pse->updateParticles();
1246  }
1247  }
1248 
1249  // determine entity types and store them
1251  partition->getVisibleEntities(camera->getFrustum()),
1252  decomposedEntities
1253  );
1254 
1255  // pre render
1256  for (auto entity: requirePreRenderEntities) {
1257  // skip on disabled entities
1258  auto parentEntity = entity->getParentEntity();
1259  if ((parentEntity != nullptr && partition->isVisibleEntity(parentEntity) == false) ||
1260  (parentEntity == nullptr && partition->isVisibleEntity(entity) == false)) continue;
1261  //
1262  decomposedEntities.requirePreRenderEntities.push_back(static_cast<Object*>(entity));
1263  }
1264 
1265  // compute transform
1266  if (computeAnimations == true) {
1267  for (auto entity: requireComputeAnimationEntities) {
1268  // skip on disabled entities
1269  auto parentEntity = entity->getParentEntity();
1270  if ((parentEntity != nullptr && partition->isVisibleEntity(parentEntity) == false) ||
1271  (parentEntity == nullptr && partition->isVisibleEntity(entity) == false)) continue;
1272  //
1273  decomposedEntities.requireComputeAnimationEntities.push_back(static_cast<Object*>(entity));
1274  }
1275  }
1276 
1277  // collect entities that do not have frustum culling enabled
1278  for (auto entity: noFrustumCullingEntities) {
1279  // skip on disabled entities
1280  if (entity->isEnabled() == false) continue;
1281 
1282  //
1283  decomposedEntities.noFrustumCullingEntities.push_back(entity);
1284  }
1285 
1286  // determine additional entity types for objects without frustum culling
1288  decomposedEntities.noFrustumCullingEntities,
1289  decomposedEntities
1290  );
1291 
1292  //
1293  if (skinningShaderEnabled == true) skinningShader->useProgram();
1294  if (renderer->isSupportingMultithreadedRendering() == false) {
1295  //
1296  preRenderFunction(decomposedEntities.requirePreRenderEntities, 0);
1298  } else {
1299  auto elementsIssued = 0;
1300  auto queueElement = engineThreadQueueElementPool.allocate();
1302  queueElement->engine = this;
1303  queueElement->animations.computeAnimations = computeAnimations;
1304  for (auto i = 0; i < decomposedEntities.requirePreRenderEntities.size(); i++) {
1305  queueElement->objects.push_back(decomposedEntities.requirePreRenderEntities[i]);
1306  if (queueElement->objects.size() == Engine::ENGINETHREADSQUEUE_PRERENDER_DISPATCH_COUNT) {
1307  auto queueElementToSubmit = queueElement;
1308  queueElement = engineThreadQueueElementPool.allocate();
1310  queueElement->engine = this;
1311  queueElement->animations.computeAnimations = computeAnimations;
1312  elementsIssued++;
1313  engineThreadsQueue->addElement(queueElementToSubmit, false);
1314  }
1315  }
1316  if (queueElement->objects.empty() == false) {
1317  elementsIssued++;
1318  engineThreadsQueue->addElement(queueElement, false);
1319  queueElement = engineThreadQueueElementPool.allocate();
1320  }
1322  queueElement->engine = this;
1323  queueElement->animations.computeAnimations = computeAnimations;
1324  for (auto i = 0; i < decomposedEntities.requireComputeAnimationEntities.size(); i++) {
1325  queueElement->objects.push_back(decomposedEntities.requireComputeAnimationEntities[i]);
1326  if (queueElement->objects.size() == Engine::ENGINETHREADSQUEUE_COMPUTE_DISPATCH_COUNT) {
1327  auto queueElementToSubmit = queueElement;
1328  queueElement = engineThreadQueueElementPool.allocate();
1330  queueElement->engine = this;
1331  queueElement->animations.computeAnimations = computeAnimations;
1332  elementsIssued++;
1333  engineThreadsQueue->addElement(queueElementToSubmit, false);
1334  }
1335  }
1336  if (queueElement->objects.empty() == false) {
1337  elementsIssued++;
1338  engineThreadsQueue->addElement(queueElement, false);
1339  queueElement = nullptr;
1340  }
1341 
1342  // wait until all elements have been processed
1343  while (true == true) {
1344  auto elementsProcessed = 0;
1345  for (const auto& engineThread: Engine::engineThreads) elementsProcessed+= engineThread->getProcessedElements();
1346  if (elementsProcessed == elementsIssued) {
1347  for (const auto& engineThread: Engine::engineThreads) engineThread->resetProcessedElements();
1348  break;
1349  }
1350  }
1351  // reset pool
1353  }
1354 
1355  //
1356  if (skinningShaderEnabled == true) {
1357  skinningShader->unUseProgram();
1358  }
1359 }
1360 
1362 {
1363  // set current engine
1364  currentEngine = this;
1365 
1366  // execute enqueued actions
1367  if (actions.empty() == false) {
1368  vector<unique_ptr<Action>> currentActions;
1369  for (auto& action: actions) {
1370  currentActions.push_back(move(action));
1371  }
1372  actions.clear();
1373  for (const auto& action: currentActions) {
1374  action->performAction();
1375  }
1376  }
1377 
1378  // finish last frame
1380 
1381  // init frame
1383 
1384  //
1385  initRendering();
1386 
1387  // default context
1388  auto _width = scaledWidth != -1?scaledWidth:width;
1389  auto _height = scaledHeight != -1?scaledHeight:height;
1390 
1391  // camera
1392  camera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
1393  // frustum
1394  camera->getFrustum()->update();
1395 
1396  // do pre rendering steps
1397  preRender(camera.get(), visibleDecomposedEntities, true, true);
1398 
1399  // render environment maps
1400  for (auto environmentMappingEntity: visibleDecomposedEntities.environmentMappingEntities) environmentMappingEntity->render();
1401 
1402  // camera
1403  camera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
1404 
1405  // create shadow maps
1406  if (shadowMapping != nullptr) shadowMapping->createShadowMaps();
1407 
1408  // do post processing programs effect passes
1409  array<bool, EFFECTPASS_COUNT - 1> effectPassFrameBuffersInUse;
1410  effectPassFrameBuffersInUse.fill(false);
1411  effectPassSkip.fill(false);
1412  for (auto programId: postProcessingPrograms) {
1413  auto program = postProcessing->getPostProcessingProgram(programId);
1414  if (program == nullptr) continue;
1415  for (const auto& effectPass: program->getEffectPasses()) {
1416  auto effectPassIdx = effectPass.effectPassIdx;
1417  auto frameBufferIdx = effectPass.effectPassIdx - 1;
1418  auto frameBufferWidth = _width / effectPass.frameBufferWidthDivideFactor;
1419  auto frameBufferHeight = _height / effectPass.frameBufferHeightDivideFactor;
1420  if (effectPassFrameBuffers[frameBufferIdx] == nullptr) {
1421  effectPassFrameBuffers[frameBufferIdx] = make_unique<FrameBuffer>(frameBufferWidth, frameBufferHeight, FrameBuffer::FRAMEBUFFER_COLORBUFFER); // TODO: types of buffers
1422  effectPassFrameBuffers[frameBufferIdx]->initialize();
1423  } else
1424  if (effectPassFrameBuffers[frameBufferIdx]->getWidth() != frameBufferWidth ||
1425  effectPassFrameBuffers[frameBufferIdx]->getHeight() != frameBufferHeight) {
1426  effectPassFrameBuffers[frameBufferIdx]->reshape(frameBufferWidth, frameBufferHeight);
1427  }
1428  effectPassFrameBuffersInUse[frameBufferIdx] = true;
1429  // enable
1430  effectPassFrameBuffers[frameBufferIdx]->enableFrameBuffer();
1431  // clear
1433  effectPass.clearColor.getRed(),
1434  effectPass.clearColor.getGreen(),
1435  effectPass.clearColor.getBlue(),
1436  effectPass.clearColor.getAlpha()
1437  );
1439  // camera
1440  camera->update(renderer->CONTEXTINDEX_DEFAULT, frameBufferWidth, frameBufferHeight);
1441  //
1442  auto lightSourceVisible = false;
1443  if (effectPass.renderLightSources == true) {
1444  if (skyShaderEnabled == true) skyRenderShader->render(this, true);
1445  lightSourceVisible = renderLightSources(frameBufferWidth, frameBufferHeight);
1446  if (skyShaderEnabled == true) lightSourceVisible = true;
1447  }
1448  if (effectPass.skipOnLightSourceNotVisible == true && lightSourceVisible == false) {
1449  effectPassSkip[frameBufferIdx] = true;
1450  } else {
1451  // Do the effect render pass
1452  render(
1453  effectPassFrameBuffers[frameBufferIdx].get(),
1454  nullptr, // TODO: we might want to use a deferred shading here for further effects
1455  camera.get(),
1457  effectPassIdx,
1459  effectPass.shaderPrefix,
1460  false,
1461  false,
1462  false,
1463  false,
1464  EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY |
1465  EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY |
1466  EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY,
1467  false
1468  );
1469  }
1470  }
1471  }
1472 
1473  // dispose effect pass frame buffers that we do not use anymore
1474  for (auto i = 0; i < effectPassFrameBuffersInUse.size(); i++) {
1475  if (effectPassFrameBuffersInUse[i] == false && effectPassFrameBuffers[i] != nullptr) {
1476  effectPassFrameBuffers[i]->dispose();
1477  effectPassFrameBuffers[i] = nullptr;
1478  }
1479  }
1480 
1481  // create post processing frame buffers if having post processing
1482  FrameBuffer* renderFrameBuffer = nullptr;
1483  if (postProcessingPrograms.size() > 0) {
1484  if (postProcessingFrameBuffer1 == nullptr) {
1486  postProcessingFrameBuffer1->initialize();
1487  }
1488  if (postProcessingFrameBuffer2 == nullptr) {
1490  postProcessingFrameBuffer2->initialize();
1491  }
1492  postProcessingFrameBuffer1->enableFrameBuffer();
1493  renderFrameBuffer = postProcessingFrameBuffer1.get();
1494  } else {
1495  if (postProcessingFrameBuffer1 != nullptr) {
1496  postProcessingFrameBuffer1->dispose();
1497  postProcessingFrameBuffer1 = nullptr;
1498  }
1499  if (postProcessingFrameBuffer2 != nullptr) {
1500  postProcessingFrameBuffer2->dispose();
1501  postProcessingFrameBuffer2 = nullptr;
1502  }
1503  // render objects to target frame buffer or screen
1504  if (frameBuffer != nullptr) {
1505  frameBuffer->enableFrameBuffer();
1506  renderFrameBuffer = frameBuffer.get();
1507  } else {
1509  }
1510  }
1511 
1512  // camera
1513  camera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
1514 
1515  // clear previous frame values
1516  if (skyShaderEnabled == true) {
1518  skyRenderShader->render(this, false);
1519  } else {
1522  }
1523 
1524  // do rendering
1525  render(
1526  renderFrameBuffer,
1527  geometryBuffer.get(),
1528  camera.get(),
1532  string(),
1533  true,
1534  true,
1535  true,
1536  true,
1537  EntityRenderer::RENDERTYPE_NORMALS |
1538  EntityRenderer::RENDERTYPE_TEXTUREARRAYS |
1539  EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY |
1540  EntityRenderer::RENDERTYPE_EFFECTCOLORS |
1541  EntityRenderer::RENDERTYPE_MATERIALS |
1542  EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY |
1543  EntityRenderer::RENDERTYPE_TEXTURES |
1544  EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY |
1545  EntityRenderer::RENDERTYPE_LIGHTS,
1547  );
1548 
1549  // delete post processing termporary buffer if not required anymore
1553  }
1554 
1555  //
1556  if (frameBuffer != nullptr) {
1558  }
1559 
1560  // camera
1561  camera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
1562 }
1563 
1564 Vector3 Engine::computeWorldCoordinateByMousePosition(int32_t mouseX, int32_t mouseY, float z, Camera* camera)
1565 {
1566  auto scaleFactorWidth = static_cast<float>(scaledWidth != -1?scaledWidth:width) / static_cast<float>(width);
1567  auto scaleFactorHeight = static_cast<float>(scaledHeight != -1?scaledHeight:height) / static_cast<float>(height);
1568  auto _width = scaledWidth != -1?scaledWidth:width;
1569  auto _height = scaledHeight != -1?scaledHeight:height;
1570  // see: http://stackoverflow.com/questions/7692988/opengl-math-projecting-screen-space-to-world-space-coords-solved
1571  auto worldCoordinate4 = camera->getModelViewProjectionInvertedMatrix().multiply(
1572  Vector4(
1573  (2.0f * (mouseX * scaleFactorWidth) / _width) - 1.0f,
1574  1.0f - (2.0f * (mouseY * scaleFactorHeight) / _height),
1575  2.0f * z - 1.0f,
1576  1.0f
1577  )
1578  );
1579  worldCoordinate4.scale(1.0f / worldCoordinate4.getW());
1580  return Vector3(
1581  worldCoordinate4.getX(),
1582  worldCoordinate4.getY(),
1583  worldCoordinate4.getZ()
1584  );
1585 }
1586 
1588 {
1589  // use framebuffer if we have one
1590  if (frameBuffer != nullptr)
1591  frameBuffer->enableFrameBuffer();
1592 
1593  //
1594  auto scaleFactorWidth = static_cast<float>(scaledWidth != -1?scaledWidth:width) / static_cast<float>(width);
1595  auto scaleFactorHeight = static_cast<float>(scaledHeight != -1?scaledHeight:height) / static_cast<float>(height);
1596 
1597  // see: http://stackoverflow.com/questions/7692988/opengl-math-projecting-screen-space-to-world-space-coords-solved
1598  auto z = renderer->readPixelDepth(mouseX * scaleFactorWidth, (height - mouseY) * scaleFactorHeight);
1599 
1600  // unuse framebuffer if we have one
1601  if (frameBuffer != nullptr)
1603 
1604  //
1605  return computeWorldCoordinateByMousePosition(mouseX, mouseY, z, camera.get());
1606 }
1607 
1609  DecomposedEntities& decomposedEntities,
1610  bool forcePicking,
1611  int32_t mouseX,
1612  int32_t mouseY,
1613  EntityPickingFilter* filter,
1614  Node** objectNode,
1615  ParticleSystem** particleSystemEntity
1616 ) {
1617  //
1618  Vector3 boundingBoxLineContactMin;
1619  Vector3 boundingBoxLineContactMax;
1620  Vector3 lineTriangleContact;
1621 
1622  // selected entity
1623  auto selectedEntityDistance = Float::MAX_VALUE;
1624  Entity* selectedEntity = nullptr;
1625  Node* selectedObjectNode = nullptr;
1626  ParticleSystem* selectedParticleSystem = nullptr;
1627 
1628  // iterate gizmo objects that have no depth test, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1629  if (decomposedEntities.objectsGizmo.empty() == false) {
1630  //
1631  auto nearPlaneWorldCoordinate = computeGizmoCoordinateByMousePosition(mouseX, mouseY, 0.0f);
1632  auto farPlaneWorldCoordinate = computeGizmoCoordinateByMousePosition(mouseX, mouseY, 1.0f);
1633 
1634  //
1635  for (auto entity: decomposedEntities.objectsGizmo) {
1636  // skip if not pickable or ignored by filter
1637  if (forcePicking == false && entity->isPickable() == false) continue;
1638  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1639  // do the collision test
1640  for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1641  const auto& vertices = it->next();
1642  if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], nearPlaneWorldCoordinate, farPlaneWorldCoordinate, lineTriangleContact) == true) {
1643  auto entityDistance = lineTriangleContact.sub(nearPlaneWorldCoordinate).computeLengthSquared();
1644  // check if match or better match
1645  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1646  selectedEntity = entity;
1647  selectedEntityDistance = entityDistance;
1648  selectedObjectNode = it->getNode();
1649  selectedParticleSystem = nullptr;
1650  }
1651  }
1652  }
1653  }
1654 
1655  // they have first priority right now
1656  if (selectedEntity != nullptr) {
1657  if (objectNode != nullptr) *objectNode = selectedObjectNode;
1658  for (auto _entity = selectedEntity; _entity != nullptr; _entity = _entity->getParentEntity()) {
1659  if (_entity->getParentEntity() == nullptr) {
1660  return _entity;
1661  }
1662  }
1663  return nullptr;
1664  }
1665  }
1666 
1667  // get world position of mouse position at near and far plane
1668  auto nearPlaneWorldCoordinate = computeWorldCoordinateByMousePosition(mouseX, mouseY, 0.0f);
1669  auto farPlaneWorldCoordinate = computeWorldCoordinateByMousePosition(mouseX, mouseY, 1.0f);
1670 
1671  // iterate visible entity decals, check if ray with given mouse position from near plane to far plane collides with bounding volume
1672  for (auto entity: decomposedEntities.decalEntities) {
1673  // skip if not pickable or ignored by filter
1674  if (forcePicking == false && entity->isPickable() == false) continue;
1675  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1676  // do the collision test
1677  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1678  auto entityDistance = lineTriangleContact.set(entity->getWorldBoundingBox()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1679  // check if match or better match
1680  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1681  selectedEntity = entity;
1682  selectedEntityDistance = entityDistance;
1683  selectedObjectNode = nullptr;
1684  selectedParticleSystem = nullptr;
1685  }
1686  }
1687  }
1688 
1689  // decals have first priority right now
1690  if (selectedEntity != nullptr) {
1691  if (objectNode != nullptr) *objectNode = selectedObjectNode;
1692  for (auto _entity = selectedEntity; _entity != nullptr; _entity = _entity->getParentEntity()) {
1693  if (_entity->getParentEntity() == nullptr) return _entity;
1694  }
1695  return nullptr;
1696  }
1697 
1698  // iterate visible objects that have no depth test, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1699  for (auto entity: decomposedEntities.objectsNoDepthTest) {
1700  // skip if not pickable or ignored by filter
1701  if (forcePicking == false && entity->isPickable() == false) continue;
1702  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1703  // do the collision test
1704  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1705  for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1706  const auto& vertices = it->next();
1707  if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], nearPlaneWorldCoordinate, farPlaneWorldCoordinate, lineTriangleContact) == true) {
1708  auto entityDistance = lineTriangleContact.sub(nearPlaneWorldCoordinate).computeLengthSquared();
1709  // check if match or better match
1710  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1711  selectedEntity = entity;
1712  selectedEntityDistance = entityDistance;
1713  selectedObjectNode = it->getNode();
1714  selectedParticleSystem = nullptr;
1715  }
1716  }
1717  }
1718  }
1719  }
1720 
1721  // objects without depth test have second priority right now
1722  if (selectedEntity != nullptr) {
1723  if (objectNode != nullptr) *objectNode = selectedObjectNode;
1724  for (auto _entity = selectedEntity; _entity != nullptr; _entity = _entity->getParentEntity()) {
1725  if (_entity->getParentEntity() == nullptr) return _entity;
1726  }
1727  return nullptr;
1728  }
1729 
1730  // iterate visible object partition systems, check if ray with given mouse position from near plane to far plane collides with bounding volume
1731  for (auto entity: decomposedEntities.opses) {
1732  // skip if not pickable or ignored by filter
1733  if (forcePicking == false && entity->isPickable() == false) continue;
1734  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1735  // do the collision test
1736  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1737  auto entityDistance = lineTriangleContact.set(entity->getWorldBoundingBox()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1738  // check if match or better match
1739  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1740  selectedEntity = entity;
1741  selectedEntityDistance = entityDistance;
1742  selectedObjectNode = nullptr;
1743  selectedParticleSystem = nullptr;
1744  }
1745  }
1746  }
1747 
1748  // iterate visible point partition systems, check if ray with given mouse position from near plane to far plane collides with bounding volume
1749  for (auto entity: decomposedEntities.ppses) {
1750  // skip if not pickable or ignored by filter
1751  if (forcePicking == false && entity->isPickable() == false) continue;
1752  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1753  // do the collision test
1754  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1755  auto entityDistance = lineTriangleContact.set(entity->getWorldBoundingBox()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1756  // check if match or better match
1757  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1758  selectedEntity = entity;
1759  selectedEntityDistance = entityDistance;
1760  selectedObjectNode = nullptr;
1761  selectedParticleSystem = nullptr;
1762  }
1763  }
1764  }
1765 
1766  // iterate visible particle system nodes, check if ray with given mouse position from near plane to far plane collides with bounding volume
1767  for (auto entity: decomposedEntities.psgs) {
1768  // skip if not pickable or ignored by filter
1769  if (forcePicking == false && entity->isPickable() == false) continue;
1770  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1771  // do the collision test
1772  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1773  auto entityDistance = lineTriangleContact.set(entity->getWorldBoundingBox()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1774  // check if match or better match
1775  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1776  selectedEntity = entity;
1777  selectedEntityDistance = entityDistance;
1778  selectedObjectNode = nullptr;
1779  selectedParticleSystem = nullptr;
1780  auto selectedSubEntityDistance = Float::MAX_VALUE;
1781  // iterate sub partition systems, check if ray with given mouse position from near plane to far plane collides with bounding volume
1782  for (auto subEntity: entity->getParticleSystems()) {
1783  if (LineSegment::doesBoundingBoxCollideWithLineSegment(subEntity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1784  auto subEntityDistance = lineTriangleContact.set(subEntity->getWorldBoundingBox()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1785  // check if match or better match
1786  if (selectedParticleSystem == nullptr || subEntityDistance < selectedSubEntityDistance) {
1787  selectedSubEntityDistance = subEntityDistance;
1788  selectedParticleSystem = subEntity;
1789  }
1790  }
1791  }
1792  }
1793  }
1794  }
1795 
1796  // iterate visible line entities, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1797  for (auto entity: decomposedEntities.linesEntities) {
1798  // skip if not pickable or ignored by filter
1799  if (forcePicking == false && entity->isPickable() == false) continue;
1800  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1801  // do the collision test
1802  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1803  auto entityDistance = lineTriangleContact.set(entity->getWorldBoundingBox()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1804  // check if match or better match
1805  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1806  selectedEntity = entity;
1807  selectedEntityDistance = entityDistance;
1808  selectedObjectNode = nullptr;
1809  selectedParticleSystem = nullptr;
1810  }
1811  }
1812  }
1813 
1814  // iterate visible objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1815  array<vector<Object*>*, 3> objectsArray { &decomposedEntities.objects, &decomposedEntities.objectsForwardShading, &decomposedEntities.objectsPostPostProcessing, };
1816  for (auto& objects: objectsArray) {
1817  for (auto entity: *objects) {
1818  // skip if not pickable or ignored by filter
1819  if (forcePicking == false && entity->isPickable() == false) continue;
1820  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1821  // do the collision test
1822  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1823  for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1824  const auto& vertices = it->next();
1825  if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], nearPlaneWorldCoordinate, farPlaneWorldCoordinate, lineTriangleContact) == true) {
1826  auto entityDistance = lineTriangleContact.sub(nearPlaneWorldCoordinate).computeLengthSquared();
1827  // check if match or better match
1828  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1829  selectedEntity = entity;
1830  selectedEntityDistance = entityDistance;
1831  selectedObjectNode = it->getNode();
1832  selectedParticleSystem = nullptr;
1833  }
1834  }
1835  }
1836  }
1837  }
1838  }
1839 
1840  // iterate visible LOD objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1841  for (auto entity: decomposedEntities.lodObjects) {
1842  // skip if not pickable or ignored by filter
1843  if (forcePicking == false && entity->isPickable() == false) continue;
1844  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1845  // do the collision test
1846  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1847  auto object = entity->getLODObject();
1848  if (object != nullptr) {
1849  for (auto it = object->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1850  const auto& vertices = it->next();
1851  if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], nearPlaneWorldCoordinate, farPlaneWorldCoordinate, lineTriangleContact) == true) {
1852  auto entityDistance = lineTriangleContact.sub(nearPlaneWorldCoordinate).computeLengthSquared();
1853  // check if match or better match
1854  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1855  selectedEntity = entity;
1856  selectedEntityDistance = entityDistance;
1857  }
1858  }
1859  selectedObjectNode = it->getNode();
1860  selectedParticleSystem = nullptr;
1861  }
1862  }
1863  }
1864  }
1865 
1866  // iterate visible entity hierarchies, check if ray with given mouse position from near plane to far plane collides with bounding volume
1867  for (auto entity: decomposedEntities.entityHierarchies) {
1868  // skip if not pickable or ignored by filter
1869  if (forcePicking == false && entity->isPickable() == false) continue;
1870  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1871  // do the collision test
1872  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1873  DecomposedEntities decomposedEntitiesEH;
1874  Node* objectNodeEH = nullptr;
1875  ParticleSystem* particleSystemEntityEH = nullptr;
1877  entity->getEntities(),
1878  decomposedEntitiesEH
1879  );
1880  auto subEntity = getEntityByMousePosition(
1881  decomposedEntitiesEH,
1882  true,
1883  mouseX,
1884  mouseY,
1885  filter,
1886  &objectNodeEH,
1887  &particleSystemEntityEH
1888  );
1889  if (subEntity != nullptr) {
1890  auto entityDistance = lineTriangleContact.set(subEntity->getWorldBoundingBox()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1891  // check if match or better match
1892  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1893  selectedEntity = entity;
1894  selectedEntityDistance = entityDistance;
1895  selectedObjectNode = objectNodeEH;
1896  selectedParticleSystem = particleSystemEntityEH;
1897  }
1898  }
1899  }
1900  }
1901 
1902  // store node
1903  if (objectNode != nullptr) *objectNode = selectedObjectNode;
1904 
1905  // store particle system entity
1906  if (particleSystemEntity != nullptr) {
1907  *particleSystemEntity = selectedParticleSystem;
1908  }
1909 
1910  // return parent entity if entity is part of a hierarchy
1911  if (selectedEntity != nullptr) {
1912  for (auto _entity = selectedEntity; _entity != nullptr; _entity = _entity->getParentEntity()) {
1913  if (_entity->getParentEntity() == nullptr) return _entity;
1914  }
1915  return nullptr;
1916  } else {
1917  return nullptr;
1918  }
1919 }
1920 
1921 Entity* Engine::getEntityByMousePosition(int32_t mouseX, int32_t mouseY, Vector3& contactPoint, EntityPickingFilter* filter, Node** objectNode, ParticleSystem** particleSystemEntity) {
1922  // get world position of mouse position at near and far plane
1923  auto startPoint = computeWorldCoordinateByMousePosition(mouseX, mouseY, 0.0f);
1924  auto endPoint = computeWorldCoordinateByMousePosition(mouseX, mouseY, 1.0f);
1925 
1926  //
1927  return doRayCasting(startPoint, endPoint, contactPoint, filter);// TODO: object node, particle system entity
1928 }
1929 
1931  DecomposedEntities& decomposedEntities,
1932  bool forcePicking,
1933  const Vector3& startPoint,
1934  const Vector3& endPoint,
1935  Vector3& contactPoint,
1936  EntityPickingFilter* filter) {
1937  Vector3 boundingBoxLineContactMin;
1938  Vector3 boundingBoxLineContactMax;
1939  Vector3 lineTriangleContact;
1940 
1941  // selected entity
1942  auto selectedEntityDistance = Float::MAX_VALUE;
1943  Entity* selectedEntity = nullptr;
1944 
1945  // iterate visible objects with no depth writing, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1946  for (auto entity: decomposedEntities.objectsNoDepthTest) {
1947  // skip if not pickable or ignored by filter
1948  if (forcePicking == false && entity->isPickable() == false) continue;
1949  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1950  // do the collision test
1951  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), startPoint, endPoint, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1952  for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1953  const auto& vertices = it->next();
1954  if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], startPoint, endPoint, lineTriangleContact) == true) {
1955  auto entityDistance = lineTriangleContact.clone().sub(startPoint).computeLengthSquared();
1956  // check if match or better match
1957  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1958  selectedEntity = entity;
1959  selectedEntityDistance = entityDistance;
1960  contactPoint = lineTriangleContact;
1961  }
1962  }
1963  }
1964  }
1965  }
1966  // they have first priority right now
1967  if (selectedEntity != nullptr) {
1968  return selectedEntity;
1969  }
1970 
1971  // iterate visible objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1972  array<vector<Object*>*, 3> objectsArray { &decomposedEntities.objects, &decomposedEntities.objectsForwardShading, &decomposedEntities.objectsPostPostProcessing, };
1973  for (auto& objects: objectsArray) {
1974  for (auto entity: *objects) {
1975  // skip if not pickable or ignored by filter
1976  if (forcePicking == false && entity->isPickable() == false) continue;
1977  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1978  // do the collision test
1979  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), startPoint, endPoint, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1980  for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1981  const auto& vertices = it->next();
1982  if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], startPoint, endPoint, lineTriangleContact) == true) {
1983  auto entityDistance = lineTriangleContact.clone().sub(startPoint).computeLengthSquared();
1984  // check if match or better match
1985  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1986  selectedEntity = entity;
1987  selectedEntityDistance = entityDistance;
1988  contactPoint = lineTriangleContact;
1989  }
1990  }
1991  }
1992  }
1993  }
1994  }
1995 
1996  // iterate visible LOD objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1997  for (auto entity: decomposedEntities.lodObjects) {
1998  // skip if not pickable or ignored by filter
1999  if (forcePicking == false && entity->isPickable() == false) continue;
2000  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
2001  // do the collision test
2002  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), startPoint, endPoint, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
2003  auto object = entity->getLODObject();
2004  if (object != nullptr) {
2005  for (auto it = object->getTransformedFacesIterator()->iterator(); it->hasNext();) {
2006  const auto& vertices = it->next();
2007  if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], startPoint, endPoint, lineTriangleContact) == true) {
2008  auto entityDistance = lineTriangleContact.sub(startPoint).computeLengthSquared();
2009  // check if match or better match
2010  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
2011  selectedEntity = entity;
2012  selectedEntityDistance = entityDistance;
2013  contactPoint = lineTriangleContact;
2014  }
2015  }
2016  }
2017  }
2018  }
2019  }
2020 
2021  // iterate visible entity hierarchies, check if ray with given mouse position from near plane to far plane collides with bounding volume
2022  for (auto entity: decomposedEntities.entityHierarchies) {
2023  // skip if not pickable or ignored by filter
2024  if (forcePicking == false && entity->isPickable() == false) continue;
2025  if (filter != nullptr && filter->filterEntity(entity) == false) continue;
2026  // do the collision test
2027  if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getWorldBoundingBox(), startPoint, endPoint, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
2028  DecomposedEntities decomposedEntitiesEH;
2030  entity->getEntities(),
2031  decomposedEntitiesEH
2032  );
2033  Vector3 contactPointEH;
2034  auto entity = doRayCasting(
2035  decomposedEntitiesEH,
2036  true,
2037  startPoint,
2038  endPoint,
2039  contactPointEH,
2040  filter
2041  );
2042  if (entity != nullptr) {
2043  auto entityDistance = lineTriangleContact.sub(startPoint).computeLengthSquared();
2044  // check if match or better match
2045  if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
2046  selectedEntity = entity;
2047  selectedEntityDistance = entityDistance;
2048  contactPoint = contactPointEH;
2049  }
2050  }
2051  }
2052  }
2053 
2054  //
2055  return selectedEntity;
2056 }
2057 
2058 bool Engine::computeScreenCoordinateByWorldCoordinate(const Vector3& worldCoordinate, Vector2& screenCoordinate, int width, int height)
2059 {
2060  auto _width = width != -1?width:(scaledWidth != -1?scaledWidth:this->width);
2061  auto _height = height != -1?height:(scaledHeight != -1?scaledHeight:this->height);
2062  // convert to normalized device coordinates
2063  auto screenCoordinate4 = camera->getModelViewProjectionMatrix().multiply(Vector4(worldCoordinate, 1.0f));
2064  screenCoordinate4.scale(1.0f / screenCoordinate4.getW());
2065  // convert to screen coordinate
2066  screenCoordinate.setX((screenCoordinate4[0] + 1.0f) * _width / 2.0f);
2067  screenCoordinate.setY(_height - ((screenCoordinate4[1] + 1.0f) * _height / 2.0f));
2068  return camera->getCameraMatrix().multiply(worldCoordinate).getZ() <= 0.0f;
2069 }
2070 
2072 {
2073  // finish last frame
2075 
2076  // remove entities
2077  vector<string> entitiesToRemove;
2078  for (const auto& [entityId, entity]: entitiesById) {
2079  entitiesToRemove.push_back(entityId);
2080  }
2081  for (const auto& entityKey: entitiesToRemove) {
2082  removeEntity(entityKey);
2083  }
2084 
2085  // dispose shadow mapping
2086  if (shadowMapping != nullptr) shadowMapping->dispose();
2087 
2088  // dispose frame buffers
2089  if (geometryBuffer != nullptr) geometryBuffer->dispose();
2090  if (frameBuffer != nullptr) frameBuffer->dispose();
2091  if (gizmoFrameBuffer != nullptr) gizmoFrameBuffer->dispose();
2092  if (postProcessingFrameBuffer1 != nullptr) postProcessingFrameBuffer1->dispose();
2093  if (postProcessingFrameBuffer2 != nullptr) postProcessingFrameBuffer2->dispose();
2095  for (const auto& effectPassFrameBuffer: effectPassFrameBuffers) if (effectPassFrameBuffer != nullptr) effectPassFrameBuffer->dispose();
2096 
2097  // dispose lights
2098  for (const auto& light: lights) light->dispose();
2099 
2100  // dispose GUI
2101  gui->dispose();
2102  if (this == Engine::instance) {
2103  guiRenderer->dispose();
2104  GUIParser::dispose();
2105  }
2106 
2107  // dispose entity renderer
2108  entityRenderer->dispose();
2109 
2110  // dispose object buffer if main engine
2111  if (this == Engine::instance) {
2113  engineThreadsQueue->stop();
2114  for (const auto& engineThread: engineThreads) engineThread->stop();
2115  for (const auto& engineThread: engineThreads) engineThread->join();
2116  }
2118  frameBufferRenderShader->dispose();
2119  skyRenderShader->dispose();
2120  texture2DRenderShader->dispose();
2121  lightingShader->dispose();
2122  postProcessingShader->dispose();
2123  ObjectBuffer::dispose();
2124  }
2125 
2126  // set current engine
2127  if (currentEngine == this) currentEngine = nullptr;
2128 }
2129 
2131 {
2132  // use framebuffer if we have one
2133  if (frameBuffer != nullptr) {
2134  frameBuffer->enableFrameBuffer();
2135  } else {
2136  frameBuffer->disableFrameBuffer();
2137  }
2138 
2139  renderer->initGuiMode();
2140 }
2141 
2143 {
2144  renderer->doneGuiMode();
2145 
2146  // unuse framebuffer if we have one
2147  if (frameBuffer != nullptr)
2149 }
2150 
2151 bool Engine::makeScreenshot(const string& pathName, const string& fileName, bool removeAlphaChannel)
2152 {
2153  // use framebuffer if we have one
2154  if (frameBuffer != nullptr) frameBuffer->enableFrameBuffer();
2155 
2156  // fetch pixel
2157  auto pixels = unique_ptr<ByteBuffer>(renderer->readPixels(0, 0, width, height));
2158  if (pixels == nullptr) {
2159  Console::println("Engine::makeScreenshot(): Failed to read pixels");
2160  return false;
2161  }
2162 
2163  // create texture, write and delete
2164  auto texture =
2165  unique_ptr<
2166  Texture,
2167  decltype([](Texture* texture){ texture->releaseReference(); })
2168  >(
2169  new Texture(
2170  "tdme.engine.makescreenshot",
2173  width,
2174  height,
2175  width,
2176  height,
2178  *pixels
2179  )
2180  );
2181  texture->acquireReference();
2182  PNGTextureWriter::write(texture.get(), pathName, fileName, removeAlphaChannel);
2183 
2184  // unuse framebuffer if we have one
2185  if (frameBuffer != nullptr) FrameBuffer::disableFrameBuffer();
2186 
2187  //
2188  return true;
2189 }
2190 
2191 bool Engine::makeScreenshot(vector<uint8_t>& pngData)
2192 {
2193  // use framebuffer if we have one
2194  if (frameBuffer != nullptr) frameBuffer->enableFrameBuffer();
2195 
2196  // fetch pixel
2197  auto pixels = unique_ptr<ByteBuffer>(renderer->readPixels(0, 0, width, height));
2198  if (pixels == nullptr) {
2199  Console::println("Engine::makeScreenshot(): Failed to read pixels");
2200  return false;
2201  }
2202 
2203  // create texture, write and delete
2204  auto texture =
2205  unique_ptr<
2206  Texture,
2207  decltype([](Texture* texture){ texture->releaseReference(); })
2208  >(
2209  new Texture(
2210  "tdme.engine.makescreenshot",
2213  width,
2214  height,
2215  width,
2216  height,
2218  *pixels
2219  )
2220  );
2221  texture->acquireReference();
2222  PNGTextureWriter::write(texture.get(), pngData);
2223 
2224  // unuse framebuffer if we have one
2225  if (frameBuffer != nullptr) FrameBuffer::disableFrameBuffer();
2226 
2227  //
2228  return true;
2229 }
2230 
2232  postProcessingPrograms.clear();
2233 }
2234 
2235 void Engine::addPostProcessingProgram(const string& programId) {
2236  postProcessingPrograms.erase(remove(postProcessingPrograms.begin(), postProcessingPrograms.end(), programId), postProcessingPrograms.end());
2237  if (postProcessing->getPostProcessingProgram(programId) != nullptr) postProcessingPrograms.push_back(programId);
2238 }
2239 
2240 void Engine::doPostProcessing(PostProcessingProgram::RenderPass renderPass, array<FrameBuffer*, 2> postProcessingFrameBuffers, FrameBuffer* targetFrameBuffer) {
2241  auto postProcessingFrameBufferIdx = 0;
2242  for (auto programId: postProcessingPrograms) {
2243  auto program = postProcessing->getPostProcessingProgram(programId);
2244  if (program == nullptr) continue;
2245  if (program->getRenderPass() != renderPass) continue;
2246  auto effectPassSkipDetected = false;
2247  for (const auto& effectPass: program->getEffectPasses()) {
2248  if (effectPassSkip[effectPass.effectPassIdx - 1] == true) effectPassSkipDetected = true;
2249  }
2250  if (effectPassSkipDetected == true) continue;
2251  for (const auto& step: program->getPostProcessingSteps()) {
2252  auto shaderId = step.shaderId;
2253  FrameBuffer* blendToSource = nullptr;
2254  FrameBuffer* source = nullptr;
2255  FrameBuffer* target = nullptr;
2256  if (step.blendToSource == PostProcessingProgram::FRAMEBUFFERSOURCE_SCREEN) {
2257  blendToSource = postProcessingFrameBuffers[postProcessingFrameBufferIdx];
2258  }
2259  switch(step.source) {
2260  case PostProcessingProgram::FRAMEBUFFERSOURCE_NONE:
2261  break;
2262  case PostProcessingProgram::FRAMEBUFFERSOURCE_SCREEN:
2263  source = postProcessingFrameBuffers[postProcessingFrameBufferIdx];
2264  break;
2265  default:
2266  source = effectPassFrameBuffers[step.source - PostProcessingProgram::FRAMEBUFFERSOURCE_EFFECTPASS0].get();
2267  break;
2268  }
2269  switch(step.target) {
2270  case PostProcessingProgram::FRAMEBUFFERTARGET_SCREEN:
2271  target = postProcessingFrameBuffers[(postProcessingFrameBufferIdx + 1) % 2];
2272  break;
2273  case PostProcessingProgram::FRAMEBUFFERTARGET_TEMPORARY:
2275  if (postProcessingTemporaryFrameBuffer == nullptr) {
2277  postProcessingTemporaryFrameBuffer->initialize();
2278  }
2279  target = postProcessingTemporaryFrameBuffer.get();
2280  break;
2281  }
2282  FrameBuffer::doPostProcessing(this, target, source, programId, shaderId, step.bindTemporary == true?postProcessingTemporaryFrameBuffer.get():nullptr, blendToSource);
2283  switch(step.target) {
2284  case PostProcessingProgram::FRAMEBUFFERTARGET_SCREEN:
2285  postProcessingFrameBufferIdx = (postProcessingFrameBufferIdx + 1) % 2;
2286  break;
2287  case PostProcessingProgram::FRAMEBUFFERTARGET_TEMPORARY:
2288  break;
2289  }
2290  }
2291  }
2292 
2293  // render back to objects frame buffer
2294  if (postProcessingFrameBuffers[postProcessingFrameBufferIdx] != targetFrameBuffer) {
2295  if (targetFrameBuffer != nullptr) {
2296  targetFrameBuffer->enableFrameBuffer();
2297  } else {
2299  }
2300  postProcessingFrameBuffers[postProcessingFrameBufferIdx]->renderToScreen(this);
2301  }
2302 }
2303 
2304 void Engine::render(FrameBuffer* renderFrameBuffer, GeometryBuffer* renderGeometryBuffer, Camera* rendererCamera, DecomposedEntities& visibleDecomposedEntities, int32_t effectPass, int32_t renderPassMask, const string& shaderPrefix, bool applyShadowMapping, bool applyPostProcessing, bool doRenderLightSource, bool doRenderParticleSystems, int32_t renderTypes, bool skyShaderEnabled) {
2305  //
2306  Engine::getRenderer()->setEffectPass(effectPass);
2307  Engine::getRenderer()->setShaderPrefix(shaderPrefix);
2308 
2309  // use lighting shader
2310  if (visibleDecomposedEntities.objects.empty() == false || visibleDecomposedEntities.objectsForwardShading.empty() == false) {
2311  //
2312  if (lightingShader != nullptr) lightingShader->useProgram(this);
2313 
2314  // render objects
2315  for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2316  auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2317  if ((renderPassMask & renderPass) == renderPass) {
2318  if (renderPass == Entity::RENDERPASS_TERRAIN) {
2319  if (renderGeometryBuffer != nullptr) {
2320  if (lightingShader != nullptr) lightingShader->unUseProgram();
2321  renderGeometryBuffer->enableGeometryBuffer();
2322  renderer->setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
2324  Engine::getRenderer()->setShaderPrefix("defer_");
2325  if (lightingShader != nullptr) lightingShader->useProgram(this);
2326  }
2327  } else
2328  if (renderPass == Entity::RENDERPASS_WATER) renderer->enableBlending();
2329  entityRenderer->render(
2330  renderPass,
2332  true,
2333  ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2334  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2335  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2336  ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2337  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2338  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2339  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2340  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2341  ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2342  );
2343  if (renderPass == Entity::RENDERPASS_STANDARD) {
2344  if (renderGeometryBuffer != nullptr) {
2345  if (lightingShader != nullptr) lightingShader->unUseProgram();
2346  renderGeometryBuffer->disableGeometryBuffer();
2347  Engine::getRenderer()->setShaderPrefix(shaderPrefix);
2348  if (renderFrameBuffer != nullptr) renderFrameBuffer->enableFrameBuffer();
2349  // clear previous frame values
2350  if (skyShaderEnabled == true) {
2352  skyRenderShader->render(this, false, rendererCamera);
2353  } else {
2356  }
2357  //
2358  renderGeometryBuffer->renderToScreen(this, visibleDecomposedEntities.decalEntities);
2359  if (lightingShader != nullptr) lightingShader->useProgram(this);
2360  if (visibleDecomposedEntities.objectsForwardShading.empty() == false) {
2361  // TODO: use a loop maybe from TERRAIN to STANDARD, but for now it works this way too :)
2362  // terrain
2363  entityRenderer->render(
2366  true,
2367  ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2368  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2369  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2370  ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2371  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2372  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2373  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2374  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2375  ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2376  );
2377  // standard
2378  entityRenderer->render(
2381  true,
2382  ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2383  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2384  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2385  ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2386  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2387  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2388  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2389  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2390  ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2391  );
2392  }
2393  }
2394  } else
2395  if (renderPass == Entity::RENDERPASS_WATER) renderer->disableBlending();
2396  }
2397  }
2398 
2399  // render transparent faces
2400  entityRenderer->renderTransparentFaces();
2401 
2402  // unuse lighting shader
2403  if (lightingShader != nullptr) lightingShader->unUseProgram();
2404 
2405  // render shadows if required
2406  if (applyShadowMapping == true && shadowMapping != nullptr) {
2407  if (visibleDecomposedEntities.objects.empty() == false) shadowMapping->renderShadowMaps(visibleDecomposedEntities.objects);
2409  }
2410  }
2411 
2412  // do post processing
2413  if (applyPostProcessing == true) {
2415  if (postProcessingPrograms.size() > 0) {
2416  doPostProcessing(PostProcessingProgram::RENDERPASS_OBJECTS, {{postProcessingFrameBuffer1.get(), postProcessingFrameBuffer2.get() }}, postProcessingFrameBuffer1.get());
2417  postProcessingFrameBuffer1->enableFrameBuffer();
2418  }
2419  }
2420 
2421  // render lines entities
2422  if (visibleDecomposedEntities.linesEntities.size() > 0) {
2423  // use lines shader
2424  if (linesShader != nullptr) linesShader->useProgram(renderer->CONTEXTINDEX_DEFAULT);
2425 
2426  // render lines entities
2427  for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2428  auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2429  if ((renderPassMask & renderPass) == renderPass) entityRenderer->render(renderPass, visibleDecomposedEntities.linesEntities);
2430  }
2431 
2432  // unuse lines shader
2433  if (linesShader != nullptr) linesShader->unUseProgram(renderer->CONTEXTINDEX_DEFAULT);
2434  }
2435 
2436  // render point particle systems
2437  if (doRenderParticleSystems == true && visibleDecomposedEntities.ppses.size() > 0) {
2438  // use particle shader
2439  if (particlesShader != nullptr) particlesShader->useProgram(renderer->CONTEXTINDEX_DEFAULT);
2440 
2441  // render points based particle systems
2442  if (visibleDecomposedEntities.ppses.size() > 0) {
2443  for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2444  auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2445  if ((renderPassMask & renderPass) == renderPass) entityRenderer->render(renderPass, visibleDecomposedEntities.ppses);
2446  }
2447  }
2448 
2449  // unuse particle shader
2450  if (particlesShader != nullptr) particlesShader->unUseProgram(renderer->CONTEXTINDEX_DEFAULT);
2451  }
2452 
2453  // render objects and particles together
2454  if (applyPostProcessing == true) {
2455  if (postProcessingPrograms.size() > 0) {
2456  doPostProcessing(PostProcessingProgram::RENDERPASS_FINAL, {{postProcessingFrameBuffer1.get(), postProcessingFrameBuffer2.get() }}, frameBuffer.get());
2457  }
2458  }
2459 
2460  // render objects that are have post post processing render pass
2462  // use lighting shader
2463  if (lightingShader != nullptr) {
2464  lightingShader->useProgram(this);
2465  }
2466 
2467  // render post processing objects
2468  for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2469  auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2470  if ((renderPassMask & renderPass) == renderPass) {
2471  if (renderPass == Entity::RENDERPASS_WATER) renderer->enableBlending();
2472  entityRenderer->render(
2473  renderPass,
2475  true,
2476  ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2477  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2478  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2479  ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2480  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2481  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2482  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2483  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2484  ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2485  );
2486  if (renderPass == Entity::RENDERPASS_WATER) renderer->disableBlending();
2487  }
2488  }
2489 
2490  // render transparent faces
2491  entityRenderer->renderTransparentFaces();
2492 
2493  // unuse lighting shader
2494  if (lightingShader != nullptr) lightingShader->unUseProgram();
2495 
2496  // render shadows if required
2497  if (applyShadowMapping == true && shadowMapping != nullptr) {
2499  }
2500  }
2501 
2502  // render objects that are have post post processing render pass
2504  // use lighting shader
2505  if (lightingShader != nullptr) {
2506  lightingShader->useProgram(this);
2507  }
2508 
2509  //
2511 
2512  // render post processing objects
2513  for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2514  auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2515  if ((renderPassMask & renderPass) == renderPass) {
2516  if (renderPass == Entity::RENDERPASS_WATER) renderer->enableBlending();
2517  entityRenderer->render(
2518  renderPass,
2520  true,
2521  ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2522  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2523  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2524  ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2525  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2526  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2527  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2528  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2529  ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2530  );
2531  if (renderPass == Entity::RENDERPASS_WATER) renderer->disableBlending();
2532  }
2533  }
2534 
2535  // render transparent faces
2536  entityRenderer->renderTransparentFaces();
2537 
2538  //
2540 
2541  // unuse lighting shader
2542  if (lightingShader != nullptr) lightingShader->unUseProgram();
2543 
2544  // render shadows if required
2545  if (applyShadowMapping == true && shadowMapping != nullptr) {
2547  }
2548  }
2549 
2550  // render gizmo objects
2551  if (visibleDecomposedEntities.objectsGizmo.size() > 0) {
2552  // default context
2553  auto _width = renderFrameBuffer != nullptr?renderFrameBuffer->getWidth():(scaledWidth != -1?scaledWidth:width);
2554  auto _height = renderFrameBuffer != nullptr?renderFrameBuffer->getHeight():(scaledHeight != -1?scaledHeight:height);
2555 
2556  if (gizmoFrameBuffer == nullptr) {
2558  gizmoFrameBuffer->setColorBufferTextureId(frameBuffer->getColorBufferTextureId());
2559  gizmoFrameBuffer->initialize();
2560  } else
2561  if (gizmoFrameBuffer->getWidth() != _width || gizmoFrameBuffer->getHeight() != _height) {
2562  gizmoFrameBuffer->reshape(_width, _height);
2563  }
2564 
2565  //
2566  gizmoCamera->setLookFrom(rendererCamera->getLookFrom());
2567  gizmoCamera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
2568 
2569  //
2570  gizmoFrameBuffer->enableFrameBuffer();
2572 
2573  // use lighting shader
2574  if (lightingShader != nullptr) {
2575  lightingShader->useProgram(this);
2576  }
2577 
2578  // render
2579  entityRenderer->render(
2582  true,
2583  ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2584  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2585  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2586  ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2587  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2588  ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2589  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2590  ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2591  ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2592  );
2593 
2594  // render transparent faces
2595  entityRenderer->renderTransparentFaces();
2596 
2597  //
2598  if (renderFrameBuffer != nullptr) {
2599  renderFrameBuffer->enableFrameBuffer();
2600  } else {
2602  }
2603 
2604  // unuse lighting shader
2605  if (lightingShader != nullptr) lightingShader->unUseProgram();
2606 
2607  //
2608  rendererCamera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
2609  }
2610 
2611  // light sources
2612  if (doRenderLightSource == true) {
2613  auto _width = scaledWidth != -1?scaledWidth:width;
2614  auto _height = scaledHeight != -1?scaledHeight:height;
2615  //
2616  renderLightSources(_width, _height);
2617  }
2618 
2619  //
2620  Engine::getRenderer()->setShaderPrefix(string());
2622 }
2623 
2625  auto lightSourceVisible = false;
2626  for (const auto& light: lights) {
2627  if (light->isEnabled() == false || light->isRenderSource() == false) continue;
2628  auto lightSourceSize = light->getSourceSize();
2629  auto lightSourcePixelSize = width < height?static_cast<float>(lightSourceSize) * static_cast<float>(width):static_cast<float>(lightSourceSize) * static_cast<float>(height);;
2630  Vector2 lightSourceDimension2D = Vector2(lightSourcePixelSize, lightSourcePixelSize);
2631  Vector2 lightSourcePosition2D;
2632  Vector3 lightSourcePosition = Vector3(light->getPosition().getX(), light->getPosition().getY(), light->getPosition().getZ());
2633  if (light->getPosition().getW() > Math::EPSILON) lightSourcePosition.scale(1.0f / light->getPosition().getW());
2634  auto visible = computeScreenCoordinateByWorldCoordinate(lightSourcePosition, lightSourcePosition2D, width, height);
2635  lightSourcePosition2D.sub(lightSourceDimension2D.clone().scale(0.5f));
2636  if (visible == true) {
2637  texture2DRenderShader->renderTexture(this, lightSourcePosition2D, lightSourceDimension2D, light->getSourceTextureId(), width, height);
2638  lightSourceVisible = true;
2639  }
2640  }
2641  return lightSourceVisible;
2642 }
2643 
2645  for (auto shaderType = 0; shaderType < SHADERTYPE_MAX; shaderType++)
2646  for (const auto& shaderId: getRegisteredShader(static_cast<ShaderType>(shaderType))) {
2647  string shaderTypeString = "unknown";
2648  switch (shaderType) {
2649  case SHADERTYPE_OBJECT: shaderTypeString = "object"; break;
2650  case SHADERTYPE_POSTPROCESSING: shaderTypeString = "postprocessing"; break;
2651  case SHADERTYPE_SKY: shaderTypeString = "sky"; break;
2652  default: break;
2653  }
2654  Console::println(string("TDME2::registered " + shaderTypeString + " shader: ") + shaderId);
2655  const auto shaderParametersDefaults = getShaderParameterDefaults(shaderId);
2656  if (shaderParametersDefaults == nullptr) continue;
2657  if (shaderParametersDefaults->size() > 0) {
2658  // TODO
2659  for (const auto parameterDefaults: *shaderParametersDefaults) {
2660  const auto& parameterName = parameterDefaults.name;
2661  Console::print("\t" + parameterName);
2662  switch(parameterDefaults.value.getType()) {
2664  Console::print(" = none");
2665  break;
2667  Console::print(" = boolean(");
2668  Console::print("value = " + string(getShaderParameter(shaderId, parameterName).getBooleanValue() == true?"true":"false"));
2669  Console::print(")");
2670  break;
2672  Console::print(" = integer(");
2673  Console::print("value = " + to_string(getShaderParameter(shaderId, parameterName).getIntegerValue()) + ", ");
2674  Console::print("min = " + to_string(parameterDefaults.min.getIntegerValue()) + ", ");
2675  Console::print("max = " + to_string(parameterDefaults.max.getIntegerValue()) + ", ");
2676  Console::print("step = " + to_string(parameterDefaults.step.getIntegerValue()));
2677  Console::print(")");
2678  break;
2680  Console::print(" = float(");
2681  Console::print("value = " + to_string(getShaderParameter(shaderId, parameterName).getFloatValue()) + ", ");
2682  Console::print("min = " + to_string(parameterDefaults.min.getFloatValue()) + ", ");
2683  Console::print("max = " + to_string(parameterDefaults.max.getFloatValue()) + ", ");
2684  Console::print("step = " + to_string(parameterDefaults.step.getFloatValue()));
2685  Console::print(")");
2686  break;
2688  {
2689  Console::print(" = Vector2(");
2690  {
2691  Console::print("value = ");
2692  const auto shaderParameterArray = getShaderParameter(shaderId, parameterName).getVector2ValueArray();
2693  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2694  if (i != 0) Console::print(",");
2695  Console::print(to_string(shaderParameterArray[i]));
2696  }
2697  }
2698  {
2699  Console::print(", min = ");
2700  const auto shaderParameterArray = parameterDefaults.min.getVector2ValueArray();
2701  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2702  if (i != 0) Console::print(",");
2703  Console::print(to_string(shaderParameterArray[i]));
2704  }
2705  }
2706  {
2707  Console::print(", max = ");
2708  const auto shaderParameterArray = parameterDefaults.max.getVector2ValueArray();
2709  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2710  if (i != 0) Console::print(",");
2711  Console::print(to_string(shaderParameterArray[i]));
2712  }
2713  }
2714  {
2715  Console::print(", step = ");
2716  const auto shaderParameterArray = parameterDefaults.step.getVector2ValueArray();
2717  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2718  if (i != 0) Console::print(",");
2719  Console::print(to_string(shaderParameterArray[i]));
2720  }
2721  }
2722  Console::print(")");
2723  }
2724  break;
2726  {
2727  Console::print(" = Vector3(");
2728  {
2729  Console::print("value = ");
2730  const auto shaderParameterArray = getShaderParameter(shaderId, parameterName).getVector3ValueArray();
2731  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2732  if (i != 0) Console::print(",");
2733  Console::print(to_string(shaderParameterArray[i]));
2734  }
2735  }
2736  {
2737  Console::print(", min = ");
2738  const auto shaderParameterArray = parameterDefaults.min.getVector3ValueArray();
2739  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2740  if (i != 0) Console::print(",");
2741  Console::print(to_string(shaderParameterArray[i]));
2742  }
2743  }
2744  {
2745  Console::print(", max = ");
2746  const auto shaderParameterArray = parameterDefaults.max.getVector3ValueArray();
2747  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2748  if (i != 0) Console::print(",");
2749  Console::print(to_string(shaderParameterArray[i]));
2750  }
2751  }
2752  {
2753  Console::print(", step = ");
2754  const auto shaderParameterArray = parameterDefaults.step.getVector3ValueArray();
2755  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2756  if (i != 0) Console::print(",");
2757  Console::print(to_string(shaderParameterArray[i]));
2758  }
2759  }
2760  Console::print(")");
2761  }
2762  break;
2764  {
2765  Console::print(" = Vector4(");
2766  {
2767  Console::print("value = ");
2768  const auto shaderParameterArray = getShaderParameter(shaderId, parameterName).getVector4ValueArray();
2769  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2770  if (i != 0) Console::print(",");
2771  Console::print(to_string(shaderParameterArray[i]));
2772  }
2773  }
2774  {
2775  Console::print(", min = ");
2776  const auto shaderParameterArray = parameterDefaults.min.getVector4ValueArray();
2777  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2778  if (i != 0) Console::print(",");
2779  Console::print(to_string(shaderParameterArray[i]));
2780  }
2781  }
2782  {
2783  Console::print(", max = ");
2784  const auto shaderParameterArray = parameterDefaults.max.getVector4ValueArray();
2785  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2786  if (i != 0) Console::print(",");
2787  Console::print(to_string(shaderParameterArray[i]));
2788  }
2789  }
2790  {
2791  Console::print(", step = ");
2792  const auto shaderParameterArray = parameterDefaults.step.getVector4ValueArray();
2793  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2794  if (i != 0) Console::print(",");
2795  Console::print(to_string(shaderParameterArray[i]));
2796  }
2797  }
2798  Console::print(")");
2799  }
2800  break;
2802  {
2803  Console::print(" = Color4(");
2804  {
2805  Console::print("value = ");
2806  const auto shaderParameterArray = getShaderParameter(shaderId, parameterName).getColor4ValueArray();
2807  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2808  if (i != 0) Console::print(",");
2809  Console::print(to_string(shaderParameterArray[i]));
2810  }
2811  }
2812  {
2813  Console::print(", min = ");
2814  const auto shaderParameterArray = parameterDefaults.min.getColor4ValueArray();
2815  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2816  if (i != 0) Console::print(",");
2817  Console::print(to_string(shaderParameterArray[i]));
2818  }
2819  }
2820  {
2821  Console::print(", max = ");
2822  const auto shaderParameterArray = parameterDefaults.max.getColor4ValueArray();
2823  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2824  if (i != 0) Console::print(",");
2825  Console::print(to_string(shaderParameterArray[i]));
2826  }
2827  }
2828  {
2829  Console::print(", step = ");
2830  const auto shaderParameterArray = parameterDefaults.step.getColor4ValueArray();
2831  for (auto i = 0; i < shaderParameterArray.size(); i++) {
2832  if (i != 0) Console::print(",");
2833  Console::print(to_string(shaderParameterArray[i]));
2834  }
2835  }
2836  Console::print(")");
2837  }
2838  break;
2839  default:
2840  Console::print(" = unknown");
2841  break;
2842  }
2843  //
2844  Console::println();
2845  }
2846  }
2847  }
2848 }
2849 
2850 void Engine::dumpEntityHierarchy(EntityHierarchy* entityHierarchy, int indent, const string& parentNodeId) {
2851  for (auto subEntity: entityHierarchy->query(parentNodeId)) {
2852  for (auto i = 0; i < indent; i++) Console::print("\t");
2853  string entityType;
2854  switch (subEntity->getEntityType()) {
2856  entityType = "Decal";
2857  break;
2859  entityType = "Entity Hierarchy";
2860  break;
2862  entityType = "Environment Mapping";
2863  break;
2865  entityType = "Imposter Object";
2866  break;
2868  entityType = "Lines";
2869  break;
2871  entityType = "LOD Object";
2872  break;
2874  entityType = "LOD Object Imposter";
2875  break;
2877  entityType = "Object";
2878  break;
2880  entityType = "Object Render Group";
2881  break;
2883  entityType = "Fog Particle System";
2884  break;
2886  entityType = "Object Particle System";
2887  break;
2889  entityType = "Particle System Group";
2890  break;
2892  entityType = "Points Particle System";
2893  break;
2894  }
2895  Console::println("\t" + subEntity->getId() + " (" + entityType + ")");
2896  if (subEntity->getEntityType() == Entity::ENTITYTYPE_ENTITYHIERARCHY) {
2897  dumpEntityHierarchy(dynamic_cast<EntityHierarchy*>(subEntity), indent + 1, string());
2898  }
2899  //
2900  dumpEntityHierarchy(entityHierarchy, indent + 1, subEntity->getId());
2901  }
2902 }
2903 
2905  Console::println("Engine::dumpEntities()");
2906  Console::println();
2907  Console::println("Engine Entities:");
2908  for (const auto& [entityId, entity]: entitiesById) {
2909  string entityType;
2910  switch (entity->getEntityType()) {
2912  entityType = "Decal";
2913  break;
2915  entityType = "Entity Hierarchy";
2916  break;
2918  entityType = "Environment Mapping";
2919  break;
2921  entityType = "Imposter Object";
2922  break;
2924  entityType = "Lines";
2925  break;
2927  entityType = "LOD Object";
2928  break;
2930  entityType = "LOD Object Imposter";
2931  break;
2933  entityType = "Object";
2934  break;
2936  entityType = "Object Render Group";
2937  break;
2939  entityType = "Fog Particle System";
2940  break;
2942  entityType = "Object Particle System";
2943  break;
2945  entityType = "Particle System Group";
2946  break;
2948  entityType = "Points Particle System";
2949  break;
2950  }
2951  Console::println("\t" + entity->getId() + " (" + entityType + ")");
2952  if (entity->getEntityType() == Entity::ENTITYTYPE_ENTITYHIERARCHY) {
2953  dumpEntityHierarchy(dynamic_cast<EntityHierarchy*>(entity), 2, string());
2954  }
2955  }
2956 }
#define CHECK_INITIALIZED(NAME, SHADER)
Application base class, please make sure to allocate application on heap to have correct application ...
Definition: Application.h:41
void update(int contextIdx, int32_t width, int32_t height)
Sets up camera while resizing the view port.
Definition: Camera.cpp:158
const Vector3 & getLookFrom() const
Definition: Camera.h:219
@ FRUSTUMMODE_ORTHOGRAPHIC
Definition: Camera.h:27
Color 4 definition class.
Definition: Color4.h:18
float getRed() const
Definition: Color4.h:92
float getGreen() const
Definition: Color4.h:107
float getAlpha() const
Definition: Color4.h:137
float getBlue() const
Definition: Color4.h:122
void set(float r, float g, float b, float a)
Sets this color by its components.
Definition: Color4.h:66
Decal entity to be used with engine class.
Definition: Decal.h:36
unique_ptr< TransparentRenderFacesPool > transparentRenderFacesPool
Definition: Engine.h:369
Engine main class.
Definition: Engine.h:131
static void setShadowMapRenderLookUps(int32_t shadowMapRenderLookUps)
Set shadowmap look ups for each pixel when rendering.
Definition: Engine.h:762
static STATIC_DLL_IMPEXT Engine * currentEngine
Definition: Engine.h:201
static STATIC_DLL_IMPEXT unique_ptr< PostProcessingShader > postProcessingShader
Definition: Engine.h:226
bool renderLightSources(int width, int height)
Render light sources.
Definition: Engine.cpp:2624
unique_ptr< FrameBuffer > frameBuffer
Definition: Engine.h:294
void dumpShaders()
Print registered shaders and it default parameters to console.
Definition: Engine.cpp:2644
bool removeEntity(const string &id)
Removes an entity.
Definition: Engine.cpp:502
array< unique_ptr< FrameBuffer >, EFFECTPASS_COUNT - 1 > effectPassFrameBuffers
Definition: Engine.h:299
static STATIC_DLL_IMPEXT unique_ptr< GUIShader > guiShader
Definition: Engine.h:220
static STATIC_DLL_IMPEXT Renderer * renderer
Definition: Engine.h:205
static STATIC_DLL_IMPEXT unique_ptr< DeferredLightingRenderShader > deferredLightingRenderShader
Definition: Engine.h:223
unique_ptr< Partition > partition
Definition: Engine.h:289
void initRendering()
Initiates the rendering process updates timing, updates camera.
Definition: Engine.cpp:1078
void doPostProcessing(PostProcessingProgram::RenderPass renderPass, const array< FrameBuffer *, 2 > postProcessingFrameBuffers, FrameBuffer *targetFrameBuffer)
Do post processing.
Definition: Engine.cpp:2240
TextureAtlas decalsTextureAtlas
Definition: Engine.h:329
vector< unique_ptr< Action > > actions
Definition: Engine.h:331
void reshape(int32_t width, int32_t height)
Reshape.
Definition: Engine.cpp:972
void display()
Renders the scene.
Definition: Engine.cpp:1361
static STATIC_DLL_IMPEXT unique_ptr< LinesShader > linesShader
Definition: Engine.h:218
TextureAtlas ppsTextureAtlas
Definition: Engine.h:328
void preRenderFunction(vector< Object * > &objects, int threadIdx)
Update vertex buffers and such before rendering.
Definition: Engine.cpp:1087
unique_ptr< FrameBuffer > postProcessingFrameBuffer2
Definition: Engine.h:297
static STATIC_DLL_IMPEXT unique_ptr< GUIRenderer > guiRenderer
Definition: Engine.h:210
void initialize()
Initialize render engine.
Definition: Engine.cpp:733
bool makeScreenshot(const string &pathName, const string &fileName, bool removeAlphaChannel=true)
Creates a PNG file from current screen( This does not seem to work with GLES2 and offscreen engines.
Definition: Engine.cpp:2151
static STATIC_DLL_IMPEXT int threadCount
Definition: Engine.h:228
Vector3 computeGizmoCoordinateByMousePosition(int32_t mouseX, int32_t mouseY, float z)
Compute gizmo coordinate from mouse position and z value.
Definition: Engine.h:1242
unique_ptr< FrameBuffer > postProcessingTemporaryFrameBuffer
Definition: Engine.h:298
int32_t getWidth()
Definition: Engine.h:1029
~Engine()
Destructor.
Definition: Engine.cpp:284
unique_ptr< GUI > gui
Definition: Engine.h:284
static STATIC_DLL_IMPEXT bool skinningShaderEnabled
Definition: Engine.h:315
unordered_set< Entity * > noFrustumCullingEntities
Definition: Engine.h:307
void decomposeEntityTypes(const vector< Entity * > &entities, DecomposedEntities &decomposedEntities, bool decomposeAllEntities=false)
Decompose entity types.
Definition: Engine.cpp:1227
Vector3 computeWorldCoordinateByMousePosition(int32_t mouseX, int32_t mouseY, float z)
Compute world coordinate from mouse position and z value.
Definition: Engine.h:1253
void setPartition(Partition *partition)
Set partition.
Definition: Engine.cpp:352
static constexpr int UNIQUEMODELID_NONE
Definition: Engine.h:335
unique_ptr< Camera > gizmoCamera
Definition: Engine.h:287
void addPostProcessingProgram(const string &programId)
Add post processing program.
Definition: Engine.cpp:2235
static STATIC_DLL_IMPEXT AnimationProcessingTarget animationProcessingTarget
Definition: Engine.h:212
void doneGUIMode()
Set up GUI mode rendering.
Definition: Engine.cpp:2142
Entity * doRayCasting(const Vector3 &startPoint, const Vector3 &endPoint, Vector3 &contactPoint, EntityPickingFilter *filter=nullptr)
Does a ray casting of visible 3d object based entities.
Definition: Engine.h:1308
unique_ptr< EntityRenderer > entityRenderer
Definition: Engine.h:313
void initGUIMode()
Set up GUI mode rendering.
Definition: Engine.cpp:2130
static STATIC_DLL_IMPEXT unique_ptr< LightingShader > lightingShader
Definition: Engine.h:216
void decomposeEntityType(Entity *entity, DecomposedEntities &decomposedEntities, bool decomposeAllEntities=false)
Decompose entity type.
Definition: Engine.cpp:1095
void computeAnimationsFunction(vector< Object * > &objects, int threadIdx)
Computes animations.
Definition: Engine.cpp:1091
static STATIC_DLL_IMPEXT unique_ptr< BRDFLUTShader > brdfLUTShader
Definition: Engine.h:221
unique_ptr< FrameBuffer > postProcessingFrameBuffer1
Definition: Engine.h:296
void removeFromDecomposedEntities(DecomposedEntities &decomposedEntities, Entity *entity)
Remove entity from decomposed entities.
Definition: Engine.cpp:534
static STATIC_DLL_IMPEXT unique_ptr< ParticlesShader > particlesShader
Definition: Engine.h:217
void deregisterModel(Model *model)
Deregister model.
Definition: Engine.h:1580
static Renderer * getRenderer()
Definition: Engine.h:434
static Engine * createOffScreenInstance(int32_t width, int32_t height, bool enableShadowMapping, bool enableDepthBuffer, bool enableGeometryBuffer)
Creates an offscreen rendering instance Note:
Definition: Engine.cpp:297
static void shutdown()
Shuts down main engine.
Definition: Engine.cpp:263
int32_t getHeight()
Definition: Engine.h:1036
vector< int > freeObjectUniqueModelIdIds
Definition: Engine.h:341
static STATIC_DLL_IMPEXT unique_ptr< ShadowMapRenderShader > shadowMappingShaderRender
Definition: Engine.h:215
void scale(int32_t width, int32_t height)
Scale which applies to main engine only.
Definition: Engine.cpp:1030
static constexpr int ENGINETHREADSQUEUE_COMPUTE_DISPATCH_COUNT
Definition: Engine.h:191
static STATIC_DLL_IMPEXT unique_ptr< ShadowMapCreationShader > shadowMappingShaderPre
Definition: Engine.h:214
bool shadowMappingEnabled
Definition: Engine.h:317
static int32_t getShadowMapWidth()
Definition: Engine.h:730
static STATIC_DLL_IMPEXT unique_ptr< Queue< EngineThreadQueueElement > > engineThreadsQueue
Definition: Engine.h:428
void dumpEntities()
Dump entities.
Definition: Engine.cpp:2904
Engine()
Private constructor.
Definition: Engine.cpp:269
void renderToScreen()
Render scaled main engine to screen.
Definition: Engine.cpp:1053
const string getGraphicsRenderer()
Definition: Engine.cpp:348
array< bool, EFFECTPASS_COUNT - 1 > effectPassSkip
Definition: Engine.h:300
static int32_t getShadowMapHeight()
Definition: Engine.h:737
unordered_set< Entity * > requirePreRenderEntities
Definition: Engine.h:308
static const vector< string > getRegisteredShader(ShaderType type, bool sort=true)
Returns registered shaders for given type.
Definition: Engine.h:837
unordered_map< string, Entity * > entitiesById
Definition: Engine.h:304
void addEntity(Entity *entity)
Adds an entity by id.
Definition: Engine.cpp:357
unordered_set< Entity * > requireComputeAnimationEntities
Definition: Engine.h:309
const ShaderParameter getShaderParameter(const string &shaderId, const string &parameterName)
Returns shader parameter for given shader id and parameter name, if the value does not exist,...
Definition: Engine.h:941
bool computeScreenCoordinateByWorldCoordinate(const Vector3 &worldCoordinate, Vector2 &screenCoordinate, int width=-1, int height=-1)
Convert screen coordinate by world coordinate.
Definition: Engine.cpp:2058
static STATIC_DLL_IMPEXT unique_ptr< TextureManager > textureManager
Definition: Engine.h:207
unique_ptr< Timing > timing
Definition: Engine.h:285
static STATIC_DLL_IMPEXT unique_ptr< SkyRenderShader > skyRenderShader
Definition: Engine.h:224
static STATIC_DLL_IMPEXT Engine * instance
Definition: Engine.h:204
static STATIC_DLL_IMPEXT unique_ptr< MeshManager > meshManager
Definition: Engine.h:209
vector< string > postProcessingPrograms
Definition: Engine.h:320
void resetPostProcessingPrograms()
Clear post processing programs.
Definition: Engine.cpp:2231
void deregisterEntity(Entity *entity)
Removes a entity from internal lists, those entities can also be sub entities from entity hierarchy o...
Definition: Engine.cpp:382
void dispose()
Shutdown the engine.
Definition: Engine.cpp:2071
void dumpEntityHierarchy(EntityHierarchy *entityHierarchy, int indent, const string &parentNodeId)
Dump entity hierarchy.
Definition: Engine.cpp:2850
static STATIC_DLL_IMPEXT EngineThreadQueueElementPool engineThreadQueueElementPool
Definition: Engine.h:429
static int32_t getShadowMapRenderLookUps()
Definition: Engine.h:744
unique_ptr< ShadowMapping > shadowMapping
Definition: Engine.h:301
static STATIC_DLL_IMPEXT unique_ptr< FrameBufferRenderShader > frameBufferRenderShader
Definition: Engine.h:222
Entity * getEntity(const string &id)
Returns a entity by given id.
Definition: Engine.h:1175
unordered_map< Model *, UniqueModelId > objectUniqueModelIdMapping
Definition: Engine.h:340
static STATIC_DLL_IMPEXT unique_ptr< Texture2DRenderShader > texture2DRenderShader
Definition: Engine.h:227
const string getGraphicsVendor()
Definition: Engine.cpp:344
void unscale()
Disable scaling, which applies to main engine only.
Definition: Engine.cpp:1044
static void setShadowMapSize(int32_t width, int32_t height)
Set shadow map size.
Definition: Engine.h:753
unordered_set< Entity * > autoEmitParticleSystemEntities
Definition: Engine.h:306
unique_ptr< GeometryBuffer > geometryBuffer
Definition: Engine.h:293
void reset()
Removes all entities and caches.
Definition: Engine.cpp:716
unique_ptr< Camera > camera
Definition: Engine.h:286
static STATIC_DLL_IMPEXT unique_ptr< VBOManager > vboManager
Definition: Engine.h:208
static STATIC_DLL_IMPEXT unique_ptr< PostProcessing > postProcessing
Definition: Engine.h:225
static STATIC_DLL_IMPEXT vector< unique_ptr< EngineThread > > engineThreads
Definition: Engine.h:427
Entity * getEntityByMousePosition(int32_t mouseX, int32_t mouseY, EntityPickingFilter *filter=nullptr, Node **objectNode=nullptr, ParticleSystem **particleSystemEntity=nullptr)
Retrieves entity by mouse position.
Definition: Engine.h:1275
static constexpr int ENGINETHREADSQUEUE_PRERENDER_DISPATCH_COUNT
Definition: Engine.h:190
int registerModel(Model *model)
Register model.
Definition: Engine.h:1545
void render(FrameBuffer *renderFrameBuffer, GeometryBuffer *renderGeometryBuffer, Camera *rendererCamera, DecomposedEntities &visibleDecomposedEntities, int32_t effectPass, int32_t renderPassMask, const string &shaderPrefix, bool applyShadowMapping, bool applyPostProcessing, bool doRenderLightSource, bool doRenderParticleSystems, int32_t renderTypes, bool skyShaderEnabled)
Do a render/effect pass.
Definition: Engine.cpp:2304
void loadTextures(const string &pathName)
Load textures.
Definition: Engine.cpp:289
int32_t scaledWidth
Definition: Engine.h:282
void removeEntityFromLists(Entity *entity)
Remove entity.
Definition: Engine.cpp:674
bool isUsingPostProcessingTemporaryFrameBuffer
Definition: Engine.h:324
static STATIC_DLL_IMPEXT unique_ptr< SkinningShader > skinningShader
Definition: Engine.h:219
DecomposedEntities visibleDecomposedEntities
Definition: Engine.h:311
void resetLists(DecomposedEntities &decomposedEntites)
Reset lists.
Definition: Engine.cpp:1057
unique_ptr< FrameBuffer > gizmoFrameBuffer
Definition: Engine.h:295
void preRender(Camera *camera, DecomposedEntities &decomposedEntites, bool autoEmit, bool computeAnimations)
Computes visibility and animations and other pre render steps.
Definition: Engine.cpp:1233
int32_t scaledHeight
Definition: Engine.h:283
void registerEntity(Entity *entity)
Adds a entity to internal lists, those entities can also be sub entities from entity hierarchy or par...
Definition: Engine.cpp:437
static const vector< Shader::ParameterDefaults > * getShaderParameterDefaults(const string &shaderId)
Returns parameter defaults of shader with given id.
Definition: Engine.h:882
array< unique_ptr< Light >, LIGHTS_MAX > lights
Definition: Engine.h:291
Entity hierarchy to be used with engine class.
const vector< Entity * > query(const string &parentId=string())
Query sub entities of parent entity.
const string & getId() override
Engine entity.
Definition: Entity.h:30
@ RENDERPASS_POST_POSTPROCESSING
Definition: Entity.h:85
virtual bool isEnabled()=0
virtual void setRenderer(Renderer *renderer)=0
Set up renderer.
virtual const string & getId()=0
Entity * getParentEntity()
Definition: Entity.h:52
virtual bool isFrustumCulling()=0
virtual void setEngine(Engine *engine)=0
Set up engine.
virtual EntityType getEntityType()=0
static constexpr int RENDERPASS_ALL
Definition: Entity.h:84
virtual void initialize()=0
Initiates this entity.
static constexpr int RENDERPASS_MAX
Definition: Entity.h:83
@ ENTITYTYPE_OBJECTRENDERGROUP
Definition: Entity.h:96
@ ENTITYTYPE_OBJECTPARTICLESYSTEM
Definition: Entity.h:98
@ ENTITYTYPE_IMPOSTEROBJECT
Definition: Entity.h:91
@ ENTITYTYPE_FOGPARTICLESYSTEM
Definition: Entity.h:97
@ ENTITYTYPE_POINTSPARTICLESYSTEM
Definition: Entity.h:100
@ ENTITYTYPE_ENVIRONMENTMAPPING
Definition: Entity.h:90
@ ENTITYTYPE_PARTICLESYSTEMGROUP
Definition: Entity.h:99
@ ENTITYTYPE_LODOBJECTIMPOSTER
Definition: Entity.h:94
@ ENTITYTYPE_ENTITYHIERARCHY
Definition: Entity.h:89
Environment mapping entity.
Fog particle system entity to be used with engine class.
Frame buffer class.
Definition: FrameBuffer.h:22
static void disableFrameBuffer()
Switches back to non offscreen main frame buffer to be rendered.
void enableFrameBuffer()
Enables this frame buffer to be rendered.
Definition: FrameBuffer.cpp:93
static constexpr int32_t FRAMEBUFFER_COLORBUFFER
Definition: FrameBuffer.h:26
static void doPostProcessing(Engine *engine, FrameBuffer *target, FrameBuffer *source, const string &programId, const string &shaderId, FrameBuffer *temporary=nullptr, FrameBuffer *blendToSource=nullptr)
Do post processing into target frame buffer (which can be screen as well when passing nullptr)
static constexpr int32_t FRAMEBUFFER_DEPTHBUFFER
Definition: FrameBuffer.h:25
Geometry buffer class.
void renderToScreen(Engine *engine, vector< Decal * > &decalEntities)
Render to screen or bound geometry buffer @engine engine.
void enableGeometryBuffer()
Enables this geometry buffer to be rendered.
static void disableGeometryBuffer()
Switches back to non offscreen main frame buffer to be rendered.
Imposter object to be used with engine class.
LOD object + imposter to be used with engine class.
LOD object to be used with engine class.
Definition: LODObject.h:49
Object * getLOD1Object()
Definition: LODObject.h:145
Light representation.
Definition: Light.h:33
Lines entity to be used with engine class.
Definition: Lines.h:38
Object particle system entity to be used with engine class.
Object render group for static objects that might be animated by shaders.
Object to be used with engine class.
Definition: Object.h:60
Oct tree partition implementation.
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.
Shader parameter model class.
const array< float, 4 > getColor4ValueArray() const
const array< float, 4 > getVector4ValueArray() const
const array< float, 3 > getVector3ValueArray() const
const array< float, 2 > getVector2ValueArray() const
Texture entity.
Definition: Texture.h:24
Timing class.
Definition: Timing.h:16
Model node.
Definition: Node.h:32
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:26
Line segment helper functions.
Definition: LineSegment.h:16
Interface to lighting shader program.
virtual void initializeFrame()=0
Pre Frame Initialization.
virtual void enableDepthBufferTest()=0
Enable depth buffer test.
void setShaderPrefix(const string &shaderPrefix)
Set shader prefix.
Definition: Renderer.h:485
virtual void finishFrame()=0
Finish frame.
virtual void setClearColor(float red, float green, float blue, float alpha)=0
Set up clear color.
virtual void enableBlending()=0
Enables blending.
virtual void disableBlending()=0
Disables blending.
virtual void initGuiMode()=0
Set up renderer for GUI rendering.
virtual void initialize()=0
Initialize renderer.
virtual ByteBuffer * readPixels(int32_t x, int32_t y, int32_t width, int32_t height)=0
Read pixels.
virtual void clear(int32_t mask)=0
Clear render buffer with given mask.
void setEffectPass(int32_t effectPass)
Set effect pass.
Definition: Renderer.h:469
virtual void doneGuiMode()=0
Set up renderer for 3d rendering.
virtual float readPixelDepth(int32_t x, int32_t y)=0
Reads a pixel depth.
virtual void disableDepthBufferTest()=0
Disable depth buffer test.
Buffers used to transfer data between main memory to graphics board memory.
Definition: ObjectBuffer.h:24
Interface to compute shader skinning shader program.
GUI parser.
Definition: GUIParser.h:40
GUI module class.
Definition: GUI.h:64
Standard math functions.
Definition: Math.h:19
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Definition: Matrix4x4.h:23
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Definition: Vector2.h:20
Vector2 & sub(float scalar)
Subtracts a scalar.
Definition: Vector2.h:152
Vector2 & scale(const float scalar)
Scales by scalar.
Definition: Vector2.h:174
Vector2 clone() const
Clones this vector2.
Definition: Vector2.h:265
Vector2 & setX(float x)
Sets x component.
Definition: Vector2.h:103
Vector2 & setY(float y)
Sets y component.
Definition: Vector2.h:120
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
float computeLengthSquared() const
Definition: Vector3.h:281
Vector3 clone() const
Clones this vector3.
Definition: Vector3.h:374
Vector3 & sub(float scalar)
Subtracts a scalar.
Definition: Vector3.h:177
Vector3 & scale(float scalar)
Scales by scalar.
Definition: Vector3.h:201
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
Definition: Vector3.h:70
Vector4 class representing vector4 mathematical structure and operations with x, y,...
Definition: Vector4.h:22
File system singleton class.
Definition: FileSystem.h:17
Consumer/producer queue.
Definition: Queue.h:26
Base class for threads.
Definition: Thread.h:20
Byte buffer class.
Definition: ByteBuffer.h:27
Console class.
Definition: Console.h:29
Float class.
Definition: Float.h:27
T * allocate()
Allocate a new element from pool.
Definition: Pool.h:55
void reset()
Reset this pool.
Definition: Pool.h:98
virtual void releaseReference()
Releases a reference, thus decrementing the counter and delete it if reference counter is zero.
Definition: Reference.h:38
virtual void acquireReference()
Acquires a reference, incrementing the counter.
Definition: Reference.h:31
void removeTexture(Texture *texture)
Remove texture.
int addTexture(Texture *texture)
Add texture.
vector< EntityHierarchy * > entityHierarchies
Definition: Engine.h:272
vector< LODObject * > lodObjects
Definition: Engine.h:264
vector< EnvironmentMapping * > environmentMappingEntities
Definition: Engine.h:273
vector< ParticleSystemGroup * > psgs
Definition: Engine.h:268
vector< Object * > objectsPostPostProcessing
Definition: Engine.h:261
vector< ObjectParticleSystem * > opses
Definition: Engine.h:266
vector< ObjectRenderGroup * > objectRenderGroups
Definition: Engine.h:271
vector< Object * > requireComputeAnimationEntities
Definition: Engine.h:275
vector< Entity * > noFrustumCullingEntities
Definition: Engine.h:258
vector< Object * > objectsNoDepthTest
Definition: Engine.h:262
vector< Object * > objectsForwardShading
Definition: Engine.h:260
vector< Object * > requirePreRenderEntities
Definition: Engine.h:274
virtual bool filterEntity(Entity *entity)=0
Filter entity.
Particle system entity interface.
virtual int emitParticles()=0
Adds particles to this particle entity at given position.
Partition interface.
Definition: Partition.h:18