Hi,

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.

Appended are two patches flightgear.diff which need to be applied to 
flightgear's source and SimGear.diff which needs to be applied to SimGear's 
source. The two files placementtrans.[ch]xx need to be put into 
SimGear/simgear/scene/model.

If nobody objects, I would like to have these applied to CVS.

Thanks to Melchior, who helped me testing that stuff.

     Greetings

             Mathias

-- 
Mathias FrÃhlich, email: [EMAIL PROTECTED]
Index: src/AIModel/AIBase.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/AIModel/AIBase.cxx,v
retrieving revision 1.34
diff -u -r1.34 AIBase.cxx
--- src/AIModel/AIBase.cxx	27 Dec 2004 17:35:22 -0000	1.34
+++ src/AIModel/AIBase.cxx	23 Apr 2005 06:58:08 -0000
@@ -69,6 +69,9 @@
 }
 
 FGAIBase::~FGAIBase() {
+    // Unregister that one at the scenery manager
+    globals->get_scenery()->unregister_placement_transform(aip.getTransform());
+  
     globals->get_scenery()->get_scene_graph()->removeKid(aip.getSceneGraph());
     // unbind();
     SGPropertyNode *root = globals->get_props()->getNode("ai/models", true);
@@ -146,6 +149,8 @@
      aip.setVisible(true);
      invisible = false;
      globals->get_scenery()->get_scene_graph()->addKid(aip.getSceneGraph());
+     // Register that one at the scenery manager
+     globals->get_scenery()->register_placement_transform(aip.getTransform());
    } else {
      if (model_path != "") { 
        SG_LOG(SG_INPUT, SG_WARN, "AIBase: Could not load model.");
Index: src/ATC/AIEntity.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/ATC/AIEntity.cxx,v
retrieving revision 1.9
diff -u -r1.9 AIEntity.cxx
--- src/ATC/AIEntity.cxx	19 Nov 2004 22:10:42 -0000	1.9
+++ src/ATC/AIEntity.cxx	23 Apr 2005 06:58:08 -0000
@@ -48,6 +48,9 @@
 	_model->deRef();	// Ought to check valid?
 	//cout << "Removing model from scene graph..." << endl;
 	globals->get_scenery()->get_scene_graph()->removeKid(_aip.getSceneGraph());
+        // Unregister that one at the scenery manager
+        globals->get_scenery()->unregister_placement_transform(_aip.getTransform());
+
 	//cout << "Done!" << endl;
 }
 
@@ -57,6 +60,9 @@
 	_aip.init(_model);
 	_aip.setVisible(false);
 	globals->get_scenery()->get_scene_graph()->addKid(_aip.getSceneGraph());
+        // Register that one at the scenery manager
+        globals->get_scenery()->register_placement_transform(_aip.getTransform());
+
 }
 
 void FGAIEntity::Update(double dt) {
Index: src/FDM/groundcache.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/FDM/groundcache.cxx,v
retrieving revision 1.5
diff -u -r1.5 groundcache.cxx
--- src/FDM/groundcache.cxx	19 Apr 2005 13:21:43 -0000	1.5
+++ src/FDM/groundcache.cxx	23 Apr 2005 06:58:10 -0000
@@ -342,6 +342,10 @@
 FGGroundCache::prepare_ground_cache(double ref_time, const double pt[3],
                                       double rad)
 {
+  Point3D old_cntr = globals->get_scenery()->get_center();
+  Point3D cntr(pt[0], pt[1], pt[2]);
+  globals->get_scenery()->set_center( cntr );
+
   // Empty cache.
   cache_root.removeAllKids();
   ground_radius = 0.0;
@@ -379,7 +383,7 @@
 
   // We need the offset to the scenery scenery center.
   sgdVec3 doffset;
-  Point3D psc = globals->get_tile_mgr()->get_current_center();
+  Point3D psc = globals->get_scenery()->get_center();
   sgdSetVec3(doffset, psc[0], psc[1], psc[2]);
   sgdSubVec3(doffset, doffset, pt);
 
@@ -396,7 +400,7 @@
   sgMakeTransMat4(xform, offset);
 
 
-  // Walk the terrain branch for now.
+  // Walk the scene graph and extract solid ground triangles and carrier data.
   ssgBranch *terrain = globals->get_scenery()->get_scene_graph();
   cache_fill(terrain, xform, &acSphere, down, &wireSphere);
 
@@ -412,6 +416,8 @@
     SG_LOG(SG_FLIGHT, SG_WARN, "prepare_ground_cache(): trying to build cache "
            "without any scenery below the aircraft" );
 
+  globals->get_scenery()->set_center( old_cntr );
+
   return found_ground;
 }
 
Index: src/Main/main.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/main.cxx,v
retrieving revision 1.195
diff -u -r1.195 main.cxx
--- src/Main/main.cxx	9 Mar 2005 21:56:00 -0000	1.195
+++ src/Main/main.cxx	23 Apr 2005 06:58:13 -0000
@@ -500,6 +500,28 @@
     double visibility_meters = fgGetDouble("/environment/visibility-m");
     FGViewer *current_view = globals->get_current_view();
 
+    // Let the scenery center follow the current view position with
+    // 30m increments.
+    //
+    // Having the scenery center near the view position will eliminate
+    // jitter of objects which are placed very near the view position
+    // and haveing it's center near that view position.
+    // So the 3d insruments of the aircraft will not jitter with this.
+    // 
+    // Following the view position exactly would introduce jitter of
+    // the scenery tiles (they would be from their center up to 10000m
+    // to the view and this will introduce roundoff too). By stepping
+    // at 30m incements the roundoff error of the scenery tiles is
+    // still present, but we will make exactly the same roundoff error
+    // at each frame until the center is switched to a new
+    // position. This roundoff is still visible but you will most
+    // propably not notice.
+    double *vp = globals->get_current_view()->get_absolute_view_pos();
+    Point3D cntr(vp[0], vp[1], vp[2]);
+    if (30.0 < cntr.distance3D(globals->get_scenery()->get_center())) {
+      globals->get_scenery()->set_next_center( cntr );
+    }
+
     // get the location data for the primary FDM (now hardcoded to ac model)...
     SGLocation *acmodel_loc = NULL;
     acmodel_loc = (SGLocation *)globals->
@@ -517,6 +539,8 @@
                         acmodel_loc->
                         get_absolute_view_pos(globals->
                                               get_scenery()->get_center()) );
