#0 

11-10-2006 16:47:09

Copland
Modérateur
Lieu: ZarbiLand
Date d'inscription: 22-09-2006
Messages: 657
Site web

Salut, j'ai repris l'exemple de Kedu et moi même en .Net pour le passer sous irrlicht avec ode en c++ sous linux.
Bon ici y'a pas les gestion des threads car je ne maîtrise pas encore assez le C++ mais le code est pleinement fonctionnel.
Il vous faudra télécharger Ode 0.7 et le compiler pour essayer se code.

Code c++ :

#include <irrlicht.h>
#include <iostream>
#include <ode/ode.h>

using namespace irr;

//Parramètre de notre physique
dWorldID world = dWorldCreate();
dSpaceID space = dHashSpaceCreate (0);
dJointGroupID contactgroup = dJointGroupCreate (0);
dMass mass;
dBodyID body;
dGeomID geom;

//Proto de la méthode nearCallback
void nearCallback (void *data, dGeomID o1, dGeomID o2);
//Proto de la méthode updateEntitiesAfterPhysics
void updateEntitiesAfterPhysics(scene::ISceneNode* irrSceneNode,dGeomID geom);
//Proto de la méthode BtnClicked
bool BtnClicked(gui::IGUIButton* buton);

int main()
{
    //Creation du Device
    IrrlichtDevice* device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(800, 600),32,false,false,true);
    if (device == 0)
        return 1; // Si on ne peut pas creer le device avec ses drivers on quitte

    //On récupère les objets pour simplifier le code plus tard
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
    gui::IGUIEnvironment* env = device->getGUIEnvironment();

    //Chargement des médias
    video::ITexture* Tex = driver->getTexture("../media/wall.jpg");
    video::ITexture* Tex2 = driver->getTexture("../media/wall.bmp");

    //Modification d'une texture
    Tex->getTransformation().setScale(core::vector3df(300,300,300));

    //Creation de la camera
    scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(NULL,core::vector3df(30,40,-82),core::vector3df(0,3,0),-1);

    //creation du mesh 3D de la sphere
    scene::ISceneNode* SphereSceneNode = smgr->addSphereSceneNode(5,32,NULL,1,core::vector3df(0,5.0f,-55));
    SphereSceneNode->setMaterialTexture(0,Tex2);
    SphereSceneNode->setMaterialFlag(video::EMF_LIGHTING,false);

    //Creation d'un plan 3D physique
    dCreatePlane (space,0,1,0,0);

    //initialisation des Body et Geom physique
    dBodyID Body[83];
    dGeomID Box[81];
    dGeomID Sphere;

    //Creation du body physique de la sphere
    Body[82] = dBodyCreate (world);
    dMassSetSphereTotal(&mass,6.0f,5);
    dBodySetMass(Body[82],&mass);
    dBodySetPosition(Body[82],0,5,-55);

    //Creation de la géométrie physique de la sphere
    Sphere = dCreateSphere(space, 5);
    dGeomSetBody(Sphere,Body[82]);

    //On va parramétrer la physique en même temps que la création de tout les cubes
    scene::ISceneNode* CubeSceneNode[81];
    s32 NbsCubeSceneNode=0;
    for (f32 y=0.0f;y<=40.0f;y+=5.0f)
    {
        for(f32 x=-40.0f+y;x<=40.0f-y;x+=5.0f)
        {
            //Creation des meshs des cubes
            CubeSceneNode[NbsCubeSceneNode] = smgr->addCubeSceneNode(5,NULL,-1,core::vector3df(x,y+2.5f,0));
            CubeSceneNode[NbsCubeSceneNode]->setMaterialTexture(0,Tex2);
            CubeSceneNode[NbsCubeSceneNode]->setMaterialFlag(video::EMF_LIGHTING,false);

            //Creation du Body physique des cubes
            Body[NbsCubeSceneNode] = dBodyCreate(world);
            dMassSetBoxTotal(&mass,5,5,5,5);
            dBodySetPosition(Body[NbsCubeSceneNode],x,y+2.5f,0);
            dBodySetAutoDisableFlag(Body[NbsCubeSceneNode],true);
            dBodyDisable(Body[NbsCubeSceneNode]);
            dBodySetAutoDisableLinearThreshold(Body[NbsCubeSceneNode],0.2);
            dBodySetAutoDisableAngularThreshold(Body[NbsCubeSceneNode],0.2);

            //Creation de la géométrie physique des cubes
            Box[NbsCubeSceneNode] = dCreateBox(space,5,5,5);
            dGeomSetBody(Box[NbsCubeSceneNode],Body[NbsCubeSceneNode]);

            //Incrémentation de la variable NbsCubeSceneNode
            NbsCubeSceneNode++;
        }
    }

    //On creer un mesh cubique qu'on applatira par le scale pour le sol
    scene::ISceneNode* SolSceneNode = smgr->addCubeSceneNode(10000,NULL,-1,core::vector3df(0,0,0));
    SolSceneNode->setMaterialTexture(0,Tex);
    SolSceneNode->setMaterialFlag(video::EMF_LIGHTING,false);
    SolSceneNode->setScale(core::vector3df(1,0.0f,1));

    //On ajoute un boutton pour expulser notre boule
    gui::IGUIButton* Buton = env->addButton(core::rect<s32>(10,10,120,35),NULL,100,L"Boum");

    //initialise la variable lastFPS
    int lastFPS = -1;

    //On parramètre la gravité de la physique et le nombre de frame qu'elle va saute pour les calculs
    dWorldSetGravity (world,0,-3,0);

    //Boucle principale
    while(device->run())
    if (device->isWindowActive())
    {
        //Calcul de notre physique
        dSpaceCollide (space, 0, &nearCallback);
        dWorldStepFast1(world,0.04f,1);
        dJointGroupEmpty(contactgroup);

        //On met à jour la boule en position + rotation grace à notre physique
        updateEntitiesAfterPhysics(SphereSceneNode,Sphere);

        //On met à jour les cubes en position + rotation grace à notre physique
        for (int i=0; i<81; i++)
        {
            updateEntitiesAfterPhysics(CubeSceneNode[i],Box[i]);
        }

        //début des calculs d'irrlicht
        driver->beginScene(true, true, video::SColor(10,10,10,10));

        //On test si le bouton de la gui est appuyé
        if (BtnClicked(Buton))
        {
            dBodyAddForce(Body[82],0,3000,10000);
        }

        //On dessine tout
        smgr->drawAll();

        //On dessine la gui
        env->drawAll();

        //Fin des calculs d'irrlicht
        driver->endScene();

        //On récupère le FPS dans la variable fps
        int fps = driver->getFPS();

        //On affiche le fps dans la barre de titre
        if (lastFPS != fps)
        {
            core::stringw str = L"Irrlicht Engine with ODE [";
            str += driver->getName();
            str += "] FPS:";
            str += fps;

            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
    }

    //On supprime le device d'irrlicht
    device->drop();

    //On supprime les groupes de joints de Ode
    dJointGroupEmpty (contactgroup);
    dJointGroupDestroy (contactgroup);

    //On supprime la géométrie de la sphère
    dGeomDestroy (Sphere);

    //On supprime les géométries des cubes
    for (int i=0;i<81;i++)
    {
        dGeomDestroy(Box[i]);
    }

    //On détruit l'espace d'ode
    dSpaceDestroy (space);

    //On détruit le monde d'ode
    dWorldDestroy (world);

    //retour 0 pour quitter
    return 0;
}

