From e7e616e07cc631a3f19a68a1fa8ee1ed5d6c33a0 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sat, 9 Aug 2014 20:34:08 +0100 Subject: [PATCH] New materials.xml format --- simgear/scene/material/mat.cxx | 62 ++++++++--- simgear/scene/material/mat.hxx | 31 ++++-- simgear/scene/material/matlib.cxx | 162 +++++++++++++++++++++-------- simgear/scene/material/matlib.hxx | 48 ++++++--- simgear/scene/tgdb/SGOceanTile.cxx | 5 +- simgear/scene/tgdb/apt_signs.cxx | 6 +- simgear/scene/tgdb/obj.cxx | 84 +++++++-------- 7 files changed, 268 insertions(+), 130 deletions(-) diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index 7d661dbb..4456e4b2 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -96,19 +96,27 @@ void SGMaterial::_internal_state::add_texture(const std::string &t, int i) SGMaterial::SGMaterial( const SGReaderWriterOptions* options, const SGPropertyNode *props, - SGPropertyNode *prop_root ) + SGPropertyNode *prop_root, + AreaList *a, + SGSharedPtr c) { init(); + areas = a; + condition = c; read_properties( options, props, prop_root ); buildEffectProperties(options); } SGMaterial::SGMaterial( const osgDB::Options* options, const SGPropertyNode *props, - SGPropertyNode *prop_root) + SGPropertyNode *prop_root, + AreaList *a, + SGSharedPtr c) { osg::ref_ptr opt; opt = SGReaderWriterOptions::copyOrCreate(options); + areas = a; + condition = c; init(); read_properties(opt.get(), props, prop_root); buildEffectProperties(opt.get()); @@ -409,12 +417,6 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options, } else { parameters = new SGPropertyNode(); } - - // Read conditions node - const SGPropertyNode *conditionNode = props->getChild("condition"); - if (conditionNode) { - condition = sgReadCondition(prop_root, conditionNode); - } } @@ -552,13 +554,43 @@ SGMaterialGlyph* SGMaterial::get_glyph (const std::string& name) const return it->second; } -bool SGMaterial::valid() const -{ - if (condition) { - return condition->test(); - } else { - return true; - } +bool SGMaterial::valid(SGVec2f loc) const +{ + SG_LOG( SG_TERRAIN, SG_BULK, "Checking materials for location (" + << loc.x() << "," + << loc.y() << ")"); + + // Check location first again the areas the material is valid for + AreaList::const_iterator i = areas->begin(); + + if (i == areas->end()) { + // No areas defined, so simply check against condition + if (condition) { + return condition->test(); + } else { + return true; + } + } + + for (; i != areas->end(); i++) { + + SG_LOG( SG_TERRAIN, SG_BULK, "Checking area (" + << i->x() << "," + << i->y() << ") width:" + << i->width() << " height:" + << i->height()); + // Areas defined, so check that the tile location falls within it + // before checking against condition + if (i->contains(loc.x(), loc.y())) { + if (condition) { + return condition->test(); + } else { + return true; + } + } + } + + return false; } diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index c0a65132..5a37b756 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -42,14 +42,18 @@ namespace osg class StateSet; } - -typedef osg::ref_ptr Texture2DRef; - #include #include // for SGMutex +#include +#include #include +#include +#include #include +typedef osg::ref_ptr Texture2DRef; +typedef std::vector > AreaList; + namespace simgear { class Effect; @@ -88,13 +92,19 @@ public: * state information for the material. This node is usually * loaded from the $FG_ROOT/materials.xml file. */ - SGMaterial( const osgDB::Options*, - const SGPropertyNode *props, - SGPropertyNode *prop_root); + SGMaterial(const osgDB::Options*, + const SGPropertyNode *props, + SGPropertyNode *prop_root, + AreaList *a, + SGSharedPtr c); + SGMaterial(const simgear::SGReaderWriterOptions*, const SGPropertyNode *props, - SGPropertyNode *prop_root); + SGPropertyNode *prop_root, + AreaList *a, + SGSharedPtr c); + /** * Destructor. */ @@ -306,9 +316,9 @@ public: /** * Evaluate whether this material is valid given the current global - * property state. + * property state and the tile location. */ - bool valid() const; + bool valid(SGVec2f loc) const; /** * Return pointer to glyph class, or 0 if it doesn't exist. @@ -474,6 +484,9 @@ private: // Condition, indicating when this material is active SGSharedPtr condition; + // List of geographical rectangles for this material + AreaList* areas; + // Parameters from the materials file const SGPropertyNode* parameters; diff --git a/simgear/scene/material/matlib.cxx b/simgear/scene/material/matlib.cxx index a7b017fa..64f75ab2 100644 --- a/simgear/scene/material/matlib.cxx +++ b/simgear/scene/material/matlib.cxx @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -68,11 +69,11 @@ SGMaterialLib::SGMaterialLib ( void ) : bool SGMaterialLib::load( const string &fg_root, const string& mpath, SGPropertyNode *prop_root ) { - SGPropertyNode materials; + SGPropertyNode materialblocks; SG_LOG( SG_INPUT, SG_INFO, "Reading materials from " << mpath ); try { - readProperties( mpath, &materials ); + readProperties( mpath, &materialblocks ); } catch (const sg_exception &ex) { SG_LOG( SG_INPUT, SG_ALERT, "Error reading materials: " << ex.getMessage() ); @@ -82,44 +83,88 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, = new osgDB::Options; options->setObjectCacheHint(osgDB::Options::CACHE_ALL); options->setDatabasePath(fg_root); - int nMaterials = materials.nChildren(); - for (int i = 0; i < nMaterials; i++) { - const SGPropertyNode *node = materials.getChild(i); - if (!strcmp(node->getName(), "material")) { - SGSharedPtr m = new SGMaterial(options.get(), node, prop_root); - - std::vectornames = node->getChildren("name"); - for ( unsigned int j = 0; j < names.size(); j++ ) { - string name = names[j]->getStringValue(); - // cerr << "Material " << name << endl; - matlib[name].push_back(m); - m->add_name(name); - SG_LOG( SG_TERRAIN, SG_DEBUG, " Loading material " - << names[j]->getStringValue() ); - } - } else { - SG_LOG(SG_INPUT, SG_WARN, - "Skipping bad material entry " << node->getName()); - } + + simgear::PropertyList blocks = materialblocks.getChildren("region"); + simgear::PropertyList::const_iterator block_iter = blocks.begin(); + + for (; block_iter != blocks.end(); block_iter++) { + SGPropertyNode_ptr node = block_iter->get(); + + // Read name node purely for logging purposes + const SGPropertyNode *nameNode = node->getChild("name"); + if (nameNode) { + SG_LOG( SG_TERRAIN, SG_INFO, "Loading region " + << nameNode->getStringValue()); + } + + // Read list of areas + AreaList* arealist = new AreaList; + + const simgear::PropertyList areas = node->getChildren("area"); + simgear::PropertyList::const_iterator area_iter = areas.begin(); + for (; area_iter != areas.end(); area_iter++) { + float x1 = area_iter->get()->getFloatValue("lon1", -180.0f); + float x2 = area_iter->get()->getFloatValue("lon2", 180.0); + float y1 = area_iter->get()->getFloatValue("lat1", -90.0f); + float y2 = area_iter->get()->getFloatValue("lat2", 90.0f); + SGRect rect = SGRect( + fminf(x1, x2), + fminf(y1, y2), + fabs(x2 - x1), + fabs(y2 - y1)); + arealist->push_back(rect); + SG_LOG( SG_TERRAIN, SG_INFO, " Area (" + << rect.x() << "," + << rect.y() << ") width:" + << rect.width() << " height:" + << rect.height()); + } + + // Read conditions node + const SGPropertyNode *conditionNode = node->getChild("condition"); + SGSharedPtr condition; + if (conditionNode) { + condition = sgReadCondition(prop_root, conditionNode); + } + + // Now build all the materials for this set of areas and conditions + + const simgear::PropertyList materials = node->getChildren("material"); + simgear::PropertyList::const_iterator materials_iter = materials.begin(); + for (; materials_iter != materials.end(); materials_iter++) { + const SGPropertyNode *node = materials_iter->get(); + SGSharedPtr m = + new SGMaterial(options.get(), node, prop_root, arealist, condition); + + std::vectornames = node->getChildren("name"); + for ( unsigned int j = 0; j < names.size(); j++ ) { + string name = names[j]->getStringValue(); + // cerr << "Material " << name << endl; + matlib[name].push_back(m); + m->add_name(name); + SG_LOG( SG_TERRAIN, SG_DEBUG, " Loading material " + << names[j]->getStringValue() ); + } + } } return true; } -// find a material record by material name -SGMaterial *SGMaterialLib::find( const string& material ) const +// find a material record by material name and tile center +SGMaterial *SGMaterialLib::find( const string& material, const SGVec2f center ) const { SGMaterial *result = NULL; const_material_map_iterator it = matlib.find( material ); if ( it != end() ) { // We now have a list of materials that match this - // name. Find the first one that either doesn't have - // a condition, or has a condition that evaluates - // to true. - material_list::const_iterator iter = it->second.begin(); - while (iter != it->second.end()) { + // name. Find the first one that matches. + // We start at the end of the list, as the materials + // list is ordered with the smallest regions at the end. + material_list::const_reverse_iterator iter = it->second.rbegin(); + while (iter != it->second.rend()) { result = *iter; - if (result->valid()) { + if (result->valid(center)) { return result; } iter++; @@ -129,31 +174,31 @@ SGMaterial *SGMaterialLib::find( const string& material ) const return NULL; } -void SGMaterialLib::refreshActiveMaterials() +// find a material record by material name and tile center +SGMaterial *SGMaterialLib::find( const string& material, const SGGeod& center ) const { - active_material_cache newCache; - material_map_iterator it = matlib.begin(); - for (; it != matlib.end(); ++it) { - newCache[it->first] = find(it->first); + SGVec2f c = SGVec2f(center.getLongitudeDeg(), center.getLatitudeDeg()); + return find(material, c); +} + +SGMaterialCache *SGMaterialLib::generateMatCache(SGVec2f center) +{ + SGMaterialCache* newCache = new SGMaterialCache(); + material_map::const_reverse_iterator it = matlib.rbegin(); + for (; it != matlib.rend(); ++it) { + newCache->insert(it->first, find(it->first, center)); } - // use this approach to minimise the time we're holding the lock - // lock on the mutex (and hence, would block findCached calls) - SGGuard g(d->mutex); - active_cache = newCache; + return newCache; } -SGMaterial *SGMaterialLib::findCached( const string& material ) const +SGMaterialCache *SGMaterialLib::generateMatCache(SGGeod center) { - SGGuard g(d->mutex); - - active_material_cache::const_iterator it = active_cache.find(material); - if (it == active_cache.end()) - return NULL; - - return it->second; + SGVec2f c = SGVec2f(center.getLongitudeDeg(), center.getLatitudeDeg()); + return SGMaterialLib::generateMatCache(c); } + // Destructor SGMaterialLib::~SGMaterialLib ( void ) { SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialLib::~SGMaterialLib() size=" << matlib.size()); @@ -176,3 +221,28 @@ const SGMaterial *SGMaterialLib::findMaterial(const osg::Geode* geode) return 0; return userData->getMaterial(); } + +// Constructor +SGMaterialCache::SGMaterialCache ( void ) +{ +} + +// Insertion into the material cache +void SGMaterialCache::insert(const std::string& name, SGSharedPtr material) { + cache[name] = material; +} + +// Search of the material cache +SGMaterial *SGMaterialCache::find(const string& material) const +{ + SGMaterialCache::material_cache::const_iterator it = cache.find(material); + if (it == cache.end()) + return NULL; + + return it->second; +} + +// Destructor +SGMaterialCache::~SGMaterialCache ( void ) { + SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialCache::~SGMaterialCache() size=" << cache.size()); +} diff --git a/simgear/scene/material/matlib.hxx b/simgear/scene/material/matlib.hxx index 8a298b5f..7ead9d75 100644 --- a/simgear/scene/material/matlib.hxx +++ b/simgear/scene/material/matlib.hxx @@ -29,6 +29,7 @@ #include #include +#include #include #include // Standard C++ string library @@ -41,6 +42,27 @@ class SGPropertyNode; namespace simgear { class Effect; } namespace osg { class Geode; } +// Material cache class +class SGMaterialCache : public osg::Referenced +{ +private: + typedef std::map < std::string, SGSharedPtr > material_cache; + material_cache cache; + +public: + // Constructor + SGMaterialCache ( void ); + + // Insertion + void insert( const std::string& name, SGSharedPtr material ); + + // Lookup + SGMaterial *find( const std::string& material ) const; + + // Destructor + ~SGMaterialCache ( void ); +}; + // Material management class class SGMaterialLib : public SGReferenced { @@ -59,9 +81,6 @@ private: material_map matlib; - typedef std::map < std::string, SGSharedPtr > active_material_cache; - active_material_cache active_cache; - public: // Constructor @@ -71,24 +90,24 @@ public: bool load( const std::string &fg_root, const std::string& mpath, SGPropertyNode *prop_root ); // find a material record by material name - SGMaterial *find( const std::string& material ) const; + SGMaterial *find( const std::string& material, SGVec2f center ) const; + SGMaterial *find( const std::string& material, const SGGeod& center ) const; /** - * Material lookup involves evaluation of SGConditions to determine which - * possible material (by season, region, etc) is valid. This involves - * vproperty tree queries, so repeated calls to find() can cause + * Material lookup involves evaluation of position and SGConditions to + * determine which possible material (by season, region, etc) is valid. + * This involves property tree queries, so repeated calls to find() can cause * race conditions when called from the osgDB pager thread. (especially * during startup) * * To fix this, and also avoid repeated re-evaluation of the material - * conditions, we provide a version which uses a cached, threadsafe table - * of the currently valid materials. The main thread calls the refresh - * method below to evaluate the valid materials, and findCached can be - * safely called from other threads with no access to unprotected state. + * conditions, we provide factory method to generate a material library + * cache of the valid materials based on the current state and a given position. */ - SGMaterial *findCached( const std::string& material ) const; - void refreshActiveMaterials(); - + + SGMaterialCache *generateMatCache( SGVec2f center); + SGMaterialCache *generateMatCache( SGGeod center); + material_map_iterator begin() { return matlib.begin(); } const_material_map_iterator begin() const { return matlib.begin(); } @@ -99,6 +118,7 @@ public: // Destructor ~SGMaterialLib ( void ); + }; typedef SGSharedPtr SGMaterialLibPtr; diff --git a/simgear/scene/tgdb/SGOceanTile.cxx b/simgear/scene/tgdb/SGOceanTile.cxx index c550280c..f4636159 100644 --- a/simgear/scene/tgdb/SGOceanTile.cxx +++ b/simgear/scene/tgdb/SGOceanTile.cxx @@ -279,7 +279,10 @@ osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib, int latPoints, double tex_width = 1000.0; // find Ocean material in the properties list - SGMaterial *mat = matlib->findCached( "Ocean" ); + SGMaterialCache* matcache = matlib->generateMatCache(b.get_center()); + SGMaterial* mat = matcache->find( "Ocean" ); + delete matcache; + if ( mat != NULL ) { // set the texture width and height values for this // material diff --git a/simgear/scene/tgdb/apt_signs.cxx b/simgear/scene/tgdb/apt_signs.cxx index 7d07132b..e04ddc67 100644 --- a/simgear/scene/tgdb/apt_signs.cxx +++ b/simgear/scene/tgdb/apt_signs.cxx @@ -260,7 +260,7 @@ AirportSignBuilder::AirportSignBuilder(SGMaterialLib* mats, const SGGeod& center assert(mats); d->materials = mats; - d->signCaseGeometry = d->getGeometry(d->materials->find("signcase")->get_effect()); + d->signCaseGeometry = d->getGeometry(d->materials->find("signcase", center)->get_effect()); } osg::Node* AirportSignBuilder::getSignsGroup() @@ -430,7 +430,7 @@ void AirportSignBuilder::addSign(const SGGeod& pos, double heading, const std::s } if (! newmat.empty()) { - material = d->materials->find(newmat); + material = d->materials->find(newmat, pos); newmat.clear(); } @@ -504,7 +504,7 @@ void AirportSignBuilder::addSign(const SGGeod& pos, double heading, const std::s // Part II: typeset double boxwidth = std::max(total_width1, total_width2) * 0.5; double hpos = -boxwidth; - SGMaterial *mat = d->materials->find("signcase"); + SGMaterial *mat = d->materials->find("signcase", pos); double coverSize = fabs(total_width1 - total_width2) * 0.5; element_info* s1 = new element_info(mat, mat->get_glyph("cover1"), sign_height, coverSize); diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index 1b55325d..1239d090 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -141,7 +141,7 @@ public: } bool - insertPtGeometry(const SGBinObject& obj, SGMaterialLib* matlib) + insertPtGeometry(const SGBinObject& obj, SGMaterialCache* matcache) { if (obj.get_pts_v().size() != obj.get_pts_n().size()) { SG_LOG(SG_TERRAIN, SG_ALERT, @@ -151,9 +151,7 @@ public: for (unsigned grp = 0; grp < obj.get_pts_v().size(); ++grp) { std::string materialName = obj.get_pt_materials()[grp]; - SGMaterial* material = 0; - if (matlib) - material = matlib->findCached(materialName); + SGMaterial* material = matcache->find(materialName); SGVec4f color = getMaterialLightColor(material); if (3 <= materialName.size() && materialName.substr(0, 3) != "RWY") { @@ -381,11 +379,11 @@ public: } } - SGVec2f getTexCoordScale(const std::string& name, SGMaterialLib* matlib) + SGVec2f getTexCoordScale(const std::string& name, SGMaterialCache* matcache) { - if (!matlib) + if (!matcache) return SGVec2f(1, 1); - SGMaterial* material = matlib->findCached(name); + SGMaterial* material = matcache->find(name); if (!material) return SGVec2f(1, 1); @@ -393,7 +391,7 @@ public: } bool - insertSurfaceGeometry(const SGBinObject& obj, SGMaterialLib* matlib) + insertSurfaceGeometry(const SGBinObject& obj, SGMaterialCache* matcache) { if (obj.get_tris_n().size() < obj.get_tris_v().size() || obj.get_tris_tcs().size() < obj.get_tris_v().size()) { @@ -404,7 +402,7 @@ public: for (unsigned grp = 0; grp < obj.get_tris_v().size(); ++grp) { std::string materialName = obj.get_tri_materials()[grp]; - SGVec2f tc0Scale = getTexCoordScale(materialName, matlib); + SGVec2f tc0Scale = getTexCoordScale(materialName, matcache); SGVec2f tc1Scale(1.0, 1.0); addTriangleGeometry(materialTriangleMap[materialName], obj, grp, tc0Scale, tc1Scale ); @@ -418,7 +416,7 @@ public: } for (unsigned grp = 0; grp < obj.get_strips_v().size(); ++grp) { std::string materialName = obj.get_strip_materials()[grp]; - SGVec2f tc0Scale = getTexCoordScale(materialName, matlib); + SGVec2f tc0Scale = getTexCoordScale(materialName, matcache); SGVec2f tc1Scale(1.0, 1.0); addStripGeometry(materialTriangleMap[materialName], obj, grp, tc0Scale, tc1Scale); @@ -432,7 +430,7 @@ public: } for (unsigned grp = 0; grp < obj.get_fans_v().size(); ++grp) { std::string materialName = obj.get_fan_materials()[grp]; - SGVec2f tc0Scale = getTexCoordScale(materialName, matlib); + SGVec2f tc0Scale = getTexCoordScale(materialName, matcache); SGVec2f tc1Scale(1.0, 1.0); addFanGeometry(materialTriangleMap[materialName], obj, grp, tc0Scale, tc1Scale ); @@ -440,7 +438,7 @@ public: return true; } - osg::Node* getSurfaceGeometry(SGMaterialLib* matlib, bool useVBOs) const + osg::Node* getSurfaceGeometry(SGMaterialCache* matcache, bool useVBOs) const { if (materialTriangleMap.empty()) return 0; @@ -456,8 +454,8 @@ public: for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { osg::Geometry* geometry = i->second.buildGeometry(useVBOs); SGMaterial *mat = NULL; - if (matlib) { - mat = matlib->findCached(i->first); + if (matcache) { + mat = matcache->find(i->first); } eg = new EffectGeode; eg->setName("EffectGeode"); @@ -478,7 +476,7 @@ public: } } - void computeRandomSurfaceLights(SGMaterialLib* matlib) + void computeRandomSurfaceLights(SGMaterialCache* matcache) { SGMaterialTriangleMap::iterator i; @@ -487,7 +485,7 @@ public: mt_init(&seed, unsigned(123)); for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { - SGMaterial *mat = matlib->findCached(i->first); + SGMaterial *mat = matcache->find(i->first); if (!mat) continue; @@ -530,7 +528,7 @@ public: } void computeRandomObjectsAndBuildings( - SGMaterialLib* matlib, + SGMaterialCache* matcache, float building_density, bool use_random_objects, bool use_random_buildings, @@ -543,7 +541,7 @@ public: mt_init(&seed, unsigned(123)); for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { - SGMaterial *mat = matlib->findCached(i->first); + SGMaterial *mat = matcache->find(i->first); SGTexturedTriangleBin triangleBin = i->second; if (!mat) @@ -850,7 +848,7 @@ public: } } - void computeRandomForest(SGMaterialLib* matlib, float vegetation_density) + void computeRandomForest(SGMaterialCache* matcache, float vegetation_density) { SGMaterialTriangleMap::iterator i; @@ -860,7 +858,7 @@ public: mt_init(&seed, unsigned(586)); for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { - SGMaterial *mat = matlib->findCached(i->first); + SGMaterial *mat = matcache->find(i->first); if (!mat) continue; @@ -910,11 +908,11 @@ public: } } - bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib) + bool insertBinObj(const SGBinObject& obj, SGMaterialCache* matcache) { - if (!insertPtGeometry(obj, matlib)) + if (!insertPtGeometry(obj, matcache)) return false; - if (!insertSurfaceGeometry(obj, matlib)) + if (!insertSurfaceGeometry(obj, matcache)) return false; return true; } @@ -978,6 +976,7 @@ public: return NULL; SGMaterialLibPtr matlib; + SGMaterialCache* matcache = 0; bool useVBOs = false; bool simplifyNear = false; double ratio = SG_SIMPLIFIER_RATIO; @@ -1001,6 +1000,9 @@ public: SGGeod geodPos = SGGeod::fromCart(center); SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180); + // Generate a materials cache + if (matlib) matcache = matlib->generateMatCache(geodPos); + // rotate the tiles so that the bounding boxes get nearly axis aligned. // this will help the collision tree's bounding boxes a bit ... std::vector nodes = tile.get_wgs84_nodes(); @@ -1016,10 +1018,10 @@ public: osg::ref_ptr tileGeometryBin = new SGTileGeometryBin; - if (!tileGeometryBin->insertBinObj(tile, matlib)) + if (!tileGeometryBin->insertBinObj(tile, matcache)) return NULL; - osg::Node* node = tileGeometryBin->getSurfaceGeometry(matlib, useVBOs); + osg::Node* node = tileGeometryBin->getSurfaceGeometry(matcache, useVBOs); if (node && simplifyNear) { osgUtil::Simplifier simplifier(ratio, maxError, maxLength); node->accept(simplifier); @@ -1031,14 +1033,8 @@ public: // Generate all the lighting objects for the tile. osg::LOD* generateLightingTileObjects() { - SGMaterialLibPtr matlib; - - if (_options) - matlib = _options->getMaterialLib(); - - // FIXME: ugly, has a side effect - if (matlib) - _tileGeometryBin->computeRandomSurfaceLights(matlib); + if (_matcache) + _tileGeometryBin->computeRandomSurfaceLights(_matcache); GroundLightManager* lightManager = GroundLightManager::instance(); osg::ref_ptr lightGroup = new SGOffsetTransform(0.94); @@ -1080,14 +1076,14 @@ public: vasiGeode->setEffect(vasiEffect); SGVec4f red(1, 0, 0, 1); SGMaterial* mat = 0; - if (matlib) - mat = matlib->findCached("RWY_RED_LIGHTS"); + if (_matcache) + mat = _matcache->find("RWY_RED_LIGHTS"); if (mat) red = mat->get_light_color(); SGVec4f white(1, 1, 1, 1); mat = 0; - if (matlib) - mat = matlib->findCached("RWY_WHITE_LIGHTS"); + if (_matcache) + mat = _matcache->find("RWY_WHITE_LIGHTS"); if (mat) white = mat->get_light_color(); SGDirectionalLightListBin::const_iterator i; @@ -1211,7 +1207,7 @@ public: if (matlib && (use_random_objects || use_random_buildings)) { - _tileGeometryBin->computeRandomObjectsAndBuildings(matlib, + _tileGeometryBin->computeRandomObjectsAndBuildings(_matcache, building_density, use_random_objects, use_random_buildings, @@ -1274,7 +1270,7 @@ public: if (use_random_vegetation && matlib) { // Now add some random forest. - _tileGeometryBin->computeRandomForest(matlib, vegetation_density); + _tileGeometryBin->computeRandomForest(_matcache, vegetation_density); if (! _tileGeometryBin->randomForest.empty()) { forestNode = createForest(_tileGeometryBin->randomForest, osg::Matrix::identity(), @@ -1301,6 +1297,7 @@ public: /// The original options to use for this bunch of models osg::ref_ptr _options; + osg::ref_ptr _matcache; osg::ref_ptr _tileGeometryBin; string _path; bool _loadterrain; @@ -1314,6 +1311,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options return NULL; SGMaterialLibPtr matlib; + osg::ref_ptr matcache; bool useVBOs = false; bool simplifyDistant = false; bool simplifyNear = false; @@ -1340,6 +1338,8 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options SGVec3d center = tile.get_gbs_center(); SGGeod geodPos = SGGeod::fromCart(center); SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180); + if (matlib) + matcache = matlib->generateMatCache(geodPos); // rotate the tiles so that the bounding boxes get nearly axis aligned. // this will help the collision tree's bounding boxes a bit ... @@ -1356,11 +1356,10 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options osg::ref_ptr tileGeometryBin = new SGTileGeometryBin; - if (!tileGeometryBin->insertBinObj(tile, matlib)) + if (!tileGeometryBin->insertBinObj(tile, matcache)) return NULL; - - osg::Node* node = tileGeometryBin->getSurfaceGeometry(matlib, useVBOs); + osg::Node* node = tileGeometryBin->getSurfaceGeometry(matcache, useVBOs); if (node && simplifyDistant) { osgUtil::Simplifier simplifier(ratio, maxError, maxLength); node->accept(simplifier); @@ -1399,6 +1398,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options randomObjectCallback->_tileGeometryBin = tileGeometryBin; randomObjectCallback->_path = std::string(path); randomObjectCallback->_loadterrain = ! (simplifyNear == simplifyDistant); + randomObjectCallback->_matcache = matcache; osg::ref_ptr callbackOptions = new osgDB::Options; callbackOptions->setReadFileCallback(randomObjectCallback.get()); -- 2.39.5