From 232cbbac5ec26dff98bdc7f6952f30191b428f9c Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Wed, 19 Dec 2018 20:05:06 +0000 Subject: [PATCH 01/26] DEBUG logging of model animation counts. --- simgear/scene/model/SGReaderWriterXML.cxx | 64 +++++++++++++---------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index 4c6304ac..3cc13eb9 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -56,7 +56,7 @@ using namespace std; using namespace simgear; using namespace osg; -static osg::Node * +static std::tuple sgLoad3DModel_internal(const SGPath& path, const osgDB::Options* options, SGPropertyNode *overlay = 0); @@ -88,8 +88,10 @@ SGReaderWriterXML::readNode(const std::string& name, if (!p.exists()) { return ReadResult::FILE_NOT_FOUND; } - - result=sgLoad3DModel_internal(p, options); + + static std::tuple retval; + int num_anims; + std::tie(num_anims, result) = sgLoad3DModel_internal(p, options); } catch (const sg_exception &t) { SG_LOG(SG_INPUT, SG_ALERT, "Failed to load model: " << t.getFormattedMessage() << "\n\tfrom:" << fileName); @@ -160,13 +162,13 @@ void makeEffectAnimations(PropertyList& animation_nodes, SGPropertyNode* typeProp = animProp->getChild("type"); if (!typeProp) continue; - + const char* typeString = typeProp->getStringValue(); if (!strcmp(typeString, "material")) { effectProp = SGMaterialAnimation::makeEffectProperties(animProp); } else if (!strcmp(typeString, "shader")) { - + SGPropertyNode* shaderProp = animProp->getChild("shader"); if (!shaderProp || strcmp(shaderProp->getStringValue(), "chrome")) continue; @@ -215,7 +217,7 @@ private: osg::Node::NodeMask nodeMaskSet; osg::Node::NodeMask nodeMaskClear; }; - + } namespace { @@ -229,7 +231,7 @@ namespace { return (typeString == "pick") || (typeString == "knob") || (typeString == "slider") || (typeString == "touch"); } }; - + bool removeNamedNode(osg::Group* aGroup, const std::string& aName) { int nKids = aGroup->getNumChildren(); @@ -240,28 +242,28 @@ namespace { return true; } } - + for (int i = 0; i < nKids; i++) { osg::Group* childGroup = aGroup->getChild(i)->asGroup(); if (!childGroup) continue; - + if (removeNamedNode(childGroup, aName)) return true; } // of child groups traversal - + return false; } } -static osg::Node * +static std::tuple sgLoad3DModel_internal(const SGPath& path, const osgDB::Options* dbOptions, SGPropertyNode *overlay) { if (!path.exists()) { SG_LOG(SG_INPUT, SG_ALERT, "Failed to load file: \"" << path << "\""); - return NULL; + return std::make_tuple(0, (osg::Node *) NULL); } osg::ref_ptr options; @@ -270,19 +272,20 @@ sgLoad3DModel_internal(const SGPath& path, SGPath modelpath(path); SGPath texturepath(path); SGPath modelDir(modelpath.dir()); - + int animationcount = 0; + SGSharedPtr prop_root = options->getPropertyNode(); if (!prop_root.valid()) prop_root = new SGPropertyNode; // The model data appear to be only used in the topmost model osg::ref_ptr data = options->getModelData(); options->setModelData(0); - + osg::ref_ptr model; osg::ref_ptr group; SGPropertyNode_ptr props = new SGPropertyNode; bool previewMode = (dbOptions->getPluginStringData("SimGear::PREVIEW") == "ON"); - + // Check for an XML wrapper if (modelpath.extension() == "xml") { try { @@ -296,9 +299,9 @@ sgLoad3DModel_internal(const SGPath& path, copyProperties(overlay, props); if (previewMode && props->hasChild("nopreview")) { - return NULL; + return std::make_tuple(0, (osg::Node *) NULL); } - + if (props->hasValue("/path")) { string modelPathStr = props->getStringValue("/path"); modelpath = SGModelLib::findDataFile(modelPathStr, NULL, modelDir); @@ -399,9 +402,9 @@ sgLoad3DModel_internal(const SGPath& path, SGPath submodelpath; osg::ref_ptr submodel; - + string subPathStr = sub_props->getStringValue("path"); - SGPath submodelPath = SGModelLib::findDataFile(subPathStr, + SGPath submodelPath = SGModelLib::findDataFile(subPathStr, NULL, modelDir); if (submodelPath.isNull()) { @@ -419,14 +422,16 @@ sgLoad3DModel_internal(const SGPath& path, } try { - submodel = sgLoad3DModel_internal(submodelPath, options.get(), + int num_anims; + std::tie(num_anims, submodel) = sgLoad3DModel_internal(submodelPath, options.get(), sub_props->getNode("overlay")); + animationcount += num_anims; } catch (const sg_exception &t) { SG_LOG(SG_INPUT, SG_ALERT, "Failed to load submodel: " << t.getFormattedMessage() << "\n\tfrom:" << t.getOrigin()); continue; } - + if (!submodel) continue; @@ -491,7 +496,7 @@ sgLoad3DModel_internal(const SGPath& path, if (i==0) { if (!texturepath.extension().empty()) texturepath = texturepath.dir(); - + options2->setDatabasePath(texturepath.local8BitStr()); } group->addChild(Particles::appendParticles(particle_nodes[i], @@ -510,13 +515,13 @@ sgLoad3DModel_internal(const SGPath& path, PropertyList effect_nodes = props->getChildren("effect"); PropertyList animation_nodes = props->getChildren("animation"); - + if (previewMode) { PropertyList::iterator it; it = std::remove_if(animation_nodes.begin(), animation_nodes.end(), ExcludeInPreview()); animation_nodes.erase(it, animation_nodes.end()); } - + // Some material animations (eventually all) are actually effects. makeEffectAnimations(animation_nodes, effect_nodes); { @@ -543,13 +548,15 @@ sgLoad3DModel_internal(const SGPath& path, /// OSGFIXME: duh, why not only model????? SGAnimation::animate(modelData); } - + + animationcount += animation_nodes.size(); + if (!needTransform && group->getNumChildren() < 2) { model = group->getChild(0); group->removeChild(model.get()); if (data.valid()) data->modelLoaded(modelpath.utf8Str(), props, model.get()); - return model.release(); + return std::make_tuple(animationcount, model.release()); } if (data.valid()) data->modelLoaded(modelpath.utf8Str(), props, group.get()); @@ -559,6 +566,7 @@ sgLoad3DModel_internal(const SGPath& path, osgDB::writeNodeFile(*group, outputfile); } - return group.release(); -} + SG_LOG(SG_GENERAL, SG_DEBUG, "Model " << path << " animation count: " << animationcount); + return std::make_tuple(animationcount, group.release()); +} From 1be3e5771a69db9fddf878887866219e8af4dcd0 Mon Sep 17 00:00:00 2001 From: James Turner Date: Thu, 20 Dec 2018 16:10:02 +0000 Subject: [PATCH 02/26] Logging API changes Remove would_log() : callbacks receive all log messages so they can do custom filtering individually. Also move popup message handling into the private (d-ptr) of sglog(), to keep the header as minimal impossible (no include of ) --- simgear/debug/BufferedLogCallback.cxx | 4 +-- simgear/debug/BufferedLogCallback.hxx | 4 +-- simgear/debug/logstream.cxx | 39 +++++++++------------------ simgear/debug/logstream.hxx | 11 +++----- 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/simgear/debug/BufferedLogCallback.cxx b/simgear/debug/BufferedLogCallback.cxx index a0e63976..b5086ad5 100644 --- a/simgear/debug/BufferedLogCallback.cxx +++ b/simgear/debug/BufferedLogCallback.cxx @@ -52,11 +52,11 @@ BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) : BufferedLogCallback::~BufferedLogCallback() { - BOOST_FOREACH(unsigned char* msg, d->m_buffer) { + for (unsigned char* msg : d->m_buffer) { free(msg); } } - + void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p, const char* file, int line, const std::string& aMessage) { diff --git a/simgear/debug/BufferedLogCallback.hxx b/simgear/debug/BufferedLogCallback.hxx index bda7fd31..ba808cc0 100644 --- a/simgear/debug/BufferedLogCallback.hxx +++ b/simgear/debug/BufferedLogCallback.hxx @@ -41,8 +41,8 @@ public: /// for broken PUI behaviour, it can be removed once PUI is gone. void truncateAt(unsigned int); - virtual void operator()(sgDebugClass c, sgDebugPriority p, - const char* file, int line, const std::string& aMessage); + void operator()(sgDebugClass c, sgDebugPriority p, + const char* file, int line, const std::string& aMessage) override; /** * read the stamp value associated with the log buffer. This is diff --git a/simgear/debug/logstream.cxx b/simgear/debug/logstream.cxx index eeda8901..7d4c5556 100644 --- a/simgear/debug/logstream.cxx +++ b/simgear/debug/logstream.cxx @@ -398,6 +398,8 @@ public: /// and hence should dynamically reflect console logging settings CallbackVec m_consoleCallbacks; + std::vector m_popupMessages; + sgDebugClass m_logClass; sgDebugPriority m_logPriority; bool m_isRunning = false; @@ -506,25 +508,11 @@ public: PauseThread pause(this); m_logPriority = p; m_logClass = c; - BOOST_FOREACH(simgear::LogCallback* cb, m_consoleCallbacks) { + for (auto cb : m_consoleCallbacks) { cb->setLogLevels(c, p); } } - bool would_log( sgDebugClass c, sgDebugPriority p ) const - { - // Testing mode, so always log. - if (m_testMode) return true; - - // SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured - // separately and thus it makes more sense to allow these message through. - if (p == SG_OSG) return true; - - p = translatePriority(p); - if (p >= SG_INFO) return true; - return ((c & m_logClass) != 0 && p >= m_logPriority); - } - void log( sgDebugClass c, sgDebugPriority p, const char* fileName, int line, const std::string& msg) { @@ -560,7 +548,6 @@ logstream::logstream() logstream::~logstream() { - popup_msgs.clear(); d->stop(); } @@ -598,6 +585,10 @@ logstream::log( sgDebugClass c, sgDebugPriority p, void logstream::hexdump(sgDebugClass c, sgDebugPriority p, const char* fileName, int line, const void *mem, unsigned int len, unsigned int columns) { + if (((c & d->m_logClass) == 0) || (p < d->m_logPriority)) { + return; + } + unsigned int i, j; char temp[3000], temp1[3000]; *temp = 0; @@ -653,17 +644,17 @@ void logstream::hexdump(sgDebugClass c, sgDebugPriority p, const char* fileName, void logstream::popup( const std::string& msg) { - popup_msgs.push_back(msg); + d->m_popupMessages.push_back(msg); } std::string logstream::get_popup() { std::string rv = ""; - if (!popup_msgs.empty()) + if (!d->m_popupMessages.empty()) { - rv = popup_msgs.front(); - popup_msgs.erase(popup_msgs.begin()); + rv = d->m_popupMessages.front(); + d->m_popupMessages.erase(d->m_popupMessages.begin()); } return rv; } @@ -671,13 +662,7 @@ logstream::get_popup() bool logstream::has_popup() { - return (popup_msgs.size() > 0) ? true : false; -} - -bool -logstream::would_log( sgDebugClass c, sgDebugPriority p ) const -{ - return d->would_log(c,p); + return !d->m_popupMessages.empty(); } sgDebugClass diff --git a/simgear/debug/logstream.hxx b/simgear/debug/logstream.hxx index 30c656c7..2f8a30af 100644 --- a/simgear/debug/logstream.hxx +++ b/simgear/debug/logstream.hxx @@ -29,7 +29,6 @@ #include #include -#include #include // forward decls @@ -93,8 +92,6 @@ public: */ void setLogLevels( sgDebugClass c, sgDebugPriority p ); - bool would_log( sgDebugClass c, sgDebugPriority p ) const; - void logToFile( const SGPath& aPath, sgDebugClass c, sgDebugPriority p ); void set_log_priority( sgDebugPriority p); @@ -179,8 +176,6 @@ private: // constructor logstream(); - std::vector popup_msgs; - class LogStreamPrivate; std::unique_ptr d; @@ -197,17 +192,17 @@ logstream& sglog(); * @param M message */ # define SG_LOGX(C,P,M) \ - do { if(sglog().would_log(C,P)) { \ + do { \ std::ostringstream os; os << M; \ sglog().log(C, P, __FILE__, __LINE__, os.str()); \ if ((P) == SG_POPUP) sglog().popup(os.str()); \ - } } while(0) + } while(0) #ifdef FG_NDEBUG # define SG_LOG(C,P,M) do { if((P) == SG_POPUP) SG_LOGX(C,P,M) } while(0) # define SG_HEXDUMP(C,P,MEM,LEN) #else # define SG_LOG(C,P,M) SG_LOGX(C,P,M) -# define SG_LOG_HEXDUMP(C,P,MEM,LEN) if(sglog().would_log(C,P)) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN) +# define SG_LOG_HEXDUMP(C,P,MEM,LEN) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN) #endif #define SG_ORIGIN __FILE__ ":" SG_STRINGIZE(__LINE__) From 4b17ea95fcffab9e513b58095aa0367e18248fcd Mon Sep 17 00:00:00 2001 From: James Turner Date: Thu, 20 Dec 2018 16:10:30 +0000 Subject: [PATCH 03/26] Random buildings: reduce log output in a common case --- simgear/scene/tgdb/SGTileDetailsCallback.hxx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/simgear/scene/tgdb/SGTileDetailsCallback.hxx b/simgear/scene/tgdb/SGTileDetailsCallback.hxx index e7612c68..6a16c5da 100644 --- a/simgear/scene/tgdb/SGTileDetailsCallback.hxx +++ b/simgear/scene/tgdb/SGTileDetailsCallback.hxx @@ -689,10 +689,13 @@ public: triangleBuildingList.clear(); } - SG_LOG(SG_TERRAIN, SG_DEBUG, "Random Buildings: " << ((bin) ? bin->getNumBuildings() : 0)); - SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to mask: " << mask_dropped); - SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to random object: " << random_dropped); - SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to other buildings: " << building_dropped); + const int numBuildings = (bin) ? bin->getNumBuildings() : 0; + if (numBuildings > 0) { + SG_LOG(SG_TERRAIN, SG_DEBUG, "computed Random Buildings: " << numBuildings); + SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to mask: " << mask_dropped); + SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to random object: " << random_dropped); + SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to other buildings: " << building_dropped); + } } } From ec14050890fb4705f1822abd12c60a2d39a1384b Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sat, 22 Dec 2018 16:52:05 +0000 Subject: [PATCH 04/26] General tiles with only BUILDING_LIST Bug found during code-read. If tile just contained BUILDING_LIST entries (i.e. no OBJECT_STATIC or OBJECT_SIGN entries), then it would not generate. --- simgear/scene/tgdb/ReaderWriterSTG.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simgear/scene/tgdb/ReaderWriterSTG.cxx b/simgear/scene/tgdb/ReaderWriterSTG.cxx index 46f73ba9..4a79e8ec 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.cxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.cxx @@ -586,7 +586,7 @@ struct ReaderWriterSTG::_ModelBin { i->_elev += elevation(*terrainGroup, SGGeod::fromDeg(i->_lon, i->_lat)); } - if (_objectStaticList.empty() && _signList.empty()) { + if (_objectStaticList.empty() && _signList.empty() && (_buildingListList.size() == 0)) { // The simple case, just return the terrain group return terrainGroup.release(); } else { From fc2630e66dffc451fda19e7e974834abbae0bd4d Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 23 Dec 2018 09:16:19 +0000 Subject: [PATCH 05/26] Revert "Logging API changes" This is causing perf impact, so reverting until we figure out a lower-impact solution. This reverts commit 1be3e5771a69db9fddf878887866219e8af4dcd0. --- simgear/debug/BufferedLogCallback.cxx | 4 +-- simgear/debug/BufferedLogCallback.hxx | 4 +-- simgear/debug/logstream.cxx | 39 ++++++++++++++++++--------- simgear/debug/logstream.hxx | 11 +++++--- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/simgear/debug/BufferedLogCallback.cxx b/simgear/debug/BufferedLogCallback.cxx index b5086ad5..a0e63976 100644 --- a/simgear/debug/BufferedLogCallback.cxx +++ b/simgear/debug/BufferedLogCallback.cxx @@ -52,11 +52,11 @@ BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) : BufferedLogCallback::~BufferedLogCallback() { - for (unsigned char* msg : d->m_buffer) { + BOOST_FOREACH(unsigned char* msg, d->m_buffer) { free(msg); } } - + void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p, const char* file, int line, const std::string& aMessage) { diff --git a/simgear/debug/BufferedLogCallback.hxx b/simgear/debug/BufferedLogCallback.hxx index ba808cc0..bda7fd31 100644 --- a/simgear/debug/BufferedLogCallback.hxx +++ b/simgear/debug/BufferedLogCallback.hxx @@ -41,8 +41,8 @@ public: /// for broken PUI behaviour, it can be removed once PUI is gone. void truncateAt(unsigned int); - void operator()(sgDebugClass c, sgDebugPriority p, - const char* file, int line, const std::string& aMessage) override; + virtual void operator()(sgDebugClass c, sgDebugPriority p, + const char* file, int line, const std::string& aMessage); /** * read the stamp value associated with the log buffer. This is diff --git a/simgear/debug/logstream.cxx b/simgear/debug/logstream.cxx index 7d4c5556..eeda8901 100644 --- a/simgear/debug/logstream.cxx +++ b/simgear/debug/logstream.cxx @@ -398,8 +398,6 @@ public: /// and hence should dynamically reflect console logging settings CallbackVec m_consoleCallbacks; - std::vector m_popupMessages; - sgDebugClass m_logClass; sgDebugPriority m_logPriority; bool m_isRunning = false; @@ -508,11 +506,25 @@ public: PauseThread pause(this); m_logPriority = p; m_logClass = c; - for (auto cb : m_consoleCallbacks) { + BOOST_FOREACH(simgear::LogCallback* cb, m_consoleCallbacks) { cb->setLogLevels(c, p); } } + bool would_log( sgDebugClass c, sgDebugPriority p ) const + { + // Testing mode, so always log. + if (m_testMode) return true; + + // SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured + // separately and thus it makes more sense to allow these message through. + if (p == SG_OSG) return true; + + p = translatePriority(p); + if (p >= SG_INFO) return true; + return ((c & m_logClass) != 0 && p >= m_logPriority); + } + void log( sgDebugClass c, sgDebugPriority p, const char* fileName, int line, const std::string& msg) { @@ -548,6 +560,7 @@ logstream::logstream() logstream::~logstream() { + popup_msgs.clear(); d->stop(); } @@ -585,10 +598,6 @@ logstream::log( sgDebugClass c, sgDebugPriority p, void logstream::hexdump(sgDebugClass c, sgDebugPriority p, const char* fileName, int line, const void *mem, unsigned int len, unsigned int columns) { - if (((c & d->m_logClass) == 0) || (p < d->m_logPriority)) { - return; - } - unsigned int i, j; char temp[3000], temp1[3000]; *temp = 0; @@ -644,17 +653,17 @@ void logstream::hexdump(sgDebugClass c, sgDebugPriority p, const char* fileName, void logstream::popup( const std::string& msg) { - d->m_popupMessages.push_back(msg); + popup_msgs.push_back(msg); } std::string logstream::get_popup() { std::string rv = ""; - if (!d->m_popupMessages.empty()) + if (!popup_msgs.empty()) { - rv = d->m_popupMessages.front(); - d->m_popupMessages.erase(d->m_popupMessages.begin()); + rv = popup_msgs.front(); + popup_msgs.erase(popup_msgs.begin()); } return rv; } @@ -662,7 +671,13 @@ logstream::get_popup() bool logstream::has_popup() { - return !d->m_popupMessages.empty(); + return (popup_msgs.size() > 0) ? true : false; +} + +bool +logstream::would_log( sgDebugClass c, sgDebugPriority p ) const +{ + return d->would_log(c,p); } sgDebugClass diff --git a/simgear/debug/logstream.hxx b/simgear/debug/logstream.hxx index 2f8a30af..30c656c7 100644 --- a/simgear/debug/logstream.hxx +++ b/simgear/debug/logstream.hxx @@ -29,6 +29,7 @@ #include #include +#include #include // forward decls @@ -92,6 +93,8 @@ public: */ void setLogLevels( sgDebugClass c, sgDebugPriority p ); + bool would_log( sgDebugClass c, sgDebugPriority p ) const; + void logToFile( const SGPath& aPath, sgDebugClass c, sgDebugPriority p ); void set_log_priority( sgDebugPriority p); @@ -176,6 +179,8 @@ private: // constructor logstream(); + std::vector popup_msgs; + class LogStreamPrivate; std::unique_ptr d; @@ -192,17 +197,17 @@ logstream& sglog(); * @param M message */ # define SG_LOGX(C,P,M) \ - do { \ + do { if(sglog().would_log(C,P)) { \ std::ostringstream os; os << M; \ sglog().log(C, P, __FILE__, __LINE__, os.str()); \ if ((P) == SG_POPUP) sglog().popup(os.str()); \ - } while(0) + } } while(0) #ifdef FG_NDEBUG # define SG_LOG(C,P,M) do { if((P) == SG_POPUP) SG_LOGX(C,P,M) } while(0) # define SG_HEXDUMP(C,P,MEM,LEN) #else # define SG_LOG(C,P,M) SG_LOGX(C,P,M) -# define SG_LOG_HEXDUMP(C,P,MEM,LEN) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN) +# define SG_LOG_HEXDUMP(C,P,MEM,LEN) if(sglog().would_log(C,P)) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN) #endif #define SG_ORIGIN __FILE__ ":" SG_STRINGIZE(__LINE__) From ed87a0b032fb0fb5bbd01a8caab0d990fbfe928f Mon Sep 17 00:00:00 2001 From: Scott Giese Date: Sun, 23 Dec 2018 22:16:05 -0600 Subject: [PATCH 06/26] Eliminate compiler warnings --- simgear/canvas/ShivaVG/src/shPath.c | 2 +- simgear/debug/logstream.cxx | 2 +- simgear/scene/util/SGSceneFeatures.cxx | 10 +++++----- simgear/sound/readwav.cxx | 8 ++++---- simgear/structure/subsystem_mgr.cxx | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/simgear/canvas/ShivaVG/src/shPath.c b/simgear/canvas/ShivaVG/src/shPath.c index 835fcd08..9c2c1ba2 100644 --- a/simgear/canvas/ShivaVG/src/shPath.c +++ b/simgear/canvas/ShivaVG/src/shPath.c @@ -1193,7 +1193,7 @@ VG_API_CALL VGboolean vgInterpolatePath(VGPath dstPath, VGPath startPath, SHfloat *procData1, *procData2; SHint procSegCount1=0, procSegCount2=0; SHint procDataCount1=0, procDataCount2=0; - SHuint8 *newSegs, *newData; + SHuint8 *newSegs, *newData=0; void *userData[4]; SHint segment1, segment2; SHint segindex, s,d,i; diff --git a/simgear/debug/logstream.cxx b/simgear/debug/logstream.cxx index eeda8901..93ba61b5 100644 --- a/simgear/debug/logstream.cxx +++ b/simgear/debug/logstream.cxx @@ -518,7 +518,7 @@ public: // SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured // separately and thus it makes more sense to allow these message through. - if (p == SG_OSG) return true; + if (static_cast(p) == static_cast(SG_OSG)) return true; p = translatePriority(p); if (p >= SG_INFO) return true; diff --git a/simgear/scene/util/SGSceneFeatures.cxx b/simgear/scene/util/SGSceneFeatures.cxx index a3549a80..48aecf22 100644 --- a/simgear/scene/util/SGSceneFeatures.cxx +++ b/simgear/scene/util/SGSceneFeatures.cxx @@ -40,14 +40,14 @@ SGSceneFeatures::SGSceneFeatures() : _textureCompression(UseARBCompression), - _shaderLights(true), - _pointSpriteLights(true), - _distanceAttenuationLights(true), - _textureFilter(1), _MaxTextureSize(4096), _TextureCacheCompressionActive(true), _TextureCacheCompressionActiveTransparent(true), - _TextureCacheActive(false) + _TextureCacheActive(false), + _shaderLights(true), + _pointSpriteLights(true), + _distanceAttenuationLights(true), + _textureFilter(1) { } diff --git a/simgear/sound/readwav.cxx b/simgear/sound/readwav.cxx index 005cf193..d5c16cd2 100644 --- a/simgear/sound/readwav.cxx +++ b/simgear/sound/readwav.cxx @@ -65,16 +65,16 @@ namespace else if (numChannels == 2 && bitsPerSample == 16) rv = SG_SAMPLE_STEREO16; else if (numChannels == 2 && bitsPerSample == 8) rv = SG_SAMPLE_STEREO8; else { - char msg[65]; - snprintf(msg, 64, "Unsupported audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample); + char msg[81]; + snprintf(msg, 80, "Unsupported audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample); throw sg_exception(msg); } } else { if (numChannels == 1 && bitsPerSample == 4) rv = SG_SAMPLE_ADPCM; else if (numChannels == 1 && bitsPerSample == 8) rv = SG_SAMPLE_MULAW; else { - char msg[65]; - snprintf(msg, 64, "Unsupported compressed audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample); + char msg[81]; + snprintf(msg, 80, "Unsupported compressed audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample); throw sg_exception(msg); } } diff --git a/simgear/structure/subsystem_mgr.cxx b/simgear/structure/subsystem_mgr.cxx index a7294f5f..fc29e883 100644 --- a/simgear/structure/subsystem_mgr.cxx +++ b/simgear/structure/subsystem_mgr.cxx @@ -281,7 +281,7 @@ SGSubsystemGroup::incrementalInit() notifyDidChange(m->subsystem, State::INIT); ++_initPosition; - if (_initPosition < _members.size()) { + if (_initPosition < static_cast(_members.size())) { // start init of the next one notifyWillChange( _members[_initPosition]->subsystem, State::INIT); } From 7981809f3639c6c323dbe7091b02c4ccf20d395a Mon Sep 17 00:00:00 2001 From: Erik Hofman Date: Tue, 15 Jan 2019 10:36:23 +0100 Subject: [PATCH 07/26] Split up SIMD support in ENABLE_SIMD which enables sse2 support for the compiler and ENABLE_SIMD_CODE which enables the hand crafted SIMD math functions which defaults to OFF now since compilers have catched up on generating optimized vectorized SIMD code. --- CMakeLists.txt | 15 ++++++++++----- simgear/math/simd.hxx | 4 ++-- simgear/math/simd4x4.hxx | 4 ++-- simgear/simgear_config_cmake.h.in | 1 + 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3562e791..8a2f59f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,9 +125,14 @@ option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support" option(USE_AEONWAVE "Set to ON to use AeonWave instead of OpenAL" ON) option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON) option(ENABLE_DNS "Set to ON to use udns library and DNS service resolver" ON) -option(ENABLE_SIMD "Enable SSE/SSE2 support for x86 compilers" ON) +option(ENABLE_SIMD "Enable SSE/SSE2 support for compilers" ON) +option(ENABLE_SIMD_CODE "Enable SSE/SSE2 support code for compilers" OFF) option(ENABLE_OPENMP "Enable OpenMP compiler support" OFF) +if (NOT ENABLE_SIMD AND ENABLE_SIMD_CODE) + set(ENABLE_SIMD_CODE OFF) +endif() + include (DetectArch) # until the fstream fix is applied and generally available in OSG, @@ -412,8 +417,8 @@ if(CMAKE_COMPILER_IS_GNUCXX) "${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline") elseif (ENABLE_SIMD) if (X86 OR X86_64) - set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse") - set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse") + set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize") + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize") endif() endif() @@ -440,8 +445,8 @@ if (CLANG) "${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions") elseif (ENABLE_SIMD) if (X86 OR X86_64) - set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse") - set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse") + set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize") + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize") endif() endif() endif() diff --git a/simgear/math/simd.hxx b/simgear/math/simd.hxx index a2847775..162820ac 100644 --- a/simgear/math/simd.hxx +++ b/simgear/math/simd.hxx @@ -309,7 +309,7 @@ inline simd4_t operator*(simd4_t v, T f) { return v; } -#ifdef ENABLE_SIMD +#ifdef ENABLE_SIMD_CODE # ifdef __SSE__ namespace simd4 @@ -1305,7 +1305,7 @@ inline simd4_t max(simd4_t v1, const simd4_t& v2) { # endif -#endif /* ENABLE_SIMD */ +#endif /* ENABLE_SIMD_CODE */ #endif /* __SIMD_H__ */ diff --git a/simgear/math/simd4x4.hxx b/simgear/math/simd4x4.hxx index 69203511..26db560f 100644 --- a/simgear/math/simd4x4.hxx +++ b/simgear/math/simd4x4.hxx @@ -289,7 +289,7 @@ inline simd4x4_t operator*(const simd4x4_t& m1, const simd4x4_t& } -#ifdef ENABLE_SIMD +#ifdef ENABLE_SIMD_CODE # ifdef __SSE__ template<> @@ -1191,7 +1191,7 @@ inline simd4_t transform(const simd4x4_t& m, const simd4_t Date: Tue, 15 Jan 2019 11:38:38 +0100 Subject: [PATCH 08/26] Use AAX_PROCESSED since AAX_STOPPED is only a request to stop but the library decides when it is actually stopped. And AeonWave has become more picky about destroying emitters which aren't completely processed yet since MIDI support was added. --- simgear/sound/soundmgr_aeonwave.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/simgear/sound/soundmgr_aeonwave.cxx b/simgear/sound/soundmgr_aeonwave.cxx index b25fe008..93ee0997 100644 --- a/simgear/sound/soundmgr_aeonwave.cxx +++ b/simgear/sound/soundmgr_aeonwave.cxx @@ -8,7 +8,7 @@ // Modified for the new SoundSystem by Erik Hofman, October 2009 // // Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt -// Copyright (C) 2009 Erik Hofman +// Copyright (C) 2009-2019 Erik Hofman // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -419,7 +419,7 @@ void SGSoundMgr::release_source( unsigned int source ) aax::Emitter& emitter = source_it->second; enum aaxState state = emitter.state(); if (state == AAX_PLAYING || state == AAX_SUSPENDED) { - TRY( emitter.set(AAX_STOPPED) ); + TRY( emitter.set(AAX_PROCESSED) ); TRY( d->_aax.remove(emitter) ); } TRY( emitter.remove_buffer() ); @@ -555,7 +555,6 @@ void SGSoundMgr::sample_play( SGSoundSample *sample ) if (bufid == SGSoundMgr::FAILED_BUFFER || bufid == SGSoundMgr::NO_BUFFER) { -printf("A: release: %i, bufid: %i (%i, %i)\n", sample->get_source(), bufid, SGSoundMgr::FAILED_BUFFER, SGSoundMgr::NO_BUFFER); release_source(sample->get_source()); return; } @@ -590,7 +589,7 @@ void SGSoundMgr::sample_stop( SGSoundSample *sample ) if ( sample->is_looping() && !stopped) { #ifdef ENABLE_SOUND aax::Emitter& emitter = d->get_emitter(source); - TRY( emitter.set(AAX_STOPPED) ); + TRY( emitter.set(AAX_PROCESSED) ); TRY( d->_aax.remove(emitter) ); #endif stopped = is_sample_stopped(sample); @@ -610,7 +609,7 @@ void SGSoundMgr::sample_destroy( SGSoundSample *sample ) unsigned int source = sample->get_source(); if ( sample->is_playing() ) { aax::Emitter& emitter = d->get_emitter(source); - TRY( emitter.set(AAX_STOPPED) ); + TRY( emitter.set(AAX_PROCESSED) ); TRY( d->_aax.remove(emitter) ); } release_source( source ); From 6393b7704e5116541a825d523fd5e5a8c6a92c17 Mon Sep 17 00:00:00 2001 From: Erik Hofman Date: Wed, 16 Jan 2019 14:55:37 +0100 Subject: [PATCH 09/26] Do not attempt to deregister the same emitter more than once --- simgear/sound/soundmgr_aeonwave.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/simgear/sound/soundmgr_aeonwave.cxx b/simgear/sound/soundmgr_aeonwave.cxx index 93ee0997..111fa10e 100644 --- a/simgear/sound/soundmgr_aeonwave.cxx +++ b/simgear/sound/soundmgr_aeonwave.cxx @@ -418,7 +418,7 @@ void SGSoundMgr::release_source( unsigned int source ) { aax::Emitter& emitter = source_it->second; enum aaxState state = emitter.state(); - if (state == AAX_PLAYING || state == AAX_SUSPENDED) { + if (state != AAX_PROCESSED) { TRY( emitter.set(AAX_PROCESSED) ); TRY( d->_aax.remove(emitter) ); } @@ -590,7 +590,6 @@ void SGSoundMgr::sample_stop( SGSoundSample *sample ) #ifdef ENABLE_SOUND aax::Emitter& emitter = d->get_emitter(source); TRY( emitter.set(AAX_PROCESSED) ); - TRY( d->_aax.remove(emitter) ); #endif stopped = is_sample_stopped(sample); } @@ -610,7 +609,6 @@ void SGSoundMgr::sample_destroy( SGSoundSample *sample ) if ( sample->is_playing() ) { aax::Emitter& emitter = d->get_emitter(source); TRY( emitter.set(AAX_PROCESSED) ); - TRY( d->_aax.remove(emitter) ); } release_source( source ); #endif From 64d51b529091525e339bc3a9e548c920ec0cdf6c Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Fri, 18 Jan 2019 12:04:06 +0100 Subject: [PATCH 10/26] sg_file: Add compute hash method --- simgear/io/sg_file.cxx | 25 +++++++++++++++++++++++++ simgear/io/sg_file.hxx | 3 +++ 2 files changed, 28 insertions(+) diff --git a/simgear/io/sg_file.cxx b/simgear/io/sg_file.cxx index be629e7e..fcba988e 100644 --- a/simgear/io/sg_file.cxx +++ b/simgear/io/sg_file.cxx @@ -64,6 +64,31 @@ SGFile::SGFile( int existingFd ) : SGFile::~SGFile() { } +#include +#include +#include "simgear/misc/strutils.hxx" + +std::string SGFile::computeHash() +{ + if (!file_name.exists()) + return std::string(); + simgear::sha1nfo info; + sha1_init(&info); + char* buf = static_cast(malloc(1024 * 1024)); + size_t readLen; + SGBinaryFile f(file_name); + if (!f.open(SG_IO_IN)) { + throw sg_io_exception("Couldn't open file for compute hash", file_name); + } + while ((readLen = f.read(buf, 1024 * 1024)) > 0) { + sha1_write(&info, buf, readLen); + } + + f.close(); + free(buf); + std::string hashBytes((char*)sha1_result(&info), HASH_LENGTH); + return simgear::strutils::encodeHex(hashBytes); +} // open the file based on specified direction bool SGFile::open( const SGProtocolDir d ) { diff --git a/simgear/io/sg_file.hxx b/simgear/io/sg_file.hxx index 613f097c..267295b0 100644 --- a/simgear/io/sg_file.hxx +++ b/simgear/io/sg_file.hxx @@ -87,6 +87,9 @@ public: /** @return true of eof conditions exists */ virtual bool eof() const { return eof_flag; }; + + std::string SGFile::computeHash(); + }; class SGBinaryFile : public SGFile { From c433d29171f4926775ea63d4f1a647cefbc6c1a8 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Fri, 18 Jan 2019 12:09:10 +0100 Subject: [PATCH 11/26] Win32: use high resolution timers (QueryPerformanceCounter) if available --- simgear/timing/timestamp.cxx | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/simgear/timing/timestamp.cxx b/simgear/timing/timestamp.cxx index 7553d322..b12f7544 100644 --- a/simgear/timing/timestamp.cxx +++ b/simgear/timing/timestamp.cxx @@ -71,14 +71,31 @@ static clockid_t getClockId() } #endif +static bool qpc_init = false; +static LARGE_INTEGER s_frequency; +static BOOL s_use_qpc; void SGTimeStamp::stamp() { #ifdef _WIN32 - unsigned int t; - t = timeGetTime(); - _sec = t / 1000; - _nsec = ( t - ( _sec * 1000 ) ) * 1000 * 1000; + if (!qpc_init) { + s_use_qpc = QueryPerformanceFrequency(&s_frequency); + qpc_init = true; + } + if (qpc_init && s_use_qpc) { + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + _sec = now.QuadPart / s_frequency.QuadPart; + _nsec = (1000000000LL * (now.QuadPart - _sec * s_frequency.QuadPart)) / s_frequency.QuadPart; + } + else { + unsigned int t; + + t = timeGetTime(); + _sec = t / 1000; + _nsec = (t - (_sec * 1000)) * 1000 * 1000; + } + #elif defined(_POSIX_TIMERS) && (0 < _POSIX_TIMERS) struct timespec ts; clock_gettime(getClockId(), &ts); From 8bcaa50ba6e8076403ec09fa6f553d870e0ab1f1 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sat, 19 Jan 2019 14:00:16 +0100 Subject: [PATCH 12/26] OSG3.7 changes --- simgear/canvas/elements/CanvasText.cxx | 86 ++++++++++++++++---------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/simgear/canvas/elements/CanvasText.cxx b/simgear/canvas/elements/CanvasText.cxx index ab226be3..3051045f 100644 --- a/simgear/canvas/elements/CanvasText.cxx +++ b/simgear/canvas/elements/CanvasText.cxx @@ -71,8 +71,12 @@ namespace canvas canvas::Text *_text_element; - void computePositions(unsigned int contextID) const override; - }; +#if OSG_VERSION_LESS_THAN(3,5,6) + void computePositions(unsigned int contextID) const override; +#else + void computePositionsImplementation() override; +#endif +}; class TextLine { @@ -122,6 +126,8 @@ namespace canvas _quads = &text->_textureGlyphQuadMap.begin()->second; + +#if OSG_VERSION_LESS_THAN(3,5,6) GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers; GlyphQuads::LineNumbers::const_iterator begin_it = std::lower_bound(line_numbers.begin(), line_numbers.end(), _line); @@ -133,6 +139,10 @@ namespace canvas _begin = begin_it - line_numbers.begin(); _end = std::upper_bound(begin_it, line_numbers.end(), _line) - line_numbers.begin(); +#else +//OSG:TODO: Need 3.5.6 version of this + +#endif } //---------------------------------------------------------------------------- @@ -162,33 +172,35 @@ namespace canvas if( empty() ) return pos; #if OSG_VERSION_LESS_THAN(3,3,5) - GlyphQuads::Coords2 const& coords = _quads->_coords; -#else - GlyphQuads::Coords2 refCoords = _quads->_coords; - GlyphQuads::Coords2::element_type &coords = *refCoords.get(); -#endif - size_t global_i = _begin + i; + GlyphQuads::Coords2 const& coords = _quads->_coords; +#elif OSG_VERSION_LESS_THAN(3,5,6) + GlyphQuads::Coords2 refCoords = _quads->_coords; + GlyphQuads::Coords2::element_type &coords = *refCoords.get(); + size_t global_i = _begin + i; - if( global_i == _begin ) - // before first character of line - pos.x() = coords[_begin * 4].x(); - else if( global_i == _end ) - // After Last character of line - pos.x() = coords[(_end - 1) * 4 + 2].x(); - else - { - float prev_l = coords[(global_i - 1) * 4].x(), - prev_r = coords[(global_i - 1) * 4 + 2].x(), - cur_l = coords[global_i * 4].x(); - - if( prev_l == prev_r ) - // If previous character width is zero set to begin of next character - // (Happens eg. with spaces) - pos.x() = cur_l; + if (global_i == _begin) + // before first character of line + pos.x() = coords[_begin * 4].x(); + else if (global_i == _end) + // After Last character of line + pos.x() = coords[(_end - 1) * 4 + 2].x(); else - // position at center between characters - pos.x() = 0.5 * (prev_r + cur_l); - } + { + float prev_l = coords[(global_i - 1) * 4].x(), + prev_r = coords[(global_i - 1) * 4 + 2].x(), + cur_l = coords[global_i * 4].x(); + + if (prev_l == prev_r) + // If previous character width is zero set to begin of next character + // (Happens eg. with spaces) + pos.x() = cur_l; + else + // position at center between characters + pos.x() = 0.5 * (prev_r + cur_l); + } +#else +//OSG:TODO: need 3.5.7 version of this. +#endif return pos; } @@ -200,12 +212,12 @@ namespace canvas return cursorPos(0); GlyphQuads::Glyphs const& glyphs = _quads->_glyphs; - #if OSG_VERSION_LESS_THAN(3,3,5) +#if OSG_VERSION_LESS_THAN(3,3,5) GlyphQuads::Coords2 const& coords = _quads->_coords; -#else +#elif OSG_VERSION_LESS_THAN(3,5,6) + GlyphQuads::Coords2 refCoords = _quads->_coords; GlyphQuads::Coords2::element_type &coords = *refCoords.get(); -#endif float const HIT_FRACTION = 0.6; float const character_width = _text->getCharacterHeight() @@ -225,6 +237,10 @@ namespace canvas } return cursorPos(i - _begin); +#else +//OSG:TODO: need 3.5.7 version of this. + return cursorPos(0); +#endif } //---------------------------------------------------------------------------- @@ -640,7 +656,7 @@ namespace canvas return bb; } - //---------------------------------------------------------------------------- +#if OSG_VERSION_LESS_THAN(3,5,6) void Text::TextOSG::computePositions(unsigned int contextID) const { if( _textureGlyphQuadMap.empty() || _layout == VERTICAL ) @@ -710,6 +726,14 @@ namespace canvas return osgText::Text::computePositions(contextID); } +#else + void Text::TextOSG::computePositionsImplementation() + { + TextBase::computePositionsImplementation(); + } +#endif + //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- const std::string Text::TYPE_NAME = "text"; From 84046a6717c506f253e4f264b8be01cb3318fbe5 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sat, 19 Jan 2019 14:04:54 +0100 Subject: [PATCH 13/26] Add missing method --- simgear/scene/model/BVHDebugCollectVisitor.hxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/simgear/scene/model/BVHDebugCollectVisitor.hxx b/simgear/scene/model/BVHDebugCollectVisitor.hxx index e99779ff..8e7be665 100644 --- a/simgear/scene/model/BVHDebugCollectVisitor.hxx +++ b/simgear/scene/model/BVHDebugCollectVisitor.hxx @@ -111,6 +111,11 @@ public: if (transform->getNumChildren()) _group->addChild(transform.get()); } + virtual void apply(BVHPageNode& leaf) + { + leaf.traverse(*this); + } + virtual void apply(BVHLineGeometry&) { } From cb024dd82d4c384df0b599640a98e762fbf66688 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sun, 20 Jan 2019 18:05:53 +0100 Subject: [PATCH 14/26] Fix for deleting still referenced object ref https://sourceforge.net/p/flightgear/codetickets/2105/ Use the thread safe versions (getRef) of the objectcache methods --- simgear/scene/material/TextureBuilder.cxx | 15 ++++++++------- simgear/scene/material/mat.cxx | 2 +- simgear/scene/model/SGReaderWriterXML.cxx | 2 +- simgear/scene/model/model.cxx | 6 +++--- simgear/scene/tgdb/ReaderWriterSPT.cxx | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/simgear/scene/material/TextureBuilder.cxx b/simgear/scene/material/TextureBuilder.cxx index fa571912..5634d966 100644 --- a/simgear/scene/material/TextureBuilder.cxx +++ b/simgear/scene/material/TextureBuilder.cxx @@ -257,7 +257,8 @@ bool setAttrs(const TexTuple& attrs, Texture* tex, return false; osgDB::ReaderWriter::ReadResult result; - result = osgDB::readImageFile(imageName, options); + + result = osgDB::readRefImageFile(imageName, options); osg::ref_ptr image; if (result.success()) image = result.getImage(); @@ -590,27 +591,27 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode* osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::POSITIVE_X, image); } - result = osgDB::readImageFile(_tuple.get<1>(), options); + result = osgDB::readRefImageFile(_tuple.get<1>(), options); if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::NEGATIVE_X, image); } - result = osgDB::readImageFile(_tuple.get<2>(), options); + result = osgDB::readRefImageFile(_tuple.get<2>(), options); if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::POSITIVE_Y, image); } - result = osgDB::readImageFile(_tuple.get<3>(), options); + result = osgDB::readRefImageFile(_tuple.get<3>(), options); if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::NEGATIVE_Y, image); } - result = osgDB::readImageFile(_tuple.get<4>(), options); + result = osgDB::readRefImageFile(_tuple.get<4>(), options); if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::POSITIVE_Z, image); } - result = osgDB::readImageFile(_tuple.get<5>(), options); + result = osgDB::readRefImageFile(_tuple.get<5>(), options); if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, image); @@ -634,7 +635,7 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode* return cubeTexture.release(); osgDB::ReaderWriter::ReadResult result; - result = osgDB::readImageFile(texname, options); + result = osgDB::readRefImageFile(texname, options); if(result.success()) { osg::Image* image = result.getImage(); image->flipVertical(); // Seems like the image coordinates are somewhat funny, flip to get better ones diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index 916d4cbd..ba9d63f7 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -227,7 +227,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options, } else { - osg::Image* image = osgDB::readImageFile(fullMaskPath, options); + osg::Image* image = osgDB::readRefImageFile(fullMaskPath, options); if (image && image->valid()) { Texture2DRef object_mask = new osg::Texture2D; diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index 3cc13eb9..105a5528 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -338,7 +338,7 @@ sgLoad3DModel_internal(const SGPath& path, options->setDatabasePath(texturepath.local8BitStr()); osgDB::ReaderWriter::ReadResult modelResult; - modelResult = osgDB::readNodeFile(modelpath.local8BitStr(), options.get()); + modelResult = osgDB::readRefNodeFile(modelpath.local8BitStr(), options.get()); if (!modelResult.validNode()) throw sg_io_exception("Failed to load 3D model:" + modelResult.message(), modelpath); diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 6b34ea9c..0b86f701 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -43,9 +43,9 @@ SGLoadTexture2D(bool staticTexture, const std::string& path, { osg::Image* image; if (options) - image = osgDB::readImageFile(path, options); + image = osgDB::readRefImageFile(path, options); else - image = osgDB::readImageFile(path); + image = osgDB::readRefImageFile(path); osg::ref_ptr texture = new osg::Texture2D; texture->setImage(image); if (staticTexture) @@ -141,7 +141,7 @@ Texture2D* TextureUpdateVisitor::textureReplace(int unit, const StateAttribute* // If it is empty or they are identical then there is nothing to do if (fullLiveryFile.empty() || fullLiveryFile == *fullFilePath) return 0; - Image* newImage = readImageFile(fullLiveryFile); + Image* newImage = readRefImageFile(fullLiveryFile); if (!newImage) return 0; CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES); diff --git a/simgear/scene/tgdb/ReaderWriterSPT.cxx b/simgear/scene/tgdb/ReaderWriterSPT.cxx index cb6f4df1..39facca1 100644 --- a/simgear/scene/tgdb/ReaderWriterSPT.cxx +++ b/simgear/scene/tgdb/ReaderWriterSPT.cxx @@ -208,7 +208,7 @@ ReaderWriterSPT::readObject(const std::string& fileName, const osgDB::Options* o imageFileName = osgDB::concatPaths(imageFileName, "Globe"); imageFileName = osgDB::concatPaths(imageFileName, "world.topo.bathy.200407.3x4096x2048.png"); } - if (osg::Image* image = osgDB::readImageFile(imageFileName, options)) { + if (osg::Image* image = osgDB::readRefImageFile(imageFileName, options)) { osg::Texture2D* texture = new osg::Texture2D; texture->setImage(image); texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT); From 8707005a97cb5bfbebbecfed1f8a1cbce5e295a8 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sun, 20 Jan 2019 18:07:57 +0100 Subject: [PATCH 15/26] Fix particles active even when disabled during load. Possibly this could be fixed better by using the plugin string data - but there is nothing that currently set this; and it seems easier to use the particle callback enabled flag. --- simgear/scene/model/SGReaderWriterXML.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index 105a5528..51a9817e 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -486,7 +486,7 @@ sgLoad3DModel_internal(const SGPath& path, } } - if (dbOptions->getPluginStringData("SimGear::PARTICLESYSTEM") != "OFF") { + if (GlobalParticleCallback::getEnabled()){//dbOptions->getPluginStringData("SimGear::PARTICLESYSTEM") != "OFF") { std::vector particle_nodes; particle_nodes = props->getChildren("particlesystem"); for (unsigned i = 0; i < particle_nodes.size(); ++i) { From 8e57a61aed437f75b8af7df60c18e26b877a4e7d Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sun, 20 Jan 2019 18:08:34 +0100 Subject: [PATCH 16/26] Fix null ref during load. This happened a few times --- simgear/scene/sky/cloud.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/simgear/scene/sky/cloud.cxx b/simgear/scene/sky/cloud.cxx index 3c03c514..89a964b7 100644 --- a/simgear/scene/sky/cloud.cxx +++ b/simgear/scene/sky/cloud.cxx @@ -485,9 +485,11 @@ SGCloudLayer::rebuild() // repaint the cloud layer colors bool SGCloudLayer::repaint( const SGVec3f& fog_color ) { osg::Vec4f combineColor(toOsg(fog_color), cloud_alpha); - osg::TexEnvCombine* combiner - = dynamic_cast(layer_root->getStateSet() - ->getTextureAttribute(1, osg::StateAttribute::TEXENV)); + osg::StateAttribute* textureAtt = layer_root->getStateSet()->getTextureAttribute(1, osg::StateAttribute::TEXENV); + osg::TexEnvCombine* combiner = dynamic_cast(textureAtt); + + if (combiner == nullptr) + return false; combiner->setConstantColor(combineColor); // Set the fog color for the 3D clouds too. From 4f6c8f7784a12e4351bc7e5f142a53d975764d18 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sun, 20 Jan 2019 18:08:57 +0100 Subject: [PATCH 17/26] Better error handling on load failure --- simgear/scene/material/Effect.cxx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index 70792a7a..72f5fba1 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -830,6 +830,9 @@ void reload_shaders() if (!fileName.empty()) { shader->loadShaderSourceFromFile(fileName); } + else + SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader: " << fileName); + } } @@ -917,8 +920,13 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass, Shader::Type stype = (Shader::Type)shaderKey.second; string fileName = SGModelLib::findDataFile(shaderName, options); if (fileName.empty()) + { + SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader" << shaderName); + + throw BuilderException(string("couldn't find shader ") + - shaderName); + shaderName); + } resolvedKey.shaders.push_back(ShaderKey(fileName, stype)); } ProgramMap::iterator resitr = resolvedProgramMap.find(resolvedKey); @@ -1405,8 +1413,11 @@ bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss) // Walk the techniques property tree, building techniques and // passes. +static SGMutex realizeTechniques_lock; bool Effect::realizeTechniques(const SGReaderWriterOptions* options) { + SGGuard g(realizeTechniques_lock); + if (_isRealized) return true; PropertyList tniqList = root->getChildren("technique"); From 07036ac48f0d2005f77d966aaf5991a9aea52d4c Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sun, 20 Jan 2019 18:10:20 +0100 Subject: [PATCH 18/26] Add load origin hint to options This is to allow the DDS cache to handle the image load differently depending on the origin. --- simgear/scene/material/TextureBuilder.cxx | 28 +++++++++++++++++-- simgear/scene/material/mipmap.hxx | 20 ++++++++------ simgear/scene/util/SGReaderWriterOptions.hxx | 29 +++++++++++++++++--- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/simgear/scene/material/TextureBuilder.cxx b/simgear/scene/material/TextureBuilder.cxx index 5634d966..0d2a60c7 100644 --- a/simgear/scene/material/TextureBuilder.cxx +++ b/simgear/scene/material/TextureBuilder.cxx @@ -76,7 +76,7 @@ osg::Texture* TextureBuilder::buildFromType(Effect* effect, Pass* pass, const st typedef boost::tuple TexTuple; + string, MipMapTuple, ImageInternalFormat> TexTuple; EffectNameValue texEnvModesInit[] = { @@ -239,6 +239,17 @@ TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props, } } + const SGPropertyNode* pInternalFormat = getEffectPropertyChild(effect, props, "internal-format"); + pInternalFormat = props->getChild("internal-format"); + ImageInternalFormat iformat = ImageInternalFormat::Unspecified; + if (pInternalFormat) { + std::string internalFormat = pInternalFormat->getStringValue(); + if (internalFormat == "normalized") { + iformat = ImageInternalFormat::Normalized; + SG_LOG(SG_INPUT, SG_ALERT, "internal-format normalized '" << imageName << "'"); + } + } + const SGPropertyNode* pMipmapControl = getEffectPropertyChild(effect, props, "mipmap-control"); MipMapTuple mipmapFunctions( AUTOMATIC, AUTOMATIC, AUTOMATIC, AUTOMATIC ); @@ -246,7 +257,7 @@ TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props, mipmapFunctions = makeMipMapTuple(effect, pMipmapControl, options); return TexTuple(absFileName, minFilter, magFilter, sWrap, tWrap, rWrap, - texType, mipmapFunctions); + texType, mipmapFunctions, iformat); } bool setAttrs(const TexTuple& attrs, Texture* tex, @@ -258,7 +269,14 @@ bool setAttrs(const TexTuple& attrs, Texture* tex, osgDB::ReaderWriter::ReadResult result; + // load texture for effect + SGReaderWriterOptions::LoadOriginHint origLOH = options->getLoadOriginHint(); + if(attrs.get<8>() == ImageInternalFormat::Normalized) + options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS_NORMALIZED); + else + options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS); result = osgDB::readRefImageFile(imageName, options); + options->setLoadOriginHint(origLOH); osg::ref_ptr image; if (result.success()) image = result.getImage(); @@ -586,7 +604,10 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode* cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE); osgDB::ReaderWriter::ReadResult result; - result = osgDB::readImageFile(_tuple.get<0>(), options); + SGReaderWriterOptions* wOpts = (SGReaderWriterOptions*)options; + SGReaderWriterOptions::LoadOriginHint origLOH = wOpts->getLoadOriginHint(); + wOpts->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS); + result = osgDB::readRefImageFile(_tuple.get<0>(), options); if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::POSITIVE_X, image); @@ -616,6 +637,7 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode* osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, image); } + wOpts->setLoadOriginHint(origLOH); if (itr == _cubemaps.end()) _cubemaps[_tuple] = cubeTexture; diff --git a/simgear/scene/material/mipmap.hxx b/simgear/scene/material/mipmap.hxx index 0a908c59..75b29231 100644 --- a/simgear/scene/material/mipmap.hxx +++ b/simgear/scene/material/mipmap.hxx @@ -31,14 +31,18 @@ class Effect; class SGReaderWriterOptions; namespace effect { -enum MipMapFunction { - AUTOMATIC, - AVERAGE, - SUM, - PRODUCT, - MIN, - MAX -}; + enum MipMapFunction { + AUTOMATIC, + AVERAGE, + SUM, + PRODUCT, + MIN, + MAX + }; + enum ImageInternalFormat { + Unspecified, + Normalized, + }; typedef boost::tuple MipMapTuple; diff --git a/simgear/scene/util/SGReaderWriterOptions.hxx b/simgear/scene/util/SGReaderWriterOptions.hxx index 2760df90..17183944 100644 --- a/simgear/scene/util/SGReaderWriterOptions.hxx +++ b/simgear/scene/util/SGReaderWriterOptions.hxx @@ -38,12 +38,22 @@ namespace simgear class SGReaderWriterOptions : public osgDB::Options { public: + enum LoadOriginHint + { + ORIGIN_MODEL, + ORIGIN_EFFECTS, + ORIGIN_EFFECTS_NORMALIZED, + }; + + //SGReaderWriterOptions* cloneOptions(const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) const { return static_cast(clone(copyop)); } + SGReaderWriterOptions() : _materialLib(0), _load_panel(0), _model_data(0), _instantiateEffects(false), - _instantiateMaterialEffects(false) + _instantiateMaterialEffects(false), + _LoadOriginHint(ORIGIN_MODEL) { } SGReaderWriterOptions(const std::string& str) : osgDB::Options(str), @@ -51,7 +61,8 @@ public: _load_panel(0), _model_data(0), _instantiateEffects(false), - _instantiateMaterialEffects(false) + _instantiateMaterialEffects(false), + _LoadOriginHint(ORIGIN_MODEL) { } SGReaderWriterOptions(const osgDB::Options& options, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : @@ -60,7 +71,8 @@ public: _load_panel(0), _model_data(0), _instantiateEffects(false), - _instantiateMaterialEffects(false) + _instantiateMaterialEffects(false), + _LoadOriginHint(ORIGIN_MODEL) { } SGReaderWriterOptions(const SGReaderWriterOptions& options, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : @@ -75,7 +87,8 @@ public: _instantiateEffects(options._instantiateEffects), _instantiateMaterialEffects(options._instantiateMaterialEffects), _materialName(options._materialName), - _sceneryPathSuffixes(options._sceneryPathSuffixes) + _sceneryPathSuffixes(options._sceneryPathSuffixes), + _LoadOriginHint(ORIGIN_MODEL) { } META_Object(simgear, SGReaderWriterOptions); @@ -139,6 +152,13 @@ public: const SGGeod& getLocation() const { return _geod; } + // the load origin defines where the load request has come from. + // example usage; to allow the DDS Texture Cache (DTC) to ignore + // any texture that is used in a shader, as these often have special values + // encoded into the channels that aren't suitable for conversion. + void setLoadOriginHint(LoadOriginHint _v) const { _LoadOriginHint = _v; } + LoadOriginHint getLoadOriginHint() const { return _LoadOriginHint; } + protected: virtual ~SGReaderWriterOptions(); @@ -157,6 +177,7 @@ private: string _materialName; string_list _sceneryPathSuffixes; SGGeod _geod; + mutable LoadOriginHint _LoadOriginHint; }; } From 105d63a69787ba04bcdd7a42c6aa94f01960fd43 Mon Sep 17 00:00:00 2001 From: Scott Giese Date: Sun, 20 Jan 2019 20:35:08 -0600 Subject: [PATCH 19/26] Simgear: LARGE_INTEGER is defined in Windows.h Fixes build issues on Linux. --- simgear/io/sg_file.hxx | 2 +- simgear/timing/timestamp.cxx | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/simgear/io/sg_file.hxx b/simgear/io/sg_file.hxx index 267295b0..59de6ba7 100644 --- a/simgear/io/sg_file.hxx +++ b/simgear/io/sg_file.hxx @@ -88,7 +88,7 @@ public: /** @return true of eof conditions exists */ virtual bool eof() const { return eof_flag; }; - std::string SGFile::computeHash(); + std::string computeHash(); }; diff --git a/simgear/timing/timestamp.cxx b/simgear/timing/timestamp.cxx index b12f7544..067a1b95 100644 --- a/simgear/timing/timestamp.cxx +++ b/simgear/timing/timestamp.cxx @@ -71,9 +71,12 @@ static clockid_t getClockId() } #endif + +#ifdef _WIN32 static bool qpc_init = false; static LARGE_INTEGER s_frequency; static BOOL s_use_qpc; +#endif void SGTimeStamp::stamp() { From 61ebee12ad692da424ac86a561749f9402e406af Mon Sep 17 00:00:00 2001 From: James Turner Date: Tue, 22 Jan 2019 10:18:25 +0100 Subject: [PATCH 20/26] Set curl VERBOSE based on current SG log settings --- simgear/io/HTTPClient.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/simgear/io/HTTPClient.cxx b/simgear/io/HTTPClient.cxx index fe6fa737..0c31354b 100644 --- a/simgear/io/HTTPClient.cxx +++ b/simgear/io/HTTPClient.cxx @@ -273,6 +273,10 @@ void Client::makeRequest(const Request_ptr& r) curl_easy_setopt(curlRequest, CURLOPT_USERAGENT, d->userAgent.c_str()); curl_easy_setopt(curlRequest, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + if (sglog().would_log(SG_TERRASYNC, SG_DEBUG)) { + curl_easy_setopt(curlRequest, CURLOPT_VERBOSE, 1); + } + curl_easy_setopt(curlRequest, CURLOPT_FOLLOWLOCATION, 1); if (!d->proxy.empty()) { From df6ec4f94c90c59a30f5a3e3106ab4a402189c9b Mon Sep 17 00:00:00 2001 From: James Turner Date: Tue, 22 Jan 2019 10:30:34 +0100 Subject: [PATCH 21/26] Property alias loop protection Patch by Henning Stahlke --- simgear/props/props.cxx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/simgear/props/props.cxx b/simgear/props/props.cxx index 1c21ecee..8b599632 100644 --- a/simgear/props/props.cxx +++ b/simgear/props/props.cxx @@ -963,6 +963,11 @@ SGPropertyNode::alias (SGPropertyNode * target) { if (target && (_type != props::ALIAS) && (!_tied)) { + /* loop protection: check alias chain; must not contain self */ + for (auto p = target; p; p = ((p->_type == props::ALIAS) ? p->_value.alias : nullptr)) { + if (p == this) return false; + } + clearValue(); get(target); _value.alias = target; @@ -973,7 +978,7 @@ SGPropertyNode::alias (SGPropertyNode * target) if (!target) { SG_LOG(SG_GENERAL, SG_ALERT, - "Failed to create alias for " << getPath() << ". " + "Failed to set alias " << getPath() << ". " "The target property does not exist."); } else @@ -981,15 +986,15 @@ SGPropertyNode::alias (SGPropertyNode * target) { if (_value.alias == target) return true; // ok, identical alias requested - SG_LOG(SG_GENERAL, SG_ALERT, - "Failed to create alias at " << target->getPath() << ". " - "Source "<< getPath() << " is already aliasing another property."); + SG_LOG(SG_GENERAL, SG_ALERT, "alias(): "<< getPath() << + " is already pointing to " << _value.alias->getPath() << + " so it cannot alias '" << target->getPath() << ". Use unalias() first."); } else if (_tied) { - SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create alias at " << target->getPath() << ". " - "Source " << getPath() << " is a tied property."); + SG_LOG(SG_GENERAL, SG_ALERT, "alias(): " << getPath() << + " is a tied property. It cannot alias " << target->getPath() << "."); } return false; From a5d8eec25fb129db5f96e365d67e364715d78c67 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Thu, 24 Jan 2019 16:10:58 +0100 Subject: [PATCH 22/26] Fix for deleting referenced object from model registry This should have been in the previous commit - However I managed to mess up the merging of this module due to other changes related to the DDS texture cache. --- simgear/scene/model/ModelRegistry.cxx | 22 ++++++++++++---------- simgear/scene/model/ModelRegistry.hxx | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/simgear/scene/model/ModelRegistry.cxx b/simgear/scene/model/ModelRegistry.cxx index 4451fd79..3756fae7 100644 --- a/simgear/scene/model/ModelRegistry.cxx +++ b/simgear/scene/model/ModelRegistry.cxx @@ -449,19 +449,21 @@ ModelRegistry::readImage(const string& fileName, } -osg::Node* DefaultCachePolicy::find(const string& fileName, - const Options* opt) +osg::ref_ptr DefaultCachePolicy::find(const string& fileName, const Options* opt) { Registry* registry = Registry::instance(); - osg::Node* cached - = dynamic_cast(registry->getFromObjectCache(fileName)); - if (cached) - SG_LOG(SG_IO, SG_BULK, "Got cached model \"" - << fileName << "\""); +#if OSG_VERSION_LESS_THAN(3,4,0) + osg::ref_ptr cachedObject = registry->getFromObjectCache(fileName); +#else + osg::ref_ptr cachedObject = registry->getRefFromObjectCache(fileName); +#endif + + ref_ptr cachedNode = dynamic_cast(cachedObject.get()); + if (cachedNode.valid()) + SG_LOG(SG_IO, SG_BULK, "Got cached model \"" << fileName << "\""); else - SG_LOG(SG_IO, SG_BULK, "Reading model \"" - << fileName << "\""); - return cached; + SG_LOG(SG_IO, SG_BULK, "Reading model \"" << fileName << "\""); + return cachedNode; } void DefaultCachePolicy::addToCache(const string& fileName, diff --git a/simgear/scene/model/ModelRegistry.hxx b/simgear/scene/model/ModelRegistry.hxx index 8c8e7467..197bb197 100644 --- a/simgear/scene/model/ModelRegistry.hxx +++ b/simgear/scene/model/ModelRegistry.hxx @@ -132,7 +132,7 @@ struct DefaultProcessPolicy { struct DefaultCachePolicy { DefaultCachePolicy(const std::string& extension) {} - osg::Node* find(const std::string& fileName, + osg::ref_ptr find(const std::string& fileName, const osgDB::Options* opt); void addToCache(const std::string& filename, osg::Node* node); }; From 8b35c9a4b121c425caa264d27d0497d93313485d Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Thu, 24 Jan 2019 18:05:37 +0100 Subject: [PATCH 23/26] Improvements to the DDS texture cache - use a file contents hash instead of filepath. - add a local lru cache for filepath->hash (for performance improvements) - calculate and resize to nearest power of two - handle normal maps and images from effects differently. - when cache is active any image that can't be converted to a dds will have a mipmap generated (which still helps the loading process); although this may be responsible for introducing purple into transparent images.. --- simgear/scene/model/ModelRegistry.cxx | 482 +++++++++++++++++++++----- 1 file changed, 394 insertions(+), 88 deletions(-) diff --git a/simgear/scene/model/ModelRegistry.cxx b/simgear/scene/model/ModelRegistry.cxx index 3756fae7..b5bbc7b9 100644 --- a/simgear/scene/model/ModelRegistry.cxx +++ b/simgear/scene/model/ModelRegistry.cxx @@ -60,6 +60,8 @@ #include #include #include +#include +#include #include "BoundingVolumeBuildVisitor.hxx" #include "model.hxx" @@ -180,9 +182,34 @@ public: } // namespace -static bool isPowerOfTwo(int width, int height) +static int nearestPowerOfTwo(unsigned int _v) { - return (((width & (width - 1)) == 0) && ((height & (height - 1))) == 0); + // uint v; // compute the next highest power of 2 of 32-bit v + unsigned int v = (unsigned int)_v; + bool neg = _v < 0; + if (neg) + v = (unsigned int)(-_v); + + v &= (2 << 16) - 1; // make +ve + + // bit twiddle to round up to nearest pot. + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + + if (neg) + _v = -(int)v; + else + _v = (int)v; + return v; +} + static bool isPowerOfTwo(int v) +{ + return ((v & (v - 1)) == 0); } osg::Node* DefaultProcessPolicy::process(osg::Node* node, const std::string& filename, const Options* opt) @@ -205,6 +232,139 @@ osg::Image* getImageByName(const std::string& filename) return nullptr; } #endif +// a cache which evicts the least recently used item when it is full +#include +#include +#include + +#include +template +class lru_cache +{ +public: + SGMutex _mutex; + + typedef Key key_type; + typedef Value value_type; + typedef std::list list_type; + typedef std::map< + key_type, + std::pair + > map_type; + + lru_cache(size_t capacity) + : m_capacity(capacity) + { + } + + ~lru_cache() + { + } + + + size_t size() const + { + return m_map.size(); + } + + size_t capacity() const + { + return m_capacity; + } + + bool empty() const + { + return m_map.empty(); + } + + bool contains(const key_type &key) + { + SGGuard scopeLock(_mutex); + return m_map.find(key) != m_map.end(); + } + + void insert(const key_type &key, const value_type &value) + { + SGGuard scopeLock(_mutex); + typename map_type::iterator i = m_map.find(key); + if (i == m_map.end()) { + // insert item into the cache, but first check if it is full + if (size() >= m_capacity) { + // cache is full, evict the least recently used item + evict(); + } + + // insert the new item + m_list.push_front(key); + m_map[key] = std::make_pair(value, m_list.begin()); + } + } + boost::optional findValue(const std::string &requiredValue) + { + SGGuard scopeLock(_mutex); + for (typename map_type::iterator it = m_map.begin(); it != m_map.end(); ++it) + if (it->second.first == requiredValue) + return it->first; + return boost::none; + } + boost::optional get(const key_type &key) + { + SGGuard scopeLock(_mutex); + // lookup value in the cache + typename map_type::iterator i = m_map.find(key); + if (i == m_map.end()) { + // value not in cache + return boost::none; + } + + // return the value, but first update its place in the most + // recently used list + typename list_type::iterator j = i->second.second; + if (j != m_list.begin()) { + // move item to the front of the most recently used list + m_list.erase(j); + m_list.push_front(key); + + // update iterator in map + j = m_list.begin(); + const value_type &value = i->second.first; + m_map[key] = std::make_pair(value, j); + + // return the value + return value; + } + else { + // the item is already at the front of the most recently + // used list so just return it + return i->second.first; + } + } + + void clear() + { + SGGuard scopeLock(_mutex); + m_map.clear(); + m_list.clear(); + } + +private: + void evict() + { + SGGuard scopeLock(_mutex); + // evict item from the end of most recently used list + typename list_type::iterator i = --m_list.end(); + m_map.erase(*i); + m_list.erase(i); + } + +private: + map_type m_map; + list_type m_list; + size_t m_capacity; +}; +lru_cache < std::string, std::string> filename_hash_cache(100000); +lru_cache < std::string, bool> filesCleaned(100000); +static bool refreshCache = false; ReaderWriter::ReadResult ModelRegistry::readImage(const string& fileName, @@ -248,6 +408,8 @@ ModelRegistry::readImage(const string& fileName, if (cache_active) { if (fileExtension != "dds" && fileExtension != "gz") { + const SGReaderWriterOptions* sgoptC = dynamic_cast(opt); + std::string root = getPathRoot(absFileName); std::string prr = getPathRelative(root, absFileName); std::string cache_root = SGSceneFeatures::instance()->getTextureCompressionPath().c_str(); @@ -255,99 +417,231 @@ ModelRegistry::readImage(const string& fileName, SGPath file(absFileName); std::stringstream tstream; - tstream << std::hex << file.modTime(); - newName += "." + tstream.str(); - newName += ".cache.dds"; - if (!fileExists(newName)) { - res = registry->readImageImplementation(absFileName, opt); + // calucate and use hash for storing cached image. This also + // helps with sharing of identical images between models. + if (fileExists(absFileName)) { + SGFile f(absFileName); + std::string hash; + boost::optional cachehash = filename_hash_cache.get(absFileName); + if (cachehash) { + hash = *cachehash; +// SG_LOG(SG_IO, SG_ALERT, "Hash for " + absFileName + " in cache " + hash); + } + else { +// SG_LOG(SG_IO, SG_ALERT, "Creating hash for " + absFileName); + hash = f.computeHash(); + filename_hash_cache.insert(absFileName, hash); + boost::optional cacheFilename = filename_hash_cache.findValue(hash); - if (res.validImage()) { - osg::ref_ptr srcImage = res.getImage(); - int width = srcImage->s(); - bool transparent = srcImage->isImageTranslucent(); - int height = srcImage->t(); - - if (height >= max_texture_size) - { - SG_LOG(SG_IO, SG_WARN, "Image texture too high " << width << "," << height << absFileName); - osg::ref_ptr resizedImage; - int factor = height / max_texture_size; - if (ImageUtils::resizeImage(srcImage, width / factor, height / factor, resizedImage)) - srcImage = resizedImage; - width = srcImage->s(); - height = srcImage->t(); - } - if (width >= max_texture_size) - { - SG_LOG(SG_IO, SG_WARN, "Image texture too wide " << width << "," << height << absFileName); - osg::ref_ptr resizedImage; - int factor = width / max_texture_size; - if (ImageUtils::resizeImage(srcImage, width / factor, height / factor, resizedImage)) - srcImage = resizedImage; - width = srcImage->s(); - height = srcImage->t(); - } - - // - // only cache power of two textures that are of a reasonable size - if (width >= 64 && height >= 64 && isPowerOfTwo(width, height)) { - simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE); - - SGPath filePath(newName); - filePath.create_dir(); - - // setup the options string for saving the texture as we don't want OSG to auto flip the texture - // as this complicates loading as it requires a flag to flip it back which will preclude the - // image from being cached because we will have to clone the options to set the flag and thus lose - // the link to the cache in the options from the caller. - osg::ref_ptr nopt; - nopt = opt->cloneOptions(); - std::string optionstring = nopt->getOptionString(); - - if (!optionstring.empty()) - optionstring += " "; - - nopt->setOptionString(optionstring + "ddsNoAutoFlipWrite"); - - /* - * decide if we need to compress this. - */ - bool compress = (transparent && compress_transparent) || (!transparent && compress_solid); - - if (compress) { - if (processor) - { - if (transparent) - processor->compress(*srcImage, osg::Texture::USE_S3TC_DXT5_COMPRESSION, true, true, osgDB::ImageProcessor::USE_CPU, osgDB::ImageProcessor::PRODUCTION); - else - processor->compress(*srcImage, osg::Texture::USE_S3TC_DXT1_COMPRESSION, true, true, osgDB::ImageProcessor::USE_CPU, osgDB::ImageProcessor::PRODUCTION); - //processor->generateMipMap(*srcImage, true, osgDB::ImageProcessor::USE_CPU); - } - else { - simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE); - SG_LOG(SG_IO, SG_WARN, "Texture compression plugin (osg_nvtt) not available; storing uncompressed image: " << newName); - srcImage = simgear::effect::computeMipmap(srcImage, mipmapFunctions); - } - } - else { - if (processor) { - processor->generateMipMap(*srcImage, true, osgDB::ImageProcessor::USE_CPU); - } - else { - simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE); - srcImage = simgear::effect::computeMipmap(srcImage, mipmapFunctions); - } - } - registry->writeImage(*srcImage, newName, nopt); - absFileName = newName; - } - } + // possibly a shared texture - but warn the user to allow investigation. + if (cacheFilename && *cacheFilename != absFileName) { + SG_LOG(SG_IO, SG_ALERT, " Already have " + hash + " : " + *cacheFilename + " not "+absFileName); + } +// SG_LOG(SG_IO, SG_ALERT, " >>>> " + hash + " :: " + newName); + } + newName = cache_root + "/" + hash.substr(0,2) + "/" + hash + ".cache.dds"; } else + { + tstream << std::hex << file.modTime(); + newName += "." + tstream.str(); + newName += ".cache.dds"; + } + bool doRefresh = refreshCache; + //if (fileExists(newName) && sgoptC && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS) { + // doRefresh = true; + // + //} + + if (fileExists(newName) && doRefresh) { + if (!filesCleaned.contains(newName)) { + SG_LOG(SG_IO, SG_ALERT, "Removing previously cached effects image " + newName); + SGPath(newName).remove(); + filesCleaned.insert(newName, true); + } + + } + + if (!fileExists(newName)) { + res = registry->readImageImplementation(absFileName, opt); + if (res.validImage()) { + osg::ref_ptr srcImage = res.getImage(); + int width = srcImage->s(); + bool transparent = srcImage->isImageTranslucent(); + bool isNormalMap = false; + bool isEffect = false; + /* + * decide if we need to compress this. + */ + bool can_compress = (transparent && compress_transparent) || (!transparent && compress_solid); + + int height = srcImage->t(); + + // use the new file origin to determine any special processing + // we handle the following + // - normal maps + // - images loaded from effects + if (sgoptC && transparent && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS_NORMALIZED) { + isNormalMap = true; + } + else if (sgoptC && transparent && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS) { + SG_LOG(SG_IO, SG_ALERT, "From effects transparent " + absFileName); + isEffect = true; +// can_compress = false; + } + else if (sgoptC && transparent && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS) { + SG_LOG(SG_IO, SG_ALERT, "From effects " + absFileName); + isEffect = true; + } + if (can_compress) + { + std::string pot_message; + bool resize = false; + if (!isPowerOfTwo(width)) { + width = nearestPowerOfTwo(width); + resize = true; + pot_message += std::string(" not POT: resized width to ") + std::to_string(width); + } + if (!isPowerOfTwo(height)) { + height = nearestPowerOfTwo(height); + resize = true; + pot_message += std::string(" not POT: resized height to ") + std::to_string(height); + } +if (pot_message.size()) +SG_LOG(SG_IO, SG_WARN, pot_message << " " << absFileName); + + // unlikely that after resizing in height the width will still be outside of the max texture size. + if (height > max_texture_size) + { + SG_LOG(SG_IO, SG_WARN, "Image texture too high (max " << max_texture_size << ") " << width << "," << height << " " << absFileName); + int factor = height / max_texture_size; + height /= factor; + width /= factor; + resize = true; + } + if (width > max_texture_size) + { + SG_LOG(SG_IO, SG_WARN, "Image texture too wide (max " << max_texture_size << ") " << width << "," << height << " " << absFileName); + int factor = width / max_texture_size; + height /= factor; + width /= factor; + resize = true; + } + if (resize) { + osg::ref_ptr resizedImage; + + if (ImageUtils::resizeImage(srcImage, width, height, resizedImage)) + srcImage = resizedImage; + } + + // + // only cache power of two textures that are of a reasonable size + if (width >= 4 && height >= 4) { + + simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE); + + SGPath filePath(newName); + filePath.create_dir(); + + // setup the options string for saving the texture as we don't want OSG to auto flip the texture + // as this complicates loading as it requires a flag to flip it back which will preclude the + // image from being cached because we will have to clone the options to set the flag and thus lose + // the link to the cache in the options from the caller. + osg::ref_ptr nopt; + nopt = opt->cloneOptions(); + std::string optionstring = nopt->getOptionString(); + + if (!optionstring.empty()) + optionstring += " "; + + nopt->setOptionString(optionstring + "ddsNoAutoFlipWrite"); + + //GLenum srcImageType = srcImage->getDataType(); + // printf("--- %-80s --> f=%8x t=%8x\n", newName.c_str(), srcImage->getPixelFormat(), srcImageType); + + try + { + if (can_compress) { + osg::Texture::InternalFormatMode targetFormat = osg::Texture::USE_S3TC_DXT1_COMPRESSION; + if (isNormalMap) { + if (transparent) { + targetFormat = osg::Texture::USE_S3TC_DXT5_COMPRESSION; + } + else + targetFormat = osg::Texture::USE_S3TC_DXT5_COMPRESSION; + } + else if (isEffect) + { + if (transparent) { + targetFormat = osg::Texture::USE_S3TC_DXT5_COMPRESSION; + } + else + targetFormat = osg::Texture::USE_S3TC_DXT1_COMPRESSION; + } + else{ + if (transparent) { + targetFormat = osg::Texture::USE_S3TC_DXT3_COMPRESSION; + } + else + targetFormat = osg::Texture::USE_S3TC_DXT1_COMPRESSION; + } + + if (processor) + { + SG_LOG(SG_IO, SG_ALERT, "Creating " << targetFormat << " for " + absFileName); + // normal maps: + // nvdxt.exe - quality_highest - rescaleKaiser - Kaiser - dxt5nm - norm + processor->compress(*srcImage, targetFormat, true, true, osgDB::ImageProcessor::USE_CPU, osgDB::ImageProcessor::PRODUCTION); + SG_LOG(SG_IO, SG_ALERT, "-- finished creating DDS: " + newName); + //processor->generateMipMap(*srcImage, true, osgDB::ImageProcessor::USE_CPU); + } + else { + simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE); + SG_LOG(SG_IO, SG_WARN, "Texture compression plugin (osg_nvtt) not available; storing uncompressed image: " << absFileName); + srcImage = simgear::effect::computeMipmap(srcImage, mipmapFunctions); + } + } + else { + SG_LOG(SG_IO, SG_ALERT, "Creating uncompressed DDS for " + absFileName); + if (processor) { + processor->generateMipMap(*srcImage, true, osgDB::ImageProcessor::USE_CPU); + } + else { + simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE); + srcImage = simgear::effect::computeMipmap(srcImage, mipmapFunctions); + } + } + //} + //else + // printf("--- no compress or mipmap of format %s\n", newName.c_str()); + registry->writeImage(*srcImage, newName, nopt); + { + std::string mdlDirectory = cache_root + "/cache-i ndex.txt"; + FILE *f = ::fopen(mdlDirectory.c_str(), "a"); + if (f) + { + ::fprintf(f, "%s, %s\n", absFileName.c_str(), newName.c_str()); + ::fclose(f); + } + } + absFileName = newName; + } + catch (...) { + SG_LOG(SG_IO, SG_ALERT, "Exception processing " << absFileName << " may be corrupted"); + } + } + else + SG_LOG(SG_IO, SG_WARN, absFileName + " too small " << width << "," << height); + } + } + } + else { absFileName = newName; + } } } + res = registry->readImageImplementation(absFileName, opt); if (!res.success()) { @@ -368,6 +662,18 @@ ModelRegistry::readImage(const string& fileName, if (srcImage1->getName().empty()) { srcImage1->setName(absFileName); } + if(cache_active && getFileExtension(absFileName) != "dds") + { + if (processor) { + processor->generateMipMap(*srcImage1, true, osgDB::ImageProcessor::USE_CPU); + SG_LOG(SG_IO, SG_ALERT, "Created nvtt mipmaps DDS for " + absFileName); + } + else { + simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE); + srcImage1 = simgear::effect::computeMipmap(srcImage1, mipmapFunctions); + SG_LOG(SG_IO, SG_ALERT, "Created sg mipmaps DDS for " + absFileName); + } + } if (res.loadedFromCache()) SG_LOG(SG_IO, SG_BULK, "Returning cached image \"" From 0d5afe83a22a042ddaf3d6dfb8ebcfd1edd6c474 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Thu, 24 Jan 2019 18:06:18 +0100 Subject: [PATCH 24/26] No need to set precipitation (rain/snow) each frame when it is turned off. --- simgear/environment/precipitation.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/simgear/environment/precipitation.cxx b/simgear/environment/precipitation.cxx index 1a2b8130..97e58d3a 100644 --- a/simgear/environment/precipitation.cxx +++ b/simgear/environment/precipitation.cxx @@ -44,6 +44,10 @@ SGPrecipitation::SGPrecipitation() : void SGPrecipitation::setEnabled( bool value ) { _enabled = value; + if (!_enabled) { + _precipitationEffect->snow(0); + _precipitationEffect->rain(0); + } } void SGPrecipitation::setDropletExternal( bool value ) @@ -64,6 +68,9 @@ bool SGPrecipitation::getEnabled() const */ osg::Group* SGPrecipitation::build(void) { + if (!_enabled) + return nullptr; + osg::ref_ptr group = new osg::Group; _precipitationEffect->snow(0); @@ -227,6 +234,9 @@ void SGPrecipitation::setWindProperty(double heading, double speed) */ bool SGPrecipitation::update(void) { + if (!_enabled) + return false; + if (this->_freeze) { if (this->_rain_intensity > 0) { this->_snow_intensity = this->_rain_intensity; From 30482a35993777498c34771fc111dd39b4d13c1a Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sat, 26 Jan 2019 17:42:55 +0100 Subject: [PATCH 25/26] Fix errant spaces in DDS cache log file --- simgear/scene/model/ModelRegistry.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simgear/scene/model/ModelRegistry.cxx b/simgear/scene/model/ModelRegistry.cxx index b5bbc7b9..ca2beb1f 100644 --- a/simgear/scene/model/ModelRegistry.cxx +++ b/simgear/scene/model/ModelRegistry.cxx @@ -617,7 +617,7 @@ SG_LOG(SG_IO, SG_WARN, pot_message << " " << absFileName); // printf("--- no compress or mipmap of format %s\n", newName.c_str()); registry->writeImage(*srcImage, newName, nopt); { - std::string mdlDirectory = cache_root + "/cache-i ndex.txt"; + std::string mdlDirectory = cache_root + "/cache-index.txt"; FILE *f = ::fopen(mdlDirectory.c_str(), "a"); if (f) { From b76f78c6daf4e92e3d4f204975c47cc9e97fc016 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Sat, 26 Jan 2019 17:47:47 +0100 Subject: [PATCH 26/26] OSG < 3.4.x fixes This will use the inherently unsafe versions of the load methods which can result in deleting an object (from the cache) that has just been loaded in the database thread. Symptom OSG WARN deleting still referenced object. --- simgear/scene/material/TextureBuilder.cxx | 32 +++++++++++++++++++++++ simgear/scene/material/mat.cxx | 4 +++ simgear/scene/model/BVHPageNodeOSG.cxx | 12 +++++++++ simgear/scene/model/SGReaderWriterXML.cxx | 4 +++ simgear/scene/model/model.cxx | 17 ++++++++++-- simgear/scene/model/modellib.cxx | 4 +++ simgear/scene/tgdb/ReaderWriterSPT.cxx | 16 ++++++++++++ simgear/scene/tgdb/ReaderWriterSTG.cxx | 8 ++++++ 8 files changed, 95 insertions(+), 2 deletions(-) diff --git a/simgear/scene/material/TextureBuilder.cxx b/simgear/scene/material/TextureBuilder.cxx index 0d2a60c7..43343169 100644 --- a/simgear/scene/material/TextureBuilder.cxx +++ b/simgear/scene/material/TextureBuilder.cxx @@ -275,7 +275,11 @@ bool setAttrs(const TexTuple& attrs, Texture* tex, options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS_NORMALIZED); else options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS); +#if OSG_VERSION_LESS_THAN(3,4,2) + result = osgDB::readImageFile(imageName, options); +#else result = osgDB::readRefImageFile(imageName, options); +#endif options->setLoadOriginHint(origLOH); osg::ref_ptr image; if (result.success()) @@ -607,32 +611,56 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode* SGReaderWriterOptions* wOpts = (SGReaderWriterOptions*)options; SGReaderWriterOptions::LoadOriginHint origLOH = wOpts->getLoadOriginHint(); wOpts->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS); +#if OSG_VERSION_LESS_THAN(3,4,0) + result = osgDB::readImageFile(_tuple.get<0>(), options); +#else result = osgDB::readRefImageFile(_tuple.get<0>(), options); +#endif if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::POSITIVE_X, image); } +#if OSG_VERSION_LESS_THAN(3,4,0) + result = osgDB::readImageFile(_tuple.get<1>(), options); +#else result = osgDB::readRefImageFile(_tuple.get<1>(), options); +#endif if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::NEGATIVE_X, image); } +#if OSG_VERSION_LESS_THAN(3,4,0) + result = osgDB::readImageFile(_tuple.get<2>(), options); +#else result = osgDB::readRefImageFile(_tuple.get<2>(), options); +#endif if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::POSITIVE_Y, image); } +#if OSG_VERSION_LESS_THAN(3,4,0) + result = osgDB::readImageFile(_tuple.get<3>(), options); +#else result = osgDB::readRefImageFile(_tuple.get<3>(), options); +#endif if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::NEGATIVE_Y, image); } +#if OSG_VERSION_LESS_THAN(3,4,0) + result = osgDB::readImageFile(_tuple.get<4>(), options); +#else result = osgDB::readRefImageFile(_tuple.get<4>(), options); +#endif if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::POSITIVE_Z, image); } +#if OSG_VERSION_LESS_THAN(3,4,0) + result = osgDB::readImageFile(_tuple.get<5>(), options); +#else result = osgDB::readRefImageFile(_tuple.get<5>(), options); +#endif if(result.success()) { osg::Image* image = result.getImage(); cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, image); @@ -657,7 +685,11 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode* return cubeTexture.release(); osgDB::ReaderWriter::ReadResult result; +#if OSG_VERSION_LESS_THAN(3,4,0) + result = osgDB::readImageFile(texname, options); +#else result = osgDB::readRefImageFile(texname, options); +#endif if(result.success()) { osg::Image* image = result.getImage(); image->flipVertical(); // Seems like the image coordinates are somewhat funny, flip to get better ones diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index ba9d63f7..0eaa37a6 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -227,7 +227,11 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options, } else { +#if OSG_VERSION_LESS_THAN(3,4,0) + osg::Image* image = osgDB::readImageFile(fullMaskPath, options); +#else osg::Image* image = osgDB::readRefImageFile(fullMaskPath, options); +#endif if (image && image->valid()) { Texture2DRef object_mask = new osg::Texture2D; diff --git a/simgear/scene/model/BVHPageNodeOSG.cxx b/simgear/scene/model/BVHPageNodeOSG.cxx index e8051847..a2f15bcb 100644 --- a/simgear/scene/model/BVHPageNodeOSG.cxx +++ b/simgear/scene/model/BVHPageNodeOSG.cxx @@ -215,7 +215,11 @@ public: if (pagedLOD.getMinRange(i) <= 0) { osg::ref_ptr options; options = getOptions(pagedLOD.getDatabaseOptions(), pagedLOD.getDatabasePath()); +#if OSG_VERSION_LESS_THAN(3,4,0) + node = osgDB::readNodeFile(pagedLOD.getFileName(i), options.get()); +#else node = osgDB::readRefNodeFile(pagedLOD.getFileName(i), options.get()); +#endif } if (!node.valid()) node = new osg::Group; @@ -256,7 +260,11 @@ public: osg::ref_ptr options; options = getOptions(proxyNode.getDatabaseOptions(), proxyNode.getDatabasePath()); osg::ref_ptr node; +#if OSG_VERSION_LESS_THAN(3,4,0) + node = osgDB::readNodeFile(proxyNode.getFileName(i), options.get()); +#else node = osgDB::readRefNodeFile(proxyNode.getFileName(i), options.get()); +#endif if (!node.valid()) node = new osg::Group; if (i < proxyNode.getNumChildren()) @@ -353,7 +361,11 @@ SGSharedPtr BVHPageNodeOSG::load(const std::string& name, const osg::ref_ptr& options) { osg::ref_ptr node; +#if OSG_VERSION_LESS_THAN(3,4,0) + node = osgDB::readNodeFile(name, dynamic_cast(options.get())); +#else node = osgDB::readRefNodeFile(name, dynamic_cast(options.get())); +#endif if (!node.valid()) return SGSharedPtr(); diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index 51a9817e..64ad2754 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -338,7 +338,11 @@ sgLoad3DModel_internal(const SGPath& path, options->setDatabasePath(texturepath.local8BitStr()); osgDB::ReaderWriter::ReadResult modelResult; +#if OSG_VERSION_LESS_THAN(3,4,0) + modelResult = osgDB::readNodeFile(modelpath.local8BitStr(), options.get()); +#else modelResult = osgDB::readRefNodeFile(modelpath.local8BitStr(), options.get()); +#endif if (!modelResult.validNode()) throw sg_io_exception("Failed to load 3D model:" + modelResult.message(), modelpath); diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 0b86f701..737c7597 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -43,9 +43,18 @@ SGLoadTexture2D(bool staticTexture, const std::string& path, { osg::Image* image; if (options) - image = osgDB::readRefImageFile(path, options); +#if OSG_VERSION_LESS_THAN(3,4,0) + image = osgDB::readImageFile(path, options); +#else + image = osgDB::readRefImageFile(path, options); +#endif else - image = osgDB::readRefImageFile(path); +#if OSG_VERSION_LESS_THAN(3,4,0) + image = osgDB::readImageFile(path); +#else + image = osgDB::readRefImageFile(path); +#endif + osg::ref_ptr texture = new osg::Texture2D; texture->setImage(image); if (staticTexture) @@ -141,7 +150,11 @@ Texture2D* TextureUpdateVisitor::textureReplace(int unit, const StateAttribute* // If it is empty or they are identical then there is nothing to do if (fullLiveryFile.empty() || fullLiveryFile == *fullFilePath) return 0; +#if OSG_VERSION_LESS_THAN(3,4,0) + Image* newImage = readImageFile(fullLiveryFile); +#else Image* newImage = readRefImageFile(fullLiveryFile); +#endif if (!newImage) return 0; CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES); diff --git a/simgear/scene/model/modellib.cxx b/simgear/scene/model/modellib.cxx index 7ce382d3..d11e0d21 100644 --- a/simgear/scene/model/modellib.cxx +++ b/simgear/scene/model/modellib.cxx @@ -101,7 +101,11 @@ osg::Node* loadFile(const string& path, SGReaderWriterOptions* options) options->setInstantiateEffects(true); } +#if OSG_VERSION_LESS_THAN(3,4,0) + ref_ptr model = readNodeFile(path, options); +#else ref_ptr model = readRefNodeFile(path, options); +#endif if (!model) return 0; else diff --git a/simgear/scene/tgdb/ReaderWriterSPT.cxx b/simgear/scene/tgdb/ReaderWriterSPT.cxx index 39facca1..66fad24b 100644 --- a/simgear/scene/tgdb/ReaderWriterSPT.cxx +++ b/simgear/scene/tgdb/ReaderWriterSPT.cxx @@ -208,7 +208,11 @@ ReaderWriterSPT::readObject(const std::string& fileName, const osgDB::Options* o imageFileName = osgDB::concatPaths(imageFileName, "Globe"); imageFileName = osgDB::concatPaths(imageFileName, "world.topo.bathy.200407.3x4096x2048.png"); } +#if OSG_VERSION_LESS_THAN(3,4,0) + if (osg::Image* image = osgDB::readImageFile(imageFileName, options)) { +#else if (osg::Image* image = osgDB::readRefImageFile(imageFileName, options)) { +#endif osg::Texture2D* texture = new osg::Texture2D; texture->setImage(image); texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT); @@ -256,7 +260,11 @@ ReaderWriterSPT::createTree(const BucketBox& bucketBox, const LocalOptions& opti if (bucketBox.getIsBucketSize()) { std::string fileName; fileName = bucketBox.getBucket().gen_index_str() + std::string(".stg"); +#if OSG_VERSION_LESS_THAN(3,4,0) + return osgDB::readNodeFile(fileName, options._options); +#else return osgDB::readRefNodeFile(fileName, options._options); +#endif } else if (!topLevel && options.isPageLevel(bucketBox.getStartLevel())) { return createPagedLOD(bucketBox, options); } else { @@ -314,7 +322,11 @@ ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const LocalOptions& std::string fileName = osgDB::findDataFile(lodPath + extensions[i], options._options); if (fileName.empty()) continue; +#if OSG_VERSION_LESS_THAN(3,4,0) + osg::ref_ptr node = osgDB::readNodeFile(fileName, options._options); +#else osg::ref_ptr node = osgDB::readRefNodeFile(fileName, options._options); +#endif if (!node.valid()) continue; pagedLOD->addChild(node.get(), range, std::numeric_limits::max()); @@ -412,7 +424,11 @@ ReaderWriterSPT::getLowLODStateSet(const LocalOptions& options) const localOptions = static_cast(options._options->clone(osg::CopyOp())); localOptions->setObjectCacheHint(osgDB::Options::CACHE_ALL); +#if OSG_VERSION_LESS_THAN(3,4,0) + osg::ref_ptr object = osgDB::readObjectFile("state.spt", localOptions.get()); +#else osg::ref_ptr object = osgDB::readRefObjectFile("state.spt", localOptions.get()); +#endif if (!dynamic_cast(object.get())) return 0; diff --git a/simgear/scene/tgdb/ReaderWriterSTG.cxx b/simgear/scene/tgdb/ReaderWriterSTG.cxx index 4a79e8ec..4a3887a4 100644 --- a/simgear/scene/tgdb/ReaderWriterSTG.cxx +++ b/simgear/scene/tgdb/ReaderWriterSTG.cxx @@ -156,7 +156,11 @@ struct ReaderWriterSTG::_ModelBin { proxy->setCenterMode(osg::ProxyNode::UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED); node = proxy; } else { +#if OSG_VERSION_LESS_THAN(3,4,0) + node = osgDB::readNodeFile(o._name, o._options.get()); +#else node = osgDB::readRefNodeFile(o._name, o._options.get()); +#endif if (!node.valid()) { SG_LOG(SG_TERRAIN, SG_ALERT, o._errorLocation << ": Failed to load " << o._token << " '" << o._name << "'"); @@ -553,7 +557,11 @@ struct ReaderWriterSTG::_ModelBin { if (_foundBase) { for (auto stgObject : _objectList) { osg::ref_ptr node; +#if OSG_VERSION_LESS_THAN(3,4,0) + node = osgDB::readNodeFile(stgObject._name, stgObject._options.get()); +#else node = osgDB::readRefNodeFile(stgObject._name, stgObject._options.get()); +#endif if (!node.valid()) { SG_LOG(SG_TERRAIN, SG_ALERT, stgObject._errorLocation << ": Failed to load " << stgObject._token << " '" << stgObject._name << "'");