1
0
Fork 0

CompositeViewer: Support for multiple view windows using osgViewer::CompositeViewer.

Overview:

    Previously Flightgear always used a single osgViewer::Viewer(), which
    inherits from both osgViewer::ViewerBase and osgViewer::View, giving a
    single view window.

    If CompositeViewer is enabled, we instead use a osgViewer::CompositeViewer
    which contains a list of osgViewer::View's. Each of these View's can have
    its own eye position, so we can have multiple different views of the same
    scene.

    Enable at runtime with: --composite-viewer=1

Changes to allow use of osgViewer::CompositeViewer:

    Previously FGRenderer had this method:

        osgViewer::Viewer* getViewer();

    This has been replaced by these two new methods:

        osgViewer::ViewerBase* getViewerBase();
        osgViewer::View* getView();

    If CompositeViewer is not enabled (the default), the actual runtime state
    is unchanged, and getViewerBase() and getView() both return a pointer to
    the singleton osgViewer::Viewer() object.

    If CompositeViewer is enabled, getViewerBase() returns a pointer to a
    singleton osgViewer::CompositeViewer object, and getView() returns a
    pointer to the first osgViewer::View in the osgViewer::CompositeViewer's
    list.

    The other significant change to FGRenderer() is the new method:

        osg::FrameStamp* getFrameStamp()

    If CompositeViewer is not enabled, this simply returns
    getView()->getFrameStamp(). If CompositeViewer is enabled it returns
    getViewerBase()->getFrameStamp(). It is important that code that previously
    called getView()->getFrameStamp() is changed to use the new method, because
    when CompositeViewer is enabled individual osgViewer::View's appear to
    return an osg::FrameStamp with zero frame number).

    All code that uses FGRenderer has been patched up to use the new methods so
    that things work as before regardless of whether CompositeViewer is enabled
    or not.

    We make FGRenderer::update() call SviewUpdate() which updates any extra
    views.

