[Orxonox-commit 3285] r7976 - in code/branches/usability/src: libraries/tools orxonox/items

landauf at orxonox.net landauf at orxonox.net
Sun Feb 27 01:06:00 CET 2011


Author: landauf
Date: 2011-02-27 01:05:59 +0100 (Sun, 27 Feb 2011)
New Revision: 7976

Modified:
   code/branches/usability/src/libraries/tools/Shader.cc
   code/branches/usability/src/libraries/tools/Shader.h
   code/branches/usability/src/orxonox/items/Engine.cc
Log:
rewrote parameter changing implementation of Shader
added documentation

Modified: code/branches/usability/src/libraries/tools/Shader.cc
===================================================================
--- code/branches/usability/src/libraries/tools/Shader.cc	2011-02-26 20:53:23 UTC (rev 7975)
+++ code/branches/usability/src/libraries/tools/Shader.cc	2011-02-27 00:05:59 UTC (rev 7976)
@@ -29,14 +29,8 @@
 #include "Shader.h"
 
 #include <OgreCompositorManager.h>
-#include <OgreCompositorInstance.h>
-#include <OgreSceneManager.h>
 #include <OgreRoot.h>
 #include <OgrePlugin.h>
-#include <OgreMaterial.h>
-#include <OgreTechnique.h>
-#include <OgrePass.h>
-#include <OgreMaterialManager.h>
 
 #include "core/CoreIncludes.h"
 #include "core/GameMode.h"
@@ -44,9 +38,9 @@
 
 namespace orxonox
 {
-    bool Shader::bLoadedCgPlugin_s = false;
-    Shader::MaterialMap Shader::parameters_s;
-
+    /**
+        @brief Initializes the values and sets the scene manager.
+    */
     Shader::Shader(Ogre::SceneManager* scenemanager) : compositorInstance_(0)
     {
         RegisterObject(Shader);
@@ -54,19 +48,31 @@
         this->scenemanager_ = scenemanager;
         this->bVisible_ = true;
         this->bLoadCompositor_ = GameMode::showsGraphics();
+        this->registeredAsListener_ = false;
 
         static bool hasCgProgramManager = Shader::hasCgProgramManager();
-        Shader::bLoadedCgPlugin_s = hasCgProgramManager;
 
-        this->bLoadCompositor_ &= Shader::bLoadedCgPlugin_s;
+        this->bLoadCompositor_ &= hasCgProgramManager;
     }
 
+    /**
+        @brief Removes the compositor and frees the resources.
+    */
     Shader::~Shader()
     {
         if (this->compositorInstance_ && GraphicsManager::getInstance().getViewport())
             Ogre::CompositorManager::getSingleton().removeCompositor(GraphicsManager::getInstance().getViewport(), this->compositorName_);
     }
 
+    /**
+        @brief Inherited from ViewportEventListener - called if the camera changes.
+
+        Since the new camera could be in a different scene, the shader has to make sure
+        it deactivates or activates itself accordingly.
+
+        Additionally the shader has to be turned off and on even if the camera stays in
+        the same scene to fix a weird behavior of Ogre.
+    */
     void Shader::cameraChanged(Ogre::Viewport* viewport, Ogre::Camera* oldCamera)
     {
         if (!this->bLoadCompositor_ || !this->scenemanager_)
@@ -94,6 +100,9 @@
             Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, this->isVisible());
     }
 
+    /**
+        @brief Changes the compositor - default viewport.
+    */
     void Shader::changedCompositorName()
     {
         // For the moment, we get the viewport always from the graphics manager
@@ -102,231 +111,122 @@
         this->changedCompositorName(GraphicsManager::getInstance().getViewport());
     }
 
+    /**
+        @brief Changes the compositor.
+    */
     void Shader::changedCompositorName(Ogre::Viewport* viewport)
     {
         if (this->bLoadCompositor_)
         {
             assert(viewport);
-            if (!this->oldcompositorName_.empty())
+            if (this->compositorInstance_)
             {
+                // remove the old compositor, remove the listener
                 Ogre::CompositorManager::getSingleton().removeCompositor(viewport, this->oldcompositorName_);
+                this->compositorInstance_->removeListener(this);
                 this->compositorInstance_ = 0;
             }
             if (!this->compositorName_.empty())
             {
+                // add the new compositor
                 this->compositorInstance_ = Ogre::CompositorManager::getSingleton().addCompositor(viewport, this->compositorName_);
-                if (!this->compositorInstance_)
+                if (this->compositorInstance_)
+                {
+                    // register as listener if required
+                    if (this->registeredAsListener_)
+                        this->compositorInstance_->addListener(this);
+                    // set visibility according to the isVisible() and the camera/viewport
+                    if (viewport->getCamera())
+                        Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, this->isVisible() && viewport->getCamera() && this->scenemanager_ == viewport->getCamera()->getSceneManager());
+                }
+                else
                     COUT(2) << "Warning: Couldn't load compositor with name \"" << this->compositorName_ << "\"." << std::endl;
-                else if (viewport->getCamera())
-                    Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, this->isVisible() && viewport->getCamera() && this->scenemanager_ == viewport->getCamera()->getSceneManager());
             }
             this->oldcompositorName_ = this->compositorName_;
         }
     }
 