+            globals->get_scenery()->set_center( cntr );
+
             // save results of update in SGLocation for fdm...
             if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
                 acmodel_loc->
@@ -539,6 +563,7 @@
     SGLocation *view_location = globals->get_current_view()->getSGLocation();
     globals->get_tile_mgr()->update( view_location, visibility_meters,
                                      current_view->get_absolute_view_pos() );
+    globals->get_scenery()->set_center( cntr );
     // save results of update in SGLocation for fdm...
     if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
         current_view->getSGLocation()->
Index: src/Main/renderer.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/renderer.cxx,v
retrieving revision 1.15
diff -u -r1.15 renderer.cxx
--- src/Main/renderer.cxx	31 Mar 2005 08:41:41 -0000	1.15
+++ src/Main/renderer.cxx	23 Apr 2005 06:58:14 -0000
@@ -306,7 +306,9 @@
         FGViewer *current__view = globals->get_current_view();
 
         // calculate our current position in cartesian space
-        globals->get_scenery()->set_center( globals->get_scenery()->get_next_center() );
+        Point3D cntr = globals->get_scenery()->get_next_center();
+        globals->get_scenery()->set_center(cntr);
+        current__view->set_scenery_center(cntr);
 
         if ( refresh_camera_settings ) {
             // update view port
Index: src/Main/viewer.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/viewer.cxx,v
retrieving revision 1.17
diff -u -r1.17 viewer.cxx
--- src/Main/viewer.cxx	25 Feb 2005 21:20:17 -0000	1.17
+++ src/Main/viewer.cxx	23 Apr 2005 06:58:14 -0000
@@ -542,14 +542,15 @@
 void
 FGViewer::updateFromModelLocation (SGLocation * location)
 {
-  sgCopyMat4(LOCAL, location->getCachedTransformMatrix());
+  Point3D center = globals->get_scenery()->get_next_center();
+  sgCopyMat4(LOCAL, location->getTransformMatrix(center));
 }
 
 void
 FGViewer::updateAtModelLocation (SGLocation * location)
 {
-  sgCopyMat4(ATLOCAL, 
-             location->getCachedTransformMatrix());
+  Point3D center = globals->get_scenery()->get_next_center();
+  sgCopyMat4(ATLOCAL, location->getTransformMatrix(center));
 }
 
 void
@@ -560,8 +561,20 @@
   dampEyeData(roll_deg, pitch_deg, heading_deg);
   location->setPosition( lon_deg, lat_deg, alt_ft );
   location->setOrientation( roll_deg, pitch_deg, heading_deg );
-  sgCopyMat4(LOCAL,
-             location->getTransformMatrix(globals->get_scenery()->get_center()));
+  Point3D center = globals->get_scenery()->get_next_center();
+  sgCopyMat4(LOCAL, location->getTransformMatrix(center));
+}
+
+void
+FGViewer::set_scenery_center(const Point3D& center)
+{
+  _location->set_tile_center(center);
+  _location->getTransformMatrix(center);
+  if (_type == FG_LOOKAT) {
+    _target_location->set_tile_center(center);
+    _target_location->getTransformMatrix(center);
+  }
+  set_dirty();
 }
 
 // recalc() is done every time one of the setters is called (making the 
@@ -670,10 +683,11 @@
           _target_roll_deg, _target_pitch_deg, _target_heading_deg );
   }
   // calculate the "at" target object positon relative to eye or view's tile center...
+  Point3D center = globals->get_scenery()->get_next_center();
   sgdVec3 dVec3;
-  sgdSetVec3(dVec3,  _location->get_tile_center()[0], _location->get_tile_center()[1], _location->get_tile_center()[2]);
+  sgdSetVec3(dVec3, center[0], center[1], center[2]);
   sgdSubVec3(dVec3,
-             _target_location->get_absolute_view_pos(globals->get_scenery()->get_center()),
+             _target_location->get_absolute_view_pos(center),
              dVec3 );
   sgSetVec3(at_pos, dVec3[0], dVec3[1], dVec3[2]);
 
@@ -739,10 +753,10 @@
 FGViewer::copyLocationData()
 {
   // Get our friendly vectors from the eye location...
+  sgdCopyVec3(_absolute_view_pos,
+              _location->get_absolute_view_pos(globals->get_scenery()->get_next_center()));
   sgCopyVec3(_zero_elev_view_pos,  _location->get_zero_elev());
   sgCopyVec3(_relative_view_pos, _location->get_view_pos());
-  sgdCopyVec3(_absolute_view_pos,
-              _location->get_absolute_view_pos(globals->get_scenery()->get_center()));
   sgCopyMat4(UP, _location->getCachedUpMatrix());
   sgCopyVec3(_world_up, _location->get_world_up());
   // these are the vectors that the sun and moon code like to get...
Index: src/Main/viewer.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/viewer.hxx,v
retrieving revision 1.13
diff -u -r1.13 viewer.hxx
--- src/Main/viewer.hxx	25 Feb 2005 21:20:17 -0000	1.13
+++ src/Main/viewer.hxx	23 Apr 2005 06:58:14 -0000
@@ -258,6 +258,8 @@
         _ground_level_nearplane_m = near_m;
     }
 
