WS30: AREA_FEATURE_LIST STG verb - lakes, lochs
- Add and AREA_FEATURE_LIST STG verb. - /sim/rendering/static-lod/area-features-lod-level to control point at which such feature are rendered - /sim/rendering/static-lod/lod-leve[n]/area-features-min-width sets the minimum width for feature rendering at that LoD level. STG Format: AREA_FEATURE_LIST <file> <material> File format: Area Attrib A B C D lon0 lat0 lon1 lat1 lon2 lat2 lon3 lat4.... where: Area is the area of the feature in m^2 Attrib is an integer attribute (currently unused) A, B, C, D are generic float attributes. Their interpretation may vary by feature type lon[n], lat[n] are pairs of lon/lat defining straight road segments
This commit is contained in:
@@ -0,0 +1,109 @@
|
|||||||
|
/* -*-c++-*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Stuart Buchanan
|
||||||
|
*
|
||||||
|
* 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 <simgear_config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <osgDB/ReadFile>
|
||||||
|
#include <osgDB/FileUtils>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/io/iostreams/sgstream.hxx>
|
||||||
|
#include <simgear/math/SGGeod.hxx>
|
||||||
|
#include <simgear/scene/util/OsgMath.hxx>
|
||||||
|
|
||||||
|
#include "AreaFeatureBin.hxx"
|
||||||
|
|
||||||
|
using namespace osg;
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
|
||||||
|
AreaFeatureBin::AreaFeatureBin(const SGPath& absoluteFileName, const std::string material) :
|
||||||
|
_material(material)
|
||||||
|
{
|
||||||
|
if (!absoluteFileName.exists()) {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_ALERT, "AreaFeature 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 line feature, consisting of a width followed by a series of lon/lat positions.
|
||||||
|
// Or 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);
|
||||||
|
|
||||||
|
// Area format is Area A B C D lon0 lat0 lon1 lat1 lon2 lat2 lon3 lat4....
|
||||||
|
// where:
|
||||||
|
// Area is the area of the feature in m^2
|
||||||
|
// A, B, C, D are generic attributes. Their interpretation may vary by feature type
|
||||||
|
// lon[n], lat[n] are pairs of lon/lat defining straight road segments
|
||||||
|
int attributes = 0;
|
||||||
|
float area=0, a=0, b=0, c=0, d=0;
|
||||||
|
std::list<osg::Vec3d> nodes;
|
||||||
|
|
||||||
|
in >> area >> attributes >> a >> b >> c >> d;
|
||||||
|
|
||||||
|
if (in.bad() || in.fail()) {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_WARN, "Error parsing area entry in: " << absoluteFileName << " line: \"" << line << "\"");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
double lon = 0.0f, lat=0.0f;
|
||||||
|
in >> lon >> lat;
|
||||||
|
|
||||||
|
if (in.bad() || in.fail()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGVec3d tmp;
|
||||||
|
SGGeodesy::SGGeodToCart(SGGeod::fromDeg(lon, lat), tmp);
|
||||||
|
nodes.push_back(toOsg(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodes.size() > 2) {
|
||||||
|
insert(AreaFeature(nodes, area, attributes, a, b, c, d));
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_WARN, "AreaFeature definition with fewer than three lon/lat nodes : " << absoluteFileName << " line: \"" << line << "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/* -*-c++-*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Stuart Buchanan
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AREA_BIN_HXX
|
||||||
|
#define AREA_BIN_HXX
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <osg/Geometry>
|
||||||
|
#include <osg/Group>
|
||||||
|
#include <osg/Matrix>
|
||||||
|
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
class AreaFeatureBin {
|
||||||
|
public:
|
||||||
|
AreaFeatureBin() = default;
|
||||||
|
AreaFeatureBin(const SGPath& absoluteFileName, const std::string material);
|
||||||
|
|
||||||
|
~AreaFeatureBin() = default;
|
||||||
|
|
||||||
|
struct AreaFeature {
|
||||||
|
const std::list<osg::Vec3d> _nodes;
|
||||||
|
const float _area;
|
||||||
|
const int _attributes;
|
||||||
|
const float _a;
|
||||||
|
const float _b;
|
||||||
|
const float _c;
|
||||||
|
const float _d;
|
||||||
|
AreaFeature(const std::list<osg::Vec3d> nodes, const float area, const int attributes, const float a, const float b, const float c, const float d) :
|
||||||
|
_nodes(nodes), _area(area), _attributes(attributes), _a(a), _b(b), _c(c), _d(d)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<AreaFeature> AreaFeatureList;
|
||||||
|
|
||||||
|
void insert(const AreaFeature& t) {
|
||||||
|
_areaFeatureList.push_back(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AreaFeatureList getAreaFeatures() const {
|
||||||
|
return _areaFeatureList;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string getMaterial() const {
|
||||||
|
return _material;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AreaFeatureList _areaFeatureList;
|
||||||
|
const std::string _material;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<AreaFeatureBin> AreaFeatureBinList;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,6 +2,7 @@ include (SimGearComponent)
|
|||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
GroundLightManager.hxx
|
GroundLightManager.hxx
|
||||||
|
AreaFeatureBin.hxx
|
||||||
LineFeatureBin.hxx
|
LineFeatureBin.hxx
|
||||||
ReaderWriterSPT.hxx
|
ReaderWriterSPT.hxx
|
||||||
ReaderWriterSTG.hxx
|
ReaderWriterSTG.hxx
|
||||||
@@ -30,6 +31,7 @@ set(HEADERS
|
|||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
GroundLightManager.cxx
|
GroundLightManager.cxx
|
||||||
|
AreaFeatureBin.cxx
|
||||||
LineFeatureBin.cxx
|
LineFeatureBin.cxx
|
||||||
ReaderWriterSPT.cxx
|
ReaderWriterSPT.cxx
|
||||||
ReaderWriterSTG.cxx
|
ReaderWriterSTG.cxx
|
||||||
|
|||||||
@@ -66,9 +66,10 @@ LineFeatureBin::LineFeatureBin(const SGPath& absoluteFileName, const std::string
|
|||||||
// and process further
|
// and process further
|
||||||
std::stringstream in(line);
|
std::stringstream in(line);
|
||||||
|
|
||||||
// Line format is W A B C D lon0 lat0 lon1 lat1 lon2 lat2 lon3 lat4....
|
// Line format is W attr A B C D lon0 lat0 lon1 lat1 lon2 lat2 lon3 lat4....
|
||||||
// where:
|
// where:
|
||||||
// W is the width in m
|
// W is the width in m
|
||||||
|
// attr is an integer attribute set
|
||||||
// A, B, C, D are generic attributes. Their interpretation may vary by feature type
|
// A, B, C, D are generic attributes. Their interpretation may vary by feature type
|
||||||
// lon[n], lat[n] are pairs of lon/lat defining straight road segments
|
// lon[n], lat[n] are pairs of lon/lat defining straight road segments
|
||||||
float w = 0.0f;
|
float w = 0.0f;
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
#define BUILDING_LIST "BUILDING_LIST"
|
#define BUILDING_LIST "BUILDING_LIST"
|
||||||
#define TREE_LIST "TREE_LIST"
|
#define TREE_LIST "TREE_LIST"
|
||||||
#define LINE_FEATURE_LIST "LINE_FEATURE_LIST"
|
#define LINE_FEATURE_LIST "LINE_FEATURE_LIST"
|
||||||
|
#define AREA_FEATURE_LIST "AREA_FEATURE_LIST"
|
||||||
|
|
||||||
namespace simgear {
|
namespace simgear {
|
||||||
|
|
||||||
@@ -159,7 +160,12 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
std::string _material;
|
std::string _material;
|
||||||
SGBucket _bucket;
|
SGBucket _bucket;
|
||||||
};
|
};
|
||||||
|
struct _AreaFeatureList {
|
||||||
|
_AreaFeatureList() { }
|
||||||
|
std::string _filename;
|
||||||
|
std::string _material;
|
||||||
|
SGBucket _bucket;
|
||||||
|
};
|
||||||
|
|
||||||
class DelayLoadReadFileCallback : public OptionsReadFileCallback {
|
class DelayLoadReadFileCallback : public OptionsReadFileCallback {
|
||||||
|
|
||||||
@@ -334,6 +340,19 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
VPBTechnique::addLineFeatureList(_bucket, lineFeatures, _terrainNode);
|
VPBTechnique::addLineFeatureList(_bucket, lineFeatures, _terrainNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_areaFeatureList.empty()) {
|
||||||
|
|
||||||
|
AreaFeatureBinList areaFeatures;
|
||||||
|
|
||||||
|
for (const auto& b : _areaFeatureList) {
|
||||||
|
// add the lineFeatures to the list
|
||||||
|
const auto path = SGPath(b._filename);
|
||||||
|
areaFeatures.push_back(AreaFeatureBin(path, b._material));
|
||||||
|
}
|
||||||
|
|
||||||
|
VPBTechnique::addAreaFeatureList(_bucket, areaFeatures, _terrainNode);
|
||||||
|
}
|
||||||
|
|
||||||
return group.release();
|
return group.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,6 +362,7 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
std::list<_BuildingList> _buildingList;
|
std::list<_BuildingList> _buildingList;
|
||||||
std::list<_TreeList> _treeList;
|
std::list<_TreeList> _treeList;
|
||||||
std::list<_LineFeatureList> _lineFeatureList;
|
std::list<_LineFeatureList> _lineFeatureList;
|
||||||
|
std::list<_AreaFeatureList> _areaFeatureList;
|
||||||
osg::ref_ptr<osg::Node> _terrainNode;
|
osg::ref_ptr<osg::Node> _terrainNode;
|
||||||
|
|
||||||
/// The original options to use for this bunch of models
|
/// The original options to use for this bunch of models
|
||||||
@@ -646,6 +666,12 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
in >> lineFeaturelist._material;
|
in >> lineFeaturelist._material;
|
||||||
lineFeaturelist._bucket = bucketIndexFromFileName(absoluteFileName.file_base().c_str());
|
lineFeaturelist._bucket = bucketIndexFromFileName(absoluteFileName.file_base().c_str());
|
||||||
_lineFeatureListList.push_back(lineFeaturelist);
|
_lineFeatureListList.push_back(lineFeaturelist);
|
||||||
|
} else if (token == AREA_FEATURE_LIST) {
|
||||||
|
_AreaFeatureList areaFeaturelist;
|
||||||
|
areaFeaturelist._filename = path.utf8Str();
|
||||||
|
in >> areaFeaturelist._material;
|
||||||
|
areaFeaturelist._bucket = bucketIndexFromFileName(absoluteFileName.file_base().c_str());
|
||||||
|
_areaFeatureListList.push_back(areaFeaturelist);
|
||||||
} else {
|
} else {
|
||||||
// Check registered callback for token. Keep lock until callback completed to make sure it will not be
|
// Check registered callback for token. Keep lock until callback completed to make sure it will not be
|
||||||
// executed after a thread successfully executed removeSTGObjectHandler()
|
// executed after a thread successfully executed removeSTGObjectHandler()
|
||||||
@@ -762,7 +788,7 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
i->_elev += elevation(*terrainGroup, SGGeod::fromDeg(i->_lon, i->_lat));
|
i->_elev += elevation(*terrainGroup, SGGeod::fromDeg(i->_lon, i->_lat));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_objectStaticList.empty() && _signList.empty() && _buildingListList.empty() && _treeListList.empty() && _lineFeatureListList.empty()) {
|
if (_objectStaticList.empty() && _signList.empty() && _buildingListList.empty() && _treeListList.empty() && _lineFeatureListList.empty() && _areaFeatureListList.empty()) {
|
||||||
// The simple case, just return the terrain group
|
// The simple case, just return the terrain group
|
||||||
return terrainGroup.release();
|
return terrainGroup.release();
|
||||||
} else {
|
} else {
|
||||||
@@ -787,6 +813,7 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
|
|
||||||
if (vpb_active && vpb_node) {
|
if (vpb_active && vpb_node) {
|
||||||
readFileCallback->_lineFeatureList = _lineFeatureListList;
|
readFileCallback->_lineFeatureList = _lineFeatureListList;
|
||||||
|
readFileCallback->_areaFeatureList = _areaFeatureListList;
|
||||||
readFileCallback->_terrainNode = vpb_node;
|
readFileCallback->_terrainNode = vpb_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,6 +844,7 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
std::list<_BuildingList> _buildingListList;
|
std::list<_BuildingList> _buildingListList;
|
||||||
std::list<_TreeList> _treeListList;
|
std::list<_TreeList> _treeListList;
|
||||||
std::list<_LineFeatureList> _lineFeatureListList;
|
std::list<_LineFeatureList> _lineFeatureListList;
|
||||||
|
std::list<_AreaFeatureList> _areaFeatureListList;
|
||||||
};
|
};
|
||||||
|
|
||||||
ReaderWriterSTG::ReaderWriterSTG()
|
ReaderWriterSTG::ReaderWriterSTG()
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <osgUtil/LineSegmentIntersector>
|
#include <osgUtil/LineSegmentIntersector>
|
||||||
#include <osgUtil/IntersectionVisitor>
|
#include <osgUtil/IntersectionVisitor>
|
||||||
#include <osgUtil/MeshOptimizers>
|
#include <osgUtil/MeshOptimizers>
|
||||||
|
#include <osgUtil/Tessellator>
|
||||||
|
|
||||||
#include <osgDB/FileUtils>
|
#include <osgDB/FileUtils>
|
||||||
#include <osgDB/ReadFile>
|
#include <osgDB/ReadFile>
|
||||||
@@ -167,6 +168,7 @@ void VPBTechnique::init(int dirtyMask, bool assumeMultiThreaded)
|
|||||||
applyColorLayers(*buffer, masterLocator);
|
applyColorLayers(*buffer, masterLocator);
|
||||||
applyTrees(*buffer, masterLocator);
|
applyTrees(*buffer, masterLocator);
|
||||||
applyLineFeatures(*buffer, masterLocator);
|
applyLineFeatures(*buffer, masterLocator);
|
||||||
|
applyAreaFeatures(*buffer, masterLocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -175,6 +177,7 @@ void VPBTechnique::init(int dirtyMask, bool assumeMultiThreaded)
|
|||||||
applyColorLayers(*buffer, masterLocator);
|
applyColorLayers(*buffer, masterLocator);
|
||||||
applyTrees(*buffer, masterLocator);
|
applyTrees(*buffer, masterLocator);
|
||||||
applyLineFeatures(*buffer, masterLocator);
|
applyLineFeatures(*buffer, masterLocator);
|
||||||
|
applyAreaFeatures(*buffer, masterLocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer->_transform.valid()) buffer->_transform->setThreadSafeRefUnref(true);
|
if (buffer->_transform.valid()) buffer->_transform->setThreadSafeRefUnref(true);
|
||||||
@@ -1456,10 +1459,6 @@ void VPBTechnique::applyTrees(BufferData& buffer, Locator* masterLocator)
|
|||||||
const int land_class = int(round(tc.x() * 255.0));
|
const int land_class = int(round(tc.x() * 255.0));
|
||||||
mat = matcache->find(land_class);
|
mat = matcache->find(land_class);
|
||||||
|
|
||||||
if ((land_class == 26) || (land_class == 27)) {
|
|
||||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Placing trees for " << land_class << " " << mat->get_one_texture(0,0) << " " << mat->get_names()[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mat) {
|
if (!mat) {
|
||||||
//SG_LOG(SG_TERRAIN, SG_ALERT, "Failed to find material for landclass " << land_class << " (" << tc.r() << ")");
|
//SG_LOG(SG_TERRAIN, SG_ALERT, "Failed to find material for landclass " << land_class << " (" << tc.r() << ")");
|
||||||
continue;
|
continue;
|
||||||
@@ -1774,6 +1773,162 @@ void VPBTechnique::generateLineFeature(BufferData& buffer, Locator* masterLocato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VPBTechnique::applyAreaFeatures(BufferData& buffer, Locator* masterLocator)
|
||||||
|
{
|
||||||
|
unsigned int area_features_lod_range = 6;
|
||||||
|
float minArea = 1000.0;
|
||||||
|
|
||||||
|
const unsigned int tileLevel = _terrainTile->getTileID().level;
|
||||||
|
const SGPropertyNode* propertyNode = _options->getPropertyNode().get();
|
||||||
|
|
||||||
|
if (propertyNode) {
|
||||||
|
const SGPropertyNode* static_lod = propertyNode->getNode("/sim/rendering/static-lod");
|
||||||
|
area_features_lod_range = static_lod->getIntValue("area-features-lod-level", area_features_lod_range);
|
||||||
|
if (static_lod->getChildren("lod-level").size() > tileLevel) {
|
||||||
|
minArea = static_lod->getChildren("lod-level")[tileLevel]->getFloatValue("area-features-min-width", minArea);
|
||||||
|
minArea *= minArea;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tileLevel < area_features_lod_range) {
|
||||||
|
// Do not generate areas for tiles too far away
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SGMaterialLibPtr matlib = _options->getMaterialLib();
|
||||||
|
SGMaterial* mat = 0;
|
||||||
|
|
||||||
|
if (! matlib) {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to get materials library to generate areas");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get all appropriate areas. We assume that the VPB terrain tile is smaller than a Bucket size.
|
||||||
|
const osg::Vec3d world = buffer._transform->getMatrix().getTrans();
|
||||||
|
const SGGeod loc = SGGeod::fromCart(toSG(world));
|
||||||
|
const SGBucket bucket = SGBucket(loc);
|
||||||
|
auto areas = std::find_if(_areaFeatureLists.begin(), _areaFeatureLists.end(), [bucket](BucketAreaFeatureBinList b){return (b.first == bucket);});
|
||||||
|
|
||||||
|
if (areas == _areaFeatureLists.end()) return;
|
||||||
|
|
||||||
|
SGMaterialCache* matcache = _options->getMaterialLib()->generateMatCache(loc, _options);
|
||||||
|
|
||||||
|
for (; areas != _areaFeatureLists.end(); ++areas) {
|
||||||
|
const AreaFeatureBinList areaBins = areas->second;
|
||||||
|
|
||||||
|
for (auto rb = areaBins.begin(); rb != areaBins.end(); ++rb)
|
||||||
|
{
|
||||||
|
mat = matcache->find(rb->getMaterial());
|
||||||
|
|
||||||
|
if (!mat) {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_ALERT, "Unable to find material " << rb->getMaterial() << " at " << loc << " " << bucket);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int xsize = mat->get_xsize();
|
||||||
|
unsigned int ysize = mat->get_ysize();
|
||||||
|
|
||||||
|
// Generate a geometry for this set of areas.
|
||||||
|
osg::Vec3Array* v = new osg::Vec3Array;
|
||||||
|
osg::Vec2Array* t = new osg::Vec2Array;
|
||||||
|
osg::Vec3Array* n = new osg::Vec3Array;
|
||||||
|
osg::Vec4Array* c = new osg::Vec4Array;
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
|
||||||
|
geometry->setVertexArray(v);
|
||||||
|
geometry->setTexCoordArray(0, t, osg::Array::BIND_PER_VERTEX);
|
||||||
|
geometry->setTexCoordArray(1, t, osg::Array::BIND_PER_VERTEX);
|
||||||
|
geometry->setNormalArray(n, osg::Array::BIND_PER_VERTEX);
|
||||||
|
geometry->setColorArray(c, osg::Array::BIND_OVERALL);
|
||||||
|
geometry->setUseDisplayList( false );
|
||||||
|
geometry->setUseVertexBufferObjects( true );
|
||||||
|
|
||||||
|
auto areaFeatures = rb->getAreaFeatures();
|
||||||
|
|
||||||
|
for (auto r = areaFeatures.begin(); r != areaFeatures.end(); ++r) {
|
||||||
|
if (r->_area > minArea) generateAreaFeature(buffer, masterLocator, *r, world, geometry, v, t, n, xsize, ysize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v->size() == 0) continue;
|
||||||
|
c->push_back(osg::Vec4(1.0,1.0,1.0,1.0));
|
||||||
|
|
||||||
|
EffectGeode* geode = new EffectGeode;
|
||||||
|
geode->addDrawable(geometry);
|
||||||
|
|
||||||
|
geode->setMaterial(mat);
|
||||||
|
geode->setEffect(mat->get_one_effect(0));
|
||||||
|
geode->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) );
|
||||||
|
buffer._transform->addChild(geode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPBTechnique::generateAreaFeature(BufferData& buffer, Locator* masterLocator, AreaFeatureBin::AreaFeature area, osg::Vec3d modelCenter, osg::Geometry* geometry, osg::Vec3Array* v, osg::Vec2Array* t, osg::Vec3Array* n, unsigned int xsize, unsigned int ysize)
|
||||||
|
{
|
||||||
|
if (area._nodes.size() < 3) {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_ALERT, "Coding error - AreaFeatureBin::LineFeature with fewer than three nodes");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec3d ma;
|
||||||
|
|
||||||
|
// We're in Earth-centered coordinates, so "up" is simply directly away from (0,0,0)
|
||||||
|
osg::Vec3d up = modelCenter;
|
||||||
|
up.normalize();
|
||||||
|
|
||||||
|
osg::ref_ptr<osgUtil::Tessellator> tessellator = new osgUtil::Tessellator;
|
||||||
|
tessellator->setBoundaryOnly(false);
|
||||||
|
tessellator->setTessellationNormal(up);
|
||||||
|
tessellator->beginTessellation();
|
||||||
|
tessellator->beginContour();
|
||||||
|
|
||||||
|
// Build up the tesselator while also determining the correct elevation for the feature.
|
||||||
|
double elev = 0;
|
||||||
|
unsigned int elev_count = 0;
|
||||||
|
|
||||||
|
auto area_iter = area._nodes.begin();
|
||||||
|
osg::Vec3d pt = *area_iter - modelCenter;
|
||||||
|
ma = getMeshIntersection(buffer, masterLocator, pt, up);
|
||||||
|
|
||||||
|
// Only build this area if the first vertex is on the mesh. This ensures that the
|
||||||
|
// area is only generated once, no matter how many tiles it spans.
|
||||||
|
if (ma == pt) return;
|
||||||
|
|
||||||
|
for (; area_iter != area._nodes.end(); area_iter++) {
|
||||||
|
pt = *area_iter - modelCenter;
|
||||||
|
ma = getMeshIntersection(buffer, masterLocator, pt, up);
|
||||||
|
if (ma !=pt) {
|
||||||
|
elev += up*ma;
|
||||||
|
elev_count++;
|
||||||
|
}
|
||||||
|
tessellator->addVertex(new osg::Vec3f(*area_iter - modelCenter));
|
||||||
|
}
|
||||||
|
|
||||||
|
tessellator->endContour();
|
||||||
|
tessellator->endTessellation();
|
||||||
|
|
||||||
|
auto primList = tessellator->getPrimList();
|
||||||
|
if (primList.size() == 0) return;
|
||||||
|
|
||||||
|
unsigned int idx = 0;
|
||||||
|
|
||||||
|
auto primItr = primList.begin();
|
||||||
|
for (; primItr < primList.end(); ++ primItr) {
|
||||||
|
auto vertices = (*primItr)->_vertices;
|
||||||
|
std::for_each( vertices.begin(),
|
||||||
|
vertices.end(),
|
||||||
|
[v, t, n, up, elev, elev_count](auto vtx) {
|
||||||
|
v->push_back(*vtx + up * (elev / elev_count));
|
||||||
|
t->push_back(osg::Vec2f(vtx->x(), vtx->y()));
|
||||||
|
n->push_back(up);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
geometry->addPrimitiveSet(new osg::DrawArrays((*primItr)->_mode, idx, vertices.size()));
|
||||||
|
idx += vertices.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the intersection of a given SGGeod with the terrain mesh
|
// Find the intersection of a given SGGeod with the terrain mesh
|
||||||
osg::Vec3d VPBTechnique::getMeshIntersection(BufferData& buffer, Locator* masterLocator, osg::Vec3d pt, osg::Vec3d up)
|
osg::Vec3d VPBTechnique::getMeshIntersection(BufferData& buffer, Locator* masterLocator, osg::Vec3d pt, osg::Vec3d up)
|
||||||
{
|
{
|
||||||
@@ -1961,12 +2116,42 @@ void VPBTechnique::addLineFeatureList(SGBucket bucket, LineFeatureBinList roadLi
|
|||||||
terrainNode->accept(ftv);
|
terrainNode->accept(ftv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VPBTechnique::unloadLineFeatures(SGBucket bucket)
|
void VPBTechnique::addAreaFeatureList(SGBucket bucket, AreaFeatureBinList areaList, osg::ref_ptr<osg::Node> terrainNode)
|
||||||
|
{
|
||||||
|
if (areaList.empty()) return;
|
||||||
|
|
||||||
|
// Block to mutex the List alone
|
||||||
|
{
|
||||||
|
const std::lock_guard<std::mutex> lock(VPBTechnique::_areaFeatureLists_mutex); // Lock the _lineFeatureLists for this scope
|
||||||
|
_areaFeatureLists.push_back(std::pair(bucket, areaList));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to trigger a re-build of the appropriate Terrain tile, so create a pretend node and run the TerrainVisitor to
|
||||||
|
// "dirty" the TerrainTile that it intersects with.
|
||||||
|
osg::ref_ptr<osg::Node> n = new osg::Node();
|
||||||
|
|
||||||
|
//SGVec3d coord1, coord2;
|
||||||
|
//SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon() -0.5*bucket.get_width(), bucket.get_center_lat() -0.5*bucket.get_height(), 0.0), coord1);
|
||||||
|
//SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon() +0.5*bucket.get_width(), bucket.get_center_lat() +0.5*bucket.get_height(), 0.0), coord2);
|
||||||
|
//osg::BoundingBox bbox = osg::BoundingBox(toOsg(coord1), toOsg(coord2));
|
||||||
|
//n->setInitialBound(bbox);
|
||||||
|
|
||||||
|
SGVec3d coord;
|
||||||
|
SGGeodesy::SGGeodToCart(SGGeod::fromDegM(bucket.get_center_lon(), bucket.get_center_lat(), 0.0), coord);
|
||||||
|
n->setInitialBound(osg::BoundingSphere(toOsg(coord), max(bucket.get_width_m(), bucket.get_height_m())));
|
||||||
|
|
||||||
|
SG_LOG(SG_TERRAIN, SG_DEBUG, "Adding line features to " << bucket.gen_index_str());
|
||||||
|
TerrainVisitor ftv(n, TerrainTile::ALL_DIRTY, 0);
|
||||||
|
terrainNode->accept(ftv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VPBTechnique::unloadFeatures(SGBucket bucket)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Erasing all roads with entry " << bucket);
|
SG_LOG(SG_TERRAIN, SG_DEBUG, "Erasing all roads with entry " << bucket);
|
||||||
const std::lock_guard<std::mutex> lock(VPBTechnique::_lineFeatureLists_mutex); // Lock the _lineFeatureLists for this scope
|
const std::lock_guard<std::mutex> lock(VPBTechnique::_lineFeatureLists_mutex); // Lock the _lineFeatureLists for this scope
|
||||||
// C++ 20...
|
// C++ 20...
|
||||||
//std::erase_if(_lineFeatureLists, [bucket](BucketLineFeatureBinList p) { return p.first == bucket; } );
|
//std::erase_if(_lineFeatureLists, [bucket](BucketLineFeatureBinList p) { return p.first == bucket; } );
|
||||||
|
//std::erase_if(_lineFeatureLists, [bucket](BucketAreaFeatureBinList p) { return p.first == bucket; } );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <simgear/bucket/newbucket.hxx>
|
#include <simgear/bucket/newbucket.hxx>
|
||||||
#include <simgear/scene/material/EffectGeode.hxx>
|
#include <simgear/scene/material/EffectGeode.hxx>
|
||||||
#include <simgear/scene/material/matlib.hxx>
|
#include <simgear/scene/material/matlib.hxx>
|
||||||
|
#include <simgear/scene/tgdb/AreaFeatureBin.hxx>
|
||||||
#include <simgear/scene/tgdb/LineFeatureBin.hxx>
|
#include <simgear/scene/tgdb/LineFeatureBin.hxx>
|
||||||
|
|
||||||
using namespace osgTerrain;
|
using namespace osgTerrain;
|
||||||
@@ -94,9 +95,10 @@ class VPBTechnique : public TerrainTechnique
|
|||||||
static void removeElevationConstraint(osg::ref_ptr<osg::Node> constraint);
|
static void removeElevationConstraint(osg::ref_ptr<osg::Node> constraint);
|
||||||
static osg::Vec3d checkAgainstElevationConstraints(osg::Vec3d origin, osg::Vec3d vertex, float vertex_gap);
|
static osg::Vec3d checkAgainstElevationConstraints(osg::Vec3d origin, osg::Vec3d vertex, float vertex_gap);
|
||||||
|
|
||||||
// LineFeatures are draped over the underlying mesh.
|
// LineFeatures and AreaFeaturesare draped over the underlying mesh.
|
||||||
static void addLineFeatureList(SGBucket bucket, LineFeatureBinList roadList, osg::ref_ptr<osg::Node> terrainNode);
|
static void addLineFeatureList(SGBucket bucket, LineFeatureBinList roadList, osg::ref_ptr<osg::Node> terrainNode);
|
||||||
static void unloadLineFeatures(SGBucket bucket);
|
static void addAreaFeatureList(SGBucket bucket, AreaFeatureBinList areaList, osg::ref_ptr<osg::Node> terrainNode);
|
||||||
|
static void unloadFeatures(SGBucket bucket);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -142,6 +144,18 @@ class VPBTechnique : public TerrainTechnique
|
|||||||
osg::Vec3Array* n,
|
osg::Vec3Array* n,
|
||||||
unsigned int xsize,
|
unsigned int xsize,
|
||||||
unsigned int ysize);
|
unsigned int ysize);
|
||||||
|
|
||||||
|
virtual void applyAreaFeatures(BufferData& buffer, Locator* masterLocator);
|
||||||
|
virtual void generateAreaFeature(BufferData& buffer, Locator*
|
||||||
|
masterLocator, AreaFeatureBin::AreaFeature area,
|
||||||
|
osg::Vec3d modelCenter,
|
||||||
|
osg::Geometry* geometry,
|
||||||
|
osg::Vec3Array* v,
|
||||||
|
osg::Vec2Array* t,
|
||||||
|
osg::Vec3Array* n,
|
||||||
|
unsigned int xsize,
|
||||||
|
unsigned int ysize);
|
||||||
|
|
||||||
virtual osg::Vec3d getMeshIntersection(BufferData& buffer, Locator* masterLocator, osg::Vec3d pt, osg::Vec3d up);
|
virtual osg::Vec3d getMeshIntersection(BufferData& buffer, Locator* masterLocator, osg::Vec3d pt, osg::Vec3d up);
|
||||||
|
|
||||||
OpenThreads::Mutex _writeBufferMutex;
|
OpenThreads::Mutex _writeBufferMutex;
|
||||||
@@ -161,9 +175,13 @@ class VPBTechnique : public TerrainTechnique
|
|||||||
static osg::Vec2d* _randomOffsets;
|
static osg::Vec2d* _randomOffsets;
|
||||||
|
|
||||||
typedef std::pair<SGBucket, LineFeatureBinList> BucketLineFeatureBinList;
|
typedef std::pair<SGBucket, LineFeatureBinList> BucketLineFeatureBinList;
|
||||||
|
typedef std::pair<SGBucket, AreaFeatureBinList> BucketAreaFeatureBinList;
|
||||||
|
|
||||||
inline static std::list<BucketLineFeatureBinList> _lineFeatureLists;
|
inline static std::list<BucketLineFeatureBinList> _lineFeatureLists;
|
||||||
inline static std::mutex _lineFeatureLists_mutex; // protects the _roadLists;
|
inline static std::mutex _lineFeatureLists_mutex; // protects the _lineFeatureLists;
|
||||||
|
|
||||||
|
inline static std::list<BucketAreaFeatureBinList> _areaFeatureLists;
|
||||||
|
inline static std::mutex _areaFeatureLists_mutex; // protects the _areaFeatureLists;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user