Skip to content
Snippets Groups Projects
Select Git revision
  • a75bbdf7a899411391c82895dbe9f4b320cca78f
  • master default protected
  • develop protected
  • cmake_boost_refactor
  • ubuntu_ci
  • mmtf
  • non-orthogonal-maps
  • no_boost_filesystem
  • data_viewer
  • 2.11.1
  • 2.11.0
  • 2.10.0
  • 2.9.3
  • 2.9.2
  • 2.9.1
  • 2.9.0
  • 2.8.0
  • 2.7.0
  • 2.6.1
  • 2.6.0
  • 2.6.0-rc4
  • 2.6.0-rc3
  • 2.6.0-rc2
  • 2.6.0-rc
  • 2.5.0
  • 2.5.0-rc2
  • 2.5.0-rc
  • 2.4.0
  • 2.4.0-rc2
29 results

transform.cc

Blame
  • scene_fx.cc 23.52 KiB
    #include <boost/random.hpp>
    
    #include "scene_fx.hh"
    
    #include <ost/log.hh>
    
    #include <ost/gfx/gfx_node.hh>
    #include <ost/gfx/shader.hh>
    #include <ost/gfx/scene.hh>
    
    #if !GL_VERSION_3_0
    #warning using OpenGL 2.0 interface
    #endif
    
    namespace ost { namespace gfx { namespace impl {
    
    namespace {
      boost::mt19937 RandomGenerator(time(NULL));
      boost::uniform_01<boost::mt19937> UniformRandom(RandomGenerator);
    }
    
    SceneFX& SceneFX::Instance()
    {
      static SceneFX inst;
      return inst;
    }
    
    SceneFX::SceneFX():
      shadow_flag(false),
      shadow_quality(1),
      shadow_weight(1.0),
      depth_dark_flag(false),
      depth_dark_factor(1.0),
      amb_occl_flag(false),
      amb_occl_factor(1.0),
      amb_occl_mode(1),
      amb_occl_quality(1),
      use_beacon(false),
      beacon(),
      scene_tex_id_(),
      depth_tex_id_(),
      shadow_tex_id_(),
      shadow_tex_mat_(),
      occl_tex_id_(),
      dark_tex_id_(),
      norm_tex_id_(),
      kernel_tex_id_(),
      kernel_size_(0),
      kernel2_tex_id_(),
      kernel2_size_(0),
      scene_tex2_id_(),
      norm_tex2_id_(),
      scene_fb_(),
      scene_rb_(),
      depth_rb_(),
      use_fb_(false)
    {}
    
    SceneFX::~SceneFX()
    {}
    
    void SceneFX::Setup()
    {
      if(!OST_GL_VERSION_2_0) return;
      LOG_DEBUG("SceneFX: setup");
    
      glGenTextures(1,&scene_tex_id_);
      glGenTextures(1,&depth_tex_id_);
      glGenTextures(1,&shadow_tex_id_);
      glGenTextures(1,&occl_tex_id_);
      glGenTextures(1,&dark_tex_id_);
      glGenTextures(1,&norm_tex_id_);
      glGenTextures(1,&kernel_tex_id_);
      glGenTextures(1,&kernel2_tex_id_);
    
    #if GL_VERSION_3_0
      glGenFramebuffers(1,&scene_fb_);
      glGenRenderbuffers(1,&scene_rb_);
      glGenRenderbuffers(1,&depth_rb_);
    #else
      glGenFramebuffersEXT(1,&scene_fb_);
      glGenRenderbuffersEXT(1,&scene_rb_);
      glGenRenderbuffersEXT(1,&depth_rb_);
    #endif
      glGenTextures(1,&scene_tex2_id_);
      glGenTextures(1,&norm_tex2_id_);
    
      glBindTexture(GL_TEXTURE_2D, scene_tex_id_);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
    
      glBindTexture(GL_TEXTURE_2D, depth_tex_id_);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
    
      glBindTexture(GL_TEXTURE_2D, shadow_tex_id_);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
    
      glBindTexture(GL_TEXTURE_2D, occl_tex_id_);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
    
      glBindTexture(GL_TEXTURE_2D, dark_tex_id_);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
    
      glBindTexture(GL_TEXTURE_2D, norm_tex_id_);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
    
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_1D, kernel_tex_id_);
      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
    
      std::vector<GLfloat> tmp;
      for(int u=-20;u<=20;++u) {
        for(int v=-20;v<=20;++v) {
          if(UniformRandom()<0.1) {
            // norm to 1
            float x = static_cast<float>(u+20)*0.025;
            float y = static_cast<float>(v+20)*0.025;
            tmp.push_back(x);
            tmp.push_back(y);
            tmp.push_back(0.0);
            tmp.push_back(0.0);
          }
        }
      }
    
      kernel_size_=tmp.size()/4;
      glTexImage1D(GL_TEXTURE_1D,0,4,kernel_size_,0,GL_RGBA, GL_FLOAT, &tmp[0]);
    
      glBindTexture(GL_TEXTURE_1D, kernel2_tex_id_);
      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      
      // depth darkening kernel
      tmp.clear();
      for(int u=-5;u<=5;++u) {
        for(int v=-5;v<=5;++v) {
          if(UniformRandom()<0.5) {
            // norm to -1 ... 1
            float x = static_cast<float>(u)*0.2;
            float y = static_cast<float>(v)*0.2;
            // gaussian kernel with sigma
            float v = exp((-x*x-y*y)*0.5);
            // norml to 0 ... 1
            tmp.push_back(x*0.5+0.5);
            tmp.push_back(y*0.5+0.5);
            tmp.push_back(v);
            tmp.push_back(0.0);
          }
        }
      }
    
      kernel2_size_=tmp.size()/4;
      glTexImage1D(GL_TEXTURE_1D,0,4,kernel2_size_,0,GL_RGBA, GL_FLOAT, &tmp[0]);
    }
    
    void SceneFX::Resize(unsigned int w, unsigned int h)
    {
    #if 0
      glBindTexture(GL_TEXTURE_2D, scene_tex2_id_);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
      glBindTexture(GL_TEXTURE_2D, norm_tex2_id_);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
      glBindTexture(GL_TEXTURE_2D, 0);
    
      glBindFramebuffer(GL_FRAMEBUFFER, scene_fb_);
    
      glBindRenderbuffer(GL_RENDERBUFFER, depth_rb_);
      glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,w,h);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rb_);
      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, scene_tex2_id_, 0);
      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, norm_tex2_id_, 0);
    
      GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    
      if(status!=GL_FRAMEBUFFER_COMPLETE) {
        use_fb_=false;
        LOG_VERBOSE("SceneFX: framebuffer error code " << status);
      } else {
        use_fb_=true;
      }
    
      glBindRenderbuffer(GL_RENDERBUFFER, 0);
      glBindFramebuffer(GL_FRAMEBUFFER, 0);
    #endif
    }
    
    void SceneFX::Preprocess() 
    {
      if(!OST_GL_VERSION_2_0) return;
      if(use_fb_) {
    #if GL_VERSION_3_0
        glBindFramebuffer(GL_FRAMEBUFFER, scene_fb_);
    #else
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, scene_fb_);
    #endif
      }
    }
    
    void SceneFX::Postprocess()
    {
      if(!OST_GL_VERSION_2_0) return;
      if(use_fb_) {
    #if GL_VERSION_3_0
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    #else
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    #endif
      }
    
      if(!shadow_flag && !amb_occl_flag && !depth_dark_flag && !use_beacon) {
        // no postprocessing is needed
        return;
      }
    
      Viewport vp=Scene::Instance().GetViewport();
    
      if(!use_fb_) {
        // grab color buffer
        glBindTexture(GL_TEXTURE_2D, scene_tex_id_);
        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vp.x, vp.y, vp.width, vp.height, 0);
        // and depth buffer
        glBindTexture(GL_TEXTURE_2D, depth_tex_id_);
        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, vp.x, vp.y, vp.width, vp.height, 0);
    
        if(amb_occl_flag) {
          // now for the normal buffer hack if the framebuffer stuff failed
          Shader::Instance().PushProgram();
          Shader::Instance().Activate("dumpnorm");
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
          Scene::Instance().GetRootNode()->RenderGL(STANDARD_RENDER_PASS);
          glBindTexture(GL_TEXTURE_2D, norm_tex_id_);
          glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vp.x, vp.y, vp.width, vp.height, 0);
          Shader::Instance().PopProgram();
        }
      }
    
      if(shadow_flag) {
        prep_shadow_map();
      }
      if(amb_occl_flag) {
        prep_amb_occlusion();
      }
      if(depth_dark_flag) {
        prep_depth_darkening();
      }
    
      Shader::Instance().PushProgram();
      glEnable(GL_TEXTURE_2D);
      glEnable(GL_TEXTURE_1D);
      Shader::Instance().Activate("scenefx");
      GLuint cpr=Shader::Instance().GetCurrentProgram();
      glActiveTexture(GL_TEXTURE1);
      glBindTexture(GL_TEXTURE_2D,depth_tex_id_);
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D,scene_tex_id_);
    
      glUniform1i(glGetUniformLocation(cpr,"scene_map"),0);
      glUniform1i(glGetUniformLocation(cpr,"depth_map"),1);
    
      glUniform2f(glGetUniformLocation(cpr,"i_vp"),
                  1.0/static_cast<float>(vp.width),
                  1.0/static_cast<float>(vp.height));
    
      if(shadow_flag) {
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D,shadow_tex_id_);
        glMatrixMode(GL_TEXTURE);
        glPushMatrix();
        glLoadTransposeMatrix(shadow_tex_mat_.Data());
        glMatrixMode(GL_MODELVIEW);
        glActiveTexture(GL_TEXTURE0);
        glUniform1i(glGetUniformLocation(cpr,"shadow_flag"),1);
        glUniform1i(glGetUniformLocation(cpr,"shadow_map"),2);
        glUniform1f(glGetUniformLocation(cpr,"shadow_depth_bias"),0.008);
        glUniform1f(glGetUniformLocation(cpr,"shadow_epsilon"),0.002);
        glUniform1f(glGetUniformLocation(cpr,"shadow_multiplier"),0.4);
        glUniform1f(glGetUniformLocation(cpr,"shadow_weight"),shadow_weight);
    
      } else {
        glUniform1i(glGetUniformLocation(cpr,"shadow_flag"),0);
      }
      if(amb_occl_flag) {
        glActiveTexture(GL_TEXTURE3);
        glBindTexture(GL_TEXTURE_2D,occl_tex_id_);
        glActiveTexture(GL_TEXTURE0);
        glUniform1i(glGetUniformLocation(cpr,"occl_flag"),1);
        glUniform1i(glGetUniformLocation(cpr,"occl_map"),3);
        glUniform1f(glGetUniformLocation(cpr,"occl_mult"),amb_occl_factor);
      } else {
        glUniform1i(glGetUniformLocation(cpr,"occl_flag"),0);
      }
    
      if(depth_dark_flag) {
        glActiveTexture(GL_TEXTURE4);
        glBindTexture(GL_TEXTURE_2D,dark_tex_id_);
        glActiveTexture(GL_TEXTURE0);
        glUniform1i(glGetUniformLocation(cpr,"dark_flag"),1);
        glUniform1i(glGetUniformLocation(cpr,"dark_map"),4);
        glUniform1f(glGetUniformLocation(cpr,"dark_mult"),depth_dark_factor);
      } else {
        glUniform1i(glGetUniformLocation(cpr,"dark_flag"),0);
      }
    
      if(use_beacon) {
        prep_beacon();
      }
    
      draw_screen_quad(vp.width,vp.height);
    
      if(shadow_flag) {
        glActiveTexture(GL_TEXTURE2);
        glMatrixMode(GL_TEXTURE);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glActiveTexture(GL_TEXTURE0);
      }
    
      if(use_beacon) {
        draw_beacon();
      }
    
      glDisable(GL_TEXTURE_1D);
      glDisable(GL_TEXTURE_2D);
      Shader::Instance().PopProgram();
    }
    
    void SceneFX::DrawTex(unsigned int w, unsigned int h, GLuint texid)
    {
      if(!OST_GL_VERSION_2_0) return;
      Shader::Instance().PushProgram();
      Shader::Instance().Activate("");
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, texid);
    
      draw_screen_quad(w,h);
    
      Shader::Instance().PopProgram();
    }
    
    void SceneFX::prep_shadow_map()
    {
      GLint smap_size=256 * (1+shadow_quality);
    
    #if GL_VERSION_3_0
      glBindFramebuffer(GL_FRAMEBUFFER, scene_fb_);
      glBindRenderbuffer(GL_RENDERBUFFER, scene_rb_);
      glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA,smap_size,smap_size);
      glBindRenderbuffer(GL_RENDERBUFFER, depth_rb_);
      glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,smap_size,smap_size);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, scene_rb_);
      glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rb_);
      
      GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
      
      if(status!=GL_FRAMEBUFFER_COMPLETE) {
        LOG_DEBUG("fbo switch for shadow mapping failed, using fallback");
        glBindRenderbuffer(GL_RENDERBUFFER, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        smap_size=512;
      }
    #else
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, scene_fb_);
      glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, scene_rb_);
      glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA,smap_size,smap_size);
      glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb_);
      glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,smap_size,smap_size);
      glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, scene_rb_);
      glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb_);
      
      GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
      
      if(status!=GL_FRAMEBUFFER_COMPLETE_EXT) {
        LOG_DEBUG("fbo switch for shadow mapping failed, using fallback");
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
        smap_size=512;
      }
    #endif
    
      // modelview transform for the lightsource pov
      mol::Transform ltrans(Scene::Instance().GetTransform());
      ltrans.SetRot(Scene::Instance().GetLightRot()*ltrans.GetRot());
    
      // calculate encompassing box for ortho projection
      geom::AlignedCuboid bb=Scene::Instance().GetBoundingBox(ltrans);
      geom::Vec3 tmin=bb.GetMin();
      geom::Vec3 tmax=bb.GetMax();
    
      // save overall gl settings
      glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
      // maximize rendering for depth-only information
      glDisable(GL_LIGHTING);
      glDisable(GL_FOG);
      glDisable(GL_COLOR_MATERIAL);
      glDisable(GL_NORMALIZE);
      //glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
    
      // render scene with only depth components
      // seen from the light's perspective
      glViewport(0,0,smap_size,smap_size);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glLoadIdentity();
      glOrtho(tmin[0],tmax[0],tmin[1],tmax[1],-tmax[2],-tmin[2]);
      //glFrustum(tmin[0],tmax[0],tmin[1],tmax[1],-tmax[2],-tmin[2]);
      float glpmat[16];
      glGetv(GL_PROJECTION_MATRIX, glpmat);
      geom::Mat4 pmat(geom::Transpose(geom::Mat4(glpmat)));
    
      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glLoadIdentity();
      glMultMatrix(ltrans.GetTransposedMatrix().Data());
    
      // only render non-transparent objects for the shadow map
      Scene::Instance().GetRootNode()->RenderGL(STANDARD_RENDER_PASS);
    
      // now get the shadow map
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, shadow_tex_id_);
      glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0,0, smap_size,smap_size, 0);
    
      // restore settings
      glPopMatrix();
      glMatrixMode(GL_PROJECTION);
      glPopMatrix();
      glMatrixMode(GL_MODELVIEW);
    
      glPopAttrib();
      //glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
    
    #if GL_VERSION_3_0
      glBindRenderbuffer(GL_RENDERBUFFER, 0);
      glBindFramebuffer(GL_FRAMEBUFFER, 0);
    #else
      glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    #endif
    
      // set up appropriate texture matrix
      geom::Mat4 bias(0.5,0.0,0.0,0.5,
                      0.0,0.5,0.0,0.5,
                      0.0,0.0,0.5,0.5,
                      0.0,0.0,0.0,1.0);
      //shadow_tex_mat_ = bias*pmat*ltrans.GetMatrix();
      glGetv(GL_PROJECTION_MATRIX, glpmat);
      geom::Mat4 pmat2(geom::Transpose(geom::Mat4(glpmat)));
      /*
        given the normalized coordinates in scenefx, the camera projection and modelview transformation
        are first reverted, and then the light modelview and projection are applied, resulting (with the
        bias) in the proper 2D lookup into the shadow map
      */
      shadow_tex_mat_ = bias*pmat*ltrans.GetMatrix()*geom::Invert(Scene::Instance().GetTransform().GetMatrix())*geom::Invert(pmat2);
    }
    
    void SceneFX::prep_amb_occlusion()
    {
      Viewport vp=Scene::Instance().GetViewport();
    
      uint qf=1;
      if(amb_occl_quality==0) {qf=4;}
      else if(amb_occl_quality==1) {qf=2;}
      uint width=vp.width/qf;
      uint height=vp.height/qf;
    
      Shader::Instance().PushProgram();
      Shader::Instance().Activate("amboccl");
      GLuint cpr=Shader::Instance().GetCurrentProgram();
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D,depth_tex_id_);
      glActiveTexture(GL_TEXTURE1);
      glBindTexture(GL_TEXTURE_2D,norm_tex_id_);
      glActiveTexture(GL_TEXTURE2);
      glBindTexture(GL_TEXTURE_1D,kernel_tex_id_);
      glActiveTexture(GL_TEXTURE0);
      glUniform1i(glGetUniformLocation(cpr,"depth_map"),0);
      glUniform1i(glGetUniformLocation(cpr,"norm_map"),1);
      glUniform1i(glGetUniformLocation(cpr,"kernel"),2);
      glUniform1f(glGetUniformLocation(cpr,"step"),1.0/static_cast<float>(kernel_size_));
      glUniform2f(glGetUniformLocation(cpr,"i_vp"),1.0/static_cast<float>(width),1.0/static_cast<float>(height));
      glUniform1i(glGetUniformLocation(cpr,"mode"),amb_occl_mode);
      double pm[16];
      glGetDoublev(GL_PROJECTION_MATRIX,pm);
      glUniform4f(glGetUniformLocation(cpr,"abcd"),pm[0],pm[5],pm[10],pm[14]);
    
      glMatrixMode(GL_TEXTURE);
      glPushMatrix();
      geom::Mat4 ipm(geom::Transpose(geom::Invert(geom::Transpose(geom::Mat4(pm)))));
      glLoadMatrix(ipm.Data());
      glMatrixMode(GL_MODELVIEW);
    
      // set up viewport filling quad to run the fragment shader
      draw_screen_quad(width,height);
    
      glMatrixMode(GL_TEXTURE);
      glPopMatrix();
      glMatrixMode(GL_MODELVIEW);
    
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, occl_tex_id_);
      glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0,0, width, height, 0);
      Shader::Instance().PopProgram();
    }
    
    void SceneFX::prep_depth_darkening()
    {
      Viewport vp=Scene::Instance().GetViewport();
    
      Shader::Instance().PushProgram();
      Shader::Instance().Activate("convolute1");
      GLuint cpr=Shader::Instance().GetCurrentProgram();
      // assign tex units
      glActiveTexture(GL_TEXTURE1);
      glBindTexture(GL_TEXTURE_2D,depth_tex_id_);
      glActiveTexture(GL_TEXTURE2);
      glBindTexture(GL_TEXTURE_1D,kernel2_tex_id_);
      glActiveTexture(GL_TEXTURE0);
    
      glUniform1i(glGetUniformLocation(cpr,"data"),1);
      glUniform1i(glGetUniformLocation(cpr,"kernel"),2);
      glUniform1f(glGetUniformLocation(cpr,"step"),1.0/static_cast<float>(kernel2_size_));
      glUniform2f(glGetUniformLocation(cpr,"i_vp"),1.0/static_cast<float>(vp.width),1.0/static_cast<float>(vp.height));
    
      // set up viewport filling quad to run the fragment shader
      draw_screen_quad(vp.width/2,vp.height/2);
    
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, dark_tex_id_);
      glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0,0,vp.width/2, vp.height/2, 0);
    
      Shader::Instance().PopProgram();
    }
    
    void SceneFX::draw_screen_quad(unsigned int w, unsigned int h) 
    {
      glPushAttrib(GL_ALL_ATTRIB_BITS);
      
      // setup
      glDisable(GL_DEPTH_TEST);
      glDisable(GL_LIGHTING);
      glDisable(GL_COLOR_MATERIAL);
      glDisable(GL_FOG);
      glDisable(GL_CULL_FACE);
      glDisable(GL_BLEND);
      glDisable(GL_LINE_SMOOTH);
      glDisable(GL_POINT_SMOOTH);
      glShadeModel(GL_FLAT);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glViewport(0,0,w,h);
      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glLoadIdentity();
      glOrtho(0,1,0,1,-1,1);
      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glLoadIdentity();
      glEnable(GL_TEXTURE_2D);
      glActiveTexture(GL_TEXTURE0);
      glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
      // draw
      glColor3f(1.0,0.0,1.0);
      glBegin(GL_QUADS);
      glTexCoord2f(0.0,0.0);
      glVertex2f(0.0,0.0);
      glTexCoord2f(0.0,1.0);
      glVertex2f(0.0,1.0);
      glTexCoord2f(1.0,1.0);
      glVertex2f(1.0,1.0);
      glTexCoord2f(1.0,0.0);
      glVertex2f(1.0,0.0);
      glEnd();
      
      // restore settings
      glMatrixMode(GL_PROJECTION);
      glPopMatrix();
      glMatrixMode(GL_MODELVIEW);
      glPopMatrix();
      glPopAttrib();
    }
    
    void SceneFX::prep_beacon()
    {
      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glLoadIdentity();
      Scene::Instance().stereo_projection(0);
      GLdouble glpmat[16];
      glGetDoublev(GL_PROJECTION_MATRIX, glpmat);
      geom::Mat4 pmat(geom::Transpose(geom::Mat4(glpmat)));
      glPopMatrix();
      glMatrixMode(GL_MODELVIEW);
      geom::Mat4 mmat=Scene::Instance().GetTransform().GetTransposedMatrix();
      GLdouble glmmat[16];
      for(int i=0;i<16;++i) glmmat[i]=static_cast<GLdouble>(mmat.Data()[i]);
      GLint glvp[4];
      glGetIntegerv(GL_VIEWPORT,glvp);
    
      double res[3];
      gluUnProject(beacon.wx,beacon.wy,0.0,
    	       glmmat,glpmat,glvp,
    	       &res[0],&res[1],&res[2]);
      beacon.p0=geom::Vec3(res[0],res[1],res[2]);
      gluUnProject(beacon.wx,beacon.wy,1.0,
    	       glmmat,glpmat,glvp,
    	       &res[0],&res[1],&res[2]);
      beacon.p1=geom::Vec3(res[0],res[1],res[2]);
    
      glGetv(GL_PROJECTION_MATRIX, glpmat);
      geom::Mat4 pmat2(geom::Transpose(geom::Mat4(glpmat)));
      beacon.mat = geom::Invert(Scene::Instance().GetTransform().GetMatrix())*geom::Invert(pmat2);
    }
    
    void SceneFX::draw_beacon()
    {
      Viewport vp=Scene::Instance().GetViewport();
      float iw=1.0/static_cast<float>(vp.width);
      float ih=1.0/static_cast<float>(vp.height);
      Shader::Instance().PushProgram();
      Shader::Instance().Activate("beacon");
      uint cpr=Shader::Instance().GetCurrentProgram();
    
      float rad=0.6;
      float delta = rad/(std::max<float>(1.0,Scene::Instance().znear_) * Scene::Instance().aspect_ratio_ * std::tan(Scene::Instance().fov_*M_PI/360.0))/iw;
      geom::Vec2 q0(beacon.wx-delta,beacon.wy-delta);
      geom::Vec2 q1(beacon.wx-delta,beacon.wy+delta);
      geom::Vec2 q2(beacon.wx+delta,beacon.wy+delta);
      geom::Vec2 q3(beacon.wx+delta,beacon.wy-delta);
    
      glActiveTexture(GL_TEXTURE1);
      glBindTexture(GL_TEXTURE_2D,depth_tex_id_);
      glMatrixMode(GL_TEXTURE);
      glPushMatrix();
      glLoadTransposeMatrix(beacon.mat.Data());
      glActiveTexture(GL_TEXTURE0);
      glUniform1i(glGetUniformLocation(cpr,"depth_map"),1);
      glUniform3f(glGetUniformLocation(cpr,"pos"),beacon.p0[0],beacon.p0[1],beacon.p0[2]);
      geom::Vec3 dir=beacon.p1-beacon.p0;
      glUniform3f(glGetUniformLocation(cpr,"dir"),dir[0],dir[1],dir[2]);
      glUniform1f(glGetUniformLocation(cpr,"len"),geom::Length(dir));
      glUniform1f(glGetUniformLocation(cpr,"rad"),rad);
    
      glPushAttrib(GL_ALL_ATTRIB_BITS);
      glMatrixMode(GL_PROJECTION);
      glPushMatrix();
      glLoadIdentity();
      glOrtho(0,vp.width,0,vp.height,-1,1);
      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      glLoadIdentity();
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glEnable(GL_BLEND);
      glDisable(GL_DEPTH_TEST);
      glDisable(GL_LIGHTING);
      glDisable(GL_COLOR_MATERIAL);
      glDisable(GL_FOG);
      glDisable(GL_CULL_FACE);
      glDisable(GL_LINE_SMOOTH);
      glDisable(GL_POINT_SMOOTH);
      glShadeModel(GL_FLAT);
      glViewport(0,0,vp.width,vp.height);
      glEnable(GL_TEXTURE_2D);
      glColor3f(1.0,0.0,1.0);
      glBegin(GL_QUADS);
      glTexCoord2f(iw*q0[0],ih*q0[1]);
      glVertex2f(q0[0],q0[1]);
      glTexCoord2f(iw*q1[0],ih*q1[1]);
      glVertex2f(q1[0],q1[1]);
      glTexCoord2f(iw*q2[0],ih*q2[1]);
      glVertex2f(q2[0],q2[1]);
      glTexCoord2f(iw*q3[0],ih*q3[1]);
      glVertex2f(q3[0],q3[1]);
      glEnd();
      glActiveTexture(GL_TEXTURE1);
      glMatrixMode(GL_TEXTURE);
      glPopMatrix();
      glActiveTexture(GL_TEXTURE0);
      glMatrixMode(GL_PROJECTION);
      glPopMatrix();
      glMatrixMode(GL_MODELVIEW);
      glPopMatrix();
      glPopAttrib();
      Shader::Instance().PopProgram();
    }
    
    void SceneFX::screenblur4()
    {
      Viewport vp=Scene::Instance().GetViewport();
      glBindTexture(GL_TEXTURE_2D, scene_tex_id_);
      glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vp.x, vp.y, vp.width, vp.height, 0);
      glBindTexture(GL_TEXTURE_2D, depth_tex_id_);
      glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, vp.x, vp.y, vp.width, vp.height, 0);
      Shader::Instance().PushProgram();
      Shader::Instance().Activate("screenblur4");
      GLuint cpr=Shader::Instance().GetCurrentProgram();
      glActiveTexture(GL_TEXTURE1);
      glBindTexture(GL_TEXTURE_2D,depth_tex_id_);
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D,scene_tex_id_);
      glUniform1i(glGetUniformLocation(cpr,"scene_map"),0);
      glUniform1i(glGetUniformLocation(cpr,"depth_map"),1);
      glUniform2f(glGetUniformLocation(cpr,"i_vp"),
                  1.0/static_cast<float>(vp.width),
                  1.0/static_cast<float>(vp.height));
      glUniform1f(glGetUniformLocation(cpr,"depth_cutoff"),0.5);
      draw_screen_quad(vp.width,vp.height);
      Shader::Instance().PopProgram();
    }
    
    }}} // ns