1
0
Fork 0

Alternative terrain engine based on pagedLOD

- remove TileMgr from sub systems - add to btg terrain engine
This commit is contained in:
Peter Sadrozinski 2016-07-30 08:26:45 -04:00
parent 6e9d4e8ae4
commit ec4b9f8542
26 changed files with 1432 additions and 163 deletions

View file

@ -167,6 +167,8 @@ option(ENABLE_YASIM "Set to ON to build FlightGear with YASIM FDM (default)
option(ENABLE_JSBSIM "Set to ON to build FlightGear with JSBSim FDM (default)" ON)
option(EVENT_INPUT "Set to ON to build FlightGear with event-based Input support" ${EVENT_INPUT_DEFAULT})
option(ENABLE_RTI "Set to ON to build FlightGear with RTI support" OFF)
option(ENABLE_GDAL "Set to ON to build FlightGear with GDAL support" OFF)
option(ENABLE_OPENMP "Set to ON to build FlightGear with OpenMP compiler support" OFF)
option(ENABLE_PROFILE "Set to ON to build FlightGear with gperftools profiling support" OFF)
option(SYSTEM_SQLITE "Set to ON to build FlightGear with the system's SQLite3 library" OFF)
option(ENABLE_IAX "Set to ON to build FlightGear with IAXClient/fgcom built-in (default)" ON)
@ -194,6 +196,7 @@ option(ENABLE_FLITE "Set to ON to build the Flite text-to-speech module" ON
option(ENABLE_QT "Set to ON to build the internal Qt launcher" ON)
option(ENABLE_TRAFFIC "Set to ON to build the external traffic generator modules" ON)
option(ENABLE_FGQCANVAS "Set to ON to build the Qt-based remote canvas application" OFF)
option(ENABLE_DEMCONVERT "Set to ON to build the dem conversion tool (default)" ON)
include (DetectArch)
@ -357,6 +360,24 @@ else()
message(STATUS "RTI: DISABLED")
endif(ENABLE_RTI)
if(ENABLE_GDAL)
find_package(GDAL 2.0.0 REQUIRED)
endif(ENABLE_GDAL)
include_directories(${GDAL_INCLUDE_DIR})
if (ENABLE_OPENMP)
find_package(OpenMP)
if(OPENMP_FOUND)
message(STATUS "OpenMP: ENABLED")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
else()
message(STATUS "OpenMP: NOT FOUND")
endif()
else()
message(STATUS "OpenMP: DISABLED")
endif()
if (ENABLE_SIMD)
message(STATUS "SSE/SSE2 support: ENABLED")
else()

View file

@ -25,7 +25,6 @@
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Airports/dynamics.hxx>
#include <Airports/airport.hxx>
#include <Main/util.hxx>
@ -551,7 +550,7 @@ void FGAIAircraft::getGroundElev(double dt) {
}
double range = 500.0;
if (globals->get_tile_mgr()->schedule_scenery(pos, range, 5.0))
if (globals->get_scenery()->schedule_scenery(pos, range, 5.0))
{
double alt;
if (getGroundElevationM(SGGeod::fromGeodM(pos, 20000), alt, 0))

View file

@ -67,7 +67,6 @@
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include "flight.hxx"
@ -330,7 +329,7 @@ FGGroundCache::prepare_ground_cache(double startSimTime, double endSimTime,
SGGeod geodPt = SGGeod::fromCart(pt);
// Don't blow away the cache ground_radius and stuff if there's no
// scenery
if (!globals->get_tile_mgr()->schedule_scenery(geodPt, rad, 1.0)) {
if (!globals->get_scenery()->schedule_scenery(geodPt, rad, 1.0)) {
SG_LOG(SG_FLIGHT, SG_BULK, "prepare_ground_cache(): scenery_available "
"returns false at " << geodPt << " " << pt << " " << rad);
return false;

View file

@ -110,6 +110,12 @@ else()
set(HLA_LIBRARIES "")
endif()
if(GDAL_FOUND)
set(GDAL_LIBRARIES ${GDAL_LIBRARY})
else()
set(GDAL_LIBRARIES "")
endif()
if(ENABLE_JSBSIM)
# FIXME - remove once JSBSim doesn't expose private headers
include_directories(${PROJECT_SOURCE_DIR}/src/FDM/JSBSim)
@ -141,6 +147,7 @@ target_link_libraries(fgfs
${OPENGL_LIBRARIES}
${PLIB_LIBRARIES}
${HLA_LIBRARIES}
${GDAL_LIBRARIES}
${EVENT_INPUT_LIBRARIES}
${PLATFORM_LIBS}
)

View file

@ -32,7 +32,6 @@
#include <GUI/dialog.hxx>
#include <Aircraft/replay.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Scripting/NasalSys.hxx>
#include <Sound/sample_queue.hxx>
#include <Airports/xmlloader.hxx>
@ -547,8 +546,8 @@ do_materials_reload (const SGPropertyNode * arg)
}
globals->set_matlib(new_matlib);
FGTileMgr* tileManager = static_cast<FGTileMgr*>(globals->get_subsystem("tile-manager"));
tileManager->materialLibChanged();
FGScenery* scenery = static_cast<FGScenery*>(globals->get_scenery());
scenery->materialLibChanged();
return true;
}

View file

@ -111,7 +111,6 @@
#include <Navaids/navlist.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/SceneryPager.hxx>
#include <Scenery/tilemgr.hxx>
#include <Scripting/NasalSys.hxx>
#include <Sound/voice.hxx>
#include <Sound/soundmanager.hxx>
@ -1029,7 +1028,7 @@ void fgStartNewReset()
string_list::const_iterator it;
for (it = names.begin(); it != names.end(); ++it) {
if ((*it == "time") || (*it == "terrasync") || (*it == "events")
|| (*it == "lighting") || (*it == FGTileMgr::subsystemName()) || (*it == FGScenery::subsystemName()))
|| (*it == "lighting") || (*it == FGScenery::subsystemName()))
{
continue;
}
@ -1052,7 +1051,6 @@ void fgStartNewReset()
// order is important here since tile-manager shutdown needs to
// access the scenery object
subsystemManger->remove(FGTileMgr::subsystemName());
subsystemManger->remove(FGScenery::subsystemName());
FGScenery::getPagerSingleton()->clearRequests();

View file

@ -210,7 +210,6 @@ FGGlobals::~FGGlobals()
subsystem_mgr->shutdown();
subsystem_mgr->unbind();
subsystem_mgr->remove(FGTileMgr::subsystemName());
// don't cancel the pager until after shutdown, since AIModels (and
// potentially others) can queue delete requests on the pager.
if (vw && vw->getDatabasePager()) {
@ -756,11 +755,6 @@ FGScenery* FGGlobals::get_scenery () const
return get_subsystem<FGScenery>();
}
FGTileMgr* FGGlobals::get_tile_mgr () const
{
return get_subsystem<FGTileMgr>();
}
FGViewMgr *FGGlobals::get_viewmgr() const
{
return get_subsystem<FGViewMgr>();

View file

@ -59,7 +59,6 @@ class FGTACANList;
class FGLocale;
class FGRouteMgr;
class FGScenery;
class FGTileMgr;
class FGViewMgr;
class FGRenderer;
@ -364,8 +363,6 @@ public:
FGControls *get_controls() const;
FGScenery * get_scenery () const;
FGTileMgr * get_tile_mgr () const;
inline FGTACANList *get_channellist() const { return channellist; }
inline void set_channellist( FGTACANList *c ) { channellist = c; }

View file

@ -58,7 +58,6 @@ extern bool global_crashRptEnabled;
#include <Model/panelnode.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
#include <Sound/soundmanager.hxx>
#include <Time/TimeManager.hxx>
#include <GUI/gui.h>
@ -313,8 +312,7 @@ static void fgIdleFunction ( void ) {
globals->add_new_subsystem<FGScenery>(SGSubsystemMgr::DISPLAY);
globals->get_scenery()->init();
globals->get_scenery()->bind();
globals->add_new_subsystem<FGTileMgr>(SGSubsystemMgr::DISPLAY);
fgSplashProgress("creating-subsystems");
} else if (( idle_state == 7 ) || (idle_state == 2007)) {
bool isReset = (idle_state == 2007);

View file

@ -120,17 +120,17 @@ static int fgSetupProxy( const char *arg );
void fgSetDefaults ()
{
// Position (deliberately out of range)
// Position (deliberately out of range)
fgSetDouble("/position/longitude-deg", 9999.0);
fgSetDouble("/position/latitude-deg", 9999.0);
fgSetDouble("/position/altitude-ft", -9999.0);
// Orientation
// Orientation
fgSetDouble("/orientation/heading-deg", 9999.0);
fgSetDouble("/orientation/roll-deg", 0.0);
fgSetDouble("/orientation/pitch-deg", 0.424);
// Velocities
// Velocities
fgSetDouble("/velocities/uBody-fps", 0.0);
fgSetDouble("/velocities/vBody-fps", 0.0);
fgSetDouble("/velocities/wBody-fps", 0.0);
@ -140,7 +140,7 @@ void fgSetDefaults ()
fgSetDouble("/velocities/airspeed-kt", 0.0);
fgSetDouble("/velocities/mach", 0.0);
// Presets
// Presets
fgSetDouble("/sim/presets/longitude-deg", 9999.0);
fgSetDouble("/sim/presets/latitude-deg", 9999.0);
fgSetDouble("/sim/presets/altitude-ft", -9999.0);
@ -162,7 +162,7 @@ void fgSetDefaults ()
fgSetBool("/sim/presets/onground", true);
fgSetBool("/sim/presets/trim", false);
// Miscellaneous
// Miscellaneous
fgSetBool("/sim/startup/splash-screen", true);
// we want mouse-pointer to have an undefined value if nothing is
// specified so we can do the right thing for voodoo-1/2 cards.
@ -170,7 +170,7 @@ void fgSetDefaults ()
fgSetBool("/controls/flight/auto-coordination", false);
fgSetString("/sim/logging/priority", "alert");
// Features
// Features
fgSetBool("/sim/hud/color/antialiased", false);
fgSetBool("/sim/hud/enable3d[1]", true);
fgSetBool("/sim/hud/visibility[1]", false);
@ -179,13 +179,21 @@ void fgSetDefaults ()
fgSetBool("/sim/sound/working", true);
fgSetBool("/sim/fgcom/enabled", false);
// Flight Model options
// Flight Model options
fgSetString("/sim/flight-model", "jsb");
fgSetString("/sim/aero", "c172");
fgSetInt("/sim/model-hz", NEW_DEFAULT_MODEL_HZ);
fgSetDouble("/sim/speed-up", 1.0);
// Rendering options
// Scenery
fgSetString("/sim/scenery/engine", "tilecache");
// ( scenery = pagedLOD )
fgSetString("/sim/scenery/lod-levels", "1 3 5 7 9");
fgSetString("/sim/scenery/lod-res", "1");
fgSetString("/sim/scenery/lod-texturing", "bluemarble");
// Rendering options
fgSetString("/sim/rendering/fog", "nicest");
fgSetBool("/environment/clouds/status", true);
fgSetBool("/sim/startup/fullscreen", false);
@ -204,16 +212,16 @@ void fgSetDefaults ()
fgSetString("/sim/view-mode", "pilot");
fgSetDouble("/sim/current-view/heading-offset-deg", 0);
// HUD options
// HUD options
fgSetString("/sim/startup/units", "feet");
fgSetString("/sim/hud/frame-stat-type", "tris");
// Time options
// Time options
fgSetInt("/sim/startup/time-offset", 0);
fgSetString("/sim/startup/time-offset-type", "system-offset");
fgSetLong("/sim/time/cur-time-override", 0);
// Freeze options
// Freeze options
fgSetBool("/sim/freeze/master", false);
fgSetBool("/sim/freeze/position", false);
fgSetBool("/sim/freeze/clock", false);
@ -1609,6 +1617,11 @@ struct OptionDesc {
{"roc", true, OPTION_FUNC, "", false, "", fgOptRoc },
{"fg-root", true, OPTION_IGNORE, "", false, "", 0 },
{"fg-scenery", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptFgScenery },
{"terrain-engine", true, OPTION_STRING, "/sim/scenery/engine", false, "tilecache", 0 },
{"lod-levels", true, OPTION_STRING, "/sim/scenery/lod-levels", false, "1 3 5 7", 0 },
{"lod-res", true, OPTION_STRING, "/sim/scenery/lod-res", false, "1", 0 },
{"lod-texturing", true, OPTION_STRING, "/sim/scenery/lod-texturing", false, "bluemarble", 0 },
{"lod-range-mult", true, OPTION_STRING, "/sim/scenery/lod-range-mult", false, "2", 0 },
{"fg-aircraft", true, OPTION_IGNORE | OPTION_MULTI, "", false, "", 0 },
{"fdm", true, OPTION_STRING, "/sim/flight-model", false, "", 0 },
{"aero", true, OPTION_STRING, "/sim/aero", false, "", 0 },

View file

@ -4,6 +4,8 @@ set(SOURCES
SceneryPager.cxx
redout.cxx
scenery.cxx
terrain_stg.cxx
terrain_pgt.cxx
tilecache.cxx
tileentry.cxx
tilemgr.cxx
@ -13,6 +15,9 @@ set(HEADERS
SceneryPager.hxx
redout.hxx
scenery.hxx
terrain.hxx
terrain_stg.hxx
terrain_pgt.hxx
tilecache.hxx
tileentry.hxx
tilemgr.hxx

View file

@ -57,8 +57,12 @@
#include <Main/fg_props.hxx>
#include <GUI/MouseCursor.hxx>
#include "tilemgr.hxx"
#include "scenery.hxx"
#include "terrain_stg.hxx"
#ifdef ENABLE_GDAL
#include "terrain_pgt.hxx"
#endif
using namespace flightgear;
using namespace simgear;
@ -298,7 +302,7 @@ FGScenery::~FGScenery()
// Initialize the Scenery Management system
void FGScenery::init() {
void FGScenery::init() {
// Already set up.
if (_inited)
return;
@ -345,14 +349,36 @@ void FGScenery::init() {
precipitation_branch->setName("Precipitation");
scene_graph->addChild(precipitation_branch.get());
// initialize the terrian based on selected engine
std::string engine = fgGetString("/sim/scenery/engine", "tilecache" );
SG_LOG( SG_TERRAIN, SG_INFO, "Selected scenery is " << engine );
if ( engine == "pagedLOD" ) {
#ifdef ENABLE_GDAL
_terrain = new FGPgtTerrain();
#else
_terrain = new FGStgTerrain();
#endif
} else {
_terrain = new FGStgTerrain();
}
_terrain->init( terrain_branch.get() );
_listener = new ScenerySwitchListener(this);
// Toggle the setup flag.
_inited = true;
}
void FGScenery::reinit()
{
_terrain->reinit();
}
void FGScenery::shutdown()
{
_terrain->shutdown();
scene_graph = NULL;
terrain_branch = NULL;
models_branch = NULL;
@ -366,17 +392,13 @@ void FGScenery::shutdown()
void FGScenery::update(double dt)
{
SG_UNUSED(dt);
// nothing here, don't call again
suspend();
{
_terrain->update(dt);
}
void FGScenery::bind() {
}
void FGScenery::unbind() {
}
@ -386,9 +408,8 @@ FGScenery::get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom)
{
SGGeod geod = SGGeod::fromCart(pos);
geod.setElevationM(geod.getElevationM() + max_altoff);
return get_elevation_m(geod, alt, material, butNotFrom);
return _terrain->get_cart_elevation_m(pos, max_altoff, alt,
material, butNotFrom);
}
bool
@ -396,25 +417,8 @@ FGScenery::get_elevation_m(const SGGeod& geod, double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom)
{
SGVec3d start = SGVec3d::fromGeod(geod);
SGGeod geodEnd = geod;
geodEnd.setElevationM(SGMiscd::min(geod.getElevationM() - 10, -10000));
SGVec3d end = SGVec3d::fromGeod(geodEnd);
FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end), butNotFrom);
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
get_scene_graph()->accept(intersectVisitor);
if (!intersectVisitor.getHaveHit())
return false;
geodEnd = SGGeod::fromCart(intersectVisitor.getLineSegment().getEnd());
alt = geodEnd.getElevationM();
if (material)
*material = intersectVisitor.getMaterial();
return true;
return _terrain->get_elevation_m( geod, alt, material,
butNotFrom );
}
bool
@ -422,50 +426,22 @@ FGScenery::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
SGVec3d& nearestHit,
const osg::Node* butNotFrom)
{
// 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 ???
FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end), butNotFrom);
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
get_scene_graph()->accept(intersectVisitor);
if (!intersectVisitor.getHaveHit())
return false;
nearestHit = intersectVisitor.getLineSegment().getEnd();
return true;
return _terrain->get_cart_ground_intersection( pos, dir, nearestHit, butNotFrom );
}
bool FGScenery::scenery_available(const SGGeod& position, double range_m)
{
if(globals->get_tile_mgr()->schedule_scenery(position, range_m, 0.0))
{
double elev;
if (!get_elevation_m(SGGeod::fromGeodM(position, SG_MAX_ELEVATION_M), elev, 0, 0))
return false;
SGVec3f p = SGVec3f::fromGeod(SGGeod::fromGeodM(position, elev));
osg::FrameStamp* framestamp
= globals->get_renderer()->getViewer()->getFrameStamp();
simgear::CheckSceneryVisitor csnv(_pager, toOsg(p), range_m, framestamp);
// currently the PagedLODs will not be loaded by the DatabasePager
// while the splashscreen is there, so CheckSceneryVisitor force-loads
// missing objects in the main thread
get_scene_graph()->accept(csnv);
if(!csnv.isLoaded()) {
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGScenery::scenery_available: waiting on CheckSceneryVisitor");
return false;
}
return true;
} else {
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGScenery::scenery_available: waiting on tile manager");
}
return false;
return _terrain->scenery_available( position, range_m );
}
bool FGScenery::schedule_scenery(const SGGeod& position, double range_m, double duration)
{
return _terrain->schedule_scenery( position, range_m, duration );
}
void FGScenery::materialLibChanged()
{
_terrain->materialLibChanged();
}
static osg::ref_ptr<SceneryPager> pager;
@ -481,4 +457,3 @@ void FGScenery::resetPagerSingleton()
{
pager = NULL;
}

View file

@ -38,18 +38,21 @@
#include <simgear/structure/subsystem_mgr.hxx>
#include "SceneryPager.hxx"
#include "terrain.hxx"
namespace simgear {
class BVHMaterial;
}
class FGTerrain;
// Define a structure containing global scenery parameters
class FGScenery : public SGSubsystem
{
class ScenerySwitchListener;
friend class ScenerySwitchListener;
// scene graph
osg::ref_ptr<osg::Switch> scene_graph;
osg::ref_ptr<osg::Group> terrain_branch;
@ -61,13 +64,14 @@ class FGScenery : public SGSubsystem
osg::ref_ptr<flightgear::SceneryPager> _pager;
ScenerySwitchListener* _listener;
public:
public:
FGScenery();
~FGScenery();
// Implementation of SGSubsystem.
void init ();
void reinit();
void shutdown ();
void bind ();
void unbind ();
@ -129,17 +133,21 @@ public:
// the scenery is initialized.
static flightgear::SceneryPager* getPagerSingleton();
static void resetPagerSingleton();
flightgear::SceneryPager* getPager() { return _pager.get(); }
flightgear::SceneryPager* getPager() { return _pager.get(); }
// tile mgr api
bool schedule_scenery(const SGGeod& position, double range_m, double duration=0.0);
void materialLibChanged();
static const char* subsystemName() { return "scenery"; }
private:
// The state of the scene graph.
// the terrain engine
FGTerrain* _terrain;
// The state of the scene graph.
bool _inited;
};
#endif // _SCENERY_HXX

112
src/Scenery/terrain.hxx Normal file
View file

@ -0,0 +1,112 @@
// scenery.hxx -- 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$
#ifndef _TERRAIN_HXX
#define _TERRAIN_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <osg/ref_ptr>
#include <osg/Switch>
#include <simgear/compiler.h>
#include <simgear/math/SGMath.hxx>
#include <simgear/scene/model/particles.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include "scenery.hxx"
#include "SceneryPager.hxx"
#include "tilemgr.hxx"
namespace simgear {
class BVHMaterial;
}
// Define a structure containing global scenery parameters
class FGTerrain
{
public:
FGTerrain() {};
~FGTerrain() {};
// Implementation of SGSubsystem. - called from Scenery
virtual void init ( osg::Group* terrain ) = 0;
virtual void reinit() = 0;
virtual void shutdown () = 0;
virtual void bind () = 0;
virtual void unbind () = 0;
virtual void update (double dt) = 0;
/// Compute the elevation of the scenery at geodetic latitude lat,
/// geodetic longitude lon and not higher than max_alt.
/// If the exact flag is set to true, the scenery center is moved to
/// gain a higher accuracy of that query. The center is restored past
/// that to the original value.
/// The altitude hit is returned in the alt argument.
/// The method returns true if the scenery is available for the given
/// lat/lon pair. If there is no scenery for that point, the altitude
/// value is undefined.
/// All values are meant to be in meters or degrees.
virtual bool get_elevation_m(const SGGeod& geod, double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom = 0) = 0;
/// Compute the elevation of the scenery below the cartesian point pos.
/// you the returned scenery altitude is not higher than the position
/// pos plus an offset given with max_altoff.
/// If the exact flag is set to true, the scenery center is moved to
/// gain a higher accuracy of that query. The center is restored past
/// that to the original value.
/// The altitude hit is returned in the alt argument.
/// The method returns true if the scenery is available for the given
/// lat/lon pair. If there is no scenery for that point, the altitude
/// value is undefined.
/// All values are meant to be in meters.
virtual bool get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
double& elevation,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom = 0) = 0;
/// Compute the nearest intersection point of the line starting from
/// start going in direction dir with the terrain.
/// The input and output values should be in cartesian coordinates in the
/// usual earth centered wgs84 coordinate system. Units are meters.
/// On success, true is returned.
virtual bool get_cart_ground_intersection(const SGVec3d& start, const SGVec3d& dir,
SGVec3d& nearestHit,
const osg::Node* butNotFrom = 0) = 0;
/// Returns true if scenery is available for the given lat, lon position
/// within a range of range_m.
/// lat and lon are expected to be in degrees.
virtual bool scenery_available(const SGGeod& position, double range_m) = 0;
// tile mgr api
virtual bool schedule_scenery(const SGGeod& position, double range_m, double duration=0.0) = 0;
virtual void materialLibChanged() = 0;
};
#endif // _TERRAIN_HXX

252
src/Scenery/terrain_pgt.cxx Normal file
View file

@ -0,0 +1,252 @@
// terrain_pgt.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
#ifdef ENABLE_GDAL
#include <boost/lexical_cast.hpp>
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Viewer/splash.hxx>
#include "terrain_pgt.hxx"
#include "scenery.hxx"
using namespace flightgear;
using namespace simgear;
using flightgear::SceneryPager;
// Terrain Management system
FGPgtTerrain::FGPgtTerrain() :
_scenery_loaded(fgGetNode("/sim/sceneryloaded", true)),
_scenery_override(fgGetNode("/sim/sceneryloaded-override", true))
{
_inited = false;
}
FGPgtTerrain::~FGPgtTerrain()
{
}
// Initialize the Scenery Management system
void FGPgtTerrain::init( osg::Group* terrain ) {
// Already set up.
if (_inited)
return;
SG_LOG(SG_TERRAIN, SG_INFO, "FGPgtTerrain::init");
// remember the scene terrain branch on scenegraph
terrain_branch = terrain;
// load the whole planet tile - database pager handles
// the quad tree / loading the highres tiles
osg::ref_ptr<simgear::SGReaderWriterOptions> options;
// drops the previous options reference
options = new simgear::SGReaderWriterOptions;
options->setPropertyNode(globals->get_props());
osgDB::FilePathList &fp = options->getDatabasePathList();
const PathList &sc = globals->get_fg_scenery();
fp.clear();
PathList::const_iterator it;
for (it = sc.begin(); it != sc.end(); ++it) {
fp.push_back(it->local8BitStr());
}
options->setPluginStringData("SimGear::FG_ROOT", globals->get_fg_root().local8BitStr());
options->setPluginStringData("SimGear::BARE_LOD_RANGE", fgGetString("/sim/rendering/static-lod/bare", boost::lexical_cast<string>(SG_OBJECT_RANGE_BARE)));
options->setPluginStringData("SimGear::ROUGH_LOD_RANGE", fgGetString("/sim/rendering/static-lod/rough", boost::lexical_cast<string>(SG_OBJECT_RANGE_ROUGH)));
options->setPluginStringData("SimGear::ROUGH_LOD_DETAILED", fgGetString("/sim/rendering/static-lod/detailed", boost::lexical_cast<string>(SG_OBJECT_RANGE_DETAILED)));
options->setPluginStringData("SimGear::RENDER_BUILDING_MESH", fgGetBool("/sim/rendering/building-mesh", false) ? "true" : "false");
options->setPluginStringData("SimGear::FG_EARTH", "ON");
// tunables
options->setPluginStringData("SimGear::SPT_PAGE_LEVELS", fgGetString("/sim/scenery/lod-levels", "1 3 5 7 9" ));
options->setPluginStringData("SimGear::SPT_RANGE_MULTIPLIER", fgGetString("/sim/scenery/lod-range-mult", "2" ));
options->setPluginStringData("SimGear::SPT_MESH_RESOLUTION", fgGetString("/sim/scenery/lod-res", "1" ));
options->setPluginStringData("SimGear::SPT_LOD_TEXTURING", fgGetString("/sim/scenery/lod-texturing", "bluemarble" ));
options->setMaterialLib(globals->get_matlib());
// a DEM can contain multiple levels from multiple locations
// priority is based on first found...
_dem = new SGDem;
if ( _dem ) {
for (osgDB::FilePathList::const_iterator i = fp.begin(); i != fp.end(); ++i) {
SGPath demPath(*i);
demPath.append("DEM");
int numLevels = _dem->addRoot(demPath);
if ( numLevels ) {
SG_LOG(SG_TERRAIN, SG_INFO, "Terrain init - dem path " << demPath << " has " << numLevels << " LOD Levels " );
} else {
SG_LOG(SG_TERRAIN, SG_INFO, "Terrain init - dem path " << demPath << " has NO LOD Levels " );
}
}
options->setDem(_dem);
SG_LOG(SG_TERRAIN, SG_INFO, "Terrain init - Load w180s90-360x180.pgt" );
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile("w180s90-360x180.pgt", options.get());
if ( loadedModel ) {
terrain_branch->addChild( loadedModel.get() );
// Toggle the setup flag.
_inited = true;
}
}
}
void FGPgtTerrain::reinit()
{
}
void FGPgtTerrain::shutdown()
{
terrain_branch = NULL;
// Toggle the setup flag.
_inited = false;
}
void FGPgtTerrain::update(double dt)
{
// scenery loading check, triggers after each sim (tile manager) reinit
if (!_scenery_loaded->getBoolValue())
{
bool fdmInited = fgGetBool("sim/fdm-initialized");
bool positionFinalized = fgGetBool("sim/position-finalized");
bool sceneryOverride = _scenery_override->getBoolValue();
// we are done if final position is set and the scenery & FDM are done.
// scenery-override can ignore the last two, but not position finalization.
if (positionFinalized && (sceneryOverride || fdmInited))
{
_scenery_loaded->setBoolValue(true);
fgSplashProgress("");
}
else
{
if (!positionFinalized) {
fgSplashProgress("finalize-position");
} else {
fgSplashProgress("loading-scenery");
}
// be nice to loader threads while waiting for initial scenery, reduce to 20fps
SGTimeStamp::sleepForMSec(50);
}
}
}
void FGPgtTerrain::bind()
{
}
void FGPgtTerrain::unbind()
{
}
bool
FGPgtTerrain::get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom)
{
SGGeod geod = SGGeod::fromCart(pos);
geod.setElevationM(geod.getElevationM() + max_altoff);
return get_elevation_m(geod, alt, material, butNotFrom);
}
static simgear::BVHMaterial def_mat;
bool
FGPgtTerrain::get_elevation_m(const SGGeod& geod, double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom)
{
alt = 100.0;
if (material) {
*material = &def_mat;
} else {
// SG_LOG(SG_TERRAIN, SG_INFO, "FGStgTerrain::get_elevation_m: alt " << alt << " no material " );
}
return true;
}
bool FGPgtTerrain::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
SGVec3d& nearestHit,
const osg::Node* butNotFrom)
{
return true;
}
bool FGPgtTerrain::scenery_available(const SGGeod& position, double range_m)
{
if( schedule_scenery(position, range_m, 0.0) )
{
return true;
}
else
{
return false;
}
}
bool FGPgtTerrain::schedule_scenery(const SGGeod& position, double range_m, double duration)
{
// sanity check (unfortunately needed!)
if (!position.isValid()) {
SG_LOG(SG_TERRAIN, SG_INFO, "FGSptTerrain::schedule_scenery - position invalid");
return false;
}
return true;
}
void FGPgtTerrain::materialLibChanged()
{
// PSADRO: TODO - passing down new regional textures won't work. these need to be set in the
// lod tree at init time, as OSGDBPager generates the load request, not the tile cache.
// _options->setMaterialLib(globals->get_matlib());
}
#endif

127
src/Scenery/terrain_pgt.hxx Normal file
View file

@ -0,0 +1,127 @@
// terrain_pgt.hxx -- 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$
#ifndef _TERRAIN_PGT_HXX
#define _TERRAIN_PGT_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <osg/ref_ptr>
#include <osg/Switch>
#include <simgear/compiler.h>
#include <simgear/props/props.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/scene/model/particles.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/scene/dem/SGDem.hxx>
#include "terrain.hxx"
//#include "SceneryPager.hxx"
//#include "tilemgr.hxx"
namespace simgear {
class BVHMaterial;
}
// Define a structure containing global scenery parameters
class FGPgtTerrain : public FGTerrain
{
public:
FGPgtTerrain();
~FGPgtTerrain();
// Implementation of SGSubsystem.
void init ( osg::Group* terrain );
void reinit();
void shutdown ();
void bind ();
void unbind ();
void update (double dt);
/// Compute the elevation of the scenery at geodetic latitude lat,
/// geodetic longitude lon and not higher than max_alt.
/// If the exact flag is set to true, the scenery center is moved to
/// gain a higher accuracy of that query. The center is restored past
/// that to the original value.
/// The altitude hit is returned in the alt argument.
/// The method returns true if the scenery is available for the given
/// lat/lon pair. If there is no scenery for that point, the altitude
/// value is undefined.
/// All values are meant to be in meters or degrees.
bool get_elevation_m(const SGGeod& geod, double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom = 0);
/// Compute the elevation of the scenery below the cartesian point pos.
/// you the returned scenery altitude is not higher than the position
/// pos plus an offset given with max_altoff.
/// If the exact flag is set to true, the scenery center is moved to
/// gain a higher accuracy of that query. The center is restored past
/// that to the original value.
/// The altitude hit is returned in the alt argument.
/// The method returns true if the scenery is available for the given
/// lat/lon pair. If there is no scenery for that point, the altitude
/// value is undefined.
/// All values are meant to be in meters.
bool get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
double& elevation,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom = 0);
/// Compute the nearest intersection point of the line starting from
/// start going in direction dir with the terrain.
/// The input and output values should be in cartesian coordinates in the
/// usual earth centered wgs84 coordinate system. Units are meters.
/// On success, true is returned.
bool get_cart_ground_intersection(const SGVec3d& start, const SGVec3d& dir,
SGVec3d& nearestHit,
const osg::Node* butNotFrom = 0);
/// Returns true if scenery is available for the given lat, lon position
/// within a range of range_m.
/// lat and lon are expected to be in degrees.
bool scenery_available(const SGGeod& position, double range_m);
// tile mgr api
bool schedule_scenery(const SGGeod& position, double range_m, double duration=0.0);
void materialLibChanged();
static const char* subsystemName() { return "scenery"; }
private:
// terrain branch of scene graph
osg::ref_ptr<osg::Group> terrain_branch;
SGPropertyNode_ptr _scenery_loaded, _scenery_override;
bool _inited;
SGDemPtr _dem;
};
#endif // _TERRAIN_PGT_HXX

409
src/Scenery/terrain_stg.cxx Normal file
View file

@ -0,0 +1,409 @@
// 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 <osg/Camera>
#include <osg/Transform>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>
#include <osg/CameraView>
#include <osg/LOD>
#include <osgViewer/Viewer>
#include <simgear/constants.h>
#include <simgear/sg_inlines.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/scene/tgdb/userdata.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGSceneUserData.hxx>
#include <simgear/scene/model/CheckSceneryVisitor.hxx>
#include <simgear/scene/sky/sky.hxx>
#include <simgear/bvh/BVHNode.hxx>
#include <simgear/bvh/BVHLineSegmentVisitor.hxx>
#include <simgear/structure/commands.hxx>
#include <Viewer/renderer.hxx>
#include <Main/fg_props.hxx>
#include <GUI/MouseCursor.hxx>
#include "terrain_stg.hxx"
using namespace flightgear;
using namespace simgear;
class FGGroundPickCallback : public SGPickCallback {
public:
FGGroundPickCallback() : SGPickCallback(PriorityScenery)
{ }
virtual bool buttonPressed( int button,
const osgGA::GUIEventAdapter&,
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;
}
};
class FGSceneryIntersect : public osg::NodeVisitor {
public:
FGSceneryIntersect(const SGLineSegmentd& lineSegment,
const osg::Node* skipNode) :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
_lineSegment(lineSegment),
_skipNode(skipNode),
_material(0),
_haveHit(false)
{ }
bool getHaveHit() const
{ return _haveHit; }
const SGLineSegmentd& getLineSegment() const
{ return _lineSegment; }
const simgear::BVHMaterial* getMaterial() const
{ return _material; }
virtual void apply(osg::Node& node)
{
if (&node == _skipNode)
return;
if (!testBoundingSphere(node.getBound()))
return;
addBoundingVolume(node);
}
virtual void apply(osg::Group& group)
{
if (&group == _skipNode)
return;
if (!testBoundingSphere(group.getBound()))
return;
traverse(group);
addBoundingVolume(group);
}
virtual void apply(osg::Transform& transform)
{ handleTransform(transform); }
virtual void apply(osg::Camera& camera)
{
if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
return;
handleTransform(camera);
}
virtual void apply(osg::CameraView& transform)
{ handleTransform(transform); }
virtual void apply(osg::MatrixTransform& transform)
{ handleTransform(transform); }
virtual void apply(osg::PositionAttitudeTransform& transform)
{ handleTransform(transform); }
private:
void handleTransform(osg::Transform& transform)
{
if (&transform == _skipNode)
return;
// Hmm, may be this needs to be refined somehow ...
if (transform.getReferenceFrame() != osg::Transform::RELATIVE_RF)
return;
if (!testBoundingSphere(transform.getBound()))
return;
osg::Matrix inverseMatrix;
if (!transform.computeWorldToLocalMatrix(inverseMatrix, this))
return;
osg::Matrix matrix;
if (!transform.computeLocalToWorldMatrix(matrix, this))
return;
SGLineSegmentd lineSegment = _lineSegment;
bool haveHit = _haveHit;
const simgear::BVHMaterial* material = _material;
_haveHit = false;
_lineSegment = lineSegment.transform(SGMatrixd(inverseMatrix.ptr()));
addBoundingVolume(transform);
traverse(transform);
if (_haveHit) {
_lineSegment = _lineSegment.transform(SGMatrixd(matrix.ptr()));
} else {
_lineSegment = lineSegment;
_material = material;
_haveHit = haveHit;
}
}
simgear::BVHNode* getNodeBoundingVolume(osg::Node& node)
{
SGSceneUserData* userData = SGSceneUserData::getSceneUserData(&node);
if (!userData)
return 0;
return userData->getBVHNode();
}
void addBoundingVolume(osg::Node& node)
{
simgear::BVHNode* bvNode = getNodeBoundingVolume(node);
if (!bvNode)
return;
// Find ground intersection on the bvh nodes
simgear::BVHLineSegmentVisitor lineSegmentVisitor(_lineSegment,
0/*startTime*/);
bvNode->accept(lineSegmentVisitor);
if (!lineSegmentVisitor.empty()) {
_lineSegment = lineSegmentVisitor.getLineSegment();
_material = lineSegmentVisitor.getMaterial();
_haveHit = true;
}
}
bool testBoundingSphere(const osg::BoundingSphere& bound) const
{
if (!bound.valid())
return false;
SGSphered sphere(toVec3d(toSG(bound._center)), bound._radius);
return intersects(_lineSegment, sphere);
}
SGLineSegmentd _lineSegment;
const osg::Node* _skipNode;
const simgear::BVHMaterial* _material;
bool _haveHit;
};
////////////////////////////////////////////////////////////////////////////
// Terrain Management system
FGStgTerrain::FGStgTerrain() :
_tilemgr()
{
_inited = false;
}
FGStgTerrain::~FGStgTerrain()
{
}
// Initialize the Scenery Management system
void FGStgTerrain::init( osg::Group* terrain ) {
// Already set up.
if (_inited)
return;
SG_LOG(SG_TERRAIN, SG_INFO, "FGStgTerrain::init - init tilemgr");
// remember the scene terrain branch on scenegraph
terrain_branch = terrain;
// initialize the tile manager
_tilemgr.init();
// Toggle the setup flag.
_inited = true;
}
void FGStgTerrain::reinit()
{
SG_LOG(SG_TERRAIN, SG_INFO, "FGStgTerrain::reinit - reinit tilemgr");
_tilemgr.reinit();
}
void FGStgTerrain::shutdown()
{
SG_LOG(SG_TERRAIN, SG_INFO, "FGStgTerrain::shutdown - shutdown tilemgr");
_tilemgr.shutdown();
terrain_branch = NULL;
// Toggle the setup flag.
_inited = false;
}
void FGStgTerrain::update(double dt)
{
_tilemgr.update(dt);
}
void FGStgTerrain::bind()
{
SG_LOG(SG_TERRAIN, SG_INFO, "FGStgTerrain::bind - noop");
}
void FGStgTerrain::unbind()
{
SG_LOG(SG_TERRAIN, SG_INFO, "FGStgTerrain::unbind - noop");
}
bool
FGStgTerrain::get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom)
{
bool ok;
SGGeod geod = SGGeod::fromCart(pos);
geod.setElevationM(geod.getElevationM() + max_altoff);
ok = get_elevation_m(geod, alt, material, butNotFrom);
return ok;
}
bool
FGStgTerrain::get_elevation_m(const SGGeod& geod, double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom)
{
SGVec3d start = SGVec3d::fromGeod(geod);
SGGeod geodEnd = geod;
geodEnd.setElevationM(SGMiscd::min(geod.getElevationM() - 10, -10000));
SGVec3d end = SGVec3d::fromGeod(geodEnd);
FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end), butNotFrom);
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
terrain_branch->accept(intersectVisitor);
if (!intersectVisitor.getHaveHit())
return false;
geodEnd = SGGeod::fromCart(intersectVisitor.getLineSegment().getEnd());
alt = geodEnd.getElevationM();
if (material) {
*material = intersectVisitor.getMaterial();
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGStgTerrain::get_elevation_m: alt " << alt << " material " << *material );
} else {
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGStgTerrain::get_elevation_m: alt " << alt << " no material " );
}
return true;
}
bool
FGStgTerrain::get_cart_ground_intersection(const SGVec3d& pos, const SGVec3d& dir,
SGVec3d& nearestHit,
const osg::Node* butNotFrom)
{
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGStgTerrain::get_cart_ground_intersection");
// 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 ???
FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end), butNotFrom);
intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
terrain_branch->accept(intersectVisitor);
if (!intersectVisitor.getHaveHit())
return false;
nearestHit = intersectVisitor.getLineSegment().getEnd();
return true;
}
bool FGStgTerrain::scenery_available(const SGGeod& position, double range_m)
{
if( schedule_scenery(position, range_m, 0.0) )
{
double elev;
if (!get_elevation_m(SGGeod::fromGeodM(position, SG_MAX_ELEVATION_M), elev, 0, 0))
{
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGStgTerrain::scenery_available - false" );
return false;
}
SGVec3f p = SGVec3f::fromGeod(SGGeod::fromGeodM(position, elev));
osg::FrameStamp* framestamp
= globals->get_renderer()->getViewer()->getFrameStamp();
FGScenery* pSceneryManager = globals->get_scenery();
simgear::CheckSceneryVisitor csnv(pSceneryManager->getPager(), toOsg(p), range_m, framestamp);
// currently the PagedLODs will not be loaded by the DatabasePager
// while the splashscreen is there, so CheckSceneryVisitor force-loads
// missing objects in the main thread
terrain_branch->accept(csnv);
if(!csnv.isLoaded()) {
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGScenery::scenery_available: waiting on CheckSceneryVisitor");
return false;
}
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGStgTerrain::scenery_available - true" );
return true;
} else {
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGScenery::scenery_available: waiting on tile manager");
}
SG_LOG(SG_TERRAIN, SG_DEBUG, "FGStgTerrain::scenery_available - false" );
return false;
}
bool FGStgTerrain::schedule_scenery(const SGGeod& position, double range_m, double duration)
{
SG_LOG(SG_TERRAIN, SG_BULK, "FGStgTerrain::schedule_scenery");
return _tilemgr.schedule_scenery( position, range_m, duration );
}
void FGStgTerrain::materialLibChanged()
{
_tilemgr.materialLibChanged();
}

