diff --git a/examples/misc/ambient_occlusion.py b/examples/misc/ambient_occlusion.py
index 60106214fc61f46d12294d40bd4f5cd5868f1ba0..3ed9da4e8c072a70a20e7d02489064c0f0b511fe 100644
--- a/examples/misc/ambient_occlusion.py
+++ b/examples/misc/ambient_occlusion.py
@@ -8,17 +8,26 @@ def test1():
     scene["surf"].SetColor(gfx.BLUE,"ele=N")
     scene.CenterOn("surf")
     scene.SetFog(False)
-    # blend the ambient occlusion 40% into the surface
-    # hence reduce diffuse to 60%
-    # give 100% to specular
-    scene.SetLightProp(0.6,0.4,1)
-    # blend the local color 25% percent into the surface
-    # keep diffuse at max
-    # add specular component at 80% with a strong hilight
-    scene["surf"].SetMat(0.25,1,0.8,128)
+    # turn on full contribution from light
+    scene.SetLightProp(1,1,1)
+    
+    # use a material with 10% global ambient light,
+    # 90% diffuse light, and full specular with small
+    # hilights
+    scene["surf"].SetMat(0.1,0.9,1,128)
+
+    # turn on ambient occlusion
+    # this may take seconds to calculate
+    scene["surf"].AmbientOcclusion(True)
+
+    # blend the ambient occlusion 100% into the surface,
+    # reducing the color intensity
+    scene["surf"].AmbientOcclusionWeight(1)
+    # blend the local color 30% percent into the surface
+    scene["surf"].AmbientLocalWeight(0.3)
+
     scene.AutoAutoslab(False)
     scene.Autoslab()
-    scene["surf"].AmbientOcclusion(True)
 
 def test2():
     global plist
diff --git a/modules/gfx/pymod/export_gfx_obj.cc b/modules/gfx/pymod/export_gfx_obj.cc
index 18e3454eead7e34dcfc09493cfcf87dc219a74ac..a285e524d7bcf89ccf776a4bebd20d7ad8f8b464 100644
--- a/modules/gfx/pymod/export_gfx_obj.cc
+++ b/modules/gfx/pymod/export_gfx_obj.cc
@@ -76,6 +76,8 @@ void export_GfxObj()
     .def("SetOutlineExpandColor",&GfxObj::SetOutlineExpandColor)
     .def("SmoothVertices",&GfxObj::SmoothVertices)
     .def("AmbientOcclusion",&GfxObj::AmbientOcclusion)
+    .def("AmbientLocalWeight",&GfxObj::AmbientLocalWeight)
+    .def("AmbientOcclusionWeight",&GfxObj::AmbientOcclusionWeight)
     .def("Debug",&GfxObj::Debug)
     .add_property("center", &GfxObj::GetCenter)
     COLOR_BY_DEF()
diff --git a/modules/gfx/pymod/export_render_options.cc b/modules/gfx/pymod/export_render_options.cc
index b27e55c46f32ec9ac3fc3c3c166eb74d58cbc1fe..113d364cb3a3b5573353077c040822bd0b603c86 100644
--- a/modules/gfx/pymod/export_render_options.cc
+++ b/modules/gfx/pymod/export_render_options.cc
@@ -102,6 +102,8 @@ void export_RenderOptions()
     .def("GetHelixEcc", &CartoonRenderOptions::GetHelixEcc)
     .def("SetHelixProfileType", &CartoonRenderOptions::SetHelixProfileType)
     .def("GetHelixProfileType", &CartoonRenderOptions::GetHelixProfileType)
+    .def("SetHelixMode", &CartoonRenderOptions::SetHelixMode)
+    .def("GetHelixMode", &CartoonRenderOptions::GetHelixMode)
     .def("SetStrandWidth", &CartoonRenderOptions::SetStrandWidth)
     .def("GetStrandWidth", &CartoonRenderOptions::GetStrandWidth)
     .def("SetStrandThickness", &CartoonRenderOptions::SetStrandThickness)
@@ -110,6 +112,8 @@ void export_RenderOptions()
     .def("GetStrandEcc", &CartoonRenderOptions::GetStrandEcc)
     .def("SetStrandProfileType", &CartoonRenderOptions::SetStrandProfileType)
     .def("GetStrandProfileType", &CartoonRenderOptions::GetStrandProfileType)
+    .def("SetStrandMode", &CartoonRenderOptions::SetStrandMode)
+    .def("GetStrandMode", &CartoonRenderOptions::GetStrandMode)
   ;
   
   class_<TraceRenderOptions, boost::shared_ptr<TraceRenderOptions>, bases<RenderOptions>, boost::noncopyable>("TraceRenderOptions")
diff --git a/modules/gfx/src/gfx_object.cc b/modules/gfx/src/gfx_object.cc
index 0a28a7e6e6dc30da9d3132f620e334b448b11add..54301a76848cfb16176ec36a309f7c1513dac71d 100644
--- a/modules/gfx/src/gfx_object.cc
+++ b/modules/gfx/src/gfx_object.cc
@@ -148,8 +148,12 @@ void GfxObj::CustomPreRenderGL(bool flag) {}
 
 void GfxObj::CustomRenderPov(PovState& pov) {}
 
+/* 
+  this should not be necessary anymore
+
 void GfxObj::RefreshVA(IndexedVertexArray& va)
 {
+
   va.SetLineWidth(GetLineWidth());
   va.SetPolyMode(GetPolyMode());
   va.SetAALines(GetAALines());
@@ -159,6 +163,7 @@ void GfxObj::RefreshVA(IndexedVertexArray& va)
   va.UseAmbient(use_occlusion_);
   va.FlagRefresh();
 }
+*/
 
 void GfxObj::OnInput(const InputEvent& e) 
 {
@@ -276,6 +281,7 @@ void GfxObj::OnRenderModeChange()
 
 void GfxObj::SetLineWidth(float w)
 {
+  va_.SetLineWidth(w);
   line_width_=std::max(float(0.01),w);
   FlagRefresh();
   Scene::Instance().RenderModeChanged(GetName());
@@ -326,6 +332,7 @@ void GfxObj::SetPolyMode(unsigned int m)
 {
   if(m==poly_mode_) return;
   poly_mode_=std::min((unsigned int)2,m);
+  va_.SetPolyMode(poly_mode_);
   FlagRefresh();
 }
 
@@ -337,6 +344,7 @@ unsigned int GfxObj::GetPolyMode() const
 void GfxObj::SetAALines(bool f)
 {
   if(f==aalines_flag_) return;
+  va_.SetAALines(f);
   aalines_flag_=f;
   FlagRefresh();
 }
@@ -348,6 +356,7 @@ bool GfxObj::GetAALines() const
 
 void GfxObj::SetLineHalo(float f)
 {
+  va_.SetLineHalo(f);
   line_halo_=f;
   FlagRefresh();
 }
@@ -613,11 +622,22 @@ void GfxObj::SmoothVertices(float smoothf)
 
 void GfxObj::AmbientOcclusion(bool f)
 {
-  use_occlusion_=f;
   va_.UseAmbient(f);
   Scene::Instance().RequestRedraw();
 }
 
+void GfxObj::AmbientLocalWeight(float w)
+{
+  va_.AmbientLocalWeight(w);
+  Scene::Instance().RequestRedraw();
+}
+
+void GfxObj::AmbientOcclusionWeight(float w)
+{
+  va_.AmbientOcclusionWeight(w);
+  Scene::Instance().RequestRedraw();
+}
+
 void GfxObj::ColorBy(const mol::EntityView& ev, 
                       const String& prop,
                       const Gradient& g, float minv, float maxv)
@@ -761,4 +781,9 @@ void GfxObj::CleanColorOps(){
   c_ops_.release();
 }
 
+void GfxObj::Debug(unsigned int flags)
+{
+  va_.DrawNormals(flags & 0x1);
+}
+
 }} // ns
diff --git a/modules/gfx/src/gfx_object.hh b/modules/gfx/src/gfx_object.hh
index 5a4bd4877dec27e434a1cdce1fe7ade9abf58adc..5d8d3393b13f737b71fbabafea1715d9a9ee7ee7 100644
--- a/modules/gfx/src/gfx_object.hh
+++ b/modules/gfx/src/gfx_object.hh
@@ -195,10 +195,18 @@ public:
   void SetOutlineExpandFactor(float f);
   void SetOutlineExpandColor(const Color& c);
 
+  /// \brief ambient occlusion rendering
+  /// results are cached, but may be very slow on first call 
+  void AmbientOcclusion(bool f);
+  
+  /// \brief blending weight of local color to fragment color
+  void AmbientLocalWeight(float w);
+
+  /// \brief blending weight of occlusion factor
+  void AmbientOcclusionWeight(float w);
+
   // experimental, don't use
   void SmoothVertices(float smoothf);
-  // experimental, don't use
-  void AmbientOcclusion(bool f);
  
   void GLCleanup();
 
@@ -256,16 +264,15 @@ public:
                const Color& c1, const Color& c2, float minv, float maxv);  
 #endif
 
-  void Debug(unsigned int flags) {debug_flags_=flags; RefreshVA();}
+  void Debug(unsigned int flags);
 
  protected:
   
   void PreRenderGL(bool flag);
   virtual void CustomPreRenderGL(bool flag);
 
-  void RefreshVA(IndexedVertexArray& va);
-
-  virtual void RefreshVA() {RefreshVA(va_);}
+  //void RefreshVA(IndexedVertexArray& va);
+  //virtual void RefreshVA() {RefreshVA(va_);}
   
  private:
   GfxObj(const GfxObj& o);
