diff --git a/modules/gfx/pymod/export_scene.cc b/modules/gfx/pymod/export_scene.cc
index 5a1a2057f0ddfdb7a4edbe4d1e855079df9fba61..f5658f464db25b7661aa0d3e1695d35186c62895 100644
--- a/modules/gfx/pymod/export_scene.cc
+++ b/modules/gfx/pymod/export_scene.cc
@@ -118,6 +118,7 @@ void export_Scene()
     .def("SetShadow",&Scene::SetShadow)
     .def("SetShadowQuality",&Scene::SetShadowQuality)
     .def("SetDepthDarkening",&Scene::SetDepthDarkening)
+    .def("SetAmbientOcclusion",&Scene::SetAmbientOcclusion)
     .def("AttachObserver",&Scene::AttachObserver)
     .def("StartOffscreenMode",&Scene::StartOffscreenMode)
     .def("StopOffscreenMode",&Scene::StopOffscreenMode)
diff --git a/modules/gfx/src/CMakeLists.txt b/modules/gfx/src/CMakeLists.txt
index 1e17c9008ebd4a3711bc1302735237528d28df59..b5667bc33ba68cd156e95e088c62a3432e3805bb 100644
--- a/modules/gfx/src/CMakeLists.txt
+++ b/modules/gfx/src/CMakeLists.txt
@@ -244,7 +244,8 @@ if (USE_SHADER)
     shader/outline_vs.glsl
     shader/quadpp_vs.glsl
     shader/convolute1_fs.glsl
-    shader/amboccl_fs.glsl
+    shader/scenefx_vs.glsl
+    shader/scenefx_fs.glsl
   )
   copy_if_different("./" "${SHARED_DATA_PATH}/shader" "${SHADER_FILES}" 
                     "SHADER_TARGETS" ost_gfx)  
diff --git a/modules/gfx/src/impl/scene_fx.cc b/modules/gfx/src/impl/scene_fx.cc
index 7e6d8033f1521e0b37273c3a4d03bdb0502185b7..413ef43f9d6840bf1d7daadfe4165158b5e40f96 100644
--- a/modules/gfx/src/impl/scene_fx.cc
+++ b/modules/gfx/src/impl/scene_fx.cc
@@ -1,29 +1,213 @@
 #include "scene_fx.hh"
 
