[[https://github.com/raysan5/raylib/raw/master/logo/raylib_logo_animation.gif]]
Fully auto-generate Common Lisp bindings to [[https://www.raylib.com/][Raylib]] (as well as Raymath, Rlgl and Raygui) using [[https://github.com/borodust/claw][claw]] and [[https://github.com/bohonghuang/cffi-object][cffi-object]].
Tip: You can clone the [[https://github.com/bohonghuang/claw-raylib/tree/prebuild][prebuild]] branch to skip steps 1 and 2.
Generate the bindings using Clozure CL. \
(ql:quickload :claw-raylib/gen) (pushnew :claw-regen-adapter features) (cffi:load-foreign-library #P"/path/to/libresect.so") (claw:load-wrapper :raylib) (claw:load-wrapper :raygui) (claw:load-wrapper :rlgl)
/Notes for Windows:/
Replace the line like:
with:
HMODULE GetModuleHandleA(LPCTSTR name); FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
(let ((arch "x86_64-pc-linux-gnu") (path (merge-pathnames #P"lib/" (asdf:component-pathname (asdf:find-system '#:claw-raylib))))) (dolist (lib '("raylib" "rlgl" "raygui")) (uiop:run-program (list "gcc" "-O3" "-fPIC" "-shared" "-o" (namestring (merge-pathnames (format nil "lib~A-adapter.so" lib) path)) (namestring (merge-pathnames (format nil "lib~A-adapter.~A.c" lib arch) path))))))
Load the system. \
(ql:quickload :claw-raylib)
/Notes for SBCL:/
During this process, SBCL may consume a significant amount of memory, potentially leading to heap exhaustion. You may need to add ~--dynamic-space-size 4096~ to the SBCL command-line arguments before the first load of ~claw-raylib~.
(let ((camera (raylib:make-camera-3d :position (raylib:make-vector3 :x 10.0 :y 10.0 :z 10.0) :target (raylib:vector3-zero) :up (raylib:make-vector3 :x 0.0 :y 1.0 :z 0.0) :fovy 33.3 :projection #.(cffi:foreign-enum-value 'raylib:camera-projection :perspective))) (model (raylib:load-model "/path/to/model")) (position (raylib:vector3-zero))) (raylib:with-window ("Simple Model Viewer" (1280 720)) (loop :until (raylib:window-should-close) :do (raylib:with-drawing (raylib:update-camera camera #.(cffi:foreign-enum-value 'raylib:camera-mode :free)) (raylib:with-mode-3d camera (raylib:clear-background raylib:+raywhite+) (raylib:draw-grid 100 1.0) (rlgl:disable-backface-culling) (raylib:draw-model model position 1.0 raylib:+white+) (rlgl:enable-backface-culling))))))
A complete [[file:examples/raygui/controls-test-suite.lisp][example]] of using ~claw-raylib~ to rewrite the [[https://github.com/raysan5/raygui/blob/master/examples/controls_test_suite/controls_test_suite.c][control test suite]] from Raygui is available. ** High-performance Thanks to the adapters generated by ~claw~, ~claw-raylib~ does not use ~cffi-libffi~ and incurs no expensive performance overhead (according to [[https://www.reddit.com/r/lisp/comments/ygebes/passing_c_struct_by_value_cffilibffi_is_250x/][this post]]) or heavy GC pressure when calling functions that accept C structures as parameters (which is the case for most functions in Raylib).
;;; The overhead of FFI calls is no longer a performance bottleneck for the system.
;; Self Total Cumul ;; Nr Count % Count % Count % Calls Function ;; ------------------------------------------------------------------------ ;; 1 261 32.2 261 32.2 261 32.2 - foreign function rlVertex3f ;; 2 109 13.4 450 55.5 370 45.6 - foreign function DrawTexturePro ;; 3 43 5.3 56 6.9 413 50.9 - (LAMBDA (&OPTIONAL POSITION ORIGIN SCALE ROTATION TINT) :IN TILED-LAYER-RENDERER) ;; 4 31 3.8 277 34.2 444 54.7 - foreign function rlVertex2f ;; 5 23 2.8 23 2.8 467 57.6 - foreign function rlTexCoord2f ;; 6 18 2.2 18 2.2 485 59.8 - foreign function __sched_yield ;; 7 16 2.0 19 2.3 501 61.8 - foreign function rlSetTexture ;; 8 15 1.8 495 61.0 516 63.6 - foreign function __claw_DrawTexturePro ;; 9 14 1.7 14 1.7 530 65.4 - (LAMBDA (POSITION SCALE) :IN TILED-LAYER-RENDERER) ;; 10 11 1.4 11 1.4 541 66.7 - foreign function rlBegin
** High-level ~claw-raylib~ utilizes ~cffi-object~ to automatically wrap Raylib's types, allowing you to completely disregard memory concerns. All types from Raylib can be seamlessly integrated into CLOS, and the API style remains highly similar to Common Lisp, and for all structure parameters in FFI functions, ~cffi-object~ objects are passed by default instead of raw pointers, greatly reducing the disconnect often associated with cross-language interoperations.
(raylib:vector2-normalize (raylib:vector2-add (raylib:make-vector2 :x 1.0 :y 2.0) (raylib:vector2-one))) ;; => #<VECTOR2 :X 0.5547002 :Y 0.8320503 @0x00007FF59C000D70>
(raylib:fade (raylib:color-brightness (raylib:get-color #xCE42EFFF) -0.5) 0.5) ;; => #<COLOR :R 103 :G 33 :B 119 :A 127 @0x00007FF59C000E50>
(defgeneric vector-add (v1 v2))
(defmethod vector-add ((v1 raylib:vector2) (v2 raylib:vector2)) (raylib:vector2-add v1 v2))
(defmethod vector-add ((v1 raylib:vector3) (v2 raylib:vector3)) (raylib:vector3-add v1 v2))
(defmethod vector-add ((v1 raylib:vector4) (v2 raylib:vector4)) (raylib:quaternion-add v1 v2))
(vector-add (raylib:vector3-one) (raylib:vector3-one)) ;; => #<VECTOR3 :X 2.0 :Y 2.0 :Z 2.0 @0x00007FF59C000ED0>
** Low-level In performance-intensive scenarios, directly using the low-level functions exposed by ~claw-raylib~ (whose names are prefixed with ~%~) in conjunction with [[https://github.com/bohonghuang/cffi-ops][cffi-ops]] for GC-free programming is a better choice. Modules written using this approach can achieve performance levels close to that of C.
(use-package :cffi-ops)
(defun camera-3d-normalize (camera) (declare (optimize (speed 3) (debug 0) (safety 0))) (clet* ((camera (cthe (:pointer (:struct raylib:camera-3d)) (& camera))) (up (& (-> camera raylib:up))) (right up) (look (foreign-alloca '(:struct raylib:vector3)))) ; Stack memory allocation (raylib:%vector3-subtract look (& (-> camera raylib:target)) (& (-> camera raylib:position))) (raylib:%vector3-cross-product right look up) (raylib:%vector3-cross-product up right look) (raylib:%vector3-normalize up up)) camera)
See the [[file:examples/][examples]] directory. To run all examples, eval this in your REPL:
(ql:quickload :claw-raylib/examples) (do-external-symbols (symbol :claw-raylib.examples) (funcall symbol))
Opening a PR for contributions is welcome. Encountering any problem, feel free to open an issue.