From fe8a623f444a7c043986b74cbfbdbc1e36307609 Mon Sep 17 00:00:00 2001
From: Ansgar Philippsen <ansgar.philippsen@gmail.com>
Date: Tue, 19 Jun 2012 16:26:00 -0400
Subject: [PATCH] shader refactoring

refactored some shader code, mostly geared towards the fast sphere functionality, but
also simplified and cleaned up some code in shader.cc
---
 modules/gfx/src/CMakeLists.txt                |  13 +-
 modules/gfx/src/impl/cpk_renderer.cc          | 129 +++-----
 modules/gfx/src/impl/cpk_renderer.hh          |   8 +-
 modules/gfx/src/impl/fast_spheres.cc          | 121 +++++++
 modules/gfx/src/impl/fast_spheres.hh          |  60 ++++
 modules/gfx/src/shader.cc                     | 298 +++++++-----------
 modules/gfx/src/shader.hh                     |  16 +-
 modules/gfx/src/shader/basic_hf_vs.glsl       |  43 ---
 modules/gfx/src/shader/basic_lf_fs.glsl       |  13 -
 modules/gfx/src/shader/basic_lf_vs.glsl       |  87 -----
 modules/gfx/src/shader/fast_sphere_fs.glsl    |  35 +-
 modules/gfx/src/shader/fast_sphere_vs.glsl    |  33 --
 modules/gfx/src/shader/fraglight_fs.glsl      |  47 +--
 modules/gfx/src/shader/fraglight_vs.glsl      |  11 +-
 modules/gfx/src/shader/material_hemi.glsl     |  18 ++
 modules/gfx/src/shader/material_phong.glsl    |  51 +++
 .../{toon_fs.glsl => material_toon1.glsl}     |  24 +-
 .../{toon2_fs.glsl => material_toon2.glsl}    |  27 +-
 modules/gfx/src/shader/toon_vs.glsl           |  19 --
 19 files changed, 464 insertions(+), 589 deletions(-)
 create mode 100644 modules/gfx/src/impl/fast_spheres.cc
 create mode 100644 modules/gfx/src/impl/fast_spheres.hh
 delete mode 100644 modules/gfx/src/shader/basic_hf_vs.glsl
 delete mode 100644 modules/gfx/src/shader/basic_lf_fs.glsl
 delete mode 100644 modules/gfx/src/shader/basic_lf_vs.glsl
 delete mode 100644 modules/gfx/src/shader/fast_sphere_vs.glsl
 create mode 100644 modules/gfx/src/shader/material_hemi.glsl
 create mode 100644 modules/gfx/src/shader/material_phong.glsl
 rename modules/gfx/src/shader/{toon_fs.glsl => material_toon1.glsl} (56%)
 rename modules/gfx/src/shader/{toon2_fs.glsl => material_toon2.glsl} (65%)
 delete mode 100644 modules/gfx/src/shader/toon_vs.glsl

diff --git a/modules/gfx/src/CMakeLists.txt b/modules/gfx/src/CMakeLists.txt
index 6028b64f8..7a92969a9 100644
--- a/modules/gfx/src/CMakeLists.txt
+++ b/modules/gfx/src/CMakeLists.txt
@@ -84,6 +84,7 @@ connect_renderer_base.hh
 mapped_property.hh
 entity_renderer_fw.hh
 tabulated_trig.hh
+fast_spheres.hh
 )
 
 
@@ -138,6 +139,7 @@ impl/trace_renderer_base.cc
 impl/mapped_property.cc
 impl/tabulated_trig.cc
 impl/trace_renderer.cc
+impl/fast_spheres.cc
 render_options/render_options.cc
 render_options/line_render_options.cc
 render_options/custom_render_options.cc
@@ -243,16 +245,12 @@ if (USE_SHADER)
     shader/aaline_fs.glsl
     shader/amboccl_fs.glsl
     shader/basic_fs.glsl
-    shader/basic_hf_vs.glsl
-    shader/basic_lf_fs.glsl
-    shader/basic_lf_vs.glsl
     shader/basic_vs.glsl
     shader/beacon_fs.glsl
     shader/convolute1_fs.glsl
     shader/dumpnorm_fs.glsl
     shader/dumpnorm_vs.glsl
     shader/fast_sphere_fs.glsl
-    shader/fast_sphere_vs.glsl
     shader/fraglight_fs.glsl
     shader/fraglight_vs.glsl
     shader/iso_fs.glsl
@@ -264,11 +262,12 @@ if (USE_SHADER)
     shader/scenefx_vs.glsl
     shader/selfx_fs.glsl
     shader/selfx_vs.glsl
-    shader/toon2_fs.glsl
-    shader/toon_fs.glsl
-    shader/toon_vs.glsl
     shader/screenblur4_fs.glsl
     shader/test_tex_fs.glsl
+    shader/material_phong.glsl
+    shader/material_hemi.glsl
+    shader/material_toon1.glsl
+    shader/material_toon2.glsl
   )
   copy_if_different("./" "${SHARED_DATA_PATH}/shader" "${SHADER_FILES}" 
                     "SHADER_TARGETS" ost_gfx)  
