Tutorial 2 : interaction avec l'utilisateur
Dans le chapitre précédent nous avons vu comment lire un fichier dff, comment récupérer les événements du clavier. Nous allons apprendre à nous servir de la souris ici.
Le picking est l'action qui consiste à récupérer l'objet cliqué par la souris. La première chose à faire est de rajouter la ligne suivante dans main.c:
| RwV2d MousePos = {0,0}; |
Et celle-ci dans utils.h:
| extern RwV2d MousePos ; |
Ainsi la variable MousePos est visible dans le fichier events.c qui comprend toute la gestion des événements. D'ailleurs dans ce fichier nous allons changer la fonction HandleMouseMove.
| static
RsEventStatus HandleMouseMove(RsMouseStatus *mouseStatus __RWUNUSED__) { /* Mouse move event handling... */ MousePos = mouseStatus->pos; |
Grâce à cette fonction on récupère la position de la souris.
Maintenant, nous allons créer un type énuméré qui va nous permettre d'indiquer l'état de la souris. Ce type est à créer dans utils.h.
| //type
énuméré pour indiquer l'état typedef enum { MNoOperation, MPickObject, MOUSEMOVEOPERATIONFORCEENUMSIZEINT = RWFORCEENUMSIZEINT |
Le dernier membre de ce type est un membre "fantôme" qui permet d'indiquer que la taille du type est la taille d'un entier. Il suffit maintenant d'inclure utils.h dans main.c. Il faut aussi créer un variable MouseMoveOperation qui va nous permettre de gérer l'état de la souris.
| MouseMoveOperation MouseMoveAction = MNoOperation; |
Par défaut on ne fait aucune opération. Maintenant, on va indiquer que lorsqu'on relache le bouton gauche de la souris, on va faire du picking. Pour ce la on va utiliser le gestionnaire d'événement du relachement du bouton gauche.
| static RsEventStatus HandleLeftButtonUp(RsMouseStatus *mouseStatus __RWUNUSED__) { /* Left mouse button up event handling... */ MouseMoveAction = MPickObject; return rsEVENTPROCESSED; |
Maintenant, il faut changer la fonction Idle() pour faire le picking et pour indiquer qu'on l'a fait!
| lastAnimTime
= thisTime;
switch(MouseMoveAction) Render(); |
Il faut ajouter une PickedAtomic de type RpAtomic * au début du fichier. Ensuite au clickil faut appeler la fonction RwCameraPickAtomicOnPixel qui teste l'intersection avec la ligne basée sur MousePos avec les sphères englobantes des objets. Cette fonction fait partie du RtPick toolkit. Pour que celui-ci soit accessible, il faut attacher le plug in de collision. Ceci doit être fait dans la fonction AttachPlugins.
| //pour le picking if (!RpCollisionPluginAttach() ) { return FALSE; } |
La dernière chose à faire est de linker les librairies : rtintsec.lib, rpcollis.lib, et rtpick.lib au projet. Il faut aussi inclure certains fichiers .h :
| #include "rpcollis.h" #include "rtcharse.h" #include "rtpick.h" |
Maintenant on compile, on exécute et on appuie sur F1 : un cube apparaît. Si on clique, en mettant un point d'arrêt on peut voir si un cube est sélectionné ou non. Si on clique sur le fond PickedAtomic est mis à 0 sinon toutes ses valeurs sont renseignées.
Il parait qu'on sait faire du picking mais pour l'instant à part le debugger rien ne nous le prouve!! Nous allons apprendre ici à mettre en surbrillance l'objet sélectionné.
Pour cela on va créer une fonction qui permet de trouver la Bounding Box (BB) de l'objet et d'en créer une plus grande pour pouvoir l'afficher. Cette fonction sera dans utils.c:
| void AtomicGetBBox(RpAtomic *atom, RwBBox *box) { // on récupère la géométrie de l'objets RpGeometry *geom = RpAtomicGetGeometry(atom); //on récupère le nombre de points de l'objet RwInt32 nVerts = RpGeometryGetNumVertices(geom); //Morph target -- vertex positions and normals RpMorphTarget *morph = RpGeometryGetMorphTarget(geom, 0); //on recupère les points du morph RwV3d *verts = RpMorphTargetGetVertices(morph); RwUInt16 i; box->inf = *verts; box->sup = *verts; //on cherche les plans inf et sup de chaque cote de la boite for (verts++, i = 1; i < nVerts; i++, verts++) { if (verts->x < box->inf.x) box->inf.x = verts->x; if (verts->y < box->inf.y) box->inf.y = verts->y; if (verts->z < box->inf.z) box->inf.z = verts->z; if (verts->x > box->sup.x) box->sup.x = verts->x; if (verts->y > box->sup.y) box->sup.y = verts->y; if (verts->z > box->sup.z) box->sup.z = verts->z; } //on l'agrandit
pour l'afficher |
Il faut aussi mettre l'entête dans utils.h:
| extern void AtomicGetBBox(RpAtomic *atom, RwBBox *box); |
On peut remarquer dans la fonction ci-dessus que suls des types RenderWare sont utilisés même lorsqu'il s'agit d'un entier. Il faut toujours utiliser les types RenderWare car ils sont optimisés pour chaque plate forme.
Pour récupérer la BB, on va ajouter une variable statique RwBBox PickedBox dans main.c et rajouter ce bout de code dans la fonction Idle():
| PickedAtomic = RwCameraPickAtomicOnPixel(Camera,&MousePos); if(PickedAtomic) // si on trouve quelque chose { //on récupère la BB AtomicGetBBox(PickedAtomic,&PickBox); } |
Ce bout de code permet de récupérer la BB. Bon maintenant qu'on a la BB, il faut l'afficher... Nous allons créer une fonction HightlightRender() qui va le permettre.
| /** fonction qui va permettre de rendre la BB du cube sélectionné */ static void HighlightRender(void) { //on recupre la matrice de transformation locale de l'atomic sélectionné RwMatrix *ltm = RwFrameGetLTM(RpAtomicGetFrame(PickedAtomic)); //tableau de points du cube RwIm3DVertex vertices[8]; RwInt32 i; //numero des vertices pour les aretes static RwImVertexIndex indices[24] = { 0, 1, 1, 3, 3, 2, 2, 0, 4, 5, 5, 7, 7, 6, 6, 4, 0, 4, 1, 5, 2, 6, 3, 7 }; //permet de positionner les vertices comme il faut for (i = 0; i < 8; i++) { RwIm3DVertexSetPos(vertices+i, i&1 ? PickBox.sup.x : PickBox.inf.x, i&2 ? PickBox.sup.y : PickBox.inf.y, i&4 ? PickBox.sup.z : PickBox.inf.z); RwIm3DVertexSetRGBA(vertices+i, 255, 0, 0, 255); } /* all
vertices have opaque colors so we can use the rwIM3D_ALLOPAQUE } |
Maintenant il faut appeler cette dernière fonction au moment adéquat dans la fonction Render():
| DisplayOnScreenInfo(Camera); if(PickedAtomic) { HighlightRender(); } |
Tout est prêt pour le picking. On compile, on exécute, on appuie sur F1 et on clique sur le cube.

Et voilà notre cube est sélectionné!! Peu de lignes de code nous ont été nécessaire pour accomplir cela mais si nous avions du tout faire à la main... Merci RenderWare!!
Dans la seconde partie de ce tutorial nous allons voir comment faire pour déplacer, tourner les atomics : Les mouvements