+    void set_scenery_center(const Point3D& center);
+
     //////////////////////////////////////////////////////////////////////
     // Part 5: misc setters and getters
     //////////////////////////////////////////////////////////////////////
Index: src/Main/viewmgr.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/viewmgr.cxx,v
retrieving revision 1.14
diff -u -r1.14 viewmgr.cxx
--- src/Main/viewmgr.cxx	25 Feb 2005 22:27:15 -0000	1.14
+++ src/Main/viewmgr.cxx	23 Apr 2005 06:58:14 -0000
@@ -24,6 +24,11 @@
 #include <string.h>		// strcmp
 
 #include <plib/sg.h>
+#include <plib/ssg.h>
+
+#include <simgear/compiler.h>
+
+#include <Model/acmodel.hxx>
 
 #include "viewmgr.hxx"
 #include "fg_props.hxx"
@@ -724,6 +729,12 @@
   set_view( newview );
   // copy in view data
   copyToCurrent ();
+
+  // Copy the fdm's position into the SGLocation which is shared with
+  // some views ...
+  globals->get_aircraft_model()->update(0);
+  // Do the update ...
+  update(0);
 }
 
 
Index: src/Main/viewmgr.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/viewmgr.hxx,v
retrieving revision 1.6
diff -u -r1.6 viewmgr.hxx
--- src/Main/viewmgr.hxx	25 Feb 2005 21:20:17 -0000	1.6
+++ src/Main/viewmgr.hxx	23 Apr 2005 06:58:14 -0000
@@ -90,18 +90,11 @@
 	return views[i];
     }
     inline FGViewer *next_view() {
-	++current;
-	if ( current >= (int)views.size() ) {
-	    current = 0;
-	}
-        copyToCurrent();
+	setView((current+1 < (int)views.size()) ? (current + 1) : 0);
 	return views[current];
     }
     inline FGViewer *prev_view() {
-	--current;
-	if ( current < 0 ) {
-	    current = views.size() - 1;
-	}
+	setView((0 < current) ? (current - 1) : (views.size() - 1));
 	return views[current];
     }
 
Index: src/Model/acmodel.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Model/acmodel.cxx,v
retrieving revision 1.10
diff -u -r1.10 acmodel.cxx
--- src/Model/acmodel.cxx	25 Feb 2005 19:41:54 -0000	1.10
+++ src/Model/acmodel.cxx	23 Apr 2005 06:58:15 -0000
@@ -46,6 +46,10 @@
 
 FGAircraftModel::~FGAircraftModel ()
 {
+  // Unregister that one at the scenery manager
+  if (_aircraft)
+    globals->get_scenery()->unregister_placement_transform(_aircraft->getTransform());
+
   delete _aircraft;
   delete _scene;
 				// SSG will delete it
@@ -75,6 +79,9 @@
   _scene->addKid(_aircraft->getSceneGraph());
   _selector->addKid(_aircraft->getSceneGraph());
   globals->get_scenery()->get_aircraft_branch()->addKid(_selector);
+
+  // Register that one at the scenery manager
+  globals->get_scenery()->register_placement_transform(_aircraft->getTransform());
 }
 
 void 
Index: src/Model/acmodel.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Model/acmodel.hxx,v
retrieving revision 1.6
diff -u -r1.6 acmodel.hxx
--- src/Model/acmodel.hxx	20 Sep 2004 13:21:52 -0000	1.6
+++ src/Model/acmodel.hxx	23 Apr 2005 06:58:15 -0000
@@ -11,6 +11,7 @@
 #endif
 
 #include <vector>
+#include <string>
 
 SG_USING_STD(string);
 SG_USING_STD(vector);
Index: src/Model/modelmgr.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Model/modelmgr.cxx,v
retrieving revision 1.10
diff -u -r1.10 modelmgr.cxx
--- src/Model/modelmgr.cxx	3 Jun 2003 13:51:22 -0000	1.10
+++ src/Model/modelmgr.cxx	23 Apr 2005 06:58:15 -0000
@@ -101,6 +101,10 @@
 				// Add this model to the global scene graph
     globals->get_scenery()->get_scene_graph()->addKid(model->getSceneGraph());
 
+    // Register that one at the scenery manager
+    globals->get_scenery()->register_placement_transform(model->getTransform());
+
+
 				// Save this instance for updating
     add_instance(instance);
   }
@@ -188,6 +192,9 @@
 
 FGModelMgr::Instance::~Instance ()
 {
+  // Unregister that one at the scenery manager
+  globals->get_scenery()->unregister_placement_transform(model->getTransform());
+
   delete model;
 }
 
Index: src/Scenery/scenery.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Scenery/scenery.cxx,v
retrieving revision 1.7
diff -u -r1.7 scenery.cxx
--- src/Scenery/scenery.cxx	19 Nov 2004 22:10:43 -0000	1.7
+++ src/Scenery/scenery.cxx	23 Apr 2005 06:58:15 -0000
@@ -30,6 +30,7 @@
 
 #include <simgear/debug/logstream.hxx>
 #include <simgear/scene/tgdb/userdata.hxx>
+#include <simgear/scene/model/placementtrans.hxx>
 
 #include <Main/fg_props.hxx>
 
@@ -100,3 +101,33 @@
 void FGScenery::unbind() {
     fgUntie("/environment/ground-elevation-m");
 }
