Mercurial > cortex
diff org/cortex.org @ 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 | 01e1427126af |
children | 775d97247dd0 |
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