Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://visualizationlibrary.org */ 00005 /* */ 00006 /* Copyright (c) 2005-2010, Michele Bosi */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without modification, */ 00010 /* are permitted provided that the following conditions are met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, this */ 00013 /* list of conditions and the following disclaimer. */ 00014 /* */ 00015 /* - Redistributions in binary form must reproduce the above copyright notice, this */ 00016 /* list of conditions and the following disclaimer in the documentation and/or */ 00017 /* other materials provided with the distribution. */ 00018 /* */ 00019 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ 00020 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ 00021 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ 00022 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ 00023 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 00024 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ 00025 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ 00026 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ 00027 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ 00028 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 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 // text label 00210 text->setText( atom->atomName().c_str() ); 00211 // text template style 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 // text actor 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 // no maps are generated for this style. 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 // actor -> atom map 00333 if (isActorToMoleculeMapEnabled()) 00334 mActorToAtomMap.insert( std::pair< ref<Actor>, ref<Atom> >(atom_act, atom(iatom)) ); 00335 // atom -> actor map 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 // mic fixme: 00361 // it would be nice to have a pool to accelerate Actor and Transform allocation 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 // actor -> atom map 00369 if (isActorToMoleculeMapEnabled()) 00370 mActorToAtomMap.insert( std::pair< ref<Actor>, ref<Atom> >(atom_act, atom(iatom)) ); 00371 // atom -> actor map 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 // fx->shader()->gocPolygonMode()->set(PM_LINE, PM_LINE); 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 // actor -> bond map 00413 if (isActorToMoleculeMapEnabled()) 00414 mActorToBondMap.insert( std::pair< ref<Actor>, ref<Bond> >(bond_act, bond(ibond)) ); 00415 // bond -> actor map 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 /*fx->shader()->gocPolygonMode()->set(PM_LINE, PM_LINE);*/ 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 // actor -> bond map 00465 if (isActorToMoleculeMapEnabled()) 00466 mActorToBondMap.insert( std::pair< ref<Actor>, ref<Bond> >(bond_act, bond(ibond)) ); 00467 // bond -> actor map 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 //-----------------------------------------------------------------------------