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 avoids crashing when using Qt : we cannot call exit() safely since
QGuiApplication won’t shut down correctly. Instead throw a special
marker object and catch this in boostrap.
For an instance of this, see:
https://sourceforge.net/p/flightgear/codetickets/2070/
Change fgcommand to take an optional property tree root element.
This fixes the animation bindings to use the defined property tree root - to support multiplayer (or other) model that can bind to the correct part of the property tree.
Requires a corresponding fix in sg to allow the command methods to take an optional root parameter.
What this means is that when inside someone else's multiplayer model (e.g. backseat, or co-pilot), the multipalyer (AI) model will correctly modify properties inside the correct part of the property tree inside (/ai), rather than modifying the properties inside the same part of the tree as the non-ai model.
This means that a properly setup model will operate within it's own space in the property tree; and permit more generic multiplayer code to be written.
This is probably responsible for some of the pollution of the root property tree with MP aircraft properties.
- Rename fatalMessageBox() to fatalMessageBoxWithoutExit(). This should
prevent the kind of bug that prompted this set of changes: someone
calling fatalMessageBox(), assuming the program would stop at that
point, whereas in reality it did not.
- Add new function fatalMessageBoxThenExit(). This is not vital of
course, but allows one to spare one line here and there and to apply
the DRY principle for such fatal exits.
- Replace every existing call to fatalMessageBox() with one or the other
of the two new functions. Improve formatting along the way. This
fixes a few bugs of the kind explained above.
This reverts commit 9e6a3ebc6b ("Make
fatalMessageBox() end with std::abort() and declare it [[noreturn]]").
After reflexion, it seems better to let fatalMessageBox() return,
because there is existing code that appears to be relying on this aspect
to do some work after having called fatalMessageBox() (cf. main() in
bootstrap.cxx). Also, the way of exiting from fatalMessageBox() after
commit 9e6a3ebc6b (std::abort()) was probably too brutal for a
controlled exit---as opposed to a terminate handler.
This allows us to display a platform-native dialog for problems
which occur early in startup (before we can show a PUI/Canvas dialog).
In particular this improves feedback where FG_HOME, FG_DATA or
aircraft selection is wrong, all of which happen very early in startup.