]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/shadanim.cxx
Do not modify danymically generated textures.
[simgear.git] / simgear / scene / model / shadanim.cxx
index ab76f23fa7253aaefb59e677131058f436eeba7d..9f94730df5687f824b82982ee260309d25258c61 100644 (file)
 #  include <simgear_config.h>
 #endif
 
-#include <plib/ul.h>
+#include <map>
+
+#include <osg/Group>
+#include <osg/Program>
+#include <osg/Shader>
+#include <osg/StateSet>
+#include <osg/TextureCubeMap>
+#include <osg/TexEnvCombine>
+#include <osg/TexGen>
+#include <osg/Texture1D>
+#include <osgUtil/HighlightMapGenerator>
+
+#include <OpenThreads/Mutex>
+#include <OpenThreads/ScopedLock>
+
+#include <simgear/scene/util/SGUpdateVisitor.hxx>
 
 #include <simgear/props/condition.hxx>
 #include <simgear/props/props.hxx>
-#include <simgear/screen/extensions.hxx>
 
 #include <simgear/debug/logstream.hxx>
 
 #include "animation.hxx"
 #include "model.hxx"
+
+using OpenThreads::Mutex;
+using OpenThreads::ScopedLock;
+
 /*
     <animation>
         <type>shader</type>
     </animation>
 
 */
