diff --git a/modules/gfx/pymod/__init__.py b/modules/gfx/pymod/__init__.py
index 2877e2faabd574161e90c3c06c488a062aaae857..54995ff502e5249115bfd901621a5c6207fdfce1 100644
--- a/modules/gfx/pymod/__init__.py
+++ b/modules/gfx/pymod/__init__.py
@@ -236,7 +236,16 @@ def _primlist_add_cyl(self,pos1,pos2,radius=None,radius1=None,radius2=None,color
     color2=color
   self._add_cyl(pos1,pos2,radius1,radius2,color1,color2)
 
+def _primlist_add_text(self,text,pos,color=None,point_size=None):
+  pos=_to_vec3(pos)
+  if not color:
+    color=WHITE
+  if not point_size:
+    point_size=1.0
+  self._add_text(text,pos,color,point_size)
+  
 PrimList.AddPoint=_primlist_add_point
 PrimList.AddLine=_primlist_add_line
 PrimList.AddSphere=_primlist_add_sphere
 PrimList.AddCyl=_primlist_add_cyl
+PrimList.AddText=_primlist_add_text
diff --git a/modules/gfx/pymod/export_primlist.cc b/modules/gfx/pymod/export_primlist.cc
index 1456d157e595fc5cfe2467ecbfe048e099a8282e..b8326509d8ed7065f120ab4760a541b5766e207b 100644
--- a/modules/gfx/pymod/export_primlist.cc
+++ b/modules/gfx/pymod/export_primlist.cc
@@ -19,18 +19,21 @@
 #include <boost/python.hpp>
 using namespace boost::python;
 
+#include <boost/shared_ptr.hpp>
+
 #include <ost/gfx/prim_list.hh>
 using namespace ost;
 using namespace ost::gfx;
 
 void export_primlist()
 {
-  class_<PrimList, bases<GfxObj>, PrimListP, boost::noncopyable>("PrimList", init<const String& >())
+  class_<PrimList, bases<GfxObj>, boost::shared_ptr<PrimList>, boost::noncopyable>("PrimList", init<const String& >())
     .def("Clear",&PrimList::Clear)
     .def("_add_line",&PrimList::AddLine)
     .def("_add_point",&PrimList::AddPoint)
     .def("_add_sphere",&PrimList::AddSphere)
     .def("_add_cyl",&PrimList::AddCyl)
+    .def("_add_text",&PrimList::AddText)
     .def("SetColor",&PrimList::SetColor)
     .def("SetDiameter",&PrimList::SetDiameter)
     .def("SetRadius",&PrimList::SetRadius)
diff --git a/modules/gfx/src/prim_list.cc b/modules/gfx/src/prim_list.cc
index c541490c1da3c9173b7fe85eee675c2028bedf5f..6113aecfb45e02867496f1c6129a92d9da8db2a1 100644
--- a/modules/gfx/src/prim_list.cc
+++ b/modules/gfx/src/prim_list.cc
@@ -35,6 +35,7 @@ PrimList::PrimList(const String& name):
   lines_(),
   spheres_(),
   cyls_(),
+  texts_(),
   sphere_detail_(4),
   arc_detail_(4),
   simple_va_()
@@ -46,11 +47,11 @@ void PrimList::Clear()
   lines_.clear();
   spheres_.clear();
   cyls_.clear();
+  texts_.clear();
   Scene::Instance().RequestRedraw();
   this->FlagRebuild();
 }
 
-
 geom::AlignedCuboid PrimList::GetBoundingBox() const
 {
   if(points_.empty() && lines_.empty() && spheres_.empty() && cyls_.empty()) {
@@ -69,31 +70,36 @@ geom::AlignedCuboid PrimList::GetBoundingBox() const
 void PrimList::ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, 
                              const mol::Transform& tf) const
 {
-  for(PointEntryList::const_iterator it=points_.begin();it!=points_.end();++it) {
-    geom::Vec3 tpos = tf.Apply(it->pos);
+  for(SpherePrimList::const_iterator it=points_.begin();it!=points_.end();++it) {
+    geom::Vec3 tpos = tf.Apply(it->position);
     minc=geom::Min(minc,tpos);
     maxc=geom::Max(maxc,tpos);
   }
-  for(LineEntryList::const_iterator it=lines_.begin();it!=lines_.end();++it) {
-    geom::Vec3 tpos = tf.Apply(it->pos1);
+  for(CylinderPrimList::const_iterator it=lines_.begin();it!=lines_.end();++it) {
+    geom::Vec3 tpos = tf.Apply(it->start);
     minc=geom::Min(minc,tpos);
     maxc=geom::Max(maxc,tpos);
-    tpos = tf.Apply(it->pos2);
+    tpos = tf.Apply(it->end);
     minc=geom::Min(minc,tpos);
     maxc=geom::Max(maxc,tpos);
   }
-  for(PointEntryList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) {
-    geom::Vec3 tpos = tf.Apply(it->pos);
-    minc=geom::Min(minc,tpos-it->rad);
-    maxc=geom::Max(maxc,tpos+it->rad);
+  for(SpherePrimList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) {
+    geom::Vec3 tpos = tf.Apply(it->position);
+    minc=geom::Min(minc,tpos-it->radius);
+    maxc=geom::Max(maxc,tpos+it->radius);
+  }
+  for(CylinderPrimList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) {
+    geom::Vec3 tpos = tf.Apply(it->start);
+    minc=geom::Min(minc,tpos-it->radius1);
+    maxc=geom::Max(maxc,tpos+it->radius1);
+    tpos = tf.Apply(it->end);
+    minc=geom::Min(minc,tpos-it->radius2);
+    maxc=geom::Max(maxc,tpos+it->radius2);
   }
-  for(LineEntryList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) {
-    geom::Vec3 tpos = tf.Apply(it->pos1);
-    minc=geom::Min(minc,tpos-it->rad1);
-    maxc=geom::Max(maxc,tpos+it->rad1);
-    tpos = tf.Apply(it->pos2);
-    minc=geom::Min(minc,tpos-it->rad2);
-    maxc=geom::Max(maxc,tpos+it->rad2);
+  for(TextPrimList::const_iterator it=texts_.begin();it!=texts_.end();++it) {
+    geom::Vec3 tpos = tf.Apply(it->position);
+    minc=geom::Min(minc,tpos);
+    maxc=geom::Max(maxc,tpos);
   }
   minc-=1.0;
   maxc+=1.0;
@@ -103,22 +109,26 @@ geom::Vec3 PrimList::GetCenter() const
 {
   geom::Vec3 cen;
   size_t sum=0;
-  for(PointEntryList::const_iterator it=points_.begin();it!=points_.end();++it) {
-    cen+=it->pos;
+  for(SpherePrimList::const_iterator it=points_.begin();it!=points_.end();++it) {
+    cen+=it->position;
   }
   sum+=points_.size();
-  for(LineEntryList::const_iterator it=lines_.begin();it!=lines_.end();++it) {
-    cen+=0.5*(it->pos1+it->pos2);
+  for(CylinderPrimList::const_iterator it=lines_.begin();it!=lines_.end();++it) {
+    cen+=0.5*(it->start+it->end);
   }
   sum+=lines_.size();
-  for(PointEntryList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) {
-    cen+=it->pos;
+  for(SpherePrimList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) {
+    cen+=it->position;
   }
   sum+=spheres_.size();
-  for(LineEntryList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) {
-    cen+=0.5*(it->pos1+it->pos2);
+  for(CylinderPrimList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) {
+    cen+=0.5*(it->start+it->end);
   }
   sum+=cyls_.size();
+  for(TextPrimList::const_iterator it=texts_.begin();it!=texts_.end();++it) {
+    cen+=it->position;
+  }
+  sum+=texts_.size();
   if(sum>0) {
     cen/=static_cast<float>(sum);
   }
@@ -141,6 +151,7 @@ void PrimList::CustomRenderGL(RenderPass pass)
   if(pass==STANDARD_RENDER_PASS || pass==TRANSPARENT_RENDER_PASS) {
     va_.RenderGL();
     simple_va_.RenderGL();
+    render_text();
   }
 }
 
@@ -149,49 +160,57 @@ void PrimList::CustomRenderPov(PovState& pov)
   if(points_.empty() && lines_.empty()) return;
   pov.write_merge_or_union(GetName());
 
-  for(PointEntryList::const_iterator it=points_.begin();it!=points_.end();++it) {
-    pov.write_sphere(it->pos,0.1,it->col,GetName());
+  for(SpherePrimList::const_iterator it=points_.begin();it!=points_.end();++it) {
+    pov.write_sphere(it->position,0.1,it->color,GetName());
   }
-  for(LineEntryList::const_iterator it=lines_.begin();it!=lines_.end();++it) {
-    pov.write_sphere(it->pos1,0.1,it->col1,GetName());
-    pov.write_sphere(it->pos2,0.1,it->col2,GetName());
-    pov.write_cyl(it->pos1,it->pos2,0.1,it->col1,GetName(),true);
+  for(CylinderPrimList::const_iterator it=lines_.begin();it!=lines_.end();++it) {
+    pov.write_sphere(it->start,0.1,it->color1,GetName());
+    pov.write_sphere(it->end,0.1,it->color2,GetName());
+    pov.write_cyl(it->start,it->end,0.1,it->color1,GetName(),true);
   }
-  for(PointEntryList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) {
-    pov.write_sphere(it->pos,it->rad,it->col,GetName());
+  for(SpherePrimList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) {
+    pov.write_sphere(it->position,it->radius,it->color,GetName());
   }
-  for(LineEntryList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) {
-    pov.write_sphere(it->pos1,it->rad1,it->col1,GetName());
-    pov.write_sphere(it->pos2,it->rad2,it->col2,GetName());
-    pov.write_cyl(it->pos1,it->pos2,it->rad1,it->col1,GetName(),true);
+  for(CylinderPrimList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) {
+    pov.write_sphere(it->start,it->radius1,it->color1,GetName());
+    pov.write_sphere(it->end,it->radius2,it->color2,GetName());
+    pov.write_cyl(it->start,it->end,it->radius1,it->color1,GetName(),true);
   }
+  // TODO text
   pov.inc() << " }\n";
 }
 
 void PrimList::AddPoint(const geom::Vec3& p, const Color& col)
 {
-  points_.push_back(PointEntry(p, 0.0, col));
+  points_.push_back(SpherePrim(p, 0.0, col));
   Scene::Instance().RequestRedraw();
   FlagRebuild();
 }
 
 void PrimList::AddLine(const geom::Vec3& p1, const geom::Vec3& p2, const Color& col1, const Color& col2)
 {
-  lines_.push_back(LineEntry(p1,p2,0.0,0.0,col1,col2));
+  lines_.push_back(CylinderPrim(p1,p2,0.0,0.0,col1,col2));
   Scene::Instance().RequestRedraw();
   FlagRebuild();
 }
 
 void PrimList::AddSphere(const geom::Vec3& c, float r, const Color& col)
 {
-  spheres_.push_back(PointEntry(c, r, col));
+  spheres_.push_back(SpherePrim(c, r, col));
   Scene::Instance().RequestRedraw();
   FlagRebuild();
 }
 
 void PrimList::AddCyl(const geom::Vec3& p1, const geom::Vec3& p2, float r1, float r2, const Color& col1, const Color& col2)
 {
-  cyls_.push_back(LineEntry(p1, p2, r1, r2, col1, col2));
+  cyls_.push_back(CylinderPrim(p1, p2, r1, r2, col1, col2));
+  Scene::Instance().RequestRedraw();
+  FlagRebuild();
+}
+
+void PrimList::AddText(const std::string& text, const geom::Vec3& pos, const Color& col, float point_size)
+{
+  texts_.push_back(TextPrim(text,pos,col,point_size));
   Scene::Instance().RequestRedraw();
   FlagRebuild();
 }
@@ -222,19 +241,22 @@ void PrimList::SetArcDetail(unsigned int d)
 
 void PrimList::SetColor(const Color& c)
 {
-  for(PointEntryList::iterator it=points_.begin();it!=points_.end();++it) {
-    it->col=c;
+  for(SpherePrimList::iterator it=points_.begin();it!=points_.end();++it) {
+    it->color=c;
   }
-  for(LineEntryList::iterator it=lines_.begin();it!=lines_.end();++it) {
-    it->col1=c;
-    it->col2=c;
+  for(CylinderPrimList::iterator it=lines_.begin();it!=lines_.end();++it) {
+    it->color1=c;
+    it->color2=c;
   }
-  for(PointEntryList::iterator it=spheres_.begin();it!=spheres_.end();++it) {
-    it->col=c;
+  for(SpherePrimList::iterator it=spheres_.begin();it!=spheres_.end();++it) {
+    it->color=c;
   }
-  for(LineEntryList::iterator it=cyls_.begin();it!=cyls_.end();++it) {
-    it->col1=c;
-    it->col2=c;
+  for(CylinderPrimList::iterator it=cyls_.begin();it!=cyls_.end();++it) {
+    it->color1=c;
+    it->color2=c;
+  }
+  for(TextPrimList::iterator it=texts_.begin();it!=texts_.end();++it) {
+    it->color=c;
   }
   Scene::Instance().RequestRedraw();
   FlagRebuild();
@@ -255,13 +277,13 @@ void PrimList::prep_simple_va()
   simple_va_.SetAALines(GetAALines());
   simple_va_.SetOpacity(GetOpacity());
 
-  for(PointEntryList::const_iterator it=points_.begin();it!=points_.end();++it) {
-    simple_va_.Add(it->pos,geom::Vec3(),it->col);
+  for(SpherePrimList::const_iterator it=points_.begin();it!=points_.end();++it) {
+    simple_va_.Add(it->position,geom::Vec3(),it->color);
   }
 
-  for(LineEntryList::const_iterator it=lines_.begin();it!=lines_.end();++it) {
-    VertexID id0 = simple_va_.Add(it->pos1,geom::Vec3(),it->col1);
-    VertexID id1 = simple_va_.Add(it->pos2,geom::Vec3(),it->col2);
+  for(CylinderPrimList::const_iterator it=lines_.begin();it!=lines_.end();++it) {
+    VertexID id0 = simple_va_.Add(it->start,geom::Vec3(),it->color1);
+    VertexID id1 = simple_va_.Add(it->end,geom::Vec3(),it->color2);
     simple_va_.AddLine(id0,id1);
   }
 }
@@ -274,16 +296,23 @@ void PrimList::prep_va()
   va_.SetColorMaterial(true);
   va_.SetMode(0x4);
 
-  for(PointEntryList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) {
-    va_.AddSphere(SpherePrim(it->pos, it->rad, it->col), 
+  for(SpherePrimList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) {
+    va_.AddSphere(SpherePrim(it->position, it->radius, it->color), 
                   GetSphereDetail());
   }
 
-  for(LineEntryList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) {
-    va_.AddCylinder(CylinderPrim(it->pos1, it->pos2, it->rad1, it->rad2, it->col1, it->col2),
+  for(CylinderPrimList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) {
+    va_.AddCylinder(CylinderPrim(it->start, it->end, it->radius1, it->radius2, it->color1, it->color2),
                     GetArcDetail(),
                     true);
   }
 }
 
+void PrimList::render_text()
+{
+  for(TextPrimList::const_iterator it=texts_.begin();it!=texts_.end();++it) {
+    Scene::Instance().RenderText(*it);
+  }
+}
+
 }} // ns
diff --git a/modules/gfx/src/prim_list.hh b/modules/gfx/src/prim_list.hh
index bf8fb98ed8ea345c97b408b96d782d609282bc41..4e8a4c297ea044eda07d2cc199a4988b3d7e4e23 100644
--- a/modules/gfx/src/prim_list.hh
+++ b/modules/gfx/src/prim_list.hh
@@ -27,14 +27,11 @@
 
 #include <ost/geom/geom.hh>
 
-#include "gfx.hh"
+#include "gfx_object.hh"
+#include "gfx_prim.hh"
 
 namespace ost { namespace gfx {
 
-class PrimList;
-
-typedef boost::shared_ptr<PrimList> PrimListP;
-
 /// \see gfx::Cuboid, \ref primitives.py "Displaying Lines and Quads",
 ///      gfx::Quad, \ref gradient.py "Gradient Example",
 ///      \ref random_lines.py "Random Lines"
@@ -94,7 +91,7 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj
 
     Python interface:
 
-    PrimList.AddLine(pos1,pos2,col=gfx.WHITE,col1=gfx.WHITE,col2=gfx.WHITE)
+    PrimList.AddLine(pos1,pos2,color=gfx.WHITE,color1=gfx.WHITE,color2=gfx.WHITE)
   */
   void AddLine(const geom::Vec3& p1, const geom::Vec3& p2, const Color& col1, const Color& col2);
 
@@ -103,7 +100,7 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj
 
     Python interface:
 
-    PrimList.AddSphere(cen,rad,col=gfx.WHITE)
+    PrimList.AddSphere(cen,radius=1.0,color=gfx.WHITE)
   */
   void AddSphere(const geom::Vec3& cen, float rad, const Color& col);
 
@@ -112,10 +109,19 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj
 
     Python interface:
 
-    PrimList.AddCyl(pos1,pos2,rad=1.0,rad1=1.0,rad2=1.0,col=gfx.WHITE,col1=gfx.WHITE,col2=gfx.WHITE)
+    PrimList.AddCyl(pos1,pos2,radius=1.0,radius1=1.0,radius2=1.0,color=gfx.WHITE,color1=gfx.WHITE,color2=gfx.WHITE)
   */
   void AddCyl(const geom::Vec3& p0, const geom::Vec3& p1, float r1, float r2, const Color& col1, const Color& col2);
 
+  /*!
+    \brief add text
+
+    Python interface:
+
+    PrimList.AddText(text,pos,color=gfx.WHITE,point_size=1.0)
+  */
+  void AddText(const std::string& text, const geom::Vec3& pos, const Color& col, float point_size);
+
   /// defunct
   void SetDiameter(float d);
   
@@ -137,10 +143,11 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj
   virtual void CustomPreRenderGL(bool flag);
 
  private:
-  PointEntryList points_;
-  LineEntryList lines_;
-  PointEntryList spheres_;
-  LineEntryList cyls_;
+  SpherePrimList points_;
+  CylinderPrimList lines_;
+  SpherePrimList spheres_;
+  CylinderPrimList cyls_;
+  TextPrimList texts_;
   unsigned int sphere_detail_;
   unsigned int arc_detail_;
 
@@ -148,6 +155,7 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj
   
   void prep_simple_va();
   void prep_va();
+  void render_text();
 };
 
 /// \example primitives.py
diff --git a/modules/gfx/tests/test_primlist.py b/modules/gfx/tests/test_primlist.py
index 82fd4a376e284e0526b5f79fb28af5df300349f2..55660f9554a958c8fbf1ee09cf8fb5a2e868f462 100644
--- a/modules/gfx/tests/test_primlist.py
+++ b/modules/gfx/tests/test_primlist.py
@@ -14,13 +14,15 @@ class TestPrimList(unittest.TestCase):
   def test_(self):
     pl=ost.gfx.PrimList("foo")
     pl.AddPoint([0,0,0])
-    pl.AddPoint(ost.geom.Vec3(1,2,3),col=ost.gfx.RED)
+    pl.AddPoint(ost.geom.Vec3(1,2,3),color=ost.gfx.RED)
     pl.AddLine([0,0,0],[1,2,3])
-    pl.AddLine(ost.geom.Vec3(0,0,0),ost.geom.Vec3(1,2,3),col=ost.gfx.BLUE)
-    pl.AddSphere([0,0,0],rad=2.0)
-    pl.AddSphere(ost.geom.Vec3(1,2,3),col=ost.gfx.RED,rad=3.0)
-    pl.AddCyl([0,0,0],[1,2,3],rad=0.5,col=ost.gfx.YELLOW)
-    pl.AddCyl(ost.geom.Vec3(0,0,0),ost.geom.Vec3(1,2,3),rad1=0.5,rad2=0.1,col1=ost.gfx.BLUE,col2=ost.gfx.GREEN)
+    pl.AddLine(ost.geom.Vec3(0,0,0),ost.geom.Vec3(1,2,3),color=ost.gfx.BLUE)
+    pl.AddSphere([0,0,0],radius=2.0)
+    pl.AddSphere(ost.geom.Vec3(1,2,3),color=ost.gfx.RED,radius=3.0)
+    pl.AddCyl([0,0,0],[1,2,3],radius=0.5,color=ost.gfx.YELLOW)
+    pl.AddCyl(ost.geom.Vec3(0,0,0),ost.geom.Vec3(1,2,3),radius1=0.5,radius2=0.1,color1=ost.gfx.BLUE,color2=ost.gfx.GREEN)
+    pl.AddText("foo",[0,2,3])
+    pl.AddText("bar",[-2,0,0],color=gfx.WHITE,point_size=8)
 
 if __name__== '__main__':
   unittest.main()