comparison 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
comparison
equal deleted inserted replaced
28:122f12f81dc1 29:6372c108c5c6
1 #+title: Helper Utilities 1 #+title: Clojure Utilities for jMonkeyEngine3
2 #+author: Robert McIntyre 2 #+author: Robert McIntyre
3 #+email: rlm@mit.edu 3 #+email: rlm@mit.edu
4 #+description: Simulating senses for AI research using JMonkeyEngine3 4 #+description:
5 #+keywords: JME3, clojure, import, utilities
5 #+SETUPFILE: ../../aurellem/org/setup.org 6 #+SETUPFILE: ../../aurellem/org/setup.org
6 #+INCLUDE: ../../aurellem/org/level-0.org 7 #+INCLUDE: ../../aurellem/org/level-0.org
7 #+babel: :mkdirp yes :noweb yes :exports both 8
9 * Utilities
10
11 These are a collection of functions to make programming jMonkeyEngine
12 in clojure easier.
8 13
9 ** Imports 14 ** Imports
10
11 jMonkeyEngine has a plethora of classes which can be overwhelming at
12 first. So that I one can get right to coding, it's good to take the
13 time right now and make a "import all" function which brings in all of
14 the important jme3 classes. Once I'm happy with the general structure
15 of a namespace I can deal with importing only the classes it actually
16 needs.
17 15
18 #+srcname: import 16 #+srcname: import
19 #+begin_src clojure :results silent 17 #+begin_src clojure :results silent
20 (ns cortex.import 18 (ns cortex.import
21 (:require swank.util.class-browse)) 19 (:require swank.util.class-browse))
47 [] 45 []
48 (doall 46 (doall
49 (map (comp permissive-import symbol) (jme-classes)))) 47 (map (comp permissive-import symbol) (jme-classes))))
50 #+end_src 48 #+end_src
51 49
50 jMonkeyEngine3 has a plethora of classes which can be overwhelming to
51 manage. This code uses reflection to import all of them. Once I'm
52 happy with the general structure of a namespace I can deal with
53 importing only the classes it actually needs.
54
52 The =mega-import-jme3= is quite usefull for debugging purposes since 55 The =mega-import-jme3= is quite usefull for debugging purposes since
53 it allows completion for almost all of JME's classes. 56 it allows completion for almost all of JME's classes.
54 57
55 Out of curiousity, let's see just how many classes =mega-import-jme3= 58 Out of curiousity, let's see just how many classes =mega-import-jme3=
56 imports: 59 imports:
57 60
58 #+begin_src clojure :exports both 61 #+begin_src clojure :exports both :results output
59 (clojure.core/count (cortex.import/jme-classes)) 62 (println (clojure.core/count (cortex.import/jme-classes)) "classes")
60 #+end_src 63 #+end_src
61 64
62 #+results: 65 #+results:
63 : 955 66 : 955 classes
64 67
65 68
66 #+srcname: world-view 69 ** Utilities
67 #+begin_src clojure :results silent 70
68 (ns cortex.util) 71 The utilities here come in three main groups:
69 (require 'cortex.import) 72 - Changing settings in a running =Application=
70 (cortex.import/mega-import-jme3) 73 - Creating objects
71 (use 'cortex.world) 74 - Visualizing objects
72 (defprotocol Viewable 75
73 (view [something])) 76
74 77 *** Changing Settings
75 (extend-type com.jme3.scene.Geometry
76 Viewable
77 (view [geo]
78 (view (doto (Node.)(.attachChild geo)))))
79
80 (extend-type com.jme3.scene.Node
81 Viewable
82 (view [node]
83 (.start
84 (world node
85 {}
86 (fn [world]
87 (.enableDebug
88 (.getPhysicsSpace
89 (.getState
90 (.getStateManager world)
91 BulletAppState))
92 (asset-manager))
93 (set-gravity* world Vector3f/ZERO)
94 ;; (set-gravity* world (Vector3f. 0 (float -0.4) 0))
95 (let [sun (doto (DirectionalLight.)
96 (.setDirection (.normalizeLocal (Vector3f. 1 0 -2)))
97 (.setColor ColorRGBA/White))]
98 (.addLight (.getRootNode world) sun)))
99 no-op))))
100 #+end_src
101
102 Here I make the =Viewable= protocol and extend it to JME's types. Now
103 hello-world can be written as easily as:
104
105 #+begin_src clojure :results silent
106 (cortex.world/view (cortex.world/box))
107 #+end_src
108
109 78
110 #+srcname: util 79 #+srcname: util
111 #+begin_src clojure 80 #+begin_src clojure
112 (in-ns 'cortex.util) 81 (ns cortex.util
113 82 "Utility functions for making jMonkeyEngine easier to program from
114 (def println-repl (bound-fn [& args] (apply println args))) 83 clojure"
115 84 {:author "Robert McIntyre"}
116 (defn position-camera [game] 85 (:use cortex.world)
117 (doto (.getCamera game) 86 (:use clojure.contrib.def)
118 (.setLocation (Vector3f. 0 6 6)) 87 (:import com.jme3.math.Vector3f)
119 (.lookAt Vector3f/ZERO (Vector3f. 0 1 0)))) 88 (:import com.jme3.math.Quaternion)
120 89 (:import com.jme3.asset.TextureKey)
121 (defn set-gravity* 90 (:import com.jme3.bullet.control.RigidBodyControl)
91 (:import com.jme3.bullet.collision.shapes.GImpactCollisionShape)
92 (:import com.jme3.scene.shape.Box)
93 (:import com.jme3.scene.Node)
94 (:import com.jme3.scene.shape.Sphere)
95 (:import com.jme3.light.DirectionalLight)
96 (:import com.jme3.math.ColorRGBA)
97 (:import com.jme3.bullet.BulletAppState)
98 (:import com.jme3.material.Material)
99 (:import com.jme3.scene.Geometry))
100
101 (defvar println-repl
102 (bound-fn [& args] (apply println args))
103 "println called from the LWJGL thread will not go to the REPL, but
104 instead to whatever terminal started the JVM process. This function
105 will always output to the REPL")
106
107 (defn position-camera
108 ([game position direction up]
109 (doto (.getCamera game)
110 (.setLocation )
111 (.lookAt direction up)))
112 ([game position direction]
113 (position-camera
114 game position direction Vector3f/UNIT_Y)))
115
116 (defn enable-debug
117 "Turn on the debug wireframes for every object in this simulation"
118 [world]
119 (.enableDebug
120 (.getPhysicsSpace
121 (.getState
122 (.getStateManager world)
123 BulletAppState))
124 (asset-manager)))
125
126 (defn set-gravity
127 "In order to change the gravity of a scene, it is not only necessary
128 to set the gravity variable, but to \"tap\" every physics object in
129 the scene to reactivate physics calculations."
122 [game gravity] 130 [game gravity]
123 (traverse 131 (traverse
124 (fn [geom] 132 (fn [geom]
125 (if-let 133 (if-let
134 ;; only set gravity for physical objects.
126 [control (.getControl geom RigidBodyControl)] 135 [control (.getControl geom RigidBodyControl)]
127 (do 136 (do
128 (.setGravity control gravity) 137 (.setGravity control gravity)
129 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO) 138 ;; tappsies!
130 ))) 139 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO))))
131 (.getRootNode game))) 140 (.getRootNode game)))
132 #+end_src 141
133 142 (defn add-element
143 "Add the Spatial to the game's environment"
144 ([game element node]
145 (.addAll
146 (.getPhysicsSpace
147 (.getState
148 (.getStateManager game)
149 BulletAppState))
150 element)
151 (.attachChild node element))
152 ([game element]
153 (add-element game element (.getRootNode game))))
154
155 (defn apply-map
156 "Like apply, but works for maps and functions that expect an
157 implicit map and nothing else as in (fn [& {}]).
158 ------- Example -------
159 (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}]
160 (println www))
161 (apply-map demo {:www \"hello!\"})
162 -->\"hello\""
163 [fn m]
164 (apply fn (reduce #(into %1 %2) [] m)))
165
166 #+end_src
167
168
169 *** Creating Basic Shapes
134 170
135 #+srcname: shapes 171 #+srcname: shapes
136 #+begin_src clojure :results silent 172 #+begin_src clojure :results silent
137 (in-ns 'cortex.util) 173 (in-ns 'cortex.util)
174
138 (defrecord shape-description 175 (defrecord shape-description
139 [name 176 [name
140 color 177 color
141 mass 178 mass
142 friction 179 friction
143 texture 180 texture
144 material 181 material
145 position 182 position
146 rotation 183 rotation
147 shape 184 shape
148 physical?]) 185 physical?
186 GImpact?
187 ])
149 188
150 (def base-shape 189 (def base-shape
151 (shape-description. 190 (shape-description.
152 "default-shape" 191 "default-shape"
153 false 192 false
159 ;; material 198 ;; material
160 "Common/MatDefs/Misc/Unshaded.j3md" 199 "Common/MatDefs/Misc/Unshaded.j3md"
161 Vector3f/ZERO 200 Vector3f/ZERO
162 Quaternion/IDENTITY 201 Quaternion/IDENTITY
163 (Box. Vector3f/ZERO 0.5 0.5 0.5) 202 (Box. Vector3f/ZERO 0.5 0.5 0.5)
164 true)) 203 true
204 false))
165 205
166 (defn make-shape 206 (defn make-shape
167 [#^shape-description d] 207 [#^shape-description d]
168 (let [asset-manager (if (:asset-manager d) (:asset-manager d) (asset-manager)) 208 (let [asset-manager (asset-manager)
169 mat (Material. asset-manager (:material d)) 209 mat (Material. asset-manager (:material d))
170 geom (Geometry. (:name d) (:shape d))] 210 geom (Geometry. (:name d) (:shape d))]
171 (if (:texture d) 211 (if (:texture d)
172 (let [key (TextureKey. (:texture d))] 212 (let [key (TextureKey. (:texture d))]
173 (.setGenerateMips key true) 213 (.setGenerateMips key true)
175 (if (:color d) (.setColor mat "Color" (:color d))) 215 (if (:color d) (.setColor mat "Color" (:color d)))
176 (.setMaterial geom mat) 216 (.setMaterial geom mat)
177 (if-let [rotation (:rotation d)] (.rotate geom rotation)) 217 (if-let [rotation (:rotation d)] (.rotate geom rotation))
178 (.setLocalTranslation geom (:position d)) 218 (.setLocalTranslation geom (:position d))
179 (if (:physical? d) 219 (if (:physical? d)
180 (let [impact-shape (doto (GImpactCollisionShape. 220 (let [physics-control
181 (.getMesh geom)) (.setMargin 0)) 221 (if (:GImpact d)
182 physics-control (RigidBodyControl. 222 ;; Create an accurate mesh collision shape if desired.
183 ;;impact-shape ;; comment to disable 223 (RigidBodyControl.
184 (float (:mass d)))] 224 (doto (GImpactCollisionShape.
185 (.createJmeMesh impact-shape) 225 (.getMesh geom))
226 (.createJmeMesh)
227 (.setMargin 0))
228 (float (:mass d)))
229 ;; otherwise use jme3's default
230 (RigidBodyControl. (float (:mass d))))]
186 (.addControl geom physics-control) 231 (.addControl geom physics-control)
187 ;;(.setSleepingThresholds physics-control (float 0) (float 0)) 232 ;;(.setSleepingThresholds physics-control (float 0) (float 0))
188 (.setFriction physics-control (:friction d)))) 233 (.setFriction physics-control (:friction d))))
189 ;;the default is to keep this node in the physics engine forever.
190 ;;these commands must come after the control is added to the geometry.
191 ;;
192 geom)) 234 geom))
193 235
194 (defn box 236 (defn box
195 ([l w h & {:as options}] 237 ([l w h & {:as options}]
196 (let [options (merge base-shape options)] 238 (let [options (merge base-shape options)]
202 ([r & {:as options}] 244 ([r & {:as options}]
203 (let [options (merge base-shape options)] 245 (let [options (merge base-shape options)]
204 (make-shape (assoc options 246 (make-shape (assoc options
205 :shape (Sphere. 32 32 (float r)))))) 247 :shape (Sphere. 32 32 (float r))))))
206 ([] (sphere 0.5))) 248 ([] (sphere 0.5)))
207 249 #+end_src
208 (defn add-element 250
209 ([game element node] 251
210 (.addAll 252 *** Viewing Objects
211 (.getPhysicsSpace 253
212 (.getState 254 #+srcname: world-view
213 (.getStateManager game) 255 #+begin_src clojure :results silent
214 BulletAppState)) 256 (in-ns 'cortex.util)
215 element) 257
216 (.attachChild node element)) 258 (defprotocol Viewable
217 ([game element] 259 (view [something]))
218 (add-element game element (.getRootNode game)))) 260
219 261 (extend-type com.jme3.scene.Geometry
220 262 Viewable
221 (defn apply-map 263 (view [geo]
222 "Like apply, but works for maps and functions that expect an 264 (view (doto (Node.)(.attachChild geo)))))
223 implicit map and nothing else as in (fn [& {}]). 265
224 ------- Example ------- 266 (extend-type com.jme3.scene.Node
225 (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}] 267 Viewable
226 (println www)) 268 (view
227 (apply-map demo {:www \"hello!\"}) 269 [node]
228 -->\"hello\"" 270 (.start
229 [fn m] 271 (world
230 (apply fn (reduce #(into %1 %2) [] m))) 272 node
231 273 {}
232 #+end_src 274 (fn [world]
275 (enable-debug world)
276 (set-gravity world Vector3f/ZERO)
277 (let [sun
278 (doto (DirectionalLight.)
279 (.setDirection
280 (.normalizeLocal (Vector3f. 1 0 -2)))
281 (.setColor ColorRGBA/White))]
282 (.addLight (.getRootNode world) sun)))
283 no-op))))
284 #+end_src
285
286 Here I make the =Viewable= protocol and extend it to JME's types. Now
287 hello-world can be written as easily as:
288
289 #+begin_src clojure :results silent
290 (cortex.util/view (cortex.util/box))
291 #+end_src
292
233 293
234 294
235 295
236 * COMMENT code generation 296 * COMMENT code generation
237 #+begin_src clojure :tangle ../src/cortex/import.clj 297 #+begin_src clojure :tangle ../src/cortex/import.clj
238 <<import>> 298 <<import>>
239 #+end_src 299 #+end_src
240 300
241 301
242 #+begin_src clojure :tangle ../src/cortex/util.clj 302 #+begin_src clojure :tangle ../src/cortex/util.clj :noweb yes
243 <<world-view>>
244 <<util>> 303 <<util>>
245 <<shapes>> 304 <<shapes>>
246 #+end_src 305 <<world-view>>
247 306 #+end_src
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323