+    /**
+        @brief Changes the visibility of the shader. Doesn't free any resources if set to invisible.
+    */
     void Shader::updateVisibility()
     {
         if (this->compositorInstance_)
             Ogre::CompositorManager::getSingleton().setCompositorEnabled(GraphicsManager::getInstance().getViewport(), this->compositorName_, this->isVisible());
     }
 
-    void Shader::setParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter, float value)
+    /**
+        @brief Defines a new integer value for a given parameter. The parameter will be updated if the compositor is rendered the next time.
+    */
+    void Shader::setParameter(size_t technique, size_t pass, const std::string& parameter, int value)
     {
-        if (Shader::_setParameter(material, technique, pass, parameter, value))
-        {
-            if (this->compositorInstance_ && this->isVisible())
-            {
-                Ogre::CompositorManager::getSingleton().setCompositorEnabled(GraphicsManager::getInstance().getViewport(), this->compositorName_, false);
-                Ogre::CompositorManager::getSingleton().setCompositorEnabled(GraphicsManager::getInstance().getViewport(), this->compositorName_, true);
-            }
-        }
+        ParameterContainer container = {technique, pass, parameter, value, 0.0f, MT_Type::Int};
+        this->parameters_.push_back(container);
+        this->addAsListener();
     }
 
-    void Shader::setParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter, int value)
+    /**
+        @brief Defines a new float value for a given parameter. The parameter will be updated if the compositor is rendered the next time.
+    */
+    void Shader::setParameter(size_t technique, size_t pass, const std::string& parameter, float value)
     {
-        if (Shader::_setParameter(material, technique, pass, parameter, value))
-        {
-            if (this->compositorInstance_ && this->isVisible())
-            {
-                Ogre::CompositorManager::getSingleton().setCompositorEnabled(GraphicsManager::getInstance().getViewport(), this->compositorName_, false);
-                Ogre::CompositorManager::getSingleton().setCompositorEnabled(GraphicsManager::getInstance().getViewport(), this->compositorName_, true);
-            }
-        }
+        ParameterContainer container = {technique, pass, parameter, 0, value, MT_Type::Float};
+        this->parameters_.push_back(container);
+        this->addAsListener();
     }
 
-    /* static */ bool Shader::_setParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter, float value)
+    /**
+        @brief Registers the shader as CompositorInstance::Listener at the compositor. Used to change parameters.
+    */
+    void Shader::addAsListener()
     {
-        ParameterPointer* pointer = Shader::getParameterPointer(material, technique, pass, parameter);
-        if (pointer)
+        if (!this->registeredAsListener_)
         {
-            if (pointer->first)
-            {
-                if ((*static_cast<float*>(pointer->second)) != value)
-                {
-                    (*static_cast<float*>(pointer->second)) = value;
-                    return true;
-                }
-            }
-            else
-            {
-                if ((*static_cast<int*>(pointer->second)) != static_cast<int>(value))
-                {
-                    (*static_cast<int*>(pointer->second)) = static_cast<int>(value);
-                    return true;
-                }
-            }
+            this->registeredAsListener_ = true;
+            if (this->compositorInstance_)
+                this->compositorInstance_->addListener(this);
         }
-        return false;
     }
 
