From 7b7d699371efc6b5800373df198ffdf207158119 Mon Sep 17 00:00:00 2001 From: Alexis Maiquez Date: Fri, 28 Oct 2022 18:21:29 +0200 Subject: [PATCH] Implemented proper dependency detection for images Simplified texture decision graph and preload it so render is quicker Improved material detecion on shaders Signed-off-by: Alexis Maiquez --- src/WallpaperEngine/Core/CScene.cpp | 11 +- src/WallpaperEngine/Core/CScene.h | 6 +- src/WallpaperEngine/Core/Objects/CEffect.cpp | 14 +- src/WallpaperEngine/Render/CObject.cpp | 5 + src/WallpaperEngine/Render/CObject.h | 1 + src/WallpaperEngine/Render/CScene.cpp | 86 ++++++--- src/WallpaperEngine/Render/CScene.h | 5 +- src/WallpaperEngine/Render/Objects/CImage.cpp | 4 + .../Render/Objects/Effects/CPass.cpp | 178 +++++++----------- .../Render/Objects/Effects/CPass.h | 5 + .../Render/Shaders/Compiler.cpp | 43 +++-- 11 files changed, 208 insertions(+), 150 deletions(-) diff --git a/src/WallpaperEngine/Core/CScene.cpp b/src/WallpaperEngine/Core/CScene.cpp index 309754f..5db36a6 100644 --- a/src/WallpaperEngine/Core/CScene.cpp +++ b/src/WallpaperEngine/Core/CScene.cpp @@ -113,16 +113,23 @@ CScene* CScene::fromFile (const std::string& filename, CContainer* container) return scene; } -const std::vector& CScene::getObjects () const +const std::map& CScene::getObjects () const { return this->m_objects; } +const std::vector& CScene::getObjectsByRenderOrder () const +{ + return this->m_objectsByRenderOrder; +} void CScene::insertObject (CObject* object) { /// TODO: XXXHACK -- TO REMOVE WHEN PARTICLE SUPPORT IS PROPERLY IMPLEMENTED if (object != nullptr) - this->m_objects.push_back (object); + { + this->m_objects.insert (std::make_pair (object->getId (), object)); + this->m_objectsByRenderOrder.emplace_back (object); + } } CContainer* CScene::getContainer () diff --git a/src/WallpaperEngine/Core/CScene.h b/src/WallpaperEngine/Core/CScene.h index 3f7c3e8..aa81f3c 100644 --- a/src/WallpaperEngine/Core/CScene.h +++ b/src/WallpaperEngine/Core/CScene.h @@ -21,7 +21,8 @@ namespace WallpaperEngine::Core public: static CScene* fromFile (const std::string& filename, CContainer* container); - const std::vector& getObjects () const; + const std::map& getObjects () const; + const std::vector& getObjectsByRenderOrder () const; const FloatColor& getAmbientColor() const; const bool isBloom() const; @@ -95,6 +96,7 @@ namespace WallpaperEngine::Core Scenes::CProjection* m_orthogonalProjection; FloatColor m_skylightColor; - std::vector m_objects; + std::map m_objects; + std::vector m_objectsByRenderOrder; }; }; diff --git a/src/WallpaperEngine/Core/Objects/CEffect.cpp b/src/WallpaperEngine/Core/Objects/CEffect.cpp index 7225b8f..2302317 100644 --- a/src/WallpaperEngine/Core/Objects/CEffect.cpp +++ b/src/WallpaperEngine/Core/Objects/CEffect.cpp @@ -91,14 +91,16 @@ CEffect* CEffect::fromJSON (json data, Core::CObject* object, CContainer* contai if ((*texturesCur).is_null () == true) { - if (object->is () == false) + if (textureNumber == 0) { - throw std::runtime_error ("unexpected null texture for non-image object"); + CImage* image = object->as (); + + texture = (*(*image->getMaterial ()->getPasses ().begin ())->getTextures ().begin ()); + } + else + { + texture = ""; } - - CImage* image = object->as (); - - texture = (*(*image->getMaterial ()->getPasses ().begin ())->getTextures ().begin ()); } else { diff --git a/src/WallpaperEngine/Render/CObject.cpp b/src/WallpaperEngine/Render/CObject.cpp index 34315cc..f4bbf92 100644 --- a/src/WallpaperEngine/Render/CObject.cpp +++ b/src/WallpaperEngine/Render/CObject.cpp @@ -24,4 +24,9 @@ CScene* CObject::getScene () const CContainer* CObject::getContainer () const { return this->getScene ()->getContainer (); +} + +const int CObject::getId () const +{ + return this->m_object->getId (); } \ No newline at end of file diff --git a/src/WallpaperEngine/Render/CObject.h b/src/WallpaperEngine/Render/CObject.h index d1a46a3..8d269a8 100644 --- a/src/WallpaperEngine/Render/CObject.h +++ b/src/WallpaperEngine/Render/CObject.h @@ -22,6 +22,7 @@ namespace WallpaperEngine::Render CScene* getScene () const; CContainer* getContainer () const; + const int getId () const; protected: CObject (CScene* scene, std::string type, Core::CObject *object); diff --git a/src/WallpaperEngine/Render/CScene.cpp b/src/WallpaperEngine/Render/CScene.cpp index 5287806..13f9779 100644 --- a/src/WallpaperEngine/Render/CScene.cpp +++ b/src/WallpaperEngine/Render/CScene.cpp @@ -24,10 +24,10 @@ CScene::CScene (Core::CScene* scene, CContainer* container, CContext* context) : for (; cur != end; cur ++) { - if ((*cur)->is () == false) + if ((*cur).second->is () == false) continue; - glm::vec2 size = (*cur)->as ()->getSize (); + glm::vec2 size = (*cur).second->as ()->getSize (); scene->getOrthogonalProjection ()->setWidth (size.x); scene->getOrthogonalProjection ()->setHeight (size.y); @@ -42,42 +42,84 @@ CScene::CScene (Core::CScene* scene, CContainer* container, CContext* context) : // setup framebuffers this->setupFramebuffers (); - auto cur = scene->getObjects ().begin (); - auto end = scene->getObjects ().end (); + // create all objects based off their dependencies + { + + auto cur = scene->getObjects ().begin (); + auto end = scene->getObjects ().end (); + + for (; cur != end; cur++) + this->createObject ((*cur).second); + } + + // now setup the render order + auto cur = scene->getObjectsByRenderOrder ().begin (); + auto end = scene->getObjectsByRenderOrder ().end (); for (; cur != end; cur ++) { - CObject* object = nullptr; + auto obj = this->m_objects.find ((*cur)->getId ()); - if ((*cur)->is() == true) - { - object = new Objects::CImage (this, (*cur)->as()); - } - else if ((*cur)->is() == true) - { - object = new Objects::CSound (this, (*cur)->as()); - } + // ignores not created objects like particle systems + if (obj == this->m_objects.end ()) + continue; - if (object != nullptr) - this->m_objects.emplace_back (object); + this->m_objectsByRenderOrder.emplace_back ((*obj).second); } - auto objectsCur = this->m_objects.begin (); - auto objectsEnd = this->m_objects.end (); +} - for (; objectsCur != objectsEnd; objectsCur ++) +Render::CObject* CScene::createObject (Core::CObject* object) +{ + Render::CObject* renderObject = nullptr; + + // ensure the item is not loaded already + auto current = this->m_objects.find (object->getId ()); + + if (current != this->m_objects.end ()) + return (*current).second; + + // check dependencies too! + auto depCur = object->getDependencies ().begin (); + auto depEnd = object->getDependencies ().end (); + + for (; depCur != depEnd; depCur ++) { + // self-dependency is a possibility... + if ((*depCur) == object->getId ()) + continue; + + auto dep = this->getScene ()->getObjects ().find (*depCur); + + if (dep != this->getScene ()->getObjects ().end ()) + this->createObject ((*dep).second); + } + + if (object->is() == true) + { + Objects::CImage* image = new Objects::CImage (this, object->as()); + try { - if ((*objectsCur)->is () == true) - (*objectsCur)->as ()->setup (); + image->setup (); } catch (std::runtime_error ex) { std::cerr << "Cannot setup image resource: " << std::endl; std::cerr << ex.what () << std::endl; } + + renderObject = image; } + else if (object->is() == true) + { + renderObject = new Objects::CSound (this, object->as()); + } + + if (renderObject != nullptr) + this->m_objects.insert (std::make_pair (renderObject->getId (), renderObject)); + + return renderObject; } CCamera* CScene::getCamera () const @@ -88,8 +130,8 @@ CCamera* CScene::getCamera () const void CScene::renderFrame (glm::ivec4 viewport) { auto projection = this->getScene ()->getOrthogonalProjection (); - auto cur = this->m_objects.begin (); - auto end = this->m_objects.end (); + auto cur = this->m_objectsByRenderOrder.begin (); + auto end = this->m_objectsByRenderOrder.end (); // ensure the virtual mouse position is up to date this->updateMouse (viewport); diff --git a/src/WallpaperEngine/Render/CScene.h b/src/WallpaperEngine/Render/CScene.h index 1011aab..941001d 100644 --- a/src/WallpaperEngine/Render/CScene.h +++ b/src/WallpaperEngine/Render/CScene.h @@ -32,8 +32,11 @@ namespace WallpaperEngine::Render static const std::string Type; private: + Render::CObject* createObject (Core::CObject* object); + CCamera* m_camera; - std::vector m_objects; + std::map m_objects; + std::vector m_objectsByRenderOrder; glm::vec2 m_mousePosition; }; } diff --git a/src/WallpaperEngine/Render/Objects/CImage.cpp b/src/WallpaperEngine/Render/Objects/CImage.cpp index d2b61d6..6aedec9 100644 --- a/src/WallpaperEngine/Render/Objects/CImage.cpp +++ b/src/WallpaperEngine/Render/Objects/CImage.cpp @@ -212,6 +212,10 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) : void CImage::setup () { + // do not double-init stuff, that's bad! + if (this->m_initialized) + return; + // generate the main material used to copy the image to the correct texture this->m_copyMaterial = new Effects::CMaterial ( new CEffect (this, new Core::Objects::CEffect ("", "", "", "", this->m_image)), diff --git a/src/WallpaperEngine/Render/Objects/Effects/CPass.cpp b/src/WallpaperEngine/Render/Objects/Effects/CPass.cpp index b513ce4..be89cfe 100644 --- a/src/WallpaperEngine/Render/Objects/Effects/CPass.cpp +++ b/src/WallpaperEngine/Render/Objects/Effects/CPass.cpp @@ -170,68 +170,22 @@ void CPass::render (CFBO* drawTo, ITexture* input, GLuint position, GLuint texco } } + // first texture is a bit special as we have to take what comes from the chain first glActiveTexture (GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, texture->getTextureID (currentTexture)); - int lastTextureIndex = 0; - // first bind the textures to their sampler place + // continue on the map from the second texture + if (this->m_finalTextures.empty () == false) { - // set texture slots for the shader - auto cur = this->m_textures.begin (); - auto end = this->m_textures.end (); + auto cur = this->m_finalTextures.begin (); + auto end = this->m_finalTextures.end (); - for (int index = 1; cur != end; cur ++, index ++) + for (; cur != end; cur ++) { - texture = this->resolveTexture ((*cur), index, input); + texture = this->resolveTexture ((*cur).second, (*cur).first, input); - glActiveTexture (GL_TEXTURE0 + index); + glActiveTexture (GL_TEXTURE0 + (*cur).first); glBindTexture (GL_TEXTURE_2D, texture->getTextureID (0)); - // increase the number of textures counter - lastTextureIndex ++; - } - } - - { - // load the extra textures needed (if any) from the shader - auto cur = this->m_fragShader->getTextures ().begin (); - auto end = this->m_fragShader->getTextures ().end (); - - for (; cur != end; cur ++) - { - if ((*cur).first <= lastTextureIndex) - continue; - - texture = this->resolveTexture ((*cur).second, (*cur).first, input); - - if (texture == nullptr) - continue; - - // set the active texture index - glActiveTexture (GL_TEXTURE0 + (*cur).first); - // bind the correct texture here - glBindTexture(GL_TEXTURE_2D, texture->getTextureID (0)); - } - } - - { - // load the extra textures needed (if any) from the shader - auto cur = this->m_vertShader->getTextures ().begin (); - auto end = this->m_vertShader->getTextures ().end (); - - for (; cur != end; cur ++) - { - if ((*cur).first <= lastTextureIndex) - continue; - - texture = this->resolveTexture ((*cur).second, (*cur).first, input); - - if (texture == nullptr) - continue; - - // set the active texture index - glActiveTexture (GL_TEXTURE0 + (*cur).first); - // bind the correct texture here - glBindTexture(GL_TEXTURE_2D, texture->getTextureID (0)); } } @@ -456,62 +410,69 @@ void CPass::setupUniforms () this->addUniform ("g_Texture7", 7); this->addUniform ("g_Texture0Resolution", texture->getResolution ()); - int lastTextureIndex = 0; - // register the extra texture resolutions + // do the real, final texture setup for the whole process { auto cur = this->m_textures.begin (); auto end = this->m_textures.end (); + auto fragCur = this->m_fragShader->getTextures ().begin (); + auto fragEnd = this->m_fragShader->getTextures ().end (); + auto vertCur = this->m_vertShader->getTextures ().begin (); + auto vertEnd = this->m_vertShader->getTextures ().end (); + auto bindCur = this->m_material->getMaterial ()->getTextureBinds ().begin (); + auto bindEnd = this->m_material->getMaterial ()->getTextureBinds ().end (); - for (int index = 1; cur != end; cur ++, index ++) + int index = 1; + + // technically m_textures should have the right amount of textures + // but better be safe than sorry + while (bindCur != bindEnd || cur != end || fragCur != fragEnd || vertCur != vertEnd) + { + if (bindCur != bindEnd) + { + this->m_finalTextures.insert (std::make_pair ((*bindCur).first, nullptr)); + } + + if (cur != end) + { + if ((*cur) != nullptr) + this->m_finalTextures.insert (std::make_pair (index, *cur)); + + index ++; + } + + if (fragCur != fragEnd && (*fragCur).second != nullptr) + { + this->m_finalTextures.insert (std::make_pair ((*fragCur).first, (*fragCur).second)); + } + + if (vertCur != vertEnd && (*vertCur).second != nullptr) + { + this->m_finalTextures.insert (std::make_pair ((*vertCur).first, (*vertCur).second)); + } + + if (bindCur != bindEnd) + bindCur ++; + if (cur != end) + cur ++; + if (fragCur != fragEnd) + fragCur ++; + if (vertCur != vertEnd) + vertCur ++; + } + } + + { + auto cur = this->m_finalTextures.begin (); + auto end = this->m_finalTextures.end (); + + for (; cur != end; cur ++) { std::ostringstream namestream; - namestream << "g_Texture" << index << "Resolution"; + namestream << "g_Texture" << (*cur).first << "Resolution"; - texture = this->resolveTexture ((*cur), index, texture); + texture = this->resolveTexture ((*cur).second, (*cur).first, texture); this->addUniform (namestream.str (), texture->getResolution ()); - lastTextureIndex ++; - } - } - - // registers the extra texture resolutions from the shader - { - auto cur = this->m_fragShader->getTextures ().begin (); - auto end = this->m_fragShader->getTextures ().end (); - - for (; cur != end; cur ++) - { - if ((*cur).first <= lastTextureIndex) - continue; - - std::ostringstream namestream; - - namestream << "g_Texture" << (*cur).first << "Resolution"; - - texture = this->resolveTexture ((*cur).second, (*cur).first, texture); - if (texture != nullptr) - this->addUniform (namestream.str (), texture->getResolution ()); - } - } - - // registers the extra texture resolutions from the shader - { - auto cur = this->m_vertShader->getTextures ().begin (); - auto end = this->m_vertShader->getTextures ().end (); - - for (; cur != end; cur ++) - { - if ((*cur).first <= lastTextureIndex) - continue; - - std::ostringstream namestream; - - namestream << "g_Texture" << (*cur).first << "Resolution"; - - texture = this->resolveTexture ((*cur).second, (*cur).first, texture); - - if (texture != nullptr) - this->addUniform (namestream.str (), texture->getResolution ()); } } @@ -599,16 +560,23 @@ void CPass::setupTextures () { this->m_fbos.insert (std::make_pair (index, fbo)); this->m_textures.emplace_back ( - nullptr + fbo ); } // _rt_texture } else { - this->m_textures.emplace_back ( - this->m_material->getImage ()->getContainer ()->readTexture ((*cur)) - ); + if ((*cur) == "") + { + this->m_textures.emplace_back (nullptr); + } + else + { + this->m_textures.emplace_back ( + this->m_material->getImage ()->getContainer ()->readTexture ((*cur)) + ); + } } } } diff --git a/src/WallpaperEngine/Render/Objects/Effects/CPass.h b/src/WallpaperEngine/Render/Objects/Effects/CPass.h index b28d307..c62a476 100644 --- a/src/WallpaperEngine/Render/Objects/Effects/CPass.h +++ b/src/WallpaperEngine/Render/Objects/Effects/CPass.h @@ -95,6 +95,11 @@ namespace WallpaperEngine::Render::Objects::Effects std::map m_uniforms; glm::mat4 m_modelViewProjectionMatrix; + /** + * Contains the final map of textures to be used + */ + std::map m_finalTextures; + Render::Shaders::Compiler* m_fragShader; Render::Shaders::Compiler* m_vertShader; diff --git a/src/WallpaperEngine/Render/Shaders/Compiler.cpp b/src/WallpaperEngine/Render/Shaders/Compiler.cpp index d45583a..a5259fe 100644 --- a/src/WallpaperEngine/Render/Shaders/Compiler.cpp +++ b/src/WallpaperEngine/Render/Shaders/Compiler.cpp @@ -12,6 +12,7 @@ #include #include +#include "WallpaperEngine/Assets/CAssetLoadException.h" #include "WallpaperEngine/Render/Shaders/Variables/CShaderVariable.h" #include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableFloat.h" #include "WallpaperEngine/Render/Shaders/Variables/CShaderVariableInteger.h" @@ -667,13 +668,13 @@ namespace WallpaperEngine::Render::Shaders // if needed auto combo = data.find ("combo"); auto textureName = data.find ("default"); + // extract the texture number from the name + char value = name.at (std::string("g_Texture").length ()); + // now convert it to integer + int index = value - '0'; if (combo != data.end ()) { - // extract the texture number from the name - char value = name.at (std::string("g_Texture").length ()); - // now convert it to integer - int index = value - '0'; // if the texture exists, add the combo if (this->m_passTextures.size () > index) @@ -698,16 +699,34 @@ namespace WallpaperEngine::Render::Shaders } else { - // material name is not resolved on compile time, but passes will do it after + // check for texture name too + if (textureName != data.end ()) + { + try + { + // also ensure that the textureName is loaded and we know about it + ITexture* texture = this->m_container->readTexture ((*textureName).get ()); - // extract the texture number from the name - char value = name.at (std::string("g_Texture").length ()); - // now convert it to integer - int index = value - '0'; + this->m_textures.insert ( + std::make_pair (index, texture) + ); + } + catch (CAssetLoadException& ex) + { + // cannot resolve texture + // TODO: TAKE CARE OF FBOS + this->m_textures.insert ( + std::make_pair (index, nullptr) + ); + } + } + else + { + this->m_textures.insert ( + std::make_pair (index, nullptr) + ); + } - this->m_textures.insert ( - std::make_pair (index, nullptr) - ); } // samplers are not saved, we can ignore them for now