2010-04-30 9 views
1

Je veux convertir une partie de mon code python en C++ pour la vitesse mais ce n'est pas aussi simple que de simplement faire une fonction C++ et de faire quelques appels de fonctions. Je ne sais pas comment obtenir un entier C++ à partir d'un objet entier python. J'ai un entier qui est un attribut d'un objet que je veux utiliser. J'ai aussi des entiers qui sont dans une liste dans l'objet que j'ai besoin d'utiliser.Confusion sur les extensions C++ Python. Des choses comme obtenir des valeurs C++ pour les valeurs python

Je voulais tester faire une extension C++ avec cette fonction:

def setup_framebuffer(surface,flip=False): 
    #Create texture if not done already 
    if surface.texture is None: 
     create_texture(surface) 
    #Render child to parent 
    if surface.frame_buffer is None: 
     surface.frame_buffer = glGenFramebuffersEXT(1) 
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, c_uint(int(surface.frame_buffer))) 
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, surface.texture, 0) 
    glPushAttrib(GL_VIEWPORT_BIT) 
    glViewport(0,0,surface._scale[0],surface._scale[1]) 
    glMatrixMode(GL_PROJECTION) 
    glLoadIdentity() #Load the projection matrix 
    if flip: 
     gluOrtho2D(0,surface._scale[0],surface._scale[1],0) 
    else: 
     gluOrtho2D(0,surface._scale[0],0,surface._scale[1]) 

Cette fonction appelle create_texture, donc je vais devoir passer cette fonction à la fonction C++ que je ferai avec le troisième argument. Voilà ce que j'ai jusqu'à présent, tout en essayant de suivre les informations sur la documentation python:

#include <Python.h> 
#include <GL/gl.h> 
static PyMethodDef SpamMethods[] = { 
    ... 
    {"setup_framebuffer", setup_framebuffer, METH_VARARGS,"Loads a texture from a Surface object to the OpenGL framebuffer."}, 
    ... 
    {NULL, NULL, 0, NULL}  /* Sentinel */ 
}; 
static PyObject * setup_framebuffer(PyObject *self, PyObject *args){ 
    bool flip; 
    PyObject *create_texture, *arg_list,*pyflip,*frame_buffer_id; 
    if (!PyArg_ParseTuple(args, "OOO", &surface,&pyflip,&create_texture)){ 
     return NULL; 
    } 
    if (PyObject_IsTrue(pyflip) == 1){ 
     flip = true; 
    }else{ 
     flip = false; 
    } 
    Py_XINCREF(create_texture); 
    //Create texture if not done already 
    if(texture == NULL){ 
     arglist = Py_BuildValue("(O)", surface) 
     result = PyEval_CallObject(create_texture, arglist); 
     Py_DECREF(arglist); 
     if (result == NULL){ 
     return NULL; 
     } 
     Py_DECREF(result); 
    } 
    Py_XDECREF(create_texture); 
    //Render child to parent 
    frame_buffer_id = PyObject_GetAttr(surface, Py_BuildValue("s","frame_buffer")) 
    if(surface.frame_buffer == NULL){ 
     glGenFramebuffersEXT(1,frame_buffer_id); 
    } 
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, surface.frame_buffer)); 
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, surface.texture, 0); 
    glPushAttrib(GL_VIEWPORT_BIT); 
    glViewport(0,0,surface._scale[0],surface._scale[1]); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); //Load the projection matrix 
    if (flip){ 
     gluOrtho2D(0,surface._scale[0],surface._scale[1],0); 
    }else{ 
     gluOrtho2D(0,surface._scale[0],0,surface._scale[1]); 
    } 
    Py_INCREF(Py_None); 
    return Py_None; 
} 
PyMODINIT_FUNC initcscalelib(void){ 
    PyObject *module; 
    module = Py_InitModule("cscalelib", Methods); 
    if (m == NULL){ 
     return; 
    } 
} 
int main(int argc, char *argv[]){ 
    /* Pass argv[0] to the Python interpreter */ 
    Py_SetProgramName(argv[0]); 
    /* Initialize the Python interpreter. Required. */ 
    Py_Initialize(); 
    /* Add a static module */ 
    initscalelib(); 
} 

