]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/SGLightAnimation.cxx
Move vector property templates to separate header file.
[simgear.git] / simgear / scene / model / SGLightAnimation.cxx
1 // Copyright (C) 2011 Frederic Bouvier (fredfgfs01@free.fr)
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #ifdef HAVE_CONFIG_H
19 #  include <simgear_config.h>
20 #endif
21
22 #include <boost/lexical_cast.hpp>
23
24 #include "animation.hxx"
25 #include "ConditionNode.hxx"
26
27 #include <osg/Geometry>
28 #include <osg/MatrixTransform>
29 #include <simgear/props/vectorPropTemplates.hxx>
30 #include <simgear/scene/material/EffectGeode.hxx>
31 #include <simgear/scene/material/Technique.hxx>
32 #include <simgear/scene/material/Pass.hxx>
33 #include <simgear/scene/util/CopyOp.hxx>
34 #include <simgear/scene/util/OsgMath.hxx>
35 #include <boost/scoped_array.hpp>
36 #include <boost/foreach.hpp>
37
38 typedef std::map<string, osg::observer_ptr<simgear::Effect> > EffectMap;
39 static EffectMap lightEffectMap;
40
41 #define GET_COLOR_VALUE(n) \
42     SGVec4d( getConfig()->getDoubleValue(n "/r"), \
43                 getConfig()->getDoubleValue(n "/g"), \
44                 getConfig()->getDoubleValue(n "/b"), \
45                 getConfig()->getDoubleValue(n "/a") )
46
47 class SGLightAnimation::UpdateCallback : public osg::NodeCallback {
48 public:
49     UpdateCallback(string k, const SGExpressiond* v, SGVec4d a, SGVec4d d, SGVec4d s) :
50         _key(k),
51         _ambient(a),
52         _diffuse(d),
53         _specular(s),
54         _animationValue(v)
55     {
56         _prev_values[k] = -1;
57     }
58     virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
59     {
60         double dim = _animationValue->getValue();
61         if (dim != _prev_values[_key]) {
62             _prev_values[_key] = dim;
63
64             osg::ref_ptr<simgear::Effect> effect;
65             EffectMap::iterator iter = lightEffectMap.find(_key);
66             if (iter != lightEffectMap.end() && iter->second.lock(effect)) {
67                 SGPropertyNode* params = effect->parametersProp;
68                 params->getNode("ambient")->setValue(_ambient * dim);
69                 params->getNode("diffuse")->setValue(_diffuse * dim);
70                 params->getNode("specular")->setValue(_specular * dim);
71                 BOOST_FOREACH(osg::ref_ptr<simgear::Technique>& technique, effect->techniques)
72                 {
73                     BOOST_FOREACH(osg::ref_ptr<simgear::Pass>& pass, technique->passes)
74                     {
75                         osg::Uniform* amb = pass->getUniform("Ambient");
76                         if (amb)
77                             amb->set(toOsg(_ambient) * dim);
78                         osg::Uniform* dif = pass->getUniform("Diffuse");
79                         if (dif)
80                             dif->set(toOsg(_diffuse) * dim);
81                         osg::Uniform* spe = pass->getUniform("Specular");
82                         if (spe)
83                             spe->set(toOsg(_specular) * dim);
84                     }
85                 }
86             }
87         }
88         traverse(node, nv);
89     }
90 public:
91     string _key;
92     SGVec4d _ambient;
93     SGVec4d _diffuse;
94     SGVec4d _specular;
95     SGSharedPtr<SGExpressiond const> _animationValue;
96
97     typedef std::map<string, double> PrevValueMap;
98     static PrevValueMap _prev_values;
99 };
100 SGLightAnimation::UpdateCallback::PrevValueMap SGLightAnimation::UpdateCallback::_prev_values;
101
102 SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode,
103                                    SGPropertyNode* modelRoot,
104                                    const string &path, int i) :
105     SGAnimation(configNode, modelRoot)
106 {
107     _light_type = getConfig()->getStringValue("light-type");
108     _position = SGVec3d( getConfig()->getDoubleValue("position/x"), getConfig()->getDoubleValue("position/y"), getConfig()->getDoubleValue("position/z") );
109     _direction = SGVec3d( getConfig()->getDoubleValue("direction/x"), getConfig()->getDoubleValue("direction/y"), getConfig()->getDoubleValue("direction/z") );
110     double l = length(_direction);
111     if (l > 0.001) _direction /= l;
112     _ambient = GET_COLOR_VALUE("ambient");
113     _diffuse = GET_COLOR_VALUE("diffuse");
114     _specular = GET_COLOR_VALUE("specular");
115     _attenuation = SGVec3d( getConfig()->getDoubleValue("attenuation/c"), getConfig()->getDoubleValue("attenuation/l"), getConfig()->getDoubleValue("attenuation/q") );
116     _exponent = getConfig()->getDoubleValue("exponent");
117     _cutoff = getConfig()->getDoubleValue("cutoff");
118     _near = getConfig()->getDoubleValue("near-m");
119     _far = getConfig()->getDoubleValue("far-m");
120     _key = path + ";" + boost::lexical_cast<string>( i );
121
122     SGConstPropertyNode_ptr dim_factor = configNode->getChild("dim-factor");
123     if (dim_factor.valid()) {
124         _animationValue = read_value(dim_factor, modelRoot, "", 0, 1);
125     }
126 }
127
128 osg::Group*
129 SGLightAnimation::createAnimationGroup(osg::Group& parent)
130 {
131     osg::Group* grp = new osg::Group;
132     grp->setName("light animation node");
133     if (_animationValue.valid())
134         grp->setUpdateCallback(new UpdateCallback(_key, _animationValue, _ambient, _diffuse, _specular));
135     parent.addChild(grp);
136     grp->setNodeMask( simgear::MODELLIGHT_BIT );
137     return grp;
138 }
139
140 void
141 SGLightAnimation::install(osg::Node& node)
142 {
143     SGAnimation::install(node);
144
145     if (_light_type == "spot") {
146
147         osg::ref_ptr<simgear::Effect> effect;
148         EffectMap::iterator iter = lightEffectMap.find(_key);
149         if (iter == lightEffectMap.end() || !iter->second.lock(effect)) {
150             SGPropertyNode_ptr effectProp = new SGPropertyNode;
151             makeChild(effectProp, "name")->setStringValue(_key);
152             makeChild(effectProp, "inherits-from")->setStringValue("Effects/light-spot");
153             double dim = 1.0;
154             if (_animationValue.valid())
155                 dim = _animationValue->getValue();
156
157             SGPropertyNode* params = makeChild(effectProp, "parameters");
158             params->getNode("position",true)->setValue(SGVec4d(_position.x(),_position.y(),_position.z(),1.0));
159             params->getNode("direction",true)->setValue(SGVec4d(_direction.x(),_direction.y(),_direction.z(),0.0));
160             params->getNode("ambient",true)->setValue(_ambient * dim);
161             params->getNode("diffuse",true)->setValue(_diffuse * dim);
162             params->getNode("specular",true)->setValue(_specular * dim);
163             params->getNode("attenuation",true)->setValue(_attenuation);
164             params->getNode("exponent",true)->setValue(_exponent);
165             params->getNode("cutoff",true)->setValue(_cutoff);
166             params->getNode("cosCutoff",true)->setValue( cos(_cutoff*SG_DEGREES_TO_RADIANS) );
167             params->getNode("near",true)->setValue(_near);
168             params->getNode("far",true)->setValue(_far);
169
170             effect = simgear::makeEffect(effectProp, true);
171             if (iter==lightEffectMap.end())
172                 lightEffectMap.insert(EffectMap::value_type(_key, effect));
173             else
174                 iter->second = effect;
175         } else {
176             effect = iter->second.get();
177         }
178
179         node.setNodeMask( simgear::MODELLIGHT_BIT );
180         simgear::EffectGeode* geode = dynamic_cast<simgear::EffectGeode*>(&node);
181         if (geode == 0) {
182             osg::Group* grp = node.asGroup();
183             if (grp != 0) {
184                 for (size_t i=0; i<grp->getNumChildren(); ++i) {
185                     geode = dynamic_cast<simgear::EffectGeode*>(grp->getChild(i));
186                     if (geode)
187                         geode->setEffect(effect);
188                 }
189             }
190         }
191     }
192     else if (_light_type == "point") {
193
194         osg::ref_ptr<simgear::Effect> effect;
195         EffectMap::iterator iter = lightEffectMap.find(_key);
196         if (iter == lightEffectMap.end() || !iter->second.lock(effect)) {
197             SGPropertyNode_ptr effectProp = new SGPropertyNode;
198             makeChild(effectProp, "name")->setStringValue(_key);
199             makeChild(effectProp, "inherits-from")->setStringValue("Effects/light-point");
200             double dim = 1.0;
201             if (_animationValue.valid())
202                 dim = _animationValue->getValue();
203
204             SGPropertyNode* params = makeChild(effectProp, "parameters");
205             params->getNode("position",true)->setValue(SGVec4d(_position.x(),_position.y(),_position.z(),1.0));
206             params->getNode("ambient",true)->setValue(_ambient * dim);
207             params->getNode("diffuse",true)->setValue(_diffuse * dim);
208             params->getNode("specular",true)->setValue(_specular * dim);
209             params->getNode("attenuation",true)->setValue(_attenuation);
210             params->getNode("near",true)->setValue(_near);
211             params->getNode("far",true)->setValue(_far);
212
213             effect = simgear::makeEffect(effectProp, true);
214             if (iter==lightEffectMap.end())
215                 lightEffectMap.insert(EffectMap::value_type(_key, effect));
216             else
217                 iter->second = effect;
218         } else {
219             effect = iter->second.get();
220         }
221
222         node.setNodeMask( simgear::MODELLIGHT_BIT );
223         simgear::EffectGeode* geode = dynamic_cast<simgear::EffectGeode*>(&node);
224         if (geode == 0) {
225             osg::Group* grp = node.asGroup();
226             if (grp != 0) {
227                 for (size_t i=0; i<grp->getNumChildren(); ++i) {
228                     geode = dynamic_cast<simgear::EffectGeode*>(grp->getChild(i));
229                     if (geode)
230                         geode->setEffect(effect);
231                 }
232             }
233         }
234     }
235 }