diff --git a/modules/gfx/pymod/export_gfx_obj.cc b/modules/gfx/pymod/export_gfx_obj.cc
index de30f31ec2c981b966cee2a042228aaf91415bf1..a68c505d11d2bf159722236da9fb9c1470df600d 100644
--- a/modules/gfx/pymod/export_gfx_obj.cc
+++ b/modules/gfx/pymod/export_gfx_obj.cc
@@ -80,6 +80,7 @@ void export_GfxObj()
     .def("SetOutlineExpandFactor",&GfxObj::SetOutlineExpandFactor)
     .def("SetOutlineExpandColor",&GfxObj::SetOutlineExpandColor)
     .def("SmoothVertices",&GfxObj::SmoothVertices)
+    .def("AmbientOcclusion",&GfxObj::AmbientOcclusion)
     .add_property("debug",get_debug,set_debug)
     .add_property("center", &GfxObj::GetCenter)
     COLOR_BY_DEF()
diff --git a/modules/gfx/src/CMakeLists.txt b/modules/gfx/src/CMakeLists.txt
index 1f3569435d076ee65bbce91396eedb07453cb918..c07798109ce865af880e7d071888cbdac7ae7991 100644
--- a/modules/gfx/src/CMakeLists.txt
+++ b/modules/gfx/src/CMakeLists.txt
@@ -61,6 +61,7 @@ trace_render_options.hh
 
 
 set(OST_GFX_IMPL_HEADERS
+calc_ambient.hh
 cartoon_renderer.hh
 custom_renderer.hh
 cpk_renderer.hh
@@ -115,6 +116,7 @@ color_ops/gradient_color_op.cc
 color_ops/entity_view_color_op.cc
 color_ops/basic_gradient_color_op.cc
 color_ops/gradient_level_color_op.cc
+impl/calc_ambient.cc
 impl/entity_renderer.cc
 impl/entity_detail.cc
 impl/cartoon_renderer.cc
diff --git a/modules/gfx/src/gfx_object.cc b/modules/gfx/src/gfx_object.cc
index 7aaf85e382283c1bb8d7645073e7dc1e4057d2d0..bfd47eaed143133ae131d9e378422d2e6e8d03f5 100644
--- a/modules/gfx/src/gfx_object.cc
+++ b/modules/gfx/src/gfx_object.cc
@@ -62,7 +62,8 @@ GfxObj::GfxObj(const String& name):
   smoothf_(0.0),
   omode_(0),
   c_ops_(),
-  labels_()
+  labels_(),
+  use_occlusion_(false)
 {
 }
 
@@ -155,6 +156,7 @@ void GfxObj::RefreshVA(IndexedVertexArray& va)
   va.SetLineHalo(GetLineHalo());
   va.DrawNormals(debug_flags_&0x1);
   va.SetPolyMode(debug_flags_&0x2 ? 1 : 2);
+  va.UseAmbient(use_occlusion_);
   va.FlagRefresh();
 }
 
@@ -609,6 +611,13 @@ void GfxObj::SmoothVertices(float smoothf)
   FlagRefresh();
 }
 
+void GfxObj::AmbientOcclusion(bool f)
+{
+  use_occlusion_=f;
+  va_.UseAmbient(f);
+  //  FlagRefresh();
+}
+
 void GfxObj::ColorBy(const mol::EntityView& ev, 
                       const String& prop,
                       const Gradient& g, float minv, float maxv)
diff --git a/modules/gfx/src/gfx_object.hh b/modules/gfx/src/gfx_object.hh
index 15500849db52db226103823d8bdbd06226df0af4..2a52179120a2d09c243d971fe64924b75b3ff68f 100644
--- a/modules/gfx/src/gfx_object.hh
+++ b/modules/gfx/src/gfx_object.hh
@@ -195,8 +195,11 @@ public:
   void SetOutlineExpandFactor(float f);
   void SetOutlineExpandColor(const Color& c);
 
+  // experimental, don't use
   void SmoothVertices(float smoothf);
-  
+  // experimental, don't use
+  void AmbientOcclusion(bool f);
+ 
   void GLCleanup();
 
   /// \brief color each component based on the gradient-mapped property of 
