topical media & game development
lib-game-delta3d-sdk-examples-testTerrain-testterrain.cpp / cpp
/* -*-c++-*-
* testTerrain - testterrain (.h & .cpp) - Using 'The MIT License'
* Copyright (C) 2005-2008, Alion Science and Technology Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This software was developed by Alion Science and Technology Corporation under
* circumstances in which the U. S. Government may have rights in the software.
*
* Matthew W. Campbell
*/
include <osg/ApplicationUsage>
include <osg/ArgumentParser>
include <dtABC/application.h>
include <dtABC/labelactor.h>
include <dtABC/weather.h>
include <dtCore/refptr.h>
include <dtCore/environment.h>
include <dtCore/flymotionmodel.h>
include <dtCore/globals.h>
include <dtCore/transform.h>
include <dtTerrain/terrain.h>
include <dtTerrain/dtedterrainreader.h>
include <dtTerrain/soarxterrainrenderer.h>
include <dtTerrain/geocoordinates.h>
include <dtTerrain/terraindecorationlayer.h>
include <dtTerrain/vegetationdecorator.h>
include <dtTerrain/lccanalyzer.h>
include <dtTerrain/lcctype.h>
include <dtTerrain/geotiffdecorator.h>
include <dtTerrain/colormapdecorator.h>
include <dtCore/camera.h>
include <dtCore/scene.h>
include <dtCore/keyboard.h>
include <dtCore/generickeyboardlistener.h>
include <dtUtil/exception.h>
include <osg/Version>
include <sstream>
include <iostream>
// helper func that should be somewhere
std::string vec3dToString(const osg::Vec3d& pt)
{
std::ostringstream ost;
ost << "Vec3d("<< pt.x()<< ", " << pt.y()<< ", " << pt.z()<< " )";
return ost.str();
}
// helper func that should be somewhere
std::string vec3ToString(const osg::Vec3& pt)
{
std::ostringstream ost;
ost << "Vec3 ("<< pt.x()<< ", " << pt.y()<< ", " << pt.z()<< " )";
return ost.str();
}
class TestTerrainApp : public dtABC::Application
{
public:
///////////////////////////////////////////////////////////////////
TestTerrainApp()
: dtABC::Application("config.xml")
, mTerrainClamp(false)
, mFlyFast(false)
{
GetKeyboardListener()->SetReleasedCallback(dtCore::GenericKeyboardListener::CallbackType(this, &TestTerrainApp::KeyReleased));
}
protected:
virtual ~TestTerrainApp() {}
public:
///////////////////////////////////////////////////////////////////
void CreateTerrain()
{
// Before we load any resources, lets set our origin to correlate to the data we
// are loading.
dtCore::Transform tx;
dtTerrain::GeoCoordinates coords;
osg::Vec3d pos;
osg::Vec3 posV3;
pos = coords.GetCartesianPoint();
coords.GetCartesianPoint(posV3);
LOG_DEBUG("Raw Geo: "+coords.ToStringAll());
LOG_DEBUG(" gotPt: "+vec3dToString(pos));
LOG_DEBUG(" altPt: "+vec3ToString(posV3));
dtTerrain::GeoCoordinates origin;
dtTerrain::GeoCoordinates::GetOrigin(origin);
pos = coords.GetCartesianPoint();
coords.GetCartesianPoint(posV3);
LOG_DEBUG("Origin : "+coords.ToStringAll());
LOG_DEBUG(" gotPt: "+vec3dToString(pos));
LOG_DEBUG(" altPt: "+vec3ToString(posV3));
coords.SetLatitude(mLatitude);
coords.SetLongitude(mLongitude);
coords.SetAltitude(0.0);
pos = coords.GetCartesianPoint();
coords.GetCartesianPoint(posV3);
LOG_DEBUG("Set Geo: "+coords.ToStringAll());
LOG_DEBUG(" gotPt: "+vec3dToString(pos));
LOG_DEBUG(" atlPt: "+vec3ToString(posV3));
// Set Origin to avoid floating point round off errors
// geo <-> cartesian is done in dbl precision
// while rest of calculations are single precision
dtTerrain::GeoCoordinates::SetOrigin(coords);
coords.SetAltitude(1000.0);
coords.GetCartesianPoint(posV3);
tx.SetTranslation(posV3);
LOG_DEBUG("SetCam: "+vec3ToString(posV3));
//std::cout << "Camera Pos = " << pos.x() << ", " << pos.y() << ", " << pos.z() << std::endl;
GetCamera()->SetTransform(tx);
// Set up a motion model so we can move the camera
mMotionModel = new dtCore::FlyMotionModel(GetKeyboard(), GetMouse());
mMotionModel->SetMaximumFlySpeed(1200.0f);
mMotionModel->SetTarget(GetCamera());
GetCamera()->GetOSGCamera()->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
GetCamera()->SetPerspectiveParams(60.0f, 1.33, 1, 120000.0f);
GetCamera()->SetProjectionResizePolicy(osg::Camera::HORIZONTAL);
// Create our terrain and add a reader and renderer to it.
mTerrain = new dtTerrain::Terrain();
mTerrain->SetCachePath(mCachePath);
mTerrain->AddResourcePath(mResourcePath);
// Create the terrain reader...
dtTerrain::DTEDTerrainReader* reader = new dtTerrain::DTEDTerrainReader();
switch (mDTEDLevel)
{
case 0:
reader->SetDTEDLevel(dtTerrain::DTEDTerrainReader::DTEDLevelEnum::ZERO);
break;
case 1:
reader->SetDTEDLevel(dtTerrain::DTEDTerrainReader::DTEDLevelEnum::ONE);
break;
case 2:
reader->SetDTEDLevel(dtTerrain::DTEDTerrainReader::DTEDLevelEnum::TWO);
break;
default:
std::cout << "Unsupported DTED level." << std::endl;
exit(1);
};
//Create the terrain renderer...
mRenderer = new dtTerrain::SoarXTerrainRenderer();
//Connect our reader and renderer to the terrain.
mTerrain->SetDataReader(reader);
mTerrain->SetDataRenderer(mRenderer.get());
//Add a decorator to generate a base texture for the terrain.
mColorMapDecorator = new dtTerrain::ColorMapDecorator();
mTerrain->AddDecorationLayer(mColorMapDecorator.get());
// Add the vegetation decorator layer if enabled.
if (mEnableVegetation)
{
mLCCType = CreateLCCType();
mVeg = new dtTerrain::VegetationDecorator;
// Add the LCCTypes
mVeg->SetLCCTypes(mLCCType);
mVeg->GetLCCAnalyzer().SetOutputDebugImages(true);
// Configure the vegetation
mVeg->SetRandomSeed(27);
mVeg->SetVegetationDistance(14000.0f);
mVeg->SetMaxVegetationPerCell(2200);
//mVeg->SetLoadDistance(15000.0f);
// Add Geospecific Dataset
mVeg->SetGeospecificImage(mGeospecificPath);
// Add the vegetation decoration layer to our terrain
mTerrain->AddDecorationLayer(mVeg.get());
}
if (!mGeoDrapePath.empty())
{
//Create a decorator used to drape a geotiff over the terrain.
dtTerrain::GeoTiffDecorator* geoTiffDecorator = new dtTerrain::GeoTiffDecorator();
geoTiffDecorator->AddGeoSpecificImage(mGeoDrapePath);
mTerrain->AddDecorationLayer(geoTiffDecorator);
}
dtABC::Weather* weather = new dtABC::Weather();
weather->SetTheme(dtABC::Weather::THEME_FAIR);
mEnvironment = weather->GetEnvironment();
mEnvironment->SetDateTime(2005,3,7,14,0,0);
mEnvironment->AddChild(mTerrain.get());
mRenderer->SetEnableFog(true);
GetScene()->AddDrawable(mEnvironment.get());
}
///////////////////////////////////////////////////////////////////
std::vector<dtTerrain::LCCType> CreateLCCType()
{
std::vector<dtTerrain::LCCType> LCCType;
dtTerrain::LCCType water(11,"water");
water.SetRGB(110,130,177);
// The models referenced here are not distributed with the Delta3D
// example-data package due to size constraints. The code remains
// here as an example of how to load your own models for LCCTypes.
dtTerrain::LCCType lowResidential(21,"low residential");
lowResidential.SetRGB(253,229,228);
lowResidential.SetSlope(0,20,1);
lowResidential.SetElevation(5,2000,1);
lowResidential.SetRelativeElevation(0,80,1);
lowResidential.SetAspect(255);
lowResidential.AddModel("models/house1.ive");
lowResidential.AddModel("models/house3.ive");
dtTerrain::LCCType highResidential(22,"high residential");
highResidential.SetRGB(247,178,159);
highResidential.SetSlope(0,20,1);
highResidential.SetElevation(5,2000,1);
highResidential.SetRelativeElevation(0,80,1);
highResidential.AddModel("models/house2.ive");
dtTerrain::LCCType industrial(23,"industrial");
industrial.SetRGB(157,186,0);
industrial.SetSlope(0,20,1);
industrial.SetElevation(5,2000,1);
industrial.SetRelativeElevation(0,80,1);
industrial.SetAspect(225);
industrial.AddModel("models/industry0.ive");
industrial.AddModel("models/industry1.ive");
industrial.AddModel("models/industry2.ive");
dtTerrain::LCCType deciduous(41,"deciduous");
deciduous.SetRGB(134,200,127);
deciduous.SetSlope(0,50,1);
deciduous.SetElevation(10,1280,1);
deciduous.SetRelativeElevation(15,73,1);
deciduous.SetAspect(225);
deciduous.AddModel("models/Maple_silver_alone_16_1.flt/Maple_silver_alone_16_1.flt",4.0);
deciduous.AddModel("models/Maple_silver_alone_21_1.flt/Maple_silver_alone_21_1.flt",4.0);
deciduous.AddModel("models/Maple_silver_alone_32_1.flt/Maple_silver_alone_32_1.flt",4.0);
dtTerrain::LCCType evergreen(42,"evergreen");
evergreen.SetRGB(56,129,78);
evergreen.SetSlope(0,50,1);
evergreen.SetElevation(10,1400,1);
evergreen.SetRelativeElevation(15,73,1);
evergreen.SetAspect(255);
evergreen.AddModel("models/Bull_bay_25_1.flt/Bull_bay_25_1.flt",3.5);
evergreen.AddModel("models/Bull_bay_32_1.flt/Bull_bay_32_1.flt",3.5);
evergreen.AddModel("models/Bull_bay_37_1.flt/Bull_bay_37_1.flt",3.5);
dtTerrain::LCCType forest(43,"mixed forest");
forest.SetRGB(212,231,177);
forest.SetSlope(0,50,1);
forest.SetElevation(10,1280,1);
forest.SetRelativeElevation(15,73,1);
forest.SetAspect(255);
forest.AddModel("models/Grape_oregon_4_1.flt/Grape_oregon_4_1.flt",2.5);
forest.AddModel("models/Maple_silver_alone_21_1.flt/Maple_silver_alone_21_1.flt",2.5);
dtTerrain::LCCType shrubland(51,"shrubland");
shrubland.SetRGB(220,202,143);
shrubland.SetSlope(0,70,1);
shrubland.SetElevation(15,2000,1);
shrubland.SetRelativeElevation(15,73,1);
shrubland.SetAspect(255);
shrubland.AddModel("models/Grape_oregon_4_1.flt/Grape_oregon_4_1.flt",3.0);
shrubland.AddModel("models/Grape_oregon_6_1.flt/Grape_oregon_6_1.flt",3.0);
shrubland.AddModel("models/Grape_oregon_8_1.flt/Grape_oregon_8_1.flt",3.0);
LCCType.push_back(water);
//LCCType.push_back(lowResidential);
//LCCType.push_back(highResidential);
//LCCType.push_back(industrial);
LCCType.push_back(deciduous);
LCCType.push_back(evergreen);
LCCType.push_back(forest);
LCCType.push_back(shrubland);
return LCCType;
}
///////////////////////////////////////////////////////////////////
virtual bool KeyPressed(const dtCore::Keyboard* keyBoard, int key)
{
bool verdict(false);
static bool wireFrame = false;
switch (key)
{
case osgGA::GUIEventAdapter::KEY_Return:
ShowStatistics();
verdict = true;
break;
case osgGA::GUIEventAdapter::KEY_Space:
wireFrame = !wireFrame;
if (wireFrame)
{
GetScene()->SetRenderState(dtCore::Scene::FRONT_AND_BACK, dtCore::Scene::LINE);
}
else
{
GetScene()->SetRenderState(dtCore::Scene::FRONT, dtCore::Scene::FILL);
}
verdict = true;
break;
case 'g':
mTerrainClamp = !mTerrainClamp;
if (!mTerrainClamp)
{
if (mFlyFast)
{
mMotionModel->SetMaximumFlySpeed(4500);
}
else
{
mMotionModel->SetMaximumFlySpeed(1200);
}
}
else
{
mMotionModel->SetMaximumFlySpeed(128);
}
verdict = true;
break;
case 'f':
mFlyFast = true;
mMotionModel->SetMaximumFlySpeed(2500);
verdict = true;
break;
case osgGA::GUIEventAdapter::KEY_F1:
mLabel->SetActive(!mLabel->GetActive());
break;
default:
verdict = dtABC::Application::KeyPressed(keyBoard,key);
break;
}
return verdict;
}
///////////////////////////////////////////////////////////////////
virtual bool KeyReleased(const dtCore::Keyboard *keyBoard, int key)
{
bool handled(false);
switch (key)
{
case 'f':
mFlyFast = false;
mMotionModel->SetMaximumFlySpeed(1200);
handled = true;
break;
default:
break;
}
return handled;
}
///////////////////////////////////////////////////////////////////
void PreFrame(const double deltaFrameTime)
{
static const float PLAYER_HEIGHT = 32.0f;
std::ostringstream ss;
//Check for some keys and adjust the terrain rendering parameters as
//neccessary.
if (GetKeyboard()->GetKeyState('-'))
{
mRenderer->SetThreshold(float(mRenderer->GetThreshold()) - deltaFrameTime*5.0f);
ss.str("");
ss << "Threshold decreased to: " << mRenderer->GetThreshold();
LOG_INFO(ss.str());
}
if (GetKeyboard()->GetKeyState('='))
{
mRenderer->SetThreshold(float(mRenderer->GetThreshold()) + deltaFrameTime*5.0f);
ss.str("");
ss << "Threshold increased to: " << mRenderer->GetThreshold();
LOG_INFO(ss.str());
}
if (GetKeyboard()->GetKeyState(']'))
{
mRenderer->SetDetailMultiplier(float(mRenderer->GetDetailMultiplier()) - deltaFrameTime*5.0f);
ss.str("");
ss << "Detail Multiplier decreased to: " << mRenderer->GetDetailMultiplier();
LOG_INFO(ss.str());
}
if (GetKeyboard()->GetKeyState('['))
{
mRenderer->SetDetailMultiplier(float(mRenderer->GetDetailMultiplier()) + deltaFrameTime*5.0f);
ss.str("");
ss << "Detail Multiplier increased to: " << mRenderer->GetDetailMultiplier();
LOG_INFO(ss.str());
}
//Ground clamp our camera...
if (mTerrainClamp)
{
dtCore::Transform tx;
GetCamera()->GetTransform(tx);
osg::Vec3 trans;
tx.GetTranslation(trans);
trans.z() = mTerrain->GetHeight(trans.x(),trans.y()) + PLAYER_HEIGHT;
tx.SetTranslation(trans);
// GetCamera()->SetTransform(tx);
}
}
///////////////////////////////////////////////////////////////////
void ShowStatistics()
{
SetNextStatisticsType();
}
///////////////////////////////////////////////////////////////////
void SetResourcePath(const std::string& path)
{
mResourcePath = path;
}
///////////////////////////////////////////////////////////////////
void SetGeospecificPath(const std::string& path)
{
mGeospecificPath = path;
}
///////////////////////////////////////////////////////////////////
void SetGeospecificDrapePath(const std::string& path)
{
mGeoDrapePath = path;
}
///////////////////////////////////////////////////////////////////
void SetEnableVegetation(bool flag)
{
mEnableVegetation = flag;
}
///////////////////////////////////////////////////////////////////
void SetCachePath(const std::string path)
{
mCachePath = path;
}
///////////////////////////////////////////////////////////////////
void SetDTEDLevel(unsigned int level)
{
mDTEDLevel = level;
}
///////////////////////////////////////////////////////////////////
void SetLatitude(double latitude)
{
mLatitude = latitude;
}
///////////////////////////////////////////////////////////////////
void SetLongitude(double longitude)
{
mLongitude = longitude;
}
///////////////////////////////////////////////////////////////////
void CreateHelpLabel()
{
mLabel = new dtABC::LabelActor();
osg::Vec2 testSize(19.0f, 5.0f);
mLabel->SetBackSize(testSize);
mLabel->SetFontSize(0.8f);
mLabel->SetTextAlignment(dtABC::LabelActor::AlignmentEnum::LEFT_CENTER);
mLabel->SetText(CreateHelpLabelText());
mLabel->SetEnableDepthTesting(false);
mLabel->SetEnableLighting(false);
GetCamera()->AddChild(mLabel.get());
dtCore::Transform labelOffset(-17.0f, 22.5f, 10.5f, 0.0f, 90.0f, 0.0f);
mLabel->SetTransform(labelOffset, dtCore::Transformable::REL_CS);
AddDrawable(GetCamera());
}
///////////////////////////////////////////////////////////////////
std::string CreateHelpLabelText()
{
std::string testString("");
testString += "F1: Toggle Help Screen\n";
testString += "\n";
testString += "f: Hold for faster fly speed\n";
testString += "g: Toggle slow fly speed\n";
testString += "Enter: Toggle statistics\n";
testString += "Space: Toggle wireframe\n";
return testString;
}
///////////////////////////////////////////////////////////////////
private:
// Motion Model
dtCore::RefPtr<dtCore::FlyMotionModel> mMotionModel;
// Terrain
dtCore::RefPtr<dtTerrain::Terrain> mTerrain;
// Environment
dtCore::RefPtr<dtCore::Environment> mEnvironment;
// Vegetation Decorator
dtCore::RefPtr<dtTerrain::VegetationDecorator> mVeg;
// Texture decorator mapping height values to color values.
dtCore::RefPtr<dtTerrain::ColorMapDecorator> mColorMapDecorator;
dtCore::RefPtr<dtTerrain::SoarXTerrainRenderer> mRenderer;
dtCore::RefPtr<dtABC::LabelActor> mLabel;
// LCC Types
std::vector<dtTerrain::LCCType> mLCCType;
// Resource Path
std::string mResourcePath;
// Geospecific Data Path
std::string mGeospecificPath;
std::string mGeoDrapePath;
// Cache Path
std::string mCachePath;
// DTED level
unsigned int mDTEDLevel;
double mLatitude;
double mLongitude;
bool mTerrainClamp;
bool mFlyFast;
bool mSkyBoxEnable;
float mFogNear;
bool mEnableVegetation;
};
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
std::string dataPath = dtCore::GetDeltaDataPathList();
dtCore::SetDataFilePathList(dataPath + ";" +
dtCore::GetDeltaRootPath() + "/examples/data" + ";" +
dtCore::GetDeltaRootPath() + "/examples/testTerrain" + ";");
dtUtil::Log::GetInstance().SetLogLevel(dtUtil::Log::LOG_DEBUG);
dtCore::RefPtr<TestTerrainApp> app;
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc, argv);
// set up the usage document, in case we need to print out how to use this program.
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is a SOARX and GENETICS terrain demonstration application.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] value ...");
arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display command line options");
arguments.getApplicationUsage()->addCommandLineOption("-c <cachepath>","Set the cache path");
arguments.getApplicationUsage()->addCommandLineOption("-r <resourcepath>","Set the resource path");
arguments.getApplicationUsage()->addCommandLineOption("--dted <level> <latitude> <longitude>","Set the dted level, latitude and longitude");
arguments.getApplicationUsage()->addCommandLineOption("--geo <geopath>","Set file for geospecific data");
arguments.getApplicationUsage()->addCommandLineOption("--geodrape <path>","Set file for geospecific drape texture across the terrain.");
arguments.getApplicationUsage()->addCommandLineOption("--enable-vegetation","Enables the placement of LCC vegetation.");
// Handle our command line arguments
// if user request help write it out to cout.
if (arguments.read("-h") || arguments.read("--help"))
{
arguments.getApplicationUsage()->write(std::cout);
return 1;
}
int level;
double latitude;
double longitude;
std::string cachePath;
std::string resourcePath;
bool vegetation(false);
std::string geospecific;
std::string drapeImagePath;
if (arguments.argc()<=1)
{
level = 0;
latitude = 36.96;
longitude = -121.96;
cachePath = "cache";
resourcePath = "dted/level0";
vegetation = false;
geospecific = "";
}
else
{
arguments.read("-c",cachePath);
arguments.read("-r",resourcePath);
arguments.read("--dted",level,latitude,longitude);
arguments.read("--geo",geospecific);
arguments.read("--geodrape",drapeImagePath);
vegetation = arguments.read("--enable-vegetation");
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occured when parsing the program aguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
}
try
{
app = new TestTerrainApp();
app->SetCachePath(cachePath);
app->SetGeospecificPath(geospecific);
app->SetResourcePath(resourcePath);
app->SetDTEDLevel(level);
app->SetLatitude(latitude);
app->SetLongitude(longitude);
app->SetEnableVegetation(vegetation);
app->SetGeospecificDrapePath(drapeImagePath);
app->CreateTerrain();
app->CreateHelpLabel();
app->Config();
app->Run();
}
catch (dtUtil::Exception& ex)
{
std::cout << ex.What() << std::endl;
}
return 0;
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.