Mercurial > hg > indyvon
changeset 65:fd1bcb67bc32
New mechanism for layers to trigger repaints.
author | Mikhail Kryshen <mikhail@kryshen.net> |
---|---|
date | Fri, 27 Aug 2010 01:24:31 +0400 |
parents | 702a4939312d |
children | a1999c1f7289 |
files | src/net/kryshen/indyvon/component.clj src/net/kryshen/indyvon/core.clj src/net/kryshen/indyvon/demo.clj src/net/kryshen/indyvon/layers.clj |
diffstat | 4 files changed, 136 insertions(+), 110 deletions(-) [+] |
line diff
1.1 --- a/src/net/kryshen/indyvon/component.clj Thu Aug 26 06:29:30 2010 +0400 1.2 +++ b/src/net/kryshen/indyvon/component.clj Fri Aug 27 01:24:31 2010 +0400 1.3 @@ -17,22 +17,6 @@ 1.4 (defn- font-context [^Component component] 1.5 (.getFontRenderContext (.getFontMetrics component (.getFont component)))) 1.6 1.7 -(defn paint-component 1.8 - [^Component component layer ^Graphics2D graphics event-dispatcher] 1.9 - (let [size (.getSize component) 1.10 - width (.width size) 1.11 - height (.height size) 1.12 - update-fn #(.repaint component)] 1.13 - (.clearRect graphics 0 0 width height) 1.14 - (context-draw! layer component graphics event-dispatcher update-fn 1.15 - width height))) 1.16 - 1.17 -(defn preferred-size [component layer] 1.18 - (binding [*target* component 1.19 - *font-context*' (font-context component)] 1.20 - (let [s (layer-size layer)] 1.21 - (Dimension. (:width s) (:height s))))) 1.22 - 1.23 (defn make-jpanel 1.24 ([layer] 1.25 (make-jpanel layer (root-event-dispatcher))) 1.26 @@ -40,9 +24,13 @@ 1.27 (let [panel 1.28 (proxy [JPanel] [] 1.29 (paintComponent [g] 1.30 - (paint-component this layer g event-dispatcher)) 1.31 + (let [size (.getSize ^Component this)] 1.32 + (draw-root! layer g (.width size) (.height size) 1.33 + event-dispatcher this))) 1.34 (getPreferredSize [] 1.35 - (preferred-size this layer)))] 1.36 + (let [s (root-size layer (font-context this) this)] 1.37 + (Dimension. (:width s) (:height s)))))] 1.38 (.setBackground panel (:back-color *theme*)) 1.39 + (add-observer layer (fn [_] (.repaint panel))) 1.40 (listen! event-dispatcher panel) 1.41 panel)))
2.1 --- a/src/net/kryshen/indyvon/core.clj Thu Aug 26 06:29:30 2010 +0400 2.2 +++ b/src/net/kryshen/indyvon/core.clj Fri Aug 27 01:24:31 2010 +0400 2.3 @@ -29,11 +29,10 @@ 2.4 2.5 (def ^Shape *clip*) 2.6 2.7 +(def *root*) 2.8 + 2.9 (def *event-dispatcher*) 2.10 2.11 -(def ^{:doc "Fn to be called in a layer context to request redraw."} 2.12 - *update*) 2.13 - 2.14 (def ^{:tag AffineTransform 2.15 :doc "Initial transform associated with the graphics context"} 2.16 *initial-transform*) 2.17 @@ -143,6 +142,24 @@ 2.18 (doseq [f (reduce #(concat %1 (get %2 target)) nil (vals @observers))] 2.19 (apply f target args))) 2.20 2.21 +(defn repaint 2.22 + "Repaint the current scene." 2.23 + [] 2.24 + (update *root*)) 2.25 + 2.26 +(defn add-context-observer 2.27 + "Observer registered with this function will be automatically 2.28 + removed after the next frame rendering is complete." 2.29 + [target f] 2.30 + (let [root *root*] 2.31 + (add-observer target f root))) 2.32 + 2.33 +(defn repaint-on-update 2.34 + "Trigger repaint of the current scene when the target updates." 2.35 + [target] 2.36 + (let [root *root*] 2.37 + (add-observer target (fn [_] (update root)) root))) 2.38 + 2.39 ;; 2.40 ;; Rendering 2.41 ;; 2.42 @@ -283,33 +300,6 @@ 2.43 ([layer x y width height] 2.44 (with-bounds* x y width height render! layer))) 2.45 2.46 -;; TODO: объект-сцена вместо context-draw! 2.47 -;; Сцена устанавливает контекст и рисует слой. Сцена - слой? 2.48 -;; Сцена идентифицирует группу обозревателя слоев. 2.49 -;; Обновления любого слоя, изображенного в сцене, вызывает обновление сцены. 2.50 -;; Обозреватель сцены вызывает repaint(). 2.51 - 2.52 -(defn context-draw! 2.53 - "Sets up layer context, draws layer and commits event dispatcher." 2.54 - ([layer graphics event-dispatcher update-fn width height] 2.55 - (context-draw! layer nil graphics event-dispatcher update-fn width height)) 2.56 - ([layer component ^Graphics2D graphics event-dispatcher update-fn 2.57 - width height] 2.58 - (binding [*graphics* graphics 2.59 - *font-context* (.getFontRenderContext graphics) 2.60 - *initial-transform* (.getTransform graphics) 2.61 - *inverse-initial-transform* 2.62 - (-> graphics .getTransform .createInverse) 2.63 - *target* component 2.64 - *update* update-fn 2.65 - *event-dispatcher* event-dispatcher 2.66 - *width* width 2.67 - *height* height 2.68 - *clip* (Rectangle2D$Double. 0 0 width height)] 2.69 - (apply-theme) 2.70 - (render! layer) 2.71 - (commit event-dispatcher)))) 2.72 - 2.73 (defn draw-anchored! 2.74 "Draws layer. Location is relative to the layer's anchor point for 2.75 the specified alignment." 2.76 @@ -320,6 +310,41 @@ 2.77 (let [anchor (anchor layer h-align v-align)] 2.78 (draw! layer (- x (:x anchor)) (- y (:y anchor)) w h)))) 2.79 2.80 +(defn draw-root! 2.81 + "Draws the root layer." 2.82 + ([layer graphics width height event-dispatcher] 2.83 + (draw-root! layer graphics width height event-dispatcher nil)) 2.84 + ([layer ^Graphics2D graphics width height event-dispatcher target] 2.85 + (binding [*root* layer 2.86 + *target* target 2.87 + *graphics* graphics 2.88 + *font-context* (.getFontRenderContext graphics) 2.89 + *initial-transform* (.getTransform graphics) 2.90 + *inverse-initial-transform* 2.91 + (-> graphics .getTransform .createInverse) 2.92 + *event-dispatcher* event-dispatcher 2.93 + *width* width 2.94 + *height* height 2.95 + *clip* (Rectangle2D$Double. 0 0 width height)] 2.96 + (let [tmp-group (Object.)] 2.97 + (apply-theme) 2.98 + (.clearRect graphics 0 0 width height) 2.99 + (change-group-id layer tmp-group) 2.100 + (try 2.101 + (render! layer) 2.102 + (finally 2.103 + (remove-group tmp-group) 2.104 + (commit event-dispatcher))))))) 2.105 + 2.106 +(defn root-size 2.107 + ([layer font-context] 2.108 + (root-size layer font-context nil)) 2.109 + ([layer font-context target] 2.110 + (binding [*root* layer 2.111 + *target* target 2.112 + *font-context* font-context] 2.113 + (layer-size layer)))) 2.114 + 2.115 ;; 2.116 ;; EventDispatcher implementation 2.117 ;;
3.1 --- a/src/net/kryshen/indyvon/demo.clj Thu Aug 26 06:29:30 2010 +0400 3.2 +++ b/src/net/kryshen/indyvon/demo.clj Fri Aug 27 01:24:31 2010 +0400 3.3 @@ -76,7 +76,7 @@ 3.4 (reify 3.5 Layer 3.6 (render! [layer] 3.7 - ;;(*update*) 3.8 + ;;(repaint) 3.9 (doto *graphics* 3.10 (.setColor (rand-nth [Color/BLACK Color/BLUE Color/RED])) 3.11 (.drawLine 0 0 *width* *height*))
4.1 --- a/src/net/kryshen/indyvon/layers.clj Thu Aug 26 06:29:30 2010 +0400 4.2 +++ b/src/net/kryshen/indyvon/layers.clj Fri Aug 27 01:24:31 2010 +0400 4.3 @@ -145,11 +145,11 @@ 4.4 height (text-height layouts)] 4.5 (Size. width height))))))) 4.6 4.7 -(defn- ^ImageObserver image-observer [update-fn] 4.8 +(defn- ^ImageObserver image-observer [layer] 4.9 (reify 4.10 ImageObserver 4.11 (imageUpdate [this img infoflags x y width height] 4.12 - (update-fn) 4.13 + (update layer) 4.14 (zero? (bit-and infoflags 4.15 (bit-or ImageObserver/ALLBITS 4.16 ImageObserver/ABORT)))))) 4.17 @@ -164,72 +164,83 @@ 4.18 (reify 4.19 Layer 4.20 (render! [layer] 4.21 - (.drawImage *graphics* image 0 0 (image-observer *update*))) 4.22 + (repaint-on-update layer) 4.23 + (.drawImage *graphics* image 0 0 (image-observer layer))) 4.24 (layer-size [layer] 4.25 - (let [observer (image-observer *update*) 4.26 + (let [observer (image-observer layer) 4.27 width (.getWidth image observer) 4.28 height (.getHeight image observer) 4.29 width (if (pos? width) width 1) 4.30 height (if (pos? height) height 1)] 4.31 (Size. width height)))))) 4.32 4.33 -(defn async-layer 4.34 +(defn- create-buffer [async-layer] 4.35 + (BufferedImage. (:width async-layer) (:height async-layer) 4.36 + BufferedImage/TYPE_INT_ARGB)) 4.37 + 4.38 +(defn- draw-offscreen [async-layer] 4.39 + ;;(Thread/sleep 3000) 4.40 + (let [buffers (:buffers async-layer) 4.41 + ^Image b (dosync 4.42 + (let [b (peek @buffers)] 4.43 + (alter buffers pop) 4.44 + b))] 4.45 + (try 4.46 + ;; TODO: use operational event dispatcher. 4.47 + (draw-root! (:content async-layer) 4.48 + (.getGraphics b) 4.49 + (:width async-layer) 4.50 + (:height async-layer) 4.51 + dummy-event-dispatcher) 4.52 + (finally 4.53 + (dosync 4.54 + (alter buffers conj b) 4.55 + (ref-set (:updated async-layer) true)))) 4.56 + (update async-layer))) 4.57 + 4.58 +(defn- draw-offscreen-async [async-layer] 4.59 + (.execute ^ThreadPoolExecutor (:executor async-layer) 4.60 + #(draw-offscreen async-layer))) 4.61 + 4.62 +(defrecord AsyncLayer [content width height executor buffers updated] 4.63 + Layer 4.64 + (render! [layer] 4.65 + (repaint-on-update layer) 4.66 + (add-context-observer content (fn [_] (draw-offscreen-async layer))) 4.67 + (when-not @buffers 4.68 + ;; TODO: dynamic size, recreate buffers when size increases. 4.69 + (let [new-buffers [(create-buffer layer) (create-buffer layer)]] 4.70 + (dosync 4.71 + (ref-set buffers new-buffers))) 4.72 + (draw-offscreen-async layer)) 4.73 + (let [buffer (dosync 4.74 + (if @updated 4.75 + (let [b (peek @buffers)] 4.76 + (alter buffers pop) 4.77 + (ref-set updated false) 4.78 + b) 4.79 + (let [b (first @buffers)] 4.80 + (alter buffers subvec 1) 4.81 + b)))] 4.82 + (.drawImage *graphics* ^Image buffer 0 0 nil) 4.83 + (dosync 4.84 + (alter buffers #(vec (cons buffer %)))))) 4.85 + (layer-size [layer] 4.86 + (Size. width height))) 4.87 + 4.88 +(defn async-layer 4.89 "Creates layer that draws the content asynchroniously in an 4.90 offscreen buffer." 4.91 [content width height] 4.92 - (let [executor (ThreadPoolExecutor. (int 1) (int 1) (long 0) TimeUnit/SECONDS 4.93 - (ArrayBlockingQueue. 1) 4.94 - (ThreadPoolExecutor$DiscardOldestPolicy.)) 4.95 - buffers (ref nil) 4.96 - updated (ref false) 4.97 - update-fn (ref nil) 4.98 - create-buffer 4.99 - #(BufferedImage. width height BufferedImage/TYPE_INT_ARGB) 4.100 - draw-offscreen 4.101 - (fn draw-offscreen [] 4.102 - ;;(Thread/sleep 3000) 4.103 - (let [^Image b (dosync 4.104 - (let [b (peek @buffers)] 4.105 - (alter buffers pop) 4.106 - b))] 4.107 - (try 4.108 - ;; TODO: use operational event dispatcher. 4.109 - (context-draw! content 4.110 - (.getGraphics b) 4.111 - dummy-event-dispatcher 4.112 - #(.execute executor draw-offscreen) 4.113 - width height) 4.114 - (finally 4.115 - (dosync 4.116 - (alter buffers conj b) 4.117 - (ref-set updated true)))) 4.118 - (update-fn)))] 4.119 - (reify 4.120 - Layer 4.121 - (render! [layer] 4.122 - (when-not @buffers 4.123 - ;; TODO: dynamic size, recreate buffers when size increases. 4.124 - (let [new-buffers [(create-buffer) (create-buffer)]] 4.125 - (dosync 4.126 - (ref-set buffers new-buffers) 4.127 - (ref-set update-fn *update*))) 4.128 - (.execute executor draw-offscreen)) 4.129 - (let [buffer (dosync 4.130 - (ref-set update-fn *update*) 4.131 - (if @updated 4.132 - (let [b (peek @buffers)] 4.133 - (alter buffers pop) 4.134 - (ref-set updated false) 4.135 - b) 4.136 - (let [b (first @buffers)] 4.137 - (alter buffers subvec 1) 4.138 - b)))] 4.139 - (.drawImage *graphics* ^Image buffer 0 0 nil) 4.140 - (dosync 4.141 - (alter buffers #(vec (cons buffer %)))))) 4.142 - (layer-size [layer] 4.143 - (Size. width height))))) 4.144 - 4.145 + (AsyncLayer. content width height 4.146 + (ThreadPoolExecutor. 4.147 + (int 1) (int 1) 4.148 + (long 0) TimeUnit/SECONDS 4.149 + (ArrayBlockingQueue. 1) 4.150 + (ThreadPoolExecutor$DiscardOldestPolicy.)) 4.151 + (ref nil) 4.152 + (ref false))) 4.153 + 4.154 (defn miniature 4.155 "Creates layer that asynchroniously renders view of the content 4.156 scaled to the specified size." 4.157 @@ -272,16 +283,18 @@ 4.158 (dosync 4.159 (ref-set fix-x (:x-on-screen e)) 4.160 (ref-set fix-y (:y-on-screen e))) 4.161 - (->> Cursor/MOVE_CURSOR Cursor. (.setCursor *target*))) 4.162 + (when *target* 4.163 + (->> Cursor/MOVE_CURSOR Cursor. (.setCursor *target*)))) 4.164 (:mouse-released e 4.165 - (->> Cursor/DEFAULT_CURSOR Cursor. (.setCursor *target*))) 4.166 + (when *target* 4.167 + (->> Cursor/DEFAULT_CURSOR Cursor. (.setCursor *target*)))) 4.168 (:mouse-dragged e 4.169 (dosync 4.170 (alter x + (- @fix-x (:x-on-screen e))) 4.171 (alter y + (- @fix-y (:y-on-screen e))) 4.172 (ref-set fix-x (:x-on-screen e)) 4.173 (ref-set fix-y (:y-on-screen e))) 4.174 - (*update*)))) 4.175 + (repaint)))) 4.176 (layer-size [layer] (layer-size content)))))) 4.177 4.178 ;;