+
+void FGScenery::set_center( Point3D p ) {
+    center = p;
+    sgdVec3 c;
+    sgdSetVec3(c, p.x(), p.y(), p.z());
+    placement_list_type::iterator it = _placement_list.begin();
+    while (it != _placement_list.end()) {
+        (*it)->setSceneryCenter(c);
+        ++it;
+    }
+}
+
+void FGScenery::register_placement_transform(ssgPlacementTransform *trans) {
+    trans->ref();
+    _placement_list.push_back(trans);        
+    sgdVec3 c;
+    sgdSetVec3(c, center.x(), center.y(), center.z());
+    trans->setSceneryCenter(c);
+}
+
+void FGScenery::unregister_placement_transform(ssgPlacementTransform *trans) {
+    placement_list_type::iterator it = _placement_list.begin();
+    while (it != _placement_list.end()) {
+        if ((*it) == trans) {
+            (*it)->deRef();
+            it = _placement_list.erase(it);        
+        } else
+            ++it;
+    }
+}
Index: src/Scenery/scenery.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Scenery/scenery.hxx,v
retrieving revision 1.8
diff -u -r1.8 scenery.hxx
--- src/Scenery/scenery.hxx	19 Nov 2004 22:10:43 -0000	1.8
+++ src/Scenery/scenery.hxx	23 Apr 2005 06:58:15 -0000
@@ -29,15 +29,19 @@
 # error This library requires C++
 #endif                                   
 
+#include <list>
 
 #include <plib/sg.h>
 
+#include <simgear/compiler.h>
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/math/point3d.hxx>
 
+SG_USING_STD(list);
 
 class ssgRoot;
 class ssgBranch;
+class ssgPlacementTransform;
 
 
 // Define a structure containing global scenery parameters
@@ -72,6 +76,10 @@
     ssgBranch *models_branch;
     ssgBranch *aircraft_branch;
 
+    // list of all placement transform, used to move the scenery center on the fly.
+    typedef list<ssgPlacementTransform*> placement_list_type;
+    placement_list_type _placement_list;
+
 public:
 
     FGScenery();
@@ -87,7 +95,7 @@
     inline void set_cur_elev( double e ) { cur_elev = e; }
 
     inline Point3D get_center() const { return center; }
-    inline void set_center( Point3D p ) { center = p; }
+    void set_center( Point3D p );
 
     inline Point3D get_next_center() const { return next_center; }
     inline void set_next_center( Point3D p ) { next_center = p; }
@@ -142,6 +150,9 @@
     inline void set_aircraft_branch (ssgBranch *t) {
         aircraft_branch = t;
     }
+
+    void register_placement_transform(ssgPlacementTransform *trans);
+    void unregister_placement_transform(ssgPlacementTransform *trans);
 };
 
 
Index: src/Scenery/tileentry.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Scenery/tileentry.cxx,v
retrieving revision 1.43
diff -u -r1.43 tileentry.cxx
--- src/Scenery/tileentry.cxx	8 Dec 2004 14:45:47 -0000	1.43
+++ src/Scenery/tileentry.cxx	23 Apr 2005 06:58:15 -0000
@@ -43,6 +43,7 @@
 #include <simgear/scene/tgdb/apt_signs.hxx>
 #include <simgear/scene/tgdb/obj.hxx>
 #include <simgear/scene/tgdb/vasi.hxx>
+#include <simgear/scene/model/placementtrans.hxx>
 
 #include <Aircraft/aircraft.hxx>
 #include <Include/general.hxx>
@@ -62,10 +63,10 @@
 FGTileEntry::FGTileEntry ( const SGBucket& b )
     : center( Point3D( 0.0 ) ),
       tile_bucket( b ),
-      terra_transform( new ssgTransform ),
-      vasi_lights_transform( new ssgTransform ),
-      rwy_lights_transform( new ssgTransform ),
-      taxi_lights_transform( new ssgTransform ),
+      terra_transform( new ssgPlacementTransform ),
+      vasi_lights_transform( new ssgPlacementTransform ),
+      rwy_lights_transform( new ssgPlacementTransform ),
+      taxi_lights_transform( new ssgPlacementTransform ),
       terra_range( new ssgRangeSelector ),
       vasi_lights_selector( new ssgSelector ),
       rwy_lights_selector( new ssgSelector ),
@@ -316,8 +317,6 @@
 void FGTileEntry::prep_ssg_node( const Point3D& p, sgVec3 up, float vis) {
     if ( !loaded ) return;
 
-    SetOffset( p );
-
     // visibility can change from frame to frame so we update the
     // range selector cutoff's each time.
     terra_range->setRange( 0, SG_ZERO );
@@ -328,9 +327,8 @@
         gnd_lights_range->setRange( 1, vis * 1.5 + bounding_radius );
     }
 
-    sgVec3 sgTrans;
-    sgSetVec3( sgTrans, offset.x(), offset.y(), offset.z() );
-    terra_transform->setTransform( sgTrans );
+    sgdVec3 sgdTrans;
+    sgdSetVec3( sgdTrans, center.x(), center.y(), center.z() );
 
     FGLight *l = (FGLight *)(globals->get_subsystem("lighting"));
     if ( gnd_lights_transform ) {
@@ -348,12 +346,8 @@
         agl = globals->get_current_view()->getAltitudeASL_ft()
             * SG_FEET_TO_METER - globals->get_scenery()->get_cur_elev();
 
-        // sgTrans just happens to be the
-        // vector from scenery center to the center of this tile which
-        // is what we want to calculate the distance of
-        sgVec3 to;
-        sgCopyVec3( to, sgTrans );
-        double dist = sgLengthVec3( to );
+        // Compute the distance of the scenery center from the view position.
+        double dist = center.distance3D(p);
 
         if ( general.get_glDepthBits() > 16 ) {
             sgScaleVec3( lift_vec, 10.0 + agl / 100.0 + dist / 10000 );
@@ -361,11 +355,12 @@
             sgScaleVec3( lift_vec, 10.0 + agl / 20.0 + dist / 5000 );
         }
 
-        sgVec3 lt_trans;
-        sgCopyVec3( lt_trans, sgTrans );
-
-        sgAddVec3( lt_trans, lift_vec );
-        gnd_lights_transform->setTransform( lt_trans );
+        sgdVec3 dlt_trans;
+        sgdCopyVec3( dlt_trans, sgdTrans );
+        sgdVec3 dlift_vec;
+        sgdSetVec3( dlift_vec, lift_vec );
+        sgdAddVec3( dlt_trans, dlift_vec );
+        gnd_lights_transform->setTransform( dlt_trans );
 
         // select which set of lights based on sun angle
         float sun_angle = l->get_sun_angle() * SGD_RADIANS_TO_DEGREES;
@@ -404,11 +399,12 @@
             sgScaleVec3( lift_vec, 0.25 + agl / 150.0 );
         }
 
