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)