+#include <ost/log.hh>
+
 #include <ost/gfx/gfx_node.hh>
 #include <ost/gfx/shader.hh>
 #include <ost/gfx/scene.hh>
 
 namespace ost { namespace gfx { namespace impl {
 
-void prep_shadow_map(Scene& scene, GLuint texunit, GLuint texid, uint quality)
+SceneFX& SceneFX::Instance()
+{
+  static SceneFX inst;
+  return inst;
+}
+
+SceneFX::SceneFX():
+  shadow_flag(false),
+  shadow_quality(1),
+  depth_dark_flag(false),
+  amb_occl_flag(false),
+  scene_tex_id_(),
+  depth_tex_id_(),
+  shadow_tex_id_(),
+  occl_tex_id_(),
+  dark_tex_id_(),
+  norm_tex_id_(),
+  scene_tex2_id_(),
+  norm_tex2_id_(),
+  scene_fb_(),
+  depth_rb_(),
+  use_fb_(false)
+{}
+
+SceneFX::~SceneFX()
+{}
+
+void 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_);
+
+  glGenFramebuffers(1,&scene_fb_);
+  glGenRenderbuffers(1,&depth_rb_);
+  glGenTextures(1,&scene_tex2_id_);
+  glGenTextures(1,&norm_tex2_id_);
+
+  glActiveTexture(GL_TEXTURE0);
+
+  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);
+
+  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);
+
+  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);
+
+  glBindTexture(GL_TEXTURE_2D, occl_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);
+
+  glBindTexture(GL_TEXTURE_2D, dark_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);
+
+  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);
+
+}
+
+void SceneFX::Resize(unsigned int w, unsigned int h)
+{
+  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;
+    LOGN_VERBOSE("framebuffer error code " << status);
+  } else {
+    use_fb_=true;
+  }
+
+  glBindRenderbuffer(GL_RENDERBUFFER, 0);
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+void SceneFX::Preprocess() 
+{
+  if(use_fb_) {
+    glBindFramebuffer(GL_FRAMEBUFFER, scene_fb_);
+  }
+}
+
+void SceneFX::Postprocess()
 {
-  GLint smap_size=256 << quality;
+  Viewport vp=Scene::Instance().GetViewport();
+  // 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(use_fb_) {
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+  }
+
+  if(shadow_flag) {
+    prep_shadow_map();
+  }
+  if(amb_occl_flag) {
+    //prep_amb_occlusion();
+    //draw_debug_tex(vp.width,vp.height,norm_tex_id_);
+  }
+  if(depth_dark_flag) {
+    //prep_depth_darkening();
+  }
+
+
+  Shader::Instance().PushProgram();
+  glEnable(GL_TEXTURE_2D);
+  Shader::Instance().Activate("scenefx");
+  glActiveTexture(GL_TEXTURE1);
+  glBindTexture(GL_TEXTURE_2D,depth_tex_id_);
+  glActiveTexture(GL_TEXTURE0);
+  glBindTexture(GL_TEXTURE_2D,scene_tex_id_);
+  GLuint cpr=Shader::Instance().GetCurrentProgram();
+  glUniform1i(glGetUniformLocation(cpr,"scene"),0);
+  glUniform1i(glGetUniformLocation(cpr,"depth"),1);
+  glUniform2f(glGetUniformLocation(cpr,"scalef"),
+	      1.0f/static_cast<float>(vp.width),
+	      1.0f/static_cast<float>(vp.height));
+  glUniform2f(glGetUniformLocation(cpr,"zmorph"),
+	      Scene::Instance().GetFar()-Scene::Instance().GetNear(),
+	      Scene::Instance().GetNear());
+
+  if(shadow_flag) {
+    glActiveTexture(GL_TEXTURE2);
+    glBindTexture(GL_TEXTURE_2D,shadow_tex_id_);
+    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);
+  } else {
+    glUniform1i(glGetUniformLocation(cpr,"shadow_flag"),0);
+  }
+#if 0
+  if(amb_occl_flag) {
+    glActiveTexture(GL_TEXTURE3);
+    glBindTexture(GL_TEXTURE_2D,occl_tex_id_);
+    glUniform1i(glGetUniformLocation(cpr,"occl_flag"),1);
+    glUniform1i(glGetUniformLocation(cpr,"occl_map"),3);
+  } else {
+    glUniform1i(glGetUniformLocation(cpr,"occl_flag"),0);
+  }
+#endif
+
+  draw_screen_quad(vp.width,vp.height);
+  glDisable(GL_TEXTURE_2D);
+  Shader::Instance().PopProgram();
+}
+
+void SceneFX::prep_shadow_map()
+{
+  GLint smap_size=256 << shadow_quality;
 
   // modelview transform for the lightsource pov
-  mol::Transform ltrans(scene.GetTransform());
-  ltrans.SetRot(scene.GetLightRot()*scene.GetTransform().GetRot());
+  mol::Transform ltrans(Scene::Instance().GetTransform());
+  ltrans.SetRot(Scene::Instance().GetLightRot()*Scene::Instance().GetTransform().GetRot());
 
   // calculate encompassing box for ortho projection
-  geom::AlignedCuboid bb=scene.GetBoundingBox(ltrans);
+  geom::AlignedCuboid bb=Scene::Instance().GetBoundingBox(ltrans);
   geom::Vec3 tmin=bb.GetMin();
   geom::Vec3 tmax=bb.GetMax();
 
-  // render pass 1 - without shadows
-
-  // turn shadowing off for subsequent rendering
-  Shader::Instance().SetShadowMapping(false,0);
-
   // save overall gl settings
   glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
   // maximize rendering for depth-only information
@@ -53,26 +237,12 @@ void prep_shadow_map(Scene& scene, GLuint texunit, GLuint texid, uint quality)
   glMultMatrix(ltrans.GetTransposedMatrix().Data());
 
   // only render non-transparent objects for the shadow map
-  scene.GetRootNode()->RenderGL(DEPTH_RENDER_PASS);
+  Scene::Instance().GetRootNode()->RenderGL(DEPTH_RENDER_PASS);
 
   // now get the shadow map
-  glActiveTexture(GL_TEXTURE0+texunit);
-  glBindTexture(GL_TEXTURE_2D, texid);
-
-  glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
-                   0,0, smap_size,smap_size, 0);
-
-  // all of the following texture and shader params need to be moved
-  // to a one-time initialization place
-  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_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);
-
-  // assign tex unit 0 to shadow map
-  Shader::Instance().SetShadowMapping(true,texunit);
+  glActiveTexture(GL_TEXTURE2);
+  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();
@@ -83,8 +253,6 @@ void prep_shadow_map(Scene& scene, GLuint texunit, GLuint texid, uint quality)
   glPopAttrib();
   glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
 
-  glEnable(GL_TEXTURE_2D);
-
   // set up appropriate texture matrix
   geom::Mat4 bias(0.5,0.0,0.0,0.5,
                   0.0,0.5,0.0,0.5,
@@ -100,78 +268,59 @@ void prep_shadow_map(Scene& scene, GLuint texunit, GLuint texid, uint quality)
   glMatrixMode(GL_MODELVIEW);
 }
 
-void prep_amb_occlusion(Scene& scene, GLuint texunit, GLuint texid)
+void SceneFX::prep_amb_occlusion()
 {
+  Viewport vp=Scene::Instance().GetViewport();
+
+  // kernel is static for now, inside the convolution shader
+  Shader::Instance().PushProgram();
+  Shader::Instance().Activate("amboccl");
+  GLuint cpr=Shader::Instance().GetCurrentProgram();
+  // assign tex units
+  glActiveTexture(GL_TEXTURE0);
+  glBindTexture(GL_TEXTURE_2D,depth_tex_id_);
+  glActiveTexture(GL_TEXTURE1);
+  glBindTexture(GL_TEXTURE_2D,norm_tex_id_);
+  glUniform1i(glGetUniformLocation(cpr,"depth"),0);
+  glUniform1i(glGetUniformLocation(cpr,"norm"),1);
+
+  // set up viewport filling quad to run the fragment shader
+  draw_screen_quad(vp.width,vp.height);
+
+  glActiveTexture(GL_TEXTURE3);
+  glBindTexture(GL_TEXTURE_2D, occl_tex_id_);
+  glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, 0,0, vp.width, vp.height, 0);
+
+  Shader::Instance().PopProgram();
 }
 