-        sgVec3 lt_trans;
-        sgCopyVec3( lt_trans, sgTrans );
-
-        sgAddVec3( lt_trans, lift_vec );
-        vasi_lights_transform->setTransform( lt_trans );
+        sgdVec3 dlt_trans;
+        sgdCopyVec3( dlt_trans, sgdTrans );
+        sgdVec3 dlift_vec;
+        sgdSetVec3( dlift_vec, lift_vec );
+        sgdAddVec3( dlt_trans, dlift_vec );
+        vasi_lights_transform->setTransform( dlt_trans );
 
         // generally, vasi lights are always on
         vasi_lights_selector->select(0x01);
@@ -438,11 +434,12 @@
             sgScaleVec3( lift_vec, 0.25 + agl / 150.0 );
         }
 
-        sgVec3 lt_trans;
-        sgCopyVec3( lt_trans, sgTrans );
-
-        sgAddVec3( lt_trans, lift_vec );
-        rwy_lights_transform->setTransform( lt_trans );
+        sgdVec3 dlt_trans;
+        sgdCopyVec3( dlt_trans, sgdTrans );
+        sgdVec3 dlift_vec;
+        sgdSetVec3( dlift_vec, lift_vec );
+        sgdAddVec3( dlt_trans, dlift_vec );
+        rwy_lights_transform->setTransform( dlt_trans );
 
         // turn runway lights on/off based on sun angle and visibility
         float sun_angle = l->get_sun_angle() * SGD_RADIANS_TO_DEGREES;
@@ -478,11 +475,12 @@
             sgScaleVec3( lift_vec, 0.25 + agl / 150.0 );
         }
 
-        sgVec3 lt_trans;
-        sgCopyVec3( lt_trans, sgTrans );
-
-        sgAddVec3( lt_trans, lift_vec );
-        taxi_lights_transform->setTransform( lt_trans );
+        sgdVec3 dlt_trans;
+        sgdCopyVec3( dlt_trans, sgdTrans );
+        sgdVec3 dlift_vec;
+        sgdSetVec3( dlift_vec, lift_vec );
+        sgdAddVec3( dlt_trans, dlift_vec );
+        taxi_lights_transform->setTransform( dlt_trans );
 
         // turn taxi lights on/off based on sun angle and visibility
         float sun_angle = l->get_sun_angle() * SGD_RADIANS_TO_DEGREES;
@@ -938,12 +936,16 @@
     terra_transform->addKid( terra_range );
 
     // calculate initial tile offset
-    SetOffset( globals->get_scenery()->get_center() );
-    sgCoord sgcoord;
-    sgSetCoord( &sgcoord,
-                offset.x(), offset.y(), offset.z(),
-                0.0, 0.0, 0.0 );
-    terra_transform->setTransform( &sgcoord );
+    sgdVec3 sgdTrans;
+    sgdSetVec3( sgdTrans, center.x(), center.y(), center.z() );
+    terra_transform->setTransform( sgdTrans );
+
+    sgdVec3 sgdCenter;
+    Point3D p = globals->get_scenery()->get_center();
+    sgdSetVec3( sgdCenter, p.x(), p.y(), p.z() );
+    terra_transform->setSceneryCenter( sgdCenter );
+    globals->get_scenery()->register_placement_transform(terra_transform);
+
     // terrain->addKid( terra_transform );
 
     // Add ground lights to scene graph if any exist
@@ -951,7 +953,7 @@
     gnd_lights_range = NULL;
     if ( light_pts->getNum() ) {
         SG_LOG( SG_TERRAIN, SG_DEBUG, "generating lights" );
-        gnd_lights_transform = new ssgTransform;
+        gnd_lights_transform = new ssgPlacementTransform;
         gnd_lights_range = new ssgRangeSelector;
         gnd_lights_brightness = new ssgSelector;
         ssgLeaf *lights;
@@ -967,22 +969,30 @@
 
         gnd_lights_range->addKid( gnd_lights_brightness );
         gnd_lights_transform->addKid( gnd_lights_range );
-        gnd_lights_transform->setTransform( &sgcoord );
+        gnd_lights_transform->setTransform( sgdTrans );
+        gnd_lights_transform->setSceneryCenter( sgdCenter );
+        globals->get_scenery()->register_placement_transform(gnd_lights_transform);
     }
 
     // Update vasi lights transform
     if ( vasi_lights_transform->getNumKids() > 0 ) {
-        vasi_lights_transform->setTransform( &sgcoord );
+        vasi_lights_transform->setTransform( sgdTrans );
+        vasi_lights_transform->setSceneryCenter( sgdCenter );
+        globals->get_scenery()->register_placement_transform(vasi_lights_transform);
     }
 
     // Update runway lights transform
     if ( rwy_lights_transform->getNumKids() > 0 ) {
-        rwy_lights_transform->setTransform( &sgcoord );
+        rwy_lights_transform->setTransform( sgdTrans );
+        rwy_lights_transform->setSceneryCenter( sgdCenter );
+        globals->get_scenery()->register_placement_transform(rwy_lights_transform);
     }
 
      // Update taxi lights transform
     if ( taxi_lights_transform->getNumKids() > 0 ) {
-        taxi_lights_transform->setTransform( &sgcoord );
+        taxi_lights_transform->setTransform( sgdTrans );
+        taxi_lights_transform->setSceneryCenter( sgdCenter );
+        globals->get_scenery()->register_placement_transform(taxi_lights_transform);
     }
 }
 
