summaryrefslogtreecommitdiff
path: root/static/src/assets/viz/1/viz/core.cljs
diff options
context:
space:
mode:
Diffstat (limited to 'static/src/assets/viz/1/viz/core.cljs')
-rw-r--r--static/src/assets/viz/1/viz/core.cljs204
1 files changed, 204 insertions, 0 deletions
diff --git a/static/src/assets/viz/1/viz/core.cljs b/static/src/assets/viz/1/viz/core.cljs
new file mode 100644
index 0000000..913cab4
--- /dev/null
+++ b/static/src/assets/viz/1/viz/core.cljs
@@ -0,0 +1,204 @@
+(ns viz.core
+ (:require [quil.core :as q :include-macros true]
+ [quil.middleware :as m]
+ [viz.forest :as forest]
+ [viz.grid :as grid]
+ [viz.ghost :as ghost]
+ [goog.string :as gstring]
+ [goog.string.format]
+ ;[gil.core :as gil]
+ ))
+
+(defn- debug [& args]
+ (.log js/console (clojure.string/join " " (map str args))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn- window-partial [k]
+ (int (* (aget js/document "documentElement" k) 0.95)))
+
+(def window-size [ (min 1025 (window-partial "clientWidth"))
+ (int (* (window-partial "clientHeight") 0.75))
+ ])
+(def window-half-size (apply vector (map #(float (/ %1 2)) window-size)))
+
+(defn- new-state []
+ {:frame-rate 15
+ :exit-wait-frames 40
+ :tail-length 15
+ :frame 0
+ :gif-seconds 0
+ :grid-width 30 ; from the center
+ :ghost (-> (ghost/new-ghost grid/euclidean)
+ (ghost/new-active-node [0 0])
+ )
+ })
+
+(defn- curr-second [state]
+ (float (/ (:frame state) (:frame-rate state))))
+
+(defn- grid-size [state]
+ (let [h (int (* (window-size 1)
+ (float (/ (:grid-width state) (window-size 0)))))]
+ [(:grid-width state) h]))
+
+(defn- positive [n] (if (> 0 n) (- n) n))
+
+(defn- spawn-chance [state]
+ (let [period-seconds 1
+ period-frames (* (:frame-rate state) period-seconds)]
+ (if (zero? (rem (:frame state) period-frames))
+ 1 100)
+ ))
+
+ ;(let [period-seconds 1
+ ; rad-per-second (float (/ (/ Math/PI 2) period-seconds))
+ ; rad (* rad-per-second (curr-second state))
+ ; chance-raw (positive (q/sin rad))
+ ; ]
+ ; (if (> chance-raw 0.97) 3 50)
+ ; ))
+
+
+;(defn- mk-poss-fn [state]
+; (let [chance (spawn-chance state)]
+; (fn [pos adj-poss]
+; (if (zero? (rand-int chance))
+; adj-poss
+; (take 1 (shuffle adj-poss))))
+; ))
+
+(defn- mk-poss-fn [state]
+ (fn [pos adj-poss]
+ (take 2 (random-sample 0.6 adj-poss))))
+
+(defn setup []
+ (let [state (new-state)]
+ (q/frame-rate (:frame-rate state))
+ state))
+
+(defn- scale [state xy]
+ (map-indexed #(* %2 (float (/ (window-half-size %1)
+ ((grid-size state) %1)))) xy))
+
+; each bound is a position vector
+(defn- in-bounds? [min-bound max-bound pos]
+ (let [pos-k (keep-indexed #(let [mini (min-bound %1)
+ maxi (max-bound %1)]
+ (when (and (>= %2 mini) (<= %2 maxi)) %2)) pos)]
+ (= (count pos) (count pos-k))))
+
+(defn- quil-bounds [state buffer]
+ (let [[w h] (apply vector (map #(- % buffer) (grid-size state)))]
+ [[(- w) (- h)] [w h]]))
+
+(defn- ghost-incr [state]
+ (assoc state :ghost
+ (ghost/filter-active-nodes (ghost/incr (:ghost state) (mk-poss-fn state))
+ #(let [[minb maxb] (quil-bounds state 2)]
+ (in-bounds? minb maxb (:pos %1))))))
+
+(defn- ghost-expire-roots [state]
+ (if-not (< (:tail-length state) (:frame state)) state
+ (update-in state [:ghost] ghost/remove-roots)))
+
+(defn- maybe-exit [state]
+ (if (empty? (get-in state [:ghost :active-node-ids]))
+ (if (zero? (:exit-wait-frames state)) (new-state)
+ (update-in state [:exit-wait-frames] dec))
+ state))
+
+(defn update-state [state]
+ (-> state
+ (ghost-incr)
+ (ghost-expire-roots)
+ (update-in [:frame] inc)
+ (maybe-exit)))
+
+(defn- draw-ellipse [state pos size] ; size is [w h]
+ (let [scaled-pos (scale state pos)
+ scaled-size (map int (scale state size))]
+ (apply q/ellipse (concat scaled-pos scaled-size))))
+
+(defn- in-line? [& nodes]
+ (apply = (map #(apply map - %1)
+ (partition 2 1 (map :pos nodes)))))
+
+(defn draw-lines [state forest parent node]
+ "Draws the lines of all children leading from the node, recursively"
+ (q/stroke 0xFF000000)
+ (q/fill 0xFFFFFFFF)
+ (let [children (map #(forest/get-node forest %) (:child-ids node))]
+
+ (if-not parent
+ (doseq [child children] (draw-lines state forest node child))
+ (let [in-line-child (some #(if (in-line? parent node %) %) children)
+ ]
+ (doseq [child children]
+ (if (and in-line-child (= in-line-child child))
+ (draw-lines state forest parent child)
+ (draw-lines state forest node child)))
+ (when-not in-line-child
+ (apply q/line (apply concat
+ (map #(scale state %)
+ (map :pos (list parent node))))))
+ ))
+
+ ; we also take the opportunity to draw the leaves
+ (when (empty? children)
+ (draw-ellipse state (:pos node) [0.3 0.3]))
+
+ ))
+
+(defn draw-state [state]
+ ; Clear the sketch by filling it with light-grey color.
+ (q/background 0xFFFFFFFF)
+ (q/with-translation [(/ (window-size 0) 2)
+ (/ (window-size 1) 2)]
+ (let [lines (forest/lines (get-in state [:ghost :forest]))
+ leaves (forest/leaves (get-in state [:ghost :forest]))
+ active (ghost/active-nodes (:ghost state))
+ roots (forest/roots (get-in state [:ghost :forest]))
+ ]
+
+ (q/stroke 0xFF000000)
+ (doseq [root roots]
+ (draw-lines state (get-in state [:ghost :forest]) nil root))
+
+ (q/stroke 0xFF000000)
+ (q/fill 0xFF000000)
+ (doseq [active-node active]
+ (let [pos (:pos active-node)]
+ (draw-ellipse state pos [0.35 0.35])
+ ))
+
+ ))
+
+ ;(when-not (zero? (:gif-seconds state))
+ ; (let [anim-frames (* (:gif-seconds state) (:frame-rate state))]
+ ; (gil/save-animation "quil.gif" anim-frames 0)
+ ; (when (> (:frame state) anim-frames) (q/exit))))
+
+ ;(q/text (clojure.string/join
+ ; "\n"
+ ; (list
+ ; (gstring/format "frame:%d" (:frame state))
+ ; (gstring/format "second:%f" (curr-second state))
+ ; (gstring/format "spawn-chance:%d" (spawn-chance state))))
+ ; 30 30)
+ )
+
+(q/defsketch viz
+ :title ""
+ :host "viz"
+ :size window-size
+ ; setup function called only once, during sketch initialization.
+ :setup setup
+ ; update-state is called on each iteration before draw-state.
+ :update update-state
+ :draw draw-state
+ :features [:keep-on-top]
+ ; This sketch uses functional-mode middleware.
+ ; Check quil wiki for more info about middlewares and particularly
+ ; fun-mode.
+ :middleware [m/fun-mode])