@@ -300,6 +303,7 @@ public:
   TextPrimList labels_;
   void render_labels() const;
 
+  bool use_occlusion_;
 };
 
 }} //ns
diff --git a/modules/gfx/src/impl/calc_ambient.cc b/modules/gfx/src/impl/calc_ambient.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7fb0584c75c8b426f3f28236a66de12ee41af14d
--- /dev/null
+++ b/modules/gfx/src/impl/calc_ambient.cc
@@ -0,0 +1,234 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2010 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
+//------------------------------------------------------------------------------
+
+/*
+  Author: Ansgar Philippsen
+*/
+
+#include <map>
+#include <vector>
+#include <limits>
+
+#include <ost/geom/geom.hh>
+#include <ost/gfx/vertex_array.hh>
+
+#include "calc_ambient.hh"
+
+using namespace ost;
+using namespace ost::gfx;
+
+namespace {
+
+  typedef IndexedVertexArray::EntryList EntryList;
+  typedef IndexedVertexArray::IndexList IndexList;
+  
+
+  std::pair<geom::Vec3, geom::Vec3> calc_limits(const EntryList& elist)
+  {
+    geom::Vec3 minc(std::numeric_limits<float>::max(),
+		    std::numeric_limits<float>::max(),
+		    std::numeric_limits<float>::max());
+    geom::Vec3 maxc(-std::numeric_limits<float>::max(),
+		    -std::numeric_limits<float>::max(),
+		    -std::numeric_limits<float>::max());
+
+    for(EntryList::const_iterator it=elist.begin();it!=elist.end();++it) {
+      minc[0]=std::min(it->v[0],minc[0]);
+      minc[1]=std::min(it->v[1],minc[1]);
+      minc[2]=std::min(it->v[2],minc[2]);
+      maxc[0]=std::max(it->v[0],maxc[0]);
+      maxc[1]=std::max(it->v[1],maxc[1]);
+      maxc[2]=std::max(it->v[2],maxc[2]);
+    }
+    return std::make_pair(minc,maxc);
+  }
+
+  struct CIndex { 
+    CIndex(): u(0),v(0),w(0) {}
+    CIndex(long uu, long vv, long ww): u(uu), v(vv), w(ww) {}
+    long u,v,w;
+    bool operator<(const CIndex& rhs) const {
+      return u==rhs.u ? (v==rhs.v ? w<rhs.w : v<rhs.v) : u<rhs.u;
+    }
+  };
+
+  struct CEntry {
+    CEntry(): id(0), v(),n(),c() {}
+    CEntry(unsigned int ii, const geom::Vec3& vv, const geom::Vec3& nn, const Color& cc): id(ii), v(vv), n(nn), c(cc) {}
+    unsigned int id;
+    geom::Vec3 v;
+    geom::Vec3 n;
+    Color c;
+  };
+
+  typedef std::map<CIndex,std::vector<CEntry> > CMap;
+
+  class AmbientOcclusionBuilder {
+  public:
+    AmbientOcclusionBuilder(IndexedVertexArray& va): va_(va), cmap_(), bsize_(5.0), weight_(0.2), cutoff2_(25.0) {}
+
+    CIndex coord_to_index(const geom::Vec3& v) 
+    {
+      return CIndex(static_cast<int>(floor(v[0]/bsize_)),
+		    static_cast<int>(floor(v[1]/bsize_)),
+		    static_cast<int>(floor(v[2]/bsize_)));
+    }
+    
+    void build_cmap() {
+      const EntryList& elist = va_.GetEntries();
+      const IndexList& tlist = va_.GetTriIndices();
+      const IndexList& qlist = va_.GetQuadIndices();
+
+      cmap_.clear();
+      
+      for(unsigned int c=0;c<tlist.size();c+=3) {
+	const float* v0=elist[tlist[c+0]].v;
+	const float* v1=elist[tlist[c+1]].v;
+	const float* v2=elist[tlist[c+2]].v;
+	const float* n0=elist[tlist[c+0]].n;
+	const float* n1=elist[tlist[c+1]].n;
+	const float* n2=elist[tlist[c+2]].n;
+	const float* c0=elist[tlist[c+0]].c;
+	const float* c1=elist[tlist[c+1]].c;
+	const float* c2=elist[tlist[c+2]].c;
+	add_to_cmap(c,
+		    geom::Vec3((v0[0]+v1[0]+v2[0])/3.0,
+			       (v0[1]+v1[1]+v2[1])/3.0,
+			       (v0[2]+v1[2]+v2[2])/3.0),
+		    geom::Normalize(geom::Vec3((n0[0]+n1[0]+n2[0]),
+					       (n0[1]+n1[1]+n2[1]),
+					       (n0[2]+n1[2]+n2[2]))),
+		    Color((c0[0]+c1[0]+c2[0])/3.0,
+			  (c0[1]+c1[1]+c2[1])/3.0,
+			  (c0[2]+c1[2]+c2[2])/3.0,
+			  (c0[3]+c1[3]+c2[3])/3.0));
+      }
+      for(unsigned int c=0;c<qlist.size();c+=4) {
+	const float* v0=elist[tlist[c+0]].v;
+	const float* v1=elist[tlist[c+1]].v;
+	const float* v2=elist[tlist[c+2]].v;
+	const float* v3=elist[tlist[c+3]].v;
+	const float* n0=elist[tlist[c+0]].n;
+	const float* n1=elist[tlist[c+1]].n;
+	const float* n2=elist[tlist[c+2]].n;
+	const float* n3=elist[tlist[c+3]].n;
+	const float* c0=elist[tlist[c+0]].c;
+	const float* c1=elist[tlist[c+1]].c;
+	const float* c2=elist[tlist[c+2]].c;
+	const float* c3=elist[tlist[c+3]].c;
+	add_to_cmap(c,
+		    geom::Vec3((v0[0]+v1[0]+v2[0]+v3[0])/4.0,
+			       (v0[1]+v1[1]+v2[1]+v3[1])/4.0,
+			       (v0[2]+v1[2]+v2[2]+v3[2])/4.0),
+		    geom::Normalize(geom::Vec3((n0[0]+n1[0]+n2[0]+n3[0]),
+					       (n0[1]+n1[1]+n2[1]+n3[1]),
+					       (n0[2]+n1[2]+n2[2]+n3[2]))),
+		    Color((c0[0]+c1[0]+c2[0]+c3[0])/4.0,
+			  (c0[1]+c1[1]+c2[1]+c3[1])/4.0,
+			  (c0[2]+c1[2]+c2[2]+c3[2])/4.0,
+			  (c0[3]+c1[3]+c2[3]+c3[3])/4.0));
+      }
+    }
+
+    void add_to_cmap(unsigned int id, const geom::Vec3& v, const geom::Vec3& n, const Color& c) 
+    {
+      CIndex cindex=coord_to_index(v);
+      CMap::iterator it=cmap_.find(cindex);
+      if(it==cmap_.end()) {
+	std::vector<CEntry> tmplist(1);
+	tmplist[0]=CEntry(id,v,n,c);
+	cmap_[cindex]=tmplist;
+      } else {
+	it->second.push_back(CEntry(id,v,n,c));
+      }
+    }
+
+    void accumulate(unsigned int eid, const CIndex& cindex, const geom::Vec3& epos, const geom::Vec3& enorm, Color& color, float& factor)
+    {
+      CMap::iterator cit=cmap_.find(cindex);
+      if(cit==cmap_.end()) return;
+      std::vector<CEntry>::const_iterator eit2=cit->second.end();
+      for(std::vector<CEntry>::const_iterator eit=cit->second.begin();eit!=eit2;++eit) {
+	geom::Vec3 diff=(eit->v-epos);
+	float l2=geom::Length2(diff);
+	if(l2<cutoff2_) {
+	  // angle between vertex normal and direction to close face
+	  float cw1=geom::Dot(geom::Normalize(diff),enorm);
+	  // only consider those that are "in front"
+	  if(cw1>0.0) {
+	    // angle between direction and close face normal
+	    float cw2=1.0-geom::Dot(diff,eit->n);
+	    // only consider those that point towards each other
+	    if(cw2>0.0) {
+	      cw2*=cw1;
+	      color[0]+=cw2*eit->c[0];
+	      color[1]+=cw2*eit->c[1];
+	      color[2]+=cw2*eit->c[2];
+	      factor+=1.0;
+	    }
+	  }
+	}
+      }
+    }
+
+    void calc_all() {
+      const EntryList& elist = va_.GetEntries();
+
+      for(unsigned int c=0;c<elist.size();++c) {
+	geom::Vec3 epos(elist[c].v[0],elist[c].v[1],elist[c].v[2]);
+	geom::Vec3 enorm(elist[c].n[0],elist[c].n[1],elist[c].n[2]);
+	CIndex cindex0=coord_to_index(epos);
+	Color color;
+	float factor;
+
+	for(int w=-1;w<=1;++w) {
+	  for(int v=-1;v<=1;++v) {
+	    for(int u=-1;u<=1;++u) {
+	      accumulate(c,CIndex(cindex0.u+u,cindex0.v+v,cindex0.w+w),epos,enorm,color,factor);
+	    }
+	  }
+	}
+
+	color[0]/=factor;
+	color[1]/=factor;
+	color[2]/=factor;
+	color[3]=weight_;
+	va_.SetAmbientColor(c,color);
+      }
+
+    }
+
+  private:
+    IndexedVertexArray& va_;
+    CMap cmap_;
+    float bsize_;
+    float weight_;
+    float cutoff2_;
+  };
+  
+} // ns
+
+
+
+void ost::gfx::CalcAmbientTerms(IndexedVertexArray& va)
+{
+  AmbientOcclusionBuilder aob(va);
+  aob.build_cmap();
+  aob.calc_all();
+}
diff --git a/modules/gfx/src/impl/calc_ambient.hh b/modules/gfx/src/impl/calc_ambient.hh
new file mode 100644
index 0000000000000000000000000000000000000000..6064f84c9aabf4344734254461e91a2b67683788
--- /dev/null
+++ b/modules/gfx/src/impl/calc_ambient.hh
@@ -0,0 +1,35 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2010 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_CALC_AMBIENT_HH
+#define OST_CALC_AMBIENT_HH
+
+/*
+  calculate ambient contributions per VA entry
+
+  Author: Ansgar Philippsen
+*/
+
+namespace ost { namespace gfx {
+
+    class IndexedVertexArray;
+    void CalcAmbientTerms(IndexedVertexArray& va);
+      
+}} // ns
+
+#endif
diff --git a/modules/gfx/src/shader/fraglight_lf_fs.glsl b/modules/gfx/src/shader/fraglight_lf_fs.glsl
index 7c225a41b86e60d92eee192fbdf4b7fdb98d6751..08b7f3a1cdc15d5737d9ca6e3ecbc75461c440ee 100644
--- a/modules/gfx/src/shader/fraglight_lf_fs.glsl
+++ b/modules/gfx/src/shader/fraglight_lf_fs.glsl
@@ -1,6 +1,7 @@
 uniform bool lighting_flag;
 uniform bool two_sided_flag;
 uniform bool fog_flag;