Répondre

1

La façon d'obtenir un C int d'un entier Python est avec PyInt_AsLong() et baissés (bien que vous pouvez utiliser un C long à la place.) Pour aller dans l'autre sens, vous appelez PyInt_FromLong(). Ce n'est pas évident pour moi où dans le code que vous voulez faire cela, bien que j'ai deux ou trois d'autres commentaires au sujet de votre code:

  • Conceptuellement, PyObject_IsTrue() retourne un booléen. Ne le comparez pas à 1, utilisez-le simplement comme une valeur booléenne. Cependant, vous devez vérifier si elle a retourné une erreur, ce qui serait -1. (La vérification habituelle est < 0.) Si vous ne vérifiez pas les retours d'erreur, vous finissez par avaler l'exception, mais en laissant l'objet d'exception traîner. C'est mauvais.

  • La Py_XINCREF() de create_texture n'est pas nécessaire. Vous avez emprunté une référence au tuple args, qui possède à son tour une référence à l'objet create_texture. Il n'y a aucun moyen pour que create_texture disparaisse avant que votre fonction ne retourne. Vous avez seulement besoin de l'augmenter si vous allez le garder plus longtemps que cet appel de fonction. Si vous deviez l'augmenter, vous n'auriez pas besoin d'utiliser Py_XINCREF() car il ne sera plus jamais NULL. Et si vous deviez l'augmenter, vous devriez vous rappeler de le décréter dans votre cas de retour d'erreur, aussi bien. Au lieu de créer un argument tuple juste pour appeler PyEval_CallObject(), appelez simplement PyObject_CallFunctionObjectArgs(create_texture, arglist, NULL) ou PyObject_CallFunction(create_texture, "O", arglist).

  • Py_BuildValue("s", "frame_buffer") n'est pas vraiment le bon moyen d'obtenir une chaîne Python pour "frame_buffer". Une meilleure façon est PyString_FromString(). Cependant, ces deux renvois renvoient de nouvelles références, et PyObject_GetAttr() ne mange pas la référence au nom de l'attribut, donc vous finissez par perdre cette référence. Vous ne devez utiliser aucun de ces éléments et utiliser à la place PyObject_GetAttrString(), qui prend le nom de l'attribut en tant que const char*.

  • N'oubliez pas de vérifier la valeur de retour de toutes fonctions qui peuvent retourner une valeur d'erreur (ce qui est presque toutes les fonctions de l'API Python.) En plus PyTrue_IsTrue() vous oubliez aussi pour cela Py_BuildValue() et PyObject_GetAttr().

+0

Merci. C'était très utile. J'ai réussi à obtenir le code pour compiler bien mais il y a une erreur d'importation: ImportError: dlopen (/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/cscalelib.so , 2): Symbole non trouvé: _glBindFramebufferEXT de Referenced: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/cscalelib.so dans Expected: recherche dynamique Pourquoi doesn 't glBindFramebufferEXT fonctionne? Je n'ai pas l'idée la plus brumeuse. Mais merci beaucoup. –

+0

Oh et j'ai compilé sur Mac OSX Snow Leopard 10.6.3 –

+0

On dirait que vous avez oublié de lier à la bibliothèque qui fournit ce symbole (-lGL, peut-être.) –

2

Puis-je faire une suggestion sincère ici? Au lieu de vous lancer une centaine de lignes de code lorsque vous essayez quelque chose de nouveau, essayez d'abord le cas de test le plus simple possible. Essayez de faire fonctionner une extension C++ qui ne fait que renvoyer la valeur 123.(Choisir 0 ou 1 peut accidentellement fonctionner, j'ai donc choisi une valeur facile à reconnaître qui ne risque pas d'être un accident.) Ensuite, obtenez l'extension pour doubler un nombre que vous transmettez, puis ajoutez deux nombres, etc

Faufiler sur le problème! :-)

+0

Mon idée était d'apprendre autant que possible pour que je puisse la conversion du code dont j'ai besoin sans avoir à apprendre en petites étapes. Peut-être avez-vous raison. Merci pour la réponse. –

Questions connexes