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);
}
}
}