+uniform bool occlusion_flag;
 
 // copy from basic_fl_vs !
 bool DirectionalLight(in vec3 normal,
@@ -51,6 +52,10 @@ void main()
     gl_FragColor = gl_Color;
   }
 
+  if(occlusion_flag) {
+    gl_FragColor.rgb = mix(gl_TexCoord[2].stp,gl_FragColor.rgb, gl_TexCoord[2].q);
+  }
+
   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_FragColor.rgb, fog);
diff --git a/modules/gfx/src/shader/fraglight_lf_vs.glsl b/modules/gfx/src/shader/fraglight_lf_vs.glsl
index 1913f445eaf04f43bdce4d9e9dea6a4021777e8c..c6328cf10c3ad357fde3abd555c9817294c12502 100644
--- a/modules/gfx/src/shader/fraglight_lf_vs.glsl
+++ b/modules/gfx/src/shader/fraglight_lf_vs.glsl
@@ -1,3 +1,5 @@
+uniform bool occlusion_flag;
+
 void main()
 {
   // transformed position
@@ -11,6 +13,10 @@ void main()
   // since a directional light is used, the position is not needed
   gl_TexCoord[0].stp=normal;
 
+  if(occlusion_flag) {
+    // ambient color
+    gl_TexCoord[2] = gl_MultiTexCoord0;
+  }
   gl_FrontColor=gl_Color;
   gl_BackColor=gl_Color;
 }
