From 460a666234af17381afec467f65f8b26f13c1d69 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sun, 18 Nov 2018 21:08:06 +0000 Subject: [PATCH] STG-defined buildings using Random Building shader Support BUILDING_LIST STG verb which references a file containing the cartesian coordinates of individual buildings, to be generated using the random-building shader approach. BUILDING_LIST buildings.txt OSM_Building -2.72943543 56.00080606 36.1 0 buildings.txt: 0 0 0 0 0 0 100 0 0 0 0 200 0 0 0 0 300 0 0 1 0 400 0 0 1 0 500 0 0 2 100 0 0 0 2 200 0 0 0 2 300 0 0 0 2 400 0 0 15 2 --- simgear/scene/tgdb/ReaderWriterSTG.cxx | 49 ++++++++++++++++++-- simgear/scene/tgdb/SGBuildingBin.cxx | 62 +++++++++++++++++++++++--- simgear/scene/tgdb/SGBuildingBin.hxx | 5 ++- simgear/scene/tgdb/TreeBin.cxx | 4 +- 4 files changed, 109 insertions(+), 11 deletions(-) diff --git a/simgear/scene/tgdb/ReaderWriterSTG.cxx b/simgear/scene/tgdb/ReaderWriterSTG.cxx index 0418d710..46f73ba9 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.cxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.cxx @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include "SGOceanTile.hxx" @@ -59,6 +61,7 @@ #define ROAD_DETAILED "OBJECT_ROAD_DETAILED" #define RAILWAY_ROUGH "OBJECT_RAILWAY_ROUGH" #define RAILWAY_DETAILED "OBJECT_RAILWAY_DETAILED" +#define BUILDING_LIST "BUILDING_LIST" namespace simgear { @@ -121,6 +124,12 @@ struct ReaderWriterSTG::_ModelBin { double _hdg; int _size; }; + struct _BuildingList { + _BuildingList() : _lon(0), _lat(0), _elev(0) { } + std::string _filename; + std::string _material_name; + double _lon, _lat, _elev; + }; class DelayLoadReadFileCallback : public OptionsReadFileCallback { @@ -185,8 +194,6 @@ struct ReaderWriterSTG::_ModelBin { }; typedef QuadTreeBuilder STGObjectsQuadtree; - - public: virtual osgDB::ReaderWriter::ReadResult readNode(const std::string&, const osgDB::Options*) @@ -203,12 +210,40 @@ struct ReaderWriterSTG::_ModelBin { if (signBuilder.getSignsGroup()) group->addChild(signBuilder.getSignsGroup()); + if (_buildingList.size() > 0) { + SGMaterialLibPtr matlib = _options->getMaterialLib(); + bool useVBOs = (_options->getPluginStringData("SimGear::USE_VBOS") == "ON"); + + if (!matlib) { + SG_LOG( SG_TERRAIN, SG_ALERT, "Unable to get materials definition for buildings"); + } else { + for (std::list<_BuildingList>::iterator i = _buildingList.begin(); i != _buildingList.end(); ++i) { + // Build buildings for each list of buildings + SGGeod geodPos = SGGeod::fromDegM(i->_lon, i->_lat, 0.0); + SGMaterial* mat = matlib->find(i->_material_name, geodPos); + SGPath path = SGPath(i->_filename); + SGBuildingBin* buildingBin = new SGBuildingBin(path, mat, useVBOs); + + SGBuildingBinList buildingBinList; + buildingBinList.push_back(buildingBin); + + osg::MatrixTransform* matrixTransform; + matrixTransform = new osg::MatrixTransform(makeZUpFrame(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev))); + matrixTransform->setName("rotateBuildings"); + matrixTransform->setDataVariance(osg::Object::STATIC); + matrixTransform->addChild(createRandomBuildings(buildingBinList, osg::Matrix::identity(), _options)); + group->addChild(matrixTransform); + } + } + } + return group.release(); } mt _seed; std::list<_ObjectStatic> _objectStaticList; std::list<_Sign> _signList; + std::list<_BuildingList> _buildingList; /// The original options to use for this bunch of models osg::ref_ptr _options; @@ -315,7 +350,6 @@ struct ReaderWriterSTG::_ModelBin { // starting with 2018.3 we will use deltas rather than absolutes as it is more intuitive for the user // and somewhat easier to visualise - double detailedRange = atof(options->getPluginStringData("SimGear::LOD_RANGE_DETAILED").c_str()); double bareRangeDelta = atof(options->getPluginStringData("SimGear::LOD_RANGE_BARE").c_str()); double roughRangeDelta = atof(options->getPluginStringData("SimGear::LOD_RANGE_ROUGH").c_str()); @@ -490,6 +524,13 @@ struct ReaderWriterSTG::_ModelBin { obj._options = opt; checkInsideBucket(absoluteFileName, obj._lon, obj._lat); _objectStaticList.push_back(obj); + } else if (token == BUILDING_LIST) { + _BuildingList buildinglist; + buildinglist._filename = path.local8BitStr(); + 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 { SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName << ": Unknown token '" << token << "'" ); @@ -560,6 +601,7 @@ struct ReaderWriterSTG::_ModelBin { // we just need to know about the read file callback that itself holds the data osg::ref_ptr readFileCallback = new DelayLoadReadFileCallback; readFileCallback->_objectStaticList = _objectStaticList; + readFileCallback->_buildingList = _buildingListList; readFileCallback->_signList = _signList; readFileCallback->_options = options; readFileCallback->_bucket = bucket; @@ -584,6 +626,7 @@ struct ReaderWriterSTG::_ModelBin { std::list<_Object> _objectList; std::list<_ObjectStatic> _objectStaticList; std::list<_Sign> _signList; + std::list<_BuildingList> _buildingListList; }; ReaderWriterSTG::ReaderWriterSTG() diff --git a/simgear/scene/tgdb/SGBuildingBin.cxx b/simgear/scene/tgdb/SGBuildingBin.cxx index 22055845..10158a5d 100644 --- a/simgear/scene/tgdb/SGBuildingBin.cxx +++ b/simgear/scene/tgdb/SGBuildingBin.cxx @@ -44,12 +44,11 @@ #include #include +#include #include #include #include #include -#include -#include #include #include @@ -107,6 +106,59 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const return bb; } + // Set up a BuildingBin from a file containing a list of individual building + // positions. + SGBuildingBin::SGBuildingBin(const SGPath& absoluteFileName, const SGMaterial *mat, bool useVBOs) : + SGBuildingBin::SGBuildingBin(mat, useVBOs) + { + if (!absoluteFileName.exists()) { + SG_LOG(SG_TERRAIN, SG_ALERT, "Building 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 << " does not exist."); + return; + } + + while (!stream.eof()) { + // read a line. Each line defines a single builing 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 R T + // where: + // X,Y,Z are the cartesian coordinates of the bottom SW corner of the building. +X is East, +Y is North + // R is the building rotation in degrees centered on the SW corner + // T is the building type [0, 1, 2] for SMALL, MEDIUM, LARGE + float x, y, z, r; + int t; + in >> x >> y >> z >> r >> t; + + //SG_LOG(SG_TERRAIN, SG_ALERT, "Building entry " << x << " " << y << " " << z << " " << t ); + SGVec3f p = SGVec3f(x,y,z); + BuildingType type = BuildingType::SMALL; + if (t == 1) type = BuildingType::MEDIUM; + if (t == 2) type = BuildingType::LARGE; + + // Rotation is in the file as degrees, but in the datastructure normalized + // to 0.0 - 1.0 + insert(p, (float) (r / 360.0f), type); + } + + stream.close(); + }; + // Set up the building set based on the material definitions SGBuildingBin::SGBuildingBin(const SGMaterial *mat, bool useVBOs) { @@ -165,7 +217,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const if (useVBOs) { sharedGeometry->setUseVertexBufferObjects(true); } - + for (unsigned int j = 0; j < BUILDING_SET_SIZE; j++) { float width; float depth; @@ -820,8 +872,8 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const }; // This actually returns a MatrixTransform node. If we rotate the whole - // forest into the local Z-up coordinate system we can reuse the - // primitive building geometry for all the forests of the same type. + // set of buildings into the local Z-up coordinate system we can reuse the + // primitive building geometry for all the buildings of the same type. osg::Group* createRandomBuildings(SGBuildingBinList& buildings, const osg::Matrix& transform, const SGReaderWriterOptions* options) { diff --git a/simgear/scene/tgdb/SGBuildingBin.hxx b/simgear/scene/tgdb/SGBuildingBin.hxx index 7124673d..d6774ca0 100644 --- a/simgear/scene/tgdb/SGBuildingBin.hxx +++ b/simgear/scene/tgdb/SGBuildingBin.hxx @@ -36,10 +36,12 @@ #include #include - #include #include +#include +#include + #include #include #include @@ -169,6 +171,7 @@ private: public: SGBuildingBin(const SGMaterial *mat, bool useVBOs); + SGBuildingBin(const SGPath& absoluteFileName, const SGMaterial *mat, bool useVBOs); ~SGBuildingBin() { smallBuildings.clear(); diff --git a/simgear/scene/tgdb/TreeBin.cxx b/simgear/scene/tgdb/TreeBin.cxx index 194a15be..7befc6a5 100644 --- a/simgear/scene/tgdb/TreeBin.cxx +++ b/simgear/scene/tgdb/TreeBin.cxx @@ -230,9 +230,9 @@ void addTreeToLeafGeode(Geode* geode, const SGVec3f& p, const SGVec3f& t) posArray->insert(posArray->end(), 4, pos); size_t numVerts = posArray->size(); - int imax = 2; + unsigned int imax = 2; if (use_tree_shadows) { imax = 3; } - for (int i = 0; i < imax; ++i) { + for (unsigned int i = 0; i < imax; ++i) { if (i < geom->getNumPrimitiveSets()) { DrawArrays* primSet = static_cast(geom->getPrimitiveSet(i)); if (primSet != nullptr)