Afin d'avoir une idée précise de ce à quoi peut ressembler un modèle réalisé avec Dynamic Graph, voici le code du cube de Sirpienski. Pour plus de renseignement sur cet outil, je vous renvoie à la documentation en ligne sur http://www-evasion.imag.fr/Frank.Perbet/these.
Voici le générateur d'amplifieurs que le créateur doit écrire. Une fois la phase de création ou de modification terminé, ce bout de code est compilé et chargé à la volée durant l'éxécution de Dynamic Graph.
class ty_square: public ty_drawableNodeBase { public: // square size ty_float size; // branching order ty_uint branchingOrder; // color vec3 color; public: // constructor without ancestor ty_square::ty_square( ty_pt_nodeBase pt_father, ty_localID li, const ty_uint& _branchingOrder, const ty_float& _size, const vec3& _color, ty_repere initialRepere): ty_drawableNodeBase(pt_father,li,createDefaultNodeContainer(), initialRepere,ty_sphericalBB(_size)), branchingOrder(_branchingOrder), color(_color), size(_size) { // Nothing } // constructor with ancestor ty_square::ty_square( ty_pt_nodeBase pt_father, ty_localID li, ty_nodeBase& _ancestor, const ty_uint& _branchingOrder, const ty_float& _size, const vec3& _color, ty_repere initialRepere): ty_drawableNodeBase(pt_father,li,createDefaultNodeContainer(),_ancestor, initialRepere,ty_sphericalBB(_size)), branchingOrder(_branchingOrder), color(_color), size(_size) { // Nothing } // visitor: generation virtual void upDown(parserFunction::ty_generation& v) { setMaturity(v.getNodeInfo()); if(branchingOrder>0) { ty_float reductionCoef = 1.0; ty_float coef = reductionCoef+(1.0-reductionCoef)*(1.0-maturity()); size*=coef; } if(precision()>0) { // create child node childGeneration(v); } else { draw(); } } protected: // creation of child node void childGeneration(parserFunction::ty_generation& v) { ty_ncRedirection& childContainer = static_cast<ty_ncRedirection&>(container()); static boost::array<vec3,8> dec = {{ vec3(1.0,1.0,1.0), vec3(1.0,1.0,-1.0), vec3(1.0,-1.0,1.0), vec3(1.0,-1.0,-1.0), vec3(-1.0,1.0,1.0), vec3(-1.0,1.0,-1.0), vec3(-1.0,-1.0,1.0), vec3(-1.0,-1.0,-1.0) }}; ty_tmpChildList tmpList = childContainer.startGeneration(); for(int i=0;i<8;i++) { vec3 newPosition = dec[i]*(size/4.0); ty_float newSize = size/2.0; vec3 newColor = color; ty_pt_nodeBaseBase it = childAncestor(i); if(it.isValid()) { ty_nodeBase& a = static_cast<ty_nodeBase&>(it.ref()); ty_nodeBase* newChild; NEW(ty_square,newChild) (this,i,a,branchingOrder+1,newSize, newColor,globalRepere*ty_repere(newPosition)); childContainer.addChild(tmpList,newChild); } else { ty_nodeBase* newChild; NEW(ty_square,newChild) (this,i,branchingOrder+1,newSize, newColor,globalRepere*ty_repere(newPosition)); childContainer.addChild(tmpList,newChild); } } childContainer.endGeneration(tmpList); } // opengl draw function void drawCore() { glPushMatrix(); glMultMatrix(globalRepere); glColor(color); draw_cube(1,0xFF,get_rapport(),size); glPopMatrix(); } /// opengl draw function void drawDebug(ty_glViewer& v) { pixel vpSize = v.mainViewportSize(); ty_float pos=-30; v.strBuf()<<"size = "<<size<<std::endl; v.drawText(10,vpSize[1]-(pos+=30)); v.strBuf()<<"branchingOrder = "<<branchingOrder; v.drawText(10,vpSize[1]-(pos+=30)); v.strBuf()<<"precision = "<<ty_maturity::precision(); v.drawText(10,vpSize[1]-(pos+=30)); v.strBuf()<<"maturity = "<<ty_maturity::maturity(); v.drawText(10,vpSize[1]-(pos+=30)); } }; // end of ty_square
Les fonctions d'échanges sont les fonctions que Dynamic Graph va explicitement chercher dans la librairie avec la fonction dlsym (dans le fichier d'entête standard dlfcn.h). Parmis ces fonctions, ont remarquera celle qui se charge de la création du premier amplifieur, racine de l'arbre d'évaluation.
extern "C" { typedef boostEXT::te_array<GLfloat,4> glvec4; typedef boostEXT::te_array<GLfloat,3> glvec3; // called one time when loading the model void init() { dpGV::initSlider(7,1,"Rapport",333,1000); dpGV::initSlider(7,2,"GL_SPOT_CUTOFF",200,1000); dpGV::initSlider(7,3,"GL_SPOT_EXPONENT",145,1000); dpGV::initSlider(7,4,"GL_AMBIENT",380,1000); dpGV::initSlider(7,5,"GL_DIFFUSE",500,1000); glPushMatrix(); glLoadIdentity(); // on est dans le repere de la camera glvec4 light_ambiant = glvec4( 4*dpGV::sliderF(7,4), 4*dpGV::sliderF(7,4), 4*dpGV::sliderF(7,4),1); glvec4 light_diffuse = glvec4( 4*dpGV::sliderF(7,5), 4*dpGV::sliderF(7,5), 4*dpGV::sliderF(7,5),1); glLightfv(GL_LIGHT1, GL_POSITION, glvec4(0,0,0,1).c_array()); glLight(GL_LIGHT1, GL_SPOT_DIRECTION, glvec4(0,0,-1,1).c_array()); glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambiant.c_array()); glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse.c_array()); glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 180*dpGV::sliderF(7,2)); glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 128*dpGV::sliderF(7,3)); glPopMatrix(); } // init // called one time when unloading the model void kill() { // Nothing } // kill // called one time before each tree generation void initFrame() { glEnable(GL_LIGHT1); } // initFrame // call one time after each tree generation void killFrame() { // nothing } // killFrame // create the root node (the axiom) void getStartInfo(ty_tree& tree) { // color vec3 color = vec3(dpGV::sliderF(3,1),dpGV::sliderF(3,2),dpGV::sliderF(3,3)); // size and position of the first square ty_float size = 1; vec3 position = vec3(0,0,0); // initial repere: ty_repere ri = tree.initialRepere; // construct the axion if(tree.isAncestorAxiomAlive()) { ty_nodeBase& ancestor = static_cast<ty_nodeBase&>(tree.ancestorAxiom()); NEW(ty_square,tree.ptAxiom()) (ty_pt_nodeBase(),0,ancestor,0,size,color,ri*position); } else { NEW(ty_square,tree.ptAxiom()) (ty_pt_nodeBase(),0,0,size,color,ri*position); } } }