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/math/SGMath.hxx>
22 #include <simgear/scene/material/Effect.hxx>
23 #include <simgear/scene/material/EffectGeode.hxx>
24 #include <simgear/scene/util/SGSceneFeatures.hxx>
25 #include <simgear/scene/util/SGSceneUserData.hxx>
26 #include <simgear/scene/util/CopyOp.hxx>
27 #include <simgear/scene/util/SplicingVisitor.hxx>
28 #include <simgear/scene/util/SGReaderWriterOptions.hxx>
30 #include <simgear/structure/exception.hxx>
31 #include <simgear/structure/Singleton.hxx>
32 #include <simgear/props/props.hxx>
33 #include <simgear/props/props_io.hxx>
34 #include <simgear/props/condition.hxx>
41 SGLoadTexture2D(bool staticTexture, const std::string& path,
42 const osgDB::ReaderWriter::Options* options,
43 bool wrapu, bool wrapv, int)
47 image = osgDB::readImageFile(path, options);
49 image = osgDB::readImageFile(path);
50 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
51 texture->setImage(image);
53 texture->setDataVariance(osg::Object::STATIC);
55 texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
57 texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
59 texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
61 texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
67 if (s <= t && 32 <= s) {
68 SGSceneFeatures::instance()->setTextureCompression(texture.get());
69 } else if (t < s && 32 <= t) {
70 SGSceneFeatures::instance()->setTextureCompression(texture.get());
74 return texture.release();
81 using simgear::CopyOp;
83 Node* copyModel(Node* model)
85 const CopyOp::CopyFlags flags = (CopyOp::DEEP_COPY_ALL
86 & ~CopyOp::DEEP_COPY_TEXTURES
87 & ~CopyOp::DEEP_COPY_IMAGES
88 & ~CopyOp::DEEP_COPY_STATESETS
89 & ~CopyOp::DEEP_COPY_STATEATTRIBUTES
90 & ~CopyOp::DEEP_COPY_ARRAYS
91 & ~CopyOp::DEEP_COPY_PRIMITIVES
92 // This will preserve display lists ...
93 & ~CopyOp::DEEP_COPY_DRAWABLES
94 & ~CopyOp::DEEP_COPY_SHAPES);
95 return (CopyOp(flags))(model);
98 TextureUpdateVisitor::TextureUpdateVisitor(const osgDB::FilePathList& pathList) :
99 NodeAndDrawableVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN),
104 void TextureUpdateVisitor::apply(Node& node)
106 StateSet* stateSet = cloneStateSet(node.getStateSet());
108 node.setStateSet(stateSet);
112 void TextureUpdateVisitor::apply(Drawable& drawable)
114 StateSet* stateSet = cloneStateSet(drawable.getStateSet());
116 drawable.setStateSet(stateSet);
119 Texture2D* TextureUpdateVisitor::textureReplace(int unit, const StateAttribute* attr)
121 using namespace osgDB;
122 const Texture2D* texture = dynamic_cast<const Texture2D*>(attr);
127 const Image* image = texture->getImage();
128 const string* fullFilePath = 0;
130 // The currently loaded file name
131 fullFilePath = &image->getFileName();
134 fullFilePath = &texture->getName();
137 string fileName = getSimpleFileName(*fullFilePath);
138 if (fileName.empty())
140 // The name that should be found with the current database path
141 string fullLiveryFile = findFileInPath(fileName, _pathList);
142 // If it is empty or they are identical then there is nothing to do
143 if (fullLiveryFile.empty() || fullLiveryFile == *fullFilePath)
145 Image* newImage = readImageFile(fullLiveryFile);
148 CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
149 Texture2D* newTexture = static_cast<Texture2D*>(copyOp(texture));
153 newTexture->setImage(newImage);
158 StateSet* TextureUpdateVisitor::cloneStateSet(const StateSet* stateSet)
160 typedef std::pair<int, Texture2D*> Tex2D;
161 vector<Tex2D> newTextures;
162 StateSet* result = 0;
166 int numUnits = stateSet->getTextureAttributeList().size();
168 for (int i = 0; i < numUnits; ++i) {
169 const StateAttribute* attr
170 = stateSet->getTextureAttribute(i, StateAttribute::TEXTURE);
171 Texture2D* newTexture = textureReplace(i, attr);
173 newTextures.push_back(Tex2D(i, newTexture));
175 if (!newTextures.empty()) {
176 result = static_cast<StateSet*>(stateSet->clone(CopyOp()));
177 for (vector<Tex2D>::iterator i = newTextures.begin();
178 i != newTextures.end();
180 result->setTextureAttribute(i->first, i->second);
187 UserDataCopyVisitor::UserDataCopyVisitor() :
188 NodeVisitor(NodeVisitor::NODE_VISITOR,
189 NodeVisitor::TRAVERSE_ALL_CHILDREN)
193 void UserDataCopyVisitor::apply(Node& node)
195 ref_ptr<SGSceneUserData> userData;
196 userData = SGSceneUserData::getSceneUserData(&node);
197 if (userData.valid()) {
198 SGSceneUserData* newUserData = new SGSceneUserData(*userData);
199 newUserData->setVelocity(0);
200 node.setUserData(newUserData);
202 node.traverse(*this);
207 class MakeEffectVisitor : public SplicingVisitor
210 typedef std::map<string, SGPropertyNode_ptr> EffectMap;
211 using SplicingVisitor::apply;
212 MakeEffectVisitor(const SGReaderWriterOptions* options = 0)
216 virtual void apply(osg::Group& node);
217 virtual void apply(osg::Geode& geode);
218 EffectMap& getEffectMap() { return _effectMap; }
219 const EffectMap& getEffectMap() const { return _effectMap; }
220 void setDefaultEffect(SGPropertyNode* effect)
222 _currentEffectParent = effect;
224 SGPropertyNode* getDefaultEffect() { return _currentEffectParent; }
226 EffectMap _effectMap;
227 SGPropertyNode_ptr _currentEffectParent;
228 osg::ref_ptr<const SGReaderWriterOptions> _options;
231 void MakeEffectVisitor::apply(osg::Group& node)
233 SGPropertyNode_ptr savedEffectRoot;
234 const string& nodeName = node.getName();
235 bool restoreEffect = false;
236 if (!nodeName.empty()) {
237 EffectMap::iterator eitr = _effectMap.find(nodeName);
238 if (eitr != _effectMap.end()) {
239 savedEffectRoot = _currentEffectParent;
240 _currentEffectParent = eitr->second;
241 restoreEffect = true;
244 SplicingVisitor::apply(node);
245 // If a new node was created, copy the user data too.
246 ref_ptr<SGSceneUserData> userData = SGSceneUserData::getSceneUserData(&node);
247 if (userData.valid() && _childStack.back().back().get() != &node)
248 _childStack.back().back()->setUserData(new SGSceneUserData(*userData));
250 _currentEffectParent = savedEffectRoot;
253 void MakeEffectVisitor::apply(osg::Geode& geode)
255 if (pushNode(getNewNode(geode)))
257 osg::StateSet* ss = geode.getStateSet();
262 SGPropertyNode_ptr ssRoot = new SGPropertyNode;
263 makeParametersFromStateSet(ssRoot, ss);
264 SGPropertyNode_ptr effectRoot = new SGPropertyNode;
265 effect::mergePropertyTrees(effectRoot, ssRoot, _currentEffectParent);
266 Effect* effect = makeEffect(effectRoot, true, _options.get());
267 EffectGeode* eg = dynamic_cast<EffectGeode*>(&geode);
269 eg->setEffect(effect);
271 eg = new EffectGeode;
272 eg->setEffect(effect);
273 ref_ptr<SGSceneUserData> userData = SGSceneUserData::getSceneUserData(&geode);
274 if (userData.valid())
275 eg->setUserData(new SGSceneUserData(*userData));
276 for (unsigned i = 0; i < geode.getNumDrawables(); ++i) {
277 osg::Drawable *drawable = geode.getDrawable(i);
278 eg->addDrawable(drawable);
280 // Generate tangent vectors etc if needed
281 osg::Geometry *geom = dynamic_cast<osg::Geometry*>(drawable);
282 if(geom) eg->runGenerators(geom);
285 pushResultNode(&geode, eg);
293 class DefaultEffect : public simgear::Singleton<DefaultEffect>
298 _effect = new SGPropertyNode;
299 makeChild(_effect.ptr(), "inherits-from")
300 ->setStringValue("Effects/model-default");
302 virtual ~DefaultEffect() {}
303 SGPropertyNode* getEffect() { return _effect.ptr(); }
305 SGPropertyNode_ptr _effect;
309 ref_ptr<Node> instantiateEffects(osg::Node* modelGroup,
310 PropertyList& effectProps,
311 const SGReaderWriterOptions* options)
313 SGPropertyNode_ptr defaultEffectPropRoot;
314 MakeEffectVisitor visitor(options);
315 MakeEffectVisitor::EffectMap& emap = visitor.getEffectMap();
316 for (PropertyList::iterator itr = effectProps.begin(),
317 end = effectProps.end();
321 SGPropertyNode_ptr configNode = *itr;
322 std::vector<SGPropertyNode_ptr> objectNames =
323 configNode->getChildren("object-name");
324 SGPropertyNode* defaultNode = configNode->getChild("default");
325 if (defaultNode && defaultNode->getValue<bool>())
326 defaultEffectPropRoot = configNode;
327 BOOST_FOREACH(SGPropertyNode_ptr objNameNode, objectNames) {
328 emap.insert(make_pair(objNameNode->getStringValue(), configNode));
330 configNode->removeChild("default");
331 configNode->removeChildren("object-name");
333 if (!defaultEffectPropRoot)
334 defaultEffectPropRoot = DefaultEffect::instance()->getEffect();
335 visitor.setDefaultEffect(defaultEffectPropRoot.ptr());
336 modelGroup->accept(visitor);
337 osg::NodeList& result = visitor.getResults();
338 return ref_ptr<Node>(result[0].get());