Tutorial 2 : interaction avec l'utilisateur : faire bouger un cube!!!

La première opération que nous allons apprendre ici est : déplacer un cube, ensuite on apprendra à le faire tourner!!

La translation
La rotation

La translation

Pour réaliser cela, on va d'abord augmenter notre type énuméré:

typedef enum
{
   MNoOperation,

   MPickAndTranslate,

   MTranslateObject,

   MOUSEMOVEOPERATIONFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
}MouseMoveOperation;

On rajoute un membre pour indiquer qu'on va faire une translation et on a changé un autre état. Maintenat il faut changer les gestionnaires d'événements de la souris pour indiquer qu'on va translater quand on clique et qu'on ne fait plus rien quand on relâche.

static RsEventStatus
HandleLeftButtonDown(RsMouseStatus *mouseStatus __RWUNUSED__)
{
   /* Left mouse button down event handling... */

   MouseMoveAction = MPickAndTranslateObject;

   return rsEVENTPROCESSED;
}

static RsEventStatus
HandleLeftButtonUp(RsMouseStatus *mouseStatus __RWUNUSED__)
{
   /* Left mouse button up event handling... */
   MouseMoveAction = MNoOperation;

   return rsEVENTPROCESSED;
}

Il faut maintenant écrire une fonction qui translate effectivement l'atomic:

/**
fonction pour réaliser la translation effective
*/

static void
TranslateAtomic(void)
{
   RwReal dx, dy;
   RwFrame *f;
   RwV3d up, right, trans;

   //recuperation de la frame attaché à la camera
   f = RwCameraGetFrame(Camera);
   //on calcule le deplacement
   dx = OldPos.x - MousePos.x;
   dy = OldPos.y - MousePos.y;

   //recuperation des vecteurs de la camera
   right = *RwMatrixGetRight(RwFrameGetMatrix(f));
   up = *RwMatrixGetUp(RwFrameGetMatrix(f));

   //on applique le deplacement
   RwV3dScale(&right, &right, dx*0.01f);
   RwV3dScale(&up, &up, dy*0.01f);
   RwV3dAdd(&trans, &up, &right);

   //recuperation de la frame de l'atomic
   f = RpAtomicGetFrame(PickedAtomic);
   //translation effective
   RwFrameTranslate(f, &trans, rwCOMBINEPOSTCONCAT);

   //on sauvegarde la position
   OldPos = MousePos;
}

Il faut aussi rajouter la déclaration de OldPos au début de main.c:

RwV2d MousePos = {0,0};
RwV2d OldPos = {0,0};

Maintenant, il faut changer Idle pour effectuer la translation au bon moment!

switch(MouseMoveAction)
{
   case MPickAndTranslateObject:
      PickedAtomic = RwCameraPickAtomicOnPixel(Camera,&MousePos);
      if(PickedAtomic) // si on trouve quelque chose
      {
         //on récupère la BB

         AtomicGetBBox(PickedAtomic,&PickBox);
         //on sauvegarde
         OldPos=MousePos;
         //on indique l'action
         MouseMoveAction=MTranslateObject;
      }
      else
      {
         MouseMoveAction = MNoOperation;
      }

      break;
   case MTranslateObject:
      TranslateAtomic();

      break;
   default:
      PickedAtomic=NULL;
      break;
}

C'est tout magique!!On copile, on exécute, on appuie plein de fois sur F1 et puis on déplace les cubes!

La rotation

Bon maintenant qu'on sait ire un fichier dff, sélectionner un cube et le déplacer, on va apprendre à le faire tourner!! Comme pour la translation, on va rajouter des états à notre type énuméré:

typedef enum
{
   MNoOperation,

   MPickAndTranslateObject,
   MPickAndRotateObject,
   MTranslateObject,
   MRotateObject,

   MOUSEMOVEOPERATIONFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
}MouseMoveOperation;

Nous avons les nouveaux états pour la rotation. Il va falloir indiquer le moment où on veut faire une rotation. Comme tout à l'heure, on va changer les gestionnaires d'événments de la souris:

static RsEventStatus
HandleLeftButtonDown(RsMouseStatus *mouseStatus __RWUNUSED__)
{
   /* Left mouse button down event handling... */
   //si on appuie sur maj en meme temps qu'on clique gauche

   if(mouseStatus->shift)
   {
      MouseMoveAction = MPickAndRotateObject;
   }
   else
   {
      MouseMoveAction = MPickAndTranslateObject;
   }

   return rsEVENTPROCESSED;
}

Lorsqu'on appuie sur la touche maj quand on clique gauche on se met en état de rotation. Comme dans le cas de la translation, il faut aussi créer la fonction qui permet de "rotater" le cube.

static void
RotateAtomic(void)
{
   RwFrame *f;
   RwMatrix *worldToLocal, *tmpMatrix;
   RwV3d up, right;
   RwReal dx, dy;

   f = RwCameraGetFrame(Camera);
   right = *RwMatrixGetRight(RwFrameGetMatrix(f));
   up = *RwMatrixGetUp(RwFrameGetMatrix(f));

   dx = OldPos.x - MousePos.x;
   dy = OldPos.y - MousePos.y;

   f = RpAtomicGetFrame(PickedAtomic);
   //matrice identite
   worldToLocal = RwMatrixCreate();
   //recuperation de la matrice locale de tranformation
   tmpMatrix = RwFrameGetLTM(f);
   //inversion de la matrice locale
   RwMatrixInvert(worldToLocal, tmpMatrix);

   //on met le vecteur up dans la monde de l'atomic choisi
   RwV3dTransformVector(&up, &up, worldToLocal);
   //on le norme
   RwV3dNormalize(&up, &up);
   //on met le vecteur right dans la monde de l'atomic choisi
   RwV3dTransformVector(&right, &right, worldToLocal);
   //on le norme
   RwV3dNormalize(&right, &right);

   //on se sert plus de la matrice
   RwMatrixDestroy(worldToLocal);

   /* Apply the rotations */
   RwFrameRotate(f, &up, -dx*0.5f, rwCOMBINEPRECONCAT);
   RwFrameRotate(f, &right, dy*0.5f, rwCOMBINEPRECONCAT);
   OldPos = MousePos;
}

Maintenant qu'on a la fonction pour tourner le cube : on va s'en servir!!Et ce dans la fonction Idle() (ah bon??)

case MTranslateObject:
   TranslateAtomic();

   break;
case MPickAndRotateObject:
   PickedAtomic = RwCameraPickAtomicOnPixel(Camera,&MousePos);
   if(PickedAtomic)    // si on trouve quelque chose
   {
      //on récupère la BB
      AtomicGetBBox(PickedAtomic,&PickBox);
      //on sauvegarde
      OldPos=MousePos;
      //on indique l'action
      MouseMoveAction=MRotateObject;
   }
   else
   {
      MouseMoveAction = MNoOperation;
   }

   break;
case MRotateObject:
   RotateAtomic();

   break;

Comme d'habitude, on compile, on exécute, on appuie plein de fois sur F1, on clique, on déplace et on appuie sur maj!

Bon on a pas mal avancé quand même : nos cubes se déplacent et tournent!! Dnas le tutorial 3 nous allons voir comment ajouter un menu et comment faire pour bouger selon l'axe des Z. Tutorial 3