1
0
Fork 0
flightgear/src/Viewer/viewmgr.cxx

264 lines
5.7 KiB
C++
Raw Normal View History

// viewmgr.cxx -- class for managing all the views in the flightgear world.
//
// Written by Curtis Olson, started October 2000.
Major viewer-code overhaul from Jim Wilson: Description: This update includes the new viewer interface as proposed by David M. and a first pass at cleaning up the viewer/view manager code by Jim W. Note that I have dropped Main/viewer_lookat.?xx and Main/viewer_rph.?xx and modified the Makefile.am accordingly. Detail of work: Overall: The code reads a little easier. There are still some unnecessary bits in there and I'd like to supplement the comments in the viewer.hxx with a tiny bit on each interface group and what the groupings mean (similar but briefer than what you emailed me the other day). I tried not to mess up the style, but there is an occasional inconsistency. In general I wouldn't call it done (especially since there's no tower yet! :)), but I'd like to get this out there so others can comment, and test. In Viewer: The interface as you suggested has been implemented. Basically everything seems to work as it did visually. There is no difference that I can see in performance, although some things might be a tiny bit faster. I've merged the lookat and rph (pilot view) code into the recalc for the viewer. There is still some redundancy between the two, but a lot has been removed. In some cases I've taken some code that we'd likely want to inline anyway and left it in there in duplicate. You'll see that the code for both looks a little cleaner. I need to take a closer look at the rotations in particular. I've cleaned up a little there, but I suspect more can be done to streamline this. The external declaration to the Quat_mat in mouse.cxx has been removed. IMHO the quat doesn't serve any intrinsic purpose in mouse.cxx, but I'm not about to rip it out. It would seem that there more conventional ways to get spherical data that are just as fast. In any case all the viewer was pulling from the quat matrix was the pitch value so I modified mouse.cxx to output to our pitchOffset input and that works fine. I've changed the native values to degrees from radians where appropriate. This required a conversion from degrees to radians in a couple modules that access the interface. Perhaps we should add interface calls that do the conversion, e.g. a getHeadingOffset_rad() to go along with the getHeadingOffset_deg(). On the view_offset (now headingOffset) thing there are two entry points because of the ability to instantly switch views or to scroll to a new view angle (by hitting the numeric keys for example). This leaves an anomaly in the interface which should be resolved by adding "goal" settings to the interface, e.g. a setGoalHeadingOffset_deg(), setGoalPitchOffset_deg(), etc. Other than these two issues, the next step here will be to look at some further optimizations, and to write support code for a tower view. That should be fairly simple at this point. I was considering creating a "simulated tower view" or "pedestrian view" that defaulted to a position off to the right of whereever the plane is at the moment you switch to the tower view. This could be a fall back when we don't have an actual tower location at hand (as would be the case with rural airports). ViewManager: Basically all I did here was neaten things up by ripping out excess crap and made it compatible as is with the new interface. The result is that viewmanager is now ready to be developed. The two preexisting views are still hardcoded into the view manager. The next step would be to design configuration xml (eg /sim/view[x]/config/blahblah) that could be used to set up as many views as we want. If we want to take the easy way out, we might want to insist that view[0] be a pilot-view and have viewmanager check for that.
2002-03-20 17:43:28 +00:00
// partially rewritten by Jim Wilson March 2002
//
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
2006-02-21 01:16:04 +00:00
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
2009-09-18 16:50:08 +00:00
#include "viewmgr.hxx"
#include "ViewPropertyEvaluator.hxx"
2009-09-18 16:50:08 +00:00
Mathias: I have done a patch to eliminate the jitter of 3D-objects near the viewpoint (for example 3D cockpit objects). The problem is the roundoff accuracy of the float values used in the scenegraph together with the transforms of the eyepoint relative to the scenery center. The solution will be to move the scenery center near the view point. This way floats relative accuracy is enough to show a stable picture. To get that right I have introduced a transform node for the scenegraph which is responsible for that shift and uses double values as long as possible. The scenery subsystem now has a list of all those transforms required to place objects in the world and will tell all those transforms that the scenery center has changed when the set_scenery_center() of the scenery subsystem is called. The problem was not solvable by SGModelPlacement and SGLocation, since not all objects, especially the scenery, are placed using these classes. The first approach was to have the scenery center exactly at the eyepoint. This works well for the cockpit. But then the ground jitters a bit below the aircraft. With our default views you can't see that, but that F-18 has a camera view below the left engine intake with the nose gear and the ground in its field of view, here I could see that. Having the scenery center constant will still have this roundoff problems, but like it is now too, the roundoff error here is exactly the same in each frame, so you will not notice any jitter. The real solution is now to keep the scenery center constant as long as it is in a ball of 30m radius around the view point. If the scenery center is outside this ball, just put it at the view point. As a sideeffect of now beeing able to switch the scenery center in the whole scenegraph with one function call, I was able to remove a one half of a problem when switching views, where the scenery center was far off for one or two frames past switching from one view to the next. Also included is a fix to the other half of this problem, where the view position was not yet copied into a view when it is switched (at least under glut). This was responsible for the 'Error: ...' messages of the cloud subsystem when views were switched.
2005-04-29 14:38:24 +00:00
#include <simgear/compiler.h>
#include <simgear/scene/util/OsgMath.hxx>
2009-09-18 16:50:08 +00:00
#include <Main/fg_props.hxx>
#include "view.hxx"
#include "CameraGroup.hxx"
// Constructor
2000-10-30 15:09:17 +00:00
FGViewMgr::FGViewMgr( void ) :
inited(false),
config_list(fgGetNode("/sim", true)->getChildren("view"))
2000-10-30 15:09:17 +00:00
{
current = fgGetInt("/sim/current-view/view-number");
}
// Destructor
FGViewMgr::~FGViewMgr( void )
{
}
void
FGViewMgr::init ()
{
if (inited) {
SG_LOG(SG_VIEW, SG_WARN, "duplicate init of view manager");
return;
}
inited = true;
for (unsigned int i = 0; i < config_list.size(); i++) {
SGPropertyNode *n = config_list[i];
SGPropertyNode *config = n->getChild("config", 0, true);
This patch includes the FGLocation class, a few fixes, cleanup in viewer code. Synced to CVS 19:36 EDT 2002-04-10 (after this evenings JSMsim and Base package updates). Description: Added FGLocation class which is new home for calculating matrix rotations. Viewer can now be configured to access rotations created by the model rather than repeating the same calculations again. Changed model initialization for the time being so that its location data is available for the viewer (currently required by other subsystems). At some point we can move this back to fg_init along with the viewer initialization. Seperated the update from the draw function in the model code. The viewer code needs the same matrix data, and moving the update portion at this time does not increase the number of matrix math iterations. Moved the model draw so that it always appears "in front" of lights and clouds. Reogranized viewer update routine for using the FGLocation class and simplified some more tasks. The routine is fairly easy to follow now, with the steps ordered and spelled out in comments. Viewmgr only updates the current (visible) view now, with the exception of an old reference to "chase view" that will be corrected in forthcoming changes. Also will be doing some work on the viewmgr outputs. Model is now clears the z-buffer in all modes. This will be changed with the next viewmgr update. The only side effect is that models always disappear when over 5km distant from the eye point (can't really see them anyway:-)). Other than a flag to indicate "internal" view I don't anticipate the configuration interface for viewmgr/views will be changed a lot for now. It is close to done. The next viewmgr update will however rework the outputs so may change location. This code will run with the previous version of preferences.xml, but will run faster with the newer version. I am attaching a preferences.xml that should not be commited before the code. All the changes are in the /sim/view section and should show a simpler view configuration that references model locations. Note that I've added a 2nd tower view in "lookfrom" mode for illustration purposes. You can look around using the mouse. You may want to remove that or comment it out.
2002-04-11 04:26:07 +00:00
Allow most default views to work on multiplayer aircraft as well as the user's aircraft. Currently this works for all the default views except for Tower Look From (for which it doesn't really make sense) and Fly-by View. We now search for and load a -set.xml that matches the model .xml, when new multiplayer aircraft is set up. This allows us to find view offsets etc, e.g. allowing cockpit and helicopter views to work with multiplayer aircraft. Properties from the -set.xml are placed into /ai/models/multiplayer[]/set, so for example viewing offsets are in /ai/models/multiplayer[]/set/sim/view[]/config/target-{x,y,z}-offset-m. We also copy the aircraft's chase-distance into the view config params, similar to how fgdata:defaults.xml does for the user's aircraft. And we also fill in views' missing offsets from the Helicopter View config; e.g. this enables the new Tower View AGL to show aircraft correctly centred, despite aircraft currently not having this view defined in their -set.xml. [We don't currently attempt to cache or reuse -set.xml data.] Have ensured that view position responds to mouse movement in the same way for viewing the user's aircraft as for multiplayer aircraft (previously, Model View reversed the affect of vertical mouse movements). Added new Tower AGL view. Behaves similarly to Tower view, but automatically scales and pans vertically in order to always show the vertical range extending from just above the aircraft down to the ground immediately below the aircraft. We use aircrafts chase-distance as an indication of size. We damp the ground level value to reduce the viewing jumping around too much e.g. if the aircraft flies over buildings. The amount of damping is set by fgdata:defaults.xml's lookat-agl-damping value. Fixed problem where Tower View eye position moves slightly as target aircraft heading changes. This was caused by us unnecessarily applying the aircraft-centre correction to the eye position. src/FDM/flight.cxx: also make /orientation/true-heading-deg. This allows local orientation to be used like multiplayer orientation, which only has /ai/models/multiplayer[]/orientation/true-heading-deg. [A better fix might be to replace all occurrencies of /orientation/true-heading-deg with /orientation/heading-deg, but this would be a rather large commit.] Details: src/Viewer/view.*: removed View::updateData() as is no longer required. src/MultiPlayer/multiplaymgr.cxx: use helicopter view target offsets as defaults. E.g. in tower view agl, aircraft won't currently be defining these offsets. More generally, this allows aircraft to define target offsets only in helicoter view. src/FDM/flight.cxx FGMultiplayMgr::FillMsgHdr(): Added tie of /orientation/true-heading-deg to get_Psi_deg, so it duplictes the existing /orientation/heading-deg. src/MultiPlayer/multiplaymgr.cxx src/MultiPlayer/multiplaymgr.hxx FGMultiplayMgr::addMultiplayer(): look for and load -set.xml that matches the model. Patch various view-related things up in similar way to what we do for the user's aircraft, so that multiplayer views work. Made FGMultiplayMgr::getMultiplayer() public, so it can be used by src/Viewer/view.cxx. src/Viewer/view.cxx src/Viewer/view.hxx View::View(): Added lookat_agl, lookat_agl_damping params for new Tower View AGL. Preserve user's field-of-view in separate variable so that Tower View AGL can modify the actual field of view independently. Added view_index param so that we can find multiplayer view[]/config/ properties. getViewOffsets(): new fn that finds view offsets for user aircraft or multiplayer aircraft. View::recalcLookFrom() View::recalcLookAt: Lots of changes to allow things to work with multiplayer aircraft. View::recalcLookAt() can now do Tower View AGL. View::Damping: support for damping, used by Tower View AGL. Might be good to use this for other damping. View::updateData(): removed, as calculations are now all done inside View::recalc*(). put properties {x,y,z}-offset-m into new View::_adjust_offset_m member instead of _offset_m. This avoids confusion between a view's offsets and the offsets added in by the user via the 'Adjust View Position' dialogue. src/Viewer/viewmgr.cxx FGViewMgr::init(): pass view number to flightgear::View::createFromProperties().
2019-05-31 23:07:46 +01:00
flightgear::View* v = flightgear::View::createFromProperties(config, n->getIndex());
if (v) {
add_view(v);
}
}
2016-01-17 16:14:11 -06:00
get_current_view()->bind();
}
void
FGViewMgr::postinit()
{
// force update now so many properties of the current view are valid,
// eg view position and orientation (as exposed via globals)
update(0.0);
}
void
FGViewMgr::shutdown()
{
if (!inited) {
return;
}
inited = false;
2016-01-17 16:14:11 -06:00
views.clear();
}
void
FGViewMgr::reinit ()
{
2016-01-17 16:14:11 -06:00
viewer_list::iterator it;
for (it = views.begin(); it != views.end(); ++it) {
(*it)->resetOffsetsAndFOV();
}
}
void
FGViewMgr::bind()
{
// these are bound to the current view properties
_tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
2016-01-17 16:14:11 -06:00
2016-01-20 21:26:51 -05:00
_tiedProperties.Tie("view-number", this,
&FGViewMgr::getView, &FGViewMgr::setView, false);
2016-01-20 21:26:51 -05:00
_viewNumberProp = _tiedProperties.getRoot()->getNode("view-number");
_viewNumberProp->setAttribute(SGPropertyNode::ARCHIVE, false);
_viewNumberProp->setAttribute(SGPropertyNode::PRESERVE, true);
_viewNumberProp->setAttribute(SGPropertyNode::LISTENER_SAFE, true);
}
void
FGViewMgr::unbind ()
{
2016-01-17 16:14:11 -06:00
flightgear::View* v = get_current_view();
if (v) {
v->unbind();
}
_tiedProperties.Untie();
2016-01-20 21:26:51 -05:00
_viewNumberProp.clear();
ViewPropertyEvaluator::clear();
}
void
FGViewMgr::update (double dt)
{
flightgear::View* currentView = get_current_view();
if (!currentView) {
return;
}
// Update the current view
currentView->update(dt);
// update the camera now
osg::ref_ptr<flightgear::CameraGroup> cameraGroup = flightgear::CameraGroup::getDefault();
cameraGroup->setCameraParameters(currentView->get_v_fov(),
cameraGroup->getMasterAspectRatio());
2019-02-04 18:01:15 +01:00
cameraGroup->update(toOsg(currentView->getViewPosition()),
toOsg(currentView->getViewOrientation()));
}
void FGViewMgr::clear()
{
views.clear();
}
flightgear::View*
FGViewMgr::get_current_view()
{
if ( current < (int)views.size() ) {
return views[current];
} else {
return NULL;
}
}
const flightgear::View*
FGViewMgr::get_current_view() const
{
if ( current < (int)views.size() ) {
return views[current];
} else {
return NULL;
}
}
flightgear::View*
FGViewMgr::get_view( int i )
{
if ( i < 0 ) { i = 0; }
if ( i >= (int)views.size() ) { i = views.size() - 1; }
return views[i];
}
const flightgear::View*
FGViewMgr::get_view( int i ) const
{
if ( i < 0 ) { i = 0; }
if ( i >= (int)views.size() ) { i = views.size() - 1; }
return views[i];
}
flightgear::View*
FGViewMgr::next_view()
{
setView((current+1 < (int)views.size()) ? (current + 1) : 0);
2016-01-20 21:26:51 -05:00
_viewNumberProp->fireValueChanged();
return views[current];
}
flightgear::View*
FGViewMgr::prev_view()
{
setView((0 < current) ? (current - 1) : (views.size() - 1));
2016-01-20 21:26:51 -05:00
_viewNumberProp->fireValueChanged();
return views[current];
}
2009-09-18 16:50:08 +00:00
void
FGViewMgr::add_view( flightgear::View * v )
2009-09-18 16:50:08 +00:00
{
views.push_back(v);
v->init();
}
2016-01-20 21:26:51 -05:00
int FGViewMgr::getView () const
{
2016-01-20 21:26:51 -05:00
return current;
}
void
FGViewMgr::setView (int newview)
{
2016-01-20 21:26:51 -05:00
if (newview == current) {
return;
}
// negative numbers -> set view with node index -newview
if (newview < 0) {
for (int i = 0; i < (int)config_list.size(); i++) {
int index = -config_list[i]->getIndex();
if (index == newview)
newview = i;
}
if (newview < 0)
return;
}
// if newview number too low wrap to last view...
if (newview < 0)
newview = (int)views.size() - 1;
// if newview number to high wrap to zero...
if (newview >= (int)views.size())
newview = 0;
if (get_current_view()) {
get_current_view()->unbind();
}
// set new view
current = newview;
if (get_current_view()) {
get_current_view()->bind();
}
}
// Register the subsystem.
SGSubsystemMgr::Registrant<FGViewMgr> registrantFGViewMgr(
SGSubsystemMgr::DISPLAY);