Search code examples
c++pythonnumpychipmunkpymunk

Cast an array of pointers to other objects?


I'm trying to send an array of objects to my c library.

The object I'm trying to send is a pymunk Body.It has a pointer object embedded in it Body._body. I was able to pass a single one to my function and extract with Chipmunk functions anything I wanted. I used cpBodyGetMass just as a test and that worked.

If I make an array of these. The only one that works is the first one.

I want to be able to send the Body._body addresses as an array to my dll. I figured I could store the pointer in a c_int or c_long array and convert those addresses to the cpBody that Chipmunk wants.

Here is my Custom function

int pymunk_body(int color_id, int numof, float * values, cpBody * body){

    glBindTexture(GL_TEXTURE_2D,0);
    cpBody bd;
    float red;
    float green;
    float blue;
    float alpha;
    float sizex;
    float sizey;
    cpVect position;
    float positionx;
    float positiony;
    float rotation;

    for (int i=0;i<numof*6;i=i+6){
        bd=body[i/6];
        red=values[0+i];
        green=values[1+i];
        blue=values[2+i];
        alpha=values[3+i];
        sizex=values[4+i];
        sizey=values[5+i];
        position=cpBodyGetPos(body);
        positionx=position.x;
        positiony=position.y;
        rotation=cpBodyGetAngle(body)*180/PI;
    }

My C++ has no python wrapping so I can only send C objects. The way I've been doing this is...

    gldll[4](ctypes.c_int(add_color),
    ctypes.c_float(color[0]),
    ctypes.c_float(color[1]),
    ctypes.c_float(color[2]),
    ctypes.c_float(color[3]),
    ctypes.c_float(position[0]),
    ctypes.c_float(position[1]),
    ctypes.c_float(rotation),
    ctypes.c_float(size[0]),
    ctypes.c_float(size[1]))

and

    ni=numpy.array([self.texture.TextureID,ublur,add_color,blurSize,self.Blur+blur,textfont],"i")
    nf=numpy.array([(self.width+self.height)/2.0,color[0],color[1],color[2],color[3],position[0],position[1],rotation,self.half_width,self.half_height,scale],"f")

    gldll[2](ctypes.c_void_p(ni.ctypes.data),ctypes.c_void_p(nf.ctypes.data))

Now if I send an array of pointers. Basically an array of 4 byte ints. The cpBody body[] assumes that it must jump, in bytes the sizeof(cpBody) in the array to get to the next object. But their not inline. Its a list of random pointers to all the bodies. I need it to read the address in each array element and have it assume that there is a cpBody at that location.

If you look at the second example. I've sent an array via a single pointer. I need to send a pointer to an array of pointers and get the cpBody from each. Which means I need the array to jump only 4 bytes and read the memory address as a cpBody.


Solution

  • This is a short example on one way to send an array of pymunk.Body objects to a c lib:

    First the c code:

    #include "chipmunk.h"
    
    double mass_sum(size_t numof, cpBody ** body);
    double mass_sum(size_t numof, cpBody ** body){
        double total = 0;  
        for (int i=0; i<numof; i++){    
             total += cpBodyGetMass(body[i]);
        }
        return total;
    }
    

    Then the python code:

    from ctypes import *
    import sys
    sys.path.insert(0,'..')
    
    import pymunk 
    
    sendbody_lib = windll.LoadLibrary("sendbody.dll")
    
    cpBody = pymunk._chipmunk.cpBody
    
    mass_sum = sendbody_lib.mass_sum
    mass_sum.restype = c_double
    mass_sum.argtypes = [c_int, POINTER(POINTER(cpBody))]
    
    b1 = pymunk.Body(1, 1)
    b2 = pymunk.Body(10, 1)
    bodies = [b1._body, b2._body, b1._body]
    arr = (POINTER(cpBody) * len(bodies))(*bodies)
    
    print mass_sum(len(arr), arr)  
    

    (I had to modify the path to have my code find pymunk as you can see in the start, but that is only because I dont have it installed into python path by default)