FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

DerelictODE - collision issue

 
Post new topic   Reply to topic     Forum Index -> Derelict
View previous topic :: View next topic  
Author Message
Pishtaco



Joined: 21 Aug 2009
Posts: 3

PostPosted: Fri Aug 21, 2009 12:10 pm    Post subject: DerelictODE - collision issue Reply with quote

Hello,

First of all, thanks very much for Derelict.

I'm trying to get an ODE tutorial about blocks falling on a plane (here) working with D. I'm afraid I'm proceeding mostly by trial and error, since I have just started with D and know very little C++. My main experience is with Python, and in fact my goal is to port a game I'm working on from Python to D.

I'm having a problem with the dCollide function. The ODE documentation lists it like this:
Code:
int dCollide (dGeomID o1, dGeomID o2, int flags, dContactGeom *contact, int skip);

where the fourth argument is more or less a pointer to an array of contactgeoms, and the fifth one is the space between adjacent contactgeoms in the array (sorry if I'm using the terminology wrong here).

But with derelict the compiler wants only four arguments, and looking in odefuncs.d I found this:
Code:
int function(dGeomID, dGeomID, int, dContactGeom*) dCollide;


Here's my code:
Code:
void handle_collision_between(dGeomID obj_0, dGeomID obj_1)
    {
      const int MAX_CONTACTS = 10;
      dContactGeom[MAX_CONTACTS] contact_geoms;
      dContact[MAX_CONTACTS] contacts;
      int numc = dCollide(obj_0, obj_1, MAX_CONTACTS, contact_geoms.ptr);
      if (numc>0)
      {
         dBodyID body_1 = dGeomGetBody(obj_0);
         dBodyID body_2 = dGeomGetBody(obj_1);
            for (int i = 0; i < numc; i++)
            {
                contacts[i].geom = contact_geoms[i];
                contacts[i].surface.mode = dContactBounce | dContactSoftCFM;
                contacts[i].surface.mu = 5; //dInfinity;
                contacts[i].surface.mu2 = 0;
                contacts[i].surface.bounce = 0.5;
                contacts[i].surface.bounce_vel = 0.1;
                contacts[i].surface.soft_cfm = 0.01;
                dJointID c = dJointCreateContact(world, contact_group, contacts.ptr+i);
                dJointAttach(c, body_1, body_2);
            }
      }
    }
}

It compiles fine, but crashes at the first collision with "object.Exception: Access Violation - Write at address 0x24f998". If I change MAX_CONTACTS to 1, and so only use the first entry in the array, then it actually runs fine and the simulation looks reasonable; but I think that limiting contacts between geoms to one contact must be bad for the stability.

There's also one other thing I noticed, which is that the compiler doesn't recognize the ODE constant "dInfinity".
Back to top
View user's profile Send private message
aldacron



Joined: 05 May 2004
Posts: 1322
Location: Seoul, South Korea

PostPosted: Fri Aug 21, 2009 8:40 pm    Post subject: Reply with quote

I've fixed the function declaration in the trunk, so it should work for you now. However, a quick "Find in Files" on the ODE headers failed to produce a hit for dInfinity. If it's not in the headers, it won't be in the bindings.
_________________
The One With D | The One With Aldacron | D Bits
Back to top
View user's profile Send private message Send e-mail
Pishtaco



Joined: 21 Aug 2009
Posts: 3

PostPosted: Sat Aug 22, 2009 5:19 am    Post subject: Reply with quote

Thanks! Now it's working nicely.

For anyone interested, here's the full collision example.
It's based on the ODE tutorial here: http://artis.imag.fr/Membres/Xavier.Decoret/resources/ode/tutorial1.html
and the SDL tutorial at: http://dmedia.dprogramming.com

Code:
import derelict.sdl.sdl;
import derelict.opengl.gl;
import derelict.opengl.glu;
import derelict.ode.ode;

import tango.time.StopWatch;
import tango.math.Math;
import tango.math.random.Kiss;

const int   xResolution     = 640;
const int   yResolution     = 480;
const int   bitsPerPixel    = 24;
const float dt_MAX = 0.005;

