diff --git a/project.clj b/project.clj index 84ff732..3048b6f 100644 --- a/project.clj +++ b/project.clj @@ -6,35 +6,28 @@ :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies - [[org.clojure/clojure "1.10.3"] + [[org.clojure/clojure "1.8.0"] [com.google.guava/guava "20.0"] [org.openpnp/opencv "2.4.11-1"] - [quil "3.1.0"] [cheshire "5.10.1"] - [de.schlichtherle.truezip/truezip-file "7.7.9"] - [de.schlichtherle.truezip/truezip-driver-zip "7.7.9"] + [de.schlichtherle.truezip/truezip-file "7.7.10"] + [de.schlichtherle.truezip/truezip-driver-zip "7.7.10"] - [kuusisto/tinysound "1.1.1"] [io.socket/socket.io-client "0.9.0"] - [org.clojure/tools.logging "0.3.1"] + [org.clojure/tools.logging "1.1.0"] - [log4j "1.2.16"] - [org.slf4j/slf4j-api "1.6.2"] - [org.slf4j/jul-to-slf4j "1.6.2"] - [org.slf4j/slf4j-log4j12 "1.6.2"] + [log4j "1.2.17"] + [org.slf4j/slf4j-api "1.7.32"] + [org.slf4j/jul-to-slf4j "1.7.32"] + [org.slf4j/slf4j-log4j12 "1.7.32"] [org.nd4j/nd4j "0.4-rc3.10" :extension "pom"] [org.nd4j/nd4j-native "0.4-rc3.10"] [org.deeplearning4j/deeplearning4j-core "0.4-rc3.10"] [org.nd4j/canova-api "0.0.0.16"]] - ;:repositories {"yadarts-maven" "https://raw.github.com/yadarts/maven/master"} - :jvm-opts - ["-Djavax.net.ssl.trustStore=resources/ogs.truststore" - "-Xms1024M" "-Xmx2048M" "-XX:NewSize=528M" "-XX:+UseParNewGC" "-XX:+UseConcMarkSweepGC" - "-XX:+CMSParallelRemarkEnabled" "-server" "-XX:-OmitStackTraceInFastThrow"] :main igoki.core :repl-options @@ -42,8 +35,6 @@ :init-ns igoki.core :init (-main)} - :min-lein-version "2.5.0" + #_#_:min-lein-version "2.5.0" - :uberjar-name "igoki.jar" - - :resource-paths ["resources"]) + :uberjar-name "igoki.jar") diff --git a/src/igoki/game.clj b/src/igoki/game.clj index 7886773..456fcce 100644 --- a/src/igoki/game.clj +++ b/src/igoki/game.clj @@ -5,15 +5,16 @@ [igoki.util :as util] [igoki.sgf :as sgf] [igoki.inferrence :as inferrence] - [quil.core :as q] - [igoki.sound.sound :as snd]) + [igoki.sound.sound :as snd] + [igoki.litequil :as lq]) (:import (java.io File ByteArrayInputStream) (java.util Date UUID) (java.text SimpleDateFormat) (org.opencv.highgui Highgui) (org.opencv.core MatOfByte) - (de.schlichtherle.truezip.file TVFS))) + (de.schlichtherle.truezip.file TVFS) + (java.awt.image BufferedImage))) ;; ======================================================== ;; TODO: Display sibling branches @@ -227,129 +228,138 @@ (last actionlist))) (defmethod ui/draw :kifu [ctx] - (q/stroke-weight 1) - (q/stroke 0) - (q/fill 128 64 78) - (q/rect 0 0 (q/width) (q/height)) + (lq/stroke-weight 1) + (lq/color 0) + (lq/background 128 64 78) + (lq/rect 0 0 (lq/width) (lq/height)) ;; Draw the board (let [{{:keys [submit kifu-board constructed movenumber] :as game} :kifu {:keys [pimg]} :camera board :board {:keys [size]} :goban} @ctx - cellsize (/ (q/height) (+ size 2)) + cellsize (/ (lq/height) (+ size 2)) grid-start (+ cellsize (/ cellsize 2)) - tx (+ (q/height) (/ cellsize 2)) + tx (+ (lq/height) (/ cellsize 2)) visiblepath (take movenumber (mapcat identity (:current-branch-path game))) actionlist (sgf/current-branch-node-list [visiblepath] (:moves game)) lastmove (last actionlist)] - (when pimg - (q/image-mode :corners) - (q/image (:pimg pimg) - (q/height) - (- (q/height) (* (- (q/width) (q/height)) (/ (.height (:pimg pimg)) (.width (:pimg pimg))))) - (q/width) (q/height))) - (ui/shadow-text (str "Recording: Img #" (:camidx game)) tx 25) + ;; TODO: This should become its own panel and use a layout mechanism instead of manually calculating pixels. + (when pimg + ;; Placing this on the far side, below instructions + (lq/image (:bufimg pimg) + (lq/height) + (- + (lq/height) + (* + (- (lq/width) (lq/height)) + (/ + (.getHeight ^BufferedImage (:bufimg pimg)) + (.getWidth ^BufferedImage (:bufimg pimg))))) + (lq/width) + (lq/height))) + + (lq/shadow-text (str "Recording: Img #" (:camidx game)) tx 25) (when (:filename game) - (ui/shadow-text (:filename game) tx 50)) - (ui/shadow-text (str "Move " (inc movenumber) ", " (if (= (:player-turn constructed) :black) "Black" "White") " to play") tx 75) - (ui/shadow-text " Reset, Back" tx 125) - (ui/shadow-text " Back to camera diff view" tx 150) - (ui/shadow-text " Export, Load SGF" tx 175) - (ui/shadow-text " Toggle show branches" tx 200) - (ui/shadow-text "

Pass" tx 225) - - (q/fill 220 179 92) - (q/rect 0 0 (q/height) (q/height)) - (q/stroke-weight 0.8) - (q/stroke-cap :square) - (q/stroke 0 196) - - (q/fill 0) + (lq/shadow-text (:filename game) tx 50)) + (lq/shadow-text (str "Move " (inc movenumber) ", " (if (= (:player-turn constructed) :black) "Black" "White") " to play") tx 75) + (lq/shadow-text " Reset, Back" tx 125) + (lq/shadow-text " Back to camera diff view" tx 150) + (lq/shadow-text " Export, Load SGF" tx 175) + (lq/shadow-text " Toggle show branches" tx 200) + (lq/shadow-text "

