TDME2 1.9.121
Engine.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <map>
5#include <string>
6
7#include <tdme/tdme.h>
43#include <tdme/engine/Camera.h>
44#include <tdme/engine/Entity.h>
52#include <tdme/engine/Light.h>
65#include <tdme/engine/Timing.h>
68#include <tdme/gui/GUI.h>
69#include <tdme/gui/GUIParser.h>
70#include <tdme/math/Math.h>
71#include <tdme/math/Matrix4x4.h>
72#include <tdme/math/Vector2.h>
73#include <tdme/math/Vector3.h>
74#include <tdme/math/Vector4.h>
83
84using std::map;
85using std::remove;
86using std::string;
87using std::to_string;
88
148using tdme::gui::GUI;
150using tdme::math::Math;
162
163Engine* Engine::instance = nullptr;
164Renderer* Engine::renderer = nullptr;
165TextureManager* Engine::textureManager = nullptr;
166VBOManager* Engine::vboManager = nullptr;
167MeshManager* Engine::meshManager = nullptr;
168GUIRenderer* Engine::guiRenderer = nullptr;
169FrameBufferRenderShader* Engine::frameBufferRenderShader = nullptr;
170DeferredLightingRenderShader* Engine::deferredLightingRenderShader = nullptr;
171PostProcessing* Engine::postProcessing = nullptr;
172PostProcessingShader* Engine::postProcessingShader = nullptr;
173Texture2DRenderShader* Engine::texture2DRenderShader = nullptr;
174Engine::AnimationProcessingTarget Engine::animationProcessingTarget = Engine::AnimationProcessingTarget::CPU;
175EZRShader* Engine::ezrShader = nullptr;
176ShadowMapCreationShader* Engine::shadowMappingShaderPre = nullptr;
177ShadowMapRenderShader* Engine::shadowMappingShaderRender = nullptr;
178LightingShader* Engine::lightingShader = nullptr;
179ParticlesShader* Engine::particlesShader = nullptr;
180LinesShader* Engine::linesShader = nullptr;
181SkinningShader* Engine::skinningShader = nullptr;
182GUIShader* Engine::guiShader = nullptr;
183Engine* Engine::currentEngine = nullptr;
184bool Engine::skinningShaderEnabled = false;
185int Engine::threadCount = 0;
186bool Engine::have4K = false;
187float Engine::animationBlendingTime = 250.0f;
188int32_t Engine::shadowMapWidth = 0;
189int32_t Engine::shadowMapHeight = 0;
190int32_t Engine::shadowMapRenderLookUps = 0;
191int32_t Engine::environmentMappingWidth = 1024;
192int32_t Engine::environmentMappingHeight = 1024;
193float Engine::transformationsComputingReduction1Distance = 25.0f;
194float Engine::transformationsComputingReduction2Distance = 50.0f;
195map<string, Engine::Shader> Engine::shaders;
196unordered_map<string, uint8_t> Engine::uniqueShaderIds;
197
198vector<Engine::EngineThread*> Engine::engineThreads;
199Queue<Engine::EngineThreadQueueElement>* Engine::engineThreadsQueue = nullptr;
200Engine::EngineThreadQueueElementPool Engine::engineThreadQueueElementPool;
201
202Engine::EngineThread::EngineThread(int idx, Queue<EngineThreadQueueElement>* queue):
203 Thread("enginethread"),
204 idx(idx),
205 queue(queue) {
206 //
208}
209
211 Console::println("EngineThread::" + string(__FUNCTION__) + "()[" + to_string(idx) + "]: INIT");
212 while (isStopRequested() == false) {
213 auto element = queue->getElement();
214 if (element == nullptr) continue;
215 switch(element->type) {
217 break;
219 element->engine->preRenderFunction(
220 element->objects,
221 idx
222 );
223 element->objects.clear();
224 elementsProcessed++;
225 break;
227 element->engine->computeTransformationsFunction(
228 element->objects,
229 idx
230 );
231 element->objects.clear();
232 elementsProcessed++;
233 break;
235 element->engine->entityRenderer->renderFunction(
236 idx,
237 element->rendering.renderPass,
238 element->objects,
239 objectsByShadersAndModels,
240 element->rendering.collectTransparentFaces,
241 element->rendering.renderTypes,
242 transparentRenderFacesPool
243 );
244 element->objects.clear();
245 elementsProcessed++;
246 break;
247 }
248 }
249 Console::println("EngineThread::" + string(__FUNCTION__) + "()[" + to_string(idx) + "]: DONE");
250}
251
253 timing = new Timing();
254 camera = nullptr;
255 sceneColor.set(0.0f, 0.0f, 0.0f, 1.0f);
256 frameBuffer = nullptr;
257 // shadow mapping
258 shadowMappingEnabled = false;
259 shadowMapping = nullptr;
260 // render process state
261 renderingInitiated = false;
263 //
264 initialized = false;
265 // post processing frame buffers
269 //
271 //
272 effectPassFrameBuffers.fill(nullptr);
273 effectPassSkip.fill(false);
274}
275
277 delete timing;
278 delete camera;
279 delete gui;
280 delete partition;
281 if (frameBuffer != nullptr) delete frameBuffer;
285 if (shadowMapping != nullptr) delete shadowMapping;
286 delete entityRenderer;
287 if (instance == this) {
288 delete renderer;
289 delete textureManager;
290 delete vboManager;
291 delete meshManager;
292 delete guiRenderer;
293 delete lightingShader;
294 delete particlesShader;
295 delete linesShader;
298 delete postProcessing;
301 delete guiShader;
302 delete ezrShader;
305 }
306 // set current engine
307 if (currentEngine == this) currentEngine = nullptr;
308}
309
310Engine* Engine::createOffScreenInstance(int32_t width, int32_t height, bool enableShadowMapping, bool enableDepthBuffer, bool enableGeometryBuffer)
311{
312 if (instance == nullptr || instance->initialized == false) {
313 Console::println(string("Engine::createOffScreenInstance(): Engine not created or not initialized."));
314 return nullptr;
315 }
316 // create off screen engine
317 auto offScreenEngine = new Engine();
318 offScreenEngine->initialized = true;
319 // create GUI
320 offScreenEngine->gui = new GUI(offScreenEngine, guiRenderer);
321 // create object 3d vbo renderer
322 offScreenEngine->entityRenderer = new EntityRenderer(offScreenEngine, renderer);
323 offScreenEngine->entityRenderer->initialize();
324 // TODO: geometry buffer
325 // create framebuffers
326 offScreenEngine->frameBuffer = new FrameBuffer(width, height, (enableDepthBuffer == true?FrameBuffer::FRAMEBUFFER_DEPTHBUFFER:0) | FrameBuffer::FRAMEBUFFER_COLORBUFFER);
327 offScreenEngine->frameBuffer->initialize();
328 // create camera, frustum partition
329 offScreenEngine->camera = new Camera(renderer);
330 offScreenEngine->partition = new OctTreePartition();
331 // create lights
332 for (auto i = 0; i < offScreenEngine->lights.size(); i++) {
333 offScreenEngine->lights[i] = Light(renderer, i);
334 offScreenEngine->lights[i].setSourceTexture(TextureReader::read("resources/engine/textures", "sun.png"));
335 }
336 // create shadow mapping
337 if (instance->shadowMappingEnabled == true && enableShadowMapping == true) {
338 offScreenEngine->shadowMapping = new ShadowMapping(offScreenEngine, renderer, offScreenEngine->entityRenderer);
339 }
340 // geometry buffer
341 if (renderer->isDeferredShadingAvailable() == true && enableGeometryBuffer == true) {
342 offScreenEngine->geometryBuffer = new GeometryBuffer(width, height);
343 offScreenEngine->geometryBuffer->initialize();
344 }
345 //
346 offScreenEngine->reshape(width, height);
347 return offScreenEngine;
348}
349
351 return renderer->getVendor();
352}
353
355 return renderer->getRenderer();
356}
357
359{
360 if (this->partition != nullptr && this->partition != partition) delete this->partition;
361 this->partition = partition;
362}
363
365{
366 {
367 auto entityByIdIt = entitiesById.find(entity->getId());
368 if (entityByIdIt != entitiesById.end()) {
369 // check if we want to add this entity a second time
370 if (entity == entityByIdIt->second) {
371 Console::println("Engine::addEntity(): " + entity->getId() + ": entity already added!");
372 return;
373 }
374 // dispose old entity if any did exist in engine with same id
375 removeEntity(entity->getId());
376 }
377 }
378
379 // init entity
380 entity->setEngine(this);
381 entity->setRenderer(renderer);
382 entity->initialize();
383 entitiesById[entity->getId()] = entity;
384
385 // add to partition if enabled and frustum culling requested
386 if (entity->isFrustumCulling() == true && entity->isEnabled() == true) partition->addEntity(entity);
387
388 // update
389 registerEntity(entity);
390}
391
393 //
394 noFrustumCullingEntities.erase(entity);
396 remove(
399 ),
401 autoEmitParticleSystemEntities.erase(entity);
403 needsPreRenderEntities.erase(entity);
404}
405
407 //
408 noFrustumCullingEntities.erase(entity);
410 remove(
413 entity
414 ),
416 );
417 autoEmitParticleSystemEntities.erase(entity);
418
419 // add to no frustum culling
420 if (entity->isFrustumCulling() == false && entity->getParentEntity() == nullptr) {
421 // otherwise add to no frustum culling entities
422 noFrustumCullingEntities.insert(entity);
424 }
425
426 // add to auto emit particle system entities
427 auto particleSystemEntity = dynamic_cast<ParticleSystemEntity*>(entity);
428 if (particleSystemEntity != nullptr && particleSystemEntity->isAutoEmit() == true) {
429 autoEmitParticleSystemEntities.insert(particleSystemEntity);
430 }
431
432 // decompose to Object3D instances to do pre render
433 DecomposedEntities decomposedEntities;
434 decomposeEntityType(entity, decomposedEntities, true);
435 array<vector<Object3D*>, 5> objectsArray = {
436 decomposedEntities.ezrObjects,
437 decomposedEntities.objects,
438 decomposedEntities.objectsForwardShading,
439 decomposedEntities.objectsNoDepthTest,
440 decomposedEntities.objectsPostPostProcessing,
441 };
442 for (auto& objects: objectsArray) {
443 for (auto object3D: objects) {
444 object3D->preRender(renderer->CONTEXTINDEX_DEFAULT);
445 if (object3D->isNeedsPreRender() == true) needsPreRenderEntities.insert(object3D);
446 if (object3D->isNeedsComputeTransformations() == true) needsComputeTransformationsEntities.insert(object3D);
447 }
448 }
449}
450
451bool Engine::removeEntity(const string& id)
452{
453 // get entity and remove if we have any
454 auto entityByIdIt = entitiesById.find(id);
455 if (entityByIdIt == entitiesById.end()) return false;
456
457 //
458 auto entity = entityByIdIt->second;
459
460 //
461 entitiesById.erase(entityByIdIt);
462 autoEmitParticleSystemEntities.erase(entity);
463 noFrustumCullingEntities.erase(entity);
464 needsPreRenderEntities.erase(entity);
466
467 // remove from partition if enabled and frustum culling requested
468 if (entity->isFrustumCulling() == true && entity->isEnabled() == true) partition->removeEntity(entity);
469
470 //
471 removeEntityFromLists(entity);
472
473 // dispose entity
474 entity->dispose();
475 entity->setEngine(nullptr);
476 entity->setRenderer(nullptr);
477 delete entity;
478
479 //
480 return true;
481}
482
483inline void Engine::removeFromDecomposedEntities(DecomposedEntities& decomposedEntities, Entity* entity) {
484 // delete from lists
485 decomposedEntities.objects.erase(
486 remove(
487 decomposedEntities.objects.begin(),
488 decomposedEntities.objects.end(),
489 entity
490 ),
491 decomposedEntities.objects.end()
492 );
493 decomposedEntities.objectsForwardShading.erase(
494 remove(
495 decomposedEntities.objectsForwardShading.begin(),
496 decomposedEntities.objectsForwardShading.end(),
497 entity
498 ),
499 decomposedEntities.objectsForwardShading.end()
500 );
501 decomposedEntities.objectsPostPostProcessing.erase(
502 remove(
503 decomposedEntities.objectsPostPostProcessing.begin(),
504 decomposedEntities.objectsPostPostProcessing.end(),
505 entity
506 ),
507 decomposedEntities.objectsPostPostProcessing.end()
508 );
509 decomposedEntities.objectsNoDepthTest.erase(
510 remove(
511 decomposedEntities.objectsNoDepthTest.begin(),
512 decomposedEntities.objectsNoDepthTest.end(),
513 entity
514 ),
515 decomposedEntities.objectsNoDepthTest.end()
516 );
517 decomposedEntities.lodObjects.erase(
518 remove(
519 decomposedEntities.lodObjects.begin(),
520 decomposedEntities.lodObjects.end(),
521 entity
522 ),
523 decomposedEntities.lodObjects.end()
524 );
525 decomposedEntities.opses.erase(
526 remove(
527 decomposedEntities.opses.begin(),
528 decomposedEntities.opses.end(),
529 entity
530 ),
531 decomposedEntities.opses.end()
532 );
533 decomposedEntities.ppses.erase(
534 remove(
535 decomposedEntities.ppses.begin(),
536 decomposedEntities.ppses.end(),
537 entity
538 ),
539 decomposedEntities.ppses.end()
540 );
541 decomposedEntities.psgs.erase(
542 remove(
543 decomposedEntities.psgs.begin(),
544 decomposedEntities.psgs.end(),
545 entity
546 ),
547 decomposedEntities.psgs.end()
548 );
549 decomposedEntities.linesObjects.erase(
550 remove(
551 decomposedEntities.linesObjects.begin(),
552 decomposedEntities.linesObjects.end(),
553 entity
554 ),
555 decomposedEntities.linesObjects.end()
556 );
557 decomposedEntities.objectRenderGroups.erase(
558 remove(
559 decomposedEntities.objectRenderGroups.begin(),
560 decomposedEntities.objectRenderGroups.end(),
561 entity
562 ),
563 decomposedEntities.objectRenderGroups.end()
564 );
565 decomposedEntities.entityHierarchies.erase(
566 remove(
567 decomposedEntities.entityHierarchies.begin(),
568 decomposedEntities.entityHierarchies.end(),
569 entity
570 ),
571 decomposedEntities.entityHierarchies.end()
572 );
573 decomposedEntities.ezrObjects.erase(
574 remove(
575 decomposedEntities.ezrObjects.begin(),
576 decomposedEntities.ezrObjects.end(),
577 entity
578 ),
579 decomposedEntities.ezrObjects.end()
580 );
581 decomposedEntities.noFrustumCullingEntities.erase(
582 remove(
583 decomposedEntities.noFrustumCullingEntities.begin(),
584 decomposedEntities.noFrustumCullingEntities.end(),
585 entity
586 ),
587 decomposedEntities.noFrustumCullingEntities.end()
588 );
589 decomposedEntities.environmentMappingEntities.erase(
590 remove(
591 decomposedEntities.environmentMappingEntities.begin(),
592 decomposedEntities.environmentMappingEntities.end(),
593 entity
594 ),
595 decomposedEntities.environmentMappingEntities.end()
596 );
597 decomposedEntities.needsPreRenderEntities.erase(
598 remove(
599 decomposedEntities.needsPreRenderEntities.begin(),
600 decomposedEntities.needsPreRenderEntities.end(),
601 entity
602 ),
603 decomposedEntities.needsPreRenderEntities.end()
604 );
605 decomposedEntities.needsComputeTransformationsEntities.erase(
606 remove(
607 decomposedEntities.needsComputeTransformationsEntities.begin(),
608 decomposedEntities.needsComputeTransformationsEntities.end(),
609 entity
610 ),
611 decomposedEntities.needsComputeTransformationsEntities.end()
612 );
613}
614
616{
617 if (entity == nullptr) return;
618 //
621 removeEntityFromLists(static_cast<Object3DRenderGroup*>(entity)->getEntity());
622 } else
624 auto ops = static_cast<ObjectParticleSystem*>(entity);
625 for (auto subEntity: ops->getObjects()) {
626 removeEntityFromLists(subEntity);
627 }
628 } else
630 auto eh = static_cast<EntityHierarchy*>(entity);
631 for (auto subEntity: eh->getEntities()) {
632 removeEntityFromLists(subEntity);
633 }
634 } else
636 auto lob3d = static_cast<LODObject3D*>(entity);
637 removeEntityFromLists(lob3d->getLOD1Object());
638 removeEntityFromLists(lob3d->getLOD2Object());
639 removeEntityFromLists(lob3d->getLOD3Object());
640 } else
642 auto io3d = static_cast<ImposterObject3D*>(entity);
643 for (auto subEntity: io3d->getBillboardObjects()) removeEntityFromLists(subEntity);
644 } else
646 auto lob3dImposter = static_cast<LODObject3DImposter*>(entity);
647 removeEntityFromLists(lob3dImposter->getLOD1Object());
648 for (auto subEntity: lob3dImposter->getLOD2Object()->getBillboardObjects()) removeEntityFromLists(subEntity);
649 }
650}
651
653{
654 vector<string> entitiesToRemove;
655 for (auto it: entitiesById) {
656 auto entityKey = it.first;
657 entitiesToRemove.push_back(entityKey);
658 }
659 for (auto entityKey: entitiesToRemove) {
660 removeEntity(entityKey);
661 }
662 partition->reset();
665 // TODO: reset engine thread queue element pool
666}
667
669{
670 // set current engine
671 currentEngine = this;
672
673 // exit if already initialized like a offscreen engine instance
674 if (initialized == true)
675 return;
676
677 //
678 renderer = Application::getRenderer();
679 if (renderer == nullptr) {
680 initialized = false;
681 Console::println("No renderer: Exiting!");
682 Application::exit(0);
683 return;
684 }
685
687 if (getShadowMapWidth() == 0 || getShadowMapHeight() == 0) setShadowMapSize(2048, 2048);
690 animationProcessingTarget = renderer->isGLCLAvailable() == true || renderer->isComputeShaderAvailable() == true?Engine::AnimationProcessingTarget::GPU:Engine::AnimationProcessingTarget::CPU;
691
692 // determine if we have the skinning compute shader or OpenCL program
694 animationProcessingTarget = skinningShaderEnabled == true?Engine::AnimationProcessingTarget::GPU:Engine::AnimationProcessingTarget::CPU;
695
696 // engine thread count
698 if (threadCount == 0) threadCount = Math::clamp(Thread::getHardwareThreadCount() == 0?3:Thread::getHardwareThreadCount() / 2, 2, 3);
699 } else {
700 threadCount = 1;
701 }
702
703 Console::println(string("TDME2::Thread count: ") + to_string(threadCount));
704
705 // initialize object buffers
706 ObjectBuffer::initialize();
707
708 // create manager
711 meshManager = new MeshManager();
712
713 // init
714 initialized = true;
717
718 // graphics device
719 Console::println(string("TDME2::Renderer::Graphics Vendor: ") + renderer->getVendor());
720 Console::println(string("TDME2::Renderer::Graphics Renderer: ") + renderer->getRenderer());
721
722 // create object 3d renderer
725 GUIParser::initialize();
726
727 // create GUI
730 gui = new GUI(this, guiRenderer);
731 gui->initialize();
732
733 // create camera
734 camera = new Camera(renderer);
735
736 // create lights
737 for (auto i = 0; i < lights.size(); i++) {
738 lights[i] = Light(renderer, i);
739 lights[i].setSourceTexture(TextureReader::read("resources/engine/textures", "sun.png"));
740 }
741
742 // create partition
744
745 // create lighting shader
748
749 // create particles shader
752
753 // create particles shader
754 linesShader = new LinesShader(this, renderer);
756
757 // create gui shader
760
761 // create frame buffer render shader
764
765 // deferred lighting render shader
766 if (renderer->isDeferredShadingAvailable() == true) {
769 }
770
771 // create post processing shader
774
775 // create post processing
777
778 // create post processing shader
781
782 // check if VBOs are available
784 Console::println("TDME2::VBOs are available.");
785 } else {
786 Console::println("TDME2::VBOs are not available! Engine will not work!");
787 initialized = false;
788 }
789
790 // check FBO support
791 if (true == false/*glContext->hasBasicFBOSupport() == false*/) {
792 Console::println("TDME2::Basic FBOs are not available!");
793 shadowMappingEnabled = false;
794 } else {
795 Console::println("TDME2::Basic FBOs are available.");
796 }
797
798 // TODO: make this configurable
801
802 // initialize shadow mapping
803 if (shadowMappingEnabled == true) {
804 Console::println("TDME2::Using shadow mapping");
810 } else {
811 Console::println("TDME2::Not using shadow mapping");
812 }
813
814 // initialize skinning shader
815 if (skinningShaderEnabled == true) {
816 Console::println("TDME2::Using skinning compute shader");
819 } else {
820 Console::println("TDME2::Not using skinning compute shader");
821 }
822
823 #define CHECK_INITIALIZED(NAME, SHADER) if (SHADER != nullptr && SHADER->isInitialized() == false) Console::println(string("TDME: ") + NAME + ": Not initialized")
824
825 CHECK_INITIALIZED("EZRShader", ezrShader);
826 CHECK_INITIALIZED("ShadowMapCreationShader", shadowMappingShaderPre);
827 CHECK_INITIALIZED("ShadowMappingShader", shadowMappingShaderRender);
828 CHECK_INITIALIZED("LightingShader", lightingShader);
829 CHECK_INITIALIZED("ParticlesShader", particlesShader);
830 CHECK_INITIALIZED("LinesShader", linesShader);
831 CHECK_INITIALIZED("GUIShader", guiShader);
832 CHECK_INITIALIZED("FrameBufferRenderShader", frameBufferRenderShader);
833 CHECK_INITIALIZED("DeferredLightingRenderShader", deferredLightingRenderShader);
834 CHECK_INITIALIZED("PostProcessingShader", postProcessingShader);
835 CHECK_INITIALIZED("Texture2DRenderShader", texture2DRenderShader);
836
837 // check if initialized
838 // initialized &= objectsFrameBuffer->isInitialized();
839 initialized &= ezrShader == nullptr ? true : ezrShader->isInitialized();
850
851 // deferred shading
852 if (renderer->isDeferredShadingAvailable() == true) {
853 Console::println("TDME2::Using deferred shading");
854 } else {
855 Console::println("TDME2::Not using deferred shading");
856 }
857
858 //
859 Console::println(string("TDME2::initialized & ready: ") + to_string(initialized));
860
861 // shut down engine if not initialized
862 if (initialized == false) {
863 Console::println("Engine not initialized: Exiting!");
864 Application::exit(0);
865 return;
866 }
867
868 //
871 engineThreads.resize(threadCount - 1);
872 for (auto i = 0; i < threadCount - 1; i++) {
874 i + 1,
876 );
877 engineThreads[i]->start();
878 }
879 }
880
881 // show registered shaders
882 dumpShaders();
883}
884
885void Engine::reshape(int32_t width, int32_t height)
886{
887 // apparently windows sends 0x0 dimension if windows gets minimized
888 if (width == 0 && height == 0) return;
889
890 // set current engine
891 currentEngine = this;
892
893 // update our width and height
894 this->width = width;
895 this->height = height;
896
897 //
898 int _width = scaledWidth != -1?scaledWidth:width;
899 int _height = scaledHeight != -1?scaledHeight:height;
900
901 // update frame buffer if we have one
902 if (frameBuffer != nullptr) frameBuffer->reshape(_width, _height);
903
904 // update post processing frame buffer if we have one
905 if (postProcessingFrameBuffer1 != nullptr) postProcessingFrameBuffer1->reshape(_width, _height);
906 if (postProcessingFrameBuffer2 != nullptr) postProcessingFrameBuffer2->reshape(_width, _height);
910
911 // update shadow mapping
913
914 // unset scaling frame buffer if width and height matches scaling
915 if (this == Engine::instance && scaledWidth != -1 && scaledHeight != -1) {
916 if (this->width == scaledWidth && this->height == scaledHeight) {
917 if (frameBuffer != nullptr) frameBuffer->dispose();
918 frameBuffer = nullptr;
919 } else {
920 if (frameBuffer == nullptr) {
923 } else {
924 frameBuffer->reshape(_width, _height);
925 }
926 }
927 }
928
929 // create geometry buffer if available
930 if (renderer->isDeferredShadingAvailable() == true) {
931 if (geometryBuffer == nullptr) {
932 geometryBuffer = new GeometryBuffer(_width, _height);
934 } else {
935 geometryBuffer->reshape(_width, _height);
936 }
937 }
938
939 // update GUI system
941}
942
943void Engine::scale(int32_t width, int32_t height)
944{
945 if (this != Engine::instance) return;
948 if (frameBuffer != nullptr) frameBuffer->dispose();
949 frameBuffer = nullptr;
950 if (scaledWidth != this->width || scaledHeight != this->height) {
953 }
954 reshape(this->width, this->height);
955}
956
958{
959 scaledWidth = -1;
960 scaledHeight = -1;
961 if (frameBuffer != nullptr) frameBuffer->dispose();
962 frameBuffer = nullptr;
963 reshape(this->width, this->height);
964}
965
967 if (this == Engine::instance && frameBuffer != nullptr) frameBuffer->renderToScreen(this);
968}
969
970void Engine::resetLists(DecomposedEntities& decomposedEntites) {
971 // clear lists of visible objects
972 decomposedEntites.objects.clear();
973 decomposedEntites.objectsForwardShading.clear();
974 decomposedEntites.objectsPostPostProcessing.clear();
975 decomposedEntites.objectsNoDepthTest.clear();
976 decomposedEntites.lodObjects.clear();
977 decomposedEntites.opses.clear();
978 decomposedEntites.ppses.clear();
979 decomposedEntites.psgs.clear();
980 decomposedEntites.linesObjects.clear();
981 decomposedEntites.objectRenderGroups.clear();
982 decomposedEntites.entityHierarchies.clear();
983 decomposedEntites.ezrObjects.clear();
984 decomposedEntites.noFrustumCullingEntities.clear();
985 decomposedEntites.environmentMappingEntities.clear();
986 decomposedEntites.needsPreRenderEntities.clear();
987 decomposedEntites.needsComputeTransformationsEntities.clear();
988}
989
991{
992 // update timing
994
995 //
997
998 //
999 renderingInitiated = true;
1000}
1001
1002void Engine::preRenderFunction(vector<Object3D*>& objects, int threadIdx) {
1003 for (auto object: objects) object->preRender(threadIdx);
1004}
1005
1006void Engine::computeTransformationsFunction(vector<Object3D*>& objects, int threadIdx) {
1007 for (auto object: objects) object->computeTransformations(threadIdx);
1008}
1009
1010inline void Engine::decomposeEntityType(Entity* entity, DecomposedEntities& decomposedEntities, bool decomposeAllEntities) {
1011 switch (entity->getEntityType()) {
1013 {
1014 auto object = static_cast<Object3D*>(entity);
1015 if (object->isDisableDepthTest() == true) {
1016 decomposedEntities.objectsNoDepthTest.push_back(object);
1017 } else
1018 if (object->getRenderPass() == Entity::RENDERPASS_POST_POSTPROCESSING) {
1019 decomposedEntities.objectsPostPostProcessing.push_back(object);
1020 } else
1021 if (object->isNeedsForwardShading() == true &&
1022 (object->getRenderPass() == Entity::RENDERPASS_TERRAIN || object->getRenderPass() == Entity::RENDERPASS_STANDARD) &&
1024 decomposedEntities.objectsForwardShading.push_back(object);
1025 } else {
1026 decomposedEntities.objects.push_back(object);
1027 }
1028 if (object->isEnableEarlyZRejection() == true) {
1029 decomposedEntities.ezrObjects.push_back(object);
1030 }
1031 }
1032 break;
1034 {
1035 auto lodObject = static_cast<LODObject3D*>(entity);
1036 if (decomposeAllEntities == true) {
1037 auto lod1Object = lodObject->getLOD1Object();
1038 auto lod2Object = lodObject->getLOD2Object();
1039 auto lod3Object = lodObject->getLOD3Object();
1040 if (lod1Object != nullptr) decomposeEntityType(lod1Object, decomposedEntities);
1041 if (lod2Object != nullptr) decomposeEntityType(lod2Object, decomposedEntities);
1042 if (lod3Object != nullptr) decomposeEntityType(lod3Object, decomposedEntities);
1043 } else {
1044 auto object = lodObject->determineLODObject(camera);
1045 if (object != nullptr) decomposeEntityType(object, decomposedEntities, decomposeAllEntities);
1046 }
1047 }
1048 break;
1050 {
1051 auto imposterObject = static_cast<ImposterObject3D*>(entity);
1052 if (decomposeAllEntities == true) {
1053 for (auto subEntity: imposterObject->getBillboardObjects()) decomposeEntityType(subEntity, decomposedEntities);
1054 } else {
1055 decomposeEntityType(imposterObject->determineBillboardObject(camera), decomposedEntities, decomposeAllEntities);
1056 }
1057 }
1058 break;
1060 {
1061 auto lodObjectImposter = static_cast<LODObject3DImposter*>(entity);
1062 if (decomposeAllEntities == true) {
1063 decomposeEntityType(lodObjectImposter->getLOD1Object(), decomposedEntities);
1064 for (auto subEntity: lodObjectImposter->getLOD2Object()->getBillboardObjects()) decomposeEntityType(subEntity, decomposedEntities);
1065 } else {
1066 auto object = lodObjectImposter->determineLODObject(camera);
1067 if (object != nullptr) decomposeEntityType(object, decomposedEntities, decomposeAllEntities);
1068 }
1069 }
1070 break;
1072 {
1073 auto opse = static_cast<ObjectParticleSystem*>(entity);
1074 if (decomposeAllEntities == true) {
1075 for (auto object: opse->getObjects()) decomposeEntityType(object, decomposedEntities, decomposeAllEntities);
1076 } else {
1077 for (auto object: opse->getEnabledObjects()) decomposeEntityType(object, decomposedEntities, decomposeAllEntities);
1078 }
1079 decomposedEntities.opses.push_back(opse);
1080 }
1081 break;
1083 {
1084 auto ppse = static_cast<PointsParticleSystem*>(entity);
1085 decomposedEntities.ppses.push_back(ppse);
1086 }
1087 break;
1089 {
1090 auto fpse = static_cast<FogParticleSystem*>(entity);
1091 decomposedEntities.ppses.push_back(fpse);
1092 }
1093 break;
1095 {
1096 auto lo = static_cast<LinesObject3D*>(entity);
1097 decomposedEntities.linesObjects.push_back(lo);
1098 }
1099 break;
1101 {
1102 auto eme = static_cast<EnvironmentMapping*>(entity);
1103 decomposedEntities.environmentMappingEntities.push_back(eme);
1104 }
1105 break;
1107 {
1108 auto org = static_cast<Object3DRenderGroup*>(entity);
1109 decomposedEntities.objectRenderGroups.push_back(org);
1110 auto subEntity = org->getEntity();
1111 if (subEntity != nullptr) decomposeEntityType(subEntity, decomposedEntities, decomposeAllEntities);
1112 }
1113 break;
1115 {
1116 auto psg = static_cast<ParticleSystemGroup*>(entity);
1117 decomposedEntities.psgs.push_back(psg); \
1118 for (auto ps: psg->getParticleSystems()) decomposeEntityType(ps, decomposedEntities, decomposeAllEntities);
1119 }
1120 break;
1122 {
1123 auto eh = static_cast<EntityHierarchy*>(entity);
1124 decomposedEntities.entityHierarchies.push_back(eh);
1125 for (auto entityEh: eh->getEntities()) {
1126 if (entityEh->isEnabled() == false && decomposeAllEntities == false) continue;
1127 decomposeEntityType(entityEh, decomposedEntities, decomposeAllEntities);
1128 }
1129 }
1130
1131 default:
1132 break;
1133 }
1134}
1135
1136inline void Engine::decomposeEntityTypes(const vector<Entity*>& entities, DecomposedEntities& decomposedEntities, bool decomposeAllEntities) {
1137 for (auto entity: entities) {
1138 decomposeEntityType(entity, decomposedEntities, decomposeAllEntities);
1139 }
1140}
1141
1143{
1144 // do particle systems auto emit
1145 if (autoEmit == true) {
1146 for (auto entity: autoEmitParticleSystemEntities) {
1147 auto pse = static_cast<ParticleSystemEntity*>(entity);
1148
1149 // skip on disabled entities
1150 if (pse->isEnabled() == false) continue;
1151
1152 // do auto emit
1153 pse->emitParticles();
1154 pse->updateParticles();
1155 }
1156 }
1157
1158 // determine entity types and store them
1161 decomposedEntities
1162 );
1163
1164 // pre render
1165 for (auto entity: needsPreRenderEntities) {
1166 // skip on disabled entities
1167 if (partition->isVisibleEntity(entity) == false) continue;
1168 //
1169 decomposedEntities.needsPreRenderEntities.push_back(static_cast<Object3D*>(entity));
1170 }
1171
1172 // compute transformations
1173 if (computeTransformations == true) {
1174 for (auto entity: needsComputeTransformationsEntities) {
1175 // skip on disabled entities
1176 if (partition->isVisibleEntity(entity) == false) continue;
1177 //
1178 decomposedEntities.needsComputeTransformationsEntities.push_back(static_cast<Object3D*>(entity));
1179 }
1180 }
1181
1182 // collect entities that do not have frustum culling enabled
1183 for (auto entity: noFrustumCullingEntities) {
1184 // skip on disabled entities
1185 if (entity->isEnabled() == false) continue;
1186
1187 //
1188 decomposedEntities.noFrustumCullingEntities.push_back(entity);
1189 }
1190
1191 // determine additional entity types for objects without frustum culling
1193 decomposedEntities.noFrustumCullingEntities,
1194 decomposedEntities
1195 );
1196
1197 //
1200 //
1201 preRenderFunction(decomposedEntities.needsPreRenderEntities, 0);
1203 } else {
1204 auto elementsIssued = 0;
1205 auto queueElement = engineThreadQueueElementPool.allocate();
1207 queueElement->engine = this;
1208 queueElement->transformations.computeTransformations = computeTransformations;
1209 for (auto i = 0; i < decomposedEntities.needsPreRenderEntities.size(); i++) {
1210 queueElement->objects.push_back(decomposedEntities.needsPreRenderEntities[i]);
1211 if (queueElement->objects.size() == Engine::ENGINETHREADSQUEUE_PRERENDER_DISPATCH_COUNT) {
1212 auto queueElementToSubmit = queueElement;
1213 queueElement = engineThreadQueueElementPool.allocate();
1215 queueElement->engine = this;
1216 queueElement->transformations.computeTransformations = computeTransformations;
1217 elementsIssued++;
1218 engineThreadsQueue->addElement(queueElementToSubmit, false);
1219 }
1220 }
1221 if (queueElement->objects.empty() == false) {
1222 elementsIssued++;
1223 engineThreadsQueue->addElement(queueElement, false);
1224 queueElement = engineThreadQueueElementPool.allocate();
1225 }
1227 queueElement->engine = this;
1228 queueElement->transformations.computeTransformations = computeTransformations;
1229 for (auto i = 0; i < decomposedEntities.needsComputeTransformationsEntities.size(); i++) {
1230 queueElement->objects.push_back(decomposedEntities.needsComputeTransformationsEntities[i]);
1231 if (queueElement->objects.size() == Engine::ENGINETHREADSQUEUE_COMPUTE_DISPATCH_COUNT) {
1232 auto queueElementToSubmit = queueElement;
1233 queueElement = engineThreadQueueElementPool.allocate();
1235 queueElement->engine = this;
1236 queueElement->transformations.computeTransformations = computeTransformations;
1237 elementsIssued++;
1238 engineThreadsQueue->addElement(queueElementToSubmit, false);
1239 }
1240 }
1241 if (queueElement->objects.empty() == false) {
1242 elementsIssued++;
1243 engineThreadsQueue->addElement(queueElement, false);
1244 queueElement = nullptr;
1245 }
1246
1247 // wait until all elements have been processed
1248 while (true == true) {
1249 auto elementsProcessed = 0;
1250 for (auto engineThread: Engine::engineThreads) elementsProcessed+= engineThread->getProcessedElements();
1251 if (elementsProcessed == elementsIssued) {
1252 for (auto engineThread: Engine::engineThreads) engineThread->resetProcessedElements();
1253 break;
1254 }
1255 }
1256 // reset pool
1258 }
1259
1260 //
1261 if (skinningShaderEnabled == true) {
1263 }
1264
1265 //
1267}
1268
1270{
1271 // set current engine
1272 currentEngine = this;
1273
1274 // execute enqueued actions
1275 for (auto action: actions) {
1276 action->performAction();
1277 delete action;
1278 }
1279 actions.clear();
1280
1281 // finish last frame
1283
1284 // init frame
1286
1287 //
1288 initRendering();
1289
1290 // default context
1291 auto _width = scaledWidth != -1?scaledWidth:width;
1292 auto _height = scaledHeight != -1?scaledHeight:height;
1293
1294 // camera
1295 camera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
1296 // frustum
1297 camera->getFrustum()->update();
1298
1299 // clear pre render states
1301
1302 // do pre rendering steps
1304
1305 // render environment maps
1306 for (auto environmentMappingEntity: visibleDecomposedEntities.environmentMappingEntities) environmentMappingEntity->render();
1307
1308 // camera
1309 camera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
1310
1311 // create shadow maps
1312 if (shadowMapping != nullptr) shadowMapping->createShadowMaps();
1313
1314 // do post processing programs effect passes
1315 array<bool, EFFECTPASS_COUNT - 1> effectPassFrameBuffersInUse;
1316 effectPassFrameBuffersInUse.fill(false);
1317 effectPassSkip.fill(false);
1318 for (auto programId: postProcessingPrograms) {
1319 auto program = postProcessing->getPostProcessingProgram(programId);
1320 if (program == nullptr) continue;
1321 for (auto& effectPass: program->getEffectPasses()) {
1322 auto effectPassIdx = effectPass.effectPassIdx;
1323 auto frameBufferIdx = effectPass.effectPassIdx - 1;
1324 auto frameBufferWidth = _width / effectPass.frameBufferWidthDivideFactor;
1325 auto frameBufferHeight = _height / effectPass.frameBufferHeightDivideFactor;
1326 if (effectPassFrameBuffers[frameBufferIdx] == nullptr) {
1327 effectPassFrameBuffers[frameBufferIdx] = new FrameBuffer(frameBufferWidth, frameBufferHeight, FrameBuffer::FRAMEBUFFER_COLORBUFFER); // TODO: types of buffers
1328 effectPassFrameBuffers[frameBufferIdx]->initialize();
1329 } else
1330 if (effectPassFrameBuffers[frameBufferIdx]->getWidth() != frameBufferWidth ||
1331 effectPassFrameBuffers[frameBufferIdx]->getHeight() != frameBufferHeight) {
1332 effectPassFrameBuffers[frameBufferIdx]->reshape(frameBufferWidth, frameBufferHeight);
1333 }
1334 effectPassFrameBuffersInUse[frameBufferIdx] = true;
1335 // enable
1336 effectPassFrameBuffers[frameBufferIdx]->enableFrameBuffer();
1337 // clear
1339 effectPass.clearColor.getRed(),
1340 effectPass.clearColor.getGreen(),
1341 effectPass.clearColor.getBlue(),
1342 effectPass.clearColor.getAlpha()
1343 );
1345 // camera
1346 camera->update(renderer->CONTEXTINDEX_DEFAULT, frameBufferWidth, frameBufferHeight);
1347 //
1348 auto lightSourceVisible = false;
1349 if (effectPass.renderLightSources == true) {
1350 lightSourceVisible = renderLightSources(frameBufferWidth, frameBufferHeight);
1351 }
1352 if (effectPass.skipOnLightSourceNotVisible == true && lightSourceVisible == false) {
1353 effectPassSkip[frameBufferIdx] = true;
1354 } else {
1355 // Do the effect render pass
1356 render(
1357 effectPassFrameBuffers[frameBufferIdx],
1358 nullptr, // TODO: we might want to use a deferred shading here for further effects
1360 effectPassIdx,
1362 effectPass.shaderPrefix,
1363 false,
1364 false,
1365 false,
1366 false,
1367 false,
1368 EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY |
1369 EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY |
1370 EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY
1371 );
1372 }
1373 }
1374 }
1375
1376 // dispose effect pass frame buffers that we do not use anymore
1377 for (auto i = 0; i < effectPassFrameBuffersInUse.size(); i++) {
1378 if (effectPassFrameBuffersInUse[i] == false && effectPassFrameBuffers[i] != nullptr) {
1379 effectPassFrameBuffers[i]->dispose();
1380 delete effectPassFrameBuffers[i];
1381 effectPassFrameBuffers[i] = nullptr;
1382 }
1383 }
1384
1385 // create post processing frame buffers if having post processing
1386 FrameBuffer* renderFrameBuffer = nullptr;
1387 if (postProcessingPrograms.size() > 0) {
1388 if (postProcessingFrameBuffer1 == nullptr) {
1391 }
1392 if (postProcessingFrameBuffer2 == nullptr) {
1395 }
1397 renderFrameBuffer = postProcessingFrameBuffer1;
1398 } else {
1399 if (postProcessingFrameBuffer1 != nullptr) {
1403 }
1404 if (postProcessingFrameBuffer2 != nullptr) {
1408 }
1409 // render objects to target frame buffer or screen
1410 if (frameBuffer != nullptr) {
1412 renderFrameBuffer = frameBuffer;
1413 } else {
1415 }
1416 }
1417
1418 // camera
1419 camera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
1420
1421 // clear previous frame values
1424
1425 // do rendering
1426 render(
1427 renderFrameBuffer,
1432 string(),
1433 true,
1434 true,
1435 true,
1436 true,
1437 true,
1438 EntityRenderer::RENDERTYPE_NORMALS |
1439 EntityRenderer::RENDERTYPE_TEXTUREARRAYS |
1440 EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY |
1441 EntityRenderer::RENDERTYPE_EFFECTCOLORS |
1442 EntityRenderer::RENDERTYPE_MATERIALS |
1443 EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY |
1444 EntityRenderer::RENDERTYPE_TEXTURES |
1445 EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY |
1446 EntityRenderer::RENDERTYPE_LIGHTS
1447 );
1448
1449 // delete post processing termporary buffer if not required anymore
1454 }
1455
1456 // clear pre render states
1457 renderingInitiated = false;
1459
1460 //
1461 if (frameBuffer != nullptr) {
1463 }
1464
1465 // camera
1466 camera->update(renderer->CONTEXTINDEX_DEFAULT, _width, _height);
1467}
1468
1469Vector3 Engine::computeWorldCoordinateByMousePosition(int32_t mouseX, int32_t mouseY, float z)
1470{
1471 auto scaleFactorWidth = static_cast<float>(scaledWidth != -1?scaledWidth:width) / static_cast<float>(width);
1472 auto scaleFactorHeight = static_cast<float>(scaledHeight != -1?scaledHeight:height) / static_cast<float>(height);
1473 auto _width = scaledWidth != -1?scaledWidth:width;
1474 auto _height = scaledHeight != -1?scaledHeight:height;
1475 // see: http://stackoverflow.com/questions/7692988/opengl-math-projecting-screen-space-to-world-space-coords-solved
1476 auto worldCoordinate4 = camera->getModelViewProjectionInvertedMatrix().multiply(
1477 Vector4(
1478 (2.0f * (mouseX * scaleFactorWidth) / _width) - 1.0f,
1479 1.0f - (2.0f * (mouseY * scaleFactorHeight) / _height),
1480 2.0f * z - 1.0f,
1481 1.0f
1482 )
1483 );
1484 worldCoordinate4.scale(1.0f / worldCoordinate4.getW());
1485 return Vector3(
1486 worldCoordinate4.getX(),
1487 worldCoordinate4.getY(),
1488 worldCoordinate4.getZ()
1489 );
1490}
1491
1493{
1494 // use framebuffer if we have one
1495 if (frameBuffer != nullptr)
1497
1498 //
1499 auto scaleFactorWidth = static_cast<float>(scaledWidth != -1?scaledWidth:width) / static_cast<float>(width);
1500 auto scaleFactorHeight = static_cast<float>(scaledHeight != -1?scaledHeight:height) / static_cast<float>(height);
1501
1502 // see: http://stackoverflow.com/questions/7692988/opengl-math-projecting-screen-space-to-world-space-coords-solved
1503 auto z = renderer->readPixelDepth(mouseX * scaleFactorWidth, (height - mouseY) * scaleFactorHeight);
1504
1505 // unuse framebuffer if we have one
1506 if (frameBuffer != nullptr)
1508
1509 //
1510 return computeWorldCoordinateByMousePosition(mouseX, mouseY, z);
1511}
1512
1514 DecomposedEntities& decomposedEntities,
1515 bool forcePicking,
1516 int32_t mouseX,
1517 int32_t mouseY,
1518 EntityPickingFilter* filter,
1519 Node** object3DNode,
1520 ParticleSystemEntity** particleSystemEntity
1521) {
1522 // get world position of mouse position at near and far plane
1523 auto nearPlaneWorldCoordinate = computeWorldCoordinateByMousePosition(mouseX, mouseY, 0.0f);
1524 auto farPlaneWorldCoordinate = computeWorldCoordinateByMousePosition(mouseX, mouseY, 1.0f);
1525 Vector3 boundingBoxLineContactMin;
1526 Vector3 boundingBoxLineContactMax;
1527 Vector3 lineTriangleContact;
1528
1529 // selected entity
1530 auto selectedEntityDistance = Float::MAX_VALUE;
1531 Entity* selectedEntity = nullptr;
1532 Node* selectedObject3DNode = nullptr;
1533 ParticleSystemEntity* selectedParticleSystem = nullptr;
1534
1535 // 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
1536 for (auto entity: decomposedEntities.objectsNoDepthTest) {
1537 // skip if not pickable or ignored by filter
1538 if (forcePicking == false && entity->isPickable() == false) continue;
1539 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1540 // do the collision test
1541 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1542 for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1543 auto& vertices = it->next();
1544 if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], nearPlaneWorldCoordinate, farPlaneWorldCoordinate, lineTriangleContact) == true) {
1545 auto entityDistance = lineTriangleContact.sub(nearPlaneWorldCoordinate).computeLengthSquared();
1546 // check if match or better match
1547 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1548 selectedEntity = entity;
1549 selectedEntityDistance = entityDistance;
1550 selectedObject3DNode = it->getNode();
1551 selectedParticleSystem = nullptr;
1552 }
1553 }
1554 }
1555 }
1556 }
1557 // they have first priority right now
1558 if (selectedEntity != nullptr) {
1559 if (object3DNode != nullptr) *object3DNode = selectedObject3DNode;
1560 for (auto _entity = selectedEntity; _entity != nullptr; _entity = _entity->getParentEntity()) {
1561 if (_entity->getParentEntity() == nullptr) return _entity;
1562 }
1563 return nullptr;
1564 }
1565
1566 // iterate visible object partition systems, check if ray with given mouse position from near plane to far plane collides with bounding volume
1567 for (auto entity: decomposedEntities.opses) {
1568 // skip if not pickable or ignored by filter
1569 if (forcePicking == false && entity->isPickable() == false) continue;
1570 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1571 // do the collision test
1572 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1573 auto entityDistance = lineTriangleContact.set(entity->getBoundingBoxTransformed()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1574 // check if match or better match
1575 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1576 selectedEntity = entity;
1577 selectedEntityDistance = entityDistance;
1578 selectedObject3DNode = nullptr;
1579 selectedParticleSystem = nullptr;
1580 }
1581 }
1582 }
1583
1584 // iterate visible point partition systems, check if ray with given mouse position from near plane to far plane collides with bounding volume
1585 for (auto entity: decomposedEntities.ppses) {
1586 // skip if not pickable or ignored by filter
1587 if (forcePicking == false && entity->isPickable() == false) continue;
1588 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1589 // do the collision test
1590 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1591 auto entityDistance = lineTriangleContact.set(entity->getBoundingBoxTransformed()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1592 // check if match or better match
1593 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1594 selectedEntity = entity;
1595 selectedEntityDistance = entityDistance;
1596 selectedObject3DNode = nullptr;
1597 selectedParticleSystem = nullptr;
1598 }
1599 }
1600 }
1601
1602 // iterate visible particle system nodes, check if ray with given mouse position from near plane to far plane collides with bounding volume
1603 for (auto entity: decomposedEntities.psgs) {
1604 // skip if not pickable or ignored by filter
1605 if (forcePicking == false && entity->isPickable() == false) continue;
1606 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1607 // do the collision test
1608 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1609 auto entityDistance = lineTriangleContact.set(entity->getBoundingBoxTransformed()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1610 // check if match or better match
1611 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1612 selectedEntity = entity;
1613 selectedEntityDistance = entityDistance;
1614 selectedObject3DNode = nullptr;
1615 selectedParticleSystem = nullptr;
1616 auto selectedSubEntityDistance = Float::MAX_VALUE;
1617 // iterate sub partition systems, check if ray with given mouse position from near plane to far plane collides with bounding volume
1618 for (auto subEntity: entity->getParticleSystems()) {
1619 if (LineSegment::doesBoundingBoxCollideWithLineSegment(subEntity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1620 auto subEntityDistance = lineTriangleContact.set(subEntity->getBoundingBoxTransformed()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1621 // check if match or better match
1622 if (selectedParticleSystem == nullptr || subEntityDistance < selectedSubEntityDistance) {
1623 selectedSubEntityDistance = subEntityDistance;
1624 selectedParticleSystem = subEntity;
1625 }
1626 }
1627 }
1628 }
1629 }
1630 }
1631
1632 // iterate visible line objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1633 for (auto entity: decomposedEntities.linesObjects) {
1634 // skip if not pickable or ignored by filter
1635 if (forcePicking == false && entity->isPickable() == false) continue;
1636 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1637 // do the collision test
1638 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1639 auto entityDistance = lineTriangleContact.set(entity->getBoundingBoxTransformed()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1640 // check if match or better match
1641 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1642 selectedEntity = entity;
1643 selectedEntityDistance = entityDistance;
1644 selectedObject3DNode = nullptr;
1645 selectedParticleSystem = nullptr;
1646 }
1647 }
1648 }
1649
1650 // iterate visible objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1651 array<vector<Object3D*>, 3> objectsArray {decomposedEntities.objects, decomposedEntities.objectsForwardShading, decomposedEntities.objectsPostPostProcessing, };
1652 for (auto& objects: objectsArray) {
1653 for (auto entity: objects) {
1654 // skip if not pickable or ignored by filter
1655 if (forcePicking == false && entity->isPickable() == false) continue;
1656 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1657 // do the collision test
1658 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1659 for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1660 auto& vertices = it->next();
1661 if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], nearPlaneWorldCoordinate, farPlaneWorldCoordinate, lineTriangleContact) == true) {
1662 auto entityDistance = lineTriangleContact.sub(nearPlaneWorldCoordinate).computeLengthSquared();
1663 // check if match or better match
1664 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1665 selectedEntity = entity;
1666 selectedEntityDistance = entityDistance;
1667 selectedObject3DNode = it->getNode();
1668 selectedParticleSystem = nullptr;
1669 }
1670 }
1671 }
1672 }
1673 }
1674 }
1675
1676 // iterate visible LOD objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1677 for (auto entity: decomposedEntities.lodObjects) {
1678 // skip if not pickable or ignored by filter
1679 if (forcePicking == false && entity->isPickable() == false) continue;
1680 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1681 // do the collision test
1682 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1683 auto object = entity->getLODObject();
1684 if (object != nullptr) {
1685 for (auto it = object->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1686 auto& vertices = it->next();
1687 if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], nearPlaneWorldCoordinate, farPlaneWorldCoordinate, lineTriangleContact) == true) {
1688 auto entityDistance = lineTriangleContact.sub(nearPlaneWorldCoordinate).computeLengthSquared();
1689 // check if match or better match
1690 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1691 selectedEntity = entity;
1692 selectedEntityDistance = entityDistance;
1693 }
1694 }
1695 selectedObject3DNode = it->getNode();
1696 selectedParticleSystem = nullptr;
1697 }
1698 }
1699 }
1700 }
1701
1702 // iterate visible entity hierarchies, check if ray with given mouse position from near plane to far plane collides with bounding volume
1703 for (auto entity: decomposedEntities.entityHierarchies) {
1704 // skip if not pickable or ignored by filter
1705 if (forcePicking == false && entity->isPickable() == false) continue;
1706 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1707 // do the collision test
1708 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), nearPlaneWorldCoordinate, farPlaneWorldCoordinate, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1709 DecomposedEntities decomposedEntitiesEH;
1710 Node* object3DNodeEH = nullptr;
1711 ParticleSystemEntity* particleSystemEntityEH = nullptr;
1713 entity->getEntities(),
1714 decomposedEntitiesEH
1715 );
1716 auto subEntity = getEntityByMousePosition(
1717 decomposedEntitiesEH,
1718 true,
1719 mouseX,
1720 mouseY,
1721 filter,
1722 &object3DNodeEH,
1723 &particleSystemEntityEH
1724 );
1725 if (subEntity != nullptr) {
1726 auto entityDistance = lineTriangleContact.set(subEntity->getBoundingBoxTransformed()->getCenter()).sub(nearPlaneWorldCoordinate).computeLengthSquared();
1727 // check if match or better match
1728 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1729 selectedEntity = entity;
1730 selectedEntityDistance = entityDistance;
1731 selectedObject3DNode = object3DNodeEH;
1732 selectedParticleSystem = particleSystemEntityEH;
1733 }
1734 }
1735 }
1736 }
1737
1738 // store node
1739 if (object3DNode != nullptr) *object3DNode = selectedObject3DNode;
1740
1741 // store particle system entity
1742 if (particleSystemEntity != nullptr) {
1743 *particleSystemEntity = selectedParticleSystem;
1744 }
1745
1746 // return parent entity if entity is part of a hierarchy
1747 if (selectedEntity != nullptr) {
1748 for (auto _entity = selectedEntity; _entity != nullptr; _entity = _entity->getParentEntity()) {
1749 if (_entity->getParentEntity() == nullptr) return _entity;
1750 }
1751 return nullptr;
1752 } else {
1753 return nullptr;
1754 }
1755}
1756
1757Entity* Engine::getEntityByMousePosition(int32_t mouseX, int32_t mouseY, Vector3& contactPoint, EntityPickingFilter* filter, Node** object3DNode, ParticleSystemEntity** particleSystemEntity) {
1758 // get world position of mouse position at near and far plane
1759 auto startPoint = computeWorldCoordinateByMousePosition(mouseX, mouseY, 0.0f);
1760 auto endPoint = computeWorldCoordinateByMousePosition(mouseX, mouseY, 1.0f);
1761
1762 //
1763 return doRayCasting(startPoint, endPoint, contactPoint, filter);// TODO: object 3d node, particle system entity
1764}
1765
1767 DecomposedEntities& decomposedEntities,
1768 bool forcePicking,
1769 const Vector3& startPoint,
1770 const Vector3& endPoint,
1771 Vector3& contactPoint,
1772 EntityPickingFilter* filter) {
1773 Vector3 boundingBoxLineContactMin;
1774 Vector3 boundingBoxLineContactMax;
1775 Vector3 lineTriangleContact;
1776
1777 // selected entity
1778 auto selectedEntityDistance = Float::MAX_VALUE;
1779 Entity* selectedEntity = nullptr;
1780
1781 // 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
1782 for (auto entity: decomposedEntities.objectsNoDepthTest) {
1783 // skip if not pickable or ignored by filter
1784 if (forcePicking == false && entity->isPickable() == false) continue;
1785 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1786 // do the collision test
1787 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), startPoint, endPoint, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1788 for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1789 auto& vertices = it->next();
1790 if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], startPoint, endPoint, lineTriangleContact) == true) {
1791 auto entityDistance = lineTriangleContact.clone().sub(startPoint).computeLengthSquared();
1792 // check if match or better match
1793 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1794 selectedEntity = entity;
1795 selectedEntityDistance = entityDistance;
1796 contactPoint = lineTriangleContact;
1797 }
1798 }
1799 }
1800 }
1801 }
1802 // they have first priority right now
1803 if (selectedEntity != nullptr) {
1804 return selectedEntity;
1805 }
1806
1807 // iterate visible objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1808 array<vector<Object3D*>, 3> objectsArray {decomposedEntities.objects, decomposedEntities.objectsForwardShading, decomposedEntities.objectsPostPostProcessing, };
1809 for (auto& objects: objectsArray) {
1810 for (auto entity: objects) {
1811 // skip if not pickable or ignored by filter
1812 if (forcePicking == false && entity->isPickable() == false) continue;
1813 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1814 // do the collision test
1815 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), startPoint, endPoint, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1816 for (auto it = entity->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1817 auto& vertices = it->next();
1818 if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], startPoint, endPoint, lineTriangleContact) == true) {
1819 auto entityDistance = lineTriangleContact.clone().sub(startPoint).computeLengthSquared();
1820 // check if match or better match
1821 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1822 selectedEntity = entity;
1823 selectedEntityDistance = entityDistance;
1824 contactPoint = lineTriangleContact;
1825 }
1826 }
1827 }
1828 }
1829 }
1830 }
1831
1832 // iterate visible LOD objects, check if ray with given mouse position from near plane to far plane collides with each object's triangles
1833 for (auto entity: decomposedEntities.lodObjects) {
1834 // skip if not pickable or ignored by filter
1835 if (forcePicking == false && entity->isPickable() == false) continue;
1836 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1837 // do the collision test
1838 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), startPoint, endPoint, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1839 auto object = entity->getLODObject();
1840 if (object != nullptr) {
1841 for (auto it = object->getTransformedFacesIterator()->iterator(); it->hasNext();) {
1842 auto& vertices = it->next();
1843 if (LineSegment::doesLineSegmentCollideWithTriangle(vertices[0], vertices[1], vertices[2], startPoint, endPoint, lineTriangleContact) == true) {
1844 auto entityDistance = lineTriangleContact.sub(startPoint).computeLengthSquared();
1845 // check if match or better match
1846 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1847 selectedEntity = entity;
1848 selectedEntityDistance = entityDistance;
1849 contactPoint = lineTriangleContact;
1850 }
1851 }
1852 }
1853 }
1854 }
1855 }
1856
1857 // iterate visible entity hierarchies, check if ray with given mouse position from near plane to far plane collides with bounding volume
1858 for (auto entity: decomposedEntities.entityHierarchies) {
1859 // skip if not pickable or ignored by filter
1860 if (forcePicking == false && entity->isPickable() == false) continue;
1861 if (filter != nullptr && filter->filterEntity(entity) == false) continue;
1862 // do the collision test
1863 if (LineSegment::doesBoundingBoxCollideWithLineSegment(entity->getBoundingBoxTransformed(), startPoint, endPoint, boundingBoxLineContactMin, boundingBoxLineContactMax) == true) {
1864 DecomposedEntities decomposedEntitiesEH;
1866 entity->getEntities(),
1867 decomposedEntitiesEH
1868 );
1869 Vector3 contactPointEH;
1870 auto entity = doRayCasting(
1871 decomposedEntitiesEH,
1872 true,
1873 startPoint,
1874 endPoint,
1875 contactPointEH,
1876 filter
1877 );
1878 if (entity != nullptr) {
1879 auto entityDistance = lineTriangleContact.sub(startPoint).computeLengthSquared();
1880 // check if match or better match
1881 if (selectedEntity == nullptr || entityDistance < selectedEntityDistance) {
1882 selectedEntity = entity;
1883 selectedEntityDistance = entityDistance;
1884 contactPoint = contactPointEH;
1885 }
1886 }
1887 }
1888 }
1889
1890 //
1891 return selectedEntity;
1892}
1893
1894bool Engine::computeScreenCoordinateByWorldCoordinate(const Vector3& worldCoordinate, Vector2& screenCoordinate, int width, int height)
1895{
1896 auto _width = width != -1?width:(scaledWidth != -1?scaledWidth:this->width);
1897 auto _height = height != -1?height:(scaledHeight != -1?scaledHeight:this->height);
1898 // convert to normalized device coordinates
1899 auto screenCoordinate4 = camera->getModelViewProjectionMatrix().multiply(Vector4(worldCoordinate, 1.0f));
1900 screenCoordinate4.scale(1.0f / screenCoordinate4.getW());
1901 // convert to screen coordinate
1902 screenCoordinate.setX((screenCoordinate4[0] + 1.0f) * _width / 2.0f);
1903 screenCoordinate.setY(_height - ((screenCoordinate4[1] + 1.0f) * _height / 2.0f));
1904 return camera->getModelViewMatrix().multiply(worldCoordinate).getZ() <= 0.0f;
1905}
1906
1908{
1909 // finish last frame
1911
1912 // remove entities
1913 vector<string> entitiesToRemove;
1914 for (auto it: entitiesById) {
1915 auto entityKey = it.first;
1916 entitiesToRemove.push_back(entityKey);
1917 }
1918 for (auto entityKey: entitiesToRemove) {
1919 removeEntity(entityKey);
1920 }
1921
1922 // dispose shadow mapping
1923 if (shadowMapping != nullptr) shadowMapping->dispose();
1924
1925 // dispose frame buffers
1926 if (frameBuffer != nullptr) frameBuffer->dispose();
1930
1931 // dispose GUI
1932 gui->dispose();
1933 if (this == Engine::instance) {
1935 GUIParser::dispose();
1936 }
1937
1938 // dispose object 3d VBO renderer
1940
1941 // dispose object buffer if main engine
1942 if (this == Engine::instance) {
1943 ObjectBuffer::dispose();
1944 }
1945
1946 // set current engine
1947 if (currentEngine == this) currentEngine = nullptr;
1948}
1949
1951{
1952 // use framebuffer if we have one
1953 if (frameBuffer != nullptr) {
1955 } else {
1957 }
1958
1960}
1961
1963{
1965
1966 // unuse framebuffer if we have one
1967 if (frameBuffer != nullptr)
1969}
1970
1971bool Engine::makeScreenshot(const string& pathName, const string& fileName, bool removeAlphaChannel)
1972{
1973 // use framebuffer if we have one
1974 if (frameBuffer != nullptr) frameBuffer->enableFrameBuffer();
1975
1976 // fetch pixel
1977 auto pixels = renderer->readPixels(0, 0, width, height);
1978 if (pixels == nullptr) {
1979 Console::println("Engine::makeScreenshot(): Failed to read pixels");
1980 return false;
1981 }
1982
1983 // create texture, write and delete
1984 auto texture = new Texture(
1985 "tdme.engine.makescreenshot",
1986 32,
1987 width,
1988 height,
1989 width,
1990 height,
1991 pixels
1992 );
1993 texture->acquireReference();
1994 PNGTextureWriter::write(texture, pathName, fileName, removeAlphaChannel);
1995 texture->releaseReference();
1996
1997 // unuse framebuffer if we have one
1999
2000 //
2001 return true;
2002}
2003
2004bool Engine::makeScreenshot(vector<uint8_t>& pngData)
2005{
2006 // use framebuffer if we have one
2007 if (frameBuffer != nullptr) frameBuffer->enableFrameBuffer();
2008
2009 // fetch pixel
2010 auto pixels = renderer->readPixels(0, 0, width, height);
2011 if (pixels == nullptr) {
2012 Console::println("Engine::makeScreenshot(): Failed to read pixels");
2013 return false;
2014 }
2015
2016 // create texture, write and delete
2017 auto texture = new Texture(
2018 "tdme.engine.makescreenshot",
2019 32,
2020 width,
2021 height,
2022 width,
2023 height,
2024 pixels
2025 );
2026
2027 texture->acquireReference();
2028 PNGTextureWriter::write(texture, pngData);
2029 texture->releaseReference();
2030
2031 // unuse framebuffer if we have one
2033
2034 //
2035 return true;
2036}
2037
2039 postProcessingPrograms.clear();
2040}
2041
2042void Engine::addPostProcessingProgram(const string& programId) {
2044 if (postProcessing->getPostProcessingProgram(programId) != nullptr) postProcessingPrograms.push_back(programId);
2045}
2046
2047void Engine::doPostProcessing(PostProcessingProgram::RenderPass renderPass, array<FrameBuffer*, 2> postProcessingFrameBuffers, FrameBuffer* targetFrameBuffer) {
2048 auto postProcessingFrameBufferIdx = 0;
2049 for (auto programId: postProcessingPrograms) {
2050 auto program = postProcessing->getPostProcessingProgram(programId);
2051 if (program == nullptr) continue;
2052 if (program->getRenderPass() != renderPass) continue;
2053 auto effectPassSkipDetected = false;
2054 for (auto& effectPass: program->getEffectPasses()) {
2055 if (effectPassSkip[effectPass.effectPassIdx - 1] == true) effectPassSkipDetected = true;
2056 }
2057 if (effectPassSkipDetected == true) continue;
2058 for (auto& step: program->getPostProcessingSteps()) {
2059 auto shaderId = step.shaderId;
2060 FrameBuffer* blendToSource = nullptr;
2061 FrameBuffer* source = nullptr;
2062 FrameBuffer* target = nullptr;
2063 if (step.blendToSource == PostProcessingProgram::FRAMEBUFFERSOURCE_SCREEN) {
2064 blendToSource = postProcessingFrameBuffers[postProcessingFrameBufferIdx];
2065 }
2066 switch(step.source) {
2067 case PostProcessingProgram::FRAMEBUFFERSOURCE_NONE:
2068 break;
2069 case PostProcessingProgram::FRAMEBUFFERSOURCE_SCREEN:
2070 source = postProcessingFrameBuffers[postProcessingFrameBufferIdx];
2071 break;
2072 default:
2073 source = effectPassFrameBuffers[step.source - PostProcessingProgram::FRAMEBUFFERSOURCE_EFFECTPASS0];
2074 break;
2075 }
2076 switch(step.target) {
2077 case PostProcessingProgram::FRAMEBUFFERTARGET_SCREEN:
2078 target = postProcessingFrameBuffers[(postProcessingFrameBufferIdx + 1) % 2];
2079 break;
2080 case PostProcessingProgram::FRAMEBUFFERTARGET_TEMPORARY:
2082 if (postProcessingTemporaryFrameBuffer == nullptr) {
2085 }
2087 break;
2088 }
2089 FrameBuffer::doPostProcessing(this, target, source, programId, shaderId, step.bindTemporary == true?postProcessingTemporaryFrameBuffer:nullptr, blendToSource);
2090 switch(step.target) {
2091 case PostProcessingProgram::FRAMEBUFFERTARGET_SCREEN:
2092 postProcessingFrameBufferIdx = (postProcessingFrameBufferIdx + 1) % 2;
2093 break;
2094 case PostProcessingProgram::FRAMEBUFFERTARGET_TEMPORARY:
2095 break;
2096 }
2097 }
2098 }
2099
2100 // render back to objects frame buffer
2101 if (postProcessingFrameBuffers[postProcessingFrameBufferIdx] != targetFrameBuffer) {
2102 if (targetFrameBuffer != nullptr) {
2103 targetFrameBuffer->enableFrameBuffer();
2104 } else {
2106 }
2107 postProcessingFrameBuffers[postProcessingFrameBufferIdx]->renderToScreen(this);
2108 }
2109}
2110
2111const vector<string> Engine::getRegisteredShader(ShaderType type) {
2112 vector<string> result;
2113 for (auto shadersIt: shaders) {
2114 auto& shader = shadersIt.second;
2115 if (shader.type == type) {
2116 result.push_back(shader.id);
2117 }
2118 }
2119 return result;
2120}
2121
2122void Engine::registerShader(ShaderType type, const string& shaderId, const map<string, ShaderParameter>& parameterDefaults) {
2123 if (shaders.find(shaderId) != shaders.end()) {
2124 Console::println("Engine::registerShader(): Shader already registered: " + shaderId);
2125 return;
2126 }
2127 shaders[shaderId] = {
2128 .type = type,
2129 .id = shaderId,
2130 .parameterDefaults = parameterDefaults
2131 };
2132}
2133
2134const map<string, ShaderParameter> Engine::getShaderParameterDefaults(const string& shaderId) {
2135 auto shaderIt = shaders.find(shaderId);
2136 if (shaderIt == shaders.end()) {
2137 Console::println("Engine::getShaderParameterDefaults(): No registered shader: " + shaderId);
2138 return map<string, ShaderParameter>();
2139 }
2140 return shaderIt->second.parameterDefaults;
2141}
2142
2143void Engine::render(FrameBuffer* renderFrameBuffer, GeometryBuffer* renderGeometryBuffer, DecomposedEntities& visibleDecomposedEntities, int32_t effectPass, int32_t renderPassMask, const string& shaderPrefix, bool useEZR, bool applyShadowMapping, bool applyPostProcessing, bool doRenderLightSource, bool doRenderParticleSystems, int32_t renderTypes) {
2144 //
2145 Engine::renderer->setEffectPass(effectPass);
2146 Engine::renderer->setShaderPrefix(shaderPrefix);
2147
2148 // do depth buffer writing aka early z rejection
2149 if (renderGeometryBuffer == nullptr && useEZR == true && ezrShader != nullptr && visibleDecomposedEntities.ezrObjects.size() > 0) {
2150 // disable color rendering, we only want to write to the Z-Buffer
2151 renderer->setColorMask(false, false, false, false);
2152 // render
2153 ezrShader->useProgram(this);
2154 // only draw opaque face entities of objects marked as EZR objects
2155 for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2156 auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2157 if ((renderPassMask & renderPass) == renderPass) {
2159 renderPass,
2161 false,
2162 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2163 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)
2164 );
2165 }
2166 }
2167 // done
2169 // restore disable color rendering
2170 renderer->setColorMask(true, true, true, true);
2171 }
2172
2173 // use lighting shader
2174 if (visibleDecomposedEntities.objects.empty() == false || visibleDecomposedEntities.objectsForwardShading.empty() == false) {
2175 //
2176 if (lightingShader != nullptr) lightingShader->useProgram(this);
2177
2178 // render objects
2179 for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2180 auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2181 if ((renderPassMask & renderPass) == renderPass) {
2182 if (renderPass == Entity::RENDERPASS_TERRAIN) {
2183 if (renderGeometryBuffer != nullptr) {
2184 if (lightingShader != nullptr) lightingShader->unUseProgram();
2185 renderGeometryBuffer->enableGeometryBuffer();
2186 renderer->setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
2189 if (lightingShader != nullptr) lightingShader->useProgram(this);
2190 }
2191 } else
2192 if (renderPass == Entity::RENDERPASS_WATER) renderer->enableBlending();
2194 renderPass,
2196 true,
2197 ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2198 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2199 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2200 ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2201 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2202 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2203 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2204 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2205 ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2206 );
2207 if (renderPass == Entity::RENDERPASS_STANDARD) {
2208 if (renderGeometryBuffer != nullptr) {
2209 if (lightingShader != nullptr) lightingShader->unUseProgram();
2210 renderGeometryBuffer->disableGeometryBuffer();
2211 Engine::renderer->setShaderPrefix(shaderPrefix);
2212 if (renderFrameBuffer != nullptr) renderFrameBuffer->enableFrameBuffer();
2213 renderGeometryBuffer->renderToScreen(this);
2214 if (lightingShader != nullptr) lightingShader->useProgram(this);
2215 if (visibleDecomposedEntities.objectsForwardShading.empty() == false) {
2216 // TODO: use a loop maybe from TERRAIN to STANDARD, but for now it works this way too :)
2217 // terrain
2221 true,
2222 ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2223 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2224 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2225 ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2226 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2227 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2228 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2229 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2230 ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2231 );
2232 // standard
2236 true,
2237 ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2238 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2239 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2240 ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2241 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2242 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2243 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2244 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2245 ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2246 );
2247 }
2248 }
2249 } else
2251 }
2252 }
2253
2254 // render transparent faces
2256
2257 // unuse lighting shader
2258 if (lightingShader != nullptr) lightingShader->unUseProgram();
2259
2260 // render shadows if required
2261 if (applyShadowMapping == true && shadowMapping != nullptr) {
2264 }
2265 }
2266
2267 // do post processing
2268 if (applyPostProcessing == true) {
2270 if (postProcessingPrograms.size() > 0) {
2273 }
2274 }
2275
2276 // render lines objects
2277 if (visibleDecomposedEntities.linesObjects.size() > 0) {
2278 // use particle shader
2280
2281 // render points based particle systems
2282 for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2283 auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2284 if ((renderPassMask & renderPass) == renderPass) entityRenderer->render(renderPass, visibleDecomposedEntities.linesObjects);
2285 }
2286
2287 // unuse particle shader
2289 }
2290
2291 // render point particle systems
2292 if (doRenderParticleSystems == true && visibleDecomposedEntities.ppses.size() > 0) {
2293 // use particle shader
2295
2296 // render points based particle systems
2297 if (visibleDecomposedEntities.ppses.size() > 0) {
2298 for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2299 auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2300 if ((renderPassMask & renderPass) == renderPass) entityRenderer->render(renderPass, visibleDecomposedEntities.ppses);
2301 }
2302 }
2303
2304 // unuse particle shader
2306 }
2307
2308 // render objects and particles together
2309 if (applyPostProcessing == true) {
2310 if (postProcessingPrograms.size() > 0) {
2311 doPostProcessing(PostProcessingProgram::RENDERPASS_FINAL, {{postProcessingFrameBuffer1, postProcessingFrameBuffer2 }}, frameBuffer);
2312 }
2313 }
2314
2315 // render objects that are have post post processing render pass
2317 // use lighting shader
2318 if (lightingShader != nullptr) {
2320 }
2321
2322 // render post processing objects
2323 for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2324 auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2325 if ((renderPassMask & renderPass) == renderPass) {
2326 if (renderPass == Entity::RENDERPASS_WATER) renderer->enableBlending();
2328 renderPass,
2330 true,
2331 ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2332 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2333 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2334 ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2335 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2336 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2337 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2338 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2339 ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2340 );
2342 }
2343 }
2344
2345 // render transparent faces
2347
2348 // unuse lighting shader
2349 if (lightingShader != nullptr) lightingShader->unUseProgram();
2350
2351 // render shadows if required
2352 if (applyShadowMapping == true && shadowMapping != nullptr) {
2354 }
2355 }
2356
2357 // render objects that are have post post processing render pass
2359 // use lighting shader
2360 if (lightingShader != nullptr) {
2362 }
2363
2364 //
2366
2367 // render post processing objects
2368 for (auto i = 0; i < Entity::RENDERPASS_MAX; i++) {
2369 auto renderPass = static_cast<Entity::RenderPass>(Math::pow(2, i));
2370 if ((renderPassMask & renderPass) == renderPass) {
2371 if (renderPass == Entity::RENDERPASS_WATER) renderer->enableBlending();
2373 renderPass,
2375 true,
2376 ((renderTypes & EntityRenderer::RENDERTYPE_NORMALS) == EntityRenderer::RENDERTYPE_NORMALS?EntityRenderer::RENDERTYPE_NORMALS:0) |
2377 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS?EntityRenderer::RENDERTYPE_TEXTUREARRAYS:0) |
2378 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTUREARRAYS_DIFFUSEMASKEDTRANSPARENCY:0) |
2379 ((renderTypes & EntityRenderer::RENDERTYPE_EFFECTCOLORS) == EntityRenderer::RENDERTYPE_EFFECTCOLORS?EntityRenderer::RENDERTYPE_EFFECTCOLORS:0) |
2380 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS) == EntityRenderer::RENDERTYPE_MATERIALS?EntityRenderer::RENDERTYPE_MATERIALS:0) |
2381 ((renderTypes & EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_MATERIALS_DIFFUSEMASKEDTRANSPARENCY:0) |
2382 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES) == EntityRenderer::RENDERTYPE_TEXTURES?EntityRenderer::RENDERTYPE_TEXTURES:0) |
2383 ((renderTypes & EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY) == EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY?EntityRenderer::RENDERTYPE_TEXTURES_DIFFUSEMASKEDTRANSPARENCY:0)|
2384 ((renderTypes & EntityRenderer::RENDERTYPE_LIGHTS) == EntityRenderer::RENDERTYPE_LIGHTS?EntityRenderer::RENDERTYPE_LIGHTS:0)
2385 );
2387 }
2388 }
2389
2390 // render transparent faces
2392
2393 //
2395
2396 // unuse lighting shader
2397 if (lightingShader != nullptr) lightingShader->unUseProgram();
2398
2399 // render shadows if required
2400 if (applyShadowMapping == true && shadowMapping != nullptr) {
2402 }
2403 }
2404
2405 if (doRenderLightSource == true) {
2406 auto _width = scaledWidth != -1?scaledWidth:width;
2407 auto _height = scaledHeight != -1?scaledHeight:height;
2408 //
2409 renderLightSources(_width, _height);
2410 }
2411
2412 //
2415}
2416
2418 auto lightSourceVisible = false;
2419 for (auto& light: lights) {
2420 if (light.isEnabled() == false || light.isRenderSource() == false) continue;
2421 auto lightSourceSize = light.getSourceSize();
2422 auto lightSourcePixelSize = width < height?static_cast<float>(lightSourceSize) * static_cast<float>(width):static_cast<float>(lightSourceSize) * static_cast<float>(height);;
2423 Vector2 lightSourceDimension2D = Vector2(lightSourcePixelSize, lightSourcePixelSize);
2424 Vector2 lightSourcePosition2D;
2425 Vector3 lightSourcePosition = Vector3(light.getPosition().getX(), light.getPosition().getY(), light.getPosition().getZ());
2426 if (light.getPosition().getW() > Math::EPSILON) lightSourcePosition.scale(1.0f / light.getPosition().getW());
2427 auto visible = computeScreenCoordinateByWorldCoordinate(lightSourcePosition, lightSourcePosition2D, width, height);
2428 lightSourcePosition2D.sub(lightSourceDimension2D.clone().scale(0.5f));
2429 if (visible == true) {
2430 texture2DRenderShader->renderTexture(this, lightSourcePosition2D, lightSourceDimension2D, light.getSourceTextureId(), width, height);
2431 lightSourceVisible = true;
2432 }
2433 }
2434 return lightSourceVisible;
2435}
2436
2438 for (auto shaderType = 0; shaderType < SHADERTYPE_MAX; shaderType++)
2439 for (auto& shaderId: getRegisteredShader(static_cast<ShaderType>(shaderType))) {
2440 string shaderTypeString = "unknowm";
2441 switch (shaderType) {
2442 case SHADERTYPE_OBJECT3D: shaderTypeString = "object3d"; break;
2443 case SHADERTYPE_POSTPROCESSING: shaderTypeString = "postprocessing"; break;
2444 default: break;
2445 }
2446 Console::println(string("TDME2::registered " + shaderTypeString + " shader: ") + shaderId);
2447 auto& defaultShaderParameters = getShaderParameterDefaults(shaderId);
2448 if (defaultShaderParameters.size() > 0) {
2449 Console::print("\t");
2450 for (auto it: defaultShaderParameters) {
2451 auto& parameterName = it.first;
2452 Console::print(parameterName);
2453 switch(it.second.getType()) {
2455 Console::print("=none; ");
2456 break;
2458 Console::print("=boolean(");
2459 Console::print(getShaderParameter(shaderId, parameterName).getBooleanValue() == true?"true":"false");
2460 Console::print("); ");
2461 break;
2463 Console::print("=integer(");
2464 Console::print(to_string(getShaderParameter(shaderId, parameterName).getIntegerValue()));
2465 Console::print("); ");
2466 break;
2468 Console::print("=float(");
2469 Console::print(to_string(getShaderParameter(shaderId, parameterName).getFloatValue()));
2470 Console::print("); ");
2471 break;
2473 {
2474 Console::print("=Vector2(");
2475 auto& shaderParameterArray = getShaderParameter(shaderId, parameterName).getVector2Value().getArray();
2476 for (auto i = 0; i < shaderParameterArray.size(); i++) {
2477 if (i != 0) Console::print(",");
2478 Console::print(to_string(shaderParameterArray[i]));
2479 }
2480 Console::print("); ");
2481 }
2482 break;
2484 {
2485 Console::print("=Vector3(");
2486 auto& shaderParameterArray = getShaderParameter(shaderId, parameterName).getVector3Value().getArray();
2487 for (auto i = 0; i < shaderParameterArray.size(); i++) {
2488 if (i != 0) Console::print(",");
2489 Console::print(to_string(shaderParameterArray[i]));
2490 }
2491 Console::print("); ");
2492 }
2493 break;
2495 {
2496 Console::print("=Vector4(");
2497 auto& shaderParameterArray = getShaderParameter(shaderId, parameterName).getVector4Value().getArray();
2498 for (auto i = 0; i < shaderParameterArray.size(); i++) {
2499 if (i != 0) Console::print(",");
2500 Console::print(to_string(shaderParameterArray[i]));
2501 }
2502 Console::print("); ");
2503 }
2504 break;
2505 default:
2506 Console::print("=unknown; ");
2507 break;
2508 }
2509 }
2510 Console::println();
2511 }
2512 }
2513}
#define CHECK_INITIALIZED(NAME, SHADER)
Application base class, please make sure to allocate application on heap to have correct application ...
Definition: Application.h:37
const Matrix4x4 & getModelViewProjectionInvertedMatrix() const
Definition: Camera.h:264
void update(int contextIdx, int32_t width, int32_t height)
Sets up camera while resizing the view port.
Definition: Camera.cpp:154
Frustum * getFrustum()
Definition: Camera.h:271
const Matrix4x4 & getModelViewMatrix() const
Definition: Camera.h:243
const Matrix4x4 & getModelViewProjectionMatrix() const
Definition: Camera.h:257
TransparentRenderFacesPool * transparentRenderFacesPool
Definition: Engine.h:321
Engine main class.
Definition: Engine.h:122
static void setShadowMapRenderLookUps(int32_t shadowMapRenderLookUps)
Set shadowmap look ups for each pixel when rendering.
Definition: Engine.h:671
static STATIC_DLL_IMPEXT Engine * currentEngine
Definition: Engine.h:180
Timing * timing
Definition: Engine.h:252
bool renderLightSources(int width, int height)
Render light sources.
Definition: Engine.cpp:2417
void dumpShaders()
Print registered shaders and it default parameters to console.
Definition: Engine.cpp:2437
bool removeEntity(const string &id)
Removes an entity.
Definition: Engine.cpp:451
static STATIC_DLL_IMPEXT MeshManager * meshManager
Definition: Engine.h:188
unordered_set< Entity * > needsPreRenderEntities
Definition: Engine.h:273
bool renderingComputedTransformations
Definition: Engine.h:283
static STATIC_DLL_IMPEXT Renderer * renderer
Definition: Engine.h:184
static STATIC_DLL_IMPEXT EZRShader * ezrShader
Definition: Engine.h:193
static STATIC_DLL_IMPEXT TextureManager * textureManager
Definition: Engine.h:186
static STATIC_DLL_IMPEXT Queue< EngineThreadQueueElement > * engineThreadsQueue
Definition: Engine.h:380
void initRendering()
Initiates the rendering process updates timing, updates camera.
Definition: Engine.cpp:990
void doPostProcessing(PostProcessingProgram::RenderPass renderPass, const array< FrameBuffer *, 2 > postProcessingFrameBuffers, FrameBuffer *targetFrameBuffer)
Do post processing.
Definition: Engine.cpp:2047
void reshape(int32_t width, int32_t height)
Reshape.
Definition: Engine.cpp:885
void display()
Renders the scene.
Definition: Engine.cpp:1269
static STATIC_DLL_IMPEXT LightingShader * lightingShader
Definition: Engine.h:196
static STATIC_DLL_IMPEXT vector< EngineThread * > engineThreads
Definition: Engine.h:379
void initialize()
Initialize render engine.
Definition: Engine.cpp:668
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:1971
static STATIC_DLL_IMPEXT int threadCount
Definition: Engine.h:206
static const vector< string > getRegisteredShader(ShaderType type)
Returns registered shaders for given type.
Definition: Engine.cpp:2111
void computeTransformationsFunction(vector< Object3D * > &objects, int threadIdx)
Computes visibility and transformations.
Definition: Engine.cpp:1006
array< Light, LIGHTS_MAX > lights
Definition: Engine.h:257
GeometryBuffer * geometryBuffer
Definition: Engine.h:259
int32_t getWidth()
Definition: Engine.h:865
~Engine()
Destructor.
Definition: Engine.cpp:276
void render(FrameBuffer *renderFrameBuffer, GeometryBuffer *renderGeometryBuffer, DecomposedEntities &visibleDecomposedEntities, int32_t effectPass, int32_t renderPassMask, const string &shaderPrefix, bool useEZR, bool applyShadowMapping, bool applyPostProcessing, bool doRenderLightSource, bool doRenderParticleSystems, int32_t renderTypes)
Do a render/effect pass.
Definition: Engine.cpp:2143
static STATIC_DLL_IMPEXT bool skinningShaderEnabled
Definition: Engine.h:280
unordered_set< Entity * > noFrustumCullingEntities
Definition: Engine.h:272
void decomposeEntityTypes(const vector< Entity * > &entities, DecomposedEntities &decomposedEntities, bool decomposeAllEntities=false)
Decompose entity types.
Definition: Engine.cpp:1136
Vector3 computeWorldCoordinateByMousePosition(int32_t mouseX, int32_t mouseY, float z)
Compute world coordinate from mouse position and z value.
Definition: Engine.cpp:1469
void setPartition(Partition *partition)
Set partition.
Definition: Engine.cpp:358
void addPostProcessingProgram(const string &programId)
Add post processing program.
Definition: Engine.cpp:2042
static STATIC_DLL_IMPEXT AnimationProcessingTarget animationProcessingTarget
Definition: Engine.h:191
void doneGUIMode()
Set up GUI mode rendering.
Definition: Engine.cpp:1962
void initGUIMode()
Set up GUI mode rendering.
Definition: Engine.cpp:1950
void decomposeEntityType(Entity *entity, DecomposedEntities &decomposedEntities, bool decomposeAllEntities=false)
Decompose entity type.
Definition: Engine.cpp:1010
static STATIC_DLL_IMPEXT ShadowMapRenderShader * shadowMappingShaderRender
Definition: Engine.h:195
static void registerShader(ShaderType type, const string &shaderId, const map< string, ShaderParameter > &parameterDefaults={})
Register shader.
Definition: Engine.cpp:2122
FrameBuffer * postProcessingFrameBuffer1
Definition: Engine.h:261
bool renderingInitiated
Definition: Engine.h:282
static STATIC_DLL_IMPEXT LinesShader * linesShader
Definition: Engine.h:198
void removeFromDecomposedEntities(DecomposedEntities &decomposedEntities, Entity *entity)
Remove entity from decomposed entities.
Definition: Engine.cpp:483
static STATIC_DLL_IMPEXT GUIShader * guiShader
Definition: Engine.h:200
static STATIC_DLL_IMPEXT ParticlesShader * particlesShader
Definition: Engine.h:197
static Engine * createOffScreenInstance(int32_t width, int32_t height, bool enableShadowMapping, bool enableDepthBuffer, bool enableGeometryBuffer)
Creates an offscreen rendering instance Note:
Definition: Engine.cpp:310
int32_t getHeight()
Definition: Engine.h:872
friend class FrameBuffer
Definition: Engine.h:130
Entity * getEntityByMousePosition(int32_t mouseX, int32_t mouseY, EntityPickingFilter *filter=nullptr, Node **object3DNode=nullptr, ParticleSystemEntity **particleSystemEntity=nullptr)
Retrieves entity by mouse position.
Definition: Engine.h:1068
FrameBuffer * postProcessingTemporaryFrameBuffer
Definition: Engine.h:263
static STATIC_DLL_IMPEXT PostProcessingShader * postProcessingShader
Definition: Engine.h:204
void scale(int32_t width, int32_t height)
Scale which applies to main engine only.
Definition: Engine.cpp:943
static STATIC_DLL_IMPEXT Texture2DRenderShader * texture2DRenderShader
Definition: Engine.h:205
static constexpr int ENGINETHREADSQUEUE_COMPUTE_DISPATCH_COUNT
Definition: Engine.h:177
bool shadowMappingEnabled
Definition: Engine.h:281
static int32_t getShadowMapWidth()
Definition: Engine.h:639
static const map< string, ShaderParameter > getShaderParameterDefaults(const string &shaderId)
Returns parameter defaults of shader with given id.
Definition: Engine.cpp:2134
static STATIC_DLL_IMPEXT map< string, Shader > shaders
Definition: Engine.h:223
Engine()
Private constructor.
Definition: Engine.cpp:252
void renderToScreen()
Render scaled main engine to screen.
Definition: Engine.cpp:966
static STATIC_DLL_IMPEXT DeferredLightingRenderShader * deferredLightingRenderShader
Definition: Engine.h:202
static STATIC_DLL_IMPEXT PostProcessing * postProcessing
Definition: Engine.h:203
const string getGraphicsRenderer()
Definition: Engine.cpp:354
array< bool, EFFECTPASS_COUNT - 1 > effectPassSkip
Definition: Engine.h:265
EntityRenderer * entityRenderer
Definition: Engine.h:278
ShadowMapping * shadowMapping
Definition: Engine.h:266
static int32_t getShadowMapHeight()
Definition: Engine.h:646
unordered_map< string, Entity * > entitiesById
Definition: Engine.h:269
void addEntity(Entity *entity)
Adds an entity by id.
Definition: Engine.cpp:364
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:792
bool computeScreenCoordinateByWorldCoordinate(const Vector3 &worldCoordinate, Vector2 &screenCoordinate, int width=-1, int height=-1)
Convert screen coordinate by world coordinate.
Definition: Engine.cpp:1894
friend class GeometryBuffer
Definition: Engine.h:131
static STATIC_DLL_IMPEXT SkinningShader * skinningShader
Definition: Engine.h:199
static STATIC_DLL_IMPEXT Engine * instance
Definition: Engine.h:183
vector< string > postProcessingPrograms
Definition: Engine.h:285
void resetPostProcessingPrograms()
Clear post processing programs.
Definition: Engine.cpp:2038
void deregisterEntity(Entity *entity)
Removes a entity from internal lists, those entities can also be sub entities from entity hierarchy o...
Definition: Engine.cpp:392
void dispose()
Shutdown the engine.
Definition: Engine.cpp:1907
void preRenderFunction(vector< Object3D * > &objects, int threadIdx)
Update vertex buffers and such before rendering.
Definition: Engine.cpp:1002
static STATIC_DLL_IMPEXT EngineThreadQueueElementPool engineThreadQueueElementPool
Definition: Engine.h:381
static int32_t getShadowMapRenderLookUps()
Definition: Engine.h:653
static STATIC_DLL_IMPEXT FrameBufferRenderShader * frameBufferRenderShader
Definition: Engine.h:201
Entity * getEntity(const string &id)
Returns a entity by given id.
Definition: Engine.h:981
const string getGraphicsVendor()
Definition: Engine.cpp:350
static STATIC_DLL_IMPEXT ShadowMapCreationShader * shadowMappingShaderPre
Definition: Engine.h:194
void unscale()
Disable scaling, which applies to main engine only.
Definition: Engine.cpp:957
static void setShadowMapSize(int32_t width, int32_t height)
Set shadow map size.
Definition: Engine.h:662
unordered_set< Entity * > autoEmitParticleSystemEntities
Definition: Engine.h:271
void reset()
Removes all entities and caches.
Definition: Engine.cpp:652
FrameBuffer * postProcessingFrameBuffer2
Definition: Engine.h:262
static STATIC_DLL_IMPEXT VBOManager * vboManager
Definition: Engine.h:187
static constexpr int ENGINETHREADSQUEUE_PRERENDER_DISPATCH_COUNT
Definition: Engine.h:176
vector< Action * > actions
Definition: Engine.h:293
void computeTransformations(Camera *camera, DecomposedEntities &decomposedEntites, bool autoEmit, bool computeTransformations)
Computes visibility and transformations.
Definition: Engine.cpp:1142
static STATIC_DLL_IMPEXT GUIRenderer * guiRenderer
Definition: Engine.h:189
FrameBuffer * frameBuffer
Definition: Engine.h:260
int32_t scaledWidth
Definition: Engine.h:249
void removeEntityFromLists(Entity *entity)
Remove entity.
Definition: Engine.cpp:615
unordered_set< Entity * > needsComputeTransformationsEntities
Definition: Engine.h:274
bool isUsingPostProcessingTemporaryFrameBuffer
Definition: Engine.h:289
DecomposedEntities visibleDecomposedEntities
Definition: Engine.h:276
void resetLists(DecomposedEntities &decomposedEntites)
Reset lists.
Definition: Engine.cpp:970
int32_t scaledHeight
Definition: Engine.h:250
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:406
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:1101
Camera * camera
Definition: Engine.h:253
array< FrameBuffer *, EFFECTPASS_COUNT - 1 > effectPassFrameBuffers
Definition: Engine.h:264
Partition * partition
Definition: Engine.h:255
Entity hierarchy to be used with engine class.
TDME engine entity.
Definition: Entity.h:31
@ RENDERPASS_POST_POSTPROCESSING
Definition: Entity.h:58
virtual bool isEnabled()=0
virtual void setRenderer(Renderer *renderer)=0
Set up renderer.
virtual const string & getId()=0
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:57
virtual void initialize()=0
Initiates this object 3d.
static constexpr int RENDERPASS_MAX
Definition: Entity.h:56
virtual Entity * getParentEntity()=0
@ ENTITYTYPE_LODOBJECT3DIMPOSTER
Definition: Entity.h:66
@ ENTITYTYPE_OBJECT3DRENDERGROUP
Definition: Entity.h:68
@ ENTITYTYPE_IMPOSTEROBJECT3D
Definition: Entity.h:63
@ ENTITYTYPE_LINESOBJECT3D
Definition: Entity.h:64
@ ENTITYTYPE_OBJECTPARTICLESYSTEM
Definition: Entity.h:70
@ ENTITYTYPE_FOGPARTICLESYSTEM
Definition: Entity.h:69
@ ENTITYTYPE_POINTSPARTICLESYSTEM
Definition: Entity.h:72
@ ENTITYTYPE_ENVIRONMENTMAPPING
Definition: Entity.h:62
@ ENTITYTYPE_PARTICLESYSTEMGROUP
Definition: Entity.h:71
@ ENTITYTYPE_ENTITYHIERARCHY
Definition: Entity.h:61
Environment mapping entity.
Fog particle system entity to be used with engine class.
Frame buffer class.
Definition: FrameBuffer.h:21
void reshape(int32_t width, int32_t height)
Resize the frame buffer.
Definition: FrameBuffer.cpp:55
void renderToScreen(Engine *engine, int32_t depthBufferTextureId, int32_t colorBufferTextureId)
Render given depth texture and color buffer texture to screen @parma engine engine.
void initialize()
Initialize the frame buffer.
Definition: FrameBuffer.cpp:33
static void disableFrameBuffer()
Switches back to non offscreen main frame buffer to be rendered.
Definition: FrameBuffer.cpp:85
void enableFrameBuffer()
Enables this frame buffer to be rendered.
Definition: FrameBuffer.cpp:78
static constexpr int32_t FRAMEBUFFER_COLORBUFFER
Definition: FrameBuffer.h:25
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:24
void dispose()
Disposes this frame buffer.
Definition: FrameBuffer.cpp:67
void update()
Setups frustum, should be called if frustum did change.
Definition: Frustum.cpp:30
Geometry buffer class.
void reshape(int32_t width, int32_t height)
Resize the geometry buffer.
void initialize()
Initialize the geometry buffer.
void renderToScreen(Engine *engine)
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 3d to be used with engine class.
LOD object 3D + imposter to be used with engine class.
LOD object 3D to be used with engine class.
Definition: LODObject3D.h:47
Object3D * getLOD1Object()
Definition: LODObject3D.h:154
Light representation.
Definition: Light.h:32
Object 3D to be used with engine class.
Definition: LinesObject3D.h:39
Object 3D render group for static objects that might be animated by shaders.
Object 3D to be used with engine class.
Definition: Object3D.h:60
Object particle system entity to be used with engine class.
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 Vector3 getVector3Value() const
const Vector4 getVector4Value() const
const Vector2 getVector2Value() const
Timing class.
Definition: Timing.h:17
void updateTiming()
Updates timing.
Definition: Timing.cpp:29
void set(const array< float, 4 > &color)
Set up color.
Definition: Color4Base.h:68
Color 4 definition.
Definition: Color4.h:20
Model node.
Definition: Node.h:31
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:25
Line segment helper functions.
Definition: LineSegment.h:17
void useProgram(Engine *engine)
Use EZR render shader program.
Definition: EZRShader.cpp:59
void unUseProgram()
Unuse EZR render shader program.
Definition: EZRShader.cpp:65
Interface to lighting shader program.
void useProgram(Engine *engine)
Use lighting program.
void unUseProgram(int contextIdx)
Unuse particles shader program.
Definition: LinesShader.cpp:95
void useProgram(int contextIdx)
Use lighting program.
Definition: LinesShader.cpp:77
void unUseProgram(int contextIdx)
Unuse particles shader program.
void useProgram(int contextIdx)
Use lighting program.
PostProcessingProgram * getPostProcessingProgram(const string &programId)
Get post processing 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:484
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 ByteBuffer * readPixels(int32_t x, int32_t y, int32_t width, int32_t height)=0
Read pixels.
virtual void initGuiMode()=0
Set up renderer for GUI rendering.
virtual bool isBufferObjectsAvailable()=0
Checks if buffer objects is available.
virtual void setColorMask(bool red, bool green, bool blue, bool alpha)=0
Set up GL rendering colormask.
virtual void initialize()=0
Initialize renderer.
virtual void clear(int32_t mask)=0
Clear render buffer with given mask.
virtual bool isDepthTextureAvailable()=0
Checks if depth texture is available.
void setEffectPass(int32_t effectPass)
Set effect pass.
Definition: Renderer.h:468
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.
void render(Entity::RenderPass renderPass, const vector< Object3D * > &objects, bool renderTransparentFaces, int32_t renderTypes)
Renders all given objects.
void reset()
Resets the object 3d renderer.
void renderTransparentFaces()
Renders collected transparent faces.
Buffers used to transfer data between main memory to graphics board memory.
Definition: ObjectBuffer.h:23
void initialize()
Initialize shadow map render shader program.
void reshape(int32_t width, int32_t height)
Reshape shadow maps.
void renderShadowMaps(const vector< Object3D * > &visibleObjects)
Render shadow maps to world.
Interface to compute shader skinning shader program.
void renderTexture(Engine *engine, const Vector2 &position, const Vector2 &dimension, int textureId, int width=-1, int height=-1)
Render texture.
GUI parser.
Definition: GUIParser.h:39
GUI module class.
Definition: GUI.h:66
void initialize()
Init.
Definition: GUI.cpp:89
void reshape(int width, int height)
Reshape.
Definition: GUI.cpp:93
void dispose()
Dispose.
Definition: GUI.cpp:103
void initialize()
Init shadow mapping.
Definition: GUIShader.cpp:35
Standard math functions.
Definition: Math.h:21
4x4 3D Matrix class
Definition: Matrix4x4.h:24
Vector3 multiply(const Vector3 &v) const
Multiplies a vector3 with this matrix into destination vector.
Definition: Matrix4x4.h:351
2D vector 2 class
Definition: Vector2.h:19
Vector2 clone() const
Clones the vector.
Definition: Vector2.h:338
Vector2 & scale(const float scale)
Scale this vector.
Definition: Vector2.h:151
Vector2 & sub(const Vector2 &v)
Subtracts a vector.
Definition: Vector2.h:140
Vector2 & setX(float x)
set X
Definition: Vector2.h:103
array< float, 2 > & getArray() const
Definition: Vector2.h:330
Vector2 & setY(float y)
set Y
Definition: Vector2.h:119
3D vector 3 class
Definition: Vector3.h:22
float getZ() const
Definition: Vector3.h:136
Vector3 & set(float x, float y, float z)
Set up vector.
Definition: Vector3.h:73
float computeLengthSquared() const
Definition: Vector3.h:209
Vector3 clone() const
Clones the vector.
Definition: Vector3.h:372
Vector3 & sub(const Vector3 &v)
Subtracts a vector.
Definition: Vector3.h:325
Vector3 & scale(float scale)
Scale this vector.
Definition: Vector3.h:349
array< float, 3 > & getArray() const
Definition: Vector3.h:171
3D vector 4 class
Definition: Vector4.h:19
array< float, 4 > & getArray() const
Definition: Vector4.h:407
File system singleton class.
Definition: FileSystem.h:14
Consumer/producer queue.
Definition: Queue.h:24
Base class for threads.
Definition: Thread.h:26
Byte buffer class.
Definition: ByteBuffer.h:24
Console class.
Definition: Console.h:26
Float class.
Definition: Float.h:23
T allocate()
Allocate a new element from pool.
Definition: Pool.h:53
void reset()
Reset this pool.
Definition: Pool.h:96
vector< Object3D * > needsComputeTransformationsEntities
Definition: Engine.h:242
vector< LODObject3D * > lodObjects
Definition: Engine.h:231
vector< Object3D * > objectsPostPostProcessing
Definition: Engine.h:229
vector< EntityHierarchy * > entityHierarchies
Definition: Engine.h:238
vector< LinesObject3D * > linesObjects
Definition: Engine.h:236
vector< Object3D * > objectsForwardShading
Definition: Engine.h:228
vector< EnvironmentMapping * > environmentMappingEntities
Definition: Engine.h:239
vector< ParticleSystemGroup * > psgs
Definition: Engine.h:235
vector< Object3D * > ezrObjects
Definition: Engine.h:240
vector< ObjectParticleSystem * > opses
Definition: Engine.h:233
vector< Object3DRenderGroup * > objectRenderGroups
Definition: Engine.h:237
vector< Object3D * > needsPreRenderEntities
Definition: Engine.h:241
vector< Entity * > noFrustumCullingEntities
Definition: Engine.h:226
vector< Object3D * > objectsNoDepthTest
Definition: Engine.h:230
virtual bool filterEntity(Entity *entity)=0
Filter entity.
Particle system entity interface.
virtual int32_t emitParticles()=0
Adds particles to this particle entity at given position.
Partition interface.
Definition: Partition.h:19
virtual bool isVisibleEntity(Entity *entity)=0
Check if entity is visible.
virtual void reset()=0
Reset.
virtual const vector< Entity * > & getVisibleEntities(Frustum *frustum)=0
Get visible entities.
virtual void addEntity(Entity *entity)=0
Adds a entity.
virtual void removeEntity(Entity *entity)=0
Removes a entity.