+
+
+class SGMapGenCallback :
+  public osg::StateAttribute::Callback {
+public:
+  virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
+  {
+    SGUpdateVisitor* updateVisitor = dynamic_cast<SGUpdateVisitor*>(nv);
+    if (!updateVisitor)
+      return;
+
+    if (distSqr(_lastLightDirection, updateVisitor->getLightDirection()) < 1e-4
+        && distSqr(_lastLightColor, updateVisitor->getAmbientLight()) < 1e-4)
+      return;
+
+    _lastLightDirection = updateVisitor->getLightDirection();
+    _lastLightColor = updateVisitor->getAmbientLight();
+
+    osg::TextureCubeMap *tcm = static_cast<osg::TextureCubeMap*>(sa);
+
+    // FIXME: need an update or callback ...
+    // generate the six highlight map images (light direction = [1, 1, -1])
+    osg::ref_ptr<osgUtil::HighlightMapGenerator> mapgen;
+    mapgen = new osgUtil::HighlightMapGenerator(_lastLightDirection.osg(),
+                                                _lastLightColor.osg(), 5);
+    mapgen->generateMap();
+
+    // assign the six images to the texture object
+    tcm->setImage(osg::TextureCubeMap::POSITIVE_X,
+                  mapgen->getImage(osg::TextureCubeMap::POSITIVE_X));
+    tcm->setImage(osg::TextureCubeMap::NEGATIVE_X,
+                  mapgen->getImage(osg::TextureCubeMap::NEGATIVE_X));
+    tcm->setImage(osg::TextureCubeMap::POSITIVE_Y,
+                  mapgen->getImage(osg::TextureCubeMap::POSITIVE_Y));
+    tcm->setImage(osg::TextureCubeMap::NEGATIVE_Y,
+                  mapgen->getImage(osg::TextureCubeMap::NEGATIVE_Y));
+    tcm->setImage(osg::TextureCubeMap::POSITIVE_Z,
+                  mapgen->getImage(osg::TextureCubeMap::POSITIVE_Z));
+    tcm->setImage(osg::TextureCubeMap::NEGATIVE_Z,
+                  mapgen->getImage(osg::TextureCubeMap::NEGATIVE_Z));
+  }
+private:
+  SGVec3f _lastLightDirection;
+  SGVec4f _lastLightColor;
+};
+
+static Mutex cubeMutex;
+
+static osg::TextureCubeMap*
+getOrCreateTextureCubeMap()
+{
+  static osg::ref_ptr<osg::TextureCubeMap> textureCubeMap;
+  if (textureCubeMap.get())
+    return textureCubeMap.get();
+
+  ScopedLock<Mutex> lock(cubeMutex);
+  if (textureCubeMap.get())
+    return textureCubeMap.get();
+
+  // create and setup the texture object
+  textureCubeMap = new osg::TextureCubeMap;
+
+  textureCubeMap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
+  textureCubeMap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
+  textureCubeMap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP);
+  textureCubeMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
+  textureCubeMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);    
+  
+  textureCubeMap->setUpdateCallback(new SGMapGenCallback);
+
+  return textureCubeMap.get();
+}
+
+static void create_specular_highlights(osg::Node *node)
+{
+  osg::StateSet *ss = node->getOrCreateStateSet();
+  
+  // create and setup the texture object
+  osg::TextureCubeMap *tcm = getOrCreateTextureCubeMap();
+  
+  // enable texturing, replacing any textures in the subgraphs
+  ss->setTextureAttributeAndModes(0, tcm, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
+  
+  // texture coordinate generation
+  osg::TexGen *tg = new osg::TexGen;
+  tg->setMode(osg::TexGen::REFLECTION_MAP);
+  ss->setTextureAttributeAndModes(0, tg, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
+  
+  // use TexEnvCombine to add the highlights to the original lighting
+  osg::TexEnvCombine *te = new osg::TexEnvCombine;
+  te->setCombine_RGB(osg::TexEnvCombine::ADD);
+  te->setSource0_RGB(osg::TexEnvCombine::TEXTURE);
+  te->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
+  te->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
+  te->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
+  ss->setTextureAttributeAndModes(0, te, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
+}
+
+
+SGShaderAnimation::SGShaderAnimation(const SGPropertyNode* configNode,
+                                     SGPropertyNode* modelRoot,
+                                     const osgDB::ReaderWriter::Options*
+                                     options) :
+  SGAnimation(configNode, modelRoot)
+{
+  const SGPropertyNode* node = configNode->getChild("texture");
+  if (node)
+    _effect_texture = SGLoadTexture2D(node->getStringValue(), options);
+}
+
+namespace {
+class ChromeLightingCallback :
+  public osg::StateAttribute::Callback {
+public:
+  virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
+  {
+    SGUpdateVisitor* updateVisitor = dynamic_cast<SGUpdateVisitor*>(nv);
+    if (!updateVisitor)
+      return;
+    osg::TexEnvCombine *combine = dynamic_cast<osg::TexEnvCombine *>(sa);
+    if (!combine)
+       return;
+    // An approximation for light reflected back by chrome.
+    osg::Vec4 globalColor = (updateVisitor->getAmbientLight().osg() * .4f
+                            + updateVisitor->getDiffuseLight().osg());
+    globalColor.a() = 1.0f;
+    combine->setConstantColor(globalColor);
+  }
+};
+    
+typedef std::map<osg::ref_ptr<osg::Texture2D>, osg::ref_ptr<osg::StateSet> >
+StateSetMap;
+}
+
+static Mutex chromeMutex;
+
+// The chrome effect is mixed by the alpha channel of the texture
+// on the model, which will be attached to a node lower in the scene
+// graph: 0 -> completely chrome, 1 -> completely model texture.
+static void create_chrome(osg::Group* group, osg::Texture2D* texture)
+{
+    ScopedLock<Mutex> lock(chromeMutex);
+    static StateSetMap chromeMap;
+    osg::StateSet *stateSet;
+    StateSetMap::iterator iterator = chromeMap.find(texture);
+    if (iterator != chromeMap.end()) {
+       stateSet = iterator->second.get();
+    } else {
+       stateSet = new osg::StateSet;
+       // If the model doesn't have any texture, we need to have one
+       // activated so that we don't need a seperate combiner
+       // attribute for the non-textured case. This texture will be
+       // shadowed by any attached to the model.
+       osg::Image *dummyImage = new osg::Image;
+       dummyImage->allocateImage(1, 1, 1, GL_LUMINANCE_ALPHA,
+                                 GL_UNSIGNED_BYTE);
+       unsigned char* imageBytes = dummyImage->data(0, 0);
+       imageBytes[0] = 255;
+       imageBytes[1] = 0;
+       osg::Texture2D* dummyTexture = new osg::Texture2D;
+       dummyTexture->setImage(dummyImage);
+       dummyTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
+       dummyTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
+       stateSet->setTextureAttributeAndModes(0, dummyTexture,
+                                             osg::StateAttribute::ON);
+       osg::TexEnvCombine* combine0 = new osg::TexEnvCombine;
+       osg::TexEnvCombine* combine1 = new osg::TexEnvCombine;
+       osg::TexGen* texGen = new osg::TexGen;
+       // Mix the environmental light color and the chrome map on texture
+       // unit 0
+       combine0->setCombine_RGB(osg::TexEnvCombine::MODULATE);
+       combine0->setSource0_RGB(osg::TexEnvCombine::CONSTANT);
+       combine0->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
+       combine0->setSource1_RGB(osg::TexEnvCombine::TEXTURE1);
+       combine0->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
+       combine0->setDataVariance(osg::Object::DYNAMIC);
+       combine0->setUpdateCallback(new ChromeLightingCallback);
+
+       // Interpolate the colored chrome map with the texture on the
+       // model, using the model texture's alpha.
+       combine1->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
+       combine1->setSource0_RGB(osg::TexEnvCombine::TEXTURE0);
+       combine1->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
+       combine1->setSource1_RGB(osg::TexEnvCombine::PREVIOUS);
+       combine1->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
+       combine1->setSource2_RGB(osg::TexEnvCombine::TEXTURE0);
+       combine1->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA);
+       // Are these used for anything?
+       combine1->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
+       combine1->setSource0_Alpha(osg::TexEnvCombine::TEXTURE1);
+       combine1->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
+    
+       texGen->setMode(osg::TexGen::SPHERE_MAP);
+       stateSet->setTextureAttribute(0, combine0);
+       stateSet->setTextureAttribute(1, combine1);
+       stateSet->setTextureAttributeAndModes(1, texture,
+                                             osg::StateAttribute::ON);
+       stateSet->setTextureAttributeAndModes(1, texGen,
+                                             osg::StateAttribute::ON);
+       chromeMap[texture] = stateSet;
+    }
+    group->setStateSet(stateSet);
+}
+
+osg::Group*
+SGShaderAnimation::createAnimationGroup(osg::Group& parent)
+{
+  osg::Group* group = new osg::Group;
+  group->setName("shader animation");
+  parent.addChild(group);
+
+  std::string shader_name = getConfig()->getStringValue("shader", "");
+//   if( shader_name == "fresnel" || shader_name == "reflection" )
+//     _shader_type = 1;
+//   else if( shader_name == "heat-haze" )
+//     _shader_type = 2;
+//   else
+  if( shader_name == "chrome")
+#if 0
+    create_specular_highlights(group);
+#endif
+  create_chrome(group, _effect_texture.get());
+  return group;
+}
+
+#if 0
 // static Shader *shFresnel=NULL;
 // static GLuint texFresnel = 0;
 
@@ -621,3 +865,4 @@ SGShaderAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
   // that the rest of cullbacks and the scene graph are traversed.
   traverse(node, nv);
 }
+#endif