FrameBufferObject.cpp there is also another fix: when initializing a FBO attachment from a CameraNode attachment, the renderbuffer's format must be set to the attachment's internal format, not to the image's pixel format. Another problem is that attaching a renderbuffer to the FBO through CameraNode is not simple (if not impossible) if you don't intend to specify an Image object. Probably CameraNode could be enriched with an "attach(buffer, width, height, format)" method. For example if you attach a color buffer as a texture whose size is different than that of the CameraNode's viewport you also need to attach a depth buffer of the same size, because the depth buffer that is automatically attached by RenderStage has the viewport's size. FBOs require that all attachment have the same dimensions, so said setup will fail if you can't specify a custom depth renderbuffer"
756 lines
23 KiB
C++
756 lines
23 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 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.
|
|
*/
|
|
|
|
#include <osg/ApplicationUsage>
|
|
#include <osg/Timer>
|
|
#include <osg/Notify>
|
|
#include <osg/Texture2D>
|
|
#include <osg/TextureRectangle>
|
|
#include <osg/ImageStream>
|
|
|
|
#include <osgUtil/DisplayRequirementsVisitor>
|
|
#include <osgDB/FileUtils>
|
|
|
|
#include <osgProducer/OsgCameraGroup>
|
|
|
|
using namespace Producer;
|
|
using namespace osgProducer;
|
|
|
|
OsgCameraGroup::RealizeCallback::~RealizeCallback()
|
|
{
|
|
}
|
|
|
|
class RenderSurfaceRealizeCallback : public Producer::RenderSurface::Callback
|
|
{
|
|
public:
|
|
|
|
RenderSurfaceRealizeCallback(OsgCameraGroup* cameraGroup,OsgSceneHandler* sceneHandler):
|
|
_cameraGroup(cameraGroup),
|
|
_sceneHandler(sceneHandler) {}
|
|
|
|
virtual void operator()( const Producer::RenderSurface & rs)
|
|
{
|
|
|
|
osg::Timer timer;
|
|
osg::Timer_t start_t = timer.tick();
|
|
|
|
if (_cameraGroup->getRealizeCallback())
|
|
{
|
|
(*(_cameraGroup->getRealizeCallback()))(*_cameraGroup,*_sceneHandler,rs);
|
|
}
|
|
else if (_sceneHandler) _sceneHandler->init();
|
|
|
|
osg::Timer_t end_t = timer.tick();
|
|
double time = timer.delta_m(start_t,end_t);
|
|
osg::notify(osg::INFO) << "Time to init = "<<time<<std::endl;
|
|
|
|
}
|
|
|
|
OsgCameraGroup* _cameraGroup;
|
|
OsgSceneHandler* _sceneHandler;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::string findCameraConfigFile(const std::string& configFile)
|
|
{
|
|
std::string foundFile = osgDB::findDataFile(configFile);
|
|
if (foundFile.empty()) return "";
|
|
else return foundFile;
|
|
}
|
|
|
|
std::string extractCameraConfigFile(osg::ArgumentParser& arguments)
|
|
{
|
|
// report the usage options.
|
|
if (arguments.getApplicationUsage())
|
|
{
|
|
arguments.getApplicationUsage()->addCommandLineOption("-c <filename>","Specify camera config file");
|
|
}
|
|
|
|
std::string filename;
|
|
if (arguments.read("-c",filename)) return findCameraConfigFile(filename);
|
|
|
|
char *ptr;
|
|
if( (ptr = getenv( "PRODUCER_CAMERA_CONFIG_FILE" )) )
|
|
{
|
|
osg::notify(osg::DEBUG_INFO) << "PRODUCER_CAMERA_CONFIG_FILE("<<ptr<<")"<<std::endl;
|
|
return findCameraConfigFile(ptr);
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
static osg::ApplicationUsageProxy OsgCameraGroup_e1(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"PRODUCER_CAMERA_CONFIG_FILE <filename>","specify the default producer camera config to use when opening osgProducer based applications.");
|
|
|
|
|
|
OsgCameraGroup::OsgCameraGroup() : Producer::CameraGroup()
|
|
{
|
|
_init();
|
|
}
|
|
|
|
OsgCameraGroup::OsgCameraGroup(Producer::CameraConfig *cfg):
|
|
Producer::CameraGroup(cfg)
|
|
{
|
|
_init();
|
|
}
|
|
|
|
OsgCameraGroup::OsgCameraGroup(const std::string& configFile):
|
|
Producer::CameraGroup(findCameraConfigFile(configFile))
|
|
{
|
|
_init();
|
|
}
|
|
|
|
OsgCameraGroup::OsgCameraGroup(osg::ArgumentParser& arguments):
|
|
Producer::CameraGroup(extractCameraConfigFile(arguments))
|
|
{
|
|
_init();
|
|
_applicationUsage = arguments.getApplicationUsage();
|
|
|
|
for( unsigned int i = 0; i < _cfg->getNumberOfCameras(); i++ )
|
|
{
|
|
Producer::Camera *cam = _cfg->getCamera(i);
|
|
Producer::RenderSurface *rs = cam->getRenderSurface();
|
|
if (rs->getWindowName()== Producer::RenderSurface::defaultWindowName )
|
|
{
|
|
rs->setWindowName(arguments.getApplicationName());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class QuitImageStreamVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
QuitImageStreamVisitor():
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
|
|
|
|
|
|
/** Simply traverse using standard NodeVisitor traverse method.*/
|
|
virtual void apply(osg::Node& node)
|
|
{
|
|
if (node.getStateSet())
|
|
apply(*(node.getStateSet()));
|
|
|
|
traverse(node);
|
|
}
|
|
|
|
virtual void apply(osg::Geode& node)
|
|
{
|
|
if (node.getStateSet())
|
|
apply(*(node.getStateSet()));
|
|
|
|
for(unsigned int i=0;i<node.getNumDrawables();++i)
|
|
{
|
|
osg::Drawable* drawable = node.getDrawable(i);
|
|
if (drawable && drawable->getStateSet())
|
|
apply(*(drawable->getStateSet()));
|
|
}
|
|
}
|
|
|
|
void apply(osg::StateSet& stateset)
|
|
{
|
|
for(unsigned int i=0;i<stateset.getTextureAttributeList().size();++i)
|
|
{
|
|
osg::StateAttribute* texture = stateset.getTextureAttribute(i,osg::StateAttribute::TEXTURE);
|
|
if (texture)
|
|
{
|
|
osg::TextureRectangle* textureRect = dynamic_cast<osg::TextureRectangle*>(texture);
|
|
if (textureRect)
|
|
{
|
|
osg::ImageStream* imageStream = dynamic_cast<osg::ImageStream*>(textureRect->getImage());
|
|
if (imageStream)
|
|
{
|
|
imageStream->quit();
|
|
}
|
|
}
|
|
|
|
osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(texture);
|
|
if (texture2D)
|
|
{
|
|
osg::ImageStream* imageStream = dynamic_cast<osg::ImageStream*>(texture2D->getImage());
|
|
if (imageStream)
|
|
{
|
|
imageStream->quit();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
OsgCameraGroup::~OsgCameraGroup()
|
|
{
|
|
// kill the DatabasePager and associated thread if one exists.
|
|
osgDB::Registry::instance()->setDatabasePager(0);
|
|
|
|
osg::Node* node = getTopMostSceneData();
|
|
if (node)
|
|
{
|
|
// kill any ImageStream threads
|
|
QuitImageStreamVisitor qisv;
|
|
node->accept(qisv);
|
|
}
|
|
}
|
|
|
|
|
|
static osg::ApplicationUsageProxy OsgCameraGroup_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_CAMERA_THREADING <value>","Set the threading model using by osgProducer::Viewer/OsgCameraGroup based apps. <value> can be SingleThreaded or ThreadPerCamera");
|
|
static osg::ApplicationUsageProxy OsgCameraGroup_e3(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_SHARE_GRAPHICS_CONTEXTS <value>","Set whether to share graphics contexts. <value> can be ON or OFF");
|
|
|
|
void OsgCameraGroup::_init()
|
|
{
|
|
if (_cfg.valid())
|
|
{
|
|
// By default select ThreadPerCamera when we have multiple cameras.
|
|
_thread_model = (_cfg->getNumberOfCameras()>1) ? ThreadPerCamera : SingleThreaded;
|
|
}
|
|
|
|
const char* str = getenv("OSG_CAMERA_THREADING");
|
|
if (str)
|
|
{
|
|
if (strcmp(str,"SingleThreaded")==0) _thread_model = SingleThreaded;
|
|
else if (strcmp(str,"ThreadPerCamera")==0) _thread_model = ThreadPerCamera;
|
|
}
|
|
|
|
str = getenv("OSG_SHARE_GRAPHICS_CONTEXTS");
|
|
if (str)
|
|
{
|
|
if (strcmp(str,"ON")==0) Producer::RenderSurface::shareAllGLContexts(true);
|
|
else if (strcmp(str,"OFF")==0) Producer::RenderSurface::shareAllGLContexts(false);
|
|
}
|
|
|
|
if (_thread_model==ThreadPerCamera && _cfg->getNumberOfCameras()>1)
|
|
{
|
|
// switch on thread safe reference counting by default when running multi-threaded.
|
|
// osg::Referenced::setThreadSafeReferenceCounting(true);
|
|
}
|
|
|
|
_scene_data = NULL;
|
|
_global_stateset = NULL;
|
|
_clear_color.set( 0.2f, 0.2f, 0.4f, 1.0f );
|
|
|
|
_fusionDistanceMode = osgUtil::SceneView::PROPORTIONAL_TO_SCREEN_DISTANCE;
|
|
_fusionDistanceValue = 1.0f;
|
|
|
|
_realizeSceneViewOptions = osgUtil::SceneView::STANDARD_SETTINGS;
|
|
|
|
_initialized = false;
|
|
|
|
// set up the time and frame counter.
|
|
_frameNumber = 0;
|
|
_start_tick = _timer.tick();
|
|
|
|
if (!_frameStamp) _frameStamp = new osg::FrameStamp;
|
|
|
|
_applicationUsage = osg::ApplicationUsage::instance();
|
|
|
|
}
|
|
|
|
void OsgCameraGroup::setSceneData( osg::Node *scene )
|
|
{
|
|
if (_scene_data==scene) return;
|
|
|
|
if (_scene_decorator.valid() && _scene_data.valid())
|
|
{
|
|
_scene_decorator->removeChild(_scene_data.get());
|
|
}
|
|
|
|
_scene_data = scene;
|
|
|
|
if (_scene_decorator.valid() && _scene_data.valid())
|
|
{
|
|
_scene_decorator->addChild(scene);
|
|
}
|
|
|
|
updatedSceneData();
|
|
}
|
|
|
|
void OsgCameraGroup::setSceneDecorator( osg::Group* decorator)
|
|
{
|
|
if (_scene_decorator==decorator) return;
|
|
|
|
_scene_decorator = decorator;
|
|
|
|
if (_scene_data.valid() && decorator)
|
|
{
|
|
decorator->addChild(_scene_data.get());
|
|
}
|
|
updatedSceneData();
|
|
}
|
|
|
|
|
|
void OsgCameraGroup::updatedSceneData()
|
|
{
|
|
setUpSceneViewsWithData();
|
|
}
|
|
|
|
void OsgCameraGroup::setUpSceneViewsWithData()
|
|
{
|
|
for(SceneHandlerList::iterator p = _shvec.begin(); p != _shvec.end(); p++ )
|
|
{
|
|
osgUtil::SceneView* sv = (*p)->getSceneView();
|
|
|
|
if (_scene_decorator.valid())
|
|
{
|
|
sv->setSceneData( _scene_decorator.get() );
|
|
}
|
|
else if (_scene_data.valid())
|
|
{
|
|
sv->setSceneData( _scene_data.get() );
|
|
}
|
|
else
|
|
{
|
|
sv->setSceneData( 0 );
|
|
}
|
|
|
|
sv->setFrameStamp( _frameStamp.get() );
|
|
sv->setGlobalStateSet( _global_stateset.get() );
|
|
sv->setFusionDistance( _fusionDistanceMode, _fusionDistanceValue );
|
|
}
|
|
}
|
|
|
|
|
|
void OsgCameraGroup::setFrameStamp( osg::FrameStamp* fs )
|
|
{
|
|
_frameStamp = fs;
|
|
setUpSceneViewsWithData();
|
|
}
|
|
|
|
|
|
void OsgCameraGroup::setGlobalStateSet( osg::StateSet *sset )
|
|
{
|
|
_global_stateset = sset;
|
|
setUpSceneViewsWithData();
|
|
}
|
|
|
|
void OsgCameraGroup::setClearColor( const osg::Vec4& clearColor )
|
|
{
|
|
_clear_color = clearColor;
|
|
for(unsigned int i=0;i<getNumberOfCameras();++i)
|
|
{
|
|
Producer::Camera *cam = _cfg->getCamera(i);
|
|
cam->setClearColor(_clear_color[0],_clear_color[1],_clear_color[2],_clear_color[3]);
|
|
}
|
|
}
|
|
|
|
const osg::Vec4& OsgCameraGroup::getClearColor() const
|
|
{
|
|
return _clear_color;
|
|
}
|
|
|
|
void OsgCameraGroup::setLODScale( float scale )
|
|
{
|
|
getCullSettings().setLODScale(scale);
|
|
setUpSceneViewsWithData();
|
|
}
|
|
|
|
float OsgCameraGroup::getLODScale() const
|
|
{
|
|
return getCullSettings().getLODScale();
|
|
}
|
|
|
|
void OsgCameraGroup::setFusionDistance( osgUtil::SceneView::FusionDistanceMode mode,float value)
|
|
{
|
|
// need to set a local variable?
|
|
_fusionDistanceMode = mode;
|
|
_fusionDistanceValue = value;
|
|
setUpSceneViewsWithData();
|
|
}
|
|
|
|
void OsgCameraGroup::advance()
|
|
{
|
|
if( !_initialized ) return;
|
|
CameraGroup::advance();
|
|
}
|
|
|
|
bool OsgCameraGroup::realize( ThreadingModel thread_model )
|
|
{
|
|
if( _realized ) return _realized;
|
|
_thread_model = thread_model;
|
|
return realize();
|
|
}
|
|
|
|
|
|
// small visitor to check for the existance of particle systems,
|
|
// which currently arn't thread safe, so we would need to disable
|
|
// multithreading of cull and draw.
|
|
class SearchForSpecialNodes : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
SearchForSpecialNodes():
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_foundParticles(false),
|
|
_foundPagedLOD(false)
|
|
{
|
|
}
|
|
|
|
virtual void apply(osg::Node& node)
|
|
{
|
|
if (strcmp(node.libraryName(),"osgParticle")==0) _foundParticles = true;
|
|
|
|
if (!_foundParticles ||
|
|
!_foundPagedLOD) traverse(node);
|
|
}
|
|
|
|
virtual void apply(osg::PagedLOD& node)
|
|
{
|
|
_foundPagedLOD = true;
|
|
apply((osg::Node&)node);
|
|
}
|
|
|
|
bool _foundParticles;
|
|
bool _foundPagedLOD;
|
|
};
|
|
|
|
bool OsgCameraGroup::realize()
|
|
{
|
|
if( _initialized ) return _realized;
|
|
|
|
if (!_ds) _ds = osg::DisplaySettings::instance();
|
|
|
|
_shvec.clear();
|
|
|
|
osg::Node* node = getTopMostSceneData();
|
|
if (node)
|
|
{
|
|
// traverse the scene graphs gathering the requirements of the OpenGL buffers.
|
|
osgUtil::DisplayRequirementsVisitor drv;
|
|
drv.setDisplaySettings(_ds.get());
|
|
node->accept(drv);
|
|
}
|
|
|
|
unsigned int numMultiSamples = 0;
|
|
|
|
#ifdef __sgi
|
|
// switch on anti-aliasing by default, just in case we have an Onyx :-)
|
|
numMultiSamples = 4;
|
|
#endif
|
|
|
|
// set up each render stage to clear the appropriate buffers.
|
|
GLbitfield clear_mask=0;
|
|
if (_ds->getRGB()) clear_mask |= GL_COLOR_BUFFER_BIT;
|
|
if (_ds->getDepthBuffer()) clear_mask |= GL_DEPTH_BUFFER_BIT;
|
|
if (_ds->getStencilBuffer()) clear_mask |= GL_STENCIL_BUFFER_BIT;
|
|
|
|
// make sure any camera's which share the same render surface also share the same osg::State.
|
|
// use a std::map to keep track of what render surfaces are associated with what state.
|
|
typedef std::map<Producer::RenderSurface*,osg::State*> RenderSurfaceStateMap;
|
|
RenderSurfaceStateMap _renderSurfaceStateMap;
|
|
|
|
bool needToCreatedNewContextID = true;
|
|
unsigned int contextID = 0;
|
|
|
|
for(unsigned int i = 0; i < _cfg->getNumberOfCameras(); i++ )
|
|
{
|
|
Producer::Camera *cam = _cfg->getCamera(i);
|
|
Producer::RenderSurface* rs = cam->getRenderSurface();
|
|
|
|
cam->setClearColor(_clear_color[0],_clear_color[1],_clear_color[2],_clear_color[3]);
|
|
|
|
// get or create the scene handler.
|
|
osgProducer::OsgSceneHandler *sh;
|
|
sh = dynamic_cast<osgProducer::OsgSceneHandler*>(cam->getSceneHandler());
|
|
if(sh == NULL)
|
|
sh = new osgProducer::OsgSceneHandler(_ds.get());
|
|
|
|
osgUtil::SceneView* sv = sh->getSceneView();
|
|
sv->setDefaults(_realizeSceneViewOptions);
|
|
|
|
if (_renderSurfaceStateMap.count(rs)==0)
|
|
{
|
|
_renderSurfaceStateMap[rs] = sv->getState();
|
|
|
|
if (needToCreatedNewContextID)
|
|
{
|
|
// create a unique contextID for this graphics context.
|
|
contextID = osg::GraphicsContext::createNewContextID();
|
|
|
|
// if we are sharing our graphics context then when needn't create any more.
|
|
needToCreatedNewContextID = !Producer::RenderSurface::allGLContextsAreShared();
|
|
}
|
|
else
|
|
{
|
|
osg::GraphicsContext::incrementContextIDUsageCount(contextID);
|
|
}
|
|
|
|
sv->getState()->setContextID(contextID);
|
|
}
|
|
else
|
|
{
|
|
sv->setState(_renderSurfaceStateMap[rs]);
|
|
}
|
|
|
|
_shvec.push_back( sh );
|
|
cam->setSceneHandler( sh );
|
|
|
|
// set up the clear mask.
|
|
osgUtil::RenderStage *stage = sv->getRenderStage();
|
|
if (stage) stage->setClearMask(clear_mask);
|
|
|
|
// set the realize callback.
|
|
rs->setRealizeCallback( new RenderSurfaceRealizeCallback(this, sh));
|
|
|
|
// set up the visual chooser.
|
|
if (_ds.valid() || numMultiSamples!=0)
|
|
{
|
|
|
|
Producer::VisualChooser* rs_vc = rs->getVisualChooser();
|
|
if (!rs_vc)
|
|
{
|
|
rs_vc = new Producer::VisualChooser;
|
|
rs_vc->setSimpleConfiguration();
|
|
rs->setVisualChooser(rs_vc);
|
|
}
|
|
|
|
unsigned int numStencilBits = 0;
|
|
if (_ds->getStereo())
|
|
{
|
|
switch(_ds->getStereoMode())
|
|
{
|
|
case(osg::DisplaySettings::QUAD_BUFFER):
|
|
rs_vc->useStereo();
|
|
break;
|
|
case(osg::DisplaySettings::HORIZONTAL_INTERLACE):
|
|
case(osg::DisplaySettings::VERTICAL_INTERLACE):
|
|
numStencilBits = 8;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// set up stencil buffer if required.
|
|
numStencilBits = osg::maximum(numStencilBits,_ds->getMinimumNumStencilBits());
|
|
if (numStencilBits > 0)
|
|
{
|
|
rs_vc->setStencilSize(numStencilBits);
|
|
}
|
|
|
|
if (_ds->getAlphaBuffer()) rs_vc->setAlphaSize(_ds->getMinimumNumAlphaBits());
|
|
|
|
rs_vc->setDepthSize(24);
|
|
|
|
if (_ds->getAccumBuffer())
|
|
{
|
|
rs_vc->setAccumRedSize(_ds->getMinimumNumAccumRedBits());
|
|
rs_vc->setAccumGreenSize(_ds->getMinimumNumAccumGreenBits());
|
|
rs_vc->setAccumBlueSize(_ds->getMinimumNumAccumBlueBits());
|
|
rs_vc->setAccumAlphaSize(_ds->getMinimumNumAccumAlphaBits());
|
|
}
|
|
|
|
if (numMultiSamples)
|
|
{
|
|
#if defined( GLX_SAMPLES_SGIS )
|
|
rs_vc->addExtendedAttribute( GLX_SAMPLES_SGIS, numMultiSamples);
|
|
#endif
|
|
#if defined( GLX_SAMPLES_BUFFER_SGIS )
|
|
rs_vc->addExtendedAttribute( GLX_SAMPLES_BUFFER_SGIS, 1);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// now set up GraphicsContext wrappers for each of the render surfaces
|
|
// to all core OSG classes to keep track of the graphics context.
|
|
for(RenderSurfaceStateMap::iterator ritr = _renderSurfaceStateMap.begin();
|
|
ritr != _renderSurfaceStateMap.end();
|
|
++ritr)
|
|
{
|
|
Producer::RenderSurface* rs = ritr->first;
|
|
osg::State* state = ritr->second;
|
|
GraphicsContextImplementation* gc = new GraphicsContextImplementation(rs);
|
|
gc->setState(state);
|
|
state->setGraphicsContext(gc);
|
|
_gcList.push_back(gc);
|
|
}
|
|
|
|
if( _global_stateset == NULL && _shvec.size() > 0 )
|
|
{
|
|
SceneHandlerList::iterator p = _shvec.begin();
|
|
_global_stateset = (*p)->getSceneView()->getGlobalStateSet();
|
|
}
|
|
|
|
setUpSceneViewsWithData();
|
|
|
|
// if we are multi-threaded check to see if particle exists in the scene
|
|
// if so we need to disable multi-threading of cameras.
|
|
if (_thread_model == Producer::CameraGroup::ThreadPerCamera)
|
|
{
|
|
if (getTopMostSceneData())
|
|
{
|
|
SearchForSpecialNodes sfsn;
|
|
getTopMostSceneData()->accept(sfsn);
|
|
if (sfsn._foundParticles)
|
|
{
|
|
osg::notify(osg::INFO)<<"Warning: disabling multi-threading of cull and draw"<<std::endl;
|
|
osg::notify(osg::INFO)<<" to avoid threading problems in osgParticle."<<std::endl;
|
|
_thread_model = Producer::CameraGroup::SingleThreaded;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// if we are still multi-thread check to make sure that no render surfaces
|
|
// are shared and don't use shared contexts, if they do we need to
|
|
// disable multi-threading of cameras.
|
|
if (_thread_model == Producer::CameraGroup::ThreadPerCamera)
|
|
{
|
|
std::set<RenderSurface*> renderSurfaceSet;
|
|
for( unsigned int i = 0; i < _cfg->getNumberOfCameras(); i++ )
|
|
{
|
|
Producer::Camera *cam = _cfg->getCamera(i);
|
|
renderSurfaceSet.insert(cam->getRenderSurface());
|
|
}
|
|
if (renderSurfaceSet.size()!=_cfg->getNumberOfCameras())
|
|
{
|
|
// camera's must be sharing a RenderSurface, so we need to ensure that we're
|
|
// running single threaded, to avoid OpenGL threading issues.
|
|
osg::notify(osg::INFO)<<"Warning: disabling multi-threading of cull and draw to avoid"<<std::endl;
|
|
osg::notify(osg::INFO)<<" threading problems when camera's share a RenderSurface."<<std::endl;
|
|
_thread_model = Producer::CameraGroup::SingleThreaded;
|
|
}
|
|
else if (renderSurfaceSet.size()>1 && RenderSurface::allGLContextsAreShared())
|
|
{
|
|
// we have multiple RenderSurface, but with share contexts, which is dangerous for multi-threaded usage,
|
|
// so need to disable multi-threading to prevent problems.
|
|
osg::notify(osg::INFO)<<"Warning: disabling multi-threading of cull and draw to avoid"<<std::endl;
|
|
osg::notify(osg::INFO)<<" threading problems when sharing graphics contexts within RenderSurface."<<std::endl;
|
|
_thread_model = Producer::CameraGroup::SingleThreaded;
|
|
}
|
|
|
|
}
|
|
|
|
if (_thread_model==Producer::CameraGroup::SingleThreaded)
|
|
{
|
|
osg::notify(osg::INFO)<<"OsgCameraGroup::realize() _thread_model==Producer::CameraGroup::SingleThreaded"<<std::endl;
|
|
}
|
|
else
|
|
{
|
|
osg::notify(osg::INFO)<<"OsgCameraGroup::realize() _thread_model==Producer::CameraGroup::ThreadPerCamera"<<std::endl;
|
|
}
|
|
|
|
_initialized = CameraGroup::realize();
|
|
|
|
return _initialized;
|
|
}
|
|
|
|
osg::Node* OsgCameraGroup::getTopMostSceneData()
|
|
{
|
|
if (_scene_decorator.valid())
|
|
return _scene_decorator.get();
|
|
else
|
|
return _scene_data.get();
|
|
}
|
|
|
|
const osg::Node* OsgCameraGroup::getTopMostSceneData() const
|
|
{
|
|
if (_scene_decorator.valid())
|
|
return _scene_decorator.get();
|
|
else
|
|
return _scene_data.get();
|
|
}
|
|
|
|
void OsgCameraGroup::setView(const osg::Matrixd& matrix)
|
|
{
|
|
Producer::Matrix pm(matrix.ptr());
|
|
|
|
setViewByMatrix(pm);
|
|
}
|
|
|
|
osg::Matrixd OsgCameraGroup::getViewMatrix() const
|
|
{
|
|
osg::Matrixd matrix;
|
|
if (_cfg.valid() && _cfg->getNumberOfCameras()>=1)
|
|
{
|
|
const Producer::Camera *cam = _cfg->getCamera(0);
|
|
matrix.set(cam->getViewMatrix());
|
|
}
|
|
return matrix;
|
|
}
|
|
|
|
static osg::Timer_t _last_frame_tick = 0;
|
|
static osg::Timer_t _previous_previous_frame_tick = 0;
|
|
static osg::Timer_t _previous_frame_tick = 0;
|
|
static bool _useStartOfUpdateForFrameTime = true;
|
|
|
|
void OsgCameraGroup::sync()
|
|
{
|
|
CameraGroup::sync();
|
|
|
|
// set the frame stamp for the new frame.
|
|
_frameStamp->setFrameNumber(_frameNumber++);
|
|
|
|
if (_useStartOfUpdateForFrameTime)
|
|
{
|
|
double time_since_start = _timer.delta_s(_start_tick,_timer.tick());
|
|
_frameStamp->setReferenceTime(time_since_start);
|
|
}
|
|
else
|
|
{
|
|
osg::Timer_t endOfNewFrameTick = _last_frame_tick + (_last_frame_tick-_previous_previous_frame_tick);
|
|
double estimatedSwapTimeForFrame = _timer.delta_s(_start_tick,endOfNewFrameTick);
|
|
|
|
_frameStamp->setReferenceTime(estimatedSwapTimeForFrame);
|
|
}
|
|
}
|
|
|
|
void OsgCameraGroup::frame()
|
|
{
|
|
if (!_useStartOfUpdateForFrameTime)
|
|
{
|
|
_previous_previous_frame_tick = _previous_frame_tick;
|
|
_previous_frame_tick = _last_frame_tick;
|
|
_last_frame_tick = _timer.tick();
|
|
}
|
|
|
|
osg::Node* node = getTopMostSceneData();
|
|
if (node) node->getBound();
|
|
|
|
|
|
// pass on the cull settings to the scene views to keep
|
|
// the settings in sync.
|
|
for(SceneHandlerList::iterator itr = _shvec.begin();
|
|
itr != _shvec.end();
|
|
++itr)
|
|
{
|
|
(*itr)->getSceneView()->inheritCullSettings(_cullSettings);
|
|
}
|
|
|
|
|
|
CameraGroup::frame();
|
|
}
|
|
|
|
void OsgCameraGroup::cleanup_frame()
|
|
{
|
|
// first relase all GL objects and switch on the flush of deleted objects
|
|
// in the next frame.
|
|
for(SceneHandlerList::iterator itr = _shvec.begin();
|
|
itr != _shvec.end();
|
|
++itr)
|
|
{
|
|
(*itr)->getSceneView()->releaseAllGLObjects();
|
|
(*itr)->getSceneView()->setRenderStage(0);
|
|
(*itr)->setCleanUpOnNextFrame(true);
|
|
}
|
|
|
|
// make sure that the registry all flushes all its texture objects.
|
|
osgDB::Registry::instance()->releaseGLObjects();
|
|
|
|
// then run the frame to do the actuall OpenGL clean up.
|
|
frame();
|
|
}
|
|
|
|
|