@@ -1070,6 +1080,9 @@
         SG_LOG( SG_TERRAIN, SG_DEBUG, "removing a fully loaded tile!  terra_transform = " << terra_transform );
     }
         
+    // Unregister that one at the scenery manager
+    globals->get_scenery()->unregister_placement_transform(terra_transform);
+
     // find the terrain branch parent
     int pcount = terra_transform->getNumParents();
     if ( pcount > 0 ) {
@@ -1092,6 +1105,8 @@
 
     // find the ground lighting branch
     if ( gnd_lights_transform ) {
+        // Unregister that one at the scenery manager
+        globals->get_scenery()->unregister_placement_transform(gnd_lights_transform);
         pcount = gnd_lights_transform->getNumParents();
         if ( pcount > 0 ) {
             // find the first parent (should only be one)
@@ -1114,6 +1129,8 @@
 
     // find the vasi lighting branch
     if ( vasi_lights_transform ) {
+        // Unregister that one at the scenery manager
+        globals->get_scenery()->unregister_placement_transform(vasi_lights_transform);
         pcount = vasi_lights_transform->getNumParents();
         if ( pcount > 0 ) {
             // find the first parent (should only be one)
@@ -1136,6 +1153,8 @@
 
     // find the runway lighting branch
     if ( rwy_lights_transform ) {
+        // Unregister that one at the scenery manager
+        globals->get_scenery()->unregister_placement_transform(rwy_lights_transform);
         pcount = rwy_lights_transform->getNumParents();
         if ( pcount > 0 ) {
             // find the first parent (should only be one)
@@ -1158,6 +1177,8 @@
 
     // find the taxi lighting branch
     if ( taxi_lights_transform ) {
+        // Unregister that one at the scenery manager
+        globals->get_scenery()->unregister_placement_transform(taxi_lights_transform);
         pcount = taxi_lights_transform->getNumParents();
         if ( pcount > 0 ) {
             // find the first parent (should only be one)
Index: src/Scenery/tileentry.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Scenery/tileentry.hxx,v
retrieving revision 1.18
diff -u -r1.18 tileentry.hxx
--- src/Scenery/tileentry.hxx	19 Nov 2004 22:10:43 -0000	1.18
+++ src/Scenery/tileentry.hxx	23 Apr 2005 06:58:15 -0000
@@ -58,6 +58,7 @@
 class ssgLeaf;
 class ssgBranch;
 class ssgTransform;
+class ssgPlacementTransform;
 class ssgSelector;
 class ssgRangeSelector;
 class ssgVertexArray;
@@ -109,7 +110,6 @@
     // global tile culling data
     Point3D center;
     double bounding_radius;
-    Point3D offset;
 
     // this tile's official location in the world
     SGBucket tile_bucket;
@@ -128,11 +128,11 @@
     //                 - kidn(fan)
 
     // pointer to ssg transform for this tile
-    ssgTransform *terra_transform;
-    ssgTransform *vasi_lights_transform;
-    ssgTransform *rwy_lights_transform;
-    ssgTransform *taxi_lights_transform;
-    ssgTransform *gnd_lights_transform;
+    ssgPlacementTransform *terra_transform;
+    ssgPlacementTransform *vasi_lights_transform;
+    ssgPlacementTransform *rwy_lights_transform;
+    ssgPlacementTransform *taxi_lights_transform;
+    ssgPlacementTransform *gnd_lights_transform;
 
     // pointer to ssg range selector for this tile
     ssgRangeSelector *terra_range;
@@ -218,15 +218,6 @@
     // completely freed.
     bool free_tile();
 
-    // Calculate this tile's offset
-    void SetOffset( const Point3D& p)
-    {
-	offset = center - p;
-    }
-
-    // Return this tile's offset
-    inline Point3D get_offset() const { return offset; }
-
     // Update the ssg transform node for this tile so it can be
     // properly drawn relative to our (0,0,0) point
     void prep_ssg_node( const Point3D& p, sgVec3 up, float vis);
@@ -283,7 +274,7 @@
     /**
      * return the SSG Transform node for the terrain
      */
-    inline ssgTransform *get_terra_transform() { return terra_transform; }
+    inline ssgPlacementTransform *get_terra_transform() { return terra_transform; }
 
     inline double get_timestamp() const { return timestamp; }
     inline void set_timestamp( double time_ms ) { timestamp = time_ms; }
Index: src/Scenery/tilemgr.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Scenery/tilemgr.cxx,v
retrieving revision 1.43
diff -u -r1.43 tilemgr.cxx
--- src/Scenery/tilemgr.cxx	22 Nov 2004 10:10:33 -0000	1.43
+++ src/Scenery/tilemgr.cxx	23 Apr 2005 06:58:16 -0000
@@ -410,15 +410,6 @@
     //         << current_bucket );
     fgSetInt( "/environment/current-tile-id", current_bucket.gen_index() );
 
-    // set global scenery center from current tile center
-    current_tile = tile_cache.get_tile( current_bucket );
-    if ( current_tile != NULL ) {
-        globals->get_scenery()->set_next_center( current_tile->center );
-    } else {
-        SG_LOG( SG_TERRAIN, SG_WARN, "Tile not found (Ok if initializing)" );
-        globals->get_scenery()->set_next_center( Point3D(0.0) );
-    }
-
     // do tile load scheduling. 
     // Note that we need keep track of both viewer buckets and fdm buckets.
     if ( state == Running ) {
@@ -517,7 +508,6 @@
     Point3D center = location->get_tile_center();
     if (center == Point3D(0.0))
       return;
-    current_center = center;
     float *up = location->get_world_up();
 
     FGTileEntry *e;
Index: src/Scenery/tilemgr.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Scenery/tilemgr.hxx,v
retrieving revision 1.20
diff -u -r1.20 tilemgr.hxx
--- src/Scenery/tilemgr.hxx	22 Nov 2004 10:10:33 -0000	1.20
+++ src/Scenery/tilemgr.hxx	23 Apr 2005 06:58:16 -0000
@@ -103,10 +103,6 @@
      * tile cache
      */
     FGNewCache tile_cache;
-    /**
-     * and its center
-     */
-    Point3D current_center;
 
     /**
      * Queue tiles for loading.
@@ -192,7 +188,6 @@
     // based on current visibilty void prep_ssg_nodes( float
     // visibility_meters );
     void prep_ssg_nodes( SGLocation *location, float visibility_meters );
-    const Point3D get_current_center(void) const { return current_center; }
 
     // Set flag with event manager so that non-moving view refreshes
     // tiles...
Index: simgear/scene/model/Makefile.am
===================================================================
RCS file: /var/cvs/SimGear-0.3/SimGear/simgear/scene/model/Makefile.am,v
retrieving revision 1.8
diff -u -r1.8 Makefile.am
--- simgear/scene/model/Makefile.am	11 May 2004 22:21:24 -0000	1.8
+++ simgear/scene/model/Makefile.am	23 Apr 2005 06:56:15 -0000
@@ -11,7 +11,8 @@
 	model.hxx \
 	modellib.hxx \
 	personality.hxx \
-	placement.hxx
+	placement.hxx \
+	placementtrans.hxx
 
 libsgmodel_a_SOURCES = \
 	animation.cxx \
@@ -20,6 +21,7 @@
 	model.cxx \
 	modellib.cxx \
 	personality.cxx \
-	placement.cxx
+	placement.cxx \
+	placementtrans.cxx
 
 INCLUDES = -I$(top_srcdir)
Index: simgear/scene/model/location.hxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/SimGear/simgear/scene/model/location.hxx,v
retrieving revision 1.3
diff -u -r1.3 location.hxx
--- simgear/scene/model/location.hxx	13 May 2003 03:18:36 -0000	1.3
+++ simgear/scene/model/location.hxx	23 Apr 2005 06:56:15 -0000
@@ -109,19 +109,21 @@
     void set_cur_elev_m ( double elev ) { _cur_elev_m = elev; }
     inline double get_cur_elev_m () { return _cur_elev_m; }
     // Interface to current buckets for use with tilemgr...
-    void set_tile_center ( Point3D tile_center ) { _tile_center = tile_center; }
+    void set_tile_center ( Point3D tile_center ) { set_dirty(); _tile_center = tile_center; }
     inline Point3D get_tile_center () { return _tile_center; }
 
     // Matrices...
     virtual const sgVec4 *getTransformMatrix( const Point3D scenery_center ) {
-        if ( _dirty ) {
+        if ( _dirty || scenery_center != _scenery_center ) {
+            _scenery_center = scenery_center;
             recalc( scenery_center );
         }
 	return TRANS;
     }
     virtual const sgVec4 *getCachedTransformMatrix() { return TRANS; }
     virtual const sgVec4 *getUpMatrix( const Point3D scenery_center )  {
-        if ( _dirty ) {
+        if ( _dirty || scenery_center != _scenery_center ) {
+            _scenery_center = scenery_center;
             recalc( scenery_center );
         }
 	return UP;
@@ -153,6 +155,7 @@
     // elevation of ground under this location...
     double _cur_elev_m;
     Point3D _tile_center;
+    Point3D _scenery_center;
 
     // surface vector heading south
     sgVec3 _surface_south;
Index: simgear/scene/model/placement.cxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/SimGear/simgear/scene/model/placement.cxx,v
retrieving revision 1.4
diff -u -r1.4 placement.cxx
--- simgear/scene/model/placement.cxx	15 May 2003 21:35:31 -0000	1.4
+++ simgear/scene/model/placement.cxx	23 Apr 2005 06:56:15 -0000
@@ -11,18 +11,15 @@
 
 #include <string.h>             // for strcmp()
 
-#include <vector>
-
 #include <plib/sg.h>
 #include <plib/ssg.h>
 #include <plib/ul.h>
 
 #include "location.hxx"
+#include "placementtrans.hxx"
 
 #include "placement.hxx"
 
-SG_USING_STD(vector);
-
 
 
 ////////////////////////////////////////////////////////////////////////
@@ -37,7 +34,7 @@
     _pitch_deg(0),
     _heading_deg(0),
     _selector(new ssgSelector),
-    _position(new ssgTransform),
+    _position(new ssgPlacementTransform),
     _location(new SGLocation)
 {
 }
@@ -73,7 +70,12 @@
       POS[i][j] += (tmp * trans[j]);
     }
   }
-  _position->setTransform(POS);
+//   _position->setTransform(POS);
+  _position->setTransform(_location->get_absolute_view_pos(scenery_center), POS);
+  sgdVec3 center;
+  sgdSetVec3(center,
+             scenery_center.x(), scenery_center.y(), scenery_center.z());
+  _position->setSceneryCenter(center);
 }
 
 bool
Index: simgear/scene/model/placement.hxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/SimGear/simgear/scene/model/placement.hxx,v
retrieving revision 1.2
diff -u -r1.2 placement.hxx
--- simgear/scene/model/placement.hxx	13 May 2003 03:18:36 -0000	1.2
+++ simgear/scene/model/placement.hxx	23 Apr 2005 06:56:15 -0000
@@ -11,10 +11,6 @@
 # error This library requires C++
 #endif
 
-#include <vector>
-
-SG_USING_STD(vector);
-
 #include <plib/sg.h>
 #include <plib/ssg.h>
 
@@ -24,6 +20,7 @@
 
 // Don't pull in the headers, since we don't need them here.
 class SGLocation;
+class ssgPlacementTransform;
 
 
 // Has anyone done anything *really* stupid, like making min and max macros?
@@ -86,6 +83,9 @@
   // Allows multiplayer to get players position transform
   virtual const sgVec4 *get_POS() { return POS; }
 
+  ssgPlacementTransform * getTransform(void)
+  { return _position; }
+
 private:
 
                                 // Geodetic position
@@ -99,7 +99,8 @@
   double _heading_deg;
 
   ssgSelector * _selector;
-  ssgTransform * _position;
+//   ssgTransform * _position;
+  ssgPlacementTransform * _position;
 
                                 // Location
   SGLocation * _location;
// placementtrans.hxx -- class for carrying transforms for placing models in the world
//
// Written by Mathias Froehlich, started April 2005.
//
// Copyright (C) 2005 Mathias Froehlich
//
// 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
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//


#ifndef __cplusplus                                                          
# error This library requires C++
#endif                                   

#include <simgear/compiler.h>
#include <simgear/constants.h>

#include <plib/sg.h>
#include <plib/ssg.h>

#include "placementtrans.hxx"

ssgPlacementTransform::ssgPlacementTransform(void)
{
}

ssgPlacementTransform::~ssgPlacementTransform(void)
{
}

ssgBase *ssgPlacementTransform::clone(int clone_flags)
{
  ssgPlacementTransform *b = new ssgPlacementTransform;
  b->copy_from(this, clone_flags);
  return b;
}

void
ssgPlacementTransform::copy_from(ssgPlacementTransform *src, int clone_flags)
{
  ssgBaseTransform::copy_from(src, clone_flags);
  sgdCopyVec3(_placement_offset, src->_placement_offset);
  sgdCopyVec3(_scenery_center,  src->_scenery_center);
}

void ssgPlacementTransform::setTransform(sgdVec3 off)
{
  sgdCopyVec3(_placement_offset, off);
  sgdVec3 tmp;
  sgdSubVec3(tmp, _placement_offset, _scenery_center);
  sgMat4 tmat;
  sgZeroVec4(tmat[0]);
  tmat[0][0] = 1;
  sgZeroVec4(tmat[1]);
  tmat[1][1] = 1;
  sgZeroVec4(tmat[2]);
  tmat[2][2] = 1;
  sgSetVec3(tmat[3], tmp);
  tmat[3][3] = 1;
  ssgTransform::setTransform(tmat);
}

void ssgPlacementTransform::setTransform(sgdVec3 off, sgMat4 rot)
{
  sgdCopyVec3(_placement_offset, off);
  sgdVec3 tmp;
  sgdSubVec3(tmp, _placement_offset, _scenery_center);
  sgMat4 tmat;
  sgCopyVec4(tmat[0], rot[0]);
  sgCopyVec4(tmat[1], rot[1]);
  sgCopyVec4(tmat[2], rot[2]);
  sgSetVec3(tmat[3], tmp);
  tmat[3][3] = 1;
  ssgTransform::setTransform(tmat);
}

void ssgPlacementTransform::setSceneryCenter(sgdVec3 xyz)
{
  sgdCopyVec3(_scenery_center, xyz);
  sgdVec3 tmp;
  sgdSubVec3(tmp, _placement_offset, _scenery_center);
  sgMat4 tmat;
  getTransform(tmat);
  sgSetVec3(tmat[3], tmp);
  ssgTransform::setTransform(tmat);
}
// placementtrans.hxx -- class for carrying transforms for placing models in the world
//
// Written by Mathias Froehlich, started April 2005.
//
// Copyright (C) 2005 Mathias Froehlich
//
// 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
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//


#ifndef _SG_PLACEMENTTRANS_HXX
#define _SG_PLACEMENTTRANS_HXX

#ifndef __cplusplus                                                          
# error This library requires C++
#endif                                   

#include <simgear/compiler.h>
#include <simgear/constants.h>

#include <plib/sg.h>
#include <plib/ssg.h>

class ssgPlacementTransform : public ssgTransform
{
public:
  
  ssgPlacementTransform(void);
  virtual ~ssgPlacementTransform(void);

//   using ssgTransform::addKid(ssgEntity*);

  virtual ssgBase *clone(int clone_flags);
protected:
  void copy_from(ssgPlacementTransform *src, int clone_flags);

private:
//   virtual void setTransform(sgVec3 xyz);
//   virtual void setTransform(sgCoord *xform);
//   virtual void setTransform(sgCoord *xform, float sx, float sy, float sz);
//   virtual void setTransform(sgMat4 xform);
public:

  void setTransform(sgdVec3 off);
  void setTransform(sgdVec3 off, sgMat4 rot);
  void setSceneryCenter(sgdVec3 xyz);

private:

  //////////////////////////////////////////////////////////////////
  // private data                                                 //
  //////////////////////////////////////////////////////////////////
  
  sgdVec3 _placement_offset;
  sgdVec3 _scenery_center;
    
};

#endif // _SG_LOCATION_HXX
_______________________________________________
Flightgear-devel mailing list
Flightgear-devel@flightgear.org
http://mail.flightgear.org/mailman/listinfo/flightgear-devel
2f585eeea02e2c79d7b1d8c4963bae2d

Reply via email to