diff --git a/modules/gfx/src/impl/cpk_renderer.cc b/modules/gfx/src/impl/cpk_renderer.cc
index a0d286047..dce0cccb0 100644
--- a/modules/gfx/src/impl/cpk_renderer.cc
+++ b/modules/gfx/src/impl/cpk_renderer.cc
@@ -32,7 +32,12 @@
 
 namespace ost { namespace gfx { namespace impl {
 
-CPKRenderer::CPKRenderer(): options_(new CPKRenderOptions()) {
+CPKRenderer::CPKRenderer(): 
+  options_(new CPKRenderOptions())
+#if OST_SHADER_SUPPORT_ENABLED
+  ,fsr_(),sel_fsr_()
+#endif  
+{
   this->SetName("Spheres");
 }
 
@@ -56,20 +61,33 @@ void CPKRenderer::PrepareRendering(GfxView& view, IndexedVertexArray& va, bool i
   if(options_!=NULL){
     factor *= options_->GetRadiusMult();
     if(factor>0.0) {
-      va.SetLighting(true);
-      va.SetCullFace(true);
-      va.SetColorMaterial(true);
-      va.SetMode(0x4);
-      
-      // draw all spheres
-      uint det=options_->GetSphereDetail();
-      for(AtomEntryMap::const_iterator it=view.atom_map.begin();it!=view.atom_map.end();++it) {
-        va.AddSphere(SpherePrim(it->second.atom.GetPos(),
-                                it->second.vdwr*factor,
-                                is_sel? sel_clr : it->second.color),
-                     det);
+#if OST_SHADER_SUPPORT_ENABLED
+      if(options_->GetSphereMode()==1 || options_->GetSphereMode()==2) {
+        FastSphereRenderer& fsr = is_sel ? sel_fsr_ : fsr_;
+        for(AtomEntryMap::const_iterator it=view.atom_map.begin();it!=view.atom_map.end();++it) {
+          fsr.Add(it->second.atom.GetPos(),
+                  is_sel? sel_clr : it->second.color,
+                  it->second.vdwr*factor);
+        }
+      } else {
+#endif
+        va.SetLighting(true);
+        va.SetCullFace(true);
+        va.SetColorMaterial(true);
+        va.SetMode(0x4);
+        
+        // draw all spheres
+        uint det=options_->GetSphereDetail();
+        for(AtomEntryMap::const_iterator it=view.atom_map.begin();it!=view.atom_map.end();++it) {
+          va.AddSphere(SpherePrim(it->second.atom.GetPos(),
+                                  it->second.vdwr*factor,
+                                  is_sel? sel_clr : it->second.color),
+                       det);
+        }
       }
+#if OST_SHADER_SUPPORT_ENABLED
     }
+#endif
   }
   sel_state_=0;
   state_=0;
@@ -79,13 +97,17 @@ void CPKRenderer::Render(RenderPass pass)
 {
   if(options_!=NULL){
 #if OST_SHADER_SUPPORT_ENABLED
-    if(pass==STANDARD_RENDER_PASS && (options_->GetSphereMode()==1 || options_->GetSphereMode()==2)) {
-      this->Render3DSprites();
+    if(options_->GetSphereMode()==1 || options_->GetSphereMode()==2) {
+      if(pass==STANDARD_RENDER_PASS) {
+        fsr_.RenderGL();
+      } else if(pass==GLOW_RENDER_PASS && this->HasSelection()) {
+        sel_fsr_.RenderGL();
+      }
       return;
     }
 #endif
   }
-  // fall back to parent if above did not fire
+  // fall back to default if above did not fire
   EntityRenderer::Render(pass);
 }
 
@@ -116,79 +138,4 @@ RenderOptionsPtr CPKRenderer::GetOptions(){
  return options_;
 }
 
-namespace {
-
-void Render3DSpritesInnerLoop(const AtomEntry* ae, const geom::Vec3& cx, 
-                              const geom::Vec3& cy, const geom::Vec3& cz, 
-                              GLdouble* gl_mmat, GLdouble* gl_pmat, GLint* gl_vp,
-                              float rmul)
-{
-  geom::Vec3 pos = ae->atom.GetPos();
-  float rad = rmul*ae->vdwr;
-  GLdouble r1[3],r2[3];
-  gluProject(pos[0],pos[1],pos[2],
-             gl_mmat,gl_pmat,gl_vp,
-             &r1[0],&r1[1],&r1[2]);
-  gluProject(pos[0]-rad*cz[0],pos[1]-rad*cz[1],pos[2]-rad*cz[2],
-             gl_mmat,gl_pmat,gl_vp,
-             &r2[0],&r2[1],&r2[2]);
-  float scale = r1[2]-r2[2];
-  glColor3fv(ae->color);
-  glTexCoord4f(0.0,0.0,-rad,scale);
-  glVertex3v((pos-rad*cx-rad*cy).Data());
-  glTexCoord4f(0.0,1.0,-rad,scale);
-  glVertex3v((pos-rad*cx+rad*cy).Data());
-  glTexCoord4f(1.0,1.0,-rad,scale);
-  glVertex3v((pos+rad*cx+rad*cy).Data());
-  glTexCoord4f(1.0,0.0,-rad,scale);
-  glVertex3v((pos+rad*cx-rad*cy).Data());
-}
-
-}
-
-void CPKRenderer::Render3DSprites()
-{
-#if OST_SHADER_SUPPORT_ENABLED
-  if(options_!=NULL){
-    float rmul= options_->GetRadiusMult();
-    if(rmul==0.0) return;
-
-    geom::Mat3 irot=geom::Transpose(Scene::Instance().GetTransform().GetRot());
-    geom::Vec3 cx=irot*geom::Vec3(1.0,0.0,0.0);
-    geom::Vec3 cy=irot*geom::Vec3(0.0,1.0,0.0);
-    geom::Vec3 cz=irot*geom::Vec3(0.0,0.0,1.0);
-
-    uint write_normals = Shader::Instance().GetCurrentName()=="dumpnorm" ? 1 : 0;
-    uint use_hemimodel = Shader::Instance().GetCurrentName()=="hemilight" ? 1 : 0;
-    Shader::Instance().PushProgram();
-    Shader::Instance().Activate("fast_sphere");
-    Shader::Instance().UpdateState();
-    glUniform1i(glGetUniformLocation(Shader::Instance().GetCurrentProgram(),"write_normals"),write_normals);
-    glUniform1i(glGetUniformLocation(Shader::Instance().GetCurrentProgram(),"use_hemimodel"),use_hemimodel);
-
-    glPushAttrib(GL_ALL_ATTRIB_BITS);
-    glDisable(GL_LIGHTING);
-    glDisable(GL_CULL_FACE);
-
-    GLdouble gl_mmat[16];
-    glGetDoublev(GL_MODELVIEW_MATRIX,gl_mmat);
-    GLdouble gl_pmat[16];
-    glGetDoublev(GL_PROJECTION_MATRIX,gl_pmat);
-    GLint gl_vp[]={0,0,1,1};
-
-    glBegin(GL_QUADS);
-    
-    for(AtomEntryMap::const_iterator it=view_.atom_map.begin();it!=view_.atom_map.end();++it) {
-      Render3DSpritesInnerLoop(&it->second,cx,cy,cz,gl_mmat,gl_pmat,gl_vp,rmul);
-    }
-    glEnd();
-
-    glPopAttrib();
-
-    Shader::Instance().PopProgram();
-    Shader::Instance().UpdateState();
-  }
-#endif
-}
-
 }}}
diff --git a/modules/gfx/src/impl/cpk_renderer.hh b/modules/gfx/src/impl/cpk_renderer.hh
index c32cb9cd1..1a6dcd2dc 100644
--- a/modules/gfx/src/impl/cpk_renderer.hh
+++ b/modules/gfx/src/impl/cpk_renderer.hh
@@ -26,6 +26,10 @@
 #include <ost/gfx/impl/connect_renderer_base.hh>
 #include <ost/gfx/render_options/cpk_render_options.hh>
 
+#if OST_SHADER_SUPPORT_ENABLED
+#include "fast_spheres.hh"
+#endif
+
 namespace ost { namespace gfx { namespace impl {
 
 /// \internal
@@ -45,9 +49,11 @@ public:
 
 private:
   void PrepareRendering(GfxView& view, IndexedVertexArray& va, bool is_sel);
-  void Render3DSprites();
 
   CPKRenderOptionsPtr options_;
+#if OST_SHADER_SUPPORT_ENABLED
+  FastSphereRenderer fsr_,sel_fsr_;
+#endif
 };
 
 }}}
diff --git a/modules/gfx/src/impl/fast_spheres.cc b/modules/gfx/src/impl/fast_spheres.cc
new file mode 100644
index 000000000..2e4c2056a
--- /dev/null
+++ b/modules/gfx/src/impl/fast_spheres.cc
@@ -0,0 +1,121 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#include <ost/gfx/shader.hh>
+#include <ost/gfx/scene.hh>
+
+#include "fast_spheres.hh"
+
+namespace ost { namespace gfx { namespace impl {
+
+  FastSphereRenderer::FastSphereRenderer(size_t reserve):
+    data_()
+  {
+    data_.reserve(reserve);
+  }
+
+  FastSphereRenderer::FastSphereRenderer(const DataList& d):
+    data_(d)
+  {}
+
+  void FastSphereRenderer::Add(float pos[3], float col[4], float rad)
+  {
+    static VData data;
+    data.pos[0]=pos[0]; data.pos[1]=pos[1]; data.pos[2]=pos[2];
+    data.col[0]=col[0]; data.col[1]=col[1]; data.col[2]=col[2]; data.col[3]=col[3];
+    data.rad=rad;
+    data_.push_back(data);
+  }
+
+  void FastSphereRenderer::Add(const geom::Vec3& pos, const Color& col, float rad)
+  {
+    static VData data;
+    data.pos[0]=pos[0]; data.pos[1]=pos[1]; data.pos[2]=pos[2];
+    data.col[0]=col.Red(); data.col[1]=col.Green(); data.col[2]=col.Blue(); data.col[3]=col.Alpha();
+    data.rad=rad;
+    data_.push_back(data);
+  }
+
+  void FastSphereRenderer::RenderGL()
+  {
+#if OST_SHADER_SUPPORT_ENABLED
+    geom::Mat3 irot=geom::Transpose(Scene::Instance().GetTransform().GetRot());
+    geom::Vec3 cx=irot*geom::Vec3(1.0,0.0,0.0);
+    geom::Vec3 cy=irot*geom::Vec3(0.0,1.0,0.0);
+
+    uint write_normals = Shader::Instance().GetCurrentName()=="dumpnorm" ? 1 : 0;
+
+    Shader::Instance().PushProgram();
+    if(Shader::Instance().GetCurrentName()=="hemilight" ||
+       Shader::Instance().GetCurrentName()=="hf") {
+      Shader::Instance().Activate("fast_sphere_hf");
+    } else if(Shader::Instance().GetCurrentName()=="toon1") {
+      Shader::Instance().Activate("fast_sphere_toon1");
+    } else if(Shader::Instance().GetCurrentName()=="toon2") {
+      Shader::Instance().Activate("fast_sphere_toon2");
+    } else {
+      Shader::Instance().Activate("fast_sphere_phong");
+    }
+    Shader::Instance().UpdateState();
+    glUniform1i(glGetUniformLocation(Shader::Instance().GetCurrentProgram(),"write_normals"),write_normals);
+
+    glPushAttrib(GL_ALL_ATTRIB_BITS);
+    glDisable(GL_LIGHTING);
+    glDisable(GL_CULL_FACE);
+
+    GLdouble gl_mmat[16];
+    glGetDoublev(GL_MODELVIEW_MATRIX,gl_mmat);
+    GLdouble gl_pmat[16];
+    glGetDoublev(GL_PROJECTION_MATRIX,gl_pmat);
+
+    glBegin(GL_QUADS);
+    for(DataList::const_iterator it=data_.begin();it!=data_.end();++it) {
+      // eye z
+      float zz=gl_mmat[2]*it->pos[0]+gl_mmat[6]*it->pos[1]+gl_mmat[10]*it->pos[2]+gl_mmat[14];
+      // difference in z of sphere center and sphere pole
+      float scale=0.5*gl_pmat[14]*it->rad/(zz*(-it->rad+zz));
+      
+      // draw correctly scaled billboards
+      glColor3fv(it->col);
+      float px=it->rad*cx[0];
+      float py=it->rad*cx[1];
+      float pz=it->rad*cx[2];
+      float qx=it->rad*cy[0];
+      float qy=it->rad*cy[1];
+      float qz=it->rad*cy[2];
+      glTexCoord4f(0.0,0.0,-it->rad,scale);
+      glVertex3f(it->pos[0]-px-qx,it->pos[1]-py-qy,it->pos[2]-pz-qz);
+      glTexCoord4f(0.0,1.0,-it->rad,scale);
+      glVertex3f(it->pos[0]-px+qx,it->pos[1]-py+qy,it->pos[2]-pz+qz);
+      glTexCoord4f(1.0,1.0,-it->rad,scale);
+      glVertex3f(it->pos[0]+px+qx,it->pos[1]+py+qy,it->pos[2]+pz+qz);
+      glTexCoord4f(1.0,0.0,-it->rad,scale);
+      glVertex3f(it->pos[0]+px-qx,it->pos[1]+py-qy,it->pos[2]+pz-qz);
+    }
+    glEnd();
+
+    glPopAttrib();
+
+    Shader::Instance().PopProgram();
+    Shader::Instance().UpdateState();
+#endif
+  }
+
+
+}}} // ns
diff --git a/modules/gfx/src/impl/fast_spheres.hh b/modules/gfx/src/impl/fast_spheres.hh
new file mode 100644
index 000000000..054b4ffcb
--- /dev/null
+++ b/modules/gfx/src/impl/fast_spheres.hh
@@ -0,0 +1,60 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_GFX_IMPL_FAST_SPHERES_HH
+#define OST_GFX_IMPL_FAST_SPHERES_HH
+
+#include <ost/geom/vec3.hh>
+#include <ost/gfx/color.hh>
+
+/*
+  Author: Ansgar Philippsen
+*/
+
+#include <vector>
+
+namespace ost { namespace gfx { namespace impl {
+
+  class FastSphereRenderer {
+  public:
+    struct VData
+    {
+      float pos[3];
+      float col[4];
+      float rad;
+    };
+
+    typedef std::vector<VData> DataList;
+
+    FastSphereRenderer(size_t reserve=0);
+    FastSphereRenderer(const DataList&);
+
+    void Add(float pos[3], float col[4], float rad);
+    void Add(const geom::Vec3& pos, const Color& col, float rad);
+
+    void RenderGL();
+
+    const DataList& Data() const {return data_;}
+
+  private:
+    DataList data_;
+  };
+  
+}}} // ns
+
+#endif
diff --git a/modules/gfx/src/shader.cc b/modules/gfx/src/shader.cc
index 80d375ce4..f567fdceb 100644
--- a/modules/gfx/src/shader.cc
+++ b/modules/gfx/src/shader.cc
@@ -47,7 +47,6 @@ Shader::Shader():
   valid_(false),
   current_program_(0),
   current_name_(""),
-  shader_code_map_(),
   shader_program_map_()
 {
   if(!OST_GL_VERSION_2_0) {
@@ -71,9 +70,12 @@ void Shader::PreGLInit()
 #endif
 }
 
-bool Shader::Compile(std::string shader_name, std::string shader_code, 
-                     GLenum shader_type, GLuint& shader_id)
+bool Shader::Compile(const std::string& shader_name, 
+                     const std::string& shader_code,
+                     GLenum shader_type,
+                     GLuint& shader_id)
 {
+  if(!OST_GL_VERSION_2_0) return false;
   shader_id = glCreateShader(shader_type);
   const char* tmp_ptr[] = {0};
   tmp_ptr[0]=shader_code.c_str();
@@ -95,18 +97,28 @@ bool Shader::Compile(std::string shader_name, std::string shader_code,
   return true;
 }
 
-bool Shader::Link(const std::vector<GLuint>& code_list, std::string pr_name, GLuint& shader_pr)
+void Shader::Link(const std::string& pr_name, const std::string& vs_code, const std::string& fs_code)
 {
-  shader_pr = glCreateProgram();
-  for(std::vector<GLuint>::const_iterator it=code_list.begin();it!=code_list.end();++it) {
-    if(*it == 0) {
-      LOG_WARNING("skipping shader [" << pr_name << "] due to missing compiled code");
-      return false;
-    }
-    LOG_VERBOSE("attaching compiled shader id " << *it << " to " << shader_pr);
-    glAttachShader(shader_pr,*it);
+  if(!OST_GL_VERSION_2_0) return;
+  shader_program_map_[pr_name]=0;
+  GLuint shader_pr = glCreateProgram();
+
+  GLuint shader_id;
+  if(Compile(pr_name+" vs",vs_code,GL_VERTEX_SHADER,shader_id)) {
+    LOG_VERBOSE("attaching compiled vertex shader id " << shader_id << " to " << shader_pr);
+    glAttachShader(shader_pr,shader_id);
+  } else {
+    LOG_WARNING("skipping [" << pr_name << "] due to error in vertex shader code");
+    return;
+  }
+  if(Compile(pr_name+" fs",fs_code,GL_FRAGMENT_SHADER,shader_id)) {
+    LOG_VERBOSE("attaching compiled fragment shader id " << shader_id << " to " << shader_pr);
+    glAttachShader(shader_pr,shader_id);
+  } else {
+    LOG_WARNING("skipping [" << pr_name << "] due to error in fragment shader code");
+    return;
   }
-    
+
   glLinkProgram(shader_pr);
   GLint pr_linked;
   glGetProgramiv(shader_pr,GL_LINK_STATUS,&pr_linked);
@@ -118,37 +130,11 @@ bool Shader::Link(const std::vector<GLuint>& code_list, std::string pr_name, GLu
     std::vector<GLchar> pr_log(pr_log_length+1);
     glGetProgramInfoLog(shader_pr, pr_log_length, NULL, &pr_log[0]);
     LOG_ERROR("shader [" << pr_name << "] linking failed:" << std::endl << String(&pr_log[0]));
-    return false;
+    return;
   }
-  return true;
-}
-
-bool Shader::Add(const std::string& name, const std::string& vs_code, const std::string& fs_code)
-{
-  GLuint vs_id=0;
-  if(!Shader::Compile(name,vs_code,GL_VERTEX_SHADER,vs_id)) {
-    return false;
-  }
-  
-  GLuint fs_id=0;
-  if(!Shader::Compile(name,fs_code,GL_FRAGMENT_SHADER,fs_id)) {
-    return false;
-  }
-  
-  std::vector<GLuint> shader_program_list;
-  GLuint id;
-
-  shader_program_list.push_back(vs_id);
-  shader_program_list.push_back(fs_id);
-  if(!Shader::Link(shader_program_list,"hatch",id)) {
-    return false;
-  }
-
-  shader_program_map_[name]=id;
-  return true;
+  shader_program_map_[pr_name]=shader_pr;
 }
 
-
 void Shader::Setup() 
 {
   if(!OST_GL_VERSION_2_0) return;
@@ -168,17 +154,12 @@ void Shader::Setup()
     {"basic_fs.glsl", GL_FRAGMENT_SHADER},
     {"fraglight_vs.glsl", GL_VERTEX_SHADER},
     {"fraglight_fs.glsl", GL_FRAGMENT_SHADER},
-    {"basic_hf_vs.glsl", GL_VERTEX_SHADER},
     {"selfx_vs.glsl", GL_VERTEX_SHADER},
     {"selfx_fs.glsl", GL_FRAGMENT_SHADER},
-    {"toon_vs.glsl", GL_VERTEX_SHADER},
-    {"toon_fs.glsl", GL_FRAGMENT_SHADER},
-    {"toon2_fs.glsl", GL_FRAGMENT_SHADER},
     {"noop_vs.glsl", GL_VERTEX_SHADER},
     {"aaline_fs.glsl", GL_FRAGMENT_SHADER},
     {"iso_vs.glsl", GL_VERTEX_SHADER},
     {"iso_fs.glsl", GL_FRAGMENT_SHADER},
-    {"fast_sphere_vs.glsl", GL_VERTEX_SHADER},
     {"fast_sphere_fs.glsl", GL_FRAGMENT_SHADER},
     {"outline_vs.glsl", GL_VERTEX_SHADER},
     {"dumpnorm_vs.glsl", GL_VERTEX_SHADER},
@@ -190,18 +171,23 @@ void Shader::Setup()
     {"scenefx_fs.glsl", GL_FRAGMENT_SHADER},
     {"beacon_fs.glsl", GL_FRAGMENT_SHADER},
     {"screenblur4_fs.glsl", GL_FRAGMENT_SHADER},
-    {"test_tex_fs.glsl", GL_FRAGMENT_SHADER}
+    {"test_tex_fs.glsl", GL_FRAGMENT_SHADER},
+    {"material_phong.glsl", GL_FRAGMENT_SHADER},
+    {"material_hemi.glsl", GL_FRAGMENT_SHADER},
+    {"material_toon1.glsl", GL_FRAGMENT_SHADER},
+    {"material_toon2.glsl", GL_FRAGMENT_SHADER}
     //////////////////////////////////////////////////////////////////
   };
 
-  shader_code_map_.clear();
+  std::map<std::string, std::string> shader_code_map;
 
   for(unsigned int i=0;i<sizeof(shader_list)/sizeof(ShaderListEntry);++i) {
     String shader_name(shader_list[i].file);
     bf::path shader_file(shader_dir / shader_name);
 
     if(!bf::exists(shader_file)){
-      LOG_ERROR("not found: [" << shader_file.string() << "], cannot create shaders");
+      LOG_ERROR("shader file not found: [" << shader_file.string() << "]");
+      shader_code_map[shader_name]=std::string();
       continue;
     }
 
@@ -211,137 +197,95 @@ void Shader::Setup()
     while (std::getline(shader_file_stream,line)) {
       shader_code += line + "\n";
     }
-
-    GLuint shader_id;
-    if(Shader::Compile(shader_name,shader_code,shader_list[i].type,shader_id)) {
-      shader_code_map_[shader_name]=shader_id;
-    } else {
-      shader_code_map_[shader_name]=0;
-    }
+    shader_code_map[shader_name]=shader_code;
   }
 
   std::vector<GLuint> shader_program_list;
-  GLuint shader_program_id;
-  // basic shader
-  shader_program_list.push_back(shader_code_map_["basic_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["basic_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"basic",shader_program_id)) {
-    shader_program_map_["basic"]=shader_program_id;
-  }
-  // fraglight shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["fraglight_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["fraglight_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"fraglight",shader_program_id)) {
-    shader_program_map_["fraglight"]=shader_program_id;
-  }
-  // basic hemisphere lighting shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["basic_hf_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["basic_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"hemilight",shader_program_id)) {
-    shader_program_map_["hemilight"]=shader_program_id;
-    // alias
-    shader_program_map_["hf"]=shader_program_id;
-  }
-  // selfx shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["selfx_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["selfx_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"selfx",shader_program_id)) {
-    shader_program_map_["selfx"]=shader_program_id;
-  }
-  // toon shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["toon_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["toon_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"toon1",shader_program_id)) {
-    shader_program_map_["toon1"]=shader_program_id;
-  }
-  // toon2 shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["toon_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["toon2_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"toon2",shader_program_id)) {
-    shader_program_map_["toon2"]=shader_program_id;
-  }
-  // line shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["basic_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["aaline_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"aaline",shader_program_id)) {
-    shader_program_map_["aaline"]=shader_program_id;
-  }
-  // iso shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["iso_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["iso_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"iso",shader_program_id)) {
-    shader_program_map_["iso"]=shader_program_id;
-  }
-  // fast sphere shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["fast_sphere_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["fast_sphere_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"fast_sphere",shader_program_id)) {
-    shader_program_map_["fast_sphere"]=shader_program_id;
-  }
-  // outline shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["outline_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["basic_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"outline",shader_program_id)) {
-    shader_program_map_["outline"]=shader_program_id;
-  }
-  // dumpnorm shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["dumpnorm_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["dumpnorm_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"dumpnorm",shader_program_id)) {
-    shader_program_map_["dumpnorm"]=shader_program_id;
-  }
-  // convolute1 shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["quadpp_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["convolute1_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"convolute1",shader_program_id)) {
-    shader_program_map_["convolute1"]=shader_program_id;
-  }
-  // amboccl shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["quadpp_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["amboccl_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"amboccl",shader_program_id)) {
-    shader_program_map_["amboccl"]=shader_program_id;
-  }
-  // beacon shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["scenefx_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["beacon_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"beacon",shader_program_id)) {
-    shader_program_map_["beacon"]=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(Shader::Link(shader_program_list,"scenefx",shader_program_id)) {
-    shader_program_map_["scenefx"]=shader_program_id;
-  }
-  // screen blur shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["quadpp_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["screenblur4_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"screenblur4",shader_program_id)) {
-    shader_program_map_["screenblur4"]=shader_program_id;
-  }
-  // test tex shader
-  shader_program_list.clear();
-  shader_program_list.push_back(shader_code_map_["fraglight_vs.glsl"]);
-  shader_program_list.push_back(shader_code_map_["test_tex_fs.glsl"]);
-  if(Shader::Link(shader_program_list,"test_tex",shader_program_id)) {
-    shader_program_map_["test_tex"]=shader_program_id;
-  }
+
+  Link("basic",
+       shader_code_map["basic_vs.glsl"],
+       shader_code_map["basic_fs.glsl"]);
+
+  // default frag lighting with phong lighting
+  Link("fraglight",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["material_phong.glsl"]+
+       shader_code_map["fraglight_fs.glsl"]);
+
+  // hf lighting model
+  Link("hemilight",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["material_hemi.glsl"]+
+       shader_code_map["fraglight_fs.glsl"]);
+  // alias
+  shader_program_map_["hf"]=shader_program_map_["hemilight"];
+
+  // toon 1 lighting model
+  Link("toon1",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["material_toon1.glsl"]+
+       shader_code_map["fraglight_fs.glsl"]);
+
+  // toon 2 lighting model
+  Link("toon2",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["material_toon2.glsl"]+
+       shader_code_map["fraglight_fs.glsl"]);
+
+  // raytraced sphere with different materials
+  Link("fast_sphere_phong",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["material_phong.glsl"]+
+       shader_code_map["fast_sphere_fs.glsl"]);
+  Link("fast_sphere_hf",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["material_hemi.glsl"]+
+       shader_code_map["fast_sphere_fs.glsl"]);
+  Link("fast_sphere_toon1",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["material_toon1.glsl"]+
+       shader_code_map["fast_sphere_fs.glsl"]);
+  Link("fast_sphere_toon2",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["material_toon2.glsl"]+
+       shader_code_map["fast_sphere_fs.glsl"]);
+
+  // selection fx
+  Link("selfx",
+       shader_code_map["selfx_vs.glsl"],
+       shader_code_map["selfx_fs.glsl"]);
+
+  Link("aaline",
+       shader_code_map["basic_vs.glsl"],
+       shader_code_map["aaline_fs.glsl"]);
+  Link("iso",
+       shader_code_map["iso_vs.glsl"],
+       shader_code_map["iso_fs.glsl"]);
+
+  Link("outline",
+       shader_code_map["outline_vs.glsl"],
+       shader_code_map["basic_fs.glsl"]);
+  Link("dumpnorm",
+       shader_code_map["dumpnorm_vs.glsl"],
+       shader_code_map["dumpnorm_fs.glsl"]);
+  Link("convolute1",
+       shader_code_map["quadpp_vs.glsl"],
+       shader_code_map["convolute1_fs.glsl"]);
+  Link("amboccl",
+       shader_code_map["quadpp_vs.glsl"],
+       shader_code_map["amboccl_fs.glsl"]);
+  Link("beacon",
+       shader_code_map["scenefx_vs.glsl"],
+       shader_code_map["beacon_fs.glsl"]);
+  Link("scenefx",
+       shader_code_map["scenefx_vs.glsl"],
+       shader_code_map["scenefx_fs.glsl"]);
+  Link("screenblur4",
+       shader_code_map["quadpp_vs.glsl"],
+       shader_code_map["screenblur4_fs.glsl"]);
+  Link("test_tex",
+       shader_code_map["fraglight_vs.glsl"],
+       shader_code_map["test_tex_fs.glsl"]);
 
   valid_=true;
 }
