/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSGVIEWER_VIEWERBASE #define OSGVIEWER_VIEWERBASE 1 #include #include #include #include #include #include #include namespace osgViewer { #define USE_REFERENCE_TIME DBL_MAX class View; /** ViewerBase is the view base class that is inherited by both Viewer and CompositeViewer.*/ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object { public: ViewerBase(); ViewerBase(const ViewerBase& vb); /** Set the Stats object used to collect various frame related timing and scene graph stats.*/ virtual void setViewerStats(osg::Stats* stats) = 0; /** Get the Viewers Stats object.*/ virtual osg::Stats* getViewerStats() = 0; /** Get the Viewers Stats object.*/ virtual const osg::Stats* getViewerStats() const = 0; /** read the viewer configuration from a configuration file.*/ virtual bool readConfiguration(const std::string& filename) = 0; /** Get whether at least of one of this viewers windows are realized.*/ virtual bool isRealized() const = 0; /** set up windows and associated threads.*/ virtual void realize() = 0; enum ThreadingModel { SingleThreaded, CullDrawThreadPerContext, ThreadPerContext = CullDrawThreadPerContext, DrawThreadPerContext, CullThreadPerCameraDrawThreadPerContext, ThreadPerCamera = CullThreadPerCameraDrawThreadPerContext, AutomaticSelection }; /** Set the threading model the rendering traversals will use.*/ virtual void setThreadingModel(ThreadingModel threadingModel); /** Get the threading model the rendering traversals will use.*/ ThreadingModel getThreadingModel() const { return _threadingModel; } /** Let the viewer suggest the best threading model for the viewers camera/window setup and the hardware available.*/ virtual ThreadingModel suggestBestThreadingModel(); /** Set up the threading and processor affinity as per the viewers threading model.*/ virtual void setUpThreading(); /** Return true if viewer threads are running. */ bool areThreadsRunning() const { return _threadsRunning; } /** Stop any threads being run by viewer.*/ virtual void stopThreading(); /** Start any threads required by the viewer.*/ virtual void startThreading(); enum BarrierPosition { BeforeSwapBuffers, AfterSwapBuffers }; /** Set the position of the end barrier. * AfterSwapBuffers may result in slightly higher framerates, but may * lead to inconsistent swapping between different windows. * BeforeSwapBuffers may lead to slightly lower framerate, but improve consistency in timing of swap buffers, * especially important if you are likely to consistently break frame.*/ void setEndBarrierPosition(BarrierPosition bp); /** Get the end barrier position.*/ BarrierPosition getEndBarrierPosition() const { return _endBarrierPosition; } /** Set the end barrier operation. \c op may be one of GL_FLUSH, GL_FINISH, * or NO_OPERATION. NO_OPERATION is the default. Per BarrierOperation::operator()(), * a glFlush() command, glFinish() command, or no additional OpenGL command will be * issued before entering the end barrier. */ void setEndBarrierOperation(osg::BarrierOperation::PreBlockOp op); /** Get the end barrier operation. */ osg::BarrierOperation::PreBlockOp getEndBarrierOperation() const { return _endBarrierOperation; } /** Set the done flag to signal the viewer's work is done and should exit the frame loop.*/ void setDone(bool done) { _done = done; } /** Return true if viewer's work is done and should exit the frame loop.*/ bool done() const { return _done; } /** Set the EventVisitor. */ void setEventVisitor(osgGA::EventVisitor* eventVisitor) { _eventVisitor = eventVisitor; } /** Get the EventVisitor. */ osgGA::EventVisitor* getEventVisitor() { return _eventVisitor.get(); } /** Get the const EventVisitor. */ const osgGA::EventVisitor* getEventVisitor() const { return _eventVisitor.get(); } /** Set the key event that the viewer checks on each frame to see if the viewer's done flag should be set to * signal end of viewers main loop. * Default value is Escape (osgGA::GUIEVentAdapter::KEY_Escape). * Setting to 0 switches off the feature.*/ void setKeyEventSetsDone(int key) { _keyEventSetsDone = key; } /** get the key event that the viewer checks on each frame to see if the viewer's done flag.*/ int getKeyEventSetsDone() const { return _keyEventSetsDone; } /** if the flag is true, the viewer set its done flag when a QUIT_APPLICATION is received, false disables this feature */ void setQuitEventSetsDone(bool flag) { _quitEventSetsDone = flag; } /** @return true if the viewer respond to the QUIT_APPLICATION-event */ bool getQuitEventSetsDone() const { return _quitEventSetsDone; } /** Hint to tell the renderingTraversals() method whether to call releaseContext() on the last * context that was made current by the thread calling renderingTraverals(). Note, when * running multi-threaded viewer no threads will be made current or release current. * Setting this hint to false can enable the frame loop to be lazy about calling makeCurrent * and releaseContext on each new frame, helping performance. However, if you frame loop * is managing multiple graphics context all from the main frame thread then this hint must * be left on, otherwise the wrong context could be left active, introducing errors in rendering.*/ void setReleaseContextAtEndOfFrameHint(bool hint) { _releaseContextAtEndOfFrameHint = hint; } /** Hint to tell the renderingTraversals() method whether to call releaseContext().*/ bool getReleaseContextAtEndOfFrameHint() const { return _releaseContextAtEndOfFrameHint; } /** Set the UpdateVisitor. */ void setUpdateVisitor(osgUtil::UpdateVisitor* updateVisitor) { _updateVisitor = updateVisitor; } /** Get the UpdateVisitor. */ osgUtil::UpdateVisitor* getUpdateVisitor() { return _updateVisitor.get(); } /** Get the const UpdateVisitor. */ const osgUtil::UpdateVisitor* getUpdateVisitor() const { return _updateVisitor.get(); } /** Set the Update OperationQueue. */ void setUpdateOperations(osg::OperationQueue* operations) { _updateOperations = operations; } /** Get the Update OperationQueue. */ osg::OperationQueue* getUpdateOperations() { return _updateOperations.get(); } /** Get the const Update OperationQueue. */ const osg::OperationQueue* getUpdateOperations() const { return _updateOperations.get(); } /** Add an update operation.*/ void addUpdateOperation(osg::Operation* operation); /** Remove an update operation.*/ void removeUpdateOperation(osg::Operation* operation); /** Set the graphics operation to call on realization of the viewers graphics windows.*/ void setRealizeOperation(osg::Operation* op) { _realizeOperation = op; } /** Get the graphics operation to call on realization of the viewers graphics windows.*/ osg::Operation* getRealizeOperation() { return _realizeOperation.get(); } /** Set the graphics operation to call before the viewers graphics contexts close.*/ void setCleanUpOperation(osg::Operation* op) { _cleanUpOperation = op; } /** Get the graphics operation to call before the viewers graphics contexts close.*/ osg::Operation* getCleanUpOperation() { return _cleanUpOperation.get(); } /** Set the incremental compile operation. * Used to manage the OpenGL object compilation and merging of subgraphs in a way that avoids overloading * the rendering of frame with too many new objects in one frame. */ void setIncrementalCompileOperation(osgUtil::IncrementalCompileOperation* ico); /** Get the incremental compile operation. */ osgUtil::IncrementalCompileOperation* getIncrementalCompileOperation() { return _incrementalCompileOperation.get(); } enum FrameScheme { ON_DEMAND, CONTINUOUS }; void setRunFrameScheme(FrameScheme fs) { _runFrameScheme = fs; } FrameScheme getRunFrameScheme() const { return _runFrameScheme; } void setRunMaxFrameRate(double frameRate) { _runMaxFrameRate = frameRate; } double getRunMaxFrameRate() const { return _runMaxFrameRate; } /** Execute a main frame loop. * Equivalent to while (!viewer.done()) viewer.frame(); * Also calls realize() if the viewer is not already realized, * and installs trackball manipulator if one is not already assigned. */ virtual int run(); /** check to see if the new frame is required, called by run(..) when FrameScheme is set to ON_DEMAND.*/ virtual bool checkNeedToDoFrame() = 0; /** check to see if events have been received, return true if events are now available.*/ virtual bool checkEvents() = 0; /** Render a complete new frame. * Calls advance(), eventTraversal(), updateTraversal(), renderingTraversals(). */ virtual void frame(double simulationTime=USE_REFERENCE_TIME); virtual void advance(double simulationTime=USE_REFERENCE_TIME) = 0; virtual void eventTraversal() = 0; virtual void updateTraversal() = 0; virtual void renderingTraversals(); typedef std::vector Cameras; virtual void getCameras(Cameras& cameras, bool onlyActive=true) = 0; typedef std::vector Contexts; virtual void getContexts(Contexts& contexts, bool onlyValid=true) = 0; typedef std::vector Windows; virtual void getWindows(Windows& windows, bool onlyValid=true); typedef std::vector Threads; virtual void getAllThreads(Threads& threads, bool onlyActive=true) = 0; typedef std::vector OperationThreads; virtual void getOperationThreads(OperationThreads& threads, bool onlyActive=true) = 0; typedef std::vector Scenes; virtual void getScenes(Scenes& scenes, bool onlyValid=true) = 0; typedef std::vector Views; virtual void getViews(Views& views, bool onlyValid=true) = 0; /** Check to see if any windows are still open. If not, set viewer done to true. */ void checkWindowStatus(); /** Check to see if windows are still open using the list of contexts given as a parameter. * If no windows are open, stop rendering threads and set viewer done to true. * This function is more effective than checkWindowStatus() as it does not query * the context list and should be used whenever context list is already available in your code.*/ void checkWindowStatus(const Contexts& contexts); virtual double elapsedTime() = 0; virtual osg::FrameStamp* getViewerFrameStamp() = 0; /** Get the keyboard and mouse usage of this viewer.*/ virtual void getUsage(osg::ApplicationUsage& usage) const = 0; bool getRequestRedraw() const { return _requestRedraw; } bool getRequestContinousUpdate() const { return _requestContinousUpdate; } protected: void viewerBaseInit(); friend class osgViewer::View; inline void makeCurrent(osg::GraphicsContext* gc) { if (_currentContext==gc) return; releaseContext(); if (gc && gc->valid() && gc->makeCurrent()) _currentContext = gc; } inline void releaseContext() { if (_currentContext.valid() && _currentContext->valid()) { _currentContext->releaseContext(); } _currentContext = 0; } virtual void viewerInit() = 0; bool _firstFrame; bool _done; int _keyEventSetsDone; bool _quitEventSetsDone; bool _releaseContextAtEndOfFrameHint; ThreadingModel _threadingModel; bool _threadsRunning; bool _requestRedraw; bool _requestContinousUpdate; FrameScheme _runFrameScheme; double _runMaxFrameRate; BarrierPosition _endBarrierPosition; osg::BarrierOperation::PreBlockOp _endBarrierOperation; osg::ref_ptr _startRenderingBarrier; osg::ref_ptr _endRenderingDispatchBarrier; osg::ref_ptr _endDynamicDrawBlock; osg::ref_ptr _eventVisitor; osg::ref_ptr _updateOperations; osg::ref_ptr _updateVisitor; osg::ref_ptr _realizeOperation; osg::ref_ptr _cleanUpOperation; osg::ref_ptr _incrementalCompileOperation; osg::observer_ptr _currentContext; private: // Define private copy constructor // otherwsie VS2015 will construct it's own which will call the private copy operator from osg::Object resulting in an compile error. ViewerBase& operator = (const ViewerBase&) { return *this; } }; } #endif