//La mise à jour de la physique se fait aussi par la mise à jour des objets
void updateEntitiesAfterPhysics(scene::ISceneNode* irrSceneNode,dGeomID geom)
{
    //Ici on met à jour la position
    irrSceneNode->setPosition(core::vector3df((f32)dGeomGetPosition(geom)[0],(f32)dGeomGetPosition(geom)[1],(f32)dGeomGetPosition(geom)[2]));

    //Un quaternion Ode pour les calculs de rotations
    dQuaternion result;

    //On écrit les rotations de ode dans le quaternion result
    dGeomGetQuaternion(geom,result);

    //Un quaternion Irrlicht pour convertir le quaternion de Ode
    core::quaternion quat;

    //On converti le quaternion de ode en quaternion Irrlicht
    quat.W = result[0];
    quat.X = result[1];
    quat.Y = result[2];
    quat.Z = result[3];

    //Vecteur Rot pour le calcul de la rotation
    core::vector3df Rot;

    //On bascule notre quaternion en vecteur d'angle euler
    quat.toEuler(Rot);

    //On converti de radian vers degré
    Rot.X = Rot.X / 3.14f * 180;
    Rot.Y = Rot.Y / 3.14f * 180;
    Rot.Z = Rot.Z / 3.14f * 180;

    //Ici on met à jour la rotation
    irrSceneNode->setRotation(Rot);
}