diff --git a/modules/gfx/src/shader.hh b/modules/gfx/src/shader.hh
index cd6e5a8bf..149c8fc86 100644
--- a/modules/gfx/src/shader.hh
+++ b/modules/gfx/src/shader.hh
@@ -40,13 +40,6 @@ public:
   // singleton implementation
   static Shader& Instance();
 
-  static bool Compile(std::string shader_name, std::string shader_code,
-                      GLenum shader_type, GLuint& shader_id);
-
-  static bool Link(const std::vector<GLuint>& code_list, std::string pr_name, GLuint& shader_pr);
-
-  bool Add(const std::string& name, const std::string& vs_code, const std::string& fs_code);
-
   void PreGLInit();
   void Setup();
   void Activate(const String& name);
@@ -61,6 +54,14 @@ public:
   void PopProgram();
 
   void UpdateState();
+
+  void Link(const std::string& pr_name, const std::string& vs_code, const std::string& fs_code);
+
+  static bool Compile(const std::string& shader_name, 
+                      const std::string& shader_code, 
+                      GLenum shader_type, 
+                      GLuint& shader_id);
+
 private:
   Shader();
 
@@ -70,7 +71,6 @@ private:
 
   std::stack<String> program_stack_;
 
-  std::map<String,GLuint> shader_code_map_;
   std::map<String,GLuint> shader_program_map_;
 };
 
