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 - curt@flightgear.org
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., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <string.h> // strcmp
28 #include <GUI/sgVec3Slider.hxx> // FIXME: this should NOT be needed
30 #include "viewmgr.hxx"
31 #include "fg_props.hxx"
34 string viewpath, nodepath, strdata;
37 FGViewMgr::FGViewMgr( void ) :
46 FGViewMgr::~FGViewMgr( void ) {
53 bool from_model = false;
54 bool at_model = false;
55 int from_model_index = 0;
56 int at_model_index = 0;
58 for (int i = 0; i < fgGetInt("/sim/number-views"); i++) {
59 viewpath = "/sim/view";
60 sprintf(stridx, "[%d]", i);
63 // find out what type of view this is...
66 strdata = fgGetString(nodepath.c_str());
69 // this is assumed to be an aircraft model...we will need to read
70 // model-from-type as well.
71 // find out if this is a model we are looking from...
73 nodepath += "/config/from-model";
74 from_model = fgGetBool(nodepath.c_str());
76 // get model index (which model)
79 nodepath += "/config/from-model-idx";
80 from_model_index = fgGetInt(nodepath.c_str());
83 if ( strcmp("lookat",strdata.c_str()) == 0 ) {
84 // find out if this is a model we are looking at...
86 nodepath += "/config/at-model";
87 at_model = fgGetBool(nodepath.c_str());
89 // get model index (which model)
92 nodepath += "/config/at-model-idx";
93 at_model_index = fgGetInt(nodepath.c_str());
97 // supporting two types now "lookat" = 1 and "lookfrom" = 0
98 if ( strcmp("lookat",strdata.c_str()) == 0 )
99 add_view(new FGViewer ( FG_LOOKAT, from_model, from_model_index, at_model, at_model_index ));
101 add_view(new FGViewer ( FG_LOOKFROM, from_model, from_model_index, false, 0 ));
105 typedef double (FGViewMgr::*double_getter)() const;
111 // need to redo these bindings to the new locations (move to viewer?)
112 fgTie("/sim/view/offset-deg", this,
113 &FGViewMgr::getViewOffset_deg, &FGViewMgr::setViewOffset_deg);
114 fgSetArchivable("/sim/view/offset-deg");
115 fgTie("/sim/view/goal-offset-deg", this,
116 &FGViewMgr::getGoalViewOffset_deg, &FGViewMgr::setGoalViewOffset_deg);
117 fgSetArchivable("/sim/view/goal-offset-deg");
118 fgTie("/sim/view/tilt-deg", this,
119 &FGViewMgr::getViewTilt_deg, &FGViewMgr::setViewTilt_deg);
120 fgSetArchivable("/sim/view/tilt-deg");
121 fgTie("/sim/view/goal-tilt-deg", this,
122 &FGViewMgr::getGoalViewTilt_deg, &FGViewMgr::setGoalViewTilt_deg);
123 fgSetArchivable("/sim/view/goal-tilt-deg");
124 fgTie("/sim/view/pilot/x-offset-m", this,
125 &FGViewMgr::getPilotXOffset_m, &FGViewMgr::setPilotXOffset_m);
126 fgSetArchivable("/sim/view/pilot/x-offset-m");
127 fgTie("/sim/view/pilot/y-offset-m", this,
128 &FGViewMgr::getPilotYOffset_m, &FGViewMgr::setPilotYOffset_m);
129 fgSetArchivable("/sim/view/pilot/y-offset-m");
130 fgTie("/sim/view/pilot/z-offset-m", this,
131 &FGViewMgr::getPilotZOffset_m, &FGViewMgr::setPilotZOffset_m);
132 fgSetArchivable("/sim/view/pilot/z-offset-m");
133 fgTie("/sim/field-of-view", this,
134 &FGViewMgr::getFOV_deg, &FGViewMgr::setFOV_deg);
135 fgSetArchivable("/sim/field-of-view");
136 fgTie("/sim/view/axes/long", this,
137 (double_getter)0, &FGViewMgr::setViewAxisLong);
138 fgTie("/sim/view/axes/lat", this,
139 (double_getter)0, &FGViewMgr::setViewAxisLat);
146 // need to redo these bindings to the new locations (move to viewer?)
147 fgUntie("/sim/view/offset-deg");
148 fgUntie("/sim/view/goal-offset-deg");
149 fgUntie("/sim/view/tilt-deg");
150 fgUntie("/sim/view/goal-tilt-deg");
151 fgUntie("/sim/view/pilot/x-offset-m");
152 fgUntie("/sim/view/pilot/y-offset-m");
153 fgUntie("/sim/view/pilot/z-offset-m");
154 fgUntie("/sim/field-of-view");
155 fgUntie("/sim/view/axes/long");
156 fgUntie("/sim/view/axes/lat");
160 FGViewMgr::update (int dt)
163 double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
165 FGViewer * view = get_current_view();
171 viewpath = "/sim/view";
172 sprintf(stridx, "[%d]", i);
176 FGViewer *loop_view = (FGViewer *)get_view( i );
178 // Set up view location and orientation
181 nodepath += "/config/from-model";
182 if (!fgGetBool(nodepath.c_str())) {
184 nodepath += "/config/eye-lon-deg-path";
185 lon_deg = fgGetDouble(fgGetString(nodepath.c_str()));
187 nodepath += "/config/eye-lat-deg-path";
188 lat_deg = fgGetDouble(fgGetString(nodepath.c_str()));
190 nodepath += "/config/eye-alt-ft-path";
191 alt_ft = fgGetDouble(fgGetString(nodepath.c_str()));
193 nodepath += "/config/eye-roll-deg-path";
194 roll_deg = fgGetDouble(fgGetString(nodepath.c_str()));
196 nodepath += "/config/eye-pitch-deg-path";
197 pitch_deg = fgGetDouble(fgGetString(nodepath.c_str()));
199 nodepath += "/config/eye-heading-deg-path";
200 heading_deg = fgGetDouble(fgGetString(nodepath.c_str()));
201 loop_view->setPosition(lon_deg, lat_deg, alt_ft);
202 loop_view->setOrientation(roll_deg, pitch_deg, heading_deg);
204 // force recalc in viewer
205 loop_view->set_dirty();
208 // if lookat (type 1) then get target data...
209 if (loop_view->getType() == 1) {
211 nodepath += "/config/from-model";
212 if (!fgGetBool(nodepath.c_str())) {
214 nodepath += "/config/target-lon-deg-path";
215 lon_deg = fgGetDouble(fgGetString(nodepath.c_str()));
217 nodepath += "/config/target-lat-deg-path";
218 lat_deg = fgGetDouble(fgGetString(nodepath.c_str()));
220 nodepath += "/config/target-alt-ft-path";
221 alt_ft = fgGetDouble(fgGetString(nodepath.c_str()));
223 nodepath += "/config/target-roll-deg-path";
224 roll_deg = fgGetDouble(fgGetString(nodepath.c_str()));
226 nodepath += "/config/target-pitch-deg-path";
227 pitch_deg = fgGetDouble(fgGetString(nodepath.c_str()));
229 nodepath += "/config/target-heading-deg-path";
230 heading_deg = fgGetDouble(fgGetString(nodepath.c_str()));
232 loop_view ->setTargetPosition(lon_deg, lat_deg, alt_ft);
233 loop_view->setTargetOrientation(roll_deg, pitch_deg, heading_deg);
235 loop_view->set_dirty();
239 // Set up the chase view
241 // Gotta change sgVec3Slider so that it takes xyz values as inputs
242 // instead of spherical coordinates.
243 FGViewer *chase_view = (FGViewer *)get_view( 1 );
245 // get xyz Position offsets directly from GUI/sgVec3Slider
246 // FIXME: change GUI/sgVec3Slider to store the xyz in properties
247 // it would probably be faster than the way PilotOffsetGet()
248 // triggers a recalc all the time.
249 sgVec3 *pPO = PilotOffsetGet();
251 sgCopyVec3( zPO, *pPO );
252 chase_view->setPositionOffsets(zPO[1], zPO[2], zPO[0] );
254 // Update the current view
260 FGViewMgr::getViewOffset_deg () const
262 const FGViewer * view = get_current_view();
263 return (view == 0 ? 0 : view->getHeadingOffset_deg());
267 FGViewMgr::setViewOffset_deg (double offset)
269 FGViewer * view = get_current_view();
271 view->setGoalHeadingOffset_deg(offset);
272 view->setHeadingOffset_deg(offset);
277 FGViewMgr::getGoalViewOffset_deg () const
279 const FGViewer * view = get_current_view();
280 return (view == 0 ? 0 : view->getGoalHeadingOffset_deg());
284 FGViewMgr::setGoalViewOffset_deg (double offset)
286 FGViewer * view = get_current_view();
288 view->setGoalHeadingOffset_deg(offset);
292 FGViewMgr::getViewTilt_deg () const
294 const FGViewer * view = get_current_view();
295 return (view == 0 ? 0 : view->getPitchOffset_deg());
299 FGViewMgr::setViewTilt_deg (double tilt)
301 FGViewer * view = get_current_view();
303 view->setGoalPitchOffset_deg(tilt);
304 view->setPitchOffset_deg(tilt);
309 FGViewMgr::getGoalViewTilt_deg () const
311 const FGViewer * view = get_current_view();
312 return (view == 0 ? 0 : view->getGoalPitchOffset_deg());
316 FGViewMgr::setGoalViewTilt_deg (double tilt)
318 FGViewer * view = get_current_view();
320 view->setGoalPitchOffset_deg(tilt);
324 FGViewMgr::getPilotXOffset_m () const
326 // FIXME: hard-coded pilot view position
327 const FGViewer * pilot_view = get_view(0);
328 if (pilot_view != 0) {
329 return ((FGViewer *)pilot_view)->getXOffset_m();
336 FGViewMgr::setPilotXOffset_m (double x)
338 // FIXME: hard-coded pilot view position
339 FGViewer * pilot_view = get_view(0);
340 if (pilot_view != 0) {
341 pilot_view->setXOffset_m(x);
346 FGViewMgr::getPilotYOffset_m () const
348 // FIXME: hard-coded pilot view position
349 const FGViewer * pilot_view = get_view(0);
350 if (pilot_view != 0) {
351 return ((FGViewer *)pilot_view)->getYOffset_m();
358 FGViewMgr::setPilotYOffset_m (double y)
360 // FIXME: hard-coded pilot view position
361 FGViewer * pilot_view = get_view(0);
362 if (pilot_view != 0) {
363 pilot_view->setYOffset_m(y);
368 FGViewMgr::getPilotZOffset_m () const
370 // FIXME: hard-coded pilot view position
371 const FGViewer * pilot_view = get_view(0);
372 if (pilot_view != 0) {
373 return ((FGViewer *)pilot_view)->getZOffset_m();
380 FGViewMgr::setPilotZOffset_m (double z)
382 // FIXME: hard-coded pilot view position
383 FGViewer * pilot_view = get_view(0);
384 if (pilot_view != 0) {
385 pilot_view->setZOffset_m(z);
390 FGViewMgr::getFOV_deg () const
392 const FGViewer * view = get_current_view();
393 return (view == 0 ? 0 : view->get_fov());
397 FGViewMgr::setFOV_deg (double fov)
399 FGViewer * view = get_current_view();
405 FGViewMgr::setViewAxisLong (double axis)
411 FGViewMgr::setViewAxisLat (double axis)
417 FGViewMgr::do_axes ()
419 // Take no action when hat is centered
420 if ( ( axis_long < 0.01 ) &&
421 ( axis_long > -0.01 ) &&
422 ( axis_lat < 0.01 ) &&
427 double viewDir = 999;
429 /* Do all the quick and easy cases */
430 if (axis_long < 0) { // Longitudinal axis forward
431 if (axis_lat == axis_long)
433 else if (axis_lat == - axis_long)
435 else if (axis_lat == 0)
437 } else if (axis_long > 0) { // Longitudinal axis backward
438 if (axis_lat == - axis_long)
440 else if (axis_lat == axis_long)
442 else if (axis_lat == 0)
444 } else if (axis_long == 0) { // Longitudinal axis neutral
447 else if (axis_lat > 0)
449 else return; /* And assertion failure maybe? */
452 // Do all the difficult cases
454 viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
455 if ( viewDir < -1 ) viewDir += 360;
457 get_current_view()->setGoalHeadingOffset_deg(viewDir);