Trouble with OpenGL/Ctypes and Pythonista
I am having a heck of a time trying to get a simple OpenGL example to run....this is an example that I have used on the Mac and Raspberry Pi that just draws a simple triangle. I started with example code from @omz then got stuck on the function glShaderSource. My code is on GitHub and it fails on line 86 with the error message "ctypes.ArgumentError: argument 3: <class 'TypeError'>: wrong type".
Any help you can provide would be much appreciated. I am using Python 2.7 with the latest version of Pythonista. Thanks!
You have commented out the lines that set the argtypes. It is expecting a c_void_p (by default, i think), you are giving it a character array.
I think if
argtypesare not set,
ctypesguesses the type based on what arguments you give. For example an
c_int. The default
argtypesguesses are often incorrect, so it's a good idea to set the
argtypesexplicitly. If you do that and you get a
TypeError, that means you're not passing an object of the right type.
In this case here, it looks like you're overthinking things a little when creating the char array :) In your code you write
char_arr = (c_char_p * len(shader_source)).
char *, so in this case you're creating an array of
char *s with
len(shader_source)elements. If you want to create a fixed-length char array, you should use
c_charas the element type (e. g.
c_char * len(shader_source)). But in this case I think you don't need to do any manual conversion at all -
ctypescan automatically convert a Python
bytesobject to a
c_char_p, so if you set the function's
argtypescorrectly, you can pass it the
Thanks JonB uncommenting argtypes and giving it a c_void_p it is now working....I have a different error but at least I got past that line. Thank you!
Thank you both @dgelessus and @JonB !! ..... I use to be good at C but Python has spoiled me :-). Without the OpenGLES-Pythonista project I am not even sure I would of gotten this far. What confuses me is I can't just pass glShaderSource a c-string with the shader code it is an array of string pointers, OpenGL ES function definition
But your answer(s) at least got me further down the road and I will continue to explore.
Ah, if the third parameter really is a
char **, that's a different story - I don't know anything about OpenGL and its APIs, so I assumed the double pointer was by accident.
In that case, first of all you should set the
argtypesappropriately, it will make calling the function much cleaner:
c.glShaderSource.restype = None c.glShaderSource.argtypes = [GLuint, GLsizei, POINTER(c_char_p), POINTER(GLint)]
Now you can call the function like this:
c.glShaderSource(shader, 1, byref(cast(source, c_char_p)), None)
argtypesare set, the integer arguments don't need to be manually wrapped in the required types.
byrefbehaves like the
&operator in C, it returns the address of the given object (which in this case creates a
char **). The
c_char_pis necessary because
byrefdoesn't perform any automatic conversions on its argument.
NULL), which according to the documentation means that all
sourcestrings are zero-terminated (which is the case for all C strings created by
@dgelessus thanks again!!!! That is much more elegant than the code I was using. I have now carefully gone through all the argtypes with the OpenGL function I was going to use and made sure they are correct. I have updated the code on github. Thanks!