Mercurial > cortex
view org/util.org @ 41:cce471a4108a
done improving the touch article for tonight
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Thu, 03 Nov 2011 10:42:28 -0700 |
parents | bc93abad23ee |
children | ee55966ce7f6 |
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 [TABLE-OF-CONTENTS]11 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 from the REPL.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 jMonkeyEngine3 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)100 (:import (java.util.logging Level Logger)))104 (defvar println-repl105 (bound-fn [& args] (apply println args))106 "println called from the LWJGL thread will not go to the REPL, but107 instead to whatever terminal started the JVM process. This function108 will always output to the REPL")110 (defn position-camera111 "Change the position of the in-world camera."112 ([world position direction up]113 (doto (.getCamera world)114 (.setLocation )115 (.lookAt direction up)))116 ([world position direction]117 (position-camera118 world position direction Vector3f/UNIT_Y)))120 (defn enable-debug121 "Turn on debug wireframes for every object in this simulation."122 [world]123 (.enableDebug124 (.getPhysicsSpace125 (.getState126 (.getStateManager world)127 BulletAppState))128 (asset-manager)))130 (defn no-logging131 "Disable all of jMonkeyEngine's logging."132 []133 (.setLevel (Logger/getLogger "com.jme3") Level/OFF))135 (defn set-accuracy136 "Change the accuracy at which the World's Physics is calculated."137 [world new-accuracy]138 (let [physics-manager139 (.getState140 (.getStateManager world) BulletAppState)]141 (.setAccuracy142 (.getPhysicsSpace physics-manager)143 (float new-accuracy))))146 (defn set-gravity147 "In order to change the gravity of a scene, it is not only necessary148 to set the gravity variable, but to \"tap\" every physics object in149 the scene to reactivate physics calculations."150 [world gravity]151 (traverse152 (fn [geom]153 (if-let154 ;; only set gravity for physical objects.155 [control (.getControl geom RigidBodyControl)]156 (do157 (.setGravity control gravity)158 ;; tappsies!159 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO))))160 (.getRootNode world)))162 (defn add-element163 "Add the Spatial to the world's environment"164 ([world element node]165 (.addAll166 (.getPhysicsSpace167 (.getState168 (.getStateManager world)169 BulletAppState))170 element)171 (.attachChild node element))172 ([world element]173 (add-element world element (.getRootNode world))))175 (defn apply-map176 "Like apply, but works for maps and functions that expect an177 implicit map and nothing else as in (fn [& {}]).178 ------- Example -------179 (defn demo [& {:keys [www] :or {www \"oh yeah\"} :as env}]180 (println www))181 (apply-map demo {:www \"hello!\"})182 -->\"hello\""183 [fn m]184 (apply fn (reduce #(into %1 %2) [] m)))186 #+end_src189 *** Creating Basic Shapes191 #+srcname: shapes192 #+begin_src clojure :results silent193 (in-ns 'cortex.util)195 (defrecord shape-description196 [name197 color198 mass199 friction200 texture201 material202 position203 rotation204 shape205 physical?206 GImpact?207 ])209 (defvar base-shape210 (shape-description.211 "default-shape"212 false213 ;;ColorRGBA/Blue214 1.0 ;; mass215 1.0 ;; friction216 ;; texture217 "Textures/Terrain/BrickWall/BrickWall.jpg"218 ;; material219 "Common/MatDefs/Misc/Unshaded.j3md"220 Vector3f/ZERO221 Quaternion/IDENTITY222 (Box. Vector3f/ZERO 0.5 0.5 0.5)223 true224 false)225 "Basic settings for shapes.")227 (defn make-shape228 [#^shape-description d]229 (let [asset-manager (asset-manager)230 mat (Material. asset-manager (:material d))231 geom (Geometry. (:name d) (:shape d))]232 (if (:texture d)233 (let [key (TextureKey. (:texture d))]234 ;;(.setGenerateMips key true)235 ;;(.setTexture mat "ColorMap" (.loadTexture asset-manager key))236 ))237 (if (:color d) (.setColor mat "Color" (:color d)))238 (.setMaterial geom mat)239 (if-let [rotation (:rotation d)] (.rotate geom rotation))240 (.setLocalTranslation geom (:position d))241 (if (:physical? d)242 (let [physics-control243 (if (:GImpact d)244 ;; Create an accurate mesh collision shape if desired.245 (RigidBodyControl.246 (doto (GImpactCollisionShape.247 (.getMesh geom))248 (.createJmeMesh)249 (.setMargin 0))250 (float (:mass d)))251 ;; otherwise use jme3's default252 (RigidBodyControl. (float (:mass d))))]253 (.addControl geom physics-control)254 ;;(.setSleepingThresholds physics-control (float 0) (float 0))255 (.setFriction physics-control (:friction d))))256 geom))258 (defn box259 ([l w h & {:as options}]260 (let [options (merge base-shape options)]261 (make-shape (assoc options262 :shape (Box. l w h)))))263 ([] (box 0.5 0.5 0.5)))265 (defn sphere266 ([r & {:as options}]267 (let [options (merge base-shape options)]268 (make-shape (assoc options269 :shape (Sphere. 32 32 (float r))))))270 ([] (sphere 0.5)))271 #+end_src273 *** Viewing Objects275 #+srcname: world-view276 #+begin_src clojure :results silent277 (in-ns 'cortex.util)279 (defprotocol Viewable280 (view [something]))282 (extend-type com.jme3.scene.Geometry283 Viewable284 (view [geo]285 (view (doto (Node.)(.attachChild geo)))))287 (extend-type com.jme3.scene.Node288 Viewable289 (view290 [node]291 (.start292 (world293 node294 {}295 (fn [world]296 (enable-debug world)297 (set-gravity world Vector3f/ZERO)298 (let [sun299 (doto (DirectionalLight.)300 (.setDirection301 (.normalizeLocal (Vector3f. 1 0 -2)))302 (.setColor ColorRGBA/White))]303 ;; lights are required to view some objects.304 (.addLight (.getRootNode world) sun)))305 no-op))))306 #+end_src308 Here I make the =Viewable= protocol and extend it to JME's types. Now309 JME3's =hello-world= can be written as easily as:311 #+begin_src clojure :results silent312 (cortex.util/view (cortex.util/box))313 #+end_src316 * COMMENT code generation317 #+begin_src clojure :tangle ../src/cortex/import.clj318 <<import>>319 #+end_src322 #+begin_src clojure :tangle ../src/cortex/util.clj :noweb yes323 <<util>>324 <<shapes>>325 <<world-view>>326 #+end_src