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>
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>
36 #include "SGReaderWriterXMLOptions.hxx"
42 SGLoadTexture2D(bool staticTexture, const std::string& path,
43 const osgDB::ReaderWriter::Options* options,
44 bool wrapu, bool wrapv, int)
48 image = osgDB::readImageFile(path, options);
50 image = osgDB::readImageFile(path);
51 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
52 texture->setImage(image);
54 texture->setDataVariance(osg::Object::STATIC);
56 texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
58 texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
60 texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
62 texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
68 if (s <= t && 32 <= s) {
69 SGSceneFeatures::instance()->setTextureCompression(texture.get());
70 } else if (t < s && 32 <= t) {
71 SGSceneFeatures::instance()->setTextureCompression(texture.get());
75 return texture.release();
82 using simgear::CopyOp;
84 Node* copyModel(Node* model)
86 const CopyOp::CopyFlags flags = (CopyOp::DEEP_COPY_ALL
87 & ~CopyOp::DEEP_COPY_TEXTURES
88 & ~CopyOp::DEEP_COPY_IMAGES
89 & ~CopyOp::DEEP_COPY_STATESETS
90 & ~CopyOp::DEEP_COPY_STATEATTRIBUTES
91 & ~CopyOp::DEEP_COPY_ARRAYS
92 & ~CopyOp::DEEP_COPY_PRIMITIVES
93 // This will preserve display lists ...
94 & ~CopyOp::DEEP_COPY_DRAWABLES
95 & ~CopyOp::DEEP_COPY_SHAPES);
96 return (CopyOp(flags))(model);
99 TextureUpdateVisitor::TextureUpdateVisitor(const osgDB::FilePathList& pathList) :
100 NodeAndDrawableVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN),
105 void TextureUpdateVisitor::apply(Node& node)
107 StateSet* stateSet = cloneStateSet(node.getStateSet());
109 node.setStateSet(stateSet);
113 void TextureUpdateVisitor::apply(Drawable& drawable)
115 StateSet* stateSet = cloneStateSet(drawable.getStateSet());
117 drawable.setStateSet(stateSet);
120 Texture2D* TextureUpdateVisitor::textureReplace(int unit, const StateAttribute* attr)
122 using namespace osgDB;
123 const Texture2D* texture = dynamic_cast<const Texture2D*>(attr);
128 const Image* image = texture->getImage();
129 const string* fullFilePath = 0;
131 // The currently loaded file name
132 fullFilePath = &image->getFileName();
135 fullFilePath = &texture->getName();
138 string fileName = getSimpleFileName(*fullFilePath);
139 if (fileName.empty())
141 // The name that should be found with the current database path
142 string fullLiveryFile = findFileInPath(fileName, _pathList);
143 // If it is empty or they are identical then there is nothing to do
144 if (fullLiveryFile.empty() || fullLiveryFile == *fullFilePath)
146 Image* newImage = readImageFile(fullLiveryFile);
149 CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
150 Texture2D* newTexture = static_cast<Texture2D*>(copyOp(texture));
154 newTexture->setImage(newImage);
159 StateSet* TextureUpdateVisitor::cloneStateSet(const StateSet* stateSet)
161 typedef std::pair<int, Texture2D*> Tex2D;
162 vector<Tex2D> newTextures;
163 StateSet* result = 0;
167 int numUnits = stateSet->getTextureAttributeList().size();
169 for (int i = 0; i < numUnits; ++i) {
170 const StateAttribute* attr
171 = stateSet->getTextureAttribute(i, StateAttribute::TEXTURE);
172 Texture2D* newTexture = textureReplace(i, attr);
174 newTextures.push_back(Tex2D(i, newTexture));
176 if (!newTextures.empty()) {
177 result = static_cast<StateSet*>(stateSet->clone(CopyOp()));
178 for (vector<Tex2D>::iterator i = newTextures.begin();
179 i != newTextures.end();
181 result->setTextureAttribute(i->first, i->second);
188 UserDataCopyVisitor::UserDataCopyVisitor() :
189 NodeVisitor(NodeVisitor::NODE_VISITOR,
190 NodeVisitor::TRAVERSE_ALL_CHILDREN)
194 void UserDataCopyVisitor::apply(Node& node)
196 ref_ptr<SGSceneUserData> userData;
197 userData = SGSceneUserData::getSceneUserData(&node);
198 if (userData.valid()) {
199 SGSceneUserData* newUserData = new SGSceneUserData(*userData);
200 newUserData->setVelocity(0);
201 node.setUserData(newUserData);
203 node.traverse(*this);
208 class MakeEffectVisitor : public SplicingVisitor
211 typedef std::map<string, SGPropertyNode_ptr> EffectMap;
212 using SplicingVisitor::apply;
213 MakeEffectVisitor(const SGReaderWriterXMLOptions* options = 0)
217 virtual void apply(osg::Group& node);
218 virtual void apply(osg::Geode& geode);
219 EffectMap& getEffectMap() { return _effectMap; }
220 const EffectMap& getEffectMap() const { return _effectMap; }
221 void setDefaultEffect(SGPropertyNode* effect)
223 _currentEffectParent = effect;
225 SGPropertyNode* getDefaultEffect() { return _currentEffectParent; }
227 EffectMap _effectMap;
228 SGPropertyNode_ptr _currentEffectParent;
229 osg::ref_ptr<const SGReaderWriterXMLOptions> _options;
232 void MakeEffectVisitor::apply(osg::Group& node)
234 SGPropertyNode_ptr savedEffectRoot;
235 const string& nodeName = node.getName();
236 bool restoreEffect = false;
237 if (!nodeName.empty()) {
238 EffectMap::iterator eitr = _effectMap.find(nodeName);
239 if (eitr != _effectMap.end()) {
240 savedEffectRoot = _currentEffectParent;
241 _currentEffectParent = eitr->second;
242 restoreEffect = true;
245 SplicingVisitor::apply(node);
246 // If a new node was created, copy the user data too.
247 ref_ptr<SGSceneUserData> userData = SGSceneUserData::getSceneUserData(&node);
248 if (userData.valid() && _childStack.back().back().get() != &node)
249 _childStack.back().back()->setUserData(new SGSceneUserData(*userData));
251 _currentEffectParent = savedEffectRoot;
254 void MakeEffectVisitor::apply(osg::Geode& geode)
256 if (pushNode(getNewNode(geode)))
258 osg::StateSet* ss = geode.getStateSet();
263 SGPropertyNode_ptr ssRoot = new SGPropertyNode;
264 makeParametersFromStateSet(ssRoot, ss);
265 SGPropertyNode_ptr effectRoot = new SGPropertyNode;
266 effect::mergePropertyTrees(effectRoot, ssRoot, _currentEffectParent);
267 Effect* effect = makeEffect(effectRoot, true, _options);
268 EffectGeode* eg = dynamic_cast<EffectGeode*>(&geode);
270 eg->setEffect(effect);
272 eg = new EffectGeode;
273 eg->setEffect(effect);
274 ref_ptr<SGSceneUserData> userData = SGSceneUserData::getSceneUserData(&geode);
275 if (userData.valid())
276 eg->setUserData(new SGSceneUserData(*userData));
277 for (int i = 0; i < geode.getNumDrawables(); ++i) {
278 osg::Drawable *drawable = geode.getDrawable(i);
279 eg->addDrawable(drawable);
281 // Generate tangent vectors etc if needed
282 osg::Geometry *geom = dynamic_cast<osg::Geometry*>(drawable);
283 if(geom) eg->runGenerators(geom);
286 pushResultNode(&geode, eg);
294 class DefaultEffect : public simgear::Singleton<DefaultEffect>
299 _effect = new SGPropertyNode;
300 makeChild(_effect.ptr(), "inherits-from")
301 ->setStringValue("Effects/model-default");
303 virtual ~DefaultEffect() {}
304 SGPropertyNode* getEffect() { return _effect.ptr(); }
306 SGPropertyNode_ptr _effect;
310 ref_ptr<Node> instantiateEffects(osg::Node* modelGroup,
311 PropertyList& effectProps,
312 const SGReaderWriterXMLOptions* options)
314 SGPropertyNode_ptr defaultEffectPropRoot;
315 MakeEffectVisitor visitor(options);
316 MakeEffectVisitor::EffectMap& emap = visitor.getEffectMap();
317 for (PropertyList::iterator itr = effectProps.begin(),
318 end = effectProps.end();
322 SGPropertyNode_ptr configNode = *itr;
323 std::vector<SGPropertyNode_ptr> objectNames =
324 configNode->getChildren("object-name");
325 SGPropertyNode* defaultNode = configNode->getChild("default");
326 if (defaultNode && defaultNode->getValue<bool>())
327 defaultEffectPropRoot = configNode;
328 BOOST_FOREACH(SGPropertyNode_ptr objNameNode, objectNames) {
329 emap.insert(make_pair(objNameNode->getStringValue(), configNode));
331 configNode->removeChild("default");
332 configNode->removeChildren("object-name");
334 if (!defaultEffectPropRoot)
335 defaultEffectPropRoot = DefaultEffect::instance()->getEffect();
336 visitor.setDefaultEffect(defaultEffectPropRoot.ptr());
337 modelGroup->accept(visitor);
338 osg::NodeList& result = visitor.getResults();
339 return ref_ptr<Node>(result[0].get());