00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 # include <simgear_config.h>
00022 #endif
00023
00024 #include "ModelRegistry.hxx"
00025
00026 #include <algorithm>
00027 #include <utility>
00028 #include <vector>
00029
00030 #include <OpenThreads/ScopedLock>
00031
00032 #include <osg/ref_ptr>
00033 #include <osg/Group>
00034 #include <osg/NodeCallback>
00035 #include <osg/Switch>
00036 #include <osg/Material>
00037 #include <osg/MatrixTransform>
00038 #include <osgDB/Archive>
00039 #include <osgDB/FileNameUtils>
00040 #include <osgDB/FileUtils>
00041 #include <osgDB/ReadFile>
00042 #include <osgDB/WriteFile>
00043 #include <osgDB/Registry>
00044 #include <osgDB/SharedStateManager>
00045 #include <osgUtil/Optimizer>
00046
00047 #include <simgear/scene/util/SGSceneFeatures.hxx>
00048 #include <simgear/scene/util/SGStateAttributeVisitor.hxx>
00049 #include <simgear/scene/util/SGTextureStateAttributeVisitor.hxx>
00050 #include <simgear/scene/util/NodeAndDrawableVisitor.hxx>
00051
00052 #include <simgear/structure/exception.hxx>
00053 #include <simgear/props/props.hxx>
00054 #include <simgear/props/props_io.hxx>
00055 #include <simgear/props/condition.hxx>
00056
00057 #include "BoundingVolumeBuildVisitor.hxx"
00058
00059 using namespace std;
00060 using namespace osg;
00061 using namespace osgUtil;
00062 using namespace osgDB;
00063 using namespace simgear;
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 namespace {
00075 class SGDatabaseReference : public Observer {
00076 public:
00077 SGDatabaseReference(Referenced* referenced) :
00078 mReferenced(referenced)
00079 { }
00080 virtual void objectDeleted(void*)
00081 {
00082 mReferenced = 0;
00083 }
00084 private:
00085 ref_ptr<Referenced> mReferenced;
00086 };
00087
00088
00089
00090
00091 class TextureNameVisitor : public NodeAndDrawableVisitor {
00092 public:
00093 TextureNameVisitor(NodeVisitor::TraversalMode tm = NodeVisitor::TRAVERSE_ALL_CHILDREN) :
00094 NodeAndDrawableVisitor(tm)
00095 {
00096 }
00097
00098 virtual void apply(Node& node)
00099 {
00100 nameTextures(node.getStateSet());
00101 traverse(node);
00102 }
00103
00104 virtual void apply(Drawable& drawable)
00105 {
00106 nameTextures(drawable.getStateSet());
00107 }
00108 protected:
00109 void nameTextures(StateSet* stateSet)
00110 {
00111 if (!stateSet)
00112 return;
00113 int numUnits = stateSet->getTextureAttributeList().size();
00114 for (int i = 0; i < numUnits; ++i) {
00115 StateAttribute* attr
00116 = stateSet->getTextureAttribute(i, StateAttribute::TEXTURE);
00117 Texture2D* texture = dynamic_cast<Texture2D*>(attr);
00118 if (!texture || !texture->getName().empty())
00119 continue;
00120 const Image *image = texture->getImage();
00121 if (!image)
00122 continue;
00123 texture->setName(image->getFileName());
00124 }
00125 }
00126 };
00127
00128
00129 class SGTexCompressionVisitor : public SGTextureStateAttributeVisitor {
00130 public:
00131 virtual void apply(int, StateSet::RefAttributePair& refAttr)
00132 {
00133 Texture2D* texture;
00134 texture = dynamic_cast<Texture2D*>(refAttr.first.get());
00135 if (!texture)
00136 return;
00137
00138
00139 if (texture->getReadPBuffer())
00140 return;
00141 if (texture->getDataVariance() == osg::Object::DYNAMIC)
00142 return;
00143
00144
00145 Image* image = texture->getImage(0);
00146 if (!image)
00147 return;
00148
00149 int s = image->s();
00150 int t = image->t();
00151
00152 if (s <= t && 32 <= s) {
00153 SGSceneFeatures::instance()->setTextureCompression(texture);
00154 } else if (t < s && 32 <= t) {
00155 SGSceneFeatures::instance()->setTextureCompression(texture);
00156 }
00157 }
00158 };
00159
00160 class SGTexDataVarianceVisitor : public SGTextureStateAttributeVisitor {
00161 public:
00162 virtual void apply(int, StateSet::RefAttributePair& refAttr)
00163 {
00164 Texture* texture;
00165 texture = dynamic_cast<Texture*>(refAttr.first.get());
00166 if (!texture)
00167 return;
00168
00169
00170 if (texture->getReadPBuffer())
00171 return;
00172 if (texture->getDataVariance() == osg::Object::DYNAMIC)
00173 return;
00174
00175 Image* image = texture->getImage(0);
00176 if (!image)
00177 return;
00178
00179 texture->setDataVariance(Object::STATIC);
00180 }
00181
00182 virtual void apply(StateSet* stateSet)
00183 {
00184 if (!stateSet)
00185 return;
00186 stateSet->setDataVariance(Object::STATIC);
00187 SGTextureStateAttributeVisitor::apply(stateSet);
00188 }
00189 };
00190
00191 }
00192
00193 Node* DefaultProcessPolicy::process(Node* node, const string& filename,
00194 const ReaderWriter::Options* opt)
00195 {
00196 TextureNameVisitor nameVisitor;
00197 node->accept(nameVisitor);
00198 return node;
00199 }
00200
00201 ReaderWriter::ReadResult
00202 ModelRegistry::readImage(const string& fileName,
00203 const ReaderWriter::Options* opt)
00204 {
00205 CallbackMap::iterator iter
00206 = imageCallbackMap.find(getFileExtension(fileName));
00207 {
00208 if (iter != imageCallbackMap.end() && iter->second.valid())
00209 return iter->second->readImage(fileName, opt);
00210 string absFileName = findDataFile(fileName, opt);
00211 if (!fileExists(absFileName)) {
00212 SG_LOG(SG_IO, SG_ALERT, "Cannot find image file \""
00213 << fileName << "\"");
00214 return ReaderWriter::ReadResult::FILE_NOT_FOUND;
00215 }
00216
00217 Registry* registry = Registry::instance();
00218 ReaderWriter::ReadResult res;
00219 res = registry->readImageImplementation(absFileName, opt);
00220 if (!res.success()) {
00221 SG_LOG(SG_IO, SG_WARN, "Image loading failed:" << res.message());
00222 return res;
00223 }
00224
00225 if (res.loadedFromCache())
00226 SG_LOG(SG_IO, SG_BULK, "Returning cached image \""
00227 << res.getImage()->getFileName() << "\"");
00228 else
00229 SG_LOG(SG_IO, SG_BULK, "Reading image \""
00230 << res.getImage()->getFileName() << "\"");
00231
00232 return res;
00233 }
00234 }
00235
00236
00237 osg::Node* DefaultCachePolicy::find(const string& fileName,
00238 const ReaderWriter::Options* opt)
00239 {
00240 Registry* registry = Registry::instance();
00241 osg::Node* cached
00242 = dynamic_cast<Node*>(registry->getFromObjectCache(fileName));
00243 if (cached)
00244 SG_LOG(SG_IO, SG_BULK, "Got cached model \""
00245 << fileName << "\"");
00246 else
00247 SG_LOG(SG_IO, SG_BULK, "Reading model \""
00248 << fileName << "\"");
00249 return cached;
00250 }
00251
00252 void DefaultCachePolicy::addToCache(const string& fileName,
00253 osg::Node* node)
00254 {
00255 Registry::instance()->addEntryToObjectCache(fileName, node);
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 OptimizeModelPolicy::OptimizeModelPolicy(const string& extension) :
00271 _osgOptions(Optimizer::SHARE_DUPLICATE_STATE
00272 | Optimizer::MERGE_GEOMETRY
00273 | Optimizer::FLATTEN_STATIC_TRANSFORMS
00274 | Optimizer::TRISTRIP_GEOMETRY)
00275 {
00276 }
00277
00278 osg::Node* OptimizeModelPolicy::optimize(osg::Node* node,
00279 const string& fileName,
00280 const osgDB::ReaderWriter::Options* opt)
00281 {
00282 osgUtil::Optimizer optimizer;
00283 optimizer.optimize(node, _osgOptions);
00284
00285
00286
00287 SGTexDataVarianceVisitor dataVarianceVisitor;
00288 node->accept(dataVarianceVisitor);
00289
00290 SGTexCompressionVisitor texComp;
00291 node->accept(texComp);
00292 return node;
00293 }
00294
00295 string OSGSubstitutePolicy::substitute(const string& name,
00296 const ReaderWriter::Options* opt)
00297 {
00298 string fileSansExtension = getNameLessExtension(name);
00299 string osgFileName = fileSansExtension + ".osg";
00300 string absFileName = findDataFile(osgFileName, opt);
00301 return absFileName;
00302 }
00303
00304
00305 void
00306 BuildLeafBVHPolicy::buildBVH(const std::string& fileName, osg::Node* node)
00307 {
00308 SG_LOG(SG_IO, SG_BULK, "Building leaf attached boundingvolume tree for \""
00309 << fileName << "\".");
00310 BoundingVolumeBuildVisitor bvBuilder(true);
00311 node->accept(bvBuilder);
00312 }
00313
00314 void
00315 BuildGroupBVHPolicy::buildBVH(const std::string& fileName, osg::Node* node)
00316 {
00317 SG_LOG(SG_IO, SG_BULK, "Building group attached boundingvolume tree for \""
00318 << fileName << "\".");
00319 BoundingVolumeBuildVisitor bvBuilder(false);
00320 node->accept(bvBuilder);
00321 }
00322
00323 void
00324 NoBuildBVHPolicy::buildBVH(const std::string& fileName, osg::Node*)
00325 {
00326 SG_LOG(SG_IO, SG_BULK, "Omitting boundingvolume tree for \""
00327 << fileName << "\".");
00328 }
00329
00330 ModelRegistry::ModelRegistry() :
00331 _defaultCallback(new DefaultCallback(""))
00332 {
00333 }
00334
00335 void
00336 ModelRegistry::addImageCallbackForExtension(const string& extension,
00337 Registry::ReadFileCallback* callback)
00338 {
00339 imageCallbackMap.insert(CallbackMap::value_type(extension, callback));
00340 }
00341
00342 void
00343 ModelRegistry::addNodeCallbackForExtension(const string& extension,
00344 Registry::ReadFileCallback* callback)
00345 {
00346 nodeCallbackMap.insert(CallbackMap::value_type(extension, callback));
00347 }
00348
00349 ReaderWriter::ReadResult
00350 ModelRegistry::readNode(const string& fileName,
00351 const ReaderWriter::Options* opt)
00352 {
00353 ReaderWriter::ReadResult res;
00354 CallbackMap::iterator iter
00355 = nodeCallbackMap.find(getFileExtension(fileName));
00356 ReaderWriter::ReadResult result;
00357 if (iter != nodeCallbackMap.end() && iter->second.valid())
00358 result = iter->second->readNode(fileName, opt);
00359 else
00360 result = _defaultCallback->readNode(fileName, opt);
00361
00362 return result;
00363 }
00364
00365 class SGReadCallbackInstaller {
00366 public:
00367 SGReadCallbackInstaller()
00368 {
00369
00370
00371 Referenced::setThreadSafeReferenceCounting(true);
00372
00373 Registry* registry = Registry::instance();
00374 ReaderWriter::Options* options = new ReaderWriter::Options;
00375 int cacheOptions = ReaderWriter::Options::CACHE_ALL;
00376 options->
00377 setObjectCacheHint((ReaderWriter::Options::CacheHintOptions)cacheOptions);
00378 registry->setOptions(options);
00379 registry->getOrCreateSharedStateManager()->
00380 setShareMode(SharedStateManager::SHARE_STATESETS);
00381 registry->setReadFileCallback(ModelRegistry::instance());
00382 }
00383 };
00384
00385 static SGReadCallbackInstaller readCallbackInstaller;
00386
00387
00388 struct ACOptimizePolicy : public OptimizeModelPolicy {
00389 ACOptimizePolicy(const string& extension) :
00390 OptimizeModelPolicy(extension)
00391 {
00392 _osgOptions &= ~Optimizer::TRISTRIP_GEOMETRY;
00393 }
00394 Node* optimize(Node* node, const string& fileName,
00395 const ReaderWriter::Options* opt)
00396 {
00397 ref_ptr<Node> optimized
00398 = OptimizeModelPolicy::optimize(node, fileName, opt);
00399 Group* group = dynamic_cast<Group*>(optimized.get());
00400 MatrixTransform* transform
00401 = dynamic_cast<MatrixTransform*>(optimized.get());
00402 if (((transform && transform->getMatrix().isIdentity()) || group)
00403 && group->getName().empty()
00404 && group->getNumChildren() == 1) {
00405 optimized = static_cast<Node*>(group->getChild(0));
00406 group = dynamic_cast<Group*>(optimized.get());
00407 if (group && group->getName().empty()
00408 && group->getNumChildren() == 1)
00409 optimized = static_cast<Node*>(group->getChild(0));
00410 }
00411 return optimized.release();
00412 }
00413 };
00414
00415 struct ACProcessPolicy {
00416 ACProcessPolicy(const string& extension) {}
00417 Node* process(Node* node, const string& filename,
00418 const ReaderWriter::Options* opt)
00419 {
00420 Matrix m(1, 0, 0, 0,
00421 0, 0, 1, 0,
00422 0, -1, 0, 0,
00423 0, 0, 0, 1);
00424
00425
00426 osg::Group* root = new Group;
00427 MatrixTransform* transform = new MatrixTransform;
00428 root->addChild(transform);
00429
00430 transform->setDataVariance(Object::STATIC);
00431 transform->setMatrix(m);
00432 transform->addChild(node);
00433
00434 return root;
00435 }
00436 };
00437
00438 typedef ModelRegistryCallback<ACProcessPolicy, DefaultCachePolicy,
00439 ACOptimizePolicy,
00440 OSGSubstitutePolicy, BuildLeafBVHPolicy>
00441 ACCallback;
00442
00443 namespace
00444 {
00445 ModelRegistryCallbackProxy<ACCallback> g_acRegister("ac");
00446 }