changeset 80:880ae8e03408

Measure time intervals between repaints. Experiments.
author Mikhail Kryshen <mikhail@kryshen.net>
date Wed, 01 Sep 2010 22:25:55 +0400
parents 5fd50e400124
children 5d2153e8a28d
files src/net/kryshen/indyvon/demo.clj src/net/kryshen/indyvon/layers.clj
diffstat 2 files changed, 170 insertions(+), 30 deletions(-) [+]
line diff
     1.1 --- a/src/net/kryshen/indyvon/demo.clj	Wed Sep 01 22:24:17 2010 +0400
     1.2 +++ b/src/net/kryshen/indyvon/demo.clj	Wed Sep 01 22:25:55 2010 +0400
     1.3 @@ -26,6 +26,110 @@
     1.4     (java.awt Color)
     1.5     (javax.swing JFrame)))
     1.6  
     1.7 +(defn draw-button!
     1.8 +  "Draws button immediately (but uses callback for button action
     1.9 +   unlike IMGUI)."
    1.10 +  [id content callback & args]
    1.11 +  (with-handlers id
    1.12 +    (let [shadow-offset 2
    1.13 +          padding 4
    1.14 +          border-width 1
    1.15 +          offset (if (picked? id) (/ shadow-offset 2) 0)
    1.16 +          ^Color color (:alt-back-color *theme*)
    1.17 +          color (if (hovered? id) (.brighter color) color)
    1.18 +          width (- *width* shadow-offset)
    1.19 +          height (- *height* shadow-offset)]
    1.20 +      (with-color Color/BLACK
    1.21 +        (.fillRect *graphics* shadow-offset shadow-offset width height))
    1.22 +      (with-color color
    1.23 +        (.fillRect *graphics* offset offset width height))
    1.24 +      (draw! (border content border-width padding)
    1.25 +             offset offset width height))
    1.26 +    ;; Event handlers
    1.27 +    (:mouse-entered _ (repaint))
    1.28 +    (:mouse-exited _ (repaint))
    1.29 +    (:mouse-pressed _ (repaint))
    1.30 +    (:mouse-released _ (repaint))
    1.31 +    (:mouse-clicked _ (apply callback args))))
    1.32 +
    1.33 +(defn combine-colors [^Color color1 ^Color color2 c]
    1.34 +  (case c
    1.35 +    0.0 color1
    1.36 +    1.0 color2
    1.37 +    (let [rgb1 (.getRGBComponents color1 nil)
    1.38 +          rgb2 (.getRGBComponents color2 nil)
    1.39 +          rgb (float-array (map #(+ (* (- 1 c) %1) (* c %2)) rgb1 rgb2))]
    1.40 +      (Color. (aget rgb 0) (aget rgb 1) (aget rgb 2) (aget rgb 3)))))
    1.41 +
    1.42 +(defn animate
    1.43 +  "Changes atom value according to specified range, speed, and current
    1.44 +   frame interval. Invokes repaint if change happens."
    1.45 +  [atom from to speed]
    1.46 +  (let [prev @atom
    1.47 +        state (cond
    1.48 +               (zero? speed) :stop
    1.49 +               (= prev from) (if (pos? speed) :start :stop)               
    1.50 +               (= prev to) (if (neg? speed) :start :stop)
    1.51 +               :default :continue)]
    1.52 +    ;;(println prev from to speed state *interval*)
    1.53 +    (if (= state :stop)
    1.54 +       prev
    1.55 +       (let [interval (if (= state :start) 1 *interval*)
    1.56 +             step (* speed interval 1E-9)
    1.57 +             val (swap! atom #(-> % (+ step) (max from) (min to)))]
    1.58 +         (repaint)
    1.59 +         val))))
    1.60 +
    1.61 +(defn button
    1.62 +  "Create animated button layer."
    1.63 +  [content callback & args]
    1.64 +  (let [padding 4
    1.65 +        border-width 1
    1.66 +        shadow-offset 2
    1.67 +        face (border content padding border-width)
    1.68 +        highlight (atom 0)
    1.69 +        animation-speed (atom 0)]
    1.70 +    (interval-layer
    1.71 +     (reify
    1.72 +      Layer
    1.73 +      (render! [button]
    1.74 +        (with-handlers button
    1.75 +          (let [hovered (hovered? button)
    1.76 +                offset (if (picked? button) (/ shadow-offset 2) 0)
    1.77 +                color (combine-colors
    1.78 +                       (:alt-back-color *theme*) Color/WHITE
    1.79 +                       (animate highlight 0.0 1.0 @animation-speed))
    1.80 +                width (- *width* shadow-offset)
    1.81 +                height (- *height* shadow-offset)]
    1.82 +            (with-color Color/BLACK
    1.83 +              (.fillRect *graphics*
    1.84 +                         shadow-offset shadow-offset
    1.85 +                         width height))
    1.86 +            (with-color color
    1.87 +              (.fillRect *graphics* offset offset width height))
    1.88 +            (draw! (border content border-width padding)
    1.89 +                   offset offset width height))
    1.90 +          ;; Event handlers
    1.91 +          (:mouse-entered _
    1.92 +            (reset! animation-speed 4)
    1.93 +            (repaint))
    1.94 +          (:mouse-exited _
    1.95 +            (reset! animation-speed -2)
    1.96 +            (repaint))
    1.97 +          (:mouse-pressed _ (repaint))
    1.98 +          (:mouse-released _ (repaint))
    1.99 +          (:mouse-clicked _ (apply callback args))))
   1.100 +     (layer-size [button]
   1.101 +        (let [face-size (layer-size face)]
   1.102 +          (Size. (+ (:width face-size) shadow-offset)
   1.103 +                 (+ (:height face-size) shadow-offset))))))))
   1.104 +
   1.105 +(def button1 (button (label "Animated button 1")
   1.106 +                     println "Animated button 1 clicked"))
   1.107 +
   1.108 +(def button2 (button (label "Animated button 2")
   1.109 +                     println "Animated button 2 clicked"))
   1.110 +
   1.111  (def layer1
   1.112    (reify
   1.113     Layer
   1.114 @@ -68,6 +172,7 @@
   1.115     Layer
   1.116     (render! [layer]
   1.117        ;;(repaint)
   1.118 +      ;;(println (format "%.3f" (/ *interval* 1E9)))
   1.119        (doto *graphics*
   1.120          ;; Random color to see when repaint happens.
   1.121          (.setColor (rand-nth [Color/BLACK Color/BLUE Color/RED]))
   1.122 @@ -75,13 +180,30 @@
   1.123          (.drawLine *width* 0 0 *height*))
   1.124        (draw! layer2 15 20)
   1.125        (draw! layer2m 120 50)
   1.126 -      (draw! layer3 100 100 80 50))
   1.127 +      (draw! layer3 100 100 80 50)
   1.128 +      (draw! button1 50 160)
   1.129 +      (with-rotate (/ Math/PI 6) 250 200
   1.130 +        (draw! button1 200 160))
   1.131 +      (draw! button2 50 250)
   1.132 +      (with-bounds 100 200 140 30
   1.133 +        (draw-button! :button
   1.134 +         (label "Immediate button" :center :center)
   1.135 +         #(println "Button clicked!"))))
   1.136     (layer-size [layer]
   1.137        (Size. 400 300))))
   1.138  
   1.139 +;; Main viewport
   1.140  (def vp (viewport layer))
   1.141  
   1.142 -(def root (fps-layer vp))
   1.143 +;; Miniature (rendered asynchronously)
   1.144 +(def vp-miniature (border (viewport-miniature vp 100 75)))
   1.145 +
   1.146 +;; Main scene
   1.147 +(def scene
   1.148 +  (fps-layer
   1.149 +   (decorate-layer vp [_]
   1.150 +     (draw! vp)
   1.151 +     (draw! vp-miniature (- *width* 105) 5))))
   1.152  
   1.153  (defn show-frame [layer]
   1.154    (doto (make-jframe "Test" layer)
   1.155 @@ -90,5 +212,4 @@
   1.156  
   1.157  (defn -main []
   1.158    (println "Try to drag the viewport.")
   1.159 -  (show-frame root)
   1.160 -  (show-frame (fps-layer (viewport-miniature vp 80 60))))
   1.161 +  (show-frame scene))
     2.1 --- a/src/net/kryshen/indyvon/layers.clj	Wed Sep 01 22:24:17 2010 +0400
     2.2 +++ b/src/net/kryshen/indyvon/layers.clj	Wed Sep 01 22:25:55 2010 +0400
     2.3 @@ -284,32 +284,6 @@
     2.4            (.drawRect *graphics* x y w h))))
     2.5     width height))
     2.6  
     2.7 -(defn- fps-label [text]
     2.8 -  (padding (label text :right :bottom) 5))
     2.9 -
    2.10 -(defn fps-layer
    2.11 -  "Creates layer that draws content and displays
    2.12 -   the frames per seconds rate." 
    2.13 -  [content]
    2.14 -  (let [update-interval 2E8 ; 0.2 s in nanoseconds
    2.15 -        frames (ref 0)
    2.16 -        prev-time (ref nil)
    2.17 -        display (ref (fps-label "fps n/a"))]
    2.18 -    (decorate-layer content [_]
    2.19 -       (draw! content)
    2.20 -       (draw!
    2.21 -        (dosync
    2.22 -         (alter frames inc)
    2.23 -         (if @prev-time
    2.24 -           (let [elapsed (- *time* @prev-time)]
    2.25 -             (when (> elapsed update-interval)
    2.26 -               (let [fps (/ @frames (/ elapsed 1E9))]
    2.27 -                 (ref-set display (fps-label (format "%.1f" fps)))
    2.28 -                 (ref-set frames 0)
    2.29 -                 (ref-set prev-time *time*))))
    2.30 -           (ref-set prev-time *time*))
    2.31 -         @display)))))
    2.32 -
    2.33  ;;
    2.34  ;; Layer context decorators.
    2.35  ;;
    2.36 @@ -338,3 +312,48 @@
    2.37       (anchor [t xa ya]
    2.38          (with-theme theme
    2.39            (anchor layer xa ya))))))
    2.40 +
    2.41 +;;
    2.42 +;; Measuring time
    2.43 +;;
    2.44 +
    2.45 +(def *interval*)
    2.46 +
    2.47 +(defn interval-layer
    2.48 +  "Creates layer that measures time between repaints ant draws it's
    2.49 +   content with the *interval* var bound to the measured time."
    2.50 +  [content]
    2.51 +  (let [last-time (atom nil)]
    2.52 +    (decorate-layer content [_]
    2.53 +      (compare-and-set! last-time nil *time*)
    2.54 +      (let [lt @last-time]
    2.55 +        (binding [*interval* (if (compare-and-set! last-time lt *time*)
    2.56 +                               (- *time* lt)
    2.57 +                               0)] ; already measured on parallel thread
    2.58 +          (render! content))))))
    2.59 +
    2.60 +(defn- fps-label [text]
    2.61 +  (padding (label text :right :bottom) 5))
    2.62 +
    2.63 +(defn fps-layer
    2.64 +  "Creates layer that draws content and displays
    2.65 +   the frames per seconds rate." 
    2.66 +  [content]
    2.67 +  (let [update-interval 2E8 ; 0.2 s in nanoseconds
    2.68 +        frames (ref 0)
    2.69 +        prev-time (ref nil)
    2.70 +        display (ref (fps-label "fps n/a"))]
    2.71 +    (decorate-layer content [_]
    2.72 +      (draw! content)
    2.73 +      (draw!
    2.74 +       (dosync
    2.75 +        (alter frames inc)
    2.76 +        (if @prev-time
    2.77 +          (let [elapsed (- *time* @prev-time)]
    2.78 +            (when (> elapsed update-interval)
    2.79 +              (let [fps (/ @frames (/ elapsed 1E9))]
    2.80 +                (ref-set display (fps-label (format "%.1f" fps)))
    2.81 +                (ref-set frames 0)
    2.82 +                (ref-set prev-time *time*))))
    2.83 +          (ref-set prev-time *time*))
    2.84 +        @display)))))