void init()
{
    DerelictSDL.load();
    DerelictGL.load();
    DerelictGLU.load();
   DerelictODE.load();
   dInitODE(); // Maybe need this

    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS,true);
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,4);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_SetVideoMode(xResolution, yResolution, bitsPerPixel, SDL_OPENGL); // | SDL_FULLSCREEN);
    SDL_WM_SetCaption("ODE example", null);
}

void cleanup() {
    SDL_Quit();
    DerelictGLU.unload();
    DerelictGL.unload();
    DerelictSDL.unload();
    DerelictODE.unload();
}

int main(char[][] args)
{
    init();
    scope(exit) cleanup();

    // Create ODE world and space
    dWorldID world = dWorldCreate();
    dSpaceID space = dHashSpaceCreate(cast(dSpaceID) 0);
    dWorldSetGravity(world, 0, -0.981, 0);
    dJointGroupID contact_group = dJointGroupCreate(0);
    Model model = new Model();
    model.world = world;
    model.space = space;
    model.contact_group = contact_group;

    // Create a floor
    dGeomID plane = dCreatePlane(space,0,1,0,0);

    // Create cubes
    const int cube_count = 80;
    Cube[cube_count] cubes;
    for (int i = 0; i < cube_count; i++)
    {
        cubes[i] = new Cube(world,space,3,1,1,1.5);
        cubes[i].set_position(cast(float)i/3-10,5+3*i,cast(float)i/10);
        cubes[i].color[] = [Kiss.instance.toInt(256),Kiss.instance.toInt(256),Kiss.instance.toInt(256)];
        //(random number generator)
    }

    GeometryRenderer geometry_renderer = new GeometryRenderer();

    StopWatch stopwatch;
    stopwatch.start();
    ulong last_time, current_time;  // measured in micro seconds
    last_time = stopwatch.microsec();
    float elapsed, dt;
    int step_count;

    mainLoop:
    while (true)
    {
        SDL_Event event;

        // handle all SDL events that we might have received in this loop iteration
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_QUIT: // user has clicked on the window's close button
                    break mainLoop;

                case SDL_KEYDOWN:
                    break mainLoop;

                default:
                    break;
            }
        }

        // SIMULATION
        current_time = stopwatch.microsec();
        elapsed = cast(float)(current_time - last_time)/1000000; // microseconds to seconds
        last_time = current_time;
        step_count = cast(int)floor(elapsed/dt_MAX)+1;
        dt = elapsed / step_count;
        step_count = min(step_count, 10);

        for (int i = 0; i<step_count; i++)
        {
            // Detect & deal with collisions
            dSpaceCollide(space, &model, &near_callback);
            // Step world
            dWorldQuickStep(world, dt);
            // Remove all temporary collision joints
            dJointGroupEmpty(contact_group);
        }

        // draw stuff
        setup_GL();
        geometry_renderer.draw_plane();
        for (int i = 0; i < cube_count; i++)
        {
            cubes[i].render(geometry_renderer);
        }
        SDL_GL_SwapBuffers();

        SDL_Delay(10);
    }
    return 0;
}

class Model //hack to get a way of passing local world variables to callback function
{
    dWorldID world;
    dSpaceID space;
    dJointGroupID contact_group;

    void handle_collision_between(dGeomID obj_0, dGeomID obj_1)
    {
      const int MAX_CONTACTS = 10;
      dContactGeom[MAX_CONTACTS] contact_geoms;
      dContact[MAX_CONTACTS] contacts;
      int numc = dCollide(obj_0, obj_1, MAX_CONTACTS, contact_geoms.ptr, dContactGeom.sizeof);
      if (numc>0)
      {
         dBodyID body_1 = dGeomGetBody(obj_0);
         dBodyID body_2 = dGeomGetBody(obj_1);
            for (int i = 0; i < numc; i++)
            {
                contacts[i].geom = contact_geoms[i];
                contacts[i].surface.mode = dContactBounce | dContactSoftCFM;
                // friction parameter
                contacts[i].surface.mu = 10;
                contacts[i].surface.mu2 = 0;
                // bounce is the amount of "bouncyness".
                contacts[i].surface.bounce = 0.5;
                // bounce_vel is the minimum incoming velocity to cause a bounce
                contacts[i].surface.bounce_vel = 0.2;
                // constraint force mixing parameter
                contacts[i].surface.soft_cfm = 0.001;
                dJointID c = dJointCreateContact(world, contact_group, contacts.ptr+i);
                dJointAttach(c, body_1, body_2);
            }
      }
    }
}

// "extern(C) below ...  see
// http://www.dsource.org/forums/viewtopic.php?t=4625&sid=3b902645a7abfd5a3fc44ef85ca2918d
extern(C) void near_callback(void* data, dGeomID obj_0, dGeomID obj_1)
{
    Model* model = cast(Model*) data;
    model.handle_collision_between(obj_0, obj_1);
}

class Entity
{
    dBodyID bbody;
    dGeomID geom;

    void render(GeometryRenderer gr)
    {
        glPushMatrix();
        dReal* p = dBodyGetPosition(this.bbody);
        dReal* r = dBodyGetRotation(this.bbody);
        float[16] m;
        m[ 0] = r[ 0];m[ 1] = r[ 4];m[ 2] = r[ 8];m[ 3] = 0;
        m[ 4] = r[ 1];m[ 5] = r[ 5];m[ 6] = r[ 9];m[ 7] = 0;
        m[ 8] = r[ 2];m[ 9] = r[ 6];m[10] = r[10];m[11] = 0;
        m[12] = p[ 0];m[13] = p[ 1];m[14] = p[ 2];m[15] = 1;
        glMultMatrixf(m.ptr);
        render_in_local_frame(gr);
        glPopMatrix();
    }

    void set_position(dReal x, dReal y, dReal z)
    {
        dBodySetPosition(bbody,x,y,z);
    }

   void render_in_local_frame(GeometryRenderer gr)
   {
   }
}

class Cube : Entity
{
    ubyte[3] color;

    this(dWorldID world, dSpaceID space, dReal width, dReal height, dReal depth, dReal mass)
    {
        bbody = dBodyCreate(world);
        geom = dCreateBox(space,width,height,depth);
        dMass m;
        dMassSetBox(&m,1.0f,width,height,depth);
        dMassAdjust(&m,mass);
        dBodySetMass(bbody,&m);
        dGeomSetBody(geom,bbody);
    }

    void render_in_local_frame(GeometryRenderer gr)
    {
        dVector3 lengths;
        dGeomBoxGetLengths(geom,lengths);
        glScalef(lengths[0]/2,lengths[1]/2,lengths[2]/2);
        glColor3ubv(color.ptr);
        gr.draw_cube();
    }
}

class GeometryRenderer
{
    GLfloat[] vertices = [-1, 1, -1,   -1, 1, 1,   1, 1, 1,   1, 1, -1,  // top face
                          -1, -1, -1,  1, -1, -1,  1, -1, 1,   -1, -1, 1];  // bottom face
    GLfloat[] plane_vertices = [-1, 0, -1,   -1, 0, 1,   1, 0, 1,   1, 0, -1];

    void draw_faces()
    {
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, vertices.ptr);
        glDrawArrays(GL_QUADS, 0, 8);
        glDisableClientState(GL_VERTEX_ARRAY);
    }

    void draw_cube()
    {
        glPushMatrix();

        draw_faces();

        glRotatef(90, 1, 0,0 );
        draw_faces();

        glRotatef(90, 0, 0, 1 );
        draw_faces();

        glPopMatrix();
    }

    void draw_plane()
    {
        glPushMatrix();
        glScalef(30,30,30);
        glColor3ub(250,250,150);
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, plane_vertices.ptr);
        glDrawArrays(GL_QUADS, 0, 4);
        glDisableClientState(GL_VERTEX_ARRAY);
        glPopMatrix();
    }
}

void setup_GL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90, cast(float)xResolution / yResolution, 0.5, 200);
    gluLookAt(-2,10,-7,  // eye location
                0,1,0,  // target
                0,1,0); // up vector
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glEnable(GL_DEPTH_TEST);
}

Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> Derelict All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group