diff --git a/modules/gfx/src/shader/basic_hf_vs.glsl b/modules/gfx/src/shader/basic_hf_vs.glsl
deleted file mode 100644
index 80324bf1d..000000000
--- a/modules/gfx/src/shader/basic_hf_vs.glsl
+++ /dev/null
@@ -1,43 +0,0 @@
-uniform bool lighting_flag;
-uniform bool two_sided;
-uniform bool occlusion_flag;
-
-void main()
-{    
-  vec4 ground_color=0.2*gl_Color;
-  vec4 sky_color=1.0*gl_Color;
-
-  if(occlusion_flag) {
-    ground_color.rgb*=gl_MultiTexCoord0.w;
-    sky_color.rgb*=gl_MultiTexCoord0.w;
-  }
-
-  gl_Position = ftransform();
-
-  // hemisphere lighting contribution
-  vec3 ec_pos = vec3(gl_ModelViewMatrix* gl_Vertex);
-  if(lighting_flag) {
-    vec3 normal = vec3(0,0,1);
-    if(dot(gl_Normal,gl_Normal)>0.001) {
-      normal = normalize(gl_NormalMatrix * gl_Normal);
-    }
-    vec3 l_dir  = normalize(gl_LightSource[0].position.xyz); // assume directional vector
-    float a  = 0.5+0.5*dot(normal,l_dir);
-    gl_FrontColor.rgb = mix(ground_color, sky_color, a).rgb;
-    gl_FrontColor.a = gl_Color.a;
-    if(two_sided) {
-      float a  = 0.5+0.5*dot(-normal,l_dir);
-      gl_BackColor.rgb = mix(ground_color, sky_color, a).rgb;
-      gl_BackColor.a = gl_Color.a;
-    } else {
-      gl_BackColor = gl_FrontColor;
-    }
-  } else {
-    gl_FrontColor = gl_Color;
-    gl_BackColor = gl_Color;
-  }
-
-  // for some reason, the fog and z coordinate are sign toggled...
-  gl_FogFragCoord = -ec_pos.z;
-}
-
diff --git a/modules/gfx/src/shader/basic_lf_fs.glsl b/modules/gfx/src/shader/basic_lf_fs.glsl
deleted file mode 100644
index 8b735383c..000000000
--- a/modules/gfx/src/shader/basic_lf_fs.glsl
+++ /dev/null
@@ -1,13 +0,0 @@
-uniform bool fog_flag;
-
-void main()
-{
-  if(fog_flag) {
-    float fog = clamp((gl_Fog.end-gl_FogFragCoord) * gl_Fog.scale, 0.0, 1.0);
-    gl_FragColor.rgb = mix(gl_Fog.color.rgb, gl_Color.rgb, fog);
-    gl_FragColor.a = gl_Color.a;
-  } else {
-    gl_FragColor = gl_Color;
-  }
-}
-
diff --git a/modules/gfx/src/shader/basic_lf_vs.glsl b/modules/gfx/src/shader/basic_lf_vs.glsl
deleted file mode 100644
index bf9ca8e12..000000000
--- a/modules/gfx/src/shader/basic_lf_vs.glsl
+++ /dev/null
@@ -1,87 +0,0 @@
-uniform bool lighting_flag;
-uniform bool two_sided_flag;
-uniform bool occlusion_flag;
-
-void DirectionalLight(in vec3 normal,
-                      in float shin,
-                      inout vec4 ambient,
-                      inout vec4 diffuse,
-                      inout vec4 specular)
-{
-  float n_vp = max(0.0, dot(normal, normalize(gl_LightSource[0].position.xyz)));
-  float pf = 0.0;
-  if(n_vp>0.0 && shin>0.0) {
-    float n_hv = max(0.0, dot(normal, normalize(gl_LightSource[0].halfVector.xyz)));
-    pf=pow(n_hv, shin);
-  }
-
-  ambient  += gl_LightSource[0].ambient;
-  diffuse  += gl_LightSource[0].diffuse * n_vp;
-  specular += gl_LightSource[0].specular * pf;
-}
-
-void CalcFrontAndBackColor(in vec3 normal)
-{
-  vec4 amb = vec4(0.0);
-  vec4 diff = vec4(0.0);
-  vec4 spec = vec4(0.0);
-
-  DirectionalLight(normal, gl_FrontMaterial.shininess, amb, diff, spec);
-
-  if(occlusion_flag) {
-    gl_FrontColor  = gl_FrontLightModelProduct.sceneColor  +
-                     (diff * gl_FrontMaterial.diffuse * gl_Color * gl_MultiTexCoord0.w) +
-                     (spec * gl_FrontMaterial.specular);
-
-  } else {
-    gl_FrontColor = gl_FrontLightModelProduct.sceneColor + 
-                    (amb  * gl_FrontMaterial.ambient * gl_Color) +
-                    (diff * gl_FrontMaterial.diffuse * gl_Color) +
-                    (spec * gl_FrontMaterial.specular);
-  }
-
-  if(two_sided_flag) {
-    amb=vec4(0.0);
-    diff=vec4(0.0);
-    spec=vec4(0.0);
-    
-    DirectionalLight(-normal, gl_BackMaterial.shininess, amb, diff, spec);
-    
-    if(occlusion_flag) {
-      gl_BackColor  = gl_FrontLightModelProduct.sceneColor  +
-                      (diff * gl_FrontMaterial.diffuse * gl_Color * gl_MultiTexCoord0.w) +
-                      (spec * gl_FrontMaterial.specular);
-
-    } else {
-      gl_BackColor = gl_BackLightModelProduct.sceneColor + 
-                     (amb  * gl_BackMaterial.ambient * gl_Color) +
-                     (diff * gl_BackMaterial.diffuse * gl_Color) +
-                     (spec * gl_BackMaterial.specular);
-    }
-
-  } else {
-    gl_BackColor = gl_FrontColor;
-  }
-
-  gl_FrontColor.a = gl_Color.a;
-  gl_BackColor.a = gl_Color.a;
-}
-
-void main()
-{    
-  // transformed position
-  gl_Position = ftransform();
-  vec4 ec_Pos = gl_ModelViewMatrix* gl_Vertex;
-
-  vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
-  
-  if(lighting_flag) {
-    CalcFrontAndBackColor(normal);
-  } else {
-    gl_FrontColor = gl_Color;
-    gl_BackColor = gl_Color;
-  }
-  // for some reason, the fog and z coordinate are sign toggled...
-  gl_FogFragCoord = -ec_Pos.z;
-}
-
diff --git a/modules/gfx/src/shader/fast_sphere_fs.glsl b/modules/gfx/src/shader/fast_sphere_fs.glsl
index 66a8ca160..72337e750 100644
--- a/modules/gfx/src/shader/fast_sphere_fs.glsl
+++ b/modules/gfx/src/shader/fast_sphere_fs.glsl
@@ -2,28 +2,10 @@ uniform bool lighting_flag;
 uniform bool two_sided_flag;
 uniform bool fog_flag;
 uniform bool write_normals;
