1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "OgreStableHeaders.h"
29 #include "OgreCompositor.h"
30 #include "OgreCompositorChain.h"
31 #include "OgreCompositionTechnique.h"
32 #include "OgreCompositorInstance.h"
33 #include "OgreCompositionTargetPass.h"
34 #include "OgreCompositionPass.h"
35 #include "OgreCompositorManager.h"
36 #include "OgreRenderTarget.h"
37
38 namespace Ogre {
CompositorChain(Viewport * vp)39 CompositorChain::CompositorChain(Viewport *vp):
40 mViewport(vp),
41 mOriginalScene(0),
42 mDirty(true),
43 mAnyCompositorsEnabled(false),
44 mOldLodBias(1.0f)
45 {
46 assert(vp);
47 mOldClearEveryFrameBuffers = vp->getClearBuffers();
48 vp->addListener(this);
49
50 createOriginalScene();
51 vp->getTarget()->addListener(this);
52 }
53 //-----------------------------------------------------------------------
~CompositorChain()54 CompositorChain::~CompositorChain()
55 {
56 destroyResources();
57 }
58 //-----------------------------------------------------------------------
destroyResources(void)59 void CompositorChain::destroyResources(void)
60 {
61 clearCompiledState();
62
63 if (mViewport)
64 {
65 mViewport->getTarget()->removeListener(this);
66 mViewport->removeListener(this);
67 removeAllCompositors();
68 destroyOriginalScene();
69
70 // destory base "original scene" compositor
71 CompositorManager::getSingleton().remove(getCompositorName(), ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
72
73 mViewport = 0;
74 }
75 }
76 //-----------------------------------------------------------------------
getCompositorName() const77 const String CompositorChain::getCompositorName() const
78 {
79 return StringUtil::format("Ogre/Scene/%zu", (size_t)mViewport);
80 }
81 //-----------------------------------------------------------------------
createOriginalScene()82 void CompositorChain::createOriginalScene()
83 {
84 /// Create "default" compositor
85 /** Compositor that is used to implicitly represent the original
86 render in the chain. This is an identity compositor with only an output pass:
87 compositor Ogre/Scene
88 {
89 technique
90 {
91 target_output
92 {
93 pass clear
94 {
95 /// Clear frame
96 }
97 pass render_scene
98 {
99 visibility_mask FFFFFFFF
100 render_queues SKIES_EARLY SKIES_LATE
101 }
102 }
103 }
104 };
105 */
106
107 // If two viewports use the same scheme but differ in settings like visibility masks, shadows, etc we don't
108 // want compositors to share their technique. Otherwise both compositors will have to recompile every time they
109 // render. Thus we generate a unique compositor per viewport.
110 const String compName = getCompositorName();
111
112 mOriginalSceneScheme = mViewport->getMaterialScheme();
113 CompositorPtr scene = CompositorManager::getSingleton().getByName(compName, ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
114 if (!scene)
115 {
116 scene = CompositorManager::getSingleton().create(compName, ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
117 CompositionTargetPass *tp = scene->createTechnique()->getOutputTargetPass();
118 tp->createPass(CompositionPass::PT_CLEAR);
119
120 /// Render everything, including skies
121 CompositionPass *pass = tp->createPass(CompositionPass::PT_RENDERSCENE);
122 pass->setFirstRenderQueue(RENDER_QUEUE_BACKGROUND);
123 pass->setLastRenderQueue(RENDER_QUEUE_SKIES_LATE);
124
125 /// Create base "original scene" compositor
126 scene = static_pointer_cast<Compositor>(CompositorManager::getSingleton().load(compName,
127 ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME));
128 }
129 mOriginalScene = OGRE_NEW CompositorInstance(scene->getSupportedTechnique(), this);
130 }
131 //-----------------------------------------------------------------------
destroyOriginalScene()132 void CompositorChain::destroyOriginalScene()
133 {
134 /// Destroy "original scene" compositor instance
135 if (mOriginalScene)
136 {
137 OGRE_DELETE mOriginalScene;
138 mOriginalScene = 0;
139 }
140 }
141
142 //-----------------------------------------------------------------------
addCompositor(CompositorPtr filter,size_t addPosition,const String & scheme)143 CompositorInstance* CompositorChain::addCompositor(CompositorPtr filter, size_t addPosition, const String& scheme)
144 {
145
146
147 filter->touch();
148 CompositionTechnique *tech = filter->getSupportedTechnique(scheme);
149 if(!tech)
150 {
151 /// Warn user
152 LogManager::getSingleton().logMessage(
153 "CompositorChain: Compositor " + filter->getName() + " has no supported techniques.", LML_CRITICAL
154 );
155 return 0;
156 }
157 CompositorInstance *t = OGRE_NEW CompositorInstance(tech, this);
158
159 if(addPosition == LAST)
160 addPosition = mInstances.size();
161 else
162 assert(addPosition <= mInstances.size() && "Index out of bounds.");
163 mInstances.insert(mInstances.begin()+addPosition, t);
164
165 mDirty = true;
166 mAnyCompositorsEnabled = true;
167 return t;
168 }
169 //-----------------------------------------------------------------------
removeCompositor(size_t index)170 void CompositorChain::removeCompositor(size_t index)
171 {
172 if(index == LAST)
173 index = mInstances.size() - 1;
174
175 assert (index < mInstances.size() && "Index out of bounds.");
176 Instances::iterator i = mInstances.begin() + index;
177 OGRE_DELETE *i;
178 mInstances.erase(i);
179
180 mDirty = true;
181 }
182 //-----------------------------------------------------------------------
getNumCompositors()183 size_t CompositorChain::getNumCompositors()
184 {
185 return mInstances.size();
186 }
187 //-----------------------------------------------------------------------
removeAllCompositors()188 void CompositorChain::removeAllCompositors()
189 {
190 Instances::iterator i, iend;
191 iend = mInstances.end();
192 for (i = mInstances.begin(); i != iend; ++i)
193 {
194 OGRE_DELETE *i;
195 }
196 mInstances.clear();
197
198 mDirty = true;
199 }
200 //-----------------------------------------------------------------------
_removeInstance(CompositorInstance * i)201 void CompositorChain::_removeInstance(CompositorInstance *i)
202 {
203 Instances::iterator it = std::find(mInstances.begin(), mInstances.end(), i);
204 assert(it != mInstances.end());
205 if(it != mInstances.end())
206 {
207 mInstances.erase(it);
208 OGRE_DELETE i;
209 }
210 }
211 //-----------------------------------------------------------------------
_queuedOperation(CompositorInstance::RenderSystemOperation * op)212 void CompositorChain::_queuedOperation(CompositorInstance::RenderSystemOperation* op)
213 {
214 mRenderSystemOperations.push_back(op);
215
216 }
217 //-----------------------------------------------------------------------
getCompositor(size_t index)218 CompositorInstance *CompositorChain::getCompositor(size_t index)
219 {
220 assert (index < mInstances.size() && "Index out of bounds.");
221 return mInstances[index];
222 }
223 //-----------------------------------------------------------------------
getCompositorPosition(const String & name)224 size_t CompositorChain::getCompositorPosition(const String& name)
225 {
226 for (Instances::iterator it = mInstances.begin(); it != mInstances.end(); ++it)
227 {
228 if ((*it)->getCompositor()->getName() == name)
229 {
230 return std::distance(mInstances.begin(), it);
231 }
232 }
233 return NPOS;
234 }
getCompositor(const String & name)235 CompositorInstance *CompositorChain::getCompositor(const String& name)
236 {
237 size_t idx = getCompositorPosition(name);
238 return idx == NPOS ? NULL : mInstances[idx];
239 }
240 //-----------------------------------------------------------------------
getCompositors()241 CompositorChain::InstanceIterator CompositorChain::getCompositors()
242 {
243 return InstanceIterator(mInstances.begin(), mInstances.end());
244 }
245 //-----------------------------------------------------------------------
setCompositorEnabled(size_t position,bool state)246 void CompositorChain::setCompositorEnabled(size_t position, bool state)
247 {
248 CompositorInstance* inst = mInstances[position];
249 if (!state && inst->getEnabled())
250 {
251 // If we're disabling a 'middle' compositor in a chain, we have to be
252 // careful about textures which might have been shared by non-adjacent
253 // instances which have now become adjacent.
254 CompositorInstance* nextInstance = getNextInstance(inst, true);
255 if (nextInstance)
256 {
257 const CompositionTechnique::TargetPasses& tps =
258 nextInstance->getTechnique()->getTargetPasses();
259 CompositionTechnique::TargetPasses::const_iterator tpit = tps.begin();
260 for(;tpit != tps.end(); ++tpit)
261 {
262 CompositionTargetPass* tp = *tpit;
263 if (tp->getInputMode() == CompositionTargetPass::IM_PREVIOUS)
264 {
265 if (nextInstance->getTechnique()->getTextureDefinition(tp->getOutputName())->pooled)
266 {
267 // recreate
268 nextInstance->freeResources(false, true);
269 nextInstance->createResources(false);
270 }
271 }
272
273 }
274 }
275
276 }
277 inst->setEnabled(state);
278 }
279 //-----------------------------------------------------------------------
preRenderTargetUpdate(const RenderTargetEvent & evt)280 void CompositorChain::preRenderTargetUpdate(const RenderTargetEvent& evt)
281 {
282 /// Compile if state is dirty
283 if(mDirty)
284 _compile();
285
286 // Do nothing if no compositors enabled
287 if (!mAnyCompositorsEnabled)
288 {
289 return;
290 }
291
292
293 /// Update dependent render targets; this is done in the preRenderTarget
294 /// and not the preViewportUpdate for a reason: at this time, the
295 /// target Rendertarget will not yet have been set as current.
296 /// ( RenderSystem::setViewport(...) ) if it would have been, the rendering
297 /// order would be screwed up and problems would arise with copying rendertextures.
298 Camera *cam = mViewport->getCamera();
299 if (cam)
300 {
301 cam->getSceneManager()->_setActiveCompositorChain(this);
302 }
303
304 /// Iterate over compiled state
305 CompositorInstance::CompiledState::iterator i;
306 for(i=mCompiledState.begin(); i!=mCompiledState.end(); ++i)
307 {
308 /// Skip if this is a target that should only be initialised initially
309 if(i->onlyInitial && i->hasBeenRendered)
310 continue;
311 i->hasBeenRendered = true;
312 /// Setup and render
313 preTargetOperation(*i, i->target->getViewport(0), cam);
314 i->target->update();
315 postTargetOperation(*i, i->target->getViewport(0), cam);
316 }
317 }
318 //-----------------------------------------------------------------------
postRenderTargetUpdate(const RenderTargetEvent & evt)319 void CompositorChain::postRenderTargetUpdate(const RenderTargetEvent& evt)
320 {
321 Camera *cam = mViewport->getCamera();
322 if (cam)
323 {
324 cam->getSceneManager()->_setActiveCompositorChain(0);
325 }
326 }
327 //-----------------------------------------------------------------------
preViewportUpdate(const RenderTargetViewportEvent & evt)328 void CompositorChain::preViewportUpdate(const RenderTargetViewportEvent& evt)
329 {
330 // Only set up if there is at least one compositor enabled, and it's this viewport
331 if(evt.source != mViewport || !mAnyCompositorsEnabled)
332 return;
333
334 // set original scene details from viewport
335 CompositionPass* pass = mOriginalScene->getTechnique()->getOutputTargetPass()->getPasses()[0];
336 CompositionTargetPass* passParent = pass->getParent();
337 if (pass->getClearBuffers() != mViewport->getClearBuffers() ||
338 pass->getClearColour() != mViewport->getBackgroundColour() ||
339 pass->getClearDepth() != mViewport->getDepthClear() ||
340 passParent->getVisibilityMask() != mViewport->getVisibilityMask() ||
341 passParent->getMaterialScheme() != mViewport->getMaterialScheme() ||
342 passParent->getShadowsEnabled() != mViewport->getShadowsEnabled())
343 {
344 // recompile if viewport settings are different
345 pass->setClearBuffers(mViewport->getClearBuffers());
346 pass->setClearColour(mViewport->getBackgroundColour());
347 pass->setClearDepth(mViewport->getDepthClear());
348 passParent->setVisibilityMask(mViewport->getVisibilityMask());
349 passParent->setMaterialScheme(mViewport->getMaterialScheme());
350 passParent->setShadowsEnabled(mViewport->getShadowsEnabled());
351 _compile();
352 }
353
354 Camera *cam = mViewport->getCamera();
355 if (cam)
356 {
357 /// Prepare for output operation
358 preTargetOperation(mOutputOperation, mViewport, cam);
359 }
360 }
361 //-----------------------------------------------------------------------
preTargetOperation(CompositorInstance::TargetOperation & op,Viewport * vp,Camera * cam)362 void CompositorChain::preTargetOperation(CompositorInstance::TargetOperation &op, Viewport *vp, Camera *cam)
363 {
364 if (cam)
365 {
366 SceneManager *sm = cam->getSceneManager();
367 /// Set up render target listener
368 mOurListener.setOperation(&op, sm, sm->getDestinationRenderSystem());
369 mOurListener.notifyViewport(vp);
370 /// Register it
371 sm->addRenderQueueListener(&mOurListener);
372 /// Set whether we find visibles
373 mOldFindVisibleObjects = sm->getFindVisibleObjects();
374 sm->setFindVisibleObjects(op.findVisibleObjects);
375 /// Set LOD bias level
376 mOldLodBias = cam->getLodBias();
377 cam->setLodBias(cam->getLodBias() * op.lodBias);
378 }
379
380 // Set the visibility mask
381 mOldVisibilityMask = vp->getVisibilityMask();
382 vp->setVisibilityMask(op.visibilityMask);
383 /// Set material scheme
384 mOldMaterialScheme = vp->getMaterialScheme();
385 vp->setMaterialScheme(op.materialScheme);
386 /// Set shadows enabled
387 mOldShadowsEnabled = vp->getShadowsEnabled();
388 vp->setShadowsEnabled(op.shadowsEnabled);
389 /// XXX TODO
390 //vp->setClearEveryFrame( true );
391 //vp->setOverlaysEnabled( false );
392 //vp->setBackgroundColour( op.clearColour );
393 }
394 //-----------------------------------------------------------------------
postTargetOperation(CompositorInstance::TargetOperation & op,Viewport * vp,Camera * cam)395 void CompositorChain::postTargetOperation(CompositorInstance::TargetOperation &op, Viewport *vp, Camera *cam)
396 {
397 if (cam)
398 {
399 SceneManager *sm = cam->getSceneManager();
400 /// Unregister our listener
401 sm->removeRenderQueueListener(&mOurListener);
402 /// Restore default scene and camera settings
403 sm->setFindVisibleObjects(mOldFindVisibleObjects);
404 cam->setLodBias(mOldLodBias);
405 }
406
407 vp->setVisibilityMask(mOldVisibilityMask);
408 vp->setMaterialScheme(mOldMaterialScheme);
409 vp->setShadowsEnabled(mOldShadowsEnabled);
410 }
411 //-----------------------------------------------------------------------
postViewportUpdate(const RenderTargetViewportEvent & evt)412 void CompositorChain::postViewportUpdate(const RenderTargetViewportEvent& evt)
413 {
414 // Only tidy up if there is at least one compositor enabled, and it's this viewport
415 if(evt.source != mViewport || !mAnyCompositorsEnabled)
416 return;
417
418 Camera *cam = mViewport->getCamera();
419 postTargetOperation(mOutputOperation, mViewport, cam);
420 }
421 //-----------------------------------------------------------------------
viewportCameraChanged(Viewport * viewport)422 void CompositorChain::viewportCameraChanged(Viewport* viewport)
423 {
424 Camera* camera = viewport->getCamera();
425 size_t count = mInstances.size();
426 for (size_t i = 0; i < count; ++i)
427 {
428 mInstances[i]->notifyCameraChanged(camera);
429 }
430 }
431 //-----------------------------------------------------------------------
viewportDimensionsChanged(Viewport * viewport)432 void CompositorChain::viewportDimensionsChanged(Viewport* viewport)
433 {
434 size_t count = mInstances.size();
435 for (size_t i = 0; i < count; ++i)
436 {
437 mInstances[i]->notifyResized();
438 }
439 }
440 //-----------------------------------------------------------------------
viewportDestroyed(Viewport * viewport)441 void CompositorChain::viewportDestroyed(Viewport* viewport)
442 {
443 // this chain is now orphaned. tell compositor manager to delete it.
444 CompositorManager::getSingleton().removeCompositorChain(viewport);
445 }
446 //-----------------------------------------------------------------------
clearCompiledState()447 void CompositorChain::clearCompiledState()
448 {
449 for (RenderSystemOperations::iterator i = mRenderSystemOperations.begin();
450 i != mRenderSystemOperations.end(); ++i)
451 {
452 OGRE_DELETE *i;
453 }
454 mRenderSystemOperations.clear();
455
456 /// Clear compiled state
457 mCompiledState.clear();
458 mOutputOperation = CompositorInstance::TargetOperation(0);
459
460 }
461 //-----------------------------------------------------------------------
_compile()462 void CompositorChain::_compile()
463 {
464 // remove original scene if it has the wrong material scheme
465 if( mOriginalSceneScheme != mViewport->getMaterialScheme() )
466 {
467 destroyOriginalScene();
468 createOriginalScene();
469 }
470
471 clearCompiledState();
472
473 bool compositorsEnabled = false;
474
475 // force default scheme so materials for compositor quads will determined correctly
476 MaterialManager& matMgr = MaterialManager::getSingleton();
477 String prevMaterialScheme = matMgr.getActiveScheme();
478 matMgr.setActiveScheme(Root::getSingleton().getRenderSystem()->_getDefaultViewportMaterialScheme());
479
480 /// Set previous CompositorInstance for each compositor in the list
481 CompositorInstance *lastComposition = mOriginalScene;
482 mOriginalScene->mPreviousInstance = 0;
483 CompositionPass* pass = mOriginalScene->getTechnique()->getOutputTargetPass()->getPasses()[0];
484 pass->setClearBuffers(mViewport->getClearBuffers());
485 pass->setClearColour(mViewport->getBackgroundColour());
486 pass->setClearDepth(mViewport->getDepthClear());
487 for(Instances::iterator i=mInstances.begin(); i!=mInstances.end(); ++i)
488 {
489 if((*i)->getEnabled())
490 {
491 compositorsEnabled = true;
492 (*i)->mPreviousInstance = lastComposition;
493 lastComposition = (*i);
494 }
495 }
496
497
498 /// Compile misc targets
499 lastComposition->_compileTargetOperations(mCompiledState);
500
501 /// Final target viewport (0)
502 mOutputOperation.renderSystemOperations.clear();
503 lastComposition->_compileOutputOperation(mOutputOperation);
504
505 // Deal with viewport settings
506 if (compositorsEnabled != mAnyCompositorsEnabled)
507 {
508 mAnyCompositorsEnabled = compositorsEnabled;
509 if (mAnyCompositorsEnabled)
510 {
511 // Save old viewport clearing options
512 mOldClearEveryFrameBuffers = mViewport->getClearBuffers();
513 // Don't clear anything every frame since we have our own clear ops
514 mViewport->setClearEveryFrame(false);
515 }
516 else
517 {
518 // Reset clearing options
519 mViewport->setClearEveryFrame(mOldClearEveryFrameBuffers > 0,
520 mOldClearEveryFrameBuffers);
521 }
522 }
523
524 // restore material scheme
525 matMgr.setActiveScheme(prevMaterialScheme);
526
527
528 mDirty = false;
529 }
530 //-----------------------------------------------------------------------
_markDirty()531 void CompositorChain::_markDirty()
532 {
533 mDirty = true;
534 }
535 //-----------------------------------------------------------------------
getViewport()536 Viewport *CompositorChain::getViewport()
537 {
538 return mViewport;
539 }
540 //---------------------------------------------------------------------
_notifyViewport(Viewport * vp)541 void CompositorChain::_notifyViewport(Viewport* vp)
542 {
543 if (vp != mViewport)
544 {
545 if (mViewport != NULL)
546 mViewport->removeListener(this);
547
548 if (vp != NULL)
549 vp->addListener(this);
550
551 if (!vp || !mViewport || vp->getTarget() != mViewport->getTarget())
552 {
553 if(mViewport)
554 mViewport->getTarget()->removeListener(this);
555
556 if(vp)
557 vp->getTarget()->addListener(this);
558 }
559 mOurListener.notifyViewport(vp);
560 mViewport = vp;
561 }
562 }
563 //-----------------------------------------------------------------------
renderQueueStarted(uint8 id,const String & invocation,bool & skipThisQueue)564 void CompositorChain::RQListener::renderQueueStarted(uint8 id,
565 const String& invocation, bool& skipThisQueue)
566 {
567 // Skip when not matching viewport
568 // shadows update is nested within main viewport update
569 if (mSceneManager->getCurrentViewport() != mViewport)
570 return;
571
572 flushUpTo(id);
573 /// If no one wants to render this queue, skip it
574 /// Don't skip the OVERLAY queue because that's handled separately
575 if(!mOperation->renderQueues.test(id) && id!=RENDER_QUEUE_OVERLAY)
576 {
577 skipThisQueue = true;
578 }
579 }
580 //-----------------------------------------------------------------------
renderQueueEnded(uint8 id,const String & invocation,bool & repeatThisQueue)581 void CompositorChain::RQListener::renderQueueEnded(uint8 id,
582 const String& invocation, bool& repeatThisQueue)
583 {
584 }
585 //-----------------------------------------------------------------------
setOperation(CompositorInstance::TargetOperation * op,SceneManager * sm,RenderSystem * rs)586 void CompositorChain::RQListener::setOperation(CompositorInstance::TargetOperation *op,SceneManager *sm,RenderSystem *rs)
587 {
588 mOperation = op;
589 mSceneManager = sm;
590 mRenderSystem = rs;
591 currentOp = op->renderSystemOperations.begin();
592 lastOp = op->renderSystemOperations.end();
593 }
594 //-----------------------------------------------------------------------
flushUpTo(uint8 id)595 void CompositorChain::RQListener::flushUpTo(uint8 id)
596 {
597 /// Process all RenderSystemOperations up to and including render queue id.
598 /// Including, because the operations for RenderQueueGroup x should be executed
599 /// at the beginning of the RenderQueueGroup render for x.
600 while(currentOp != lastOp && currentOp->first <= id)
601 {
602 currentOp->second->execute(mSceneManager, mRenderSystem);
603 ++currentOp;
604 }
605 }
606 //-----------------------------------------------------------------------
getPreviousInstance(CompositorInstance * curr,bool activeOnly)607 CompositorInstance* CompositorChain::getPreviousInstance(CompositorInstance* curr, bool activeOnly)
608 {
609 bool found = false;
610 for(Instances::reverse_iterator i=mInstances.rbegin(); i!=mInstances.rend(); ++i)
611 {
612 if (found)
613 {
614 if ((*i)->getEnabled() || !activeOnly)
615 return *i;
616 }
617 else if(*i == curr)
618 {
619 found = true;
620 }
621 }
622
623 return 0;
624 }
625 //---------------------------------------------------------------------
getNextInstance(CompositorInstance * curr,bool activeOnly)626 CompositorInstance* CompositorChain::getNextInstance(CompositorInstance* curr, bool activeOnly)
627 {
628 bool found = false;
629 for(Instances::iterator i=mInstances.begin(); i!=mInstances.end(); ++i)
630 {
631 if (found)
632 {
633 if ((*i)->getEnabled() || !activeOnly)
634 return *i;
635 }
636 else if(*i == curr)
637 {
638 found = true;
639 }
640 }
641
642 return 0;
643 }
644 //---------------------------------------------------------------------
645 }
646
647