diff --git a/modules/gfx/src/vertex_array.cc b/modules/gfx/src/vertex_array.cc
index b93bd594159f8b486fbe4ce0a930324fd49b79ab..f0ef0822c36eaad65d8c205be6506d37b4c8bda3 100644
--- a/modules/gfx/src/vertex_array.cc
+++ b/modules/gfx/src/vertex_array.cc
@@ -31,6 +31,8 @@
 #include "vertex_array_helper.hh"
 #include "povray.hh"
 
+#include "impl/calc_ambient.hh"
+
 #if OST_SHADER_SUPPORT_ENABLED
 #include "shader.hh"
 #endif
@@ -48,6 +50,15 @@ using namespace geom;
 
 namespace gfx {
 
+// the header and this file contain several magic number 7 uses related to the max buffer
+static const int VA_VERTEX_BUFFER=0;
+static const int VA_LINEINDEX_BUFFER=1;
+static const int VA_TRIINDEX_BUFFER=2;
+static const int VA_QUADINDEX_BUFFER=3;
+static const int VA_AMBIENT_BUFFER=4;
+static const int VA_NORMAL_BUFFER=5;
+static const int VA_COLOR_BUFFER=6;
+
 IndexedVertexArray::Entry::Entry()
 {
   v[0]=0.0; v[1]=0.0; v[2]=0.0;
@@ -96,7 +107,7 @@ void IndexedVertexArray::Cleanup()
   if(initialized_) {
     glDeleteLists(outline_mat_dlist_,1);
 #if OST_SHADER_SUPPORT_ENABLED
-    glDeleteBuffers(4,buffer_id_);
+    glDeleteBuffers(7,buffer_id_);
 #endif
     initialized_=false;
   }
@@ -329,7 +340,7 @@ void IndexedVertexArray::RenderGL()
   if(!initialized_) {
     LOGN_DUMP("initializing vertex array lists");
 #if OST_SHADER_SUPPORT_ENABLED
-    glGenBuffers(4,buffer_id_);
+    glGenBuffers(7,buffer_id_);
 #endif
     outline_mat_dlist_=glGenLists(1);
     initialized_=true;
@@ -338,6 +349,11 @@ void IndexedVertexArray::RenderGL()
   if(dirty_) {
     dirty_=false;
 #if OST_SHADER_SUPPORT_ENABLED
+    if(use_ambient_) {
+      LOGN_DUMP("re-calculating ambient occlusion terms");
+      recalc_ambient_occlusion();
+    }
+
     LOGN_DUMP("checking buffer object availability");
     if(mode_&0x2 && aalines_flag_) {
       use_buff=false;
@@ -396,6 +412,7 @@ void IndexedVertexArray::RenderGL()
       glDisable(GL_BLEND);
     }
   } else {
+    // not in outline mode
     if(lighting_) {
       glEnable(GL_LIGHTING); 
     } else {
@@ -416,6 +433,11 @@ void IndexedVertexArray::RenderGL()
     } else { 
       glDisable(GL_CULL_FACE); 
     }
+#if OST_SHADER_SUPPORT_ENABLED
+    if(use_ambient_ && !ambient_data_.empty()) {
+      glUniform1i(glGetUniformLocation(Shader::Instance().GetCurrentProgram(),"occlusion_flag"),1);
+    }
+#endif
   }
   
   if(mode_&0x1) {
@@ -481,6 +503,12 @@ void IndexedVertexArray::RenderGL()
     }
   }
 
+#if OST_SHADER_SUPPORT_ENABLED
+  if(use_ambient_) {
+    glUniform1i(glGetUniformLocation(Shader::Instance().GetCurrentProgram(),"occlusion_flag"),0);
+  }
+#endif
+
   if(draw_normals_) {
     //glColor3f(1,0,0);
     glBegin(GL_LINES);
@@ -596,6 +624,9 @@ void IndexedVertexArray::Clear()
   outline_exp_factor_=0.1;
   outline_exp_color_=Color(0,0,0);
   draw_normals_=false;
+  use_ambient_=false;
+  ambient_dirty_=true;
+  ambient_data_.clear();
 }
 
 void IndexedVertexArray::FlagRefresh()
@@ -868,6 +899,35 @@ void IndexedVertexArray::SmoothVertices(float smoothf)
   }
 }
 