Extra view windows:

    If CompositeViewer is enabled, one can create top-level extra view windows
    by calling SviewCreate(). See src/Viewer/sview.hxx for details.

    Each extra view window has its own simgear::compositor::Compositor
    instance.

    Currently SviewCreate() can create extra view windows that clone the
    current view, or view from one point to another (e.g. from one multiplayer
    aircraft to the user's aircradt) or keep two aircraft in view, one at a
    fixed distance in the foreground.

    SviewCreate() can be called from nasal via new nasal commands "view-clone",
    "view-last-pair", "view-last-pair-double" and "view-push". Associated
    changes to fgdata gives access to these via the View menu. The "view-push"
    command tags the current view for later use by "view-last-pair" and
    "view-last-pair-double".

    Extra view windows created by SviewCreate() use a new view system called
    Sview, which allows views to be constructed at runtime instead of being
    hard-coded in *-set.xml files. This is work in progress and views aren't
    all fully implemented. For example Pilot view gets things slightly wrong
    with large roll values, Tower View AGL is not implemented, and we don't
    implement damping. See top of src/Viewer/sview.cxx for an overview.

OpenSceneGraph-3.4 issues:

    OSG-3.4's event handling seems to be incorrect with CompositeViewer -
    events get sent for the wrong window which causes issues with resize and
    closing. It doesn't seem to be possible to work around this, so closing
    extra view windows can end up closing the main window for example.

    OSG-3.6 seems to fix the problems.

    We warn if CompositeViewer is enabled and OpenSceneGraph is 3.4.
This commit is contained in:
Julian Smith 2020-11-16 18:43:46 +00:00
parent 578f414c42
commit f62e5b9ce3
31 changed files with 1972 additions and 172 deletions

View file

@ -672,7 +672,7 @@ void GUIMgr::init()
_event_handler = new GUIEventHandler(desktop); _event_handler = new GUIEventHandler(desktop);
globals->get_renderer() globals->get_renderer()
->getViewer() ->getView()
->getEventHandlers() ->getEventHandlers()
// GUI is on top of everything so lets install as first event handler // GUI is on top of everything so lets install as first event handler
.push_front( _event_handler ); .push_front( _event_handler );
@ -706,7 +706,7 @@ void GUIMgr::shutdown()
if( _event_handler ) if( _event_handler )
{ {
globals->get_renderer() globals->get_renderer()
->getViewer() ->getView()
->removeEventHandler( _event_handler ); ->removeEventHandler( _event_handler );
_event_handler = 0; _event_handler = 0;
} }

View file

@ -85,7 +85,7 @@ void CocoaFileDialog::exec()
// it window-modal. // it window-modal.
NSWindow* cocoaWindow = nil; NSWindow* cocoaWindow = nil;
std::vector<osgViewer::GraphicsWindow*> windows; std::vector<osgViewer::GraphicsWindow*> windows;
globals->get_renderer()->getViewer()->getWindows(windows); globals->get_renderer()->getViewerBase()->getWindows(windows);
for (auto gw : windows) { for (auto gw : windows) {
// OSG doesn't use RTTI, so no dynamic cast. Let's check the class type // OSG doesn't use RTTI, so no dynamic cast. Let's check the class type

View file

@ -26,11 +26,11 @@ namespace {
HWND getMainViewerHWND() HWND getMainViewerHWND()
{ {
osgViewer::Viewer::Windows windows; osgViewer::Viewer::Windows windows;
if (!globals->get_renderer() || !globals->get_renderer()->getViewer()) { if (!globals->get_renderer() || !globals->get_renderer()->getViewerBase()) {
return 0; return 0;
} }
globals->get_renderer()->getViewer()->getWindows(windows); globals->get_renderer()->getViewerBase()->getWindows(windows);
osgViewer::Viewer::Windows::const_iterator it = windows.begin(); osgViewer::Viewer::Windows::const_iterator it = windows.begin();
for(; it != windows.end(); ++it) { for(; it != windows.end(); ++it) {
if (strcmp((*it)->className(), "GraphicsWindowWin32")) { if (strcmp((*it)->className(), "GraphicsWindowWin32")) {

View file

@ -61,11 +61,11 @@ bool isCanvasImplementationRegistered()
HWND getMainViewerHWND() HWND getMainViewerHWND()
{ {
osgViewer::Viewer::Windows windows; osgViewer::Viewer::Windows windows;
if (!globals || !globals->get_renderer() || !globals->get_renderer()->getViewer()) { if (!globals || !globals->get_renderer() || !globals->get_renderer()->getViewerBase()) {
return 0; return 0;
} }
globals->get_renderer()->getViewer()->getWindows(windows); globals->get_renderer()->getViewerBase()->getWindows(windows);
osgViewer::Viewer::Windows::const_iterator it = windows.begin(); osgViewer::Viewer::Windows::const_iterator it = windows.begin();
for(; it != windows.end(); ++it) { for(; it != windows.end(); ++it) {
if (strcmp((*it)->className(), "GraphicsWindowWin32")) { if (strcmp((*it)->className(), "GraphicsWindowWin32")) {

View file

@ -62,7 +62,7 @@ public:
{ {
mActualCursor = mCursor; mActualCursor = mCursor;
globals->get_renderer()->getViewer()->getWindows(mWindows); globals->get_renderer()->getViewerBase()->getWindows(mWindows);
} }
virtual void setCursor(Cursor aCursor) virtual void setCursor(Cursor aCursor)
@ -160,7 +160,7 @@ FGMouseCursor* FGMouseCursor::instance()
#ifdef SG_WINDOWS #ifdef SG_WINDOWS
// set osgViewer cursor inherit, otherwise it will interefere // set osgViewer cursor inherit, otherwise it will interefere
std::vector<osgViewer::GraphicsWindow*> gws; std::vector<osgViewer::GraphicsWindow*> gws;
globals->get_renderer()->getViewer()->getWindows(gws); globals->get_renderer()->getViewerBase()->getWindows(gws);
for (auto gw : gws) { for (auto gw : gws) {
gw->setCursor(osgViewer::GraphicsWindow::InheritCursor); gw->setCursor(osgViewer::GraphicsWindow::InheritCursor);
} }

View file

@ -20,11 +20,11 @@ namespace {
HWND getMainViewerHWND() HWND getMainViewerHWND()
{ {
osgViewer::Viewer::Windows windows; osgViewer::Viewer::Windows windows;
if (!globals->get_renderer() || !globals->get_renderer()->getViewer()) { if (!globals->get_renderer() || !globals->get_renderer()->getViewerBase()) {
return 0; return 0;
} }
globals->get_renderer()->getViewer()->getWindows(windows); globals->get_renderer()->getViewerBase()->getWindows(windows);
osgViewer::Viewer::Windows::const_iterator it = windows.begin(); osgViewer::Viewer::Windows::const_iterator it = windows.begin();
for(; it != windows.end(); ++it) { for(; it != windows.end(); ++it) {
if (strcmp((*it)->className(), "GraphicsWindowWin32")) { if (strcmp((*it)->className(), "GraphicsWindowWin32")) {

View file

@ -361,6 +361,54 @@ do_view_cycle (const SGPropertyNode * arg, SGPropertyNode * root)
return true; return true;
} }
/**
* Built-in command: view-push.
*/
static bool
do_view_push (const SGPropertyNode * arg, SGPropertyNode * root)
{
SG_LOG(SG_GENERAL, SG_ALERT, "do_view_push() called");
globals->get_viewmgr()->view_push();
return true;
}
/**
* Built-in command: clone view.
*/
static bool
do_view_clone (const SGPropertyNode * arg, SGPropertyNode * root)
{
SG_LOG(SG_GENERAL, SG_ALERT, "do_view_clone() called");
globals->get_viewmgr()->clone_current_view();
return true;
}
/**
* Built-in command: view last pair.
*/
static bool
do_view_last_pair (const SGPropertyNode * arg, SGPropertyNode * root)
{
SG_LOG(SG_GENERAL, SG_ALERT, "do_view_last_pair() called");
globals->get_viewmgr()->clone_last_pair();
return true;
}
/**
* Built-in command: double view last pair.
*/
static bool
do_view_last_pair_double (const SGPropertyNode * arg, SGPropertyNode * root)
{
SG_LOG(SG_GENERAL, SG_ALERT, "do_view_last_pair_double() called");
globals->get_viewmgr()->clone_last_pair_double();
return true;
}
/** /**
* Built-in command: toggle a bool property value. * Built-in command: toggle a bool property value.
* *
@ -948,6 +996,10 @@ static struct {
{ "save-tape", do_save_tape }, { "save-tape", do_save_tape },
{ "load-tape", do_load_tape }, { "load-tape", do_load_tape },
{ "view-cycle", do_view_cycle }, { "view-cycle", do_view_cycle },
{ "view-push", do_view_push },
{ "view-clone", do_view_clone },
{ "view-last-pair", do_view_last_pair },
{ "view-last-pair-double", do_view_last_pair_double },
/* /*
{ "set-sea-level-air-temp-degc", do_set_sea_level_degc }, { "set-sea-level-air-temp-degc", do_set_sea_level_degc },
{ "set-outside-air-temp-degc", do_set_oat_degc }, { "set-outside-air-temp-degc", do_set_oat_degc },

View file

@ -1283,7 +1283,7 @@ void fgStartNewReset()
FGRenderer* render = globals->get_renderer(); FGRenderer* render = globals->get_renderer();
// needed or we crash in multi-threaded OSG mode // needed or we crash in multi-threaded OSG mode
render->getViewer()->stopThreading(); render->getViewerBase()->stopThreading();
// order is important here since tile-manager shutdown needs to // order is important here since tile-manager shutdown needs to
// access the scenery object // access the scenery object
@ -1294,8 +1294,8 @@ void fgStartNewReset()
// don't cancel the pager until after shutdown, since AIModels (and // don't cancel the pager until after shutdown, since AIModels (and
// potentially others) can queue delete requests on the pager. // potentially others) can queue delete requests on the pager.
render->getViewer()->getDatabasePager()->cancel(); render->getView()->getDatabasePager()->cancel();
render->getViewer()->getDatabasePager()->clear(); render->getView()->getDatabasePager()->clear();
osgDB::Registry::instance()->clearObjectCache(); osgDB::Registry::instance()->clearObjectCache();
// Pager requests depend on this, so don't clear it until now // Pager requests depend on this, so don't clear it until now
@ -1376,7 +1376,7 @@ void fgStartNewReset()
eventHandler->reset(); eventHandler->reset();
globals->set_renderer(render); globals->set_renderer(render);
render->init(); render->init();
render->setViewer(viewer.get()); render->setView(viewer.get());
sgUserDataInit( globals->get_props() ); sgUserDataInit( globals->get_props() );

View file

@ -195,15 +195,15 @@ FGGlobals::~FGGlobals()
// stop OSG threading first, to avoid thread races while we tear down // stop OSG threading first, to avoid thread races while we tear down
// scene-graph pieces // scene-graph pieces
// there are some scenarios where renderer is already gone. // there are some scenarios where renderer is already gone.
osg::ref_ptr<osgViewer::Viewer> vw; osg::ref_ptr<osgViewer::ViewerBase> vb;
if (renderer) { if (renderer) {
vw = renderer->getViewer(); vb = renderer->getViewerBase();
if (vw) { if (vb) {
// https://code.google.com/p/flightgear-bugs/issues/detail?id=1291 // https://code.google.com/p/flightgear-bugs/issues/detail?id=1291
// explicitly stop trheading before we delete the renderer or // explicitly stop trheading before we delete the renderer or
// viewMgr (which ultimately holds refs to the CameraGroup, and // viewMgr (which ultimately holds refs to the CameraGroup, and
// GraphicsContext) // GraphicsContext)
vw->stopThreading(); vb->stopThreading();
} }
} }
@ -212,9 +212,10 @@ FGGlobals::~FGGlobals()
// don't cancel the pager until after shutdown, since AIModels (and // don't cancel the pager until after shutdown, since AIModels (and
// potentially others) can queue delete requests on the pager. // potentially others) can queue delete requests on the pager.
if (vw && vw->getDatabasePager()) { osgViewer::View* v = renderer->getView();
vw->getDatabasePager()->cancel(); if (v && v->getDatabasePager()) {
vw->getDatabasePager()->clear(); v->getDatabasePager()->cancel();
v->getDatabasePager()->clear();
} }
osgDB::Registry::instance()->clearObjectCache(); osgDB::Registry::instance()->clearObjectCache();
@ -230,7 +231,7 @@ FGGlobals::~FGGlobals()
delete subsystem_mgr; delete subsystem_mgr;
subsystem_mgr = nullptr; // important so ::get_subsystem returns NULL subsystem_mgr = nullptr; // important so ::get_subsystem returns NULL
vw = nullptr; vb = nullptr;
set_matlib(NULL); set_matlib(NULL);
delete time_params; delete time_params;

View file

@ -743,10 +743,6 @@ int fgMainInit( int argc, char **argv )
fntInit(); fntInit();
globals->get_renderer()->preinit(); globals->get_renderer()->preinit();
#if defined(ENABLE_COMPOSITOR)
flightgear::addSentryTag("compositor", "yes");
#endif
if (fgGetBool("/sim/ati-viewport-hack", true)) { if (fgGetBool("/sim/ati-viewport-hack", true)) {
SG_LOG(SG_GENERAL, SG_WARN, "Enabling ATI/AMD viewport hack"); SG_LOG(SG_GENERAL, SG_WARN, "Enabling ATI/AMD viewport hack");
flightgear::addSentryTag("ati-viewport-hack", "enabled"); flightgear::addSentryTag("ati-viewport-hack", "enabled");

View file

@ -1617,6 +1617,7 @@ where:
OPTION_INT - property is an integer OPTION_INT - property is an integer
OPTION_CHANNEL - name of option is the name of a channel OPTION_CHANNEL - name of option is the name of a channel
OPTION_FUNC - the option trigger a function OPTION_FUNC - the option trigger a function
property :
b_param : if type==OPTION_BOOL, b_param : if type==OPTION_BOOL,
value set to the property (has_param is false for boolean) value set to the property (has_param is false for boolean)
s_param : if type==OPTION_STRING, s_param : if type==OPTION_STRING,
@ -1870,6 +1871,7 @@ struct OptionDesc {
{"developer", true, OPTION_IGNORE | OPTION_BOOL, "", false, "", nullptr }, {"developer", true, OPTION_IGNORE | OPTION_BOOL, "", false, "", nullptr },
{"jsbsim-output-directive-file", true, OPTION_STRING, "/sim/jsbsim/output-directive-file", false, "", nullptr }, {"jsbsim-output-directive-file", true, OPTION_STRING, "/sim/jsbsim/output-directive-file", false, "", nullptr },
{"disable-gui", false, OPTION_FUNC, "", false, "", fgOptDisableGUI }, {"disable-gui", false, OPTION_FUNC, "", false, "", fgOptDisableGUI },
{"composite-viewer", true, OPTION_INT, "/sim/rendering/composite-viewer-enabled", "", "", nullptr},
{nullptr, false, 0, nullptr, false, nullptr, nullptr} {nullptr, false, 0, nullptr, false, nullptr, nullptr}
}; };

View file

@ -436,7 +436,7 @@ static InitPosResult setInitialPosFromCarrier( const string& carrier )
static InitPosResult checkCarrierSceneryLoaded(const SGSharedPtr<FGAICarrier> carrierRef) static InitPosResult checkCarrierSceneryLoaded(const SGSharedPtr<FGAICarrier> carrierRef)
{ {
SGVec3d cartPos = carrierRef->getCartPos(); SGVec3d cartPos = carrierRef->getCartPos();
auto framestamp = globals->get_renderer()->getViewer()->getFrameStamp(); auto framestamp = globals->get_renderer()->getFrameStamp();
simgear::CheckSceneryVisitor csnv(globals->get_scenery()->getPager(), simgear::CheckSceneryVisitor csnv(globals->get_scenery()->getPager(),
toOsg(cartPos), toOsg(cartPos),
100.0 /* range in metres */, 100.0 /* range in metres */,

View file

@ -213,7 +213,7 @@ public:
if ( NULL == osgDB::Registry::instance()->getReaderWriterForExtension(_type)) if ( NULL == osgDB::Registry::instance()->getReaderWriterForExtension(_type))
throw sg_format_exception("Unsupported image type: " + type, type); throw sg_format_exception("Unsupported image type: " + type, type);
osg::Camera * camera = findLastCamera(globals->get_renderer()->getViewer(), window); osg::Camera * camera = findLastCamera(globals->get_renderer()->getViewerBase(), window);
if ( NULL == camera) if ( NULL == camera)
throw sg_error("Can't find a camera for window '" + window + "'"); throw sg_error("Can't find a camera for window '" + window + "'");

View file

@ -371,7 +371,7 @@ bool FGStgTerrain::scenery_available(const SGGeod& position, double range_m)
SGVec3f p = SGVec3f::fromGeod(SGGeod::fromGeodM(position, elev)); SGVec3f p = SGVec3f::fromGeod(SGGeod::fromGeodM(position, elev));
osg::FrameStamp* framestamp osg::FrameStamp* framestamp
= globals->get_renderer()->getViewer()->getFrameStamp(); = globals->get_renderer()->getFrameStamp();
FGScenery* pSceneryManager = globals->get_scenery(); FGScenery* pSceneryManager = globals->get_scenery();
simgear::CheckSceneryVisitor csnv(pSceneryManager->getPager(), toOsg(p), range_m, framestamp); simgear::CheckSceneryVisitor csnv(pSceneryManager->getPager(), toOsg(p), range_m, framestamp);

View file

@ -76,8 +76,8 @@ public:
if (_pagedLODMaximumProp->getType() == simgear::props::NONE) { if (_pagedLODMaximumProp->getType() == simgear::props::NONE) {
// not set, use OSG default / environment value variable // not set, use OSG default / environment value variable
osg::ref_ptr<osgViewer::Viewer> viewer(globals->get_renderer()->getViewer()); osg::ref_ptr<osgViewer::View> view(globals->get_renderer()->getView());
int current = viewer->getDatabasePager()->getTargetMaximumNumberOfPageLOD(); int current = view->getDatabasePager()->getTargetMaximumNumberOfPageLOD();
_pagedLODMaximumProp->setIntValue(current); _pagedLODMaximumProp->setIntValue(current);
} }
_pagedLODMaximumProp->addChangeListener(this, true); _pagedLODMaximumProp->addChangeListener(this, true);
@ -106,9 +106,9 @@ public:
_manager->_enableCache = prop->getBoolValue(); _manager->_enableCache = prop->getBoolValue();
} else if (prop == _pagedLODMaximumProp) { } else if (prop == _pagedLODMaximumProp) {
int v = prop->getIntValue(); int v = prop->getIntValue();
osg::ref_ptr<osgViewer::Viewer> viewer(globals->get_renderer()->getViewer()); osg::ref_ptr<osgViewer::View> view(globals->get_renderer()->getView());
if (viewer) { if (view) {
osgDB::DatabasePager* pager = viewer->getDatabasePager(); osgDB::DatabasePager* pager = view->getDatabasePager();
if (pager) pager->setTargetMaximumNumberOfPageLOD(v); if (pager) pager->setTargetMaximumNumberOfPageLOD(v);
} }
} else if (prop == _lodDetailed || prop == _lodBareDelta || prop == _lodRoughDelta) { } else if (prop == _lodDetailed || prop == _lodBareDelta || prop == _lodRoughDelta) {
@ -344,7 +344,7 @@ void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis)
// update timestamps, so all tiles scheduled now are *newer* than any tile previously loaded // update timestamps, so all tiles scheduled now are *newer* than any tile previously loaded
osg::FrameStamp* framestamp osg::FrameStamp* framestamp
= globals->get_renderer()->getViewer()->getFrameStamp(); = globals->get_renderer()->getFrameStamp();
tile_cache.set_current_time(framestamp->getReferenceTime()); tile_cache.set_current_time(framestamp->getReferenceTime());
SGBucket b; SGBucket b;
@ -379,8 +379,7 @@ void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis)
*/ */
void FGTileMgr::update_queues(bool& isDownloadingScenery) void FGTileMgr::update_queues(bool& isDownloadingScenery)
{ {
osg::FrameStamp* framestamp osg::FrameStamp* framestamp = globals->get_renderer()->getFrameStamp();
= globals->get_renderer()->getViewer()->getFrameStamp();
double current_time = framestamp->getReferenceTime(); double current_time = framestamp->getReferenceTime();
double vis = _visibilityMeters->getDoubleValue(); double vis = _visibilityMeters->getDoubleValue();
TileEntry *e; TileEntry *e;

View file

@ -12,6 +12,7 @@ set(SOURCES
splash.cxx splash.cxx
view.cxx view.cxx
viewmgr.cxx viewmgr.cxx
sview.cxx
) )
set(HEADERS set(HEADERS
@ -24,6 +25,7 @@ set(HEADERS
splash.hxx splash.hxx
view.hxx view.hxx
viewmgr.hxx viewmgr.hxx
sview.hxx
) )
if (Qt5Core_FOUND) if (Qt5Core_FOUND)

View file

@ -23,6 +23,7 @@
#include "FGEventHandler.hxx" #include "FGEventHandler.hxx"
#include "WindowBuilder.hxx" #include "WindowBuilder.hxx"
#include "WindowSystemAdapter.hxx" #include "WindowSystemAdapter.hxx"
#include "sview.hxx"
#include <simgear/math/SGRect.hxx> #include <simgear/math/SGRect.hxx>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
@ -192,8 +193,8 @@ typedef std::vector<SGPropertyNode_ptr> SGPropertyNodeVec;
osg::ref_ptr<CameraGroup> CameraGroup::_defaultGroup; osg::ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
CameraGroup::CameraGroup(osgViewer::Viewer* viewer) : CameraGroup::CameraGroup(osgViewer::View* view) :
_viewer(viewer) _viewer(view)
{ {
} }
@ -688,6 +689,9 @@ void CameraGroup::buildCamera(SGPropertyNode* cameraNode)
osg::ref_ptr<SGReaderWriterOptions> options = osg::ref_ptr<SGReaderWriterOptions> options =
SGReaderWriterOptions::fromPath(globals->get_fg_root()); SGReaderWriterOptions::fromPath(globals->get_fg_root());
options->setPropertyNode(globals->get_props()); options->setPropertyNode(globals->get_props());
SViewSetCompositorParams(options, compositor_path);
Compositor *compositor = Compositor::create(_viewer, Compositor *compositor = Compositor::create(_viewer,
window->gc, window->gc,
viewport, viewport,
@ -783,10 +787,10 @@ void CameraGroup::buildGUICamera(SGPropertyNode* cameraNode,
camera->setStats(0); camera->setStats(0);
} }
CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer, CameraGroup* CameraGroup::buildCameraGroup(osgViewer::View* view,
SGPropertyNode* gnode) SGPropertyNode* gnode)
{ {
CameraGroup* cgroup = new CameraGroup(viewer); CameraGroup* cgroup = new CameraGroup(view);
cgroup->_listener.reset(new CameraGroupListener(cgroup, gnode)); cgroup->_listener.reset(new CameraGroupListener(cgroup, gnode));
for (int i = 0; i < gnode->nChildren(); ++i) { for (int i = 0; i < gnode->nChildren(); ++i) {
@ -862,7 +866,7 @@ computeCameraIntersection(const CameraGroup *cgroup,
osgUtil::IntersectionVisitor iv(picker); osgUtil::IntersectionVisitor iv(picker);
iv.setTraversalMask(simgear::PICK_BIT); iv.setTraversalMask(simgear::PICK_BIT);
const_cast<CameraGroup *>(cgroup)->getViewer()->getCamera()->accept(iv); const_cast<CameraGroup *>(cgroup)->getView()->getCamera()->accept(iv);
if (picker->containsIntersections()) { if (picker->containsIntersections()) {
intersections = picker->getIntersections(); intersections = picker->getIntersections();
return true; return true;
@ -921,7 +925,7 @@ void warpGUIPointer(CameraGroup* cgroup, int x, int y)
gw->getEventQueue()->mouseWarped(wx, wy); gw->getEventQueue()->mouseWarped(wx, wy);
gw->requestWarpPointer(wx, wy); gw->requestWarpPointer(wx, wy);
osgGA::GUIEventAdapter* eventState osgGA::GUIEventAdapter* eventState
= cgroup->getViewer()->getEventQueue()->getCurrentEventState(); = cgroup->getView()->getEventQueue()->getCurrentEventState();
double viewerX double viewerX
= (eventState->getXmin() = (eventState->getXmin()
+ ((wx / double(traits->width)) + ((wx / double(traits->width))
@ -930,10 +934,10 @@ void warpGUIPointer(CameraGroup* cgroup, int x, int y)
= (eventState->getYmin() = (eventState->getYmin()
+ ((wyUp / double(traits->height)) + ((wyUp / double(traits->height))
* (eventState->getYmax() - eventState->getYmin()))); * (eventState->getYmax() - eventState->getYmin())));
cgroup->getViewer()->getEventQueue()->mouseWarped(viewerX, viewerY); cgroup->getView()->getEventQueue()->mouseWarped(viewerX, viewerY);
} }
void CameraGroup::buildDefaultGroup(osgViewer::Viewer* viewer) void CameraGroup::buildDefaultGroup(osgViewer::View* viewer)
{ {
// Look for windows, camera groups, and the old syntax of // Look for windows, camera groups, and the old syntax of
// top-level cameras // top-level cameras

View file

@ -30,6 +30,7 @@
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/TexGen> #include <osg/TexGen>
#include <osgUtil/RenderBin> #include <osgUtil/RenderBin>
#include <osgViewer/View>
#include <simgear/scene/viewer/Compositor.hxx> #include <simgear/scene/viewer/Compositor.hxx>
@ -122,14 +123,14 @@ public:
/** Create a camera group associated with an osgViewer::Viewer. /** Create a camera group associated with an osgViewer::Viewer.
* @param viewer the viewer * @param viewer the viewer
*/ */
CameraGroup(osgViewer::Viewer* viewer); CameraGroup(osgViewer::View* viewer);
virtual ~CameraGroup(); virtual ~CameraGroup();
/** Set the default CameraGroup, which is the only one that /** Set the default CameraGroup, which is the only one that
* matters at this time. * matters at this time.
* @param group the group to set. * @param group the group to set.
*/ */
static void buildDefaultGroup(osgViewer::Viewer* viewer); static void buildDefaultGroup(osgViewer::View* view);
static void setDefault(CameraGroup* group) { _defaultGroup = group; } static void setDefault(CameraGroup* group) { _defaultGroup = group; }
/** Get the default CameraGroup. /** Get the default CameraGroup.
* @return the default camera group. * @return the default camera group.
@ -138,7 +139,7 @@ public:
/** Get the camera group's Viewer. /** Get the camera group's Viewer.
* @return the viewer * @return the viewer
*/ */
osgViewer::Viewer* getViewer() { return _viewer.get(); } osgViewer::View* getView() { return _viewer.get(); }
/** Create an osg::Camera from a property node and add it to the /** Create an osg::Camera from a property node and add it to the
* camera group. * camera group.
* @param cameraNode the property node. * @param cameraNode the property node.
@ -192,7 +193,7 @@ protected:
typedef std::vector<osg::ref_ptr<CameraInfo>> CameraList; typedef std::vector<osg::ref_ptr<CameraInfo>> CameraList;
CameraList _cameras; CameraList _cameras;
osg::ref_ptr<osgViewer::Viewer> _viewer; osg::ref_ptr<osgViewer::View> _viewer;
static osg::ref_ptr<CameraGroup> _defaultGroup; static osg::ref_ptr<CameraGroup> _defaultGroup;
std::unique_ptr<CameraGroupListener> _listener; std::unique_ptr<CameraGroupListener> _listener;
@ -206,7 +207,7 @@ protected:
* @param wbuilder the window builder to be used for this camera group. * @param wbuilder the window builder to be used for this camera group.
* @param the camera group property node. * @param the camera group property node.
*/ */
static CameraGroup* buildCameraGroup(osgViewer::Viewer* viewer, static CameraGroup* buildCameraGroup(osgViewer::View* viewer,
SGPropertyNode* node); SGPropertyNode* node);
}; };

View file

@ -12,7 +12,9 @@
#include "CameraGroup.hxx" #include "CameraGroup.hxx"
#include "FGEventHandler.hxx" #include "FGEventHandler.hxx"
#include "WindowSystemAdapter.hxx" #include "WindowSystemAdapter.hxx"
#include "WindowBuilder.hxx"
#include "renderer.hxx" #include "renderer.hxx"
#include "sview.hxx"
#ifdef SG_MAC #ifdef SG_MAC
// hack - during interactive resize on Mac, OSG queues and then flushes // hack - during interactive resize on Mac, OSG queues and then flushes
@ -85,12 +87,18 @@ bool
eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us, eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
int& x, int& y) int& x, int& y)
{ {
flightgear::WindowBuilder* window_builder = flightgear::WindowBuilder::getWindowBuilder();
flightgear::GraphicsWindow* main_window = window_builder->getDefaultWindow();
x = -1; x = -1;
y = -1; y = -1;
const osg::GraphicsContext* eventGC = ea.getGraphicsContext(); const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
if( !eventGC ) if( !eventGC )
return false; // TODO how can this happen? return false; // TODO how can this happen?
if (eventGC != main_window->gc.get()) {
return false;
}
const osg::GraphicsContext::Traits* traits = eventGC->getTraits(); const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault()); osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
if (!guiCamera) if (!guiCamera)
@ -115,6 +123,20 @@ eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
return false; return false;
} }
} }
/* A hack for when we are linked with OSG-3.4 and CompositeViewer is
enabled. It seems that OSG-3.4 incorrectly calls our event handler for
extra view windows (e.g. resize/close events), so we try to detect
this. Unfortunately OSG also messes up <ea>'s graphics context pointer so this
does't alwys work. */
bool isMainWindow(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
{
int x;
int y;
bool ret = eventToViewport(ea, us, x, y);
return ret;
}
} }
bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea, bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
@ -224,6 +246,9 @@ bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
return true; return true;
case osgGA::GUIEventAdapter::RESIZE: case osgGA::GUIEventAdapter::RESIZE:
SG_LOG(SG_VIEW, SG_DEBUG, "FGEventHandler::handle: RESIZE event " << ea.getWindowHeight() << " x " << ea.getWindowWidth() << ", resizable: " << resizable); SG_LOG(SG_VIEW, SG_DEBUG, "FGEventHandler::handle: RESIZE event " << ea.getWindowHeight() << " x " << ea.getWindowWidth() << ", resizable: " << resizable);
if (!isMainWindow(ea, us)) {
return true;
}
CameraGroup::getDefault()->resized(); CameraGroup::getDefault()->resized();
if (resizable) if (resizable)
globals->get_renderer()->resize(ea.getWindowWidth(), ea.getWindowHeight()); globals->get_renderer()->resize(ea.getWindowWidth(), ea.getWindowHeight());
@ -236,6 +261,10 @@ bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
#endif #endif
return true; return true;
case osgGA::GUIEventAdapter::CLOSE_WINDOW: case osgGA::GUIEventAdapter::CLOSE_WINDOW:
if (!isMainWindow(ea, us)) {
return true;
}
// Fall through.
case osgGA::GUIEventAdapter::QUIT_APPLICATION: case osgGA::GUIEventAdapter::QUIT_APPLICATION:
fgOSExit(0); fgOSExit(0);
return true; return true;

View file

@ -275,13 +275,13 @@ PUICamera::~PUICamera()
// depending on if we're doing shutdown or reset, various things can be // depending on if we're doing shutdown or reset, various things can be
// null here. // null here.
auto renderer = globals->get_renderer(); auto renderer = globals->get_renderer();
auto viewer = renderer ? renderer->getViewer() : nullptr; auto view = renderer ? renderer->getView() : nullptr;
if (viewer) { if (view) {
viewer->removeEventHandler(_eventHandler); view->removeEventHandler(_eventHandler);
} }
} }
void PUICamera::init(osg::Group* parent, osgViewer::Viewer* viewer) void PUICamera::init(osg::Group* parent, osgViewer::View* view)
{ {
setName("PUI FBO camera"); setName("PUI FBO camera");
@ -351,7 +351,7 @@ void PUICamera::init(osg::Group* parent, osgViewer::Viewer* viewer)
// the rendering order (i.e top-most UI layer has the front-most event // the rendering order (i.e top-most UI layer has the front-most event
// handler) // handler)
_eventHandler = new PUIEventHandler(this); _eventHandler = new PUIEventHandler(this);
viewer->getEventHandlers().push_front(_eventHandler); view->getEventHandlers().push_front(_eventHandler);
} }
// remove once we require OSG 3.4 // remove once we require OSG 3.4

View file

@ -19,6 +19,7 @@
#include <osg/Camera> #include <osg/Camera>
#include <osg/Version> #include <osg/Version>
#include <osgViewer/View>
namespace osg namespace osg
{ {
@ -51,7 +52,7 @@ public:
// osg::Camera already defines a resize() so use this name // osg::Camera already defines a resize() so use this name
void resizeUi(int width, int height); void resizeUi(int width, int height);
void init(osg::Group* parent, osgViewer::Viewer* viewer); void init(osg::Group* parent, osgViewer::View* view);
private: private:
void manuallyResizeFBO(int width, int height); void manuallyResizeFBO(int width, int height);

View file

@ -189,7 +189,7 @@ class NotifyLevelListener : public SGPropertyChangeListener
public: public:
void valueChanged(SGPropertyNode* node) void valueChanged(SGPropertyNode* node)
{ {
osg::NotifySeverity severity = osg::WARN; osg::NotifySeverity severity = osg::getNotifyLevel();
string val = simgear::strutils::lowercase(node->getStringValue()); string val = simgear::strutils::lowercase(node->getStringValue());
if (val == "fatal") { if (val == "fatal") {
@ -216,6 +216,61 @@ void fgOSOpenWindow(bool stencil)
{ {
osg::setNotifyHandler(new NotifyLogger); osg::setNotifyHandler(new NotifyLogger);
auto composite_viewer = dynamic_cast<osgViewer::CompositeViewer*>(
globals->get_renderer()->getViewerBase()
);
if (0) {}
else if (composite_viewer) {
/* We are using CompositeViewer. */
SG_LOG(SG_VIEW, SG_ALERT, "Using CompositeViewer");
osgViewer::ViewerBase* viewer = globals->get_renderer()->getViewerBase();
SG_LOG(SG_VIEW, SG_ALERT, "Creating osgViewer::View");
osgViewer::View* view = new osgViewer::View;
view->setFrameStamp(composite_viewer->getFrameStamp());
globals->get_renderer()->setView(view);
assert(globals->get_renderer()->getView() == view);
view->setDatabasePager(FGScenery::getPagerSingleton());
// https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg29820.html
view->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true, false);
osg::GraphicsContext::createNewContextID();
//viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
std::string mode;
mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
SG_LOG( SG_VIEW, SG_INFO, "mode=" << mode);
if (mode == "AutomaticSelection")
viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
else if (mode == "CullDrawThreadPerContext")
viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
else if (mode == "DrawThreadPerContext")
viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
else if (mode == "CullThreadPerCameraDrawThreadPerContext")
viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
else
viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
WindowBuilder::initWindowBuilder(stencil);
CameraGroup::buildDefaultGroup(view);
FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
if (wsa->windows.size() != 1) {
manipulator->setResizable(false);
}
view->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
view->addEventHandler(manipulator);
// Let FG handle the escape key with a confirmation
viewer->setKeyEventSetsDone(0);
// The viewer won't start without some root.
view->setSceneData(new osg::Group);
globals->get_renderer()->setView(view);
}
else {
/* Not using CompositeViewer. */
SG_LOG(SG_VIEW, SG_DEBUG, "Not CompositeViewer.");
SG_LOG(SG_VIEW, SG_DEBUG, "Creating osgViewer::Viewer");
viewer = new osgViewer::Viewer; viewer = new osgViewer::Viewer;
viewer->setDatabasePager(FGScenery::getPagerSingleton()); viewer->setDatabasePager(FGScenery::getPagerSingleton());
@ -247,7 +302,8 @@ void fgOSOpenWindow(bool stencil)
viewer->setKeyEventSetsDone(0); viewer->setKeyEventSetsDone(0);
// The viewer won't start without some root. // The viewer won't start without some root.
viewer->setSceneData(new osg::Group); viewer->setSceneData(new osg::Group);
globals->get_renderer()->setViewer(viewer.get()); globals->get_renderer()->setView(viewer.get());
}
} }
SGPropertyNode* simHost = 0, *simFrameCount, *simTotalHostTime, *simFrameResetCount, *frameWait; SGPropertyNode* simHost = 0, *simFrameCount, *simTotalHostTime, *simFrameResetCount, *frameWait;
void fgOSResetProperties() void fgOSResetProperties()
@ -286,8 +342,9 @@ static int status = 0;
void fgOSExit(int code) void fgOSExit(int code)
{ {
viewer->setDone(true); FGRenderer* renderer = globals->get_renderer();
viewer->getDatabasePager()->cancel(); renderer->getViewerBase()->setDone(true);
renderer->getView()->getDatabasePager()->cancel();
status = code; status = code;
// otherwise we crash if OSG does logging during static destruction, eg // otherwise we crash if OSG does logging during static destruction, eg
@ -299,12 +356,13 @@ SGTimeStamp _lastUpdate;
int fgOSMainLoop() int fgOSMainLoop()
{ {
viewer->setReleaseContextAtEndOfFrameHint(false); osgViewer::ViewerBase* viewer_base = globals->get_renderer()->getViewerBase();
if (!viewer->isRealized()) { viewer_base->setReleaseContextAtEndOfFrameHint(false);
viewer->realize(); if (!viewer_base->isRealized()) {
viewer_base->realize();
} }
while (!viewer->done()) { while (!viewer_base->done()) {
fgIdleHandler idleFunc = globals->get_renderer()->getEventHandler()->getIdleHandler(); fgIdleHandler idleFunc = globals->get_renderer()->getEventHandler()->getIdleHandler();
if (idleFunc) if (idleFunc)
{ {
@ -338,7 +396,7 @@ int fgOSMainLoop()
} }
} }
globals->get_renderer()->update(); globals->get_renderer()->update();
viewer->frame( globals->get_sim_time_sec() ); viewer_base->frame( globals->get_sim_time_sec() );
} }
flightgear::addSentryBreadcrumb("main loop exited", "info"); flightgear::addSentryBreadcrumb("main loop exited", "info");
@ -383,13 +441,16 @@ void fgOSInit(int* argc, char** argv)
void fgOSCloseWindow() void fgOSCloseWindow()
{ {
if (viewer) { if (globals && globals->get_renderer()) {
osgViewer::ViewerBase* viewer_base = globals->get_renderer()->getViewerBase();
if (viewer_base) {
// https://code.google.com/p/flightgear-bugs/issues/detail?id=1291 // https://code.google.com/p/flightgear-bugs/issues/detail?id=1291
// https://sourceforge.net/p/flightgear/codetickets/1830/ // https://sourceforge.net/p/flightgear/codetickets/1830/
// explicitly stop threading before we delete the renderer or // explicitly stop threading before we delete the renderer or
// viewMgr (which ultimately holds refs to the CameraGroup, and // viewMgr (which ultimately holds refs to the CameraGroup, and
// GraphicsContext) // GraphicsContext)
viewer->stopThreading(); viewer_base->stopThreading();
}
} }
FGScenery::resetPagerSingleton(); FGScenery::resetPagerSingleton();
flightgear::CameraGroup::setDefault(NULL); flightgear::CameraGroup::setDefault(NULL);
@ -399,8 +460,9 @@ void fgOSCloseWindow()
void fgOSFullScreen() void fgOSFullScreen()
{ {
osgViewer::ViewerBase* viewer_base = globals->get_renderer()->getViewerBase();
std::vector<osgViewer::GraphicsWindow*> windows; std::vector<osgViewer::GraphicsWindow*> windows;
viewer->getWindows(windows); viewer_base->getWindows(windows);
if (windows.empty()) if (windows.empty())
return; // Huh?!? return; // Huh?!?
@ -544,11 +606,14 @@ static int _cursor = -1;
void fgSetMouseCursor(int cursor) void fgSetMouseCursor(int cursor)
{ {
_cursor = cursor; _cursor = cursor;
if (!viewer) if (!globals || !globals->get_renderer())
return;
osgViewer::ViewerBase* viewer_base = globals->get_renderer()->getViewerBase();
if (!viewer_base)
return; return;
std::vector<osgViewer::GraphicsWindow*> windows; std::vector<osgViewer::GraphicsWindow*> windows;
viewer->getWindows(windows); viewer_base->getWindows(windows);
for (osgViewer::GraphicsWindow* gw : windows) { for (osgViewer::GraphicsWindow* gw : windows) {
setMouseCursor(gw, cursor); setMouseCursor(gw, cursor);
} }

View file

@ -115,7 +115,7 @@ fgviewerMain(int argc, char** argv)
// construct the viewer. // construct the viewer.
FGRenderer* fgrenderer = new FGRenderer(); FGRenderer* fgrenderer = new FGRenderer();
osgViewer::Viewer* viewer = new osgViewer::Viewer(arguments); osgViewer::Viewer* viewer = new osgViewer::Viewer(arguments);
fgrenderer->setViewer(viewer); fgrenderer->setView(viewer);
osg::Camera* camera = viewer->getCamera(); osg::Camera* camera = viewer->getCamera();
osgViewer::Renderer* renderer osgViewer::Renderer* renderer
= static_cast<osgViewer::Renderer*>(camera->getRenderer()); = static_cast<osgViewer::Renderer*>(camera->getRenderer());

View file

@ -359,8 +359,8 @@ FGRenderer::~FGRenderer()
} }
// replace the viewer's scene completely // replace the viewer's scene completely
if (getViewer()) { if (getView()) {
getViewer()->setSceneData(new osg::Group); getView()->setSceneData(new osg::Group);
} }
delete _sky; delete _sky;
@ -398,28 +398,39 @@ FGRenderer::addChangeListener(SGPropertyChangeListener* l, const char* path)
} }
// Initialize various GL/view parameters // Initialize various GL/view parameters
//
// Note that this appears to be called *after* FGRenderer::init().
//
void void
FGRenderer::preinit( void ) FGRenderer::preinit( void )
{ {
// important that we reset the viewer sceneData here, to ensure the reference // important that we reset the viewer sceneData here, to ensure the reference
// time for everything is in sync; otherwise on reset the Viewer and // time for everything is in sync; otherwise on reset the Viewer and
// GraphicsWindow clocks are out of sync. // GraphicsWindow clocks are out of sync.
osgViewer::Viewer* viewer = getViewer(); osgViewer::View* view = getView();
viewer->setName("osgViewer"); view->setName("osgViewer");
_viewerSceneRoot = new osg::Group; _viewerSceneRoot = new osg::Group;
_viewerSceneRoot->setName("viewerSceneRoot"); _viewerSceneRoot->setName("viewerSceneRoot");
viewer->setSceneData(_viewerSceneRoot); view->setSceneData(_viewerSceneRoot);
view->setDatabasePager(FGScenery::getPagerSingleton());
_quickDrawable = nullptr; _quickDrawable = nullptr;
_splash = new SplashScreen; _splash = new SplashScreen;
_viewerSceneRoot->addChild(_splash); _viewerSceneRoot->addChild(_splash);
if (composite_viewer) {
// Nothing to do - composite_viewer->addView() will tell view to use
// composite_viewer's FrameStamp.
}
else {
_frameStamp = new osg::FrameStamp; _frameStamp = new osg::FrameStamp;
viewer->setFrameStamp(_frameStamp.get()); view->setFrameStamp(_frameStamp.get());
}
// Scene doesn't seem to pass the frame stamp to the update // Scene doesn't seem to pass the frame stamp to the update
// visitor automatically. // visitor automatically.
_updateVisitor->setFrameStamp(_frameStamp.get()); _updateVisitor->setFrameStamp(getFrameStamp());
viewer->setUpdateVisitor(_updateVisitor.get()); getViewerBase()->setUpdateVisitor(_updateVisitor.get());
fgSetDouble("/sim/startup/splash-alpha", 1.0); fgSetDouble("/sim/startup/splash-alpha", 1.0);
// hide the menubar if it overlaps the window, so the splash screen // hide the menubar if it overlaps the window, so the splash screen
@ -436,6 +447,31 @@ FGRenderer::init( void )
sgUserDataInit( globals->get_props() ); sgUserDataInit( globals->get_props() );
SGPropertyNode* composite_viewer_enabled_prop = fgGetNode("/sim/rendering/composite-viewer-enabled", true);
// After we've read composite_viewer_enabled_prop here, changing its value
// will have no affect, so mark it as read-only for clarity.
composite_viewer_enabled_prop->setAttributes(SGPropertyNode::READ);
if (composite_viewer_enabled_prop->getBoolValue()) {
const char* osg_version = osgGetVersion();
if (simgear::strutils::starts_with(osg_version, "3.4")) {
SG_LOG( SG_GENERAL, SG_POPUP,
"CompositeViewer is enabled and requires OpenSceneGraph-3.6, but\n"
" Flightgear has been built with OpenSceneGraph-" << osg_version << ".\n"
" There may be problems when opening/closing extra view windows.\n"
);
}
composite_viewer_enabled = 1;
SG_LOG(SG_VIEW, SG_ALERT, "Creating osgViewer::CompositeViewer");
composite_viewer = new osgViewer::CompositeViewer;
// https://stackoverflow.com/questions/15207076/openscenegraph-and-multiple-viewers
composite_viewer->setReleaseContextAtEndOfFrameHint(false);
composite_viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
}
else {
composite_viewer_enabled = 0;
SG_LOG(SG_VIEW, SG_ALERT, "Not creating osgViewer::CompositeViewer");
}
_scenery_loaded = fgGetNode("/sim/sceneryloaded", true); _scenery_loaded = fgGetNode("/sim/sceneryloaded", true);
_position_finalized = fgGetNode("/sim/position-finalized", true); _position_finalized = fgGetNode("/sim/position-finalized", true);
@ -542,7 +578,7 @@ void FGRenderer::setupRoot()
void void
FGRenderer::setupView( void ) FGRenderer::setupView( void )
{ {
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer(); osgViewer::View* view = globals->get_renderer()->getView();
osg::initNotifyLevel(); osg::initNotifyLevel();
// The number of polygon-offset "units" to place between layers. In // The number of polygon-offset "units" to place between layers. In
@ -571,7 +607,7 @@ FGRenderer::setupView( void )
fgGetNode("/environment", true), fgGetNode("/environment", true),
opt.get()); opt.get());
viewer->getCamera() view->getCamera()
->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); ->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
@ -647,10 +683,12 @@ FGRenderer::setupView( void )
#if defined(HAVE_PUI) #if defined(HAVE_PUI)
_puiCamera = new flightgear::PUICamera; _puiCamera = new flightgear::PUICamera;
_puiCamera->init(guiCamera, viewer); _puiCamera->init(guiCamera, view);
#endif #endif
#if defined(ENABLE_QQ_UI) #if defined(ENABLE_QQ_UI)
osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(view);
if (viewer) {
std::string rootQMLPath = fgGetString("/sim/gui/qml-root-path"); std::string rootQMLPath = fgGetString("/sim/gui/qml-root-path");
auto graphicsWindow = dynamic_cast<osgViewer::GraphicsWindow*>(guiCamera->getGraphicsContext()); auto graphicsWindow = dynamic_cast<osgViewer::GraphicsWindow*>(guiCamera->getGraphicsContext());
@ -664,6 +702,7 @@ FGRenderer::setupView( void )
qqGeode->addDrawable(_quickDrawable); qqGeode->addDrawable(_quickDrawable);
guiCamera->addChild(qqGeode); guiCamera->addChild(qqGeode);
} }
}
#endif #endif
guiCamera->insertChild(0, FGPanelNode::create2DPanelNode()); guiCamera->insertChild(0, FGPanelNode::create2DPanelNode());
} }
@ -706,7 +745,6 @@ FGRenderer::update( ) {
} }
return; return;
} }
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
if (_splash_alpha->getDoubleValue()>0.0) if (_splash_alpha->getDoubleValue()>0.0)
{ {
@ -748,8 +786,21 @@ FGRenderer::update( ) {
// Force update of center dependent values ... // Force update of center dependent values ...
current__view->set_dirty(); current__view->set_dirty();
osg::Camera *camera = viewer->getCamera(); assert(composite_viewer_enabled != -1);
std::vector<osg::Camera*> cameras;
if (composite_viewer) {
assert(!viewer);
unsigned n = composite_viewer->getNumViews();
for (unsigned i=0; i<n; ++i) {
osgViewer::View* view = composite_viewer->getView(i);
osg::Camera* camera = view->getCamera();
cameras.push_back(camera);
}
}
else {
cameras.push_back(viewer->getCamera());
}
for (osg::Camera* camera: cameras) {
osg::Vec4 clear_color = _altitude_ft->getDoubleValue() < 250000 osg::Vec4 clear_color = _altitude_ft->getDoubleValue() < 250000
? toOsg(l->adj_fog_color()) ? toOsg(l->adj_fog_color())
// skydome ends at ~262000ft (default rendering) // skydome ends at ~262000ft (default rendering)
@ -762,9 +813,10 @@ FGRenderer::update( ) {
updateSky(); updateSky();
// need to call the update visitor once // need to call the update visitor once
_frameStamp->setCalendarTime(*globals->get_time_params()->getGmt()); getFrameStamp()->setCalendarTime(*globals->get_time_params()->getGmt());
_updateVisitor->setViewData(current__view->getViewPosition(), _updateVisitor->setViewData(current__view->getViewPosition(),
current__view->getViewOrientation()); current__view->getViewOrientation());
//_updateVisitor->setViewData(eye2, center3);
SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]); SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
_updateVisitor->setLight(direction, l->scene_ambient(), _updateVisitor->setLight(direction, l->scene_ambient(),
l->scene_diffuse(), l->scene_specular(), l->scene_diffuse(), l->scene_specular(),
@ -781,6 +833,7 @@ FGRenderer::update( ) {
camera->setCullMaskLeft(cullMask); camera->setCullMaskLeft(cullMask);
camera->setCullMaskRight(cullMask); camera->setCullMaskRight(cullMask);
} }
}
void void
FGRenderer::updateSky() FGRenderer::updateSky()
@ -958,11 +1011,66 @@ PickList FGRenderer::pick(const osg::Vec2& windowPos)
return result; return result;
} }
void osgViewer::ViewerBase* FGRenderer::getViewerBase()
FGRenderer::setViewer(osgViewer::Viewer* viewer_)
{ {
if (composite_viewer) {
return composite_viewer.get();
}
else {
return viewer.get();
}
}
osgViewer::View* FGRenderer::getView()
{
assert(composite_viewer_enabled != -1);
if (composite_viewer) {
assert(composite_viewer->getNumViews());
return composite_viewer->getView(0);
}
else {
return viewer.get();
}
}
const osgViewer::View* FGRenderer::getView() const
{
FGRenderer* this_ = const_cast<FGRenderer*>(this);
return this_->getView();
}
void
FGRenderer::setView(osgViewer::View* view)
{
assert(composite_viewer_enabled != -1);
if (composite_viewer) {
if (composite_viewer->getNumViews() == 0) {
SG_LOG(SG_VIEW, SG_ALERT, "adding view to composite_viewer.");
composite_viewer->stopThreading();
composite_viewer->addView(view);
composite_viewer->startThreading();
}
}
else {
osgViewer::Viewer* viewer_ = dynamic_cast<osgViewer::Viewer*>(view);
assert(viewer_);
viewer = viewer_; viewer = viewer_;
} }
}
osg::FrameStamp*
FGRenderer::getFrameStamp()
{
assert(composite_viewer_enabled != -1);
if (composite_viewer) {
assert(!viewer);
return composite_viewer->getFrameStamp();
}
else {
assert(viewer);
return viewer->getFrameStamp();
}
}
void void
FGRenderer::setEventHandler(FGEventHandler* eventHandler_) FGRenderer::setEventHandler(FGEventHandler* eventHandler_)
@ -991,8 +1099,8 @@ FGRenderer::setPlanes( double zNear, double zFar )
bool bool
fgDumpSceneGraphToFile(const char* filename) fgDumpSceneGraphToFile(const char* filename)
{ {
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer(); osgViewer::View* view = globals->get_renderer()->getView();
return osgDB::writeNodeFile(*viewer->getSceneData(), filename); return osgDB::writeNodeFile(*view->getSceneData(), filename);
} }
bool bool
@ -1199,14 +1307,14 @@ protected:
bool printVisibleSceneInfo(FGRenderer* renderer) bool printVisibleSceneInfo(FGRenderer* renderer)
{ {
osgViewer::Viewer* viewer = renderer->getViewer(); osgViewer::View* view = renderer->getView();
VisibleSceneInfoVistor vsv; VisibleSceneInfoVistor vsv;
Viewport* vp = 0; Viewport* vp = 0;
if (!viewer->getCamera()->getViewport() && viewer->getNumSlaves() > 0) { if (!view->getCamera()->getViewport() && view->getNumSlaves() > 0) {
const osg::View::Slave& slave = viewer->getSlave(0); const osg::View::Slave& slave = view->getSlave(0);
vp = slave._camera->getViewport(); vp = slave._camera->getViewport();
} }
vsv.doTraversal(viewer->getCamera(), viewer->getSceneData(), vp); vsv.doTraversal(view->getCamera(), view->getSceneData(), vp);
return true; return true;
} }

View file

@ -10,6 +10,9 @@
#include <osg/Vec2> #include <osg/Vec2>
#include <osg/Vec3> #include <osg/Vec3>
#include <osgViewer/CompositeViewer>
namespace osg namespace osg
{ {
class Camera; class Camera;
@ -62,11 +65,19 @@ public:
*/ */
PickList pick(const osg::Vec2& windowPos); PickList pick(const osg::Vec2& windowPos);
/* Returns either composite_viewer or viewer. */
osgViewer::ViewerBase* getViewerBase();
/** Get and set the OSG Viewer object, if any. /** Get and set the OSG Viewer object, if any.
*/ */
osgViewer::Viewer* getViewer() { return viewer.get(); } osgViewer::View* getView();
const osgViewer::Viewer* getViewer() const { return viewer.get(); } const osgViewer::View* getView() const;
void setViewer(osgViewer::Viewer* viewer); void setView(osgViewer::View* view);
/** Calls osgViewer::CompositeViewer::getFrameStamp() if we are using
composite viewer, otherwise osgViewer::Viewer::getFrameStamp(). */
osg::FrameStamp* getFrameStamp();
/** Get and set the manipulator object, if any. /** Get and set the manipulator object, if any.
*/ */
flightgear::FGEventHandler* getEventHandler() { return eventHandler.get(); } flightgear::FGEventHandler* getEventHandler() { return eventHandler.get(); }
@ -84,7 +95,9 @@ public:
void setPlanes( double zNear, double zFar ); void setPlanes( double zNear, double zFar );
protected: protected:
int composite_viewer_enabled = -1;
osg::ref_ptr<osgViewer::Viewer> viewer; osg::ref_ptr<osgViewer::Viewer> viewer;
osg::ref_ptr<osgViewer::CompositeViewer> composite_viewer;
osg::ref_ptr<flightgear::FGEventHandler> eventHandler; osg::ref_ptr<flightgear::FGEventHandler> eventHandler;
osg::ref_ptr<osg::FrameStamp> _frameStamp; osg::ref_ptr<osg::FrameStamp> _frameStamp;

View file

@ -204,6 +204,12 @@ void SplashScreen::createNodes()
nullptr, -1.0, osg::Vec4(1.0, 0.0, 0.0, 1.0)); nullptr, -1.0, osg::Vec4(1.0, 0.0, 0.0, 1.0));
} }
if (fgGetBool("/sim/rendering/composite-viewer-enabled")) {
addText(geode, osg::Vec2(0.5f, 0.65f), 0.03,
"CompositeViewer",
osgText::Text::CENTER_CENTER,
nullptr, -1.0, osg::Vec4(1.0, 0.0, 0.0, 1.0));
}
/////////// ///////////

1394
src/Viewer/sview.cxx Normal file

File diff suppressed because it is too large Load diff

80
src/Viewer/sview.hxx Normal file
View file

@ -0,0 +1,80 @@
#pragma once
/*
Support for extra view windows. Requires that composite-viewer is enabled at
startup with --composite-viewer=1.
*/
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <osgViewer/View>
/* Should be called before the first call to SviewCreate() so that
SviewCreate() can create new simgear::compositor::Compositor instances with the
same parameters as were used for the main window.
options
compositor_path
Suitable for passing to simgear::compositor::Compositor().
*/
void SViewSetCompositorParams(
osg::ref_ptr<simgear::SGReaderWriterOptions> options,
const std::string& compositor_path
);
/* Pushes current main window view to internal circular list of two items used
by SviewCreate() with 'last_pair' or 'last_pair_double'. */
void SviewPush();
/* Updates camera position/orientation/zoom of all sviews - should be called
each frame. Will also handle closing of Sview windows. */
void SviewUpdate(double dt);
/* Deletes all internal views; e.g. used when restarting. */
void SviewClear();
/* A view, typically an extra view window. The definition of this is not
public. */
struct SviewView;
/*
This is the main interface to the Sview system. We create a new SviewView in a
new top-level window. It will be updated as required by SviewUpdate().
As of 2020-11-18, the new window will be half width and height of the main
window, and will have top-left corner at (100, 100). It can be dragged, resized
and closed by the user.
type:
This controls what sort of view we create:
"current"
Clones the current view.
"last_pair"
Look from first pushed view's eye to second pushed view's eye. Returns
nullptr if SviewPush hasn't been called at least twice.
"last_pair_double"
Keep first pushed view's aircraft in foreground and second pushed
view's aircraft in background. Returns nullptr if SviewPush hasn't been
called at least twice.
Returns:
Shared ptr to SviewView instance. As of 2020-11-18 there is little that
the caller can do with this. We handle closing of the SviewView's window
internally.
As of 2020-11-17, extra views have various limitations including:
No event handling, so no panning, zooming etc.
Tower View AGL is like Tower View so no zooming to keep ground visible.
Cockpit view has a incorrect calculation giving slightly incorrect
translation when rolling.
No damping in chase views.
Hard-coded chase distances.
*/
std::shared_ptr<SviewView> SviewCreate(const std::string& type);

View file

@ -33,8 +33,12 @@
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
#include "view.hxx" #include "view.hxx"
#include "sview.hxx"
#include "renderer.hxx"
#include "CameraGroup.hxx" #include "CameraGroup.hxx"
#include "Scenery/scenery.hxx"
// Constructor // Constructor
FGViewMgr::FGViewMgr(void) FGViewMgr::FGViewMgr(void)
@ -134,6 +138,7 @@ FGViewMgr::unbind ()
_viewNumberProp.clear(); _viewNumberProp.clear();
ViewPropertyEvaluator::clear(); ViewPropertyEvaluator::clear();
SviewClear();
} }
void void
@ -155,6 +160,7 @@ FGViewMgr::update (double dt)
cameraGroup->update(toOsg(currentView->getViewPosition()), cameraGroup->update(toOsg(currentView->getViewPosition()),
toOsg(currentView->getViewOrientation())); toOsg(currentView->getViewOrientation()));
} }
SviewUpdate(dt);
} }
void FGViewMgr::clear() void FGViewMgr::clear()
@ -222,6 +228,33 @@ FGViewMgr::prev_view()
return get_current_view(); return get_current_view();
} }
void FGViewMgr::view_push()
{
SviewPush();
}
void FGViewMgr::clone_current_view()
{
clone_internal("current");
}
void FGViewMgr::clone_last_pair()
{
clone_internal("last_pair");
}
void FGViewMgr::clone_last_pair_double()
{
clone_internal("last_pair_double");
}
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
void FGViewMgr::clone_internal(const std::string& type)
{
SviewCreate(type);
}
void void
FGViewMgr::add_view( flightgear::View * v ) FGViewMgr::add_view( flightgear::View * v )
{ {

View file

@ -75,6 +75,19 @@ public:
flightgear::View* next_view(); flightgear::View* next_view();
flightgear::View* prev_view(); flightgear::View* prev_view();
//
void view_push();
// Experimental. Only works if --compositer-viewer=1 was specified. Creates
// new window with clone of current view. As of 2020-09-03, the clone's
// scenery is not displayed correctly.
void clone_current_view();
//
void clone_last_pair();
void clone_last_pair_double();
// setters // setters
void clear(); void clear();
@ -84,6 +97,7 @@ private:
simgear::TiedPropertyList _tiedProperties; simgear::TiedPropertyList _tiedProperties;
void setCurrentViewIndex(int newview); void setCurrentViewIndex(int newview);
void clone_internal(const std::string& type);
bool _inited = false; bool _inited = false;
std::vector<SGPropertyNode_ptr> config_list; std::vector<SGPropertyNode_ptr> config_list;

View file

@ -45,7 +45,7 @@ void initScenery()
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer; osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
FGRenderer* render = globals->get_renderer(); FGRenderer* render = globals->get_renderer();
render->init(); render->init();
render->setViewer(viewer.get()); render->setView(viewer.get());
// Start up the scenery subsystem. // Start up the scenery subsystem.
globals->add_new_subsystem<FGScenery>(SGSubsystemMgr::DISPLAY); globals->add_new_subsystem<FGScenery>(SGSubsystemMgr::DISPLAY);