]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/SGLightAnimation.cxx
Full implementation of the spotlight by Effects
[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 "animation.hxx"
23 #include "ConditionNode.hxx"
24
25 #include <osg/Geometry>
26 #include <osg/MatrixTransform>
27 #include <simgear/scene/material/EffectGeode.hxx>
28 #include <boost/scoped_array.hpp>
29 #include <simgear/scene/util/CopyOp.hxx>
30
31 #define GET_COLOR_VALUE(n) \
32     SGVec4d( getConfig()->getDoubleValue(n "/r"), \
33                 getConfig()->getDoubleValue(n "/g"), \
34                 getConfig()->getDoubleValue(n "/b"), \
35                 getConfig()->getDoubleValue(n "/a") )
36
37 SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode,
38                                    SGPropertyNode* modelRoot) :
39     SGAnimation(configNode, modelRoot)
40 {
41     _position = SGVec3d( getConfig()->getDoubleValue("position/x"), getConfig()->getDoubleValue("position/y"), getConfig()->getDoubleValue("position/z") );
42     _direction = SGVec3d( getConfig()->getDoubleValue("direction/x"), getConfig()->getDoubleValue("direction/y"), getConfig()->getDoubleValue("direction/z") );
43     double l = length(_direction);
44     if (l > 0.001) _direction /= l;
45     _ambient = GET_COLOR_VALUE("ambient");
46     _diffuse = GET_COLOR_VALUE("diffuse");
47     _specular = GET_COLOR_VALUE("specular");
48     _attenuation = SGVec3d( getConfig()->getDoubleValue("attenuation/c"), getConfig()->getDoubleValue("attenuation/l"), getConfig()->getDoubleValue("attenuation/q") );
49     _exponent = getConfig()->getDoubleValue("exponent");
50     _cutoff = getConfig()->getDoubleValue("cutoff");
51     _near = getConfig()->getDoubleValue("near-m");
52     _far = getConfig()->getDoubleValue("far-m");
53 }
54
55 osg::Group*
56 SGLightAnimation::createAnimationGroup(osg::Group& parent)
57 {
58     osg::MatrixTransform* grp = new osg::MatrixTransform;
59     grp->setMatrix(osg::Matrix::translate(toOsg(_position)));
60     parent.addChild(grp);
61     grp->setNodeMask( simgear::MODELLIGHT_BIT );
62     return grp;
63 }
64
65 void
66 SGLightAnimation::install(osg::Node& node)
67 {
68     SGAnimation::install(node);
69
70     std::string light_type = getConfig()->getStringValue("light-type");
71     if (light_type == "spot") {
72
73         SGVec3d p1( _direction.z(), _direction.x(), _direction.y() ),
74         p2 = cross( _direction, p1 );
75         p1 = cross( p2, _direction );
76
77         float r2 = _far * tan( _cutoff * SG_DEGREES_TO_RADIANS );
78
79         osg::Geometry* cone = new osg::Geometry;
80 cone->setUseDisplayList(false);
81         osg::Vec3Array* vertices = new osg::Vec3Array(34);
82         (*vertices)[0] = osg::Vec3(0.0,0.0,0.0);
83         for (int i=0; i<16; ++i) {
84             (*vertices)[16-i]    = toOsg(_direction)*_far + toOsg(p1)*r2*cos( i * 2 * M_PI / 16 ) + toOsg(p2)*r2*sin( i * 2 * M_PI / 16 );
85         }
86         (*vertices)[17] = (*vertices)[1];
87
88         // Bottom
89         for (int i=0; i<16; ++i) {
90             (*vertices)[18+i]    = toOsg(_direction)*_far + toOsg(p1)*r2*cos( i * 2 * M_PI / 16 ) + toOsg(p2)*r2*sin( i * 2 * M_PI / 16 );
91         }
92
93         osg::Vec4Array* colours = new osg::Vec4Array(1);
94         (*colours)[0] = osg::Vec4d(toOsg(getConfig()->getValue<SGVec3d>("diffuse")), 1.0f);
95         cone->setColorArray(colours);
96         cone->setColorBinding(osg::Geometry::BIND_OVERALL);
97
98         osg::Vec3Array* normals = new osg::Vec3Array(1);
99         (*normals)[0] = toOsg(_direction);
100         cone->setNormalArray(normals);
101         cone->setNormalBinding(osg::Geometry::BIND_OVERALL);
102
103         cone->setVertexArray(vertices);
104         cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 0, 18 ) );
105         cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 18, 16 ) );
106
107         simgear::EffectGeode* geode = new simgear::EffectGeode;
108         geode->addDrawable( cone );
109
110         node.asGroup()->addChild( geode );
111
112         // TODO: build a cache - problem: what is the key ?
113         SGPropertyNode_ptr effectProp = new SGPropertyNode;
114         makeChild(effectProp, "inherits-from")->setStringValue("Effects/light-spot");
115         SGPropertyNode* params = makeChild(effectProp, "parameters");
116         params->getNode("light-spot/position",true)->setValue(SGVec4d(_position.x(),_position.y(),_position.z(),1.0));
117         params->getNode("light-spot/direction",true)->setValue(SGVec4d(_direction.x(),_direction.y(),_direction.z(),0.0));
118         params->getNode("light-spot/ambient",true)->setValue(_ambient);
119         params->getNode("light-spot/diffuse",true)->setValue(_diffuse);
120         params->getNode("light-spot/specular",true)->setValue(_specular);
121         params->getNode("light-spot/attenuation",true)->setValue(_attenuation);
122         params->getNode("light-spot/exponent",true)->setValue(_exponent);
123         params->getNode("light-spot/cutoff",true)->setValue(_cutoff);
124         params->getNode("light-spot/cosCutoff",true)->setValue( cos(_cutoff*SG_DEGREES_TO_RADIANS) );
125         params->getNode("light-spot/near",true)->setValue(_near);
126         params->getNode("light-spot/far",true)->setValue(_far);
127
128         simgear::Effect* effect = simgear::makeEffect(effectProp, true);
129         geode->setEffect(effect);
130     }
131 }