]> git.mxchange.org Git - flightgear.git/blob - src/Viewer/viewmgr.cxx
Simplify setting view eye/target offsets
[flightgear.git] / src / Viewer / viewmgr.cxx
1 // viewmgr.cxx -- class for managing all the views in the flightgear world.
2 //
3 // Written by Curtis Olson, started October 2000.
4 //   partially rewritten by Jim Wilson March 2002
5 //
6 // Copyright (C) 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
7 //
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.
12 //
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.
17 //
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.
21 //
22 // $Id$
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "viewmgr.hxx"
29
30 #include <string.h>        // strcmp
31
32 #include <simgear/compiler.h>
33 #include <simgear/scene/util/OsgMath.hxx>
34
35 #include <Main/fg_props.hxx>
36 #include "viewer.hxx"
37
38 #include "CameraGroup.hxx"
39
40 // Constructor
41 FGViewMgr::FGViewMgr( void ) :
42   axis_long(0),
43   axis_lat(0),
44   inited(false),
45   config_list(fgGetNode("/sim", true)->getChildren("view")),
46   current(0)
47 {
48 }
49
50 // Destructor
51 FGViewMgr::~FGViewMgr( void )
52 {
53 }
54
55 void
56 FGViewMgr::init ()
57 {
58   if (inited) {
59     SG_LOG(SG_VIEW, SG_WARN, "duplicate init of view manager");
60     return;
61   }
62   
63   inited = true;
64
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);
68
69       flightgear::View* v = flightgear::View::createFromProperties(config);
70       if (v) {
71           add_view(v);
72       }
73   }
74
75     get_current_view()->bind();
76 }
77
78 void
79 FGViewMgr::postinit()
80 {
81     // force update now so many properties of the current view are valid,
82     // eg view position and orientation (as exposed via globals)
83     update(0.0);
84 }
85
86 void
87 FGViewMgr::shutdown()
88 {
89     if (!inited) {
90         return;
91     }
92     
93     inited = false;
94     views.clear();
95 }
96
97 void
98 FGViewMgr::reinit ()
99 {
100     viewer_list::iterator it;
101     for (it = views.begin(); it != views.end(); ++it) {
102         (*it)->resetOffsetsAndFOV();
103     }
104 }
105
106 typedef double (FGViewMgr::*double_getter)() const;
107
108 void
109 FGViewMgr::bind()
110 {
111     // these are bound to the current view properties
112     _tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
113
114
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);
120
121
122     _tiedProperties.Tie("axes/long", this,
123                         (double_getter)0, &FGViewMgr::setViewAxisLong);
124     fgSetArchivable("/sim/current-view/axes/long");
125
126     _tiedProperties.Tie("axes/lat", this,
127                         (double_getter)0, &FGViewMgr::setViewAxisLat);
128     fgSetArchivable("/sim/current-view/axes/lat");
129
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);
136 }
137
138
139 void
140 FGViewMgr::unbind ()
141 {
142     flightgear::View* v = get_current_view();
143     if (v) {
144         v->unbind();
145     }
146
147   _tiedProperties.Untie();
148     _viewNumberProp.clear();
149     
150     config_list.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();
157 }
158
159 void
160 FGViewMgr::update (double dt)
161 {
162     flightgear::View* currentView = get_current_view();
163   if (!currentView) return;
164
165   // Set up view location and orientation
166
167     currentView->updateData();
168
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());
174
175     currentView->setTargetXOffset_m(target_x_offs->getDoubleValue());
176     currentView->setTargetYOffset_m(target_y_offs->getDoubleValue());
177     currentView->setTargetZOffset_m(target_z_offs->getDoubleValue());
178
179   // Update the current view
180   do_axes();
181   currentView->update(dt);
182
183
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());
190 }
191
192 void FGViewMgr::clear()
193 {
194     views.clear();
195 }
196
197 flightgear::View*
198 FGViewMgr::get_current_view()
199 {
200     if ( current < (int)views.size() ) {
201         return views[current];
202     } else {
203         return NULL;
204     }
205 }
206
207 const flightgear::View*
208 FGViewMgr::get_current_view() const
209 {
210     if ( current < (int)views.size() ) {
211         return views[current];
212     } else {
213         return NULL;
214     }
215 }
216
217
218 flightgear::View*
219 FGViewMgr::get_view( int i )
220 {
221     if ( i < 0 ) { i = 0; }
222     if ( i >= (int)views.size() ) { i = views.size() - 1; }
223     return views[i];
224 }
225
226 const flightgear::View*
227 FGViewMgr::get_view( int i ) const
228 {
229     if ( i < 0 ) { i = 0; }
230     if ( i >= (int)views.size() ) { i = views.size() - 1; }
231     return views[i];
232 }
233
234 flightgear::View*
235 FGViewMgr::next_view()
236 {
237     setView((current+1 < (int)views.size()) ? (current + 1) : 0);
238     _viewNumberProp->fireValueChanged();
239     return views[current];
240 }
241
242 flightgear::View*
243 FGViewMgr::prev_view()
244 {
245     setView((0 < current) ? (current - 1) : (views.size() - 1));
246     _viewNumberProp->fireValueChanged();
247     return views[current];
248 }
249
250 void
251 FGViewMgr::add_view( flightgear::View * v )
252 {
253   views.push_back(v);
254   v->init();
255 }
256
257 int FGViewMgr::getView () const
258 {
259   return current;
260 }
261
262 void
263 FGViewMgr::setView (int newview)
264 {
265     if (newview == current) {
266         return;
267     }
268
269   // negative numbers -> set view with node index -newview
270   if (newview < 0) {
271     for (int i = 0; i < (int)config_list.size(); i++) {
272       int index = -config_list[i]->getIndex();
273       if (index == newview)
274         newview = i;
275     }
276     if (newview < 0)
277       return;
278   }
279
280   // if newview number too low wrap to last view...
281   if (newview < 0)
282     newview = (int)views.size() - 1;
283
284   // if newview number to high wrap to zero...
285   if (newview >= (int)views.size())
286     newview = 0;
287
288     if (get_current_view()) {
289         get_current_view()->unbind();
290     }
291
292   // set new view
293   current = newview;
294
295     if (get_current_view()) {
296         get_current_view()->bind();
297     }
298
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.
302     update(0.0);
303 }
304
305 void
306 FGViewMgr::setViewAxisLong (double axis)
307 {
308   axis_long = axis;
309 }
310
311 void
312 FGViewMgr::setViewAxisLat (double axis)
313 {
314   axis_lat = axis;
315 }
316
317 void
318 FGViewMgr::do_axes ()
319 {
320                 // Take no action when hat is centered
321   if ( ( axis_long <  0.01 ) &&
322        ( axis_long > -0.01 ) &&
323        ( axis_lat  <  0.01 ) &&
324        ( axis_lat  > -0.01 )
325      )
326     return;
327
328   double viewDir = 999;
329
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
346     if (axis_lat < 0)
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? */
351   }
352
353                 // Do all the difficult cases
354   if ( viewDir > 900 )
355     viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
356   if ( viewDir < -1 ) viewDir += 360;
357
358   get_current_view()->setGoalHeadingOffset_deg(viewDir);
359 }