From 3a8d764408130a6437616f26063031e50faeb36c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 26 May 2019 20:24:57 +0100 Subject: [PATCH] add pythonic wrapper, pyray --- raylib/richlib/__init__.py | 2 +- raylib/static/__init__.py | 1 - raylib/static/pyray.py | 50 ++++++++++++++++++++++++++++++++++++++ test_dynamic.py | 26 ++++++-------------- test_pyray.py | 30 +++++++++++++++++++++++ test_richlib.py | 11 ++++++--- test_static.py | 49 ++++++++++++------------------------- 7 files changed, 113 insertions(+), 56 deletions(-) create mode 100644 raylib/static/pyray.py create mode 100644 test_pyray.py diff --git a/raylib/richlib/__init__.py b/raylib/richlib/__init__.py index c5175eb..f079291 100755 --- a/raylib/richlib/__init__.py +++ b/raylib/richlib/__init__.py @@ -2,7 +2,7 @@ """ __version__ = '0.1' -from ..static import ffi, rl +from ..static import ffi, rl, prl #from ..dynamic import ffi, raylib as rl from ..colors import * diff --git a/raylib/static/__init__.py b/raylib/static/__init__.py index fd575dc..181d7b7 100644 --- a/raylib/static/__init__.py +++ b/raylib/static/__init__.py @@ -5,4 +5,3 @@ from .helpers import * print("RAYLIB STATIC LOADED") - diff --git a/raylib/static/pyray.py b/raylib/static/pyray.py new file mode 100644 index 0000000..2e501aa --- /dev/null +++ b/raylib/static/pyray.py @@ -0,0 +1,50 @@ +from . import rl, ffi +from ..colors import * +from inspect import ismethod,getmembers,isbuiltin +import inflection + +class PyRay: + def pointer(self, struct): + return ffi.addressof(struct) + +pyray = PyRay() + + +def makefunc(a): + #print("makefunc ",a) + def func(self, *args): + modified_args = [] + for arg in args: + #print(arg, type(arg)) + if type(arg) == str: + encoded = arg.encode('utf-8') + modified_args.append(encoded) + else: + modified_args.append(arg) + return a(*modified_args) + return func + +def makeStructHelper(struct): + def func(self, *args): + return ffi.new(f"struct {struct} *", args)[0] + return func + + +for name, attr in getmembers(rl): + print(name, attr) + uname = inflection.underscore(name).replace('3_d','_3d').replace('2_d','_2d') + if isbuiltin(attr): + #print(attr) + #print(dir(attr)) + #print(dir(attr.__repr__)) + f = makefunc(attr) + setattr(PyRay, uname, f) + #def wrap(*args): + # print("call to ",attr) + #setattr(PyRay, uname, lambda *args: print("call to ",attr)) + else: + setattr(PyRay, name, attr) + +for struct in ('Vector2','Vector3','Vector4','Camera2D', 'Camera3D', 'Quaternion', 'Color'): + f = makeStructHelper(struct) + setattr(PyRay, struct, f) \ No newline at end of file diff --git a/test_dynamic.py b/test_dynamic.py index b02d7aa..90c452c 100644 --- a/test_dynamic.py +++ b/test_dynamic.py @@ -1,47 +1,37 @@ """ -This shows how to use the CFFI dynamic (ABI) binding. Note that is slower and more likely to run into silent errors. +This shows how to use the CFFI dynamic (ABI) binding. Note that is slower and more likely to run into silent errors and segfaults. But it doesnt require any C compiler to build. """ -import pathlib -MODULE = pathlib.Path(__file__).parent - from raylib.dynamic import ffi, raylib as rl from raylib.colors import * -rl.InitWindow(800,450,b"Raylib dynamic binding test") +rl.InitWindow(800, 450, b"Raylib dynamic binding test") 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) +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 = rl.LoadImage(b"examples/models/resources/heightmap.png") texture = rl.LoadTextureFromImage(image) -mesh = rl.GenMeshHeightmap(image, [ 16, 8, 16 ]) +mesh = rl.GenMeshHeightmap(image, [16, 8, 16]) model = rl.LoadModelFromMesh(mesh) -print(model.materials) # SHOULD BE A pointer to a 'struct Material' but some is NULL pointer to 'Material' ? - +print(model.materials) # SHOULD BE A pointer to a 'struct Material' but some is NULL pointer to 'Material' ? model.materials.maps[rl.MAP_DIFFUSE].texture = texture -mapPosition = ( -8.0, 0.0, -8.0 ) rl.UnloadImage(image) - rl.SetCameraMode(camera[0], rl.CAMERA_ORBITAL) - while not rl.WindowShouldClose(): rl.UpdateCamera(camera) rl.BeginDrawing() rl.ClearBackground(RAYWHITE) rl.BeginMode3D(camera[0]) - rl.DrawModel(model, mapPosition, 1.0, RED) + rl.DrawModel(model, (-8.0, 0.0, -8.0), 1.0, RED) rl.DrawGrid(20, 1.0) rl.EndMode3D() rl.DrawText(b"This mesh should be textured", 190, 200, 20, VIOLET) rl.EndDrawing() rl.CloseWindow() - """ Previously this failed to work in the same place the ctypes binding fails, accessing materials of a model. I though it was because Python can't dynamically tell the difference between a pointer and an array. -""" \ No newline at end of file +""" diff --git a/test_pyray.py b/test_pyray.py new file mode 100644 index 0000000..a86fdbd --- /dev/null +++ b/test_pyray.py @@ -0,0 +1,30 @@ +""" +This shows how to use the Pyray wrapper around the static binding. +""" +from raylib.static.pyray import pyray as prl +from raylib.colors import * + +prl.init_window(800, 450, "Raylib texture test") +prl.set_target_fps(60) + +camera = prl.Camera3D([18.0, 16.0, 18.0], [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], 45.0, 0) +image = prl.load_image("examples/models/resources/heightmap.png") +texture = prl.load_texture_from_image(image) +mesh = prl.gen_mesh_heightmap(image, (16, 8, 16)) +model = prl.load_model_from_mesh(mesh) +model.materials.maps[prl.MAP_DIFFUSE].texture = texture + +prl.unload_image(image) +prl.set_camera_mode(camera, prl.CAMERA_ORBITAL) + +while not prl.window_should_close(): + prl.update_camera(prl.pointer(camera)) + prl.begin_drawing() + prl.clear_background(RAYWHITE) + prl.begin_mode_3d(camera) + prl.draw_model(model, (-8.0, 0.0, -8.0), 1.0, RED) + prl.draw_grid(20, 1.0) + prl.end_mode_3d() + prl.draw_text("This mesh should be textured", 190, 200, 20, VIOLET) + prl.end_drawing() +prl.close_window() diff --git a/test_richlib.py b/test_richlib.py index c1f0f30..adcda96 100644 --- a/test_richlib.py +++ b/test_richlib.py @@ -1,4 +1,5 @@ from raylib.richlib import * +from raylib.static.pyray import pyray WIDTH=800 HEIGHT=640 @@ -14,6 +15,7 @@ castle.scale.y=2 castle.scale.x=1 castle.scale.z=1 + #def init(): # set_camera_mode(camera, CAMERA_FIRST_PERSON) @@ -39,12 +41,15 @@ def draw3d(): enemy_sphere.draw() player.draw() castle.draw() - rl.DrawGrid(10, 10) + pyray.draw_grid(10, 10) def draw2d(): - rl.DrawText(b"Move player with cursors to collide", 220, 40, 20, GRAY) - rl.DrawFPS(10, 10) + pyray.draw_text("Move player with cursors to collide", 220, 40, 20, (255,0,0,255)) + rl.DrawText(b"Move player with cursors to collide", 220, 80, 20, (255,0,0,255)) + #prl.DrawFPS(10, 10) + #pyray.foo(10,10) + pyray.draw_fps(20,20) run() diff --git a/test_static.py b/test_static.py index 5f8072e..a2dcd95 100644 --- a/test_static.py +++ b/test_static.py @@ -1,48 +1,31 @@ +""" +This shows how to use the CFFI static (API) binding. It should be fast and code be as close as possible to original +C code. +""" + from raylib.static import * - -InitWindow(800,450,b"Raylib texture test") +InitWindow(800, 450, b"Raylib static texture test") 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"examples/models/resources/heightmap.png") # Load heightmap image (RAM) -print(image) -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.meshes) -print(model.meshes[1]) - -print(model.materials) -print(model.materialCount) -print(model.materials[0].maps[rl.MAP_DIFFUSE]) - -model.materials.maps[MAP_DIFFUSE].texture = texture # Set map diffuse texture -print(model.materials[0].maps[rl.MAP_DIFFUSE].value) - - -mapPosition = ( -8.0, 0.0, -8.0 ) # Define model position - -UnloadImage(image) # Unload heightmap image from RAM, already uploaded to VRAM - -SetCameraMode(camera[0], CAMERA_ORBITAL) # Set an orbital camera mode +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"examples/models/resources/heightmap.png") +texture = LoadTextureFromImage(image) +mesh = GenMeshHeightmap(image, (16, 8, 16)) +model = LoadModelFromMesh(mesh) +model.materials.maps[MAP_DIFFUSE].texture = texture +UnloadImage(image) +SetCameraMode(camera[0], CAMERA_ORBITAL) while not WindowShouldClose(): UpdateCamera(camera) BeginDrawing() ClearBackground(RAYWHITE) BeginMode3D(camera[0]) - DrawModel(model, mapPosition, 1.0, RED) + DrawModel(model, (-8.0, 0.0, -8.0), 1.0, RED) DrawGrid(20, 1.0) EndMode3D() DrawText(b"This mesh should be textured", 190, 200, 20, VIOLET) EndDrawing() -CloseWindow() \ No newline at end of file +CloseWindow()