-uniform bool use_hemimodel;
 
 // gl_TexCoord[0] is from gl_MultiTexCoord0, which in turn
 // is custom crafted in the fast sphere prep routine
 
-// copy from basic_fl_vs !
-bool DirectionalLight(in vec3 normal,
-                      in float shin,
-                      inout vec4 ambient,
-                      inout vec4 diffuse,
-                      inout vec4 specular)
-{
-  float n_vp = max(0.0, dot(normal, normalize(vec3(gl_LightSource[0].position))));
-  float n_hv = max(0.0, dot(normal, vec3(gl_LightSource[0].halfVector)));
-  float pf = n_vp>0.0 ? pow(n_vp, shin) : 0.0;
-
-  ambient  += gl_LightSource[0].ambient;
-  diffuse  += gl_LightSource[0].diffuse*n_vp;
-  specular += gl_LightSource[0].specular * pf;
-  return true;
-}
-
 void main()
 {
   float xx = (gl_TexCoord[0].x-0.5)*2.0;
@@ -44,19 +26,9 @@ void main()
     return;
   }
 
-  vec4 color = vec4(0.0);
-  if(use_hemimodel) {
-    color = gl_Color;
-  } else {
-    vec4 amb = vec4(0.0);
-    vec4 diff = vec4(0.0);
-    vec4 spec = vec4(0.0);
-
-    DirectionalLight(normal, gl_FrontMaterial.shininess, amb, diff, spec);
-    color  = gl_FrontLightModelProduct.sceneColor  +
-             (amb  * gl_FrontMaterial.ambient * gl_Color) +
-             (diff * gl_FrontMaterial.diffuse * gl_Color) +
-             (spec * gl_FrontMaterial.specular);
+  vec4 color = gl_Color;
+  if(lighting_flag) {
+    color = light(normal,color,two_sided_flag);
   }
 
   if(fog_flag) {
@@ -65,5 +37,4 @@ void main()
   }
   gl_FragColor.rgb = color.rgb;
   gl_FragColor.a = 1.0;
-
 }