-    /* static */ bool Shader::_setParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter, int value)
+    /**
+        @brief Inherited by Ogre::CompositorInstance::Listener, called whenever the material is rendered. Used to change parameters.
+    */
+    void Shader::notifyMaterialRender(Ogre::uint32 pass_id, Ogre::MaterialPtr& materialPtr)
     {
-        ParameterPointer* pointer = Shader::getParameterPointer(material, technique, pass, parameter);
-        if (pointer)
+        // iterate through the list of parameters
+        for (std::list<ParameterContainer>::iterator it = this->parameters_.begin(); it != this->parameters_.end(); ++it)
         {
-            if (pointer->first)
+            Ogre::Technique* techniquePtr = materialPtr->getTechnique(it->technique_);
+            if (techniquePtr)
             {
-                if ((*static_cast<float*>(pointer->second)) != static_cast<float>(value))
+                Ogre::Pass* passPtr = techniquePtr->getPass(it->pass_);
+                if (passPtr)
                 {
-                    (*static_cast<float*>(pointer->second)) = static_cast<float>(value);
-                    return true;
+                    // change the value of the parameter depending on its type
+                    switch (it->valueType_)
+                    {
+                        case MT_Type::Int:
+                            passPtr->getFragmentProgramParameters()->setNamedConstant(it->parameter_, it->valueInt_);
+                            break;
+                        case MT_Type::Float:
+                            passPtr->getFragmentProgramParameters()->setNamedConstant(it->parameter_, it->valueFloat_);
+                            break;
+                        default:
+                            break;
+                    }
                 }
-            }
-            else
-            {
-                if ((*static_cast<int*>(pointer->second)) != value)
-                {
-                    (*static_cast<int*>(pointer->second)) = value;
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /* static */ float Shader::getParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter)
-    {
-        ParameterPointer* pointer = Shader::getParameterPointer(material, technique, pass, parameter);
-        if (pointer)
-        {
-            if (pointer->first)
-                return (*static_cast<float*>(pointer->second));
-            else
-                return static_cast<float>(*static_cast<int*>(pointer->second));
-        }
-        else
-            return 0;
-    }
-
-    /* static */ bool Shader::getParameterIsFloat(const std::string& material, size_t technique, size_t pass, const std::string& parameter)
-    {
-        ParameterPointer* pointer = Shader::getParameterPointer(material, technique, pass, parameter);
-        if (pointer)
-            return pointer->first;
-        else
-            return false;
-    }
-
-    /* static */ bool Shader::getParameterIsInt(const std::string& material, size_t technique, size_t pass, const std::string& parameter)
-    {
-        ParameterPointer* pointer = Shader::getParameterPointer(material, technique, pass, parameter);
-        if (pointer)
-            return (!pointer->first);
-        else
-            return false;
-    }
-
-    /* static */ Shader::ParameterPointer* Shader::getParameterPointer(const std::string& material, size_t technique, size_t pass, const std::string& parameter)
-    {
-        if (!GameMode::showsGraphics() || !Shader::bLoadedCgPlugin_s)
-            return 0;
-
-        MaterialMap::iterator material_iterator = Shader::parameters_s.find(material);
-        if (material_iterator != Shader::parameters_s.end())
-        {
-            TechniqueVector& technique_vector = material_iterator->second;
-            if (technique < technique_vector.size())
-            {
-                PassVector& pass_vector = technique_vector[technique];
-                if (pass < pass_vector.size())
-                {
-                    ParameterMap& parameter_map = pass_vector[pass];
-                    ParameterMap::iterator parameter_iterator = parameter_map.find(parameter);
-
-                    if (parameter_iterator != parameter_map.end())
-                        return (&parameter_iterator->second);
-                    else
-                        COUT(2) << "Warning: No shader parameter \"" << parameter << "\" in pass " << pass << " in technique " << technique << " in material \"" << material << "\"." << std::endl;
-                }
                 else
-                    COUT(2) << "Warning: No pass " << pass << " in technique " << technique << " in material \"" << material << "\" or pass has no shader." << std::endl;
+                    COUT(2) << "Warning: No pass " << it->pass_ << " in technique " << it->technique_ << " in compositor \"" << this->compositorName_ << "\" or pass has no shader." << std::endl;
             }
             else
-                COUT(2) << "Warning: No technique " << technique << " in material \"" << material << "\" or technique has no pass with shader." << std::endl;
+                COUT(2) << "Warning: No technique " << it->technique_ << " in compositor \"" << this->compositorName_ << "\" or technique has no pass with shader." << std::endl;
         }
-        else
-        {
-            bool foundAtLeastOneShaderParameter = false;
-            Ogre::MaterialManager::ResourceMapIterator iterator = Ogre::MaterialManager::getSingleton().getResourceIterator();
-            Ogre::Material* material_pointer = 0;
-
-            while (iterator.hasMoreElements())
-            {
-                Ogre::Resource* resource = iterator.getNext().get();
-                if (resource->getName() == material)
-                    material_pointer = (Ogre::Material*)resource;
-            }
-
-            if (!material_pointer)
-            {
-                COUT(2) << "Warning: No material with name \"" << material << "\" found." << std::endl;
-                return 0;
-            }
-
-            for (unsigned int t = 0; t < material_pointer->getNumTechniques(); ++t)
-            {
-                Ogre::Technique* technique_pointer = material_pointer->getTechnique(t);
-                if (!technique_pointer)
-                    continue;
-
-                for (unsigned int p = 0; p < technique_pointer->getNumPasses(); ++p)
-                {
-                    Ogre::Pass* pass_pointer = technique_pointer->getPass(p);
-                    if (!pass_pointer)
-                        continue;
-
-                    if (!pass_pointer->getFragmentProgramName().empty())
-                    {
-                        Ogre::GpuProgramParameters* parameter_pointer = pass_pointer->getFragmentProgramParameters().get();
-                        if (!parameter_pointer)
-                            continue;
-
-                        const Ogre::GpuConstantDefinitionMap& constant_definitions = parameter_pointer->getConstantDefinitions().map;
-                        for (Ogre::GpuConstantDefinitionMap::const_iterator definition_iterator = constant_definitions.begin(); definition_iterator != constant_definitions.end(); ++definition_iterator)
-                        {
-                            void* temp = (definition_iterator->second.isFloat())
-                                            ? static_cast<void*>(parameter_pointer->getFloatPointer(definition_iterator->second.physicalIndex))
-                                            : static_cast<void*>(parameter_pointer->getIntPointer(definition_iterator->second.physicalIndex));
-                            ParameterPointer parameter_pointer = ParameterPointer(definition_iterator->second.isFloat(), temp);
-
-                            TechniqueVector& technique_vector = Shader::parameters_s[material];
-                            technique_vector.resize(technique + 1);
-                            PassVector& pass_vector = technique_vector[technique];
-                            pass_vector.resize(pass + 1);
-                            pass_vector[pass][definition_iterator->first] = parameter_pointer;
-                            foundAtLeastOneShaderParameter = true;
-                        }
-                    }
-                }
-            }
-
-            // recursive call if the material was added to the map
-            if (foundAtLeastOneShaderParameter)
-                return Shader::getParameterPointer(material, technique, pass, parameter);
-        }
-        return 0;
+        this->parameters_.clear();
     }
 
+    /**
+        @brief Detects if the Cg program manager plugin is active.
+    */
     /* static */ bool Shader::hasCgProgramManager()
     {
         if (Ogre::Root::getSingletonPtr())

Modified: code/branches/usability/src/libraries/tools/Shader.h
===================================================================
--- code/branches/usability/src/libraries/tools/Shader.h	2011-02-26 20:53:23 UTC (rev 7975)
+++ code/branches/usability/src/libraries/tools/Shader.h	2011-02-27 00:05:59 UTC (rev 7976)
@@ -35,23 +35,24 @@
 #include <string>
 #include <vector>
 
+#include <OgreCompositorInstance.h>
+
 #include "util/OgreForwardRefs.h"
 #include "core/ViewportEventListener.h"
 
 namespace orxonox
 {
-    class _ToolsExport Shader : public ViewportEventListener
+    /**
+        @brief Shader is a wrapper class around Ogre::CompositorInstance. It provides some
+        functions to easily change the visibility and parameters for shader programs.
+    */
+    class _ToolsExport Shader : public ViewportEventListener, public Ogre::CompositorInstance::Listener
     {
-        typedef std::pair<bool, void*>                  ParameterPointer;
-        typedef std::map<std::string, ParameterPointer> ParameterMap;
-        typedef std::vector<ParameterMap>               PassVector;
-        typedef std::vector<PassVector>                 TechniqueVector;
-        typedef std::map<std::string, TechniqueVector>  MaterialMap;
-
         public:
             Shader(Ogre::SceneManager* scenemanager = 0);
             virtual ~Shader();
 
+            /// Defines if the shader is visible or not.
             inline void setVisible(bool bVisible)
             {
                 if (this->bVisible_ != bVisible)
@@ -60,10 +61,12 @@
                     this->updateVisibility();
                 }
             }
+            /// Returns whether or not the shader is visible.
             inline bool isVisible() const
                 { return this->bVisible_; }
             void updateVisibility();
 
+            /// Defines the compositor's name (located in a .compositor file).
             inline void setCompositorName(const std::string& name)
             {
                 if (this->compositorName_ != name)
@@ -72,40 +75,54 @@
                     this->changedCompositorName();
                 }
             }
+            /// Returns the compositor's name.
             inline const std::string& getCompositorName() const
                 { return this->compositorName_; }
             void changedCompositorName();
             void changedCompositorName(Ogre::Viewport* viewport);
 
+            /// Sets the scenemanager (usually provided in the constructor, but can be set later). Shouldn't be changed once it's set.
             inline void setSceneManager(Ogre::SceneManager* scenemanager)
                 { this->scenemanager_ = scenemanager; }
+            /// Returns the scene manager.
             inline Ogre::SceneManager* getSceneManager() const
                 { return this->scenemanager_; }
 
             virtual void cameraChanged(Ogre::Viewport* viewport, Ogre::Camera* oldCamera);
 
-            void setParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter, float value);
-            void setParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter, int value);
+            void setParameter(size_t technique, size_t pass, const std::string& parameter, float value);
+            void setParameter(size_t technique, size_t pass, const std::string& parameter, int value);
 
-            static bool _setParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter, float value);
-            static bool _setParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter, int value);
-            static float getParameter(const std::string& material, size_t technique, size_t pass, const std::string& parameter);
-            static bool  getParameterIsFloat(const std::string& material, size_t technique, size_t pass, const std::string& parameter);
-            static bool  getParameterIsInt  (const std::string& material, size_t technique, size_t pass, const std::string& parameter);
-            static ParameterPointer* getParameterPointer(const std::string& material, size_t technique, size_t pass, const std::string& parameter);
+            virtual void notifyMaterialRender(Ogre::uint32 pass_id, Ogre::MaterialPtr& materialPtr);
 
         private:
             static bool hasCgProgramManager();
 
