Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutorial/src/libraries/tools/Shader.cc @ 9215

Last change on this file since 9215 was 7976, checked in by landauf, 14 years ago

rewrote parameter changing implementation of Shader
added documentation

  • Property svn:eol-style set to native
File size: 9.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "Shader.h"
30
31#include <OgreCompositorManager.h>
32#include <OgreRoot.h>
33#include <OgrePlugin.h>
34
35#include "core/CoreIncludes.h"
36#include "core/GameMode.h"
37#include "core/GraphicsManager.h"
38
39namespace orxonox
40{
41    /**
42        @brief Initializes the values and sets the scene manager.
43    */
44    Shader::Shader(Ogre::SceneManager* scenemanager) : compositorInstance_(0)
45    {
46        RegisterObject(Shader);
47
48        this->scenemanager_ = scenemanager;
49        this->bVisible_ = true;
50        this->bLoadCompositor_ = GameMode::showsGraphics();
51        this->registeredAsListener_ = false;
52
53        static bool hasCgProgramManager = Shader::hasCgProgramManager();
54
55        this->bLoadCompositor_ &= hasCgProgramManager;
56    }
57
58    /**
59        @brief Removes the compositor and frees the resources.
60    */
61    Shader::~Shader()
62    {
63        if (this->compositorInstance_ && GraphicsManager::getInstance().getViewport())
64            Ogre::CompositorManager::getSingleton().removeCompositor(GraphicsManager::getInstance().getViewport(), this->compositorName_);
65    }
66
67    /**
68        @brief Inherited from ViewportEventListener - called if the camera changes.
69
70        Since the new camera could be in a different scene, the shader has to make sure
71        it deactivates or activates itself accordingly.
72
73        Additionally the shader has to be turned off and on even if the camera stays in
74        the same scene to fix a weird behavior of Ogre.
75    */
76    void Shader::cameraChanged(Ogre::Viewport* viewport, Ogre::Camera* oldCamera)
77    {
78        if (!this->bLoadCompositor_ || !this->scenemanager_)
79            return;
80
81        // load the compositor if not already done
82        if (!this->compositorName_.empty() && !this->compositorInstance_)
83            this->changedCompositorName(viewport);
84
85        // update compositor in viewport (shader should only be active if the current camera is in the same scene as the shader)
86
87        // Note:
88        // The shader needs also to be switched off and on after changing the camera in the
89        // same scene to avoid weird behaviour with active compositors while switching the
90        // camera (like freezing the image)
91        //
92        // Last known Ogre version needing this workaround:
93        // 1.4.8
94        // 1.7.2
95
96        if (oldCamera && this->scenemanager_ == oldCamera->getSceneManager())
97            Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, false);
98
99        if (viewport->getCamera() && this->scenemanager_ == viewport->getCamera()->getSceneManager())
100            Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, this->isVisible());
101    }
102
103    /**
104        @brief Changes the compositor - default viewport.
105    */
106    void Shader::changedCompositorName()
107    {
108        // For the moment, we get the viewport always from the graphics manager
109        // TODO: Try to support multiple viewports - note however that scenemanager_->getCurrentViewport() returns NULL
110        //       after switching to a camera in a different scene (only for the first time this scene is displayed though)
111        this->changedCompositorName(GraphicsManager::getInstance().getViewport());
112    }
113
114    /**
115        @brief Changes the compositor.
116    */
117    void Shader::changedCompositorName(Ogre::Viewport* viewport)
118    {
119        if (this->bLoadCompositor_)
120        {
121            assert(viewport);
122            if (this->compositorInstance_)
123            {
124                // remove the old compositor, remove the listener
125                Ogre::CompositorManager::getSingleton().removeCompositor(viewport, this->oldcompositorName_);
126                this->compositorInstance_->removeListener(this);
127                this->compositorInstance_ = 0;
128            }
129            if (!this->compositorName_.empty())
130            {
131                // add the new compositor
132                this->compositorInstance_ = Ogre::CompositorManager::getSingleton().addCompositor(viewport, this->compositorName_);
133                if (this->compositorInstance_)
134                {
135                    // register as listener if required
136                    if (this->registeredAsListener_)
137                        this->compositorInstance_->addListener(this);
138                    // set visibility according to the isVisible() and the camera/viewport
139                    if (viewport->getCamera())
140                        Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, this->isVisible() && viewport->getCamera() && this->scenemanager_ == viewport->getCamera()->getSceneManager());
141                }
142                else
143                    COUT(2) << "Warning: Couldn't load compositor with name \"" << this->compositorName_ << "\"." << std::endl;
144            }
145            this->oldcompositorName_ = this->compositorName_;
146        }
147    }
148
149    /**
150        @brief Changes the visibility of the shader. Doesn't free any resources if set to invisible.
151    */
152    void Shader::updateVisibility()
153    {
154        if (this->compositorInstance_)
155            Ogre::CompositorManager::getSingleton().setCompositorEnabled(GraphicsManager::getInstance().getViewport(), this->compositorName_, this->isVisible());
156    }
157
158    /**
159        @brief Defines a new integer value for a given parameter. The parameter will be updated if the compositor is rendered the next time.
160    */
161    void Shader::setParameter(size_t technique, size_t pass, const std::string& parameter, int value)
162    {
163        ParameterContainer container = {technique, pass, parameter, value, 0.0f, MT_Type::Int};
164        this->parameters_.push_back(container);
165        this->addAsListener();
166    }
167
168    /**
169        @brief Defines a new float value for a given parameter. The parameter will be updated if the compositor is rendered the next time.
170    */
171    void Shader::setParameter(size_t technique, size_t pass, const std::string& parameter, float value)
172    {
173        ParameterContainer container = {technique, pass, parameter, 0, value, MT_Type::Float};
174        this->parameters_.push_back(container);
175        this->addAsListener();
176    }
177
178    /**
179        @brief Registers the shader as CompositorInstance::Listener at the compositor. Used to change parameters.
180    */
181    void Shader::addAsListener()
182    {
183        if (!this->registeredAsListener_)
184        {
185            this->registeredAsListener_ = true;
186            if (this->compositorInstance_)
187                this->compositorInstance_->addListener(this);
188        }
189    }
190
191    /**
192        @brief Inherited by Ogre::CompositorInstance::Listener, called whenever the material is rendered. Used to change parameters.
193    */
194    void Shader::notifyMaterialRender(Ogre::uint32 pass_id, Ogre::MaterialPtr& materialPtr)
195    {
196        // iterate through the list of parameters
197        for (std::list<ParameterContainer>::iterator it = this->parameters_.begin(); it != this->parameters_.end(); ++it)
198        {
199            Ogre::Technique* techniquePtr = materialPtr->getTechnique(it->technique_);
200            if (techniquePtr)
201            {
202                Ogre::Pass* passPtr = techniquePtr->getPass(it->pass_);
203                if (passPtr)
204                {
205                    // change the value of the parameter depending on its type
206                    switch (it->valueType_)
207                    {
208                        case MT_Type::Int:
209                            passPtr->getFragmentProgramParameters()->setNamedConstant(it->parameter_, it->valueInt_);
210                            break;
211                        case MT_Type::Float:
212                            passPtr->getFragmentProgramParameters()->setNamedConstant(it->parameter_, it->valueFloat_);
213                            break;
214                        default:
215                            break;
216                    }
217                }
218                else
219                    COUT(2) << "Warning: No pass " << it->pass_ << " in technique " << it->technique_ << " in compositor \"" << this->compositorName_ << "\" or pass has no shader." << std::endl;
220            }
221            else
222                COUT(2) << "Warning: No technique " << it->technique_ << " in compositor \"" << this->compositorName_ << "\" or technique has no pass with shader." << std::endl;
223        }
224        this->parameters_.clear();
225    }
226
227    /**
228        @brief Detects if the Cg program manager plugin is active.
229    */
230    /* static */ bool Shader::hasCgProgramManager()
231    {
232        if (Ogre::Root::getSingletonPtr())
233        {
234            const Ogre::Root::PluginInstanceList& plugins = Ogre::Root::getSingleton().getInstalledPlugins();
235            for (size_t i = 0; i < plugins.size(); ++i)
236                if (plugins[i]->getName() == "Cg Program Manager")
237                    return true;
238        }
239        return false;
240    }
241}
Note: See TracBrowser for help on using the repository browser.