I'm trying to get the Chipmunk Physics library integrated with Racket. I've made some progress (https://www.youtube.com/watch?v=GjvLaP7I0gg), but I need to ask for some input on an issue.
The Chipmunk C library provides a primitive called a "cpBody" (i.e. a moving thing). A cpBody struct has a velocity_func pointer which allows customization of how the body's velocity is updated during the simulation. I have noticed odd behavior with these function pointers. Perhaps this is a bug with the FFI? Perhaps it's perfectly normal and I just don't understand something about the FFI? In any event, when I have one body, this works: (define body1 (box 25 5 (cpv 25.0 80.0) #:mass 10 #:meta 'green)) (define (f body gravity damping dt) (ffi:cpointer-push-tag! body 'cpBody) (cpBodySetVelocity body (cpv 0 -10)) ffi:_void) (set-cpBody-velocity_func! (chipmunk-body body1) f) But when I have two bodies that share the same velocity_func, I get a segfault: (define body1 (box 25 5 (cpv 25.0 80.0) #:mass 10 #:meta 'green)) (define body2 (box 25 5 (cpv 50.0 80.0) #:mass 10 #:meta 'blue)) (define (f body gravity damping dt) (ffi:cpointer-push-tag! body 'cpBody) (cpBodySetVelocity body (cpv 0 -10)) ffi:_void) (set-cpBody-velocity_func! (chipmunk-body body1) f) (set-cpBody-velocity_func! (chipmunk-body body2) f) I've tried various ways to work around this issue. But all of them either didn't work or feel dumb. *Things that didn't work* 1) Wrapping the function f in separate lambdas still gives a segfault: (set-cpBody-velocity_func! (chipmunk-body body1) (lambda(b g d dt) (f b d g dt))) (set-cpBody-velocity_func! (chipmunk-body body2) (lambda(b g d dt) (f b d g dt))) 2) Storing a reference to the function f in a stab-in-the-dark attempt to "trick the system" or "prevent some kind of mysterious garbage collection" still segfaults: (define probably-silly (list (lambda(b g d dt) (f b d g dt)) (lambda(b g d dt) (f b d g dt)))) (set-cpBody-velocity_func! (chipmunk-body body1) (list-ref probably-silly 0)) (set-cpBody-velocity_func! (chipmunk-body body2) (list-ref probably-silly 1)) 3) Storing the function f in two separate variables also segfaults: (define (f body gravity damping dt) (ffi:cpointer-push-tag! body 'cpBody) (cpBodySetVelocity body (cpv 0 -10)) ffi:_void) (define f2 f) (set-cpBody-velocity_func! (chipmunk-body body1) f) (set-cpBody-velocity_func! (chipmunk-body body2) f2) *Things that do work but feel dumb* 1) Explicitly duplicating the function verbatim: (define (f body gravity damping dt) (ffi:cpointer-push-tag! body 'cpBody) (cpBodySetVelocity body (cpv 0 -10)) ffi:_void) (define (f2 body gravity damping dt) (ffi:cpointer-push-tag! body 'cpBody) (cpBodySetVelocity body (cpv 0 -10)) ffi:_void) (set-cpBody-velocity_func! (chipmunk-body body1) f) (set-cpBody-velocity_func! (chipmunk-body body2) f2) 2) Duplicating the function with a macro lets me generalize the above workaround for more than two bodies, but it still feels gross. I know the macro could be improved, but that isn't really the point. The fact that I have to know how many functions to make at compile time is gross. ;The stupid macro.... (define-syntax-rule (dumb-duplicate id body) (define id (list body body body body body))) (dumb-duplicate fs (lambda (body gravity damping dt) (f body gravity damping dt))) (set-cpBody-velocity_func! (chipmunk-body body1) (list-ref fs 0)) (set-cpBody-velocity_func! (chipmunk-body body2) (list-ref fs 1)) That's all I have. To sum up, sharing the same function pointer across two cpBodies seems to segfault to matter what clever tricks I try. Using functions with distinct compile-time source locations does work, but it makes me feel icky. I would prefer to construct the functions I need dynamically rather than statically. In simulations where objects are created at runtime, it feels sillier and sillier to have to know beforehand how many objects there will be at runtime. If someone has an explanation or a better workaround, that would be great. I'm assuming there's something about the Racket FFI that I haven't learned yet. However, if others are as mystified as I am, I'll assume it's a Chipmunk issue, and I'll ask about it over on the Chipmunk forums. *Appendix A* Below is a full program with some rendering, just for context. It uses this newborn git repo for the Racket FFI bindings: https://github.com/thoughtstem/racket-chipmunk Also, here are the latest docs for Chipmunk: https://chipmunk-physics.net/release/ChipmunkLatest-API-Reference (require 2htdp/image lang/posn) (require 2htdp/universe) (require racket-chipmunk) (require (prefix-in ffi: ffi/unsafe)) (define body1 (box 25 5 (cpv 25.0 80.0) #:mass 10 #:meta 'green)) (define body2 (box 25 5 (cpv 50.0 80.0) #:mass 10 #:meta 'blue)) (define (f body gravity damping dt) (ffi:cpointer-push-tag! body 'cpBody) (cpBodySetVelocity body (cpv 0 -10)) ffi:_void) ;The stupid macro.... (define-syntax-rule (dumb-duplicate id body) (define id (list body body body body body))) (dumb-duplicate fs (lambda (body gravity damping dt) (f body gravity damping dt))) (set-cpBody-velocity_func! (chipmunk-body body1) (list-ref fs 0)) (set-cpBody-velocity_func! (chipmunk-body body2) (list-ref fs 1)) (define boxes (list body1 body2)) (define *tick-rate* (/ 1 120.0)) (define *canvas* (square 100 'solid 'white)) (define (box->color b) (or (chipmunk-meta b) 'red)) (define (render-box b) (rotate (* -57.29 (angle b)) (rectangle (w b) (h b) 'solid (box->color b)))) (define (box->posn b) (make-posn (x b) (y b))) (big-bang 0 [on-tick (lambda (state) (step-chipmunk *tick-rate*) (+ state 1)) *tick-rate*] [on-draw (lambda (state) (scale 6 (place-images (map render-box boxes) (map box->posn boxes) *canvas*)))]) -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.