1 // Copyright (C) 2011 Frederic Bouvier (fredfgfs01@free.fr)
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.
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.
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.
19 # include <simgear_config.h>
22 #include <boost/lexical_cast.hpp>
24 #include "animation.hxx"
25 #include "ConditionNode.hxx"
27 #include <osg/Geometry>
28 #include <osg/MatrixTransform>
29 #include <simgear/scene/material/EffectGeode.hxx>
30 #include <simgear/scene/material/Technique.hxx>
31 #include <simgear/scene/material/Pass.hxx>
32 #include <simgear/scene/util/CopyOp.hxx>
33 #include <simgear/scene/util/OsgMath.hxx>
34 #include <boost/scoped_array.hpp>
35 #include <boost/foreach.hpp>
37 typedef std::map<string, osg::observer_ptr<simgear::Effect> > EffectMap;
38 static EffectMap lightEffectMap;
40 #define GET_COLOR_VALUE(n) \
41 SGVec4d( getConfig()->getDoubleValue(n "/r"), \
42 getConfig()->getDoubleValue(n "/g"), \
43 getConfig()->getDoubleValue(n "/b"), \
44 getConfig()->getDoubleValue(n "/a") )
46 class SGLightAnimation::UpdateCallback : public osg::NodeCallback {
48 UpdateCallback(string k, const SGExpressiond* v, SGVec4d a, SGVec4d d, SGVec4d s) :
57 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
59 double dim = _animationValue->getValue();
60 if (dim != _prev_values[_key]) {
61 _prev_values[_key] = dim;
63 osg::ref_ptr<simgear::Effect> effect;
64 EffectMap::iterator iter = lightEffectMap.find(_key);
65 if (iter != lightEffectMap.end() && iter->second.lock(effect)) {
66 SGPropertyNode* params = effect->parametersProp;
67 params->getNode("ambient")->setValue(_ambient * dim);
68 params->getNode("diffuse")->setValue(_diffuse * dim);
69 params->getNode("specular")->setValue(_specular * dim);
70 BOOST_FOREACH(osg::ref_ptr<simgear::Technique>& technique, effect->techniques)
72 BOOST_FOREACH(osg::ref_ptr<simgear::Pass>& pass, technique->passes)
74 osg::Uniform* amb = pass->getUniform("Ambient");
76 amb->set(toOsg(_ambient) * dim);
77 osg::Uniform* dif = pass->getUniform("Diffuse");
79 dif->set(toOsg(_diffuse) * dim);
80 osg::Uniform* spe = pass->getUniform("Specular");
82 spe->set(toOsg(_specular) * dim);
94 SGSharedPtr<SGExpressiond const> _animationValue;
96 typedef std::map<string, double> PrevValueMap;
97 static PrevValueMap _prev_values;
99 SGLightAnimation::UpdateCallback::PrevValueMap SGLightAnimation::UpdateCallback::_prev_values;
101 SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode,
102 SGPropertyNode* modelRoot,
103 const string &path, int i) :
104 SGAnimation(configNode, modelRoot)
106 _light_type = getConfig()->getStringValue("light-type");
107 _position = SGVec3d( getConfig()->getDoubleValue("position/x"), getConfig()->getDoubleValue("position/y"), getConfig()->getDoubleValue("position/z") );
108 _direction = SGVec3d( getConfig()->getDoubleValue("direction/x"), getConfig()->getDoubleValue("direction/y"), getConfig()->getDoubleValue("direction/z") );
109 double l = length(_direction);
110 if (l > 0.001) _direction /= l;
111 _ambient = GET_COLOR_VALUE("ambient");
112 _diffuse = GET_COLOR_VALUE("diffuse");
113 _specular = GET_COLOR_VALUE("specular");
114 _attenuation = SGVec3d( getConfig()->getDoubleValue("attenuation/c"), getConfig()->getDoubleValue("attenuation/l"), getConfig()->getDoubleValue("attenuation/q") );
115 _exponent = getConfig()->getDoubleValue("exponent");
116 _cutoff = getConfig()->getDoubleValue("cutoff");
117 _near = getConfig()->getDoubleValue("near-m");
118 _far = getConfig()->getDoubleValue("far-m");
119 _key = path + ";" + boost::lexical_cast<string>( i );
121 SGConstPropertyNode_ptr dim_factor = configNode->getChild("dim-factor");
122 if (dim_factor.valid()) {
123 _animationValue = read_value(dim_factor, modelRoot, "", 0, 1);
128 SGLightAnimation::createAnimationGroup(osg::Group& parent)
130 osg::Group* grp = new osg::Group;
131 grp->setName("light animation node");
132 if (_animationValue.valid())
133 grp->setUpdateCallback(new UpdateCallback(_key, _animationValue, _ambient, _diffuse, _specular));
134 parent.addChild(grp);
135 grp->setNodeMask( simgear::MODELLIGHT_BIT );
140 SGLightAnimation::install(osg::Node& node)
142 SGAnimation::install(node);
144 if (_light_type == "spot") {
146 osg::ref_ptr<simgear::Effect> effect;
147 EffectMap::iterator iter = lightEffectMap.find(_key);
148 if (iter == lightEffectMap.end() || !iter->second.lock(effect)) {
149 SGPropertyNode_ptr effectProp = new SGPropertyNode;
150 makeChild(effectProp, "name")->setStringValue(_key);
151 makeChild(effectProp, "inherits-from")->setStringValue("Effects/light-spot");
153 if (_animationValue.valid())
154 dim = _animationValue->getValue();
156 SGPropertyNode* params = makeChild(effectProp, "parameters");
157 params->getNode("position",true)->setValue(SGVec4d(_position.x(),_position.y(),_position.z(),1.0));
158 params->getNode("direction",true)->setValue(SGVec4d(_direction.x(),_direction.y(),_direction.z(),0.0));
159 params->getNode("ambient",true)->setValue(_ambient * dim);
160 params->getNode("diffuse",true)->setValue(_diffuse * dim);
161 params->getNode("specular",true)->setValue(_specular * dim);
162 params->getNode("attenuation",true)->setValue(_attenuation);
163 params->getNode("exponent",true)->setValue(_exponent);
164 params->getNode("cutoff",true)->setValue(_cutoff);
165 params->getNode("cosCutoff",true)->setValue( cos(_cutoff*SG_DEGREES_TO_RADIANS) );
166 params->getNode("near",true)->setValue(_near);
167 params->getNode("far",true)->setValue(_far);
169 effect = simgear::makeEffect(effectProp, true);
170 if (iter==lightEffectMap.end())
171 lightEffectMap.insert(EffectMap::value_type(_key, effect));
173 iter->second = effect;
175 effect = iter->second.get();
178 node.setNodeMask( simgear::MODELLIGHT_BIT );
179 simgear::EffectGeode* geode = dynamic_cast<simgear::EffectGeode*>(&node);
181 osg::Group* grp = node.asGroup();
183 for (size_t i=0; i<grp->getNumChildren(); ++i) {
184 geode = dynamic_cast<simgear::EffectGeode*>(grp->getChild(i));
186 geode->setEffect(effect);
191 else if (_light_type == "point") {
193 osg::ref_ptr<simgear::Effect> effect;
194 EffectMap::iterator iter = lightEffectMap.find(_key);
195 if (iter == lightEffectMap.end() || !iter->second.lock(effect)) {
196 SGPropertyNode_ptr effectProp = new SGPropertyNode;
197 makeChild(effectProp, "name")->setStringValue(_key);
198 makeChild(effectProp, "inherits-from")->setStringValue("Effects/light-point");
200 if (_animationValue.valid())
201 dim = _animationValue->getValue();
203 SGPropertyNode* params = makeChild(effectProp, "parameters");
204 params->getNode("position",true)->setValue(SGVec4d(_position.x(),_position.y(),_position.z(),1.0));
205 params->getNode("ambient",true)->setValue(_ambient * dim);
206 params->getNode("diffuse",true)->setValue(_diffuse * dim);
207 params->getNode("specular",true)->setValue(_specular * dim);
208 params->getNode("attenuation",true)->setValue(_attenuation);
209 params->getNode("near",true)->setValue(_near);
210 params->getNode("far",true)->setValue(_far);
212 effect = simgear::makeEffect(effectProp, true);
213 if (iter==lightEffectMap.end())
214 lightEffectMap.insert(EffectMap::value_type(_key, effect));
216 iter->second = effect;
218 effect = iter->second.get();
221 node.setNodeMask( simgear::MODELLIGHT_BIT );
222 simgear::EffectGeode* geode = dynamic_cast<simgear::EffectGeode*>(&node);
224 osg::Group* grp = node.asGroup();
226 for (size_t i=0; i<grp->getNumChildren(); ++i) {
227 geode = dynamic_cast<simgear::EffectGeode*>(grp->getChild(i));
229 geode->setEffect(effect);