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
00248 mAtomToActorMap.clear();
00249 mActorToAtomMap.clear();
00250 mBondToActorMap.clear();
00251 mActorToBondMap.clear();
00252
00253 ref<Geometry> geom = new Geometry;
00254 ref<ArrayFloat3> points = new ArrayFloat3;
00255 geom->setVertexArray(points.get());
00256 ref<ArrayFloat4> colors = new ArrayFloat4;
00257 geom->setColorArray(colors.get());
00258 std::vector<fvec3> pt;
00259 std::vector<fvec4> cols;
00260 for(unsigned ibond=0; ibond<bonds().size(); ++ibond)
00261 {
00262 Bond* b = bond(ibond);
00263 if (b->visible() && b->atom1()->visible() && b->atom2()->visible())
00264 {
00265 fvec4 c1 = b->color();
00266 fvec4 c2 = b->color();
00267 if (b->useAtomColors())
00268 {
00269 c1 = b->atom1()->color();
00270 c2 = b->atom2()->color();
00271 }
00272 if (c1 == c2)
00273 {
00274 pt.push_back( b->atom1()->coordinates() );
00275 pt.push_back( b->atom2()->coordinates() );
00276 cols.push_back(c1);
00277 cols.push_back(c1);
00278 }
00279 else
00280 {
00281 fvec3 center = (b->atom1()->coordinates() + b->atom2()->coordinates())/2.0f;
00282 pt.push_back( b->atom1()->coordinates() );
00283 pt.push_back( center );
00284 pt.push_back( center );
00285 pt.push_back( b->atom2()->coordinates() );
00286 cols.push_back(c1);
00287 cols.push_back(c1);
00288 cols.push_back(c2);
00289 cols.push_back(c2);
00290 }
00291 }
00292 }
00293 points->initFrom(pt);
00294 colors->initFrom(cols);
00295 geom->drawCalls()->push_back(new DrawArrays(PT_LINES, 0, (int)points->size()));
00296
00297 ref<Effect> fx = new Effect;
00298 fx->shader()->enable(EN_DEPTH_TEST);
00299 if (smoothLines())
00300 {
00301 fx->shader()->enable(EN_BLEND);
00302 fx->shader()->enable(EN_LINE_SMOOTH);
00303 }
00304 if (lineWidth() != 1.0f)
00305 fx->shader()->gocLineWidth()->set(lineWidth());
00306
00307 actorTree()->actors()->push_back( new Actor(geom.get(), fx.get(), NULL) );
00308 }
00309
00310 void Molecule::atomsStyle()
00311 {
00312 mAtomToActorMap.clear();
00313 mActorToAtomMap.clear();
00314 mBondToActorMap.clear();
00315 mActorToBondMap.clear();
00316
00317 EffectCache fx_cache;
00318 AtomGeometryCache atom_geom_cache;
00319 atom_geom_cache.setDetail(atomDetail());
00320 for(unsigned iatom=0; iatom<atoms().size(); ++iatom)
00321 {
00322 if (atom(iatom)->visible())
00323 {
00324 Effect* fx = fx_cache.acquireEffect(atom(iatom)->color());
00325 float r = atom(iatom)->radius();
00326 ref<Geometry> ball = atom_geom_cache.acquireAtomGeometry(r);
00327 ref<Actor> atom_act = new Actor( ball.get(), fx, new Transform );
00328 atom_act->transform()->setLocalMatrix( mat4::getTranslation( (vec3)atom(iatom)->coordinates()) );
00329 transformTree()->addChild(atom_act->transform());
00330 actorTree()->actors()->push_back( atom_act.get() );
00331
00332
00333 if (isActorToMoleculeMapEnabled())
00334 mActorToAtomMap.insert( std::pair< ref<Actor>, ref<Atom> >(atom_act, atom(iatom)) );
00335
00336 if (isMoleculeToActorMapEnabled())
00337 mAtomToActorMap.insert( std::pair< ref<Atom>, ref<Actor> >(atom(iatom), atom_act) );
00338 }
00339 }
00340 }
00341
00342 void Molecule::ballAndStickStyle()
00343 {
00344 mAtomToActorMap.clear();
00345 mActorToAtomMap.clear();
00346 mBondToActorMap.clear();
00347 mActorToBondMap.clear();
00348
00349 EffectCache fx_cache;
00350 AtomGeometryCache atom_geom_cache;
00351 atom_geom_cache.setDetail(atomDetail());
00352 for(unsigned int iatom=0; iatom<atoms().size(); ++iatom)
00353 {
00354 if (atom(iatom)->visible())
00355 {
00356 Effect* fx = fx_cache.acquireEffect(atom(iatom)->color());
00357 float r = atom(iatom)->radius();
00358 ref<Geometry> ball = atom_geom_cache.acquireAtomGeometry(r);
00359
00360
00361
00362
00363 ref<Actor> atom_act = new Actor( ball.get(), fx, new Transform );
00364 atom_act->transform()->setLocalMatrix( mat4::getTranslation( (vec3)atom(iatom)->coordinates()) );
00365 transformTree()->addChild(atom_act->transform());
00366 actorTree()->actors()->push_back( atom_act.get() );
00367
00368
00369 if (isActorToMoleculeMapEnabled())
00370 mActorToAtomMap.insert( std::pair< ref<Actor>, ref<Atom> >(atom_act, atom(iatom)) );
00371
00372 if (isMoleculeToActorMapEnabled())
00373 mAtomToActorMap.insert( std::pair< ref<Atom>, ref<Actor> >(atom(iatom), atom_act) );
00374 }
00375 }
00376
00377 ref<Effect> fx = new Effect;
00378 fx->shader()->enable(EN_DEPTH_TEST);
00379 fx->shader()->enable(EN_CULL_FACE);
00380 fx->shader()->gocMaterial()->setColorMaterialEnabled(true);
00381 fx->shader()->gocLightModel()->setTwoSide(false);
00382 fx->shader()->enable(EN_LIGHTING);
00383 fx->shader()->setRenderState( fx_cache.light(), 0 );
00384
00385
00386 BondGeometryCache bond_geom_cache;
00387 bond_geom_cache.setDetail(bondDetail());
00388 for(unsigned int ibond=0; ibond<bonds().size(); ++ibond)
00389 {
00390 if (bond(ibond)->visible() && bond(ibond)->atom1()->visible() && bond(ibond)->atom2()->visible())
00391 {
00392 Bond* b = bond(ibond);
00393 fvec4 c1 = b->color();
00394 fvec4 c2 = b->color();
00395 if (b->useAtomColors())
00396 {
00397 c1 = b->atom1()->color();
00398 c2 = b->atom2()->color();
00399 }
00400 float len = (b->atom1()->coordinates() - b->atom2()->coordinates()).length();
00401 float diam = b->radius()*2.0f;
00402 bond_geom_cache.setDiameter(diam);
00403 ref<Geometry> geom = bond_geom_cache.acquireBondGeometry(len,c1,c2,CC_NoCap,CC_NoCap);
00404 ref<Actor> bond_act = new Actor( geom.get(), fx.get(), new Transform );
00405 transformTree()->addChild(bond_act->transform());
00406 fvec3 center = (b->atom1()->coordinates() + b->atom2()->coordinates()) / 2.0f;
00407 fvec3 direction = (b->atom2()->coordinates() - b->atom1()->coordinates()).normalize();
00408 fmat4 mat = fmat4::getTranslation(center) * fmat4::getRotation(fvec3(0,1,0), direction);
00409 bond_act->transform()->setLocalMatrix( (mat4)mat );
00410 actorTree()->actors()->push_back( bond_act.get() );
00411
00412
00413 if (isActorToMoleculeMapEnabled())
00414 mActorToBondMap.insert( std::pair< ref<Actor>, ref<Bond> >(bond_act, bond(ibond)) );
00415
00416 if (isMoleculeToActorMapEnabled())
00417 mBondToActorMap.insert( std::pair< ref<Bond>, ref<Actor> >(bond(ibond), bond_act) );
00418 }
00419 }
00420 }
00421
00422 void Molecule::sticksStyle()
00423 {
00424 mAtomToActorMap.clear();
00425 mActorToAtomMap.clear();
00426 mBondToActorMap.clear();
00427 mActorToBondMap.clear();
00428
00429 ref<Effect> fx = new Effect;
00430 fx->shader()->enable(EN_DEPTH_TEST);
00431 fx->shader()->enable(EN_CULL_FACE);
00432 fx->shader()->gocMaterial()->setColorMaterialEnabled(true);
00433 fx->shader()->gocLightModel()->setTwoSide(false);
00434 fx->shader()->enable(EN_LIGHTING);
00435 fx->shader()->setRenderState( new Light, 0 );
00436
00437
00438 BondGeometryCache bond_geom_cache;
00439 bond_geom_cache.setDetail(bondDetail());
00440 for(unsigned int ibond=0; ibond<bonds().size(); ++ibond)
00441 {
00442 if (bond(ibond)->visible() && bond(ibond)->atom1()->visible() && bond(ibond)->atom2()->visible())
00443 {
00444 Bond* b = bond(ibond);
00445 fvec4 c1 = b->color();
00446 fvec4 c2 = b->color();
00447 if (b->useAtomColors())
00448 {
00449 c1 = b->atom1()->color();
00450 c2 = b->atom2()->color();
00451 }
00452 float len = (b->atom1()->coordinates() - b->atom2()->coordinates()).length();
00453 float diam = b->radius()*2.0f;
00454 bond_geom_cache.setDiameter(diam);
00455 ref<Geometry> geom = bond_geom_cache.acquireBondGeometry(len,c1,c2,CC_RoundedCap,CC_RoundedCap);
00456 ref<Actor> bond_act = new Actor( geom.get(), fx.get(), new Transform );
00457 transformTree()->addChild(bond_act->transform());
00458 fvec3 center = (b->atom1()->coordinates() + b->atom2()->coordinates()) / 2.0f;
00459 fvec3 direction = (b->atom2()->coordinates() - b->atom1()->coordinates()).normalize();
00460 fmat4 mat = fmat4::getTranslation(center) * fmat4::getRotation(fvec3(0,1,0), direction);
00461 bond_act->transform()->setLocalMatrix( (mat4)mat );
00462 actorTree()->actors()->push_back( bond_act.get() );
00463
00464
00465 if (isActorToMoleculeMapEnabled())
00466 mActorToBondMap.insert( std::pair< ref<Actor>, ref<Bond> >(bond_act, bond(ibond)) );
00467
00468 if (isMoleculeToActorMapEnabled())
00469 mBondToActorMap.insert( std::pair< ref<Bond>, ref<Actor> >(bond(ibond), bond_act) );
00470 }
00471 }
00472 }
00473
00474 void Molecule::generateRings()
00475 {
00476 if (!cycles().empty())
00477 {
00478 ref<Geometry> geom = new Geometry;
00479 ref<ArrayFloat3> points = new ArrayFloat3;
00480 geom->setVertexArray(points.get());
00481 ref<ArrayFloat4> colors = new ArrayFloat4;
00482 geom->setColorArray(colors.get());
00483 std::vector<fvec3> pt;
00484 std::vector<fvec4> cols;
00485 for(unsigned icycle=0; icycle<cycles().size(); ++icycle)
00486 {
00487 AABB aabb;
00488 for(unsigned iatom=0; iatom<cycle(icycle).size(); ++iatom)
00489 aabb += (vec3)cycle(icycle)[iatom]->coordinates();
00490 fvec3 center = (fvec3)aabb.center();
00491
00492 for(unsigned iatom=0; iatom<cycle(icycle).size(); ++iatom)
00493 {
00494 int iatom2 = (iatom+1) % cycle(icycle).size();
00495 fvec3 v1 = cycle(icycle)[iatom ]->coordinates();
00496 fvec3 v2 = cycle(icycle)[iatom2]->coordinates();
00497 v1 += (center-v1).normalize() * ringOffset();
00498 v2 += (center-v2).normalize() * ringOffset();
00499 pt.push_back( v1 );
00500 pt.push_back( v2 );
00501 cols.push_back( aromaticRingColor() );
00502 cols.push_back( aromaticRingColor() );
00503 }
00504 }
00505 points->initFrom(pt);
00506 colors->initFrom(cols);
00507 geom->drawCalls()->push_back(new DrawArrays(PT_LINES, 0, (int)points->size()));
00508
00509 ref<Effect> fx = new Effect;
00510 fx->shader()->enable(EN_DEPTH_TEST);
00511
00512 actorTree()->actors()->push_back( new Actor(geom.get(), fx.get(), NULL) );
00513 }
00514 }
00515