changeset 60:7e456697924d

Asynchronous drawing (continue).
author Mikhail Kryshen <mikhail@kryshen.net>
date Mon, 23 Aug 2010 21:24:33 +0400
parents b68de6a43f29
children 88bb47e3a401
files src/net/kryshen/indyvon/component.clj src/net/kryshen/indyvon/core.clj src/net/kryshen/indyvon/layers.clj
diffstat 3 files changed, 59 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/src/net/kryshen/indyvon/component.clj	Mon Aug 23 14:06:13 2010 +0400
+++ b/src/net/kryshen/indyvon/component.clj	Mon Aug 23 21:24:33 2010 +0400
@@ -21,22 +21,11 @@
   [^Component component layer ^Graphics2D graphics event-dispatcher]
   (let [size (.getSize component)
         width (.width size)
-        height (.height size)]
+        height (.height size)
+        update-fn #(.repaint component)]
     (.clearRect graphics 0 0 width height)
-    ;; Setup the root layer context (move to core?).
-    (binding [*graphics* graphics
-              *font-context* (.getFontRenderContext graphics)
-              *initial-transform* (.getTransform graphics)
-              *inverse-initial-transform*
-                (-> graphics .getTransform .createInverse)
-              *target* component
-              *event-dispatcher* event-dispatcher
-              *update* #(.repaint component)
-              *width* width
-              *height* height
-              *clip* (Rectangle2D$Double. 0 0 width height)]
-      (render! layer)
-      (commit event-dispatcher))))
+    (context-draw! layer component graphics event-dispatcher update-fn
+                   width height)))
 
 (defn preferred-size [component layer]
   (binding [*target* component
--- a/src/net/kryshen/indyvon/core.clj	Mon Aug 23 14:06:13 2010 +0400
+++ b/src/net/kryshen/indyvon/core.clj	Mon Aug 23 21:24:33 2010 +0400
@@ -19,7 +19,9 @@
 
 (def ^FontRenderContext *font-context*)
 
-(def ^Component *target*)
+(def ^{:tag Component
+       :doc "Target AWT component, may be nil if drawing off-screen."}
+     *target*)
 
 (def *width*)
 
@@ -238,6 +240,26 @@
   ([layer x y width height]
      (with-bounds* x y width height render! layer)))
 
+(defn context-draw!
+  "Sets up layer context, draws layer and commits event dispatcher."
+  ([layer graphics event-dispatcher update-fn width height]
+     (draw! layer nil graphics event-dispatcher update-fn width height))
+  ([layer component ^Graphics2D graphics event-dispatcher update-fn
+    width height]
+     (binding [*graphics* graphics
+               *font-context* (.getFontRenderContext graphics)
+               *initial-transform* (.getTransform graphics)
+               *inverse-initial-transform*
+                 (-> graphics .getTransform .createInverse)
+               *target* component
+               *update* update-fn
+               *event-dispatcher* event-dispatcher
+               *width* width
+               *height* height
+               *clip* (Rectangle2D$Double. 0 0 width height)]
+       (render! layer)
+       (commit event-dispatcher))))
+
 (defn draw-anchored!
   "Draws layer. Location is relative to the layer's anchor point for
    the specified alignment."
@@ -261,6 +283,13 @@
       java.awt.event.MouseEvent/MOUSE_PRESSED  :mouse-pressed
       java.awt.event.MouseEvent/MOUSE_RELEASED :mouse-released})
 
+(def dummy-event-dispatcher
+     (reify
+      EventDispatcher
+      (listen! [this component])
+      (create-dispatcher [this handle handlers] this)
+      (commit [this])))
+
 (defrecord DispatcherNode [handle handlers parent
                            ^Shape clip ^AffineTransform transform
                            bindings]
--- a/src/net/kryshen/indyvon/layers.clj	Mon Aug 23 14:06:13 2010 +0400
+++ b/src/net/kryshen/indyvon/layers.clj	Mon Aug 23 21:24:33 2010 +0400
@@ -173,16 +173,6 @@
               height (if (pos? height) height 1)]
           (Size. width height))))))
 
-;; (defn- validate-buffer [^Image image restore-fn]
-;;   (if (and image
-;;            (>= (.getWidth image nil) *width*)
-;;            (>= (.getHeight image nil) *height*))
-;;     image
-;;     ;;(let [image (BufferedImage. *width* *height* BufferedImage/TYPE_INT_ARGB)]
-;;     (let [image (.createImage *target* *width* *height*)]
-;;       (restore-fn image)
-;;       image)))
-
 (defn async-layer
   "Creates layer that draws the content asynchroniously in an
    offscreen buffer."
@@ -191,38 +181,42 @@
   (let [executor (ThreadPoolExecutor. 1 1 0 TimeUnit/SECONDS
                    (ArrayBlockingQueue. 1)
                    (ThreadPoolExecutor$DiscardOldestPolicy.))
-        buffers (ref
-                 [(BufferedImage. width height BufferedImage/TYPE_INT_ARGB)
-                  (BufferedImage. width height BufferedImage/TYPE_INT_ARGB)])
+        buffers (ref [nil nil])
         updated (ref false)
+        create-buffer
+          #(BufferedImage. width height BufferedImage/TYPE_INT_ARGB)
         draw-offscreen
-         (fn []
-           (let [b (dosync (let [b (peek @buffers)]
-                             (alter buffers pop)
-                             b))]
-             ;; TODO: set complete layer context.
-             (binding [*graphics* (.getGraphics b)
-                       *width* width
-                       *height* height
-                       ;; !!!
-                       *update* #(.execute executor draw-offscreen)]
-               (render! content))
-             (dosync
-              (alter buffers conj b)
-              (ref-set updated true))))]
+          (fn draw-offscreen []
+            (let [b (dosync (let [b (peek @buffers)]
+                              (alter buffers pop)
+                              b))]
+              ;; TODO: use operational event dispatcher.
+              (context-draw! (.getGraphics b)
+                             dummy-event-dispatcher
+                             #(.execute executor draw-offscreen)
+                             width height)
+              (dosync
+               (alter buffers conj b)
+               (ref-set updated true))))]
     (reify
      Layer
      (render! [layer]
-        (let [b (dosync
+        (let [buffer (dosync
                  (if @updated
                    (do (peek @buffers)
                        (alter buffers pop)
                        (ref-set updated false))
                    (do (first @buffers)
                        (alter buffers next))))]
-          (.drawImage *graphics* b)
-          (dosync
-           (alter buffers #(cons b %)))))
+          (when buffer
+            (.drawImage *graphics* buffer))
+          (let [new-buffer (or buffer (create-buffer))]
+            (dosync
+             (alter buffers #(cons new-buffer %)))
+            (when (not buffer)
+              ;; No cached image to draw.
+              ;; TODO: draw immediately.
+              (.execute executor draw-offscreen)))))
      (layer-size [layer]
         (Size. width height)))))