root/OpenSceneGraph/branches/OpenSceneGraph-2.8/src/osg/GraphicsContext.cpp @ 11208

Revision 11208, 27.4 kB (checked in by paulmartz, 5 years ago)

Merge 10664 to 2.8 branch (MSFBO workaround for OS X).

  • Property svn:mergeinfo set to
    /OpenSceneGraph/branches/OpenSceneGraph-2.8.2/src/osg/GraphicsContext.cpp:10664
    /OpenSceneGraph/trunk/src/osg/GraphicsContext.cpp:10154
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <stdlib.h>
15
16#include <osg/GraphicsContext>
17#include <osg/Camera>
18#include <osg/View>
19#include <osg/GLObjects>
20
21#include <osg/FrameBufferObject>
22#include <osg/Program>
23#include <osg/Drawable>
24#include <osg/FragmentProgram>
25#include <osg/VertexProgram>
26
27#include <OpenThreads/ReentrantMutex>
28
29#include <osg/Notify>
30
31#include <map>
32#include <sstream>
33#include <algorithm>
34
35using namespace osg;
36
37/////////////////////////////////////////////////////////////////////////////
38
39
40// Use a static reference pointer to hold the window system interface.
41// Wrap this within a function, in order to control the order in which
42// the static pointer's constructor is executed.
43
44static ref_ptr<GraphicsContext::WindowingSystemInterface> &windowingSystemInterfaceRef()
45{
46    static ref_ptr<GraphicsContext::WindowingSystemInterface> s_WindowingSystemInterface;
47    return s_WindowingSystemInterface;
48}
49
50
51//  GraphicsContext static method implementations
52
53void GraphicsContext::setWindowingSystemInterface(WindowingSystemInterface* callback)
54{
55    ref_ptr<GraphicsContext::WindowingSystemInterface> &wsref = windowingSystemInterfaceRef();
56    wsref = callback;
57    osg::notify(osg::INFO)<<"GraphicsContext::setWindowingSystemInterface() "<<wsref.get()<<"\t"<<&wsref<<std::endl;
58}
59
60GraphicsContext::WindowingSystemInterface* GraphicsContext::getWindowingSystemInterface()
61{
62    ref_ptr<GraphicsContext::WindowingSystemInterface> &wsref = windowingSystemInterfaceRef();
63    osg::notify(osg::INFO)<<"GraphicsContext::getWindowingSystemInterface() "<<wsref.get()<<"\t"<<&wsref<<std::endl;
64    return wsref.get();
65}
66
67GraphicsContext* GraphicsContext::createGraphicsContext(Traits* traits)
68{
69    ref_ptr<GraphicsContext::WindowingSystemInterface> &wsref = windowingSystemInterfaceRef();
70    if ( wsref.valid())
71    {
72        // catch any undefined values.
73        if (traits) traits->setUndefinedScreenDetailsToDefaultScreen();
74       
75        return wsref->createGraphicsContext(traits);
76    }
77    else
78        return 0;   
79}
80
81GraphicsContext::ScreenIdentifier::ScreenIdentifier():
82    displayNum(0),
83    screenNum(0) {}
84
85GraphicsContext::ScreenIdentifier::ScreenIdentifier(int in_screenNum):
86    displayNum(0),
87    screenNum(in_screenNum) {}
88
89GraphicsContext::ScreenIdentifier::ScreenIdentifier(const std::string& in_hostName,int in_displayNum, int in_screenNum):
90    hostName(in_hostName),
91    displayNum(in_displayNum),
92    screenNum(in_screenNum) {}
93
94std::string GraphicsContext::ScreenIdentifier::displayName() const
95{
96    std::stringstream ostr;
97    ostr<<hostName<<":"<<displayNum<<"."<<screenNum;
98    return ostr.str();
99}
100
101void GraphicsContext::ScreenIdentifier::readDISPLAY()
102{
103    const char* ptr = 0;
104    if ((ptr=getenv("DISPLAY")) != 0)
105    {
106        setScreenIdentifier(ptr);
107    }
108}
109
110void GraphicsContext::ScreenIdentifier::setScreenIdentifier(const std::string& displayName)
111{
112    std::string::size_type colon = displayName.find_last_of(':');
113    std::string::size_type point = displayName.find_last_of('.');
114   
115    if (point!=std::string::npos &&
116        colon==std::string::npos &&
117        point < colon) point = std::string::npos;
118
119    if (colon==std::string::npos)
120    {
121        hostName = "";
122    }
123    else
124    {
125        hostName = displayName.substr(0,colon);
126    }
127   
128    std::string::size_type startOfDisplayNum = (colon==std::string::npos) ? 0 : colon+1;
129    std::string::size_type endOfDisplayNum = (point==std::string::npos) ?  displayName.size() : point;
130
131    if (startOfDisplayNum<endOfDisplayNum)
132    {
133        displayNum = atoi(displayName.substr(startOfDisplayNum,endOfDisplayNum-startOfDisplayNum).c_str());
134    }
135    else
136    {
137        displayNum = -1;
138    }
139
140    if (point!=std::string::npos && point+1<displayName.size())
141    {
142        screenNum = atoi(displayName.substr(point+1,displayName.size()-point-1).c_str());
143    }
144    else
145    {
146        screenNum = -1;
147    }
148
149#if 0   
150    osg::notify(osg::NOTICE)<<"   hostName ["<<hostName<<"]"<<std::endl;
151    osg::notify(osg::NOTICE)<<"   displayNum "<<displayNum<<std::endl;
152    osg::notify(osg::NOTICE)<<"   screenNum "<<screenNum<<std::endl;
153#endif
154}
155
156class ContextData
157{
158public:
159
160    ContextData():
161        _numContexts(0) {}
162
163    unsigned int _numContexts;
164   
165    void incrementUsageCount() {  ++_numContexts; }
166
167    void decrementUsageCount()
168    {
169        --_numContexts;
170
171        osg::notify(osg::INFO)<<"decrementUsageCount()"<<_numContexts<<std::endl;
172
173        if (_numContexts <= 1 && _compileContext.valid())
174        {
175            osg::notify(osg::INFO)<<"resetting compileContext "<<_compileContext.get()<<" refCount "<<_compileContext->referenceCount()<<std::endl;
176           
177            _compileContext = 0;
178        }
179    }
180   
181    osg::ref_ptr<osg::GraphicsContext> _compileContext;
182
183};
184
185
186typedef std::map<unsigned int, ContextData>  ContextIDMap;
187static ContextIDMap s_contextIDMap;
188static OpenThreads::ReentrantMutex s_contextIDMapMutex;
189static GraphicsContext::GraphicsContexts s_registeredContexts;
190
191unsigned int GraphicsContext::createNewContextID()
192{
193    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
194   
195    // first check to see if we can reuse contextID;
196    for(ContextIDMap::iterator itr = s_contextIDMap.begin();
197        itr != s_contextIDMap.end();
198        ++itr)
199    {
200        if (itr->second._numContexts == 0)
201        {
202
203            // reuse contextID;
204            itr->second._numContexts = 1;
205
206            osg::notify(osg::INFO)<<"GraphicsContext::createNewContextID() reusing contextID="<<itr->first<<std::endl;
207
208            return itr->first;
209        }
210    }
211
212    unsigned int contextID = s_contextIDMap.size();
213    s_contextIDMap[contextID]._numContexts = 1;
214   
215    osg::notify(osg::INFO)<<"GraphicsContext::createNewContextID() creating contextID="<<contextID<<std::endl;
216    osg::notify(osg::INFO)<<"Updating the MaxNumberOfGraphicsContexts to "<<contextID+1<<std::endl;
217
218    // update the the maximum number of graphics contexts,
219    // to ensure that texture objects and display buffers are configured to the correct size.
220    osg::DisplaySettings::instance()->setMaxNumberOfGraphicsContexts( contextID + 1 );
221
222    return contextID;   
223}
224
225unsigned int GraphicsContext::getMaxContextID()
226{
227    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
228    unsigned int maxContextID = 0;
229    for(ContextIDMap::iterator itr = s_contextIDMap.begin();
230        itr != s_contextIDMap.end();
231        ++itr)
232    {
233        if (itr->first > maxContextID) maxContextID = itr->first;
234    }
235    return maxContextID;
236}
237
238
239void GraphicsContext::incrementContextIDUsageCount(unsigned int contextID)
240{
241    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
242   
243    osg::notify(osg::INFO)<<"GraphicsContext::incrementContextIDUsageCount("<<contextID<<") to "<<s_contextIDMap[contextID]._numContexts<<std::endl;
244
245    s_contextIDMap[contextID].incrementUsageCount();
246}
247
248void GraphicsContext::decrementContextIDUsageCount(unsigned int contextID)
249{
250
251    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
252
253    if (s_contextIDMap[contextID]._numContexts!=0)
254    {
255        s_contextIDMap[contextID].decrementUsageCount();
256    }
257    else
258    {
259        osg::notify(osg::NOTICE)<<"Warning: decrementContextIDUsageCount("<<contextID<<") called on expired contextID."<<std::endl;
260    }
261
262    osg::notify(osg::INFO)<<"GraphicsContext::decrementContextIDUsageCount("<<contextID<<") to "<<s_contextIDMap[contextID]._numContexts<<std::endl;
263
264}
265
266
267void GraphicsContext::registerGraphicsContext(GraphicsContext* gc)
268{
269    osg::notify(osg::INFO)<<"GraphicsContext::registerGraphicsContext "<<gc<<std::endl;
270
271    if (!gc) return;
272
273    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
274
275    GraphicsContexts::iterator itr = std::find(s_registeredContexts.begin(), s_registeredContexts.end(), gc);
276    if (itr != s_registeredContexts.end()) s_registeredContexts.erase(itr);
277
278    s_registeredContexts.push_back(gc);
279}
280
281void GraphicsContext::unregisterGraphicsContext(GraphicsContext* gc)
282{
283    osg::notify(osg::INFO)<<"GraphicsContext::unregisterGraphicsContext "<<gc<<std::endl;
284
285    if (!gc) return;
286
287    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
288
289    GraphicsContexts::iterator itr = std::find(s_registeredContexts.begin(), s_registeredContexts.end(), gc);
290    if (itr != s_registeredContexts.end()) s_registeredContexts.erase(itr);
291}
292
293GraphicsContext::GraphicsContexts GraphicsContext::getAllRegisteredGraphicsContexts()
294{
295    osg::notify(osg::INFO)<<"GraphicsContext::getAllRegisteredGraphicsContexts s_registeredContexts.size()="<<s_registeredContexts.size()<<std::endl;
296    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
297    return s_registeredContexts;
298}
299
300GraphicsContext::GraphicsContexts GraphicsContext::getRegisteredGraphicsContexts(unsigned int contextID)
301{
302    GraphicsContexts contexts;
303
304    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
305    for(GraphicsContexts::iterator itr = s_registeredContexts.begin();
306        itr != s_registeredContexts.end();
307        ++itr)
308    {
309        GraphicsContext* gc = *itr;
310        if (gc->getState() && gc->getState()->getContextID()==contextID) contexts.push_back(gc);
311    }
312
313    osg::notify(osg::INFO)<<"GraphicsContext::getRegisteredGraphicsContexts "<<contextID<<" contexts.size()="<<contexts.size()<<std::endl;
314   
315    return contexts;
316}
317
318GraphicsContext* GraphicsContext::getOrCreateCompileContext(unsigned int contextID)
319{
320    osg::notify(osg::INFO)<<"GraphicsContext::createCompileContext."<<std::endl;
321
322    {   
323        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
324        if (s_contextIDMap[contextID]._compileContext.valid()) return s_contextIDMap[contextID]._compileContext.get();
325    }
326   
327    GraphicsContext::GraphicsContexts contexts = GraphicsContext::getRegisteredGraphicsContexts(contextID);
328    if (contexts.empty()) return 0;
329   
330    GraphicsContext* src_gc = contexts.front();
331    const osg::GraphicsContext::Traits* src_traits = src_gc->getTraits();
332
333    osg::GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
334    traits->screenNum = src_traits->screenNum;
335    traits->displayNum = src_traits->displayNum;
336    traits->hostName = src_traits->hostName;
337    traits->width = 100;
338    traits->height = 100;
339    traits->red = src_traits->red;
340    traits->green = src_traits->green;
341    traits->blue = src_traits->blue;
342    traits->alpha = src_traits->alpha;
343    traits->depth = src_traits->depth;
344    traits->sharedContext = src_gc;
345    traits->pbuffer = true;
346
347    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits);
348    if (gc.valid() && gc->realize())
349    {   
350        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
351        s_contextIDMap[contextID]._compileContext = gc;
352        osg::notify(osg::INFO)<<"   succeeded GraphicsContext::createCompileContext."<<std::endl;
353        return gc.release();
354    }
355    else
356    {
357        return 0;
358    }
359   
360}
361
362void GraphicsContext::setCompileContext(unsigned int contextID, GraphicsContext* gc)
363{
364    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
365    s_contextIDMap[contextID]._compileContext = gc;
366}
367
368GraphicsContext* GraphicsContext::getCompileContext(unsigned int contextID)
369{
370    // osg::notify(osg::NOTICE)<<"GraphicsContext::getCompileContext "<<contextID<<std::endl;
371    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
372    ContextIDMap::iterator itr = s_contextIDMap.find(contextID);
373    if (itr != s_contextIDMap.end()) return itr->second._compileContext.get();
374    else return 0;
375}
376
377
378/////////////////////////////////////////////////////////////////////////////
379//
380//  GraphicsContext standard method implementations
381//
382GraphicsContext::GraphicsContext():
383    _clearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f)),
384    _clearMask(0),
385    _threadOfLastMakeCurrent(0)
386{
387    setThreadSafeRefUnref(true);
388    _operationsBlock = new RefBlock;
389
390    registerGraphicsContext(this);
391}
392
393GraphicsContext::GraphicsContext(const GraphicsContext&, const osg::CopyOp&):
394    _clearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f)),
395    _clearMask(0),
396    _threadOfLastMakeCurrent(0)
397{
398    setThreadSafeRefUnref(true);
399    _operationsBlock = new RefBlock;
400
401    registerGraphicsContext(this);
402}
403
404GraphicsContext::~GraphicsContext()
405{
406    close(false);
407
408    unregisterGraphicsContext(this);
409}
410
411void GraphicsContext::clear()
412{
413    if (_clearMask==0 || !_traits) return;
414
415    glViewport(0, 0, _traits->width, _traits->height);
416    glScissor(0, 0, _traits->width, _traits->height);
417
418    glClearColor( _clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]);
419
420    glClear( _clearMask );
421}
422
423bool GraphicsContext::realize()
424{
425    if (realizeImplementation())
426    {
427        return true;
428    }
429    else
430    {   
431        return false;
432    }
433}
434
435void GraphicsContext::close(bool callCloseImplementation)
436{
437    osg::notify(osg::INFO)<<"close("<<callCloseImplementation<<")"<<this<<std::endl;
438
439    // switch off the graphics thread...
440    setGraphicsThread(0);
441   
442   
443    bool sharedContextExists = false;
444   
445    if (_state.valid())
446    {
447        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
448        if (s_contextIDMap[_state->getContextID()]._numContexts>1) sharedContextExists = true;
449    }
450
451    // release all the OpenGL objects in the scene graphs associated with this
452    for(Cameras::iterator itr = _cameras.begin();
453        itr != _cameras.end();
454        ++itr)
455    {
456        Camera* camera = (*itr);
457        if (camera)
458        {
459            osg::notify(osg::INFO)<<"Releasing GL objects for Camera="<<camera<<" _state="<<_state.get()<<std::endl;
460            camera->releaseGLObjects(_state.get());
461        }
462    }
463
464
465    if (callCloseImplementation && _state.valid() && isRealized())
466    {
467        osg::notify(osg::INFO)<<"Closing still viable window "<<sharedContextExists<<" _state->getContextID()="<<_state->getContextID()<<std::endl;
468
469        if (makeCurrent())
470        {
471       
472            osg::notify(osg::INFO)<<"Doing Flush"<<std::endl;
473
474            osg::flushAllDeletedGLObjects(_state->getContextID());
475
476            osg::notify(osg::INFO)<<"Done Flush "<<std::endl;
477
478            _state->reset();
479
480            releaseContext();
481        }
482        else
483        {
484            osg::notify(osg::INFO)<<"makeCurrent did not succeed, could not do flush/deletion of OpenGL objects."<<std::endl;
485        }
486    }
487   
488    if (callCloseImplementation) closeImplementation();
489
490
491    // now discard any deleted deleted OpenGL objects that the are still hanging around - such as due to
492    // the the flushDelete*() methods not being invoked, such as when using GraphicContextEmbedded where makeCurrent
493    // does not work.
494    if (_state.valid())
495    {
496        osg::notify(osg::INFO)<<"Doing discard of deleted OpenGL objects."<<std::endl;
497
498        osg::discardAllDeletedGLObjects(_state->getContextID());
499    }
500
501    if (_state.valid())
502    {
503        decrementContextIDUsageCount(_state->getContextID());
504       
505        _state = 0;
506    }
507}
508
509
510bool GraphicsContext::makeCurrent()
511{
512    bool result = makeCurrentImplementation();
513   
514    if (result)
515    {
516        _threadOfLastMakeCurrent = OpenThreads::Thread::CurrentThread();
517
518        // initialize extension process, not only initializes on first
519        // call, will be a non-op on subsequent calls.       
520        getState()->initializeExtensionProcs();
521    }
522   
523    return result;
524}
525
526bool GraphicsContext::makeContextCurrent(GraphicsContext* readContext)
527{
528    bool result = makeContextCurrentImplementation(readContext);
529
530    if (result)
531    {
532        _threadOfLastMakeCurrent = OpenThreads::Thread::CurrentThread();
533
534        // initialize extension process, not only initializes on first
535        // call, will be a non-op on subsequent calls.       
536        getState()->initializeExtensionProcs();
537    }
538   
539    return result;
540}
541
542bool GraphicsContext::releaseContext()
543{
544    bool result = releaseContextImplementation();
545   
546    _threadOfLastMakeCurrent = (OpenThreads::Thread*)(-1);
547   
548    return result;
549}
550
551void GraphicsContext::swapBuffers()
552{
553    if (isCurrent())
554    {
555        swapBuffersImplementation();
556        clear();
557    }
558    else if (_graphicsThread.valid() &&
559             _threadOfLastMakeCurrent == _graphicsThread.get())
560    {
561        _graphicsThread->add(new SwapBuffersOperation);
562    }
563    else
564    {
565        makeCurrent();
566        swapBuffersImplementation();
567        clear();
568    }
569}
570
571
572
573void GraphicsContext::createGraphicsThread()
574{
575    if (!_graphicsThread)
576    {
577        setGraphicsThread(new GraphicsThread);
578    }
579}
580
581void GraphicsContext::setGraphicsThread(GraphicsThread* gt)
582{
583    if (_graphicsThread==gt) return;
584
585    if (_graphicsThread.valid())
586    {
587        // need to kill the thread in some way...
588        _graphicsThread->cancel();
589        _graphicsThread->setParent(0);
590    }
591
592    _graphicsThread = gt;
593   
594    if (_graphicsThread.valid())
595    {
596        _graphicsThread->setParent(this);
597    }
598}
599
600void GraphicsContext::add(Operation* operation)
601{
602    osg::notify(osg::INFO)<<"Doing add"<<std::endl;
603
604    // acquire the lock on the operations queue to prevent anyone else for modifying it at the same time
605    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
606
607    // add the operation to the end of the list
608    _operations.push_back(operation);
609
610    _operationsBlock->set(true);
611}
612
613void GraphicsContext::remove(Operation* operation)
614{
615    osg::notify(osg::INFO)<<"Doing remove operation"<<std::endl;
616
617    // acquire the lock on the operations queue to prevent anyone else for modifying it at the same time
618    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
619
620    for(OperationQueue::iterator itr = _operations.begin();
621        itr!=_operations.end();)
622    {
623        if ((*itr)==operation) itr = _operations.erase(itr);
624        else ++itr;
625    }
626
627    if (_operations.empty())
628    {
629        _operationsBlock->set(false);
630    }
631}
632
633void GraphicsContext::remove(const std::string& name)
634{
635    osg::notify(osg::INFO)<<"Doing remove named operation"<<std::endl;
636   
637    // acquire the lock on the operations queue to prevent anyone else for modifying it at the same time
638    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
639
640    // find the remove all operations with specified name
641    for(OperationQueue::iterator itr = _operations.begin();
642        itr!=_operations.end();)
643    {
644        if ((*itr)->getName()==name) itr = _operations.erase(itr);
645        else ++itr;
646    }
647
648    if (_operations.empty())
649    {
650        _operationsBlock->set(false);
651    }
652}
653
654void GraphicsContext::removeAllOperations()
655{
656    osg::notify(osg::INFO)<<"Doing remove all operations"<<std::endl;
657
658    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
659    _operations.clear();
660    _operationsBlock->set(false);
661}
662
663
664struct CameraRenderOrderSortOp
665{
666    inline bool operator() (const Camera* lhs,const Camera* rhs) const
667    {
668        if (lhs->getRenderOrder()<rhs->getRenderOrder()) return true;
669        if (rhs->getRenderOrder()<lhs->getRenderOrder()) return false;
670        return lhs->getRenderOrderNum()<rhs->getRenderOrderNum();
671    }
672};
673
674
675void GraphicsContext::runOperations()
676{
677    // sort the cameras into order
678    typedef std::vector<Camera*> CameraVector;
679    CameraVector camerasCopy;
680    std::copy(_cameras.begin(), _cameras.end(), std::back_inserter(camerasCopy));
681    std::sort(camerasCopy.begin(), camerasCopy.end(), CameraRenderOrderSortOp());
682   
683    for(CameraVector::iterator itr = camerasCopy.begin();
684        itr != camerasCopy.end();
685        ++itr)
686    {
687        osg::Camera* camera = *itr;
688        if (camera->getRenderer()) (*(camera->getRenderer()))(this);
689    }
690
691    for(OperationQueue::iterator itr = _operations.begin();
692        itr != _operations.end();
693        )
694    {
695        {
696            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
697            _currentOperation = *itr;
698
699            if (!_currentOperation->getKeep())
700            {
701                itr = _operations.erase(itr);
702
703                if (_operations.empty())
704                {
705                    _operationsBlock->set(false);
706                }
707            }
708            else
709            {
710                ++itr;
711            }
712        }
713               
714        if (_currentOperation.valid())
715        {
716            // osg::notify(osg::INFO)<<"Doing op "<<_currentOperation->getName()<<" "<<this<<std::endl;
717
718            // call the graphics operation.
719            (*_currentOperation)(this);
720
721            {           
722                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
723                _currentOperation = 0;
724            }
725        }
726    }
727}
728
729void GraphicsContext::addCamera(osg::Camera* camera)
730{
731    _cameras.push_back(camera);
732}
733
734void GraphicsContext::removeCamera(osg::Camera* camera)
735{
736    Cameras::iterator itr = std::find(_cameras.begin(), _cameras.end(), camera);
737    if (itr != _cameras.end())
738    {
739        // find a set of nodes attached the camera that we are removing that isn't
740        // shared by any other cameras on this GraphicsContext
741        typedef std::set<Node*> NodeSet;
742        NodeSet nodes;
743        for(unsigned int i=0; i<camera->getNumChildren(); ++i)
744        {
745            nodes.insert(camera->getChild(i));           
746        }
747       
748        for(Cameras::iterator citr = _cameras.begin();
749            citr != _cameras.end();
750            ++citr)
751        {
752            if (citr != itr)
753            {
754                osg::Camera* otherCamera = *citr;
755                for(unsigned int i=0; i<otherCamera->getNumChildren(); ++i)
756                {
757                    NodeSet::iterator nitr = nodes.find(otherCamera->getChild(i));
758                    if (nitr != nodes.end()) nodes.erase(nitr);
759                }
760            }           
761        }
762       
763        // now release the GLobjects associated with these non shared nodes
764        for(NodeSet::iterator nitr = nodes.begin();
765            nitr != nodes.end();
766            ++nitr)
767        {
768            const_cast<osg::Node*>(*nitr)->releaseGLObjects(_state.get());
769        }
770
771        // release the context of the any RenderingCache that the Camera has.
772        if (camera->getRenderingCache())
773        {
774            camera->getRenderingCache()->releaseGLObjects(_state.get());
775        }
776
777        _cameras.erase(itr);
778
779    }
780}
781
782void GraphicsContext::resizedImplementation(int x, int y, int width, int height)
783{
784    if (!_traits) return;
785   
786    double widthChangeRatio = double(width) / double(_traits->width);
787    double heigtChangeRatio = double(height) / double(_traits->height);
788    double aspectRatioChange = widthChangeRatio / heigtChangeRatio;
789   
790    for(Cameras::iterator itr = _cameras.begin();
791        itr != _cameras.end();
792        ++itr)
793    {
794        Camera* camera = (*itr);
795       
796        // resize doesn't affect Cameras set up with FBO's.
797        if (camera->getRenderTargetImplementation()==osg::Camera::FRAME_BUFFER_OBJECT) continue;
798       
799        Viewport* viewport = camera->getViewport();
800        if (viewport)
801        {
802            if (viewport->x()==0 && viewport->y()==0 &&
803                viewport->width()>=_traits->width && viewport->height()>=_traits->height)
804            {
805                viewport->setViewport(0,0,width,height);
806            }
807            else
808            {
809                viewport->x() = static_cast<osg::Viewport::value_type>(double(viewport->x())*widthChangeRatio);
810                viewport->y() = static_cast<osg::Viewport::value_type>(double(viewport->y())*heigtChangeRatio);
811                viewport->width() = static_cast<osg::Viewport::value_type>(double(viewport->width())*widthChangeRatio);
812                viewport->height() = static_cast<osg::Viewport::value_type>(double(viewport->height())*heigtChangeRatio);
813            }
814        }
815
816        // if aspect ratio adjusted change the project matrix to suit.
817        if (aspectRatioChange != 1.0)
818        {
819            osg::View* view = camera->getView();
820            osg::View::Slave* slave = view ? view->findSlaveForCamera(camera) : 0;
821
822
823            if (slave)
824            {
825                if (camera->getReferenceFrame()==osg::Transform::RELATIVE_RF)
826                {
827                    switch(view->getCamera()->getProjectionResizePolicy())
828                    {
829                        case(osg::Camera::HORIZONTAL): slave->_projectionOffset *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0); break;
830                        case(osg::Camera::VERTICAL): slave->_projectionOffset *= osg::Matrix::scale(1.0, aspectRatioChange,1.0); break;
831                        default: break;
832                    }
833                }
834                else
835                {
836                    switch(camera->getProjectionResizePolicy())
837                    {
838                        case(osg::Camera::HORIZONTAL): camera->getProjectionMatrix() *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0); break;
839                        case(osg::Camera::VERTICAL): camera->getProjectionMatrix() *= osg::Matrix::scale(1.0, aspectRatioChange,1.0); break;
840                        default: break;
841                    }
842                }
843            }
844            else
845            {
846                Camera::ProjectionResizePolicy policy = view ? view->getCamera()->getProjectionResizePolicy() : camera->getProjectionResizePolicy();
847                switch(policy)
848                {
849                    case(osg::Camera::HORIZONTAL): camera->getProjectionMatrix() *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0); break;
850                    case(osg::Camera::VERTICAL): camera->getProjectionMatrix() *= osg::Matrix::scale(1.0, aspectRatioChange,1.0); break;
851                    default: break;
852                }
853
854                osg::Camera* master = view ? view->getCamera() : 0;
855                if (view && camera==master)
856                {
857                    for(unsigned int i=0; i<view->getNumSlaves(); ++i)
858                    {
859                        osg::View::Slave& child = view->getSlave(i);
860                        if (child._camera.valid() && child._camera->getReferenceFrame()==osg::Transform::RELATIVE_RF)
861                        {
862                            // scale the slaves by the inverse of the change that has been applied to master, to avoid them be
863                            // scaled twice (such as when both master and slave are on the same GraphicsContexts) or by the wrong scale
864                            // when master and slave are on different GraphicsContexts.
865                            switch(policy)
866                            {
867                                case(osg::Camera::HORIZONTAL): child._projectionOffset *= osg::Matrix::scale(aspectRatioChange,1.0,1.0); break;
868                                case(osg::Camera::VERTICAL): child._projectionOffset *= osg::Matrix::scale(1.0, 1.0/aspectRatioChange,1.0); break;
869                                default: break;
870                            }
871                        }
872                    }
873                }
874
875
876            }
877
878        }
879
880    }
881
882    _traits->x = x;
883    _traits->y = y;
884    _traits->width = width;
885    _traits->height = height;
886}
Note: See TracBrowser for help on using the browser.