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