changeset 0:92f8d83b5d0b

initial import: I've made hearing and vision, and am working on touch.
author Robert McIntyre <rlm@mit.edu>
date Sun, 16 Oct 2011 05:12:19 -0700
parents
children 4588025678b0
files .hgignore assets/Sounds/dream.wav assets/Sounds/pure.wav assets/Sounds/silence.wav assets/Textures/BronzeCopper030.jpg assets/Textures/PokeCopper.jpg assets/Textures/purpleWisp.png assets/Textures/redWisp.png org/body.org org/capture-video.org org/cortex.org org/skin.org
diffstat 12 files changed, 2734 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Sun Oct 16 05:12:19 2011 -0700
     1.3 @@ -0,0 +1,4 @@
     1.4 +syntax: glob
     1.5 +video*
     1.6 +src*
     1.7 +html*
     2.1 Binary file assets/Sounds/dream.wav has changed
     3.1 Binary file assets/Sounds/pure.wav has changed
     4.1 Binary file assets/Sounds/silence.wav has changed
     5.1 Binary file assets/Textures/BronzeCopper030.jpg has changed
     6.1 Binary file assets/Textures/PokeCopper.jpg has changed
     7.1 Binary file assets/Textures/purpleWisp.png has changed
     8.1 Binary file assets/Textures/redWisp.png has changed
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/org/body.org	Sun Oct 16 05:12:19 2011 -0700
     9.3 @@ -0,0 +1,37 @@
     9.4 +#+title: The BODY!!!
     9.5 +#+author: Robert McIntyre
     9.6 +#+email: rlm@mit.edu
     9.7 +#+MATHJAX: align:"left" mathml:t path:"../aurellem/src/MathJax/MathJax.js"
     9.8 +#+STYLE: <link rel="stylesheet" type="text/css" href="../aurellem/src/css/aurellem.css"/>
     9.9 +#+BABEL: :exports both :noweb yes :cache no :mkdirp yes
    9.10 +#+INCLUDE: ../aurellem/src/templates/level-0.org
    9.11 +#+description: Simulating a body (movement, tough, propioception) in jMonkeyEngine3.
    9.12 +
    9.13 +
    9.14 +* Body ! 
    9.15 +
    9.16 +#+srcname: body-main
    9.17 +#+begin_src clojure 
    9.18 +(ns body.body)
    9.19 +(use 'cortex.world)
    9.20 +(use 'cortex.import)
    9.21 +(use 'clojure.contrib.def)
    9.22 +(cortex.import/mega-import-jme3)
    9.23 +(rlm.rlm-commands/help)
    9.24 +
    9.25 +
    9.26 +
    9.27 +#+end_src
    9.28 +
    9.29 +
    9.30 +
    9.31 +
    9.32 +
    9.33 +
    9.34 +
    9.35 +
    9.36 +* COMMENT generate Source.
    9.37 +#+begin_src clojure :tangle ../src/body/body.clj
    9.38 +<<body-main>>
    9.39 +#+end_src
    9.40 +  
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/org/capture-video.org	Sun Oct 16 05:12:19 2011 -0700
    10.3 @@ -0,0 +1,633 @@
    10.4 +#+title: Capture Live Video Feeds from JMonkeyEngine
    10.5 +#+author: Robert McIntyre
    10.6 +#+email: rlm@mit.edu
    10.7 +#+MATHJAX: align:"left" mathml:t path:"../aurellem/src/MathJax/MathJax.js"
    10.8 +#+STYLE: <link rel="stylesheet" type="text/css" href="../aurellem/src/css/aurellem.css"/>
    10.9 +#+OPTIONS:   H:3 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
   10.10 +#+BABEL: :exports both :noweb yes :cache no :mkdirp yes
   10.11 +#+description: Capture video from a JMonkeyEngine3 Application with Xuggle, and use gstreamer to compress the video to upload to YouTube.
   10.12 +#+keywords: JME3, video, Xuggle, JMonkeyEngine, youtube, capture video, Java
   10.13 +#+INCLUDE: ../aurellem/src/templates/level-0.org
   10.14 +:PROPERTIES:
   10.15 +:EXPORT_FILE_NAME: ../whatever.html
   10.16 +:END:
   10.17 +
   10.18 +
   10.19 +* The Problem
   10.20 +So you've made your cool new JMonkeyEngine3 game and you want to
   10.21 +create a demo video to show off your hard work. Screen capturing is
   10.22 +the most straightforward way to do this, but it can slow down your
   10.23 +game and produce low-quality video as a result. A better way is to
   10.24 +record a video feed directly from the game while it is
   10.25 +running.
   10.26 +
   10.27 +In this post, I'll explain how you can alter your JMonkeyEngine3 game
   10.28 +to output video while it is running. The main trick is to alter the
   10.29 +pace of JMonkeyEngine3's in-game time: we allow the engine as much
   10.30 +time as it needs to compute complicated in-game events and to encode
   10.31 +video frames. As a result, the game appears to speed up and slow down
   10.32 +as the computational demands shift, but the end result is perfectly
   10.33 +smooth video output at a constant framerate.
   10.34 +
   10.35 +
   10.36 +* Game-time vs. User-time vs. Video-time
   10.37 +
   10.38 +A standard JME3 application that extends =SimpleApplication= or
   10.39 +=Application= tries as hard as it can to keep in sync with
   10.40 +/user-time/.  If a ball is rolling at 1 game-mile per game-hour in the
   10.41 +game, and you wait for one user-hour as measured by the clock on your
   10.42 +wall, then the ball should have traveled exactly one game-mile. In
   10.43 +order to keep sync with the real world, the game throttles its physics
   10.44 +engine and graphics display.  If the computations involved in running
   10.45 +the game are too intense, then the game will first skip frames, then
   10.46 +sacrifice physics accuracy.  If there are particuraly demanding
   10.47 +computations, then you may only get 1 fps, and the ball may tunnel
   10.48 +through the floor or obstacles due to inaccurate physics simulation,
   10.49 +but after the end of one user-hour, that ball will have traveled one
   10.50 +game-mile.
   10.51 +
   10.52 +When we're recording video, we don't care if the game-time syncs with
   10.53 +user-time, but instead whether the time in the recorded video
   10.54 +(video-time) syncs with user-time. To continue the analogy, if we
   10.55 +recorded the ball rolling at 1 game-mile per game-hour and watched the
   10.56 +video later, we would want to see 30 fps video of the ball rolling at
   10.57 +1 video-mile per /user-hour/. It doesn't matter how much user-time it
   10.58 +took to simulate that hour of game-time to make the high-quality
   10.59 +recording.
   10.60 +
   10.61 +* COMMENT Two examples to clarify the point:
   10.62 +** Recording from a Simple Simulation
   10.63 +
   10.64 +*** Without a Special Timer
   10.65 +You have a simulation of a ball rolling on an infinite empty plane at
   10.66 +one game-mile per game-hour, and a really good computer. Normally,
   10.67 +JME3 will throttle the physics engine and graphics display to sync the
   10.68 +game-time with user-time. If it takes one-thousandth of a second
   10.69 +user-time to simulate one-sixtieth of a second game time and another
   10.70 +one-thousandth of a second to draw to the screen, then JME3 will just
   10.71 +sit around for the remainder of $\frac{1}{60} - \frac{2}{1000}$
   10.72 +user-seconds, then calculate the next frame in $\frac{2}{1000}$
   10.73 +user-seconds, then wait, and so on. For every second of user time that
   10.74 +passes, one second of game-time passes, and the game will run at 60
   10.75 +frames per user-second.
   10.76 +
   10.77 +
   10.78 +*** With a Special Timer
   10.79 +Then, you change the game's timer so that user-time will be synced to
   10.80 +video-time. Assume that encoding a single frame takes 0 seconds
   10.81 +user-time to complete.
   10.82 +
   10.83 +Now, JME3 takes advantage of all available resources. It still takes
   10.84 +one-thousandth of a second to calculate a physics tick, and another
   10.85 +one-thousandth to render to the screen. Then it takes 0 seconds to
   10.86 +write the video frame to disk and encode the video. In only one second
   10.87 +of user time, JME3 will complete 500 physics-tick/render/encode-video
   10.88 +cycles, and $\frac{500}{60}=8\frac{1}{3}$ seconds of game-time will
   10.89 +have passed.  Game-time appears to dilate $8\frac{1}{3}\times$ with
   10.90 +respect to user-time, and in only 7.2 minutes user-time, one hour of
   10.91 +video will have been recorded. The game itself will run at 500 fps.
   10.92 +When someone watches the video, they will see 60 frames per
   10.93 +user-second, and $\frac{1}{60}$ video-seconds will pass each frame. It
   10.94 +will take exactly one hour user-time (and one hour video-time) for the
   10.95 +ball in the video to travel one video-mile.
   10.96 +
   10.97 +** Recording from a Complex Simulation 
   10.98 +
   10.99 +*** Without a Special Timer
  10.100 +You have a simulation of a ball rolling on an infinite empty plane at
  10.101 +one game-mile per game-hour accompanied by multiple explosions
  10.102 +involving thousands of nodes, particle effects, and complicated shadow
  10.103 +shaders to create realistic shadows. You also have a slow
  10.104 +laptop. Normally, JME3 must sacrifice rendering and physics simulation
  10.105 +to try to keep up.  If it takes $\frac{1}{120}$ of a user-second to
  10.106 +calculate $\frac{1}{60}$ game-seconds, and an additional
  10.107 +$\frac{1}{60}$ of a user-second to render to screen, then JME3 has
  10.108 +it's work cut out for it.  In order to render to the screen, it will
  10.109 +first step the game forward by up to four physics ticks before
  10.110 +rendering to the screen. If it still isn't fast enough then it will
  10.111 +decrease the accuracy of the physics engine until game-time and user
  10.112 +time are synched or a certain threshold is reached, at which point the
  10.113 +game visibly slows down. In this case, JME3 continuously repeat a
  10.114 +cycle of two physics ticks, and one screen render. For every
  10.115 +user-second that passes, one game-second will pass, but the game will
  10.116 +run at 30 fps instead of 60 fps like before.
  10.117 +
  10.118 +*** With a Special Timer
  10.119 +Then, you change the game's timer so that user-time will be synced to
  10.120 +video-time. Once again, assume video encoding takes $\frac{1}{60}$ of
  10.121 +a user-second.
  10.122 +
  10.123 +Now, JME3 will spend $\frac{1}{120}$ of a user-second to step the
  10.124 +physics tick $\frac{1}{60}$ game-seconds, $\frac{1}{60}$ to draw to
  10.125 +the screen, and an additional $\frac{1}{60}$ to encode the video and
  10.126 +write the frame to disk. This is a total of $\frac{1}{24}$
  10.127 +user-seconds for each $\frac{1}{60}$ game-seconds. It will take
  10.128 +$(\frac{60}{24} = 2.5)$ user-hours to record one game-hour and game-time
  10.129 +will appear to flow two-fifths as fast as user time while the game is
  10.130 +running. However, just as in example one, when all is said and done we
  10.131 +will have an hour long video at 60 fps.
  10.132 +
  10.133 +
  10.134 +* COMMENT proposed names for the new timer
  10.135 +# METRONOME
  10.136 +# IsoTimer
  10.137 +# EvenTimer
  10.138 +# PulseTimer
  10.139 +# FixedTimer
  10.140 +# RigidTimer
  10.141 +# FixedTempo
  10.142 +# RegularTimer
  10.143 +# MetronomeTimer
  10.144 +# ConstantTimer
  10.145 +# SteadyTimer
  10.146 +
  10.147 +
  10.148 +* =IsoTimer= records time like a metronome
  10.149 +
  10.150 +The easiest way to achieve this special timing is to create a new
  10.151 +timer that always reports the same framerate to JME3 every time it is
  10.152 +called.
  10.153 +
  10.154 +
  10.155 +=./jme3/src/core/com/jme3/system/IsoTimer.java=
  10.156 +#+include ./jme3/src/core/com/jme3/system/IsoTimer.java src java
  10.157 +
  10.158 +If an Application uses this =IsoTimer= instead of the normal one, we
  10.159 +can be sure that every call to =simpleUpdate=, for example, corresponds
  10.160 +to exactly $(\frac{1}{fps})$ seconds of game-time.
  10.161 +
  10.162 +In order to facilitate setting the =Timer= in user code, I added
  10.163 +getter and setter methods to =Application.java=.
  10.164 +
  10.165 +In =./jme3/src/core/com/jme3/app/Application.java= I added:
  10.166 +#+include ./jme3/src/core/com/jme3/app/Application.java src java :lines "340-356"
  10.167 +
  10.168 +* Encoding to Video
  10.169 +
  10.170 +Now that the issue of time is solved, we just need a function that
  10.171 +writes each frame to a video.  We can put this function somewhere
  10.172 +where it will be called exactly one per frame.
  10.173 +
  10.174 +JME3 already provides exactly the class we need: the =SceneProcessor=
  10.175 +class can be attached to any viewport and the methods defined therein
  10.176 +will be called at the appropriate points in the rendering process.
  10.177 +
  10.178 +If you want to generate video from Java, a great option is [[http://www.xuggle.com/][Xuggle]]. It
  10.179 +takes care of everything related to video encoding and decoding and
  10.180 +runs on Windows, Linux and Mac.  Out of all the video frameworks for
  10.181 +Java I personally like this one the best.
  10.182 +
  10.183 +Here is a =SceneProcessor= that uses [[http://www.xuggle.com/][Xuggle]] to write each frame to a
  10.184 +video file.
  10.185 +
  10.186 +=./jme3/src/core/com/jme3/app/VideoProcessor.java=
  10.187 +#+include ./jme3/src/core/com/jme3/app/VideoProcessor.java src java
  10.188 +
  10.189 +With this, we are able to record video!
  10.190 +
  10.191 +* Hello Video!
  10.192 +
  10.193 +I've taken [[http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/helloworld/HelloLoop.java][=./jme3/src/test/jme3test/helloworld/HelloLoop.java=]] and
  10.194 +augmented it with video output as follows:
  10.195 +
  10.196 +=./jme3/src/test/jme3test/helloworld/HelloVideo.java=
  10.197 +#+include ./jme3/src/test/jme3test/helloworld/HelloVideo.java src java
  10.198 +
  10.199 +The videos are created in the =hello-video= directory
  10.200 +
  10.201 +#+begin_src sh :results verbatim
  10.202 +du -h hello-video/*
  10.203 +#+end_src
  10.204 +
  10.205 +#+results:
  10.206 +: 932K	hello-video/hello-video-moving.flv
  10.207 +: 640K	hello-video/hello-video-static.flv
  10.208 +
  10.209 +And can be immediately uploaded to youtube
  10.210 +
  10.211 +- [[http://www.youtube.com/watch?v=C8gxVAySaPg][hello-video-moving.flv]]
  10.212 +#+BEGIN_HTML
  10.213 +<iframe width="425" height="349" 
  10.214 +	src="http://www.youtube.com/embed/C8gxVAySaPg" 
  10.215 +	frameborder="0" allowfullscreen>
  10.216 +</iframe>
  10.217 +#+END_HTML
  10.218 +- [[http://www.youtube.com/watch?v=pHcFOtIS07Q][hello-video-static.flv]]
  10.219 +#+BEGIN_HTML
  10.220 +<iframe width="425" height="349" 
  10.221 +	src="http://www.youtube.com/embed/pHcFOtIS07Q" 
  10.222 +	frameborder="0" allowfullscreen>
  10.223 +</iframe>
  10.224 +
  10.225 +#+END_HTML
  10.226 +
  10.227 +  
  10.228 +
  10.229 +* Summary 
  10.230 +It's quite easy to augment your own application to record video,
  10.231 +almost regardless of how complicated the actual application is.  You
  10.232 +can also record from multiple ViewPorts as the above example shows.
  10.233 +
  10.234 +The process for adding video recording to your application is as
  10.235 +follows:
  10.236 +
  10.237 +Assuming you want to record at 30 fps, add:
  10.238 +
  10.239 +#+begin_src java :exports code
  10.240 +this.setTimer(new IsoTimer(30));
  10.241 +#+end_src
  10.242 +
  10.243 +Somewhere in the initialization of your Application.  Right now, you
  10.244 +will have to add the =setTimer= method to =Application=, but hopefully
  10.245 +this method will be included soon by the JMonkeyEngine3 team.
  10.246 +
  10.247 +Then, you create a =VideoProcessor= object and attach it to the
  10.248 +=ViewPort= from which you want to record.
  10.249 +
  10.250 +If you want to record from the game's main =ViewPort= to a file called
  10.251 +=/home/r/record.flv=, then add:
  10.252 +
  10.253 +#+begin_src java :exports code
  10.254 +viewPort.addProcessor(new VideoProcessor(new File("/home/r/record.flv")));
  10.255 +#+end_src
  10.256 +
  10.257 +Do this for each =ViewPort= from which you want to record.  The more
  10.258 +ViewPorts from which you record, the slower the game will run, but
  10.259 +this slowness will not affect the final video output.
  10.260 +
  10.261 +* More Examples
  10.262 +** Hello Physics
  10.263 +=HelloVideo= is boring. Let's add some video capturing to =HelloPhysics=
  10.264 +and create something fun!
  10.265 +
  10.266 +This example is a modified version of =HelloPhysics= that creates four
  10.267 +simultaneous views of the same scene of cannonballs careening into a
  10.268 +brick wall.
  10.269 +
  10.270 +=./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java=
  10.271 +#+include ./jme3/src/test/jme3test/helloworld/HelloPhysicsWithVideo.java src java
  10.272 +
  10.273 +Running the program outputs four videos into the =./physics-videos=
  10.274 +directory.
  10.275 +
  10.276 +#+begin_src sh :exports both :results verbatim
  10.277 +ls ./physics-videos | grep -
  10.278 +#+end_src
  10.279 +
  10.280 +#+results:
  10.281 +: lower-left.flv
  10.282 +: lower-right.flv
  10.283 +: upper-left.flv
  10.284 +: upper-right.flv
  10.285 +
  10.286 +The videos are fused together with the following =gstreamer= commands:
  10.287 +
  10.288 +#+begin_src sh :results silent
  10.289 +cd physics-videos
  10.290 +
  10.291 +gst-launch-0.10 \
  10.292 + filesrc location=./upper-right.flv ! decodebin ! \
  10.293 + videoscale ! ffmpegcolorspace ! \
  10.294 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.295 + videobox border-alpha=0 left=-640 ! \
  10.296 + videomixer name=mix ! ffmpegcolorspace ! videorate ! \
  10.297 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.298 + jpegenc ! avimux  ! filesink location=upper.flv \
  10.299 + \
  10.300 + filesrc location=./upper-left.flv ! decodebin ! \
  10.301 + videoscale ! ffmpegcolorspace ! \
  10.302 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.303 + videobox right=-640 ! mix.
  10.304 +#+end_src
  10.305 +
  10.306 +#+begin_src sh :results silent
  10.307 +cd physics-videos
  10.308 +
  10.309 +gst-launch-0.10 \
  10.310 + filesrc location=./lower-left.flv ! decodebin ! \
  10.311 + videoscale ! ffmpegcolorspace ! \
  10.312 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.313 + videobox border-alpha=0 left=-640 ! \
  10.314 + videomixer name=mix ! ffmpegcolorspace ! videorate ! \
  10.315 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.316 + jpegenc ! avimux  ! filesink location=lower.flv \
  10.317 + \
  10.318 + filesrc location=./lower-right.flv ! decodebin ! \
  10.319 + videoscale ! ffmpegcolorspace ! \
  10.320 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.321 + videobox right=-640 ! mix.
  10.322 +#+end_src
  10.323 +
  10.324 +#+begin_src sh :results silent
  10.325 +cd physics-videos
  10.326 +
  10.327 +gst-launch-0.10 \
  10.328 + filesrc location=./upper.flv ! decodebin ! \
  10.329 + videoscale ! ffmpegcolorspace ! \
  10.330 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.331 + videobox border-alpha=0 bottom=-480 ! \
  10.332 + videomixer name=mix ! ffmpegcolorspace ! videorate ! \
  10.333 + video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
  10.334 + jpegenc ! avimux  ! filesink location=../youtube/helloPhysics.flv \
  10.335 + \
  10.336 + filesrc location=./lower.flv ! decodebin ! \
  10.337 + videoscale ! ffmpegcolorspace ! \
  10.338 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.339 + videobox top=-480 ! mix.
  10.340 +#+end_src
  10.341 +
  10.342 +#+begin_src sh :results verbatim
  10.343 +du -h youtube/helloPhysics.flv
  10.344 +#+end_src
  10.345 +
  10.346 +#+results:
  10.347 +: 180M	physics-videos/helloPhysics.flv
  10.348 +
  10.349 +
  10.350 +Thats a terribly large size!
  10.351 +Let's compress it:
  10.352 +
  10.353 +** Compressing the HelloPhysics Video
  10.354 +First, we'll scale the video, then, we'll decrease it's bitrate. The
  10.355 +end result will be perfect for upload to YouTube.
  10.356 +
  10.357 +#+begin_src sh :results silent
  10.358 +cd youtube
  10.359 +
  10.360 +gst-launch-0.10 \
  10.361 + filesrc location=./helloPhysics.flv ! decodebin ! \
  10.362 + videoscale ! ffmpegcolorspace ! \
  10.363 + `: # the original size is 1280 by 960` \
  10.364 + video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
  10.365 + videoscale ! \
  10.366 + `: # here we scale the video down` \
  10.367 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.368 + `: # and here we limit the bitrate` \
  10.369 + theoraenc bitrate=1024 quality=30 ! \
  10.370 + oggmux ! progressreport update-freq=1 ! \
  10.371 + filesink location=./helloPhysics.ogg 
  10.372 +#+end_src
  10.373 +
  10.374 +#+begin_src sh :results verbatim
  10.375 +du -h youtube/helloPhysics.ogg
  10.376 +#+end_src
  10.377 +
  10.378 +#+results:
  10.379 +: 13M	youtube/helloPhysics.ogg
  10.380 +
  10.381 +[[http://www.youtube.com/watch?v=WIJt9aRGusc][helloPhysics.ogg]]
  10.382 +
  10.383 +#+begin_html
  10.384 +<iframe width="425" height="349" 
  10.385 +	src="http://www.youtube.com/embed/WIJt9aRGusc?hl=en&fs=1" 
  10.386 +	frameborder="0" allowfullscreen>
  10.387 +</iframe>
  10.388 +#+end_html
  10.389 +
  10.390 +
  10.391 +** COMMENT failed attempts
  10.392 +Let's try the [[http://diracvideo.org/][Dirac]] video encoder.
  10.393 +
  10.394 +#+begin_src sh :results verbatim
  10.395 +cd youtube
  10.396 +START=$(date +%s) 
  10.397 +gst-launch-0.10 \
  10.398 + filesrc location=./helloPhysics.flv ! decodebin ! \
  10.399 + videoscale ! ffmpegcolorspace ! \
  10.400 + video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
  10.401 + schroenc ! filesink location=./helloPhysics.drc > /dev/null
  10.402 +echo `expr $(( $(date +%s) - $START))`
  10.403 +#+end_src
  10.404 +
  10.405 +
  10.406 +#+results:
  10.407 +: 142
  10.408 +
  10.409 +That took 142 seconds. Let's see how it does compression-wise:
  10.410 +
  10.411 +#+begin_src sh :results verbatim
  10.412 +du -h ./youtube/helloPhysics.drc
  10.413 +#+end_src
  10.414 +
  10.415 +#+results:
  10.416 +: 22M	./physics-videos/helloPhysics.drc
  10.417 +
  10.418 +
  10.419 +#+begin_src sh :results verbatim
  10.420 +cd youtube
  10.421 +START=$(date +%s) 
  10.422 +gst-launch-0.10 \
  10.423 + filesrc location=./helloPhysics.flv ! decodebin ! \
  10.424 + videoscale ! ffmpegcolorspace ! \
  10.425 + video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
  10.426 + theoraenc ! oggmux ! filesink location=./helloPhysics.ogg \
  10.427 + > /dev/null
  10.428 +echo `expr $(( $(date +%s) - $START))`
  10.429 +#+end_src
  10.430 +
  10.431 +#+results:
  10.432 +: 123
  10.433 +
  10.434 +#+begin_src sh :results verbatim
  10.435 +du -h youtube/helloPhysics.ogg
  10.436 +#+end_src
  10.437 +
  10.438 +#+results:
  10.439 +: 59M	physics-videos/helloPhysics.ogg
  10.440 +
  10.441 +
  10.442 +=*.drc= files can not be uploaded to YouTube, so I'll go for the
  10.443 +avi file.
  10.444 +
  10.445 +
  10.446 +** COMMENT text for videos
  10.447 +Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) using Xuggle
  10.448 +(www.xuggle.com/).  Everything is explained at
  10.449 +http://aurellem.org/cortex/capture-video.html.
  10.450 +
  10.451 +
  10.452 +Video output from JMonkeyEngine3 (www.jmonkeyengine.org/) HelloPhysics
  10.453 +demo application using Xuggle (www.xuggle.com/).  Everything is
  10.454 +explained at http://aurellem.org/cortex/capture-video.html.  Here,
  10.455 +four points of view are simultaneously recorded and then glued
  10.456 +together later.
  10.457 +
  10.458 + JME3 Xuggle Aurellem video capture
  10.459 + 
  10.460 + 
  10.461 +* Sample Videos
  10.462 +I encoded most of the original JME3 Hello demos for your viewing
  10.463 +pleasure, all using the =VideoProcessor= and =IsoTimer= classes.
  10.464 +
  10.465 +** HelloTerrain
  10.466 +[[http://youtu.be/5_4wyDFwrVQ][HelloTerrain.avi]]
  10.467 +
  10.468 +#+begin_html
  10.469 +<iframe width="425" height="349" 
  10.470 +	src="http://www.youtube.com/embed/5_4wyDFwrVQ" 
  10.471 +	frameborder="0" allowfullscreen>
  10.472 +</iframe>
  10.473 +#+end_html
  10.474 +
  10.475 +** HelloAssets
  10.476 +[[http://www.youtube.com/watch?v=oGg-Q6k1BM4][HelloAssets.avi]]
  10.477 +
  10.478 +#+begin_html
  10.479 +<iframe width="425" height="349" 
  10.480 +	src="http://www.youtube.com/embed/oGg-Q6k1BM4?hl=en&fs=1" 
  10.481 +	frameborder="0" allowfullscreen>
  10.482 +</iframe>
  10.483 +#+end_html
  10.484 +
  10.485 +** HelloEffects
  10.486 +[[http://www.youtube.com/watch?v=TuxlLMe53hA][HelloEffects]]
  10.487 +
  10.488 +#+begin_html
  10.489 +<iframe width="425" height="349" 
  10.490 +	src="http://www.youtube.com/embed/TuxlLMe53hA?hl=en&fs=1" 
  10.491 +	frameborder="0" allowfullscreen>
  10.492 +</iframe>
  10.493 +#+end_html
  10.494 +
  10.495 +** HelloCollision
  10.496 +[[http://www.youtube.com/watch?v=GPlvJkiZfFw][HelloCollision.avi]]
  10.497 +
  10.498 +#+begin_html
  10.499 +<iframe width="425" height="349" 
  10.500 +	src="http://www.youtube.com/embed/GPlvJkiZfFw?hl=en&fs=1" 
  10.501 +	frameborder="0" allowfullscreen>
  10.502 +</iframe>
  10.503 +#+end_html
  10.504 +
  10.505 +** HelloAnimation
  10.506 +[[http://www.youtube.com/watch?v=SDCfOSPYUkg][HelloAnimation.avi]]
  10.507 +
  10.508 +#+begin_html
  10.509 +<iframe width="425" height="349" 
  10.510 +	src="http://www.youtube.com/embed/SDCfOSPYUkg?hl=en&fs=1" 
  10.511 +	frameborder="0" allowfullscreen>
  10.512 +</iframe>
  10.513 +#+end_html
  10.514 +
  10.515 +** HelloNode
  10.516 +[[http://www.youtube.com/watch?v=pL-0fR0-ilQ][HelloNode.avi]]
  10.517 +
  10.518 +#+begin_html
  10.519 +<iframe width="425" height="349" 
  10.520 +	src="http://www.youtube.com/embed/pL-0fR0-ilQ?hl=en&fs=1" 
  10.521 +	frameborder="0" allowfullscreen>
  10.522 +</iframe>
  10.523 +#+end_html
  10.524 +
  10.525 +** HelloLoop
  10.526 +[[http://www.youtube.com/watch?v=mosZzzcdE5w][HelloLoop.avi]]
  10.527 +
  10.528 +#+begin_html
  10.529 +<iframe width="425" height="349" 
  10.530 +	src="http://www.youtube.com/embed/mosZzzcdE5w?hl=en&fs=1" 
  10.531 +	frameborder="0" allowfullscreen>
  10.532 +</iframe>
  10.533 +#+end_html
  10.534 +
  10.535 +
  10.536 +*** COMMENT x-form the other stupid 
  10.537 +progressreport update-freq=1 
  10.538 +
  10.539 +gst-launch-0.10 \
  10.540 + filesrc location=./helloPhy ! decodebin ! \
  10.541 + videoscale ! ffmpegcolorspace ! \
  10.542 + video/x-raw-yuv, width=1280, height=960, framerate=25/1 ! \
  10.543 + x264enc ! avimux ! filesink location=helloPhysics.avi \
  10.544 +
  10.545 +
  10.546 +gst-launch-0.10 \
  10.547 + filesrc location=./HelloAnimationStatic.flv ! decodebin ! \
  10.548 + videoscale ! ffmpegcolorspace ! \
  10.549 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.550 + videobox border-alpha=0 left=-640 ! \
  10.551 + videomixer name=mix ! ffmpegcolorspace ! videorate ! \
  10.552 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.553 +  x264enc ! avimux ! progressreport update-freq=1 ! \
  10.554 +  filesink location=../youtube/HelloAnimation.avi \
  10.555 + \
  10.556 + filesrc location=./HelloAnimationMotion.flv ! decodebin ! \
  10.557 + videoscale ! ffmpegcolorspace ! \
  10.558 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.559 + videobox right=-640 ! mix.
  10.560 +
  10.561 +gst-launch-0.10 \
  10.562 + filesrc location=./HelloCollisionMotion.flv ! decodebin ! \
  10.563 + videoscale ! ffmpegcolorspace ! \
  10.564 + video/x-raw-yuv, width=800, height=600, framerate=25/1 ! \
  10.565 + x264enc bitrate=1024 ! avimux ! \
  10.566 + filesink location=../youtube/HelloCollision.avi 
  10.567 +
  10.568 +gst-launch-0.10 \
  10.569 + filesrc location=./HelloEffectsStatic.flv ! decodebin ! \
  10.570 + videoscale ! ffmpegcolorspace ! \
  10.571 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.572 + videobox border-alpha=0 left=-640 ! \
  10.573 + videomixer name=mix ! ffmpegcolorspace ! videorate ! \
  10.574 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.575 +  x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
  10.576 +  filesink location=../youtube/HelloEffects.avi \
  10.577 + \
  10.578 + filesrc location=./HelloEffectsMotion.flv ! decodebin ! \
  10.579 + videoscale ! ffmpegcolorspace ! \
  10.580 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.581 + videobox right=-640 ! mix.
  10.582 +
  10.583 +gst-launch-0.10 \
  10.584 + filesrc location=./HelloTerrainMotion.flv ! decodebin ! \
  10.585 + videoscale ! ffmpegcolorspace ! \
  10.586 + video/x-raw-yuv, width=800, height=600, framerate=25/1 ! \
  10.587 + x264enc bitrate=1024 ! avimux ! \
  10.588 + filesink location=../youtube/HelloTerrain.avi 
  10.589 +
  10.590 +
  10.591 +gst-launch-0.10 \
  10.592 + filesrc location=./HelloAssetsStatic.flv ! decodebin ! \
  10.593 + videoscale ! ffmpegcolorspace ! \
  10.594 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.595 + videobox border-alpha=0 left=-640 ! \
  10.596 + videomixer name=mix ! ffmpegcolorspace ! videorate ! \
  10.597 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.598 +  x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
  10.599 +  filesink location=../youtube/HelloAssets.avi \
  10.600 + \
  10.601 + filesrc location=./HelloAssetsMotion.flv ! decodebin ! \
  10.602 + videoscale ! ffmpegcolorspace ! \
  10.603 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.604 + videobox right=-640 ! mix.
  10.605 +
  10.606 +
  10.607 +gst-launch-0.10 \
  10.608 + filesrc location=./HelloNodeStatic.flv ! decodebin ! \
  10.609 + videoscale ! ffmpegcolorspace ! \
  10.610 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.611 + videobox border-alpha=0 left=-640 ! \
  10.612 + videomixer name=mix ! ffmpegcolorspace ! videorate ! \
  10.613 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.614 +  x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
  10.615 +  filesink location=../youtube/HelloNode.avi \
  10.616 + \
  10.617 + filesrc location=./HelloNodeMotion.flv ! decodebin ! \
  10.618 + videoscale ! ffmpegcolorspace ! \
  10.619 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.620 + videobox right=-640 ! mix.
  10.621 +
  10.622 +gst-launch-0.10 \
  10.623 + filesrc location=./HelloLoopStatic.flv ! decodebin ! \
  10.624 + videoscale ! ffmpegcolorspace ! \
  10.625 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.626 + videobox border-alpha=0 left=-640 ! \
  10.627 + videomixer name=mix ! ffmpegcolorspace ! videorate ! \
  10.628 + video/x-raw-yuv, width=1280, height=480, framerate=25/1 ! \
  10.629 +  x264enc bitrate=1024 ! avimux ! progressreport update-freq=1 ! \
  10.630 +  filesink location=../youtube/HelloLoop.avi \
  10.631 + \
  10.632 + filesrc location=./HelloLoopMotion.flv ! decodebin ! \
  10.633 + videoscale ! ffmpegcolorspace ! \
  10.634 + video/x-raw-yuv, width=640, height=480, framerate=25/1 ! \
  10.635 + videobox right=-640 ! mix.
  10.636 +
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/org/cortex.org	Sun Oct 16 05:12:19 2011 -0700
    11.3 @@ -0,0 +1,1738 @@
    11.4 +#+title: Simulated Senses
    11.5 +#+author: Robert McIntyre
    11.6 +#+email: rlm@mit.edu
    11.7 +#+MATHJAX: align:"left" mathml:t path:"../aurellem/src/MathJax/MathJax.js"
    11.8 +#+STYLE: <link rel="stylesheet" type="text/css" href="../aurellem/src/css/aurellem.css"/>
    11.9 +#+BABEL: :exports both :noweb yes :cache no :mkdirp yes
   11.10 +#+INCLUDE: ../aurellem/src/templates/level-0.org
   11.11 +#+description: Simulating senses for AI research using JMonkeyEngine3
   11.12 +
   11.13 +* Background
   11.14 +Artificial Intelligence has tried and failed for more than half a
   11.15 +century to produce programs as flexible, creative, and “intelligent”
   11.16 +as the human mind itself. Clearly, we are still missing some important
   11.17 +ideas concerning intelligent programs or we would have strong AI
   11.18 +already. What idea could be missing?
   11.19 +
   11.20 +When Turing first proposed his famous “Turing Test” in the
   11.21 +groundbreaking paper [[./sources/turing.pdf][/Computing Machines and Intelligence/]], he gave
   11.22 +little importance to how a computer program might interact with the
   11.23 +world:
   11.24 +
   11.25 +#+BEGIN_QUOTE
   11.26 +\ldquo{}We need not be too concerned about the legs, eyes, etc. The example of
   11.27 +Miss Helen Keller shows that education can take place provided that
   11.28 +communication in both directions between teacher and pupil can take
   11.29 +place by some means or other.\rdquo{}
   11.30 +#+END_QUOTE
   11.31 +
   11.32 +And from the example of Hellen Keller he went on to assume that the
   11.33 +only thing a fledgling AI program could need by way of communication
   11.34 +is a teletypewriter. But Hellen Keller did possess vision and hearing
   11.35 +for the first few months of her life, and her tactile sense was far
   11.36 +more rich than any text-stream could hope to achieve. She possessed a
   11.37 +body she could move freely, and had continual access to the real world
   11.38 +to learn from her actions.
   11.39 +
   11.40 +I believe that our programs are suffering from too little sensory
   11.41 +input to become really intelligent. Imagine for a moment that you
   11.42 +lived in a world completely cut off form all sensory stimulation. You
   11.43 +have no eyes to see, no ears to hear, no mouth to speak. No body, no
   11.44 +taste, no feeling whatsoever. The only sense you get at all is a
   11.45 +single point of light, flickering on and off in the void. If this was
   11.46 +your life from birth, you would never learn anything, and could never
   11.47 +become intelligent. Actual humans placed in sensory deprivation
   11.48 +chambers experience hallucinations and can begin to loose their sense
   11.49 +of reality in as little as 15 minutes[sensory-deprivation]. Most of
   11.50 +the time, the programs we write are in exactly this situation. They do
   11.51 +not interface with cameras and microphones, and they do not control a
   11.52 +real or simulated body or interact with any sort of world.
   11.53 +
   11.54 +
   11.55 +* Simulation vs. Reality
   11.56 +I want demonstrate that multiple senses are what enable
   11.57 +intelligence. There are two ways of playing around with senses and
   11.58 +computer programs:
   11.59 +
   11.60 +The first is to go entirely with simulation: virtual world, virtual
   11.61 +character, virtual senses. The advantages are that when everything is
   11.62 +a simulation, experiments in that simulation are absolutely
   11.63 +reproducible. It's also easier to change the character and world to
   11.64 +explore new situations and different sensory combinations.
   11.65 +
   11.66 +
   11.67 +** Issues with Simulation
   11.68 +
   11.69 +If the world is to be simulated on a computer, then not only do you
   11.70 +have to worry about whether the character's senses are rich enough to
   11.71 +learn from the world, but whether the world itself is rendered with
   11.72 +enough detail and realism to give enough working material to the
   11.73 +character's senses. To name just a few difficulties facing modern
   11.74 +physics simulators: destructibility of the environment, simulation of
   11.75 +water/other fluids, large areas, nonrigid bodies, lots of objects,
   11.76 +smoke. I don't know of any computer simulation that would allow a
   11.77 +character to take a rock and grind it into fine dust, then use that
   11.78 +dust to make a clay sculpture, at least not without spending years
   11.79 +calculating the interactions of every single small grain of
   11.80 +dust. Maybe a simulated world with today's limitations doesn't provide
   11.81 +enough richness for real intelligence to evolve.
   11.82 +
   11.83 +** Issues with Reality
   11.84 +
   11.85 +The other approach for playing with senses is to hook your software up
   11.86 +to real cameras, microphones, robots, etc., and let it loose in the
   11.87 +real world. This has the advantage of eliminating concerns about
   11.88 +simulating the world at the expense of increasing the complexity of
   11.89 +implementing the senses. Instead of just grabbing the current rendered
   11.90 +frame for processing, you have to use an actual camera with real
   11.91 +lenses and interact with photons to get an image. It is much harder to
   11.92 +change the character, which is now partly a physical robot of some
   11.93 +sort, since doing so involves changing things around in the real world
   11.94 +instead of modifying lines of code. While the real world is very rich
   11.95 +and definitely provides enough stimulation for intelligence to develop
   11.96 +as evidenced by our own existence, it is also uncontrollable in the
   11.97 +sense that a particular situation cannot be recreated perfectly or
   11.98 +saved for later use. It is harder to conduct science because it is
   11.99 +harder to repeat an experiment. The worst thing about using the real
  11.100 +world instead of a simulation is the matter of time. Instead of
  11.101 +simulated time you get the constant and unstoppable flow of real
  11.102 +time. This severely limits the sorts of software you can use to
  11.103 +program the AI because all sense inputs must be handled in real
  11.104 +time. Complicated ideas may have to be implemented in hardware or may
  11.105 +simply be impossible given the current speed of our
  11.106 +processors. Contrast this with a simulation, in which the flow of time
  11.107 +in the simulated world can be slowed down to accommodate the
  11.108 +limitations of the character's programming. In terms of cost, doing
  11.109 +everything in software is far cheaper than building custom real-time
  11.110 +hardware. All you need is a laptop and some patience.
  11.111 +
  11.112 +* Choose a Simulation Engine
  11.113 +
  11.114 +Mainly because of issues with controlling the flow of time, I chose to
  11.115 +simulate both the world and the character. I set out to make a minimal
  11.116 +world in which I could embed a character with multiple senses. My main
  11.117 +goal is to make an environment where I can perform further experiments
  11.118 +in simulated senses.
  11.119 +
  11.120 +As Carl Sagan once said, "If you wish to make an apple pie from
  11.121 +scratch, you must first invent the universe.” I examined many
  11.122 +different 3D environments to try and find something I would use as the
  11.123 +base for my simulation; eventually the choice came down to three
  11.124 +engines: the Quake II engine, the Source Engine, and jMonkeyEngine.
  11.125 +
  11.126 +** Quake II/Jake2
  11.127 +
  11.128 +I spent a bit more than a month working with the Quake II Engine from
  11.129 +ID software to see if I could use it for my purposes. All the source
  11.130 +code was released by ID software into the Public Domain several years
  11.131 +ago, and as a result it has been ported and modified for many
  11.132 +different reasons. This engine was famous for its advanced use of
  11.133 +realistic shading and had decent and fast physics
  11.134 +simulation. Researchers at Princeton [[http://www.nature.com/nature/journal/v461/n7266/pdf/nature08499.pdf][used this code]] to study spatial
  11.135 +information encoding in the hippocampal cells of rats. Those
  11.136 +researchers created a special Quake II level that simulated a maze,
  11.137 +and added an interface where a mouse could run around inside a ball in
  11.138 +various directions to move the character in the simulated maze. They
  11.139 +measured hippocampal activity during this exercise to try and tease
  11.140 +out the method in which spatial data was stored in that area of the
  11.141 +brain. I find this promising because if a real living rat can interact
  11.142 +with a computer simulation of a maze in the same way as it interacts
  11.143 +with a real-world maze, then maybe that simulation is close enough to
  11.144 +reality that a simulated sense of vision and motor control interacting
  11.145 +with that simulation could reveal useful information about the real
  11.146 +thing. It happens that there is a Java port of the original C source
  11.147 +code called Jake2. The port demonstrates Java's OpenGL bindings and
  11.148 +runs anywhere from 90% to 105% as fast as the C version. After
  11.149 +reviewing much of the source of Jake2, I eventually rejected it
  11.150 +because the engine is too tied to the concept of a first-person
  11.151 +shooter game. One of the problems I had was that there does not seem
  11.152 +to be any easy way to attach multiple cameras to a single
  11.153 +character. There are also several physics clipping issues that are
  11.154 +corrected in a way that only applies to the main character and does
  11.155 +not apply to arbitrary objects. While there is a large community of
  11.156 +level modders, I couldn't find a community to support using the engine
  11.157 +to make new things.
  11.158 +
  11.159 +** Source Engine
  11.160 +
  11.161 +The Source Engine evolved from the Quake II and Quake I engines and is
  11.162 +used by Valve in the Half-Life series of games. The physics simulation
  11.163 +in the Source Engine is quite accurate and probably the best out of
  11.164 +all the engines I investigated. There is also an extensive community
  11.165 +actively working with the engine. However, applications that use the
  11.166 +Source Engine must be written in C++, the code is not open, it only
  11.167 +runs on Windows, and the tools that come with the SDK to handle models
  11.168 +and textures are complicated and awkward to use.
  11.169 +
  11.170 +** jMonkeyEngine
  11.171 +
  11.172 +jMonkeyEngine is a new library for creating games in Java. It uses
  11.173 +OpenGL to render to the screen and uses screengraphs to avoid drawing
  11.174 +things that do not appear on the screen. It has an active community
  11.175 +and several games in the pipeline. The engine was not built to serve
  11.176 +any particular game but is instead meant to be used for any 3D
  11.177 +game. After experimenting with each of these three engines and a few
  11.178 +others for about 2 months I settled on jMonkeyEngine. I chose it
  11.179 +because it had the most features out of all the open projects I looked
  11.180 +at, and because I could then write my code in Clojure, an
  11.181 +implementation of LISP that runs on the JVM.
  11.182 +
  11.183 +* Setup
  11.184 +
  11.185 +First, I checked out the source to jMonkeyEngine:
  11.186 +
  11.187 +#+srcname: checkout 
  11.188 +#+begin_src sh :results verbatim
  11.189 +svn checkout http://jmonkeyengine.googlecode.com/svn/trunk/engine jme3
  11.190 +#+end_src
  11.191 +
  11.192 +#+results: checkout
  11.193 +: Checked out revision 7975.
  11.194 +
  11.195 +
  11.196 +Building jMonkeyEngine is easy enough:
  11.197 +
  11.198 +#+srcname: build
  11.199 +#+begin_src sh :results verbatim
  11.200 +cd jme3
  11.201 +ant jar | tail -n 2
  11.202 +#+end_src
  11.203 +
  11.204 +#+results: build
  11.205 +: BUILD SUCCESSFUL
  11.206 +: Total time: 15 seconds
  11.207 +
  11.208 +
  11.209 +Also build the javadoc:
  11.210 +
  11.211 +#+srcname: javadoc
  11.212 +#+begin_src sh :results verbatim
  11.213 +cd jme3
  11.214 +ant javadoc | tail -n 2
  11.215 +#+end_src
  11.216 +
  11.217 +#+results: javadoc
  11.218 +: BUILD SUCCESSFUL
  11.219 +: Total time: 12 seconds
  11.220 +
  11.221 +Now, move the jars from the compilation into the project's lib folder.
  11.222 +
  11.223 +#+srcname: move-jars
  11.224 +#+begin_src sh :results verbatim
  11.225 +mkdir -p lib 
  11.226 +mkdir -p src
  11.227 +cp jme3/dist/jMonkeyEngine3.jar lib/
  11.228 +cp jme3/dist/lib/* lib/
  11.229 +ls lib
  11.230 +#+end_src
  11.231 +
  11.232 +#+results: move-jars
  11.233 +#+begin_example
  11.234 +eventbus-1.4.jar
  11.235 +jbullet.jar
  11.236 +jheora-jst-debug-0.6.0.jar
  11.237 +jinput.jar
  11.238 +jME3-jbullet.jar
  11.239 +jME3-lwjgl-natives.jar
  11.240 +jME3-testdata.jar
  11.241 +jME3-test.jar
  11.242 +jMonkeyEngine3.jar
  11.243 +j-ogg-oggd.jar
  11.244 +j-ogg-vorbisd.jar
  11.245 +lwjgl.jar
  11.246 +nifty-1.3.jar
  11.247 +nifty-default-controls-1.3.jar
  11.248 +nifty-examples-1.3.jar
  11.249 +nifty-lwjgl-renderer-1.3.jar
  11.250 +nifty-openal-soundsystem-1.0.jar
  11.251 +nifty-style-black-1.3.jar
  11.252 +nifty-style-grey-1.0.jar
  11.253 +noise-0.0.1-SNAPSHOT.jar
  11.254 +stack-alloc.jar
  11.255 +vecmath.jar
  11.256 +xmlpull-xpp3-1.1.4c.jar
  11.257 +#+end_example
  11.258 +
  11.259 +It's good to create a =assets= directory in the style that the
  11.260 +=AssetManager= will like.
  11.261 +
  11.262 +#+srcname: create-assets
  11.263 +#+begin_src sh :results verbatim
  11.264 +mkdir -p assets
  11.265 +mkdir -p assets/Interface
  11.266 +mkdir -p assets/Materials
  11.267 +mkdir -p assets/MatDefs
  11.268 +mkdir -p assets/Models
  11.269 +mkdir -p assets/Scenes
  11.270 +mkdir -p assets/Shaders
  11.271 +mkdir -p assets/Sounds
  11.272 +mkdir -p assets/Textures
  11.273 +tree -L 1 assets
  11.274 +#+end_src
  11.275 +
  11.276 +#+results: create-assets
  11.277 +#+begin_example
  11.278 +assets
  11.279 +|-- Interface
  11.280 +|-- MatDefs
  11.281 +|-- Materials
  11.282 +|-- Models
  11.283 +|-- Scenes
  11.284 +|-- Shaders
  11.285 +|-- Sounds
  11.286 +`-- Textures
  11.287 +
  11.288 +8 directories, 0 files
  11.289 +#+end_example
  11.290 +
  11.291 +
  11.292 +The java classpath should have all the jars contained in the =lib=
  11.293 +directory as well as the src directory.
  11.294 +
  11.295 +For example, here is the file I use to run my REPL for clojure.
  11.296 +
  11.297 +#+include: "~/swank-all" src sh :exports code
  11.298 +
  11.299 +The important thing here is that =cortex/lib/*=, =cortex/src=, and
  11.300 +=cortex/assets= appear on the classpath. (=cortex= is the base
  11.301 +directory of this project.)
  11.302 +
  11.303 +#+srcname: pwd
  11.304 +#+begin_src sh 
  11.305 +pwd
  11.306 +#+end_src
  11.307 +
  11.308 +#+results: pwd
  11.309 +: /home/r/cortex
  11.310 +
  11.311 +
  11.312 +* Simulation Base
  11.313 +  
  11.314 +** Imports
  11.315 +First, I'll import jme core classes. 
  11.316 +#+srcname: import
  11.317 +#+begin_src clojure :results silent
  11.318 +(ns cortex.import
  11.319 +  (:require swank.util.class-browse))
  11.320 +
  11.321 +(defn import-jme3 []
  11.322 +  (import '[com.jme3.system AppSettings JmeSystem]) 
  11.323 +  (import '[com.jme3.app Application SimpleApplication])
  11.324 +  (import 'com.jme3.material.Material)
  11.325 +  (import '[com.jme3.math Vector3f ColorRGBA Quaternion Transform])
  11.326 +  (import '[com.jme3.scene Node  Geometry])
  11.327 +  (import '[com.jme3.scene.shape Box Sphere Sphere$TextureMode])
  11.328 +  (import 'com.jme3.font.BitmapText)
  11.329 +  (import '[com.jme3.input KeyInput InputManager])
  11.330 +  (import '[com.jme3.input.controls
  11.331 +	    ActionListener AnalogListener KeyTrigger MouseButtonTrigger])
  11.332 +  (import '[com.jme3.asset AssetManager DesktopAssetManager] )
  11.333 +  (import '[com.jme3.asset.plugins HttpZipLocator ZipLocator])
  11.334 +  (import '[com.jme3.light PointLight DirectionalLight])
  11.335 +  (import '[com.jme3.animation AnimControl Skeleton Bone])
  11.336 +  (import '[com.jme3.bullet.collision.shapes
  11.337 +	    MeshCollisionShape SphereCollisionShape BoxCollisionShape])
  11.338 +  (import 'com.jme3.renderer.queue.RenderQueue$ShadowMode)
  11.339 +  (import 'jme3test.TestChooser)
  11.340 +  (import '[com.jme3.bullet PhysicsTickListener PhysicsSpace])
  11.341 +  (import '[com.jme3.bullet.joints SixDofJoint HingeJoint
  11.342 +	    SliderJoint Point2PointJoint ConeJoint]))
  11.343 +
  11.344 +
  11.345 +(defmacro permissive-import* [class-symbol]
  11.346 +  `(try
  11.347 +       (import ~class-symbol)
  11.348 +       (catch Exception e#
  11.349 +	 (println "can't import " ~class-symbol))))
  11.350 +
  11.351 +(defn permissive-import [class-symbol]
  11.352 +  (eval (list 'cortex.import/permissive-import* class-symbol)))
  11.353 +
  11.354 +(defn selection-import [selection-fn]
  11.355 +  (dorun
  11.356 +   (map (comp permissive-import symbol)
  11.357 +	(filter selection-fn
  11.358 +		(map :name
  11.359 +		     swank.util.class-browse/available-classes)))))
  11.360 +  
  11.361 +(defn mega-import-jme3
  11.362 +  "ALL the jme classes. For REPL use."
  11.363 +  []
  11.364 +  (selection-import
  11.365 +   #(and
  11.366 +     (.startsWith % "com.jme3.")
  11.367 +     ;; Don't import the Lwjgl stuff since it can throw exceptions
  11.368 +     ;; upon being loaded.
  11.369 +     (not (re-matches #".*Lwjgl.*" %)))))
  11.370 +#+end_src  
  11.371 +
  11.372 +The =mega-import-jme3= is quite usefull for debugging purposes since
  11.373 +it allows completion for almost all of JME's classes
  11.374 +
  11.375 +** Simplification
  11.376 +*** World
  11.377 +
  11.378 +It is comvienent to wrap the JME elements that deal with creating a
  11.379 +world, creation of basic objects, and Keyboard input with a nicer
  11.380 +interface (at least for my purposes).
  11.381 +
  11.382 +#+srcname: world-inputs
  11.383 +#+begin_src clojure :results silent
  11.384 +(ns cortex.world)
  11.385 +(require 'cortex.import)
  11.386 +(use 'clojure.contrib.def)
  11.387 +(rlm.rlm-commands/help)
  11.388 +(cortex.import/mega-import-jme3)
  11.389 +
  11.390 +(defvar *app-settings*
  11.391 +  (doto (AppSettings. true)
  11.392 +    (.setFullscreen false)
  11.393 +    (.setTitle "Aurellem.")
  11.394 +    ;; disable 32 bit stuff for now
  11.395 +    ;;(.setAudioRenderer "Send")
  11.396 +    )
  11.397 +  "These settings control how the game is displayed on the screen for
  11.398 +   debugging purposes.  Use binding forms to change this if desired.
  11.399 +   Full-screen mode does not work on some computers.")
  11.400 +
  11.401 +(defn asset-manager
  11.402 +  "returns a new, configured assetManager" []
  11.403 +  (JmeSystem/newAssetManager
  11.404 +   (.getResource
  11.405 +    (.getContextClassLoader (Thread/currentThread))
  11.406 +    "com/jme3/asset/Desktop.cfg")))
  11.407 +
  11.408 +(defmacro no-exceptions
  11.409 +  "Sweet relief like I never knew."
  11.410 +  [& forms]
  11.411 +  `(try ~@forms (catch Exception e# (.printStackTrace e#))))
  11.412 +
  11.413 +(defn thread-exception-removal []
  11.414 +  (println "removing exceptions from " (Thread/currentThread))
  11.415 +  (.setUncaughtExceptionHandler
  11.416 +   (Thread/currentThread)
  11.417 +   (proxy [Thread$UncaughtExceptionHandler] []
  11.418 +     (uncaughtException
  11.419 +      [thread thrown]
  11.420 +      (println "uncaught-exception thrown in " thread)
  11.421 +      (println (.getMessage thrown))))))
  11.422 +
  11.423 +(def println-repl (bound-fn [& args] (apply println args)))
  11.424 +
  11.425 +(use '[pokemon [lpsolve :only [constant-map]]])
  11.426 +
  11.427 +(defn no-op [& _])
  11.428 +
  11.429 +(defn all-keys
  11.430 +  "Construct a map of strings representing all the manual inputs from
  11.431 +   either the keyboard or mouse." 
  11.432 +  []
  11.433 +  (let [inputs (constant-map KeyInput)]
  11.434 +    (assoc
  11.435 +	(zipmap (map (fn [field]
  11.436 +		       (.toLowerCase (re-gsub #"_" "-" field))) (vals inputs))
  11.437 +		(map (fn [val] (KeyTrigger. val)) (keys inputs)))
  11.438 +      ;;explicitly add mouse controls
  11.439 +      "mouse-left" (MouseButtonTrigger. 0)
  11.440 +      "mouse-middle" (MouseButtonTrigger. 2)
  11.441 +      "mouse-right" (MouseButtonTrigger. 1))))
  11.442 +
  11.443 +(defn initialize-inputs
  11.444 +  "more java-interop cruft to establish keybindings for a particular virtual world"
  11.445 +  [game  input-manager key-map]
  11.446 +  (doall (map (fn [[name trigger]]
  11.447 +		(.addMapping ^InputManager input-manager
  11.448 +			     name (into-array (class trigger) [trigger]))) key-map))
  11.449 +  (doall (map (fn [name] 
  11.450 +		(.addListener ^InputManager input-manager game
  11.451 +			      (into-array String  [name]))) (keys key-map))))
  11.452 +
  11.453 +#+end_src
  11.454 +
  11.455 +These functions are all for debug controlling of the world through
  11.456 +keyboard and mouse. 
  11.457 +
  11.458 +We reuse  =constant-map= from =pokemon.lpsolve= to get the numerical
  11.459 +values for all the keys defined in the =KeyInput= class. The
  11.460 +documentation for =constant-map= is:
  11.461 +
  11.462 +#+begin_src clojure :results output
  11.463 +(doc pokemon.lpsolve/constant-map)
  11.464 +#+end_src
  11.465 +
  11.466 +#+results:
  11.467 +: -------------------------
  11.468 +: pokemon.lpsolve/constant-map
  11.469 +: ([class])
  11.470 +:   Takes a class and creates a map of the static constant integer
  11.471 +:   fields with their names.  This helps with C wrappers where they have
  11.472 +:   just defined a bunch of integer constants instead of enums
  11.473 +
  11.474 +
  11.475 +Then, =all-keys= converts the constant names like =KEY_J= to the more
  11.476 +clojure-like =key-j=, and returns a map from these keys to
  11.477 +jMonkeyEngine KeyTrigger objects, the use of which will soon become
  11.478 +apparent. =all-keys= also adds the three mouse button controls to the
  11.479 +map.
  11.480 +
  11.481 +#+srcname: world
  11.482 +#+begin_src clojure :results silent
  11.483 +(in-ns 'cortex.world)
  11.484 +
  11.485 +(defn traverse
  11.486 +  "apply f to every non-node, deeply"
  11.487 +  [f node]
  11.488 +  (if (isa? (class node) Node)
  11.489 +    (dorun (map (partial traverse f) (.getChildren node)))
  11.490 +    (f node)))
  11.491 +
  11.492 +(def gravity (Vector3f. 0 -9.81 0))
  11.493 +
  11.494 +(defn world
  11.495 +  [root-node key-map setup-fn update-fn]
  11.496 +  (let [physics-manager (BulletAppState.)
  11.497 +	shadow-renderer (BasicShadowRenderer. (asset-manager) (int 256))
  11.498 +	;;maybe use a better shadow renderer someday!
  11.499 +	;;shadow-renderer (PssmShadowRenderer. (asset-manager) 256 1)
  11.500 +	]   	
  11.501 +  (doto
  11.502 +      (proxy [SimpleApplication ActionListener] []
  11.503 +	(simpleInitApp
  11.504 +	 []
  11.505 +	 (no-exceptions
  11.506 +	  (.setTimer this (IsoTimer. 60))
  11.507 +	  ;; Create key-map.
  11.508 +	  (.setFrustumFar (.getCamera this) 300)
  11.509 +	  (initialize-inputs this (.getInputManager this) (all-keys))
  11.510 +	  ;; Don't take control of the mouse
  11.511 +	  (org.lwjgl.input.Mouse/setGrabbed false)
  11.512 +	  ;; add all objects to the world
  11.513 +	  (.attachChild (.getRootNode this) root-node)
  11.514 +	  ;; enable physics
  11.515 +	  ;; add a physics manager
  11.516 +	  (.attach (.getStateManager this) physics-manager)
  11.517 +	  (.setGravity (.getPhysicsSpace physics-manager) gravity)
  11.518 +
  11.519 +
  11.520 +	  ;; go through every object and add it to the physics manager
  11.521 +	  ;; if relavant.
  11.522 +	   (traverse (fn [geom]
  11.523 +		       (dorun
  11.524 +			(for [n (range (.getNumControls geom))]
  11.525 +			  (do
  11.526 +			    (println-repl "adding control " (.getControl geom n))
  11.527 +			    (.add (.getPhysicsSpace physics-manager)
  11.528 +				  (.getControl geom n))))))
  11.529 +		     (.getRootNode this))
  11.530 +	  ;;(.addAll (.getPhysicsSpace physics-manager) (.getRootNode this))
  11.531 +
  11.532 +	  (setup-fn this)
  11.533 +	  (.setDirection shadow-renderer
  11.534 +			 (.normalizeLocal (Vector3f. -1 -1 -1)))
  11.535 +	  (.addProcessor (.getViewPort this) shadow-renderer)
  11.536 +	  (.setShadowMode (.getRootNode this) RenderQueue$ShadowMode/Off)
  11.537 +	  ))
  11.538 +	(simpleUpdate
  11.539 +	 [tpf]
  11.540 +	 (no-exceptions
  11.541 +	  (update-fn this tpf))) 
  11.542 +	(onAction
  11.543 +	 [binding value tpf]
  11.544 +	 ;; whenever a key is pressed, call the function returned from
  11.545 +	 ;; key-map.
  11.546 +	 (no-exceptions
  11.547 +	  (if-let [react (key-map binding)]
  11.548 +	    (react this value)))))
  11.549 +    ;; don't show a menu to change options.
  11.550 +    
  11.551 +    (.setShowSettings false)
  11.552 +    (.setPauseOnLostFocus false)
  11.553 +    (.setSettings *app-settings*))))
  11.554 +
  11.555 +(defn apply-map
  11.556 +  "Like apply, but works for maps and functions that expect an implicit map
  11.557 +   and nothing else as in (fn [& {}]).
  11.558 +------- Example -------
  11.559 + (defn jjj [& {:keys [www] :or {www \"oph yeah\"} :as env}] (println www))
  11.560 + (apply-map jjj {:www \"whatever\"})
  11.561 +  -->\"whatever\""
  11.562 +  [fn m]
  11.563 +  (apply fn (reduce #(into %1 %2) [] m)))
  11.564 +
  11.565 +#+end_src 
  11.566 +
  11.567 +
  11.568 +=world= is the most important function here.  
  11.569 +***  TODO more documentation
  11.570 +
  11.571 +#+srcname: world-shapes
  11.572 +#+begin_src clojure :results silent
  11.573 +(in-ns 'cortex.world)
  11.574 +(defrecord shape-description
  11.575 +  [name
  11.576 +   color
  11.577 +   mass
  11.578 +   friction
  11.579 +   texture
  11.580 +   material
  11.581 +   position
  11.582 +   rotation
  11.583 +   shape
  11.584 +   physical?])
  11.585 +
  11.586 +(def base-shape
  11.587 +     (shape-description.
  11.588 +      "default-shape"
  11.589 +      false
  11.590 +      ;;ColorRGBA/Blue
  11.591 +      1.0 ;; mass
  11.592 +      1.0 ;; friction
  11.593 +      ;; texture
  11.594 +      "Textures/Terrain/BrickWall/BrickWall.jpg"
  11.595 +      ;; material
  11.596 +      "Common/MatDefs/Misc/Unshaded.j3md"
  11.597 +      Vector3f/ZERO
  11.598 +      Quaternion/IDENTITY
  11.599 +      (Box. Vector3f/ZERO 0.5 0.5 0.5)
  11.600 +      true))
  11.601 +
  11.602 +(defn make-shape
  11.603 +  [#^shape-description d]
  11.604 +  (let [mat (Material. (asset-manager) (:material d))
  11.605 +	geom (Geometry. (:name d) (:shape d))]
  11.606 +    (if (:texture d)
  11.607 +      (let [key (TextureKey. (:texture d))]
  11.608 +	(.setGenerateMips key true)
  11.609 +	(.setTexture mat "ColorMap" (.loadTexture (asset-manager) key))))
  11.610 +    (if (:color d) (.setColor mat "Color" (:color d)))
  11.611 +    (.setMaterial geom mat)
  11.612 +    (if-let [rotation (:rotation d)] (.rotate geom rotation))
  11.613 +    (.setLocalTranslation geom (:position d))
  11.614 +    (if (:physical? d)
  11.615 +      (let [impact-shape (doto (GImpactCollisionShape. (.getMesh geom)) (.setMargin 0))
  11.616 +	    physics-control (RigidBodyControl.
  11.617 +			     impact-shape 
  11.618 +			     (float (:mass d)))]
  11.619 +	(.createJmeMesh impact-shape)
  11.620 +	(.addControl geom physics-control)
  11.621 +	;;(.setSleepingThresholds physics-control (float 0) (float 0))
  11.622 +	(.setFriction physics-control (:friction d))))
  11.623 +    ;;the default is to keep this node in the physics engine forever.
  11.624 +    ;;these commands must come after the control is added to the geometry.
  11.625 +    ;;
  11.626 +    geom))
  11.627 +  
  11.628 +(defn box
  11.629 +  ([l w h & {:as options}]
  11.630 +     (let [options (merge base-shape options)]
  11.631 +       (make-shape (assoc options
  11.632 +		     :shape (Box. l w h)))))
  11.633 +  ([] (box 0.5 0.5 0.5)))
  11.634 +
  11.635 +(defn sphere
  11.636 +  ([r & {:as options}]
  11.637 +     (let [options (merge base-shape options)]
  11.638 +       (make-shape (assoc options
  11.639 +		     :shape (Sphere. 32 32 (float r)))))) 
  11.640 +  ([] (sphere 0.5)))
  11.641 +
  11.642 +(defn add-element [game node]
  11.643 +  (.addAll
  11.644 +   (.getPhysicsSpace
  11.645 +    (.getState
  11.646 +     (.getStateManager game)
  11.647 +     BulletAppState))
  11.648 +    node)
  11.649 +  (.attachChild (.getRootNode game) node))
  11.650 +
  11.651 +(defn set-gravity*
  11.652 +  [game gravity]
  11.653 +  (traverse
  11.654 +   (fn [geom]
  11.655 +     (if-let
  11.656 +	 [control (.getControl geom RigidBodyControl)]
  11.657 +       (do
  11.658 +	 (.setGravity control gravity)
  11.659 +	 (.applyImpulse control Vector3f/ZERO Vector3f/ZERO)
  11.660 +	 )))
  11.661 +   (.getRootNode game)))
  11.662 +
  11.663 +#+end_src
  11.664 +
  11.665 +These are convienence functions for creating JME objects and
  11.666 +manipulating a world.
  11.667 +
  11.668 +#+srcname: world-view
  11.669 +#+begin_src clojure :results silent
  11.670 +(in-ns 'cortex.world)
  11.671 +
  11.672 +(defprotocol Viewable
  11.673 +  (view [something]))
  11.674 +
  11.675 +(extend-type com.jme3.scene.Geometry
  11.676 +  Viewable
  11.677 +  (view [geo]
  11.678 +	(view (doto (Node.)(.attachChild geo)))))
  11.679 +
  11.680 +(extend-type com.jme3.scene.Node
  11.681 +  Viewable
  11.682 +  (view [node]
  11.683 +	(.start
  11.684 +	 (world node
  11.685 +		{}
  11.686 +		(fn [world]
  11.687 +		  (.enableDebug 
  11.688 +		   (.getPhysicsSpace
  11.689 +		    (.getState
  11.690 +		     (.getStateManager world)
  11.691 +		     BulletAppState))
  11.692 +		   (asset-manager))
  11.693 +		  (set-gravity* world Vector3f/ZERO)
  11.694 +;;		  (set-gravity* world (Vector3f. 0 (float -0.4) 0))
  11.695 +		  (let [sun (doto (DirectionalLight.)
  11.696 +			      (.setDirection (.normalizeLocal (Vector3f. 1 0 -2)))
  11.697 +			      (.setColor ColorRGBA/White))]
  11.698 +		    (.addLight (.getRootNode world) sun)))
  11.699 +		no-op))))
  11.700 +
  11.701 +(defn position-camera [game]
  11.702 +  (doto (.getCamera game)
  11.703 +    (.setLocation (Vector3f. 0 6 6))
  11.704 +    (.lookAt Vector3f/ZERO (Vector3f. 0 1 0))))
  11.705 +
  11.706 +#+end_src
  11.707 +
  11.708 +Here I make the =Viewable= protocol and extend it to JME's types.  Now
  11.709 +hello-world can be written as easily as:
  11.710 +
  11.711 +#+begin_src clojure :results silent
  11.712 +(cortex.world/view (cortex.world/box))
  11.713 +#+end_src
  11.714 +
  11.715 +** Hello
  11.716 +Here are the jmonkeyengine "Hello" programs translated to clojure.
  11.717 +*** Hello Simple App
  11.718 +Here is the hello world example for jme3 in clojure.
  11.719 +It's a more or less direct translation from the java source
  11.720 +from
  11.721 +http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_simpleapplication.
  11.722 +
  11.723 +Of note is the fact that since we don't have access to the
  11.724 +=AssetManager= via extendig =SimpleApplication=, we have to build one
  11.725 +ourselves. 
  11.726 +
  11.727 +#+srcname: hello-simple-app
  11.728 +#+begin_src clojure :results silent
  11.729 +(ns hello.hello-simple-app)
  11.730 +(require 'cortex.import)
  11.731 +(use 'clojure.contrib.def)
  11.732 +(rlm.rlm-commands/help)
  11.733 +(cortex.import/import-jme3)
  11.734 +(use 'cortex.world)
  11.735 +
  11.736 +
  11.737 +(def cube (Box. Vector3f/ZERO 1 1 1))
  11.738 +
  11.739 +(def geom (Geometry. "Box" cube))
  11.740 +
  11.741 +(def mat (Material. (asset-manager) "Common/MatDefs/Misc/Unshaded.j3md"))
  11.742 +
  11.743 +(.setColor mat "Color" ColorRGBA/Blue)
  11.744 +
  11.745 +(.setMaterial geom mat)
  11.746 +
  11.747 +(defn simple-app []
  11.748 +  (doto
  11.749 +      (proxy [SimpleApplication] []
  11.750 +	(simpleInitApp
  11.751 +	 []
  11.752 +	 ;; Don't take control of the mouse
  11.753 +	 (org.lwjgl.input.Mouse/setGrabbed false)
  11.754 +	 (.attachChild (.getRootNode this) geom)))
  11.755 +    ;; don't show a menu to change options.
  11.756 +    (.setShowSettings false)
  11.757 +    (.setPauseOnLostFocus false)
  11.758 +    (.setSettings *app-settings*)))
  11.759 +#+end_src
  11.760 +
  11.761 +Running this program will begin a new jMonkeyEngine game which
  11.762 +displays a single blue cube.
  11.763 +
  11.764 +#+begin_src clojure :exports code :results silent
  11.765 +(.start (hello.hello-simple-app/simple-app))
  11.766 +#+end_src
  11.767 +
  11.768 +#+caption: the simplest JME game.
  11.769 +[[./images/simple-app.jpg]]
  11.770 +
  11.771 +
  11.772 +
  11.773 +*** Hello Physics
  11.774 +From http://jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_physics
  11.775 +
  11.776 +#+srcname: brick-wall-header
  11.777 +#+begin_src clojure :results silent
  11.778 +(ns hello.brick-wall)
  11.779 +(require 'cortex.import)
  11.780 +(use 'clojure.contrib.def)
  11.781 +(rlm.rlm-commands/help)
  11.782 +(cortex.import/mega-import-jme3)
  11.783 +(use '[pokemon [lpsolve :only [constant-map]]])
  11.784 +(use 'cortex.world)
  11.785 +#+end_src
  11.786 +
  11.787 +#+srcname: brick-wall-body
  11.788 +#+begin_src clojure :results silent
  11.789 +(in-ns 'hello.brick-wall)
  11.790 +
  11.791 +(defn floor
  11.792 +  "make a sturdy, unmovable physical floor"
  11.793 +  []
  11.794 +  (box 20 1 20 :mass 0 :color false :position (Vector3f. 0 -2 0)))
  11.795 +
  11.796 +(def brick-length 0.48)
  11.797 +(def brick-width 0.24)
  11.798 +(def brick-height 0.12)
  11.799 +
  11.800 +
  11.801 +(defn brick* [position]
  11.802 +  (doto (box brick-length brick-height brick-width
  11.803 +	     :position position :name "brick"
  11.804 +	     :material "Common/MatDefs/Misc/Unshaded.j3md"
  11.805 +	     :texture "Textures/Terrain/BrickWall/BrickWall.jpg"
  11.806 +	     :mass 36)
  11.807 +    (->
  11.808 +     (.getMesh)
  11.809 +     (.scaleTextureCoordinates (Vector2f. 1 0.5)))
  11.810 +    ;;(.setShadowMode RenderQueue$ShadowMode/CastAndReceive)
  11.811 +    )
  11.812 +  )
  11.813 +
  11.814 +(defn inception-brick-wall
  11.815 +  "construct a physical brick wall"
  11.816 +  []
  11.817 +  (let [node (Node. "brick-wall")]
  11.818 +    (dorun
  11.819 +     (map (comp #(.attachChild node %) brick*)
  11.820 +	  (for
  11.821 +	      [x (range 15)
  11.822 +	       y (range 10)
  11.823 +	       z (range 1)]
  11.824 +	    (Vector3f.
  11.825 +	     (* brick-length x 1.03)
  11.826 +	     (* brick-width y y 10)
  11.827 +	     (* brick-height z)))))
  11.828 +    node))
  11.829 +
  11.830 +(defn gravity-toggle
  11.831 +  [new-value]
  11.832 +  (fn [game value]
  11.833 +    (println-repl "set gravity to " new-value)
  11.834 +    (if value
  11.835 +      (set-gravity* game new-value)
  11.836 +      (set-gravity* game gravity))))
  11.837 +
  11.838 +(defn fire-cannon-ball []
  11.839 +  (fn [game value]
  11.840 +    (if (not value)
  11.841 +      (let [camera (.getCamera game)
  11.842 +	    cannon-ball
  11.843 +	    (sphere  0.7 
  11.844 +		     :material "Common/MatDefs/Misc/Unshaded.j3md"
  11.845 +		     :texture "Textures/PokeCopper.jpg"
  11.846 +		     :position
  11.847 +		     (.add (.getLocation camera)
  11.848 +			   (.mult (.getDirection camera) (float 1)))
  11.849 +		     :mass 3)] ;200 0.05
  11.850 +	(.setShadowMode cannon-ball RenderQueue$ShadowMode/CastAndReceive)
  11.851 +	(.setLinearVelocity
  11.852 +	 (.getControl cannon-ball RigidBodyControl)
  11.853 +	 (.mult (.getDirection camera) (float 50))) ;50
  11.854 +	(add-element game cannon-ball)))))
  11.855 +
  11.856 +(defn floor* []
  11.857 +  (doto (box 10 0.1 5 :name "floor" ;10 0.1 5 ; 240 0.1 240
  11.858 +	     :material "Common/MatDefs/Misc/Unshaded.j3md"
  11.859 +	     :texture "Textures/Terrain/Pond/Pond.png"
  11.860 +	     :position (Vector3f. 0 -0.1 0 )
  11.861 +	     :mass 0)
  11.862 +    (->
  11.863 +     (.getMesh)
  11.864 +     (.scaleTextureCoordinates (Vector2f. 3 6)));64 64
  11.865 +    (->
  11.866 +     (.getMaterial)
  11.867 +     (.getTextureParam "ColorMap")
  11.868 +     (.getTextureValue)
  11.869 +     (.setWrap Texture$WrapMode/Repeat))
  11.870 +    (.setShadowMode RenderQueue$ShadowMode/Receive)
  11.871 +  ))
  11.872 +    
  11.873 +(defn brick-wall* []
  11.874 +  (let [node (Node. "brick-wall")]
  11.875 +    (dorun
  11.876 +     (map
  11.877 +      (comp  #(.attachChild node %) brick*)
  11.878 +       (for [y (range 15)
  11.879 +	     x (range 4)
  11.880 +	     z (range 1)]
  11.881 +       	    (Vector3f.
  11.882 +       	     (+ (* 2 x brick-length)
  11.883 +		(if (even? (+ y z)) 
  11.884 +		  (/ brick-length 4) (/ brick-length -4)))
  11.885 +       	     (+ (* brick-height (inc (* 2 y))))
  11.886 +	     (* 2 z brick-width) ))))
  11.887 +    (.setShadowMode node RenderQueue$ShadowMode/CastAndReceive)
  11.888 +    node))
  11.889 +
  11.890 +(defn brick-wall-game-run []
  11.891 +  (doto
  11.892 +      (world
  11.893 +       (doto (Node.) (.attachChild (floor*))
  11.894 +	     (.attachChild (brick-wall*))
  11.895 +	     )
  11.896 +       {"key-i" (gravity-toggle (Vector3f. 0 0 -9.81))
  11.897 +	"key-m" (gravity-toggle (Vector3f. 0 0 9.81))
  11.898 +	"key-l" (gravity-toggle (Vector3f. 9.81 0 0))
  11.899 +	"key-j" (gravity-toggle (Vector3f. -9.81 0 0))
  11.900 +	"key-k" (gravity-toggle Vector3f/ZERO)
  11.901 +	"key-u" (gravity-toggle (Vector3f. 0 9.81 0))
  11.902 +	"key-o" (gravity-toggle (Vector3f. 0 -9.81 0))
  11.903 +	"key-f" (fn[game value] 
  11.904 +		  (if (not value) (add-element game (brick-wall*))))
  11.905 +	"key-return" (fire-cannon-ball)}
  11.906 +       position-camera
  11.907 +       (fn [& _]))     
  11.908 +    (.start)))
  11.909 +#+end_src
  11.910 +
  11.911 +#+begin_src clojure :results silent
  11.912 +(hello.brick-wall/brick-wall-game-run)
  11.913 +#+end_src
  11.914 +
  11.915 +#+caption: the brick wall standing
  11.916 +[[./images/brick-wall-standing.jpg]]
  11.917 +
  11.918 +#+caption: the brick wall after it has been knocked over by a "pok\eacute{}ball"
  11.919 +[[./images/brick-wall-knocked-down.jpg]]
  11.920 +
  11.921 +*** Other Brick Games
  11.922 +#+srcname: other-games
  11.923 +#+begin_src clojure :results silent
  11.924 +(ns cortex.other-games
  11.925 +   {:author "Dylan Holmes"})
  11.926 +(use 'cortex.world)
  11.927 +(use 'hello.brick-wall)
  11.928 +(use 'cortex.import)
  11.929 +(cortex.import/mega-import-jme3)
  11.930 +
  11.931 +(defn scad [position]
  11.932 +  (doto (box 0.1 0.1 0.1
  11.933 +	     :position position :name "brick"
  11.934 +	     :material "Common/MatDefs/Misc/Unshaded.j3md"
  11.935 +	     :texture "Textures/Terrain/BrickWall/BrickWall.jpg"
  11.936 +	     :mass 20)
  11.937 +    (->
  11.938 +     (.getMesh)
  11.939 +     (.scaleTextureCoordinates (Vector2f. 1 0.5))
  11.940 +     )
  11.941 +        (->	(.getControl RigidBodyControl)
  11.942 +	(.setLinearVelocity (Vector3f. 0 100 0))
  11.943 +	)
  11.944 +	
  11.945 +    ;;(.setShadowMode RenderQueue$ShadowMode/Cast)
  11.946 +    ))
  11.947 +
  11.948 +
  11.949 +(defn shrapnel []
  11.950 +  (let [node (Node. "explosion-day")]
  11.951 +    (dorun
  11.952 +     (map
  11.953 +      (comp  #(.attachChild node %) scad)
  11.954 +       (for [y (range 15)
  11.955 +	     x (range 4)
  11.956 +	     z (range 1)]
  11.957 +       	    (Vector3f.
  11.958 +       	     (+ (* 2 x brick-height)
  11.959 +		(if (even? (+ y z)) (/ brick-height 4) (/ brick-height -4)))
  11.960 +       	     (+ (* brick-height (inc (* 2 y))))
  11.961 +	     (* 2 z brick-height) ))))
  11.962 +    node))
  11.963 +
  11.964 +
  11.965 +(def domino-height 0.48)
  11.966 +(def domino-thickness 0.12)
  11.967 +(def domino-width 0.24)
  11.968 +
  11.969 +(def domino-thickness 0.05)
  11.970 +(def domino-width 0.5)
  11.971 +(def domino-height 1)
  11.972 +
  11.973 +(defn domino
  11.974 +  ([position]
  11.975 +     (domino position (Quaternion/IDENTITY)))
  11.976 +  ([position rotation]
  11.977 +     (doto (box domino-width domino-height domino-thickness
  11.978 +	     :position position :name "domino"
  11.979 +	     :material "Common/MatDefs/Misc/Unshaded.j3md"
  11.980 +	     :texture "Textures/Terrain/BrickWall/BrickWall.jpg"
  11.981 +	     :mass 1
  11.982 +	     :rotation rotation)
  11.983 +       (.setShadowMode RenderQueue$ShadowMode/CastAndReceive)
  11.984 +       )))
  11.985 +
  11.986 +
  11.987 +(defn domino-row []
  11.988 +  (let [node (Node. "domino-row")]
  11.989 +    (dorun
  11.990 +     (map
  11.991 +      (comp  #(.attachChild node %) domino)
  11.992 +       (for [
  11.993 +	     z (range 10)
  11.994 +	     x (range 5)
  11.995 +	     ]
  11.996 +       	    (Vector3f.
  11.997 +	     (+ (* z domino-width) (* x 5 domino-width))
  11.998 +	     (/ domino-height 1)
  11.999 +	     (* -5.5 domino-thickness z) ))))
 11.1000 +
 11.1001 +    node))
 11.1002 +
 11.1003 +(defn domino-cycle []
 11.1004 +  (let [node (Node. "domino-cycle")]
 11.1005 +    (dorun
 11.1006 +     (map
 11.1007 +      (comp  #(.attachChild node %) (partial apply domino) ) 
 11.1008 +      (for [n (range 720)]
 11.1009 +	(let [space (* domino-height 5.5)
 11.1010 +	      r (fn[n] (* (+ n 3) domino-width 0.5)) 
 11.1011 +	      t (fn[n] (reduce
 11.1012 +			+
 11.1013 +			(map
 11.1014 +			 (fn dt[n] (/ space (* 2 (Math/PI) (r n))))
 11.1015 +			 (range n))))
 11.1016 +	      t (t n)
 11.1017 +	      r (r n)
 11.1018 +	      ct (Math/cos t)
 11.1019 +	      st (Math/sin t)
 11.1020 +	      ]
 11.1021 +	(list
 11.1022 +       	    (Vector3f.
 11.1023 +	     (* -1 r st)
 11.1024 +	     (/ domino-height 1)
 11.1025 +	     (* r ct))
 11.1026 +	    (.fromAngleAxis (Quaternion.)
 11.1027 +			    (- (/ 3.1415926 2) t) (Vector3f. 0 1 0))
 11.1028 +	    )))
 11.1029 +	))
 11.1030 +    node))
 11.1031 +
 11.1032 +
 11.1033 +(defn domino-game-run []
 11.1034 +  (doto
 11.1035 +      (world
 11.1036 +       (doto (Node.) (.attachChild (floor*))
 11.1037 +	     )
 11.1038 +       {"key-i" (gravity-toggle (Vector3f. 0 0 -9.81))
 11.1039 +	"key-m" (gravity-toggle (Vector3f. 0 0 9.81))
 11.1040 +	"key-l" (gravity-toggle (Vector3f. 9.81 0 0))
 11.1041 +	"key-j" (gravity-toggle (Vector3f. -9.81 0 0))
 11.1042 +	"key-k" (gravity-toggle (Vector3f. 0 9.81 0) )
 11.1043 +	"key-u" (fn[g v] ((gravity-toggle (Vector3f. 0 -0 0)) g true))
 11.1044 +	"key-o" (gravity-toggle (Vector3f. 0 -9.81 0))
 11.1045 +
 11.1046 +	"key-space"
 11.1047 +	(fn[game value]
 11.1048 +	  
 11.1049 +	  (if (not value)
 11.1050 +	    (let [d (domino (Vector3f. 0 (/ domino-height 0.25) 0)
 11.1051 +			    (.fromAngleAxis (Quaternion.)
 11.1052 +					    (/ Math/PI 2) (Vector3f. 0 1 0)))]
 11.1053 +	      (add-element game d))))
 11.1054 +	"key-f"
 11.1055 +	(fn[game value](if (not value) (add-element game (domino-cycle))))
 11.1056 +	"key-return" (fire-cannon-ball)}
 11.1057 +       position-camera
 11.1058 +       (fn [& _]))     
 11.1059 +    (.start)))       
 11.1060 +#+end_src
 11.1061 +
 11.1062 +#+begin_src clojure :results silent
 11.1063 +(cortex.other-games/domino-game-run)
 11.1064 +#+end_src
 11.1065 +
 11.1066 +#+caption: floating dominos
 11.1067 +[[./images/dominos.jpg]]
 11.1068 +
 11.1069 +*** Hello Loop
 11.1070 +#+srcname: hello-loop
 11.1071 +#+begin_src clojure :results silent
 11.1072 +(ns hello.loop)
 11.1073 +(use 'cortex.world)
 11.1074 +(use 'cortex.import)
 11.1075 +(cortex.import/mega-import-jme3)
 11.1076 +(rlm.rlm-commands/help)
 11.1077 +
 11.1078 +(defn blue-cube []
 11.1079 +  (box 1 1 1
 11.1080 +       :color ColorRGBA/Blue
 11.1081 +       :texture false
 11.1082 +       :material "Common/MatDefs/Misc/Unshaded.j3md"
 11.1083 +       :name "blue-cube"
 11.1084 +       :physical? false))
 11.1085 +
 11.1086 +(defn blue-cube-game []
 11.1087 +  (let [cube (blue-cube)
 11.1088 +	root (doto (Node.) (.attachChild cube))]
 11.1089 +  (world root
 11.1090 +	 {}
 11.1091 +	 no-op
 11.1092 +	 (fn [game tpf]
 11.1093 +	   (.rotate cube 0.0 (* 2 tpf) 0.0)))))	 	 		  
 11.1094 +#+end_src
 11.1095 +
 11.1096 +*** Hello Collision
 11.1097 +
 11.1098 +#+srcname: hello-collision
 11.1099 +#+begin_src clojure :results silent
 11.1100 +(ns hello.collision)
 11.1101 +(use 'cortex.world)
 11.1102 +(use 'cortex.import)
 11.1103 +(use 'clojure.contrib.def)
 11.1104 +
 11.1105 +
 11.1106 +(cortex.import/mega-import-jme3)
 11.1107 +(rlm.rlm-commands/help)
 11.1108 +(use '[hello [brick-wall :only [fire-cannon-ball brick-wall*]]])
 11.1109 +
 11.1110 +
 11.1111 +(defn environment []
 11.1112 +     (let
 11.1113 +	 [scene-model
 11.1114 +	  (doto
 11.1115 +	      (.loadModel
 11.1116 +	       (doto (asset-manager)
 11.1117 +		 (.registerLocator
 11.1118 +		  "/home/r/cortex/assets/zips/town.zip" ZipLocator))
 11.1119 +	       "main.scene")
 11.1120 +	    (.setLocalScale (float 2.0)))
 11.1121 +	  collision-shape
 11.1122 +	  (CollisionShapeFactory/createMeshShape #^Node scene-model)
 11.1123 +	  landscape (RigidBodyControl. collision-shape 0)]
 11.1124 +       (.setShadowMode scene-model RenderQueue$ShadowMode/CastAndReceive)
 11.1125 +       (.addControl scene-model landscape)
 11.1126 +       scene-model))
 11.1127 +	  
 11.1128 +(defn player-fn []
 11.1129 +  (doto
 11.1130 +      (CharacterControl.
 11.1131 +       (CapsuleCollisionShape. (float 1.5) (float 6)(float 1))
 11.1132 +       (float 0.05))
 11.1133 +    (.setJumpSpeed 20)
 11.1134 +    (.setFallSpeed 30)
 11.1135 +    (.setGravity 30) ;30
 11.1136 +    (.setPhysicsLocation (Vector3f. 0 10 0))))
 11.1137 +
 11.1138 +(defn lights []
 11.1139 +  [(doto (AmbientLight.) (.setColor (.mult (ColorRGBA. 1 1 1 1) (float 1))))
 11.1140 +   (doto (AmbientLight.) (.setColor (.mult (ColorRGBA. 1 0.7 0 1) (float 1))))
 11.1141 +   (doto (DirectionalLight.)
 11.1142 +     (.setColor (.mult ColorRGBA/White (float 0.9) ))
 11.1143 +     (.setDirection (.normalizeLocal (Vector3f. 2.8 -28 2.8))))])
 11.1144 +
 11.1145 +(defn night-lights []
 11.1146 +  [(doto (AmbientLight.) (.setColor (.mult (ColorRGBA. 0.275 0.467 0.784 1) (float 0.3))))
 11.1147 +   (doto (DirectionalLight.)
 11.1148 +     (.setColor (.mult ColorRGBA/White (float 0.2) ))
 11.1149 +     (.setDirection (.normalizeLocal (Vector3f. 2.8 -28 2.8))))])
 11.1150 +
 11.1151 +(def player (atom (player-fn)))
 11.1152 +
 11.1153 +(defn setup-fn [game]
 11.1154 +  (dorun (map #(.addLight (.getRootNode game) %) (lights)))
 11.1155 +  ;; set the color of the sky
 11.1156 +  (.setBackgroundColor (.getViewPort game) (ColorRGBA. 0.3 0.4 0.9 1))
 11.1157 +  ;(.setBackgroundColor (.getViewPort game) (ColorRGBA. 0 0 0 1)
 11.1158 +  (doto (.getFlyByCamera game)
 11.1159 +    (.setMoveSpeed (float 100))
 11.1160 +    (.setRotationSpeed 3))
 11.1161 +  (.add
 11.1162 +   (.getPhysicsSpace
 11.1163 +    (.getState (.getStateManager game) BulletAppState))
 11.1164 +   @player)
 11.1165 +
 11.1166 +   (doto (Node.) (.attachChild (.getRootNode game))
 11.1167 +	     (.attachChild (brick-wall*))
 11.1168 +   )
 11.1169 +
 11.1170 +)
 11.1171 +
 11.1172 +
 11.1173 +(def walking-up? (atom false))
 11.1174 +(def walking-down? (atom false))
 11.1175 +(def walking-left? (atom false))
 11.1176 +(def walking-right? (atom false))
 11.1177 +
 11.1178 +(defn set-walk [walk-atom game value]
 11.1179 +  ;;(println-repl "setting  stuff to " value)
 11.1180 +  (reset! walk-atom value))
 11.1181 +
 11.1182 +(defn responses []
 11.1183 +     {"key-w" (partial set-walk walking-up?)
 11.1184 +      "key-d" (partial set-walk walking-right?)
 11.1185 +      "key-s" (partial set-walk walking-down?)
 11.1186 +      "key-a" (partial set-walk walking-left?)
 11.1187 +      "key-return" (fire-cannon-ball)
 11.1188 +      "key-space" (fn [game value] (.jump @player))
 11.1189 +      })
 11.1190 +     
 11.1191 +(defn update-fn
 11.1192 +  [game tpf]
 11.1193 +  (let [camera (.getCamera game)         
 11.1194 +	cam-dir (.multLocal
 11.1195 +		 (.clone
 11.1196 +		  (.getDirection camera)) (float 0.6))
 11.1197 +	cam-left (.multLocal
 11.1198 +		  (.clone
 11.1199 +		   (.getLeft camera)) (float 0.4))
 11.1200 +	walk-direction (Vector3f. 0 0 0)]
 11.1201 +    
 11.1202 +    (cond
 11.1203 +     @walking-up?     (.addLocal walk-direction cam-dir)
 11.1204 +     @walking-right?  (.addLocal walk-direction (.negate cam-left))
 11.1205 +     @walking-down?   (.addLocal walk-direction (.negate cam-dir))
 11.1206 +     @walking-left?   (.addLocal walk-direction cam-left))
 11.1207 +    (.setWalkDirection @player walk-direction)
 11.1208 +    (.setLocation camera (.getPhysicsLocation @player))))
 11.1209 +    
 11.1210 +(defn run-game []
 11.1211 +  (.start
 11.1212 +   (world (environment)
 11.1213 +	  (responses)
 11.1214 +	  setup-fn
 11.1215 +	  update-fn)))
 11.1216 +#+end_src
 11.1217 +
 11.1218 +*** Hello Terrain
 11.1219 +#+srcname: hello-terrain
 11.1220 +#+begin_src clojure :results silent
 11.1221 +(ns hello.terrain)
 11.1222 +(use 'cortex.world)
 11.1223 +(use 'cortex.import)
 11.1224 +(use 'clojure.contrib.def)
 11.1225 +(import jme3tools.converters.ImageToAwt)
 11.1226 +
 11.1227 +
 11.1228 +(cortex.import/mega-import-jme3)
 11.1229 +(rlm.rlm-commands/help)
 11.1230 +(use '[hello [brick-wall :only [fire-cannon-ball brick-wall*]]])
 11.1231 +
 11.1232 +
 11.1233 +(defn setup-fn [type game]
 11.1234 +  (.setMoveSpeed (.getFlyByCamera game) 50)
 11.1235 +  (.setFrustumFar (.getCamera game) 10000)
 11.1236 +  (let [env (environment type)
 11.1237 +	cameras [(.getCamera game)]
 11.1238 +	control (TerrainLodControl. env cameras)]
 11.1239 +    ;;(.addControl env control)
 11.1240 +    (.attachChild (.getRootNode game) env)))                
 11.1241 +
 11.1242 +(defn environment [type]
 11.1243 +  (let
 11.1244 +      [mat_terrain
 11.1245 +       (Material. (asset-manager) "Common/MatDefs/Terrain/Terrain.j3md")
 11.1246 +       grass (.loadTexture (asset-manager) "Textures/Terrain/splat/grass.jpg")
 11.1247 +       dirt (.loadTexture (asset-manager) "Textures/Terrain/splat/dirt.jpg")
 11.1248 +       rock (.loadTexture (asset-manager) "Textures/Terrain/splat/road.jpg")
 11.1249 +       heightmap-image (.loadTexture (asset-manager)
 11.1250 +				     ({:mountain "Textures/Terrain/splat/mountains512.png"
 11.1251 +				       :fortress "Textures/Terrain/splat/fortress512.png"
 11.1252 +				       }type))
 11.1253 +       heightmap (ImageBasedHeightMap.
 11.1254 +		  (ImageToAwt/convert (.getImage heightmap-image) false true 0))
 11.1255 +       terrain (do (.load heightmap)
 11.1256 +		   (TerrainQuad. "my terrain" 65 513 (.getHeightMap heightmap)))
 11.1257 +       ]
 11.1258 +    
 11.1259 +    (dorun (map #(.setWrap % Texture$WrapMode/Repeat)
 11.1260 +		[grass dirt rock]))
 11.1261 +
 11.1262 +    (doto mat_terrain
 11.1263 +      (.setTexture "Tex1" grass)
 11.1264 +      (.setFloat "Tex1Scale" (float 64))
 11.1265 +
 11.1266 +      (.setTexture "Tex2" dirt)
 11.1267 +      (.setFloat "Tex2Scale" (float 32))
 11.1268 +
 11.1269 +      (.setTexture "Tex3" rock)
 11.1270 +      (.setFloat "Tex3Scale" (float 128))
 11.1271 +
 11.1272 +      (.setTexture "Alpha"
 11.1273 +		   (.loadTexture
 11.1274 +		    (asset-manager) 
 11.1275 +		    ({:mountain "Textures/Terrain/splat/alphamap.png"
 11.1276 +		      :fortress "Textures/Terrain/splat/alphamap2.png"} type))))
 11.1277 +
 11.1278 +    (doto terrain
 11.1279 +      (.setMaterial mat_terrain)
 11.1280 +      (.setLocalTranslation 0 -100 0)
 11.1281 +      (.setLocalScale 2 1 2))))
 11.1282 +      
 11.1283 +
 11.1284 +
 11.1285 +(defn run-terrain-game [type]
 11.1286 +  (.start
 11.1287 +   (world
 11.1288 +    (Node.)
 11.1289 +    {}
 11.1290 +    (partial setup-fn type)
 11.1291 +    no-op)))
 11.1292 +#+end_src
 11.1293 +
 11.1294 +
 11.1295 +
 11.1296 +#+srcname: hello-animation
 11.1297 +#+begin_src clojure :results silent
 11.1298 +(ns hello.animation)
 11.1299 +(use 'cortex.world)
 11.1300 +(use 'cortex.import)
 11.1301 +(use 'clojure.contrib.def)
 11.1302 +(cortex.import/mega-import-jme3)
 11.1303 +(rlm.rlm-commands/help)
 11.1304 +(use '[hello [collision :only [lights]]])
 11.1305 +
 11.1306 +(defn stand
 11.1307 +  [channel]
 11.1308 +  (doto channel
 11.1309 +    (.setAnim "stand" (float 0.5))
 11.1310 +    (.setLoopMode LoopMode/DontLoop)
 11.1311 +    (.setSpeed (float 1))))
 11.1312 +
 11.1313 +(defn anim-listener []
 11.1314 +     (proxy [AnimEventListener] []
 11.1315 +       (onAnimChange
 11.1316 +	[control channel animation-name]
 11.1317 +	(println-repl "RLM --- onAnimChange"))
 11.1318 +       (onAnimCycleDone
 11.1319 +	[control channel animation-name]
 11.1320 +	(if (= animation-name "Walk")
 11.1321 +	  (stand channel)
 11.1322 +	  ))))
 11.1323 +       
 11.1324 +(defn setup-fn [channel game]
 11.1325 +  (dorun (map #(.addLight (.getRootNode game) %) (lights)))
 11.1326 +  ;; set the color of the sky
 11.1327 +  (.setBackgroundColor (.getViewPort game) (ColorRGBA. 0.3 0.4 0.9 1))
 11.1328 +  ;(.setBackgroundColor (.getViewPort game) (ColorRGBA. 0 0 0 1)
 11.1329 +  (.setAnim channel "stand")
 11.1330 +  (doto (.getFlyByCamera game)
 11.1331 +    (.setMoveSpeed (float 10))
 11.1332 +    (.setRotationSpeed 1)))
 11.1333 +
 11.1334 +(defn walk [channel]
 11.1335 +  (println-repl "zzz")
 11.1336 +  (doto channel
 11.1337 +    (.setAnim "Walk" (float 0.5))
 11.1338 +    (.setLoopMode LoopMode/Loop)))
 11.1339 +    
 11.1340 +
 11.1341 +(defn key-map [channel]
 11.1342 +  {"key-space" (fn [game value]
 11.1343 +		 (if (not value)
 11.1344 +		   (walk channel)))})
 11.1345 +
 11.1346 +(defn player []
 11.1347 +  (let [model (.loadModel (asset-manager) "Models/Oto/Oto.mesh.xml")
 11.1348 +	control (.getControl model AnimControl)]
 11.1349 +    (.setLocalScale model (float 0.5))
 11.1350 +    (.clearListeners control)
 11.1351 +    (.addListener control (anim-control))
 11.1352 +    model))
 11.1353 +    
 11.1354 +
 11.1355 +
 11.1356 +(defn run-anim-game []
 11.1357 +  (let [ninja (player)
 11.1358 +	control  (.getControl ninja AnimControl)
 11.1359 +	channel (.createChannel control)]
 11.1360 +    (.start
 11.1361 +     (world
 11.1362 +      ninja
 11.1363 +      (key-map channel)
 11.1364 +      (partial setup-fn channel)
 11.1365 +      no-op))))
 11.1366 +#+end_src
 11.1367 +
 11.1368 +*** Hello Materials
 11.1369 +#+srcname: material
 11.1370 +#+begin_src clojure :results silent
 11.1371 +(ns hello.material)
 11.1372 +(use 'cortex.world)
 11.1373 +(use 'cortex.import)
 11.1374 +(use 'clojure.contrib.def)
 11.1375 +(cortex.import/mega-import-jme3)
 11.1376 +(rlm.rlm-commands/help)
 11.1377 +
 11.1378 +(defn simple-cube []
 11.1379 +  (box 1 1 1
 11.1380 +       :position (Vector3f. -3 1.1 0)
 11.1381 +       :material "Common/MatDefs/Misc/Unshaded.j3md"
 11.1382 +       :texture "Interface/Logo/Monkey.jpg"
 11.1383 +       :physical? false))
 11.1384 +
 11.1385 +(defn leaky-box []
 11.1386 +  (box 1 1 1
 11.1387 +       :position (Vector3f. 3 -1 0)
 11.1388 +       :material "Common/MatDefs/Misc/ColoredTextured.j3md"
 11.1389 +       :texture  "Textures/ColoredTex/Monkey.png"
 11.1390 +       :color    (ColorRGBA. 1 0 1 1)
 11.1391 +       :physical? false))
 11.1392 +
 11.1393 +(defn transparent-box []
 11.1394 +  (doto
 11.1395 +      (box 1 1 0.1
 11.1396 +	   :position Vector3f/ZERO
 11.1397 +	   :name "window frame"
 11.1398 +	   :material "Common/MatDefs/Misc/Unshaded.j3md"
 11.1399 +	   :texture "Textures/ColoredTex/Monkey.png"
 11.1400 +	   :physical? false)
 11.1401 +    (-> (.getMaterial)
 11.1402 +	(.getAdditionalRenderState)
 11.1403 +	(.setBlendMode RenderState$BlendMode/Alpha))
 11.1404 +    (.setQueueBucket RenderQueue$Bucket/Transparent)))
 11.1405 +                  
 11.1406 +(defn bumpy-sphere []
 11.1407 +  (doto 
 11.1408 +      (sphere 2
 11.1409 +	      :position (Vector3f. 0 2 -2)
 11.1410 +	      :name "Shiny rock"
 11.1411 +	      :material "Common/MatDefs/Light/Lighting.j3md"
 11.1412 +	      :texture false
 11.1413 +	      :physical? false)
 11.1414 +    (-> (.getMesh)
 11.1415 +	(doto 
 11.1416 +	  (.setTextureMode Sphere$TextureMode/Projected)
 11.1417 +	  (TangentBinormalGenerator/generate)))
 11.1418 +    (-> (.getMaterial)
 11.1419 +	(doto
 11.1420 +	  (.setTexture "DiffuseMap" (.loadTexture (asset-manager)
 11.1421 +						  "Textures/Terrain/Pond/Pond.png"))
 11.1422 +	  (.setTexture "NormalMap"  (.loadTexture (asset-manager)
 11.1423 +						  "Textures/Terrain/Pond/Pond_normal.png"))
 11.1424 +	  (.setFloat   "Shininess"  (float 5))))
 11.1425 +    (.rotate (float 1.6) 0 0)))
 11.1426 +
 11.1427 +
 11.1428 +(defn start-game []
 11.1429 +  (.start
 11.1430 +   (world
 11.1431 +    (let [root  (Node.)]
 11.1432 +      (dorun (map #(.attachChild root %)
 11.1433 +		  [(simple-cube) (leaky-box) (transparent-box) (bumpy-sphere)]))
 11.1434 +      root)
 11.1435 +    {}
 11.1436 +    (fn [world]
 11.1437 +      (let [sun (doto (DirectionalLight.)
 11.1438 +		  (.setDirection (.normalizeLocal (Vector3f. 1 0 -2)))
 11.1439 +		  (.setColor ColorRGBA/White))]
 11.1440 +	(.addLight (.getRootNode world) sun)))
 11.1441 +    no-op 
 11.1442 +    )))
 11.1443 +#+end_src
 11.1444 +
 11.1445 +
 11.1446 +    
 11.1447 +* The Body
 11.1448 +** Eyes
 11.1449 +
 11.1450 +Ultimately I want to make creatures with eyes. Each eye can be
 11.1451 +independely moved and should see its own version of the world
 11.1452 +depending on where it is.
 11.1453 +#+srcname: eyes
 11.1454 +#+begin_src clojure 
 11.1455 +(ns body.eye)
 11.1456 +(use 'cortex.world)
 11.1457 +(use 'cortex.import)
 11.1458 +(use 'clojure.contrib.def)
 11.1459 +(cortex.import/mega-import-jme3)
 11.1460 +(rlm.rlm-commands/help)
 11.1461 +(import java.nio.ByteBuffer)
 11.1462 +(import java.awt.image.BufferedImage)
 11.1463 +(import java.awt.Color)
 11.1464 +(import java.awt.Dimension)
 11.1465 +(import java.awt.Graphics)
 11.1466 +(import java.awt.Graphics2D)
 11.1467 +(import java.awt.event.WindowAdapter)
 11.1468 +(import java.awt.event.WindowEvent)
 11.1469 +(import java.awt.image.BufferedImage)
 11.1470 +(import java.nio.ByteBuffer)
 11.1471 +(import javax.swing.JFrame)
 11.1472 +(import javax.swing.JPanel)
 11.1473 +(import javax.swing.SwingUtilities)
 11.1474 +(import javax.swing.ImageIcon)
 11.1475 +(import javax.swing.JOptionPane)
 11.1476 +(import java.awt.image.ImageObserver)
 11.1477 +
 11.1478 +
 11.1479 +
 11.1480 +(defn scene-processor
 11.1481 +  "deals with converting FrameBuffers to BufferedImages so
 11.1482 +   that the continuation function can be defined only in terms
 11.1483 +   of what it does with BufferedImages"
 11.1484 +  [continuation]
 11.1485 +  (let [byte-buffer (atom nil)
 11.1486 +	renderer (atom nil)
 11.1487 +	image (atom nil)]
 11.1488 +  (proxy [SceneProcessor] []
 11.1489 +    (initialize
 11.1490 +     [renderManager viewPort]
 11.1491 +     (let [cam (.getCamera viewPort)
 11.1492 +	   width (.getWidth cam)
 11.1493 +	   height (.getHeight cam)]
 11.1494 +       (reset! renderer (.getRenderer renderManager))
 11.1495 +       (reset! byte-buffer
 11.1496 +	     (BufferUtils/createByteBuffer
 11.1497 +	      (* width height 4)))
 11.1498 +       (reset! image (BufferedImage. width height
 11.1499 +				     BufferedImage/TYPE_4BYTE_ABGR))))
 11.1500 +    (isInitialized [] (not (nil? @byte-buffer)))
 11.1501 +    (reshape [_ _ _])
 11.1502 +    (preFrame [_])
 11.1503 +    (postQueue [_])
 11.1504 +    (postFrame
 11.1505 +     [#^FrameBuffer fb]
 11.1506 +     (.clear @byte-buffer)
 11.1507 +     (.readFrameBuffer @renderer fb @byte-buffer)
 11.1508 +     (Screenshots/convertScreenShot @byte-buffer @image)
 11.1509 +     (continuation @image))
 11.1510 +    (cleanup []))))
 11.1511 +    
 11.1512 +(defn add-eye
 11.1513 +  "Add an eye to the world, and call continuation on
 11.1514 +   every frame produced"
 11.1515 +  [world camera continuation]
 11.1516 +  (let [width (.getWidth camera)
 11.1517 +	height (.getHeight camera)
 11.1518 +	render-manager (.getRenderManager world)
 11.1519 +	viewport (.createMainView render-manager "eye-view" camera)]
 11.1520 +    (doto viewport
 11.1521 +      (.setBackgroundColor ColorRGBA/Black)
 11.1522 +      (.setClearFlags true true true)
 11.1523 +      (.addProcessor (scene-processor continuation))
 11.1524 +      (.attachScene (.getRootNode world)))))
 11.1525 +
 11.1526 +(defn make-display-frame [display width height]
 11.1527 +  (SwingUtilities/invokeLater
 11.1528 +   (fn []
 11.1529 +     (.setPreferredSize display (Dimension. width height))
 11.1530 +     (doto (JFrame. "Eye Camera!")
 11.1531 +       (-> (.getContentPane) (.add display))
 11.1532 +       (.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE)
 11.1533 +       (.pack)
 11.1534 +       (.setLocationRelativeTo nil)
 11.1535 +       (.setResizable false)
 11.1536 +       (.setVisible true)))))
 11.1537 +	   
 11.1538 +(defn image-monitor [#^BufferedImage image]
 11.1539 +  (proxy [JPanel] []
 11.1540 +    (paintComponent 
 11.1541 +     [g]
 11.1542 +     (proxy-super paintComponent g)
 11.1543 +     (locking image
 11.1544 +       (.drawImage g image 0 0
 11.1545 +		   (proxy [ImageObserver]
 11.1546 +		       []
 11.1547 +		     (imageUpdate
 11.1548 +		      []
 11.1549 +		      (proxy-super imageUpdate))))))))
 11.1550 +
 11.1551 +(defn movie-image []
 11.1552 +  (let [setup
 11.1553 +	(runonce
 11.1554 +	 (fn [#^BufferedImage image]
 11.1555 +	   (let [width (.getWidth image)
 11.1556 +		 height (.getHeight image)
 11.1557 +		 display (image-monitor image)
 11.1558 +		 frame (make-display-frame display width height)]
 11.1559 +	     display)))]
 11.1560 +    (fn [#^BufferedImage image]
 11.1561 +      (.repaint (setup image)))))
 11.1562 +	     
 11.1563 +
 11.1564 +(defn observer
 11.1565 +  "place thy eye!"
 11.1566 +  [world camera]
 11.1567 +  (let [eye camera
 11.1568 +	width (.getWidth eye)
 11.1569 +	height (.getHeight eye)]
 11.1570 +    (no-exceptions
 11.1571 +     (add-eye
 11.1572 +      world
 11.1573 +      eye
 11.1574 +      (movie-image)))))
 11.1575 +#+end_src
 11.1576 +
 11.1577 +#+srcname: test-vision
 11.1578 +#+begin_src clojure
 11.1579 +
 11.1580 +(ns test.vision)
 11.1581 +(use 'cortex.world)
 11.1582 +(use 'cortex.import)
 11.1583 +(use 'clojure.contrib.def)
 11.1584 +(use 'body.eye)
 11.1585 +(cortex.import/mega-import-jme3)
 11.1586 +(rlm.rlm-commands/help)
 11.1587 +(import java.nio.ByteBuffer)
 11.1588 +(import java.awt.image.BufferedImage)
 11.1589 +(import java.awt.Color)
 11.1590 +(import java.awt.Dimension)
 11.1591 +(import java.awt.Graphics)
 11.1592 +(import java.awt.Graphics2D)
 11.1593 +(import java.awt.event.WindowAdapter)
 11.1594 +(import java.awt.event.WindowEvent)
 11.1595 +(import java.awt.image.BufferedImage)
 11.1596 +(import java.nio.ByteBuffer)
 11.1597 +(import javax.swing.JFrame)
 11.1598 +(import javax.swing.JPanel)
 11.1599 +(import javax.swing.SwingUtilities)
 11.1600 +(import javax.swing.ImageIcon)
 11.1601 +(import javax.swing.JOptionPane)
 11.1602 +(import java.awt.image.ImageObserver)
 11.1603 +
 11.1604 +
 11.1605 +(def width 200)
 11.1606 +(def height 200)
 11.1607 +
 11.1608 +(defn camera []
 11.1609 +  (doto (Camera. width height)
 11.1610 +    (.setFrustumPerspective 45 1 1 1000)
 11.1611 +    (.setLocation (Vector3f. -3 0 -5))
 11.1612 +    (.lookAt Vector3f/ZERO Vector3f/UNIT_Y)))
 11.1613 +
 11.1614 +(defn camera2 []
 11.1615 +  (doto (Camera. width height)
 11.1616 +    (.setFrustumPerspective 45 1 1 1000)
 11.1617 +    (.setLocation (Vector3f. 3 0 -5))
 11.1618 +    (.lookAt Vector3f/ZERO Vector3f/UNIT_Y)))
 11.1619 +
 11.1620 +(defn setup-fn [world]
 11.1621 +  (let [eye (camera)
 11.1622 +	width (.getWidth eye)
 11.1623 +	height (.getHeight eye)]
 11.1624 +    (no-exceptions
 11.1625 +     (add-eye
 11.1626 +      world
 11.1627 +      eye
 11.1628 +      (runonce visual))
 11.1629 +     (add-eye
 11.1630 +      world
 11.1631 +      (camera2)
 11.1632 +      (runonce visual)))))
 11.1633 +
 11.1634 +(defn spider-eye [position]
 11.1635 +  (doto (Camera. 200 200 )
 11.1636 +    (.setFrustumPerspective 45 1 1 1000)
 11.1637 +    (.setLocation position)
 11.1638 +    (.lookAt Vector3f/ZERO Vector3f/UNIT_Y)))
 11.1639 +  
 11.1640 +(defn setup-fn* [world]
 11.1641 +  (let [eye (camera)
 11.1642 +	width (.getWidth eye)
 11.1643 +	height (.getHeight eye)]
 11.1644 +    ;;(.setClearFlags (.getViewPort world) true true true)
 11.1645 +    (observer world (.getCamera world))
 11.1646 +    (observer world (spider-eye (Vector3f.  3  0 -5)))
 11.1647 +    ;;(observer world (spider-eye (Vector3f.  0  0 -5)))
 11.1648 +    ;; (observer world (spider-eye (Vector3f. -3  0 -5)))
 11.1649 +    ;; (observer world (spider-eye (Vector3f.  0  3 -5)))
 11.1650 +    ;; (observer world (spider-eye (Vector3f.  0 -3 -5)))
 11.1651 +    ;; (observer world (spider-eye (Vector3f.  3  3 -5)))
 11.1652 +    ;; (observer world (spider-eye (Vector3f. -3  3 -5)))
 11.1653 +    ;; (observer world (spider-eye (Vector3f.  3 -3 -5)))
 11.1654 +    ;; (observer world (spider-eye (Vector3f. -3 -3 -5)))
 11.1655 +
 11.1656 +    )
 11.1657 +  world)
 11.1658 +
 11.1659 +(defn test-world []
 11.1660 +  (let [thing (box 1 1 1 :physical? false)]
 11.1661 +    (world
 11.1662 +     (doto (Node.)
 11.1663 +       (.attachChild thing))
 11.1664 +     {}
 11.1665 +     setup-fn
 11.1666 +     (fn [world tpf]
 11.1667 +       (.rotate thing (* tpf 0.2) 0 0)
 11.1668 +       ))))
 11.1669 +
 11.1670 +
 11.1671 +#+end_src
 11.1672 +
 11.1673 +
 11.1674 +#+results: eyes
 11.1675 +: #'body.eye/test-world
 11.1676 +
 11.1677 +Note the use of continuation passing style for connecting the eye to a
 11.1678 +function to process the output. The example code will create two
 11.1679 +videos of the same rotating cube from different angles, sutiable for
 11.1680 +stereoscopic vision.
 11.1681 +
 11.1682 +
 11.1683 +
 11.1684 +
 11.1685 +
 11.1686 +
 11.1687 +* COMMENT code generation
 11.1688 +#+begin_src clojure :tangle ../src/cortex/import.clj
 11.1689 +<<import>>
 11.1690 +#+end_src
 11.1691 +
 11.1692 +#+begin_src clojure :tangle ../src/hello/brick_wall.clj
 11.1693 +<<brick-wall-header>>
 11.1694 +<<brick-wall-body>>
 11.1695 +#+end_src
 11.1696 +
 11.1697 +#+begin_src clojure :tangle ../src/hello/hello_simple_app.clj
 11.1698 +<<hello-simple-app>>
 11.1699 +#+end_src
 11.1700 +  
 11.1701 +#+begin_src clojure :tangle ../src/cortex/world.clj
 11.1702 +<<world-inputs>>
 11.1703 +<<world>>
 11.1704 +<<world-shapes>>
 11.1705 +<<world-view>>
 11.1706 +#+end_src
 11.1707 +
 11.1708 +#+begin_src clojure :tangle ../src/cortex/other_games.clj
 11.1709 +<<other-games>>
 11.1710 +#+end_src
 11.1711 +
 11.1712 +#+begin_src clojure :tangle ../src/hello/loop.clj
 11.1713 +<<hello-loop>>
 11.1714 +#+end_src
 11.1715 +
 11.1716 +#+begin_src clojure :tangle ../src/hello/collision.clj
 11.1717 +<<hello-collision>>
 11.1718 +#+end_src
 11.1719 +
 11.1720 +#+begin_src clojure :tangle ../src/hello/terrain.clj
 11.1721 +<<hello-terrain>>
 11.1722 +#+end_src
 11.1723 +
 11.1724 +#+begin_src clojure :tangle ../src/hello/animation.clj
 11.1725 +<<hello-animation>>
 11.1726 +#+end_src
 11.1727 +
 11.1728 +#+begin_src clojure :tangle ../src/hello/material.clj
 11.1729 +<<material>>
 11.1730 +#+end_src
 11.1731 +
 11.1732 +#+begin_src clojure :tangle ../src/body/eye.clj
 11.1733 +<<eyes>>
 11.1734 +#+end_src
 11.1735 +
 11.1736 +#+begin_src clojure :tangle ../src/test/vision.clj
 11.1737 +<<test-vision>>
 11.1738 +#+end_src
 11.1739 +
 11.1740 +  
 11.1741 +
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/org/skin.org	Sun Oct 16 05:12:19 2011 -0700
    12.3 @@ -0,0 +1,322 @@
    12.4 +#+title: SKIN!
    12.5 +#+author: Robert McIntyre
    12.6 +#+email: rlm@mit.edu
    12.7 +#+MATHJAX: align:"left" mathml:t path:"../aurellem/src/MathJax/MathJax.js"
    12.8 +#+STYLE: <link rel="stylesheet" type="text/css" href="../aurellem/src/css/aurellem.css"/>
    12.9 +#+BABEL: :exports both :noweb yes :cache no :mkdirp yes
   12.10 +#+INCLUDE: ../aurellem/src/templates/level-0.org
   12.11 +#+description: Simulating touch in JMonkeyEngine
   12.12 +
   12.13 +
   12.14 +
   12.15 +
   12.16 +* skin!
   12.17 +
   12.18 +#+srcname: skin-main
   12.19 +#+begin_src clojure
   12.20 +(ns body.skin)
   12.21 +(use 'cortex.world)
   12.22 +(use 'cortex.import)
   12.23 +(use 'clojure.contrib.def)
   12.24 +(cortex.import/mega-import-jme3)
   12.25 +(rlm.rlm-commands/help)
   12.26 +
   12.27 +(import java.util.logging.Level)
   12.28 +(import java.util.logging.Logger)
   12.29 +
   12.30 +
   12.31 +
   12.32 +;; looks like we can use GhostControls for implementing touch.
   12.33 +;; for example:
   12.34 +(def rc (GhostControl. (BoxCollisionShape. (Vector3f. 2 2 2))))
   12.35 +(def shifted-sphere
   12.36 +     (doto (CompoundCollisionShape.)
   12.37 +       (.addChildShape (SphereCollisionShape. 3) (Vector3f. 1 0 0))))
   12.38 +
   12.39 +(def gc (GhostControl. shifted-sphere))
   12.40 +(def b (box 1 1 1 :mass 1))
   12.41 +(.addControl b rc)
   12.42 +(.addControl b gc)
   12.43 +
   12.44 +
   12.45 +(defn looksies! []
   12.46 +  (view b))
   12.47 +
   12.48 +;; overlapping objects can be gotten via =.getOverlappingCount= and
   12.49 +;; =.getOverlappingObjects=
   12.50 +
   12.51 +;; looks like I might be able to place a small "touch-sphere" whther
   12.52 +;; on every triangle in the object's  mesh, or at the verticies, using
   12.53 +;; .getTriangleCount() on the mesh gotten by .getMesh()
   12.54 +
   12.55 +;; this way, I can create a mesh and just divide up it's faces using
   12.56 +;; blender, and this will create the touch sensor distribution.
   12.57 +
   12.58 +
   12.59 +(defn make-touch-sphere [#^Geometry geom]
   12.60 +  (let [tri (Triangle.)
   12.61 +	mesh (.getMesh geom)
   12.62 +	controls! (transient [])]
   12.63 +    (dorun
   12.64 +     (for [n (range (.getTriangleCount mesh))]
   12.65 +       (do
   12.66 +	 (.getTriangle mesh n tri)
   12.67 +	 (.calculateCenter tri)
   12.68 +	 (let [control 
   12.69 +	       (doto
   12.70 +		   (GhostControl.
   12.71 +		    (doto (CompoundCollisionShape.)
   12.72 +		      (.addChildShape
   12.73 +		       (SphereCollisionShape. (float 0.1))
   12.74 +		       (.mult (.getCenter tri) (float 1)))
   12.75 +		      (.setMargin -0.1)))
   12.76 +		 (.setApplyPhysicsLocal true))]
   12.77 +		  
   12.78 +	   (.addControl geom control)
   12.79 +	   (conj! controls! control)))))
   12.80 +    (persistent! controls!)))
   12.81 +	 
   12.82 +
   12.83 +(defn make-touch [#^Geometry geom]
   12.84 +  (let [tri (Triangle.)
   12.85 +	mesh (.getMesh geom)
   12.86 +	controls! (transient [])]
   12.87 +    (dorun
   12.88 +     (for [n (range (.getTriangleCount mesh))]
   12.89 +       (do
   12.90 +	 (.getTriangle mesh n tri)
   12.91 +	 (.calculateCenter tri)
   12.92 +	 (.calculateNormal tri)
   12.93 +	 (println-repl tri)
   12.94 +	 (println-repl (.get1 tri))
   12.95 +	 (println-repl (.get2 tri))
   12.96 +	 (println-repl (.get3 tri))
   12.97 +	 (println-repl (.getCenter tri))
   12.98 +	 (println-repl (.getNormal tri))
   12.99 +	 (let [control
  12.100 +	       (doto 
  12.101 +		   (GhostControl.
  12.102 +		    
  12.103 +		     (doto (CompoundCollisionShape.)
  12.104 +		       (.addChildShape
  12.105 +		        (SimplexCollisionShape. Vector3f/ZERO)
  12.106 +			(.mult (.getCenter tri) (float 1)))		    
  12.107 +		      (.setMargin 0)
  12.108 +		      ))
  12.109 +		 (.setApplyPhysicsLocal true))]
  12.110 +
  12.111 +	   (.addControl geom control)
  12.112 +	   (conj! controls! control)))))
  12.113 +    (persistent! controls!)))
  12.114 +
  12.115 +(defn make-fucked-touch [#^Geometry geom]
  12.116 +  (let [tri (Triangle.)
  12.117 +	mesh (.getMesh geom)
  12.118 +	controls! (transient [])]
  12.119 +    (dorun
  12.120 +     (for [n (range (.getTriangleCount mesh))]
  12.121 +       (do
  12.122 +	 (.getTriangle mesh n tri)
  12.123 +	 (.calculateCenter tri)
  12.124 +	 (.calculateNormal tri)
  12.125 +	 (println-repl tri)
  12.126 +	 (println-repl (.get1 tri))
  12.127 +	 (println-repl (.get2 tri))
  12.128 +	 (println-repl (.get3 tri))
  12.129 +	 (println-repl (.getCenter tri))
  12.130 +	 (println-repl (.getNormal tri))
  12.131 +	 (let [control1
  12.132 +	       (doto 
  12.133 +		   (GhostControl.
  12.134 +		    (doto (CompoundCollisionShape.)
  12.135 +		       (.addChildShape
  12.136 +		        (SimplexCollisionShape. Vector3f/ZERO)
  12.137 +		       (.get1 tri))))
  12.138 +		 (.setApplyPhysicsLocal true))]
  12.139 +
  12.140 +	   (.addControl geom control1)
  12.141 +	   (conj! controls! control1)
  12.142 +	   )
  12.143 +	 
  12.144 +	 ;; (let [control1
  12.145 +	 ;;       (doto 
  12.146 +	 ;; 	   (GhostControl.
  12.147 +	 ;; 	    (doto (CompoundCollisionShape.)
  12.148 +	 ;; 	      (.addChildShape
  12.149 +	 ;; 	       (SimplexCollisionShape. Vector3f/ZERO)
  12.150 +	 ;; 	      (.get2 tri))))
  12.151 +	 ;; 	 (.setApplyPhysicsLocal true))]
  12.152 +	   
  12.153 +	 ;;   (.addControl geom control1)
  12.154 +	 ;;   (conj! controls! control1)
  12.155 +	 ;;   )
  12.156 +	 
  12.157 +	 ;; (let [control1
  12.158 +	 ;;       (doto 
  12.159 +	 ;; 	   (GhostControl.
  12.160 +	 ;; 	    (doto (CompoundCollisionShape.)
  12.161 +	 ;; 	       (.addChildShape
  12.162 +	 ;; 	        (SimplexCollisionShape. Vector3f/ZERO)
  12.163 +	 ;; 	       (.get3 tri))))
  12.164 +	 ;; 	 (.setApplyPhysicsLocal true))]
  12.165 +	   
  12.166 +	 ;;   (.addControl geom control1)
  12.167 +	 ;;   (conj! controls! control1)
  12.168 +	 
  12.169 +	   )))
  12.170 +	 (persistent! controls!)))
  12.171 +
  12.172 +
  12.173 +
  12.174 +(use 'hello.brick-wall)
  12.175 +
  12.176 +(defn touch-reception [controls]
  12.177 +    (let [control
  12.178 +	  (first 
  12.179 +	   (filter 
  12.180 +	    #(< 2 (.getOverlappingCount %)) controls))]
  12.181 +      (if (not (nil? control))
  12.182 +	(println
  12.183 +	 (seq
  12.184 +	  (.getOverlappingObjects control))))))
  12.185 +
  12.186 +(defn touch-print [controls]
  12.187 +  (println
  12.188 +   (map #(count (.getNonGhostOverlappingObjects %)) controls)))
  12.189 +
  12.190 +(defn set-debug-color [#^ColorRGBA color #^GhostControl gc]
  12.191 +  (.setColor (.getMaterial (.getChild (.getDebugShape gc) 0)) "Color" color))
  12.192 +
  12.193 +(defn html-color [html-str]
  12.194 +  ((fn [[r g b]] (ColorRGBA. r g b (float 1)))
  12.195 +   (map #(float (/ (Integer/parseInt % 16) 255))
  12.196 +	(map (partial apply str) (partition 2 html-str)))))
  12.197 +  
  12.198 +
  12.199 +(defn color-touch [controls]
  12.200 +  (no-exceptions
  12.201 +   (dorun
  12.202 +    (map
  12.203 +     (fn [control]
  12.204 +       (case (count (.getNonGhostOverlappingObjects control))
  12.205 +	     0 (set-debug-color ColorRGBA/Gray control)
  12.206 +	     1 (set-debug-color ColorRGBA/Blue control)
  12.207 +	     2 (set-debug-color ColorRGBA/Green control)
  12.208 +	     3 (set-debug-color ColorRGBA/Yellow control)
  12.209 +	     4 (set-debug-color ColorRGBA/Orange control)
  12.210 +	     5 (set-debug-color ColorRGBA/Red control)
  12.211 +	     6 (set-debug-color ColorRGBA/Magenta control)
  12.212 +	     7 (set-debug-color ColorRGBA/Pink control)
  12.213 +	     8 (set-debug-color ColorRGBA/White control)))
  12.214 +     controls))))
  12.215 +
  12.216 +(defn enable-debug [world]
  12.217 +  (.enableDebug 
  12.218 +   (.getPhysicsSpace
  12.219 +    (.getState
  12.220 +     (.getStateManager world)
  12.221 +     BulletAppState))
  12.222 +   (asset-manager)))
  12.223 +
  12.224 +(def with-debug
  12.225 +     '(1 1 1 1 0 1 2 0 2 0 1 1 1 1 0 2 0 2 2 1 0 0 0 1 0 0 0 0 1 0))
  12.226 +(def no-debug
  12.227 +     '(1 1 1 1 0 1 2 0 2 0 1 1 1 1 0 2 0 2 2 1 0 0 0 1 0 0 0 0 1 0))
  12.228 +
  12.229 +
  12.230 +
  12.231 +(defn transparent-sphere []
  12.232 +  (doto
  12.233 +      (make-shape
  12.234 +       (merge base-shape
  12.235 +	      {:position (Vector3f. 0 2 0)
  12.236 +	       :name "the blob."
  12.237 +	       :material "Common/MatDefs/Misc/Unshaded.j3md"
  12.238 +	       :texture "Textures/purpleWisp.png"
  12.239 +	       :physical? true
  12.240 +	       :mass 70
  12.241 +	       :color ColorRGBA/Blue
  12.242 +	       :shape (Sphere. 10 10 1)}))
  12.243 +    (-> (.getMaterial)
  12.244 +	(.getAdditionalRenderState)
  12.245 +	(.setBlendMode RenderState$BlendMode/Alpha))
  12.246 +    (.setQueueBucket RenderQueue$Bucket/Transparent)))
  12.247 +
  12.248 +(defn transparent-box []
  12.249 +    (doto
  12.250 +      (make-shape
  12.251 +       (merge base-shape
  12.252 +	      {:position (Vector3f. 0 2 0)
  12.253 +	       :name "the blob."
  12.254 +	       :material "Common/MatDefs/Misc/Unshaded.j3md"
  12.255 +	       :texture "Textures/purpleWisp.png"
  12.256 +	       :physical? true
  12.257 +	       :mass 70
  12.258 +	       :color ColorRGBA/Blue
  12.259 +	       :shape (Box. 1 1 1)}))
  12.260 +    (-> (.getMaterial)
  12.261 +	(.getAdditionalRenderState)
  12.262 +	(.setBlendMode RenderState$BlendMode/Alpha))
  12.263 +    (.setQueueBucket RenderQueue$Bucket/Transparent)))
  12.264 +
  12.265 +  
  12.266 +
  12.267 +(defn no-logging []
  12.268 +  (.setLevel (Logger/getLogger "com.jme3") Level/OFF))
  12.269 +
  12.270 +(defn set-accuracy [world new-accuracy]
  12.271 +  (let [physics-manager (.getState (.getStateManager world) BulletAppState)]
  12.272 +    (.setAccuracy (.getPhysicsSpace physics-manager) (float new-accuracy))))
  12.273 +
  12.274 +(defn test-skin []
  12.275 +  (let [b
  12.276 +	;;(transparent-box)
  12.277 +	(transparent-sphere)
  12.278 +	
  12.279 +	controls
  12.280 +	;;(make-touch-sphere b)
  12.281 +	(make-touch b)
  12.282 +	]
  12.283 +    
  12.284 +    (world
  12.285 +     (doto (Node.) (.attachChild b)
  12.286 +	   (.attachChild
  12.287 +	    (doto
  12.288 +		(box 5 0.2 5  :mass 0 :position (Vector3f. 0 -2 0)
  12.289 +		     :material "Common/MatDefs/Misc/Unshaded.j3md"
  12.290 +		     :texture "Textures/redWisp.png")
  12.291 +	      (-> (.getMaterial)
  12.292 +		  (.getAdditionalRenderState)
  12.293 +		  (.setBlendMode RenderState$BlendMode/Alpha))
  12.294 +	      (.setQueueBucket RenderQueue$Bucket/Transparent))))
  12.295 +     
  12.296 +     {"key-return" (fire-cannon-ball)
  12.297 +      "key-space"  (fn [game value]
  12.298 +     		     (touch-print controls))}
  12.299 +     (fn [world]
  12.300 +       (Capture/SimpleCaptureVideo world (file-str "~/out-temp/blob.avi"))
  12.301 +       (no-logging)
  12.302 +       (enable-debug world)
  12.303 +       (set-accuracy world (/ 1 60))
  12.304 +       )
  12.305 +
  12.306 +     (fn [& _]
  12.307 +       (touch-print controls)
  12.308 +       (color-touch controls)
  12.309 +       ))))
  12.310 +
  12.311 +#+end_src
  12.312 +
  12.313 +
  12.314 +
  12.315 +
  12.316 +
  12.317 +
  12.318 +* COMMENT code generation
  12.319 +#+begin_src clojure :tangle ../src/body/skin.clj
  12.320 +<<skin-main>>
  12.321 +#+end_src
  12.322 +
  12.323 +
  12.324 +
  12.325 +