1
0
Fork 0
flightgear/src/Scenery/scenery.cxx
timoore 616b2bf4f6 Use the OSG DatabasePager instead of FGTileLoader
Make an OSG file reader for .stg files.

New class flightgear::SceneryPager, which is a subclass
osg::DatabasePager to handle explicit delete requests.

Modify FGNewCache, FGTileEntry, and FGTileManager to use
SceneryPager. Mostly this involved removing the queues that talked to
FGTileLoader.

Calculate accurate tile timestamps from the time they are traversed in
the cull stage (which means that they are visible) instead of updating
them periodically.

Replace tile entry transform and range node with one LOD node
2007-12-14 22:51:56 +00:00

218 lines
6.5 KiB
C++

// scenery.cxx -- data structures and routines for managing scenery.
//
// Written by Curtis Olson, started May 1997.
//
// Copyright (C) 1997 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
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <osgUtil/IntersectVisitor>
#include <simgear/debug/logstream.hxx>
#include <simgear/scene/tgdb/userdata.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/scene/model/placementtrans.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/util/SGSceneUserData.hxx>
#include <Main/fg_props.hxx>
#include "scenery.hxx"
using namespace flightgear;
class FGGroundPickCallback : public SGPickCallback {
public:
virtual bool buttonPressed(int button, const Info& info)
{
// only on left mouse button
if (button != 0)
return false;
SGGeod geod = SGGeod::fromCart(info.wgs84);
SG_LOG( SG_TERRAIN, SG_INFO, "Got ground pick at " << geod );
SGPropertyNode *c = fgGetNode("/sim/input/click", true);
c->setDoubleValue("longitude-deg", geod.getLongitudeDeg());
c->setDoubleValue("latitude-deg", geod.getLatitudeDeg());
c->setDoubleValue("elevation-m", geod.getElevationM());
c->setDoubleValue("elevation-ft", geod.getElevationFt());
fgSetBool("/sim/signals/click", 1);
return true;
}
};
// Scenery Management system
FGScenery::FGScenery()
{
SG_LOG( SG_TERRAIN, SG_INFO, "Initializing scenery subsystem" );
}
// Initialize the Scenery Management system
FGScenery::~FGScenery() {
}
void FGScenery::init() {
// Scene graph root
scene_graph = new osg::Group;
scene_graph->setName( "Scene" );
// Terrain branch
terrain_branch = new osg::Group;
terrain_branch->setName( "Terrain" );
scene_graph->addChild( terrain_branch.get() );
SGSceneUserData* userData;
userData = SGSceneUserData::getOrCreateSceneUserData(terrain_branch.get());
userData->setPickCallback(new FGGroundPickCallback);
models_branch = new osg::Group;
models_branch->setName( "Models" );
scene_graph->addChild( models_branch.get() );
aircraft_branch = new osg::Group;
aircraft_branch->setName( "Aircraft" );
scene_graph->addChild( aircraft_branch.get() );
// Initials values needed by the draw-time object loader
sgUserDataInit( globals->get_model_lib(), globals->get_fg_root(),
globals->get_props(), globals->get_sim_time_sec() );
}
void FGScenery::update(double dt) {
}
void FGScenery::bind() {
}
void FGScenery::unbind() {
}
bool
FGScenery::get_elevation_m(double lat, double lon, double max_alt,
double& alt, const SGMaterial** material)
{
return get_elevation_m(SGGeod::fromDegM(lon, lat, max_alt), alt, material);
}
bool
FGScenery::get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
double& alt, const SGMaterial** material)
{
SGGeod geod = SGGeod::fromCart(pos);
geod.setElevationM(geod.getElevationM() + max_altoff);
return get_elevation_m(geod, alt, material);
}
bool
FGScenery::get_elevation_m(const SGGeod& geod, double& alt,
const SGMaterial** material)
{
SGVec3d start = SGVec3d::fromGeod(geod);
SGGeod geodEnd = geod;
geodEnd.setElevationM(SGMiscd::min(geod.getElevationM() - 10, -10000));
SGVec3d end = SGVec3d::fromGeod(geodEnd);
osgUtil::IntersectVisitor intersectVisitor;
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
osg::ref_ptr<osg::LineSegment> lineSegment;
lineSegment = new osg::LineSegment(start.osg(), end.osg());
intersectVisitor.addLineSegment(lineSegment.get());
get_scene_graph()->accept(intersectVisitor);
bool hits = intersectVisitor.hits();
if (hits) {
int nHits = intersectVisitor.getNumHits(lineSegment.get());
alt = -SGLimitsd::max();
for (int i = 0; i < nHits; ++i) {
const osgUtil::Hit& hit
= intersectVisitor.getHitList(lineSegment.get())[i];
SGVec3d point;
point.osg() = hit.getWorldIntersectPoint();
SGGeod geod = SGGeod::fromCart(point);
double elevation = geod.getElevationM();
if (alt < elevation) {
alt = elevation;
if (material) {
const osg::StateSet* stateSet = hit.getDrawable()->getStateSet();
*material = globals->get_matlib()->findMaterial(stateSet);
}
}
}
}
return hits;
}
bool
FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
SGVec3d& nearestHit)
{
// We assume that starting positions in the center of the earth are invalid
if ( norm1(pos) < 1 )
return false;
// Make really sure the direction is normalized, is really cheap compared to
// computation of ground intersection.
SGVec3d start = pos;
SGVec3d end = start + 1e5*normalize(dir); // FIXME visibility ???
osgUtil::IntersectVisitor intersectVisitor;
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
osg::ref_ptr<osg::LineSegment> lineSegment;
lineSegment = new osg::LineSegment(start.osg(), end.osg());
intersectVisitor.addLineSegment(lineSegment.get());
get_scene_graph()->accept(intersectVisitor);
bool hits = intersectVisitor.hits();
if (hits) {
int nHits = intersectVisitor.getNumHits(lineSegment.get());
double dist = SGLimitsd::max();
for (int i = 0; i < nHits; ++i) {
const osgUtil::Hit& hit
= intersectVisitor.getHitList(lineSegment.get())[i];
SGVec3d point;
point.osg() = hit.getWorldIntersectPoint();
double newdist = length(start - point);
if (newdist < dist) {
dist = newdist;
nearestHit = point;
}
}
}
return hits;
}
SceneryPager* FGScenery::getPagerSingleton()
{
static osg::ref_ptr<SceneryPager> pager = new SceneryPager;
return pager.get();
}