root/OpenSceneGraph/trunk/src/osg/GraphicsContext.cpp @ 10833

Revision 10833, 29.5 kB (checked in by robert, 5 years ago)

Introduced preliminary osg::deleteAllGLObjects() and osg::discardAllGLObjects() functions and associated support into Texture and BufferObjects?

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