]> git.mxchange.org Git - simgear.git/commitdiff
Full implementation of the spotlight by Effects
authorFrederic Bouvier <fredfgfs01@free.fr>
Mon, 2 Jan 2012 23:32:00 +0000 (00:32 +0100)
committerFrederic Bouvier <fredfgfs01@free.fr>
Sun, 4 Mar 2012 19:21:21 +0000 (20:21 +0100)
simgear/scene/model/SGLightAnimation.cxx
simgear/scene/model/animation.hxx

index bad681c31485bfe84196af7446da41099fd4ec2b..6d6257b47df2b49ec0d28d638ae4ab6ba25968e8 100644 (file)
 #include <osg/MatrixTransform>
 #include <simgear/scene/material/EffectGeode.hxx>
 #include <boost/scoped_array.hpp>
+#include <simgear/scene/util/CopyOp.hxx>
+
+#define GET_COLOR_VALUE(n) \
+    SGVec4d( getConfig()->getDoubleValue(n "/r"), \
+                getConfig()->getDoubleValue(n "/g"), \
+                getConfig()->getDoubleValue(n "/b"), \
+                getConfig()->getDoubleValue(n "/a") )
 
 SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode,
                                    SGPropertyNode* modelRoot) :
     SGAnimation(configNode, modelRoot)
 {
+    _position = SGVec3d( getConfig()->getDoubleValue("position/x"), getConfig()->getDoubleValue("position/y"), getConfig()->getDoubleValue("position/z") );
+    _direction = SGVec3d( getConfig()->getDoubleValue("direction/x"), getConfig()->getDoubleValue("direction/y"), getConfig()->getDoubleValue("direction/z") );
+    double l = length(_direction);
+    if (l > 0.001) _direction /= l;
+    _ambient = GET_COLOR_VALUE("ambient");
+    _diffuse = GET_COLOR_VALUE("diffuse");
+    _specular = GET_COLOR_VALUE("specular");
+    _attenuation = SGVec3d( getConfig()->getDoubleValue("attenuation/c"), getConfig()->getDoubleValue("attenuation/l"), getConfig()->getDoubleValue("attenuation/q") );
+    _exponent = getConfig()->getDoubleValue("exponent");
+    _cutoff = getConfig()->getDoubleValue("cutoff");
+    _near = getConfig()->getDoubleValue("near-m");
+    _far = getConfig()->getDoubleValue("far-m");
 }
 
 osg::Group*
 SGLightAnimation::createAnimationGroup(osg::Group& parent)
 {
     osg::MatrixTransform* grp = new osg::MatrixTransform;
-    osg::Vec3 position( getConfig()->getDoubleValue("position/x-m"),
-                        getConfig()->getDoubleValue("position/y-m"),
-                        getConfig()->getDoubleValue("position/z-m") );
-    grp->setMatrix(osg::Matrix::translate(position));
-  parent.addChild(grp);
-  grp->setNodeMask( simgear::MODELLIGHT_BIT );
-  return grp;
+    grp->setMatrix(osg::Matrix::translate(toOsg(_position)));
+    parent.addChild(grp);
+    grp->setNodeMask( simgear::MODELLIGHT_BIT );
+    return grp;
 }
 
 void
 SGLightAnimation::install(osg::Node& node)
 {
-  SGAnimation::install(node);
-
-  std::string light_type = getConfig()->getStringValue("light-type");
-  if (light_type == "spot") {
-    osg::Vec3 axis( getConfig()->getDoubleValue("axis/x"),
-                    getConfig()->getDoubleValue("axis/y"),
-                    getConfig()->getDoubleValue("axis/z") );
-    double l = axis.length();
-    if (l < 0.001) return;
-    axis /= l;
-
-    osg::Vec3 p1(  axis.z(), axis.x(), axis.y() ),
-              p2 = axis ^ p1;
-    p1 = p2 ^ axis;
-
-    float n = getConfig()->getFloatValue("near-m"),
-          f = getConfig()->getFloatValue("far-m"),
-          a1 = getConfig()->getFloatValue("angle-inner-deg"),
-          a2 = getConfig()->getFloatValue("angle-outer-deg"),
-          r1 = n * tan( a2 * SG_DEGREES_TO_RADIANS ),
-          r2 = f * tan( a2 * SG_DEGREES_TO_RADIANS );
-
-    osg::Geometry* cone = new osg::Geometry;
-cone->setUseDisplayList(false);
-    osg::Vec3Array* vertices = new osg::Vec3Array(36);
-    (*vertices)[0] = osg::Vec3(0.0,0.0,0.0);
-    for (int i=0; i<16; ++i) {
-      (*vertices)[16-i]    = axis*f + p1*r2*cos( i * 2 * M_PI / 16 ) + p2*r2*sin( i * 2 * M_PI / 16 );
-    }
-    (*vertices)[17] = (*vertices)[1];
+    SGAnimation::install(node);
 
-    // Bottom
-    (*vertices)[18] = axis*f;
-    for (int i=0; i<16; ++i) {
-      (*vertices)[19+i]    = axis*f + p1*r2*cos( i * 2 * M_PI / 16 ) + p2*r2*sin( i * 2 * M_PI / 16 );
-    }
-    (*vertices)[35] = (*vertices)[19];
-
-    osg::Vec4Array* colours = new osg::Vec4Array(1);
-    (*colours)[0].set(  getConfig()->getFloatValue("color/red"),
-                        getConfig()->getFloatValue("color/green"),
-                        getConfig()->getFloatValue("color/blue"),
-                        1.0f);
-    cone->setColorArray(colours);
-    cone->setColorBinding(osg::Geometry::BIND_OVERALL);
-
-    osg::Vec3Array* normals = new osg::Vec3Array(1);
-    (*normals)[0] = axis;
-    cone->setNormalArray(normals);
-    cone->setNormalBinding(osg::Geometry::BIND_OVERALL);
-
-    cone->setVertexArray(vertices);
-    cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 0, 18 ) );
-    cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 18, 18 ) );
-
-    simgear::EffectGeode* geode = new simgear::EffectGeode;
-    geode->addDrawable( cone );
-
-    node.asGroup()->addChild( geode );
-    simgear::Effect *effect = simgear::makeEffect("Effects/light-spot", true);
-    if (effect) {
-      effect->parametersProp->setFloatValue("inner-angle",getConfig()->getFloatValue("angle-inner-deg"));
-      effect->parametersProp->setFloatValue("outer-angle",getConfig()->getFloatValue("angle-outer-deg"));
-      geode->setEffect(effect);
+    std::string light_type = getConfig()->getStringValue("light-type");
+    if (light_type == "spot") {
+
+        SGVec3d p1( _direction.z(), _direction.x(), _direction.y() ),
+        p2 = cross( _direction, p1 );
+        p1 = cross( p2, _direction );
+
+        float r2 = _far * tan( _cutoff * SG_DEGREES_TO_RADIANS );
+
+        osg::Geometry* cone = new osg::Geometry;
+cone->setUseDisplayList(false);
+        osg::Vec3Array* vertices = new osg::Vec3Array(34);
+        (*vertices)[0] = osg::Vec3(0.0,0.0,0.0);
+        for (int i=0; i<16; ++i) {
+            (*vertices)[16-i]    = toOsg(_direction)*_far + toOsg(p1)*r2*cos( i * 2 * M_PI / 16 ) + toOsg(p2)*r2*sin( i * 2 * M_PI / 16 );
+        }
+        (*vertices)[17] = (*vertices)[1];
+
+        // Bottom
+        for (int i=0; i<16; ++i) {
+            (*vertices)[18+i]    = toOsg(_direction)*_far + toOsg(p1)*r2*cos( i * 2 * M_PI / 16 ) + toOsg(p2)*r2*sin( i * 2 * M_PI / 16 );
+        }
+
+        osg::Vec4Array* colours = new osg::Vec4Array(1);
+        (*colours)[0] = osg::Vec4d(toOsg(getConfig()->getValue<SGVec3d>("diffuse")), 1.0f);
+        cone->setColorArray(colours);
+        cone->setColorBinding(osg::Geometry::BIND_OVERALL);
+
+        osg::Vec3Array* normals = new osg::Vec3Array(1);
+        (*normals)[0] = toOsg(_direction);
+        cone->setNormalArray(normals);
+        cone->setNormalBinding(osg::Geometry::BIND_OVERALL);
+
+        cone->setVertexArray(vertices);
+        cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 0, 18 ) );
+        cone->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_FAN, 18, 16 ) );
+
+        simgear::EffectGeode* geode = new simgear::EffectGeode;
+        geode->addDrawable( cone );
+
+        node.asGroup()->addChild( geode );
+
+        // TODO: build a cache - problem: what is the key ?
+        SGPropertyNode_ptr effectProp = new SGPropertyNode;
+        makeChild(effectProp, "inherits-from")->setStringValue("Effects/light-spot");
+        SGPropertyNode* params = makeChild(effectProp, "parameters");
+        params->getNode("light-spot/position",true)->setValue(SGVec4d(_position.x(),_position.y(),_position.z(),1.0));
+        params->getNode("light-spot/direction",true)->setValue(SGVec4d(_direction.x(),_direction.y(),_direction.z(),0.0));
+        params->getNode("light-spot/ambient",true)->setValue(_ambient);
+        params->getNode("light-spot/diffuse",true)->setValue(_diffuse);
+        params->getNode("light-spot/specular",true)->setValue(_specular);
+        params->getNode("light-spot/attenuation",true)->setValue(_attenuation);
+        params->getNode("light-spot/exponent",true)->setValue(_exponent);
+        params->getNode("light-spot/cutoff",true)->setValue(_cutoff);
+        params->getNode("light-spot/cosCutoff",true)->setValue( cos(_cutoff*SG_DEGREES_TO_RADIANS) );
+        params->getNode("light-spot/near",true)->setValue(_near);
+        params->getNode("light-spot/far",true)->setValue(_far);
+
+        simgear::Effect* effect = simgear::makeEffect(effectProp, true);
+        geode->setEffect(effect);
     }
-  }
 }
index d6c1863352ee8d8b776a908ba5774e08d6493ff1..fcd81a97aae8c91767d7979ff7222de411e12cb0 100644 (file)
@@ -355,6 +355,16 @@ public:
   virtual osg::Group* createAnimationGroup(osg::Group& parent);
   virtual void install(osg::Node& node);
 private:
+  SGVec3d _position;
+  SGVec3d _direction;
+  SGVec4d _ambient;
+  SGVec4d _diffuse;
+  SGVec4d _specular;
+  SGVec3d _attenuation;
+  double _exponent;
+  double _cutoff;
+  double _near;
+  double _far;
 };
 
 #endif // _SG_ANIMATION_HXX