+void IndexedVertexArray::UseAmbient(bool f)
+{
+  if(use_ambient_==f) return;
+  use_ambient_=f;
+  FlagRefresh();
+}
+
+Color IndexedVertexArray::GetAmbientColor(VertexID id) const
+{
+  Color nrvo;
+  if(id*4>=ambient_data_.size()) return nrvo;
+  unsigned int offset=id*4;
+  nrvo = Color(ambient_data_[offset+0],
+               ambient_data_[offset+1],
+               ambient_data_[offset+2],
+               ambient_data_[offset+3]);
+  return nrvo;
+} 
+
+void IndexedVertexArray::SetAmbientColor(VertexID id, const Color& c) 
+{
+  if(id*4>=ambient_data_.size()) return;
+  unsigned int offset=id*4;
+  ambient_data_[offset+0]=c[0];
+  ambient_data_[offset+1]=c[1];
+  ambient_data_[offset+2]=c[2];
+  ambient_data_[offset+3]=c[3];
+}
+
 
 namespace {
 
@@ -991,43 +1051,91 @@ void IndexedVertexArray::copy(const IndexedVertexArray& va)
   outline_exp_factor_=va.outline_exp_factor_;
   outline_exp_color_=va.outline_exp_color_;
   draw_normals_=va.draw_normals_;
+  use_ambient_=va.use_ambient_;
+  ambient_dirty_=va.ambient_dirty_;
+  ambient_data_=va.ambient_data_;
 }
   
 bool IndexedVertexArray::prep_buff()
 {
 #if OST_SHADER_SUPPORT_ENABLED
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glEnableClientState(GL_NORMAL_ARRAY);
+  glEnableClientState(GL_COLOR_ARRAY);
+  glEnableClientState(GL_INDEX_ARRAY);
+
   int glerr=glGetError(); // clear error flag
-  glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[0]);
-  VERTEX_ARRAY_CHECK_GL_ERROR("bind buf0");
+  glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_VERTEX_BUFFER]);
+  VERTEX_ARRAY_CHECK_GL_ERROR("bind vertex buf");
   glBufferData(GL_ARRAY_BUFFER, 
                sizeof(Entry) * entry_list_.size(),
                &entry_list_[0],
                GL_STATIC_DRAW);