-            Ogre::SceneManager* scenemanager_;
-            Ogre::CompositorInstance* compositorInstance_;
-            bool bVisible_;
-            bool bLoadCompositor_;
-            std::string compositorName_;
-            std::string oldcompositorName_;
+            Ogre::SceneManager* scenemanager_;              ///< The scenemanager for which the shader is active
+            Ogre::CompositorInstance* compositorInstance_;  ///< The compositor instance representing the wrapped compositor
+            bool bVisible_;                                 ///< True if the shader should be visible
+            bool bLoadCompositor_;                          ///< True if the compositor should be loaded (usually false if no graphics)
+            std::string compositorName_;                    ///< The name of the current compositor
+            std::string oldcompositorName_;                 ///< The name of the previous compositor (used to unregister)
 
-            static MaterialMap parameters_s;
-            static bool bLoadedCgPlugin_s;
+        private:
+            void addAsListener();
+
+            /// Helper struct to store parameters for shader programs.
+            struct ParameterContainer
+            {
+                size_t technique_;          ///< The ID of the technique
+                size_t pass_;               ///< The ID of the pass
+                std::string parameter_;     ///< The name of the parameter
+
+                int valueInt_;              ///< The desired int value of the parameter
+                float valueFloat_;          ///< The desired float value of the parameter
+
+                MT_Type::Value valueType_;  ///< The type of the parameter (currently only int or float)
+            };
+
+            std::list<ParameterContainer> parameters_;  ///< The list of parameters that should be set on the next update
+            bool registeredAsListener_;                 ///< True if the shader should register itself as listener at the compositor
     };
 }
 

