Mercurial > cortex
changeset 23:cab2da252494
split off the rest of cortex.org
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 23 Oct 2011 23:54:26 -0700 |
parents | 157b416152ea |
children | e965675ec4d0 |
files | org/cortex.org org/eyes.org org/util.org org/world.org |
diffstat | 4 files changed, 663 insertions(+), 404 deletions(-) [+] |
line wrap: on
line diff
1.1 --- a/org/cortex.org Sun Oct 23 23:35:04 2011 -0700 1.2 +++ b/org/cortex.org Sun Oct 23 23:54:26 2011 -0700 1.3 @@ -9,414 +9,12 @@ 1.4 1.5 * Simulation Base 1.6 1.7 -** Imports 1.8 -jMonkeyEngine has a plethora of classes which can be overwhelming at 1.9 -first. So that I one can get right to coding, it's good to take the 1.10 -time right now and make a "import all" function which brings in all of 1.11 -the important jme3 classes. Once I'm happy with the general structure 1.12 -of a namespace I can deal with importing only the classes it actually 1.13 -needs. 1.14 - 1.15 -#+srcname: import 1.16 -#+begin_src clojure :results silent 1.17 -(ns cortex.import 1.18 - (:require swank.util.class-browse)) 1.19 - 1.20 -(defn permissive-import 1.21 - [classname] 1.22 - (eval `(try (import '~classname) 1.23 - (catch java.lang.Exception e# 1.24 - (println "couldn't import " '~classname)))) 1.25 - classname) 1.26 - 1.27 -(defn jme-class? [classname] 1.28 - (and 1.29 - (.startsWith classname "com.jme3.") 1.30 - ;; Don't import the Lwjgl stuff since it can throw exceptions 1.31 - ;; upon being loaded. 1.32 - (not (re-matches #".*Lwjgl.*" classname)))) 1.33 - 1.34 -(defn jme-classes 1.35 - "returns a list of all jme3 classes" 1.36 - [] 1.37 - (filter 1.38 - jme-class? 1.39 - (map :name 1.40 - swank.util.class-browse/available-classes))) 1.41 - 1.42 -(defn mega-import-jme3 1.43 - "Import ALL the jme classes. For REPL use." 1.44 - [] 1.45 - (doall 1.46 - (map (comp permissive-import symbol) (jme-classes)))) 1.47 -#+end_src 1.48 - 1.49 -The =mega-import-jme3= is quite usefull for debugging purposes since 1.50 -it allows completion for almost all of JME's classes. 1.51 - 1.52 -Out of curiousity, let's see just how many classes =mega-import-jme3= 1.53 -imports: 1.54 - 1.55 -#+begin_src clojure :exports both 1.56 -(clojure.core/count (cortex.import/jme-classes)) 1.57 -#+end_src 1.58 - 1.59 -#+results: 1.60 -: 955 1.61 - 1.62 -** Simplification 1.63 -*** World 1.64 - 1.65 -It is comvienent to wrap the JME elements that deal with creating a 1.66 -world, creation of basic objects, and Keyboard input with a nicer 1.67 -interface (at least for my purposes). 1.68 - 1.69 -#+srcname: world-inputs 1.70 -#+begin_src clojure :results silent 1.71 -(ns cortex.world) 1.72 -(require 'cortex.import) 1.73 -(use 'clojure.contrib.def) 1.74 -(rlm.rlm-commands/help) 1.75 -(cortex.import/mega-import-jme3) 1.76 - 1.77 -(defvar *app-settings* 1.78 - (doto (AppSettings. true) 1.79 - (.setFullscreen false) 1.80 - (.setTitle "Aurellem.") 1.81 - ;; disable 32 bit stuff for now 1.82 - ;;(.setAudioRenderer "Send") 1.83 - ) 1.84 - "These settings control how the game is displayed on the screen for 1.85 - debugging purposes. Use binding forms to change this if desired. 1.86 - Full-screen mode does not work on some computers.") 1.87 - 1.88 -(defn asset-manager 1.89 - "returns a new, configured assetManager" [] 1.90 - (JmeSystem/newAssetManager 1.91 - (.getResource 1.92 - (.getContextClassLoader (Thread/currentThread)) 1.93 - "com/jme3/asset/Desktop.cfg"))) 1.94 - 1.95 -(defmacro no-exceptions 1.96 - "Sweet relief like I never knew." 1.97 - [& forms] 1.98 - `(try ~@forms (catch Exception e# (.printStackTrace e#)))) 1.99 - 1.100 -(defn thread-exception-removal [] 1.101 - (println "removing exceptions from " (Thread/currentThread)) 1.102 - (.setUncaughtExceptionHandler 1.103 - (Thread/currentThread) 1.104 - (proxy [Thread$UncaughtExceptionHandler] [] 1.105 - (uncaughtException 1.106 - [thread thrown] 1.107 - (println "uncaught-exception thrown in " thread) 1.108 - (println (.getMessage thrown)))))) 1.109 - 1.110 -(def println-repl (bound-fn [& args] (apply println args))) 1.111 - 1.112 -(use '[pokemon [lpsolve :only [constant-map]]]) 1.113 - 1.114 -(defn no-op [& _]) 1.115 - 1.116 -(defn all-keys 1.117 - "Construct a map of strings representing all the manual inputs from 1.118 - either the keyboard or mouse." 1.119 - [] 1.120 - (let [inputs (constant-map KeyInput)] 1.121 - (assoc 1.122 - (zipmap (map (fn [field] 1.123 - (.toLowerCase (re-gsub #"_" "-" field))) (vals inputs)) 1.124 - (map (fn [val] (KeyTrigger. val)) (keys inputs))) 1.125 - ;;explicitly add mouse controls 1.126 - "mouse-left" (MouseButtonTrigger. 0) 1.127 - "mouse-middle" (MouseButtonTrigger. 2) 1.128 - "mouse-right" (MouseButtonTrigger. 1)))) 1.129 - 1.130 -(defn initialize-inputs 1.131 - "more java-interop cruft to establish keybindings for a particular virtual world" 1.132 - [game input-manager key-map] 1.133 - (doall (map (fn [[name trigger]] 1.134 - (.addMapping ^InputManager input-manager 1.135 - name (into-array (class trigger) [trigger]))) key-map)) 1.136 - (doall (map (fn [name] 1.137 - (.addListener ^InputManager input-manager game 1.138 - (into-array String [name]))) (keys key-map)))) 1.139 - 1.140 -#+end_src 1.141 - 1.142 -These functions are all for debug controlling of the world through 1.143 -keyboard and mouse. 1.144 - 1.145 -We reuse =constant-map= from =pokemon.lpsolve= to get the numerical 1.146 -values for all the keys defined in the =KeyInput= class. The 1.147 -documentation for =constant-map= is: 1.148 - 1.149 -#+begin_src clojure :results output 1.150 -(doc pokemon.lpsolve/constant-map) 1.151 -#+end_src 1.152 - 1.153 -#+results: 1.154 -: ------------------------- 1.155 -: pokemon.lpsolve/constant-map 1.156 -: ([class]) 1.157 -: Takes a class and creates a map of the static constant integer 1.158 -: fields with their names. This helps with C wrappers where they have 1.159 -: just defined a bunch of integer constants instead of enums 1.160 - 1.161 - 1.162 -Then, =all-keys= converts the constant names like =KEY_J= to the more 1.163 -clojure-like =key-j=, and returns a map from these keys to 1.164 -jMonkeyEngine KeyTrigger objects, the use of which will soon become 1.165 -apparent. =all-keys= also adds the three mouse button controls to the 1.166 -map. 1.167 - 1.168 -#+srcname: world 1.169 -#+begin_src clojure :results silent 1.170 -(in-ns 'cortex.world) 1.171 - 1.172 -(defn traverse 1.173 - "apply f to every non-node, deeply" 1.174 - [f node] 1.175 - (if (isa? (class node) Node) 1.176 - (dorun (map (partial traverse f) (.getChildren node))) 1.177 - (f node))) 1.178 - 1.179 -(def gravity (Vector3f. 0 -9.81 0)) 1.180 - 1.181 -(defn world 1.182 - [root-node key-map setup-fn update-fn] 1.183 - (let [physics-manager (BulletAppState.) 1.184 - shadow-renderer (BasicShadowRenderer. (asset-manager) (int 256)) 1.185 - ;;maybe use a better shadow renderer someday! 1.186 - ;;shadow-renderer (PssmShadowRenderer. (asset-manager) 256 1) 1.187 - ] 1.188 - (doto 1.189 - (proxy [SimpleApplication ActionListener] [] 1.190 - (simpleInitApp 1.191 - [] 1.192 - (no-exceptions 1.193 - (.setTimer this (IsoTimer. 60)) 1.194 - ;; Create key-map. 1.195 - (.setFrustumFar (.getCamera this) 300) 1.196 - (initialize-inputs this (.getInputManager this) (all-keys)) 1.197 - ;; Don't take control of the mouse 1.198 - (org.lwjgl.input.Mouse/setGrabbed false) 1.199 - ;; add all objects to the world 1.200 - (.attachChild (.getRootNode this) root-node) 1.201 - ;; enable physics 1.202 - ;; add a physics manager 1.203 - (.attach (.getStateManager this) physics-manager) 1.204 - (.setGravity (.getPhysicsSpace physics-manager) gravity) 1.205 - 1.206 - 1.207 - ;; go through every object and add it to the physics manager 1.208 - ;; if relavant. 1.209 - (traverse (fn [geom] 1.210 - (dorun 1.211 - (for [n (range (.getNumControls geom))] 1.212 - (do 1.213 - (println-repl "adding control " (.getControl geom n)) 1.214 - (.add (.getPhysicsSpace physics-manager) 1.215 - (.getControl geom n)))))) 1.216 - (.getRootNode this)) 1.217 - ;;(.addAll (.getPhysicsSpace physics-manager) (.getRootNode this)) 1.218 - 1.219 - (setup-fn this) 1.220 - (.setDirection shadow-renderer 1.221 - (.normalizeLocal (Vector3f. -1 -1 -1))) 1.222 - (.addProcessor (.getViewPort this) shadow-renderer) 1.223 - (.setShadowMode (.getRootNode this) RenderQueue$ShadowMode/Off) 1.224 - )) 1.225 - (simpleUpdate 1.226 - [tpf] 1.227 - (no-exceptions 1.228 - (update-fn this tpf))) 1.229 - (onAction 1.230 - [binding value tpf] 1.231 - ;; whenever a key is pressed, call the function returned from 1.232 - ;; key-map. 1.233 - (no-exceptions 1.234 - (if-let [react (key-map binding)] 1.235 - (react this value))))) 1.236 - ;; don't show a menu to change options. 1.237 - 1.238 - (.setShowSettings false) 1.239 - (.setPauseOnLostFocus false) 1.240 - (.setSettings *app-settings*)))) 1.241 - 1.242 -(defn apply-map 1.243 - "Like apply, but works for maps and functions that expect an implicit map 1.244 - and nothing else as in (fn [& {}]). 1.245 -------- Example ------- 1.246 - (defn jjj [& {:keys [www] :or {www \"oh yeah\"} :as env}] (println www)) 1.247 - (apply-map jjj {:www \"whatever\"}) 1.248 - -->\"whatever\"" 1.249 - [fn m] 1.250 - (apply fn (reduce #(into %1 %2) [] m))) 1.251 - 1.252 -#+end_src 1.253 - 1.254 - 1.255 -=world= is the most important function here. 1.256 -*** TODO more documentation 1.257 - 1.258 -#+srcname: world-shapes 1.259 -#+begin_src clojure :results silent 1.260 -(in-ns 'cortex.world) 1.261 -(defrecord shape-description 1.262 - [name 1.263 - color 1.264 - mass 1.265 - friction 1.266 - texture 1.267 - material 1.268 - position 1.269 - rotation 1.270 - shape 1.271 - physical?]) 1.272 - 1.273 -(def base-shape 1.274 - (shape-description. 1.275 - "default-shape" 1.276 - false 1.277 - ;;ColorRGBA/Blue 1.278 - 1.0 ;; mass 1.279 - 1.0 ;; friction 1.280 - ;; texture 1.281 - "Textures/Terrain/BrickWall/BrickWall.jpg" 1.282 - ;; material 1.283 - "Common/MatDefs/Misc/Unshaded.j3md" 1.284 - Vector3f/ZERO 1.285 - Quaternion/IDENTITY 1.286 - (Box. Vector3f/ZERO 0.5 0.5 0.5) 1.287 - true)) 1.288 - 1.289 -(defn make-shape 1.290 - [#^shape-description d] 1.291 - (let [asset-manager (if (:asset-manager d) (:asset-manager d) (asset-manager)) 1.292 - mat (Material. asset-manager (:material d)) 1.293 - geom (Geometry. (:name d) (:shape d))] 1.294 - (if (:texture d) 1.295 - (let [key (TextureKey. (:texture d))] 1.296 - (.setGenerateMips key true) 1.297 - (.setTexture mat "ColorMap" (.loadTexture asset-manager key)))) 1.298 - (if (:color d) (.setColor mat "Color" (:color d))) 1.299 - (.setMaterial geom mat) 1.300 - (if-let [rotation (:rotation d)] (.rotate geom rotation)) 1.301 - (.setLocalTranslation geom (:position d)) 1.302 - (if (:physical? d) 1.303 - (let [impact-shape (doto (GImpactCollisionShape. 1.304 - (.getMesh geom)) (.setMargin 0)) 1.305 - physics-control (RigidBodyControl. 1.306 - ;;impact-shape ;; comment to disable 1.307 - (float (:mass d)))] 1.308 - (.createJmeMesh impact-shape) 1.309 - (.addControl geom physics-control) 1.310 - ;;(.setSleepingThresholds physics-control (float 0) (float 0)) 1.311 - (.setFriction physics-control (:friction d)))) 1.312 - ;;the default is to keep this node in the physics engine forever. 1.313 - ;;these commands must come after the control is added to the geometry. 1.314 - ;; 1.315 - geom)) 1.316 - 1.317 -(defn box 1.318 - ([l w h & {:as options}] 1.319 - (let [options (merge base-shape options)] 1.320 - (make-shape (assoc options 1.321 - :shape (Box. l w h))))) 1.322 - ([] (box 0.5 0.5 0.5))) 1.323 - 1.324 -(defn sphere 1.325 - ([r & {:as options}] 1.326 - (let [options (merge base-shape options)] 1.327 - (make-shape (assoc options 1.328 - :shape (Sphere. 32 32 (float r)))))) 1.329 - ([] (sphere 0.5))) 1.330 - 1.331 -(defn add-element 1.332 - ([game element node] 1.333 - (.addAll 1.334 - (.getPhysicsSpace 1.335 - (.getState 1.336 - (.getStateManager game) 1.337 - BulletAppState)) 1.338 - element) 1.339 - (.attachChild node element)) 1.340 - ([game element] 1.341 - (add-element game element (.getRootNode game)))) 1.342 - 1.343 - 1.344 -(defn set-gravity* 1.345 - [game gravity] 1.346 - (traverse 1.347 - (fn [geom] 1.348 - (if-let 1.349 - [control (.getControl geom RigidBodyControl)] 1.350 - (do 1.351 - (.setGravity control gravity) 1.352 - (.applyImpulse control Vector3f/ZERO Vector3f/ZERO) 1.353 - ))) 1.354 - (.getRootNode game))) 1.355 - 1.356 -#+end_src 1.357 - 1.358 -These are convienence functions for creating JME objects and 1.359 -manipulating a world. 1.360 - 1.361 -#+srcname: world-view 1.362 -#+begin_src clojure :results silent 1.363 -(in-ns 'cortex.world) 1.364 - 1.365 -(defprotocol Viewable 1.366 - (view [something])) 1.367 - 1.368 -(extend-type com.jme3.scene.Geometry 1.369 - Viewable 1.370 - (view [geo] 1.371 - (view (doto (Node.)(.attachChild geo))))) 1.372 - 1.373 -(extend-type com.jme3.scene.Node 1.374 - Viewable 1.375 - (view [node] 1.376 - (.start 1.377 - (world node 1.378 - {} 1.379 - (fn [world] 1.380 - (.enableDebug 1.381 - (.getPhysicsSpace 1.382 - (.getState 1.383 - (.getStateManager world) 1.384 - BulletAppState)) 1.385 - (asset-manager)) 1.386 - (set-gravity* world Vector3f/ZERO) 1.387 -;; (set-gravity* world (Vector3f. 0 (float -0.4) 0)) 1.388 - (let [sun (doto (DirectionalLight.) 1.389 - (.setDirection (.normalizeLocal (Vector3f. 1 0 -2))) 1.390 - (.setColor ColorRGBA/White))] 1.391 - (.addLight (.getRootNode world) sun))) 1.392 - no-op)))) 1.393 - 1.394 -(defn position-camera [game] 1.395 - (doto (.getCamera game) 1.396 - (.setLocation (Vector3f. 0 6 6)) 1.397 - (.lookAt Vector3f/ZERO (Vector3f. 0 1 0)))) 1.398 - 1.399 -#+end_src 1.400 - 1.401 -Here I make the =Viewable= protocol and extend it to JME's types. Now 1.402 -hello-world can be written as easily as: 1.403 - 1.404 -#+begin_src clojure :results silent 1.405 -(cortex.world/view (cortex.world/box)) 1.406 -#+end_src 1.407 1.408 ** Hello 1.409 Here are the jmonkeyengine "Hello" programs translated to clojure. 1.410 *** Hello Simple App 1.411 -Here is the hello world example for jme3 in clojure. 1.412 -It's a more or less direct translation from the java source 1.413 -from 1.414 -http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_simpleapplication. 1.415 +Here is the hello world example for jme3 in clojure. It's a more or 1.416 +less direct translation from the java source [[http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_simpleapplication][here]]. 1.417 1.418 Of note is the fact that since we don't have access to the 1.419 =AssetManager= via extendig =SimpleApplication=, we have to build one
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/org/eyes.org Sun Oct 23 23:54:26 2011 -0700 2.3 @@ -0,0 +1,243 @@ 2.4 +#+title: Eyes 2.5 +#+author: Robert McIntyre 2.6 +#+email: rlm@mit.edu 2.7 +#+description: Simulating senses for AI research using JMonkeyEngine3 2.8 +#+SETUPFILE: ../../aurellem/org/setup.org 2.9 +#+INCLUDE: ../../aurellem/org/level-0.org 2.10 +#+babel: :mkdirp yes :noweb yes :exports both 2.11 + 2.12 + 2.13 + 2.14 +** Eyes 2.15 + 2.16 +Ultimately I want to make creatures with eyes. Each eye can be 2.17 +independely moved and should see its own version of the world 2.18 +depending on where it is. 2.19 +#+srcname: eyes 2.20 +#+begin_src clojure 2.21 +(ns body.eye) 2.22 +(use 'cortex.world) 2.23 +(use 'cortex.import) 2.24 +(use 'clojure.contrib.def) 2.25 +(cortex.import/mega-import-jme3) 2.26 +(rlm.rlm-commands/help) 2.27 +(import java.nio.ByteBuffer) 2.28 +(import java.awt.image.BufferedImage) 2.29 +(import java.awt.Color) 2.30 +(import java.awt.Dimension) 2.31 +(import java.awt.Graphics) 2.32 +(import java.awt.Graphics2D) 2.33 +(import java.awt.event.WindowAdapter) 2.34 +(import java.awt.event.WindowEvent) 2.35 +(import java.awt.image.BufferedImage) 2.36 +(import java.nio.ByteBuffer) 2.37 +(import javax.swing.JFrame) 2.38 +(import javax.swing.JPanel) 2.39 +(import javax.swing.SwingUtilities) 2.40 +(import javax.swing.ImageIcon) 2.41 +(import javax.swing.JOptionPane) 2.42 +(import java.awt.image.ImageObserver) 2.43 + 2.44 + 2.45 + 2.46 +(defn scene-processor 2.47 + "deals with converting FrameBuffers to BufferedImages so 2.48 + that the continuation function can be defined only in terms 2.49 + of what it does with BufferedImages" 2.50 + [continuation] 2.51 + (let [byte-buffer (atom nil) 2.52 + renderer (atom nil) 2.53 + image (atom nil)] 2.54 + (proxy [SceneProcessor] [] 2.55 + (initialize 2.56 + [renderManager viewPort] 2.57 + (let [cam (.getCamera viewPort) 2.58 + width (.getWidth cam) 2.59 + height (.getHeight cam)] 2.60 + (reset! renderer (.getRenderer renderManager)) 2.61 + (reset! byte-buffer 2.62 + (BufferUtils/createByteBuffer 2.63 + (* width height 4))) 2.64 + (reset! image (BufferedImage. width height 2.65 + BufferedImage/TYPE_4BYTE_ABGR)))) 2.66 + (isInitialized [] (not (nil? @byte-buffer))) 2.67 + (reshape [_ _ _]) 2.68 + (preFrame [_]) 2.69 + (postQueue [_]) 2.70 + (postFrame 2.71 + [#^FrameBuffer fb] 2.72 + (.clear @byte-buffer) 2.73 + (.readFrameBuffer @renderer fb @byte-buffer) 2.74 + (Screenshots/convertScreenShot @byte-buffer @image) 2.75 + (continuation @image)) 2.76 + (cleanup [])))) 2.77 + 2.78 +(defn add-eye 2.79 + "Add an eye to the world, and call continuation on 2.80 + every frame produced" 2.81 + [world camera continuation] 2.82 + (let [width (.getWidth camera) 2.83 + height (.getHeight camera) 2.84 + render-manager (.getRenderManager world) 2.85 + viewport (.createMainView render-manager "eye-view" camera)] 2.86 + (doto viewport 2.87 + (.setBackgroundColor ColorRGBA/Black) 2.88 + (.setClearFlags true true true) 2.89 + (.addProcessor (scene-processor continuation)) 2.90 + (.attachScene (.getRootNode world))))) 2.91 + 2.92 +(defn make-display-frame [display width height] 2.93 + (SwingUtilities/invokeLater 2.94 + (fn [] 2.95 + (.setPreferredSize display (Dimension. width height)) 2.96 + (doto (JFrame. "Eye Camera!") 2.97 + (-> (.getContentPane) (.add display)) 2.98 + (.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE) 2.99 + (.pack) 2.100 + (.setLocationRelativeTo nil) 2.101 + (.setResizable false) 2.102 + (.setVisible true))))) 2.103 + 2.104 +(defn image-monitor [#^BufferedImage image] 2.105 + (proxy [JPanel] [] 2.106 + (paintComponent 2.107 + [g] 2.108 + (proxy-super paintComponent g) 2.109 + (locking image 2.110 + (.drawImage g image 0 0 2.111 + (proxy [ImageObserver] 2.112 + [] 2.113 + (imageUpdate 2.114 + [] 2.115 + (proxy-super imageUpdate)))))))) 2.116 + 2.117 +(defn movie-image [] 2.118 + (let [setup 2.119 + (runonce 2.120 + (fn [#^BufferedImage image] 2.121 + (let [width (.getWidth image) 2.122 + height (.getHeight image) 2.123 + display (image-monitor image) 2.124 + frame (make-display-frame display width height)] 2.125 + display)))] 2.126 + (fn [#^BufferedImage image] 2.127 + (.repaint (setup image))))) 2.128 + 2.129 + 2.130 +(defn observer 2.131 + "place thy eye!" 2.132 + [world camera] 2.133 + (let [eye camera 2.134 + width (.getWidth eye) 2.135 + height (.getHeight eye)] 2.136 + (no-exceptions 2.137 + (add-eye 2.138 + world 2.139 + eye 2.140 + (movie-image))))) 2.141 +#+end_src 2.142 + 2.143 +#+srcname: test-vision 2.144 +#+begin_src clojure 2.145 + 2.146 +(ns test.vision) 2.147 +(use 'cortex.world) 2.148 +(use 'cortex.import) 2.149 +(use 'clojure.contrib.def) 2.150 +(use 'body.eye) 2.151 +(cortex.import/mega-import-jme3) 2.152 +(rlm.rlm-commands/help) 2.153 +(import java.nio.ByteBuffer) 2.154 +(import java.awt.image.BufferedImage) 2.155 +(import java.awt.Color) 2.156 +(import java.awt.Dimension) 2.157 +(import java.awt.Graphics) 2.158 +(import java.awt.Graphics2D) 2.159 +(import java.awt.event.WindowAdapter) 2.160 +(import java.awt.event.WindowEvent) 2.161 +(import java.awt.image.BufferedImage) 2.162 +(import java.nio.ByteBuffer) 2.163 +(import javax.swing.JFrame) 2.164 +(import javax.swing.JPanel) 2.165 +(import javax.swing.SwingUtilities) 2.166 +(import javax.swing.ImageIcon) 2.167 +(import javax.swing.JOptionPane) 2.168 +(import java.awt.image.ImageObserver) 2.169 + 2.170 + 2.171 +(def width 200) 2.172 +(def height 200) 2.173 + 2.174 +(defn camera [] 2.175 + (doto (Camera. width height) 2.176 + (.setFrustumPerspective 45 1 1 1000) 2.177 + (.setLocation (Vector3f. -3 0 -5)) 2.178 + (.lookAt Vector3f/ZERO Vector3f/UNIT_Y))) 2.179 + 2.180 +(defn camera2 [] 2.181 + (doto (Camera. width height) 2.182 + (.setFrustumPerspective 45 1 1 1000) 2.183 + (.setLocation (Vector3f. 3 0 -5)) 2.184 + (.lookAt Vector3f/ZERO Vector3f/UNIT_Y))) 2.185 + 2.186 +(defn setup-fn [world] 2.187 + (let [eye (camera) 2.188 + width (.getWidth eye) 2.189 + height (.getHeight eye)] 2.190 + (no-exceptions 2.191 + (add-eye 2.192 + world 2.193 + eye 2.194 + (runonce visual)) 2.195 + (add-eye 2.196 + world 2.197 + (camera2) 2.198 + (runonce visual))))) 2.199 + 2.200 +(defn spider-eye [position] 2.201 + (doto (Camera. 200 200 ) 2.202 + (.setFrustumPerspective 45 1 1 1000) 2.203 + (.setLocation position) 2.204 + (.lookAt Vector3f/ZERO Vector3f/UNIT_Y))) 2.205 + 2.206 +(defn setup-fn* [world] 2.207 + (let [eye (camera) 2.208 + width (.getWidth eye) 2.209 + height (.getHeight eye)] 2.210 + ;;(.setClearFlags (.getViewPort world) true true true) 2.211 + (observer world (.getCamera world)) 2.212 + (observer world (spider-eye (Vector3f. 3 0 -5))) 2.213 + ;;(observer world (spider-eye (Vector3f. 0 0 -5))) 2.214 + ;; (observer world (spider-eye (Vector3f. -3 0 -5))) 2.215 + ;; (observer world (spider-eye (Vector3f. 0 3 -5))) 2.216 + ;; (observer world (spider-eye (Vector3f. 0 -3 -5))) 2.217 + ;; (observer world (spider-eye (Vector3f. 3 3 -5))) 2.218 + ;; (observer world (spider-eye (Vector3f. -3 3 -5))) 2.219 + ;; (observer world (spider-eye (Vector3f. 3 -3 -5))) 2.220 + ;; (observer world (spider-eye (Vector3f. -3 -3 -5))) 2.221 + 2.222 + ) 2.223 + world) 2.224 + 2.225 +(defn test-world [] 2.226 + (let [thing (box 1 1 1 :physical? false)] 2.227 + (world 2.228 + (doto (Node.) 2.229 + (.attachChild thing)) 2.230 + {} 2.231 + setup-fn 2.232 + (fn [world tpf] 2.233 + (.rotate thing (* tpf 0.2) 0 0) 2.234 + )))) 2.235 + 2.236 + 2.237 +#+end_src 2.238 + 2.239 + 2.240 +#+results: eyes 2.241 +: #'body.eye/test-world 2.242 + 2.243 +Note the use of continuation passing style for connecting the eye to a 2.244 +function to process the output. The example code will create two 2.245 +videos of the same rotating cube from different angles, sutiable for 2.246 +stereoscopic vision.
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/org/util.org Sun Oct 23 23:54:26 2011 -0700 3.3 @@ -0,0 +1,110 @@ 3.4 +#+title: Helper Utilities 3.5 +#+author: Robert McIntyre 3.6 +#+email: rlm@mit.edu 3.7 +#+description: Simulating senses for AI research using JMonkeyEngine3 3.8 +#+SETUPFILE: ../../aurellem/org/setup.org 3.9 +#+INCLUDE: ../../aurellem/org/level-0.org 3.10 +#+babel: :mkdirp yes :noweb yes :exports both 3.11 + 3.12 +** Imports 3.13 +jMonkeyEngine has a plethora of classes which can be overwhelming at 3.14 +first. So that I one can get right to coding, it's good to take the 3.15 +time right now and make a "import all" function which brings in all of 3.16 +the important jme3 classes. Once I'm happy with the general structure 3.17 +of a namespace I can deal with importing only the classes it actually 3.18 +needs. 3.19 + 3.20 +#+srcname: import 3.21 +#+begin_src clojure :results silent 3.22 +(ns cortex.import 3.23 + (:require swank.util.class-browse)) 3.24 + 3.25 +(defn permissive-import 3.26 + [classname] 3.27 + (eval `(try (import '~classname) 3.28 + (catch java.lang.Exception e# 3.29 + (println "couldn't import " '~classname)))) 3.30 + classname) 3.31 + 3.32 +(defn jme-class? [classname] 3.33 + (and 3.34 + (.startsWith classname "com.jme3.") 3.35 + ;; Don't import the Lwjgl stuff since it can throw exceptions 3.36 + ;; upon being loaded. 3.37 + (not (re-matches #".*Lwjgl.*" classname)))) 3.38 + 3.39 +(defn jme-classes 3.40 + "returns a list of all jme3 classes" 3.41 + [] 3.42 + (filter 3.43 + jme-class? 3.44 + (map :name 3.45 + swank.util.class-browse/available-classes))) 3.46 + 3.47 +(defn mega-import-jme3 3.48 + "Import ALL the jme classes. For REPL use." 3.49 + [] 3.50 + (doall 3.51 + (map (comp permissive-import symbol) (jme-classes)))) 3.52 +#+end_src 3.53 + 3.54 +The =mega-import-jme3= is quite usefull for debugging purposes since 3.55 +it allows completion for almost all of JME's classes. 3.56 + 3.57 +Out of curiousity, let's see just how many classes =mega-import-jme3= 3.58 +imports: 3.59 + 3.60 +#+begin_src clojure :exports both 3.61 +(clojure.core/count (cortex.import/jme-classes)) 3.62 +#+end_src 3.63 + 3.64 +#+results: 3.65 +: 955 3.66 + 3.67 +** Simplification 3.68 +#+srcname: world-view 3.69 +#+begin_src clojure :results silent 3.70 +(in-ns 'cortex.world) 3.71 + 3.72 +(defprotocol Viewable 3.73 + (view [something])) 3.74 + 3.75 +(extend-type com.jme3.scene.Geometry 3.76 + Viewable 3.77 + (view [geo] 3.78 + (view (doto (Node.)(.attachChild geo))))) 3.79 + 3.80 +(extend-type com.jme3.scene.Node 3.81 + Viewable 3.82 + (view [node] 3.83 + (.start 3.84 + (world node 3.85 + {} 3.86 + (fn [world] 3.87 + (.enableDebug 3.88 + (.getPhysicsSpace 3.89 + (.getState 3.90 + (.getStateManager world) 3.91 + BulletAppState)) 3.92 + (asset-manager)) 3.93 + (set-gravity* world Vector3f/ZERO) 3.94 +;; (set-gravity* world (Vector3f. 0 (float -0.4) 0)) 3.95 + (let [sun (doto (DirectionalLight.) 3.96 + (.setDirection (.normalizeLocal (Vector3f. 1 0 -2))) 3.97 + (.setColor ColorRGBA/White))] 3.98 + (.addLight (.getRootNode world) sun))) 3.99 + no-op)))) 3.100 + 3.101 +(defn position-camera [game] 3.102 + (doto (.getCamera game) 3.103 + (.setLocation (Vector3f. 0 6 6)) 3.104 + (.lookAt Vector3f/ZERO (Vector3f. 0 1 0)))) 3.105 + 3.106 +#+end_src 3.107 + 3.108 +Here I make the =Viewable= protocol and extend it to JME's types. Now 3.109 +hello-world can be written as easily as: 3.110 + 3.111 +#+begin_src clojure :results silent 3.112 +(cortex.world/view (cortex.world/box)) 3.113 +#+end_src
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/org/world.org Sun Oct 23 23:54:26 2011 -0700 4.3 @@ -0,0 +1,308 @@ 4.4 +#+title: A world for the creatures to live 4.5 +#+author: Robert McIntyre 4.6 +#+email: rlm@mit.edu 4.7 +#+description: Simulating senses for AI research using JMonkeyEngine3 4.8 +#+SETUPFILE: ../../aurellem/org/setup.org 4.9 +#+INCLUDE: ../../aurellem/org/level-0.org 4.10 +#+babel: :mkdirp yes :noweb yes :exports both 4.11 + 4.12 + 4.13 + 4.14 +*** World 4.15 + 4.16 +It is comvienent to wrap the JME elements that deal with creating a 4.17 +world, creation of basic objects, and Keyboard input with a nicer 4.18 +interface (at least for my purposes). 4.19 + 4.20 +#+srcname: world-inputs 4.21 +#+begin_src clojure :results silent 4.22 +(ns cortex.world) 4.23 +(require 'cortex.import) 4.24 +(use 'clojure.contrib.def) 4.25 +(rlm.rlm-commands/help) 4.26 +(cortex.import/mega-import-jme3) 4.27 + 4.28 +(defvar *app-settings* 4.29 + (doto (AppSettings. true) 4.30 + (.setFullscreen false) 4.31 + (.setTitle "Aurellem.") 4.32 + ;; disable 32 bit stuff for now 4.33 + ;;(.setAudioRenderer "Send") 4.34 + ) 4.35 + "These settings control how the game is displayed on the screen for 4.36 + debugging purposes. Use binding forms to change this if desired. 4.37 + Full-screen mode does not work on some computers.") 4.38 + 4.39 +(defn asset-manager 4.40 + "returns a new, configured assetManager" [] 4.41 + (JmeSystem/newAssetManager 4.42 + (.getResource 4.43 + (.getContextClassLoader (Thread/currentThread)) 4.44 + "com/jme3/asset/Desktop.cfg"))) 4.45 + 4.46 +(defmacro no-exceptions 4.47 + "Sweet relief like I never knew." 4.48 + [& forms] 4.49 + `(try ~@forms (catch Exception e# (.printStackTrace e#)))) 4.50 + 4.51 +(defn thread-exception-removal [] 4.52 + (println "removing exceptions from " (Thread/currentThread)) 4.53 + (.setUncaughtExceptionHandler 4.54 + (Thread/currentThread) 4.55 + (proxy [Thread$UncaughtExceptionHandler] [] 4.56 + (uncaughtException 4.57 + [thread thrown] 4.58 + (println "uncaught-exception thrown in " thread) 4.59 + (println (.getMessage thrown)))))) 4.60 + 4.61 +(def println-repl (bound-fn [& args] (apply println args))) 4.62 + 4.63 +(use '[pokemon [lpsolve :only [constant-map]]]) 4.64 + 4.65 +(defn no-op [& _]) 4.66 + 4.67 +(defn all-keys 4.68 + "Construct a map of strings representing all the manual inputs from 4.69 + either the keyboard or mouse." 4.70 + [] 4.71 + (let [inputs (constant-map KeyInput)] 4.72 + (assoc 4.73 + (zipmap (map (fn [field] 4.74 + (.toLowerCase (re-gsub #"_" "-" field))) (vals inputs)) 4.75 + (map (fn [val] (KeyTrigger. val)) (keys inputs))) 4.76 + ;;explicitly add mouse controls 4.77 + "mouse-left" (MouseButtonTrigger. 0) 4.78 + "mouse-middle" (MouseButtonTrigger. 2) 4.79 + "mouse-right" (MouseButtonTrigger. 1)))) 4.80 + 4.81 +(defn initialize-inputs 4.82 + "more java-interop cruft to establish keybindings for a particular virtual world" 4.83 + [game input-manager key-map] 4.84 + (doall (map (fn [[name trigger]] 4.85 + (.addMapping ^InputManager input-manager 4.86 + name (into-array (class trigger) [trigger]))) key-map)) 4.87 + (doall (map (fn [name] 4.88 + (.addListener ^InputManager input-manager game 4.89 + (into-array String [name]))) (keys key-map)))) 4.90 + 4.91 +#+end_src 4.92 + 4.93 +These functions are all for debug controlling of the world through 4.94 +keyboard and mouse. 4.95 + 4.96 +We reuse =constant-map= from =pokemon.lpsolve= to get the numerical 4.97 +values for all the keys defined in the =KeyInput= class. The 4.98 +documentation for =constant-map= is: 4.99 + 4.100 +#+begin_src clojure :results output 4.101 +(doc pokemon.lpsolve/constant-map) 4.102 +#+end_src 4.103 + 4.104 +#+results: 4.105 +: ------------------------- 4.106 +: pokemon.lpsolve/constant-map 4.107 +: ([class]) 4.108 +: Takes a class and creates a map of the static constant integer 4.109 +: fields with their names. This helps with C wrappers where they have 4.110 +: just defined a bunch of integer constants instead of enums 4.111 + 4.112 + 4.113 +Then, =all-keys= converts the constant names like =KEY_J= to the more 4.114 +clojure-like =key-j=, and returns a map from these keys to 4.115 +jMonkeyEngine KeyTrigger objects, the use of which will soon become 4.116 +apparent. =all-keys= also adds the three mouse button controls to the 4.117 +map. 4.118 + 4.119 +#+srcname: world 4.120 +#+begin_src clojure :results silent 4.121 +(in-ns 'cortex.world) 4.122 + 4.123 +(defn traverse 4.124 + "apply f to every non-node, deeply" 4.125 + [f node] 4.126 + (if (isa? (class node) Node) 4.127 + (dorun (map (partial traverse f) (.getChildren node))) 4.128 + (f node))) 4.129 + 4.130 +(def gravity (Vector3f. 0 -9.81 0)) 4.131 + 4.132 +(defn world 4.133 + [root-node key-map setup-fn update-fn] 4.134 + (let [physics-manager (BulletAppState.) 4.135 + shadow-renderer (BasicShadowRenderer. (asset-manager) (int 256)) 4.136 + ;;maybe use a better shadow renderer someday! 4.137 + ;;shadow-renderer (PssmShadowRenderer. (asset-manager) 256 1) 4.138 + ] 4.139 + (doto 4.140 + (proxy [SimpleApplication ActionListener] [] 4.141 + (simpleInitApp 4.142 + [] 4.143 + (no-exceptions 4.144 + (.setTimer this (IsoTimer. 60)) 4.145 + ;; Create key-map. 4.146 + (.setFrustumFar (.getCamera this) 300) 4.147 + (initialize-inputs this (.getInputManager this) (all-keys)) 4.148 + ;; Don't take control of the mouse 4.149 + (org.lwjgl.input.Mouse/setGrabbed false) 4.150 + ;; add all objects to the world 4.151 + (.attachChild (.getRootNode this) root-node) 4.152 + ;; enable physics 4.153 + ;; add a physics manager 4.154 + (.attach (.getStateManager this) physics-manager) 4.155 + (.setGravity (.getPhysicsSpace physics-manager) gravity) 4.156 + 4.157 + 4.158 + ;; go through every object and add it to the physics manager 4.159 + ;; if relavant. 4.160 + (traverse (fn [geom] 4.161 + (dorun 4.162 + (for [n (range (.getNumControls geom))] 4.163 + (do 4.164 + (println-repl "adding control " (.getControl geom n)) 4.165 + (.add (.getPhysicsSpace physics-manager) 4.166 + (.getControl geom n)))))) 4.167 + (.getRootNode this)) 4.168 + ;;(.addAll (.getPhysicsSpace physics-manager) (.getRootNode this)) 4.169 + 4.170 + (setup-fn this) 4.171 + (.setDirection shadow-renderer 4.172 + (.normalizeLocal (Vector3f. -1 -1 -1))) 4.173 + (.addProcessor (.getViewPort this) shadow-renderer) 4.174 + (.setShadowMode (.getRootNode this) RenderQueue$ShadowMode/Off) 4.175 + )) 4.176 + (simpleUpdate 4.177 + [tpf] 4.178 + (no-exceptions 4.179 + (update-fn this tpf))) 4.180 + (onAction 4.181 + [binding value tpf] 4.182 + ;; whenever a key is pressed, call the function returned from 4.183 + ;; key-map. 4.184 + (no-exceptions 4.185 + (if-let [react (key-map binding)] 4.186 + (react this value))))) 4.187 + ;; don't show a menu to change options. 4.188 + 4.189 + (.setShowSettings false) 4.190 + (.setPauseOnLostFocus false) 4.191 + (.setSettings *app-settings*)))) 4.192 + 4.193 +(defn apply-map 4.194 + "Like apply, but works for maps and functions that expect an implicit map 4.195 + and nothing else as in (fn [& {}]). 4.196 +------- Example ------- 4.197 + (defn jjj [& {:keys [www] :or {www \"oh yeah\"} :as env}] (println www)) 4.198 + (apply-map jjj {:www \"whatever\"}) 4.199 + -->\"whatever\"" 4.200 + [fn m] 4.201 + (apply fn (reduce #(into %1 %2) [] m))) 4.202 + 4.203 +#+end_src 4.204 + 4.205 + 4.206 +=world= is the most important function here. 4.207 +*** TODO more documentation 4.208 + 4.209 +#+srcname: world-shapes 4.210 +#+begin_src clojure :results silent 4.211 +(in-ns 'cortex.world) 4.212 +(defrecord shape-description 4.213 + [name 4.214 + color 4.215 + mass 4.216 + friction 4.217 + texture 4.218 + material 4.219 + position 4.220 + rotation 4.221 + shape 4.222 + physical?]) 4.223 + 4.224 +(def base-shape 4.225 + (shape-description. 4.226 + "default-shape" 4.227 + false 4.228 + ;;ColorRGBA/Blue 4.229 + 1.0 ;; mass 4.230 + 1.0 ;; friction 4.231 + ;; texture 4.232 + "Textures/Terrain/BrickWall/BrickWall.jpg" 4.233 + ;; material 4.234 + "Common/MatDefs/Misc/Unshaded.j3md" 4.235 + Vector3f/ZERO 4.236 + Quaternion/IDENTITY 4.237 + (Box. Vector3f/ZERO 0.5 0.5 0.5) 4.238 + true)) 4.239 + 4.240 +(defn make-shape 4.241 + [#^shape-description d] 4.242 + (let [asset-manager (if (:asset-manager d) (:asset-manager d) (asset-manager)) 4.243 + mat (Material. asset-manager (:material d)) 4.244 + geom (Geometry. (:name d) (:shape d))] 4.245 + (if (:texture d) 4.246 + (let [key (TextureKey. (:texture d))] 4.247 + (.setGenerateMips key true) 4.248 + (.setTexture mat "ColorMap" (.loadTexture asset-manager key)))) 4.249 + (if (:color d) (.setColor mat "Color" (:color d))) 4.250 + (.setMaterial geom mat) 4.251 + (if-let [rotation (:rotation d)] (.rotate geom rotation)) 4.252 + (.setLocalTranslation geom (:position d)) 4.253 + (if (:physical? d) 4.254 + (let [impact-shape (doto (GImpactCollisionShape. 4.255 + (.getMesh geom)) (.setMargin 0)) 4.256 + physics-control (RigidBodyControl. 4.257 + ;;impact-shape ;; comment to disable 4.258 + (float (:mass d)))] 4.259 + (.createJmeMesh impact-shape) 4.260 + (.addControl geom physics-control) 4.261 + ;;(.setSleepingThresholds physics-control (float 0) (float 0)) 4.262 + (.setFriction physics-control (:friction d)))) 4.263 + ;;the default is to keep this node in the physics engine forever. 4.264 + ;;these commands must come after the control is added to the geometry. 4.265 + ;; 4.266 + geom)) 4.267 + 4.268 +(defn box 4.269 + ([l w h & {:as options}] 4.270 + (let [options (merge base-shape options)] 4.271 + (make-shape (assoc options 4.272 + :shape (Box. l w h))))) 4.273 + ([] (box 0.5 0.5 0.5))) 4.274 + 4.275 +(defn sphere 4.276 + ([r & {:as options}] 4.277 + (let [options (merge base-shape options)] 4.278 + (make-shape (assoc options 4.279 + :shape (Sphere. 32 32 (float r)))))) 4.280 + ([] (sphere 0.5))) 4.281 + 4.282 +(defn add-element 4.283 + ([game element node] 4.284 + (.addAll 4.285 + (.getPhysicsSpace 4.286 + (.getState 4.287 + (.getStateManager game) 4.288 + BulletAppState)) 4.289 + element) 4.290 + (.attachChild node element)) 4.291 + ([game element] 4.292 + (add-element game element (.getRootNode game)))) 4.293 + 4.294 + 4.295 +(defn set-gravity* 4.296 + [game gravity] 4.297 + (traverse 4.298 + (fn [geom] 4.299 + (if-let 4.300 + [control (.getControl geom RigidBodyControl)] 4.301 + (do 4.302 + (.setGravity control gravity) 4.303 + (.applyImpulse control Vector3f/ZERO Vector3f/ZERO) 4.304 + ))) 4.305 + (.getRootNode game))) 4.306 + 4.307 +#+end_src 4.308 + 4.309 +These are convienence functions for creating JME objects and 4.310 +manipulating a world. 4.311 +