-  VERTEX_ARRAY_CHECK_GL_ERROR("set buf0");
-  
-  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[1]);
+  VERTEX_ARRAY_CHECK_GL_ERROR("set vertex buf");
+
+  // this will be used later, when refactoring v,c,n to live in separate lists
+  /*
+  glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_COLOR_BUFFER]);
   VERTEX_ARRAY_CHECK_GL_ERROR("bind buf1");
-  glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
-               sizeof(unsigned int) * line_index_list_.size(),
-               &line_index_list_[0],
+  glBufferData(GL_ARRAY_BUFFER, 
+               sizeof(Entry) * entry_list_.size(),
+               &entry_list_[0].c[0],
                GL_STATIC_DRAW);
   VERTEX_ARRAY_CHECK_GL_ERROR("set buf1");
-  
-  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[2]);
+
+  glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_NORMAL_BUFFER]);
   VERTEX_ARRAY_CHECK_GL_ERROR("bind buf2");
-  glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
-               sizeof(unsigned int) * tri_index_list_.size(),
-               &tri_index_list_[0],
+  glBufferData(GL_ARRAY_BUFFER, 
+               sizeof(Entry) * entry_list_.size(),
+               &entry_list_[0].n[0],
                GL_STATIC_DRAW);
   VERTEX_ARRAY_CHECK_GL_ERROR("set buf2");
-  
-  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[3]);
-  VERTEX_ARRAY_CHECK_GL_ERROR("bind buf3");
-  glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
-               sizeof(unsigned int) * quad_index_list_.size(),
-               &quad_index_list_[0],
-               GL_STATIC_DRAW);
-  VERTEX_ARRAY_CHECK_GL_ERROR("set buf3");
+  */
+
+  if(!line_index_list_.empty()) {
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[VA_LINEINDEX_BUFFER]);
+    VERTEX_ARRAY_CHECK_GL_ERROR("bind lindex buf");
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
+		 sizeof(unsigned int) * line_index_list_.size(),
+		 &line_index_list_[0],
+		 GL_STATIC_DRAW);
+    VERTEX_ARRAY_CHECK_GL_ERROR("set lindex buf");
+  }
+
+  if(!tri_index_list_.empty()) {
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[VA_TRIINDEX_BUFFER]);
+    VERTEX_ARRAY_CHECK_GL_ERROR("bind tindex buf");
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
+		 sizeof(unsigned int) * tri_index_list_.size(),
+		 &tri_index_list_[0],
+		 GL_STATIC_DRAW);
+    VERTEX_ARRAY_CHECK_GL_ERROR("set tindex buf");
+  }
+
+  if(!quad_index_list_.empty()) {
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[VA_QUADINDEX_BUFFER]);
+    VERTEX_ARRAY_CHECK_GL_ERROR("bind qindex buf");
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 
+		 sizeof(unsigned int) * quad_index_list_.size(),
+		 &quad_index_list_[0],
+		 GL_STATIC_DRAW);
+    VERTEX_ARRAY_CHECK_GL_ERROR("set qindex buf");
+  }
+
+  if(use_ambient_) {
+    if(ambient_data_.empty()) {
+      LOGN_VERBOSE("ambient data empty");
+    } else {
+      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+      glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_AMBIENT_BUFFER]);
+      VERTEX_ARRAY_CHECK_GL_ERROR("bind ambient buf");
+      glBufferData(GL_ARRAY_BUFFER,
+		   sizeof(float) * ambient_data_.size(),
+		   &ambient_data_[0],
+		   GL_STATIC_DRAW);
+      VERTEX_ARRAY_CHECK_GL_ERROR("set ambient buf");
+    }
+  }
   
   return true;
 #else