-void prep_depth_darkening(Scene& scene, GLuint texunit, GLuint texid)
+void SceneFX::prep_depth_darkening()
 {
-  Viewport vp=scene.GetViewport();
-  prep_depth_map(scene,vp.width/2,vp.height/2,texunit,texid);
+  Viewport vp=Scene::Instance().GetViewport();
 
   // kernel is static for now, inside the convolution shader
-
-  // now convolute the depth map with the kernel
   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_);
   glUniform1i(glGetUniformLocation(cpr,"data"),1);
   glUniform1i(glGetUniformLocation(cpr,"vp_width"),vp.width/2);
   glUniform1i(glGetUniformLocation(cpr,"vp_height"),vp.height/2);
 
   // set up viewport filling quad to run the fragment shader
-  draw_screen_quad(vp.width/2,vp.height/2,texunit, texid);
-
-  Shader::Instance().PopProgram();
-
-  // mode 1, tex unit 1
-  Shader::Instance().SetDepthMapping(1,texunit);
-}
-
-void prep_depth_map(Scene& scene, unsigned int width, unsigned int height,GLuint texunit, GLuint texid)
-{
-  // render pass 1 - without shadows
-  Shader::Instance().SetShadowMapping(false,0);
-  // save overall gl settings
-  glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_COLOR_BUFFER_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);
+  draw_screen_quad(vp.width/2,vp.height/2);
 
-  // render scene with only depth components
-  glClear(GL_DEPTH_BUFFER_BIT);
-  glViewport(0,0,width,height);
-  glMatrixMode(GL_MODELVIEW);
-  glPushMatrix();
-  glLoadIdentity();
-  glMultMatrix(scene.GetTransform().GetTransposedMatrix().Data());
-  scene.GetRootNode()->RenderGL(DEPTH_RENDER_PASS);
+  glBindTexture(GL_TEXTURE_2D, dark_tex_id_);
+  glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0,0,vp.width/2, vp.height/2, 0);
 
-  // now get the depth map
-  glActiveTexture(texunit);
-  glBindTexture(GL_TEXTURE_2D, texid);
-  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);
-  glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0,0, width, height, 0);
-
-  // restore settings
-  glMatrixMode(GL_PROJECTION);
-  glPopMatrix();
-  glMatrixMode(GL_MODELVIEW);
-  glPopMatrix();
-  glPopAttrib();
-  glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
+  Shader::Instance().PopProgram();
 }
 
-void draw_screen_quad(unsigned int w, unsigned int h, GLuint gltex, GLuint tex_id) 
+void SceneFX::draw_screen_quad(unsigned int w, unsigned int h) 
 {
-  glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_FOG_BIT);
+  glPushAttrib(GL_ALL_ATTRIB_BITS);
   
   // setup
   glDisable(GL_DEPTH_TEST);
