py-sdl / py-sdl2

Python ctypes wrapper around SDL2
Other
303 stars 49 forks source link

Problem with SDL_GL_GetProcAddress() #222

Closed DeafMan1983 closed 2 years ago

DeafMan1983 commented 2 years ago

I have problem with SDL_GL_GetProcAddress()

like custom function with ctypes:

def gl_function(func_name, args_types, return_type = None):
    func = (sdl2.SDL_GL_GetProcAddress(func_name)
    func.restype = return_type
    func.argtypes = args_types
    return func

But it throws error: ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type

How do I cast with SDL_GL_GetProcAddress() example I want create function for example: GetString = gl_function("glGetString", [ctypes.c_int], ctypes.c_char_p) It means const char* glString(GLEnum type) GLEnum is int

How do I get successful with SDL_GL_GetProcAddress thanks I am sorry for disturbance :/

Kind regards

a-hurst commented 2 years ago

Hi @DeafMan1983,

I think your issue is that PySDL2 expects bytestrings instead of regular strings in Python 3, hence why you're getting a type error. If you swap out "glGetString" for b"glGetString", your code should work as intended.

That said, you may want to check out PyOpenGL if you haven't already: that's what I personally use for working with OpenGL in PySDL2 and it makes things much easier.

Hope that helps!

DeafMan1983 commented 2 years ago

@a-hurst - I think you would like to pass like in C# like example from MonoGame's FuncLoader

But I would know how does it work under Python.

def gl_function(func_name, args_types, return_type):
    sdlgl_param = ctypes.WINFUNCTYPE(func_name, args_types, return_type)
    sdlgl = sdl2.SDL_GL_GetProcAddress(func_name)
    if sdlgl == 0:
        raise Exception("Error: wrong method if you check method from binding library.")
    gl_func = sdlgl_param(sdlgl)
    gl_func.argtypes = args_types
    gl_func.restype = return_type
    return gl_func

But I got error:

Traceback (most recent call last):
  File "C:\Users\Jens\PycharmProjects\01_HelloWorld\01_HelloWorld.py", line 63, in <module>
    sys.exit(run())
  File "C:\Users\Jens\PycharmProjects\01_HelloWorld\01_HelloWorld.py", line 35, in run
    GetString = gl_function("glGetString", [ctypes.c_int32], ctypes.c_char_p)
  File "C:\Users\Jens\PycharmProjects\01_HelloWorld\01_HelloWorld.py", line 8, in gl_function
    sdlgl_param = ctypes.WINFUNCTYPE(func_name, args_types, return_type)
  File "C:\Users\Jens\scoop\apps\python\current\lib\ctypes\__init__.py", line 124, in WINFUNCTYPE
    return _win_functype_cache[(restype, argtypes, flags)]
TypeError: unhashable type: 'list'

Why I don't like PyOpenGL because it has many wrong types like glVertexAttribPointer and glBufferData - I have installed with PyOpenGL but it is not append to C/C++, Java, C# or other langauges both methods from PyOpenGL have bad parameters

I want create own method with SDL_GL_GetProcAddress() Like I show you

glBufferData(GLEnum type, "POINTER or ulong", c_void_p, GLEnum usage) is correct Example: glBufferData(GL_ARRAY_BUFFER, POINTER(vertices.nBytes * sizeof(float), c_void_p(vertices[0]), GL_STATIC_DRAW) like in C# example: glBufferData(GL_ARRAY_BUFFER, (IntPtr)(vertices.Length * sizeof(float), vertices_ptr, GL_STATIC_ARRAY) vertices_ptr was fixed statement.

a-hurst commented 2 years ago

@DeafMan1983 You're running into another type error: it looks like you're creating your WINFUNCTYPE with args_types as a list, but the ctypes docs show that you're supposed to define the type of each argument as a separate parameter.

Changing the first line of your function to

sdlgl_param = ctypes.WINFUNCTYPE(func_name, *args_types, return_type)

(note the asterisk in front of args_types) should fix the issue.

DeafMan1983 commented 2 years ago

@a-hurst Thanks I already fixed it but why does error throw me I should type for restype?

def gl_function(func_name, args_types, return_type):
    sdlgl_param = ctypes.WINFUNCTYPE(func_name, *args_types, return_type)
    sdlgl = sdl2.SDL_GL_GetProcAddress(func_name)
    if sdlgl == 0:
        raise Exception("Error: wrong method if you check method from binding library.")
    gl_func = sdlgl_param(sdlgl)
    gl_func.argtypes = args_types
    gl_func.restype = return_type
    return gl_func

And I type function GetString

GetString = gl_function("glGetString", [ctypes.c_int32], ctypes.c_char_p)

And I give end of function in while loop or after creating gl_context of SDL2

print(b"OpenGL Version is " + GetString(GL.GL_VERSION)) # It is my initial test GL_Function with SDL_GL_GetProcAddress()

Then I got exception:

TypeError: _restype_ must be a type, a callable, or None

Where do I put casting of gl_function?

a-hurst commented 2 years ago

@DeafMan1983 Just tested this out myself, looks like there were a couple issues with your code: first, "glGetString" is a regular string and not a byte string (which is what ctypes needs). Second, ctypes.CFUNCTYPE takes return type as its first argument, then argument types, and doesn't take the function name at all. Third, maybe you didn't paste the full test code, but you need to initialize an OpenGL context with SDL2 in order to get function addresses from the library. The following code does what I think you were looking for:

import sdl2
import ctypes
from OpenGL import GL

def gl_function(func_name, args_types, return_type):
    sdlgl_param = ctypes.CFUNCTYPE(return_type, *args_types)
    sdlgl = sdl2.SDL_GL_GetProcAddress(func_name)
    if sdlgl == 0:
        raise Exception("Error: wrong method if you check method from binding library.")
    gl_func = sdlgl_param(sdlgl)
    return gl_func

sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
sdl2.SDL_GL_LoadLibrary(None)
window = sdl2.SDL_CreateWindow(
    b"OpenGL", 10, 40, 32, 24, sdl2.SDL_WINDOW_OPENGL
)
ctx = sdl2.SDL_GL_CreateContext(window)
GetString = gl_function(b"glGetString", [ctypes.c_uint], ctypes.c_char_p)
print(b"OpenGL Version is " + GetString(GL.GL_VERSION))

...which gets me b'OpenGL Version is 2.1 Metal - 76.3' on my system. Hope that helps!