@@ -1039,29 +1147,43 @@ void IndexedVertexArray::draw_ltq(bool use_buff)
 {
   if(use_buff && !Scene::Instance().InOffscreenMode()) {
 #if OST_SHADER_SUPPORT_ENABLED
-    LOGN_TRACE("binding vertex array buffer");
-    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[0]);
-    LOGN_TRACE("setting up vertex array");
+#if 1
+    /*
+      for now, since v,n,c live in a packed format (formerly used
+      with glInterleavedArrays), only a single buffer is
+      used, with the gl*Pointer calls giving the byte offset
+      in place of the absolute pointer
+    */
+    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_VERTEX_BUFFER]);
+    glVertexPointer(3, GL_FLOAT, sizeof(Entry), reinterpret_cast<void*>(sizeof(float)*7));
+    glNormalPointer(GL_FLOAT, sizeof(Entry), reinterpret_cast<void*>(sizeof(float)*4));
+    glColorPointer(4, GL_FLOAT, sizeof(Entry), 0);
+#else
+    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_VERTEX_BUFFER]);
     glInterleavedArrays(GetFormat(),sizeof(Entry),NULL);
-    
+#endif
+
+    if(use_ambient_) {
+      if(!ambient_data_.empty()) {
+	glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_AMBIENT_BUFFER]);
+	glTexCoordPointer(4,GL_FLOAT,0,NULL);
+      }
+    }
+    glBindBuffer(GL_ARRAY_BUFFER,0);
+
     if(!tri_index_list_.empty() && (mode_ & 0x4)) {
-      LOGN_TRACE("binding and rendering vertex array tris");
-      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[2]);
+      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[VA_TRIINDEX_BUFFER]);
       glDrawElements(GL_TRIANGLES,tri_index_list_.size(),GL_UNSIGNED_INT,NULL);
     }
     if(!quad_index_list_.empty() && (mode_ & 0x4)) {
-      LOGN_TRACE("binding and rendering vertex arras quads");
-      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[3]);
+      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[VA_QUADINDEX_BUFFER]);
       glDrawElements(GL_QUADS,quad_index_list_.size(),GL_UNSIGNED_INT,NULL);
     }
     if(!line_index_list_.empty() && (mode_ & 0x2)) {
-      LOGN_TRACE("binding and rendering vertex array lines");
-      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[1]);
+      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_id_[VA_LINEINDEX_BUFFER]);
       glDrawElements(GL_LINES,line_index_list_.size(),GL_UNSIGNED_INT,NULL);
     }
     
