diff --git a/README.md b/README.md index 03700e6..90b1a3e 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Python Bindings for Raylib -These bindings use CFFI rather than ctypes. Hopefully this will be faster, the static type knowledge from the C +This uses CFFI API static bindins rather than ctypes. Hopefully this will be faster, the static type knowledge from the C headers will result in fewer bugs, and using the original headers will make it easier to maintain. Currently the goal is make usage as similar to the original C as CFFI will allow. There are a few differences you can see in the examples. Making a 'Pythonic' library would be an additional layer on top which hasn't been done yet. +See test.py and examples/*.py for how to use. + # Platforms tested * MacOS 10.12.6 @@ -16,3 +18,12 @@ done yet. * converting more examples from C to python * testing and building on more platforms +### Dynamic bindings + +I have attempted to do CFFI ABI dynamic bindings too in order to avoid the need to compile a C extension module, +but they don't work properly. They fails to work in the same place the ctypes binding fails, accessing +materials of a model, because Python can't dynamically tell the difference between a pointer and an array. There's probably + some way to specify this (e.g. in raylib_modified.h) but it's difficult to be sure we fixed them all, and the errors + are often completely silent. + + See test_static.py for the non-working example. \ No newline at end of file diff --git a/raylib/__init__.py b/raylib/__init__.py index a9830f6..da1eb0e 100644 --- a/raylib/__init__.py +++ b/raylib/__init__.py @@ -2,33 +2,9 @@ __version__ = "2.5.dev1" from ._raylib_cffi import ffi, lib as rl from _raylib_cffi.lib import * +from .colors import * +from .helpers import * + + -def Vector3(x, y, z): - return ffi.new("struct Vector3 *", [x, y, z])[0] -LIGHTGRAY =( 200, 200, 200, 255 ) -GRAY =( 130, 130, 130, 255 ) -DARKGRAY =( 80, 80, 80, 255 ) -YELLOW =( 253, 249, 0, 255 ) -GOLD =( 255, 203, 0, 255 ) -ORANGE =( 255, 161, 0, 255 ) -PINK =( 255, 109, 194, 255 ) -RED =( 230, 41, 55, 255 ) -MAROON =( 190, 33, 55, 255 ) -GREEN =( 0, 228, 48, 255 ) -LIME =( 0, 158, 47, 255 ) -DARKGREEN =( 0, 117, 44, 255 ) -SKYBLUE =( 102, 191, 255, 255 ) -BLUE =( 0, 121, 241, 255 ) -DARKBLUE =( 0, 82, 172, 255 ) -PURPLE =( 200, 122, 255, 255 ) -VIOLET =( 135, 60, 190, 255 ) -DARKPURPLE =( 112, 31, 126, 255 ) -BEIGE =( 211, 176, 131, 255 ) -BROWN =( 127, 106, 79, 255 ) -DARKBROWN =( 76, 63, 47, 255 ) -WHITE =( 255, 255, 255, 255 ) -BLACK =( 0, 0, 0, 255 ) -BLANK =( 0, 0, 0, 0 ) -MAGENTA =( 255, 0, 255, 255 ) -RAYWHITE =( 245, 245, 245, 255 ) \ No newline at end of file diff --git a/raylib/colors.py b/raylib/colors.py new file mode 100644 index 0000000..dafbc83 --- /dev/null +++ b/raylib/colors.py @@ -0,0 +1,26 @@ +LIGHTGRAY =( 200, 200, 200, 255 ) +GRAY =( 130, 130, 130, 255 ) +DARKGRAY =( 80, 80, 80, 255 ) +YELLOW =( 253, 249, 0, 255 ) +GOLD =( 255, 203, 0, 255 ) +ORANGE =( 255, 161, 0, 255 ) +PINK =( 255, 109, 194, 255 ) +RED =( 230, 41, 55, 255 ) +MAROON =( 190, 33, 55, 255 ) +GREEN =( 0, 228, 48, 255 ) +LIME =( 0, 158, 47, 255 ) +DARKGREEN =( 0, 117, 44, 255 ) +SKYBLUE =( 102, 191, 255, 255 ) +BLUE =( 0, 121, 241, 255 ) +DARKBLUE =( 0, 82, 172, 255 ) +PURPLE =( 200, 122, 255, 255 ) +VIOLET =( 135, 60, 190, 255 ) +DARKPURPLE =( 112, 31, 126, 255 ) +BEIGE =( 211, 176, 131, 255 ) +BROWN =( 127, 106, 79, 255 ) +DARKBROWN =( 76, 63, 47, 255 ) +WHITE =( 255, 255, 255, 255 ) +BLACK =( 0, 0, 0, 255 ) +BLANK =( 0, 0, 0, 0 ) +MAGENTA =( 255, 0, 255, 255 ) +RAYWHITE =( 245, 245, 245, 255 ) \ No newline at end of file diff --git a/raylib/dynamic_binding/__init__.py b/raylib/dynamic_binding/__init__.py new file mode 100644 index 0000000..181b7e8 --- /dev/null +++ b/raylib/dynamic_binding/__init__.py @@ -0,0 +1,15 @@ +""" +This is an attempt at a CFFI dynamic (ABI) binding. However, it fails to work in the exactly same place the ctypes binding fails, accessing +materials of a model. +""" + + +import pathlib +MODULE = pathlib.Path(__file__).parent.parent + +from cffi import FFI +ffi = FFI() +ffi.cdef(open(MODULE / "raylib_modified.h").read().replace('RLAPI ', '')) + +raylib = ffi.dlopen(str(MODULE)+"/dynamic_binding/libraylib.2.dylib") + diff --git a/raylib/dynamic_binding/libraylib.2.dylib b/raylib/dynamic_binding/libraylib.2.dylib new file mode 100755 index 0000000..7dbf942 Binary files /dev/null and b/raylib/dynamic_binding/libraylib.2.dylib differ diff --git a/raylib/helpers.py b/raylib/helpers.py new file mode 100644 index 0000000..76f9963 --- /dev/null +++ b/raylib/helpers.py @@ -0,0 +1,5 @@ +from ._raylib_cffi import ffi + +def Vector3(x, y, z): + return ffi.new("struct Vector3 *", [x, y, z])[0] + diff --git a/test_dynamic.py b/test_dynamic.py new file mode 100644 index 0000000..fe2fb76 --- /dev/null +++ b/test_dynamic.py @@ -0,0 +1,52 @@ +""" +This is an attempt at a CFFI dynamic (ABI) binding. However, it fails to work in the same place the ctypes binding fails, accessing +materials of a model, because Python can't dynamically tell the difference between a pointer and an array. There's probably +some way to specify this (e.g. in raylib_modified.h) but it's difficult to be sure we fixed them all, and the errors +are often completely silent. +""" +import pathlib +MODULE = pathlib.Path(__file__).parent +print(MODULE) + +from raylib.dynamic_binding import ffi, raylib as rl +from raylib.colors import * + +rl.InitWindow(800,450,b"foo") +rl.SetTargetFPS(60) + + + +camera = ffi.new("struct Camera3D *", [[ 18.0, 16.0, 18.0 ], [ 0.0, 0.0, 0.0 ], [ 0.0, 1.0, 0.0 ], 45.0, 0 ]) + +imageFile = str(MODULE / "examples/models/resources/heightmap.png").encode('utf-8') +image = rl.LoadImage(imageFile) # Load heightmap image (RAM) +print(image) +texture = rl.LoadTextureFromImage(image) # Convert image to texture (VRAM) + +mesh = rl.GenMeshHeightmap(image, [ 16, 8, 16 ]) # Generate heightmap mesh (RAM and VRAM) + +print(mesh) + +model = rl.LoadModelFromMesh(mesh) # Load model from generated mesh + +print(model.materials) # SHOULD BE A pointer to a 'struct Material' but instead is NULL pointer to 'Material' + +#model.materials[0].maps[rl.MAP_DIFFUSE].texture = texture # Set map diffuse texture +mapPosition = ( -8.0, 0.0, -8.0 ) # Define model position + +rl.UnloadImage(image) # Unload heightmap image from RAM, already uploaded to VRAM + +rl.SetCameraMode(camera[0], rl.CAMERA_ORBITAL) # Set an orbital camera mode + + +while not rl.WindowShouldClose(): + rl.UpdateCamera(camera) + rl.BeginDrawing() + rl.ClearBackground(RAYWHITE) + rl.BeginMode3D(camera[0]) + rl.DrawModel(model, mapPosition, 1.0, RED) + rl.DrawGrid(20, 1.0) + rl.EndMode3D() + rl.DrawText(b"sdfsdf", 190, 200, 20, BLACK) + rl.EndDrawing() +rl.CloseWindow() \ No newline at end of file diff --git a/test.py b/test_static.py similarity index 87% rename from test.py rename to test_static.py index a2c8d4f..e1826dc 100644 --- a/test.py +++ b/test_static.py @@ -4,17 +4,20 @@ from raylib import * InitWindow(800,450,b"foo") SetTargetFPS(60) - +print(Vector3(1,1,1)) camera = ffi.new("struct Camera3D *", [[ 18.0, 16.0, 18.0 ], [ 0.0, 0.0, 0.0 ], [ 0.0, 1.0, 0.0 ], 45.0, 0 ]) -image = LoadImage(b"resources/heightmap.png") # Load heightmap image (RAM) +image = LoadImage(b"examples/models/resources/heightmap.png") # Load heightmap image (RAM) texture = LoadTextureFromImage(image) # Convert image to texture (VRAM) mesh = GenMeshHeightmap(image, ( 16, 8, 16 )) # Generate heightmap mesh (RAM and VRAM) +print(mesh) model = LoadModelFromMesh(mesh) # Load model from generated mesh +print(model.materials) + model.materials[0].maps[MAP_DIFFUSE].texture = texture # Set map diffuse texture mapPosition = ( -8.0, 0.0, -8.0 ) # Define model position