1
0
Fork 0

WS3.0 AirportBuilder update to use Effects.

This commit is contained in:
Stuart Buchanan 2020-07-07 13:09:34 +01:00
parent c71fc5ae73
commit 2bb15866b8
2 changed files with 139 additions and 94 deletions

View file

@ -26,21 +26,27 @@
#include <osgDB/Registry>
#include <osgUtil/Tessellator>
#include <osgUtil/DelaunayTriangulator>
#include "AirportBuilder.hxx"
#include <osg/Geode>
#include <osg/Geometry>
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include "simgear/scene/model/ModelRegistry.hxx"
#include "simgear/scene/util/OsgMath.hxx"
#include "simgear/math/SGGeodesy.hxx"
#include "airport.hxx"
#include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/math/SGGeodesy.hxx>
#include <Airports/apt_loader.hxx>
#include "airport.hxx"
#include "runways.hxx"
#include "pavement.hxx"
#include "AirportBuilder.hxx"
using namespace osg;
using namespace simgear;
namespace flightgear
{
@ -58,66 +64,76 @@ const char* AirportBuilder::className() const
return "Airport Builder";
}
osgDB::ReaderWriter::ReadResult
AirportBuilder::readNode(const std::string& fileName,
const osgDB::Options* options) const
osgDB::ReaderWriter::ReadResult AirportBuilder::readNode(const std::string& fileName,
const osgDB::Options* options) const
{
const SGPath aptFile = SGPath(fileName);
const string airportId = aptFile.file_base();
SGPath aptFile = SGPath(fileName);
if (! aptFile.isFile()) {
// Search for the file if we don't have a full path.
auto pathList = options->getDatabasePathList();
for(auto itr = pathList.begin(); itr != pathList.end(); ++itr) {
aptFile = SGPath(*itr, fileName);
if (aptFile.isFile()) break;
}
}
if (! aptFile.isFile()) return ReadResult::FILE_NOT_HANDLED;;
const string airportId = aptFile.file_base();
APTLoader aptLoader;
const FGAirport* airport = aptLoader.loadAirportFromFile(airportId, aptFile);
if (! airport) return ReadResult::FILE_NOT_HANDLED;;
if (! airport) return ReadResult::FILE_NOT_HANDLED;
std::cout << "AirportBuilder, building airport : " << airportId << " " << airport->getName() << "\n";
std::cout << "Elevation : " << airport->getElevation() << "ft\n";
std::cout << "Latitude : " << airport->getLatitude() << "ft\n";
std::cout << "Longitude : " << airport->getLongitude() << "ft\n";
std::cout << "Runways : " << airport->numRunways() << "\n";
std::cout << "Helipads : " << airport->numHelipads() << "\n";
std::cout << "Taxiways : " << airport->numTaxiways() << "\n";
std::cout << "Pavements : " << airport->numPavements() << "\n";
std::cout << "Line Features : " << airport->numLineFeatures() << "\n";
SG_LOG( SG_GENERAL, SG_DEBUG, "Building airport : " << airportId << " " << airport->getName());
SG_LOG( SG_GENERAL, SG_DEBUG, "Lat/Lon : " << airport->getLatitude() << ", " << airport->getLongitude());
SG_LOG( SG_GENERAL, SG_DEBUG, "Elevation : " << airport->getElevation());
SG_LOG( SG_GENERAL, SG_DEBUG, "Runways : " << airport->numRunways());
SG_LOG( SG_GENERAL, SG_DEBUG, "Helipads : " << airport->numHelipads());
SG_LOG( SG_GENERAL, SG_DEBUG, "Taxiways : " << airport->numTaxiways());
SG_LOG( SG_GENERAL, SG_DEBUG, "Pavements : " << airport->numPavements());
SG_LOG( SG_GENERAL, SG_DEBUG, "Line Features : " << airport->numLineFeatures());
const SGVec3f center = SGVec3f::fromGeod(airport->geod());
const SGVec3f offset = SGVec3f::fromGeod(SGGeod::fromGeodM(airport->geod(), airport->geod().getElevationM() + 1.0));
const osg::Vec3f up = osg::Vec3f(toOsg(offset - center));
// Create a matrix operation that will center the airport facing the z axis
// We cannot also perform the translate to the center of the airport as we
// hit floating point precision issues, so we do that separately.
osg::Matrixd mat = osg::Matrix(toOsg(SGQuatd::fromLonLat(airport->geod())));
mat.preMultRotate(osg::Quat(0.0, 1.0, 0.0, 0.0));
std::vector<osg::Node*> nodeList;
osg::Group* group = new osg::Group();
// Build the various components
auto runwaylist = airport->getRunways();
std::for_each( runwaylist.begin(),
runwaylist.end(),
[&, center] (FGRunwayRef p) { group->addChild(this->createRunway(center, up, p)); } );
// Build the pavements
auto pavementlist = airport->getPavements();
std::for_each( pavementlist.begin(),
pavementlist.end(),
[&, center, up] (FGPavementRef p) { group->addChild(this->createPavement(center, up, p)); } );
// Build the boundary
auto boundaryList = airport->getBoundary();
std::for_each( boundaryList.begin(),
boundaryList.end(),
[&, center] (FGPavementRef p) { group->addChild(this->createBoundary(center, up, p)); } );
[&, mat, center, options] (FGPavementRef p) { group->addChild(this->createBoundary(mat, center, p, options)); } );
// Build the pavements
auto pavementlist = airport->getPavements();
std::for_each( pavementlist.begin(),
pavementlist.end(),
[&, mat, center, options] (FGPavementRef p) { group->addChild(this->createPavement(mat, center, p, options)); } );
// Build the runways
auto runwaylist = airport->getRunways();
std::for_each( runwaylist.begin(),
runwaylist.end(),
[&, mat, center, options] (FGRunwayRef p) { group->addChild(this->createRunway(mat, center, p, options)); } );
// Build line features
auto lineList = airport->getLineFeatures();
std::for_each( lineList.begin(),
lineList.end(),
[&, center] (FGPavementRef p) { group->addChild(this->createLine(center, up, p)); } );
[&, mat, center, options] (FGPavementRef p) { group->addChild(this->createLine(mat, center, p, options)); } );
return group;
}
osg::Node* AirportBuilder::createRunway(const SGVec3f center, const osg::Vec3f up, const FGRunwayRef runway) const
osg::Node* AirportBuilder::createRunway(const osg::Matrixd mat, const SGVec3f center, const FGRunwayRef runway, const osgDB::Options* options) const
{
std::vector<SGGeod> nodes;
nodes.push_back(runway->pointOffCenterline(0.0, -0.5 * runway->widthM()));
@ -130,7 +146,9 @@ osg::Node* AirportBuilder::createRunway(const SGVec3f center, const osg::Vec3f u
std::transform( nodes.begin(),
nodes.end(),
std::back_inserter(*points),
[center](SGGeod n) { return toOsg(SGVec3f::fromGeod(SGGeod::fromGeodM(n, n.getElevationM() + RUNWAY_OFFSET)) - center); }
[mat, center](SGGeod n) {
return mat * toOsg(SGVec3f::fromGeod(n) - center) + osg::Vec3f(0,0, RUNWAY_OFFSET);
}
);
osg::ref_ptr<osgUtil::DelaunayTriangulator> triangulator = new osgUtil::DelaunayTriangulator;
@ -142,26 +160,26 @@ osg::Node* AirportBuilder::createRunway(const SGVec3f center, const osg::Vec3f u
geometry->addPrimitiveSet(triangulator->getTriangles()); // triangles with constraint cut
osg::Vec3Array* n = new osg::Vec3Array;
n->push_back(up);
n->push_back(osg::Vec3f(0.0f, 0.0f, 1.0f));
osg::Vec4Array* c = new osg::Vec4Array;
c->push_back(osg::Vec4f(0.2f,0.2f,0.2f,1.0f));
c->push_back(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
geometry->setColorArray(c, osg::Array::BIND_OVERALL);
geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
simgear::EffectGeode* geode = new simgear::EffectGeode;
EffectGeode* geode = new EffectGeode;
ref_ptr<Effect> effect = getMaterialEffect("pa_rest", options);
geode->setEffect(effect.get());
geode->addDrawable(geometry);
//geode->setEffect(_effect.get());
return geode;
}
osg::Node* AirportBuilder::createPavement(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const
osg::Node* AirportBuilder::createPavement(const osg::Matrixd mat, const SGVec3f center, const FGPavementRef pavement, const osgDB::Options* options) const
{
const FGPavement::NodeList nodes = pavement->getNodeList();
if (nodes.size() == 0) return NULL;
if (nodes.size() < 2) return NULL;
osg::ref_ptr<osgUtil::Tessellator> tessellator = new osgUtil::Tessellator;
tessellator->setBoundaryOnly(false);
@ -169,7 +187,7 @@ osg::Node* AirportBuilder::createPavement(const SGVec3f center, const osg::Vec3f
tessellator->beginContour();
// Track the previous vertex for bezier curve generation.
osg::Vec3f* previous;
osg::Vec3f* previous = NULL;
// Bezier control. Bezier curve is node n-1 -> n -> n+1 so need to store for
// handling the next node in addition to generating for the BezierNode itself.
@ -180,19 +198,18 @@ osg::Node* AirportBuilder::createPavement(const SGVec3f center, const osg::Vec3f
for (; itr < nodes.end(); ++itr) {
FGPavement::NodeBase* node = *itr;
// Create an offset so we can easily layer the boundary, pavement, lights and runways
SGGeod offset = SGGeod::fromGeodM(node->mPos, node->mPos.getElevationM() + PAVEMENT_OFFSET);
osg::Vec3f* v = new osg::Vec3f(toOsg(SGVec3f::fromGeod(offset) - center));
osg::Vec3f* v = new osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(node->mPos) - center) + osg::Vec3f(0,0, PAVEMENT_OFFSET));
if (FGPavement::BezierNode *bez = dynamic_cast<FGPavement::BezierNode*>(node)) {
// Store the bezier control node for generation when we know the next node.
SGGeod controlGeod = SGGeod::fromGeodM(bez->mControl, bez->mControl.getElevationM() + PAVEMENT_OFFSET);
control = osg::Vec3f(toOsg(SGVec3f::fromGeod(controlGeod) - center));
control = mat * toOsg(SGVec3f::fromGeod(bez->mControl) - center) + osg::Vec3f(0,0, PAVEMENT_OFFSET);
bezier = true;
// Generate from the last node to this one, reflecting the control point
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = *previous;
osg::Vec3f p0 = osg::Vec3f();
if (previous != NULL) p0 = *previous;
osg::Vec3f p1 = *v + *v - control;
osg::Vec3f p2 = *v;
@ -225,8 +242,6 @@ osg::Node* AirportBuilder::createPavement(const SGVec3f center, const osg::Vec3f
// SimpleNode
tessellator->addVertex(v);
}
previous = v;
if (node->mClose) {
tessellator->endContour();
@ -242,6 +257,8 @@ osg::Node* AirportBuilder::createPavement(const SGVec3f center, const osg::Vec3f
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
auto primList = tessellator->getPrimList();
osg::Vec3Array* points = new osg::Vec3Array();
osg::Vec3Array* normals = new osg::Vec3Array();
osg::Vec2Array* texCoords = new osg::Vec2Array();
geometry->setVertexArray(points);
unsigned int idx = 0;
auto primItr = primList.begin();
@ -249,30 +266,33 @@ osg::Node* AirportBuilder::createPavement(const SGVec3f center, const osg::Vec3f
auto vertices = (*primItr)->_vertices;
std::for_each( vertices.begin(),
vertices.end(),
[points](auto v) { points->push_back(*v); }
[points, texCoords, normals](auto v) {
points->push_back(*v);
texCoords->push_back(osg::Vec2f(v->x(), v->y()));
normals->push_back(osg::Vec3f(0.0, 0.0, 1.0));
}
);
geometry->addPrimitiveSet(new osg::DrawArrays((*primItr)->_mode, idx, vertices.size()));
idx += vertices.size();
}
osg::Vec3Array* n = new osg::Vec3Array;
n->push_back(up);
osg::Vec4Array* c = new osg::Vec4Array;
c->push_back(osg::Vec4f(0.5f, 0.5f, 0.5f, 1.0f));
c->push_back(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
geometry->setColorArray(c, osg::Array::BIND_OVERALL);
geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
geometry->setTexCoordArray(0, texCoords, osg::Array::BIND_PER_VERTEX);
simgear::EffectGeode* geode = new simgear::EffectGeode;
EffectGeode* geode = new EffectGeode;
ref_ptr<Effect> effect = getMaterialEffect("Asphalt", options);
geode->setEffect(effect.get());
geode->addDrawable(geometry);
//geode->setEffect(_effect.get());
return geode;
}
osg::Node* AirportBuilder::createBoundary(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const
osg::Node* AirportBuilder::createBoundary(const osg::Matrixd mat, const SGVec3f center, const FGPavementRef pavement, const osgDB::Options* options) const
{
const FGPavement::NodeList nodes = pavement->getNodeList();
@ -284,31 +304,28 @@ osg::Node* AirportBuilder::createBoundary(const SGVec3f center, const osg::Vec3f
tessellator->beginContour();
// Track the previous vertex for bezier curve generation.
osg::Vec3f* previous;
osg::Vec3f* previous = NULL;
// Bezier control. Bezier curve is node n-1 -> n -> n+1 so need to store for
// handling the next node in addition to generating for the BezierNode itself.
bool bezier = false;
osg::Vec3f control;
auto itr = nodes.begin();
for (; itr < nodes.end(); ++itr) {
FGPavement::NodeBase* node = *itr;
// Create an offset so we can easily layer the boundary, pavement, lights and runways
SGGeod offset = SGGeod::fromGeodM(node->mPos, node->mPos.getElevationM() + BOUNDARY_OFFSET);
osg::Vec3f* v = new osg::Vec3f(toOsg(SGVec3f::fromGeod(offset) - center));
osg::Vec3f* v = new osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(node->mPos) - center) + osg::Vec3f(0,0, BOUNDARY_OFFSET));
if (FGPavement::BezierNode *bez = dynamic_cast<FGPavement::BezierNode*>(node)) {
// Store the bezier control node for generation when we know the next node.
SGGeod controlGeod = SGGeod::fromGeodM(bez->mControl, bez->mControl.getElevationM() + BOUNDARY_OFFSET);
control = osg::Vec3f(toOsg(SGVec3f::fromGeod(controlGeod) - center));
control = osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(bez->mControl) - center) + osg::Vec3f(0,0, BOUNDARY_OFFSET));
bezier = true;
// Generate from the last node to this one, reflecting the control point
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = *previous;
osg::Vec3f p0 = osg::Vec3f();
if (previous != NULL) p0 = *previous;
osg::Vec3f p1 = *v + *v - control;
osg::Vec3f p2 = *v;
@ -371,22 +388,23 @@ osg::Node* AirportBuilder::createBoundary(const SGVec3f center, const osg::Vec3f
}
osg::Vec3Array* n = new osg::Vec3Array;
n->push_back(up);
n->push_back(osg::Vec3f(0.0, 0.0, 1.0));
osg::Vec4Array* c = new osg::Vec4Array;
c->push_back(osg::Vec4f(0.3f, 0.7f, 0.3f, 1.0f));
c->push_back(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
geometry->setColorArray(c, osg::Array::BIND_OVERALL);
geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
simgear::EffectGeode* geode = new simgear::EffectGeode;
EffectGeode* geode = new EffectGeode;
ref_ptr<Effect> effect = getMaterialEffect("Default", options);
geode->setEffect(effect.get());
geode->addDrawable(geometry);
//geode->setEffect(_effect.get());
return geode;
}
osg::Node* AirportBuilder::createLine(const SGVec3f center, const osg::Vec3f up, const FGPavementRef line) const
osg::Node* AirportBuilder::createLine(const osg::Matrixd mat, const SGVec3f center, const FGPavementRef line, const osgDB::Options* options) const
{
const FGPavement::NodeList nodes = line->getNodeList();
@ -414,7 +432,7 @@ osg::Node* AirportBuilder::createLine(const SGVec3f center, const osg::Vec3f up,
geometry->setVertexArray(points);
osg::Vec3Array* n = new osg::Vec3Array;
n->push_back(up);
n->push_back(osg::Vec3f(0.0, 0.0, 1.0));
geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
osg::Vec4Array* c = new osg::Vec4Array;
@ -423,17 +441,13 @@ osg::Node* AirportBuilder::createLine(const SGVec3f center, const osg::Vec3f up,
auto itr = nodes.begin();
for (; itr < nodes.end(); ++itr) {
FGPavement::NodeBase* node = *itr;
// Create an offset so we can easily layer the boundary, pavement, lights and runways
SGGeod offset = SGGeod::fromGeodM(node->mPos, node->mPos.getElevationM() + MARKING_OFFSET);
osg::Vec3f v = osg::Vec3f(toOsg(SGVec3f::fromGeod(offset) - center));
osg::Vec3f v = osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(node->mPos) - center) + osg::Vec3f(0,0, MARKING_OFFSET));
if (node->mPaintCode != 0) paintCode = node->mPaintCode;
if (FGPavement::BezierNode *bez = dynamic_cast<FGPavement::BezierNode*>(node)) {
// Store the bezier control node for generation when we know the next node.
SGGeod controlGeod = SGGeod::fromGeodM(bez->mControl, bez->mControl.getElevationM() + MARKING_OFFSET);
control = osg::Vec3f(toOsg(SGVec3f::fromGeod(controlGeod) - center));
control = osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(bez->mControl) - center) + osg::Vec3f(0,0, MARKING_OFFSET));
bezier = true;
// Generate from the last node to this one, reflecting the control point
@ -517,14 +531,20 @@ osg::Node* AirportBuilder::createLine(const SGVec3f center, const osg::Vec3f up,
}
}
simgear::EffectGeode* geode = new simgear::EffectGeode;
// We should be using different Effects for different lines, and/or
// parameterizing a single Effect to encode some line type information so
// we can use a single Effect for all lines.
EffectGeode* geode = new EffectGeode;
ref_ptr<Effect> effect = getMaterialEffect("lf_sng_solid_yellow", options);
geode->setEffect(effect.get());
geode->addDrawable(geometry);
//geode->setEffect(_effect.get());
return geode;
}
osg::Vec4f AirportBuilder::getLineColor(const int aPaintCode) const {
osg::Vec4f AirportBuilder::getLineColor(const int aPaintCode) const
{
if (aPaintCode == 1) return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f); // Solid yellow
if (aPaintCode == 2) return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f); // Broken yellow
if (aPaintCode == 3) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Double yellow
@ -550,9 +570,32 @@ osg::Vec4f AirportBuilder::getLineColor(const int aPaintCode) const {
if (aPaintCode == 21) return osg::Vec4f(0.7f, 0.7f, 0.7f, 1.0f); // White chequerboard
if (aPaintCode == 22) return osg::Vec4f(0.6f, 0.6f, 0.6f, 1.0f); // Broken white line
//std::cout << "Unknown line colour " << aPaintCode << "\n";
return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f); // Default (probably an error), so red
}
osg::ref_ptr<Effect> AirportBuilder::getMaterialEffect(std::string material, const osgDB::Options* options) const
{
ref_ptr<Effect> effect;
SGPropertyNode_ptr effectProp = new SGPropertyNode();
osg::ref_ptr<SGReaderWriterOptions> sgOpts(SGReaderWriterOptions::copyOrCreate(options));
if (sgOpts->getMaterialLib()) {
const SGGeod loc = SGGeod(sgOpts->getLocation());
SGMaterialCache* matcache = sgOpts->getMaterialLib()->generateMatCache(loc);
SGMaterial* mat = matcache->find(material);
delete matcache;
if (mat) {
return mat->get_effect();
}
}
SG_LOG( SG_TERRAIN, SG_ALERT, "Unable to get effect for " << material);
makeChild(effectProp, "inherits-from")->setStringValue("Effects/model-default");
effectProp->addChild("default")->setBoolValue(true);
effect = makeEffect(effectProp, true, sgOpts);
return effect;
}

View file

@ -22,6 +22,8 @@
// $Id$
#include <osgDB/Registry>
#include "airport.hxx"
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
namespace flightgear
{
@ -48,12 +50,12 @@ public:
private:
osg::Node* createAirport(const std::string airportId) const;
osg::Node* createRunway(const SGVec3f center, const osg::Vec3f up, const FGRunwayRef runway) const;
osg::Node* createPavement(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const;
osg::Node* createBoundary(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const;
osg::Node* createLine(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const;
osg::Node* createRunway(const osg::Matrixd mat, const SGVec3f center, const FGRunwayRef runway, const osgDB::Options* options) const;
osg::Node* createPavement(const osg::Matrixd mat, const SGVec3f center, const FGPavementRef pavement, const osgDB::Options* options) const;
osg::Node* createBoundary(const osg::Matrixd mat, const SGVec3f center, const FGPavementRef pavement, const osgDB::Options* options) const;
osg::Node* createLine(const osg::Matrixd mat, const SGVec3f center, const FGPavementRef pavement, const osgDB::Options* options) const;
osg::Vec4f getLineColor(const int aPaintCode) const;
osg::ref_ptr<simgear::Effect> getMaterialEffect(std::string material, const osgDB::Options* options) const;
};
}