@@ -182,7 +331,7 @@ void draw_screen_quad(unsigned int w, unsigned int h, GLuint gltex, GLuint tex_i
   glDisable(GL_BLEND);
   glDisable(GL_LINE_SMOOTH);
   glDisable(GL_POINT_SMOOTH);
-  glClear(GL_COLOR_BUFFER_BIT);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glViewport(0,0,w,h);
   glMatrixMode(GL_PROJECTION);
   glPushMatrix();
@@ -191,7 +340,7 @@ void draw_screen_quad(unsigned int w, unsigned int h, GLuint gltex, GLuint tex_i
   glMatrixMode(GL_MODELVIEW);
   glPushMatrix();
   glLoadIdentity();
-  
+  glEnable(GL_TEXTURE_2D);
   // draw
   glColor3f(1.0,0.0,1.0);
   glBegin(GL_QUADS);
@@ -205,16 +354,6 @@ void draw_screen_quad(unsigned int w, unsigned int h, GLuint gltex, GLuint tex_i
   glVertex2f(1.0,0.0);
   glEnd();
   
-  // grab the result
-  glEnable(GL_TEXTURE_2D);
-  glActiveTexture(gltex);
-  glBindTexture(GL_TEXTURE_2D, 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);
-  glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0,0, w, h, 0);
-  
   // restore settings
   glMatrixMode(GL_PROJECTION);
   glPopMatrix();
@@ -224,7 +363,7 @@ void draw_screen_quad(unsigned int w, unsigned int h, GLuint gltex, GLuint tex_i
 }
 
 // this debug code draws the given texture across the complete screen
-void draw_debug_tex(unsigned int w, unsigned int h, GLuint texid)
+void SceneFX::draw_debug_tex(unsigned int w, unsigned int h, GLuint texid)
 {
   glPushAttrib(GL_ALL_ATTRIB_BITS);
   Shader::Instance().PushProgram();
diff --git a/modules/gfx/src/impl/scene_fx.hh b/modules/gfx/src/impl/scene_fx.hh
index 5c407e8be1899f99ec99a810e58de347471422f1..6db023e03987e0fbe34ac41e51ef9cf3f2304619 100644
--- a/modules/gfx/src/impl/scene_fx.hh
+++ b/modules/gfx/src/impl/scene_fx.hh
@@ -33,12 +33,49 @@ class Scene;
 
 namespace impl {
 
-void prep_shadow_map(Scene& scene, GLuint texunit, GLuint texid, uint quality);
-void prep_depth_darkening(Scene& scene, GLuint texunit, GLuint texid);
-void prep_amb_occlusion(Scene& scene, GLuint texunit, GLuint texid);
-void prep_depth_map(Scene& scene, uint, uint, GLuint texunit, GLuint texid);
-void draw_screen_quad(unsigned int w, unsigned int h, GLuint texunit, GLuint texid);
-void draw_debug_tex(unsigned int w, unsigned int h, GLuint texid);
+class SceneFX {
+public:
+  ~SceneFX();
+  static SceneFX& Instance();
+
+  void Setup();
+
+  void Resize(unsigned int w, unsigned int h);
+  
+  void Preprocess();
+  // assumes scene has been drawn in the active framebuffer
+  void Postprocess();
+
+  bool shadow_flag;
+  int shadow_quality;
+  bool depth_dark_flag;
+  bool amb_occl_flag;
+
+private:
+  SceneFX();
+  SceneFX(const SceneFX&) {}
+  SceneFX& operator=(const SceneFX&) {return *this;}
+
+  void prep_shadow_map();
+  void prep_depth_darkening();
+  void prep_amb_occlusion();
+  void draw_screen_quad(uint w, uint h);
+  void draw_debug_tex(unsigned int w, unsigned int h, GLuint texid);
+
+  GLuint scene_tex_id_;
+  GLuint depth_tex_id_;
+  GLuint shadow_tex_id_;
+  GLuint occl_tex_id_;
+  GLuint dark_tex_id_;
+  GLuint norm_tex_id_;
+
+  GLuint scene_tex2_id_;
+  GLuint norm_tex2_id_;
+  GLuint scene_fb_;
+  GLuint depth_rb_;
+
+  bool use_fb_;
+};
 
 }}} // ns
 
diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc
index 5a8222295e22f6336f574ba2e526071706d0422d..6c8bbded8a36d710529892a2d4b33682600aefef 100644
--- a/modules/gfx/src/scene.cc
+++ b/modules/gfx/src/scene.cc
@@ -109,14 +109,6 @@ Scene::Scene():
   axis_flag_(false),
   fog_flag_(true),
   fog_color_(0.0,0.0,0.0,0.0),
-  shadow_flag_(false),
-  shadow_quality_(1),
-  shadow_tex_id_(),
-  depth_dark_flag_(false),
-  amb_occl_flag_(false),
-  depth_tex_id_(),
-  kernel_tex_id_(),
-  scene_tex_id_(),
   auto_autoslab_(true),
   offscreen_flag_(false),
   main_offscreen_buffer_(0),
@@ -168,34 +160,46 @@ Color Scene::GetFogColor() const
 
 void Scene::SetShadow(bool f)
 {
-  shadow_flag_=f;
+#if OST_SHADER_SUPPORT_ENABLED
+  impl::SceneFX::Instance().shadow_flag=f;
   // the redraw routine will deal with the Shader
   RequestRedraw();
+#endif
+}
+
+bool Scene::GetShadow() const
+{
+#if OST_SHADER_SUPPORT_ENABLED
+  return impl::SceneFX::Instance().shadow_flag;
+#endif
 }
 
 void Scene::SetShadowQuality(int q)
 {
-  shadow_quality_=std::min(3,std::max(0,q));
-  if(shadow_flag_) {
-    RequestRedraw();
-  }
+#if OST_SHADER_SUPPORT_ENABLED
+  impl::SceneFX::Instance().shadow_quality=std::min(3,std::max(0,q));
+  RequestRedraw();
+#endif
 }
 
 void Scene::SetDepthDarkening(bool f)
 {
-  depth_dark_flag_=f;
+#if OST_SHADER_SUPPORT_ENABLED
+  impl::SceneFX::Instance().depth_dark_flag=f;
   // the redraw routine will deal with the Shader
   RequestRedraw();
+#endif
 }
 
 void Scene::SetAmbientOcclusion(bool f)
 {
-  amb_occl_flag_=f;
+#if OST_SHADER_SUPPORT_ENABLED
+  impl::SceneFX::Instance().amb_occl_flag=f;
   // the redraw routine will deal with the Shader
   RequestRedraw();
+#endif
 }
 
-
 void Scene::SetShadingMode(const std::string& smode)
 {
 #if OST_SHADER_SUPPORT_ENABLED
@@ -320,11 +324,8 @@ void Scene::InitGL()
   LOGN_DEBUG("scene: shader setup");
   Shader::Instance().Setup();
   SetShadingMode("default");
-
-  glGenTextures(1,&shadow_tex_id_);
-  glGenTextures(1,&depth_tex_id_);
-  glGenTextures(1,&kernel_tex_id_);
-  glGenTextures(1,&scene_tex_id_);
+  LOGN_DEBUG("scene: scenefx setup");
+  impl::SceneFX::Instance().Setup();
 #endif
 
   prep_glyphs();
@@ -369,6 +370,9 @@ void Scene::SetViewport(int w, int h)
   vp_height_=h;
   aspect_ratio_=static_cast<float>(w)/static_cast<float>(h);
   ResetProjection();
+#if OST_SHADER_SUPPORT_ENABLED
+  impl::SceneFX::Instance().Resize(w,h);
+#endif
 }
 
 void Scene::Resize(int w, int h)
@@ -506,23 +510,6 @@ void Scene::RenderGL()
 {
   if(auto_autoslab_) Autoslab(false, false);
 
-  #if OST_SHADER_SUPPORT_ENABLED
-  if(amb_occl_flag_) {
-    impl::prep_amb_occlusion(*this,GL_TEXTURE1, depth_tex_id_);
-  } else {
-    Shader::Instance().SetOcclusionMapping(0,0);
-  }
-  if(depth_dark_flag_) {
-    impl::prep_depth_darkening(*this,GL_TEXTURE1, depth_tex_id_);
-  } else {
-    Shader::Instance().SetDepthMapping(0,0);
-  }
-  if(shadow_flag_) {
-    impl::prep_shadow_map(*this,GL_TEXTURE0,shadow_tex_id_,shadow_quality_);
-  } else {
-    Shader::Instance().SetShadowMapping(0,0);
-  }
-  #endif
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   prep_blur();
 
@@ -533,6 +520,17 @@ void Scene::RenderGL()
 
   glMultMatrix(transform_.GetTransposedMatrix().Data());
 
+  // TODO: handle stereo
+#if OST_SHADER_SUPPORT_ENABLED
+  impl::SceneFX::Instance().Preprocess();
+#endif
+  render_standard_scene();
+#if OST_SHADER_SUPPORT_ENABLED
+  impl::SceneFX::Instance().Postprocess();
+#endif
+  render_glow();
+  
+#if 0
   if(stereo_==2 || stereo_==3) {
     render_interlaced_stereo();
   } else if (stereo_==1) {
@@ -540,11 +538,8 @@ void Scene::RenderGL()
   } else {
     this->render_scene_with_glow();
   }
-  #if OST_SHADER_SUPPORT_ENABLED
-  if(shadow_flag_) {
-    glDisable(GL_TEXTURE_2D);
-  }
-  #endif
+#endif
+
 }
 
 void Scene::Register(GLWinBase* win)
@@ -1681,7 +1676,7 @@ void Scene::prep_blur()
   glFlush();
 }
 
