]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/model.cxx
1ea486f0d13afc5b1dae4353c449539f77df3d85
[simgear.git] / simgear / scene / model / model.cxx
1 // model.cxx - manage a 3D aircraft model.
2 // Written by David Megginson, started 2002.
3 //
4 // This file is in the Public Domain, and comes with no warranty.
5
6 #ifdef HAVE_CONFIG_H
7 #include <simgear_config.h>
8 #endif
9
10 #include <utility>
11
12 #include <boost/foreach.hpp>
13
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>
20
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
29
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>
35
36 #include "SGReaderWriterXMLOptions.hxx"
37 #include "model.hxx"
38
39 using std::vector;
40
41 osg::Texture2D*
42 SGLoadTexture2D(bool staticTexture, const std::string& path,
43                 const osgDB::ReaderWriter::Options* options,
44                 bool wrapu, bool wrapv, int)
45 {
46   osg::Image* image;
47   if (options)
48     image = osgDB::readImageFile(path, options);
49   else
50     image = osgDB::readImageFile(path);
51   osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
52   texture->setImage(image);
53   if (staticTexture)
54     texture->setDataVariance(osg::Object::STATIC);
55   if (wrapu)
56     texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
57   else
58     texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
59   if (wrapv)
60     texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
61   else
62     texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
63
64   if (image) {
65     int s = image->s();
66     int t = image->t();
67
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());
72     }
73   }
74
75   return texture.release();
76 }
77
78 namespace simgear
79 {
80 using namespace std;
81 using namespace osg;
82 using simgear::CopyOp;
83
84 Node* copyModel(Node* model)
85 {
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);
97 }
98
99 TextureUpdateVisitor::TextureUpdateVisitor(const osgDB::FilePathList& pathList) :
100     NodeAndDrawableVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN),
101     _pathList(pathList)
102 {
103 }
104
105 void TextureUpdateVisitor::apply(Node& node)
106 {
107     StateSet* stateSet = cloneStateSet(node.getStateSet());
108     if (stateSet)
109         node.setStateSet(stateSet);
110     traverse(node);
111 }
112
113 void TextureUpdateVisitor::apply(Drawable& drawable)
114 {
115     StateSet* stateSet = cloneStateSet(drawable.getStateSet());
116     if (stateSet)
117         drawable.setStateSet(stateSet);
118 }
119
120 Texture2D* TextureUpdateVisitor::textureReplace(int unit, const StateAttribute* attr)
121 {
122     using namespace osgDB;
123     const Texture2D* texture = dynamic_cast<const Texture2D*>(attr);
124
125     if (!texture)
126         return 0;
127
128     const Image* image = texture->getImage();
129     const string* fullFilePath = 0;
130     if (image) {
131         // The currently loaded file name
132         fullFilePath = &image->getFileName();
133
134     } else {
135         fullFilePath = &texture->getName();
136     }
137     // The short name
138     string fileName = getSimpleFileName(*fullFilePath);
139     if (fileName.empty())
140         return 0;
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)
145         return 0;
146     Image* newImage = readImageFile(fullLiveryFile);
147     if (!newImage)
148         return 0;
149     CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
150     Texture2D* newTexture = static_cast<Texture2D*>(copyOp(texture));
151     if (!newTexture) {
152         return 0;
153     } else {
154         newTexture->setImage(newImage);
155         return newTexture;
156     }
157 }
158
159 StateSet* TextureUpdateVisitor::cloneStateSet(const StateSet* stateSet)
160 {
161     typedef std::pair<int, Texture2D*> Tex2D;
162     vector<Tex2D> newTextures;
163     StateSet* result = 0;
164
165     if (!stateSet)
166         return 0;
167     int numUnits = stateSet->getTextureAttributeList().size();
168     if (numUnits > 0) {
169         for (int i = 0; i < numUnits; ++i) {
170             const StateAttribute* attr
171                 = stateSet->getTextureAttribute(i, StateAttribute::TEXTURE);
172             Texture2D* newTexture = textureReplace(i, attr);
173             if (newTexture)
174                 newTextures.push_back(Tex2D(i, newTexture));
175         }
176         if (!newTextures.empty()) {
177             result = static_cast<StateSet*>(stateSet->clone(CopyOp()));
178             for (vector<Tex2D>::iterator i = newTextures.begin();
179                  i != newTextures.end();
180                  ++i) {
181                 result->setTextureAttribute(i->first, i->second);
182             }
183         }
184     }
185     return result;
186 }
187
188 UserDataCopyVisitor::UserDataCopyVisitor() :
189     NodeVisitor(NodeVisitor::NODE_VISITOR,
190                 NodeVisitor::TRAVERSE_ALL_CHILDREN)
191 {
192 }
193
194 void UserDataCopyVisitor::apply(Node& node)
195 {
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);
202     }
203     node.traverse(*this);
204 }
205
206 namespace
207 {
208 class MakeEffectVisitor : public SplicingVisitor
209 {
210 public:
211     typedef std::map<string, SGPropertyNode_ptr> EffectMap;
212     using SplicingVisitor::apply;
213     MakeEffectVisitor(const SGReaderWriterXMLOptions* options = 0)
214         : _options(options)
215     {
216     }
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)
222     {
223         _currentEffectParent = effect;
224     }
225     SGPropertyNode* getDefaultEffect() { return _currentEffectParent; }
226 protected:
227     EffectMap _effectMap;
228     SGPropertyNode_ptr _currentEffectParent;
229     osg::ref_ptr<const SGReaderWriterXMLOptions> _options;
230 };
231
232 void MakeEffectVisitor::apply(osg::Group& node)
233 {
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;
243         }
244     }
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));
250     if (restoreEffect)
251         _currentEffectParent = savedEffectRoot;
252 }
253
254 void MakeEffectVisitor::apply(osg::Geode& geode)
255 {
256     if (pushNode(getNewNode(geode)))
257         return;
258     osg::StateSet* ss = geode.getStateSet();
259     if (!ss) {
260         pushNode(&geode);
261         return;
262     }
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);
269     if (eg) {
270         eg->setEffect(effect);
271     } else {
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             eg->addDrawable(geode.getDrawable(i));
279     }
280     pushResultNode(&geode, eg);
281
282 }
283
284 }
285
286 namespace
287 {
288 class DefaultEffect : public simgear::Singleton<DefaultEffect>
289 {
290 public:
291     DefaultEffect()
292     {
293         _effect = new SGPropertyNode;
294         makeChild(_effect.ptr(), "inherits-from")
295             ->setStringValue("Effects/model-default");
296     }
297     virtual ~DefaultEffect() {}
298     SGPropertyNode* getEffect() { return _effect.ptr(); }
299 protected:
300     SGPropertyNode_ptr _effect;
301 };
302 }
303
304 ref_ptr<Node> instantiateEffects(osg::Node* modelGroup,
305                                  PropertyList& effectProps,
306                                  const SGReaderWriterXMLOptions* options)
307 {
308     SGPropertyNode_ptr defaultEffectPropRoot;
309     MakeEffectVisitor visitor(options);
310     MakeEffectVisitor::EffectMap& emap = visitor.getEffectMap();
311     for (PropertyList::iterator itr = effectProps.begin(),
312              end = effectProps.end();
313          itr != end;
314         ++itr)
315     {
316         SGPropertyNode_ptr configNode = *itr;
317         std::vector<SGPropertyNode_ptr> objectNames =
318             configNode->getChildren("object-name");
319         SGPropertyNode* defaultNode = configNode->getChild("default");
320         if (defaultNode && defaultNode->getValue<bool>())
321             defaultEffectPropRoot = configNode;
322         BOOST_FOREACH(SGPropertyNode_ptr objNameNode, objectNames) {
323             emap.insert(make_pair(objNameNode->getStringValue(), configNode));
324         }
325         configNode->removeChild("default");
326         configNode->removeChildren("object-name");
327     }
328     if (!defaultEffectPropRoot)
329         defaultEffectPropRoot = DefaultEffect::instance()->getEffect();
330     visitor.setDefaultEffect(defaultEffectPropRoot.ptr());
331     modelGroup->accept(visitor);
332     osg::NodeList& result = visitor.getResults();
333     return ref_ptr<Node>(result[0].get());
334 }
335 }
336 // end of model.cxx