-    LOGN_TRACE("unbinding vertex array buffer");
-    glBindBuffer(GL_ARRAY_BUFFER,0);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
 #endif
   } else {
@@ -1088,11 +1210,12 @@ void IndexedVertexArray::draw_p(bool use_buff)
 {
   if(use_buff && !Scene::Instance().InOffscreenMode()) {
 #if OST_SHADER_SUPPORT_ENABLED
-    LOGN_TRACE("binding vertex array buffer");
-    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[0]);
-    LOGN_TRACE("calling vertex array");
-    glInterleavedArrays(GetFormat(),sizeof(Entry),NULL);
-    glDrawArrays(GL_POINTS,0,entry_list_.size());
+    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_VERTEX_BUFFER]);
+    glVertexPointer(3, GL_FLOAT, sizeof(Entry), NULL);
+    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_NORMAL_BUFFER]);
+    glNormalPointer(GL_FLOAT, sizeof(Entry), NULL);
+    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_COLOR_BUFFER]);
+    glColorPointer(4, GL_FLOAT, sizeof(Entry), NULL);
 #endif
   } else {
     LOGN_TRACE("calling vertex array");
@@ -1277,4 +1400,11 @@ void IndexedVertexArray::draw_line_halo(bool use_buff)
   glLineWidth(line_width_);
 }
 
+void IndexedVertexArray::recalc_ambient_occlusion()
+{
+  ambient_data_.resize(4*entry_list_.size());
+  CalcAmbientTerms(*this);
+  std::cerr << ambient_data_[0] << "," << ambient_data_[1] << "," << ambient_data_[2] << "," << ambient_data_[3] << std::endl;
+}
+
 }} // ns
diff --git a/modules/gfx/src/vertex_array.hh b/modules/gfx/src/vertex_array.hh
index f54640c44911e1401c983f7f477dd842063e1fdd..eed4d2a7fdc97f4d3f92c3f883ed5caaed50e316 100644
--- a/modules/gfx/src/vertex_array.hh
+++ b/modules/gfx/src/vertex_array.hh
@@ -46,7 +46,7 @@ typedef unsigned int LineID;
 typedef unsigned int TriID;
 typedef unsigned int QuadID;
 class DLLEXPORT_OST_GFX IndexedVertexArray {
-
+ public:
   struct Entry {
     Entry();
     Entry(const geom::Vec3& vv, const geom::Vec3& nn, const Color& cc);
@@ -74,7 +74,6 @@ class DLLEXPORT_OST_GFX IndexedVertexArray {
   typedef std::vector<NormalizerVertexEntry> NVEntryList;
   typedef std::vector<NormalizerTriEntry> NTEntryList;
 
-public:
   IndexedVertexArray();
   ~IndexedVertexArray();
 
@@ -167,7 +166,17 @@ public:
   void NPatch();
   // experimental, do not use
   void SmoothVertices(float smoothf);
+  // experimental, do not use
+  void UseAmbient(bool f);
+
+  const EntryList& GetEntries() const {return entry_list_;}
+  const IndexList& GetQuadIndices() const {return quad_index_list_;}
+  const IndexList& GetTriIndices() const {return tri_index_list_;}
+  const IndexList& GetLineIndices() const {return line_index_list_;}
 
+  Color GetAmbientColor(VertexID id) const;
+  void SetAmbientColor(VertexID id, const Color& col);
+  
  private:
   bool initialized_;
   
@@ -200,7 +209,11 @@ public:
 
   bool draw_normals_;
 
-  unsigned int buffer_id_[4];
+  unsigned int buffer_id_[7]; // magic number related to the .cc buffer use
+
+  bool use_ambient_;
+  bool ambient_dirty_;
+  std::vector<float> ambient_data_;
 
   void copy(const IndexedVertexArray& va);
   bool prep_buff();
@@ -208,6 +221,7 @@ public:
   void draw_p(bool use_buff);
   void draw_aalines();
   void draw_line_halo(bool use_buff);
+  void recalc_ambient_occlusion();
 };
 
 }} // ns