-void Scene::render_scene_with_glow()
+void Scene::render_standard_scene()
 {
   glDepthFunc(GL_LEQUAL);    
   glDepthMask(1);
@@ -1693,8 +1688,11 @@ void Scene::render_scene_with_glow()
   root_node_->RenderGL(TRANSPARENT_RENDER_PASS);
   glDisable(GL_BLEND);
   root_node_->RenderGL(OVERLAY_RENDER_PASS);
+}
 
-  glPushAttrib(GL_ENABLE_BIT);
+void Scene::render_glow()
+{
+  glPushAttrib(GL_ALL_ATTRIB_BITS);
   glEnable(GL_COLOR_MATERIAL);
   glShadeModel(GL_FLAT);
   glDisable(GL_FOG);
@@ -1739,6 +1737,7 @@ void Scene::stereo_projection(unsigned int view)
 
 void Scene::render_interlaced_stereo()
 {
+#if 0
   // set up stencil buffer
   glPushAttrib(GL_STENCIL_BUFFER_BIT| GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT);
   glMatrixMode(GL_PROJECTION);
@@ -1791,10 +1790,12 @@ void Scene::render_interlaced_stereo()
   root_node_->RenderGL(GLOW_RENDER_PASS);
   glDisable(GL_STENCIL_TEST);
   glPopAttrib();
+#endif
 }
 
 void Scene::render_quad_buffered_stereo()
 {
+#if 0
   glDrawBuffer(GL_BACK);
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
   glDrawBuffer(GL_BACK_LEFT);
@@ -1814,6 +1815,7 @@ void Scene::render_quad_buffered_stereo()
   }
   this->render_scene_with_glow();
   glDrawBuffer(GL_BACK);
+#endif
 }
 
 }} // ns
diff --git a/modules/gfx/src/scene.hh b/modules/gfx/src/scene.hh
index f35920a8377550b1ab4050560682188f94c63735..17182a20e7ab931e1913bfddb1e5fff9702ae82b 100644
--- a/modules/gfx/src/scene.hh
+++ b/modules/gfx/src/scene.hh
@@ -51,8 +51,8 @@ class OffscreenBuffer;
 typedef std::vector<SceneObserver*>  SceneObserverList;
 
 struct Viewport {
-  int bottom;
-  int left;
+  int x;
+  int y;
   int width;
   int height;
 };
@@ -106,7 +106,7 @@ class DLLEXPORT_OST_GFX Scene {
   void SetShadow(bool f);
 
   /// \brief get shadow mapping status
-  bool GetShadow() const {return shadow_flag_;}
+  bool GetShadow() const;
 
   /// \brief shadow quality from 0 (low) to 3 (high), default=1
   void SetShadowQuality(int q);
@@ -409,14 +409,6 @@ private:
   bool axis_flag_;
   bool fog_flag_;
   Color fog_color_;
-  bool shadow_flag_;
-  int shadow_quality_;
-  GLuint shadow_tex_id_;
-  bool depth_dark_flag_;
-  bool amb_occl_flag_;
-  GLuint depth_tex_id_;
-  GLuint kernel_tex_id_;
-  GLuint scene_tex_id_;
   bool auto_autoslab_;
 
   bool offscreen_flag_; // a simple indicator whether in offscreen mode or not
@@ -449,7 +441,8 @@ private:
   void stereo_projection(unsigned int view);
   void render_interlaced_stereo();
   void render_quad_buffered_stereo();
-  void render_scene_with_glow();
+  void render_standard_scene();
+  void render_glow();
   bool IsNameAvailable(String name);
 };
 
