annotate org/util.org @ 320:52de8a36edde

removed last vestiges of clojure.contrib
author Robert McIntyre <rlm@mit.edu>
date Thu, 01 Mar 2012 06:24:17 -0700
parents bb3f8a4af87f
children 5dcd44576cbc
rev   line source
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@306 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@306 55 The =mega-import-jme3= is quite useful for debugging purposes since
rlm@34 56 it allows completion for almost all of JME's classes from the REPL.
rlm@23 57
rlm@306 58 Out of curiosity, 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 (:import com.jme3.math.Vector3f)
rlm@29 87 (:import com.jme3.math.Quaternion)
rlm@29 88 (:import com.jme3.asset.TextureKey)
rlm@29 89 (:import com.jme3.bullet.control.RigidBodyControl)
rlm@29 90 (:import com.jme3.bullet.collision.shapes.GImpactCollisionShape)
rlm@29 91 (:import com.jme3.scene.shape.Box)
rlm@29 92 (:import com.jme3.scene.Node)
rlm@29 93 (:import com.jme3.scene.shape.Sphere)
rlm@47 94 (:import com.jme3.light.AmbientLight)
rlm@29 95 (:import com.jme3.light.DirectionalLight)
rlm@114 96 (:import (com.jme3.math Triangle ColorRGBA))
rlm@29 97 (:import com.jme3.bullet.BulletAppState)
rlm@29 98 (:import com.jme3.material.Material)
rlm@40 99 (:import com.jme3.scene.Geometry)
rlm@114 100 (:import java.awt.image.BufferedImage)
rlm@114 101 (:import javax.swing.JPanel)
rlm@114 102 (:import javax.swing.JFrame)
rlm@114 103 (:import javax.swing.SwingUtilities)
rlm@192 104 (:import com.jme3.scene.plugins.blender.BlenderModelLoader)
rlm@40 105 (:import (java.util.logging Level Logger)))
rlm@40 106
rlm@320 107 (def println-repl
rlm@29 108 "println called from the LWJGL thread will not go to the REPL, but
rlm@114 109 instead to whatever terminal started the JVM process. This function
rlm@320 110 will always output to the REPL"
rlm@320 111 (bound-fn [& args] (apply println args)))
rlm@25 112
rlm@29 113 (defn position-camera
rlm@34 114 "Change the position of the in-world camera."
rlm@297 115 [world #^Vector3f position #^Quaternion rotation]
rlm@34 116 (doto (.getCamera world)
rlm@297 117 (.setLocation position)
rlm@297 118 (.setRotation rotation)))
rlm@25 119
rlm@29 120 (defn enable-debug
rlm@34 121 "Turn on debug wireframes for every object in this simulation."
rlm@29 122 [world]
rlm@29 123 (.enableDebug
rlm@29 124 (.getPhysicsSpace
rlm@29 125 (.getState
rlm@29 126 (.getStateManager world)
rlm@29 127 BulletAppState))
rlm@29 128 (asset-manager)))
rlm@29 129
rlm@78 130 (defn speed-up
rlm@78 131 "Increase the dismally slow speed of the world's camera."
rlm@78 132 [world]
rlm@78 133 (.setMoveSpeed (.getFlyByCamera world)
rlm@122 134 (float 60))
rlm@78 135 (.setRotationSpeed (.getFlyByCamera world)
rlm@122 136 (float 3))
rlm@78 137 world)
rlm@78 138
rlm@78 139
rlm@40 140 (defn no-logging
rlm@40 141 "Disable all of jMonkeyEngine's logging."
rlm@40 142 []
rlm@40 143 (.setLevel (Logger/getLogger "com.jme3") Level/OFF))
rlm@40 144
rlm@40 145 (defn set-accuracy
rlm@40 146 "Change the accuracy at which the World's Physics is calculated."
rlm@40 147 [world new-accuracy]
rlm@40 148 (let [physics-manager
rlm@40 149 (.getState
rlm@40 150 (.getStateManager world) BulletAppState)]
rlm@40 151 (.setAccuracy
rlm@40 152 (.getPhysicsSpace physics-manager)
rlm@40 153 (float new-accuracy))))
rlm@40 154
rlm@40 155
rlm@34 156 (defn set-gravity
rlm@29 157 "In order to change the gravity of a scene, it is not only necessary
rlm@29 158 to set the gravity variable, but to \"tap\" every physics object in
rlm@29 159 the scene to reactivate physics calculations."
rlm@34 160 [world gravity]
rlm@25 161 (traverse
rlm@25 162 (fn [geom]
rlm@25 163 (if-let
rlm@29 164 ;; only set gravity for physical objects.
rlm@25 165 [control (.getControl geom RigidBodyControl)]
rlm@25 166 (do
rlm@25 167 (.setGravity control gravity)
rlm@29 168 ;; tappsies!
rlm@29 169 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO))))
rlm@34 170 (.getRootNode world)))
rlm@29 171
rlm@29 172 (defn add-element
rlm@34 173 "Add the Spatial to the world's environment"
rlm@34 174 ([world element node]
rlm@29 175 (.addAll
rlm@29 176 (.getPhysicsSpace
rlm@29 177 (.getState
rlm@34 178 (.getStateManager world)
rlm@29 179 BulletAppState))
rlm@29 180 element)
rlm@29 181 (.attachChild node element))
rlm@34 182 ([world element]
rlm@34 183 (add-element world element (.getRootNode world))))
rlm@29 184
rlm@29 185 (defn apply-map
rlm@29 186 "Like apply, but works for maps and functions that expect an
rlm@29 187 implicit map and nothing else as in (fn [& {}]).
rlm@29 188 ------- Example -------
rlm@29 189 (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}]
rlm@29 190 (println www))
rlm@29 191 (apply-map demo {:www \"hello!\"})
rlm@29 192 -->\"hello\""
rlm@29 193 [fn m]
rlm@29 194 (apply fn (reduce #(into %1 %2) [] m)))
rlm@29 195
rlm@151 196 (defn map-vals
rlm@151 197 "Transform a map by applying a function to its values,
rlm@151 198 keeping the keys the same."
rlm@151 199 [f m] (zipmap (keys m) (map f (vals m))))
rlm@151 200
rlm@164 201 (defn runonce
rlm@164 202 "Decorator. returns a function which will run only once.
rlm@164 203 Inspired by Halloway's version from Lancet."
rlm@164 204 {:author "Robert McIntyre"}
rlm@164 205 [function]
rlm@164 206 (let [sentinel (Object.)
rlm@164 207 result (atom sentinel)]
rlm@164 208 (fn [& args]
rlm@164 209 (locking sentinel
rlm@164 210 (if (= @result sentinel)
rlm@164 211 (reset! result (apply function args))
rlm@164 212 @result)))))
rlm@164 213
rlm@151 214
rlm@25 215 #+end_src
rlm@25 216
rlm@47 217 #+results: util
rlm@297 218 : #'cortex.util/runonce
rlm@73 219
rlm@25 220
rlm@29 221 *** Creating Basic Shapes
rlm@29 222
rlm@66 223 #+name: shapes
rlm@25 224 #+begin_src clojure :results silent
rlm@25 225 (in-ns 'cortex.util)
rlm@29 226
rlm@153 227 (defn load-bullet
rlm@306 228 "Running this function unpacks the native bullet libraries and makes
rlm@153 229 them available."
rlm@153 230 []
rlm@153 231 (let [sim (world (Node.) {} no-op no-op)]
rlm@153 232 (doto sim
rlm@153 233 (.enqueue
rlm@153 234 (fn []
rlm@153 235 (.stop sim)))
rlm@153 236 (.start))))
rlm@153 237
rlm@153 238
rlm@25 239 (defrecord shape-description
rlm@25 240 [name
rlm@25 241 color
rlm@25 242 mass
rlm@25 243 friction
rlm@25 244 texture
rlm@25 245 material
rlm@25 246 position
rlm@25 247 rotation
rlm@25 248 shape
rlm@29 249 physical?
rlm@29 250 GImpact?
rlm@29 251 ])
rlm@25 252
rlm@320 253 (def base-shape
rlm@320 254 "Basic settings for shapes."
rlm@320 255 (shape-description.
rlm@320 256 "default-shape"
rlm@320 257 false
rlm@320 258 ;;ColorRGBA/Blue
rlm@320 259 1.0 ;; mass
rlm@320 260 1.0 ;; friction
rlm@320 261 ;; texture
rlm@320 262 "Textures/Terrain/BrickWall/BrickWall.jpg"
rlm@320 263 ;; material
rlm@320 264 "Common/MatDefs/Misc/Unshaded.j3md"
rlm@320 265 Vector3f/ZERO
rlm@320 266 Quaternion/IDENTITY
rlm@320 267 (Box. Vector3f/ZERO 0.5 0.5 0.5)
rlm@320 268 true
rlm@320 269 false))
rlm@25 270
rlm@25 271 (defn make-shape
rlm@25 272 [#^shape-description d]
rlm@29 273 (let [asset-manager (asset-manager)
rlm@25 274 mat (Material. asset-manager (:material d))
rlm@25 275 geom (Geometry. (:name d) (:shape d))]
rlm@25 276 (if (:texture d)
rlm@25 277 (let [key (TextureKey. (:texture d))]
rlm@34 278 ;;(.setGenerateMips key true)
rlm@34 279 ;;(.setTexture mat "ColorMap" (.loadTexture asset-manager key))
rlm@34 280 ))
rlm@25 281 (if (:color d) (.setColor mat "Color" (:color d)))
rlm@25 282 (.setMaterial geom mat)
rlm@25 283 (if-let [rotation (:rotation d)] (.rotate geom rotation))
rlm@25 284 (.setLocalTranslation geom (:position d))
rlm@25 285 (if (:physical? d)
rlm@29 286 (let [physics-control
rlm@29 287 (if (:GImpact d)
rlm@29 288 ;; Create an accurate mesh collision shape if desired.
rlm@29 289 (RigidBodyControl.
rlm@29 290 (doto (GImpactCollisionShape.
rlm@29 291 (.getMesh geom))
rlm@29 292 (.createJmeMesh)
rlm@73 293 ;;(.setMargin 0)
rlm@73 294 )
rlm@29 295 (float (:mass d)))
rlm@29 296 ;; otherwise use jme3's default
rlm@29 297 (RigidBodyControl. (float (:mass d))))]
rlm@25 298 (.addControl geom physics-control)
rlm@25 299 ;;(.setSleepingThresholds physics-control (float 0) (float 0))
rlm@25 300 (.setFriction physics-control (:friction d))))
rlm@25 301 geom))
rlm@25 302
rlm@25 303 (defn box
rlm@25 304 ([l w h & {:as options}]
rlm@25 305 (let [options (merge base-shape options)]
rlm@25 306 (make-shape (assoc options
rlm@25 307 :shape (Box. l w h)))))
rlm@25 308 ([] (box 0.5 0.5 0.5)))
rlm@25 309
rlm@25 310 (defn sphere
rlm@25 311 ([r & {:as options}]
rlm@25 312 (let [options (merge base-shape options)]
rlm@25 313 (make-shape (assoc options
rlm@25 314 :shape (Sphere. 32 32 (float r))))))
rlm@25 315 ([] (sphere 0.5)))
rlm@62 316
rlm@192 317 (defn x-ray
rlm@306 318 "A useful material for debugging -- it can be seen no matter what
rlm@306 319 object occludes it."
rlm@192 320 [#^ColorRGBA color]
rlm@192 321 (doto (Material. (asset-manager)
rlm@192 322 "Common/MatDefs/Misc/Unshaded.j3md")
rlm@192 323 (.setColor "Color" color)
rlm@192 324 (-> (.getAdditionalRenderState)
rlm@192 325 (.setDepthTest false))))
rlm@74 326
rlm@62 327 (defn node-seq
rlm@62 328 "Take a node and return a seq of all its children
rlm@62 329 recursively. There will be no nodes left in the resulting
rlm@62 330 structure"
rlm@62 331 [#^Node node]
rlm@62 332 (tree-seq #(isa? (class %) Node) #(.getChildren %) node))
rlm@62 333
rlm@62 334 (defn nodify
rlm@62 335 "Take a sequence of things that can be attached to a node and return
rlm@62 336 a node with all of them attached"
rlm@62 337 ([name children]
rlm@62 338 (let [node (Node. name)]
rlm@62 339 (dorun (map #(.attachChild node %) children))
rlm@62 340 node))
rlm@62 341 ([children] (nodify "" children)))
rlm@62 342
rlm@192 343 (defn load-blender-model
rlm@192 344 "Load a .blend file using an asset folder relative path."
rlm@192 345 [^String model]
rlm@192 346 (.loadModel
rlm@192 347 (doto (asset-manager)
rlm@192 348 (.registerLoader BlenderModelLoader
rlm@192 349 (into-array String ["blend"]))) model))
rlm@192 350
rlm@62 351
rlm@29 352 #+end_src
rlm@25 353
rlm@25 354
rlm@50 355 *** Debug Actions
rlm@66 356 #+name: debug-actions
rlm@29 357 #+begin_src clojure :results silent
rlm@60 358 (in-ns 'cortex.util)
rlm@60 359
rlm@47 360 (defn basic-light-setup
rlm@306 361 "returns a sequence of lights appropriate for fully lighting a scene"
rlm@47 362 []
rlm@47 363 (conj
rlm@47 364 (doall
rlm@47 365 (map
rlm@47 366 (fn [direction]
rlm@47 367 (doto (DirectionalLight.)
rlm@47 368 (.setDirection direction)
rlm@47 369 (.setColor ColorRGBA/White)))
rlm@47 370 [;; six faces of a cube
rlm@47 371 Vector3f/UNIT_X
rlm@47 372 Vector3f/UNIT_Y
rlm@47 373 Vector3f/UNIT_Z
rlm@47 374 (.mult Vector3f/UNIT_X (float -1))
rlm@47 375 (.mult Vector3f/UNIT_Y (float -1))
rlm@47 376 (.mult Vector3f/UNIT_Z (float -1))]))
rlm@47 377 (doto (AmbientLight.)
rlm@47 378 (.setColor ColorRGBA/White))))
rlm@47 379
rlm@47 380 (defn light-up-everything
rlm@306 381 "Add lights to a world appropriate for quickly seeing everything
rlm@47 382 in the scene. Adds six DirectionalLights facing in orthogonal
rlm@47 383 directions, and one AmbientLight to provide overall lighting
rlm@47 384 coverage."
rlm@47 385 [world]
rlm@47 386 (dorun
rlm@47 387 (map
rlm@47 388 #(.addLight (.getRootNode world) %)
rlm@47 389 (basic-light-setup))))
rlm@50 390
rlm@50 391 (defn fire-cannon-ball
rlm@50 392 "Creates a function that fires a cannon-ball from the current game's
rlm@50 393 camera. The cannon-ball will be attached to the node if provided, or
rlm@50 394 to the game's RootNode if no node is provided."
rlm@50 395 ([node]
rlm@50 396 (fn [game value]
rlm@50 397 (if (not value)
rlm@50 398 (let [camera (.getCamera game)
rlm@50 399 cannon-ball
rlm@50 400 (sphere 0.7
rlm@50 401 :material "Common/MatDefs/Misc/Unshaded.j3md"
rlm@216 402 :color ColorRGBA/White
rlm@216 403 :name "cannonball!"
rlm@50 404 :position
rlm@50 405 (.add (.getLocation camera)
rlm@50 406 (.mult (.getDirection camera) (float 1)))
rlm@50 407 :mass 3)] ;200 0.05
rlm@50 408 (.setLinearVelocity
rlm@50 409 (.getControl cannon-ball RigidBodyControl)
rlm@50 410 (.mult (.getDirection camera) (float 50))) ;50
rlm@216 411 (add-element game cannon-ball (if node node (.getRootNode
rlm@216 412 game)))
rlm@216 413 cannon-ball))))
rlm@50 414 ([]
rlm@50 415 (fire-cannon-ball false)))
rlm@60 416
rlm@60 417 (def standard-debug-controls
rlm@60 418 {"key-space" (fire-cannon-ball)})
rlm@60 419
rlm@60 420
rlm@160 421 (defn tap [obj direction force]
rlm@160 422 (let [control (.getControl obj RigidBodyControl)]
rlm@160 423 (.applyTorque
rlm@160 424 control
rlm@160 425 (.mult (.getPhysicsRotation control)
rlm@160 426 (.mult (.normalize direction) (float force))))))
rlm@160 427
rlm@160 428
rlm@160 429 (defn with-movement
rlm@160 430 [object
rlm@160 431 [up down left right roll-up roll-down :as keyboard]
rlm@160 432 forces
rlm@160 433 [root-node
rlm@160 434 keymap
rlm@306 435 initialization
rlm@160 436 world-loop]]
rlm@160 437 (let [add-keypress
rlm@160 438 (fn [state keymap key]
rlm@160 439 (merge keymap
rlm@160 440 {key
rlm@160 441 (fn [_ pressed?]
rlm@160 442 (reset! state pressed?))}))
rlm@160 443 move-up? (atom false)
rlm@160 444 move-down? (atom false)
rlm@160 445 move-left? (atom false)
rlm@160 446 move-right? (atom false)
rlm@160 447 roll-left? (atom false)
rlm@160 448 roll-right? (atom false)
rlm@160 449
rlm@160 450 directions [(Vector3f. 0 1 0)(Vector3f. 0 -1 0)
rlm@160 451 (Vector3f. 0 0 1)(Vector3f. 0 0 -1)
rlm@160 452 (Vector3f. -1 0 0)(Vector3f. 1 0 0)]
rlm@160 453 atoms [move-left? move-right? move-up? move-down?
rlm@160 454 roll-left? roll-right?]
rlm@160 455
rlm@160 456 keymap* (reduce merge
rlm@160 457 (map #(add-keypress %1 keymap %2)
rlm@160 458 atoms
rlm@160 459 keyboard))
rlm@160 460
rlm@160 461 splice-loop (fn []
rlm@160 462 (dorun
rlm@160 463 (map
rlm@160 464 (fn [sym direction force]
rlm@160 465 (if @sym
rlm@160 466 (tap object direction force)))
rlm@160 467 atoms directions forces)))
rlm@160 468
rlm@160 469 world-loop* (fn [world tpf]
rlm@160 470 (world-loop world tpf)
rlm@160 471 (splice-loop))]
rlm@160 472 [root-node
rlm@160 473 keymap*
rlm@306 474 initialization
rlm@160 475 world-loop*]))
rlm@160 476
rlm@205 477 (import com.jme3.font.BitmapText)
rlm@205 478 (import com.jme3.scene.control.AbstractControl)
rlm@205 479 (import com.aurellem.capture.IsoTimer)
rlm@60 480
rlm@306 481 (defn display-dilated-time
rlm@205 482 "Shows the time as it is flowing in the simulation on a HUD display.
rlm@205 483 Useful for making videos."
rlm@205 484 [world timer]
rlm@205 485 (let [font (.loadFont (asset-manager) "Interface/Fonts/Default.fnt")
rlm@205 486 text (BitmapText. font false)]
rlm@205 487 (.setLocalTranslation text 300 (.getLineHeight text) 0)
rlm@205 488 (.addControl
rlm@205 489 text
rlm@205 490 (proxy [AbstractControl] []
rlm@205 491 (controlUpdate [tpf]
rlm@205 492 (.setText text (format
rlm@205 493 "%.2f"
rlm@205 494 (float (/ (.getTime timer) 1000)))))
rlm@205 495 (controlRender [_ _])))
rlm@205 496 (.attachChild (.getGuiNode world) text)))
rlm@50 497 #+end_src
rlm@50 498
rlm@50 499
rlm@50 500 *** Viewing Objects
rlm@50 501
rlm@66 502 #+name: world-view
rlm@50 503 #+begin_src clojure :results silent
rlm@50 504 (in-ns 'cortex.util)
rlm@50 505
rlm@50 506 (defprotocol Viewable
rlm@50 507 (view [something]))
rlm@50 508
rlm@50 509 (extend-type com.jme3.scene.Geometry
rlm@50 510 Viewable
rlm@50 511 (view [geo]
rlm@50 512 (view (doto (Node.)(.attachChild geo)))))
rlm@47 513
rlm@29 514 (extend-type com.jme3.scene.Node
rlm@29 515 Viewable
rlm@29 516 (view
rlm@29 517 [node]
rlm@29 518 (.start
rlm@29 519 (world
rlm@29 520 node
rlm@29 521 {}
rlm@29 522 (fn [world]
rlm@29 523 (enable-debug world)
rlm@29 524 (set-gravity world Vector3f/ZERO)
rlm@47 525 (light-up-everything world))
rlm@29 526 no-op))))
rlm@62 527
rlm@62 528 (extend-type com.jme3.math.ColorRGBA
rlm@62 529 Viewable
rlm@62 530 (view
rlm@62 531 [color]
rlm@62 532 (view (doto (Node.)
rlm@62 533 (.attachChild (box 1 1 1 :color color))))))
rlm@62 534
rlm@62 535 (defprotocol Textual
rlm@62 536 (text [something]
rlm@62 537 "Display a detailed textual analysis of the given object."))
rlm@62 538
rlm@62 539 (extend-type com.jme3.scene.Node
rlm@62 540 Textual
rlm@62 541 (text [node]
rlm@62 542 (println "Total Vertexes: " (.getVertexCount node))
rlm@62 543 (println "Total Triangles: " (.getTriangleCount node))
rlm@62 544 (println "Controls :")
rlm@62 545 (dorun (map #(text (.getControl node %)) (range (.getNumControls node))))
rlm@62 546 (println "Has " (.getQuantity node) " Children:")
rlm@62 547 (doall (map text (.getChildren node)))))
rlm@62 548
rlm@62 549 (extend-type com.jme3.animation.AnimControl
rlm@62 550 Textual
rlm@62 551 (text [control]
rlm@62 552 (let [animations (.getAnimationNames control)]
rlm@62 553 (println "Animation Control with " (count animations) " animation(s):")
rlm@62 554 (dorun (map println animations)))))
rlm@62 555
rlm@62 556 (extend-type com.jme3.animation.SkeletonControl
rlm@62 557 Textual
rlm@62 558 (text [control]
rlm@62 559 (println "Skeleton Control with the following skeleton:")
rlm@62 560 (println (.getSkeleton control))))
rlm@62 561
rlm@62 562 (extend-type com.jme3.bullet.control.KinematicRagdollControl
rlm@62 563 Textual
rlm@62 564 (text [control]
rlm@62 565 (println "Ragdoll Control")))
rlm@62 566
rlm@62 567 (extend-type com.jme3.scene.Geometry
rlm@62 568 Textual
rlm@62 569 (text [control]
rlm@62 570 (println "...geo...")))
rlm@108 571
rlm@108 572 (extend-type Triangle
rlm@108 573 Textual
rlm@108 574 (text [t]
rlm@108 575 (println "Triangle: " \newline (.get1 t) \newline
rlm@108 576 (.get2 t) \newline (.get3 t))))
rlm@108 577
rlm@25 578 #+end_src
rlm@25 579
rlm@29 580 Here I make the =Viewable= protocol and extend it to JME's types. Now
rlm@34 581 JME3's =hello-world= can be written as easily as:
rlm@29 582
rlm@29 583 #+begin_src clojure :results silent
rlm@29 584 (cortex.util/view (cortex.util/box))
rlm@29 585 #+end_src
rlm@29 586
rlm@29 587
rlm@24 588 * COMMENT code generation
rlm@24 589 #+begin_src clojure :tangle ../src/cortex/import.clj
rlm@24 590 <<import>>
rlm@24 591 #+end_src
rlm@25 592
rlm@25 593
rlm@29 594 #+begin_src clojure :tangle ../src/cortex/util.clj :noweb yes
rlm@25 595 <<util>>
rlm@25 596 <<shapes>>
rlm@50 597 <<debug-actions>>
rlm@29 598 <<world-view>>
rlm@25 599 #+end_src
rlm@25 600
rlm@29 601
rlm@29 602
rlm@29 603
rlm@29 604
rlm@29 605
rlm@29 606
rlm@29 607
rlm@29 608
rlm@29 609
rlm@29 610
rlm@29 611
rlm@29 612
rlm@29 613
rlm@29 614
rlm@29 615
rlm@29 616