TREE_LIST STG verb
Add a TREE_LIST STG analogous to the existing BUILDING_LIST verb TREE_LIST <filename> <material name> <lon> <lat> <elev> where <filename> is a file containing a set of trees to generate using the defined <material name> at the given location. The referenced <filename> contains lines of the form X Y Z A B C Where: - X,Y,Z are the cartesian coordinates of the tree. +X is East, +Y is North - A,B,C is optional and represents the normal of the underlying terrain. Used for shadows. Defaults to (0,0,1)
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
#include <simgear/scene/tgdb/obj.hxx>
|
||||
#include <simgear/scene/material/matlib.hxx>
|
||||
#include <simgear/scene/tgdb/SGBuildingBin.hxx>
|
||||
#include <simgear/scene/tgdb/TreeBin.hxx>
|
||||
|
||||
#include <simgear/scene/util/SGSceneFeatures.hxx>
|
||||
|
||||
@@ -64,6 +65,7 @@
|
||||
#define RAILWAY_ROUGH "OBJECT_RAILWAY_ROUGH"
|
||||
#define RAILWAY_DETAILED "OBJECT_RAILWAY_DETAILED"
|
||||
#define BUILDING_LIST "BUILDING_LIST"
|
||||
#define TREE_LIST "TREE_LIST"
|
||||
|
||||
namespace simgear {
|
||||
|
||||
@@ -139,6 +141,13 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
std::string _material_name;
|
||||
double _lon, _lat, _elev;
|
||||
};
|
||||
struct _TreeList {
|
||||
_TreeList() : _lon(0), _lat(0), _elev(0) { }
|
||||
std::string _filename;
|
||||
std::string _material_name;
|
||||
double _lon, _lat, _elev;
|
||||
};
|
||||
|
||||
|
||||
class DelayLoadReadFileCallback : public OptionsReadFileCallback {
|
||||
|
||||
@@ -258,6 +267,45 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
}
|
||||
}
|
||||
|
||||
if (!_treeList.empty()) {
|
||||
SGMaterialLibPtr matlib = _options->getMaterialLib();
|
||||
|
||||
if (!matlib) {
|
||||
SG_LOG( SG_TERRAIN, SG_ALERT, "Unable to get materials definition for buildings");
|
||||
} else {
|
||||
for (const auto& b : _treeList) {
|
||||
// Build buildings for each list of buildings
|
||||
SGGeod geodPos = SGGeod::fromDegM(b._lon, b._lat, 0.0);
|
||||
SGSharedPtr<SGMaterial> mat = matlib->find(b._material_name, geodPos);
|
||||
|
||||
// trying to avoid crash on null material, see:
|
||||
// https://sentry.io/organizations/flightgear/issues/1867075869
|
||||
if (!mat) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Tree list specifies unknown material: " << b._filename << " " << b._material_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto path = SGPath(b._filename);
|
||||
TreeBin* treeBin = new TreeBin(path, mat);
|
||||
|
||||
SGTreeBinList treeList;
|
||||
treeList.push_back(treeBin);
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Making trees " << b._material_name);
|
||||
|
||||
osg::MatrixTransform* matrixTransform;
|
||||
matrixTransform = new osg::MatrixTransform(makeZUpFrame(SGGeod::fromDegM(b._lon, b._lat, b._elev)));
|
||||
matrixTransform->setName("rotateTrees");
|
||||
matrixTransform->setDataVariance(osg::Object::STATIC);
|
||||
matrixTransform->addChild(createForest(treeList, osg::Matrix::identity(), _options));
|
||||
group->addChild(matrixTransform);
|
||||
|
||||
std::for_each(treeList.begin(), treeList.end(), [](TreeBin* bb) {
|
||||
delete bb;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return group.release();
|
||||
}
|
||||
|
||||
@@ -265,6 +313,7 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
std::list<_ObjectStatic> _objectStaticList;
|
||||
std::list<_Sign> _signList;
|
||||
std::list<_BuildingList> _buildingList;
|
||||
std::list<_TreeList> _treeList;
|
||||
|
||||
/// The original options to use for this bunch of models
|
||||
osg::ref_ptr<SGReaderWriterOptions> _options;
|
||||
@@ -554,7 +603,12 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
in >> buildinglist._material_name >> buildinglist._lon >> buildinglist._lat >> buildinglist._elev;
|
||||
checkInsideBucket(absoluteFileName, buildinglist._lon, buildinglist._lat);
|
||||
_buildingListList.push_back(buildinglist);
|
||||
//SG_LOG(SG_TERRAIN, SG_ALERT, "Building list: " << buildinglist._filename << " " << buildinglist._material_name << " " << buildinglist._lon << " " << buildinglist._lat);
|
||||
} else if (token == TREE_LIST) {
|
||||
_TreeList treelist;
|
||||
treelist._filename = path.utf8Str();
|
||||
in >> treelist._material_name >> treelist._lon >> treelist._lat >> treelist._elev;
|
||||
checkInsideBucket(absoluteFileName, treelist._lon, treelist._lat);
|
||||
_treeListList.push_back(treelist);
|
||||
} else {
|
||||
// Check registered callback for token. Keep lock until callback completed to make sure it will not be
|
||||
// executed after a thread successfully executed removeSTGObjectHandler()
|
||||
@@ -640,7 +694,7 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
i->_elev += elevation(*terrainGroup, SGGeod::fromDeg(i->_lon, i->_lat));
|
||||
}
|
||||
|
||||
if (_objectStaticList.empty() && _signList.empty() && (_buildingListList.size() == 0)) {
|
||||
if (_objectStaticList.empty() && _signList.empty() && (_buildingListList.size() == 0) && (_treeListList.size() == 0)) {
|
||||
// The simple case, just return the terrain group
|
||||
return terrainGroup.release();
|
||||
} else {
|
||||
@@ -656,6 +710,7 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
|
||||
readFileCallback->_objectStaticList = _objectStaticList;
|
||||
readFileCallback->_buildingList = _buildingListList;
|
||||
readFileCallback->_treeList = _treeListList;
|
||||
readFileCallback->_signList = _signList;
|
||||
readFileCallback->_options = options;
|
||||
readFileCallback->_bucket = bucket;
|
||||
@@ -683,6 +738,7 @@ struct ReaderWriterSTG::_ModelBin {
|
||||
std::list<_ObjectStatic> _objectStaticList;
|
||||
std::list<_Sign> _signList;
|
||||
std::list<_BuildingList> _buildingListList;
|
||||
std::list<_TreeList> _treeListList;
|
||||
};
|
||||
|
||||
ReaderWriterSTG::ReaderWriterSTG()
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <osgDB/FileUtils>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/scene/material/Effect.hxx>
|
||||
@@ -442,5 +443,70 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform
|
||||
return mt;
|
||||
}
|
||||
|
||||
TreeBin::TreeBin(const SGMaterial *mat)
|
||||
{
|
||||
texture_varieties = mat->get_tree_varieties();
|
||||
range = mat->get_tree_range();
|
||||
height = mat->get_tree_height();
|
||||
width = mat->get_tree_width();
|
||||
texture = mat->get_tree_texture();
|
||||
teffect = mat->get_tree_effect();
|
||||
};
|
||||
|
||||
|
||||
TreeBin::TreeBin(const SGPath& absoluteFileName, const SGMaterial *mat) :
|
||||
TreeBin(mat)
|
||||
{
|
||||
if (!absoluteFileName.exists()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Tree list file " << absoluteFileName << " does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
sg_gzifstream stream(absoluteFileName);
|
||||
if (!stream.is_open()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to open " << absoluteFileName);
|
||||
return;
|
||||
}
|
||||
|
||||
while (!stream.eof()) {
|
||||
// read a line. Each line defines a single tree position, and may have
|
||||
// a comment, starting with #
|
||||
std::string line;
|
||||
std::getline(stream, line);
|
||||
|
||||
// strip comments
|
||||
std::string::size_type hash_pos = line.find('#');
|
||||
if (hash_pos != std::string::npos)
|
||||
line.resize(hash_pos);
|
||||
|
||||
// and process further
|
||||
std::stringstream in(line);
|
||||
|
||||
// Line format is X Y Z A B C
|
||||
// where:
|
||||
// X,Y,Z are the cartesian coordinates of the center tree
|
||||
// A,B,C is the normal of the underlying terrain, defaulting to 0,0,1
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f, a = 0.0f, b = 0.0f, c = 1.0f;
|
||||
in >> x >> y >> z;
|
||||
|
||||
if (in.bad() || in.fail()) {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "Error parsing tree entry in: " << absoluteFileName << " line: \"" << line << "\"");
|
||||
continue;
|
||||
}
|
||||
|
||||
// these might fail, so check them after we look at failbit
|
||||
in >> a >> b >> c;
|
||||
|
||||
SGVec3f loc = SGVec3f(x,y,z);
|
||||
SGVec3f norm = SGVec3f(a,b,c);
|
||||
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Adding tree " << x << " " << y << " " << z);
|
||||
|
||||
insert(Tree(loc, norm));
|
||||
}
|
||||
|
||||
stream.close();
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ namespace simgear
|
||||
{
|
||||
class TreeBin {
|
||||
public:
|
||||
TreeBin() = default;
|
||||
TreeBin(const SGMaterial *mat);
|
||||
TreeBin(const SGPath& absoluteFileName, const SGMaterial *mat);
|
||||
|
||||
~TreeBin() = default;
|
||||
|
||||
struct Tree {
|
||||
|
||||
Reference in New Issue
Block a user