# HG changeset patch # User Robert McIntyre # Date 1319484915 25200 # Node ID 6372c108c5c676c4b6bcac02c8d16ef84d17e6af # Parent 122f12f81dc15c5462a0a0c586fff12c7029dcee cleaned up util.org diff -r 122f12f81dc1 -r 6372c108c5c6 org/cortex.org --- a/org/cortex.org Mon Oct 24 07:36:04 2011 -0700 +++ b/org/cortex.org Mon Oct 24 12:35:15 2011 -0700 @@ -783,3 +783,7 @@ + + + + diff -r 122f12f81dc1 -r 6372c108c5c6 org/intro.org --- a/org/intro.org Mon Oct 24 07:36:04 2011 -0700 +++ b/org/intro.org Mon Oct 24 12:35:15 2011 -0700 @@ -173,3 +173,34 @@ because it had the most features out of all the open projects I looked at, and because I could then write my code in Clojure, an implementation of LISP that runs on the JVM... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 122f12f81dc1 -r 6372c108c5c6 org/skin.org --- a/org/skin.org Mon Oct 24 07:36:04 2011 -0700 +++ b/org/skin.org Mon Oct 24 12:35:15 2011 -0700 @@ -148,14 +148,6 @@ ;;(dorun (map #(println-repl (.getName %)) touch-objects)) (count touch-objects)))))))) -(defn enable-debug [world] - (.enableDebug - (.getPhysicsSpace - (.getState - (.getStateManager world) - BulletAppState)) - (asset-manager))) - (defn no-logging [] (.setLevel (Logger/getLogger "com.jme3") Level/OFF)) diff -r 122f12f81dc1 -r 6372c108c5c6 org/util.org --- a/org/util.org Mon Oct 24 07:36:04 2011 -0700 +++ b/org/util.org Mon Oct 24 12:35:15 2011 -0700 @@ -1,20 +1,18 @@ -#+title: Helper Utilities +#+title: Clojure Utilities for jMonkeyEngine3 #+author: Robert McIntyre #+email: rlm@mit.edu -#+description: Simulating senses for AI research using JMonkeyEngine3 +#+description: +#+keywords: JME3, clojure, import, utilities #+SETUPFILE: ../../aurellem/org/setup.org #+INCLUDE: ../../aurellem/org/level-0.org -#+babel: :mkdirp yes :noweb yes :exports both + +* Utilities + +These are a collection of functions to make programming jMonkeyEngine +in clojure easier. ** Imports -jMonkeyEngine has a plethora of classes which can be overwhelming at -first. So that I one can get right to coding, it's good to take the -time right now and make a "import all" function which brings in all of -the important jme3 classes. Once I'm happy with the general structure -of a namespace I can deal with importing only the classes it actually -needs. - #+srcname: import #+begin_src clojure :results silent (ns cortex.import @@ -49,92 +47,131 @@ (map (comp permissive-import symbol) (jme-classes)))) #+end_src +jMonkeyEngine3 has a plethora of classes which can be overwhelming to +manage. This code uses reflection to import all of them. Once I'm +happy with the general structure of a namespace I can deal with +importing only the classes it actually needs. + The =mega-import-jme3= is quite usefull for debugging purposes since it allows completion for almost all of JME's classes. Out of curiousity, let's see just how many classes =mega-import-jme3= imports: -#+begin_src clojure :exports both -(clojure.core/count (cortex.import/jme-classes)) +#+begin_src clojure :exports both :results output +(println (clojure.core/count (cortex.import/jme-classes)) "classes") #+end_src #+results: -: 955 +: 955 classes -#+srcname: world-view -#+begin_src clojure :results silent -(ns cortex.util) -(require 'cortex.import) -(cortex.import/mega-import-jme3) -(use 'cortex.world) -(defprotocol Viewable - (view [something])) +** Utilities -(extend-type com.jme3.scene.Geometry - Viewable - (view [geo] - (view (doto (Node.)(.attachChild geo))))) +The utilities here come in three main groups: + - Changing settings in a running =Application= + - Creating objects + - Visualizing objects -(extend-type com.jme3.scene.Node - Viewable - (view [node] - (.start - (world node - {} - (fn [world] - (.enableDebug - (.getPhysicsSpace - (.getState - (.getStateManager world) - BulletAppState)) - (asset-manager)) - (set-gravity* world Vector3f/ZERO) -;; (set-gravity* world (Vector3f. 0 (float -0.4) 0)) - (let [sun (doto (DirectionalLight.) - (.setDirection (.normalizeLocal (Vector3f. 1 0 -2))) - (.setColor ColorRGBA/White))] - (.addLight (.getRootNode world) sun))) - no-op)))) -#+end_src -Here I make the =Viewable= protocol and extend it to JME's types. Now -hello-world can be written as easily as: - -#+begin_src clojure :results silent -(cortex.world/view (cortex.world/box)) -#+end_src - +*** Changing Settings #+srcname: util #+begin_src clojure -(in-ns 'cortex.util) +(ns cortex.util + "Utility functions for making jMonkeyEngine easier to program from + clojure" + {:author "Robert McIntyre"} + (:use cortex.world) + (:use clojure.contrib.def) + (:import com.jme3.math.Vector3f) + (:import com.jme3.math.Quaternion) + (:import com.jme3.asset.TextureKey) + (:import com.jme3.bullet.control.RigidBodyControl) + (:import com.jme3.bullet.collision.shapes.GImpactCollisionShape) + (:import com.jme3.scene.shape.Box) + (:import com.jme3.scene.Node) + (:import com.jme3.scene.shape.Sphere) + (:import com.jme3.light.DirectionalLight) + (:import com.jme3.math.ColorRGBA) + (:import com.jme3.bullet.BulletAppState) + (:import com.jme3.material.Material) + (:import com.jme3.scene.Geometry)) -(def println-repl (bound-fn [& args] (apply println args))) +(defvar println-repl + (bound-fn [& args] (apply println args)) + "println called from the LWJGL thread will not go to the REPL, but + instead to whatever terminal started the JVM process. This function + will always output to the REPL") -(defn position-camera [game] - (doto (.getCamera game) - (.setLocation (Vector3f. 0 6 6)) - (.lookAt Vector3f/ZERO (Vector3f. 0 1 0)))) +(defn position-camera + ([game position direction up] + (doto (.getCamera game) + (.setLocation ) + (.lookAt direction up))) + ([game position direction] + (position-camera + game position direction Vector3f/UNIT_Y))) -(defn set-gravity* +(defn enable-debug + "Turn on the debug wireframes for every object in this simulation" + [world] + (.enableDebug + (.getPhysicsSpace + (.getState + (.getStateManager world) + BulletAppState)) + (asset-manager))) + +(defn set-gravity + "In order to change the gravity of a scene, it is not only necessary + to set the gravity variable, but to \"tap\" every physics object in + the scene to reactivate physics calculations." [game gravity] (traverse (fn [geom] (if-let + ;; only set gravity for physical objects. [control (.getControl geom RigidBodyControl)] (do (.setGravity control gravity) - (.applyImpulse control Vector3f/ZERO Vector3f/ZERO) - ))) + ;; tappsies! + (.applyImpulse control Vector3f/ZERO Vector3f/ZERO)))) (.getRootNode game))) + +(defn add-element + "Add the Spatial to the game's environment" + ([game element node] + (.addAll + (.getPhysicsSpace + (.getState + (.getStateManager game) + BulletAppState)) + element) + (.attachChild node element)) + ([game element] + (add-element game element (.getRootNode game)))) + +(defn apply-map + "Like apply, but works for maps and functions that expect an + implicit map and nothing else as in (fn [& {}]). + ------- Example ------- + (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}] + (println www)) + (apply-map demo {:www \"hello!\"}) + -->\"hello\"" + [fn m] + (apply fn (reduce #(into %1 %2) [] m))) + #+end_src +*** Creating Basic Shapes + #+srcname: shapes #+begin_src clojure :results silent (in-ns 'cortex.util) + (defrecord shape-description [name color @@ -145,7 +182,9 @@ position rotation shape - physical?]) + physical? + GImpact? + ]) (def base-shape (shape-description. @@ -161,11 +200,12 @@ Vector3f/ZERO Quaternion/IDENTITY (Box. Vector3f/ZERO 0.5 0.5 0.5) - true)) + true + false)) (defn make-shape [#^shape-description d] - (let [asset-manager (if (:asset-manager d) (:asset-manager d) (asset-manager)) + (let [asset-manager (asset-manager) mat (Material. asset-manager (:material d)) geom (Geometry. (:name d) (:shape d))] (if (:texture d) @@ -177,18 +217,20 @@ (if-let [rotation (:rotation d)] (.rotate geom rotation)) (.setLocalTranslation geom (:position d)) (if (:physical? d) - (let [impact-shape (doto (GImpactCollisionShape. - (.getMesh geom)) (.setMargin 0)) - physics-control (RigidBodyControl. - ;;impact-shape ;; comment to disable - (float (:mass d)))] - (.createJmeMesh impact-shape) + (let [physics-control + (if (:GImpact d) + ;; Create an accurate mesh collision shape if desired. + (RigidBodyControl. + (doto (GImpactCollisionShape. + (.getMesh geom)) + (.createJmeMesh) + (.setMargin 0)) + (float (:mass d))) + ;; otherwise use jme3's default + (RigidBodyControl. (float (:mass d))))] (.addControl geom physics-control) ;;(.setSleepingThresholds physics-control (float 0) (float 0)) (.setFriction physics-control (:friction d)))) - ;;the default is to keep this node in the physics engine forever. - ;;these commands must come after the control is added to the geometry. - ;; geom)) (defn box @@ -204,33 +246,51 @@ (make-shape (assoc options :shape (Sphere. 32 32 (float r)))))) ([] (sphere 0.5))) +#+end_src -(defn add-element - ([game element node] - (.addAll - (.getPhysicsSpace - (.getState - (.getStateManager game) - BulletAppState)) - element) - (.attachChild node element)) - ([game element] - (add-element game element (.getRootNode game)))) +*** Viewing Objects -(defn apply-map - "Like apply, but works for maps and functions that expect an - implicit map and nothing else as in (fn [& {}]). - ------- Example ------- - (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}] - (println www)) - (apply-map demo {:www \"hello!\"}) - -->\"hello\"" - [fn m] - (apply fn (reduce #(into %1 %2) [] m))) +#+srcname: world-view +#+begin_src clojure :results silent +(in-ns 'cortex.util) +(defprotocol Viewable + (view [something])) + +(extend-type com.jme3.scene.Geometry + Viewable + (view [geo] + (view (doto (Node.)(.attachChild geo))))) + +(extend-type com.jme3.scene.Node + Viewable + (view + [node] + (.start + (world + node + {} + (fn [world] + (enable-debug world) + (set-gravity world Vector3f/ZERO) + (let [sun + (doto (DirectionalLight.) + (.setDirection + (.normalizeLocal (Vector3f. 1 0 -2))) + (.setColor ColorRGBA/White))] + (.addLight (.getRootNode world) sun))) + no-op)))) #+end_src +Here I make the =Viewable= protocol and extend it to JME's types. Now +hello-world can be written as easily as: + +#+begin_src clojure :results silent +(cortex.util/view (cortex.util/box)) +#+end_src + + * COMMENT code generation @@ -239,9 +299,25 @@ #+end_src -#+begin_src clojure :tangle ../src/cortex/util.clj -<> +#+begin_src clojure :tangle ../src/cortex/util.clj :noweb yes <> <> +<> #+end_src + + + + + + + + + + + + + + + + diff -r 122f12f81dc1 -r 6372c108c5c6 org/world.org --- a/org/world.org Mon Oct 24 07:36:04 2011 -0700 +++ b/org/world.org Mon Oct 24 12:35:15 2011 -0700 @@ -5,7 +5,7 @@ #+keywords: JME3, clojure, virtual world, exception handling #+SETUPFILE: ../../aurellem/org/setup.org #+INCLUDE: ../../aurellem/org/level-0.org -#+babel: :mkdirp yes :noweb yes :exports both +#+BABEL: :mkdirp yes :noweb yes :exports both * The World @@ -344,7 +344,7 @@ * COMMENT code generation -#+begin_src clojure :tangle ../src/cortex/world.clj +#+begin_src clojure :tangle ../src/cortex/world.clj :noweb yes <
> <> <>