rlm@29
|
1 #+title: Clojure Utilities for jMonkeyEngine3
|
rlm@23
|
2 #+author: Robert McIntyre
|
rlm@23
|
3 #+email: rlm@mit.edu
|
rlm@29
|
4 #+description:
|
rlm@29
|
5 #+keywords: JME3, clojure, import, utilities
|
rlm@23
|
6 #+SETUPFILE: ../../aurellem/org/setup.org
|
rlm@23
|
7 #+INCLUDE: ../../aurellem/org/level-0.org
|
rlm@29
|
8
|
rlm@34
|
9 [TABLE-OF-CONTENTS]
|
rlm@29
|
10
|
rlm@29
|
11 These are a collection of functions to make programming jMonkeyEngine
|
rlm@29
|
12 in clojure easier.
|
rlm@23
|
13
|
rlm@34
|
14 * Imports
|
rlm@28
|
15
|
rlm@66
|
16 #+name: import
|
rlm@23
|
17 #+begin_src clojure :results silent
|
rlm@23
|
18 (ns cortex.import
|
rlm@23
|
19 (:require swank.util.class-browse))
|
rlm@23
|
20
|
rlm@23
|
21 (defn permissive-import
|
rlm@23
|
22 [classname]
|
rlm@23
|
23 (eval `(try (import '~classname)
|
rlm@23
|
24 (catch java.lang.Exception e#
|
rlm@23
|
25 (println "couldn't import " '~classname))))
|
rlm@23
|
26 classname)
|
rlm@23
|
27
|
rlm@23
|
28 (defn jme-class? [classname]
|
rlm@23
|
29 (and
|
rlm@23
|
30 (.startsWith classname "com.jme3.")
|
rlm@23
|
31 ;; Don't import the Lwjgl stuff since it can throw exceptions
|
rlm@23
|
32 ;; upon being loaded.
|
rlm@23
|
33 (not (re-matches #".*Lwjgl.*" classname))))
|
rlm@23
|
34
|
rlm@23
|
35 (defn jme-classes
|
rlm@23
|
36 "returns a list of all jme3 classes"
|
rlm@23
|
37 []
|
rlm@23
|
38 (filter
|
rlm@23
|
39 jme-class?
|
rlm@23
|
40 (map :name
|
rlm@23
|
41 swank.util.class-browse/available-classes)))
|
rlm@23
|
42
|
rlm@23
|
43 (defn mega-import-jme3
|
rlm@23
|
44 "Import ALL the jme classes. For REPL use."
|
rlm@23
|
45 []
|
rlm@23
|
46 (doall
|
rlm@23
|
47 (map (comp permissive-import symbol) (jme-classes))))
|
rlm@23
|
48 #+end_src
|
rlm@23
|
49
|
rlm@29
|
50 jMonkeyEngine3 has a plethora of classes which can be overwhelming to
|
rlm@29
|
51 manage. This code uses reflection to import all of them. Once I'm
|
rlm@29
|
52 happy with the general structure of a namespace I can deal with
|
rlm@29
|
53 importing only the classes it actually needs.
|
rlm@29
|
54
|
rlm@23
|
55 The =mega-import-jme3= is quite usefull for debugging purposes since
|
rlm@34
|
56 it allows completion for almost all of JME's classes from the REPL.
|
rlm@23
|
57
|
rlm@23
|
58 Out of curiousity, let's see just how many classes =mega-import-jme3=
|
rlm@23
|
59 imports:
|
rlm@23
|
60
|
rlm@29
|
61 #+begin_src clojure :exports both :results output
|
rlm@29
|
62 (println (clojure.core/count (cortex.import/jme-classes)) "classes")
|
rlm@23
|
63 #+end_src
|
rlm@23
|
64
|
rlm@23
|
65 #+results:
|
rlm@29
|
66 : 955 classes
|
rlm@23
|
67
|
rlm@25
|
68
|
rlm@34
|
69 * Utilities
|
rlm@23
|
70
|
rlm@29
|
71 The utilities here come in three main groups:
|
rlm@29
|
72 - Changing settings in a running =Application=
|
rlm@29
|
73 - Creating objects
|
rlm@50
|
74 - Debug Actions
|
rlm@29
|
75 - Visualizing objects
|
rlm@23
|
76
|
rlm@29
|
77 *** Changing Settings
|
rlm@24
|
78
|
rlm@66
|
79 #+name: util
|
rlm@25
|
80 #+begin_src clojure
|
rlm@29
|
81 (ns cortex.util
|
rlm@34
|
82 "Utility functions for making jMonkeyEngine3 easier to program from
|
rlm@34
|
83 clojure."
|
rlm@29
|
84 {:author "Robert McIntyre"}
|
rlm@29
|
85 (:use cortex.world)
|
rlm@29
|
86 (:use clojure.contrib.def)
|
rlm@29
|
87 (:import com.jme3.math.Vector3f)
|
rlm@29
|
88 (:import com.jme3.math.Quaternion)
|
rlm@29
|
89 (:import com.jme3.asset.TextureKey)
|
rlm@29
|
90 (:import com.jme3.bullet.control.RigidBodyControl)
|
rlm@29
|
91 (:import com.jme3.bullet.collision.shapes.GImpactCollisionShape)
|
rlm@29
|
92 (:import com.jme3.scene.shape.Box)
|
rlm@29
|
93 (:import com.jme3.scene.Node)
|
rlm@29
|
94 (:import com.jme3.scene.shape.Sphere)
|
rlm@47
|
95 (:import com.jme3.light.AmbientLight)
|
rlm@29
|
96 (:import com.jme3.light.DirectionalLight)
|
rlm@114
|
97 (:import (com.jme3.math Triangle ColorRGBA))
|
rlm@29
|
98 (:import com.jme3.bullet.BulletAppState)
|
rlm@29
|
99 (:import com.jme3.material.Material)
|
rlm@40
|
100 (:import com.jme3.scene.Geometry)
|
rlm@114
|
101 (:import java.awt.image.BufferedImage)
|
rlm@114
|
102 (:import javax.swing.JPanel)
|
rlm@114
|
103 (:import javax.swing.JFrame)
|
rlm@114
|
104 (:import javax.swing.SwingUtilities)
|
rlm@114
|
105
|
rlm@40
|
106 (:import (java.util.logging Level Logger)))
|
rlm@40
|
107
|
rlm@29
|
108 (defvar println-repl
|
rlm@29
|
109 (bound-fn [& args] (apply println args))
|
rlm@29
|
110 "println called from the LWJGL thread will not go to the REPL, but
|
rlm@114
|
111 instead to whatever terminal started the JVM process. This function
|
rlm@114
|
112 will always output to the REPL")
|
rlm@25
|
113
|
rlm@29
|
114 (defn position-camera
|
rlm@34
|
115 "Change the position of the in-world camera."
|
rlm@34
|
116 ([world position direction up]
|
rlm@34
|
117 (doto (.getCamera world)
|
rlm@29
|
118 (.setLocation )
|
rlm@29
|
119 (.lookAt direction up)))
|
rlm@34
|
120 ([world position direction]
|
rlm@29
|
121 (position-camera
|
rlm@34
|
122 world position direction Vector3f/UNIT_Y)))
|
rlm@25
|
123
|
rlm@29
|
124 (defn enable-debug
|
rlm@34
|
125 "Turn on debug wireframes for every object in this simulation."
|
rlm@29
|
126 [world]
|
rlm@29
|
127 (.enableDebug
|
rlm@29
|
128 (.getPhysicsSpace
|
rlm@29
|
129 (.getState
|
rlm@29
|
130 (.getStateManager world)
|
rlm@29
|
131 BulletAppState))
|
rlm@29
|
132 (asset-manager)))
|
rlm@29
|
133
|
rlm@78
|
134 (defn speed-up
|
rlm@78
|
135 "Increase the dismally slow speed of the world's camera."
|
rlm@78
|
136 [world]
|
rlm@78
|
137 (.setMoveSpeed (.getFlyByCamera world)
|
rlm@122
|
138 (float 60))
|
rlm@78
|
139 (.setRotationSpeed (.getFlyByCamera world)
|
rlm@122
|
140 (float 3))
|
rlm@78
|
141 world)
|
rlm@78
|
142
|
rlm@78
|
143
|
rlm@40
|
144 (defn no-logging
|
rlm@40
|
145 "Disable all of jMonkeyEngine's logging."
|
rlm@40
|
146 []
|
rlm@40
|
147 (.setLevel (Logger/getLogger "com.jme3") Level/OFF))
|
rlm@40
|
148
|
rlm@40
|
149 (defn set-accuracy
|
rlm@40
|
150 "Change the accuracy at which the World's Physics is calculated."
|
rlm@40
|
151 [world new-accuracy]
|
rlm@40
|
152 (let [physics-manager
|
rlm@40
|
153 (.getState
|
rlm@40
|
154 (.getStateManager world) BulletAppState)]
|
rlm@40
|
155 (.setAccuracy
|
rlm@40
|
156 (.getPhysicsSpace physics-manager)
|
rlm@40
|
157 (float new-accuracy))))
|
rlm@40
|
158
|
rlm@40
|
159
|
rlm@34
|
160 (defn set-gravity
|
rlm@29
|
161 "In order to change the gravity of a scene, it is not only necessary
|
rlm@29
|
162 to set the gravity variable, but to \"tap\" every physics object in
|
rlm@29
|
163 the scene to reactivate physics calculations."
|
rlm@34
|
164 [world gravity]
|
rlm@25
|
165 (traverse
|
rlm@25
|
166 (fn [geom]
|
rlm@25
|
167 (if-let
|
rlm@29
|
168 ;; only set gravity for physical objects.
|
rlm@25
|
169 [control (.getControl geom RigidBodyControl)]
|
rlm@25
|
170 (do
|
rlm@25
|
171 (.setGravity control gravity)
|
rlm@29
|
172 ;; tappsies!
|
rlm@29
|
173 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO))))
|
rlm@34
|
174 (.getRootNode world)))
|
rlm@29
|
175
|
rlm@29
|
176 (defn add-element
|
rlm@34
|
177 "Add the Spatial to the world's environment"
|
rlm@34
|
178 ([world element node]
|
rlm@29
|
179 (.addAll
|
rlm@29
|
180 (.getPhysicsSpace
|
rlm@29
|
181 (.getState
|
rlm@34
|
182 (.getStateManager world)
|
rlm@29
|
183 BulletAppState))
|
rlm@29
|
184 element)
|
rlm@29
|
185 (.attachChild node element))
|
rlm@34
|
186 ([world element]
|
rlm@34
|
187 (add-element world element (.getRootNode world))))
|
rlm@29
|
188
|
rlm@29
|
189 (defn apply-map
|
rlm@29
|
190 "Like apply, but works for maps and functions that expect an
|
rlm@29
|
191 implicit map and nothing else as in (fn [& {}]).
|
rlm@29
|
192 ------- Example -------
|
rlm@29
|
193 (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}]
|
rlm@29
|
194 (println www))
|
rlm@29
|
195 (apply-map demo {:www \"hello!\"})
|
rlm@29
|
196 -->\"hello\""
|
rlm@29
|
197 [fn m]
|
rlm@29
|
198 (apply fn (reduce #(into %1 %2) [] m)))
|
rlm@29
|
199
|
rlm@151
|
200 (defn map-vals
|
rlm@151
|
201 "Transform a map by applying a function to its values,
|
rlm@151
|
202 keeping the keys the same."
|
rlm@151
|
203 [f m] (zipmap (keys m) (map f (vals m))))
|
rlm@151
|
204
|
rlm@151
|
205
|
rlm@25
|
206 #+end_src
|
rlm@25
|
207
|
rlm@47
|
208 #+results: util
|
rlm@47
|
209 : #'cortex.util/apply-map
|
rlm@73
|
210
|
rlm@25
|
211
|
rlm@29
|
212 *** Creating Basic Shapes
|
rlm@29
|
213
|
rlm@66
|
214 #+name: shapes
|
rlm@25
|
215 #+begin_src clojure :results silent
|
rlm@25
|
216 (in-ns 'cortex.util)
|
rlm@29
|
217
|
rlm@153
|
218 (defn load-bullet
|
rlm@153
|
219 "Runnig this function unpacks the native bullet libraries and makes
|
rlm@153
|
220 them available."
|
rlm@153
|
221 []
|
rlm@153
|
222 (let [sim (world (Node.) {} no-op no-op)]
|
rlm@153
|
223 (doto sim
|
rlm@153
|
224 (.enqueue
|
rlm@153
|
225 (fn []
|
rlm@153
|
226 (.stop sim)))
|
rlm@153
|
227 (.start))))
|
rlm@153
|
228
|
rlm@153
|
229
|
rlm@25
|
230 (defrecord shape-description
|
rlm@25
|
231 [name
|
rlm@25
|
232 color
|
rlm@25
|
233 mass
|
rlm@25
|
234 friction
|
rlm@25
|
235 texture
|
rlm@25
|
236 material
|
rlm@25
|
237 position
|
rlm@25
|
238 rotation
|
rlm@25
|
239 shape
|
rlm@29
|
240 physical?
|
rlm@29
|
241 GImpact?
|
rlm@29
|
242 ])
|
rlm@25
|
243
|
rlm@34
|
244 (defvar base-shape
|
rlm@25
|
245 (shape-description.
|
rlm@25
|
246 "default-shape"
|
rlm@25
|
247 false
|
rlm@25
|
248 ;;ColorRGBA/Blue
|
rlm@25
|
249 1.0 ;; mass
|
rlm@25
|
250 1.0 ;; friction
|
rlm@25
|
251 ;; texture
|
rlm@25
|
252 "Textures/Terrain/BrickWall/BrickWall.jpg"
|
rlm@25
|
253 ;; material
|
rlm@25
|
254 "Common/MatDefs/Misc/Unshaded.j3md"
|
rlm@25
|
255 Vector3f/ZERO
|
rlm@25
|
256 Quaternion/IDENTITY
|
rlm@25
|
257 (Box. Vector3f/ZERO 0.5 0.5 0.5)
|
rlm@29
|
258 true
|
rlm@34
|
259 false)
|
rlm@34
|
260 "Basic settings for shapes.")
|
rlm@25
|
261
|
rlm@25
|
262 (defn make-shape
|
rlm@25
|
263 [#^shape-description d]
|
rlm@29
|
264 (let [asset-manager (asset-manager)
|
rlm@25
|
265 mat (Material. asset-manager (:material d))
|
rlm@25
|
266 geom (Geometry. (:name d) (:shape d))]
|
rlm@25
|
267 (if (:texture d)
|
rlm@25
|
268 (let [key (TextureKey. (:texture d))]
|
rlm@34
|
269 ;;(.setGenerateMips key true)
|
rlm@34
|
270 ;;(.setTexture mat "ColorMap" (.loadTexture asset-manager key))
|
rlm@34
|
271 ))
|
rlm@25
|
272 (if (:color d) (.setColor mat "Color" (:color d)))
|
rlm@25
|
273 (.setMaterial geom mat)
|
rlm@25
|
274 (if-let [rotation (:rotation d)] (.rotate geom rotation))
|
rlm@25
|
275 (.setLocalTranslation geom (:position d))
|
rlm@25
|
276 (if (:physical? d)
|
rlm@29
|
277 (let [physics-control
|
rlm@29
|
278 (if (:GImpact d)
|
rlm@29
|
279 ;; Create an accurate mesh collision shape if desired.
|
rlm@29
|
280 (RigidBodyControl.
|
rlm@29
|
281 (doto (GImpactCollisionShape.
|
rlm@29
|
282 (.getMesh geom))
|
rlm@29
|
283 (.createJmeMesh)
|
rlm@73
|
284 ;;(.setMargin 0)
|
rlm@73
|
285 )
|
rlm@29
|
286 (float (:mass d)))
|
rlm@29
|
287 ;; otherwise use jme3's default
|
rlm@29
|
288 (RigidBodyControl. (float (:mass d))))]
|
rlm@25
|
289 (.addControl geom physics-control)
|
rlm@25
|
290 ;;(.setSleepingThresholds physics-control (float 0) (float 0))
|
rlm@25
|
291 (.setFriction physics-control (:friction d))))
|
rlm@25
|
292 geom))
|
rlm@25
|
293
|
rlm@25
|
294 (defn box
|
rlm@25
|
295 ([l w h & {:as options}]
|
rlm@25
|
296 (let [options (merge base-shape options)]
|
rlm@25
|
297 (make-shape (assoc options
|
rlm@25
|
298 :shape (Box. l w h)))))
|
rlm@25
|
299 ([] (box 0.5 0.5 0.5)))
|
rlm@25
|
300
|
rlm@25
|
301 (defn sphere
|
rlm@25
|
302 ([r & {:as options}]
|
rlm@25
|
303 (let [options (merge base-shape options)]
|
rlm@25
|
304 (make-shape (assoc options
|
rlm@25
|
305 :shape (Sphere. 32 32 (float r))))))
|
rlm@25
|
306 ([] (sphere 0.5)))
|
rlm@62
|
307
|
rlm@74
|
308 (defn green-x-ray
|
rlm@74
|
309 "A usefull material for debuging -- it can be seen no matter what
|
rlm@74
|
310 object occuldes it."
|
rlm@74
|
311 []
|
rlm@74
|
312 (doto (Material. (asset-manager)
|
rlm@74
|
313 "Common/MatDefs/Misc/Unshaded.j3md")
|
rlm@74
|
314 (.setColor "Color" ColorRGBA/Green)
|
rlm@74
|
315 (-> (.getAdditionalRenderState)
|
rlm@74
|
316 (.setDepthTest false))))
|
rlm@74
|
317
|
rlm@62
|
318 (defn node-seq
|
rlm@62
|
319 "Take a node and return a seq of all its children
|
rlm@62
|
320 recursively. There will be no nodes left in the resulting
|
rlm@62
|
321 structure"
|
rlm@62
|
322 [#^Node node]
|
rlm@62
|
323 (tree-seq #(isa? (class %) Node) #(.getChildren %) node))
|
rlm@62
|
324
|
rlm@62
|
325 (defn nodify
|
rlm@62
|
326 "Take a sequence of things that can be attached to a node and return
|
rlm@62
|
327 a node with all of them attached"
|
rlm@62
|
328 ([name children]
|
rlm@62
|
329 (let [node (Node. name)]
|
rlm@62
|
330 (dorun (map #(.attachChild node %) children))
|
rlm@62
|
331 node))
|
rlm@62
|
332 ([children] (nodify "" children)))
|
rlm@62
|
333
|
rlm@62
|
334
|
rlm@29
|
335 #+end_src
|
rlm@25
|
336
|
rlm@25
|
337
|
rlm@50
|
338 *** Debug Actions
|
rlm@66
|
339 #+name: debug-actions
|
rlm@29
|
340 #+begin_src clojure :results silent
|
rlm@60
|
341 (in-ns 'cortex.util)
|
rlm@60
|
342
|
rlm@47
|
343 (defn basic-light-setup
|
rlm@47
|
344 "returns a sequence of lights appropiate for fully lighting a scene"
|
rlm@47
|
345 []
|
rlm@47
|
346 (conj
|
rlm@47
|
347 (doall
|
rlm@47
|
348 (map
|
rlm@47
|
349 (fn [direction]
|
rlm@47
|
350 (doto (DirectionalLight.)
|
rlm@47
|
351 (.setDirection direction)
|
rlm@47
|
352 (.setColor ColorRGBA/White)))
|
rlm@47
|
353 [;; six faces of a cube
|
rlm@47
|
354 Vector3f/UNIT_X
|
rlm@47
|
355 Vector3f/UNIT_Y
|
rlm@47
|
356 Vector3f/UNIT_Z
|
rlm@47
|
357 (.mult Vector3f/UNIT_X (float -1))
|
rlm@47
|
358 (.mult Vector3f/UNIT_Y (float -1))
|
rlm@47
|
359 (.mult Vector3f/UNIT_Z (float -1))]))
|
rlm@47
|
360 (doto (AmbientLight.)
|
rlm@47
|
361 (.setColor ColorRGBA/White))))
|
rlm@47
|
362
|
rlm@47
|
363 (defn light-up-everything
|
rlm@47
|
364 "Add lights to a world appropiate for quickly seeing everything
|
rlm@47
|
365 in the scene. Adds six DirectionalLights facing in orthogonal
|
rlm@47
|
366 directions, and one AmbientLight to provide overall lighting
|
rlm@47
|
367 coverage."
|
rlm@47
|
368 [world]
|
rlm@47
|
369 (dorun
|
rlm@47
|
370 (map
|
rlm@47
|
371 #(.addLight (.getRootNode world) %)
|
rlm@47
|
372 (basic-light-setup))))
|
rlm@50
|
373
|
rlm@50
|
374 (defn fire-cannon-ball
|
rlm@50
|
375 "Creates a function that fires a cannon-ball from the current game's
|
rlm@50
|
376 camera. The cannon-ball will be attached to the node if provided, or
|
rlm@50
|
377 to the game's RootNode if no node is provided."
|
rlm@50
|
378 ([node]
|
rlm@50
|
379 (fn [game value]
|
rlm@50
|
380 (if (not value)
|
rlm@50
|
381 (let [camera (.getCamera game)
|
rlm@50
|
382 cannon-ball
|
rlm@50
|
383 (sphere 0.7
|
rlm@50
|
384 :material "Common/MatDefs/Misc/Unshaded.j3md"
|
rlm@50
|
385 :texture "Textures/PokeCopper.jpg"
|
rlm@50
|
386 :position
|
rlm@50
|
387 (.add (.getLocation camera)
|
rlm@50
|
388 (.mult (.getDirection camera) (float 1)))
|
rlm@50
|
389 :mass 3)] ;200 0.05
|
rlm@50
|
390 (.setLinearVelocity
|
rlm@50
|
391 (.getControl cannon-ball RigidBodyControl)
|
rlm@50
|
392 (.mult (.getDirection camera) (float 50))) ;50
|
rlm@50
|
393 (add-element game cannon-ball (if node node (.getRootNode game)))))))
|
rlm@50
|
394 ([]
|
rlm@50
|
395 (fire-cannon-ball false)))
|
rlm@60
|
396
|
rlm@60
|
397 (def standard-debug-controls
|
rlm@60
|
398 {"key-space" (fire-cannon-ball)})
|
rlm@60
|
399
|
rlm@60
|
400
|
rlm@160
|
401 (defn tap [obj direction force]
|
rlm@160
|
402 (let [control (.getControl obj RigidBodyControl)]
|
rlm@160
|
403 (.applyTorque
|
rlm@160
|
404 control
|
rlm@160
|
405 (.mult (.getPhysicsRotation control)
|
rlm@160
|
406 (.mult (.normalize direction) (float force))))))
|
rlm@160
|
407
|
rlm@160
|
408
|
rlm@160
|
409 (defn with-movement
|
rlm@160
|
410 [object
|
rlm@160
|
411 [up down left right roll-up roll-down :as keyboard]
|
rlm@160
|
412 forces
|
rlm@160
|
413 [root-node
|
rlm@160
|
414 keymap
|
rlm@160
|
415 intilization
|
rlm@160
|
416 world-loop]]
|
rlm@160
|
417 (let [add-keypress
|
rlm@160
|
418 (fn [state keymap key]
|
rlm@160
|
419 (merge keymap
|
rlm@160
|
420 {key
|
rlm@160
|
421 (fn [_ pressed?]
|
rlm@160
|
422 (reset! state pressed?))}))
|
rlm@160
|
423 move-up? (atom false)
|
rlm@160
|
424 move-down? (atom false)
|
rlm@160
|
425 move-left? (atom false)
|
rlm@160
|
426 move-right? (atom false)
|
rlm@160
|
427 roll-left? (atom false)
|
rlm@160
|
428 roll-right? (atom false)
|
rlm@160
|
429
|
rlm@160
|
430 directions [(Vector3f. 0 1 0)(Vector3f. 0 -1 0)
|
rlm@160
|
431 (Vector3f. 0 0 1)(Vector3f. 0 0 -1)
|
rlm@160
|
432 (Vector3f. -1 0 0)(Vector3f. 1 0 0)]
|
rlm@160
|
433 atoms [move-left? move-right? move-up? move-down?
|
rlm@160
|
434 roll-left? roll-right?]
|
rlm@160
|
435
|
rlm@160
|
436 keymap* (reduce merge
|
rlm@160
|
437 (map #(add-keypress %1 keymap %2)
|
rlm@160
|
438 atoms
|
rlm@160
|
439 keyboard))
|
rlm@160
|
440
|
rlm@160
|
441 splice-loop (fn []
|
rlm@160
|
442 (dorun
|
rlm@160
|
443 (map
|
rlm@160
|
444 (fn [sym direction force]
|
rlm@160
|
445 (if @sym
|
rlm@160
|
446 (tap object direction force)))
|
rlm@160
|
447 atoms directions forces)))
|
rlm@160
|
448
|
rlm@160
|
449 world-loop* (fn [world tpf]
|
rlm@160
|
450 (world-loop world tpf)
|
rlm@160
|
451 (splice-loop))]
|
rlm@160
|
452 [root-node
|
rlm@160
|
453 keymap*
|
rlm@160
|
454 intilization
|
rlm@160
|
455 world-loop*]))
|
rlm@160
|
456
|
rlm@60
|
457
|
rlm@60
|
458
|
rlm@50
|
459 #+end_src
|
rlm@50
|
460
|
rlm@50
|
461
|
rlm@50
|
462 *** Viewing Objects
|
rlm@50
|
463
|
rlm@66
|
464 #+name: world-view
|
rlm@50
|
465 #+begin_src clojure :results silent
|
rlm@50
|
466 (in-ns 'cortex.util)
|
rlm@50
|
467
|
rlm@114
|
468 (defn view-image
|
rlm@114
|
469 "Initailizes a JPanel on which you may draw a BufferedImage.
|
rlm@114
|
470 Returns a function that accepts a BufferedImage and draws it to the
|
rlm@114
|
471 JPanel."
|
rlm@114
|
472 []
|
rlm@114
|
473 (let [image
|
rlm@114
|
474 (atom
|
rlm@114
|
475 (BufferedImage. 1 1 BufferedImage/TYPE_4BYTE_ABGR))
|
rlm@114
|
476 panel
|
rlm@114
|
477 (proxy [JPanel] []
|
rlm@114
|
478 (paint
|
rlm@114
|
479 [graphics]
|
rlm@114
|
480 (proxy-super paintComponent graphics)
|
rlm@114
|
481 (.drawImage graphics @image 0 0 nil)))
|
rlm@114
|
482 frame (JFrame. "Display Image")]
|
rlm@114
|
483 (SwingUtilities/invokeLater
|
rlm@114
|
484 (fn []
|
rlm@114
|
485 (doto frame
|
rlm@114
|
486 (-> (.getContentPane) (.add panel))
|
rlm@114
|
487 (.pack)
|
rlm@114
|
488 (.setLocationRelativeTo nil)
|
rlm@114
|
489 (.setResizable true)
|
rlm@114
|
490 (.setVisible true))))
|
rlm@114
|
491 (fn [#^BufferedImage i]
|
rlm@114
|
492 (reset! image i)
|
rlm@114
|
493 (.setSize frame (+ 8 (.getWidth i)) (+ 28 (.getHeight i)))
|
rlm@114
|
494 (.repaint panel 0 0 (.getWidth i) (.getHeight i)))))
|
rlm@114
|
495
|
rlm@50
|
496 (defprotocol Viewable
|
rlm@50
|
497 (view [something]))
|
rlm@50
|
498
|
rlm@50
|
499 (extend-type com.jme3.scene.Geometry
|
rlm@50
|
500 Viewable
|
rlm@50
|
501 (view [geo]
|
rlm@50
|
502 (view (doto (Node.)(.attachChild geo)))))
|
rlm@47
|
503
|
rlm@29
|
504 (extend-type com.jme3.scene.Node
|
rlm@29
|
505 Viewable
|
rlm@29
|
506 (view
|
rlm@29
|
507 [node]
|
rlm@29
|
508 (.start
|
rlm@29
|
509 (world
|
rlm@29
|
510 node
|
rlm@29
|
511 {}
|
rlm@29
|
512 (fn [world]
|
rlm@29
|
513 (enable-debug world)
|
rlm@29
|
514 (set-gravity world Vector3f/ZERO)
|
rlm@47
|
515 (light-up-everything world))
|
rlm@29
|
516 no-op))))
|
rlm@62
|
517
|
rlm@62
|
518 (extend-type com.jme3.math.ColorRGBA
|
rlm@62
|
519 Viewable
|
rlm@62
|
520 (view
|
rlm@62
|
521 [color]
|
rlm@62
|
522 (view (doto (Node.)
|
rlm@62
|
523 (.attachChild (box 1 1 1 :color color))))))
|
rlm@62
|
524
|
rlm@62
|
525 (defprotocol Textual
|
rlm@62
|
526 (text [something]
|
rlm@62
|
527 "Display a detailed textual analysis of the given object."))
|
rlm@62
|
528
|
rlm@62
|
529 (extend-type com.jme3.scene.Node
|
rlm@62
|
530 Textual
|
rlm@62
|
531 (text [node]
|
rlm@62
|
532 (println "Total Vertexes: " (.getVertexCount node))
|
rlm@62
|
533 (println "Total Triangles: " (.getTriangleCount node))
|
rlm@62
|
534 (println "Controls :")
|
rlm@62
|
535 (dorun (map #(text (.getControl node %)) (range (.getNumControls node))))
|
rlm@62
|
536 (println "Has " (.getQuantity node) " Children:")
|
rlm@62
|
537 (doall (map text (.getChildren node)))))
|
rlm@62
|
538
|
rlm@62
|
539 (extend-type com.jme3.animation.AnimControl
|
rlm@62
|
540 Textual
|
rlm@62
|
541 (text [control]
|
rlm@62
|
542 (let [animations (.getAnimationNames control)]
|
rlm@62
|
543 (println "Animation Control with " (count animations) " animation(s):")
|
rlm@62
|
544 (dorun (map println animations)))))
|
rlm@62
|
545
|
rlm@62
|
546 (extend-type com.jme3.animation.SkeletonControl
|
rlm@62
|
547 Textual
|
rlm@62
|
548 (text [control]
|
rlm@62
|
549 (println "Skeleton Control with the following skeleton:")
|
rlm@62
|
550 (println (.getSkeleton control))))
|
rlm@62
|
551
|
rlm@62
|
552 (extend-type com.jme3.bullet.control.KinematicRagdollControl
|
rlm@62
|
553 Textual
|
rlm@62
|
554 (text [control]
|
rlm@62
|
555 (println "Ragdoll Control")))
|
rlm@62
|
556
|
rlm@62
|
557 (extend-type com.jme3.scene.Geometry
|
rlm@62
|
558 Textual
|
rlm@62
|
559 (text [control]
|
rlm@62
|
560 (println "...geo...")))
|
rlm@108
|
561
|
rlm@108
|
562 (extend-type Triangle
|
rlm@108
|
563 Textual
|
rlm@108
|
564 (text [t]
|
rlm@108
|
565 (println "Triangle: " \newline (.get1 t) \newline
|
rlm@108
|
566 (.get2 t) \newline (.get3 t))))
|
rlm@108
|
567
|
rlm@25
|
568 #+end_src
|
rlm@25
|
569
|
rlm@29
|
570 Here I make the =Viewable= protocol and extend it to JME's types. Now
|
rlm@34
|
571 JME3's =hello-world= can be written as easily as:
|
rlm@29
|
572
|
rlm@29
|
573 #+begin_src clojure :results silent
|
rlm@29
|
574 (cortex.util/view (cortex.util/box))
|
rlm@29
|
575 #+end_src
|
rlm@29
|
576
|
rlm@29
|
577
|
rlm@24
|
578 * COMMENT code generation
|
rlm@24
|
579 #+begin_src clojure :tangle ../src/cortex/import.clj
|
rlm@24
|
580 <<import>>
|
rlm@24
|
581 #+end_src
|
rlm@25
|
582
|
rlm@25
|
583
|
rlm@29
|
584 #+begin_src clojure :tangle ../src/cortex/util.clj :noweb yes
|
rlm@25
|
585 <<util>>
|
rlm@25
|
586 <<shapes>>
|
rlm@50
|
587 <<debug-actions>>
|
rlm@29
|
588 <<world-view>>
|
rlm@25
|
589 #+end_src
|
rlm@25
|
590
|
rlm@29
|
591
|
rlm@29
|
592
|
rlm@29
|
593
|
rlm@29
|
594
|
rlm@29
|
595
|
rlm@29
|
596
|
rlm@29
|
597
|
rlm@29
|
598
|
rlm@29
|
599
|
rlm@29
|
600
|
rlm@29
|
601
|
rlm@29
|
602
|
rlm@29
|
603
|
rlm@29
|
604
|
rlm@29
|
605
|
rlm@29
|
606
|