diff --git a/modules/gfx/src/shader/fast_sphere_vs.glsl b/modules/gfx/src/shader/fast_sphere_vs.glsl
deleted file mode 100644
index 5acd60562..000000000
--- a/modules/gfx/src/shader/fast_sphere_vs.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-bool use_hemimodel;
-
-void main()
-{
-  // transformed position
-  gl_Position = ftransform();
-
-  vec4 ec_Pos = gl_ModelViewMatrix* gl_Vertex;
-  // for some reason, the fog and z coordinate are sign toggled...
-  gl_FogFragCoord = -ec_Pos.z;
-
-  gl_TexCoord[0]=gl_MultiTexCoord0;
-
-  if(use_hemimodel) {
-    vec4 ground_color=0.2*gl_Color;
-    vec4 sky_color=1.0*gl_Color;
-
-    // hemisphere lighting contribution
-    vec3 ec_pos = vec3(gl_ModelViewMatrix* gl_Vertex);
-    vec3 normal = vec3(0,0,1);
-    if(dot(gl_Normal,gl_Normal)>0.001) {
-      normal = normalize(gl_NormalMatrix * gl_Normal);
-    }
-    vec3 l_dir  = normalize(gl_LightSource[0].position.xyz); // assume directional vector
-    float a  = 0.5+0.5*dot(normal,l_dir);
-    gl_FrontColor.rgb = mix(ground_color, sky_color, a).rgb;
-    gl_FrontColor.a = gl_Color.a;
-    gl_BackColor = gl_FrontColor;
-  } else {
-    gl_FrontColor=gl_Color;
-    gl_BackColor=gl_Color;
-  }
-}
diff --git a/modules/gfx/src/shader/fraglight_fs.glsl b/modules/gfx/src/shader/fraglight_fs.glsl
index 76ff5dfaf..9baa64b04 100644
--- a/modules/gfx/src/shader/fraglight_fs.glsl
+++ b/modules/gfx/src/shader/fraglight_fs.glsl
@@ -6,34 +6,8 @@ uniform int depth_mode;
 uniform bool tex_flag;
 uniform sampler2D tex_map;
 