126
src/Scenery/terrain_stg.hxx Normal file
View file

@ -0,0 +1,126 @@
// scenery.hxx -- 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$
#ifndef _TERRAIN_STG_HXX
#define _TERRAIN_STG_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <osg/ref_ptr>
#include <osg/Switch>
#include <simgear/compiler.h>
#include <simgear/math/SGMath.hxx>
#include <simgear/scene/model/particles.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include "terrain.hxx"
#include "SceneryPager.hxx"
#include "tilemgr.hxx"
namespace simgear {
class BVHMaterial;
}
// Define a structure containing global scenery parameters
class FGStgTerrain : public FGTerrain
{
public:
FGStgTerrain();
~FGStgTerrain();
// Implementation of SGSubsystem.
void init ( osg::Group* terrain );
void reinit();
void shutdown ();
void bind ();
void unbind ();
void update (double dt);
/// Compute the elevation of the scenery at geodetic latitude lat,
/// geodetic longitude lon and not higher than max_alt.
/// If the exact flag is set to true, the scenery center is moved to
/// gain a higher accuracy of that query. The center is restored past
/// that to the original value.
/// The altitude hit is returned in the alt argument.
/// The method returns true if the scenery is available for the given
/// lat/lon pair. If there is no scenery for that point, the altitude
/// value is undefined.
/// All values are meant to be in meters or degrees.
bool get_elevation_m(const SGGeod& geod, double& alt,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom = 0);
/// Compute the elevation of the scenery below the cartesian point pos.
/// you the returned scenery altitude is not higher than the position
/// pos plus an offset given with max_altoff.
/// If the exact flag is set to true, the scenery center is moved to
/// gain a higher accuracy of that query. The center is restored past
/// that to the original value.
/// The altitude hit is returned in the alt argument.
/// The method returns true if the scenery is available for the given
/// lat/lon pair. If there is no scenery for that point, the altitude
/// value is undefined.
/// All values are meant to be in meters.
bool get_cart_elevation_m(const SGVec3d& pos, double max_altoff,
double& elevation,
const simgear::BVHMaterial** material,
const osg::Node* butNotFrom = 0);
/// Compute the nearest intersection point of the line starting from
/// start going in direction dir with the terrain.
/// The input and output values should be in cartesian coordinates in the
/// usual earth centered wgs84 coordinate system. Units are meters.
/// On success, true is returned.
bool get_cart_ground_intersection(const SGVec3d& start, const SGVec3d& dir,
SGVec3d& nearestHit,
const osg::Node* butNotFrom = 0);
/// Returns true if scenery is available for the given lat, lon position
/// within a range of range_m.
/// lat and lon are expected to be in degrees.
bool scenery_available(const SGGeod& position, double range_m);
// tile mgr api
bool schedule_scenery(const SGGeod& position, double range_m, double duration=0.0);
void materialLibChanged();
static const char* subsystemName() { return "scenery"; }
private:
// tile manager
FGTileMgr _tilemgr;
// terrain branch of scene graph
osg::ref_ptr<osg::Group> terrain_branch;
bool _inited;
};
#endif // _TERRAIN_STG_HXX

