1 // model.cxx - manage a 3D aircraft model.
2 // Written by David Megginson, started 2002.
4 // This file is in the Public Domain, and comes with no warranty.
7 #include <simgear_config.h>
12 #include <boost/foreach.hpp>
14 #include <osg/ref_ptr>
15 #include <osgDB/FileNameUtils>
16 #include <osgDB/FileUtils>
17 #include <osgDB/ReaderWriter>
18 #include <osgDB/ReadFile>
19 #include <osgDB/SharedStateManager>
21 #include <simgear/scene/material/Effect.hxx>
22 #include <simgear/scene/material/EffectGeode.hxx>
23 #include <simgear/scene/util/SGSceneFeatures.hxx>
24 #include <simgear/scene/util/SGSceneUserData.hxx>
25 #include <simgear/scene/util/CopyOp.hxx>
26 #include <simgear/scene/util/SplicingVisitor.hxx>
27 #include <simgear/scene/util/SGReaderWriterOptions.hxx>
29 #include <simgear/structure/exception.hxx>
30 #include <simgear/structure/Singleton.hxx>
31 #include <simgear/props/props.hxx>
32 #include <simgear/props/props_io.hxx>
33 #include <simgear/props/condition.hxx>
40 SGLoadTexture2D(bool staticTexture, const std::string& path,
41 const osgDB::Options* options,
42 bool wrapu, bool wrapv, int)
46 image = osgDB::readImageFile(path, options);
48 image = osgDB::readImageFile(path);
49 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
50 texture->setImage(image);
52 texture->setDataVariance(osg::Object::STATIC);
54 texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
56 texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
58 texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
60 texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
66 if (s <= t && 32 <= s) {
67 SGSceneFeatures::instance()->setTextureCompression(texture.get());
68 } else if (t < s && 32 <= t) {
69 SGSceneFeatures::instance()->setTextureCompression(texture.get());
73 return texture.release();
80 using simgear::CopyOp;
82 Node* copyModel(Node* model)
84 const CopyOp::CopyFlags flags = (CopyOp::DEEP_COPY_ALL
85 & ~CopyOp::DEEP_COPY_TEXTURES
86 & ~CopyOp::DEEP_COPY_IMAGES
87 & ~CopyOp::DEEP_COPY_STATESETS
88 & ~CopyOp::DEEP_COPY_STATEATTRIBUTES
89 & ~CopyOp::DEEP_COPY_ARRAYS
90 & ~CopyOp::DEEP_COPY_PRIMITIVES
91 // This will preserve display lists ...
92 & ~CopyOp::DEEP_COPY_DRAWABLES
93 & ~CopyOp::DEEP_COPY_SHAPES);
94 return (CopyOp(flags))(model);
97 TextureUpdateVisitor::TextureUpdateVisitor(const osgDB::FilePathList& pathList) :
98 NodeAndDrawableVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN),
103 void TextureUpdateVisitor::apply(Node& node)
105 StateSet* stateSet = cloneStateSet(node.getStateSet());
107 node.setStateSet(stateSet);
111 void TextureUpdateVisitor::apply(Drawable& drawable)
113 StateSet* stateSet = cloneStateSet(drawable.getStateSet());
115 drawable.setStateSet(stateSet);
118 Texture2D* TextureUpdateVisitor::textureReplace(int unit, const StateAttribute* attr)
120 using namespace osgDB;
121 const Texture2D* texture = dynamic_cast<const Texture2D*>(attr);
126 const Image* image = texture->getImage();
127 const string* fullFilePath = 0;
129 // The currently loaded file name
130 fullFilePath = &image->getFileName();
133 fullFilePath = &texture->getName();
136 string fileName = getSimpleFileName(*fullFilePath);
137 if (fileName.empty())
139 // The name that should be found with the current database path
140 string fullLiveryFile = findFileInPath(fileName, _pathList);
141 // If it is empty or they are identical then there is nothing to do
142 if (fullLiveryFile.empty() || fullLiveryFile == *fullFilePath)
144 Image* newImage = readImageFile(fullLiveryFile);
147 CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
148 Texture2D* newTexture = static_cast<Texture2D*>(copyOp(texture));
152 newTexture->setImage(newImage);
157 StateSet* TextureUpdateVisitor::cloneStateSet(const StateSet* stateSet)
159 typedef std::pair<int, Texture2D*> Tex2D;
160 vector<Tex2D> newTextures;
161 StateSet* result = 0;
165 int numUnits = stateSet->getTextureAttributeList().size();
167 for (int i = 0; i < numUnits; ++i) {
168 const StateAttribute* attr
169 = stateSet->getTextureAttribute(i, StateAttribute::TEXTURE);
170 Texture2D* newTexture = textureReplace(i, attr);
172 newTextures.push_back(Tex2D(i, newTexture));
174 if (!newTextures.empty()) {
175 result = static_cast<StateSet*>(stateSet->clone(CopyOp()));
176 for (vector<Tex2D>::iterator i = newTextures.begin();
177 i != newTextures.end();
179 result->setTextureAttribute(i->first, i->second);
186 UserDataCopyVisitor::UserDataCopyVisitor() :
187 NodeVisitor(NodeVisitor::NODE_VISITOR,
188 NodeVisitor::TRAVERSE_ALL_CHILDREN)
192 void UserDataCopyVisitor::apply(Node& node)
194 ref_ptr<SGSceneUserData> userData;
195 userData = SGSceneUserData::getSceneUserData(&node);
196 if (userData.valid()) {
197 SGSceneUserData* newUserData = new SGSceneUserData(*userData);
198 newUserData->setVelocity(0);
199 node.setUserData(newUserData);
201 node.traverse(*this);
206 class MakeEffectVisitor : public SplicingVisitor
209 typedef std::map<string, SGPropertyNode_ptr> EffectMap;
210 using SplicingVisitor::apply;
211 MakeEffectVisitor(const SGReaderWriterOptions* options = 0)
215 virtual void apply(osg::Group& node);
216 virtual void apply(osg::Geode& geode);
217 EffectMap& getEffectMap() { return _effectMap; }
218 const EffectMap& getEffectMap() const { return _effectMap; }
219 void setDefaultEffect(SGPropertyNode* effect)
221 _currentEffectParent = effect;
223 SGPropertyNode* getDefaultEffect() { return _currentEffectParent; }
225 EffectMap _effectMap;
226 SGPropertyNode_ptr _currentEffectParent;
227 osg::ref_ptr<const SGReaderWriterOptions> _options;
230 void MakeEffectVisitor::apply(osg::Group& node)
232 SGPropertyNode_ptr savedEffectRoot;
233 const string& nodeName = node.getName();
234 bool restoreEffect = false;
235 if (!nodeName.empty()) {
236 EffectMap::iterator eitr = _effectMap.find(nodeName);
237 if (eitr != _effectMap.end()) {
238 savedEffectRoot = _currentEffectParent;
239 _currentEffectParent = eitr->second;
240 restoreEffect = true;
243 SplicingVisitor::apply(node);
244 // If a new node was created, copy the user data too.
245 ref_ptr<SGSceneUserData> userData = SGSceneUserData::getSceneUserData(&node);
246 if (userData.valid() && _childStack.back().back().get() != &node)
247 _childStack.back().back()->setUserData(new SGSceneUserData(*userData));
249 _currentEffectParent = savedEffectRoot;
252 void MakeEffectVisitor::apply(osg::Geode& geode)
254 if (pushNode(getNewNode(geode)))
256 osg::StateSet* ss = geode.getStateSet();
261 SGPropertyNode_ptr ssRoot = new SGPropertyNode;
262 makeParametersFromStateSet(ssRoot, ss);
263 SGPropertyNode_ptr effectRoot = new SGPropertyNode;
264 effect::mergePropertyTrees(effectRoot, ssRoot, _currentEffectParent);
265 Effect* effect = makeEffect(effectRoot, true, _options.get());
266 EffectGeode* eg = dynamic_cast<EffectGeode*>(&geode);
268 eg->setEffect(effect);
270 eg = new EffectGeode;
271 eg->setEffect(effect);
272 ref_ptr<SGSceneUserData> userData = SGSceneUserData::getSceneUserData(&geode);
273 if (userData.valid())
274 eg->setUserData(new SGSceneUserData(*userData));
275 for (unsigned i = 0; i < geode.getNumDrawables(); ++i) {
276 osg::Drawable *drawable = geode.getDrawable(i);
277 eg->addDrawable(drawable);
279 // Generate tangent vectors etc if needed
280 osg::Geometry *geom = dynamic_cast<osg::Geometry*>(drawable);
281 if(geom) eg->runGenerators(geom);
284 pushResultNode(&geode, eg);
292 class DefaultEffect : public simgear::Singleton<DefaultEffect>
297 _effect = new SGPropertyNode;
298 makeChild(_effect.ptr(), "inherits-from")
299 ->setStringValue("Effects/model-default");
301 virtual ~DefaultEffect() {}
302 SGPropertyNode* getEffect() { return _effect.ptr(); }
304 SGPropertyNode_ptr _effect;
308 ref_ptr<Node> instantiateEffects(osg::Node* modelGroup,
309 PropertyList& effectProps,
310 const SGReaderWriterOptions* options)
312 SGPropertyNode_ptr defaultEffectPropRoot;
313 MakeEffectVisitor visitor(options);
314 MakeEffectVisitor::EffectMap& emap = visitor.getEffectMap();
315 for (PropertyList::iterator itr = effectProps.begin(),
316 end = effectProps.end();
320 SGPropertyNode_ptr configNode = *itr;
321 std::vector<SGPropertyNode_ptr> objectNames =
322 configNode->getChildren("object-name");
323 SGPropertyNode* defaultNode = configNode->getChild("default");
324 if (defaultNode && defaultNode->getValue<bool>())
325 defaultEffectPropRoot = configNode;
326 BOOST_FOREACH(SGPropertyNode_ptr objNameNode, objectNames) {
327 emap.insert(make_pair(objNameNode->getStringValue(), configNode));
329 configNode->removeChild("default");
330 configNode->removeChildren("object-name");
332 if (!defaultEffectPropRoot)
333 defaultEffectPropRoot = DefaultEffect::instance()->getEffect();
334 visitor.setDefaultEffect(defaultEffectPropRoot.ptr());
335 modelGroup->accept(visitor);
336 osg::NodeList& result = visitor.getResults();
337 return ref_ptr<Node>(result[0].get());