-// copy from basic_fl_vs !
-bool DirectionalLight(in vec3 normal,
-                      in float shin,
-                      inout vec4 ambient,
-                      inout vec4 diffuse,
-                      inout vec4 specular,
-		      inout bool lflag)
-{
-  float n_vp = max(0.0, dot(normal, normalize(gl_LightSource[0].position.xyz)));
-
-  float pf = 0.0;
-  lflag = n_vp>0.0;
-  if(n_vp>0.0 && shin>0.0) {
-    float n_hv = max(0.0, dot(normal, normalize(gl_LightSource[0].halfVector.xyz)));
-    pf=pow(n_hv, shin);
-  }
-
-  ambient  += gl_LightSource[0].ambient;
-  diffuse  += gl_LightSource[0].diffuse * n_vp;
-  specular += gl_LightSource[0].specular * pf;
-
-  return true;
-}
-
 void main()
 {
-  bool lflag=false;
-
   vec4 color = gl_Color;
 
   if(tex_flag) {
@@ -42,26 +16,7 @@ void main()
 
   if(lighting_flag) {
     vec3 normal = normalize(gl_TexCoord[2].stp);
-
-    vec4 amb = vec4(0.0);
-    vec4 diff = vec4(0.0);
-    vec4 spec = vec4(0.0);
-
-    if(DirectionalLight(normal, gl_FrontMaterial.shininess, amb, diff, spec, lflag)) {
-
-      color  = gl_FrontLightModelProduct.sceneColor  +
-               (amb  * gl_FrontMaterial.ambient * color) +
-               (diff * gl_FrontMaterial.diffuse * color) +
-               (spec * gl_FrontMaterial.specular);
-    } else {
-      bool dummy;
-      DirectionalLight(-normal, gl_BackMaterial.shininess, amb, diff, spec, dummy);
-
-      color = gl_BackLightModelProduct.sceneColor  +
-              (amb  * gl_BackMaterial.ambient * color) +
-              (diff * gl_BackMaterial.diffuse * color) +
-              (spec * gl_BackMaterial.specular);
-    }
+    color=light(normal,color,two_sided_flag);
   }
 
   gl_FragColor = color;
diff --git a/modules/gfx/src/shader/fraglight_vs.glsl b/modules/gfx/src/shader/fraglight_vs.glsl
index 279016e14..8a7ca2a3b 100644
--- a/modules/gfx/src/shader/fraglight_vs.glsl
+++ b/modules/gfx/src/shader/fraglight_vs.glsl
@@ -3,13 +3,18 @@ void main()
   // transformed position
   gl_Position = ftransform();
 
+  // eye coordinate position
   vec4 ec_Pos = gl_ModelViewMatrix* gl_Vertex;
+
   // for some reason, the fog and z coordinate are sign toggled...
   gl_FogFragCoord = -ec_Pos.z;
 
-  // since a directional light is used, the position is not needed
-  // and only the normal is passed on
-  gl_TexCoord[2].stp=normalize(gl_NormalMatrix * gl_Normal);
+  // store fragment normal in tex coord 2
+  vec3 normal = vec3(0,0,1);
+  if(dot(gl_Normal,gl_Normal)>0.001) {
+    normal = normalize(gl_NormalMatrix * gl_Normal);
+  }
+  gl_TexCoord[2].stp=normal;
 
   // default tex coord
   gl_TexCoord[0] = gl_MultiTexCoord0;
diff --git a/modules/gfx/src/shader/material_hemi.glsl b/modules/gfx/src/shader/material_hemi.glsl
new file mode 100644
index 000000000..e9d223dea
--- /dev/null
+++ b/modules/gfx/src/shader/material_hemi.glsl
@@ -0,0 +1,18 @@
+vec4 light(in vec3 normal,
+           in vec4 color,
+           in bool two_sided)
+{
+  vec4 ground_color=0.2*color;
+  vec4 sky_color=1.0*color;
+  
+  vec3 l_dir  = normalize(gl_LightSource[0].position.xyz); // assume directional vector
+  float a  = 0.5+0.5*dot(normal,l_dir);
+  color.rgb = mix(ground_color, sky_color, a).rgb;
+  bool backside = false;
+  if(two_sided && backside) {
+    float a  = 0.5+0.5*dot(-normal,l_dir);
+    color.rgb = mix(ground_color, sky_color, a).rgb;
+  }
+  return color;
+}
+
diff --git a/modules/gfx/src/shader/material_phong.glsl b/modules/gfx/src/shader/material_phong.glsl
new file mode 100644
index 000000000..ca5e097ce
--- /dev/null
+++ b/modules/gfx/src/shader/material_phong.glsl
@@ -0,0 +1,51 @@
+bool DirectionalLight(in vec3 normal,
+                      in int lightn,
+                      in float shin,
+                      inout vec4 ambient,
+                      inout vec4 diffuse,
+                      inout vec4 specular,
+                      inout bool lflag)
+{
+  float n_vp = max(0.0, dot(normal, normalize(gl_LightSource[lightn].position.xyz)));
+
+  float pf = 0.0;
+  lflag = n_vp>0.0;
+  if(n_vp>0.0 && shin>0.0) {
+    float n_hv = max(0.0, dot(normal, normalize(gl_LightSource[lightn].halfVector.xyz)));
+    pf=pow(n_hv, shin);
+  }
+
+  ambient  += gl_LightSource[lightn].ambient;
+  diffuse  += gl_LightSource[lightn].diffuse * n_vp;
+  specular += gl_LightSource[lightn].specular * pf;
+
+  return true;
+}
+
+
+vec4 light(in vec3 normal,
+           in vec4 color,
+           in bool two_sided)
+{
+  vec4 amb = vec4(0.0);
+  vec4 diff = vec4(0.0);
+  vec4 spec = vec4(0.0);
+  bool lflag=false;
+
+  DirectionalLight(normal, 0, gl_FrontMaterial.shininess, amb, diff, spec, lflag);
+
+  color  = gl_FrontLightModelProduct.sceneColor  +
+           (amb  * gl_FrontMaterial.ambient * color) +
+           (diff * gl_FrontMaterial.diffuse * color) +
+           (spec * gl_FrontMaterial.specular);
+
+/* TODO
+    DirectionalLight(-normal, 0, gl_BackMaterial.shininess, amb, diff, spec, dummy);
+    color = gl_BackLightModelProduct.sceneColor  +
+            (amb  * gl_BackMaterial.ambient * color) +
+            (diff * gl_BackMaterial.diffuse * color) +
+            (spec * gl_BackMaterial.specular);
+*/
+
+  return color;
+}
diff --git a/modules/gfx/src/shader/toon_fs.glsl b/modules/gfx/src/shader/material_toon1.glsl
similarity index 56%
rename from modules/gfx/src/shader/toon_fs.glsl
rename to modules/gfx/src/shader/material_toon1.glsl
index 4298ec02a..2a21c7b14 100644
--- a/modules/gfx/src/shader/toon_fs.glsl
+++ b/modules/gfx/src/shader/material_toon1.glsl
@@ -1,7 +1,3 @@
-uniform bool lighting_flag;
-uniform bool two_sided_flag;
-uniform bool fog_flag;
-
 void DirectionalLight(in vec3 normal,
                       inout vec4 ambient,
                       inout vec4 diffuse)
@@ -20,26 +16,26 @@ void DirectionalLight(in vec3 normal,
   diffuse  += gl_LightSource[0].diffuse*n_vp;
 }
 
-void main()
+vec4 light(in vec3 normal,
+           in vec4 color,
+           in bool two_sided)
 {
   vec4 amb = vec4(0.0);
   vec4 diff = vec4(0.0);
-  vec4 color = vec4(0.0);
-  vec3 normal = normalize(gl_TexCoord[2].stp);
+  vec4 color2 = vec4(0.0);
 
   DirectionalLight(normal, amb, diff);
 
-  color = (gl_FrontLightModelProduct.sceneColor + 
-           amb*gl_Color + diff*gl_Color);
+  color2 = (gl_FrontLightModelProduct.sceneColor + 
+           amb*color + diff*color);
 
-  if(two_sided_flag) {
+  if(two_sided) {
     amb=vec4(0.0);
     diff=vec4(0.0);
     DirectionalLight(-normal, amb, diff);
-    color += (gl_BackLightModelProduct.sceneColor + 
-              amb*gl_Color + diff*gl_Color);
+    color2 += (gl_BackLightModelProduct.sceneColor + 
+              amb*color + diff*color);
   }
 
-  gl_FragColor = clamp(color,0.0,1.0);
-  gl_FragColor.a = gl_Color.a;
+  return clamp(color2,0.0,1.0);
 }
diff --git a/modules/gfx/src/shader/toon2_fs.glsl b/modules/gfx/src/shader/material_toon2.glsl
similarity index 65%
rename from modules/gfx/src/shader/toon2_fs.glsl
rename to modules/gfx/src/shader/material_toon2.glsl
index ae1297837..71332af6f 100644
--- a/modules/gfx/src/shader/toon2_fs.glsl
+++ b/modules/gfx/src/shader/material_toon2.glsl
@@ -1,8 +1,4 @@
-uniform bool lighting_flag;
-uniform bool two_sided_flag;
-uniform bool fog_flag;
-
-void DirectionalLight(in vec3 normal,
+bool DirectionalLight(in vec3 normal,
                       in float shin,
                       inout vec4 ambient,
                       inout vec4 diffuse,
@@ -25,30 +21,31 @@ void DirectionalLight(in vec3 normal,
   ambient  += gl_LightSource[0].ambient;
   diffuse  += gl_LightSource[0].diffuse*n_vp;
   spec     += gl_LightSource[0].specular*pf;
+  return true;
 }
 
-void main()
+vec4 light(in vec3 normal,
+           in vec4 color,
+           in bool two_sided)
 {
   vec4 amb = vec4(0.0);
   vec4 diff = vec4(0.0);
   vec4 spec = vec4(0.0);
-  vec4 color = vec4(0.0);
-  vec3 normal = normalize(gl_TexCoord[2].stp);
+  vec4 color2 = vec4(0.0);
 
   DirectionalLight(normal, gl_FrontMaterial.shininess, amb, diff, spec);
 
-  color = (gl_FrontLightModelProduct.sceneColor + 
-           amb*gl_Color + diff*gl_Color + spec*gl_Color);
+  color2 = (gl_FrontLightModelProduct.sceneColor + 
+           amb*color + diff*color + spec*color);
 
-  if(two_sided_flag) {
+  if(two_sided) {
     amb=vec4(0.0);
     diff=vec4(0.0);
     spec=vec4(0.0);
     DirectionalLight(-normal, gl_FrontMaterial.shininess, amb, diff, spec);
-    color += (gl_BackLightModelProduct.sceneColor + 
-              amb*gl_Color + diff*gl_Color + spec*gl_Color);
+    color2 += (gl_BackLightModelProduct.sceneColor + 
+              amb*color + diff*color + spec*color);
   }
 
-  gl_FragColor = clamp(color,0.0,1.0);
-  gl_FragColor.a = gl_Color.a;
+  return clamp(color2,0.0,1.0);
 }
diff --git a/modules/gfx/src/shader/toon_vs.glsl b/modules/gfx/src/shader/toon_vs.glsl
deleted file mode 100644
index c4624ebd7..000000000
--- a/modules/gfx/src/shader/toon_vs.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-void main()
-{
-  // transformed position
-  gl_Position = ftransform();
-
-  vec4 ec_Pos = gl_ModelViewMatrix* gl_Vertex;
-  // for some reason, the fog and z coordinate are sign toggled...
-  gl_FogFragCoord = -ec_Pos.z;
-
-  vec3 normal = vec3(0,0,1);
-  if(dot(gl_Normal,gl_Normal)>0.001) {
-    normal = normalize(gl_NormalMatrix * gl_Normal);
-  }
-  // since a directional light is used, the position is not needed
-  gl_TexCoord[2].stp=normal;
-
-  gl_FrontColor=gl_Color;
-  gl_BackColor=gl_Color;
-}
-- 
GitLab