diff --git a/modules/gfx/src/shader.cc b/modules/gfx/src/shader.cc
index a3940c457238f78f00e543fda7b7620162643f04..3fed86bf6bad13dd1c54cc499d25435d5308ecd0 100644
--- a/modules/gfx/src/shader.cc
+++ b/modules/gfx/src/shader.cc
@@ -150,7 +150,9 @@ void Shader::Setup()
     {"outline_vs.glsl", GL_VERTEX_SHADER},
     {"quadpp_vs.glsl", GL_VERTEX_SHADER},
     {"convolute1_fs.glsl", GL_FRAGMENT_SHADER},
-    {"amboccl_fs.glsl", GL_FRAGMENT_SHADER}
+    {"amboccl_fs.glsl", GL_FRAGMENT_SHADER},
+    {"scenefx_vs.glsl", GL_VERTEX_SHADER},
+    {"scenefx_fs.glsl", GL_FRAGMENT_SHADER}
     //////////////////////////////////////////////////////////////////
   };
 
@@ -253,18 +255,25 @@ void Shader::Setup()
   }
   // convolute1 shader
   shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["quadpp.glsl"]);
+  shader_program_list.push_back(shader_code_map_["quadpp_vs.glsl"]);
   shader_program_list.push_back(shader_code_map_["convolute1_fs.glsl"]);
   if(link_shader(shader_program_list,"convolute1",shader_program_id)) {
     shader_program_map_["convolute1"]=shader_program_id;
   }
-  // amb occl shader
+  // amboccl shader
   shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["quadpp.glsl"]);
+  shader_program_list.push_back(shader_code_map_["quadpp_vs.glsl"]);
   shader_program_list.push_back(shader_code_map_["amboccl_fs.glsl"]);
   if(link_shader(shader_program_list,"amboccl",shader_program_id)) {
     shader_program_map_["amboccl"]=shader_program_id;
   }
+  // scenefx shader
+  shader_program_list.clear();
+  shader_program_list.push_back(shader_code_map_["scenefx_vs.glsl"]);
+  shader_program_list.push_back(shader_code_map_["scenefx_fs.glsl"]);
+  if(link_shader(shader_program_list,"scenefx",shader_program_id)) {
+    shader_program_map_["scenefx"]=shader_program_id;
+  }
 
   valid_=true;
 }
@@ -327,33 +336,6 @@ void Shader::PopProgram()
   }
 }
 
