changeset 151:aaacf087504c

refactored vision code
author Robert McIntyre <rlm@mit.edu>
date Fri, 03 Feb 2012 05:52:18 -0700
parents e1232043656a
children c901b17a1f52
files org/blender.org org/eyes.org org/sense-util.org org/test-creature.org org/util.org
diffstat 5 files changed, 348 insertions(+), 286 deletions(-) [+]
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/org/blender.org	Fri Feb 03 05:52:18 2012 -0700
     1.3 @@ -0,0 +1,19 @@
     1.4 +#+title: Blender Clojure utilities
     1.5 +#+author: Robert McIntyre
     1.6 +#+email: rlm@mit.edu
     1.7 +#+description: blender utilities
     1.8 +#+keywords: simulation, jMonkeyEngine3, clojure, blender
     1.9 +#+SETUPFILE: ../../aurellem/org/setup.org
    1.10 +#+INCLUDE: ../../aurellem/org/level-0.org
    1.11 +
    1.12 +
    1.13 +#+name: blender
    1.14 +#+begin_src clojure 
    1.15 +
    1.16 +#+end_src
    1.17 +
    1.18 +
    1.19 +* COMMENT generate source
    1.20 +#+begin_src clojure :tangle ../src/cortex/blender.clj
    1.21 +<<blender>>
    1.22 +#+end_src
     2.1 --- a/org/eyes.org	Fri Feb 03 05:08:45 2012 -0700
     2.2 +++ b/org/eyes.org	Fri Feb 03 05:52:18 2012 -0700
     2.3 @@ -11,6 +11,47 @@
     2.4  
     2.5  I want to make creatures with eyes. Each eye can be independely moved
     2.6  and should see its own version of the world depending on where it is.
     2.7 +
     2.8 +Here's how vision will work.
     2.9 +
    2.10 +Make the continuation in scene-processor take FrameBuffer,
    2.11 +byte-buffer, BufferedImage already sized to the correct
    2.12 +dimensions. the continuation will decide wether to "mix" them
    2.13 +into the BufferedImage, lazily ignore them, or mix them halfway
    2.14 +and call c/graphics card routines.
    2.15 +
    2.16 +(vision creature) will take an optional :skip argument which will
    2.17 +inform the continuations in scene processor to skip the given
    2.18 +number of cycles 0 means that no cycles will be skipped.
    2.19 +
    2.20 +(vision creature) will return [init-functions sensor-functions].
    2.21 +The init-functions are each single-arg functions that take the
    2.22 +world and register the cameras and must each be called before the
    2.23 +corresponding sensor-functions.  Each init-function returns the
    2.24 +viewport for that eye which can be manipulated, saved, etc. Each
    2.25 +sensor-function is a thunk and will return data in the same
    2.26 +format as the tactile-sensor functions the structure is
    2.27 +[topology, sensor-data]. Internally, these sensor-functions
    2.28 +maintain a reference to sensor-data which is periodically updated
    2.29 +by the continuation function established by its init-function.
    2.30 +They can be queried every cycle, but their information may not
    2.31 +necessairly be different every cycle.
    2.32 +
    2.33 +Each eye in the creature in blender will work the same way as
    2.34 +joints -- a zero dimensional object with no geometry whose local
    2.35 +coordinate system determines the orientation of the resulting
    2.36 +eye. All eyes will have a parent named "eyes" just as all joints
    2.37 +have a parent named "joints". The resulting camera will be a
    2.38 +ChaseCamera or a CameraNode bound to the geo that is closest to
    2.39 +the eye marker. The eye marker will contain the metadata for the
    2.40 +eye, and will be moved by it's bound geometry. The dimensions of
    2.41 +the eye's camera are equal to the dimensions of the eye's "UV"
    2.42 +map.
    2.43 +
    2.44 +
    2.45 +
    2.46 +
    2.47 +
    2.48  #+name: eyes
    2.49  #+begin_src clojure 
    2.50  (ns cortex.vision
    2.51 @@ -18,14 +59,18 @@
    2.52    eyes from different positions to observe the same world, and pass
    2.53    the observed data to any arbitray function."
    2.54    {:author "Robert McIntyre"}
    2.55 -  (:use cortex.world)
    2.56 +  (:use (cortex world sense util))
    2.57    (:import com.jme3.post.SceneProcessor)
    2.58    (:import (com.jme3.util BufferUtils Screenshots))
    2.59    (:import java.nio.ByteBuffer)
    2.60    (:import java.awt.image.BufferedImage)
    2.61    (:import com.jme3.renderer.ViewPort)
    2.62    (:import com.jme3.math.ColorRGBA)
    2.63 -  (:import com.jme3.renderer.Renderer))
    2.64 +  (:import com.jme3.renderer.Renderer)
    2.65 +  (:import jme3tools.converters.ImageToAwt)
    2.66 +  (:import com.jme3.scene.Node))
    2.67 +
    2.68 +(cortex.import/mega-import-jme3)
    2.69  
    2.70  
    2.71  (defn vision-pipeline
    2.72 @@ -92,10 +137,108 @@
    2.73        (.setBackgroundColor ColorRGBA/Black)
    2.74        (.addProcessor (vision-pipeline continuation))
    2.75        (.attachScene (.getRootNode world)))))
    2.76 +
    2.77 +(defn retina-sensor-image
    2.78 +  "Return a map of pixel selection functions to BufferedImages
    2.79 +   describing the distribution of light-sensitive components on this
    2.80 +   geometry's surface. Each function creates an integer from the rgb
    2.81 +   values found in the pixel. :red, :green, :blue, :gray are already
    2.82 +   defined as extracting the red green blue and average components
    2.83 +   respectively."
    2.84 +   [#^Spatial eye]
    2.85 +   (if-let [eye-map (meta-data eye "eye")]
    2.86 +     (map-vals
    2.87 +      #(ImageToAwt/convert
    2.88 +        (.getImage (.loadTexture (asset-manager) %))
    2.89 +        false false 0)
    2.90 +      (eval (read-string eye-map)))))
    2.91 +
    2.92 +(defn eye-dimensions
    2.93 +  "returns the width and height specified in the metadata of the eye"
    2.94 +  [#^Spatial eye]
    2.95 +  (let [dimensions
    2.96 +          (map #(vector (.getWidth %) (.getHeight %))
    2.97 +               (vals (retina-sensor-image eye)))]
    2.98 +    [(apply max (map first dimensions))
    2.99 +     (apply max (map second dimensions))]))
   2.100 +
   2.101 +(defn creature-eyes
   2.102 +  ;;dylan
   2.103 +  "Return the children of the creature's \"eyes\" node."
   2.104 +  ;;"The eye nodes which are children of the \"eyes\" node in the
   2.105 +  ;;creature."
   2.106 +  [#^Node creature]
   2.107 +  (if-let [eye-node (.getChild creature "eyes")]
   2.108 +    (seq (.getChildren eye-node))
   2.109 +    (do (println-repl "could not find eyes node") [])))
   2.110 +
   2.111 +
   2.112 +(defn attach-eye
   2.113 +  "Attach a Camera to the appropiate area and return the Camera."
   2.114 +  [#^Node creature #^Spatial eye]
   2.115 +  (let [target (closest-node creature eye)
   2.116 +        [cam-width cam-height] (eye-dimensions eye)
   2.117 +        cam (Camera. cam-width cam-height)]
   2.118 +    (.setLocation cam (.getWorldTranslation eye))
   2.119 +    (.setRotation cam (.getWorldRotation eye))
   2.120 +    (.setFrustumPerspective
   2.121 +     cam 45 (/ (.getWidth cam) (.getHeight cam))
   2.122 +     1 1000)
   2.123 +    (bind-sense target cam)
   2.124 +    cam))
   2.125 +
   2.126 +(def presets
   2.127 +  {:all    0xFFFFFF
   2.128 +   :red    0xFF0000
   2.129 +   :blue   0x0000FF
   2.130 +   :green  0x00FF00})
   2.131 +
   2.132 +(defn enable-vision
   2.133 +  "return [init-function sensor-functions] for a particular eye"
   2.134 +  [#^Node creature #^Spatial eye & {skip :skip :or {skip 0}}]
   2.135 +  (let [retinal-map (retina-sensor-image eye)
   2.136 +        camera (attach-eye creature eye)
   2.137 +        vision-image
   2.138 +        (atom
   2.139 +         (BufferedImage. (.getWidth camera)
   2.140 +                         (.getHeight camera)
   2.141 +                         BufferedImage/TYPE_BYTE_BINARY))]
   2.142 +    [(fn [world]
   2.143 +       (add-eye
   2.144 +        world camera
   2.145 +        (let [counter  (atom 0)]
   2.146 +          (fn [r fb bb bi]
   2.147 +            (if (zero? (rem (swap! counter inc) (inc skip)))
   2.148 +              (reset! vision-image (BufferedImage! r fb bb bi)))))))
   2.149 +     (vec
   2.150 +      (map
   2.151 +       (fn [[key image]]
   2.152 +         (let [whites (white-coordinates image)
   2.153 +               topology (vec (collapse whites))
   2.154 +               mask (presets key)]
   2.155 +           (fn []
   2.156 +             (vector
   2.157 +              topology
   2.158 +              (vec 
   2.159 +               (for [[x y] whites]
   2.160 +                 (bit-and
   2.161 +                  mask (.getRGB @vision-image x y))))))))
   2.162 +       retinal-map))]))
   2.163 +
   2.164 +(defn vision
   2.165 +  [#^Node creature & {skip :skip :or {skip 0}}]
   2.166 +  (reduce
   2.167 +   (fn [[init-a senses-a]
   2.168 +        [init-b senses-b]]
   2.169 +     [(conj init-a init-b)
   2.170 +      (into senses-a senses-b)])
   2.171 +   [[][]]      
   2.172 +   (for [eye (creature-eyes creature)]
   2.173 +     (enable-vision creature eye))))
   2.174 +
   2.175 +
   2.176  #+end_src
   2.177  
   2.178 -#+results: eyes
   2.179 -: #'cortex.vision/add-eye
   2.180  
   2.181  Note the use of continuation passing style for connecting the eye to a
   2.182  function to process the output. You can create any number of eyes, and
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/org/sense-util.org	Fri Feb 03 05:52:18 2012 -0700
     3.3 @@ -0,0 +1,174 @@
     3.4 +#+title: General sense/effector utilities
     3.5 +#+author: Robert McIntyre
     3.6 +#+email: rlm@mit.edu
     3.7 +#+description: sensory utilities
     3.8 +#+keywords: simulation, jMonkeyEngine3, clojure, simulated senses
     3.9 +#+SETUPFILE: ../../aurellem/org/setup.org
    3.10 +#+INCLUDE: ../../aurellem/org/level-0.org
    3.11 +
    3.12 +
    3.13 +#+name: sense-util
    3.14 +#+begin_src clojure 
    3.15 +(ns cortex.sense)
    3.16 +(cortex.import/mega-import-jme3)
    3.17 +(import ij.process.ImageProcessor)
    3.18 +(import java.awt.image.BufferedImage)
    3.19 +
    3.20 +
    3.21 +(defn meta-data [blender-node key]
    3.22 +  (if-let [data (.getUserData blender-node "properties")]
    3.23 +    (.findValue data key)
    3.24 +    nil))
    3.25 +
    3.26 +(defn closest-node
    3.27 +  "Return the object in creature which is closest to the given node."
    3.28 +  ;;dylan"The closest object in creature to the given node."
    3.29 +  [#^Node creature #^Node eye]
    3.30 +  (loop [radius (float 0.01)]
    3.31 +    (let [results (CollisionResults.)]
    3.32 +      (.collideWith
    3.33 +       creature
    3.34 +       (BoundingBox. (.getWorldTranslation eye)
    3.35 +                     radius radius radius)
    3.36 +       results)
    3.37 +      (if-let [target (first results)]
    3.38 +        (.getGeometry target)
    3.39 +        (recur (float (* 2 radius)))))))
    3.40 +
    3.41 +(defn bind-sense
    3.42 +  "Bind the sense to the Spatial such that it will maintain its
    3.43 +   current position relative to the Spatial no matter how the spatial
    3.44 +   moves. 'sense can be either a Camera or Listener object."
    3.45 +  [#^Spatial obj sense]
    3.46 +  (let [sense-offset (.subtract (.getLocation sense)
    3.47 +                                (.getWorldTranslation obj))
    3.48 +        initial-sense-rotation (Quaternion. (.getRotation sense))
    3.49 +        base-anti-rotation (.inverse (.getWorldRotation obj))]
    3.50 +    (.addControl
    3.51 +     obj
    3.52 +     (proxy [AbstractControl] []
    3.53 +       (controlUpdate [tpf]
    3.54 +         (let [total-rotation
    3.55 +               (.mult base-anti-rotation (.getWorldRotation obj))]
    3.56 +           (.setLocation sense
    3.57 +                         (.add
    3.58 +                          (.mult total-rotation sense-offset)
    3.59 +                          (.getWorldTranslation obj)))
    3.60 +           (.setRotation sense
    3.61 +                         (.mult total-rotation initial-sense-rotation))))
    3.62 +       (controlRender [_ _])))))
    3.63 +
    3.64 +(def white -1)
    3.65 +  
    3.66 +(defn filter-pixels
    3.67 +  "List the coordinates of all pixels matching pred, within the bounds
    3.68 +   provided. Bounds -> [x0 y0 width height]"
    3.69 +  {:author "Dylan Holmes"}
    3.70 +  ([pred #^BufferedImage image]
    3.71 +     (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)]))
    3.72 +  ([pred #^BufferedImage image [x0 y0 width height]]
    3.73 +     ((fn accumulate [x y matches]
    3.74 +        (cond
    3.75 +         (>= y (+ height y0)) matches
    3.76 +         (>= x (+ width x0)) (recur 0 (inc y) matches)
    3.77 +         (pred (.getRGB image x y))
    3.78 +         (recur (inc x) y (conj matches [x y]))
    3.79 +         :else (recur (inc x) y matches)))
    3.80 +      x0 y0 [])))
    3.81 +
    3.82 +(defn white-coordinates
    3.83 +  "Coordinates of all the white pixels in a subset of the image."
    3.84 +  ([#^BufferedImage image bounds]
    3.85 +     (filter-pixels #(= % white) image bounds))
    3.86 +  ([#^BufferedImage image]
    3.87 +     (filter-pixels #(= % white) image)))
    3.88 +
    3.89 +(defn points->image
    3.90 +  "Take a sparse collection of points and visuliaze it as a
    3.91 +   BufferedImage."
    3.92 +
    3.93 +  ;; TODO maybe parallelize this since it's easy
    3.94 +
    3.95 +  [points]
    3.96 +  (if (empty? points)
    3.97 +    (BufferedImage. 1 1 BufferedImage/TYPE_BYTE_BINARY)
    3.98 +    (let [xs (vec (map first points))
    3.99 +          ys (vec (map second points))
   3.100 +          x0 (apply min xs)
   3.101 +          y0 (apply min ys)
   3.102 +          width (- (apply max xs) x0)
   3.103 +          height (- (apply max ys) y0)
   3.104 +          image (BufferedImage. (inc width) (inc height)
   3.105 +                                BufferedImage/TYPE_INT_RGB)]
   3.106 +      (dorun
   3.107 +       (for [x (range (.getWidth image))
   3.108 +             y (range (.getHeight image))]
   3.109 +         (.setRGB image x y 0xFF0000)))
   3.110 +      (dorun 
   3.111 +       (for [index (range (count points))]
   3.112 +         (.setRGB image (- (xs index) x0) (- (ys index) y0) -1)))
   3.113 +      
   3.114 +      image)))
   3.115 +
   3.116 +(defn average [coll]
   3.117 +  (/ (reduce + coll) (count coll)))
   3.118 +
   3.119 +(defn collapse-1d
   3.120 +  "One dimensional analogue of collapse"
   3.121 +  [center line]
   3.122 +  (let [length (count line)
   3.123 +        num-above (count (filter (partial < center) line))
   3.124 +        num-below (- length num-above)]
   3.125 +    (range (- center num-below)
   3.126 +           (+ center num-above))))
   3.127 +
   3.128 +(defn collapse
   3.129 +  "Take a set of pairs of integers and collapse them into a
   3.130 +   contigous bitmap."
   3.131 +  [points]
   3.132 +  (if (empty? points) []
   3.133 +      (let
   3.134 +          [num-points (count points)
   3.135 +           center (vector
   3.136 +                   (int (average (map first points)))
   3.137 +                   (int (average (map first points))))
   3.138 +           flattened
   3.139 +           (reduce
   3.140 +            concat 
   3.141 +            (map
   3.142 +             (fn [column]
   3.143 +               (map vector
   3.144 +                    (map first column)
   3.145 +                    (collapse-1d (second center)
   3.146 +                                 (map second column))))
   3.147 +             (partition-by first (sort-by first points))))
   3.148 +           squeezed
   3.149 +           (reduce
   3.150 +            concat 
   3.151 +            (map
   3.152 +             (fn [row]
   3.153 +               (map vector
   3.154 +                    (collapse-1d (first center)
   3.155 +                                 (map first row))
   3.156 +                    (map second row)))
   3.157 +             (partition-by second (sort-by second flattened))))
   3.158 +           relocate
   3.159 +           (let [min-x (apply min (map first squeezed))
   3.160 +                 min-y (apply min (map second squeezed))]
   3.161 +             (map (fn [[x y]]
   3.162 +                    [(- x min-x)
   3.163 +                     (- y min-y)])
   3.164 +                  squeezed))]
   3.165 +        relocate)))
   3.166 +
   3.167 +#+end_src
   3.168 +
   3.169 +#+results: sense-util
   3.170 +: #'cortex.sense/meta-data
   3.171 +
   3.172 +
   3.173 +
   3.174 +* COMMENT generate source
   3.175 +#+begin_src clojure :tangle ../src/cortex/sense.clj
   3.176 +<<sense-util>>
   3.177 +#+end_src
     4.1 --- a/org/test-creature.org	Fri Feb 03 05:08:45 2012 -0700
     4.2 +++ b/org/test-creature.org	Fri Feb 03 05:52:18 2012 -0700
     4.3 @@ -147,7 +147,7 @@
     4.4  ;; TODO remove this!
     4.5  (require 'cortex.import)
     4.6  (cortex.import/mega-import-jme3)
     4.7 -(use '(cortex world util body hearing touch vision))
     4.8 +(use '(cortex world util body hearing touch vision sense))
     4.9  
    4.10  (rlm.rlm-commands/help)
    4.11  (import java.awt.image.BufferedImage)
    4.12 @@ -160,83 +160,6 @@
    4.13  (declare joint-create)
    4.14  (use 'clojure.contrib.def)
    4.15  
    4.16 -(defn points->image
    4.17 -  "Take a sparse collection of points and visuliaze it as a
    4.18 -   BufferedImage."
    4.19 -
    4.20 -  ;; TODO maybe parallelize this since it's easy
    4.21 -
    4.22 -  [points]
    4.23 -  (if (empty? points)
    4.24 -    (BufferedImage. 1 1 BufferedImage/TYPE_BYTE_BINARY)
    4.25 -    (let [xs (vec (map first points))
    4.26 -          ys (vec (map second points))
    4.27 -          x0 (apply min xs)
    4.28 -          y0 (apply min ys)
    4.29 -          width (- (apply max xs) x0)
    4.30 -          height (- (apply max ys) y0)
    4.31 -          image (BufferedImage. (inc width) (inc height)
    4.32 -                                BufferedImage/TYPE_INT_RGB)]
    4.33 -      (dorun
    4.34 -       (for [x (range (.getWidth image))
    4.35 -             y (range (.getHeight image))]
    4.36 -         (.setRGB image x y 0xFF0000)))
    4.37 -      (dorun 
    4.38 -       (for [index (range (count points))]
    4.39 -         (.setRGB image (- (xs index) x0) (- (ys index) y0) -1)))
    4.40 -      
    4.41 -      image)))
    4.42 -
    4.43 -(defn average [coll]
    4.44 -  (/ (reduce + coll) (count coll)))
    4.45 -
    4.46 -(defn collapse-1d
    4.47 -  "One dimensional analogue of collapse"
    4.48 -  [center line]
    4.49 -  (let [length (count line)
    4.50 -        num-above (count (filter (partial < center) line))
    4.51 -        num-below (- length num-above)]
    4.52 -    (range (- center num-below)
    4.53 -           (+ center num-above))))
    4.54 -
    4.55 -(defn collapse
    4.56 -  "Take a set of pairs of integers and collapse them into a
    4.57 -   contigous bitmap."
    4.58 -  [points]
    4.59 -  (if (empty? points) []
    4.60 -      (let
    4.61 -          [num-points (count points)
    4.62 -           center (vector
    4.63 -                   (int (average (map first points)))
    4.64 -                   (int (average (map first points))))
    4.65 -           flattened
    4.66 -           (reduce
    4.67 -            concat 
    4.68 -            (map
    4.69 -             (fn [column]
    4.70 -               (map vector
    4.71 -                    (map first column)
    4.72 -                    (collapse-1d (second center)
    4.73 -                                 (map second column))))
    4.74 -             (partition-by first (sort-by first points))))
    4.75 -           squeezed
    4.76 -           (reduce
    4.77 -            concat 
    4.78 -            (map
    4.79 -             (fn [row]
    4.80 -               (map vector
    4.81 -                    (collapse-1d (first center)
    4.82 -                                 (map first row))
    4.83 -                    (map second row)))
    4.84 -             (partition-by second (sort-by second flattened))))
    4.85 -           relocate
    4.86 -           (let [min-x (apply min (map first squeezed))
    4.87 -                 min-y (apply min (map second squeezed))]
    4.88 -             (map (fn [[x y]]
    4.89 -                    [(- x min-x)
    4.90 -                     (- y min-y)])
    4.91 -                  squeezed))]
    4.92 -        relocate)))
    4.93  
    4.94  (defn load-bullet []
    4.95    (let [sim (world (Node.) {} no-op no-op)]
    4.96 @@ -254,11 +177,6 @@
    4.97       (.registerLoader BlenderModelLoader (into-array String ["blend"])))
    4.98     model))
    4.99  
   4.100 -(defn meta-data [blender-node key]
   4.101 -  (if-let [data (.getUserData blender-node "properties")]
   4.102 -    (.findValue data key)
   4.103 -    nil))
   4.104 -
   4.105  (defn blender-to-jme
   4.106    "Convert from Blender coordinates to JME coordinates"
   4.107    [#^Vector3f in]
   4.108 @@ -474,33 +392,7 @@
   4.109         image-path))
   4.110      false false 0)))
   4.111       
   4.112 -(import ij.process.ImageProcessor)
   4.113 -(import java.awt.image.BufferedImage)
   4.114  
   4.115 -(def white -1)
   4.116 -  
   4.117 -(defn filter-pixels
   4.118 -  "List the coordinates of all pixels matching pred, within the bounds
   4.119 -   provided. Bounds -> [x0 y0 width height]"
   4.120 -  {:author "Dylan Holmes"}
   4.121 -  ([pred #^BufferedImage image]
   4.122 -     (filter-pixels pred image [0 0 (.getWidth image) (.getHeight image)]))
   4.123 -  ([pred #^BufferedImage image [x0 y0 width height]]
   4.124 -     ((fn accumulate [x y matches]
   4.125 -        (cond
   4.126 -         (>= y (+ height y0)) matches
   4.127 -         (>= x (+ width x0)) (recur 0 (inc y) matches)
   4.128 -         (pred (.getRGB image x y))
   4.129 -         (recur (inc x) y (conj matches [x y]))
   4.130 -         :else (recur (inc x) y matches)))
   4.131 -      x0 y0 [])))
   4.132 -
   4.133 -(defn white-coordinates
   4.134 -  "Coordinates of all the white pixels in a subset of the image."
   4.135 -  ([#^BufferedImage image bounds]
   4.136 -     (filter-pixels #(= % white) image bounds))
   4.137 -  ([#^BufferedImage image]
   4.138 -     (filter-pixels #(= % white) image)))
   4.139  
   4.140  (defn triangle
   4.141    "Get the triangle specified by triangle-index from the mesh within
   4.142 @@ -718,87 +610,12 @@
   4.143                         (node-seq pieces)))))
   4.144  
   4.145  
   4.146 -;; human eye transmits 62kb/s to brain Bandwidth is 8.75 Mb/s
   4.147 -;; http://en.wikipedia.org/wiki/Retina
   4.148 -
   4.149  (defn test-eye  []
   4.150    (.getChild 
   4.151     (.getChild (worm-model) "eyes")
   4.152     "eye"))
   4.153  
   4.154  
   4.155 -(defn retina-sensor-image
   4.156 -  "Return a map of pixel selection functions to BufferedImages
   4.157 -   describing the distribution of light-sensitive components on this
   4.158 -   geometry's surface. Each function creates an integer from the rgb
   4.159 -   values found in the pixel. :red, :green, :blue, :gray are already
   4.160 -   defined as extracting the red green blue and average components
   4.161 -   respectively."
   4.162 -   [#^Spatial eye]
   4.163 -   (if-let [eye-map (meta-data eye "eye")]
   4.164 -     (map-vals
   4.165 -      #(ImageToAwt/convert
   4.166 -        (.getImage (.loadTexture (asset-manager) %))
   4.167 -        false false 0)
   4.168 -      (eval (read-string eye-map)))))
   4.169 -
   4.170 -(defn eye-dimensions
   4.171 -  "returns the width and height specified in the metadata of the eye"
   4.172 -  [#^Spatial eye]
   4.173 -  (let [dimensions
   4.174 -          (map #(vector (.getWidth %) (.getHeight %))
   4.175 -               (vals (retina-sensor-image eye)))]
   4.176 -    [(apply max (map first dimensions))
   4.177 -     (apply max (map second dimensions))]))
   4.178 -
   4.179 -(defn creature-eyes
   4.180 -  ;;dylan
   4.181 -  "Return the children of the creature's \"eyes\" node."
   4.182 -  ;;"The eye nodes which are children of the \"eyes\" node in the
   4.183 -  ;;creature."
   4.184 -  [#^Node creature]
   4.185 -  (if-let [eye-node (.getChild creature "eyes")]
   4.186 -    (seq (.getChildren eye-node))
   4.187 -    (do (println-repl "could not find eyes node") [])))
   4.188 -
   4.189 -;; Here's how vision will work.
   4.190 -
   4.191 -;; Make the continuation in scene-processor take FrameBuffer,
   4.192 -;; byte-buffer, BufferedImage already sized to the correct
   4.193 -;; dimensions. the continuation will decide wether to "mix" them
   4.194 -;; into the BufferedImage, lazily ignore them, or mix them halfway
   4.195 -;; and call c/graphics card routines.
   4.196 -
   4.197 -;; (vision creature) will take an optional :skip argument which will
   4.198 -;; inform the continuations in scene processor to skip the given
   4.199 -;; number of cycles; 0 means that no cycles will be skipped.
   4.200 -
   4.201 -;; (vision creature) will return [init-functions sensor-functions].
   4.202 -;; The init-functions are each single-arg functions that take the
   4.203 -;; world and register the cameras and must each be called before the
   4.204 -;; corresponding sensor-functions.  Each init-function returns the
   4.205 -;; viewport for that eye which can be manipulated, saved, etc. Each
   4.206 -;; sensor-function is a thunk and will return data in the same
   4.207 -;; format as the tactile-sensor functions; the structure is
   4.208 -;; [topology, sensor-data]. Internally, these sensor-functions
   4.209 -;; maintain a reference to sensor-data which is periodically updated
   4.210 -;; by the continuation function established by its init-function.
   4.211 -;; They can be queried every cycle, but their information may not
   4.212 -;; necessairly be different every cycle.
   4.213 -
   4.214 -;; Each eye in the creature in blender will work the same way as
   4.215 -;; joints -- a zero dimensional object with no geometry whose local
   4.216 -;; coordinate system determines the orientation of the resulting
   4.217 -;; eye. All eyes will have a parent named "eyes" just as all joints
   4.218 -;; have a parent named "joints". The resulting camera will be a
   4.219 -;; ChaseCamera or a CameraNode bound to the geo that is closest to
   4.220 -;; the eye marker. The eye marker will contain the metadata for the
   4.221 -;; eye, and will be moved by it's bound geometry. The dimensions of
   4.222 -;; the eye's camera are equal to the dimensions of the eye's "UV"
   4.223 -;; map.
   4.224 -
   4.225 -
   4.226 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   4.227  
   4.228  ;; Ears work the same way as vision.
   4.229  
   4.230 @@ -817,45 +634,9 @@
   4.231      (seq (.getChildren ear-node))
   4.232      (do (println-repl "could not find ears node") [])))
   4.233  
   4.234 -(defn closest-node
   4.235 -  "Return the object in creature which is closest to the given node."
   4.236 -  ;;dylan"The closest object in creature to the given node."
   4.237 -  [#^Node creature #^Node eye]
   4.238 -  (loop [radius (float 0.01)]
   4.239 -    (let [results (CollisionResults.)]
   4.240 -      (.collideWith
   4.241 -       creature
   4.242 -       (BoundingBox. (.getWorldTranslation eye)
   4.243 -                     radius radius radius)
   4.244 -       results)
   4.245 -      (if-let [target (first results)]
   4.246 -        (.getGeometry target)
   4.247 -        (recur (float (* 2 radius)))))))
   4.248  
   4.249  ;;dylan (defn follow-sense, adjoin-sense, attach-stimuli,
   4.250  ;;anchor-qualia, augment-organ, with-organ
   4.251 -(defn bind-sense
   4.252 -  "Bind the sense to the Spatial such that it will maintain its
   4.253 -   current position relative to the Spatial no matter how the spatial
   4.254 -   moves. 'sense can be either a Camera or Listener object."
   4.255 -  [#^Spatial obj sense]
   4.256 -  (let [sense-offset (.subtract (.getLocation sense)
   4.257 -                                (.getWorldTranslation obj))
   4.258 -        initial-sense-rotation (Quaternion. (.getRotation sense))
   4.259 -        base-anti-rotation (.inverse (.getWorldRotation obj))]
   4.260 -    (.addControl
   4.261 -     obj
   4.262 -     (proxy [AbstractControl] []
   4.263 -       (controlUpdate [tpf]
   4.264 -         (let [total-rotation
   4.265 -               (.mult base-anti-rotation (.getWorldRotation obj))]
   4.266 -           (.setLocation sense
   4.267 -                         (.add
   4.268 -                          (.mult total-rotation sense-offset)
   4.269 -                          (.getWorldTranslation obj)))
   4.270 -           (.setRotation sense
   4.271 -                         (.mult total-rotation initial-sense-rotation))))
   4.272 -       (controlRender [_ _])))))
   4.273  
   4.274  
   4.275  (defn update-listener-velocity
   4.276 @@ -919,68 +700,6 @@
   4.277     (for [ear (creature-ears creature)]
   4.278       (enable-hearing creature ear))))
   4.279  
   4.280 -(defn attach-eye
   4.281 -  "Attach a Camera to the appropiate area and return the Camera."
   4.282 -  [#^Node creature #^Spatial eye]
   4.283 -  (let [target (closest-node creature eye)
   4.284 -        [cam-width cam-height] (eye-dimensions eye)
   4.285 -        cam (Camera. cam-width cam-height)]
   4.286 -    (.setLocation cam (.getWorldTranslation eye))
   4.287 -    (.setRotation cam (.getWorldRotation eye))
   4.288 -    (.setFrustumPerspective
   4.289 -     cam 45 (/ (.getWidth cam) (.getHeight cam))
   4.290 -     1 1000)
   4.291 -    (bind-sense target cam)
   4.292 -    cam))
   4.293 -
   4.294 -(def presets
   4.295 -  {:all    0xFFFFFF
   4.296 -   :red    0xFF0000
   4.297 -   :blue   0x0000FF
   4.298 -   :green  0x00FF00})
   4.299 -
   4.300 -(defn enable-vision
   4.301 -  "return [init-function sensor-functions] for a particular eye"
   4.302 -  [#^Node creature #^Spatial eye & {skip :skip :or {skip 0}}]
   4.303 -  (let [retinal-map (retina-sensor-image eye)
   4.304 -        camera (attach-eye creature eye)
   4.305 -        vision-image
   4.306 -        (atom
   4.307 -         (BufferedImage. (.getWidth camera)
   4.308 -                         (.getHeight camera)
   4.309 -                         BufferedImage/TYPE_BYTE_BINARY))]
   4.310 -    [(fn [world]
   4.311 -       (add-eye
   4.312 -        world camera
   4.313 -        (let [counter  (atom 0)]
   4.314 -          (fn [r fb bb bi]
   4.315 -            (if (zero? (rem (swap! counter inc) (inc skip)))
   4.316 -              (reset! vision-image (BufferedImage! r fb bb bi)))))))
   4.317 -     (vec
   4.318 -      (map
   4.319 -       (fn [[key image]]
   4.320 -         (let [whites (white-coordinates image)
   4.321 -               topology (vec (collapse whites))
   4.322 -               mask (presets key)]
   4.323 -           (fn []
   4.324 -             (vector
   4.325 -              topology
   4.326 -              (vec 
   4.327 -               (for [[x y] whites]
   4.328 -                 (bit-and
   4.329 -                  mask (.getRGB @vision-image x y))))))))
   4.330 -       retinal-map))]))
   4.331 -
   4.332 -(defn vision
   4.333 -  [#^Node creature & {skip :skip :or {skip 0}}]
   4.334 -  (reduce
   4.335 -   (fn [[init-a senses-a]
   4.336 -        [init-b senses-b]]
   4.337 -     [(conj init-a init-b)
   4.338 -      (into senses-a senses-b)])
   4.339 -   [[][]]      
   4.340 -   (for [eye (creature-eyes creature)]
   4.341 -     (enable-vision creature eye))))
   4.342  
   4.343  
   4.344  
     5.1 --- a/org/util.org	Fri Feb 03 05:08:45 2012 -0700
     5.2 +++ b/org/util.org	Fri Feb 03 05:52:18 2012 -0700
     5.3 @@ -197,6 +197,13 @@
     5.4    [fn m]
     5.5    (apply fn (reduce #(into %1 %2) [] m)))
     5.6  
     5.7 +(defn map-vals 
     5.8 +  "Transform a map by applying a function to its values,
     5.9 +  keeping the keys the same."  
    5.10 +  [f m] (zipmap (keys m) (map f (vals m))))
    5.11 +
    5.12 +
    5.13 +
    5.14  #+end_src
    5.15  
    5.16  #+results: util