Mercurial > cortex
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 +