Pass" tx 225) + + (lq/background 220 179 92) + (lq/rect 0 0 (lq/height) (lq/height)) + + (lq/stroke-weight 0.8) + #_(lq/stroke-cap :square) + (lq/color 0 196) + (lq/background 0) ;; Draw the grid - (q/text-font (q/create-font "Helvetica" 20)) + (lq/text-font "helvetica-20pt") + (doseq [x (range size)] (let [coord (+ grid-start (* x cellsize)) extent (+ grid-start (* cellsize (dec size))) x-offset (if (> x 7) 66 65)] - (q/text-align :center :bottom) - (q/text (str (inc x)) coord (- grid-start (/ cellsize 2))) - (q/text-align :center :top) - (q/text (str (inc x)) coord (+ extent (/ cellsize 2))) + (lq/text (str (inc x)) coord (- grid-start (/ cellsize 2)) + {:align [:center :bottom]}) + (lq/text (str (inc x)) coord (+ extent (/ cellsize 2)) + {:align [:center :top]}) - (q/text-align :right :center) - (q/text (str (inc x)) (- grid-start (/ cellsize 2)) coord) - (q/text-align :left :center) - (q/text (str (inc x)) (+ extent (/ cellsize 2)) coord) + (lq/text (str (inc x)) + (- grid-start (/ cellsize 2)) coord + {:align [:right :center]}) + (lq/text (str (inc x)) (+ extent (/ cellsize 2)) coord + {:align [:left :center]}) - (q/line coord grid-start coord extent) - (q/line grid-start coord extent coord))) + (lq/line coord grid-start coord extent) + (lq/line grid-start coord extent coord))) ;; Draw star points (doseq [[x y] (util/star-points size)] - (q/stroke-weight 1) - (q/stroke 0 32) - (q/fill 0) - (q/ellipse (+ grid-start (* x cellsize)) - (+ grid-start (* y cellsize)) 6 6)) + (lq/stroke-weight 1) + (lq/color 0 32) + (lq/background 0) + (lq/ellipse + (+ grid-start (* x cellsize)) + (+ grid-start (* y cellsize)) 6 6)) ;; Draw camera board (shadow) (doseq [[y row] (map-indexed vector board) [x d] (map-indexed vector row)] (when d - (q/stroke-weight 1) - (q/stroke 0 32) - (q/fill (if (= d :w) 255 0) 32) - (q/ellipse (+ grid-start (* x cellsize)) - (+ grid-start (* y cellsize)) (- cellsize 3) (- cellsize 3)))) + (lq/stroke-weight 1) + (lq/color 0 32) + (lq/background (if (= d :w) 255 0) 32) + (lq/ellipse + (+ grid-start (* x cellsize)) + (+ grid-start (* y cellsize)) + (- cellsize 3) (- cellsize 3)))) + + (lq/text-size 12) - (q/text-size 12) ;; Draw the constructed sgf board stones (doseq [[pt {:keys [stone] mn :movenumber}] (:board constructed)] (let [[x y :as p] (sgf/convert-sgf-coord pt)] (when (and p stone) - (q/stroke-weight 0.5) - (q/stroke 0) - (q/fill (if (= stone :white) 255 0)) - (q/ellipse (+ grid-start (* x cellsize)) + (lq/stroke-weight 0.5) + (lq/color 0) + (lq/background (if (= stone :white) 255 0)) + (lq/ellipse (+ grid-start (* x cellsize)) (+ grid-start (* y cellsize)) (- cellsize 2) (- cellsize 2)) - (q/fill (if (= stone :white) 0 255))) + (lq/background (if (= stone :white) 0 255))) (when (and (not stone) mn) - (q/stroke-weight 0) - (q/stroke 220 179 92) - (q/fill 220 179 92) - (q/ellipse (+ grid-start (* x cellsize)) + (lq/stroke-weight 0) + (lq/color 220 179 92) + (lq/background 220 179 92) + (lq/ellipse (+ grid-start (* x cellsize)) (+ grid-start (* y cellsize)) 20 20) - (q/fill 0)) + (lq/background 0)) (when (and mn (< (- movenumber mn) 40)) (let [movediff (- movenumber mn) movenum (mod (inc mn) 100) movecol (get-in move-colours [(int (/ mn 100)) (or stone :black)] [0 0 0]) movecol (if (> movediff 20) (conj movecol (- 255 (* 255 (/ (- movediff 20) 20)))) movecol)] - (apply q/fill movecol) - #_(when (>= (inc movenumber) 100) - (q/fill 255 0 0)) - (q/text-size 12) - (q/text-align :center :center) - (q/text (str movenum) (+ grid-start (* x cellsize)) (- (+ grid-start (* y cellsize)) 1)))))) + (apply lq/color movecol) + (lq/text-size 12) + (lq/text (str movenum) (+ grid-start (* x cellsize)) (- (+ grid-start (* y cellsize)) 1) + {:align [:center :center]}))))) (when (:comment lastmove) - (when (not= (:comment-spoken game) visiblepath) - (swap! ctx assoc-in [:kifu :comment-spoken] visiblepath) - (.exec (Runtime/getRuntime) (str "say " (:comment lastmove)))) - (q/text-align :left :top) - - (q/fill 255) - (q/text-size 12) - (q/text (first (:comment lastmove)) tx 240 (- (q/width) tx) (q/height))) + (lq/color 255) + (lq/text-size 12) + (lq/text (first (:comment lastmove)) tx 240 (- (lq/width) tx) (lq/height) + {:align [:left :top]})) ;; Draw labels @@ -361,43 +371,43 @@ (cond (= stone :w) (do - (q/fill 255) - (q/stroke 255)) + (lq/background 255) + (lq/color 255)) (= stone :b) (do - (q/fill 0) - (q/stroke 0)) + (lq/background 0) + (lq/color 0)) :else (do - (q/fill 220 179 92) - (q/stroke 220 179 92))) + (lq/background 220 179 92) + (lq/color 220 179 92))) - (q/stroke-weight 0) - (q/ellipse (+ grid-start (* x cellsize)) + (lq/stroke-weight 0) + (lq/ellipse (+ grid-start (* x cellsize)) (+ grid-start (* y cellsize)) (/ cellsize 1.5) (/ cellsize 1.5)) - (q/fill (if (= stone :b) 255 0)) + (lq/background (if (= stone :b) 255 0)) - (q/text-align :center :center) - (q/text + (lq/text text (+ grid-start (* x cellsize)) - (- (+ grid-start (* y cellsize)) 1)))) - #_(println (:triangle lastmove)) + (- (+ grid-start (* y cellsize)) 1) + {:align [:center :center]}))) ;; Draw annotated triangles. (doseq [pt (:triangle lastmove)] (let [[x y :as p] (sgf/convert-sgf-coord pt) stone (nth (nth kifu-board y) x)] - (q/stroke-weight 0) - (apply q/fill (cond (= stone :b) [0] (= stone :w) [255] :else [220 179 92])) - (q/ellipse (+ grid-start (* x cellsize)) + (lq/stroke-weight 0) + (apply lq/background (cond (= stone :b) [0] (= stone :w) [255] :else [220 179 92])) + (lq/ellipse (+ grid-start (* x cellsize)) (+ grid-start (* y cellsize)) (/ cellsize 1.1) (/ cellsize 1.1)) - (q/stroke-weight 2) - (q/stroke (if (= stone :b) 255 0)) - (q/triangle + + (lq/stroke-weight 2) + (lq/color (if (= stone :b) 255 0)) + (lq/triangle (+ grid-start (* x cellsize)) (- (+ grid-start (* y cellsize)) 6) (- (+ grid-start (* x cellsize)) 6) (+ (+ grid-start (* y cellsize)) 4.5) (+ (+ grid-start (* x cellsize)) 6) (+ (+ grid-start (* y cellsize)) 4.5)))) @@ -405,14 +415,16 @@ ;; If in the process of submitting, mark that stone. (when submit #_(let [[x y _ d] (:move submit)] - (q/stroke-weight 1) - (q/stroke 0 128) - (q/fill (if (= d :w) 255 0) 128) - (q/ellipse (+ grid-start (* x cellsize)) - (+ grid-start (* y cellsize)) (- cellsize 3) (- cellsize 3)) - (q/fill (if (= d :w) 0 255)) - (q/text-align :center :center) - (q/text "?" (+ grid-start (* x cellsize)) (+ grid-start (* y cellsize))))) + (lq/stroke-weight 1) + (lq/stroke 0 128) + (lq/background (if (= d :w) 255 0) 128) + (lq/ellipse + (+ grid-start (* x cellsize)) + (+ grid-start (* y cellsize)) + (- cellsize 3) (- cellsize 3)) + (lq/background (if (= d :w) 0 255)) + (lq/text "?" (+ grid-start (* xcellsize)) (+ grid-start (* y cellsize)) + {:align [:center :center]}))) ;; Mark the last move (when lastmove @@ -420,10 +432,10 @@ (doseq [m (or black white)] (let [[x y :as p] (sgf/convert-sgf-coord m)] (when p - (q/stroke (if white 0 255)) - (q/stroke-weight 3) - (q/fill 0 0) - (q/ellipse (+ grid-start (* x cellsize)) + (lq/color (if white 0 255)) + (lq/stroke-weight 3) + (lq/background 0 0) + (lq/ellipse (+ grid-start (* x cellsize)) (+ grid-start (* y cellsize)) (/ cellsize 2) (/ cellsize 2)))))) ;; Mark next branches @@ -433,16 +445,17 @@ (let [[x y :as p] (sgf/convert-sgf-coord m)] (when p (if (zero? idx) - (q/stroke (if white 255 0)) - (apply q/stroke (if white [255 0 0] [0 0 255]))) - (q/stroke-weight 3) - (q/fill 0 0) - (q/ellipse (+ grid-start (* x cellsize)) + (lq/color (if white 255 0)) + (apply lq/color (if white [255 0 0] [0 0 255]))) + (lq/stroke-weight 3) + (lq/background 0 0) + (lq/ellipse (+ grid-start (* x cellsize)) (+ grid-start (* y cellsize)) (/ cellsize 2) (/ cellsize 2)) - (q/fill 0) + (lq/background 0) + (when (pos? idx) - (q/text-size 9) - (q/text + (lq/text-size 9) + (lq/text (str idx) (- (+ grid-start (* x cellsize)) 9) (- (+ grid-start (* y cellsize)) 9)))))))) @@ -451,10 +464,10 @@ (when (and board kifu-board) (doseq [[x y _ _] (board-diff kifu-board board)] - (q/stroke-weight 3) - (q/stroke 255 0 0) - (q/fill 0 0) - (q/ellipse (+ grid-start (* x cellsize)) + (lq/stroke-weight 3) + (lq/color 255 0 0) + (lq/background 0 0) + (lq/ellipse (+ grid-start (* x cellsize)) (+ grid-start (* y cellsize)) (- cellsize 3) (- cellsize 3)))))) (defn export-sgf [ctx] @@ -496,9 +509,8 @@ :kifu (inferrence/play-move kifu [-1 -1 nil ({:white :w :black :b} (-> kifu :constructed :player-turn))])))) -(defmethod ui/key-pressed :kifu [ctx] - (case - (q/key-code) +(defmethod ui/key-pressed :kifu [ctx e] + (case (lq/key-code e) 67 (ui/transition ctx :goban) 86 (ui/transition ctx :goban) 82 (reset-kifu ctx) @@ -508,4 +520,4 @@ 37 (swap! ctx move-backward) 39 (swap! ctx move-forward) 80 (swap! ctx pass) - (println "Key code not handled: " (q/key-code)))) + (println "Key code not handled: " (lq/key-code e)))) diff --git a/src/igoki/goban.clj b/src/igoki/goban.clj index 46e9513..7eef08c 100644 --- a/src/igoki/goban.clj +++ b/src/igoki/goban.clj @@ -3,12 +3,12 @@ [igoki.util :as util] [igoki.ui :as ui] [igoki.view :as view] - [quil.core :as q] - [igoki.simulated :as sim]) + [igoki.simulated :as sim] + [igoki.litequil :as lq]) (:import - (processing.core PImage) (org.opencv.core Mat MatOfPoint2f Core Scalar TermCriteria Size Point) - (org.opencv.imgproc Imgproc))) + (org.opencv.imgproc Imgproc) + (java.awt.image BufferedImage))) (defn start-simulation [ctx] (sim/stop) @@ -144,7 +144,7 @@ (doseq [p (seq (.toArray pts2f))] (Core/circle cropped p 2 (Scalar. 255 0 255) 3))) (swap! ctx assoc-in [:goban :flat] - (util/mat-to-pimage bilat nil nil)) + (util/mat-to-pimage bilat nil)) #_(util/write-mat pts))) @@ -167,72 +167,74 @@ (defmethod ui/destruct :goban [ctx] (remove-watch ctx :goban-camera)) -(defn convert-point [pimg [px py]] - [(/ (* px (q/width)) (.width pimg)) - (/ (* py (q/height)) (.height pimg))]) +(defn convert-point [bufimg [px py]] + [(/ (* px (lq/width)) (.getWidth bufimg)) + (/ (* py (lq/height)) (.getHeight bufimg))]) (def pn ["A19" "T19" "T1" "A1"]) (defmethod ui/draw :goban [ctx] - (q/frame-rate 20) - (q/fill 128 64 78) - (q/rect 0 0 (q/width) (q/height)) + (lq/frame-rate 20) + (lq/background 128 64 78) + (lq/rect 0 0 (lq/width) (lq/height)) - (let [c (-> @ctx :camera :pimg :pimg)] + (let [c (-> @ctx :camera :pimg :bufimg)] (cond (nil? c) - (ui/shadow-text "Could not acquire image?" 10 25) + (lq/shadow-text "Could not acquire image?" 10 25) + :else (let [{{:keys [size edges points lines flat flat-view? camerapoints]} :goban board :board} @ctx points (map (partial convert-point c) points) edges (map #(map (partial convert-point c) %) edges)] - (q/image c 0 0 (q/width) (q/height)) - (ui/shadow-text "Please select the corners of the board" 10 25) + (lq/image c 0 0 (lq/width) (lq/height)) + (lq/shadow-text "Please select the corners of the board" 10 25) - (ui/shadow-text " Cycle 9x9, 13x13 and 19x19. " 10 50) - (ui/shadow-text " Confirm Calibration" 10 75) - (ui/shadow-text " Toggle flat view" 10 100) - (ui/shadow-text "<1..5> Camera Sources" 10 125) - (ui/shadow-text " Camera Sim" 10 150) + (lq/shadow-text " Cycle 9x9, 13x13 and 19x19. " 10 50) + (lq/shadow-text " Confirm Calibration" 10 75) + (lq/shadow-text " Toggle flat view" 10 100) + (lq/shadow-text "<1..5> Camera Sources" 10 125) + (lq/shadow-text " Camera Sim" 10 150) - (q/stroke 255 255 255 128) - (q/stroke-weight 0.5) + (lq/color 255 255 255 128) + (lq/stroke-weight 0.5) (when (and camerapoints board size) (doseq [[idx p] (map-indexed vector camerapoints) :let [[px py] (convert-point c p) stone (get-in board [(int (/ idx size)) (mod idx size)])] :when stone] (if (= stone :b) - (do (q/fill 0 0 0) (q/stroke 255 255 255)) - (do (q/fill 255 255 255) (q/stroke 0 0 0))) - (q/ellipse px py 10 10))) + (do (lq/background 0 0 0) (lq/color 255 255 255)) + (do (lq/background 255 255 255) (lq/color 0 0 0))) + (lq/ellipse px py 10 10))) - (q/stroke 255 255 255 96) - (q/stroke-weight 1) + (lq/color 255 255 255 96) + (lq/stroke-weight 1) (when lines (doseq [[p1 p2] lines] - (q/line (convert-point c p1) (convert-point c p2))) - (ui/shadow-text + (lq/line (convert-point c p1) (convert-point c p2))) + (lq/shadow-text (str size "x" size) (/ (reduce + (map first points)) 4) (/ (reduce + (map second points)) 4) :center :bottom)) - (q/stroke 78 64 255 128) - (q/stroke-weight 2) + (lq/color 78 64 255 128) + (lq/stroke-weight 2) (doseq [[p1 p2] edges] - (q/line p1 p2)) + (lq/line p1 p2)) + - (q/text-align :center :bottom) (doseq [[p [x y]] (map-indexed vector points)] - (q/text (get pn p) x (- y 5)) - (q/ellipse x y 2 2)) + (lq/text (get pn p) x (- y 5) + {:align [:center :bottom]}) + (lq/ellipse x y 2 2)) (when (and flat flat-view?) - (q/image (:pimg flat) 0 0 (q/width) (q/height))))))) + (lq/image (:bufimg flat) 0 0 (lq/width) (lq/height))))))) (defn update-corners [ctx points] (swap! ctx update :goban @@ -244,10 +246,10 @@ (reverse-transform ctx)) -(defmethod ui/mouse-dragged :goban [ctx] - (when-let [c ^PImage (-> @ctx :camera :pimg :pimg)] - (let [px (/ (* (q/mouse-x) (.width c)) (q/width)) - py (/ (* (- (q/mouse-y) 5) (.height c)) (q/height)) +(defmethod ui/mouse-dragged :goban [ctx e] + (when-let [c ^BufferedImage (-> @ctx :camera :pimg :bufimg)] + (let [px (/ (* (lq/mouse-x) (.getWidth c)) (lq/width)) + py (/ (* (- (lq/mouse-y) 5) (.getHeight c)) (lq/height)) p [px py] points (-> @ctx :goban :points) points @@ -256,18 +258,17 @@ (vec (conj points p)))] (update-corners ctx points)))) -(defmethod ui/mouse-pressed :goban [ctx] - (ui/mouse-dragged ctx)) +(defmethod ui/mouse-pressed :goban [ctx e] + (ui/mouse-dragged ctx e)) -(defmethod ui/mouse-released :goban [ctx] +(defmethod ui/mouse-released :goban [ctx e] (reverse-transform ctx)) (defn cycle-corners [ctx] (update-corners ctx (vec (take 4 (drop 1 (cycle (-> @ctx :goban :points))))))) -(defmethod ui/key-pressed :goban [ctx] - (case - (q/key-code) +(defmethod ui/key-pressed :goban [ctx e] + (case (lq/key-code e) 10 (ui/transition ctx :kifu) 9 @@ -285,9 +286,12 @@ 83 (start-simulation ctx) 32 (swap! ctx update-in [:goban :flat-view?] (fnil not false)) 67 (cycle-corners ctx) - (println "Unhandled key-down: " (q/key-code)))) + (println "Unhandled key-down: " (lq/key-code e)))) + + (comment + ;; What was this again? maybe delete. (let [f (fn [[x1 y1 x2 y2]] (* (/ 180 Math/PI) (Math/atan2 (- x2 x1) (- y2 y1)))) diff --git a/src/igoki/litequil.clj b/src/igoki/litequil.clj new file mode 100644 index 0000000..ff0e41a --- /dev/null +++ b/src/igoki/litequil.clj @@ -0,0 +1,264 @@ +(ns igoki.litequil + (:import + (javax.swing JPanel JFrame SwingUtilities WindowConstants) + (java.awt Graphics2D Container Component Dimension Color Stroke Image BasicStroke RenderingHints Font Rectangle Polygon) + (java.awt.event MouseListener MouseEvent MouseMotionListener KeyListener KeyEvent WindowStateListener) + (java.awt.geom Ellipse2D$Double Rectangle2D))) + +;; We desperately need to move off Processing. It doesn't compose well, so this implements the same +;; abstractions we use in quil, but directly in a jpanel, which will let us do more UI things +;; in basic Swing later. + +(def ^:dynamic ^JPanel panel nil) +(def ^:dynamic ^Graphics2D g2d nil) + +(defn input-action [local-panel options e k] + (let [afn (get options k)] + (if afn + (with-bindings + {#'panel local-panel + #'g2d (.getGraphics local-panel)} + (afn e))))) + +(defn sketch [options] + (let [{:keys [title size draw setup]} options + + local-frame (JFrame. ^String title) + local-panel + (proxy [JPanel] [] + (paint [^Graphics2D local-g2d] + (when draw + (with-bindings + {#'panel this + #'g2d local-g2d} + (draw)))))] + + (.setFocusable local-panel true) + (when size + (let [[w h] size] + (.setSize local-panel (Dimension. w h)) + (.setPreferredSize local-panel (Dimension. w h)))) + + (.addMouseListener local-panel + (proxy [MouseListener] [] + (mouseClicked [^MouseEvent e] + (input-action local-panel options e :mouse-clicked)) + (mousePressed [^MouseEvent e] + (input-action local-panel options e :mouse-pressed)) + (mouseReleased [^MouseEvent e] + (input-action local-panel options e :mouse-released)) + (mouseEntered [^MouseEvent e] + (input-action local-panel options e :mouse-entered)) + (mouseExited [^MouseEvent e] + (input-action local-panel options e :mouse-exited)))) + + (.addMouseMotionListener local-panel + (proxy [MouseMotionListener] [] + (mouseDragged [^MouseEvent e] + (input-action local-panel options e :mouse-dragged)) + (mouseMoved [^MouseEvent e] + (input-action local-panel options e :mouse-moved)))) + + (.addKeyListener local-panel + (proxy [KeyListener] [] + (keyPressed [^KeyEvent e] + (input-action local-panel options e :key-pressed)) + (keyReleased [^KeyEvent e] + (input-action local-panel options e :key-released)) + (keyTyped [^KeyEvent e] + (input-action local-panel options e :key-typed)))) + + + (.add (.getContentPane local-frame) local-panel) + ; + (doto local-frame + (.pack) + (.setDefaultCloseOperation WindowConstants/EXIT_ON_CLOSE) + (.setResizable true) + (.setVisible true)) + + + (doto + (Thread. + #(while (and (.isVisible local-frame)) + (Thread/sleep 250) + (.repaint local-panel))) + + (.setDaemon true) + (.start)) + + (.grabFocus local-panel) + + (when setup + (with-bindings + {#'panel local-panel + #'g2d (.getGraphics local-panel)} + (setup))) + + {:panel local-panel + :frame local-frame + :options options})) + +(defn smooth [] + (doto g2d + (.setRenderingHint RenderingHints/KEY_ANTIALIASING + RenderingHints/VALUE_ANTIALIAS_ON) + (.setRenderingHint RenderingHints/KEY_FRACTIONALMETRICS + RenderingHints/VALUE_FRACTIONALMETRICS_ON) + (.setRenderingHint RenderingHints/KEY_INTERPOLATION + RenderingHints/VALUE_INTERPOLATION_BICUBIC))) + +(defn frame-rate [rate]) +(defn width [] + (.getWidth panel)) + +(defn height [] + (.getHeight panel)) + +(defn color + ([g] + (.setColor g2d (Color. (int g) (int g) (int g)))) + ([g a] + (.setColor g2d (Color. (int g) (int g) (int g) (int a)))) + ([r g b] + (.setColor g2d (Color. (int r) (int g) (int b)))) + ([r g b a] + (.setColor g2d (Color. (int r) (int g) (int b) (int a))))) + +(defn background + ([g] + (.setBackground g2d (Color. (int g) (int g) (int g)))) + ([g a] + (.setBackground g2d (Color. (int g) (int g) (int g) (int a)))) + ([r g b] + (.setBackground g2d (Color. (int r) (int g) (int b)))) + ([r g b a] + (.setBackground g2d (Color. (int r) (int g) (int b) (int a))))) + +(defn stroke-weight [width] + (.setStroke g2d (BasicStroke. width))) + + + +(defn rect [x y w h] + (.clearRect g2d x y w h) + (.drawRect g2d x y w h)) + +(defn ellipse [x y w h] + (let [e (Ellipse2D$Double. (- x (/ w 2)) (- y (/ h 2)) w h) + bg (.getBackground g2d) + c (.getColor g2d)] + (.setColor g2d bg) + (.fill g2d e) + (.setColor g2d c) + (.draw g2d e))) + +(defn triangle [x1 y1 x2 y2 x3 y3] + (let [t (doto (Polygon.) + (.addPoint x1 y1) + (.addPoint x2 y2) + (.addPoint x3 y3) + (.addPoint x1 y1)) + bg (.getBackground g2d) + c (.getColor g2d)] + (.setColor g2d bg) + (.fill g2d t) + (.setColor g2d c) + (.draw g2d t))) + +(defn line + ([[x1 y1] [x2 y2]] + (line x1 y1 x2 y2)) + ([x1 y1 x2 y2] + (.drawLine g2d x1 y1 x2 y2))) + +(defn text-size [size] + (.setFont g2d + (.deriveFont (.getFont g2d) (float size)))) + +(defn calculate-horiz-offset [alignh ^Rectangle2D bounds] + (case alignh + :right (- (.getWidth bounds)) + :center (- (/ (.getWidth bounds) 2)) + 0)) + +(defn calculate-vert-offset [alignv ^Rectangle2D bounds] + (case alignv + :bottom (- (.getHeight bounds)) + :center (- (/ (.getHeight bounds) 2)) + 0)) + +(defn text [txt x y & [{:keys [align]}]] + (let [txt (str txt) + [alignh alignv] align + render-ctx (.getFontRenderContext g2d) + metrics (.getFontMetrics g2d) + font (.getFont g2d) + bounds (.getStringBounds font txt render-ctx) + offset-x (calculate-horiz-offset alignh bounds) + offset-y (calculate-vert-offset alignv bounds)] + #_(.drawRect g2d (+ offset-x x) + (+ + offset-y + #_(.getDescent metrics) + (+ y #_(.getAscent metrics))) (.getWidth bounds) (.getHeight bounds)) + + (.drawString g2d ^String txt + (int (+ x offset-x)) + (int (+ y offset-y (.getAscent metrics)))))) + +(defn image [^Image img x y w h] + (let [scaled (.getScaledInstance img w h Image/SCALE_SMOOTH)] + (.drawImage g2d scaled (int x) (int y) nil))) + +(defn focused [] + (.isFocused + (SwingUtilities/getWindowAncestor panel))) + +(defn mouse-position [] + (.getMousePosition panel)) + +(defn mouse-x + ([] + (let [position (.getMousePosition panel)] + (if position + (.getX position) + 0))) + ([^MouseEvent e] + (.getX e))) + +(defn mouse-y + ([] + (let [position (.getMousePosition panel)] + (if position + (.getY position) + 0))) + ([^MouseEvent e] + (.getY e))) + +(defn key-code [^KeyEvent e] + (.getKeyCode e)) + +(defn shadow-text + ([^String s x y] + (shadow-text s x y :left :bottom)) + ([^String s x y align-horiz] + (shadow-text s x y align-horiz :bottom)) + ([^String s x y align-horiz align-vert] + (color 0 196) + (text-size 20) + (text s (inc x) (inc y) + {:align [(or align-horiz :left) (or align-vert :bottom)]}) + + (color 255) + (text-size 20) + (text s x y + {:align [(or align-horiz :left) (or align-vert :bottom)]}))) + +(def fonts + {"helvetica-20pt" (Font. "Helvetica" Font/PLAIN 20)}) + +(defn text-font [font-name] + (let [font (get fonts font-name (Font/decode font-name))] + (.setFont g2d font))) + diff --git a/src/igoki/projector.clj b/src/igoki/projector.clj index 65cbc97..0b51c02 100644 --- a/src/igoki/projector.clj +++ b/src/igoki/projector.clj @@ -1,11 +1,11 @@ (ns igoki.projector (:require [igoki.ui :as ui] - [quil.core :as q] [igoki.util :as util] [igoki.view :as view] [igoki.game :as game] - [igoki.sgf :as sgf]) + [igoki.sgf :as sgf] + [igoki.litequil :as lq]) (:import (org.opencv.calib3d Calib3d) (org.opencv.imgproc Imgproc) @@ -79,19 +79,19 @@ (Imgproc/warpPerspective projmat newflat (.inv board-homography) (Size. (.width sketch) (.height sketch))) - (swap! ctx assoc :proj-img (util/mat-to-pimage newflat (:bufimg proj-img) (:pimg proj-img))) + (swap! ctx assoc :proj-img (util/mat-to-pimage newflat (:bufimg proj-img))) #_(doseq [[x y] (util/mat->seq target)] - (q/stroke 0 0 255) - (q/stroke-weight 20) - (q/point x y) - (q/stroke-weight 0)))) + (lq/color 0 0 255) + (lq/stroke-weight 20) + (lq/point x y) + (lq/stroke-weight 0)))) #_(Core/circle (:raw camera) (Point. 540 265) 20 (Scalar. 255 0 0))))) (defn draw-checkerboard [{:keys [board]}] (doseq [[x y w h] board] - (q/rect x y w h))) + (lq/rect x y w h))) (defn checker [x y width height xblocks yblocks] (let [bw (/ width xblocks) @@ -120,44 +120,42 @@ corners-mat))) (defmethod ui/draw :calibration-pattern [ctx] - (q/frame-rate 10) - #_(println (q/current-frame-rate)) + (lq/frame-rate 10) ;; If camera is reading, render black and quit. (if (:reading @ctx) (do - (q/fill 0 0 0) - (q/rect 0 0 (q/width) (q/height))) + (lq/background 0 0 0) + (lq/rect 0 0 (lq/width) (lq/height))) (do - (q/fill 0 0 0) - (q/rect 0 0 (q/width) (q/height)) + (lq/background 0 0 0) + (lq/rect 0 0 (lq/width) (lq/height)) - (let [[w h] [(q/width) (q/height)] + (let [[w h] [(lq/width) (lq/height)] [gw gh] [(/ w 2) (/ h 2)] checker (checker (- gw (/ gw 2)) (- gh (/ gh 2)) gw gh 10 8) {:keys [camera] :as context} @ui/ctx {:keys [homography board-homography proj-img] :as projcontext} @ctx - existing-corners (:corners projcontext)] + existing-corners (:corners projcontext) + img (:bufimg proj-img)] - (q/fill 255 255 255) - (q/rect 0 0 (q/width) (q/height)) - (q/fill 0 0 0) + (lq/background 255 255 255) + (lq/rect 0 0 (lq/width) (lq/height)) + (lq/background 0 0 0) #_(when-not homography) (draw-checkerboard checker) ;; Draw screen intersection points #_(do - (q/stroke 255 0 0) - (q/stroke-weight 10) + (lq/color 255 0 0) (doseq [[x y] (:points checker)] - (q/point x y)) - (q/stroke-weight 0)) + (lq/ellipse x y 5 5))) - #_(q/image (-> @ctx :pattern) (- (/ (q/width) 2) 180) (- (/ (q/height) 2) 200) 300 400) + #_(lq/image (-> @ctx :pattern) (- (/ (q/width) 2) 180) (- (/ (q/height) 2) 200) 300 400) (when proj-img - (q/image (:pimg proj-img) 0 0)) + (lq/image img 0 0 (.getWidth img) (.getHeight img))) (when (and (not existing-corners) (:raw camera)) (util/with-release [gray (Mat.)] @@ -178,8 +176,7 @@ #_(swap! ui/ctx update :camera assoc :pimg (util/mat-to-pimage (:raw camera) - (-> context :camera :pimg :bufimg) - (-> context :camera :pimg :pimg))) + (-> context :camera :pimg :bufimg))) (swap! ctx assoc :corners corners)))))) (when (and existing-corners (not homography)) @@ -202,10 +199,8 @@ board-homography (Calib3d/findHomography projector-space board-space Calib3d/FM_RANSAC 3)] (doseq [[x y] (util/mat->seq projector-space)] - (q/stroke 255 0 0) - (q/stroke-weight 40) - (q/point x y) - (q/stroke-weight 0)) + (lq/color 255 0 0) + (lq/ellipse x y 10 10)) (when board-homography (println "Board Homography updated") @@ -213,16 +208,15 @@ (when (:reading @ctx) - (q/fill 0 0 0) - (q/rect 0 0 (q/width) (q/height))) + (lq/background 0 0 0) + (lq/rect 0 0 (lq/width) (lq/height))) #_(when existing-corners (util/with-release [clone (.clone (:raw camera))] (Calib3d/drawChessboardCorners clone (:size checker) existing-corners true) (swap! ui/ctx update :camera assoc :pimg (util/mat-to-pimage clone - (-> context :camera :pimg :bufimg) - (-> context :camera :pimg :pimg))))))))) + (-> context :camera :pimg :bufimg))))))))) (defn pre-cam-reading [] diff --git a/src/igoki/scratch.clj b/src/igoki/scratch.clj index fe7602e..1622441 100644 --- a/src/igoki/scratch.clj +++ b/src/igoki/scratch.clj @@ -5,7 +5,6 @@ [igoki.view] [igoki.game] [igoki.util :as util :refer [-->]]) - (:gen-class) (:import (org.opencv.objdetect CascadeClassifier) (org.opencv.highgui Highgui VideoCapture) diff --git a/src/igoki/simulated.clj b/src/igoki/simulated.clj index 1092b61..fb8e8a5 100644 --- a/src/igoki/simulated.clj +++ b/src/igoki/simulated.clj @@ -1,12 +1,14 @@ (ns igoki.simulated (:require [igoki.ui :as ui] - [quil.core :as q] + [igoki.litequil :as lq] [igoki.util :as util]) (:import (org.opencv.core Mat Size Core CvType Point Scalar MatOfPoint MatOfPoint2f MatOfByte) (org.opencv.highgui Highgui) - (de.schlichtherle.truezip.fs FsEntryNotFoundException))) + (de.schlichtherle.truezip.fs FsEntryNotFoundException) + (javax.swing JFrame JPanel) + (java.awt.event MouseEvent))) ;; This view simulates a camera for testing igoki's behaviour without having a board and camera handy (defonce simctx (atom {:sketchconfig {:framerate 5 :size [640 480]}})) @@ -29,11 +31,6 @@ (defn reset-board [ctx size] (swap! ctx update :sim assoc :size size :board (blank-board size) :next :b :mode :alt)) -(defmethod ui/construct :simulation [ctx] - (reset-board ctx 19)) - - - (defn stone-colors [c] (if (= c :w) [(Scalar. 255 255 255) (Scalar. 28 28 28)] @@ -46,15 +43,17 @@ (Core/circle m (Point. x y) (/ cellsize 2) bcolor 2)))) (defn draw-board [^Mat m] - (try + (try (when (and m (.rows m)) #_(.setTo m (Scalar. 92 179 220)) (let [{{:keys [size board next]} :sim} @simctx [cellsize grid-start] (grid-spec m) + mpos (lq/mouse-position) [mx my] - (if (q/focused) - [(* (/ (.rows m) (q/height)) (q/mouse-x)) - (* (/ (.cols m) (q/width)) (q/mouse-y))] [2000 2000])] + (if mpos + [(* (/ (.rows m) (lq/height)) (.getX mpos)) + (* (/ (.cols m) (lq/width)) (.getY mpos))] + [2000 2000])] (doseq [x (range size)] (let [coord (+ grid-start (* x cellsize)) @@ -94,48 +93,14 @@ update :camera assoc :raw (-> context :camera :raw) :pimg (util/mat-to-pimage (-> context :camera :raw) - (-> context :camera :pimg :bufimg) - (-> context :camera :pimg :pimg))) + (-> context :camera :pimg :bufimg))) (let [m (.clone (-> context :sim :background))] (draw-board m) (swap! simctx update :camera assoc :raw m :pimg (util/mat-to-pimage m - (-> context :camera :pimg :bufimg) - (-> context :camera :pimg :pimg))))))) - -(defmethod ui/draw :simulation [ctx] - - (simulate) - - (let [{{:keys [^Mat raw pimg]} :camera - {:keys [frame index]} :replay - mode :mode} @ctx - [cellsize grid-start] (if raw (grid-spec raw) []) - tx (q/height)] - (q/fill 128 64 78) - (q/rect 0 0 (q/width) (q/height)) - (cond - (nil? pimg) - (ui/shadow-text "Image not built yet, please wait..." 10 25) - (= mode :replay) - (do - (q/image (:pimg pimg) 0 0 (q/width) (q/height)) - (ui/shadow-text "Esc: Back to simulation" tx 50) - (ui/shadow-text (str "Arrows: Forward/back (" index ")") tx 75) - (ui/shadow-text "L: Load captured zip" tx 100)) - - :else - (do - (q/image (:pimg pimg) 0 0 (q/width) (q/height)) - (ui/shadow-text "Tab: Cycle Size" tx 50) - (ui/shadow-text "B: Black " tx 75) - (ui/shadow-text "W: White" tx 100) - (ui/shadow-text "A: Alternating" tx 125) - (ui/shadow-text "C: Clear" tx 150) - (ui/shadow-text "R: Reset board. " tx 175) - (ui/shadow-text "L: Load zip. " tx 200))))) + (-> context :camera :pimg :bufimg))))))) (defn next-stone [{:keys [next mode]}] @@ -145,14 +110,16 @@ :erase nil (if (= next :w) :b :w))) -(defmethod ui/mouse-pressed :simulation [ctx] - (swap! - ctx +(defn mouse-pressed [ctx ^MouseEvent e] + (swap! ctx (fn [{{:keys [raw]} :camera :keys [sim] :as c}] (let [[cs gs] (grid-spec raw) - [px py] (stone-point [(* (/ (.rows raw) (q/height)) (q/mouse-x)) - (* (/ (.cols raw) (q/width)) (q/mouse-y))] gs cs) + [px py] (stone-point [(* (/ (.rows raw) (lq/height)) (lq/mouse-x e)) + (* (/ (.cols raw) (lq/width)) (lq/mouse-y e))] gs cs) current (get-in sim [:board py px] :outside)] + (println "[cs gs]" [cs gs]) + (println "[px py]" [px py]) + (println "current" current) (cond (= current :outside) c :else @@ -173,7 +140,7 @@ nextindex (nextfn index) image (util/zip-read-file file (str nextindex ".jpg")) raw (Highgui/imdecode (MatOfByte. image) Highgui/IMREAD_UNCHANGED) - pimg (util/mat-to-pimage raw (:bufimg pimg) (:pimg pimg))] + pimg (util/mat-to-pimage raw (:bufimg pimg))] (swap! ctx (fn [c] @@ -191,9 +158,8 @@ (swap! ctx assoc :mode :replay :replay {:file file :index 0}) (step-file-index ctx identity)) -(defmethod ui/key-pressed :simulation [ctx] - (case - (q/key-code) +(defn key-pressed [ctx e] + (case (lq/key-code e) 9 (swap! ctx update-in [:sim :size] @@ -215,16 +181,54 @@ 39 (step-file-index simctx inc) ;; L 76 (ui/load-dialog #(load-zip simctx (.getAbsolutePath %)) (str (System/getProperty "user.dir") "/capture")) - (println "Unhandled key-down: " (q/key-code)))) + (println "Unhandled key-down: " (lq/key-code e)))) +(defn setup [ctx] + (lq/smooth) + (lq/frame-rate (or (-> @ctx :sketchconfig :framerate) 5)) + (lq/background 200)) + +(defn paint [ctx] + (simulate) + (let [{{:keys [^Mat raw pimg]} :camera + {:keys [frame index]} :replay + mode :mode} @ctx + [cellsize grid-start] (if raw (grid-spec raw) []) + tx (- (lq/width) 180)] + (lq/color 128 64 78) + (lq/rect 0 0 (lq/width) (lq/height)) + (cond + (nil? pimg) + (lq/shadow-text "Image not built yet, please wait..." 10 25) + (= mode :replay) + (do + (lq/image (:bufimg pimg) 0 0 (lq/width) (lq/height)) + (lq/shadow-text "Esc: Back to simulation" tx 50) + (lq/shadow-text (str "Arrows: Forward/back (" index ")") tx 75) + (lq/shadow-text "L: Load captured zip" tx 100)) + :else + (do + (lq/image (:bufimg pimg) 0 0 (lq/width) (lq/height)) + (lq/shadow-text "Tab: Cycle Size" tx 50) + (lq/shadow-text "B: Black " tx 75) + (lq/shadow-text "W: White" tx 100) + (lq/shadow-text "A: Alternating" tx 125) + (lq/shadow-text "C: Clear" tx 150) + (lq/shadow-text "R: Reset board. " tx 175) + (lq/shadow-text "L: Load zip. " tx 200))))) (defn start-simulation [ctx] - (swap! simctx assoc - :stopped false - :sim {:background (Highgui/imread "./resources/wooden-background.jpg")}) + (swap! simctx + (fn [s] + (-> + s + (assoc :stopped false) + (update :sim assoc :background (Highgui/imread "./resources/wooden-background.jpg"))))) + (reset-board simctx 19) + (doto (Thread. #(when-not @@ -233,9 +237,20 @@ (swap! ctx update :camera assoc :raw raw :pimg pimg) (Thread/sleep (or (-> @ctx :camera :read-delay) 500)) (recur)))) + (.setDaemon true) (.start)) - (ui/start (ui/transition simctx :simulation))) + + (let [sketch + (lq/sketch + {:title "Simulation" + :size [640 480] + :draw (partial #'paint simctx) + :setup (partial #'setup simctx) + :mouse-pressed (partial #'mouse-pressed simctx) + :key-pressed (partial #'key-pressed simctx)})] + (swap! simctx assoc :sketch sketch))) (defn stop [] (swap! simctx assoc :stopped true) - (q/with-sketch (-> @simctx :sketch) (q/exit))) + (when-let [frame (get-in @simctx [:sketch :frame])] + (.dispose ^JFrame frame))) diff --git a/src/igoki/sound/announce.clj b/src/igoki/sound/announce.clj index 7672557..7444c89 100644 --- a/src/igoki/sound/announce.clj +++ b/src/igoki/sound/announce.clj @@ -1,8 +1,9 @@ (ns igoki.sound.announce - (:require [clojure.string :as str] - [igoki.sgf :as sgf] - [clojure.java.io :as io] - [igoki.sound.sound :as snd])) + (:require + [clojure.string :as str] + [igoki.sgf :as sgf] + [clojure.java.io :as io] + [igoki.sound.sound :as snd])) (comment ;; Words.. diff --git a/src/igoki/sound/sound.clj b/src/igoki/sound/sound.clj index b28fe18..8e30bec 100644 --- a/src/igoki/sound/sound.clj +++ b/src/igoki/sound/sound.clj @@ -1,6 +1,7 @@ (ns igoki.sound.sound - (:import (javax.sound.sampled AudioSystem LineListener LineEvent LineEvent$Type) - (java.util.concurrent CountDownLatch))) + (:import + (javax.sound.sampled AudioSystem LineListener LineEvent LineEvent$Type) + (java.util.concurrent CountDownLatch))) (def get-clip (memoize diff --git a/src/igoki/training.clj b/src/igoki/training.clj index 5f73af3..90c9735 100644 --- a/src/igoki/training.clj +++ b/src/igoki/training.clj @@ -39,7 +39,7 @@ _ (println imgfile) raw (load-raw imgfile) oldpimg (-> @ctx :camera :pimg) - pimg (util/mat-to-pimage raw (:bufimg oldpimg) (:pimg oldpimg))] + pimg (util/mat-to-pimage raw (:bufimg oldpimg))] (swap! ctx #(-> % (assoc :goban {:points [] :size 19} diff --git a/src/igoki/ui.clj b/src/igoki/ui.clj index a69b1bc..e5658a2 100644 --- a/src/igoki/ui.clj +++ b/src/igoki/ui.clj @@ -1,36 +1,22 @@ (ns igoki.ui (:require - [quil.core :as q] - [igoki.util :as util]) + [igoki.util :as util] + [igoki.litequil :as lq]) (:import (org.opencv.highgui VideoCapture Highgui) (org.opencv.core Mat Core) (javax.swing SwingUtilities JFrame JFileChooser) (org.opencv.imgproc Imgproc) - (java.util LinkedList))) + (java.util LinkedList) + (java.awt.event WindowStateListener WindowEvent))) (defn setup [ctx] - (q/smooth) - (q/frame-rate (or (-> @ctx :sketchconfig :framerate) 5)) - (q/background 200)) - -(defn shadow-text - ([^String s x y] - (shadow-text s x y :left :bottom)) - ([^String s x y align-horiz] - (shadow-text s x y align-horiz :bottom)) - ([^String s x y align-horiz align-vert] - (q/text-align (or align-horiz :left) (or align-vert :bottom)) - (q/fill 0 196) - (q/text-size 20) - (q/text s (inc x) (inc y)) - - (q/fill 255) - (q/text-size 20) - (q/text s x y))) - -(defn state [ctx] (:state @ctx)) + (lq/smooth) + (lq/frame-rate (or (-> @ctx :sketchconfig :framerate) 5)) + (lq/background 200)) + +(defn state [ctx & _] (:state @ctx)) (defmulti construct state) (defmethod construct :default [ctx]) @@ -40,24 +26,24 @@ (defmulti draw state) (defmethod draw :default [ctx] - (q/fill 255 64 78) - (q/rect 0 0 (q/width) (q/height)) - (shadow-text (str "State not implemented: " (:state @ctx)) 10 25)) + (lq/color 255 64 78) + (lq/rect 0 0 (lq/width) (lq/height)) + (lq/shadow-text (str "State not implemented: " (:state @ctx)) 10 25)) (defmulti mouse-dragged state) -(defmethod mouse-dragged :default [ctx]) +(defmethod mouse-dragged :default [ctx e]) (defmulti mouse-pressed state) -(defmethod mouse-pressed :default [ctx]) +(defmethod mouse-pressed :default [ctx e]) (defmulti mouse-released state) -(defmethod mouse-released :default [ctx]) +(defmethod mouse-released :default [ctx e]) (defmulti mouse-moved state) -(defmethod mouse-moved :default [ctx]) +(defmethod mouse-moved :default [ctx e]) (defmulti key-pressed state) -(defmethod key-pressed :default [ctx]) +(defmethod key-pressed :default [ctx e]) (defn transition [ctx new-state] (destruct ctx) @@ -67,18 +53,17 @@ (defn start [ctx] (let [sketch - (q/sketch - :renderer :java2d - :title "Goban panel" - :setup (partial setup ctx) - :draw (partial #'draw ctx) - :size (or (-> @ctx :sketchconfig :size) [1280 720]) - :features [:resizable] - :mouse-dragged (partial #'mouse-dragged ctx) - :mouse-pressed (partial #'mouse-pressed ctx) - :mouse-released (partial #'mouse-released ctx) - :mouse-moved (partial #'mouse-moved ctx) - :key-pressed (partial #'key-pressed ctx))] + (lq/sketch + {:title "igoki" + :setup (partial setup ctx) + :draw (partial #'draw ctx) + :size (or (-> @ctx :sketchconfig :size) [1280 720]) + :mouse-dragged (partial #'mouse-dragged ctx) + :mouse-pressed (partial #'mouse-pressed ctx) + :mouse-released (partial #'mouse-released ctx) + :mouse-moved (partial #'mouse-moved ctx) + :key-pressed (partial #'key-pressed ctx)})] + (swap! ctx assoc :sketch sketch))) ;; Following code doesn't belong in here, but can move it out in due time. @@ -94,7 +79,7 @@ update :camera #(assoc % :raw frame - :pimg (util/mat-to-pimage frame (get-in % [:pimg :bufimg]) (get-in % [:pimg :pimg])))) + :pimg (util/mat-to-pimage frame (get-in % [:pimg :bufimg])))) (.release video))) (defn read-file [ctx fname] @@ -103,7 +88,7 @@ ctx update :camera #(assoc % :raw frame - :pimg (util/mat-to-pimage frame (get-in % [:pimg :bufimg]) (get-in % [:pimg :pimg])))))) + :pimg (util/mat-to-pimage frame (get-in % [:pimg :bufimg])))))) (defn stop-read-loop [ctx] (if-let [video ^VideoCapture (-> @ctx :camera :video)] @@ -142,7 +127,7 @@ :raw frame ;; TODO: this chows memory - better to have a hook on update for each specific ;; view - this will only be needed on the first screen. - :pimg (util/mat-to-pimage frame (get-in % [:pimg :bufimg]) (get-in % [:pimg :pimg]))))) + :pimg (util/mat-to-pimage frame (get-in % [:pimg :bufimg]))))) (Thread/sleep (or (-> @ctx :camera :read-delay) 1000)) (catch Exception e (println "exception thrown") diff --git a/src/igoki/util.clj b/src/igoki/util.clj index 323f1a8..5e344e7 100644 --- a/src/igoki/util.clj +++ b/src/igoki/util.clj @@ -1,10 +1,11 @@ (ns igoki.util - (:require [clojure.java.io :as io]) - (:import (org.opencv.core Mat Size CvType Point MatOfPoint2f MatOfPoint) - (java.awt.image BufferedImage DataBufferByte) - (processing.core PImage PConstants) - (de.schlichtherle.truezip.file TFile TFileWriter TArchiveDetector) - (java.io InputStream ByteArrayInputStream ByteArrayOutputStream))) + (:require + [clojure.java.io :as io]) + (:import + (org.opencv.core Mat Size CvType Point MatOfPoint2f MatOfPoint) + (java.awt.image BufferedImage DataBufferByte) + (de.schlichtherle.truezip.file TFile TFileWriter TArchiveDetector) + (java.io InputStream ByteArrayInputStream ByteArrayOutputStream))) (defn star-points [size] (case size @@ -28,20 +29,9 @@ (.get frame 0 0 data) image)) -(defn bufimage-to-pimage [^BufferedImage bimg ^PImage pimg] - (let [img - (if (and pimg (= (.-width pimg) (.getWidth bimg)) (= (.-height pimg) (.getHeight bimg))) - pimg - (PImage. (.getWidth bimg) (.getHeight bimg) PConstants/ARGB))] - (.getRGB bimg 0 0 (.-width img) (.-height img) (.-pixels img) 0 (.-width img)) - (.updatePixels img) - img)) - -(defn mat-to-pimage [^Mat frame ^BufferedImage oldbuffer ^PImage oldpimg] +(defn mat-to-pimage [^Mat frame ^BufferedImage oldbuffer] (when (and (> (.rows frame) 0) (> (.cols frame) 0)) - (let [buf (mat-to-buffered-image frame oldbuffer) - pimg (bufimage-to-pimage buf oldpimg)] - {:bufimg buf :pimg pimg}))) + {:bufimg (mat-to-buffered-image frame oldbuffer)})) (defmacro with-release "A let block, calling .release on each provided binding at the end, in a finally block." diff --git a/src/igoki/view.clj b/src/igoki/view.clj index ba2a7ed..57e05f9 100644 --- a/src/igoki/view.clj +++ b/src/igoki/view.clj @@ -1,7 +1,8 @@ (ns igoki.view (:require [igoki.ui :as ui] - [igoki.util :as util]) + [igoki.util :as util] + [clojure.java.io :as io]) (:import (org.opencv.core MatOfPoint2f Mat Rect Size Core) (org.opencv.calib3d Calib3d) @@ -21,9 +22,17 @@ ;; Stone detection, neural network -(defn load-net [nm] - (ModelSerializer/restoreMultiLayerNetwork (File. (str nm ".cnet")))) -(def net (load-net "resources/supersimple")) +(defn load-net [^File nm] + (ModelSerializer/restoreMultiLayerNetwork nm)) + +(def net + (let [tmp (File/createTempFile "igoki" "cnet") + cnet (io/input-stream (io/resource "supersimple.cnet"))] + (io/copy cnet tmp) + (let [net (load-net tmp)] + (.delete tmp) + net))) + (def loader (ImageLoader. 10 10 3)) (def block-size 10) @@ -108,8 +117,7 @@ (assoc-in [:camera :flattened] new-flat) (assoc-in [:camera :flattened-pimage] (util/mat-to-pimage new-flat - (:bufimg flattened-pimage) - (:pimg flattened-pimage))) + (:bufimg flattened-pimage))) (assoc :board board)))) ctx) )