00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <vlMolecule/Molecule.hpp>
00033 #include <vlGraphics/GeometryPrimitives.hpp>
00034 #include <vlGraphics/Text.hpp>
00035 #include <vlGraphics/Light.hpp>
00036
00037 using namespace vl;
00038
00039
00040 class EffectCache
00041 {
00042 public:
00043 EffectCache(): mLight(new Light) {}
00044
00045 void clear() { effects().clear(); }
00046
00047 Effect* acquireEffect(const fvec4& color)
00048 {
00049 for(unsigned i=0; i<effects().size(); ++i)
00050 {
00051 if (effects()[i]->shader()->gocMaterial()->frontDiffuse() == color)
00052 {
00053 return effects()[i].get();
00054 }
00055 }
00056
00057 ref<Effect> fx = new Effect;
00058 fx->shader()->enable(EN_DEPTH_TEST);
00059 fx->shader()->enable(EN_CULL_FACE);
00060 fx->shader()->enable(EN_LIGHTING);
00061 fx->shader()->setRenderState(mLight.get(), 0);
00062 fx->shader()->gocMaterial()->setDiffuse(color);
00063 effects().push_back(fx.get());
00064 return fx.get();
00065 }
00066
00067 const std::vector< ref<Effect> >& effects() const { return mEffects; }
00068 std::vector< ref<Effect> >& effects() { return mEffects; }
00069
00070 const Light* light() const { return mLight.get(); }
00071 Light* light() { return mLight.get(); }
00072
00073 protected:
00074 std::vector< ref<Effect> > mEffects;
00075 ref<Light> mLight;
00076 };
00077
00078 class AtomGeometryCache
00079 {
00080 public:
00081 AtomGeometryCache(): mDetail(1) {}
00082
00083 void clear() { mGeometryMap.clear(); }
00084 const std::map< float, ref<Geometry> >& geometryMap() const { return mGeometryMap; }
00085 std::map< float, ref<Geometry> >& geometryMap() { return mGeometryMap; }
00086 Geometry* acquireAtomGeometry(float radius)
00087 {
00088 std::map< float, ref<Geometry> >::iterator it = geometryMap().find(radius);
00089 if (it!=geometryMap().end())
00090 return it->second.get();
00091 else
00092 {
00093 ref<Geometry> sphere = makeIcosphere( vec3(0,0,0), radius*2.0f, detail() );
00094 geometryMap()[radius] = sphere;
00095 return sphere.get();
00096 }
00097 }
00098
00099 int detail() const { return mDetail; }
00100 void setDetail(int detail) { mDetail = detail; }
00101
00102 protected:
00103 std::map< float, ref<Geometry> > mGeometryMap;
00104 int mDetail;
00105 };
00106
00107 class BondGeometryCache
00108 {
00109 class BondKey
00110 {
00111 public:
00112 float height;
00113 fvec4 col1;
00114 fvec4 col2;
00115 ECapsuleCap top_cap;
00116 ECapsuleCap bottom_cap;
00117
00118 BondKey(float h, const fvec4& c1, const fvec4& c2, ECapsuleCap topcap, ECapsuleCap bottomcap): height(h), col1(c1), col2(c2), top_cap(topcap), bottom_cap(bottomcap) {}
00119 bool operator==(const BondKey& other) const
00120 {
00121 return height == other.height &&
00122 col1 == other.col1 &&
00123 col2 == other.col2 &&
00124 top_cap == other.top_cap &&
00125 bottom_cap == other.bottom_cap;
00126 }
00127 bool operator<(const BondKey& other) const
00128 {
00129 if (top_cap!=other.top_cap)
00130 return top_cap<other.top_cap;
00131 else
00132 if (bottom_cap!=other.bottom_cap)
00133 return bottom_cap<other.bottom_cap;
00134 else
00135 if (height!=other.height)
00136 return height<other.height;
00137 else
00138 if (col1!=other.col1)
00139 return col1<other.col1;
00140 else
00141 return col2<other.col2;
00142 }
00143 };
00144 public:
00145 BondGeometryCache(): mDetail(20), mDiameter(0.20f), mQuantization(100.0f) {}
00146
00147 void clear() { mGeometryMap.clear(); }
00148 const std::map< BondKey, ref<Geometry> >& geometryMap() const { return mGeometryMap; }
00149 std::map< BondKey, ref<Geometry> >& geometryMap() { return mGeometryMap; }
00150 Geometry* acquireBondGeometry(float length, const fvec4& c1, const fvec4& c2, ECapsuleCap top_cap, ECapsuleCap bottom_cap)
00151 {
00152 float quant_lenght = int(length*quantization()) / quantization();
00153 BondKey key(quant_lenght,c1,c2,top_cap,bottom_cap);
00154 std::map< BondKey, ref<Geometry> >::iterator it = geometryMap().find( key );
00155 if (it!=geometryMap().end())
00156 {
00157 VL_CHECK(it->first == key)
00158 return it->second.get();
00159 }
00160 else
00161 {
00162 ref<Geometry> cylinder = makeCapsule( diameter()/2.0f, quant_lenght+2.0f/quantization(), detail(), top_cap, bottom_cap, c2, c1 );
00163 cylinder->computeNormals();
00164 geometryMap()[key] = cylinder;
00165 return cylinder.get();
00166 }
00167 }
00168
00169 int detail() const { return mDetail; }
00170 void setDetail(int detail) { mDetail = detail; }
00171
00172 float diameter() const { return mDiameter; }
00173 void setDiameter(float diameter) { mDiameter = diameter; }
00174
00175 float quantization() const { return mQuantization; }
00176 void setQuantization(float quantization) { mQuantization = quantization; }
00177
00178 protected:
00179 std::map< BondKey, ref<Geometry> > mGeometryMap;
00180 int mDetail;
00181 float mDiameter;
00182 float mQuantization;
00183 };
00184
00185 void Molecule::prepareForRendering()
00186 {
00187 actorTree()->actors()->clear();
00188 transformTree()->eraseAllChildren();
00189
00190 switch(moleculeStyle())
00191 {
00192 case MS_Wireframe: wireframeStyle(); generateRings(); break;
00193 case MS_BallAndStick: ballAndStickStyle(); generateRings(); break;
00194 case MS_Sticks: sticksStyle(); generateRings(); break;
00195 case MS_AtomsOnly: atomsStyle(); break;
00196 }
00197 generateAtomLabels();
00198 transformTree()->computeWorldMatrixRecursive();
00199 }
00200
00201 void Molecule::generateAtomLabel(const Atom* atom, Transform* tr)
00202 {
00203 if (atomLabelTemplate()->font() &&
00204 showAtomNames() &&
00205 atom->visible() &&
00206 atom->showAtomName() )
00207 {
00208 ref<Text> text = new Text;
00209
00210 text->setText( atom->atomName().c_str() );
00211
00212 text->setViewportAlignment( atomLabelTemplate()->viewportAlignment() );
00213 text->setTextAlignment( atomLabelTemplate()->textAlignment() );
00214 text->setShadowVector( atomLabelTemplate()->shadowVector() );
00215 text->setShadowEnabled( atomLabelTemplate()->shadowEnabled() );
00216 text->setShadowColor( atomLabelTemplate()->shadowColor() );
00217 text->setOutlineEnabled( atomLabelTemplate()->outlineEnabled() );
00218 text->setOutlineColor( atomLabelTemplate()->outlineColor() );
00219 text->setMode( atomLabelTemplate()->mode() );
00220 text->setMargin( atomLabelTemplate()->margin() );
00221 text->setKerningEnabled( atomLabelTemplate()->kerningEnabled() );
00222 text->setFont( atomLabelTemplate()->font() );
00223 text->setColor( atomLabelTemplate()->color() );
00224 text->setBorderEnabled( atomLabelTemplate()->borderEnabled() );
00225 text->setBorderColor( atomLabelTemplate()->borderColor() );
00226 text->setBackgroundEnabled( atomLabelTemplate()->backgroundEnabled() );
00227 text->setBackgroundColor( atomLabelTemplate()->backgroundColor() );
00228 text->setAlignment( atomLabelTemplate()->alignment() );
00229
00230 ref<Actor> text_act = new Actor( text.get(), mAtomLabelEffect.get(), tr );
00231 actorTree()->actors()->push_back(text_act.get());
00232 }
00233 }
00234
00235 void Molecule::generateAtomLabels()
00236 {
00237 for(unsigned i=0; i<atoms().size(); ++i)
00238 {
00239 ref<Transform> tr = new Transform(mat4::getTranslation((vec3)atoms()[i]->coordinates()));
00240 transformTree()->addChild(tr.get());
00241 generateAtomLabel(atoms()[i].get(), tr.get());
00242 }
00243 }
00244
00245 void Molecule::wireframeStyle()
00246 {
00247 ref<Geometry> geom = new Geometry;
00248 ref<ArrayFloat3> points = new ArrayFloat3;
00249 geom->setVertexArray(points.get());
00250 ref<ArrayFloat4> colors = new ArrayFloat4;
00251 geom->setColorArray(colors.get());
00252 std::vector<fvec3> pt;
00253 std::vector<fvec4> cols;
00254 for(unsigned ibond=0; ibond<bonds().size(); ++ibond)
00255 {
00256 Bond* b = bond(ibond);
00257 if (b->visible() && b->atom1()->visible() && b->atom2()->visible())
00258 {
00259 fvec4 c1 = b->color();
00260 fvec4 c2 = b->color();
00261 if (b->useAtomColors())
00262 {
00263 c1 = b->atom1()->color();
00264 c2 = b->atom2()->color();
00265 }
00266 if (c1 == c2)
00267 {
00268 pt.push_back( b->atom1()->coordinates() );
00269 pt.push_back( b->atom2()->coordinates() );
00270 cols.push_back(c1);
00271 cols.push_back(c1);
00272 }
00273 else
00274 {
00275 fvec3 center = (b->atom1()->coordinates() + b->atom2()->coordinates())/2.0f;
00276 pt.push_back( b->atom1()->coordinates() );
00277 pt.push_back( center );
00278 pt.push_back( center );
00279 pt.push_back( b->atom2()->coordinates() );
00280 cols.push_back(c1);
00281 cols.push_back(c1);
00282 cols.push_back(c2);
00283 cols.push_back(c2);
00284 }
00285 }
00286 }
00287 points->initFrom(pt);
00288 colors->initFrom(cols);
00289 geom->drawCalls()->push_back(new DrawArrays(PT_LINES, 0, (int)points->size()));
00290
00291 ref<Effect> fx = new Effect;
00292 fx->shader()->enable(EN_DEPTH_TEST);
00293 if (smoothLines())
00294 {
00295 fx->shader()->enable(EN_BLEND);
00296 fx->shader()->enable(EN_LINE_SMOOTH);
00297 }
00298 if (lineWidth() != 1.0f)
00299 fx->shader()->gocLineWidth()->set(lineWidth());
00300
00301 actorTree()->actors()->push_back( new Actor(geom.get(), fx.get(), NULL) );
00302 }
00303
00304 void Molecule::atomsStyle()
00305 {
00306 EffectCache fx_cache;
00307 AtomGeometryCache atom_geom_cache;
00308 atom_geom_cache.setDetail(atomDetail());
00309 for(unsigned iatom=0; iatom<atoms().size(); ++iatom)
00310 {
00311 if (atom(iatom)->visible())
00312 {
00313 Effect* fx = fx_cache.acquireEffect(atom(iatom)->color());
00314 float r = atom(iatom)->radius();
00315 ref<Geometry> ball = atom_geom_cache.acquireAtomGeometry(r);
00316 ref<Actor> atom_act = new Actor( ball.get(), fx, new Transform );
00317 atom_act->transform()->setLocalMatrix( mat4::getTranslation( (vec3)atom(iatom)->coordinates()) );
00318 transformTree()->addChild(atom_act->transform());
00319 actorTree()->actors()->push_back( atom_act.get() );
00320 }
00321 }
00322 }
00323
00324 void Molecule::ballAndStickStyle()
00325 {
00326 EffectCache fx_cache;
00327 AtomGeometryCache atom_geom_cache;
00328 atom_geom_cache.setDetail(atomDetail());
00329 for(unsigned int iatom=0; iatom<atoms().size(); ++iatom)
00330 {
00331 if (atom(iatom)->visible())
00332 {
00333 Effect* fx = fx_cache.acquireEffect(atom(iatom)->color());
00334 float r = atom(iatom)->radius();
00335 ref<Geometry> ball = atom_geom_cache.acquireAtomGeometry(r);
00336 ref<Actor> atom_act = new Actor( ball.get(), fx, new Transform );
00337 atom_act->transform()->setLocalMatrix( mat4::getTranslation( (vec3)atom(iatom)->coordinates()) );
00338 transformTree()->addChild(atom_act->transform());
00339 actorTree()->actors()->push_back( atom_act.get() );
00340 }
00341 }
00342
00343 ref<Effect> fx = new Effect;
00344 fx->shader()->enable(EN_DEPTH_TEST);
00345 fx->shader()->enable(EN_CULL_FACE);
00346 fx->shader()->gocMaterial()->setColorMaterialEnabled(true);
00347 fx->shader()->gocLightModel()->setTwoSide(false);
00348 fx->shader()->enable(EN_LIGHTING);
00349 fx->shader()->setRenderState( fx_cache.light(), 0 );
00350
00351
00352 BondGeometryCache bond_geom_cache;
00353 bond_geom_cache.setDetail(bondDetail());
00354 for(unsigned int ibond=0; ibond<bonds().size(); ++ibond)
00355 {
00356 if (bond(ibond)->visible() && bond(ibond)->atom1()->visible() && bond(ibond)->atom2()->visible())
00357 {
00358 Bond* b = bond(ibond);
00359 fvec4 c1 = b->color();
00360 fvec4 c2 = b->color();
00361 if (b->useAtomColors())
00362 {
00363 c1 = b->atom1()->color();
00364 c2 = b->atom2()->color();
00365 }
00366 float len = (b->atom1()->coordinates() - b->atom2()->coordinates()).length();
00367 float diam = b->radius()*2.0f;
00368 bond_geom_cache.setDiameter(diam);
00369 ref<Geometry> geom = bond_geom_cache.acquireBondGeometry(len,c1,c2,CC_NoCap,CC_NoCap);
00370 ref<Actor> bond_act = new Actor( geom.get(), fx.get(), new Transform );
00371 transformTree()->addChild(bond_act->transform());
00372 fvec3 center = (b->atom1()->coordinates() + b->atom2()->coordinates()) / 2.0f;
00373 fvec3 direction = (b->atom2()->coordinates() - b->atom1()->coordinates()).normalize();
00374 fmat4 mat = fmat4::getTranslation(center) * fmat4::getRotation(fvec3(0,1,0), direction);
00375 bond_act->transform()->setLocalMatrix( (mat4)mat );
00376 actorTree()->actors()->push_back( bond_act.get() );
00377 }
00378 }
00379 }
00380
00381 void Molecule::sticksStyle()
00382 {
00383 ref<Effect> fx = new Effect;
00384 fx->shader()->enable(EN_DEPTH_TEST);
00385 fx->shader()->enable(EN_CULL_FACE);
00386 fx->shader()->gocMaterial()->setColorMaterialEnabled(true);
00387 fx->shader()->gocLightModel()->setTwoSide(false);
00388 fx->shader()->enable(EN_LIGHTING);
00389 fx->shader()->setRenderState( new Light, 0 );
00390
00391
00392 BondGeometryCache bond_geom_cache;
00393 bond_geom_cache.setDetail(bondDetail());
00394 for(unsigned int ibond=0; ibond<bonds().size(); ++ibond)
00395 {
00396 if (bond(ibond)->visible() && bond(ibond)->atom1()->visible() && bond(ibond)->atom2()->visible())
00397 {
00398 Bond* b = bond(ibond);
00399 fvec4 c1 = b->color();
00400 fvec4 c2 = b->color();
00401 if (b->useAtomColors())
00402 {
00403 c1 = b->atom1()->color();
00404 c2 = b->atom2()->color();
00405 }
00406 float len = (b->atom1()->coordinates() - b->atom2()->coordinates()).length();
00407 float diam = b->radius()*2.0f;
00408 bond_geom_cache.setDiameter(diam);
00409 ref<Geometry> geom = bond_geom_cache.acquireBondGeometry(len,c1,c2,CC_RoundedCap,CC_RoundedCap);
00410 ref<Actor> bond_act = new Actor( geom.get(), fx.get(), new Transform );
00411 transformTree()->addChild(bond_act->transform());
00412 fvec3 center = (b->atom1()->coordinates() + b->atom2()->coordinates()) / 2.0f;
00413 fvec3 direction = (b->atom2()->coordinates() - b->atom1()->coordinates()).normalize();
00414 fmat4 mat = fmat4::getTranslation(center) * fmat4::getRotation(fvec3(0,1,0), direction);
00415 bond_act->transform()->setLocalMatrix( (mat4)mat );
00416 actorTree()->actors()->push_back( bond_act.get() );
00417 }
00418 }
00419 }
00420
00421 void Molecule::generateRings()
00422 {
00423 if (!cycles().empty())
00424 {
00425 ref<Geometry> geom = new Geometry;
00426 ref<ArrayFloat3> points = new ArrayFloat3;
00427 geom->setVertexArray(points.get());
00428 ref<ArrayFloat4> colors = new ArrayFloat4;
00429 geom->setColorArray(colors.get());
00430 std::vector<fvec3> pt;
00431 std::vector<fvec4> cols;
00432 for(unsigned icycle=0; icycle<cycles().size(); ++icycle)
00433 {
00434 AABB aabb;
00435 for(unsigned iatom=0; iatom<cycle(icycle).size(); ++iatom)
00436 aabb += (vec3)cycle(icycle)[iatom]->coordinates();
00437 fvec3 center = (fvec3)aabb.center();
00438
00439 for(unsigned iatom=0; iatom<cycle(icycle).size(); ++iatom)
00440 {
00441 int iatom2 = (iatom+1) % cycle(icycle).size();
00442 fvec3 v1 = cycle(icycle)[iatom ]->coordinates();
00443 fvec3 v2 = cycle(icycle)[iatom2]->coordinates();
00444 v1 += (center-v1).normalize() * ringOffset();
00445 v2 += (center-v2).normalize() * ringOffset();
00446 pt.push_back( v1 );
00447 pt.push_back( v2 );
00448 cols.push_back( aromaticRingColor() );
00449 cols.push_back( aromaticRingColor() );
00450 }
00451 }
00452 points->initFrom(pt);
00453 colors->initFrom(cols);
00454 geom->drawCalls()->push_back(new DrawArrays(PT_LINES, 0, (int)points->size()));
00455
00456 ref<Effect> fx = new Effect;
00457 fx->shader()->enable(EN_DEPTH_TEST);
00458
00459 actorTree()->actors()->push_back( new Actor(geom.get(), fx.get(), NULL) );
00460 }
00461 }
00462