rlm@23: #+title: Helper Utilities rlm@23: #+author: Robert McIntyre rlm@23: #+email: rlm@mit.edu rlm@23: #+description: Simulating senses for AI research using JMonkeyEngine3 rlm@23: #+SETUPFILE: ../../aurellem/org/setup.org rlm@23: #+INCLUDE: ../../aurellem/org/level-0.org rlm@23: #+babel: :mkdirp yes :noweb yes :exports both rlm@23: rlm@23: ** Imports rlm@28: rlm@23: jMonkeyEngine has a plethora of classes which can be overwhelming at rlm@23: first. So that I one can get right to coding, it's good to take the rlm@23: time right now and make a "import all" function which brings in all of rlm@23: the important jme3 classes. Once I'm happy with the general structure rlm@23: of a namespace I can deal with importing only the classes it actually rlm@23: needs. rlm@23: rlm@23: #+srcname: import rlm@23: #+begin_src clojure :results silent rlm@23: (ns cortex.import rlm@23: (:require swank.util.class-browse)) rlm@23: rlm@23: (defn permissive-import rlm@23: [classname] rlm@23: (eval `(try (import '~classname) rlm@23: (catch java.lang.Exception e# rlm@23: (println "couldn't import " '~classname)))) rlm@23: classname) rlm@23: rlm@23: (defn jme-class? [classname] rlm@23: (and rlm@23: (.startsWith classname "com.jme3.") rlm@23: ;; Don't import the Lwjgl stuff since it can throw exceptions rlm@23: ;; upon being loaded. rlm@23: (not (re-matches #".*Lwjgl.*" classname)))) rlm@23: rlm@23: (defn jme-classes rlm@23: "returns a list of all jme3 classes" rlm@23: [] rlm@23: (filter rlm@23: jme-class? rlm@23: (map :name rlm@23: swank.util.class-browse/available-classes))) rlm@23: rlm@23: (defn mega-import-jme3 rlm@23: "Import ALL the jme classes. For REPL use." rlm@23: [] rlm@23: (doall rlm@23: (map (comp permissive-import symbol) (jme-classes)))) rlm@23: #+end_src rlm@23: rlm@23: The =mega-import-jme3= is quite usefull for debugging purposes since rlm@23: it allows completion for almost all of JME's classes. rlm@23: rlm@23: Out of curiousity, let's see just how many classes =mega-import-jme3= rlm@23: imports: rlm@23: rlm@23: #+begin_src clojure :exports both rlm@23: (clojure.core/count (cortex.import/jme-classes)) rlm@23: #+end_src rlm@23: rlm@23: #+results: rlm@23: : 955 rlm@23: rlm@25: rlm@23: #+srcname: world-view rlm@23: #+begin_src clojure :results silent rlm@25: (ns cortex.util) rlm@25: (require 'cortex.import) rlm@25: (cortex.import/mega-import-jme3) rlm@25: (use 'cortex.world) rlm@23: (defprotocol Viewable rlm@23: (view [something])) rlm@23: rlm@23: (extend-type com.jme3.scene.Geometry rlm@23: Viewable rlm@23: (view [geo] rlm@23: (view (doto (Node.)(.attachChild geo))))) rlm@23: rlm@23: (extend-type com.jme3.scene.Node rlm@23: Viewable rlm@23: (view [node] rlm@23: (.start rlm@23: (world node rlm@23: {} rlm@23: (fn [world] rlm@23: (.enableDebug rlm@23: (.getPhysicsSpace rlm@23: (.getState rlm@23: (.getStateManager world) rlm@23: BulletAppState)) rlm@23: (asset-manager)) rlm@23: (set-gravity* world Vector3f/ZERO) rlm@23: ;; (set-gravity* world (Vector3f. 0 (float -0.4) 0)) rlm@23: (let [sun (doto (DirectionalLight.) rlm@23: (.setDirection (.normalizeLocal (Vector3f. 1 0 -2))) rlm@23: (.setColor ColorRGBA/White))] rlm@23: (.addLight (.getRootNode world) sun))) rlm@23: no-op)))) rlm@23: #+end_src rlm@23: rlm@23: Here I make the =Viewable= protocol and extend it to JME's types. Now rlm@23: hello-world can be written as easily as: rlm@23: rlm@23: #+begin_src clojure :results silent rlm@23: (cortex.world/view (cortex.world/box)) rlm@23: #+end_src rlm@24: rlm@24: rlm@25: #+srcname: util rlm@25: #+begin_src clojure rlm@25: (in-ns 'cortex.util) rlm@25: rlm@25: (def println-repl (bound-fn [& args] (apply println args))) rlm@25: rlm@25: (defn position-camera [game] rlm@25: (doto (.getCamera game) rlm@25: (.setLocation (Vector3f. 0 6 6)) rlm@25: (.lookAt Vector3f/ZERO (Vector3f. 0 1 0)))) rlm@25: rlm@25: (defn set-gravity* rlm@25: [game gravity] rlm@25: (traverse rlm@25: (fn [geom] rlm@25: (if-let rlm@25: [control (.getControl geom RigidBodyControl)] rlm@25: (do rlm@25: (.setGravity control gravity) rlm@25: (.applyImpulse control Vector3f/ZERO Vector3f/ZERO) rlm@25: ))) rlm@25: (.getRootNode game))) rlm@25: #+end_src rlm@25: rlm@25: rlm@25: #+srcname: shapes rlm@25: #+begin_src clojure :results silent rlm@25: (in-ns 'cortex.util) rlm@25: (defrecord shape-description rlm@25: [name rlm@25: color rlm@25: mass rlm@25: friction rlm@25: texture rlm@25: material rlm@25: position rlm@25: rotation rlm@25: shape rlm@25: physical?]) rlm@25: rlm@25: (def base-shape rlm@25: (shape-description. rlm@25: "default-shape" rlm@25: false rlm@25: ;;ColorRGBA/Blue rlm@25: 1.0 ;; mass rlm@25: 1.0 ;; friction rlm@25: ;; texture rlm@25: "Textures/Terrain/BrickWall/BrickWall.jpg" rlm@25: ;; material rlm@25: "Common/MatDefs/Misc/Unshaded.j3md" rlm@25: Vector3f/ZERO rlm@25: Quaternion/IDENTITY rlm@25: (Box. Vector3f/ZERO 0.5 0.5 0.5) rlm@25: true)) rlm@25: rlm@25: (defn make-shape rlm@25: [#^shape-description d] rlm@25: (let [asset-manager (if (:asset-manager d) (:asset-manager d) (asset-manager)) rlm@25: mat (Material. asset-manager (:material d)) rlm@25: geom (Geometry. (:name d) (:shape d))] rlm@25: (if (:texture d) rlm@25: (let [key (TextureKey. (:texture d))] rlm@25: (.setGenerateMips key true) rlm@25: (.setTexture mat "ColorMap" (.loadTexture asset-manager key)))) rlm@25: (if (:color d) (.setColor mat "Color" (:color d))) rlm@25: (.setMaterial geom mat) rlm@25: (if-let [rotation (:rotation d)] (.rotate geom rotation)) rlm@25: (.setLocalTranslation geom (:position d)) rlm@25: (if (:physical? d) rlm@25: (let [impact-shape (doto (GImpactCollisionShape. rlm@25: (.getMesh geom)) (.setMargin 0)) rlm@25: physics-control (RigidBodyControl. rlm@25: ;;impact-shape ;; comment to disable rlm@25: (float (:mass d)))] rlm@25: (.createJmeMesh impact-shape) rlm@25: (.addControl geom physics-control) rlm@25: ;;(.setSleepingThresholds physics-control (float 0) (float 0)) rlm@25: (.setFriction physics-control (:friction d)))) rlm@25: ;;the default is to keep this node in the physics engine forever. rlm@25: ;;these commands must come after the control is added to the geometry. rlm@25: ;; rlm@25: geom)) rlm@25: rlm@25: (defn box rlm@25: ([l w h & {:as options}] rlm@25: (let [options (merge base-shape options)] rlm@25: (make-shape (assoc options rlm@25: :shape (Box. l w h))))) rlm@25: ([] (box 0.5 0.5 0.5))) rlm@25: rlm@25: (defn sphere rlm@25: ([r & {:as options}] rlm@25: (let [options (merge base-shape options)] rlm@25: (make-shape (assoc options rlm@25: :shape (Sphere. 32 32 (float r)))))) rlm@25: ([] (sphere 0.5))) rlm@25: rlm@25: (defn add-element rlm@25: ([game element node] rlm@25: (.addAll rlm@25: (.getPhysicsSpace rlm@25: (.getState rlm@25: (.getStateManager game) rlm@25: BulletAppState)) rlm@25: element) rlm@25: (.attachChild node element)) rlm@25: ([game element] rlm@25: (add-element game element (.getRootNode game)))) rlm@25: rlm@25: rlm@26: (defn apply-map rlm@26: "Like apply, but works for maps and functions that expect an rlm@26: implicit map and nothing else as in (fn [& {}]). rlm@26: ------- Example ------- rlm@26: (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}] rlm@26: (println www)) rlm@26: (apply-map demo {:www \"hello!\"}) rlm@26: -->\"hello\"" rlm@26: [fn m] rlm@26: (apply fn (reduce #(into %1 %2) [] m))) rlm@25: rlm@25: #+end_src rlm@25: rlm@25: rlm@24: rlm@24: * COMMENT code generation rlm@24: #+begin_src clojure :tangle ../src/cortex/import.clj rlm@24: <> rlm@24: #+end_src rlm@25: rlm@25: rlm@25: #+begin_src clojure :tangle ../src/cortex/util.clj rlm@25: <> rlm@25: <> rlm@25: <> rlm@25: #+end_src rlm@25: