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:
parent
578f414c42
commit
f62e5b9ce3
31 changed files with 1972 additions and 172 deletions
|
@ -672,7 +672,7 @@ void GUIMgr::init()
|
|||
|
||||
_event_handler = new GUIEventHandler(desktop);
|
||||
globals->get_renderer()
|
||||
->getViewer()
|
||||
->getView()
|
||||
->getEventHandlers()
|
||||
// GUI is on top of everything so lets install as first event handler
|
||||
.push_front( _event_handler );
|
||||
|
@ -706,7 +706,7 @@ void GUIMgr::shutdown()
|
|||
if( _event_handler )
|
||||
{
|
||||
globals->get_renderer()
|
||||
->getViewer()
|
||||
->getView()
|
||||
->removeEventHandler( _event_handler );
|
||||
_event_handler = 0;
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ void CocoaFileDialog::exec()
|
|||
// it window-modal.
|
||||
NSWindow* cocoaWindow = nil;
|
||||
std::vector<osgViewer::GraphicsWindow*> windows;
|
||||
globals->get_renderer()->getViewer()->getWindows(windows);
|
||||
globals->get_renderer()->getViewerBase()->getWindows(windows);
|
||||
|
||||
for (auto gw : windows) {
|
||||
// OSG doesn't use RTTI, so no dynamic cast. Let's check the class type
|
||||
|
|
|
@ -26,11 +26,11 @@ namespace {
|
|||
HWND getMainViewerHWND()
|
||||
{
|
||||
osgViewer::Viewer::Windows windows;
|
||||
if (!globals->get_renderer() || !globals->get_renderer()->getViewer()) {
|
||||
if (!globals->get_renderer() || !globals->get_renderer()->getViewerBase()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
globals->get_renderer()->getViewer()->getWindows(windows);
|
||||
globals->get_renderer()->getViewerBase()->getWindows(windows);
|
||||
osgViewer::Viewer::Windows::const_iterator it = windows.begin();
|
||||
for(; it != windows.end(); ++it) {
|
||||
if (strcmp((*it)->className(), "GraphicsWindowWin32")) {
|
||||
|
|
|
@ -61,11 +61,11 @@ bool isCanvasImplementationRegistered()
|
|||
HWND getMainViewerHWND()
|
||||
{
|
||||
osgViewer::Viewer::Windows windows;
|
||||
if (!globals || !globals->get_renderer() || !globals->get_renderer()->getViewer()) {
|
||||
if (!globals || !globals->get_renderer() || !globals->get_renderer()->getViewerBase()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
globals->get_renderer()->getViewer()->getWindows(windows);
|
||||
globals->get_renderer()->getViewerBase()->getWindows(windows);
|
||||
osgViewer::Viewer::Windows::const_iterator it = windows.begin();
|
||||
for(; it != windows.end(); ++it) {
|
||||
if (strcmp((*it)->className(), "GraphicsWindowWin32")) {
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
{
|
||||
mActualCursor = mCursor;
|
||||
|
||||
globals->get_renderer()->getViewer()->getWindows(mWindows);
|
||||
globals->get_renderer()->getViewerBase()->getWindows(mWindows);
|
||||
}
|
||||
|
||||
virtual void setCursor(Cursor aCursor)
|
||||
|
@ -160,7 +160,7 @@ FGMouseCursor* FGMouseCursor::instance()
|
|||
#ifdef SG_WINDOWS
|
||||
// set osgViewer cursor inherit, otherwise it will interefere
|
||||
std::vector<osgViewer::GraphicsWindow*> gws;
|
||||
globals->get_renderer()->getViewer()->getWindows(gws);
|
||||
globals->get_renderer()->getViewerBase()->getWindows(gws);
|
||||
for (auto gw : gws) {
|
||||
gw->setCursor(osgViewer::GraphicsWindow::InheritCursor);
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ namespace {
|
|||
HWND getMainViewerHWND()
|
||||
{
|
||||
osgViewer::Viewer::Windows windows;
|
||||
if (!globals->get_renderer() || !globals->get_renderer()->getViewer()) {
|
||||
if (!globals->get_renderer() || !globals->get_renderer()->getViewerBase()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
globals->get_renderer()->getViewer()->getWindows(windows);
|
||||
globals->get_renderer()->getViewerBase()->getWindows(windows);
|
||||
osgViewer::Viewer::Windows::const_iterator it = windows.begin();
|
||||
for(; it != windows.end(); ++it) {
|
||||
if (strcmp((*it)->className(), "GraphicsWindowWin32")) {
|
||||
|
|
|
@ -361,6 +361,54 @@ do_view_cycle (const SGPropertyNode * arg, SGPropertyNode * root)
|
|||
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.
|
||||
*
|
||||
|
@ -948,6 +996,10 @@ static struct {
|
|||
{ "save-tape", do_save_tape },
|
||||
{ "load-tape", do_load_tape },
|
||||
{ "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-outside-air-temp-degc", do_set_oat_degc },
|
||||
|
|
|
@ -1283,7 +1283,7 @@ void fgStartNewReset()
|
|||
|
||||
FGRenderer* render = globals->get_renderer();
|
||||
// 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
|
||||
// access the scenery object
|
||||
|
@ -1294,8 +1294,8 @@ void fgStartNewReset()
|
|||
|
||||
// don't cancel the pager until after shutdown, since AIModels (and
|
||||
// potentially others) can queue delete requests on the pager.
|
||||
render->getViewer()->getDatabasePager()->cancel();
|
||||
render->getViewer()->getDatabasePager()->clear();
|
||||
render->getView()->getDatabasePager()->cancel();
|
||||
render->getView()->getDatabasePager()->clear();
|
||||
|
||||
osgDB::Registry::instance()->clearObjectCache();
|
||||
// Pager requests depend on this, so don't clear it until now
|
||||
|
@ -1376,7 +1376,7 @@ void fgStartNewReset()
|
|||
eventHandler->reset();
|
||||
globals->set_renderer(render);
|
||||
render->init();
|
||||
render->setViewer(viewer.get());
|
||||
render->setView(viewer.get());
|
||||
|
||||
sgUserDataInit( globals->get_props() );
|
||||
|
||||
|
|
|
@ -195,15 +195,15 @@ FGGlobals::~FGGlobals()
|
|||
// stop OSG threading first, to avoid thread races while we tear down
|
||||
// scene-graph pieces
|
||||
// there are some scenarios where renderer is already gone.
|
||||
osg::ref_ptr<osgViewer::Viewer> vw;
|
||||
osg::ref_ptr<osgViewer::ViewerBase> vb;
|
||||
if (renderer) {
|
||||
vw = renderer->getViewer();
|
||||
if (vw) {
|
||||
vb = renderer->getViewerBase();
|
||||
if (vb) {
|
||||
// https://code.google.com/p/flightgear-bugs/issues/detail?id=1291
|
||||
// explicitly stop trheading before we delete the renderer or
|
||||
// viewMgr (which ultimately holds refs to the CameraGroup, and
|
||||
// GraphicsContext)
|
||||
vw->stopThreading();
|
||||
vb->stopThreading();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,9 +212,10 @@ FGGlobals::~FGGlobals()
|
|||
|
||||
// don't cancel the pager until after shutdown, since AIModels (and
|
||||
// potentially others) can queue delete requests on the pager.
|
||||
if (vw && vw->getDatabasePager()) {
|
||||
vw->getDatabasePager()->cancel();
|
||||
vw->getDatabasePager()->clear();
|
||||
osgViewer::View* v = renderer->getView();
|
||||
if (v && v->getDatabasePager()) {
|
||||
v->getDatabasePager()->cancel();
|
||||
v->getDatabasePager()->clear();
|
||||
}
|
||||
|
||||
osgDB::Registry::instance()->clearObjectCache();
|
||||
|
@ -230,7 +231,7 @@ FGGlobals::~FGGlobals()
|
|||
|
||||
delete subsystem_mgr;
|
||||
subsystem_mgr = nullptr; // important so ::get_subsystem returns NULL
|
||||
vw = nullptr;
|
||||
vb = nullptr;
|
||||
set_matlib(NULL);
|
||||
|
||||
delete time_params;
|
||||
|
|
|
@ -743,10 +743,6 @@ int fgMainInit( int argc, char **argv )
|
|||
fntInit();
|
||||
globals->get_renderer()->preinit();
|
||||
|
||||
#if defined(ENABLE_COMPOSITOR)
|
||||
flightgear::addSentryTag("compositor", "yes");
|
||||
#endif
|
||||
|
||||
if (fgGetBool("/sim/ati-viewport-hack", true)) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "Enabling ATI/AMD viewport hack");
|
||||
flightgear::addSentryTag("ati-viewport-hack", "enabled");
|
||||
|
|
|
@ -1617,6 +1617,7 @@ where:
|
|||
OPTION_INT - property is an integer
|
||||
OPTION_CHANNEL - name of option is the name of a channel
|
||||
OPTION_FUNC - the option trigger a function
|
||||
property :
|
||||
b_param : if type==OPTION_BOOL,
|
||||
value set to the property (has_param is false for boolean)
|
||||
s_param : if type==OPTION_STRING,
|
||||
|
@ -1870,6 +1871,7 @@ struct OptionDesc {
|
|||
{"developer", true, OPTION_IGNORE | OPTION_BOOL, "", false, "", nullptr },
|
||||
{"jsbsim-output-directive-file", true, OPTION_STRING, "/sim/jsbsim/output-directive-file", false, "", nullptr },
|
||||
{"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}
|
||||
};
|
||||
|
||||
|
|
|
@ -436,7 +436,7 @@ static InitPosResult setInitialPosFromCarrier( const string& carrier )
|
|||
static InitPosResult checkCarrierSceneryLoaded(const SGSharedPtr<FGAICarrier> carrierRef)
|
||||
{
|
||||
SGVec3d cartPos = carrierRef->getCartPos();
|
||||
auto framestamp = globals->get_renderer()->getViewer()->getFrameStamp();
|
||||
auto framestamp = globals->get_renderer()->getFrameStamp();
|
||||
simgear::CheckSceneryVisitor csnv(globals->get_scenery()->getPager(),
|
||||
toOsg(cartPos),
|
||||
100.0 /* range in metres */,
|
||||
|
|
|
@ -213,7 +213,7 @@ public:
|
|||
if ( NULL == osgDB::Registry::instance()->getReaderWriterForExtension(_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)
|
||||
throw sg_error("Can't find a camera for window '" + window + "'");
|
||||
|
||||
|
|
|
@ -371,7 +371,7 @@ bool FGStgTerrain::scenery_available(const SGGeod& position, double range_m)
|
|||
|
||||
SGVec3f p = SGVec3f::fromGeod(SGGeod::fromGeodM(position, elev));
|
||||
osg::FrameStamp* framestamp
|
||||
= globals->get_renderer()->getViewer()->getFrameStamp();
|
||||
= globals->get_renderer()->getFrameStamp();
|
||||
|
||||
FGScenery* pSceneryManager = globals->get_scenery();
|
||||
simgear::CheckSceneryVisitor csnv(pSceneryManager->getPager(), toOsg(p), range_m, framestamp);
|
||||
|
|
|
@ -76,8 +76,8 @@ public:
|
|||
|
||||
if (_pagedLODMaximumProp->getType() == simgear::props::NONE) {
|
||||
// not set, use OSG default / environment value variable
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer(globals->get_renderer()->getViewer());
|
||||
int current = viewer->getDatabasePager()->getTargetMaximumNumberOfPageLOD();
|
||||
osg::ref_ptr<osgViewer::View> view(globals->get_renderer()->getView());
|
||||
int current = view->getDatabasePager()->getTargetMaximumNumberOfPageLOD();
|
||||
_pagedLODMaximumProp->setIntValue(current);
|
||||
}
|
||||
_pagedLODMaximumProp->addChangeListener(this, true);
|
||||
|
@ -106,9 +106,9 @@ public:
|
|||
_manager->_enableCache = prop->getBoolValue();
|
||||
} else if (prop == _pagedLODMaximumProp) {
|
||||
int v = prop->getIntValue();
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer(globals->get_renderer()->getViewer());
|
||||
if (viewer) {
|
||||
osgDB::DatabasePager* pager = viewer->getDatabasePager();
|
||||
osg::ref_ptr<osgViewer::View> view(globals->get_renderer()->getView());
|
||||
if (view) {
|
||||
osgDB::DatabasePager* pager = view->getDatabasePager();
|
||||
if (pager) pager->setTargetMaximumNumberOfPageLOD(v);
|
||||
}
|
||||
} 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
|
||||
osg::FrameStamp* framestamp
|
||||
= globals->get_renderer()->getViewer()->getFrameStamp();
|
||||
= globals->get_renderer()->getFrameStamp();
|
||||
tile_cache.set_current_time(framestamp->getReferenceTime());
|
||||
|
||||
SGBucket b;
|
||||
|
@ -379,8 +379,7 @@ void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis)
|
|||
*/
|
||||
void FGTileMgr::update_queues(bool& isDownloadingScenery)
|
||||
{
|
||||
osg::FrameStamp* framestamp
|
||||
= globals->get_renderer()->getViewer()->getFrameStamp();
|
||||
osg::FrameStamp* framestamp = globals->get_renderer()->getFrameStamp();
|
||||
double current_time = framestamp->getReferenceTime();
|
||||
double vis = _visibilityMeters->getDoubleValue();
|
||||
TileEntry *e;
|
||||
|
|
|
@ -12,6 +12,7 @@ set(SOURCES
|
|||
splash.cxx
|
||||
view.cxx
|
||||
viewmgr.cxx
|
||||
sview.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
|
@ -24,6 +25,7 @@ set(HEADERS
|
|||
splash.hxx
|
||||
view.hxx
|
||||
viewmgr.hxx
|
||||
sview.hxx
|
||||
)
|
||||
|
||||
if (Qt5Core_FOUND)
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "FGEventHandler.hxx"
|
||||
#include "WindowBuilder.hxx"
|
||||
#include "WindowSystemAdapter.hxx"
|
||||
#include "sview.hxx"
|
||||
|
||||
#include <simgear/math/SGRect.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
@ -192,8 +193,8 @@ typedef std::vector<SGPropertyNode_ptr> SGPropertyNodeVec;
|
|||
|
||||
osg::ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
|
||||
|
||||
CameraGroup::CameraGroup(osgViewer::Viewer* viewer) :
|
||||
_viewer(viewer)
|
||||
CameraGroup::CameraGroup(osgViewer::View* view) :
|
||||
_viewer(view)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -688,6 +689,9 @@ void CameraGroup::buildCamera(SGPropertyNode* cameraNode)
|
|||
osg::ref_ptr<SGReaderWriterOptions> options =
|
||||
SGReaderWriterOptions::fromPath(globals->get_fg_root());
|
||||
options->setPropertyNode(globals->get_props());
|
||||
|
||||
SViewSetCompositorParams(options, compositor_path);
|
||||
|
||||
Compositor *compositor = Compositor::create(_viewer,
|
||||
window->gc,
|
||||
viewport,
|
||||
|
@ -783,10 +787,10 @@ void CameraGroup::buildGUICamera(SGPropertyNode* cameraNode,
|
|||
camera->setStats(0);
|
||||
}
|
||||
|
||||
CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer,
|
||||
CameraGroup* CameraGroup::buildCameraGroup(osgViewer::View* view,
|
||||
SGPropertyNode* gnode)
|
||||
{
|
||||
CameraGroup* cgroup = new CameraGroup(viewer);
|
||||
CameraGroup* cgroup = new CameraGroup(view);
|
||||
cgroup->_listener.reset(new CameraGroupListener(cgroup, gnode));
|
||||
|
||||
for (int i = 0; i < gnode->nChildren(); ++i) {
|
||||
|
@ -862,7 +866,7 @@ computeCameraIntersection(const CameraGroup *cgroup,
|
|||
osgUtil::IntersectionVisitor iv(picker);
|
||||
iv.setTraversalMask(simgear::PICK_BIT);
|
||||
|
||||
const_cast<CameraGroup *>(cgroup)->getViewer()->getCamera()->accept(iv);
|
||||
const_cast<CameraGroup *>(cgroup)->getView()->getCamera()->accept(iv);
|
||||
if (picker->containsIntersections()) {
|
||||
intersections = picker->getIntersections();
|
||||
return true;
|
||||
|
@ -921,7 +925,7 @@ void warpGUIPointer(CameraGroup* cgroup, int x, int y)
|
|||
gw->getEventQueue()->mouseWarped(wx, wy);
|
||||
gw->requestWarpPointer(wx, wy);
|
||||
osgGA::GUIEventAdapter* eventState
|
||||
= cgroup->getViewer()->getEventQueue()->getCurrentEventState();
|
||||
= cgroup->getView()->getEventQueue()->getCurrentEventState();
|
||||
double viewerX
|
||||
= (eventState->getXmin()
|
||||
+ ((wx / double(traits->width))
|
||||
|
@ -930,10 +934,10 @@ void warpGUIPointer(CameraGroup* cgroup, int x, int y)
|
|||
= (eventState->getYmin()
|
||||
+ ((wyUp / double(traits->height))
|
||||
* (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
|
||||
// top-level cameras
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <osg/Texture2D>
|
||||
#include <osg/TexGen>
|
||||
#include <osgUtil/RenderBin>
|
||||
#include <osgViewer/View>
|
||||
|
||||
#include <simgear/scene/viewer/Compositor.hxx>
|
||||
|
||||
|
@ -122,14 +123,14 @@ public:
|
|||
/** Create a camera group associated with an osgViewer::Viewer.
|
||||
* @param viewer the viewer
|
||||
*/
|
||||
CameraGroup(osgViewer::Viewer* viewer);
|
||||
CameraGroup(osgViewer::View* viewer);
|
||||
virtual ~CameraGroup();
|
||||
|
||||
/** Set the default CameraGroup, which is the only one that
|
||||
* matters at this time.
|
||||
* @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; }
|
||||
/** Get the default CameraGroup.
|
||||
* @return the default camera group.
|
||||
|
@ -138,7 +139,7 @@ public:
|
|||
/** Get the camera group's 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
|
||||
* camera group.
|
||||
* @param cameraNode the property node.
|
||||
|
@ -192,7 +193,7 @@ protected:
|
|||
|
||||
typedef std::vector<osg::ref_ptr<CameraInfo>> CameraList;
|
||||
CameraList _cameras;
|
||||
osg::ref_ptr<osgViewer::Viewer> _viewer;
|
||||
osg::ref_ptr<osgViewer::View> _viewer;
|
||||
static osg::ref_ptr<CameraGroup> _defaultGroup;
|
||||
std::unique_ptr<CameraGroupListener> _listener;
|
||||
|
||||
|
@ -206,7 +207,7 @@ protected:
|
|||
* @param wbuilder the window builder to be used for this camera group.
|
||||
* @param the camera group property node.
|
||||
*/
|
||||
static CameraGroup* buildCameraGroup(osgViewer::Viewer* viewer,
|
||||
static CameraGroup* buildCameraGroup(osgViewer::View* viewer,
|
||||
SGPropertyNode* node);
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#include "CameraGroup.hxx"
|
||||
#include "FGEventHandler.hxx"
|
||||
#include "WindowSystemAdapter.hxx"
|
||||
#include "WindowBuilder.hxx"
|
||||
#include "renderer.hxx"
|
||||
#include "sview.hxx"
|
||||
|
||||
#ifdef SG_MAC
|
||||
// hack - during interactive resize on Mac, OSG queues and then flushes
|
||||
|
@ -85,12 +87,18 @@ bool
|
|||
eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
|
||||
int& x, int& y)
|
||||
{
|
||||
flightgear::WindowBuilder* window_builder = flightgear::WindowBuilder::getWindowBuilder();
|
||||
flightgear::GraphicsWindow* main_window = window_builder->getDefaultWindow();
|
||||
|
||||
x = -1;
|
||||
y = -1;
|
||||
|
||||
const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
|
||||
if( !eventGC )
|
||||
return false; // TODO how can this happen?
|
||||
if (eventGC != main_window->gc.get()) {
|
||||
return false;
|
||||
}
|
||||
const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
|
||||
osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
|
||||
if (!guiCamera)
|
||||
|
@ -115,6 +123,20 @@ eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
|
|||
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,
|
||||
|
@ -224,6 +246,9 @@ bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
|
|||
return true;
|
||||
case osgGA::GUIEventAdapter::RESIZE:
|
||||
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();
|
||||
if (resizable)
|
||||
globals->get_renderer()->resize(ea.getWindowWidth(), ea.getWindowHeight());
|
||||
|
@ -236,6 +261,10 @@ bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
|
|||
#endif
|
||||
return true;
|
||||
case osgGA::GUIEventAdapter::CLOSE_WINDOW:
|
||||
if (!isMainWindow(ea, us)) {
|
||||
return true;
|
||||
}
|
||||
// Fall through.
|
||||
case osgGA::GUIEventAdapter::QUIT_APPLICATION:
|
||||
fgOSExit(0);
|
||||
return true;
|
||||
|
|
|
@ -275,13 +275,13 @@ PUICamera::~PUICamera()
|
|||
// depending on if we're doing shutdown or reset, various things can be
|
||||
// null here.
|
||||
auto renderer = globals->get_renderer();
|
||||
auto viewer = renderer ? renderer->getViewer() : nullptr;
|
||||
if (viewer) {
|
||||
viewer->removeEventHandler(_eventHandler);
|
||||
auto view = renderer ? renderer->getView() : nullptr;
|
||||
if (view) {
|
||||
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");
|
||||
|
||||
|
@ -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
|
||||
// handler)
|
||||
_eventHandler = new PUIEventHandler(this);
|
||||
viewer->getEventHandlers().push_front(_eventHandler);
|
||||
view->getEventHandlers().push_front(_eventHandler);
|
||||
}
|
||||
|
||||
// remove once we require OSG 3.4
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <osg/Camera>
|
||||
#include <osg/Version>
|
||||
#include <osgViewer/View>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
|
@ -51,7 +52,7 @@ public:
|
|||
// osg::Camera already defines a resize() so use this name
|
||||
void resizeUi(int width, int height);
|
||||
|
||||
void init(osg::Group* parent, osgViewer::Viewer* viewer);
|
||||
void init(osg::Group* parent, osgViewer::View* view);
|
||||
|
||||
private:
|
||||
void manuallyResizeFBO(int width, int height);
|
||||
|
|
|
@ -189,7 +189,7 @@ class NotifyLevelListener : public SGPropertyChangeListener
|
|||
public:
|
||||
void valueChanged(SGPropertyNode* node)
|
||||
{
|
||||
osg::NotifySeverity severity = osg::WARN;
|
||||
osg::NotifySeverity severity = osg::getNotifyLevel();
|
||||
string val = simgear::strutils::lowercase(node->getStringValue());
|
||||
|
||||
if (val == "fatal") {
|
||||
|
@ -216,38 +216,94 @@ void fgOSOpenWindow(bool stencil)
|
|||
{
|
||||
osg::setNotifyHandler(new NotifyLogger);
|
||||
|
||||
viewer = new osgViewer::Viewer;
|
||||
viewer->setDatabasePager(FGScenery::getPagerSingleton());
|
||||
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");
|
||||
flightgear::addSentryTag("osg-thread-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(viewer.get());
|
||||
|
||||
FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
if (wsa->windows.size() != 1) {
|
||||
manipulator->setResizable(false);
|
||||
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->setDatabasePager(FGScenery::getPagerSingleton());
|
||||
|
||||
std::string mode;
|
||||
mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
|
||||
flightgear::addSentryTag("osg-thread-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(viewer.get());
|
||||
|
||||
FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
if (wsa->windows.size() != 1) {
|
||||
manipulator->setResizable(false);
|
||||
}
|
||||
viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
viewer->addEventHandler(manipulator);
|
||||
// Let FG handle the escape key with a confirmation
|
||||
viewer->setKeyEventSetsDone(0);
|
||||
// The viewer won't start without some root.
|
||||
viewer->setSceneData(new osg::Group);
|
||||
globals->get_renderer()->setView(viewer.get());
|
||||
}
|
||||
viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
viewer->addEventHandler(manipulator);
|
||||
// Let FG handle the escape key with a confirmation
|
||||
viewer->setKeyEventSetsDone(0);
|
||||
// The viewer won't start without some root.
|
||||
viewer->setSceneData(new osg::Group);
|
||||
globals->get_renderer()->setViewer(viewer.get());
|
||||
}
|
||||
SGPropertyNode* simHost = 0, *simFrameCount, *simTotalHostTime, *simFrameResetCount, *frameWait;
|
||||
void fgOSResetProperties()
|
||||
|
@ -286,8 +342,9 @@ static int status = 0;
|
|||
|
||||
void fgOSExit(int code)
|
||||
{
|
||||
viewer->setDone(true);
|
||||
viewer->getDatabasePager()->cancel();
|
||||
FGRenderer* renderer = globals->get_renderer();
|
||||
renderer->getViewerBase()->setDone(true);
|
||||
renderer->getView()->getDatabasePager()->cancel();
|
||||
status = code;
|
||||
|
||||
// otherwise we crash if OSG does logging during static destruction, eg
|
||||
|
@ -299,12 +356,13 @@ SGTimeStamp _lastUpdate;
|
|||
|
||||
int fgOSMainLoop()
|
||||
{
|
||||
viewer->setReleaseContextAtEndOfFrameHint(false);
|
||||
if (!viewer->isRealized()) {
|
||||
viewer->realize();
|
||||
osgViewer::ViewerBase* viewer_base = globals->get_renderer()->getViewerBase();
|
||||
viewer_base->setReleaseContextAtEndOfFrameHint(false);
|
||||
if (!viewer_base->isRealized()) {
|
||||
viewer_base->realize();
|
||||
}
|
||||
|
||||
while (!viewer->done()) {
|
||||
while (!viewer_base->done()) {
|
||||
fgIdleHandler idleFunc = globals->get_renderer()->getEventHandler()->getIdleHandler();
|
||||
if (idleFunc)
|
||||
{
|
||||
|
@ -338,7 +396,7 @@ int fgOSMainLoop()
|
|||
}
|
||||
}
|
||||
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");
|
||||
|
@ -383,13 +441,16 @@ void fgOSInit(int* argc, char** argv)
|
|||
|
||||
void fgOSCloseWindow()
|
||||
{
|
||||
if (viewer) {
|
||||
// https://code.google.com/p/flightgear-bugs/issues/detail?id=1291
|
||||
// https://sourceforge.net/p/flightgear/codetickets/1830/
|
||||
// explicitly stop threading before we delete the renderer or
|
||||
// viewMgr (which ultimately holds refs to the CameraGroup, and
|
||||
// GraphicsContext)
|
||||
viewer->stopThreading();
|
||||
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://sourceforge.net/p/flightgear/codetickets/1830/
|
||||
// explicitly stop threading before we delete the renderer or
|
||||
// viewMgr (which ultimately holds refs to the CameraGroup, and
|
||||
// GraphicsContext)
|
||||
viewer_base->stopThreading();
|
||||
}
|
||||
}
|
||||
FGScenery::resetPagerSingleton();
|
||||
flightgear::CameraGroup::setDefault(NULL);
|
||||
|
@ -399,8 +460,9 @@ void fgOSCloseWindow()
|
|||
|
||||
void fgOSFullScreen()
|
||||
{
|
||||
osgViewer::ViewerBase* viewer_base = globals->get_renderer()->getViewerBase();
|
||||
std::vector<osgViewer::GraphicsWindow*> windows;
|
||||
viewer->getWindows(windows);
|
||||
viewer_base->getWindows(windows);
|
||||
|
||||
if (windows.empty())
|
||||
return; // Huh?!?
|
||||
|
@ -544,11 +606,14 @@ static int _cursor = -1;
|
|||
void fgSetMouseCursor(int cursor)
|
||||
{
|
||||
_cursor = cursor;
|
||||
if (!viewer)
|
||||
if (!globals || !globals->get_renderer())
|
||||
return;
|
||||
osgViewer::ViewerBase* viewer_base = globals->get_renderer()->getViewerBase();
|
||||
if (!viewer_base)
|
||||
return;
|
||||
|
||||
std::vector<osgViewer::GraphicsWindow*> windows;
|
||||
viewer->getWindows(windows);
|
||||
viewer_base->getWindows(windows);
|
||||
for (osgViewer::GraphicsWindow* gw : windows) {
|
||||
setMouseCursor(gw, cursor);
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ fgviewerMain(int argc, char** argv)
|
|||
// construct the viewer.
|
||||
FGRenderer* fgrenderer = new FGRenderer();
|
||||
osgViewer::Viewer* viewer = new osgViewer::Viewer(arguments);
|
||||
fgrenderer->setViewer(viewer);
|
||||
fgrenderer->setView(viewer);
|
||||
osg::Camera* camera = viewer->getCamera();
|
||||
osgViewer::Renderer* renderer
|
||||
= static_cast<osgViewer::Renderer*>(camera->getRenderer());
|
||||
|
|
|
@ -359,8 +359,8 @@ FGRenderer::~FGRenderer()
|
|||
}
|
||||
|
||||
// replace the viewer's scene completely
|
||||
if (getViewer()) {
|
||||
getViewer()->setSceneData(new osg::Group);
|
||||
if (getView()) {
|
||||
getView()->setSceneData(new osg::Group);
|
||||
}
|
||||
|
||||
delete _sky;
|
||||
|
@ -398,28 +398,39 @@ FGRenderer::addChangeListener(SGPropertyChangeListener* l, const char* path)
|
|||
}
|
||||
|
||||
// Initialize various GL/view parameters
|
||||
//
|
||||
// Note that this appears to be called *after* FGRenderer::init().
|
||||
//
|
||||
void
|
||||
FGRenderer::preinit( void )
|
||||
{
|
||||
// important that we reset the viewer sceneData here, to ensure the reference
|
||||
// time for everything is in sync; otherwise on reset the Viewer and
|
||||
// GraphicsWindow clocks are out of sync.
|
||||
osgViewer::Viewer* viewer = getViewer();
|
||||
viewer->setName("osgViewer");
|
||||
osgViewer::View* view = getView();
|
||||
view->setName("osgViewer");
|
||||
_viewerSceneRoot = new osg::Group;
|
||||
_viewerSceneRoot->setName("viewerSceneRoot");
|
||||
viewer->setSceneData(_viewerSceneRoot);
|
||||
view->setSceneData(_viewerSceneRoot);
|
||||
view->setDatabasePager(FGScenery::getPagerSingleton());
|
||||
|
||||
_quickDrawable = nullptr;
|
||||
_splash = new SplashScreen;
|
||||
_viewerSceneRoot->addChild(_splash);
|
||||
|
||||
_frameStamp = new osg::FrameStamp;
|
||||
viewer->setFrameStamp(_frameStamp.get());
|
||||
if (composite_viewer) {
|
||||
// Nothing to do - composite_viewer->addView() will tell view to use
|
||||
// composite_viewer's FrameStamp.
|
||||
}
|
||||
else {
|
||||
_frameStamp = new osg::FrameStamp;
|
||||
view->setFrameStamp(_frameStamp.get());
|
||||
}
|
||||
|
||||
// Scene doesn't seem to pass the frame stamp to the update
|
||||
// visitor automatically.
|
||||
_updateVisitor->setFrameStamp(_frameStamp.get());
|
||||
viewer->setUpdateVisitor(_updateVisitor.get());
|
||||
_updateVisitor->setFrameStamp(getFrameStamp());
|
||||
getViewerBase()->setUpdateVisitor(_updateVisitor.get());
|
||||
fgSetDouble("/sim/startup/splash-alpha", 1.0);
|
||||
|
||||
// hide the menubar if it overlaps the window, so the splash screen
|
||||
|
@ -436,6 +447,31 @@ FGRenderer::init( void )
|
|||
|
||||
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);
|
||||
_position_finalized = fgGetNode("/sim/position-finalized", true);
|
||||
|
||||
|
@ -542,7 +578,7 @@ void FGRenderer::setupRoot()
|
|||
void
|
||||
FGRenderer::setupView( void )
|
||||
{
|
||||
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
|
||||
osgViewer::View* view = globals->get_renderer()->getView();
|
||||
osg::initNotifyLevel();
|
||||
|
||||
// The number of polygon-offset "units" to place between layers. In
|
||||
|
@ -571,7 +607,7 @@ FGRenderer::setupView( void )
|
|||
fgGetNode("/environment", true),
|
||||
opt.get());
|
||||
|
||||
viewer->getCamera()
|
||||
view->getCamera()
|
||||
->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
|
||||
|
||||
|
||||
|
@ -647,22 +683,25 @@ FGRenderer::setupView( void )
|
|||
|
||||
#if defined(HAVE_PUI)
|
||||
_puiCamera = new flightgear::PUICamera;
|
||||
_puiCamera->init(guiCamera, viewer);
|
||||
_puiCamera->init(guiCamera, view);
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_QQ_UI)
|
||||
std::string rootQMLPath = fgGetString("/sim/gui/qml-root-path");
|
||||
auto graphicsWindow = dynamic_cast<osgViewer::GraphicsWindow*>(guiCamera->getGraphicsContext());
|
||||
osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(view);
|
||||
if (viewer) {
|
||||
std::string rootQMLPath = fgGetString("/sim/gui/qml-root-path");
|
||||
auto graphicsWindow = dynamic_cast<osgViewer::GraphicsWindow*>(guiCamera->getGraphicsContext());
|
||||
|
||||
if (!rootQMLPath.empty()) {
|
||||
_quickDrawable = new QQuickDrawable;
|
||||
_quickDrawable->setup(graphicsWindow, viewer);
|
||||
if (!rootQMLPath.empty()) {
|
||||
_quickDrawable = new QQuickDrawable;
|
||||
_quickDrawable->setup(graphicsWindow, viewer);
|
||||
|
||||
_quickDrawable->setSource(QUrl::fromLocalFile(QString::fromStdString(rootQMLPath)));
|
||||
|
||||
osg::Geode* qqGeode = new osg::Geode;
|
||||
qqGeode->addDrawable(_quickDrawable);
|
||||
guiCamera->addChild(qqGeode);
|
||||
_quickDrawable->setSource(QUrl::fromLocalFile(QString::fromStdString(rootQMLPath)));
|
||||
|
||||
osg::Geode* qqGeode = new osg::Geode;
|
||||
qqGeode->addDrawable(_quickDrawable);
|
||||
guiCamera->addChild(qqGeode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
guiCamera->insertChild(0, FGPanelNode::create2DPanelNode());
|
||||
|
@ -706,7 +745,6 @@ FGRenderer::update( ) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
|
||||
|
||||
if (_splash_alpha->getDoubleValue()>0.0)
|
||||
{
|
||||
|
@ -748,38 +786,53 @@ FGRenderer::update( ) {
|
|||
// Force update of center dependent values ...
|
||||
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
|
||||
? toOsg(l->adj_fog_color())
|
||||
// skydome ends at ~262000ft (default rendering)
|
||||
// ~328000 ft (ALS) and would produce a strange
|
||||
// looking greyish space -> black looks much
|
||||
// better :-)
|
||||
: osg::Vec4(0, 0, 0, 1);
|
||||
camera->setClearColor(clear_color);
|
||||
|
||||
osg::Vec4 clear_color = _altitude_ft->getDoubleValue() < 250000
|
||||
? toOsg(l->adj_fog_color())
|
||||
// skydome ends at ~262000ft (default rendering)
|
||||
// ~328000 ft (ALS) and would produce a strange
|
||||
// looking greyish space -> black looks much
|
||||
// better :-)
|
||||
: osg::Vec4(0, 0, 0, 1);
|
||||
camera->setClearColor(clear_color);
|
||||
updateSky();
|
||||
|
||||
updateSky();
|
||||
|
||||
// need to call the update visitor once
|
||||
_frameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
|
||||
_updateVisitor->setViewData(current__view->getViewPosition(),
|
||||
current__view->getViewOrientation());
|
||||
SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
|
||||
_updateVisitor->setLight(direction, l->scene_ambient(),
|
||||
l->scene_diffuse(), l->scene_specular(),
|
||||
l->adj_fog_color(),
|
||||
l->get_sun_angle()*SGD_RADIANS_TO_DEGREES);
|
||||
_updateVisitor->setVisibility(actual_visibility);
|
||||
simgear::GroundLightManager::instance()->update(_updateVisitor.get());
|
||||
osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
|
||||
cullMask |= simgear::GroundLightManager::instance()
|
||||
->getLightNodeMask(_updateVisitor.get());
|
||||
if (_panel_hotspots->getBoolValue())
|
||||
cullMask |= simgear::PICK_BIT;
|
||||
camera->setCullMask(cullMask);
|
||||
camera->setCullMaskLeft(cullMask);
|
||||
camera->setCullMaskRight(cullMask);
|
||||
// need to call the update visitor once
|
||||
getFrameStamp()->setCalendarTime(*globals->get_time_params()->getGmt());
|
||||
_updateVisitor->setViewData(current__view->getViewPosition(),
|
||||
current__view->getViewOrientation());
|
||||
//_updateVisitor->setViewData(eye2, center3);
|
||||
SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
|
||||
_updateVisitor->setLight(direction, l->scene_ambient(),
|
||||
l->scene_diffuse(), l->scene_specular(),
|
||||
l->adj_fog_color(),
|
||||
l->get_sun_angle()*SGD_RADIANS_TO_DEGREES);
|
||||
_updateVisitor->setVisibility(actual_visibility);
|
||||
simgear::GroundLightManager::instance()->update(_updateVisitor.get());
|
||||
osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
|
||||
cullMask |= simgear::GroundLightManager::instance()
|
||||
->getLightNodeMask(_updateVisitor.get());
|
||||
if (_panel_hotspots->getBoolValue())
|
||||
cullMask |= simgear::PICK_BIT;
|
||||
camera->setCullMask(cullMask);
|
||||
camera->setCullMaskLeft(cullMask);
|
||||
camera->setCullMaskRight(cullMask);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -958,10 +1011,65 @@ PickList FGRenderer::pick(const osg::Vec2& windowPos)
|
|||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
FGRenderer::setViewer(osgViewer::Viewer* viewer_)
|
||||
osgViewer::ViewerBase* FGRenderer::getViewerBase()
|
||||
{
|
||||
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_;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -991,8 +1099,8 @@ FGRenderer::setPlanes( double zNear, double zFar )
|
|||
bool
|
||||
fgDumpSceneGraphToFile(const char* filename)
|
||||
{
|
||||
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
|
||||
return osgDB::writeNodeFile(*viewer->getSceneData(), filename);
|
||||
osgViewer::View* view = globals->get_renderer()->getView();
|
||||
return osgDB::writeNodeFile(*view->getSceneData(), filename);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1199,14 +1307,14 @@ protected:
|
|||
|
||||
bool printVisibleSceneInfo(FGRenderer* renderer)
|
||||
{
|
||||
osgViewer::Viewer* viewer = renderer->getViewer();
|
||||
osgViewer::View* view = renderer->getView();
|
||||
VisibleSceneInfoVistor vsv;
|
||||
Viewport* vp = 0;
|
||||
if (!viewer->getCamera()->getViewport() && viewer->getNumSlaves() > 0) {
|
||||
const osg::View::Slave& slave = viewer->getSlave(0);
|
||||
if (!view->getCamera()->getViewport() && view->getNumSlaves() > 0) {
|
||||
const osg::View::Slave& slave = view->getSlave(0);
|
||||
vp = slave._camera->getViewport();
|
||||
}
|
||||
vsv.doTraversal(viewer->getCamera(), viewer->getSceneData(), vp);
|
||||
vsv.doTraversal(view->getCamera(), view->getSceneData(), vp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#include <osg/Vec2>
|
||||
#include <osg/Vec3>
|
||||
|
||||
#include <osgViewer/CompositeViewer>
|
||||
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Camera;
|
||||
|
@ -61,12 +64,20 @@ public:
|
|||
/** Just pick into the scene and return the pick callbacks on the way ...
|
||||
*/
|
||||
PickList pick(const osg::Vec2& windowPos);
|
||||
|
||||
/* Returns either composite_viewer or viewer. */
|
||||
osgViewer::ViewerBase* getViewerBase();
|
||||
|
||||
/** Get and set the OSG Viewer object, if any.
|
||||
*/
|
||||
osgViewer::Viewer* getViewer() { return viewer.get(); }
|
||||
const osgViewer::Viewer* getViewer() const { return viewer.get(); }
|
||||
void setViewer(osgViewer::Viewer* viewer);
|
||||
osgViewer::View* getView();
|
||||
const osgViewer::View* getView() const;
|
||||
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.
|
||||
*/
|
||||
flightgear::FGEventHandler* getEventHandler() { return eventHandler.get(); }
|
||||
|
@ -84,7 +95,9 @@ public:
|
|||
void setPlanes( double zNear, double zFar );
|
||||
|
||||
protected:
|
||||
int composite_viewer_enabled = -1;
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer;
|
||||
osg::ref_ptr<osgViewer::CompositeViewer> composite_viewer;
|
||||
osg::ref_ptr<flightgear::FGEventHandler> eventHandler;
|
||||
|
||||
osg::ref_ptr<osg::FrameStamp> _frameStamp;
|
||||
|
|
|
@ -204,6 +204,12 @@ void SplashScreen::createNodes()
|
|||
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
1394
src/Viewer/sview.cxx
Normal file
File diff suppressed because it is too large
Load diff
80
src/Viewer/sview.hxx
Normal file
80
src/Viewer/sview.hxx
Normal 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);
|
|
@ -33,8 +33,12 @@
|
|||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include "view.hxx"
|
||||
#include "sview.hxx"
|
||||
#include "renderer.hxx"
|
||||
|
||||
#include "CameraGroup.hxx"
|
||||
#include "Scenery/scenery.hxx"
|
||||
|
||||
|
||||
// Constructor
|
||||
FGViewMgr::FGViewMgr(void)
|
||||
|
@ -134,6 +138,7 @@ FGViewMgr::unbind ()
|
|||
_viewNumberProp.clear();
|
||||
|
||||
ViewPropertyEvaluator::clear();
|
||||
SviewClear();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -155,6 +160,7 @@ FGViewMgr::update (double dt)
|
|||
cameraGroup->update(toOsg(currentView->getViewPosition()),
|
||||
toOsg(currentView->getViewOrientation()));
|
||||
}
|
||||
SviewUpdate(dt);
|
||||
}
|
||||
|
||||
void FGViewMgr::clear()
|
||||
|
@ -222,6 +228,33 @@ FGViewMgr::prev_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
|
||||
FGViewMgr::add_view( flightgear::View * v )
|
||||
{
|
||||
|
|
|
@ -75,6 +75,19 @@ public:
|
|||
flightgear::View* next_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
|
||||
void clear();
|
||||
|
||||
|
@ -84,6 +97,7 @@ private:
|
|||
simgear::TiedPropertyList _tiedProperties;
|
||||
|
||||
void setCurrentViewIndex(int newview);
|
||||
void clone_internal(const std::string& type);
|
||||
|
||||
bool _inited = false;
|
||||
std::vector<SGPropertyNode_ptr> config_list;
|
||||
|
|
|
@ -45,7 +45,7 @@ void initScenery()
|
|||
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
|
||||
FGRenderer* render = globals->get_renderer();
|
||||
render->init();
|
||||
render->setViewer(viewer.get());
|
||||
render->setView(viewer.get());
|
||||
|
||||
// Start up the scenery subsystem.
|
||||
globals->add_new_subsystem<FGScenery>(SGSubsystemMgr::DISPLAY);
|
||||
|
|
Loading…
Reference in a new issue