1 // viewmgr.cxx -- class for managing all the views in the flightgear world.
3 // Written by Curtis Olson, started October 2000.
4 // partially rewritten by Jim Wilson March 2002
6 // Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include "viewmgr.hxx"
30 #include <string.h> // strcmp
32 #include <simgear/compiler.h>
33 #include <simgear/scene/util/OsgMath.hxx>
35 #include <Main/fg_props.hxx>
38 #include "CameraGroup.hxx"
41 FGViewMgr::FGViewMgr( void ) :
45 config_list(fgGetNode("/sim", true)->getChildren("view")),
51 FGViewMgr::~FGViewMgr( void )
59 SG_LOG(SG_VIEW, SG_WARN, "duplicate init of view manager");
65 for (unsigned int i = 0; i < config_list.size(); i++) {
66 SGPropertyNode *n = config_list[i];
67 SGPropertyNode *config = n->getChild("config", 0, true);
69 flightgear::View* v = flightgear::View::createFromProperties(config);
75 get_current_view()->bind();
81 // force update now so many properties of the current view are valid,
82 // eg view position and orientation (as exposed via globals)
100 viewer_list::iterator it;
101 for (it = views.begin(); it != views.end(); ++it) {
102 (*it)->resetOffsetsAndFOV();
106 typedef double (FGViewMgr::*double_getter)() const;
111 // these are bound to the current view properties
112 _tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
115 _tiedProperties.Tie("view-number", this,
116 &FGViewMgr::getView, &FGViewMgr::setView, false);
117 _viewNumberProp = _tiedProperties.getRoot()->getNode("view-number");
118 _viewNumberProp->setAttribute(SGPropertyNode::ARCHIVE, false);
119 _viewNumberProp->setAttribute(SGPropertyNode::PRESERVE, true);
122 _tiedProperties.Tie("axes/long", this,
123 (double_getter)0, &FGViewMgr::setViewAxisLong);
124 fgSetArchivable("/sim/current-view/axes/long");
126 _tiedProperties.Tie("axes/lat", this,
127 (double_getter)0, &FGViewMgr::setViewAxisLat);
128 fgSetArchivable("/sim/current-view/axes/lat");
130 current_x_offs = fgGetNode("/sim/current-view/x-offset-m", true);
131 current_y_offs = fgGetNode("/sim/current-view/y-offset-m", true);
132 current_z_offs = fgGetNode("/sim/current-view/z-offset-m", true);
133 target_x_offs = fgGetNode("/sim/current-view/target-x-offset-m", true);
134 target_y_offs = fgGetNode("/sim/current-view/target-y-offset-m", true);
135 target_z_offs = fgGetNode("/sim/current-view/target-z-offset-m", true);
142 flightgear::View* v = get_current_view();
147 _tiedProperties.Untie();
148 _viewNumberProp.clear();
151 target_x_offs.clear();
152 target_y_offs.clear();
153 target_z_offs.clear();
154 current_x_offs.clear();
155 current_y_offs.clear();
156 current_z_offs.clear();
160 FGViewMgr::update (double dt)
162 flightgear::View* currentView = get_current_view();
163 if (!currentView) return;
165 // Set up view location and orientation
167 currentView->updateData();
169 // these properties aren't tied - manually propogate them to the
170 // currently active view
171 currentView->setXOffset_m(current_x_offs->getDoubleValue());
172 currentView->setYOffset_m(current_y_offs->getDoubleValue());
173 currentView->setZOffset_m(current_z_offs->getDoubleValue());
175 currentView->setTargetXOffset_m(target_x_offs->getDoubleValue());
176 currentView->setTargetYOffset_m(target_y_offs->getDoubleValue());
177 currentView->setTargetZOffset_m(target_z_offs->getDoubleValue());
179 // Update the current view
181 currentView->update(dt);
184 // update the camera now
185 osg::ref_ptr<flightgear::CameraGroup> cameraGroup = flightgear::CameraGroup::getDefault();
186 cameraGroup->update(toOsg(currentView->getViewPosition()),
187 toOsg(currentView->getViewOrientation()));
188 cameraGroup->setCameraParameters(currentView->get_v_fov(),
189 cameraGroup->getMasterAspectRatio());
192 void FGViewMgr::clear()
198 FGViewMgr::get_current_view()
200 if ( current < (int)views.size() ) {
201 return views[current];
207 const flightgear::View*
208 FGViewMgr::get_current_view() const
210 if ( current < (int)views.size() ) {
211 return views[current];
219 FGViewMgr::get_view( int i )
221 if ( i < 0 ) { i = 0; }
222 if ( i >= (int)views.size() ) { i = views.size() - 1; }
226 const flightgear::View*
227 FGViewMgr::get_view( int i ) const
229 if ( i < 0 ) { i = 0; }
230 if ( i >= (int)views.size() ) { i = views.size() - 1; }
235 FGViewMgr::next_view()
237 setView((current+1 < (int)views.size()) ? (current + 1) : 0);
238 _viewNumberProp->fireValueChanged();
239 return views[current];
243 FGViewMgr::prev_view()
245 setView((0 < current) ? (current - 1) : (views.size() - 1));
246 _viewNumberProp->fireValueChanged();
247 return views[current];
251 FGViewMgr::add_view( flightgear::View * v )
257 int FGViewMgr::getView () const
263 FGViewMgr::setView (int newview)
265 if (newview == current) {
269 // negative numbers -> set view with node index -newview
271 for (int i = 0; i < (int)config_list.size(); i++) {
272 int index = -config_list[i]->getIndex();
273 if (index == newview)
280 // if newview number too low wrap to last view...
282 newview = (int)views.size() - 1;
284 // if newview number to high wrap to zero...
285 if (newview >= (int)views.size())
288 if (get_current_view()) {
289 get_current_view()->unbind();
295 if (get_current_view()) {
296 get_current_view()->bind();
299 // force an update now, to avoid returning bogus data.
300 // real fix would to be make all the accessors use the dirty mechanism
301 // on FGViewer, so update() is a no-op.
306 FGViewMgr::setViewAxisLong (double axis)
312 FGViewMgr::setViewAxisLat (double axis)
318 FGViewMgr::do_axes ()
320 // Take no action when hat is centered
321 if ( ( axis_long < 0.01 ) &&
322 ( axis_long > -0.01 ) &&
323 ( axis_lat < 0.01 ) &&
328 double viewDir = 999;
330 /* Do all the quick and easy cases */
331 if (axis_long < 0) { // Longitudinal axis forward
332 if (axis_lat == axis_long)
333 viewDir = fgGetDouble("/sim/view/config/front-left-direction-deg");
334 else if (axis_lat == - axis_long)
335 viewDir = fgGetDouble("/sim/view/config/front-right-direction-deg");
336 else if (axis_lat == 0)
337 viewDir = fgGetDouble("/sim/view/config/front-direction-deg");
338 } else if (axis_long > 0) { // Longitudinal axis backward
339 if (axis_lat == - axis_long)
340 viewDir = fgGetDouble("/sim/view/config/back-left-direction-deg");
341 else if (axis_lat == axis_long)
342 viewDir = fgGetDouble("/sim/view/config/back-right-direction-deg");
343 else if (axis_lat == 0)
344 viewDir = fgGetDouble("/sim/view/config/back-direction-deg");
345 } else if (axis_long == 0) { // Longitudinal axis neutral
347 viewDir = fgGetDouble("/sim/view/config/left-direction-deg");
348 else if (axis_lat > 0)
349 viewDir = fgGetDouble("/sim/view/config/right-direction-deg");
350 else return; /* And assertion failure maybe? */
353 // Do all the difficult cases
355 viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
356 if ( viewDir < -1 ) viewDir += 360;
358 get_current_view()->setGoalHeadingOffset_deg(viewDir);