View file

@ -65,12 +65,12 @@ public:
_pagedLODMaximumProp(fgGetNode("/sim/rendering/max-paged-lod", true))
{
_useVBOsProp->addChangeListener(this, true);
_enableCacheProp->addChangeListener(this, true);
if (_enableCacheProp->getType() == simgear::props::NONE) {
_enableCacheProp->setBoolValue(true);
}
if (_pagedLODMaximumProp->getType() == simgear::props::NONE) {
// not set, use OSG default / environment value variable
osg::ref_ptr<osgViewer::Viewer> viewer(globals->get_renderer()->getViewer());
@ -79,14 +79,14 @@ public:
}
_pagedLODMaximumProp->addChangeListener(this, true);
}
~TileManagerListener()
{
_useVBOsProp->removeChangeListener(this);
_enableCacheProp->removeChangeListener(this);
_pagedLODMaximumProp->removeChangeListener(this);
}
virtual void valueChanged(SGPropertyNode* prop)
{
if (prop == _useVBOsProp) {
@ -101,7 +101,7 @@ public:
viewer->getDatabasePager()->setTargetMaximumNumberOfPageLOD(v);
}
}
private:
FGTileMgr* _manager;
SGPropertyNode_ptr _useVBOsProp,
@ -128,8 +128,7 @@ FGTileMgr::FGTileMgr():
FGTileMgr::~FGTileMgr()
{
}
}
// Initialize the Tile Manager subsystem
void FGTileMgr::init()
@ -160,10 +159,10 @@ void FGTileMgr::reinit()
// drops the previous options reference
_options = new simgear::SGReaderWriterOptions;
_listener = new TileManagerListener(this);
materialLibChanged();
_options->setPropertyNode(globals->get_props());
osgDB::FilePathList &fp = _options->getDatabasePathList();
const PathList &sc = globals->get_fg_scenery();
fp.clear();
@ -172,11 +171,11 @@ void FGTileMgr::reinit()
fp.push_back(it->local8BitStr());
}
_options->setPluginStringData("SimGear::FG_ROOT", globals->get_fg_root().local8BitStr());
if (_terra_sync) {
_options->setPluginStringData("SimGear::TERRASYNC_ROOT", globals->get_terrasync_dir().local8BitStr());
}
if (!_disableNasalHooks->getBoolValue())
_options->setModelData(new FGNasalModelDataProxy);
@ -197,7 +196,7 @@ void FGTileMgr::reinit()
}
_options->setSceneryPathSuffixes(scenerySuffixes);
if (state != Start)
{
// protect against multiple scenery reloads and properly reset flags,
@ -207,25 +206,25 @@ void FGTileMgr::reinit()
return;
}
}
_scenery_loaded->setBoolValue(false);
fgSetDouble("/sim/startup/splash-alpha", 1.0);
materialLibChanged();
// remove all old scenery nodes from scenegraph and clear cache
osg::Group* group = globals->get_scenery()->get_terrain_branch();
group->removeChildren(0, group->getNumChildren());
tile_cache.init();
// clear OSG cache, except on initial start-up
if (state != Start)
{
osgDB::Registry::instance()->clearObjectCache();
}
state = Inited;
previous_bucket.make_bad();
current_bucket.make_bad();
scheduled_visibility = 100.0;
@ -293,7 +292,7 @@ void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis)
"scheduling needed tiles for " << curr_bucket
<< ", tile-width-m:" << tile_width << ", tile-height-m:" << tile_height);
// cout << "tile width = " << tile_width << " tile_height = "
// << tile_height << endl;
@ -310,7 +309,7 @@ void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis)
// cout << "max cache size = " << tile_cache.get_max_cache_size()
// << " current cache size = " << tile_cache.get_size() << endl;
// clear flags of all tiles belonging to the previous view set
// clear flags of all tiles belonging to the previous view set
tile_cache.clear_current_view();
// update timestamps, so all tiles scheduled now are *newer* than any tile previously loaded
@ -332,10 +331,10 @@ void FGTileMgr::schedule_needed(const SGBucket& curr_bucket, double vis)
if (!b.isValid()) {
continue;
}
float priority = (-1.0) * (x*x+y*y);
sched_tile( b, priority, true, 0.0 );
if (_terra_sync) {
_terra_sync->scheduleTile(b);
}
@ -356,7 +355,7 @@ void FGTileMgr::update_queues(bool& isDownloadingScenery)
TileEntry *e;
int loading=0;
int sz=0;
tile_cache.set_current_time( current_time );
tile_cache.reset_traversal();
@ -369,7 +368,7 @@ void FGTileMgr::update_queues(bool& isDownloadingScenery)
// Set the ssg transform and update it's range selector
// based on current visibilty
e->prep_ssg_node(vis);
if (!e->is_loaded()) {
bool nonExpiredOrCurrent = !e->is_expired(current_time) || e->is_current_view();
bool downloading = isTileDirSyncing(e->tileFileName);
@ -400,7 +399,7 @@ void FGTileMgr::update_queues(bool& isDownloadingScenery)
dropTiles = true;
drop_count = sz; // no limit on tiles to drop
}
if (dropTiles)
{
long drop_index = _enableCache ? tile_cache.get_drop_tile() :
@ -412,14 +411,14 @@ void FGTileMgr::update_queues(bool& isDownloadingScenery)
SG_LOG(SG_TERRAIN, SG_DEBUG, "Dropping:" << old->get_tile_bucket());
tile_cache.clear_entry(drop_index);
osg::ref_ptr<osg::Object> subgraph = old->getNode();
old->removeFromSceneGraph();
delete old;
// zeros out subgraph ref_ptr, so subgraph is owned by
// the pager and will be deleted in the pager thread.
_pager->queueDeleteRequest(subgraph);
if (!_enableCache)
drop_index = tile_cache.get_first_expired_tile();
// limit tiles dropped to drop_count
@ -448,8 +447,8 @@ void FGTileMgr::update(double)
bool fdmInited = fgGetBool("sim/fdm-initialized");
bool positionFinalized = fgGetBool("sim/position-finalized");
bool sceneryOverride = _scenery_override->getBoolValue();
// we are done if final position is set and the scenery & FDM are done.
// scenery-override can ignore the last two, but not position finalization.
if (positionFinalized && (sceneryOverride || (isSceneryLoaded() && fdmInited)))
@ -466,7 +465,7 @@ void FGTileMgr::update(double)
} else {
fgSplashProgress("loading-scenery");
}
// be nice to loader threads while waiting for initial scenery, reduce to 20fps
SGTimeStamp::sleepForMSec(50);
}
@ -506,7 +505,7 @@ void FGTileMgr::schedule_tiles_at(const SGGeod& location, double range_m)
scheduled_visibility = range_m;
schedule_needed(current_bucket, range_m);
}
// save bucket
previous_bucket = current_bucket;
} else if ( state == Start || state == Inited ) {
@ -533,7 +532,7 @@ bool FGTileMgr::schedule_scenery(const SGGeod& position, double range_m, double
SGBucket bucket(position);
available = sched_tile( bucket, priority, false, duration );
if ((!available)&&(duration==0.0)) {
SG_LOG( SG_TERRAIN, SG_DEBUG, "schedule_scenery: Scheduling tile at bucket:" << bucket << " return false" );
return false;
@ -547,7 +546,7 @@ bool FGTileMgr::schedule_scenery(const SGGeod& position, double range_m, double
double tile_r = 0.5*sqrt(tile_width*tile_width + tile_height*tile_height);
double max_dist = tile_r + range_m;
double max_dist2 = max_dist*max_dist;
int xrange = (int)fabs(range_m / tile_width) + 1;
int yrange = (int)fabs(range_m / tile_height) + 1;
@ -562,7 +561,7 @@ bool FGTileMgr::schedule_scenery(const SGGeod& position, double range_m, double
if (!b.isValid()) {
continue;
}
double distance2 = distSqr(cartPos, SGVec3d::fromGeod(b.get_center()));
// Do not ask if it is just the next tile but way out of range.
if (distance2 <= max_dist2)
@ -593,10 +592,11 @@ bool FGTileMgr::isTileDirSyncing(const std::string& tileFileName) const
if (!_terra_sync) {
return false;
}
std::string nameWithoutExtension = tileFileName.substr(0, tileFileName.size() - 4);
long int bucketIndex = simgear::strutils::to_int(nameWithoutExtension);
SGBucket bucket(bucketIndex);
return _terra_sync->isTileDirPending(bucket.gen_base_path());
}

View file

@ -26,7 +26,6 @@
#include <simgear/compiler.h>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/bucket/newbucket.hxx>
#include "SceneryPager.hxx"
#include "tilecache.hxx"
@ -42,7 +41,7 @@ class SGTerraSync;
class SGReaderWriterOptions;
}
class FGTileMgr : public SGSubsystem {
class FGTileMgr {
private:
@ -93,17 +92,16 @@ private:
osg::ref_ptr<flightgear::SceneryPager> _pager;
/// is caching of expired tiles enabled or not?
bool _enableCache;
bool _enableCache;
public:
FGTileMgr();
~FGTileMgr();
// Initialize the Tile Manager
virtual void init();
virtual void reinit();
virtual void shutdown();
virtual void update(double dt);
void init();
void reinit();
void shutdown();
void update(double dt);
const SGBucket& get_current_bucket () const { return current_bucket; }
@ -118,9 +116,6 @@ public:
// notify the tile manahger the material library was reloaded,
// so it can pass this through to its options object
void materialLibChanged();
static const char* subsystemName() { return "tile-manager"; }
};
#endif // _TILEMGR_HXX

View file

@ -200,10 +200,6 @@ fgviewerMain(int argc, char** argv)
throw sg_io_exception("Error loading materials file", mpath);
}
FGScenery* scenery = globals->add_new_subsystem<FGScenery>();
scenery->init();
scenery->bind();
// The file path list must be set in the registry.
osgDB::Registry::instance()->getDataFilePathList() = filePathList;
@ -212,7 +208,11 @@ fgviewerMain(int argc, char** argv)
options->setMaterialLib(globals->get_matlib());
options->setPropertyNode(globals->get_props());
options->setPluginStringData("SimGear::PREVIEW", "ON");
FGScenery* scenery = globals->add_new_subsystem<FGScenery>();
scenery->init();
scenery->bind();
// read the scene from the list of file specified command line args.
osg::ref_ptr<osg::Node> loadedModel;
loadedModel = osgDB::readNodeFiles(dataFiles, options);

View file

@ -38,3 +38,9 @@ endif()
if (ENABLE_FGQCANVAS)
add_subdirectory(fgqcanvas)
endif()
if(ENABLE_DEMCONVERT)
if(GDALFOUND)
add_subdirectory(demconvert)
endif()
endif()

View file

@ -0,0 +1,8 @@
add_executable(demconvert demconvert.cxx )
target_link_libraries(demconvert
SimGearScene SimGearCore
${GDAL_LIBRARY}
)
install(TARGETS demconvert RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

View file

@ -0,0 +1,219 @@
// demconvert.cxx -- convert dem into lower resolutions
//
// Copyright (C) 2016 Peter Sadrozinski
//
// 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.
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <fstream>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <osg/ArgumentParser>
#include <simgear/misc/stdint.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/scene/dem/SGDem.hxx>
#include <simgear/scene/dem/SGDemSession.hxx>
int main(int argc, char** argv)
{
std::string demroot;
std::string inputvfp;
int tileWidth;
int tileHeight;
int resx, resy;
int overlap = 0;
SGDem dem;
osg::ApplicationUsage* usage = new osg::ApplicationUsage();
usage->setApplicationName("demconvert");
usage->setCommandLineUsage(
"Convert high resolution DEM to low res suitable for terrasync dl.");
usage->addCommandLineOption("--inputvfp <dir>", "input VFP root directory");
usage->addCommandLineOption("--demroot <dir>", "input/ouput DEM root directory");
usage->addCommandLineOption("--width <N>", "width (in degrees) of created tiles");
usage->addCommandLineOption("--height <N>", "height (in degrees) of created tiles");
usage->addCommandLineOption("--resx <N>", "resolution of created tiles (w/o overlap)");
usage->addCommandLineOption("--resy <N>", "resolution of created tiles (w/o overlap)");
usage->addCommandLineOption("--overlap <N>", "number of pixels of overlap");
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc, argv);
arguments.setApplicationUsage(usage);
sglog().setLogLevels( SG_TERRAIN, SG_INFO );
arguments.read("--inputvfp", inputvfp);
printf( "--inputvfp is %s\n", inputvfp.c_str() );
arguments.read("--demroot", demroot);
if ( inputvfp.empty() && demroot.empty() ) {
arguments.reportError("--inputvfp or --demroot argument required.");
} else if ( !demroot.empty() ) {
SGPath s(demroot);
if (!s.isDir()) {
arguments.reportError(
"--demroot directory does not exist or is not directory.");
} else if (!s.canRead()) {
arguments.reportError(
"--demroot directory cannot be read. Check permissions.");
} else if (!s.canWrite()) {
arguments.reportError(
"--demroot directory cannot be written. Check permissions.");
} else if ( !dem.addRoot(s) ) {
// see if we specified input as raw directory
if ( inputvfp.empty() ) {
arguments.reportError(
"--demroot directory is not a DEM heiarchy");
} else {
// create a new dem heiarchy
printf("Creating new dem heiarchy at %s\n", s.c_str() );
dem.createRoot(s);
}
}
} else {
SGPath s(inputvfp);
if (!s.isDir()) {
arguments.reportError(
"--inputvfp directory does not exist or is not directory.");
} else if (!s.canRead()) {
arguments.reportError(
"--inputvfp directory cannot be read. Check permissions.");
}
}
if (!arguments.read("--width", tileWidth)) {
arguments.reportError("--width argument required.");
} else {
if ( tileWidth < 1 || tileWidth > 60 )
arguments.reportError(
"--width must be between 1 and 60");
}
if (!arguments.read("--height", tileHeight)) {
arguments.reportError("--height argument required.");
} else {
if ( tileHeight < 1 || tileHeight > 60 )
arguments.reportError(
"--height must be between 1 and 60");
}
if (!arguments.read("--resx", resx)) {
arguments.reportError("--resx argument required.");
} else {
if ( resx < 2 )
arguments.reportError(
"--resx must be between greater than 2");
}
if (!arguments.read("--resy", resy)) {
arguments.reportError("--resy argument required.");
} else {
if ( resy < 2 )
arguments.reportError(
"--resy must be between greater than 2");
}
if (arguments.read("--overlap", overlap)) {
if ( overlap > (resx/2) || overlap > (resy/2) )
arguments.reportError(
"--overlap is greater than half tile");
}
if (arguments.errors()) {
arguments.writeErrorMessages(std::cout);
arguments.getApplicationUsage()->write(std::cout,
osg::ApplicationUsage::COMMAND_LINE_OPTION |
osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE, 80, true);
return EXIT_FAILURE;
}
double lat_dec = (double)tileHeight / (double)resy;
double lon_inc = (double)tileWidth / (double)resx;
SG_LOG( SG_TERRAIN, SG_INFO, "tileWidth: " << tileWidth);
SG_LOG( SG_TERRAIN, SG_INFO, "tileHeight: " << tileHeight);
SG_LOG( SG_TERRAIN, SG_INFO, "lon_inc: " << lon_inc);
SG_LOG( SG_TERRAIN, SG_INFO, "lat_dec: " << lat_dec);
#define MIN_X -180
#define MIN_Y -90
#define MAX_X 180
#define MAX_Y 90
// create a new dem level in demRoot
SGDemRoot* root = dem.getRoot(0);
if ( root ) {
int outLvl = root->createLevel( tileWidth, tileHeight, resx, resy, overlap, ".tiff" );
if ( outLvl >= 0 ) {
printf("SGDem::createLevel success\n");
// traverse the new tiles, 1 at a time
for ( int tilex = MIN_X; tilex < MAX_X; tilex += tileWidth ) {
for ( int tiley = MAX_Y; tiley > MIN_Y; tiley -= tileHeight ) {
// traverse rows from north to south, then columns west to east
double lonmin = (double)tilex;
double lonmax = lonmin + (double)tileWidth;
double latmax = (double)tiley;
double latmin = latmax - (double)tileHeight;
unsigned wo = SGDem::longitudeDegToOffset(lonmin);
unsigned eo = SGDem::longitudeDegToOffset(lonmax);
unsigned so = SGDem::latitudeDegToOffset(latmin);
unsigned no = SGDem::latitudeDegToOffset(latmax);
if ( !inputvfp.empty() ) {
// read from vfp files
printf("open session from raw directory\n");
SGDemSession s = dem.openSession( SGGeod::fromDeg(lonmin, latmin), SGGeod::fromDeg(lonmax, latmax), SGPath(inputvfp) );
printf("opened session from raw directory\n");
// create a new dem tile for the new level
SGDemTileRef tile = root->createTile( outLvl, (int)lonmin, (int)latmin, overlap, s );
s.close();
} else {
// read session from DEM root - don't cache - include adjacent tiles
fprintf( stderr, "open session from DEM level %d\n", outLvl-1);
SGDemSession s = dem.openSession( wo, so, eo, no, outLvl-1, false );
fprintf( stderr, "session has %d tiles\n", s.size() );
// create a new dem tile for the new level
SGDemTileRef tile = root->createTile( outLvl, (int)lonmin, (int)latmin, overlap, s );
s.close();
}
}
}
printf("SGDem::close Level \n");
root->closeLevel( outLvl );
} else {
printf("SGDem::createLevel failed\n");
}
} else {
printf("SGDem::getRoot failed\n");
}
return EXIT_SUCCESS;
}

View file

@ -2,6 +2,7 @@ add_executable(fgelev fgelev.cxx)
target_link_libraries(fgelev
SimGearScene SimGearCore
${GDAL_LIBRARY}
)
install(TARGETS fgelev RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

View file

@ -49,5 +49,6 @@ endif()
target_link_libraries(fgviewer
SimGearScene SimGearCore
${FGVIEWER_RTI_LIBRARIES}
${GDAL_LIBRARY}
)
install(TARGETS fgviewer RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})