From 45fa8787e5723033295e223cce0a6df6daaebc9b Mon Sep 17 00:00:00 2001 From: Ansgar Philippsen <ansgar.philippsen@gmail.com> Date: Tue, 12 Jul 2011 20:57:12 -0400 Subject: [PATCH] revamped gfx PrimList PrimList now contains four specific rendering primitives: points, lines, spheres and cylinders; lines and cylinders accept two different colors for each endpoint, and cylinders support two different radii for their ends. The rendering mode no longer has any effect, also, it is no longer possible to change the radius of spheres and cylinders once they are added. The python interface is much more sophisticated, using named arguments for optional parameters. The low-level cylinder routine in IndexedVertexArray was adjusted accordingly --- modules/gfx/pymod/CMakeLists.txt | 1 + modules/gfx/pymod/__init__.py | 62 ++++++++- modules/gfx/pymod/export_primlist.cc | 39 ++++++ modules/gfx/pymod/wrap_gfx.cc | 11 +- modules/gfx/src/gfx_prim.hh | 36 ++++- modules/gfx/src/prim_list.cc | 191 ++++++++++++++++----------- modules/gfx/src/prim_list.hh | 82 ++++++++---- modules/gfx/src/vertex_array.cc | 30 +++-- modules/gfx/tests/CMakeLists.txt | 1 + modules/gfx/tests/test_primlist.py | 27 ++++ 10 files changed, 346 insertions(+), 134 deletions(-) create mode 100644 modules/gfx/pymod/export_primlist.cc create mode 100644 modules/gfx/tests/test_primlist.py diff --git a/modules/gfx/pymod/CMakeLists.txt b/modules/gfx/pymod/CMakeLists.txt index f77be27fc..0fcc9a8ed 100644 --- a/modules/gfx/pymod/CMakeLists.txt +++ b/modules/gfx/pymod/CMakeLists.txt @@ -7,6 +7,7 @@ set(OST_GFX_PYMOD_SOURCES export_entity.cc export_surface.cc export_primitives.cc + export_primlist.cc export_scene_observer.cc export_render_options.cc export_color_ops.cc diff --git a/modules/gfx/pymod/__init__.py b/modules/gfx/pymod/__init__.py index e9276ead1..8fbbedeaf 100644 --- a/modules/gfx/pymod/__init__.py +++ b/modules/gfx/pymod/__init__.py @@ -59,11 +59,11 @@ def Stereo(mode,flip=None,alg=None): :type param: int """ if(flip): - _gfx.Scene().SetStereoFlip(flip) + Scene().SetStereoFlip(flip) if(alg): - _gfx.Scene().SetStereoAlg(alg) + Scene().SetStereoAlg(alg) - _gfx.Scene().SetStereoMode(mode) + Scene().SetStereoMode(mode) def FitToScreen(gfx_ent, width=None, height=None, margin=0.05): """ @@ -184,3 +184,59 @@ def _Match(scene, pattern="*"): return GfxNodeListProxy(_Recurse("", Scene().root_node, pattern)) SceneSingleton.Match=_Match + +def _to_vec3(p): + import ost.geom + if isinstance(p,ost.geom.Vec3): + return p + else: + try: + return ost.geom.Vec3(p[0],p[1],p[2]) + except: + raise TypeError("expected either a sequence or a geom.Vec3 object") + + +def _primlist_add_point(self,pos,col=None): + pos=_to_vec3(pos) + if not col: + col=WHITE + self._add_point(pos,col) + +def _primlist_add_line(self,pos1,pos2,col=None,col1=None,col2=None): + pos1=_to_vec3(pos1) + pos2=_to_vec3(pos2) + if not col: + col=WHITE + if not col1: + col1=col + if not col2: + col2=col + self._add_line(pos1,pos2,col1,col2) + +def _primlist_add_sphere(self,cen,rad=1.0,col=None): + pos=_to_vec3(cen) + if not col: + col=WHITE + self._add_sphere(pos,rad,col) + +def _primlist_add_cyl(self,pos1,pos2,rad=None,rad1=None,rad2=None,col=None,col1=None,col2=None): + pos1=_to_vec3(pos1) + pos2=_to_vec3(pos2) + if rad is None: + rad=1.0 + if rad1 is None: + rad1=rad + if rad2 is None: + rad2=rad + if not col: + col=WHITE + if not col1: + col1=col + if not col2: + col2=col + self._add_cyl(pos1,pos2,rad1,rad2,col1,col2) + +PrimList.AddPoint=_primlist_add_point +PrimList.AddLine=_primlist_add_line +PrimList.AddSphere=_primlist_add_sphere +PrimList.AddCyl=_primlist_add_cyl diff --git a/modules/gfx/pymod/export_primlist.cc b/modules/gfx/pymod/export_primlist.cc new file mode 100644 index 000000000..1456d157e --- /dev/null +++ b/modules/gfx/pymod/export_primlist.cc @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------------ +// This file is part of the OpenStructure project <www.openstructure.org> +// +// Copyright (C) 2008-2011 by the OpenStructure authors +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation; either version 3.0 of the License, or (at your option) +// any later version. +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +//------------------------------------------------------------------------------ +#include <boost/python.hpp> +using namespace boost::python; + +#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& >()) + .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("SetColor",&PrimList::SetColor) + .def("SetDiameter",&PrimList::SetDiameter) + .def("SetRadius",&PrimList::SetRadius) + ; + +} diff --git a/modules/gfx/pymod/wrap_gfx.cc b/modules/gfx/pymod/wrap_gfx.cc index c6b37a25b..4be1d63f2 100644 --- a/modules/gfx/pymod/wrap_gfx.cc +++ b/modules/gfx/pymod/wrap_gfx.cc @@ -34,6 +34,7 @@ extern void export_GfxNode(); extern void export_GfxObj(); extern void export_Entity(); extern void export_Surface(); +extern void export_primlist(); extern void export_primitives(); #if OST_IMG_ENABLED extern void export_Map(); @@ -134,17 +135,8 @@ BOOST_PYTHON_MODULE(_ost_gfx) class_<InputEvent>("InputEvent", init<InputDevice, InputCommand, float>()) .def(init<InputDevice,InputCommand,int,int,float>()) ; - class_<PrimList, bases<GfxObj>, PrimListP, boost::noncopyable>("PrimList", init<const String& >()) - .def("Clear",&PrimList::Clear) - .def("AddLine",&PrimList::AddLine) - .def("AddPoint",&PrimList::AddPoint) - .def("SetColor",&PrimList::SetColor) - .def("SetDiameter",&PrimList::SetDiameter) - .def("SetRadius",&PrimList::SetRadius) - ; class_<GfxTestObj, bases<GfxObj>, boost::noncopyable>("GfxTestObj", init<>()); - class_<Color>("Color",init<>()) .def(init<float, float, float, optional<float> >()) @@ -189,6 +181,7 @@ BOOST_PYTHON_MODULE(_ost_gfx) #endif export_primitives(); + export_primlist(); } diff --git a/modules/gfx/src/gfx_prim.hh b/modules/gfx/src/gfx_prim.hh index c88a92368..d3b97cec8 100644 --- a/modules/gfx/src/gfx_prim.hh +++ b/modules/gfx/src/gfx_prim.hh @@ -48,19 +48,46 @@ typedef std::vector<SpherePrim> SpherePrimList; struct CylinderPrim { CylinderPrim(): - start(),end(),radius(1.0),color1(),color2(),length(1.0),rotmat(),rotmat_t() + start(), end(), + radius1(1.0), radius2(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),color1(col),color2(col),length(geom::Length(end-start)),rotmat(),rotmat_t() + start(st), end(en), + radius1(rad), radius2(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() + start(st), end(en), + radius1(rad), radius2(rad), + color1(col1), color2(col2), + length(geom::Length(end-start)), rotmat(), rotmat_t() + { + calc_rotmat(); + } + + CylinderPrim(const geom::Vec3& st, const geom::Vec3& en, float rad1, float rad2, const Color& col): + start(st), end(en), + radius1(rad1), radius2(rad2), + color1(col), color2(col), + length(geom::Length(end-start)), rotmat(), rotmat_t() + { + calc_rotmat(); + } + + CylinderPrim(const geom::Vec3& st, const geom::Vec3& en, float rad1, float rad2, const Color& col1, const Color& col2): + start(st), end(en), + radius1(rad1), radius2(rad2), + color1(col1), color2(col2), + length(geom::Length(end-start)), rotmat(), rotmat_t() { calc_rotmat(); } @@ -68,7 +95,7 @@ struct CylinderPrim { void calc_rotmat(); geom::Vec3 start,end; - float radius; + float radius1,radius2; Color color1, color2; float length; geom::Mat3 rotmat; @@ -77,7 +104,6 @@ struct CylinderPrim { typedef std::vector<CylinderPrim> CylinderPrimList; - struct TextPrim { TextPrim(): str(""), position(),color(),points(1.0) {} TextPrim(const String& s, const geom::Vec3& p, const Color& c, float ps): diff --git a/modules/gfx/src/prim_list.cc b/modules/gfx/src/prim_list.cc index 5486ccaed..95ed64cfb 100644 --- a/modules/gfx/src/prim_list.cc +++ b/modules/gfx/src/prim_list.cc @@ -33,19 +33,36 @@ PrimList::PrimList(const String& name): GfxObj(name), points_(), lines_(), - radius_(0.5), + spheres_(), + cyls_(), sphere_detail_(4), - arc_detail_(4) + arc_detail_(4), + simple_va_() {} void PrimList::Clear() { points_.clear(); lines_.clear(); + spheres_.clear(); + cyls_.clear(); Scene::Instance().RequestRedraw(); this->FlagRebuild(); } + +geom::AlignedCuboid PrimList::GetBoundingBox() const +{ + 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()); + ProcessLimits(minc,maxc,mol::Transform()); + return geom::AlignedCuboid(minc,maxc); +} + void PrimList::ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, const mol::Transform& tf) const { @@ -62,6 +79,19 @@ void PrimList::ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, 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); + maxc=geom::Max(maxc,tpos); + } + for(LineEntryList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) { + geom::Vec3 tpos = tf.Apply(it->pos1); + minc=geom::Min(minc,tpos); + maxc=geom::Max(maxc,tpos); + tpos = tf.Apply(it->pos2); + minc=geom::Min(minc,tpos); + maxc=geom::Max(maxc,tpos); + } minc-=1.0; maxc+=1.0; } @@ -69,71 +99,45 @@ void PrimList::ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, 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; } + sum+=points_.size(); for(LineEntryList::const_iterator it=lines_.begin();it!=lines_.end();++it) { cen+=0.5*(it->pos1+it->pos2); } - if(!lines_.empty() || !points_.empty()) { - cen/=static_cast<float>(points_.size()+lines_.size()); + sum+=lines_.size(); + for(PointEntryList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) { + cen+=it->pos; + } + sum+=spheres_.size(); + for(LineEntryList::const_iterator it=cyls_.begin();it!=cyls_.end();++it) { + cen+=0.5*(it->pos1+it->pos2); + } + sum+=cyls_.size(); + if(sum>0) { + cen/=static_cast<float>(sum); } return cen; } void PrimList::OnRenderModeChange() { - if(GetRenderMode()==RenderMode::CUSTOM) { - render_custom(); - } else { - render_simple(); - } - // this does not work - //GfxObj::OnRenderModeChange(); + // noop } void PrimList::CustomPreRenderGL(bool flag) { - if(flag) { - if(GetRenderMode()==RenderMode::CUSTOM) { - render_custom(); - } else { - render_simple(); - } - } -} - -namespace { - -struct AALineEntry { - float p0[3],p1[3]; - float edge0[3],edge1[3],edge2[3],edge3[3]; - float color[4]; - float z; -}; - -geom::Vec3 make_edge(const geom::Vec2& c1, const geom::Vec2& c0, float s) -{ - geom::Vec3 nrvo(c1[1]-c0[1],c0[0]-c1[0],c1[0]*c0[1]-c0[0]*c1[1]); - nrvo*=1.0/(s*Length(c1-c0)); - return nrvo; -} - -struct AALineEntryLess -{ - bool operator()(const AALineEntry& e1, const AALineEntry& e2) - { - // provides back-to-front sorting - return e1.z<e2.z; - } -}; - + prep_va(); + prep_simple_va(); } void PrimList::CustomRenderGL(RenderPass pass) { if(pass==STANDARD_RENDER_PASS || pass==TRANSPARENT_RENDER_PASS) { va_.RenderGL(); + simple_va_.RenderGL(); } } @@ -143,44 +147,62 @@ void PrimList::CustomRenderPov(PovState& pov) pov.write_merge_or_union(GetName()); for(PointEntryList::const_iterator it=points_.begin();it!=points_.end();++it) { - pov.write_sphere(it->pos,radius_,it->color,GetName()); + pov.write_sphere(it->pos,0.1,it->col,GetName()); } for(LineEntryList::const_iterator it=lines_.begin();it!=lines_.end();++it) { - pov.write_sphere(it->pos1,radius_,it->color,GetName()); - pov.write_sphere(it->pos2,radius_,it->color,GetName()); - pov.write_cyl(it->pos1,it->pos2,radius_,it->color,GetName(),true); + 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(PointEntryList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) { + pov.write_sphere(it->pos,it->rad,it->col,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); } pov.inc() << " }\n"; } -void PrimList::AddPoint(geom::Vec3& p, const Color& col) +void PrimList::AddPoint(const geom::Vec3& p, const Color& col) { - points_.push_back(PointEntry(p,col)); + points_.push_back(PointEntry(p, 0.0, col)); Scene::Instance().RequestRedraw(); FlagRebuild(); } -void PrimList::AddLine(geom::Vec3& p1, geom::Vec3& p2, const Color& col) +void PrimList::AddLine(const geom::Vec3& p1, const geom::Vec3& p2, const Color& col1, const Color& col2) { - lines_.push_back(LineEntry(p1,p2,col)); + lines_.push_back(LineEntry(p1,p2,0.0,0.0,col1,col2)); Scene::Instance().RequestRedraw(); FlagRebuild(); } -void PrimList::SetDiameter(float d) +void PrimList::AddSphere(const geom::Vec3& c, float r, const Color& col) { - radius_=d*0.5; + spheres_.push_back(PointEntry(c, r, col)); Scene::Instance().RequestRedraw(); FlagRebuild(); } -void PrimList::SetRadius(float r) +void PrimList::AddCyl(const geom::Vec3& p1, const geom::Vec3& p2, float r1, float r2, const Color& col1, const Color& col2) { - radius_=r; + cyls_.push_back(LineEntry(p1, p2, r1, r2, col1, col2)); Scene::Instance().RequestRedraw(); FlagRebuild(); } +void PrimList::SetDiameter(float d) +{ + LOG_WARNING("PrimList::SetDiameter is defunct"); +} + +void PrimList::SetRadius(float r) +{ + LOG_WARNING("PrimList::SetDiameter is defunct"); +} + void PrimList::SetSphereDetail(unsigned int d) { sphere_detail_=d; @@ -197,8 +219,19 @@ 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(LineEntryList::iterator it=lines_.begin();it!=lines_.end();++it) { - it->color=c; + it->col1=c; + it->col2=c; + } + for(PointEntryList::iterator it=spheres_.begin();it!=spheres_.end();++it) { + it->col=c; + } + for(LineEntryList::iterator it=cyls_.begin();it!=cyls_.end();++it) { + it->col1=c; + it->col2=c; } Scene::Instance().RequestRedraw(); FlagRebuild(); @@ -208,28 +241,29 @@ void PrimList::SetColor(const Color& c) //////////////////////////////// // private methods -void PrimList::render_simple() +void PrimList::prep_simple_va() { - va_.Clear(); - va_.SetLighting(false); - va_.SetCullFace(false); - va_.SetColorMaterial(false); - va_.SetMode(0x3); - va_.SetTwoSided(true); - va_.SetAALines(GetAALines()); + simple_va_.Clear(); + simple_va_.SetLighting(false); + simple_va_.SetCullFace(false); + simple_va_.SetColorMaterial(false); + simple_va_.SetMode(0x3); + simple_va_.SetTwoSided(true); + simple_va_.SetAALines(GetAALines()); + simple_va_.SetOpacity(GetOpacity()); for(PointEntryList::const_iterator it=points_.begin();it!=points_.end();++it) { - va_.Add(it->pos,geom::Vec3(),it->color); + simple_va_.Add(it->pos,geom::Vec3(),it->col); } for(LineEntryList::const_iterator it=lines_.begin();it!=lines_.end();++it) { - VertexID id0 = va_.Add(it->pos1,geom::Vec3(),it->color); - VertexID id1 = va_.Add(it->pos2,geom::Vec3(),it->color); - va_.AddLine(id0,id1); + VertexID id0 = simple_va_.Add(it->pos1,geom::Vec3(),it->col1); + VertexID id1 = simple_va_.Add(it->pos2,geom::Vec3(),it->col2); + simple_va_.AddLine(id0,id1); } } -void PrimList::render_custom() +void PrimList::prep_va() { va_.Clear(); va_.SetLighting(true); @@ -237,18 +271,15 @@ void PrimList::render_custom() va_.SetColorMaterial(true); va_.SetMode(0x4); - for(PointEntryList::const_iterator it=points_.begin();it!=points_.end();++it) { - va_.AddSphere(SpherePrim(it->pos, radius_, it->color), + for(PointEntryList::const_iterator it=spheres_.begin();it!=spheres_.end();++it) { + va_.AddSphere(SpherePrim(it->pos, it->rad, it->col), GetSphereDetail()); } - for(LineEntryList::const_iterator it=lines_.begin();it!=lines_.end();++it) { - va_.AddSphere(SpherePrim(it->pos1, radius_, it->color), - GetSphereDetail()); - va_.AddSphere(SpherePrim(it->pos2, radius_, it->color), - GetSphereDetail()); - va_.AddCylinder(CylinderPrim(it->pos1,it->pos2,radius_,it->color), - GetArcDetail()); + 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), + GetArcDetail(), + true); } } diff --git a/modules/gfx/src/prim_list.hh b/modules/gfx/src/prim_list.hh index daba0e7e5..bf8fb98ed 100644 --- a/modules/gfx/src/prim_list.hh +++ b/modules/gfx/src/prim_list.hh @@ -35,33 +35,27 @@ class PrimList; typedef boost::shared_ptr<PrimList> PrimListP; -/// \brief rudimentary graphical lines rendering. -/// -/// The primitives may be rendered either with gfx::RenderMode::SIMPLE or -/// gfx::RenderMode::CUSTOM. The render mode can be changed with -/// GfxObj::SetRenderMode(). -/// /// \see gfx::Cuboid, \ref primitives.py "Displaying Lines and Quads", /// gfx::Quad, \ref gradient.py "Gradient Example", /// \ref random_lines.py "Random Lines" class DLLEXPORT_OST_GFX PrimList: public GfxObj { struct PointEntry { - PointEntry(const geom::Vec3& p, const Color& c): - pos(p), color(c) {} + PointEntry(const geom::Vec3& p, float r, const Color& c): + pos(p), rad(r), col(c) {} geom::Vec3 pos; - Color color; - geom::Mat3 rotmat; + float rad; + Color col; }; typedef std::vector<PointEntry> PointEntryList; struct LineEntry { - LineEntry(const geom::Vec3& p1, const geom::Vec3& p2, const Color& c): - pos1(p1), pos2(p2), color(c) {} - geom::Vec3 pos1,pos2; - Color color; - geom::Mat3 rotmat; + LineEntry(const geom::Vec3& p1, const geom::Vec3& p2, float r1, float r2, const Color& c1, const Color& c2): + pos1(p1), pos2(p2), rad1(r1), rad2(r2), col1(c1), col2(c2) {} + geom::Vec3 pos1, pos2; + float rad1, rad2; + Color col1, col2; }; typedef std::vector<LineEntry> LineEntryList; @@ -70,6 +64,8 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj /// \brief create new prim list PrimList(const String& name); + virtual geom::AlignedCuboid GetBoundingBox() const; + virtual void ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc, const mol::Transform& tf) const; /// \brief get center @@ -81,19 +77,49 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj virtual void OnRenderModeChange(); - /// \brief clear all prims + /// \brief clear all prims void Clear(); - /// \brief add line as defined by two endpoints - void AddPoint(geom::Vec3& p, const Color& col=Color()); + /*! + \brief add point + + python interface: + + PrimList.AddPoint(pos, color=gfx.Color()) + */ + void AddPoint(const geom::Vec3& p, const Color& col); + + /*! + \brief add line + + Python interface: + + PrimList.AddLine(pos1,pos2,col=gfx.WHITE,col1=gfx.WHITE,col2=gfx.WHITE) + */ + void AddLine(const geom::Vec3& p1, const geom::Vec3& p2, const Color& col1, const Color& col2); - /// \brief add line as defined by two endpoints - void AddLine(geom::Vec3& p1, geom::Vec3& p2, const Color& col=Color()); + /*! + \brief add sphere - /// \brief cylinder diameter for custom rendering mode + Python interface: + + PrimList.AddSphere(cen,rad,col=gfx.WHITE) + */ + void AddSphere(const geom::Vec3& cen, float rad, const Color& col); + + /*! + \brief add cylinder + + Python interface: + + PrimList.AddCyl(pos1,pos2,rad=1.0,rad1=1.0,rad2=1.0,col=gfx.WHITE,col1=gfx.WHITE,col2=gfx.WHITE) + */ + void AddCyl(const geom::Vec3& p0, const geom::Vec3& p1, float r1, float r2, const Color& col1, const Color& col2); + + /// defunct void SetDiameter(float d); - /// \brief sphere radius for points in custom rendering mode + /// defunct void SetRadius(float r); /// \brief set global prims color, overriding individual ones @@ -105,19 +131,23 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj void SetArcDetail(unsigned int d); unsigned int GetArcDetail() const {return arc_detail_;} + // TODO: add point and line pixel width + protected: virtual void CustomPreRenderGL(bool flag); private: PointEntryList points_; LineEntryList lines_; - float radius_; - float diameter_; + PointEntryList spheres_; + LineEntryList cyls_; unsigned int sphere_detail_; unsigned int arc_detail_; + + IndexedVertexArray simple_va_; - void render_simple(); - void render_custom(); + void prep_simple_va(); + void prep_va(); }; /// \example primitives.py diff --git a/modules/gfx/src/vertex_array.cc b/modules/gfx/src/vertex_array.cc index da764f97f..ab6db586b 100644 --- a/modules/gfx/src/vertex_array.cc +++ b/modules/gfx/src/vertex_array.cc @@ -78,7 +78,7 @@ IndexedVertexArray::IndexedVertexArray() { initialized_=false; Reset(); // replaces ctor initialization list - glGenTextures(1,&tex_id_); + //glGenTextures(1,&tex_id_); } IndexedVertexArray::~IndexedVertexArray() @@ -88,7 +88,7 @@ IndexedVertexArray::~IndexedVertexArray() IndexedVertexArray::IndexedVertexArray(const IndexedVertexArray& va) { copy(va); - glGenTextures(1,&tex_id_); + //glGenTextures(1,&tex_id_); } IndexedVertexArray& IndexedVertexArray::operator=(const IndexedVertexArray& va) @@ -248,7 +248,7 @@ void IndexedVertexArray::AddIcoSphere(const SpherePrim& prim, unsigned int detai } } -void IndexedVertexArray::AddCylinder(const CylinderPrim& prim, unsigned int detail,bool cap) +void IndexedVertexArray::AddCylinder(const CylinderPrim& prim, unsigned int detail, bool cap) { dirty_=true; @@ -266,12 +266,19 @@ void IndexedVertexArray::AddCylinder(const CylinderPrim& prim, unsigned int deta // prepare first vertices to add std::vector<Vec3>::const_iterator it=vlist.begin(); Vec3 v0 = (*it); - Vec3 n0 = prim.rotmat * v0; - v0*=prim.radius; + bool slant=(prim.radius1!=prim.radius2); + // adjust for slant + float beta = slant ? atan2(prim.radius1-prim.radius2,prim.length) : 0.0; + float cosb = slant ? cos(beta) : 1.0; + float sinb = slant ? sin(beta) : 0.0; + Vec3 n0 = slant ? prim.rotmat * (cosb*v0+geom::Vec3(0.0,0.0,sinb)) : prim.rotmat*v0; + + v0*=prim.radius1; + Vec3 v1 = (*it)*prim.radius2+off; VertexID id1 = Add(prim.rotmat * v0 + prim.start, n0, prim.color1); - VertexID id2 = Add(prim.rotmat * (v0+off) + prim.start, n0, prim.color2); + VertexID id2 = Add(prim.rotmat * v1 + 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; + VertexID cid2 = cap ? Add(prim.rotmat * v1 + prim.start, cn1, prim.color2) : 0; // now for the loop around the circle VertexID id3=id1; @@ -281,15 +288,16 @@ void IndexedVertexArray::AddCylinder(const CylinderPrim& prim, unsigned int deta ++it; for(;it!=vlist.end();++it) { v0 = (*it); - n0 = prim.rotmat * v0; - v0 *= prim.radius; + Vec3 n0 = slant ? prim.rotmat * (cosb*v0+geom::Vec3(0.0,0.0,sinb)) : prim.rotmat*v0; + v0 *= prim.radius1; + Vec3 v1 = (*it)*prim.radius2+off; VertexID id5 = Add(prim.rotmat * v0 + prim.start, n0, prim.color1); - VertexID id6 = Add(prim.rotmat * (v0+off) + prim.start, n0, prim.color2); + VertexID id6 = Add(prim.rotmat * v1 + 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); + VertexID cid6 = Add(prim.rotmat * v1 + prim.start, cn1, prim.color2); AddTri(cid0,cid5,cid3); AddTri(cid7,cid4,cid6); cid3=cid5; diff --git a/modules/gfx/tests/CMakeLists.txt b/modules/gfx/tests/CMakeLists.txt index 469122e94..c87cf9183 100644 --- a/modules/gfx/tests/CMakeLists.txt +++ b/modules/gfx/tests/CMakeLists.txt @@ -1,6 +1,7 @@ set(OST_GFX_UNIT_TESTS tests.cc test_gfx_node.cc + test_primlist.py ) if (ENABLE_IMG) list(APPEND OST_GFX_UNIT_TESTS test_map_octree.cc) diff --git a/modules/gfx/tests/test_primlist.py b/modules/gfx/tests/test_primlist.py new file mode 100644 index 000000000..82fd4a376 --- /dev/null +++ b/modules/gfx/tests/test_primlist.py @@ -0,0 +1,27 @@ +import unittest +if __name__== '__main__': + import sys + sys.path.insert(0,"../../../stage/lib64/openstructure/") + +import ost +import ost.gfx +import ost.geom + +class TestPrimList(unittest.TestCase): + def setUp(self): + pass + + 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.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) + +if __name__== '__main__': + unittest.main() + -- GitLab