Closed giuliods closed 2 years ago
@giuliods Please have a look at https://github.com/longlene/cl-raylib/issues/12 That's just the question we talked.
@giuliods Currently, seems no solution for it.
Here's my attempt at some macros to help solve this.
This is my first attempt at doing anything serious with macros so I'm very open to feedback.
(defmacro define-struct (name description fields)
(let* ((cstruct-name (read-from-string (concatenate 'string "%" (string-trim " " name))))
(cstruct-type (read-from-string (concatenate 'string "%" (string-trim " " name) "-tclass")))
(lisp-struct-name (read-from-string name))
(field-names (loop :for f :in fields :collect (nth 0 f))))
`(progn
(cffi:defcstruct ,cstruct-name
,description
,@fields)
(defstruct ,lisp-struct-name
,description
,@(loop :for f :in fields
:collect (nth 0 f)))
(defmethod cffi:translate-into-foreign-memory (lisp-var (type ,cstruct-type) ptr)
(cffi:with-foreign-slots (,field-names ptr (:struct cstruct-name))
,@(loop :for f :in field-names
:collect `(setf ,f (,(read-from-string (concatenate 'string name "-" (string f))) lisp-var)))))
(defmethod cffi:translate-from-foreign (ptr (type ,cstruct-type))
(cffi:with-foreign-slots (,field-names ptr (:struct ,cstruct-name))
(,(read-from-string (concatenate 'string "make-" name))
,@(loop :for f :in field-names
:collect `(,(read-from-string (concatenate 'string ":" (string f))) ,f) :into s
:finally (return (apply #'append s))))))
(defmacro ,(read-from-string (concatenate 'string "update-" name "-from-foreign"))
(lisp-var ptr)
(,(read-from-string "sb-int:quasiquote")
(progn
,@(loop :for f :in field-names
:collect `(setf (,(read-from-string (concatenate 'string name "-" (string f)))
(unquote lisp-var))
(cffi:foreign-slot-value ptr '(:struct ,cstruct-name) ',f)))))))))
;; Example
(define-struct "Camera3D"
"Camera, defines position/orientation in 3d space"
((position (:struct %Vector3))
(target (:struct %Vector3))
(up (:struct %Vector3))
(fovy :float)
(projection :int)))
(cffi:defcfun ("UpdateCamera" %update-camera) :void
"Update camera position for selected mode"
(camera (:pointer (:struct %Camera3D))))
(defmacro update-camera (camera)
(let ((foreign-camera (gensym)))
`(cffi:with-foreign-object (,foreign-camera (:struct %Camera))
(cffi:translate-into-foreign-memory ,camera %Camera-tclass ,foreign-camera)
(%update-camera ,foreign-camera)
(update-camera3d-from-foreign ,camera ,foreign-camera))))
;; Example
(update-camera test)
Here's an example of what the macros expand to:
;; (define-struct "Camera3D"...)
(progn
(cffi:defcstruct %camera3d
"Camera, defines position/orientation in 3d space"
(position (:struct %vector3))
(target (:struct %vector3))
(up (:struct %vector3))
(fovy :float)
(projection :int))
(defstruct camera3d
"Camera, defines position/orientation in 3d space"
position
target
up
fovy
projection)
(defmethod cffi:translate-into-foreign-memory
(lisp-var (type %camera3d-tclass) ptr)
(cffi:with-foreign-slots ((position target up fovy projection) ptr
(:struct cstruct-name))
(setf position (camera3d-position lisp-var))
(setf target (camera3d-target lisp-var))
(setf up (camera3d-up lisp-var))
(setf fovy (camera3d-fovy lisp-var))
(setf projection (camera3d-projection lisp-var))))
(defmethod cffi:translate-from-foreign (ptr (type %camera3d-tclass))
(cffi:with-foreign-slots ((position target up fovy projection) ptr
(:struct %camera3d))
(make-camera3d :position position :target target :up up :fovy fovy
:projection projection)))
(defmacro update-camera3d-from-foreign (lisp-var ptr)
`(progn
(setf (camera3d-position (unquote lisp-var))
(cffi:foreign-slot-value ptr '(:struct %camera3d) 'position))
(setf (camera3d-target (unquote lisp-var))
(cffi:foreign-slot-value ptr '(:struct %camera3d) 'target))
(setf (camera3d-up (unquote lisp-var))
(cffi:foreign-slot-value ptr '(:struct %camera3d) 'up))
(setf (camera3d-fovy (unquote lisp-var))
(cffi:foreign-slot-value ptr '(:struct %camera3d) 'fovy))
(setf (camera3d-projection (unquote lisp-var))
(cffi:foreign-slot-value ptr '(:struct %camera3d) 'projection)))))
;; (update-camera test)
(cffi:with-foreign-object (#:g636 (:struct %camera))
(cffi:translate-into-foreign-memory test %camera-tclass #:g636)
(%update-camera #:g636)
(update-camera3d-from-foreign test #:g636))
It should be fairly simple to create a macro that generates the update-camera
type functions too.
Oh, I should add that the define-struct
isn't portable because I can't figure out nested backquotes. I wrote this in sbcl but I'll keep working on cleaning it up.
With setting the camera3d's mode to free I have to update it on every frame. But the function require the camera to be passed as a pointer. I actually have +camera+ storing the camera3d struct. There is a function or a macro I'm not aware to pass it to the update-camera function?