//Le fameux callBack de calcul pour la physique (merci les samples de ode)
void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  assert(o1);
  assert(o2);

  if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
  {
    //Y'a-t-il une collision dans l'espace
    dSpaceCollide2(o1,o2,data,&nearCallback);
    return;
  }

  const int N = 32;
  dContact contact[N];
  int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact));
  if (n > 0)
  {
    for (int i=0; i<n; i++)
    {
      contact[i].surface.slip1 = 0.7;
      contact[i].surface.slip2 = 0.7;
      contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1 | dContactSlip1 | dContactSlip2;
      contact[i].surface.mu = 50.0; // was: dInfinity
      contact[i].surface.soft_erp = 0.97;
      contact[i].surface.soft_cfm = 0.2;
      dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
      dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2));
    }
  }
}

//Si on veut pas passer par les events ont peut bidouiller se genre de méthode
bool BtnClicked(gui::IGUIButton* buton)
{
    static bool AncienClic;

    if (AncienClic==true && buton->isPressed()==false)
    {
        AncienClic=buton->isPressed();
        return true;
    }
    else
    {
        AncienClic=buton->isPressed();
        return false;
    }
}


Voilou Bon code et @+


Config : I5 2400, ATI HD6870 1Go DDR5, 4Go DDR3.
Single Boot : Windows Seven.

Hors ligne


#1 

11-10-2006 17:19:47

DeusXL
Abonné
Lieu: Paris
Date d'inscription: 27-09-2006
Messages: 174

Salut ça a l'air tout bon ça,
Je n'ai pas encore pu tester mais sache que la gestion des threads sous UNIX (POSIX) c'est avec la fonction "fork()".
Concrètement, tu fais :

Code:

#include <unistd.h>
//Code
pid_t i = fork();
if(i > 0)
 //Premier thread principal, la variable i contient l'ID du thread fils
else if(i == 0)
 //thread secondaire
else
 //bug

Enfin ça c'est des souvenirs vieux de 3 ans donc j'espère que c'est bien ça.


Fanatique d'Irrlicht + Fanatique de Mono + Fanatique de Linux => Créateur d'Irrlicht .NET CP bien sûr !
Version actuelle d'Irrlicht .NET CP : 0.8, Version en test : 0.9.

Hors ligne


#2 

14-10-2006 18:51:52

kedu
Modérateur
Date d'inscription: 23-09-2006
Messages: 155

Bravo pour ce code, les amateurs de c++ apprécieront ;-)

Hors ligne


#3 

23-10-2006 17:53:28

Heavymetal
Petit nouveau
Date d'inscription: 23-10-2006
Messages: 3

fork() ne cree pas des threads mais des processus... ce qui est bien different...
La creation d'un processus fils est beaucoup plus gourmande en temps et memoire, car il y a une recopie du contexte d'execution du processus pere.
=> man fork

Hors ligne


#4 

23-10-2006 18:31:57

kedu
Modérateur
Date d'inscription: 23-09-2006
Messages: 155

