Add support for soft bodies

This commit is contained in:
oakes
2014-04-18 20:33:13 -04:00
parent dca75ea7ff
commit de27b633ed

View File

@@ -6,12 +6,15 @@
[com.badlogic.gdx.physics.bullet Bullet] [com.badlogic.gdx.physics.bullet Bullet]
[com.badlogic.gdx.physics.bullet.collision btBoxShape [com.badlogic.gdx.physics.bullet.collision btBoxShape
btCollisionDispatcher btCylinderShape btCollisionObject btCollisionDispatcher btCylinderShape btCollisionObject
btCollisionWorld btDefaultCollisionConfiguration btDbvtBroadphase btDefaultCollisionConfiguration btDbvtBroadphase
btSphereShape] btSphereShape]
[com.badlogic.gdx.physics.bullet.dynamics btDiscreteDynamicsWorld [com.badlogic.gdx.physics.bullet.dynamics btDiscreteDynamicsWorld
btDynamicsWorld btRigidBody btRigidBody$btRigidBodyConstructionInfo btDynamicsWorld btRigidBody btRigidBody$btRigidBodyConstructionInfo
btSequentialImpulseConstraintSolver] btSequentialImpulseConstraintSolver]
[com.badlogic.gdx.physics.bullet.linearmath btMotionState])) [com.badlogic.gdx.physics.bullet.linearmath btMotionState]
[com.badlogic.gdx.physics.bullet.softbody btSoftBody
btSoftBodyRigidBodyCollisionConfiguration btSoftBodyWorldInfo
btSoftRigidDynamicsWorld]))
(def ^:private init (delay (Bullet/init))) (def ^:private init (delay (Bullet/init)))
@@ -30,51 +33,47 @@
:config config :config config
:dispatcher dispatcher :dispatcher dispatcher
:broadphase broad :broadphase broad
:solver solver))) :constraint-solver solver)))
(defn ^:private soft-rigid-dynamics
[]
(let [config (btSoftBodyRigidBodyCollisionConfiguration.)
dispatcher (btCollisionDispatcher. config)
broad (btDbvtBroadphase.)
solver (btSequentialImpulseConstraintSolver.)]
(assoc (World3D. (btSoftRigidDynamicsWorld. dispatcher broad solver config))
:config config
:dispatcher dispatcher
:broadphase broad
:constraint-solver solver)))
(defn bullet-3d* (defn bullet-3d*
[type] [type]
@init @init
(case type (case type
:discrete-dynamics (discrete-dynamics) :rigid (discrete-dynamics)
:soft-rigid (soft-rigid-dynamics)
(u/throw-key-not-found type))) (u/throw-key-not-found type)))
(defmacro bullet-3d (defmacro bullet-3d
"Returns a world based on btCollisionWorld. "Returns a world based on btDynamicsWorld.
(bullet-3d :discrete-dynamics)" (bullet-3d :rigid) ; can only handle rigid bodies
(bullet-3d :soft-rigid) ; can handle soft and rigid bodies"
[type & options] [type & options]
`(let [world# (bullet-3d* ~type) `(let [world# (bullet-3d* ~type)
^btCollisionWorld object# (:object world#)] ^btDynamicsWorld object# (:object world#)]
(u/calls! object# ~@options) (u/calls! object# ~@options)
world#)) world#))
(defmacro bullet-3d! (defmacro bullet-3d!
"Calls a single method on a `bullet-3d`." "Calls a single method on a `bullet-3d`."
[screen k & options] [screen k & options]
`(let [^btCollisionWorld object# (:object (u/get-obj ~screen :world))] `(let [^btDynamicsWorld object# (:object (u/get-obj ~screen :world))]
(u/call! object# ~k ~@options))) (u/call! object# ~k ~@options)))
; bodies ; bodies
(defn basic-body*
[]
(Body3D. (btCollisionObject.)))
(defmacro basic-body
"Returns a body based on btCollisionObject."
[& options]
`(let [body# (basic-body*)
^btCollisionObject object# (:object body#)]
(u/calls! object# ~@options)
body#))
(defmacro basic-body!
"Calls a single method on a `basic-body`."
[object k & options]
`(let [^btCollisionObject object# (:object (u/get-obj ~object :body))]
(u/call! object# ~k ~@options)))
(defn rigid-body* (defn rigid-body*
[info] [info]
(assoc (Body3D. (btRigidBody. info)) (assoc (Body3D. (btRigidBody. info))
@@ -100,10 +99,29 @@
(btRigidBody$btRigidBodyConstructionInfo. (btRigidBody$btRigidBodyConstructionInfo.
mass motion-state collision-shape local-inertia)) mass motion-state collision-shape local-inertia))
(defmacro rigid-body-info! (defn soft-body*
"Calls a single method on a `rigid-body-info`." [info]
(assoc (Body3D. (btSoftBody. info))
:info info))
(defmacro soft-body
"Returns a body based on btSoftBody."
[info & options]
`(let [body# (soft-body* ~info)
^btSoftBody object# (:object body#)]
(u/calls! object# ~@options)
body#))
(defmacro soft-body!
"Calls a single method on a `soft-body`."
[object k & options] [object k & options]
`(u/call! ^btRigidBody$btRigidBodyConstructionInfo ~object ~k ~@options)) `(let [^btSoftBody object# (:object (u/get-obj ~object :body))]
(u/call! object# ~k ~@options)))
(defn soft-body-info
"Returns a btSoftBodyWorldInfo."
[]
(btSoftBodyWorldInfo.))
(defn ^:private body-x (defn ^:private body-x
[entity] [entity]
@@ -195,8 +213,8 @@
(cond (cond
(isa? (type (:object body)) btRigidBody) (isa? (type (:object body)) btRigidBody)
(bullet-3d! screen :add-rigid-body (:object body)) (bullet-3d! screen :add-rigid-body (:object body))
:else (isa? (type (:object body)) btSoftBody)
(bullet-3d! screen :add-collision-object (:object body))) (bullet-3d! screen :add-soft-body (:object body)))
body) body)
(defn ^:private get-bodies (defn ^:private get-bodies
@@ -208,31 +226,27 @@
(defmethod c/update-physics! (defmethod c/update-physics!
World3D World3D
[screen & [entities]] [screen & [entities]]
; initialize bodies ; initialize bodies if necessary
(doseq [e entities] (doseq [e entities]
(let [object (u/get-obj e :object) (let [object (u/get-obj e :object)
body (u/get-obj e :body)] body (u/get-obj e :body)]
(when (and object body) (when (and object (isa? (type (:object body)) btRigidBody))
(cond (when-not (rigid-body! e :get-motion-state)
(isa? (type (:object body)) btRigidBody) (->> (proxy [btMotionState] []
(when-not (rigid-body! e :get-motion-state) (getWorldTransform [world-t])
(rigid-body! e (setWorldTransform [world-t]
:set-motion-state (m/matrix-4! (. object transform) :set world-t)))
(proxy [btMotionState] [] (rigid-body! e :set-motion-state))))))
(getWorldTransform [world-t])
(setWorldTransform [world-t]
(m/matrix-4! (. object transform) :set world-t)))))
:else
(basic-body! e :set-world-transform (. object transform))))))
; remove bodies that no longer exist ; remove bodies that no longer exist
(when entities (when entities
(doseq [body (get-bodies screen)] (doseq [^btCollisionObject body (get-bodies screen)]
(when-not (some #(= body (-> % :body :object)) entities) (when-not (some #(= body (-> % :body :object)) entities)
(cond (cond
(isa? (type body) btRigidBody) (isa? (type body) btRigidBody)
(bullet-3d! screen :remove-rigid-body body) (bullet-3d! screen :remove-rigid-body body)
:else (isa? (type body) btSoftBody)
(bullet-3d! screen :remove-collision-object body)))))) (bullet-3d! screen :remove-soft-body body))
(.dispose body)))))
(defmethod c/step! (defmethod c/step!
World3D World3D
@@ -240,14 +254,13 @@
:or {max-sub-steps 5 time-step (/ 1 60)} :or {max-sub-steps 5 time-step (/ 1 60)}
:as screen} :as screen}
& [entities]] & [entities]]
(when (isa? (type (:object (u/get-obj screen :world))) btDynamicsWorld) (bullet-3d! screen :step-simulation delta-time max-sub-steps time-step)
(bullet-3d! screen :step-simulation delta-time max-sub-steps time-step) (when entities
(when entities (map (fn [e]
(map (fn [e] (if (u/get-obj e :body)
(if (u/get-obj e :body) (assoc e
(assoc e :x (body-x e)
:x (body-x e) :y (body-y e)
:y (body-y e) :z (body-z e))
:z (body-z e)) e))
e)) entities)))
entities))))