diff org/util.org @ 29:6372c108c5c6

cleaned up util.org
author Robert McIntyre <rlm@mit.edu>
date Mon, 24 Oct 2011 12:35:15 -0700
parents 122f12f81dc1
children 0206878c28b4
line wrap: on
line diff
     1.1 --- a/org/util.org	Mon Oct 24 07:36:04 2011 -0700
     1.2 +++ b/org/util.org	Mon Oct 24 12:35:15 2011 -0700
     1.3 @@ -1,20 +1,18 @@
     1.4 -#+title: Helper Utilities
     1.5 +#+title: Clojure Utilities for jMonkeyEngine3
     1.6  #+author: Robert McIntyre
     1.7  #+email: rlm@mit.edu
     1.8 -#+description: Simulating senses for AI research using JMonkeyEngine3
     1.9 +#+description: 
    1.10 +#+keywords: JME3, clojure, import, utilities
    1.11  #+SETUPFILE: ../../aurellem/org/setup.org
    1.12  #+INCLUDE: ../../aurellem/org/level-0.org
    1.13 -#+babel: :mkdirp yes :noweb yes :exports both
    1.14 +
    1.15 +* Utilities
    1.16 +
    1.17 +These are a collection of functions to make programming jMonkeyEngine
    1.18 +in clojure easier.
    1.19  
    1.20  ** Imports
    1.21  
    1.22 -jMonkeyEngine has a plethora of classes which can be overwhelming at
    1.23 -first. So that I one can get right to coding, it's good to take the
    1.24 -time right now and make a "import all" function which brings in all of
    1.25 -the important jme3 classes. Once I'm happy with the general structure
    1.26 -of a namespace I can deal with importing only the classes it actually
    1.27 -needs.
    1.28 -
    1.29  #+srcname: import
    1.30  #+begin_src clojure :results silent
    1.31  (ns cortex.import
    1.32 @@ -49,92 +47,131 @@
    1.33     (map (comp permissive-import symbol) (jme-classes))))
    1.34  #+end_src  
    1.35  
    1.36 +jMonkeyEngine3 has a plethora of classes which can be overwhelming to
    1.37 +manage. This code uses reflection to import all of them. Once I'm
    1.38 +happy with the general structure of a namespace I can deal with
    1.39 +importing only the classes it actually needs.
    1.40 +
    1.41  The =mega-import-jme3= is quite usefull for debugging purposes since
    1.42  it allows completion for almost all of JME's classes.
    1.43  
    1.44  Out of curiousity, let's see just how many classes =mega-import-jme3=
    1.45  imports:
    1.46  
    1.47 -#+begin_src clojure :exports both
    1.48 -(clojure.core/count (cortex.import/jme-classes))
    1.49 +#+begin_src clojure :exports both :results output
    1.50 +(println (clojure.core/count (cortex.import/jme-classes)) "classes")
    1.51  #+end_src
    1.52  
    1.53  #+results:
    1.54 -: 955
    1.55 +: 955 classes
    1.56  
    1.57  
    1.58 -#+srcname: world-view
    1.59 -#+begin_src clojure :results silent
    1.60 -(ns cortex.util)
    1.61 -(require 'cortex.import)
    1.62 -(cortex.import/mega-import-jme3)
    1.63 -(use 'cortex.world)
    1.64 -(defprotocol Viewable
    1.65 -  (view [something]))
    1.66 +** Utilities
    1.67  
    1.68 -(extend-type com.jme3.scene.Geometry
    1.69 -  Viewable
    1.70 -  (view [geo]
    1.71 -	(view (doto (Node.)(.attachChild geo)))))
    1.72 +The utilities here come in three main groups:
    1.73 + - Changing settings in a running =Application=
    1.74 + - Creating objects
    1.75 + - Visualizing objects
    1.76  
    1.77 -(extend-type com.jme3.scene.Node
    1.78 -  Viewable
    1.79 -  (view [node]
    1.80 -	(.start
    1.81 -	 (world node
    1.82 -		{}
    1.83 -		(fn [world]
    1.84 -		  (.enableDebug 
    1.85 -		   (.getPhysicsSpace
    1.86 -		    (.getState
    1.87 -		     (.getStateManager world)
    1.88 -		     BulletAppState))
    1.89 -		   (asset-manager))
    1.90 -		  (set-gravity* world Vector3f/ZERO)
    1.91 -;;		  (set-gravity* world (Vector3f. 0 (float -0.4) 0))
    1.92 -		  (let [sun (doto (DirectionalLight.)
    1.93 -			      (.setDirection (.normalizeLocal (Vector3f. 1 0 -2)))
    1.94 -			      (.setColor ColorRGBA/White))]
    1.95 -		    (.addLight (.getRootNode world) sun)))
    1.96 -		no-op))))
    1.97 -#+end_src
    1.98  
    1.99 -Here I make the =Viewable= protocol and extend it to JME's types.  Now
   1.100 -hello-world can be written as easily as:
   1.101 -
   1.102 -#+begin_src clojure :results silent
   1.103 -(cortex.world/view (cortex.world/box))
   1.104 -#+end_src
   1.105 -
   1.106 +*** Changing Settings
   1.107  
   1.108  #+srcname: util
   1.109  #+begin_src clojure 
   1.110 -(in-ns 'cortex.util)
   1.111 +(ns cortex.util
   1.112 +  "Utility functions for making jMonkeyEngine easier to program from
   1.113 +   clojure"
   1.114 +  {:author "Robert McIntyre"}
   1.115 +  (:use cortex.world)
   1.116 +  (:use clojure.contrib.def)
   1.117 +  (:import com.jme3.math.Vector3f)
   1.118 +  (:import com.jme3.math.Quaternion)
   1.119 +  (:import com.jme3.asset.TextureKey)
   1.120 +  (:import com.jme3.bullet.control.RigidBodyControl)
   1.121 +  (:import com.jme3.bullet.collision.shapes.GImpactCollisionShape)
   1.122 +  (:import com.jme3.scene.shape.Box)
   1.123 +  (:import com.jme3.scene.Node)
   1.124 +  (:import com.jme3.scene.shape.Sphere)
   1.125 +  (:import com.jme3.light.DirectionalLight)
   1.126 +  (:import com.jme3.math.ColorRGBA)
   1.127 +  (:import com.jme3.bullet.BulletAppState)
   1.128 +  (:import com.jme3.material.Material)
   1.129 +  (:import com.jme3.scene.Geometry))
   1.130  
   1.131 -(def println-repl (bound-fn [& args] (apply println args)))
   1.132 +(defvar println-repl
   1.133 +  (bound-fn [& args] (apply println args))
   1.134 +  "println called from the LWJGL thread will not go to the REPL, but
   1.135 +  instead to whatever terminal started the JVM process. This function
   1.136 +  will always output to the REPL")
   1.137  
   1.138 -(defn position-camera [game]
   1.139 -  (doto (.getCamera game)
   1.140 -    (.setLocation (Vector3f. 0 6 6))
   1.141 -    (.lookAt Vector3f/ZERO (Vector3f. 0 1 0))))
   1.142 +(defn position-camera
   1.143 +  ([game position direction up]
   1.144 +     (doto (.getCamera game)
   1.145 +       (.setLocation )
   1.146 +       (.lookAt direction up)))
   1.147 +  ([game position direction]
   1.148 +     (position-camera
   1.149 +      game position direction Vector3f/UNIT_Y)))
   1.150  
   1.151 -(defn set-gravity*
   1.152 +(defn enable-debug 
   1.153 +  "Turn on the debug wireframes for every object in this simulation"
   1.154 +  [world]
   1.155 +  (.enableDebug 
   1.156 +   (.getPhysicsSpace
   1.157 +    (.getState
   1.158 +     (.getStateManager world)
   1.159 +     BulletAppState))
   1.160 +   (asset-manager)))
   1.161 +
   1.162 +(defn set-gravity
   1.163 +  "In order to change the gravity of a scene, it is not only necessary
   1.164 +   to set the gravity variable, but to \"tap\" every physics object in
   1.165 +   the scene to reactivate physics calculations."
   1.166    [game gravity]
   1.167    (traverse
   1.168     (fn [geom]
   1.169       (if-let
   1.170 +         ;; only set gravity for physical objects.
   1.171  	 [control (.getControl geom RigidBodyControl)]
   1.172         (do
   1.173  	 (.setGravity control gravity)
   1.174 -	 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO)
   1.175 -	 )))
   1.176 +         ;; tappsies!
   1.177 +	 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO))))
   1.178     (.getRootNode game)))
   1.179 +
   1.180 +(defn add-element
   1.181 +  "Add the Spatial to the game's environment"
   1.182 +  ([game element node]
   1.183 +  (.addAll
   1.184 +   (.getPhysicsSpace
   1.185 +    (.getState
   1.186 +     (.getStateManager game)
   1.187 +     BulletAppState))
   1.188 +    element)
   1.189 +  (.attachChild node element))
   1.190 +  ([game element]
   1.191 +     (add-element game element (.getRootNode game))))
   1.192 +
   1.193 +(defn apply-map
   1.194 +  "Like apply, but works for maps and functions that expect an
   1.195 +   implicit map and nothing else as in (fn [& {}]).
   1.196 +   ------- Example -------
   1.197 +   (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}] 
   1.198 +     (println www))
   1.199 +   (apply-map demo {:www \"hello!\"})
   1.200 +   -->\"hello\""
   1.201 +  [fn m]
   1.202 +  (apply fn (reduce #(into %1 %2) [] m)))
   1.203 +
   1.204  #+end_src
   1.205  
   1.206  
   1.207 +*** Creating Basic Shapes
   1.208 +
   1.209  #+srcname: shapes
   1.210  #+begin_src clojure :results silent
   1.211  (in-ns 'cortex.util)
   1.212 +
   1.213  (defrecord shape-description
   1.214    [name
   1.215     color
   1.216 @@ -145,7 +182,9 @@
   1.217     position
   1.218     rotation
   1.219     shape
   1.220 -   physical?])
   1.221 +   physical?
   1.222 +   GImpact?
   1.223 +   ])
   1.224  
   1.225  (def base-shape
   1.226       (shape-description.
   1.227 @@ -161,11 +200,12 @@
   1.228        Vector3f/ZERO
   1.229        Quaternion/IDENTITY
   1.230        (Box. Vector3f/ZERO 0.5 0.5 0.5)
   1.231 -      true))
   1.232 +      true
   1.233 +      false))
   1.234  
   1.235  (defn make-shape
   1.236    [#^shape-description d]
   1.237 -  (let [asset-manager (if (:asset-manager d) (:asset-manager d) (asset-manager))
   1.238 +  (let [asset-manager (asset-manager)
   1.239          mat (Material. asset-manager (:material d))
   1.240  	geom (Geometry. (:name d) (:shape d))]
   1.241      (if (:texture d)
   1.242 @@ -177,18 +217,20 @@
   1.243      (if-let [rotation (:rotation d)] (.rotate geom rotation))
   1.244      (.setLocalTranslation geom (:position d))
   1.245      (if (:physical? d)
   1.246 -      (let [impact-shape (doto (GImpactCollisionShape. 
   1.247 -                                (.getMesh geom)) (.setMargin 0))
   1.248 -	    physics-control (RigidBodyControl.
   1.249 -			     ;;impact-shape ;; comment to disable 
   1.250 -			     (float (:mass d)))]
   1.251 -	(.createJmeMesh impact-shape)
   1.252 +      (let [physics-control
   1.253 +            (if (:GImpact d)
   1.254 +              ;; Create an accurate mesh collision shape if desired. 
   1.255 +              (RigidBodyControl.
   1.256 +               (doto (GImpactCollisionShape. 
   1.257 +                      (.getMesh geom))
   1.258 +                 (.createJmeMesh)
   1.259 +                 (.setMargin 0))
   1.260 +               (float (:mass d)))
   1.261 +              ;; otherwise use jme3's default
   1.262 +              (RigidBodyControl. (float (:mass d))))]
   1.263  	(.addControl geom physics-control)
   1.264  	;;(.setSleepingThresholds physics-control (float 0) (float 0))
   1.265  	(.setFriction physics-control (:friction d))))
   1.266 -    ;;the default is to keep this node in the physics engine forever.
   1.267 -    ;;these commands must come after the control is added to the geometry.
   1.268 -    ;;
   1.269      geom))
   1.270    
   1.271  (defn box
   1.272 @@ -204,33 +246,51 @@
   1.273         (make-shape (assoc options
   1.274  		     :shape (Sphere. 32 32 (float r)))))) 
   1.275    ([] (sphere 0.5)))
   1.276 +#+end_src
   1.277  
   1.278 -(defn add-element
   1.279 -  ([game element node]
   1.280 -  (.addAll
   1.281 -   (.getPhysicsSpace
   1.282 -    (.getState
   1.283 -     (.getStateManager game)
   1.284 -     BulletAppState))
   1.285 -    element)
   1.286 -  (.attachChild node element))
   1.287 -  ([game element]
   1.288 -     (add-element game element (.getRootNode game))))
   1.289  
   1.290 +*** Viewing Objects
   1.291  
   1.292 -(defn apply-map
   1.293 -  "Like apply, but works for maps and functions that expect an
   1.294 -   implicit map and nothing else as in (fn [& {}]).
   1.295 -   ------- Example -------
   1.296 -   (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}] 
   1.297 -     (println www))
   1.298 -   (apply-map demo {:www \"hello!\"})
   1.299 -   -->\"hello\""
   1.300 -  [fn m]
   1.301 -  (apply fn (reduce #(into %1 %2) [] m)))
   1.302 +#+srcname: world-view
   1.303 +#+begin_src clojure :results silent
   1.304 +(in-ns 'cortex.util)
   1.305  
   1.306 +(defprotocol Viewable
   1.307 +  (view [something]))
   1.308 +
   1.309 +(extend-type com.jme3.scene.Geometry
   1.310 +  Viewable
   1.311 +  (view [geo]
   1.312 +	(view (doto (Node.)(.attachChild geo)))))
   1.313 +
   1.314 +(extend-type com.jme3.scene.Node
   1.315 +  Viewable
   1.316 +  (view 
   1.317 +    [node]
   1.318 +    (.start
   1.319 +     (world
   1.320 +      node
   1.321 +      {}
   1.322 +      (fn [world]
   1.323 +        (enable-debug world)
   1.324 +        (set-gravity world Vector3f/ZERO)
   1.325 +        (let [sun 
   1.326 +              (doto (DirectionalLight.)
   1.327 +                (.setDirection
   1.328 +                 (.normalizeLocal (Vector3f. 1 0 -2)))
   1.329 +                (.setColor ColorRGBA/White))]
   1.330 +          (.addLight (.getRootNode world) sun)))
   1.331 +      no-op))))
   1.332  #+end_src
   1.333  
   1.334 +Here I make the =Viewable= protocol and extend it to JME's types.  Now
   1.335 +hello-world can be written as easily as:
   1.336 +
   1.337 +#+begin_src clojure :results silent
   1.338 +(cortex.util/view (cortex.util/box))
   1.339 +#+end_src
   1.340 +
   1.341 +
   1.342  
   1.343  
   1.344  * COMMENT code generation
   1.345 @@ -239,9 +299,25 @@
   1.346  #+end_src
   1.347  
   1.348  
   1.349 -#+begin_src clojure :tangle ../src/cortex/util.clj
   1.350 -<<world-view>>
   1.351 +#+begin_src clojure :tangle ../src/cortex/util.clj :noweb yes
   1.352  <<util>>
   1.353  <<shapes>>
   1.354 +<<world-view>>
   1.355  #+end_src
   1.356  
   1.357 +
   1.358 +
   1.359 +
   1.360 +
   1.361 +
   1.362 +
   1.363 +
   1.364 +
   1.365 +
   1.366 +
   1.367 +
   1.368 +
   1.369 +
   1.370 +
   1.371 +
   1.372 +