Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreCompositorChain.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 14.9 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30#include "OgreCompositorChain.h"
31#include "OgreCompositionTechnique.h"
32#include "OgreCompositorInstance.h"
33#include "OgreCompositionTargetPass.h"
34#include "OgreCompositionPass.h"
35#include "OgreViewport.h"
36#include "OgreCamera.h"
37#include "OgreRenderTarget.h"
38#include "OgreLogManager.h"
39#include "OgreCompositorManager.h"
40#include "OgreSceneManager.h"
41#include "OgreRenderQueueInvocation.h"
42namespace Ogre {
43CompositorChain::CompositorChain(Viewport *vp):
44    mViewport(vp),
45        mOriginalScene(0),
46    mDirty(true),
47        mAnyCompositorsEnabled(false)
48{
49        mOldClearEveryFrameBuffers = mViewport->getClearBuffers();
50    assert(mViewport);
51}
52//-----------------------------------------------------------------------
53CompositorChain::~CompositorChain()
54{
55        destroyResources();
56}
57//-----------------------------------------------------------------------
58void CompositorChain::destroyResources(void)
59{
60        clearCompiledState();
61
62        if (mViewport)
63        {
64                removeAllCompositors();
65                mViewport->getTarget()->removeListener(this);
66                /// Destroy "original scene" compositor instance
67                if (mOriginalScene)
68                {
69                        mOriginalScene->getTechnique()->destroyInstance(mOriginalScene);
70                        mOriginalScene = 0;
71                }
72                mViewport = 0;
73        }
74}
75//-----------------------------------------------------------------------
76CompositorInstance* CompositorChain::addCompositor(CompositorPtr filter, size_t addPosition, size_t technique)
77{
78        // Init on demand
79        if (!mOriginalScene)
80        {
81                mViewport->getTarget()->addListener(this);
82               
83                /// Create base "original scene" compositor
84                CompositorPtr base = CompositorManager::getSingleton().load("Ogre/Scene",
85                        ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
86                mOriginalScene = base->getSupportedTechnique(0)->createInstance(this);
87        }
88
89
90        filter->touch();
91    if(technique >= filter->getNumSupportedTechniques())
92    {
93        /// Warn user
94        LogManager::getSingleton().logMessage(
95            "CompositorChain: Compositor " + filter->getName() + " has no supported techniques.", LML_CRITICAL
96        );
97        return 0;
98    }
99    CompositionTechnique *tech = filter->getSupportedTechnique(technique);
100    CompositorInstance *t = tech->createInstance(this);
101   
102    if(addPosition == LAST)
103        addPosition = mInstances.size();
104    else
105        assert(addPosition <= mInstances.size() && "Index out of bounds.");
106    mInstances.insert(mInstances.begin()+addPosition, t);
107   
108    mDirty = true;
109        mAnyCompositorsEnabled = true;
110    return t;
111}
112//-----------------------------------------------------------------------
113void CompositorChain::removeCompositor(size_t index)
114{
115    assert (index < mInstances.size() && "Index out of bounds.");
116    Instances::iterator i = mInstances.begin() + index;
117    (*i)->getTechnique()->destroyInstance(*i);
118    mInstances.erase(i);
119   
120    mDirty = true;
121}
122//-----------------------------------------------------------------------
123size_t CompositorChain::getNumCompositors()
124{
125    return mInstances.size();
126}
127//-----------------------------------------------------------------------
128void CompositorChain::removeAllCompositors()
129{
130    Instances::iterator i, iend;
131    iend = mInstances.end();
132    for (i = mInstances.begin(); i != iend; ++i)
133    {
134        (*i)->getTechnique()->destroyInstance(*i);
135    }
136    mInstances.clear();
137   
138    mDirty = true;
139}
140//-----------------------------------------------------------------------
141void CompositorChain::_removeInstance(CompositorInstance *i)
142{
143        mInstances.erase(std::find(mInstances.begin(), mInstances.end(), i));
144        i->getTechnique()->destroyInstance(i);
145}
146//-----------------------------------------------------------------------
147void CompositorChain::_queuedOperation(CompositorInstance::RenderSystemOperation* op)
148{
149        mRenderSystemOperations.push_back(op);
150
151}
152//-----------------------------------------------------------------------
153CompositorInstance *CompositorChain::getCompositor(size_t index)
154{
155    assert (index < mInstances.size() && "Index out of bounds.");
156    return mInstances[index];
157}
158
159//-----------------------------------------------------------------------
160CompositorChain::InstanceIterator CompositorChain::getCompositors()
161{
162    return InstanceIterator(mInstances.begin(), mInstances.end());
163}
164//-----------------------------------------------------------------------
165void CompositorChain::setCompositorEnabled(size_t position, bool state)
166{
167    getCompositor(position)->setEnabled(state);
168}
169//-----------------------------------------------------------------------
170void CompositorChain::preRenderTargetUpdate(const RenderTargetEvent& evt)
171{
172        /// Compile if state is dirty
173        if(mDirty)
174                _compile();
175
176        // Do nothing if no compositors enabled
177        if (!mAnyCompositorsEnabled)
178        {
179                return;
180        }
181
182
183        /// Update dependent render targets; this is done in the preRenderTarget
184        /// and not the preViewportUpdate for a reason: at this time, the
185        /// target Rendertarget will not yet have been set as current.
186        /// ( RenderSystem::setViewport(...) ) if it would have been, the rendering
187        /// order would be screwed up and problems would arise with copying rendertextures.
188    Camera *cam = mViewport->getCamera();
189    /// Iterate over compiled state
190    CompositorInstance::CompiledState::iterator i;
191    for(i=mCompiledState.begin(); i!=mCompiledState.end(); ++i)
192    {
193                /// Skip if this is a target that should only be initialised initially
194                if(i->onlyInitial && i->hasBeenRendered)
195                        continue;
196                i->hasBeenRendered = true;
197                /// Setup and render
198        preTargetOperation(*i, i->target->getViewport(0), cam);
199        i->target->update();
200        postTargetOperation(*i, i->target->getViewport(0), cam);
201    }
202}
203//-----------------------------------------------------------------------
204void CompositorChain::preViewportUpdate(const RenderTargetViewportEvent& evt)
205{
206        // Only set up if there is at least one compositor enabled, and it's this viewport
207    if(evt.source != mViewport || !mAnyCompositorsEnabled)
208        return;
209
210        // set original scene details from viewport
211        CompositionPass* pass = mOriginalScene->getTechnique()->getOutputTargetPass()->getPass(0);
212        CompositionTargetPass* passParent = pass->getParent();
213        if (pass->getClearBuffers() != mViewport->getClearBuffers() ||
214                pass->getClearColour() != mViewport->getBackgroundColour() ||
215                passParent->getVisibilityMask() != mViewport->getVisibilityMask() ||
216                passParent->getMaterialScheme() != mViewport->getMaterialScheme() ||
217                passParent->getShadowsEnabled() != mViewport->getShadowsEnabled())
218        {
219                // recompile if viewport settings are different
220                pass->setClearBuffers(mViewport->getClearBuffers());
221                pass->setClearColour(mViewport->getBackgroundColour());
222                passParent->setVisibilityMask(mViewport->getVisibilityMask());
223                passParent->setMaterialScheme(mViewport->getMaterialScheme());
224                passParent->setShadowsEnabled(mViewport->getShadowsEnabled());
225                _compile();
226        }
227
228        Camera *cam = mViewport->getCamera();
229        /// Prepare for output operation
230        preTargetOperation(mOutputOperation, mViewport, cam);
231}
232//-----------------------------------------------------------------------
233void CompositorChain::preTargetOperation(CompositorInstance::TargetOperation &op, Viewport *vp, Camera *cam)
234{
235    SceneManager *sm = cam->getSceneManager();
236        /// Set up render target listener
237        mOurListener.setOperation(&op, sm, sm->getDestinationRenderSystem());
238        mOurListener.notifyViewport(vp);
239        /// Register it
240        sm->addRenderQueueListener(&mOurListener);
241        /// Set visiblity mask
242        mOldVisibilityMask = sm->getVisibilityMask();
243        sm->setVisibilityMask(op.visibilityMask);
244        /// Set whether we find visibles
245        mOldFindVisibleObjects = sm->getFindVisibleObjects();
246        sm->setFindVisibleObjects(op.findVisibleObjects);
247    /// Set LOD bias level
248    mOldLodBias = cam->getLodBias();
249    cam->setLodBias(cam->getLodBias() * op.lodBias);
250        /// Set material scheme
251        mOldMaterialScheme = vp->getMaterialScheme();
252        vp->setMaterialScheme(op.materialScheme);
253        /// Set shadows enabled
254        mOldShadowsEnabled = vp->getShadowsEnabled();
255        vp->setShadowsEnabled(op.shadowsEnabled);
256    /// XXX TODO
257    //vp->setClearEveryFrame( true );
258    //vp->setOverlaysEnabled( false );
259    //vp->setBackgroundColour( op.clearColour );
260}
261//-----------------------------------------------------------------------
262void CompositorChain::postTargetOperation(CompositorInstance::TargetOperation &op, Viewport *vp, Camera *cam)
263{
264    SceneManager *sm = cam->getSceneManager();
265        /// Unregister our listener
266        sm->removeRenderQueueListener(&mOurListener);
267        /// Flush remaing operations
268        mOurListener.flushUpTo((uint8)RENDER_QUEUE_COUNT);
269        /// Restore default scene and camera settings
270        sm->setVisibilityMask(mOldVisibilityMask);
271        sm->setFindVisibleObjects(mOldFindVisibleObjects);
272    cam->setLodBias(mOldLodBias);
273        vp->setMaterialScheme(mOldMaterialScheme);
274        vp->setShadowsEnabled(mOldShadowsEnabled);
275}
276//-----------------------------------------------------------------------
277void CompositorChain::postViewportUpdate(const RenderTargetViewportEvent& evt)
278{
279        // Only tidy up if there is at least one compositor enabled, and it's this viewport
280    if(evt.source != mViewport || !mAnyCompositorsEnabled)
281        return;
282
283        postTargetOperation(mOutputOperation, mViewport, mViewport->getCamera());
284}
285//-----------------------------------------------------------------------
286void CompositorChain::viewportRemoved(const RenderTargetViewportEvent& evt)
287{
288        // this chain is now orphaned
289        // can't delete it since held from outside, but release all resources being used
290        destroyResources();
291
292}
293//-----------------------------------------------------------------------
294void CompositorChain::clearCompiledState()
295{
296        for (RenderSystemOperations::iterator i = mRenderSystemOperations.begin();
297                i != mRenderSystemOperations.end(); ++i)
298        {
299                delete *i;
300        }
301        mRenderSystemOperations.clear();
302
303        /// Clear compiled state
304        mCompiledState.clear();
305        mOutputOperation = CompositorInstance::TargetOperation(0);
306
307}
308//-----------------------------------------------------------------------
309void CompositorChain::_compile()
310{
311        clearCompiledState();
312
313        bool compositorsEnabled = false;
314
315    /// Set previous CompositorInstance for each compositor in the list
316    CompositorInstance *lastComposition = mOriginalScene;
317        mOriginalScene->mPreviousInstance = 0;
318        CompositionPass* pass = mOriginalScene->getTechnique()->getOutputTargetPass()->getPass(0);
319        pass->setClearBuffers(mViewport->getClearBuffers());
320        pass->setClearColour(mViewport->getBackgroundColour());
321    for(Instances::iterator i=mInstances.begin(); i!=mInstances.end(); ++i)
322    {
323        if((*i)->getEnabled())
324        {
325                        compositorsEnabled = true;
326            (*i)->mPreviousInstance = lastComposition;
327            lastComposition = (*i);
328        }
329    }
330   
331
332    /// Compile misc targets
333    lastComposition->_compileTargetOperations(mCompiledState);
334   
335    /// Final target viewport (0)
336        mOutputOperation.renderSystemOperations.clear();
337    lastComposition->_compileOutputOperation(mOutputOperation);
338
339        // Deal with viewport settings
340        if (compositorsEnabled != mAnyCompositorsEnabled)
341        {
342                mAnyCompositorsEnabled = compositorsEnabled;
343                if (mAnyCompositorsEnabled)
344                {
345                        // Save old viewport clearing options
346                        mOldClearEveryFrameBuffers = mViewport->getClearBuffers();
347                        // Don't clear anything every frame since we have our own clear ops
348                        mViewport->setClearEveryFrame(false);
349                }
350                else
351                {
352                        // Reset clearing options
353                        mViewport->setClearEveryFrame(mOldClearEveryFrameBuffers > 0, 
354                                mOldClearEveryFrameBuffers);
355                }
356        }
357   
358    mDirty = false;
359}
360//-----------------------------------------------------------------------
361void CompositorChain::_markDirty()
362{
363    mDirty = true;
364}
365//-----------------------------------------------------------------------
366Viewport *CompositorChain::getViewport()
367{
368    return mViewport;
369}
370//-----------------------------------------------------------------------
371void CompositorChain::RQListener::renderQueueStarted(uint8 id, 
372        const String& invocation, bool& skipThisQueue)
373{
374        // Skip when not matching viewport
375        // shadows update is nested within main viewport update
376        if (mSceneManager->getCurrentViewport() != mViewport)
377                return;
378
379        flushUpTo(id);
380        /// If noone wants to render this queue, skip it
381        /// Don't skip the OVERLAY queue because that's handled seperately
382        if(!mOperation->renderQueues.test(id) && id!=RENDER_QUEUE_OVERLAY)
383        {
384                skipThisQueue = true;
385        }
386}
387//-----------------------------------------------------------------------
388void CompositorChain::RQListener::renderQueueEnded(uint8 id, 
389        const String& invocation, bool& repeatThisQueue)
390{
391}
392//-----------------------------------------------------------------------
393void CompositorChain::RQListener::setOperation(CompositorInstance::TargetOperation *op,SceneManager *sm,RenderSystem *rs)
394{
395        mOperation = op;
396        mSceneManager = sm;
397        mRenderSystem = rs;
398        currentOp = op->renderSystemOperations.begin();
399        lastOp = op->renderSystemOperations.end();
400}
401//-----------------------------------------------------------------------
402void CompositorChain::RQListener::flushUpTo(uint8 id)
403{
404        /// Process all RenderSystemOperations up to and including render queue id.
405    /// Including, because the operations for RenderQueueGroup x should be executed
406        /// at the beginning of the RenderQueueGroup render for x.
407        while(currentOp != lastOp && currentOp->first <= id)
408        {
409                currentOp->second->execute(mSceneManager, mRenderSystem);
410                ++currentOp;
411        }
412}
413//-----------------------------------------------------------------------
414}
Note: See TracBrowser for help on using the repository browser.