Mercurial > cortex
view org/util.org @ 30:0206878c28b4
going to start on games.org
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 24 Oct 2011 12:43:58 -0700 |
parents | 6372c108c5c6 |
children | 183744c179e6 |
line wrap: on
line source
1 #+title: Clojure Utilities for jMonkeyEngine32 #+author: Robert McIntyre3 #+email: rlm@mit.edu4 #+description:5 #+keywords: JME3, clojure, import, utilities6 #+SETUPFILE: ../../aurellem/org/setup.org7 #+INCLUDE: ../../aurellem/org/level-0.org9 * Utilities11 These are a collection of functions to make programming jMonkeyEngine12 in clojure easier.14 ** Imports16 #+srcname: import17 #+begin_src clojure :results silent18 (ns cortex.import19 (:require swank.util.class-browse))21 (defn permissive-import22 [classname]23 (eval `(try (import '~classname)24 (catch java.lang.Exception e#25 (println "couldn't import " '~classname))))26 classname)28 (defn jme-class? [classname]29 (and30 (.startsWith classname "com.jme3.")31 ;; Don't import the Lwjgl stuff since it can throw exceptions32 ;; upon being loaded.33 (not (re-matches #".*Lwjgl.*" classname))))35 (defn jme-classes36 "returns a list of all jme3 classes"37 []38 (filter39 jme-class?40 (map :name41 swank.util.class-browse/available-classes)))43 (defn mega-import-jme344 "Import ALL the jme classes. For REPL use."45 []46 (doall47 (map (comp permissive-import symbol) (jme-classes))))48 #+end_src50 jMonkeyEngine3 has a plethora of classes which can be overwhelming to51 manage. This code uses reflection to import all of them. Once I'm52 happy with the general structure of a namespace I can deal with53 importing only the classes it actually needs.55 The =mega-import-jme3= is quite usefull for debugging purposes since56 it allows completion for almost all of JME's classes.58 Out of curiousity, let's see just how many classes =mega-import-jme3=59 imports:61 #+begin_src clojure :exports both :results output62 (println (clojure.core/count (cortex.import/jme-classes)) "classes")63 #+end_src65 #+results:66 : 955 classes69 ** Utilities71 The utilities here come in three main groups:72 - Changing settings in a running =Application=73 - Creating objects74 - Visualizing objects77 *** Changing Settings79 #+srcname: util80 #+begin_src clojure81 (ns cortex.util82 "Utility functions for making jMonkeyEngine easier to program from83 clojure"84 {:author "Robert McIntyre"}85 (:use cortex.world)86 (:use clojure.contrib.def)87 (:import com.jme3.math.Vector3f)88 (:import com.jme3.math.Quaternion)89 (:import com.jme3.asset.TextureKey)90 (:import com.jme3.bullet.control.RigidBodyControl)91 (:import com.jme3.bullet.collision.shapes.GImpactCollisionShape)92 (:import com.jme3.scene.shape.Box)93 (:import com.jme3.scene.Node)94 (:import com.jme3.scene.shape.Sphere)95 (:import com.jme3.light.DirectionalLight)96 (:import com.jme3.math.ColorRGBA)97 (:import com.jme3.bullet.BulletAppState)98 (:import com.jme3.material.Material)99 (:import com.jme3.scene.Geometry))101 (defvar println-repl102 (bound-fn [& args] (apply println args))103 "println called from the LWJGL thread will not go to the REPL, but104 instead to whatever terminal started the JVM process. This function105 will always output to the REPL")107 (defn position-camera108 ([game position direction up]109 (doto (.getCamera game)110 (.setLocation )111 (.lookAt direction up)))112 ([game position direction]113 (position-camera114 game position direction Vector3f/UNIT_Y)))116 (defn enable-debug117 "Turn on the debug wireframes for every object in this simulation"118 [world]119 (.enableDebug120 (.getPhysicsSpace121 (.getState122 (.getStateManager world)123 BulletAppState))124 (asset-manager)))126 (defn set-gravity127 "In order to change the gravity of a scene, it is not only necessary128 to set the gravity variable, but to \"tap\" every physics object in129 the scene to reactivate physics calculations."130 [game gravity]131 (traverse132 (fn [geom]133 (if-let134 ;; only set gravity for physical objects.135 [control (.getControl geom RigidBodyControl)]136 (do137 (.setGravity control gravity)138 ;; tappsies!139 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO))))140 (.getRootNode game)))142 (defn add-element143 "Add the Spatial to the game's environment"144 ([game element node]145 (.addAll146 (.getPhysicsSpace147 (.getState148 (.getStateManager game)149 BulletAppState))150 element)151 (.attachChild node element))152 ([game element]153 (add-element game element (.getRootNode game))))155 (defn apply-map156 "Like apply, but works for maps and functions that expect an157 implicit map and nothing else as in (fn [& {}]).158 ------- Example -------159 (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}]160 (println www))161 (apply-map demo {:www \"hello!\"})162 -->\"hello\""163 [fn m]164 (apply fn (reduce #(into %1 %2) [] m)))166 #+end_src169 *** Creating Basic Shapes171 #+srcname: shapes172 #+begin_src clojure :results silent173 (in-ns 'cortex.util)175 (defrecord shape-description176 [name177 color178 mass179 friction180 texture181 material182 position183 rotation184 shape185 physical?186 GImpact?187 ])189 (def base-shape190 (shape-description.191 "default-shape"192 false193 ;;ColorRGBA/Blue194 1.0 ;; mass195 1.0 ;; friction196 ;; texture197 "Textures/Terrain/BrickWall/BrickWall.jpg"198 ;; material199 "Common/MatDefs/Misc/Unshaded.j3md"200 Vector3f/ZERO201 Quaternion/IDENTITY202 (Box. Vector3f/ZERO 0.5 0.5 0.5)203 true204 false))206 (defn make-shape207 [#^shape-description d]208 (let [asset-manager (asset-manager)209 mat (Material. asset-manager (:material d))210 geom (Geometry. (:name d) (:shape d))]211 (if (:texture d)212 (let [key (TextureKey. (:texture d))]213 (.setGenerateMips key true)214 (.setTexture mat "ColorMap" (.loadTexture asset-manager key))))215 (if (:color d) (.setColor mat "Color" (:color d)))216 (.setMaterial geom mat)217 (if-let [rotation (:rotation d)] (.rotate geom rotation))218 (.setLocalTranslation geom (:position d))219 (if (:physical? d)220 (let [physics-control221 (if (:GImpact d)222 ;; Create an accurate mesh collision shape if desired.223 (RigidBodyControl.224 (doto (GImpactCollisionShape.225 (.getMesh geom))226 (.createJmeMesh)227 (.setMargin 0))228 (float (:mass d)))229 ;; otherwise use jme3's default230 (RigidBodyControl. (float (:mass d))))]231 (.addControl geom physics-control)232 ;;(.setSleepingThresholds physics-control (float 0) (float 0))233 (.setFriction physics-control (:friction d))))234 geom))236 (defn box237 ([l w h & {:as options}]238 (let [options (merge base-shape options)]239 (make-shape (assoc options240 :shape (Box. l w h)))))241 ([] (box 0.5 0.5 0.5)))243 (defn sphere244 ([r & {:as options}]245 (let [options (merge base-shape options)]246 (make-shape (assoc options247 :shape (Sphere. 32 32 (float r))))))248 ([] (sphere 0.5)))249 #+end_src252 *** Viewing Objects254 #+srcname: world-view255 #+begin_src clojure :results silent256 (in-ns 'cortex.util)258 (defprotocol Viewable259 (view [something]))261 (extend-type com.jme3.scene.Geometry262 Viewable263 (view [geo]264 (view (doto (Node.)(.attachChild geo)))))266 (extend-type com.jme3.scene.Node267 Viewable268 (view269 [node]270 (.start271 (world272 node273 {}274 (fn [world]275 (enable-debug world)276 (set-gravity world Vector3f/ZERO)277 (let [sun278 (doto (DirectionalLight.)279 (.setDirection280 (.normalizeLocal (Vector3f. 1 0 -2)))281 (.setColor ColorRGBA/White))]282 (.addLight (.getRootNode world) sun)))283 no-op))))284 #+end_src286 Here I make the =Viewable= protocol and extend it to JME's types. Now287 hello-world can be written as easily as:289 #+begin_src clojure :results silent290 (cortex.util/view (cortex.util/box))291 #+end_src294 * COMMENT code generation295 #+begin_src clojure :tangle ../src/cortex/import.clj296 <<import>>297 #+end_src300 #+begin_src clojure :tangle ../src/cortex/util.clj :noweb yes301 <<util>>302 <<shapes>>303 <<world-view>>304 #+end_src