I am trying to define the following callback from Nim:
static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
int i;
//-- Get the body's ID
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
//-- If they are connected by a joint, no collision detection is done. Finish
if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) {
return;
}
//-- Configure the properties for the contact points
dContact contact[MAX_CONTACTS];
for (i=0; i<MAX_CONTACTS; i++) {
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = MU;
contact[i].surface.mu2 = MU2;
contact[i].surface.bounce = BOUNCE;
contact[i].surface.bounce_vel = BOUNCE_VEL;
contact[i].surface.soft_cfm = SOFT_CFM;
}
//-- Get the contact points
int numc = dCollide (o1,o2,MAX_CONTACTS,&contact[0].geom, sizeof(dContact));
//-- If there are at least one contact point...
if (numc!=0) {
//-- For every contact point a joint should be created
for (i=0; i<numc; i++) {
//-- Create the joint and add it to the contact group
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
//-- Set the articulation between the two bodies
dJointAttach (c,b1,b2);
}
}
}
In the C example, both world and contactgroup are global.
I tried to define this callback using a closure like this:
proc genNearCallBack(world:dWorldID, contactgroup:dJointGroupID):dNearCallback =
let world = world
let contactgroup = contactgroup
return proc( data:pointer, o1,o2:dGeomID) {.exportc,cdecl.} =
#[
Callback function invoked by the dSpaceCollide function when two objects
are about to collide
The contact points should be found and a special contact joints should be
added. After that simulation step, the contact joints should be removed
]#
# Get the body's ID
var b1 = dGeomGetBody(o1)
var b2 = dGeomGetBody(o2)
# If they are connected by a joint, no collision detection is done. Finish
if b1 != nil and b2 != nil and (dAreConnectedExcluding(b1,b2,dJointTypeContact.cint) == 1):
discard ""
else:
# Configure the properties for the contact points
var contact = newSeq[dContact]( MAX_CONTACTS )
for i in 0..<MAX_CONTACTS:
contact[i].surface.mode = dContactBounce.cint + dContactSoftCFM.cint #dContactBounce | dContactSoftCFM
contact[i].surface.mu = MU
contact[i].surface.mu2 = MU2
contact[i].surface.bounce = BOUNCE
contact[i].surface.bounce_vel = BOUNCE_VEL
contact[i].surface.soft_cfm = SOFT_CFM
# Get the contact points
let numc = dCollide(o1, o2, MAX_CONTACTS, contact[0].geom.unsafeAddr, sizeof(dContact).cint)
# If there are at least one contact point...
if numc != 0:
# For every contact point a joint should be created
for i in 0..<numc:
# Create the joint and add it to the contact group
var c = dJointCreateContact(world,contactgroup,contact[i].unsafeAddr)
# Set the articulation between the two bodies
dJointAttach(c,b1,b2)
and I am getting the mentioned error:
Error: illegal capture 'world' because ':anonymous' has the calling convention: <cdecl>
It is simply not possible or to do it because of the calling convention or is it that I am not doing the closure properly?
Cheers
world must be a parameter of your internal "closure".
Either you use {.closure.} and when the compiler sees that world is capture from the external context it will allocate a copy on the heap.
Or you use {.nimcall.} or {.cdecl.} and all the values captured must have a infinite lifetime (i.e. be globals) but in your case you are trying to capture let world = world which has the lifetime of the function.