1

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.

Kaliber64
  • 586
  • 1
  • 5
  • 16

2 Answers2

1

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)

viblo
  • 4,159
  • 4
  • 20
  • 28
  • Awsome thanks! Two reasons I couldn't have figured that out. I didn't know about that ** in c++ and I didn't know you could make an array of pointers like that. yay. One question. What does `sys.path.insert(0,'..')` do – Kaliber64 Mar 05 '13 at 02:02
  • It was to make my code find pymunk. I dont have pymunk installed in my standard python. So, the path.insert inserts the path to my local pymunk folder. In my case that was just one folder up (I had this code in the dump folder inside the pymunk source tree), but it could have been anything.. for example, the absolute path would in my case be `sys.path.insert(0, '''c:\svn\pymunk\trunk''')` – viblo Mar 05 '13 at 09:58
0

I am not sure but you use cpBodyGetAngle(body) shouldn't it be cpBodyGetAngle(bd) (same for cpBodyGetPos), since that will always decay the array to a pointer to the first element.

If this is not what you are looking for, could you describe what is not working? Does your program crash, yield unexpected results, ...

ted
  • 4,791
  • 5
  • 38
  • 84
  • The only way it works is if I send only one. I have no python array that will store these pointers so that cpp will read them. Only the first element will work. There is no crashing probably because I'm only reading. The memory its reading is most likely blank or something else entirely. – Kaliber64 Feb 21 '13 at 14:34
  • @Kaliber64: `If I make an array of these. The only one that works is the first one.`. I can't follow, have or haven't you tried to pass an array/list from python to c? Maybe you should show the code (minimal example) of what you want to pass from python to c. Anyways be sure to check out this question maybe it helps: http://stackoverflow.com/questions/2307290/pass-array-of-structs-from-python-to-c – ted Feb 21 '13 at 16:08
  • I didn't think about a structure but I'll get to work on more info. – Kaliber64 Feb 21 '13 at 18:21