Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/tools/Shader.cc @ 11853

Last change on this file since 11853 was 11071, checked in by landauf, 9 years ago

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 9.5 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    RegisterClassNoArgs(Shader);
42
43    /**
44        @brief Initializes the values and sets the scene manager.
45    */
46    Shader::Shader(Ogre::SceneManager* scenemanager) : compositorInstance_(nullptr)
47    {
48        RegisterObject(Shader);
49
50        this->scenemanager_ = scenemanager;
51        this->bVisible_ = true;
52        this->bLoadCompositor_ = GameMode::showsGraphics();
53        this->registeredAsListener_ = false;
54
55        static bool hasCgProgramManager = Shader::hasCgProgramManager();
56
57        this->bLoadCompositor_ &= hasCgProgramManager;
58    }
59
60    /**
61        @brief Removes the compositor and frees the resources.
62    */
63    Shader::~Shader()
64    {
65        if (this->compositorInstance_ && GraphicsManager::getInstance().getViewport())
66            Ogre::CompositorManager::getSingleton().removeCompositor(GraphicsManager::getInstance().getViewport(), this->compositorName_);
67    }
68
69    /**
70        @brief Inherited from ViewportEventListener - called if the camera changes.
71
72        Since the new camera could be in a different scene, the shader has to make sure
73        it deactivates or activates itself accordingly.
74
75        Additionally the shader has to be turned off and on even if the camera stays in
76        the same scene to fix a weird behavior of Ogre.
77    */
78    void Shader::cameraChanged(Ogre::Viewport* viewport, Ogre::Camera* oldCamera)
79    {
80        if (!this->bLoadCompositor_ || !this->scenemanager_)
81            return;
82
83        // load the compositor if not already done
84        if (!this->compositorName_.empty() && !this->compositorInstance_)
85            this->changedCompositorName(viewport);
86
87        // update compositor in viewport (shader should only be active if the current camera is in the same scene as the shader)
88
89        // Note:
90        // The shader needs also to be switched off and on after changing the camera in the
91        // same scene to avoid weird behaviour with active compositors while switching the
92        // camera (like freezing the image)
93        //
94        // Last known Ogre version needing this workaround:
95        // 1.4.8
96        // 1.7.2
97
98        if (oldCamera && this->scenemanager_ == oldCamera->getSceneManager())
99            Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, false);
100
101        if (viewport->getCamera() && this->scenemanager_ == viewport->getCamera()->getSceneManager())
102            Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, this->isVisible());
103    }
104
105    /**
106        @brief Changes the compositor - default viewport.
107    */
108    void Shader::changedCompositorName()
109    {
110        // For the moment, we get the viewport always from the graphics manager
111        // TODO: Try to support multiple viewports - note however that scenemanager_->getCurrentViewport() returns nullptr
112        //       after switching to a camera in a different scene (only for the first time this scene is displayed though)
113        this->changedCompositorName(GraphicsManager::getInstance().getViewport());
114    }
115
116    /**
117        @brief Changes the compositor.
118    */
119    void Shader::changedCompositorName(Ogre::Viewport* viewport)
120    {
121        if (this->bLoadCompositor_)
122        {
123            assert(viewport);
124            if (this->compositorInstance_)
125            {
126                // remove the old compositor, remove the listener
127                Ogre::CompositorManager::getSingleton().removeCompositor(viewport, this->oldcompositorName_);
128                this->compositorInstance_->removeListener(this);
129                this->compositorInstance_ = nullptr;
130            }
131            if (!this->compositorName_.empty())
132            {
133                // add the new compositor
134                this->compositorInstance_ = Ogre::CompositorManager::getSingleton().addCompositor(viewport, this->compositorName_);
135                if (this->compositorInstance_)
136                {
137                    // register as listener if required
138                    if (this->registeredAsListener_)
139                        this->compositorInstance_->addListener(this);
140                    // set visibility according to the isVisible() and the camera/viewport
141                    if (viewport->getCamera())
142                        Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, this->compositorName_, this->isVisible() && viewport->getCamera() && this->scenemanager_ == viewport->getCamera()->getSceneManager());
143                }
144                else
145                    orxout(internal_warning) << "Couldn't load compositor with name \"" << this->compositorName_ << "\"." << endl;
146            }
147            this->oldcompositorName_ = this->compositorName_;
148        }
149    }
150
151    /**
152        @brief Changes the visibility of the shader. Doesn't free any resources if set to invisible.
153    */
154    void Shader::updateVisibility()
155    {
156        if (this->compositorInstance_)
157            Ogre::CompositorManager::getSingleton().setCompositorEnabled(GraphicsManager::getInstance().getViewport(), this->compositorName_, this->isVisible());
158    }
159
160    /**
161        @brief Defines a new integer value for a given parameter. The parameter will be updated if the compositor is rendered the next time.
162    */
163    void Shader::setParameter(unsigned short technique, unsigned short pass, const std::string& parameter, int value)
164    {
165        ParameterContainer container = {technique, pass, parameter, value};
166        this->parameters_.push_back(container);
167        this->addAsListener();
168    }
169
170    /**
171        @brief Defines a new float value for a given parameter. The parameter will be updated if the compositor is rendered the next time.
172    */
173    void Shader::setParameter(unsigned short technique, unsigned short pass, const std::string& parameter, float value)
174    {
175        ParameterContainer container = {technique, pass, parameter, value};
176        this->parameters_.push_back(container);
177        this->addAsListener();
178    }
179
180    /**
181        @brief Registers the shader as CompositorInstance::Listener at the compositor. Used to change parameters.
182    */
183    void Shader::addAsListener()
184    {
185        if (!this->registeredAsListener_)
186        {
187            this->registeredAsListener_ = true;
188            if (this->compositorInstance_)
189                this->compositorInstance_->addListener(this);
190        }
191    }
192
193    /**
194        @brief Inherited by Ogre::CompositorInstance::Listener, called whenever the material is rendered. Used to change parameters.
195    */
196    void Shader::notifyMaterialRender(Ogre::uint32 pass_id, Ogre::MaterialPtr& materialPtr)
197    {
198        // iterate through the list of parameters
199        for (const ParameterContainer& parameter : this->parameters_)
200        {
201            Ogre::Technique* techniquePtr = materialPtr->getTechnique(parameter.technique_);
202            if (techniquePtr)
203            {
204                Ogre::Pass* passPtr = techniquePtr->getPass(parameter.pass_);
205                if (passPtr)
206                {
207                    // change the value of the parameter depending on its type
208                    if (parameter.value_.isType<int>())
209                        passPtr->getFragmentProgramParameters()->setNamedConstant(parameter.parameter_, parameter.value_.get<int>());
210                    else if (parameter.value_.isType<float>())
211                        passPtr->getFragmentProgramParameters()->setNamedConstant(parameter.parameter_, parameter.value_.get<float>());
212                }
213                else
214                    orxout(internal_warning) << "No pass " << parameter.pass_ << " in technique " << parameter.technique_ << " in compositor \"" << this->compositorName_ << "\" or pass has no shader." << endl;
215            }
216            else
217                orxout(internal_warning) << "No technique " << parameter.technique_ << " in compositor \"" << this->compositorName_ << "\" or technique has no pass with shader." << endl;
218        }
219        this->parameters_.clear();
220    }
221
222    /**
223        @brief Detects if the Cg program manager plugin is active.
224    */
225    /* static */ bool Shader::hasCgProgramManager()
226    {
227        if (Ogre::Root::getSingletonPtr())
228        {
229            const Ogre::Root::PluginInstanceList& plugins = Ogre::Root::getSingleton().getInstalledPlugins();
230            for (Ogre::Plugin* plugin : plugins)
231                if (plugin->getName() == "Cg Program Manager")
232                    return true;
233        }
234        return false;
235    }
236}
Note: See TracBrowser for help on using the repository browser.