-void Shader::SetShadowMapping(bool flag, GLuint texid)
-{
-  shadow_flag_=flag;
-  if(flag) {
-    shadow_map_id_=texid;
-  }
-  UpdateState();
-}
-
-void Shader::SetOcclusionMapping(bool flag, GLuint texid)
-{
-  occl_flag_=flag;
-  if(flag) {
-    occl_map_id_=texid;
-  }
-  UpdateState();
-}
-
-void Shader::SetDepthMapping(int mode, GLuint texid)
-{
-  depth_mode_=mode;
-  if(mode>0) {
-    depth_map_id_=texid;
-  }
-  UpdateState();
-}
-
 void Shader::UpdateState()
 {
   if(current_program_!=0) {
@@ -369,23 +351,6 @@ void Shader::UpdateState()
     glGetIntegerv(GL_FOG,&result);
     LOGN_TRACE("setting fog flag to " << result);
     glUniform1i(glGetUniformLocation(current_program_,"fog_flag"),result);
-    if(shadow_flag_) {
-      LOGN_TRACE("setting shadow flag to 1");
-      glUniform1i(glGetUniformLocation(current_program_,"shadow_flag"),1);
-      glUniform1i(glGetUniformLocation(current_program_,"shadow_map"),shadow_map_id_);
-      glUniform1f(glGetUniformLocation(current_program_,"shadow_depth_bias"),0.008);
-      glUniform1f(glGetUniformLocation(current_program_,"shadow_epsilon"),0.002);
-      glUniform1f(glGetUniformLocation(current_program_,"shadow_multiplier"),0.4);
-    } else {
-      LOGN_TRACE("setting shadow flag to 0");
-      glUniform1i(glGetUniformLocation(current_program_,"shadow_flag"),0);
-    }
-    LOGN_TRACE("setting depth mode to" << depth_mode_);
-    glUniform1i(glGetUniformLocation(current_program_,"depth_mode"),depth_mode_);
-    if(depth_mode_>0) {
-      glUniform1i(glGetUniformLocation(current_program_,"depth_map"),depth_map_id_);
-    }
-
     glDisable(GL_COLOR_MATERIAL);
 
   } else {
diff --git a/modules/gfx/src/shader.hh b/modules/gfx/src/shader.hh
index b8938108f433527bd33eeb6fa5a2f63414f6fc77..8715e907cd9375966b3e465f674e7b31a46abab9 100644
--- a/modules/gfx/src/shader.hh
+++ b/modules/gfx/src/shader.hh
@@ -52,11 +52,6 @@ public:
   void PopProgram();
 
   void UpdateState();
-
-  void SetShadowMapping(bool flag, GLuint texid);
-  void SetDepthMapping(int mode, GLuint texid);
-  void SetOcclusionMapping(bool flag, GLuint texid);
-  
 private:
   Shader();
 
@@ -64,13 +59,6 @@ private:
   GLuint current_program_;
   String current_name_;
 
-  bool shadow_flag_;
-  GLuint shadow_map_id_;
-  int depth_mode_;
-  GLuint depth_map_id_;
-  bool occl_flag_;
-  GLuint occl_map_id_;
-
   std::stack<String> program_stack_;
 
   std::map<String,GLuint> shader_code_map_;
diff --git a/modules/gfx/src/shader/amboccl_fs.glsl b/modules/gfx/src/shader/amboccl_fs.glsl
index 44ad2220da64942e6d16e90396f36855bde2ec7e..76501a6cbda6754aea849c5d9071230f6941a6bd 100644
--- a/modules/gfx/src/shader/amboccl_fs.glsl
+++ b/modules/gfx/src/shader/amboccl_fs.glsl
@@ -1,6 +1,9 @@
-uniform sampler2D data;
+uniform sampler2D depth;
+uniform sampler2D norm;
 
 void main()
 {
-  gl_FragColor=texture2D(data,gl_TexCoord[0].xy);
+  float val = texture2D(depth,gl_TexCoord[0].xy).r;
+  gl_FragColor.rgb=1.0;
+  gl_FragColor.a=1.0;
 }
diff --git a/modules/gfx/src/shader/basic_fs.glsl b/modules/gfx/src/shader/basic_fs.glsl
index ceda497725ff8666bda220f6ab20e734bb66bae9..68059f4d1f084dcdd512e1c9f62fc409b15511d0 100644
--- a/modules/gfx/src/shader/basic_fs.glsl
+++ b/modules/gfx/src/shader/basic_fs.glsl
@@ -1,33 +1,10 @@
-uniform sampler2D shadow_map;
-uniform bool shadow_flag;
-uniform float shadow_depth_bias;
-uniform float shadow_epsilon;
-uniform float shadow_multiplier;
 uniform bool fog_flag;
 
-float CalcShadowFactor(in vec4 coord, in vec2 o)
-{
-  // get original depth value of line projected towards light
-  float d = texture2D(shadow_map, coord.xy+o*shadow_epsilon).x+shadow_depth_bias;
-  return d<=coord.z ? shadow_multiplier : 1.0;
-}
-
 void main()
 {
   float fog = fog_flag ? clamp((gl_Fog.end-gl_FogFragCoord) * gl_Fog.scale, 0.0, 1.0) : 1.0;
-  if(shadow_flag) {
-    vec4 coord=gl_TexCoord[1]/gl_TexCoord[1].w;
-    float sum = 0.0;
-    sum += 0.18*CalcShadowFactor(coord, vec2(-0.7, -0.7));
-    sum += 0.18*CalcShadowFactor(coord, vec2(0.7, -0.7));
-    sum += 0.18*CalcShadowFactor(coord, vec2(0.7, 0.7));
-    sum += 0.18*CalcShadowFactor(coord, vec2(-0.7, 0.7));
-    sum += 0.28*CalcShadowFactor(coord, vec2(0, 0));
-
-    gl_FragColor = vec4(sum*mix(gl_Fog.color.rgb, gl_Color.rgb, fog),gl_Color.a);
-  } else {
-    gl_FragColor.rgb = mix(gl_Fog.color.rgb, gl_Color.rgb, fog);
-    gl_FragColor.a = gl_Color.a;
-  }
+  gl_FragColor.rgb = mix(gl_Fog.color.rgb, gl_Color.rgb, fog);
+  gl_FragColor.a = gl_Color.a;
+  gl_FragBuffer[1].rgb=gl_TexCoord[0].stp*0.5+0.5;
 }
 
diff --git a/modules/gfx/src/shader/basic_vs.glsl b/modules/gfx/src/shader/basic_vs.glsl
index 9f43289f6ab97923b819fa89c5fe71d6a6f5f43e..10cdf3a2439b017f7e922544e8f2c558e1038c16 100644
--- a/modules/gfx/src/shader/basic_vs.glsl
+++ b/modules/gfx/src/shader/basic_vs.glsl
@@ -56,6 +56,7 @@ void main()
   vec4 ec_Pos = gl_ModelViewMatrix* gl_Vertex;
 
   vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
+  gl_TexCoord[0].stp = normal;
   
   if(lighting_flag) {
     CalcFrontAndBackColor(normal);
diff --git a/modules/gfx/src/shader/fraglight_fs.glsl b/modules/gfx/src/shader/fraglight_fs.glsl
index ac28cee890768a42313d1a3feb297b40a60b6937..a19d6b9a58f7017e8af5d859a6fda64a42ed3951 100644
--- a/modules/gfx/src/shader/fraglight_fs.glsl
+++ b/modules/gfx/src/shader/fraglight_fs.glsl
@@ -4,11 +4,6 @@ uniform bool fog_flag;
 uniform bool occlusion_flag;
 uniform vec2 ambient_weight;
 varying vec4 ambient_color;
-uniform bool shadow_flag;
-uniform sampler2D shadow_map;
-uniform float shadow_depth_bias;
-uniform float shadow_epsilon;
-uniform float shadow_multiplier;
 uniform sampler2D depth_map;
 uniform int depth_mode;
 
@@ -36,14 +31,6 @@ bool DirectionalLight(in vec3 normal,
   return true;
 }
 
-// copy from basic_lfs_fs !
-float CalcShadowFactor(in vec4 coord, in vec2 o)
-{
-  // get original depth value of line projected towards light
-  float d = texture2D(shadow_map, coord.xy+o*shadow_epsilon).x+shadow_depth_bias;
-  return d<=coord.z ? shadow_multiplier : 1.0;
-}
-
 void main()
 {
   bool lflag=false;
@@ -92,22 +79,7 @@ void main()
   }
 
   float fog = fog_flag ? clamp((gl_Fog.end-gl_FogFragCoord) * gl_Fog.scale, 0.0, 1.0) : 1.0;
-  if(shadow_flag) {
-    vec4 coord = gl_TexCoord[1]/gl_TexCoord[1].w;
-    float sum = 0.0;
-    if(lflag) {
-      sum += 0.18*CalcShadowFactor(coord, vec2(-0.7, -0.7));
-      sum += 0.18*CalcShadowFactor(coord, vec2(0.7, -0.7));
-      sum += 0.18*CalcShadowFactor(coord, vec2(0.7, 0.7));
-      sum += 0.18*CalcShadowFactor(coord, vec2(-0.7, 0.7));
-      sum += 0.28*CalcShadowFactor(coord, vec2(0, 0));
-    } else {
-      sum = shadow_multiplier;
-    }
-
-    gl_FragColor = vec4(sum*mix(gl_Fog.color.rgb, gl_FragColor.rgb, fog),gl_FragColor.a);
-  } else {
-    gl_FragColor.rgb = mix(gl_Fog.color.rgb, gl_FragColor.rgb, fog);
-    gl_FragColor.a = gl_Color.a;
-  }
+  gl_FragColor.rgb = mix(gl_Fog.color.rgb, gl_FragColor.rgb, fog);
+  gl_FragColor.a = gl_Color.a;
+  gl_FragBuffer[1].rgb=gl_TexCoord[0].stp*0.5+0.5;
 }
diff --git a/modules/gfx/src/shader/quadpp_vs.glsl b/modules/gfx/src/shader/quadpp_vs.glsl
index 5760f62116b23c27f68ef3f74d9e4a079429718c..043c65d69b2d1a4f96d705cc84d12ba9b847d592 100644
--- a/modules/gfx/src/shader/quadpp_vs.glsl
+++ b/modules/gfx/src/shader/quadpp_vs.glsl
@@ -1,6 +1,6 @@
 void main()
 {    
   gl_Position = ftransform();
-  gl_TexCoord[0].st = 0.5*(gl_Position.xy+vec2(1.0,1.0));
+  gl_TexCoord[0] = gl_MultiTexCoord0;
 }
 
diff --git a/modules/gfx/src/shader/scenefx_fs.glsl b/modules/gfx/src/shader/scenefx_fs.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..83cc911d22c2a4c523ba629d0bef5a0a820053e3
--- /dev/null
+++ b/modules/gfx/src/shader/scenefx_fs.glsl
@@ -0,0 +1,42 @@
+uniform sampler2D scene;
+uniform sampler2D depth;
+uniform vec2 scalef;
+uniform vec2 zmorph;
+uniform bool shadow_flag;
+uniform sampler2D shadow_map;
+uniform float shadow_depth_bias;
+uniform float shadow_epsilon;
+uniform float shadow_multiplier;
+uniform bool occl_flag;
+uniform sampler2D occl_map;
+
+float CalcShadowFactor(in vec4 coord, in vec2 o)
+{
+  // get original depth value of line projected towards light
+  float d = texture2D(shadow_map, coord.xy+o*shadow_epsilon).x+shadow_depth_bias;
+  return d<=coord.z ? shadow_multiplier : 1.0;
+}
+
+void main()
+{
+  float shadow_factor=1.0;
+  if(shadow_flag) {
+    // TODO: calculate appropriate coord from glTexCoord[1].xy and the depth map
+    vec4 coord;
+    shadow_factor = 0.0;
+    shadow_factor += 0.18*CalcShadowFactor(coord, vec2(-0.7, -0.7));
+    shadow_factor += 0.18*CalcShadowFactor(coord, vec2(0.7, -0.7));
+    shadow_factor += 0.18*CalcShadowFactor(coord, vec2(0.7, 0.7));
+    shadow_factor += 0.18*CalcShadowFactor(coord, vec2(-0.7, 0.7));
+    shadow_factor += 0.28*CalcShadowFactor(coord, vec2(0, 0));
+  }
+
+  float occl_factor=1.0;
+  if(occl_flag) {
+    occl_factor=texture2D(occl_map,gl_TexCoord[0].xy).r;
+  }
+    
+  vec4 scene_color=texture2D(scene,gl_TexCoord[0].xy);
+  gl_FragColor.rgb = shadow_factor*occl_factor*scene_color.rgb;
+  gl_FragColor.a = scene_color.a;
+}
diff --git a/modules/gfx/src/shader/scenefx_vs.glsl b/modules/gfx/src/shader/scenefx_vs.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..59aa7bb4e40cb464102a85b54b902f36376398df
--- /dev/null
+++ b/modules/gfx/src/shader/scenefx_vs.glsl
@@ -0,0 +1,8 @@
+void main()
+{    
+  gl_Position = ftransform();
+  // relative screen coordinates
+  gl_TexCoord[0] = gl_MultiTexCoord0;
+  gl_TexCoord[1] = gl_Vertex;
+}
+