diff --git a/modules/gfx/src/gfx_prim.hh b/modules/gfx/src/gfx_prim.hh
index 1ec2bc25a55c382af86d52087a56b5c900e069d5..aead546538e44fe83dab8c948b65b976cf2eb6d7 100644
--- a/modules/gfx/src/gfx_prim.hh
+++ b/modules/gfx/src/gfx_prim.hh
@@ -48,13 +48,19 @@ typedef std::vector<SpherePrim> SpherePrimList;
 
 struct CylinderPrim {
   CylinderPrim():
-    start(),end(),radius(1.0),color(),length(1.0),rotmat(),rotmat_t()
+    start(),end(),radius(1.0),color1(),color2(),length(1.0),rotmat(),rotmat_t()
   {
     calc_rotmat();
   }
 
   CylinderPrim(const geom::Vec3& st, const geom::Vec3& en, float rad, const Color& col):
-    start(st),end(en),radius(rad),color(col),length(geom::Length(end-start)),rotmat(),rotmat_t() 
+    start(st),end(en),radius(rad),color1(col),color2(col),length(geom::Length(end-start)),rotmat(),rotmat_t() 
+  {
+    calc_rotmat();
+  }
+
+  CylinderPrim(const geom::Vec3& st, const geom::Vec3& en, float rad, const Color& col1, const Color& col2):
+    start(st),end(en),radius(rad),color1(col1),color2(col2),length(geom::Length(end-start)),rotmat(),rotmat_t() 
   {
     calc_rotmat();
   }
@@ -63,7 +69,7 @@ struct CylinderPrim {
 
   geom::Vec3 start,end;
   float radius;
-  Color color;
+  Color color1, color2;
   float length;
   geom::Mat3 rotmat;
   geom::Mat3 rotmat_t;
diff --git a/modules/gfx/src/impl/backbone_trace.cc b/modules/gfx/src/impl/backbone_trace.cc
index 33e7be49ca8be0b642cbb9a643224c3c389824a4..28ebb3842557e98b72eed9e6c9fb805d37cfad49 100644
--- a/modules/gfx/src/impl/backbone_trace.cc
+++ b/modules/gfx/src/impl/backbone_trace.cc
@@ -115,67 +115,72 @@ void BackboneTrace::AddNodeList(const NodeEntryList& l)
 {
   if(l.size()>=3) {
     node_list_list_.push_back(l);
-    // assign direction and normal vectors for each entry
-    // they are composed of the i-1 -> i and i->i+1 directions
-    //
-    // this same algorithm is used in the spline generation, so
-    // perhaps all of this here is not necessary ?!
-    //
-    NodeEntry* e0=&node_list_list_.back()[0];
-    NodeEntry* e1=&node_list_list_.back()[1];
-    NodeEntry* e2=&node_list_list_.back()[2];
-    geom::Vec3 p0 = e0->atom.GetPos();
-    geom::Vec3 p1 = e1->atom.GetPos();
-    geom::Vec3 p2 = e2->atom.GetPos();
-
-    e0->direction=geom::Normalize(p1-p0);
-    // e0->normal is set afterwards to normal of second one
-    // backup residue normal
-    e0->v1 = e0->normal;
-
-    //reference normal to avoid twisting
-    geom::Vec3 nref=geom::Normalize(geom::Cross(p0-p1,p2-p1));
-
-    // start loop with the second
-    unsigned int i=1;
-    for(;i<node_list_list_.back().size()-1;++i) {
-      geom::Vec3 p10 = p0-p1;
-      geom::Vec3 p12 = p2-p1;
-      if(p10==-p12 || p10==p12) p12+=geom::Vec3(0.001,0.001,0.001);
-      e1->v1=e1->normal;
-      // twist avoidance
-      if(geom::Dot(e0->v1,e1->v1)<0.0) {
-        e1->v1=-e1->v1;
-      }
-      e1->normal=geom::Normalize(geom::Cross(p10,p12));
-      float omega=0.5*acos(geom::Dot(geom::Normalize(p10),geom::Normalize(p12)));
-      geom::Vec3 orth=geom::AxisRotation(e1->normal, -omega)*p12;
-      e1->direction=geom::Normalize(geom::Cross(e1->normal,orth));
+    PrepList(node_list_list_.back());
+  }
+}
 
-      // align normals to avoid twisting
-      //if(geom::Dot(e1->normal,nref)<0.0) e1->normal=-e1->normal;
-      //nref=e1->normal;
-      // skip over shift for the last iteration
-      if(i==node_list_list_.back().size()-2) break;
-      // shift to i+1 for next iteration
-      e0=&node_list_list_.back()[i];
-      e1=&node_list_list_.back()[i+1];
-      e2=&node_list_list_.back()[i+2];
-      p0 = e0->atom.GetPos();
-      p1 = e1->atom.GetPos();
-      p2 = e2->atom.GetPos();
-    }
-    // finish remaining values
-    // i is at size-2 due to break statement above
-    node_list_list_.back()[0].normal=node_list_list_.back()[1].normal;
-    node_list_list_.back()[i+1].direction=geom::Normalize(p2-p1);
-    node_list_list_.back()[i+1].v1=node_list_list_.back()[i+1].normal;
-    if (geom::Dot(node_list_list_.back()[i].v1,
-                  node_list_list_.back()[i+1].v1)<0.0) {
-      node_list_list_.back()[i+1].v1=-node_list_list_.back()[i+1].v1;
+void BackboneTrace::PrepList(NodeEntryList& nelist)
+{
+  // assign direction and normal vectors for each entry
+  // they are composed of the i-1 -> i and i->i+1 directions
+  //
+  // this same algorithm is used in the spline generation, so
+  // perhaps all of this here is not necessary ?!
+  //
+  NodeEntry* e0=&nelist[0];
+  NodeEntry* e1=&nelist[1];
+  NodeEntry* e2=&nelist[2];
+  geom::Vec3 p0 = e0->atom.GetPos();
+  geom::Vec3 p1 = e1->atom.GetPos();
+  geom::Vec3 p2 = e2->atom.GetPos();
+  
+  e0->direction=geom::Normalize(p1-p0);
+  // e0->normal is set afterwards to normal of second one
+  // backup residue normal
+  e0->v1 = e0->normal;
+  
+  //reference normal to avoid twisting
+  geom::Vec3 nref=geom::Normalize(geom::Cross(p0-p1,p2-p1));
+  
+  // start loop with the second
+  unsigned int i=1;
+  for(;i<nelist.size()-1;++i) {
+    geom::Vec3 p10 = p0-p1;
+    geom::Vec3 p12 = p2-p1;
+    if(p10==-p12 || p10==p12) p12+=geom::Vec3(0.001,0.001,0.001);
+    e1->v1=e1->normal;
+    // twist avoidance
+    if(geom::Dot(e0->v1,e1->v1)<0.0) {
+      e1->v1=-e1->v1;
     }
-    node_list_list_.back()[i+1].normal=node_list_list_.back()[i].normal;
+    e1->normal=geom::Normalize(geom::Cross(p10,p12));
+    float omega=0.5*acos(geom::Dot(geom::Normalize(p10),geom::Normalize(p12)));
+    geom::Vec3 orth=geom::AxisRotation(e1->normal, -omega)*p12;
+    e1->direction=geom::Normalize(geom::Cross(e1->normal,orth));
+    
+    // align normals to avoid twisting
+    //if(geom::Dot(e1->normal,nref)<0.0) e1->normal=-e1->normal;
+    //nref=e1->normal;
+    // skip over shift for the last iteration
+    if(i==nelist.size()-2) break;
+    // shift to i+1 for next iteration
+    e0=&nelist[i];
+    e1=&nelist[i+1];
+    e2=&nelist[i+2];
+    p0 = e0->atom.GetPos();
+    p1 = e1->atom.GetPos();
+    p2 = e2->atom.GetPos();
+  }
+  // finish remaining values
+  // i is at size-2 due to break statement above
+  nelist[0].normal=nelist[1].normal;
+  nelist[i+1].direction=geom::Normalize(p2-p1);
+  nelist[i+1].v1=nelist[i+1].normal;
+  if (geom::Dot(nelist[i].v1,
+                nelist[i+1].v1)<0.0) {
+    nelist[i+1].v1=-nelist[i+1].v1;
   }
+  nelist[i+1].normal=nelist[i].normal;
 }
 
 int BackboneTrace::GetListCount() const
diff --git a/modules/gfx/src/impl/backbone_trace.hh b/modules/gfx/src/impl/backbone_trace.hh
index c6663f12c336b9b87470bf8cce4c3540ef711d4e..25ebdce1fe5cf3b764c0aac06e64b546121f4434 100644
--- a/modules/gfx/src/impl/backbone_trace.hh
+++ b/modules/gfx/src/impl/backbone_trace.hh
@@ -50,8 +50,9 @@ public:
   
   void SetView(const mol::EntityView& ent);
   
-  // used internally
   void AddNodeList(const NodeEntryList& entries);  
+
+  static void PrepList(NodeEntryList& nelist);
   
   void Rebuild();
   
diff --git a/modules/gfx/src/impl/calc_ambient.cc b/modules/gfx/src/impl/calc_ambient.cc
index c7900dcf4c0c4da852cd9f42687a540155e848b4..cfbbdacc183db740b9156b214a791693d74eca3d 100644
--- a/modules/gfx/src/impl/calc_ambient.cc
+++ b/modules/gfx/src/impl/calc_ambient.cc
@@ -213,57 +213,34 @@ namespace {
       CMap::iterator mit=cmap_.find(cindex);
       if(mit==cmap_.end()) return;
       for(std::vector<CEntry>::const_iterator eit=mit->second.begin();eit!=mit->second.end();++eit) {
-        //std::cerr << " comparing with v=" << eit->v0 << std::endl;
         geom::Vec3 dir0=(eit->v0-ce.v0); // vector from reference entry to current entry
         float l2=geom::Length2(dir0);
-        if(l2>cutoff2 || l2<0.01) {
-          //std::cerr << "  MISS: l2 failed: " << l2 << std::endl;
-          continue;
-        }
-        dir0=geom::Normalize(dir0);
-
-        //std::cerr << "  dir0=" << dir0 << " dot=" << geom::Dot(dir0,ce.n) << std::endl;
+        if(l2>cutoff2 || l2<0.01) continue;
 
-        if(geom::Dot(dir0,ce.n)<1e-6) { 
-          //std::cerr << "  MISS: dir0 points to back" << std::endl;
-          continue;
-        }
-
-        geom::Vec3 dir1=geom::Normalize(eit->v1-ce.v0); // vector from reference entry to corner 1
-        geom::Vec3 dir2=geom::Normalize(eit->v2-ce.v0); // vector from reference entry to corner 2
-        geom::Vec3 dir3=geom::Normalize(eit->v3-ce.v0); // vector from reference entry to corner 3
-        geom::Vec3 dir4=geom::Normalize(eit->v4-ce.v0); // vector from reference entry to corner 4
+        dir0=geom::Normalize(dir0);
 
-        //std::cerr << "  v1=" << eit->v1 << std::endl;
-        //std::cerr << "  v2=" << eit->v2 << std::endl;
-        //std::cerr << "  v3=" << eit->v3 << std::endl;
-        //std::cerr << "  v4=" << eit->v4 << std::endl;
+        if(geom::Dot(dir0,ce.n)<1e-6) continue;
 
         // largest opening angle from reference entry to corners
         float a0=1.0;
         if(eit->type==3) {
-          a0 = (geom::Dot(dir0,dir1)+geom::Dot(dir0,dir2)+geom::Dot(dir0,dir3))/3.0;
+          a0 = (geom::Dot(dir0,geom::Normalize(eit->v1-ce.v0))+
+                geom::Dot(dir0,geom::Normalize(eit->v2-ce.v0))+
+                geom::Dot(dir0,geom::Normalize(eit->v3-ce.v0)))/3.0;
         } else if(eit->type==4) {
-          a0 = (geom::Dot(dir0,dir1)+geom::Dot(dir0,dir2)+geom::Dot(dir0,dir3)+geom::Dot(dir0,dir4))/4.0;
+          a0 = (geom::Dot(dir0,geom::Normalize(eit->v1-ce.v0))+
+                geom::Dot(dir0,geom::Normalize(eit->v2-ce.v0))+
+                geom::Dot(dir0,geom::Normalize(eit->v3-ce.v0))+
+                geom::Dot(dir0,geom::Normalize(eit->v4-ce.v0)))/4.0;
         }
-        //std::cerr << "  a0=" << a0 << std::endl;
+
         for(std::vector<RayEntry>::iterator rit=rays_.begin();rit!=rays_.end();++rit) {
-          //std::cerr << "   ray " << rit->v << std::endl;
-          if(rit->back) {
-            //std::cerr << "    MISS: points to back" << std::endl;
-            continue;
-          }
+          if(rit->back) continue;
           if(geom::Dot(ce.n,rit->v)<1e-6) {
             rit->back=true;
-            //std::cerr << "    MISS: points to back" << std::endl;
             continue;
           }
-          //std::cerr << "    dot(dir0,ray)=" << geom::Dot(dir0,rit->v) << std::endl;
-          if(geom::Dot(dir0,rit->v)<a0) {
-            //std::cerr << "    MISS: outside" << std::endl;
-            continue;
-          }
-          //std::cerr << "    HIT" << std::endl;
+          if(geom::Dot(dir0,rit->v)<a0) continue;
           if(rit->d2<l2) continue;
           rit->d2=l2;
           rit->c=eit->c;
@@ -277,16 +254,12 @@ namespace {
       const IndexList& tlist = va_.GetTriIndices();
       const IndexList& qlist = va_.GetQuadIndices();
       float cutoff2=cutoff_*cutoff_;
+      float isig2 = 1.0/(2.0*2.0*cutoff_/3.0*cutoff_/3.0);
 
       std::vector<std::pair<geom::Vec4, int> > entry_accum(elist.size());
       
       for(CMap::iterator mit=cmap_.begin();mit!=cmap_.end();++mit) {
         for(CList::iterator lit=mit->second.begin();lit!=mit->second.end();++lit) {
-          //std::cerr << "working on v=" << lit->v0 << " n=" << lit->n << std::endl;
-          //std::cerr << " v1=" << lit->v1 << std::endl;
-          //std::cerr << " v2=" << lit->v2 << std::endl;
-          //std::cerr << " v3=" << lit->v3 << std::endl;
-          //std::cerr << " v4=" << lit->v4 << std::endl;
           // reset rays
           for(std::vector<RayEntry>::iterator rit=rays_.begin();rit!=rays_.end();++rit) {
             rit->d2=cutoff2;
@@ -302,51 +275,55 @@ namespace {
             }
           }
 
-          float kA=0.0;
-          float kS=0.0;
-          geom::Vec3 col(0.0,0.0,0.0);
-          unsigned int miss_count=0;
-          unsigned int back_count=0;
-          unsigned int hit_count=0;
+          // sum up ray contributions
+          float occl=0.0;
+          float occl_sum=0.0;
+          geom::Vec4 col(0.0,0.0,0.0,0.0);
+          float col_weight_sum=0.0;
           for(std::vector<RayEntry>::iterator rit=rays_.begin();rit!=rays_.end();++rit) {
             if(!rit->back) {
-              float ca=geom::Dot(rit->v,lit->n);
-              kS += ca;
+              float ca=std::max(Real(0.0),geom::Dot(rit->v,lit->n));
+              occl_sum += ca;
               if(!rit->hit) {
-                kA += ca;
-                col[0] += rit->c[0];
-                col[1] += rit->c[1];
-                col[2] += rit->c[2];
-                ++miss_count;
+                occl += ca;
+                float col_weight=exp(-rit->d2*isig2);
+                col[0] += col_weight*rit->c[0];
+                col[1] += col_weight*rit->c[1];
+                col[2] += col_weight*rit->c[2];
+                col_weight_sum+=col_weight;
               }
             }
-            if(rit->back) ++back_count;
-            if(rit->hit) ++hit_count;
-          }
-          float amb=kA/kS;
-          if(miss_count>0) {
-            col*=1.0f/static_cast<float>(miss_count);
           }
-          //std::cerr << " hits=" << hit_count << ", miss=" << miss_count << ", back=" << back_count << " (" << rays_.size() << "), kA= " << kA << ", kS=" << kS << ", amb=" << amb << std::endl;
+          if(occl_sum>0.0) occl/=occl_sum;
+          if(col_weight_sum>0.0) col/=col_weight_sum;
 
+          col[3]=occl;
           if(lit->type==3) {
-            // please provide a Vec explicit float ctor in double-precision mode
-            // instead of typecasting here
-            entry_accum[tlist[lit->id+0]].first+=geom::Vec4(col[0],col[1],col[2],amb);
-            entry_accum[tlist[lit->id+1]].first+=geom::Vec4(col[0],col[1],col[2],amb);
-            entry_accum[tlist[lit->id+2]].first+=geom::Vec4(col[0],col[1],col[2],amb);
-            ++entry_accum[tlist[lit->id+0]].second;
-            ++entry_accum[tlist[lit->id+1]].second;
-            ++entry_accum[tlist[lit->id+2]].second;
+            unsigned int litid=lit->id;
+            /*
+            entry_accum[tlist[litid+0]].first+=col;
+            entry_accum[tlist[litid+0]].second+=1;
+            entry_accum[tlist[litid+1]].first+=col;
+            entry_accum[tlist[litid+1]].second+=1;
+            entry_accum[tlist[litid+2]].first+=col;
+            entry_accum[tlist[litid+2]].second+=1;
+            */
+            std::pair<geom::Vec4,int>* e=&entry_accum[tlist[litid++]];
+            e->first+=col; ++e->second;
+            e=&entry_accum[tlist[litid++]];
+            e->first+=col; ++e->second;
+            e=&entry_accum[tlist[litid++]];
+            e->first+=col; ++e->second;
           } else if(lit->type==4) {
-            entry_accum[qlist[lit->id+0]].first+=geom::Vec4(col[0],col[1],col[2],amb);
-            entry_accum[qlist[lit->id+1]].first+=geom::Vec4(col[0],col[1],col[2],amb);
-            entry_accum[qlist[lit->id+2]].first+=geom::Vec4(col[0],col[1],col[2],amb);
-            entry_accum[qlist[lit->id+3]].first+=geom::Vec4(col[0],col[1],col[2],amb);
-            ++entry_accum[qlist[lit->id+0]].second;
-            ++entry_accum[qlist[lit->id+1]].second;
-            ++entry_accum[qlist[lit->id+2]].second;
-            ++entry_accum[qlist[lit->id+3]].second;
+            unsigned int litid=lit->id;
+            std::pair<geom::Vec4,int>* e=&entry_accum[qlist[litid++]];
+            e->first+=col; ++e->second;
+            e=&entry_accum[qlist[litid++]];
+            e->first+=col; ++e->second;
+            e=&entry_accum[qlist[litid++]];
+            e->first+=col; ++e->second;
+            e=&entry_accum[qlist[litid++]];
+            e->first+=col; ++e->second;
           }
         }
       }
diff --git a/modules/gfx/src/impl/cartoon_renderer.cc b/modules/gfx/src/impl/cartoon_renderer.cc
index 08f0a0c3e5a1167a35d35a9712afc2f677505cc5..d95119c9fbd50d40773e33c5e4d57a5a3d11b5d0 100644
--- a/modules/gfx/src/impl/cartoon_renderer.cc
+++ b/modules/gfx/src/impl/cartoon_renderer.cc
@@ -18,6 +18,10 @@
 //------------------------------------------------------------------------------
 #include "cartoon_renderer.hh"
 
+#include <Eigen/Core>
+#include <Eigen/Array>
+#include <Eigen/SVD>
+#include <Eigen/LU>
 
 #include <ost/gfx/entity.hh>
 #include <ost/gfx/impl/tabulated_trig.hh>
@@ -34,12 +38,7 @@ CartoonRenderer::CartoonRenderer(BackboneTrace& trace, bool force_tube):
   TraceRendererBase(trace, 3),   force_tube_(force_tube),
   options_(new CartoonRenderOptions(force_tube))
 {
-if(force_tube){
-  this->SetName("Smooth Tube");
-}
-else{
-  this->SetName("Helix & Strand Cartoon");
-}
+  this->SetName(force_tube ? "Smooth Tube" : "Helix & Strand Cartoon");
 }
 
 void CartoonRenderer::SetForceTube(bool force_tube)
@@ -47,6 +46,77 @@ void CartoonRenderer::SetForceTube(bool force_tube)
   force_tube_ = force_tube;
 }
 
+namespace {
+
+  void smooth_strands(SplineEntryList& spl)
+  {
+    for(unsigned int i=0;i<spl.size();++i) {
+      if(spl[i].type==2 || spl[i].type==3 || spl[i].type==4) {
+	unsigned int kstart = i++;
+	//kstart = std::max<unsigned int>(0,kstart-1);
+	for(;(spl[i].type==2 || spl[i].type==3 || spl[i].type==4) && i<spl.size();++i);
+	unsigned int kend = i;
+	//kend = std::min<unsigned int>(spl.size(),kend+2);
+	
+	if(kend>kstart) {
+	  SplineEntry& xstart=spl[kstart];
+	  SplineEntry& xend=spl[kend];
+	  
+	  xstart.direction = geom::Normalize(xend.position-xstart.position);
+	  xend.direction=xstart.direction;
+	  float invf=1.0/static_cast<float>(kend-kstart);
+	  for(unsigned int k=kstart;k<kend;++k) {
+	    float f = static_cast<float>(k-kstart)*invf;
+	    spl[k].position=xstart.position+f*(xend.position-xstart.position);
+	    spl[k].direction=xstart.direction;
+	    geom::Vec3 tmpn=geom::Normalize(xstart.normal+f*(xend.normal-xstart.normal));
+	    geom::Vec3 tmpx=geom::Normalize(geom::Cross(xstart.direction,tmpn));
+	    spl[k].normal=geom::Normalize(geom::Cross(tmpx,xstart.direction));
+	  }
+	}        
+      }
+    }
+  }
+  
+  typedef Eigen::Matrix<Real,3,1> EVec3;
+  typedef Eigen::Matrix<Real,3,3> EMat3;
+  typedef Eigen::Matrix<Real,1,3> ERVec3;
+  typedef Eigen::Matrix<Real,Eigen::Dynamic,Eigen::Dynamic> EMatX;
+  typedef Eigen::Matrix<Real,1,Eigen::Dynamic> ERVecX;
+
+  ERVec3 to_eigen(const geom::Vec3& v)
+  {
+    EVec3 nrvo=EVec3::Zero();
+    nrvo[0]=v[0]; nrvo[1]=v[1]; nrvo[2]=v[2];
+    return nrvo;
+  }
+  
+  std::pair<geom::Vec3,geom::Vec3> fit_helix(const std::vector<geom::Vec3>& points)
+  {
+    if(points.size()<4) {
+      return std::make_pair(points.front(),points.back());
+    }
+    geom::Vec3 cen(0.0,0.0,0.0);
+    for(unsigned int i=0;i<points.size();++i) cen+=points[i];
+    cen/=static_cast<float>(points.size());
+
+    EMatX A=EMatX::Zero(points.size(),3);
+    for(unsigned int i=0;i<points.size();++i) {
+      A.row(i)=to_eigen(points[i]-cen);
+    }
+
+    Eigen::SVD<EMatX> svd(A);
+    EMatX V=svd.matrixV();
+    geom::Vec3 ax(V(0,0),V(1,0),V(2,0));
+
+    geom::Vec3 p1=cen+ax*(-geom::Dot(cen,ax)+geom::Dot(points.front(),ax))/geom::Length2(ax);
+    geom::Vec3 p2=cen+ax*(-geom::Dot(cen,ax)+geom::Dot(points.back(),ax))/geom::Length2(ax);
+
+    return std::make_pair(p1,p2);
+  }
+  
+} // ns
+
 void CartoonRenderer::PrepareRendering(TraceSubset& subset, 
                                        IndexedVertexArray& va,
                                        SplineEntryListList& spline_list_list,
@@ -64,8 +134,9 @@ void CartoonRenderer::PrepareRendering(TraceSubset& subset,
     spline_list_list.clear();
     for (int node_list=0; node_list<subset.GetSize(); ++node_list) {
       // first build the spline
-      Spline spl;
+      SplineEntryList spl;
       const NodeListSubset& nl=subset[node_list];
+      int prev_type=0;
       for (int i=0; i<nl.GetSize();++i) {      
         int type=0;
         const NodeEntry& entry=nl[i];
@@ -78,28 +149,55 @@ void CartoonRenderer::PrepareRendering(TraceSubset& subset,
             sst2=resh2.GetSecStructure();
           }
           if(sst.IsHelical()) {
-            type=1;
+            if(options_->GetHelixMode()==1) {
+              if(prev_type==5) {
+                type=5; // cylindrical helix
+              } else {
+                type=prev_type;
+              }
+              prev_type=5;
+            } else {
+              if(prev_type==1) {
+                type=1;
+              } else {
+                type=prev_type;
+              }
+              prev_type=1;
+            }
           } else if(sst.IsExtended()) {
             if(!sst2.IsExtended()) {
               type=3; // end of strand
             } else {
-              type=2;
+              if(prev_type==2) {
+                type=2;
+              } else {
+                type=prev_type;
+              }
             }
+            prev_type=2;
+          } else {
+            prev_type=type;
           }
         }
-        SplineEntry& ee = spl.AddEntry(entry.atom.GetPos(),entry.direction,
-                                       entry.normal, entry.rad, 
-                                       is_sel ? sel_clr : entry.color1, 
-                                       is_sel ? sel_clr : entry.color2, type);
+        SplineEntry ee(entry.atom.GetPos(),entry.direction,
+                       entry.normal, entry.rad, 
+                       is_sel ? sel_clr : entry.color1, 
+                       is_sel ? sel_clr : entry.color2, type);
         ee.v1 = entry.v1;
+        spl.push_back(ee);
+      }
+      if(!spl.empty()) {
+        if(options_->GetStrandMode()==1) {
+          smooth_strands(spl);
+        }
+        spline_list_list.push_back(Spline::Generate(spl,spline_detail));
       }
-      spline_list_list.push_back(spl.Generate(spline_detail));
-      // now create the shape around the interpolated pathway
     }
-    RebuildSplineObj(spline_list_list.back(), va, spline_list_list, subset, is_sel);    
+    RebuildSplineObj(va, spline_list_list, subset, is_sel);    
     va.SmoothNormals(options_->GetNormalSmoothFactor());
   }  
 }
+
 void CartoonRenderer::PrepareRendering()
 {
   TraceRendererBase::PrepareRendering();
@@ -131,8 +229,7 @@ RenderOptionsPtr CartoonRenderer::GetOptions()
  return options_;
 }
 
-void CartoonRenderer::RebuildSplineObj(const SplineEntryList& l, 
-                                       IndexedVertexArray& va,
+void CartoonRenderer::RebuildSplineObj(IndexedVertexArray& va,
                                        SplineEntryListList& spline_list_list,
                                        const TraceSubset& subset, bool is_sel)
 {
@@ -168,6 +265,7 @@ void CartoonRenderer::RebuildSplineObj(const SplineEntryList& l,
 				      1.1*options_->GetStrandThickness()+factor,
 				      options_->GetStrandProfileType(),
 				      options_->GetStrandEcc())); // arrow start
+    profiles.push_back(profiles[0]); // cylindrical helix start+end == tube
   }
 
   // iterate over all spline segments
@@ -203,11 +301,50 @@ void CartoonRenderer::RebuildSplineObj(const SplineEntryList& l,
         tprof2=TransformAndAddProfile(profiles,se, va);
         AssembleProfile(tprof1,tprof2,va);
         tprof1=tprof2;
-        tprof2=TransformAndAddProfile(profiles,slist[sc], va);
-        last_se=slist[sc];
-      } else {
-        tprof2=TransformAndAddProfile(profiles,slist[sc], va);
+        // and continue with the normal profiles
+      } else if(slist[sc].type==5) {
+        // this profile is a helix in cylinder mode
+        SplineEntry& hstart = slist[sc];
+	int istart = sc;
+        // skip over all helical ones
+        while(slist[sc].type==5 && sc<send) ++sc;
+        if(sc==send) sc-=1; // hack for helix at end of trace
+	SplineEntry& hend = slist[sc-1];
+
+	// fit helix into ca points
+	std::vector<geom::Vec3> points;
+	for(int i=istart;i<sc;++i) points.push_back(slist[i].position);
+	std::pair<geom::Vec3,geom::Vec3> cyl=fit_helix(points);
+
+	// extend end of current trace to beginning of cylinder
+	// and then cap it
+	SplineEntry tmp_se(slist[istart]);
+	tmp_se.position=cyl.first;
+	//tmp_se.direction=geom::Normalize(cyl.second-cyl.first);
+	//tmp_se.normal=geom::Normalize(geom::Cross(tmp_se.direction,geom::Normalize(geom::Cross(tmp_se.normal,tmp_se.direction))));
+        tprof2=TransformAndAddProfile(profiles,tmp_se, va);
+        AssembleProfile(tprof1,tprof2,va);
+        CapProfile(tprof2,tmp_se,false,va);
+        // add the cylinder
+        va.AddCylinder(CylinderPrim(cyl.first,cyl.second,
+                                    options_->GetHelixWidth(),
+                                    hstart.color1,
+                                    hend.color1),
+                       options_->GetArcDetail(),true);
+
+        // restart with a new cap and another extended profile
+	SplineEntry tmp_se2(slist[sc-1]);
+	tmp_se2.position=cyl.second;
+	//tmp_se2.direction=geom::Normalize(cyl.first-cyl.second);
+	//tmp_se2.normal=geom::Normalize(geom::Cross(tmp_se2.direction,geom::Normalize(geom::Cross(tmp_se2.normal,tmp_se2.direction))));
+        tprof1=TransformAndAddProfile(profiles,tmp_se2, va);
+        CapProfile(tprof1,tmp_se2,true,va);
+        tprof2=TransformAndAddProfile(profiles,hend, va);
+        AssembleProfile(tprof1,tprof2,va);
+	tprof1=tprof2;
+        // and continue with the normal profiles
       }
+      tprof2=TransformAndAddProfile(profiles,slist[sc], va);
       AssembleProfile(tprof1,tprof2,va);
       tprof1=tprof2;
       last_se=slist[sc];
diff --git a/modules/gfx/src/impl/cartoon_renderer.hh b/modules/gfx/src/impl/cartoon_renderer.hh
index ff9097e5c5f2bee0c04ac945aeb0ded32c4d26ca..df3e0e69b34e48a25d044ed6cfd5ee0cb4c7c92d 100644
--- a/modules/gfx/src/impl/cartoon_renderer.hh
+++ b/modules/gfx/src/impl/cartoon_renderer.hh
@@ -50,7 +50,7 @@ public:
   virtual ~CartoonRenderer();
   
 private:
-  void RebuildSplineObj(const SplineEntryList& l, IndexedVertexArray& va,
+  void RebuildSplineObj(IndexedVertexArray& va,
                         SplineEntryListList& spline_list_list,
                         const TraceSubset& subset, bool is_sel);
   
diff --git a/modules/gfx/src/impl/debug_renderer.cc b/modules/gfx/src/impl/debug_renderer.cc
index 918117400b0b4a1e2039590e4739cbcfd26aa611..27138b32ef6b4f1d88271b447168f0de58dc1896 100644
--- a/modules/gfx/src/impl/debug_renderer.cc
+++ b/modules/gfx/src/impl/debug_renderer.cc
@@ -51,7 +51,7 @@ void DebugRenderer::PrepareRendering()
 
   for(NodeEntryListList::const_iterator ll_it=node_list_list_->begin();ll_it!=node_list_list_->end();++ll_it) {
 
-    Spline spl;
+    SplineEntryList spl;
     for(NodeEntryList::const_iterator it=(*ll_it).begin();it!=(*ll_it).end();++it) {
       int type=0;
       ResidueHandle resh = it->atom.GetResidue();
@@ -62,12 +62,13 @@ void DebugRenderer::PrepareRendering()
         type=2;
       }
 
-      SplineEntry& ee = spl.AddEntry(it->atom.GetPos(),it->direction,it->normal,
-                                     it->rad,it->color1,it->color2,type);
+      SplineEntry ee(it->atom.GetPos(),it->direction,it->normal,
+                     it->rad,it->color1,it->color2,type);
       ee.v1 = it->v1;
+      spl.push_back(ee);
     }
 
-    SplineEntryList sel = spl.Generate(std::max((unsigned int) 1,options_->GetSplineDetail()));
+    SplineEntryList sel = Spline::Generate(spl,std::max((unsigned int) 1,options_->GetSplineDetail()));
 
     SplineEntryList::const_iterator sit = sel.begin();
     geom::Vec3 ap = sit->position;
diff --git a/modules/gfx/src/impl/entity_detail.cc b/modules/gfx/src/impl/entity_detail.cc
index aa99b5f6c1104f01be96aa0b589401a6559c0291..23de774e199b62b99b7f09a74e7e9d8ecbdf64f8 100644
--- a/modules/gfx/src/impl/entity_detail.cc
+++ b/modules/gfx/src/impl/entity_detail.cc
@@ -87,64 +87,15 @@ void GfxView::AddBond(const BondHandle& b)
 }
 
 
-void SplineEntry::ToQuat()
-{
-  // assert orthonormal system
-  // TODO: this seems broken
-  geom::Vec3 dir = geom::Normalize(direction);
-  geom::Vec3 norm0 = geom::Normalize(normal);
-  geom::Vec3 norm2 = geom::Cross(dir,norm0);
-  geom::Vec3 norm1 = geom::Cross(norm2,dir);
-  geom::Mat3 rmat(dir[0],norm1[0],norm2[0],
-                  dir[1],norm1[1],norm2[1],
-                  dir[2],norm1[2],norm2[2]);
-  
-  geom::Quat quat(rmat);
-  quat_value[0]=quat.w;
-  quat_value[1]=quat.x;
-  quat_value[2]=quat.y;
-  quat_value[3]=quat.z;
-}
-
-void SplineEntry::FromQuat() 
-{
-  /* 
-     assert orthornormal system since direction was
-     probably adjusted for curvature
-  */
-  // TODO: this seems broken
-  geom::Quat quat(quat_value[0],quat_value[1],quat_value[2],quat_value[3]);
-  geom::Mat3 rmat = quat.ToRotationMatrix();
-  geom::Vec3 norm0 = geom::Normalize(geom::Vec3(rmat(0,1),rmat(1,1),rmat(2,1)));
-  geom::Vec3 dir = geom::Normalize(direction);
-  geom::Vec3 norm2 = geom::Normalize(geom::Cross(dir,norm0));
-  normal = geom::Normalize(geom::Cross(norm2,dir));
-}
-
 ////////////////////////////
 
 
-Spline::Spline():
-  entry_list_()
-{}
-
-
-SplineEntry& Spline::AddEntry(const geom::Vec3& pos, const geom::Vec3& dir, const geom::Vec3& normal, float rad, const Color& c1, const Color& c2, int type)
-{
-  entry_list_.push_back(SplineEntry(pos,
-                                    geom::Normalize(dir),
-                                    geom::Normalize(normal),
-                                    rad,c1,c2,type));
-  entry_list_.back().ToQuat();
-  return entry_list_.back();
-}
-
 static int bsplineGen(float *x,float *y, int n, float yp1, float ypn, float *y2);
 static int bsplineGet(float *xa, float *ya, float *y2a, int n, float x, float *y);
 
 #define SPLINE_ENTRY_INTERPOLATE(COMPONENT)             \
     for(int c=0;c<size;++c) {                           \
-      yc[c]=entry_list_[c]. COMPONENT ;                 \
+      yc[c]=entry_list[c]. COMPONENT ;                 \
     }                                                   \
     bsplineGen(xp,yp,size,1.0e30,1.0e30,y2p);           \
     for(int c=0;c<size;++c) {                           \
@@ -156,14 +107,14 @@ static int bsplineGet(float *xa, float *ya, float *y2a, int n, float x, float *y
       }                                                 \
     }                                                   
 
-SplineEntryList Spline::Generate(int nsub) const
+SplineEntryList Spline::Generate(const SplineEntryList& entry_list, int nsub)
 {
   if(nsub<=0) {
-    return entry_list_;
+    return entry_list;
   }
-  int size=entry_list_.size();
+  int size=entry_list.size();
   if (size==0) {
-    return entry_list_;
+    return entry_list;
   }
   int ipsize=(size)*nsub;
   float i_nsub=1.0/static_cast<float>(nsub);
@@ -184,9 +135,8 @@ SplineEntryList Spline::Generate(int nsub) const
   // create sublist with enough entries
   SplineEntryList sublist(ipsize);
 
-  // interpolate internal quaternion and color
+  // interpolate color
   for(int k=0;k<4;++k) {
-    SPLINE_ENTRY_INTERPOLATE(quat_value[k]);
     SPLINE_ENTRY_INTERPOLATE(color1[k]);
     SPLINE_ENTRY_INTERPOLATE(color2[k]);
   }
@@ -263,21 +213,21 @@ SplineEntryList Spline::Generate(int nsub) const
   // finally the non-interpolated type
   // with some tweaks for proper strand rendering
   for(int c=0;c<size;++c) {
+    int type1=entry_list[c].type;
+    int type2=entry_list[std::min(c+1,size-1)].type;
+    //int type0=entry_list[std::max(0,c-1)].type;
+    if(type1==2 && type2==3) {
+      type1=2;
+      type2=2;
+    } else if(type1==3) {
+      type1=4;
+      // uncommenting this causes the strand arrows
+      // to blend into a tip instead of the n+1
+      // profile - gives visual artefacts
+      //type2=3;
+    }
     for(int d=0;d<nsub;++d) {
-      sublist[c*nsub+d].type=entry_list_[c].type;
-      int type1=entry_list_[c].type;
-      int type2=entry_list_[std::min(c+1,size-1)].type;
-      //int type0=entry_list_[std::max(0,c-1)].type;
-      if(type1==2 && type2==3) {
-        type1=2;
-        type2=2;
-      } else if(type1==3) {
-        type1=4;
-        // uncommenting this causes the strand arrows
-        // to blend into a tip instead of the n+1
-        // profile - gives visual artefacts
-        //type2=3;
-      }
+      sublist[c*nsub+d].type=entry_list[c].type;
       sublist[c*nsub+d].type1=type1;
       sublist[c*nsub+d].type2=type2;
       sublist[c*nsub+d].frac=float(d)/float(nsub);
diff --git a/modules/gfx/src/impl/entity_detail.hh b/modules/gfx/src/impl/entity_detail.hh
index 7cf19d622fda4ad015caca9d3643cbb152f4793e..02eeeac4ad2298dd91498586a46329357f0bb932 100644
--- a/modules/gfx/src/impl/entity_detail.hh
+++ b/modules/gfx/src/impl/entity_detail.hh
@@ -129,13 +129,8 @@ struct DLLEXPORT_OST_GFX SplineEntry {
   {
   }
 
-  void ToQuat();
-
-  void FromQuat();
-
   geom::Vec3 position,direction,normal;
   Color color1, color2;
-  float quat_value[4];
   float rad;
   int type;
   int type1, type2;
@@ -149,20 +144,7 @@ typedef std::vector<SplineEntryList> SplineEntryListList;
 
 class DLLEXPORT_OST_GFX Spline {
 public:
-
-public:
-  // ctor
-  Spline();
-
-  // add entry at a given position, with direction and normal vectors
-  SplineEntry& AddEntry(const geom::Vec3& pos, const geom::Vec3& dir, 
-                        const geom::Vec3& normal, float r, const Color& col1, 
-                        const Color& col2, int type);
-
-  SplineEntryList Generate(int nsub) const;
-
-private:
-  SplineEntryList entry_list_;
+  static SplineEntryList Generate(const SplineEntryList& entry_list,int nsub);
 };
 
 }}} // ns
diff --git a/modules/gfx/src/impl/sline_renderer.cc b/modules/gfx/src/impl/sline_renderer.cc
index 6d1fe022dd2f56dcad4b6245f89c57df79632b3a..a558bc6732f27c4a283beab4dfbeaa34763d9fe4 100644
--- a/modules/gfx/src/impl/sline_renderer.cc
+++ b/modules/gfx/src/impl/sline_renderer.cc
@@ -58,18 +58,19 @@ void SlineRenderer::PrepareRendering(TraceSubset& trace_subset,
     va.SetAALines(options_->GetAALines());
     for (int node_list=0; node_list<trace_subset.GetSize(); ++node_list) {
       // first build the spline
-      Spline spl;
+      SplineEntryList spl;
       const NodeListSubset& nl=trace_subset[node_list];
       assert(nl.GetSize() && "node list subset with zero eles encountered!");
       for (int i=0; i<nl.GetSize();++i) {
         const NodeEntry& entry=nl[i];
-        SplineEntry& ee = spl.AddEntry(entry.atom.GetPos(), entry.direction,
-                                       entry.normal, entry.rad, 
-                                       is_sel ? sel_clr : entry.color1, 
-                                       is_sel ? sel_clr : entry.color2, 0);
+        SplineEntry ee(entry.atom.GetPos(), entry.direction,
+                       entry.normal, entry.rad, 
+                       is_sel ? sel_clr : entry.color1, 
+                       is_sel ? sel_clr : entry.color2, 0);
         ee.v1 = entry.v1;
+        spl.push_back(ee);
       }
-      SplineEntryList sel = spl.Generate(spline_detail);      
+      SplineEntryList sel = Spline::Generate(spl,spline_detail);      
       SplineEntryList::const_iterator sit=sel.begin(), 
                                      send=sel.end()-spline_detail+1;
       if (nl.AtStart()>0) {
diff --git a/modules/gfx/src/map_iso.cc b/modules/gfx/src/map_iso.cc
index 58859f5449d07abd28fe23bd618343671ab63b37..a383bd737f28a27292a4172bb4088664e9e3ad53 100644
--- a/modules/gfx/src/map_iso.cc
+++ b/modules/gfx/src/map_iso.cc
@@ -131,7 +131,7 @@ void MapIso::CustomPreRenderGL(bool flag)
   if(flag) {
     Rebuild();
   } else {
-    RefreshVA(va_);
+    //RefreshVA(va_);
   }
 }
 
diff --git a/modules/gfx/src/prim_list.cc b/modules/gfx/src/prim_list.cc
index 2302dc7fea417ff6c07748da0d0a5c1c0c11ed5e..c2b4641bc66e53cd4f2403c6ff8b1a28444ab199 100644
--- a/modules/gfx/src/prim_list.cc
+++ b/modules/gfx/src/prim_list.cc
@@ -95,8 +95,6 @@ void PrimList::CustomPreRenderGL(bool flag)
     } else {
       render_simple();
     }
-  } else {
-    RefreshVA(va_);
   }
 }
 
diff --git a/modules/gfx/src/render_options/cartoon_render_options.cc b/modules/gfx/src/render_options/cartoon_render_options.cc
index da5d2e70376999782799e027b87586530b9016ed..f50d28a5b89dc91bf6d3069e00fb3b038f167956 100644
--- a/modules/gfx/src/render_options/cartoon_render_options.cc
+++ b/modules/gfx/src/render_options/cartoon_render_options.cc
@@ -39,10 +39,12 @@ CartoonRenderOptions::CartoonRenderOptions(bool force_tube):
   helix_thickness_(0.2),
   helix_ecc_(0.3),
   helix_profile_(1),
+  helix_mode_(0),
   strand_width_(1.2),
   strand_thickness_(0.2),
   strand_ecc_(0.3),
-  strand_profile_(1)
+  strand_profile_(1),
+  strand_mode_(0)
 {}
 
 RenderMode::Type CartoonRenderOptions::GetRenderMode(){
@@ -66,12 +68,17 @@ void CartoonRenderOptions::ApplyRenderOptions(RenderOptionsPtr render_options){
   smooth_factor_=options->GetNormalSmoothFactor();
   tube_radius_=options->GetTubeRadius();
   tube_ratio_=options->GetTubeRatio();
+  tube_profile_=options->GetTubeProfileType();
   helix_width_=options->GetHelixWidth();
   helix_thickness_=options->GetHelixThickness();
   helix_ecc_=options->GetHelixEcc();
+  helix_profile_=options->GetHelixProfileType();
+  helix_mode_=options->GetHelixMode();
   strand_width_=options->GetStrandWidth();
   strand_thickness_=options->GetStrandThickness();
   strand_ecc_=options->GetStrandEcc();
+  strand_profile_=options->GetStrandProfileType();
+  strand_mode_=options->GetStrandMode();
   this->NotifyStateChange();
 }
 
@@ -196,6 +203,17 @@ void CartoonRenderOptions::SetHelixProfileType(unsigned int t)
   this->NotifyStateChange();
 }
 
+unsigned int CartoonRenderOptions::GetHelixMode() const
+{
+  return helix_mode_;
+}
+
+void CartoonRenderOptions::SetHelixMode(unsigned int m)
+{
+  helix_mode_=m;
+  this->NotifyStateChange();
+}
+
 void CartoonRenderOptions::SetStrandWidth(float strand_width){
   if(strand_width_ != strand_width){
     strand_width_= strand_width>0.0 ? strand_width : strand_width_;
@@ -240,6 +258,17 @@ void CartoonRenderOptions::SetStrandProfileType(unsigned int t)
   this->NotifyStateChange();
 }
 
+unsigned int CartoonRenderOptions::GetStrandMode() const
+{
+  return strand_mode_;
+}
+
+void CartoonRenderOptions::SetStrandMode(unsigned int m)
+{
+  strand_mode_=m;
+  this->NotifyStateChange();
+}
+
 float CartoonRenderOptions::GetMaxRad() const{
   float max_rad=std::max(float(3.0),tube_radius_*tube_ratio_);
   max_rad=std::max(max_rad,tube_radius_);
diff --git a/modules/gfx/src/render_options/cartoon_render_options.hh b/modules/gfx/src/render_options/cartoon_render_options.hh
index 092fafe69f85cf55a6e6a29592288ac53b8e5566..98f49043030e9cba8bc12034bf7306529fa45642 100644
--- a/modules/gfx/src/render_options/cartoon_render_options.hh
+++ b/modules/gfx/src/render_options/cartoon_render_options.hh
@@ -67,6 +67,8 @@ public:
   virtual float GetHelixEcc() const;
   virtual unsigned int GetHelixProfileType() const;
   virtual void SetHelixProfileType(unsigned int);
+  virtual unsigned int GetHelixMode() const;
+  virtual void SetHelixMode(unsigned int);
 
   virtual void SetStrandWidth(float strand_width);
   virtual float GetStrandWidth() const;
@@ -76,6 +78,8 @@ public:
   virtual float GetStrandEcc() const;
   virtual unsigned int GetStrandProfileType() const;
   virtual void SetStrandProfileType(unsigned int);
+  virtual unsigned int GetStrandMode() const;
+  virtual void SetStrandMode(unsigned int);
 
   float GetMaxRad() const;
 
@@ -96,10 +100,13 @@ private:
   float helix_thickness_;
   float helix_ecc_;
   unsigned int helix_profile_;
+  unsigned int helix_mode_;
   float strand_width_;
   float strand_thickness_;
   float strand_ecc_;
   unsigned int strand_profile_;
+  unsigned int strand_mode_;
+
 };
 
 typedef boost::shared_ptr<CartoonRenderOptions> CartoonRenderOptionsPtr;
diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc
index c85abc13d5e38dfb1ed38f3537ab66df7b37db6e..7e6ee6e2c8116a35f23239f89b65772c7e5da83f 100644
--- a/modules/gfx/src/scene.cc
+++ b/modules/gfx/src/scene.cc
@@ -306,6 +306,7 @@ void Scene::SetCenter(const Vec3& cen)
   float delta_z = tcen[2]-transform_.GetTrans()[2];
 
   transform_.SetCenter(cen);
+  transform_.SetTrans(Vec3(0,0,transform_.GetTrans()[2]));
   SetNearFar(znear_+delta_z,zfar_+delta_z);
   RequestRedraw();  
 }
diff --git a/modules/gfx/src/shader/fraglight_lf_fs.glsl b/modules/gfx/src/shader/fraglight_lf_fs.glsl
index 7ffec79b80c30e5f4daf458f3cf63bc510d6fc16..ad34b9f401a65f0b43470b519168f35195477b7f 100644
--- a/modules/gfx/src/shader/fraglight_lf_fs.glsl
+++ b/modules/gfx/src/shader/fraglight_lf_fs.glsl
@@ -2,6 +2,7 @@ uniform bool lighting_flag;
 uniform bool two_sided_flag;
 uniform bool fog_flag;
 uniform bool occlusion_flag;
+uniform vec2 ambient_weight;
 varying vec4 ambient_color;
 
 // copy from basic_fl_vs !
@@ -34,31 +35,34 @@ void main()
     vec4 amb = vec4(0.0);
     vec4 diff = vec4(0.0);
     vec4 spec = vec4(0.0);
-    vec4 color = vec4(0.0);
 
-    /* 
-      For ambient occlusion, this blends the local ambient color together with
-      the fragment color at intensity given my the ambient material settings;
-      ambient_color defaults to gl_Color, so for non ambient-occluded scenes,
-      this is a noop
-    */
-    vec4 diff_color = gl_Color;
+    vec4 color = gl_Color;
     if(occlusion_flag) {
-      diff_color.rgb = mix(gl_Color.rgb,ambient_color.rgb,gl_FrontMaterial.ambient.rgb);
+      /* 
+        For ambient occlusion and local coloring, two effects are possible. 
+        (1) Blending of the original fragment color and the accumulated
+            color of the neighbouring fragments, by ambient_weight[0].
+        (2) Attenuating the resulting color intensity by the ambient occlusion,
+            modulated by ambient_weight[1]
+        Only the rgb values are affected, fragment opacity is unchanged
+      */
+
+      color.rgb = mix(gl_Color.rgb,ambient_color.rgb,ambient_weight[0]);
+      color.rgb = mix(color.rgb,ambient_color.aaa*color.rgb,ambient_weight[1]);
     }
 
     if(DirectionalLight(normal, gl_FrontMaterial.shininess, amb, diff, spec)) {
 
       color  = gl_FrontLightModelProduct.sceneColor  +
-               (amb  * gl_FrontMaterial.diffuse * diff_color * ambient_color.a) +
-               (diff * gl_FrontMaterial.diffuse * diff_color) +
+               (amb  * gl_FrontMaterial.ambient * color) +
+               (diff * gl_FrontMaterial.diffuse * color) +
                (spec * gl_FrontMaterial.specular);
     } else {
       DirectionalLight(-normal, gl_BackMaterial.shininess, amb, diff, spec);
 
       color = gl_BackLightModelProduct.sceneColor  +
-              (amb  * gl_BackMaterial.ambient * diff_color * ambient_color.a) +
-              (diff * gl_BackMaterial.diffuse * diff_color) +
+              (amb  * gl_BackMaterial.ambient * color) +
+              (diff * gl_BackMaterial.diffuse * color) +
               (spec * gl_BackMaterial.specular);
     }
     
diff --git a/modules/gfx/src/surface.cc b/modules/gfx/src/surface.cc
index e0d08cdc162ff04985d9dbeec79f0f725e20e922..a3ec9db3940758706dfac4c3729040c67a04bb84 100644
--- a/modules/gfx/src/surface.cc
+++ b/modules/gfx/src/surface.cc
@@ -164,10 +164,11 @@ geom::AlignedCuboid Surface::GetBoundingBox() const
 
 void Surface::CustomPreRenderGL(bool flag)
 {
+  va_.FlagRefresh();
   if(flag) {
     //Rebuild();
   } else {
-    RefreshVA(va_);
+    //RefreshVA(va_);
   }
 }
 
@@ -244,28 +245,29 @@ void Surface::ColorBy(const String& prop,
 
 void Surface::Apply(const gfx::UniformColorOp& op, bool store){
   if(store){
-	UniformColorOp* op_ptr = new UniformColorOp(op);
+    UniformColorOp* op_ptr = new UniformColorOp(op);
     this->AppendColorOp(op_ptr);
   }
   mol::Query q(op.GetSelection());
   gfx::Color col = op.GetColor();
   if(op.GetSelection()=="") {
-	for(VMap::const_iterator it=vmap_.begin();it!=vmap_.end();++it) {
-	  va_.SetColor(it->second,col);
-	}
+    for(VMap::const_iterator it=vmap_.begin();it!=vmap_.end();++it) {
+      va_.SetColor(it->second,col);
+    }
   } else {
-	for(VMap::const_iterator it=vmap_.begin();it!=vmap_.end();++it) {
-	  mol::AtomHandle ah = sh_.GetVertex(it->first).atom;
-	  if(ah.IsValid()) {
-		if(q.IsAtomSelected(ah)) {
-		  va_.SetColor(it->second,col);
-		}
-	  }
-	}
+    for(VMap::const_iterator it=vmap_.begin();it!=vmap_.end();++it) {
+      mol::AtomHandle ah = sh_.GetVertex(it->first).atom;
+      if(ah.IsValid()) {
+        if(q.IsAtomSelected(ah)) {
+          va_.SetColor(it->second,col);
+        }
+      }
+    }
   }
   FlagRefresh();
 }
-void Surface::Apply(const gfx::BasicGradientColorOp& op, bool store){
+void Surface::Apply(const gfx::BasicGradientColorOp& op, bool store)
+{
   if(store){
     BasicGradientColorOp* op_ptr = new BasicGradientColorOp(op);
     this->AppendColorOp(op_ptr);
@@ -279,23 +281,24 @@ void Surface::Apply(const gfx::BasicGradientColorOp& op, bool store){
   mol::EntityPropertyMapper epm(prop, level);
   std::vector<std::pair<VertexID,float> > v2v;
   for(VMap::const_iterator it=vmap_.begin();it!=vmap_.end();++it) {
-	mol::AtomHandle ah = sh_.GetVertex(it->first).atom;
-	if(ah.IsValid()) {
-	  float v = epm.Get(ah);
-	  v2v.push_back(std::make_pair(it->second,v));
-	  minv=std::min(minv,v);
-	  maxv=std::max(maxv,v);
-	}
+    mol::AtomHandle ah = sh_.GetVertex(it->first).atom;
+    if(ah.IsValid()) {
+      float v = epm.Get(ah);
+      v2v.push_back(std::make_pair(it->second,v));
+      minv=std::min(minv,v);
+      maxv=std::max(maxv,v);
+    }
   }
-
+  
   // reuse values for speed optimization
   for(std::vector<std::pair<VertexID,float> >::const_iterator it=v2v.begin();it!=v2v.end();++it) {
-	va_.SetColor(it->first,gradient.GetColorAt(normalize(it->second,minv,maxv)));
+    va_.SetColor(it->first,gradient.GetColorAt(normalize(it->second,minv,maxv)));
   }
   FlagRefresh();
 }
 
-void Surface::Apply(const gfx::GradientLevelColorOp& op, bool store){
+void Surface::Apply(const gfx::GradientLevelColorOp& op, bool store)
+{
   if(store){
     GradientLevelColorOp* op_ptr = new GradientLevelColorOp(op);
     this->AppendColorOp(op_ptr);
@@ -309,15 +312,16 @@ void Surface::Apply(const gfx::GradientLevelColorOp& op, bool store){
   // for the attached atoms
   mol::EntityPropertyMapper epm(prop, level);
   for(VMap::const_iterator it=vmap_.begin();it!=vmap_.end();++it) {
-	mol::AtomHandle ah = sh_.GetVertex(it->first).atom;
-	if(ah.IsValid()) {
-	  va_.SetColor(it->second,gradient.GetColorAt(normalize(epm.Get(ah),minv,maxv)));
-	}
+    mol::AtomHandle ah = sh_.GetVertex(it->first).atom;
+    if(ah.IsValid()) {
+      va_.SetColor(it->second,gradient.GetColorAt(normalize(epm.Get(ah),minv,maxv)));
+    }
   }
   FlagRefresh();
 }
 
-void Surface::Apply(const gfx::EntityViewColorOp& op, bool store){
+void Surface::Apply(const gfx::EntityViewColorOp& op, bool store)
+{
   if(store){
     EntityViewColorOp* op_ptr = new EntityViewColorOp(op);
     this->AppendColorOp(op_ptr);
@@ -328,14 +332,15 @@ void Surface::Apply(const gfx::EntityViewColorOp& op, bool store){
   float minv = op.GetMinV();
   float maxv = op.GetMaxV();
   for(VMap::const_iterator it=vmap_.begin();it!=vmap_.end();++it) {
-  va_.SetColor(it->second,impl::MappedProperty(ev,prop,g,minv,maxv,
-                                               sh_.GetVertex(it->first).position));
+    va_.SetColor(it->second,impl::MappedProperty(ev,prop,g,minv,maxv,
+                                                 sh_.GetVertex(it->first).position));
   }
   FlagRefresh();
 }
-
+  
 #if OST_IMG_ENABLED
-void Surface::Apply(const gfx::MapHandleColorOp& op, bool store){
+void Surface::Apply(const gfx::MapHandleColorOp& op, bool store)
+{
   if(store){
     MapHandleColorOp* op_ptr = new MapHandleColorOp(op);
     this->AppendColorOp(op_ptr);
@@ -346,17 +351,19 @@ void Surface::Apply(const gfx::MapHandleColorOp& op, bool store){
   float minv = op.GetMinV();
   float maxv = op.GetMaxV();
   for(VMap::const_iterator it=vmap_.begin();it!=vmap_.end();++it) {
-	va_.SetColor(it->second,impl::MappedProperty(mh,prop,g,minv,maxv,sh_.GetVertex(it->first).position));
+    va_.SetColor(it->second,impl::MappedProperty(mh,prop,g,minv,maxv,sh_.GetVertex(it->first).position));
   }
   FlagRefresh();
 }
 #endif //OST_IMG_ENABLED
 
-void Surface::CleanColorOps(){
+void Surface::CleanColorOps()
+{
   GfxObj::CleanColorOps();
 }
 
-void Surface::ReapplyColorOps(){
+void Surface::ReapplyColorOps()
+{
   GfxObj::ReapplyColorOps();
 }
 
diff --git a/modules/gfx/src/vertex_array.cc b/modules/gfx/src/vertex_array.cc
index 970c0988762301883084e992ef948ac4529f4906..01ea30514b6ea0b99a1927f6cb9174511554421f 100644
--- a/modules/gfx/src/vertex_array.cc
+++ b/modules/gfx/src/vertex_array.cc
@@ -77,7 +77,7 @@ IndexedVertexArray::Entry::Entry(const Vec3& vv, const Vec3& nn, const Color& cc
 IndexedVertexArray::IndexedVertexArray()
 {
   initialized_=false;
-  Clear(); // replaces ctor initialization list
+  Reset(); // replaces ctor initialization list
 }
 
 IndexedVertexArray::~IndexedVertexArray()
@@ -249,7 +249,7 @@ void IndexedVertexArray::AddIcoSphere(const SpherePrim& prim, unsigned int detai
   }
 }
 
-void IndexedVertexArray::AddCylinder(const CylinderPrim& prim, unsigned int detail)
+void IndexedVertexArray::AddCylinder(const CylinderPrim& prim, unsigned int detail,bool cap)
 {
   dirty_=true;
   ambient_dirty_=true;
@@ -259,33 +259,54 @@ void IndexedVertexArray::AddCylinder(const CylinderPrim& prim, unsigned int deta
   const std::vector<Vec3>& vlist = detail::GetPrebuildCyl(level);
   
   Vec3 off(0.0,0.0,prim.length);
+
+  Vec3 cn0 = cap ? prim.rotmat* geom::Vec3(0.0,0.0,-1.0) : Vec3();
+  Vec3 cn1 = -cn0;
+  VertexID cid0 = cap ? Add(prim.start, cn0 , prim.color1) : 0;
+  VertexID cid7 = cap ? Add(prim.rotmat * off + prim.start, cn1, prim.color2) : 0;
   
   // prepare first vertices to add
   std::vector<Vec3>::const_iterator it=vlist.begin();
   Vec3 v0 = (*it);
   Vec3 n0 = prim.rotmat * v0; 
   v0*=prim.radius;
-  VertexID id1 = Add(prim.rotmat * v0 + prim.start, n0, prim.color);
-  VertexID id2 = Add(prim.rotmat * (v0+off) + prim.start, n0, prim.color);
+  VertexID id1 = Add(prim.rotmat * v0 + prim.start, n0, prim.color1);
+  VertexID id2 = Add(prim.rotmat * (v0+off) + prim.start, n0, prim.color2);
+  VertexID cid1 = cap ? Add(prim.rotmat * v0 + prim.start, cn0, prim.color1) : 0;
+  VertexID cid2 = cap ? Add(prim.rotmat * (v0+off) + prim.start, cn1, prim.color2) : 0;
   
   // now for the loop around the circle
   VertexID id3=id1;
   VertexID id4=id2;
+  VertexID cid3=cid1;
+  VertexID cid4=cid2;
   ++it;
   for(;it!=vlist.end();++it) {
     v0 = (*it);
     n0 = prim.rotmat * v0; 
     v0 *= prim.radius;
-    VertexID id5 = Add(prim.rotmat * v0 + prim.start, n0, prim.color);
-    VertexID id6 = Add(prim.rotmat * (v0+off) + prim.start, n0, prim.color);
+    VertexID id5 = Add(prim.rotmat * v0 + prim.start, n0, prim.color1);
+    VertexID id6 = Add(prim.rotmat * (v0+off) + prim.start, n0, prim.color2);
     AddTri(id3,id5,id4);
     AddTri(id5,id6,id4);
+    if(cap) {
+      VertexID cid5 = Add(prim.rotmat * v0 + prim.start, cn0, prim.color1);
+      VertexID cid6 = Add(prim.rotmat * (v0+off) + prim.start, cn1, prim.color2);
+      AddTri(cid0,cid5,cid3);
+      AddTri(cid7,cid4,cid6);
+      cid3=cid5;
+      cid4=cid6;
+    }
     id3=id5;
     id4=id6;
   }
   // and finally close the circle
   AddTri(id3,id1,id4);
   AddTri(id1,id2,id4);
+  if(cap) {
+    AddTri(cid0,cid1,cid3);
+    AddTri(cid7,cid4,cid2);
+  }
 }
 
 Vec3 IndexedVertexArray::GetVert(VertexID id) const
@@ -444,6 +465,11 @@ void IndexedVertexArray::RenderGL()
 #if OST_SHADER_SUPPORT_ENABLED
     if(use_ambient_ && !ambient_data_.empty()) {
       glUniform1i(glGetUniformLocation(Shader::Instance().GetCurrentProgram(),"occlusion_flag"),1);
+      glUniform2f(glGetUniformLocation(Shader::Instance().GetCurrentProgram(),"ambient_weight"),
+                  local_ambient_weight_,
+                  ambient_occlusion_weight_);
+    } else {
+      glUniform1i(glGetUniformLocation(Shader::Instance().GetCurrentProgram(),"occlusion_flag"),0);
     }
 #endif
   }
@@ -511,12 +537,6 @@ 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);
@@ -607,7 +627,7 @@ void IndexedVertexArray::RenderPov(PovState& pov, const std::string& name)
   pov.inc() << "}\n";
 }
 
-void IndexedVertexArray::Clear() 
+void IndexedVertexArray::Clear()
 {
   dirty_=true;
   ambient_dirty_=true;
@@ -616,6 +636,13 @@ void IndexedVertexArray::Clear()
   tri_index_list_.clear();
   line_index_list_.clear();
   ntentry_list_.clear();
+  ambient_data_.clear();
+  use_ambient_=false;
+} 
+
+void IndexedVertexArray::Reset() 
+{
+  Clear();
   mode_=0x4;
   poly_mode_=2;
   lighting_=true;
@@ -633,8 +660,8 @@ void IndexedVertexArray::Clear()
   outline_exp_factor_=0.1;
   outline_exp_color_=Color(0,0,0);
   draw_normals_=false;
-  use_ambient_=false;
-  ambient_data_.clear();
+  local_ambient_weight_=0.3;
+  ambient_occlusion_weight_=1.0;
 }
 
 void IndexedVertexArray::FlagRefresh()
@@ -1062,6 +1089,8 @@ void IndexedVertexArray::copy(const IndexedVertexArray& va)
   draw_normals_=va.draw_normals_;
   use_ambient_=va.use_ambient_;
   ambient_data_=va.ambient_data_;
+  local_ambient_weight_=va.local_ambient_weight_;
+  ambient_occlusion_weight_=va.ambient_occlusion_weight_;
 }
   
 bool IndexedVertexArray::prep_buff()
diff --git a/modules/gfx/src/vertex_array.hh b/modules/gfx/src/vertex_array.hh
index eed4d2a7fdc97f4d3f92c3f883ed5caaed50e316..3279eafad303cc12a34e2950a6fd013574598fa0 100644
--- a/modules/gfx/src/vertex_array.hh
+++ b/modules/gfx/src/vertex_array.hh
@@ -134,7 +134,7 @@ class DLLEXPORT_OST_GFX IndexedVertexArray {
   // add an icosahedral based sphere with the given params to the va
   void AddIcoSphere(const SpherePrim& prim, unsigned int detail);
 
-  void AddCylinder(const CylinderPrim& prim, unsigned int detail);
+  void AddCylinder(const CylinderPrim& prim, unsigned int detail,bool cap=false);
 
   geom::Vec3 GetVert(VertexID id) const;
   void SetVert(VertexID id, const geom::Vec3& vert);
@@ -151,13 +151,33 @@ class DLLEXPORT_OST_GFX IndexedVertexArray {
   // POVray export
   void RenderPov(PovState& pov, const std::string& name);
 
-  
+  // turn on ambient lighting, first call may take a while
+  void UseAmbient(bool f);
+
+  // see fraglight_lf_fs shader
+  void AmbientLocalWeight(float w) {local_ambient_weight_=w;}
+  // see fraglight_lf_fs shader
+  void AmbientOcclusionWeight(float w) {ambient_occlusion_weight_=w;}
+
+  Color GetAmbientColor(VertexID id) const;
+  void SetAmbientColor(VertexID id, const Color& col);
+
+  // only removes the drawing elements
   void Clear();
+  // removes all elements and resets internal state to default
+  void Reset();
+
+  // forces re-calculation of some buffered features
   void FlagRefresh();
 
-  void CalcNormals(float smoothf);
+  // for debugging, draw all normals
   void DrawNormals(bool f);
 
+  // NOTE: all methods below could be delegated to the outside, 
+  // using the GetEntries() and Get*Indices() member functions
+
+  // experimental, do not use
+  void CalcNormals(float smoothf);
   // experimental, do not use
   void CalcFullNormals();
   // experimental, do not use
@@ -166,17 +186,13 @@ class DLLEXPORT_OST_GFX IndexedVertexArray {
   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_;
   
@@ -214,6 +230,8 @@ class DLLEXPORT_OST_GFX IndexedVertexArray {
   bool use_ambient_;
   bool ambient_dirty_;
   std::vector<float> ambient_data_;
+  float local_ambient_weight_;
+  float ambient_occlusion_weight_;
 
   void copy(const IndexedVertexArray& va);
   bool prep_buff();
diff --git a/modules/gui/pymod/scene/hsc_widget.py b/modules/gui/pymod/scene/hsc_widget.py
index b5f716a0af5449f5cd49ebb8bbb3137556701fbe..dd63750b0e3da3c996298b81e6f745cf9b585526 100644
--- a/modules/gui/pymod/scene/hsc_widget.py
+++ b/modules/gui/pymod/scene/hsc_widget.py
@@ -23,7 +23,7 @@ from ost import gfx
 from PyQt4 import QtCore, QtGui
 from render_mode_widget import RenderModeWidget
 
-#Tube Render Options
+# HSC Render Options
 class HSCWidget(RenderModeWidget):
   def __init__(self, parent=None):
     RenderModeWidget.__init__(self, parent)
@@ -55,7 +55,7 @@ class HSCWidget(RenderModeWidget):
 
     min_profile=0
     max_profile=4
-    
+
     #########UI##########
     
     #Poly Mode
@@ -119,48 +119,41 @@ class HSCWidget(RenderModeWidget):
     font = helix_label.font()
     font.setBold(True)
     
-    #Helix Radius
+    helix_mode_label = QtGui.QLabel("Helix Mode")
+    self.helix_mode_cb_ = QtGui.QComboBox()
+    self.helix_mode_cb_.addItem("Spiral")
+    self.helix_mode_cb_.addItem("Cylinder")
+
     radius_helix_label = QtGui.QLabel("Width")
-    
     self.width_helix_spinbox_ = QtGui.QDoubleSpinBox()
     self.width_helix_spinbox_.setRange(min_width, max_width)
     self.width_helix_spinbox_.setDecimals(1)
     self.width_helix_spinbox_.setSingleStep(0.1)
-    
     self.width_helix_slider_ = QtGui.QSlider(QtCore.Qt.Horizontal, self)
     self.width_helix_slider_.setRange(min_width*10.0, max_width*10.0)
     self.width_helix_slider_.setTickPosition(QtGui.QSlider.NoTicks)
     self.width_helix_slider_.setTickInterval(1)
     
-    
-    #Helix Ratio
     ratio_helix_label = QtGui.QLabel("Thickness")
-    
     self.thickness_helix_spinbox_ = QtGui.QDoubleSpinBox()
     self.thickness_helix_spinbox_.setRange(min_ratio,max_ratio)
     self.thickness_helix_spinbox_.setDecimals(1)
     self.thickness_helix_spinbox_.setSingleStep(0.1)
-    
     self.thickness_helix_slider_ = QtGui.QSlider(QtCore.Qt.Horizontal, self)
     self.thickness_helix_slider_.setRange(min_ratio*10.0,max_ratio*10.0)
     self.thickness_helix_slider_.setTickPosition(QtGui.QSlider.NoTicks)
     self.thickness_helix_slider_.setTickInterval(1)
     
-    
-    #Helix ECC
     ecc_helix_label = QtGui.QLabel("ECC")
-    
     self.ecc_helix_spinbox_ = QtGui.QDoubleSpinBox()
     self.ecc_helix_spinbox_.setRange(min_ecc,max_ecc)
     self.ecc_helix_spinbox_.setDecimals(1)
     self.ecc_helix_spinbox_.setSingleStep(0.1)
-    
     self.ecc_helix_slider_ = QtGui.QSlider(QtCore.Qt.Horizontal, self)
     self.ecc_helix_slider_.setRange(min_ecc*10,max_ecc*10)
     self.ecc_helix_slider_.setTickPosition(QtGui.QSlider.NoTicks)
     self.ecc_helix_slider_.setTickInterval(1)
     
-    # Helix Profile Type
     helix_profile_label = QtGui.QLabel("Helix Profile Type")
     self.helix_profile_spinbox_ = QtGui.QSpinBox()
     self.helix_profile_spinbox_.setRange(min_profile, max_profile)
@@ -170,52 +163,47 @@ class HSCWidget(RenderModeWidget):
     font = strand_label.font()
     font.setBold(1)
     
-    #Strand Radius
+    strand_mode_label = QtGui.QLabel("Strand Mode")
+    self.strand_mode_cb_ = QtGui.QComboBox()
+    self.strand_mode_cb_.addItem("Curved")
+    self.strand_mode_cb_.addItem("Straight")
+
     radius_strand_label = QtGui.QLabel("Width")
-    
     self.width_strand_spinbox_ = QtGui.QDoubleSpinBox()
     self.width_strand_spinbox_.setRange(min_width, max_width)
     self.width_strand_spinbox_.setDecimals(1)
     self.width_strand_spinbox_.setSingleStep(0.1)
-    
     self.width_strand_slider_ = QtGui.QSlider(QtCore.Qt.Horizontal, self)
     self.width_strand_slider_.setRange(min_width*10, max_width*10)
     self.width_strand_slider_.setTickPosition(QtGui.QSlider.NoTicks)
     self.width_strand_slider_.setTickInterval(1)
     
-    
-    #Strand Ratio
+
     ratio_strand_label = QtGui.QLabel("Thickness")
-    
     self.thickness_strand_spinbox_ = QtGui.QDoubleSpinBox()
     self.thickness_strand_spinbox_.setRange(min_ratio,max_ratio)
     self.thickness_strand_spinbox_.setDecimals(1)
     self.thickness_strand_spinbox_.setSingleStep(0.1)
-    
     self.thickness_strand_slider_ = QtGui.QSlider(QtCore.Qt.Horizontal, self)
     self.thickness_strand_slider_.setRange(min_ratio*10,max_ratio*10)
     self.thickness_strand_slider_.setTickPosition(QtGui.QSlider.NoTicks)
     self.thickness_strand_slider_.setTickInterval(1)
     
-    
-    #Strand ECC
     ecc_strand_label = QtGui.QLabel("ECC")
-    
     self.ecc_strand_spinbox_ = QtGui.QDoubleSpinBox()
     self.ecc_strand_spinbox_.setRange(min_ecc,max_ecc)
     self.ecc_strand_spinbox_.setDecimals(1)
     self.ecc_strand_spinbox_.setSingleStep(0.1)
-    
     self.ecc_strand_slider_ = QtGui.QSlider(QtCore.Qt.Horizontal, self)
     self.ecc_strand_slider_.setRange(min_ecc*10,max_ecc*10)
     self.ecc_strand_slider_.setTickPosition(QtGui.QSlider.NoTicks)
     self.ecc_strand_slider_.setTickInterval(1)  
     
-    # Strand Profile Type
     strand_profile_label = QtGui.QLabel("Strand Profile Type")
     self.strand_profile_spinbox_ = QtGui.QSpinBox()
     self.strand_profile_spinbox_.setRange(min_profile, max_profile)
 
+    # layout
     row=1
     grid = QtGui.QGridLayout()
     grid.addWidget(poly_mode_label,row,0,1,1)
@@ -242,6 +230,9 @@ class HSCWidget(RenderModeWidget):
     row+=1
     grid.addWidget(helix_label, row, 0, 1, 3)
     row+=1
+    grid.addWidget(helix_mode_label,row,0,1,1)
+    grid.addWidget(self.helix_mode_cb_,row,3,1,2)
+    row+=1
     grid.addWidget(radius_helix_label, row, 0, 1, 1)
     grid.addWidget(self.width_helix_slider_, row, 1, 1, 3)
     grid.addWidget(self.width_helix_spinbox_, row, 4, 1, 1)
@@ -259,6 +250,9 @@ class HSCWidget(RenderModeWidget):
     row+=1
     grid.addWidget(strand_label, row, 0, 1, 3)
     row+=1
+    grid.addWidget(strand_mode_label,row,0,1,1)
+    grid.addWidget(self.strand_mode_cb_,row,3,1,2)
+    row+=1
     grid.addWidget(radius_strand_label, row, 0, 1, 1)
     grid.addWidget(self.width_strand_slider_, row, 1, 1, 3)
     grid.addWidget(self.width_strand_spinbox_, row, 4, 1, 1)
@@ -276,7 +270,8 @@ class HSCWidget(RenderModeWidget):
     
     grid.setRowStretch(row+1,1)
     self.setLayout(grid)
-    
+
+    # signals
     QtCore.QObject.connect(self.spline_spinbox_, QtCore.SIGNAL("valueChanged(int)"), self.UpdateSplineDetail)
     QtCore.QObject.connect(self.arc_spinbox_, QtCore.SIGNAL("valueChanged(int)"), self.UpdateArcDetail)
     QtCore.QObject.connect(self.poly_mode_cb_, QtCore.SIGNAL("currentIndexChanged(int)"), self.UpdatePolyMode)
@@ -287,6 +282,7 @@ class HSCWidget(RenderModeWidget):
     QtCore.QObject.connect(self.thickness_tube_slider_, QtCore.SIGNAL("valueChanged(int)"), self.UpdateSliderTubeRatio)
     QtCore.QObject.connect(self.tube_profile_spinbox_, QtCore.SIGNAL("valueChanged(int)"), self.UpdateTubeProfileType)
     
+    QtCore.QObject.connect(self.helix_mode_cb_, QtCore.SIGNAL("currentIndexChanged(int)"), self.UpdateHelixMode)
     QtCore.QObject.connect(self.width_helix_spinbox_, QtCore.SIGNAL("valueChanged(double)"), self.UpdateHelixWidth)
     QtCore.QObject.connect(self.width_helix_slider_, QtCore.SIGNAL("valueChanged(int)"), self.UpdateSliderHelixWidth)
     QtCore.QObject.connect(self.thickness_helix_spinbox_, QtCore.SIGNAL("valueChanged(double)"), self.UpdateHelixThickness)
@@ -295,6 +291,7 @@ class HSCWidget(RenderModeWidget):
     QtCore.QObject.connect(self.ecc_helix_slider_, QtCore.SIGNAL("valueChanged(int)"), self.UpdateSliderHelixEcc)
     QtCore.QObject.connect(self.helix_profile_spinbox_, QtCore.SIGNAL("valueChanged(int)"), self.UpdateHelixProfileType)
 
+    QtCore.QObject.connect(self.strand_mode_cb_, QtCore.SIGNAL("currentIndexChanged(int)"), self.UpdateStrandMode)
     QtCore.QObject.connect(self.width_strand_spinbox_, QtCore.SIGNAL("valueChanged(double)"), self.UpdateStrandWidth)
     QtCore.QObject.connect(self.width_strand_slider_, QtCore.SIGNAL("valueChanged(int)"), self.UpdateSliderStrandWidth)
     QtCore.QObject.connect(self.thickness_strand_spinbox_, QtCore.SIGNAL("valueChanged(double)"), self.UpdateStrandThickness)
@@ -314,10 +311,14 @@ class HSCWidget(RenderModeWidget):
     self.UpdateTubeRadiusGui(options.GetTubeRadius())
     self.UpdateTubeRatioGui(options.GetTubeRatio())
     self.tube_profile_spinbox_.setValue(options.GetTubeProfileType())
+
+    self.helix_mode_cb_.setCurrentIndex(options.GetHelixMode())
     self.UpdateHelixWidthGui(options.GetHelixWidth())
     self.UpdateHelixThicknessGui(options.GetHelixThickness())
     self.UpdateHelixEccGui(options.GetHelixEcc())
     self.helix_profile_spinbox_.setValue(options.GetHelixProfileType())
+
+    self.strand_mode_cb_.setCurrentIndex(options.GetStrandMode())
     self.UpdateStrandWidthGui(options.GetStrandWidth())
     self.UpdateStrandThicknessGui(options.GetStrandThickness())
     self.UpdateStrandEccGui(options.GetStrandEcc())
@@ -347,6 +348,9 @@ class HSCWidget(RenderModeWidget):
   def UpdateTubeProfileType(self, value):
     self.GetOptions().SetTubeProfileType(value)
     
+  def UpdateHelixMode(self, value):
+    self.GetOptions().SetHelixMode(value)
+    
   def UpdateHelixWidth(self, value):
     self.GetOptions().SetHelixWidth(value) 
     
@@ -368,6 +372,9 @@ class HSCWidget(RenderModeWidget):
   def UpdateSliderHelixEcc(self, value):
     self.GetOptions().SetHelixEcc(value/10.0)
     
+  def UpdateStrandMode(self, value):
+    self.GetOptions().SetStrandMode(value)
+    
   def UpdateStrandWidth(self, value):
     self.GetOptions().SetStrandWidth(value)