Merci de la précision HeavyMetal ! Aurais-tu la possibilité de proposer une version corrigée du code avec de "vrais" threads ?

Hors ligne


#5 

23-10-2006 18:50:51

Heavymetal
Petit nouveau
Date d'inscription: 23-10-2006
Messages: 3

J'en aurai surtout pas le temps.
Je vous conseille le tutorial (trouve' vite fait grace a google) :
http://yolinux.com/TUTORIALS/LinuxTutor … reads.html
Cela va ensuite poser des problemes de portabilites sous Windows.
Je ne pense pas que la libpthread soit portee sous windows...
Quoique, il faudrait creuser du cote' de http://sourceware.org/pthreads-win32/

Hors ligne


#6 

24-10-2006 07:37:24

DeusXL
Abonné
Lieu: Paris
Date d'inscription: 27-09-2006
Messages: 174

Heavymetal :

fork() ne cree pas des threads mais des processus... ce qui est bien different...
La creation d'un processus fils est beaucoup plus gourmande en temps et memoire, car il y a une recopie du contexte d'execution du processus pere.
=> man fork


Autant pour moi, je me souvenais de cette histoire que fork ne créait pas des threads cependant il m'avait semblé comprendre que dans ce cas c'était souvent conseillé...

Maintenant toute solution autre peut être plus commode, je n'en doute pas *s'en va réviser ses bases de la programmation Linux* smile


Fanatique d'Irrlicht + Fanatique de Mono + Fanatique de Linux => Créateur d'Irrlicht .NET CP bien sûr !
Version actuelle d'Irrlicht .NET CP : 0.8, Version en test : 0.9.

Hors ligne


#7 

24-10-2006 16:17:26

Metos
Petit nouveau
Date d'inscription: 20-10-2006
Messages: 3

Salut,
très interressant.
je regarde de long en large wink je viens de me peter les dents sur newton avec une terrain et un bete objet dessus.
alors on va voir avec ogre et cette exemple ci.

thx

Hors ligne


#8 

04-11-2006 16:28:48

diOxy
Abonné
Date d'inscription: 10-10-2006
Messages: 153

Metos :

Salut,
très interressant.
je regarde de long en large wink je viens de me peter les dents sur newton avec une terrain et un bete objet dessus.
alors on va voir avec ogre et cette exemple ci.

thx


Je suppose que tu voulais dire ODE wink

Quand à Ogre, j'aime aussi. Simplement son wrapper c# est a la traine.

Hors ligne


#9 

04-11-2006 17:46:05

Dekron
Membre
Lieu: Orléans
Date d'inscription: 21-10-2006
Messages: 46
Site web

Au fait ... ce code sert à quoi exactement ? Il montre comment intégrer un moteur physique ( en l'occurence ode ) à irrlicht ?


Visitez Arcis : MMORPG ammateur utilisant irrlicht !
Etudiant ingénieur, maitrise C++, connaissances python & php.

Hors ligne


#10 

04-11-2006 18:22:40

Copland
Modérateur
Lieu: ZarbiLand
Date d'inscription: 22-09-2006
Messages: 657
Site web

Yep Dekron, un code qui permet de faire fonctionner Ode et Irrlicht ensemble.
C'est juste un petit essai simple avec un mur de briques et une boule (également programmé par duke et moi même en C# avec thread).


Config : I5 2400, ATI HD6870 1Go DDR5, 4Go DDR3.
Single Boot : Windows Seven.

Hors ligne


#11 

05-11-2006 14:42:06

Dekron
Membre
Lieu: Orléans
Date d'inscription: 21-10-2006
Messages: 46
Site web

tres sympa ca, justement moi qui me demandait comment on faisait pour itégrer un moteur physique à un moteur graphique smile


Visitez Arcis : MMORPG ammateur utilisant irrlicht !
Etudiant ingénieur, maitrise C++, connaissances python & php.

Hors ligne


#12 

09-12-2006 21:51:09

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

salut,

je réagit a la discussion sur les threads Unix, il faut bien faire la différence entre un fork (création d'un nouveau processus) et un thread
il est inexact de dire que l'équivalent d'un thread windows est un fork, les deux existent sous linux, en fait l'ordonancement des threads se fait directement dans le noyau, alors que windows ne le prévoit pas nativement

pour faire des threads portables linux/windows, le mieux est d'utiliser des threads Posix, pour lesquels il existe une dll

je poste quelques examples des que je remet la main dessus

Dernière modification par Jerry Kan (09-12-2006 21:51:55)

Hors ligne


#13 

10-12-2006 12:08:55

smeagol
Membre
Date d'inscription: 30-10-2006
Messages: 34

Les thread posix s'utilise avec pthread.h. Je vais vous passer un header très sympathique qui permet d'utiliser les thread sous win et linux.

Code:

#ifndef MY_THREAD_H

#define MY_THREAD_H



//Ces macros servent à uniformiser certaines fonctionnalités entre Windows et Linux.

#ifdef WIN32 //macro version Windows



#   include <windows.h>



    //definition des threads



#   define callback_t                       unsigned long __stdcall



#   define thread_t                         HANDLE*

#   define thread_create(thrd, fct, param)  thrd = new HANDLE;\

                                            *(thrd) = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(fct),(param),0,NULL)

#   define thread_delete(thrd)              CloseHandle(*(thrd));\

                                            delete (thrd);

#   define thread_wait_close(thrd)          WaitForMultipleObjects(1, *thrd, TRUE, INFINITE)



    //definition des semaphores et mutex



#   define mutex_t                          CRITICAL_SECTION

#   define mutex_init(mutex)                InitializeCriticalSection((mutex))

#   define mutex_lock(mutex)                EnterCriticalSection((mutex))

#   define mutex_unlock(mutex)              LeaveCriticalSection((mutex))

#   define mutex_delete(mutex)              DeleteCriticalSection((mutex))



#   define semaphore_t                      HANDLE

#   define semaphore_init(sema, max, place) ((sema) = CreateSemaphore(NULL, (max), (place), NULL))

#   define semaphore_lock(sema)             WaitForSingleObject((sema), INFINITE)

#   define semaphore_unlock(sema)           ReleaseSemaphore((sema), 1, NULL)

#   define semaphore_delete(sema)           CloseHandle(sema)



#else //macro version Linux



    //definition des threads



#   include <pthread.h>



#   define callback_t                       void * 



#   define thread_t                         pthread_t*

#   define thread_create(thrd, fct, param)  (thrd) = new pthread_t;\

                                            pthread_create((thrd), NULL, (fct), (param))

#   define thread_delete(thrd)              delete (thrd);

#   define thread_wait_close(thrd)          pthread_join(*thrd, NULL)



    //definition des semaphores et mutex



#   include <semaphore.h>



#   define mutex_t                          pthread_mutex_t *

#   define mutex_init(mutex)                (mutex) = new pthread_mutex_t;\

                                            pthread_mutex_init ((mutex), NULL)

#   define mutex_lock(mutex)                pthread_mutex_lock((mutex))

#   define mutex_unlock(mutex)              pthread_mutex_unlock((mutex))

#   define mutex_delete(mutex)              pthread_mutex_destroy((mutex));\

                                            delete ((mutex))



#   define semaphore_t                      sem_t*

#   define semaphore_init(sema, max, place) (sema) = new sem_t;\

                                            sem_init ((sema), (max), (place))

#   define semaphore_lock(sema)             sem_wait((sema))

#   define semaphore_unlock(sema)           sem_post((sema))

#   define semaphore_delete(sema)           sem_destroy((sema));\

                                            delete ((sema))



#endif



#endif

pour creer un thread vous faite:

Code:

//la fonction lancer dans le thread
callback_t mafonc(void* ptr);

//dans la fonc main
int main()
{
    pthread_t thrd;
    thread_create(thrd, mafonc, 'ptr');
    //'ptr' est un pointeur qui sera envoyer en parametre (ne pas oublier de le caster)
    //il peut etre egal a NULL
    
    return 0;
}

Les mutex et les semaphore son des macro qui permette de rentrer dans des section critique.(les semaphore permette a plusieurs processus de rentrer en section critique. Il doivent être global par rapport au fonction threader

il suffit de creer le type

Code:

mutex_t mutex;    //en global
mutex_init(mutex);    //dans la fonction main

pour entrer en section critiques

Code:

mutex_lock(mutex);

pour en sortir

Code:

mutex_unlock(mutex);

pour supprimer le thread;

Code:

mutex_delete(mutex)

pour les semaphores s'est la même chose mais 'max' represente le maximum d'entrer en section critique et 'place' a combien est initialisé le conteur.

Je ne dit pas que s'est parfait. Car elle n'est pas entièrement tester mais sa marche pas mal

Dernière modification par smeagol (10-12-2006 12:11:56)

Hors ligne


#14 

10-12-2006 12:19:23

izguit
Administrateur
Lieu: 127.0.0.1
Date d'inscription: 14-09-2006
Messages: 306
Site web

@ smeagol : tu pourrais peut être créer un nouveau thread ca me paraît bien utile tout ça smile


Athlon 64 3000+ // 1Go RAM // Geforce 6600GT 128Mo
Turion 64 X2 // 1Go RAM // ATI X1250

Hors ligne


#15 

11-12-2006 06:34:34

smeagol
Membre
Date d'inscription: 30-10-2006
Messages: 34

je n'est pas trop le temps aujourd'hui je vous fait une tuto pour vendredi au plus tard.

je tient à préciser l'importance des mutex et sémaphore. Example:

dons un server multi thread. une position d'un joueur est en x=0 et y=0

un thread va déplacer de 5 sur x
puis un autre thread de 2.
et enfin un dernier de -7

si tout c'est bien passer on retourne en position initial.

mais il faut savoir que le processeur de vos machine peux permuter à n'importe quel moment.
clos si il permute pendant qu'il n'a pas fini d'ajouter 5 qu'il fait -7 mais la encore il n'a pas terminé qu'il permute aussi et il fait +2. Pendant qu'il fait plus 2 il revient au thread 1 et le termine sauf que la valeur dans la mémoire est à 2.

on se retrouve donc à faire un 2+2+2  et la position final est 6.

on apel l'objet de position une section critique

Comment faire donc pour éviter ces section critique. et bien de déclarer un mutex global au thread. Et faire un lock avant de rentrer en section critique. Ainsi 1 seul thread (Ou plusieurs avec les sémaphore) peu entrer dedans.

je tiens à préciser que seul les outils prédéfinis par  C/C++ comme le mutex ou autre sont fiable. tous les autres créer pas vous même on des chances de créer des interblocages ou autres problèmes. Un mutex utilise des instructions spécials sur le processeur.

Hors ligne


#16 

13-01-2007 11:51:47

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

Copland, tu aurai la ligne de commande qui compile ton programme ?

j'ai fait quelques essais et j'ai des trucs manquants, et les exemples fournis par ode sont compilés avec 3 ligne de charabia smile

Hors ligne


#17 

13-01-2007 12:56:56

Copland
Modérateur
Lieu: ZarbiLand
Date d'inscription: 22-09-2006
Messages: 657
Site web

Je l'ai compilé sous Code::Blocks si mes souvenirs sont bon, c'est plus facile pour parramettrer l'ide façon Visual C++.


Config : I5 2400, ATI HD6870 1Go DDR5, 4Go DDR3.
Single Boot : Windows Seven.

Hors ligne


#18 

13-01-2007 18:34:28

Jerry Kan
Habitué
Date d'inscription: 21-11-2006
Messages: 265

ok, si je trouve je posterai,

pour l'instant ca compile sans histoire mais ca me fait une erreur de segmentation, a l'initialisation, ya un truc que j'ai pas du lier sad

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
881 membres
1427 sujets
11117 messages
Dernier membre inscrit: Bidule
52 invités en ligne
Aucun membre connecté
RSS Feed