Modified: code/branches/usability/src/orxonox/items/Engine.cc
===================================================================
--- code/branches/usability/src/orxonox/items/Engine.cc	2011-02-26 20:53:23 UTC (rev 7975)
+++ code/branches/usability/src/orxonox/items/Engine.cc	2011-02-27 00:05:59 UTC (rev 7976)
@@ -206,11 +206,11 @@
         if (!this->boostBlur_ && this->ship_->hasLocalController() && this->ship_->hasHumanController())
         {
             this->boostBlur_ = new Shader(this->ship_->getScene()->getSceneManager());
-            this->boostBlur_->setCompositor("Radial Blur");
+            this->boostBlur_->setCompositorName("Radial Blur");
         }
 
         if (this->boostBlur_ && this->maxSpeedFront_ != 0 && this->boostFactor_ != 1)
-            this->boostBlur_->setParameter("Ogre/Compositor/Radial_Blur", 0, 0, "sampleStrength", this->blurStrength_ * clamp((-velocity.z - this->maxSpeedFront_) / ((this->boostFactor_ - 1) * this->maxSpeedFront_), 0.0f, 1.0f));
+            this->boostBlur_->setParameter(0, 0, "sampleStrength", this->blurStrength_ * clamp((-velocity.z - this->maxSpeedFront_) / ((this->boostFactor_ - 1) * this->maxSpeedFront_), 0.0f, 1.0f));
     }
 
     void Engine::changedActivity()




More information about the Orxonox-commit mailing list