├── .gitignore
├── day1
├── ex01
│ ├── project.clj
│ ├── resources
│ │ └── public
│ │ │ ├── css
│ │ │ └── style.css
│ │ │ └── index.html
│ └── src
│ │ └── ex01
│ │ ├── core.cljs
│ │ ├── faster.cljs
│ │ ├── fastest.cljs
│ │ ├── naive.cljs
│ │ └── utils.cljs
├── ex02
│ ├── project.clj
│ ├── resources
│ │ └── public
│ │ │ ├── css
│ │ │ └── style.css
│ │ │ └── index.html
│ └── src
│ │ └── ex02
│ │ ├── core.cljs
│ │ ├── csgtest.clj
│ │ ├── shapes01.cljs
│ │ ├── shapes02.cljs
│ │ └── utils.cljs
└── ex03
│ ├── project.clj
│ ├── resources
│ └── public
│ │ ├── css
│ │ └── style.css
│ │ ├── img
│ │ ├── cubev.png
│ │ ├── dione.jpg
│ │ ├── earth.jpg
│ │ └── moon.jpg
│ │ └── index.html
│ └── src
│ └── ex03
│ ├── webgl01.cljs
│ ├── webgl02.cljs
│ ├── webgl03.cljs
│ ├── webgl04.cljs
│ ├── webgl05.cljs
│ ├── webgl06.cljs
│ └── webgl07.cljs
├── day2
├── ex04
│ ├── project.clj
│ ├── resources
│ │ └── public
│ │ │ ├── css
│ │ │ └── style.css
│ │ │ ├── img
│ │ │ ├── cubev.png
│ │ │ ├── sjo512.png
│ │ │ └── sjo512_2.png
│ │ │ └── index.html
│ └── src
│ │ └── ex04
│ │ ├── cache.cljs
│ │ ├── camera.cljs
│ │ ├── config.cljs
│ │ ├── core.cljs
│ │ ├── game.cljs
│ │ ├── mesh.cljs
│ │ ├── shaders.cljs
│ │ └── texture.cljs
└── ex05
│ ├── project.clj
│ ├── resources
│ └── public
│ │ └── index.html
│ └── src
│ └── ex05
│ ├── core.cljs
│ └── worker.cljs
├── day3
├── ex06
│ ├── project.clj
│ ├── resources
│ │ └── public
│ │ │ ├── css
│ │ │ └── style.css
│ │ │ └── index.html
│ └── src
│ │ └── ex06
│ │ ├── core.cljs
│ │ ├── main.cljs
│ │ └── shaders.cljs
└── ex07
│ ├── compile.sh
│ ├── externs.js
│ ├── particles.c
│ ├── project.clj
│ ├── resources
│ └── public
│ │ ├── css
│ │ └── style.css
│ │ ├── img
│ │ └── tex32.png
│ │ └── index.html
│ └── src
│ └── ex07
│ └── core.cljs
└── docs
├── GLSL_ES_Specification_1.0.17.pdf
└── WebGL1.0-Specification.pdf
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | js/
3 | .lein-repl-history
4 | .nrepl-port
5 | .DS_Store
--------------------------------------------------------------------------------
/day1/ex01/project.clj:
--------------------------------------------------------------------------------
1 | (defproject ws-ldn-8-ex01 "0.1.0-SNAPSHOT"
2 | :description "thi.ng Clojurescript workshop WS-LDN-5"
3 | :url "http://workshop.thi.ng"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 |
7 | :min-lein-version "2.5.3"
8 |
9 | :dependencies [[org.clojure/clojure "1.8.0"]
10 | [org.clojure/clojurescript "1.8.51"]
11 | [org.clojure/core.async "0.2.374" :exclusions [org.clojure/tools.reader]]
12 | [thi.ng/geom "0.0.1158-SNAPSHOT"]
13 | [thi.ng/domus "0.3.0-SNAPSHOT"]
14 | [reagent "0.5.1"]]
15 |
16 | :plugins [[lein-figwheel "0.5.0-6"]
17 | [lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]]
18 |
19 | :source-paths ["src"]
20 |
21 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
22 |
23 | :cljsbuild {:builds
24 | [{:id "dev"
25 | :source-paths ["src"]
26 | :figwheel true
27 | :compiler {:main ex01.core
28 | :asset-path "js/compiled/out"
29 | :output-to "resources/public/js/compiled/app.js"
30 | :output-dir "resources/public/js/compiled/out"
31 | :source-map-timestamp true}}
32 | {:id "min"
33 | :source-paths ["src"]
34 | :compiler {:output-to "resources/public/js/compiled/app.js"
35 | :main ex01.core
36 | :optimizations :advanced
37 | :pretty-print false}}]}
38 |
39 | :figwheel {:css-dirs ["resources/public/css"]
40 | ;; :ring-handler hello_world.server/handler
41 | })
42 |
--------------------------------------------------------------------------------
/day1/ex01/resources/public/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica, Arial, sans-serif;
3 | }
4 |
5 | div {
6 | margin-bottom: 1em;
7 | }
8 | select {
9 | margin-right: 2em;
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/day1/ex01/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | WS-LDN-8: Hi-perf Clojurescript workshop
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/day1/ex01/src/ex01/core.cljs:
--------------------------------------------------------------------------------
1 | (ns ex01.core
2 | (:require-macros
3 | [reagent.ratom :refer [reaction]]
4 | [cljs-log.core :refer [debug info warn severe]])
5 | (:require
6 | [ex01.state :as state]
7 | [ex01.naive :as naive]
8 | [ex01.faster :as faster]
9 | [ex01.fastest :as fastest]
10 | [thi.ng.geom.gl.webgl.animator :as anim]
11 | [thi.ng.strf.core :as f]
12 | [reagent.core :as r]))
13 |
14 | (def modes
15 | {:naive {:init naive/init :update naive/redraw}
16 | :faster {:init faster/init :update faster/redraw}
17 | :fastest {:init fastest/init :update fastest/redraw}})
18 |
19 | (defn update-sim
20 | [this props]
21 | (fn [_ _]
22 | (let [{:keys [mode size]} @state/app
23 | {:keys [init update]} (modes mode)
24 | props (assoc props :width size :height size)
25 | canvas (r/dom-node this)]
26 | (when (:reset @state/app)
27 | (debug :reset mode)
28 | (init this props)
29 | (swap! state/app dissoc :reset))
30 | (set! (.-width canvas) size)
31 | (set! (.-height canvas) size)
32 | (update this props)
33 | (:active (r/state this)))))
34 |
35 | (defn canvas-component
36 | [props]
37 | (r/create-class
38 | {:component-did-mount
39 | (fn [this]
40 | (r/set-state this {:active true})
41 | ((:init props) this props)
42 | (anim/animate (update-sim this props)))
43 | :component-will-unmount
44 | (fn [this]
45 | (debug "unmount canvas")
46 | (r/set-state this {:active false}))
47 | :reagent-render
48 | (fn [_]
49 | [:canvas
50 | (merge
51 | {:width (.-innerWidth js/window)
52 | :height (.-innerHeight js/window)}
53 | props)])}))
54 |
55 | (defn mode-selector
56 | []
57 | (let [mode (reaction (:mode @state/app))]
58 | (fn []
59 | [:select {:default-value @mode :on-change state/set-mode!}
60 | (for [m ["naive" "faster" "fastest"]]
61 | [:option {:key m :value m} m])])))
62 |
63 | (defn size-selector
64 | []
65 | (let [size (reaction (:size @state/app))]
66 | (fn []
67 | [:select {:default-value @size :on-change state/set-size!}
68 | (for [m [256 512 1024]]
69 | [:option {:key (str m) :value m} m])])))
70 |
71 | (defn stats
72 | []
73 | (let [avg (reaction (:avg @state/app))]
74 | (fn [] [:span (f/format [(f/float 3) " ms"] @avg)])))
75 |
76 | (defn app-component
77 | []
78 | (let [mode (reaction (:mode @state/app))
79 | size (reaction (:size @state/app))]
80 | (fn []
81 | (let [props (assoc (modes @mode) :width @size :height @size)]
82 | [:div
83 | [:div
84 | [mode-selector]
85 | [size-selector]
86 | [stats]]
87 | [canvas-component props]]))))
88 |
89 | (defn main
90 | []
91 | (r/render-component
92 | [app-component]
93 | (.getElementById js/document "app")))
94 |
95 | (main)
96 |
--------------------------------------------------------------------------------
/day1/ex01/src/ex01/faster.cljs:
--------------------------------------------------------------------------------
1 | (ns ex01.faster
2 | (:require-macros
3 | [thi.ng.math.macros :as mm])
4 | (:require
5 | [ex01.state :as state]
6 | [ex01.utils :as utils]
7 | [thi.ng.typedarrays.core :as ta]
8 | [reagent.core :as r]))
9 |
10 | (defn sum-neighbors
11 | "Returns number of active neighbours for a cell at x;y using
12 | thi.ng.math macro to compute sum."
13 | [grid idx stride]
14 | (let [t (- idx stride)
15 | b (+ idx stride)]
16 | (mm/add
17 | (nth grid (- t 1))
18 | (nth grid t)
19 | (nth grid (+ t 1))
20 | (nth grid (- idx 1))
21 | (nth grid (+ idx 1))
22 | (nth grid (- b 1))
23 | (nth grid b)
24 | (nth grid (+ b 1)))))
25 |
26 | (defn life-step
27 | "Computes new state for a single cell."
28 | [grid idx stride]
29 | (let [neighbors (sum-neighbors grid idx stride)]
30 | (if (pos? (nth grid idx))
31 | (if (or (== neighbors 2) (== neighbors 3)) 1 0)
32 | (if (== 3 neighbors) 1 0))))
33 |
34 | (defn life
35 | "Computes next generation of entire cell grid."
36 | [w h grid]
37 | (let [w' (- w 1)
38 | h' (- h 2)]
39 | (loop [grid' grid, idx (+ w 1), x 1, y 1]
40 | (if (< x w')
41 | (recur (assoc grid' idx (life-step grid idx w)) (inc idx) (inc x) y)
42 | (if (< y h')
43 | (recur grid' (+ idx 2) 1 (inc y))
44 | grid')))))
45 |
46 | (defn draw
47 | "Visualizes grid state in given canvas context."
48 | [ctx w h grid]
49 | (let [w' (- w 1)
50 | h' (- h 2)]
51 | (set! (.-fillStyle ctx) "#000")
52 | (.fillRect ctx 0 0 w h)
53 | (set! (.-fillStyle ctx) "#0ff")
54 | (loop [i 0, x 1, y 1]
55 | (if (< x w')
56 | (do (when (pos? (nth grid i))
57 | (.fillRect ctx x y 1 1))
58 | (recur (inc i) (inc x) y))
59 | (if (< y h')
60 | (recur (+ i 2) 1 (inc y))
61 | grid)))))
62 |
63 | (defn init
64 | [this props]
65 | (swap! state/app merge
66 | {:grid (->> #(if (< (rand) 0.25) 1 0)
67 | (repeatedly (* (:width props) (:height props)))
68 | vec)}))
69 |
70 | (defn redraw
71 | [this props]
72 | (let [{:keys [width height]} props
73 | ctx (.getContext (r/dom-node this) "2d")]
74 | (let [[avg grid] (utils/run-with-timer
75 | #(->> (:grid @state/app)
76 | (life width height)
77 | (draw ctx width height)))]
78 | (swap! state/app assoc :grid grid :avg avg))))
79 |
--------------------------------------------------------------------------------
/day1/ex01/src/ex01/fastest.cljs:
--------------------------------------------------------------------------------
1 | (ns ex01.fastest
2 | (:require-macros
3 | [thi.ng.math.macros :as mm])
4 | (:require
5 | [ex01.state :as state]
6 | [ex01.utils :as utils]
7 | [thi.ng.typedarrays.core :as ta]
8 | [reagent.core :as r]))
9 |
10 | (defn sum-neighbors
11 | "Returns number of active neighbours for a cell at x;y using
12 | thi.ng.math macro to compute sum."
13 | [grid idx stride]
14 | (let [t (- idx stride)
15 | b (+ idx stride)]
16 | (mm/add
17 | (aget grid (- t 1))
18 | (aget grid t)
19 | (aget grid (+ t 1))
20 | (aget grid (- idx 1))
21 | (aget grid (+ idx 1))
22 | (aget grid (- b 1))
23 | (aget grid b)
24 | (aget grid (+ b 1)))))
25 |
26 | (defn life-step
27 | "Computes new state for a single cell."
28 | [grid idx stride]
29 | (let [neighbors (sum-neighbors grid idx stride)]
30 | (if (pos? (aget grid idx))
31 | (if (or (== neighbors 2) (== neighbors 3)) 1 0)
32 | (if (== neighbors 3) 1 0))))
33 |
34 | (defn life
35 | "Computes next generation of entire cell grid."
36 | [w h [old new]]
37 | (let [w' (- w 1)
38 | h' (- h 2)]
39 | (loop [idx (+ w 1), x 1, y 1]
40 | (if (< x w')
41 | (do
42 | (aset new idx (life-step old idx w))
43 | (recur (inc idx) (inc x) y))
44 | (if (< y h')
45 | (recur (+ idx 2) 1 (inc y))
46 | [new old])))))
47 |
48 | (defn draw
49 | "Visualizes grid state in given canvas context & image data buffer."
50 | [ctx img len [grid :as state]]
51 | (let [pixels (-> img .-data ta/uint32-view)]
52 | (loop [i 0, idx 0]
53 | (if (< i len)
54 | ;; byteorder: ABGR
55 | (do (aset pixels idx (if (pos? (aget grid i)) 0xff00ffff 0xff000000))
56 | (recur (inc i) (+ idx 1)))
57 | (do (.putImageData ctx img 0 0)
58 | state)))))
59 |
60 | (defn prepare-image
61 | "Creates an ImageData object for given canvas context and fills it
62 | with opaque black."
63 | [ctx width height]
64 | (let [img (.createImageData ctx width height)]
65 | (.fill (ta/uint32-view (.-data img)) (int 0xff000000))
66 | img))
67 |
68 | (defn init
69 | [this props]
70 | (let [{:keys [width height]} props
71 | num (* width height)
72 | grid (->> #(if (< (rand) 0.5) 1 0)
73 | (repeatedly num)
74 | ta/uint8)
75 | grid2 (ta/uint8 num)
76 | ctx (.getContext (r/dom-node this) "2d")]
77 | (swap! state/app merge
78 | {:grid [grid grid2]
79 | :pixels (prepare-image ctx width height)
80 | :num-cells num})))
81 |
82 | (defn redraw
83 | [this props]
84 | (let [{:keys [width height]} props
85 | {:keys [pixels num-cells]} @state/app
86 | canvas (r/dom-node this)
87 | ctx (.getContext canvas "2d")]
88 | (let [[avg grid] (utils/run-with-timer
89 | #(->> (:grid @state/app)
90 | (life width height)
91 | (draw ctx pixels num-cells)))]
92 | (swap! state/app assoc :grid grid :avg avg))))
93 |
--------------------------------------------------------------------------------
/day1/ex01/src/ex01/naive.cljs:
--------------------------------------------------------------------------------
1 | (ns ex01.naive
2 | (:require
3 | [ex01.state :as state]
4 | [ex01.utils :as utils]
5 | [reagent.core :as r]))
6 |
7 | (defn sum-neighbors
8 | "Returns number of active neighbours for a cell at x;y using
9 | standard map/reduce."
10 | [grid x y]
11 | (let [-x (dec x)
12 | +x (inc x)
13 | -y (dec y)
14 | +y (inc y)]
15 | (->> [[-y -x] [-y x] [-y +x]
16 | [y -x] [y +x]
17 | [+y -x] [+y x] [+y +x]]
18 | (map #(get-in grid %))
19 | (reduce +))))
20 |
21 | (defn sum-neighbors-transduce
22 | "Returns number of active neighbours for a cell at x;y using transduce."
23 | [grid x y]
24 | (let [-x (dec x)
25 | +x (inc x)
26 | -y (dec y)
27 | +y (inc y)]
28 | (transduce
29 | (map #(get-in grid %))
30 | +
31 | [[-y -x] [-y x] [-y +x]
32 | [ y -x] [ y +x]
33 | [+y -x] [+y x] [+y +x]])))
34 |
35 | (defn sum-neighbors-no-reduce
36 | "Returns number of active neighbours for a cell at x;y using
37 | flattened cell lookups w/o reduce."
38 | [grid x y]
39 | (let [-x (dec x)
40 | +x (inc x)
41 | -y (dec y)
42 | +y (inc y)]
43 | (+ (+ (+ (+ (+ (+ (+ (get-in grid [-y -x])
44 | (get-in grid [-y x]))
45 | (get-in grid [-y +x]))
46 | (get-in grid [y -x]))
47 | (get-in grid [y +x]))
48 | (get-in grid [+y -x]))
49 | (get-in grid [+y x]))
50 | (get-in grid [+y +x]))))
51 |
52 | (defn sum-neighbors-nth
53 | "Returns number of active neighbours for a cell at x;y using
54 | flattened cell lookups and avoiding use of get-in."
55 | [grid x y]
56 | (let [-x (dec x)
57 | +x (inc x)
58 | -y (nth grid (dec y))
59 | +y (nth grid (inc y))
60 | y (nth grid y)]
61 | (+ (+ (+ (+ (+ (+ (+ (nth -y -x)
62 | (nth -y x))
63 | (nth -y +x))
64 | (nth y -x))
65 | (nth y +x))
66 | (nth +y -x))
67 | (nth +y x))
68 | (nth +y +x))))
69 |
70 | (defn life-step
71 | "Computes new state for a single cell."
72 | [grid x y state]
73 | (let [neighbors (sum-neighbors grid x y) ;; 594ms (advanced compile, else x2)
74 | ;;neighbors (sum-neighbors-transduce grid x y) ;; 780ms
75 | ;;neighbors (sum-neighbors-no-reduce grid x y) ;; 270ms
76 | ;;neighbors (sum-neighbors-nth grid x y) ;; 128ms
77 | ]
78 | (if (pos? state)
79 | (if (or (== neighbors 2) (== neighbors 3)) 1 0)
80 | (if (== 3 neighbors) 1 0))))
81 |
82 | (defn life
83 | "Computes next generation of entire cell grid."
84 | [w h grid]
85 | (let [w' (- w 1)
86 | h' (- h 2)]
87 | (loop [grid' grid, y 1, x 1]
88 | (if (< x w')
89 | (recur (update-in grid' [y x] #(life-step grid x y %)) y (inc x))
90 | (if (< y h')
91 | (recur grid' (inc y) 1)
92 | grid')))))
93 |
94 | (defn draw
95 | "Visualizes grid state in given canvas."
96 | [ctx w h grid]
97 | (let [w' (- w 1)
98 | h' (- h 2)]
99 | (set! (.-fillStyle ctx) "#000")
100 | (.fillRect ctx 0 0 w h)
101 | (set! (.-fillStyle ctx) "#f00")
102 | (loop [y 1, x 1]
103 | (if (< x w)
104 | (do (when (pos? (get-in grid [y x]))
105 | (.fillRect ctx x y 1 1))
106 | (recur y (inc x)))
107 | (if (< y h')
108 | (recur (inc y) 1)
109 | grid)))))
110 |
111 | (defn init
112 | [this props]
113 | (swap! state/app merge
114 | {:grid (->> #(if (< (rand) 0.25) 1 0)
115 | (repeatedly (* (:width props) (:height props)))
116 | (partition (:width props))
117 | (mapv vec))}))
118 |
119 | (defn redraw
120 | [this props]
121 | (let [{:keys [width height]} props
122 | ctx (.getContext (r/dom-node this) "2d")]
123 | (let [[avg grid] (utils/run-with-timer
124 | #(->> (:grid @state/app)
125 | (life width height)
126 | (draw ctx width height)))]
127 | (swap! state/app assoc :grid grid :avg avg))))
128 |
--------------------------------------------------------------------------------
/day1/ex01/src/ex01/utils.cljs:
--------------------------------------------------------------------------------
1 | (ns ex01.utils
2 | (:require
3 | [ex01.state :as state]
4 | [thi.ng.strf.core :as f]))
5 |
6 | (defn timed
7 | "Executes function f and returns vector of [execution-time result-of-f]"
8 | [f] (let [t0 (f/now) res (f)] [(- (f/now) t0) res]))
9 |
10 | (defn conj-max
11 | "Takes a vector, size limit and value x. Appends x to vector and
12 | ensures vector does not grow beyond limit."
13 | [vec limit x]
14 | (let [n (count vec)]
15 | (if (>= n limit)
16 | (conj (subvec vec (inc (- n limit))) x)
17 | (conj vec x))))
18 |
19 | (defn run-with-timer
20 | "Executes f, measures and records execution time,
21 | returns vector of avg. exec time of whole time window and result of f."
22 | [f]
23 | (let [[t res] (timed f)
24 | _ (swap! state/app update :samples conj-max (:num-samples @state/app) t)
25 | samples (get @state/app :samples)]
26 | [(/ (reduce + samples) (count samples)) res]))
27 |
--------------------------------------------------------------------------------
/day1/ex02/project.clj:
--------------------------------------------------------------------------------
1 | (defproject ws-ldn-8-ex02 "0.1.0-SNAPSHOT"
2 | :description "thi.ng Clojurescript workshop WS-LDN-8"
3 | :url "http://workshop.thi.ng"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 |
7 | :min-lein-version "2.5.3"
8 |
9 | :dependencies [[org.clojure/clojure "1.8.0"]
10 | [org.clojure/clojurescript "1.8.51"]
11 | [org.clojure/core.async "0.2.374"
12 | :exclusions [org.clojure/tools.reader]]
13 | [thi.ng/geom "0.0.1158-SNAPSHOT"]
14 | [thi.ng/domus "0.3.0-SNAPSHOT"]]
15 |
16 | :plugins [[lein-figwheel "0.5.0-6"]
17 | [lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]]
18 |
19 | :source-paths ["src"]
20 |
21 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
22 |
23 | :cljsbuild {:builds
24 | [{:id "dev"
25 | :source-paths ["src"]
26 | :figwheel true
27 | :compiler {:main ex02.core
28 | :asset-path "js/compiled/out"
29 | :output-to "resources/public/js/compiled/app.js"
30 | :output-dir "resources/public/js/compiled/out"
31 | :source-map-timestamp true}}
32 | {:id "min"
33 | :source-paths ["src"]
34 | :compiler {:output-to "resources/public/js/compiled/app.js"
35 | :main ex02.core
36 | :optimizations :advanced
37 | :pretty-print false}}]}
38 |
39 | :figwheel {:css-dirs ["resources/public/css"]
40 | ;; :ring-handler hello_world.server/handler
41 | })
42 |
--------------------------------------------------------------------------------
/day1/ex02/resources/public/css/style.css:
--------------------------------------------------------------------------------
1 | /* some style */
2 |
3 |
--------------------------------------------------------------------------------
/day1/ex02/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/day1/ex02/src/ex02/core.cljs:
--------------------------------------------------------------------------------
1 | (ns ex02.core
2 | (:require
3 | [ex02.utils :as utils]
4 | [ex02.shapes01]
5 | [ex02.shapes02]
6 | [thi.ng.math.core :as m]
7 | [thi.ng.geom.core :as g]
8 | [thi.ng.geom.vector :as v :refer [vec2]]
9 | [thi.ng.geom.circle :as c]
10 | [thi.ng.geom.svg.core :as svg]
11 | [thi.ng.geom.gl.webgl.animator :as anim]
12 | [thi.ng.color.core :as col]
13 | [thi.ng.domus.core :as dom]
14 | [thi.ng.strf.core :as f]))
15 |
16 | (enable-console-print!)
17 |
18 | (defonce app
19 | (atom
20 | {:width 640
21 | :height 480
22 | :num 100}))
23 |
24 | (defn make-particle
25 | [w h]
26 | {:pos (vec2 (m/random w) (m/random h))
27 | :vel (v/randvec2 (m/random 2 10))
28 | :radius (m/random 2 6)
29 | :col @(col/as-css (col/random-rgb))})
30 |
31 | (defn collide-particle
32 | [coll {:keys [pos radius] :as p}]
33 | (loop [coll coll]
34 | (if coll
35 | (let [q (first coll)]
36 | (if (identical? p q)
37 | (recur (next coll))
38 | (let [{qpos :pos qr :radius} q
39 | d (g/dist pos qpos)]
40 | (if (< d (+ radius qr))
41 | (let [vel (m/normalize (m/- pos qpos) (* 0.999 (m/mag (get p :vel))))
42 | pos (m/+ pos (m/normalize vel (* 1.01 (- d qr))))]
43 | (assoc p :pos pos :vel vel))
44 | (recur (next coll))))))
45 | p)))
46 |
47 | (defn update-particle
48 | [particles w h p]
49 | (let [;p (collide-particle particles p)
50 | {:keys [pos vel radius]} p
51 | [x y] (m/+ pos vel)
52 | [vx vy] vel
53 | [x vx] (if (< x radius)
54 | [(+ radius (Math/abs vx)) (- vx)]
55 | (if (> x (- w radius))
56 | [(- (- w radius) (Math/abs vx)) (- vx)]
57 | [x vx]))
58 | [y vy] (if (< y radius)
59 | [(+ radius (Math/abs vy)) (- vy)]
60 | (if (> y (- h radius))
61 | [(- (- h radius) (Math/abs vy)) (- vy)]
62 | [y vy]))]
63 | (assoc p :pos (vec2 x y) :vel (vec2 vx vy))))
64 |
65 | (defn svg-particle
66 | [p]
67 | (svg/circle (get p :pos) (get p :radius) {:fill (get p :col)}))
68 |
69 | (defn init
70 | []
71 | (swap!
72 | app
73 | (fn [{:keys [width height num] :as state}]
74 | (merge state
75 | {:particles (vec (repeatedly num #(make-particle width height)))}))))
76 |
77 | (defn run-sim
78 | [{:keys [width height num] :as state}]
79 | (update state
80 | :particles (fn [particles]
81 | (reduce
82 | (fn [acc i] (assoc acc i (update-particle acc width height (acc i))))
83 | particles (range num)))))
84 |
85 | (defn draw-canvas
86 | [canvas ctx particles]
87 | (set! (.-width canvas) (.-width canvas))
88 | (loop [particles particles]
89 | (when particles
90 | (let [{:keys [pos] :as p} (first particles)]
91 | (set! (.-fillStyle ctx) (get p :col))
92 | (doto ctx
93 | (.beginPath)
94 | (.arc (v/x pos) (v/y pos) (get p :radius) 0 m/TWO_PI)
95 | (.fill))
96 | (recur (next particles))))))
97 |
98 | (defn main-svg
99 | []
100 | (init)
101 | (let [root (dom/create! "div" (dom/by-id "app"))
102 | samples (volatile! [])]
103 | (anim/animate
104 | (fn [t frame]
105 | (let [fps (utils/run-with-timer
106 | samples 30
107 | #(->> root
108 | (dom/clear!)
109 | (dom/create-dom!
110 | (svg/svg
111 | {:width 640 :height 480}
112 | (svg/group
113 | {:stroke "none"}
114 | (map svg-particle (:particles (swap! app run-sim))))))))]
115 | (dom/set-text!
116 | (dom/by-id "stats") (f/format ["SVG: " (f/float 3) " ms"] fps))
117 | true)))))
118 |
119 | (defn main-svg-attribs
120 | []
121 | (init)
122 | (let [root (dom/create! "div" (dom/by-id "app"))
123 | samples (volatile! [])
124 | num (:num @app)]
125 | (dom/create-dom!
126 | (svg/svg
127 | {:width 640 :height 480}
128 | (svg/group
129 | {:id "particles" :stroke "none"}
130 | (map svg-particle (:particles (swap! app run-sim)))))
131 | root)
132 | (anim/animate
133 | (fn [t frame]
134 | (let [pel (.-children (dom/by-id "particles"))
135 | fps (utils/run-with-timer
136 | samples 30
137 | (fn []
138 | (let [particles (:particles (swap! app run-sim))]
139 | (loop [i 0]
140 | (if (< i num)
141 | (let [pos (get (nth particles i) :pos)
142 | e (aget pel i)]
143 | (.setAttribute e "cx" (v/x pos))
144 | (.setAttribute e "cy" (v/y pos))
145 | (recur (inc i))))))))]
146 | (dom/set-text!
147 | (dom/by-id "stats") (f/format ["SVG: " (f/float 3) " ms"] fps))
148 | true)))))
149 |
150 | (defn main-canvas
151 | []
152 | (init)
153 | (let [canvas (dom/create-dom!
154 | [:canvas {:width 640 :height 480}]
155 | (dom/by-id "app"))
156 | ctx (.getContext canvas "2d")
157 | samples (volatile! [])]
158 | (anim/animate
159 | (fn [t frame]
160 | (let [fps (utils/run-with-timer
161 | samples 30
162 | #(->> (swap! app run-sim)
163 | :particles
164 | (draw-canvas canvas ctx)))]
165 | (dom/set-text!
166 | (dom/by-id "stats") (f/format ["Canvas: " (f/float 3) " ms"] fps))
167 | true)))))
168 |
169 | ;;(main-svg)
170 | ;;(main-svg-attribs)
171 | ;;(main-canvas)
172 |
--------------------------------------------------------------------------------
/day1/ex02/src/ex02/csgtest.clj:
--------------------------------------------------------------------------------
1 | (with-open [o (io/output-stream "foo.stl")]
2 | (mio/write-stl
3 | (mio/wrapped-output-stream o)
4 | (g/tessellate (g/as-mesh (a/aabb 1)))))
5 |
6 |
7 | ;; [thi.ng.geom.mesh.csg]
8 | ;; [thi.ng.geom.mesh.io]
9 | ;; [thi.ng.geom.mesh.subdivision]
10 |
11 | (let [a (g/as-mesh (g/translate (s/sphere 1) [0.75 0 0]))
12 | b (g/as-mesh (s/sphere 1))
13 | result (csg/csg->mesh
14 | (csg/substract
15 | (csg/mesh->csg b)
16 | (csg/mesh->csg a)))]
17 | (with-open [o (io/output-stream "foo.obj")]
18 | (mio/write-obj
19 | (mio/wrapped-output-stream o)
20 | result)))
21 |
--------------------------------------------------------------------------------
/day1/ex02/src/ex02/shapes01.cljs:
--------------------------------------------------------------------------------
1 | (ns ex02.shapes01
2 | (:require
3 | [thi.ng.geom.core :as g]
4 | [thi.ng.geom.polygon :as poly]
5 | [thi.ng.geom.svg.core :as svg]
6 | [thi.ng.domus.core :as dom]))
7 |
8 | (enable-console-print!)
9 |
10 | (defn ^:export main
11 | []
12 | (dom/create-dom!
13 | (svg/svg
14 | {:width 640 :height 480}
15 | (-> (poly/cog 0.5 20 [0.9 1 1 0.9 0.3])
16 | (g/scale 480)
17 | (g/translate [320 240])
18 | (g/vertices)
19 | (svg/polygon {:fill "black" :stroke "#0ff"})))
20 | (dom/by-id "app")))
21 |
22 | ;;(main)
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/day1/ex02/src/ex02/shapes02.cljs:
--------------------------------------------------------------------------------
1 | (ns ex02.shapes02
2 | (:require
3 | [thi.ng.geom.core :as g]
4 | [thi.ng.geom.vector :refer [vec3]]
5 | [thi.ng.geom.matrix :as mat]
6 | [thi.ng.geom.circle :as c]
7 | [thi.ng.geom.polygon :as p]
8 | [thi.ng.geom.gmesh :as gm]
9 | [thi.ng.geom.mesh.subdivision :as sd]
10 | [thi.ng.geom.svg.core :as svg]
11 | [thi.ng.geom.svg.shaders :as shader]
12 | [thi.ng.geom.svg.renderer :as render]
13 | [thi.ng.math.core :as m]
14 | [thi.ng.domus.core :as dom]))
15 |
16 | (enable-console-print!)
17 |
18 | (def width 640)
19 | (def height 480)
20 | (def model (g/rotate-y (mat/matrix44) m/SIXTH_PI))
21 | (def view (apply mat/look-at (mat/look-at-vectors 0 1.75 0.75 0 0 0)))
22 | (def proj (mat/perspective 60 (/ width height) 0.1 10))
23 | (def mvp (->> model (m/* view) (m/* proj)))
24 |
25 | (def diffuse (shader/normal-rgb (g/rotate-y (mat/matrix44) m/PI)))
26 | (def uniforms {:stroke "white" :stroke-width 0.25})
27 |
28 | (def shader-diffuse
29 | (shader/shader
30 | {:fill diffuse
31 | :uniforms uniforms
32 | :flags {:solid true}}))
33 |
34 | (def shader-lambert
35 | (shader/shader
36 | {:fill (shader/lambert
37 | {:view view
38 | :light-dir [-1 0 1]
39 | :light-col [1 1 1]
40 | :diffuse diffuse
41 | :ambient 0.1})
42 | :uniforms uniforms
43 | :flags {:solid true}}))
44 |
45 | (def shader-phong
46 | (shader/shader
47 | {:fill (shader/phong
48 | {:model model
49 | :view view
50 | :light-pos [-1 2 1]
51 | :light-col [1 1 1]
52 | :diffuse diffuse
53 | :ambient [0.05 0.05 0.2]
54 | :specular 0.8
55 | :shininess 8.0})
56 | :uniforms uniforms
57 | :flags {:solid true}}))
58 |
59 | (defn ring
60 | [res radius depth wall]
61 | (-> (c/circle radius)
62 | (g/as-polygon res)
63 | (g/extrude-shell {:depth depth :wall wall :inset -0.1 :mesh (gm/gmesh)})
64 | (g/center)))
65 |
66 | (def mesh
67 | (->> [[1 0.25 0.15] [0.75 0.35 0.1] [0.5 0.5 0.05] [0.25 0.75 0.05]]
68 | (map (partial apply ring 40))
69 | (reduce g/into)
70 | #_(sd/catmull-clark)
71 | #_(sd/catmull-clark)))
72 |
73 | ;; 2d text label w/ projected anchor point
74 | (defn label-3d
75 | [p mvp screen [l1 l2]]
76 | (let [p' (mat/project-point p mvp screen)
77 | p2' (mat/project-point (m/+ p 0 0 0.2) mvp screen)
78 | p3' (m/+ p2' 100 0)]
79 | (svg/group
80 | {:fill "black"
81 | :font-family "Arial"
82 | :font-size 12
83 | :text-anchor "end"}
84 | (svg/circle p' 2 nil)
85 | (svg/line-strip [p' p2' p3'] {:stroke "black"})
86 | (svg/text (m/+ p3' 0 -5) l1 {})
87 | (svg/text (m/+ p3' 0 12) l2 {:font-weight "bold"}))))
88 |
89 | (defn render-svg
90 | [shader]
91 | (let [screen (mat/viewport-matrix width height)
92 | max-z (/ 0.75 2)]
93 | (dom/create-dom!
94 | (->> (svg/svg
95 | {:width width :height height}
96 | (render/mesh mesh mvp screen shader)))
97 | (dom/by-id "app"))))
98 |
99 | (defn ^:export main
100 | []
101 | (time (render-svg shader-diffuse))
102 | (time (render-svg shader-lambert))
103 | (time (render-svg shader-phong)))
104 |
105 | ;;(main)
106 |
107 |
--------------------------------------------------------------------------------
/day1/ex02/src/ex02/utils.cljs:
--------------------------------------------------------------------------------
1 | (ns ex02.utils
2 | (:require
3 | [thi.ng.strf.core :as f]))
4 |
5 | (defn timed
6 | "Executes function f and returns its execution time in ms."
7 | [f] (let [t0 (f/now)] (f) (- (f/now) t0)))
8 |
9 | (defn conj-max
10 | "Takes a vector, size limit and value x. Appends x to vector and
11 | ensures vector does not grow beyond limit."
12 | [vec limit x]
13 | (let [n (count vec)]
14 | (if (>= n limit)
15 | (conj (subvec vec (inc (- n limit))) x)
16 | (conj vec x))))
17 |
18 | (defn run-with-timer
19 | "Takes a volatile containing vector of timing samples, window size
20 | and function f. Executes f and measures and records execution time,
21 | returns avg. exec time of whole time window."
22 | [samples window f]
23 | (let [samples (vswap! samples conj-max window (timed f))]
24 | (/ (reduce + samples) (count samples))))
25 |
--------------------------------------------------------------------------------
/day1/ex03/project.clj:
--------------------------------------------------------------------------------
1 | (defproject ws-ldn-8-ex03 "0.1.0-SNAPSHOT"
2 | :description "thi.ng Clojurescript workshop WS-LDN-8"
3 | :url "http://workshop.thi.ng"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 |
7 | :min-lein-version "2.5.3"
8 |
9 | :dependencies [[org.clojure/clojure "1.8.0"]
10 | [org.clojure/clojurescript "1.8.51"]
11 | [org.clojure/core.async "0.2.374"
12 | :exclusions [org.clojure/tools.reader]]
13 | [thi.ng/geom "0.0.1158-SNAPSHOT"]
14 | [thi.ng/domus "0.3.0-SNAPSHOT"]]
15 |
16 | :plugins [[lein-figwheel "0.5.0-6"]
17 | [lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]]
18 |
19 | :source-paths ["src"]
20 |
21 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
22 |
23 | :cljsbuild {:builds
24 | [{:id "dev"
25 | :source-paths ["src"]
26 | :compiler {:asset-path "js/compiled/out"
27 | :output-to "resources/public/js/compiled/app.js"
28 | :output-dir "resources/public/js/compiled/out"
29 | :optimizations :simple
30 | :pretty-print true}}
31 | {:id "min"
32 | :source-paths ["src"]
33 | :compiler {:output-to "resources/public/js/compiled/app.js"
34 | :optimizations :advanced
35 | :pretty-print false}}]}
36 |
37 | :figwheel {:css-dirs ["resources/public/css"]
38 | ;; :ring-handler hello_world.server/handler
39 | })
40 |
--------------------------------------------------------------------------------
/day1/ex03/resources/public/css/style.css:
--------------------------------------------------------------------------------
1 | .stats { position: fixed; top: 0px; left: 0px; }
--------------------------------------------------------------------------------
/day1/ex03/resources/public/img/cubev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/day1/ex03/resources/public/img/cubev.png
--------------------------------------------------------------------------------
/day1/ex03/resources/public/img/dione.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/day1/ex03/resources/public/img/dione.jpg
--------------------------------------------------------------------------------
/day1/ex03/resources/public/img/earth.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/day1/ex03/resources/public/img/earth.jpg
--------------------------------------------------------------------------------
/day1/ex03/resources/public/img/moon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/day1/ex03/resources/public/img/moon.jpg
--------------------------------------------------------------------------------
/day1/ex03/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/day1/ex03/src/ex03/webgl01.cljs:
--------------------------------------------------------------------------------
1 | (ns ex03.webgl01
2 | (:require
3 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
4 | [thi.ng.geom.gl.core :as gl]
5 | [thi.ng.geom.gl.webgl.constants :as glc]
6 | [thi.ng.geom.gl.webgl.animator :as anim]
7 | [thi.ng.geom.gl.glmesh :as glm]
8 | [thi.ng.geom.gl.shaders :as sh]
9 | [thi.ng.geom.core :as g]
10 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
11 | [thi.ng.geom.matrix :as mat :refer [M44]]
12 | [thi.ng.geom.circle :as c]
13 | [thi.ng.geom.polygon :as poly]))
14 |
15 | (enable-console-print!)
16 |
17 | (def shader-spec
18 | {:vs "void main() { gl_Position = proj * view * model * vec4(position, 0.0, 1.0); }"
19 | :fs "void main() { gl_FragColor = color; }"
20 | :uniforms {:proj :mat4
21 | :model [:mat4 M44]
22 | :view [:mat4 M44]
23 | :color [:vec4 [0 0 0 1]]}
24 | :attribs {:position :vec2}
25 | :state {:depth false}})
26 |
27 | (defn ^:export demo
28 | []
29 | (let [teeth 20
30 | gl (gl/gl-context "main")
31 | view-rect (gl/get-viewport-rect gl)
32 | model (-> (poly/cog 0.5 teeth [0.9 1 1 0.9])
33 | (gl/as-gl-buffer-spec {:normals false})
34 | (gl/make-buffers-in-spec gl glc/static-draw)
35 | (assoc-in [:uniforms :proj] (gl/ortho view-rect))
36 | (assoc :shader (sh/make-shader-from-spec gl shader-spec)))]
37 | (anim/animate
38 | (fn [t frame]
39 | (doto gl
40 | (gl/set-viewport view-rect)
41 | (gl/clear-color-and-depth-buffer 0.9 0.9 0.92 1 1)
42 | ;; draw left polygon
43 | (gl/draw-with-shader
44 | (update model :uniforms merge
45 | {:model (-> M44 (g/translate -0.48 0 0) (g/rotate t))
46 | :color [0 1 1 1]}))
47 | ;; draw right polygon
48 | (gl/draw-with-shader
49 | (update model :uniforms merge
50 | {:model (-> M44 (g/translate 0.48 0 0) (g/rotate (- (+ t (/ HALF_PI teeth)))))
51 | :color [0 1 0 1]})))
52 | true))))
53 |
--------------------------------------------------------------------------------
/day1/ex03/src/ex03/webgl02.cljs:
--------------------------------------------------------------------------------
1 | (ns ex03.webgl02
2 | (:require
3 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
4 | [thi.ng.geom.gl.core :as gl]
5 | [thi.ng.geom.gl.webgl.constants :as glc]
6 | [thi.ng.geom.gl.webgl.animator :as anim]
7 | [thi.ng.geom.gl.glmesh :as glm]
8 | [thi.ng.geom.gl.camera :as cam]
9 | [thi.ng.geom.gl.shaders :as sh]
10 | [thi.ng.geom.gl.shaders.basic :as basic]
11 | [thi.ng.geom.core :as g]
12 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
13 | [thi.ng.geom.matrix :as mat :refer [M44]]
14 | [thi.ng.geom.aabb :as a]
15 | [thi.ng.geom.attribs :as attr]
16 | [thi.ng.color.core :as col]))
17 |
18 | (defn ^:export demo
19 | []
20 | (let [gl (gl/gl-context "main")
21 | view-rect (gl/get-viewport-rect gl)
22 | model (-> (a/aabb 1)
23 | (g/center)
24 | (g/as-mesh
25 | {:mesh (glm/indexed-gl-mesh 12 #{:col})
26 | ;;:flags :ewfb
27 | :attribs {:col (->> [[1 0 0] [0 1 0] [0 0 1] [0 1 1] [1 0 1] [1 1 0]]
28 | (map col/rgba)
29 | (attr/const-face-attribs))}})
30 | (gl/as-gl-buffer-spec {})
31 | (cam/apply (cam/perspective-camera {:aspect view-rect}))
32 | (assoc :shader (sh/make-shader-from-spec gl (basic/make-shader-spec-3d true)))
33 | (gl/make-buffers-in-spec gl glc/static-draw))]
34 | (anim/animate
35 | (fn [t frame]
36 | (doto gl
37 | (gl/set-viewport view-rect)
38 | (gl/clear-color-and-depth-buffer col/WHITE 1)
39 | (gl/enable glc/depth-test)
40 | (gl/draw-with-shader
41 | (assoc-in model [:uniforms :model] (-> M44 (g/rotate-x t) (g/rotate-y (* t 2))))))
42 | true))))
43 |
--------------------------------------------------------------------------------
/day1/ex03/src/ex03/webgl03.cljs:
--------------------------------------------------------------------------------
1 | (ns ex03.webgl03
2 | (:require
3 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
4 | [thi.ng.geom.gl.core :as gl]
5 | [thi.ng.geom.gl.webgl.constants :as glc]
6 | [thi.ng.geom.gl.webgl.animator :as anim]
7 | [thi.ng.geom.gl.glmesh :as glm]
8 | [thi.ng.geom.gl.camera :as cam]
9 | [thi.ng.geom.gl.shaders :as sh]
10 | [thi.ng.geom.gl.shaders.lambert :as lambert]
11 | [thi.ng.geom.core :as g]
12 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
13 | [thi.ng.geom.matrix :as mat :refer [M44]]
14 | [thi.ng.geom.aabb :as a]
15 | [thi.ng.geom.attribs :as attr]
16 | [thi.ng.color.core :as col]))
17 |
18 | (defn ^:export demo
19 | []
20 | (let [gl (gl/gl-context "main")
21 | view-rect (gl/get-viewport-rect gl)
22 | model (-> (a/aabb 0.8)
23 | (g/center)
24 | (g/as-mesh
25 | {:mesh (glm/indexed-gl-mesh 12 #{:col :fnorm})
26 | ;;:flags :ewfbs
27 | :attribs {:col (->> [[1 0 0] [0 1 0] [0 0 1] [0 1 1] [1 0 1] [1 1 0]]
28 | (map col/rgba)
29 | (attr/const-face-attribs))}})
30 | (gl/as-gl-buffer-spec {})
31 | (cam/apply (cam/perspective-camera {:aspect view-rect}))
32 | (assoc :shader (sh/make-shader-from-spec gl lambert/shader-spec-two-sided-attrib))
33 | (gl/make-buffers-in-spec gl glc/static-draw))]
34 | (anim/animate
35 | (fn [t frame]
36 | (doto gl
37 | (gl/set-viewport view-rect)
38 | (gl/clear-color-and-depth-buffer col/GRAY 1)
39 | (gl/draw-with-shader
40 | (assoc-in model [:uniforms :model] (-> M44 (g/rotate-x t) (g/rotate-y (* t 2))))))
41 | true))))
42 |
--------------------------------------------------------------------------------
/day1/ex03/src/ex03/webgl04.cljs:
--------------------------------------------------------------------------------
1 | (ns ex03.webgl04
2 | (:require
3 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
4 | [thi.ng.geom.gl.core :as gl]
5 | [thi.ng.geom.gl.webgl.constants :as glc]
6 | [thi.ng.geom.gl.webgl.animator :as anim]
7 | [thi.ng.geom.gl.buffers :as buf]
8 | [thi.ng.geom.gl.shaders :as sh]
9 | [thi.ng.geom.gl.glmesh :as glm]
10 | [thi.ng.geom.gl.camera :as cam]
11 | [thi.ng.geom.core :as g]
12 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
13 | [thi.ng.geom.matrix :as mat :refer [M44]]
14 | [thi.ng.geom.aabb :as a]
15 | [thi.ng.geom.attribs :as attr]
16 | [thi.ng.color.core :as col]))
17 |
18 | (enable-console-print!)
19 |
20 | (def shader-spec
21 | {:vs "void main() {
22 | vUV = uv;
23 | gl_Position = proj * view * model * vec4(position, 1.0);
24 | }"
25 | :fs "void main() {
26 | gl_FragColor = texture2D(tex, vUV);
27 | }"
28 | :uniforms {:model [:mat4 M44]
29 | :view :mat4
30 | :proj :mat4
31 | :tex :sampler2D}
32 | :attribs {:position :vec3
33 | :uv :vec2}
34 | :varying {:vUV :vec2}
35 | :state {:depth-test false
36 | :blend true
37 | :blend-fn [glc/src-alpha glc/one]}})
38 |
39 | (defn ^:export demo
40 | []
41 | (let [gl (gl/gl-context "main")
42 | view-rect (gl/get-viewport-rect gl)
43 | model (-> (a/aabb 1)
44 | (g/center)
45 | (g/as-mesh
46 | {:mesh (glm/indexed-gl-mesh 12 #{:uv})
47 | ;;:flags :nsb
48 | :attribs {:uv (attr/face-attribs (attr/uv-cube-map-v 256 false))}})
49 | (gl/as-gl-buffer-spec {})
50 | (assoc :shader (sh/make-shader-from-spec gl shader-spec))
51 | (gl/make-buffers-in-spec gl glc/static-draw))
52 | tex-ready (volatile! false)
53 | tex (buf/load-texture
54 | gl {:callback (fn [tex img] (vreset! tex-ready true))
55 | :src "img/cubev.png"
56 | :flip true})]
57 | (anim/animate
58 | (fn [t frame]
59 | (when @tex-ready
60 | (gl/bind tex 0)
61 | (doto gl
62 | (gl/set-viewport view-rect)
63 | (gl/clear-color-and-depth-buffer 0.1 0.1 0.1 1 1)
64 | (gl/draw-with-shader
65 | (-> model
66 | (cam/apply
67 | (cam/perspective-camera
68 | {:eye (vec3 0 0 1.25)
69 | ;;:up (m/normalize (vec3 (Math/sin t) 1 0))
70 | :fov 90
71 | :aspect view-rect}))
72 | (assoc-in [:uniforms :model]
73 | (-> M44
74 | (g/rotate-x (* HALF_PI (Math/sin t)))
75 | (g/rotate-y (* t 2))))))))
76 | true))))
77 |
--------------------------------------------------------------------------------
/day1/ex03/src/ex03/webgl05.cljs:
--------------------------------------------------------------------------------
1 | (ns ex03.webgl05
2 | (:require
3 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
4 | [thi.ng.geom.gl.core :as gl]
5 | [thi.ng.geom.gl.webgl.constants :as glc]
6 | [thi.ng.geom.gl.webgl.animator :as anim]
7 | [thi.ng.geom.gl.buffers :as buf]
8 | [thi.ng.geom.gl.shaders :as sh]
9 | [thi.ng.geom.gl.glmesh :as glm]
10 | [thi.ng.geom.gl.camera :as cam]
11 | [thi.ng.geom.core :as g]
12 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
13 | [thi.ng.geom.matrix :as mat :refer [M44]]
14 | [thi.ng.geom.attribs :as attr]
15 | [thi.ng.geom.circle :as c]
16 | [thi.ng.geom.ptf :as ptf]
17 | [thi.ng.glsl.core :as glsl :include-macros true]
18 | [thi.ng.glsl.vertex :as vertex]
19 | [thi.ng.glsl.lighting :as light]
20 | [thi.ng.glsl.fog :as fog]
21 | [thi.ng.color.core :as col]
22 | [thi.ng.color.gradients :as grad]))
23 |
24 | (enable-console-print!)
25 |
26 | (def shader-spec
27 | {:vs (->> "void main() {
28 | vUV = uv + vec2(0, time * 0.025);
29 | vPos = (view * model * vec4(position, 1.0)).xyz;
30 | vNormal = surfaceNormal(normal, normalMat);
31 | vLightDir = (view * vec4(lightPos, 1.0)).xyz - vPos;
32 | gl_Position = proj * vec4(vPos, 1.0);
33 | }"
34 | (glsl/glsl-spec [vertex/surface-normal])
35 | (glsl/assemble))
36 | :fs (->> "void main() {
37 | vec3 n = normalize(vNormal);
38 | vec3 v = normalize(-vPos);
39 | vec3 l = normalize(vLightDir);
40 | float NdotL = max(0.0, dot(n, l));
41 | vec3 specular = Ks * beckmannSpecular(l, v, n, m);
42 | vec3 att = lightCol / pow(length(vLightDir), lightAtt);
43 | vec3 diff = texture2D(tex, vUV).xyz;
44 | vec3 col = att * NdotL * ((1.0 - s) * diff + s * specular) + Ka * diff;
45 | //float fog = fogLinear(length(vPos), 1.0, 7.5);
46 | //col = mix(col, Kf, fog);
47 | gl_FragColor = vec4(col, 1.0);
48 | }"
49 | (glsl/glsl-spec [fog/fog-linear light/beckmann-specular])
50 | (glsl/assemble))
51 | :uniforms {:model :mat4
52 | :view :mat4
53 | :proj :mat4
54 | :normalMat :mat4
55 | :tex :sampler2D
56 | :Ks [:vec3 [1 1 1]]
57 | :Ka [:vec3 [0.0 0.0 0.3]]
58 | :Kf [:vec3 [0.0 0.0 0.1]]
59 | :m [:float 0.9]
60 | :s [:float 0.1]
61 | :lightCol [:vec3 [200 80 40]]
62 | :lightPos [:vec3 [0 0 5]]
63 | :lightAtt [:float 3.0]
64 | :time :float}
65 | :attribs {:position :vec3
66 | :normal :vec3
67 | :uv :vec2}
68 | :varying {:vUV :vec2
69 | :vPos :vec3
70 | :vNormal :vec3
71 | :vLightDir :vec3}
72 | :state {:depth-test true}})
73 |
74 | (defn cinquefoil
75 | [t]
76 | (let [t (* t m/TWO_PI)
77 | pt (* 2.0 t)
78 | qt (* 5.0 t)
79 | qc (+ 3.0 (Math/cos qt))]
80 | (v/vec3 (* qc (Math/cos pt)) (* qc (Math/sin pt)) (Math/sin qt))))
81 |
82 | (defn knot-simple
83 | []
84 | (-> (mapv cinquefoil (butlast (m/norm-range 400)))
85 | (ptf/sweep-mesh
86 | (g/vertices (c/circle 0.5) 20)
87 | {:mesh (glm/gl-mesh 16800 #{:fnorm :uv})
88 | :attribs {:uv attr/uv-tube}
89 | :align? true
90 | :loop? true
91 | :close? false})))
92 |
93 | (defn knot-nested
94 | [nums numt]
95 | (-> (mapv cinquefoil (m/norm-range 400))
96 | (ptf/compute-frames)
97 | (ptf/align-frames)
98 | (ptf/sweep-strand-mesh
99 | #(+ 0.5 (* 0.5 (Math/sin (* 8 TWO_PI (/ % 400.0)))))
100 | 8 7 (g/vertices (c/circle 0.05) 8)
101 | {:mesh (glm/gl-mesh 65536 #{:fnorm :uv})
102 | :attribs {:uv attr/uv-tube}
103 | :close? true
104 | :align? true})))
105 |
106 | (defn gradient-texture
107 | [gl w h opts]
108 | (let [canv (.createElement js/document "canvas")
109 | ctx (.getContext canv "2d")
110 | cols (apply grad/cosine-gradient h (:rainbow1 grad/cosine-schemes))]
111 | (set! (.-width canv) w)
112 | (set! (.-height canv) h)
113 | (set! (.-strokeStyle ctx) "none")
114 | (loop [y 0, cols cols]
115 | (if cols
116 | (let [c (first cols)
117 | c (if (< (mod y 16) 8)
118 | (col/adjust-brightness c -0.75)
119 | c)]
120 | (set! (.-fillStyle ctx) @(col/as-css c))
121 | (.fillRect ctx 0 y w 1)
122 | (recur (inc y) (next cols)))
123 | [canv (buf/make-canvas-texture gl canv opts)]))))
124 |
125 | (defn ^:export demo
126 | []
127 | (let [gl (gl/gl-context "main")
128 | view-rect (gl/get-viewport-rect gl)
129 | model (-> (knot-simple)
130 | #_(knot-nested 8 7)
131 | (gl/as-gl-buffer-spec {})
132 | (cam/apply (cam/perspective-camera {:eye (vec3 0 0 5) :fov 90 :aspect view-rect}))
133 | (assoc :shader (sh/make-shader-from-spec gl shader-spec))
134 | (gl/make-buffers-in-spec gl glc/static-draw)
135 | (time))
136 | [tcanv tex] (gradient-texture gl 4 1024 {:wrap [glc/clamp-to-edge glc/repeat]})]
137 | (anim/animate
138 | (fn [t frame]
139 | (gl/bind tex 0)
140 | (doto gl
141 | (gl/set-viewport view-rect)
142 | (gl/clear-color-and-depth-buffer 0.0 0.0 0.1 1 1)
143 | (gl/draw-with-shader
144 | (-> model
145 | (update :uniforms assoc
146 | :time t
147 | :m (+ 0.21 (* 0.2 (Math/sin (* t 0.5))))
148 | :model (-> M44 (g/rotate-x (* t 0.36)) (g/rotate-y t)))
149 | (gl/inject-normal-matrix :model :view :normalMat))))
150 | true))
151 | (.appendChild (.-body js/document) tcanv)))
152 |
--------------------------------------------------------------------------------
/day1/ex03/src/ex03/webgl06.cljs:
--------------------------------------------------------------------------------
1 | (ns ex03.webgl06
2 | (:require
3 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
4 | [thi.ng.geom.gl.core :as gl]
5 | [thi.ng.geom.gl.webgl.constants :as glc]
6 | [thi.ng.geom.gl.webgl.animator :as anim]
7 | [thi.ng.geom.gl.buffers :as buf]
8 | [thi.ng.geom.gl.shaders :as sh]
9 | [thi.ng.geom.gl.shaders.lambert :as lambert]
10 | [thi.ng.geom.gl.fx :as fx]
11 | [thi.ng.geom.gl.glmesh :as glm]
12 | [thi.ng.geom.gl.camera :as cam]
13 | [thi.ng.geom.core :as g]
14 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
15 | [thi.ng.geom.matrix :as mat :refer [M44]]
16 | [thi.ng.geom.sphere :as s]
17 | [thi.ng.geom.attribs :as attr]
18 | [thi.ng.color.core :as col]
19 | [thi.ng.glsl.core :as glsl :include-macros true]
20 | [thi.ng.glsl.vertex :as vertex]))
21 |
22 | (enable-console-print!)
23 |
24 | (def shader-spec
25 | {:vs (->> "void main() {
26 | vUV = uv;
27 | vec3 p = rotateZ(position, position.z * sin(time) + time);
28 | gl_Position = proj * view * model * vec4(p, 1.0);
29 | }"
30 | (glsl/minified)
31 | (glsl/glsl-spec-plain [vertex/rotate-z])
32 | (glsl/assemble))
33 | :fs (->> "void main(){
34 | gl_FragColor = texture2D(tex, vUV);
35 | }"
36 | (glsl/minified))
37 | :uniforms {:model [:mat4 M44]
38 | :view :mat4
39 | :proj :mat4
40 | :tex [:sampler2D 0]
41 | :time :float}
42 | :attribs {:position :vec3
43 | :uv :vec2}
44 | :varying {:vUV :vec2}
45 | :state {:depth-test true}})
46 |
47 | (defn ^:export demo
48 | []
49 | (let [gl (gl/gl-context "main")
50 | view-rect (gl/get-viewport-rect gl)
51 | main-shader (sh/make-shader-from-spec gl shader-spec)
52 | lambert-shader (sh/make-shader-from-spec gl lambert/shader-spec-attrib)
53 | fbo-size 512
54 | fbo-tex (buf/make-texture
55 | gl {:width fbo-size
56 | :height fbo-size
57 | :filter glc/linear
58 | :wrap glc/clamp-to-edge})
59 | fbo (buf/make-fbo-with-attachments
60 | gl {:tex fbo-tex
61 | :width fbo-size
62 | :height fbo-size
63 | :depth? true})
64 | quad (-> (fx/init-fx-quad gl)
65 | (assoc :shader (sh/make-shader-from-spec gl fx/shader-spec))
66 | (assoc-in [:shader :state :tex] fbo-tex))
67 | model1 (-> (s/sphere 1)
68 | (g/as-mesh
69 | {:mesh (glm/gl-mesh 64 #{:col :fnorm})
70 | :attribs {:col (fn [_ _ v _] (col/rgba (m/madd (m/normalize v) 0.5 0.5)))}
71 | :res 6})
72 | (gl/as-gl-buffer-spec {})
73 | (cam/apply (cam/perspective-camera {:eye (vec3 0 0 3) :aspect 1.0}))
74 | (assoc :shader lambert-shader)
75 | (gl/make-buffers-in-spec gl glc/static-draw))
76 | model2 (-> (s/sphere 2.5)
77 | (g/as-mesh
78 | {:mesh (glm/gl-mesh 2048 #{:uv})
79 | :attribs {:uv attr/uv-faces}
80 | :res 32})
81 | (gl/as-gl-buffer-spec {})
82 | (cam/apply (cam/perspective-camera {:fov 90 :aspect view-rect}))
83 | (assoc :shader main-shader)
84 | (gl/make-buffers-in-spec gl glc/static-draw))]
85 |
86 | (anim/animate
87 | (fn [t frame]
88 | ;; render pass #1: Render to FBO
89 | (gl/bind fbo)
90 | (doto gl
91 | (gl/set-viewport 0 0 fbo-size fbo-size)
92 | (gl/clear-color-and-depth-buffer col/BLACK 1)
93 | (gl/draw-with-shader
94 | (assoc-in model1 [:uniforms :model]
95 | (-> M44 (g/rotate-x t) (g/rotate-y (* t 2))))))
96 | (gl/unbind fbo)
97 |
98 | ;; render pass #2: Render with FBO as texture
99 | (gl/bind fbo-tex)
100 | (doto gl
101 | (gl/set-viewport view-rect)
102 | (gl/clear-color-and-depth-buffer 0.8 0.8 0.8 1 1)
103 | (gl/draw-with-shader
104 | (update model2 :uniforms merge
105 | {:model (-> M44 (g/rotate-x (* t -0.25)) (g/rotate-y (* t -0.45)))
106 | :time t})))
107 | (gl/unbind fbo-tex)
108 |
109 | ;; render pass #3: Draw FBO texture as 2D image
110 | (doto gl
111 | (gl/set-viewport 0 0 128 128)
112 | (gl/draw-with-shader quad))
113 |
114 | true))))
115 |
--------------------------------------------------------------------------------
/day1/ex03/src/ex03/webgl07.cljs:
--------------------------------------------------------------------------------
1 | (ns ex03.webgl07
2 | (:require
3 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
4 | [thi.ng.geom.gl.core :as gl]
5 | [thi.ng.geom.gl.webgl.constants :as glc]
6 | [thi.ng.geom.gl.webgl.animator :as anim]
7 | [thi.ng.geom.gl.buffers :as buf]
8 | [thi.ng.geom.gl.shaders :as sh]
9 | [thi.ng.geom.gl.glmesh :as glm]
10 | [thi.ng.geom.gl.camera :as cam]
11 | [thi.ng.geom.core :as g]
12 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
13 | [thi.ng.geom.matrix :as mat :refer [M44]]
14 | [thi.ng.geom.sphere :as s]
15 | [thi.ng.geom.attribs :as attr]
16 | [thi.ng.color.core :as col]
17 | [thi.ng.glsl.core :as glsl :include-macros true]
18 | [thi.ng.glsl.vertex :as vertex]))
19 |
20 | (enable-console-print!)
21 |
22 | (def shader-spec
23 | {:vs "void main() {
24 | vUV = uv;
25 | gl_Position = proj * view * model * vec4(position, 1.0);
26 | }"
27 | :fs "void main() { gl_FragColor = texture2D(tex, vUV); }"
28 | :uniforms {:model [:mat4 M44]
29 | :view :mat4
30 | :proj :mat4
31 | :tex :sampler2D}
32 | :attribs {:position :vec3
33 | :uv :vec2}
34 | :varying {:vUV :vec2}
35 | :state {:depth-test true}})
36 |
37 | (defn ^:export demo
38 | []
39 | (let [gl (gl/gl-context "main")
40 | view-rect (gl/get-viewport-rect gl)
41 | sphere-res 40
42 | model (-> (s/sphere 1)
43 | (g/center)
44 | (g/as-mesh {:mesh (glm/gl-mesh 4096 #{:uv})
45 | :res sphere-res
46 | :attribs {:uv (attr/supplied-attrib :uv (fn [[u v]] (vec2 (- 1 u) v)))}})
47 | (gl/as-gl-buffer-spec {})
48 | (cam/apply
49 | (cam/perspective-camera
50 | {:eye (vec3 0 0 1.5)
51 | :fov 90
52 | :aspect view-rect}))
53 | (assoc :shader (sh/make-shader-from-spec gl shader-spec))
54 | (gl/make-buffers-in-spec gl glc/static-draw))
55 | tex-ready (volatile! false)
56 | tex (buf/load-texture
57 | gl {:callback (fn [tex img] (.generateMipmap gl (:target tex)) (vreset! tex-ready true))
58 | :src "img/earth.jpg"
59 | :filter [glc/linear-mipmap-linear glc/linear]
60 | :flip false})]
61 | (anim/animate
62 | (fn [t frame]
63 | (when @tex-ready
64 | (gl/bind tex 0)
65 | (doto gl
66 | (gl/set-viewport view-rect)
67 | (gl/clear-color-and-depth-buffer 0 0 0.05 1 1)
68 | (gl/draw-with-shader
69 | (assoc-in model [:uniforms :model]
70 | (-> M44 (g/rotate-x (m/radians 24.5)) (g/rotate-y (/ t 3)))))))
71 | true))))
72 |
--------------------------------------------------------------------------------
/day2/ex04/project.clj:
--------------------------------------------------------------------------------
1 | (defproject ws-ldn-8-ex04 "0.1.0-SNAPSHOT"
2 | :description "thi.ng Clojurescript workshop WS-LDN-8"
3 | :url "http://workshop.thi.ng"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 |
7 | :min-lein-version "2.5.3"
8 |
9 | :dependencies [[org.clojure/clojure "1.8.0"]
10 | [org.clojure/clojurescript "1.8.51"]
11 | [org.clojure/core.async "0.2.374"
12 | :exclusions [org.clojure/tools.reader]]
13 | [thi.ng/geom "0.0.1158-SNAPSHOT"]
14 | [thi.ng/domus "0.3.0-SNAPSHOT"]
15 | [reagent "0.5.1"]
16 | [cljsjs/localforage "1.3.1-0"]]
17 |
18 | :plugins [[lein-figwheel "0.5.0-6"]
19 | [lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]]
20 |
21 | :source-paths ["src"]
22 |
23 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
24 |
25 | :cljsbuild {:builds
26 | [{:id "dev1"
27 | :source-paths ["src"]
28 | :figwheel true
29 | :compiler {:main ex04.core
30 | :asset-path "js/compiled/out"
31 | :output-to "resources/public/js/compiled/app.js"
32 | :output-dir "resources/public/js/compiled/out"
33 | :source-map-timestamp true}}
34 | {:id "min"
35 | :source-paths ["src"]
36 | :compiler {:output-to "resources/public/js/compiled/app.js"
37 | :optimizations :advanced
38 | :pretty-print false}}]}
39 |
40 | :figwheel {:css-dirs ["resources/public/css"]
41 | ;; :ring-handler hello_world.server/handler
42 | })
43 |
--------------------------------------------------------------------------------
/day2/ex04/resources/public/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | overflow: hidden;
5 | background-color: black;
6 | }
--------------------------------------------------------------------------------
/day2/ex04/resources/public/img/cubev.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/day2/ex04/resources/public/img/cubev.png
--------------------------------------------------------------------------------
/day2/ex04/resources/public/img/sjo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/day2/ex04/resources/public/img/sjo512.png
--------------------------------------------------------------------------------
/day2/ex04/resources/public/img/sjo512_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/day2/ex04/resources/public/img/sjo512_2.png
--------------------------------------------------------------------------------
/day2/ex04/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/day2/ex04/src/ex04/cache.cljs:
--------------------------------------------------------------------------------
1 | (ns ex04.cache
2 | (:require
3 | ))
4 |
5 | ;; localforage.config({
6 | ;; driver: localforage.LOCALSTORAGE,
7 | ;; name: 'I-<3-localStorage'
8 | ;; });
9 |
--------------------------------------------------------------------------------
/day2/ex04/src/ex04/camera.cljs:
--------------------------------------------------------------------------------
1 | (ns ex04.camera
2 | (:require
3 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
4 | [thi.ng.geom.gl.camera :as cam]
5 | [thi.ng.geom.utils :as gu]))
6 |
7 | (defn camera-path
8 | [points frames]
9 | (let [up (nth frames 2)]
10 | {:pos points
11 | :pos-index (gu/arc-length-index points)
12 | :up up
13 | :up-index (gu/arc-length-index up)}))
14 |
15 | (defn camera-at-path-pos
16 | [{:keys [pos pos-index up up-index]} t delta view-rect]
17 | (let [t (mod t 1.0)
18 | t (if (neg? t) (inc t) t)
19 | t' (mod (+ t delta) 1.0)
20 | eye (gu/point-at t pos pos-index)
21 | target (gu/point-at t' pos pos-index)
22 | up (m/normalize (gu/point-at t up up-index))]
23 | (cam/perspective-camera
24 | {:eye eye
25 | :target target
26 | :up up
27 | :fov 90
28 | :aspect view-rect
29 | :far 10})))
30 |
--------------------------------------------------------------------------------
/day2/ex04/src/ex04/config.cljs:
--------------------------------------------------------------------------------
1 | (ns ex04.config)
2 |
3 | (def config
4 | {:player-speed 0.0004
5 | :player-max-speed 0.0012
6 | :accel 0.025
7 | :steer-accel 0.05
8 | :tunnel-path-res 0.2
9 | :cam-distance 0.005
10 | :cam-dist-factor 20
11 | :cam-speed-factor 50})
12 |
--------------------------------------------------------------------------------
/day2/ex04/src/ex04/core.cljs:
--------------------------------------------------------------------------------
1 | (ns ex04.core
2 | (:require-macros
3 | [reagent.ratom :refer [reaction]]
4 | [cljs-log.core :refer [debug info warn severe]])
5 | (:require
6 | [ex04.game :as game]
7 | [thi.ng.geom.gl.webgl.animator :as anim]
8 | [thi.ng.domus.core :as dom]
9 | [reagent.core :as reagent]))
10 |
11 | (enable-console-print!)
12 |
13 | (defn gl-component
14 | [props]
15 | (reagent/create-class
16 | {:component-did-mount
17 | (fn [this]
18 | (reagent/set-state this {:active true})
19 | ((:init props) this)
20 | (anim/animate ((:loop props) this)))
21 | :component-will-unmount
22 | (fn [this]
23 | (debug "unmount GL")
24 | (reagent/set-state this {:active false}))
25 | :reagent-render
26 | (fn [_]
27 | [:canvas
28 | (merge
29 | {:width (.-innerWidth js/window)
30 | :height (.-innerHeight js/window)}
31 | props)])}))
32 |
33 | (defn main
34 | []
35 | (.initializeTouchEvents js/React)
36 | (let [root [gl-component
37 | {:init game/init-game
38 | :loop game/game-loop
39 | :on-mouse-move (fn [e] (game/update-player-pos! (.-clientX e)))
40 | :on-mouse-down (fn [e] (game/player-max-speed!))
41 | :on-mouse-up (fn [e] (game/player-normal-speed!))
42 | :on-touch-move (fn [e]
43 | (game/update-player-pos! (.-clientX (aget (.-touches e) 0)))
44 | (game/player-max-speed!))
45 | :on-touch-end (fn [e] (game/player-normal-speed!))}]]
46 | (reagent/render-component root (dom/by-id "app"))))
47 |
48 | (main)
49 |
--------------------------------------------------------------------------------
/day2/ex04/src/ex04/game.cljs:
--------------------------------------------------------------------------------
1 | (ns ex04.game
2 | (:require-macros
3 | [thi.ng.math.macros :as mm]
4 | [cljs-log.core :refer [debug info warn severe]])
5 | (:require
6 | [ex04.config :refer [config]]
7 | [ex04.camera :as wscam]
8 | [ex04.shaders :as wsshader]
9 | [ex04.mesh :as wsmesh]
10 | [ex04.texture :as wstex]
11 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
12 | [thi.ng.geom.gl.core :as gl]
13 | [thi.ng.geom.gl.webgl.constants :as glc]
14 | [thi.ng.geom.gl.webgl.animator :as anim]
15 | [thi.ng.geom.gl.buffers :as buf]
16 | [thi.ng.geom.gl.shaders :as sh]
17 | [thi.ng.geom.gl.utils :as glu]
18 | [thi.ng.geom.gl.camera :as cam]
19 | [thi.ng.geom.gl.fx :as fx]
20 | [thi.ng.geom.core :as g]
21 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
22 | [thi.ng.geom.matrix :as mat :refer [M44]]
23 | [thi.ng.geom.ptf :as ptf]
24 | [thi.ng.geom.rect :as r]
25 | [thi.ng.geom.utils :as gu]
26 | [thi.ng.color.core :as col]
27 | [reagent.core :as reagent]))
28 |
29 | (defonce app
30 | (atom {}))
31 |
32 | (defn update-player-pos!
33 | [x]
34 | (let [w (g/width (:view @app))]
35 | (swap! app assoc-in [:player :target-pos]
36 | (m/map-interval-clamped
37 | x (* 0.25 w) (* 0.75 w) 0 1))))
38 |
39 | (defn player-normal-speed!
40 | []
41 | (swap! app assoc-in [:player :target-speed] (:player-speed config)))
42 |
43 | (defn player-max-speed!
44 | []
45 | (swap! app assoc-in [:player :target-speed] (:player-max-speed config)))
46 |
47 | (defn compute-player-worldpos
48 | [[path tangents norms binorms] x t]
49 | (let [player-theta (m/map-interval x 1 0 (m/radians 60) (m/radians 300))
50 | n (dec (count path))
51 | t (mod t 1.0)
52 | t*n (* t n)
53 | i (int t*n)
54 | j (mod (inc i) n)
55 | fract (- t*n i)
56 | pos (m/mix (nth path i) (nth path j) fract)
57 | fwd (m/normalize (m/mix (nth tangents i) (nth tangents j) fract))
58 | up (m/normalize (m/mix (nth norms i) (nth norms j) fract))
59 | right (m/normalize (m/mix (nth binorms i) (nth binorms j) fract))
60 | pos (->> (vec2 0.4 player-theta)
61 | g/as-cartesian
62 | (ptf/sweep-point pos up right))]
63 | (-> M44
64 | (g/translate pos)
65 | (m/* (mat/matrix44 ;; TODO add as mat/rotation-matrix-from-axes
66 | (right 0) (right 1) (right 2) 0
67 | (up 0) (up 1) (up 2) 0
68 | (fwd 0) (fwd 1) (fwd 2) 0
69 | 0 0 0 1))
70 | (g/rotate-z
71 | (m/map-interval x 0 1 (m/radians -110) (m/radians 110))))))
72 |
73 | (defn init-game
74 | [this]
75 | (let [gl (gl/gl-context (reagent/dom-node this))
76 | view-rect (gl/get-viewport-rect gl)
77 | tunnel-tex (wstex/gradient-texture gl 32 1024 {:wrap [glc/clamp-to-edge glc/repeat]})
78 | logo (buf/load-texture
79 | gl {:callback (fn [tex img] (swap! app assoc-in [:flags :logo-ready] true))
80 | :src "img/sjo512_2.png"
81 | :format glc/rgba
82 | :flip true})
83 | vw (g/width view-rect)
84 | vh (g/height view-rect)
85 | logo-size (min (* 0.8 (min vw vh)) 512)]
86 | (reset! app
87 | {:player {:speed 0
88 | :target-speed (:player-speed config)
89 | :pos 0.5
90 | :target-pos 0.5
91 | :track-pos 0.02
92 | :laps 0}
93 | :cam (wscam/camera-path wsmesh/path-points wsmesh/path-frames)
94 | :gl gl
95 | :view view-rect
96 | :logo-view (r/rect [(/ (- vw logo-size) 2) (/ (- vh logo-size) 2)] logo-size)
97 | :scene {:tunnel (-> (wsmesh/knot-simple)
98 | (gl/as-gl-buffer-spec {})
99 | (assoc :shader (sh/make-shader-from-spec gl wsshader/tunnel-shader))
100 | (assoc-in [:shader :state :tex] tunnel-tex)
101 | (gl/make-buffers-in-spec gl glc/static-draw)
102 | (time))
103 | :player (-> (wsmesh/player)
104 | (gl/as-gl-buffer-spec {})
105 | (assoc :shader (sh/make-shader-from-spec gl wsshader/player-shader))
106 | (gl/make-buffers-in-spec gl glc/static-draw))
107 | :tunnel-tex tunnel-tex
108 | :logo (-> (fx/init-fx-quad gl)
109 | (assoc :shader (sh/make-shader-from-spec gl fx/shader-spec))
110 | (update-in [:shader :state] merge
111 | {:tex logo
112 | :blend true}))}
113 | :flags {:active true
114 | :logo-ready false}})))
115 |
116 | (defn update-game-state!
117 | []
118 | (swap!
119 | app
120 | (fn [app]
121 | (let [{:keys [pos target-pos track-pos speed target-speed laps]} (:player app)
122 | speed (m/mix* speed target-speed (:accel config))
123 | tp (+ track-pos speed)
124 | laps (if (>= tp 1.0) (inc laps) laps)
125 | tp (if (>= tp 1.0) (dec tp) tp)
126 | xp (m/mix* pos target-pos (:steer-accel config))
127 | cam (wscam/camera-at-path-pos
128 | (:cam app)
129 | (- tp (+ (:cam-distance config) (* speed (:cam-dist-factor config))))
130 | (* speed (:cam-speed-factor config))
131 | (:view app))]
132 | (-> app
133 | (update :player merge
134 | {:pos xp
135 | :track-pos tp
136 | :speed speed
137 | :laps laps
138 | :tx (compute-player-worldpos wsmesh/path-frames xp tp)})
139 | (assoc-in [:scene :cam] cam))))))
140 |
141 | (defn game-loop
142 | [this]
143 | (fn [t frame]
144 | (update-game-state!)
145 | (let [{:keys [gl view logo-view player scene flags]} @app
146 | cam (:cam scene)
147 | lum (m/map-interval (Math/sin (+ PI (* t 0.2))) -1 1 0.1 0.5)
148 | [bgr bgg bgb] @(col/as-rgba (col/hsla 0.6666 1 lum))]
149 | (doto gl
150 | (gl/set-viewport view)
151 | (gl/clear-color-and-depth-buffer bgr bgg bgb 1 1)
152 | (gl/draw-with-shader
153 | (-> (:tunnel scene)
154 | (cam/apply cam)
155 | (update :uniforms assoc
156 | :time t
157 | :Ka [bgr bgg bgb]
158 | :Kf [bgr bgg bgb]
159 | :lightPos (:eye cam)
160 | :model M44)
161 | (gl/inject-normal-matrix :model :view :normalMat)))
162 | ;; draw player
163 | (gl/draw-with-shader
164 | (-> (:player scene)
165 | (cam/apply cam)
166 | (update :uniforms assoc
167 | :lightPos (:eye cam)
168 | :model (:tx player))
169 | (gl/inject-normal-matrix :model :view :normalMat))))
170 | (when (:logo-ready flags)
171 | (gl/set-viewport gl logo-view)
172 | (gl/draw-with-shader gl (:logo scene)))
173 | (:active (reagent/state this)))))
174 |
--------------------------------------------------------------------------------
/day2/ex04/src/ex04/mesh.cljs:
--------------------------------------------------------------------------------
1 | (ns ex04.mesh
2 | (:require
3 | [ex04.config :refer [config]]
4 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
5 | [thi.ng.geom.core :as g]
6 | [thi.ng.geom.vector :as v :refer [vec3]]
7 | [thi.ng.geom.attribs :as attr]
8 | [thi.ng.geom.aabb :as a]
9 | [thi.ng.geom.circle :refer [circle]]
10 | [thi.ng.geom.utils :as gu]
11 | [thi.ng.geom.gl.glmesh :refer [gl-mesh]]
12 | [thi.ng.geom.ptf :as ptf]))
13 |
14 | (defn cinquefoil
15 | [t]
16 | (let [t (* t TWO_PI)
17 | pt (* 2.0 t)
18 | qt (* 5.0 t)
19 | qc (+ 3.0 (Math/cos qt))]
20 | (v/vec3 (* qc (Math/cos pt)) (* qc (Math/sin pt)) (Math/sin qt))))
21 |
22 | (def path-points
23 | "Evaluated points of cinquefoil knot"
24 | (gu/sample-uniform
25 | (:tunnel-path-res config)
26 | false
27 | (map cinquefoil (m/norm-range 400))))
28 |
29 | (def path-frames
30 | "Precompute Parallel Transport Frames for each path point"
31 | (-> path-points ptf/compute-frames ptf/align-frames))
32 |
33 | (defn solidify-segment
34 | [res seg]
35 | (let [off (- (count seg) 2)
36 | front (loop [acc [], i 0, j off]
37 | (if (< i (dec res))
38 | (let [[averts aattr] (nth seg i)
39 | [bverts battr] (nth seg j)
40 | auv (:uv aattr)
41 | buv (:uv battr)
42 | f1 [[(nth averts 1) (nth averts 0) (nth bverts 1) (nth bverts 0)]
43 | {:uv [(nth auv 1) (nth auv 0) (nth buv 1) (nth buv 0)]}]]
44 | (recur (conj acc f1) (inc i) (dec j)))
45 | acc))]
46 | (concat seg front)))
47 |
48 | (defn knot-simple
49 | []
50 | (let [res 7
51 | profile (concat (reverse (g/vertices (circle 0.5) res))
52 | (g/vertices (circle 0.55) res))
53 | attribs {:uv attr/uv-tube}
54 | opts {:loop? false :close? true}
55 | size (* (inc (bit-shift-right (count path-points) 1)) (+ (* 2 res) (dec res)) 2)]
56 | (->> path-frames
57 | (ptf/sweep-profile profile attribs opts)
58 | (partition (* res 2))
59 | (take-nth 2)
60 | (mapcat #(solidify-segment res %))
61 | (g/into (gl-mesh size #{:fnorm :uv}))
62 | (time))))
63 |
64 | (defn player
65 | []
66 | (-> (a/aabb 0.15 0.05 0.3)
67 | (g/center)
68 | (g/as-mesh {:mesh (gl-mesh 12 #{:fnorm})})))
69 |
--------------------------------------------------------------------------------
/day2/ex04/src/ex04/shaders.cljs:
--------------------------------------------------------------------------------
1 | (ns ex04.shaders
2 | (:require
3 | [thi.ng.geom.matrix :as mat :refer [M44]]
4 | [thi.ng.geom.gl.shaders.phong :as phong]
5 | [thi.ng.glsl.core :as glsl :include-macros true]
6 | [thi.ng.glsl.vertex :as vertex]
7 | [thi.ng.glsl.lighting :as light]
8 | [thi.ng.glsl.fog :as fog]))
9 |
10 | (glsl/defglsl tunnel-vs
11 | [vertex/surface-normal]
12 | "void main() {
13 | vUV = uv;
14 | vPos = (view * model * vec4(position, 1.0)).xyz;
15 | vNormal = surfaceNormal(normal, normalMat);
16 | vLightDir = (view * vec4(lightPos, 1.0)).xyz - vPos;
17 | gl_Position = proj * vec4(vPos, 1.0);
18 | }")
19 |
20 | (glsl/defglsl tunnel-fs
21 | [fog/fog-linear light/beckmann-specular]
22 | "void main() {
23 | vec3 n = normalize(vNormal);
24 | vec3 v = normalize(-vPos);
25 | vec3 l = normalize(vLightDir);
26 | float NdotL = max(0.0, dot(n, l));
27 | vec3 specular = Ks * beckmannSpecular(l, v, n, m);
28 | vec3 att = lightCol / pow(length(vLightDir), lightAtt);
29 | vec3 diff = texture2D(tex, vUV).xyz;
30 | vec3 col = att * NdotL * ((1.0 - s) * diff + s * specular) + Ka * diff;
31 | float fog = fogLinear(length(vPos), fogDist.x, fogDist.y);
32 | col = mix(col, Kf, fog);
33 | gl_FragColor = vec4(col, 1.0);
34 | }")
35 |
36 | (def tunnel-shader
37 | {:vs (glsl/assemble tunnel-vs)
38 | :fs (glsl/assemble tunnel-fs)
39 | :uniforms {:model [:mat4 M44]
40 | :view :mat4
41 | :proj :mat4
42 | :normalMat :mat4
43 | :tex :sampler2D
44 | :Ks [:vec3 [1 1 1]]
45 | :Ka [:vec3 [0.0 0.0 0.3]]
46 | :Kf [:vec3 [0.0 0.0 0.1]]
47 | :m [:float 0.5]
48 | :s [:float 0.5]
49 | :lightCol [:vec3 [1 1 1]]
50 | :lightPos [:vec3 [0 0 5]]
51 | :lightAtt [:float 3.0]
52 | :fogDist [:vec2 [1 4.5]]
53 | :time :float}
54 | :attribs {:position :vec3
55 | :normal :vec3
56 | :uv :vec2}
57 | :varying {:vUV :vec2
58 | :vPos :vec3
59 | :vNormal :vec3
60 | :vLightDir :vec3}
61 | :state {:depth-test true}})
62 |
63 | (def player-shader phong/shader-spec)
64 |
--------------------------------------------------------------------------------
/day2/ex04/src/ex04/texture.cljs:
--------------------------------------------------------------------------------
1 | (ns ex04.texture
2 | (:require
3 | [thi.ng.geom.gl.buffers :as buf]
4 | [thi.ng.color.core :as col]
5 | [thi.ng.color.gradients :as grad]))
6 |
7 | (defn gradient-texture
8 | [gl w h opts]
9 | (let [canv (.createElement js/document "canvas")
10 | ctx (.getContext canv "2d")
11 | cols (reverse (grad/cosine-gradient h (:rainbow1 grad/cosine-schemes)))]
12 | (set! (.-width canv) w)
13 | (set! (.-height canv) h)
14 | (set! (.-strokeStyle ctx) "none")
15 | (loop [y 0, cols cols]
16 | (if cols
17 | (do
18 | (set! (.-fillStyle ctx) @(col/as-css (first cols)))
19 | (.fillRect ctx 0 y w 1)
20 | (recur (inc y) (next cols)))
21 | (buf/make-canvas-texture gl canv opts)))))
22 |
--------------------------------------------------------------------------------
/day2/ex05/project.clj:
--------------------------------------------------------------------------------
1 | (defproject ws-ldn-8-ex05 "0.1.0-SNAPSHOT"
2 | :description "FIXME: write description"
3 | :url "http://example.com/FIXME"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 | :dependencies [[org.clojure/clojure "1.8.0"]
7 | [org.clojure/clojurescript "1.8.51"]
8 | [reagent "0.5.1"]]
9 |
10 | :plugins [[lein-figwheel "0.5.0-6"]
11 | [lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]]
12 |
13 | :clean-targets ^{:protect false} ["resources/public/js" "target"]
14 |
15 | :cljsbuild {:builds
16 | [{:source-paths ["src"]
17 | :id "dev"
18 | :compiler {:optimizations :simple
19 | :pretty-print true
20 | :output-to "resources/public/js/main.js"
21 | :modules {:cljs-base {:output-to "resources/public/js/base.js"}
22 | :app {:output-to "resources/public/js/app.js"
23 | :entries #{"ex05.core"}}
24 | :worker {:output-to "resources/public/js/worker.js"
25 | :entries #{"worker"}
26 | ;;:depends-on #{}
27 | }}}}
28 | {:source-paths ["src"]
29 | :id "prod"
30 | :compiler {:optimizations :advanced
31 | :output-to "resources/public/js/main.js"
32 | :modules {:cljs-base {:output-to "resources/public/js/base.js"}
33 | :app {:output-to "resources/public/js/app.js"
34 | :entries #{"ex05.core"}}
35 | :worker {:output-to "resources/public/js/worker.js"
36 | :entries #{"worker"}}}}}
37 | ]})
38 |
--------------------------------------------------------------------------------
/day2/ex05/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/day2/ex05/src/ex05/core.cljs:
--------------------------------------------------------------------------------
1 | (ns ex05.core
2 | (:require-macros
3 | [reagent.ratom :refer [reaction]])
4 | (:require
5 | [reagent.core :as r]))
6 |
7 | (def app (r/atom {}))
8 |
9 | (enable-console-print!)
10 |
11 | (defn update-worker-state
12 | "Callback handler for worker messages."
13 | [msg]
14 | (prn :received (.-data msg))
15 | (swap! app assoc :worker-msg (.-data msg)))
16 |
17 | (defn start-worker
18 | "Handler to send :start command to worker, enables
19 | :worker-active key in app state."
20 | []
21 | (.postMessage
22 | (:worker @app)
23 | (pr-str {:command :start :interval 1000}))
24 | (swap! app assoc :worker-msg nil :worker-active true))
25 |
26 | (defn stop-worker
27 | "Handler to send :stop command to worker, disables :worker-active
28 | key in app state atom."
29 | []
30 | (.postMessage
31 | (:worker @app)
32 | (pr-str {:command :stop}))
33 | (swap! app assoc :worker-active false))
34 |
35 | (defn app-component
36 | "Main reagent app component"
37 | []
38 | (let [msg (reaction (:worker-msg @app))
39 | active? (reaction (:worker-active @app))]
40 | (fn []
41 | [:div
42 | [:h1 "Worker example"]
43 | (if @active?
44 | [:div
45 | [:p "Latest message from worker:"]
46 | [:p (if @msg
47 | [:textarea
48 | {:cols 60
49 | :rows 5
50 | :value (pr-str @msg)}]
51 | "Waiting...")]
52 | [:p [:button {:on-click stop-worker} "Stop"]]]
53 | [:div
54 | [:p "Worker idle..."]
55 | [:button {:on-click start-worker} "Start"]])])))
56 |
57 | (defn init-app
58 | "Initializes worker & stores handle in app state atom."
59 | []
60 | (let [worker (js/Worker. "js/worker.js")]
61 | (set! (.-onmessage worker) update-worker-state)
62 | (reset! app {:worker worker})))
63 |
64 | (defn main
65 | []
66 | (init-app)
67 | (r/render-component [app-component] (.-body js/document)))
68 |
69 | (main)
70 |
--------------------------------------------------------------------------------
/day2/ex05/src/ex05/worker.cljs:
--------------------------------------------------------------------------------
1 | (ns worker
2 | (:require
3 | [cljs.reader :refer [read-string]]))
4 |
5 | ;; base.js contains all of cljs.core etc.
6 | (.importScripts js/self "base.js")
7 |
8 | ;; worker's app state
9 | (def state (atom {}))
10 |
11 | (defn start-ping
12 | "Command handler to start (and keep) pinging main app with given
13 | interval. Pinging stops when :active? key is false."
14 | [delay]
15 | (js/setTimeout
16 | (fn []
17 | (.postMessage
18 | js/self
19 | (str "Worker running (" (js/Date.) ")"))
20 | (when (:active? @state)
21 | (start-ping delay)))
22 | delay)
23 | (swap! state assoc :active? true))
24 |
25 | (defn stop-ping
26 | "Command handler to stop pinging main app."
27 | [] (swap! state assoc :active? false))
28 |
29 | (defn dispatch-command
30 | "Worker's onmessage handler. Decodes message as EDN and dispatches
31 | to command handlers based on :command key in message."
32 | [msg]
33 | (let [msg (read-string (.-data msg))]
34 | (case (keyword (:command msg))
35 | :start (start-ping (:interval msg))
36 | :stop (stop-ping)
37 | (.warn js/console (str "unknown worker command: " (:command msg))))))
38 |
39 | (set! (.-onmessage js/self) dispatch-command)
40 |
--------------------------------------------------------------------------------
/day3/ex06/project.clj:
--------------------------------------------------------------------------------
1 | (defproject ws-ldn-8-ex06 "0.1.0-SNAPSHOT"
2 | :description "thi.ng Clojurescript workshop WS-LDN-8"
3 | :url "http://workshop.thi.ng"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 |
7 | :min-lein-version "2.5.3"
8 |
9 | :dependencies [[org.clojure/clojure "1.8.0"]
10 | [org.clojure/clojurescript "1.8.51"]
11 | [org.clojure/core.async "0.2.374"
12 | :exclusions [org.clojure/tools.reader]]
13 | [thi.ng/geom "0.0.1158-SNAPSHOT"]
14 | [thi.ng/domus "0.3.0-SNAPSHOT"]
15 | [reagent "0.5.1"]
16 | [cljsjs/localforage "1.3.1-0"]]
17 |
18 | :plugins [[lein-figwheel "0.5.0-6"]
19 | [lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]]
20 |
21 | :source-paths ["src"]
22 |
23 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
24 |
25 | :cljsbuild {:builds
26 | [{:id "dev1"
27 | :source-paths ["src"]
28 | :figwheel true
29 | :compiler {:main ex06.core
30 | :asset-path "js/compiled/out"
31 | :output-to "resources/public/js/compiled/app.js"
32 | :output-dir "resources/public/js/compiled/out"
33 | :source-map-timestamp true}}
34 | {:id "min"
35 | :source-paths ["src"]
36 | :compiler {:output-to "resources/public/js/compiled/app.js"
37 | :optimizations :advanced
38 | :pretty-print false}}]}
39 |
40 | :figwheel {:css-dirs ["resources/public/css"]
41 | ;; :ring-handler hello_world.server/handler
42 | })
43 |
--------------------------------------------------------------------------------
/day3/ex06/resources/public/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica,Arial,sans-serif;
3 | margin: 0;
4 | padding: 0;
5 | overflow: hidden;
6 | background-color: black;
7 | color: white;
8 | }
9 |
10 | #ui {
11 | position: fixed;
12 | top: 10px;
13 | left: 10px;
14 | z-index: 1;
15 | }
--------------------------------------------------------------------------------
/day3/ex06/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/day3/ex06/src/ex06/core.cljs:
--------------------------------------------------------------------------------
1 | (ns ex06.core
2 | (:require-macros
3 | [reagent.ratom :refer [reaction]]
4 | [cljs-log.core :refer [debug info warn severe]])
5 | (:require
6 | [ex06.main :as main]
7 | [thi.ng.geom.gl.webgl.animator :as anim]
8 | [thi.ng.domus.core :as dom]
9 | [reagent.core :as reagent]))
10 |
11 | (enable-console-print!)
12 |
13 | (defn canvas-component
14 | [props]
15 | (reagent/create-class
16 | {:component-did-mount
17 | (fn [this]
18 | (reagent/set-state this {:active true})
19 | ((:init props) this)
20 | (anim/animate ((:loop props) this)))
21 | :component-will-unmount
22 | (fn [this]
23 | (debug "unmount GL")
24 | (reagent/set-state this {:active false}))
25 | :reagent-render
26 | (fn [_]
27 | [:canvas
28 | (merge
29 | {:width (.-innerWidth js/window)
30 | :height (.-innerHeight js/window)}
31 | props)])}))
32 |
33 | (defn rtc-status
34 | []
35 | (let [status (reaction (-> @main/app :stream :state))]
36 | (fn []
37 | [:div#rtc-status "Stream status: " (name @status)])))
38 |
39 | (defn shader-selector
40 | []
41 | (let [shaders (reaction (-> @main/app :shaders))
42 | curr (reaction (-> @main/app :curr-shader))]
43 | (fn []
44 | (when @shaders
45 | [:select {:default-value (name @curr)
46 | :on-change #(main/set-shader! (-> % .-target .-value))}
47 | (for [s (sort (keys @shaders)) :let [s (name s)]]
48 | [:option {:key s :value s} s])]))))
49 |
50 | (defn controls
51 | []
52 | [:div#ui
53 | [rtc-status]
54 | [shader-selector]])
55 |
56 | (defn app-component
57 | []
58 | [:div
59 | [canvas-component {:init main/init-app :loop main/update-app}]
60 | [controls]])
61 |
62 | (defn main
63 | []
64 | (.initializeTouchEvents js/React)
65 | (reagent/render-component [app-component] (dom/by-id "app")))
66 |
67 | (main)
68 |
--------------------------------------------------------------------------------
/day3/ex06/src/ex06/main.cljs:
--------------------------------------------------------------------------------
1 | (ns ex06.main
2 | (:require-macros
3 | [reagent.ratom :refer [reaction]]
4 | [cljs-log.core :refer [debug info warn severe]])
5 | (:require
6 | [ex06.shaders :as shaders]
7 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]]
8 | [thi.ng.geom.gl.core :as gl]
9 | [thi.ng.geom.gl.webgl.constants :as glc]
10 | [thi.ng.geom.gl.buffers :as buf]
11 | [thi.ng.geom.gl.shaders :as sh]
12 | [thi.ng.geom.gl.utils :as glu]
13 | [thi.ng.geom.gl.fx :as fx]
14 | [thi.ng.geom.core :as g]
15 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
16 | [thi.ng.geom.matrix :as mat :refer [M44]]
17 | [thi.ng.geom.rect :as r]
18 | [thi.ng.geom.aabb :as a]
19 | [thi.ng.geom.attribs :as attr]
20 | [thi.ng.geom.gl.glmesh :as glm]
21 | [thi.ng.geom.gl.camera :as cam]
22 | [thi.ng.geom.utils :as gu]
23 | [thi.ng.color.core :as col]
24 | [thi.ng.domus.core :as dom]
25 | [reagent.core :as reagent]))
26 |
27 | (defonce app
28 | (reagent/atom
29 | {:stream {:state :wait}
30 | :curr-shader :thresh}))
31 |
32 | (defn set-stream-state!
33 | [state] (swap! app assoc-in [:stream :state] state))
34 |
35 | (defn set-shader!
36 | [id] (swap! app assoc :curr-shader (keyword id)))
37 |
38 | (defn init-video-texture
39 | [video]
40 | (let [tex (buf/make-canvas-texture
41 | (:gl @app) video
42 | {:filter glc/linear
43 | :wrap glc/clamp-to-edge
44 | :width (.-width video)
45 | :height (.-height video)
46 | :flip true
47 | :premultiply false})]
48 | (swap! app assoc-in [:scene :img :shader :state :tex] tex)))
49 |
50 | (defn activate-rtc-stream
51 | [video stream]
52 | (swap! app assoc-in [:stream :video] video)
53 | (set! (.-onerror video)
54 | (fn [] (.stop stream) (set-stream-state! :error)))
55 | (set! (.-onended stream)
56 | (fn [] (.stop stream) (set-stream-state! :stopped)))
57 | (set! (.-src video)
58 | (.createObjectURL (or (aget js/window "URL") (aget js/window "webkitURL")) stream))
59 | (set-stream-state! :ready)
60 | (init-video-texture video))
61 |
62 | (defn init-rtc-stream
63 | [w h]
64 | (let [video (dom/create-dom!
65 | [:video {:width w :height h :hidden true :autoplay true}]
66 | (.-body js/document))]
67 | (cond
68 | (aget js/navigator "webkitGetUserMedia")
69 | (.webkitGetUserMedia js/navigator #js {:video true}
70 | #(activate-rtc-stream video %)
71 | #(set-stream-state! :forbidden))
72 | (aget js/navigator "mozGetUserMedia")
73 | (.mozGetUserMedia js/navigator #js {:video true}
74 | #(activate-rtc-stream video %)
75 | #(set-stream-state! :forbidden))
76 | :else
77 | (set-stream-state! :unavailable))))
78 |
79 | (defn init-app
80 | [this]
81 | (let [vw 640
82 | vh 480
83 | gl (gl/gl-context (reagent/dom-node this))
84 | view-rect (gl/get-viewport-rect gl)
85 | thresh (sh/make-shader-from-spec gl shaders/threshold-shader-spec)
86 | hue-shift (sh/make-shader-from-spec gl shaders/hueshift-shader-spec)
87 | twirl (sh/make-shader-from-spec gl shaders/twirl-shader-spec)
88 | pixelate (sh/make-shader-from-spec gl shaders/pixelate-shader-spec)
89 | tile (sh/make-shader-from-spec gl shaders/tile-shader-spec)
90 | fbo-tex (buf/make-texture
91 | gl {:width 512
92 | :height 512
93 | :filter glc/linear
94 | :wrap glc/clamp-to-edge})
95 | fbo (buf/make-fbo-with-attachments
96 | gl {:tex fbo-tex
97 | :width 512
98 | :height 512
99 | :depth? true})]
100 | (swap! app merge
101 | {:gl gl
102 | :view view-rect
103 | :shaders {:thresh thresh
104 | :hue-shift hue-shift
105 | :twirl twirl
106 | :tile tile
107 | :pixelate pixelate}
108 | :scene {:fbo fbo
109 | :fbo-tex fbo-tex
110 | :cube (-> (a/aabb 1)
111 | (g/center)
112 | (g/as-mesh
113 | {:mesh (glm/indexed-gl-mesh 12 #{:uv})
114 | :attribs {:uv attr/uv-faces}})
115 | (gl/as-gl-buffer-spec {})
116 | (assoc :shader (sh/make-shader-from-spec gl shaders/cube-shader-spec))
117 | (gl/make-buffers-in-spec gl glc/static-draw))
118 | :img (-> (fx/init-fx-quad gl)
119 | #_(assoc :shader thresh))}})
120 | (init-rtc-stream vw vh)))
121 |
122 | (defn update-app
123 | [this]
124 | (fn [t frame]
125 | (let [{:keys [gl view scene stream shaders curr-shader]} @app]
126 | (when-let [tex (get-in scene [:img :shader :state :tex])]
127 | (gl/configure tex {:image (:video stream)})
128 | (gl/bind tex)
129 | ;; render to texture
130 | ;; (gl/bind (:fbo scene))
131 | (doto gl
132 | ;;(gl/set-viewport 0 0 512 512)
133 | (gl/clear-color-and-depth-buffer col/BLACK 1)
134 | (gl/draw-with-shader
135 | (-> (:img scene)
136 | (assoc-in [:uniforms :time] t)
137 | (assoc :shader (shaders curr-shader)))))
138 | ;;(gl/unbind (:fbo scene))
139 | ;; render cube to main canvas
140 | ;;(gl/bind (:fbo-tex scene) 0)
141 | #_(doto gl
142 | (gl/set-viewport view)
143 | (gl/draw-with-shader
144 | (-> (:cube scene)
145 | (cam/apply
146 | (cam/perspective-camera
147 | {:eye (vec3 0 0 1.25) :fov 90 :aspect view}))
148 | (assoc-in [:uniforms :model] (-> M44 (g/rotate-x t) (g/rotate-y (* t 2))))))))
149 | (:active (reagent/state this)))))
150 |
--------------------------------------------------------------------------------
/day3/ex06/src/ex06/shaders.cljs:
--------------------------------------------------------------------------------
1 | (ns ex06.shaders
2 | (:require
3 | [thi.ng.geom.matrix :as mat]
4 | [thi.ng.geom.gl.fx :as fx]
5 | [thi.ng.glsl.core :as glsl :include-macros true]
6 | [thi.ng.glsl.color :as col]
7 | [thi.ng.glsl.vertex :as vertex]
8 | [thi.ng.dstruct.core :as d]))
9 |
10 | (def threshold-shader-spec
11 | (d/merge-deep
12 | fx/shader-spec
13 | {:fs (->> "void main() {
14 | vec3 rgb = texture2D(tex, vUV).rgb;
15 | float c = threshold(rgb, thresh1, thresh2);
16 | gl_FragColor = vec4(c, c, c, 1.0);
17 | }"
18 | (glsl/glsl-spec-plain [col/threshold])
19 | (glsl/assemble))
20 | :uniforms {:thresh1 [:float 0.4]
21 | :thresh2 [:float 0.401]
22 | :time [:float 0]}}))
23 |
24 | (def hueshift-shader-spec
25 | (d/merge-deep
26 | fx/shader-spec
27 | {:fs (->> "void main() {
28 | vec3 rgb = texture2D(tex, vUV).rgb;
29 | gl_FragColor = vec4(rotateHueRGB(rgb, time), 1.0);
30 | }"
31 | (glsl/glsl-spec-plain [col/rotate-hue-rgb])
32 | (glsl/assemble))
33 | :uniforms {:time [:float 0]}}))
34 |
35 | (def twirl-shader-spec
36 | (d/merge-deep
37 | fx/shader-spec
38 | {:fs (->> "void main() {
39 | vec2 uv = vUV - vec2(0.5);
40 | float theta = 10.0 * sin(time) * length(uv);
41 | float c = cos(theta);
42 | float s = sin(theta);
43 | uv = vec2(uv.x * c - uv.y * s, uv.x * s + uv.y * c) + vec2(0.5);
44 | vec3 rgb = texture2D(tex, uv).rgb;
45 | gl_FragColor = vec4(rgb, 1.0);
46 | }"
47 | (glsl/glsl-spec-plain [col/threshold])
48 | (glsl/assemble))
49 | :uniforms {:time [:float 0.0]}}))
50 |
51 | (def pixelate-shader-spec
52 | (d/merge-deep
53 | fx/shader-spec
54 | {:fs (->> "void main() {
55 | vec2 uv = floor(vUV / (1.0 / size) + 0.5) / size;
56 | gl_FragColor = vec4(texture2D(tex, uv).rgb, 1.0);
57 | }"
58 | (glsl/glsl-spec-plain [])
59 | (glsl/assemble))
60 | :uniforms {:time [:float 0.0]
61 | :size [:float 32]}}))
62 |
63 | (def tile-shader-spec
64 | (d/merge-deep
65 | fx/shader-spec
66 | {:fs (->> "void main() {
67 | gl_FragColor = vec4(texture2D(tex, fract(vUV * 32.0 * (sin(time) * 0.4 + 0.5))).rgb, 1.0);
68 | }"
69 | (glsl/glsl-spec-plain [])
70 | (glsl/assemble))
71 | :uniforms {:time [:float 0.0]
72 | :size [:float 32]}}))
73 |
74 | (def cube-shader-spec
75 | {:vs "void main() {
76 | vUV = uv;
77 | gl_Position = proj * view * model * vec4(position, 1.0);
78 | }"
79 | :fs "void main() {
80 | gl_FragColor = texture2D(tex, vUV);
81 | }"
82 | :uniforms {:model [:mat4 mat/M44]
83 | :view :mat4
84 | :proj :mat4
85 | :tex [:sampler2D 0]}
86 | :attribs {:position :vec3
87 | :uv :vec2}
88 | :varying {:vUV :vec2}
89 | :state {:depth-test true
90 | ;;:blend true
91 | ;;:blend-fn [glc/src-alpha glc/one]
92 | }})
93 |
--------------------------------------------------------------------------------
/day3/ex07/compile.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This compiles the file particles.c with optimizations,
4 | # declares a number of exported function names,
5 | # post-processes the resulting JS with Closure compiler and
6 | # wraps all within a global 'Particles' module/object
7 | # This module MUST be initialized by calling 'Particles();'
8 | # before first use (in our example this is done from CLJS in ex07.core/main)
9 |
10 | emcc -O2 -s ASM_JS=1 -s INVOKE_RUN=0 \
11 | -s EXPORTED_FUNCTIONS="['_main','_initParticleSystem','_updateParticleSystem','_getNumParticles','_getParticleComponent','_getParticlesPointer']" \
12 | -s "EXPORT_NAME='Particles'" \
13 | -s MODULARIZE=1 \
14 | --closure 1 \
15 | -o resources/public/js/native.js \
16 | particles.c
17 |
18 | # copy memory initialization file to main webroot dir
19 | cp resources/public/js/native.js.mem resources/public/
20 |
--------------------------------------------------------------------------------
/day3/ex07/externs.js:
--------------------------------------------------------------------------------
1 | var Module = {};
2 |
3 | Module.ccall = function() {};
4 | Module.cwrap = function() {};
5 |
--------------------------------------------------------------------------------
/day3/ex07/particles.c:
--------------------------------------------------------------------------------
1 | // Use ./compile.sh to compile this file
2 | // See comments there for further information...
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
11 |
12 | typedef struct {
13 | float x,y,z;
14 | } Vec3;
15 |
16 | typedef struct {
17 | Vec3 pos; // 12 bytes
18 | Vec3 vel; // 12 bytes
19 | Vec3 col; // 12 bytes
20 | } Particle;
21 |
22 | typedef struct {
23 | Particle *particles;
24 | uint32_t numParticles;
25 | uint32_t maxParticles;
26 | Vec3 emitPos;
27 | Vec3 emitDir;
28 | Vec3 gravity;
29 | float speed;
30 | uint32_t age;
31 | uint32_t maxAge;
32 | } ParticleSystem;
33 |
34 | static inline void setVec3(Vec3 *v, float x, float y, float z) {
35 | v->x = x;
36 | v->y = y;
37 | v->z = z;
38 | }
39 |
40 | static inline void addVec3(Vec3* v, Vec3* v2) {
41 | v->x += v2->x;
42 | v->y += v2->y;
43 | v->z += v2->z;
44 | }
45 |
46 | static inline void scaleVec3(Vec3* v, float s) {
47 | v->x *= s;
48 | v->y *= s;
49 | v->z *= s;
50 | }
51 |
52 | static inline void normalizeVec3(Vec3* v, float l) {
53 | float m = sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
54 | if (m > 0.0f) {
55 | l /= m;
56 | v->x *= l;
57 | v->y *= l;
58 | v->z *= l;
59 | }
60 | }
61 |
62 | static inline float randf01() {
63 | return (float)rand() / (float)RAND_MAX;
64 | }
65 |
66 | static inline float randf() {
67 | return randf01() * 2.0f - 1.0f;
68 | }
69 |
70 | static void emitParticle(ParticleSystem* psys) {
71 | Particle *p = &psys->particles[psys->numParticles];
72 | p->pos = psys->emitPos;
73 | p->vel = psys->emitDir;
74 | scaleVec3(&p->vel, 1.0f + randf01() * 5.0f);
75 | p->vel.x += randf();
76 | p->vel.z += randf();
77 | scaleVec3(&p->vel, psys->speed);
78 | setVec3(&p->col, randf01(), randf01(), randf01());
79 | psys->numParticles++;
80 | }
81 |
82 | uint32_t getNumParticles(ParticleSystem* psys) {
83 | return psys->numParticles;
84 | }
85 |
86 | Particle* getParticlesPointer(ParticleSystem* psys) {
87 | return psys->particles;
88 | }
89 |
90 | float getParticleComponent(ParticleSystem* psys, uint32_t idx, uint32_t component) {
91 | float *pos = (float*)&(psys->particles[idx]).pos;
92 | return pos[component];
93 | }
94 |
95 | static ParticleSystem* makeParticleSystem(uint32_t num) {
96 | ParticleSystem *psys = (ParticleSystem*)malloc(sizeof(ParticleSystem));
97 | psys->particles = (Particle*)malloc(num * sizeof(Particle));
98 | psys->maxParticles = num;
99 | psys->numParticles = 0;
100 | return psys;
101 | }
102 |
103 | ParticleSystem* initParticleSystem(uint32_t num, uint32_t maxAge, float emitX, float gravityY, float speed) {
104 | ParticleSystem *psys = makeParticleSystem(num);
105 | setVec3(&psys->emitPos, emitX, 1.f, 0.f);
106 | setVec3(&psys->emitDir, 0.f, 1.f, 0.f);
107 | setVec3(&psys->gravity, 0.f, gravityY, 0.f);
108 | psys->maxAge = maxAge;
109 | psys->speed = speed;
110 | return psys;
111 | }
112 |
113 | ParticleSystem* updateParticleSystem(ParticleSystem* psys) {
114 | if (psys->age == psys->maxAge) {
115 | psys->numParticles = 0;
116 | psys->age = 0;
117 | }
118 | if (psys->numParticles < psys->maxParticles) {
119 | uint32_t limit = MIN(psys->numParticles + 10, psys->maxParticles);
120 | while(psys->numParticles < limit) {
121 | emitParticle(psys);
122 | }
123 | }
124 | for(uint32_t i=0; i < psys->numParticles; i++) {
125 | Particle *p = &psys->particles[i];
126 | addVec3(&p->pos, &p->vel);
127 | addVec3(&p->vel, &psys->gravity);
128 | if (p->pos.y < 0) {
129 | p->pos.y = 0;
130 | p->vel.y *= -0.88f;
131 | }
132 | }
133 | psys->age++;
134 | return psys;
135 | }
136 |
137 | int main(int argc, char** argv) {
138 | printf("Hello Emscripten!\n");
139 | printf("Particle size: %u\n", sizeof(Particle));
140 | return 0;
141 | }
142 |
--------------------------------------------------------------------------------
/day3/ex07/project.clj:
--------------------------------------------------------------------------------
1 | (defproject ws-ldn-8-ex07 "0.1.0-SNAPSHOT"
2 | :description "thi.ng Clojurescript workshop WS-LDN-8"
3 | :url "http://workshop.thi.ng"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 |
7 | :min-lein-version "2.5.3"
8 |
9 | :dependencies [[org.clojure/clojure "1.8.0"]
10 | [org.clojure/clojurescript "1.8.51"]
11 | [org.clojure/core.async "0.2.374"
12 | :exclusions [org.clojure/tools.reader]]
13 | [thi.ng/geom "0.0.1158-SNAPSHOT"]
14 | [thi.ng/domus "0.3.0-SNAPSHOT"]
15 | [reagent "0.5.1"]
16 | [cljsjs/localforage "1.3.1-0"]]
17 |
18 | :plugins [[lein-figwheel "0.5.0-6"]
19 | [lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]]
20 |
21 | :source-paths ["src"]
22 |
23 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
24 |
25 | :cljsbuild {:builds
26 | [{:id "dev1"
27 | :source-paths ["src"]
28 | :figwheel true
29 | :compiler {:main ex07.core
30 | :asset-path "js/compiled/out"
31 | :output-to "resources/public/js/compiled/app.js"
32 | :output-dir "resources/public/js/compiled/out"
33 | :source-map-timestamp true}}
34 | {:id "min"
35 | :source-paths ["src"]
36 | :compiler {:output-to "resources/public/js/compiled/app.js"
37 | :optimizations :advanced
38 | :externs ["externs.js"]}}]}
39 |
40 | :figwheel {:css-dirs ["resources/public/css"]
41 | ;; :ring-handler hello_world.server/handler
42 | })
43 |
--------------------------------------------------------------------------------
/day3/ex07/resources/public/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica,Arial,sans-serif;
3 | margin: 0;
4 | padding: 0;
5 | overflow: hidden;
6 | background-color: black;
7 | color: white;
8 | }
9 |
10 | #ui {
11 | position: fixed;
12 | top: 10px;
13 | left: 10px;
14 | z-index: 1;
15 | }
--------------------------------------------------------------------------------
/day3/ex07/resources/public/img/tex32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/day3/ex07/resources/public/img/tex32.png
--------------------------------------------------------------------------------
/day3/ex07/resources/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/day3/ex07/src/ex07/core.cljs:
--------------------------------------------------------------------------------
1 | (ns ex07.core
2 | (:require-macros
3 | [reagent.ratom :refer [reaction]]
4 | [cljs-log.core :refer [debug info warn severe]])
5 | (:require
6 | [thi.ng.math.core :as m]
7 | [thi.ng.geom.gl.webgl.animator :as anim]
8 | [thi.ng.geom.gl.webgl.constants :as glc]
9 | [thi.ng.geom.gl.core :as gl]
10 | [thi.ng.geom.gl.shaders :as sh]
11 | [thi.ng.geom.gl.buffers :as buf]
12 | [thi.ng.geom.core :as g]
13 | [thi.ng.geom.matrix :as mat :refer [M44]]
14 | [thi.ng.geom.vector :as v :refer [vec2 vec3]]
15 | [thi.ng.domus.core :as dom]
16 | [thi.ng.color.core :as col]
17 | [reagent.core :as reagent]))
18 |
19 | (defonce app (reagent/atom {:mpos [0 0]}))
20 |
21 | (enable-console-print!)
22 |
23 | (defn canvas-component
24 | [props]
25 | (reagent/create-class
26 | {:component-did-mount
27 | (fn [this]
28 | (reagent/set-state this {:active true})
29 | ((:init props) this)
30 | (anim/animate ((:loop props) this)))
31 | :component-will-unmount
32 | (fn [this]
33 | (debug "unmount GL")
34 | (reagent/set-state this {:active false}))
35 | :reagent-render
36 | (fn [_]
37 | [:canvas
38 | (merge
39 | {:width (.-innerWidth js/window)
40 | :height (.-innerHeight js/window)}
41 | props)])}))
42 |
43 |
44 | (defn init-app-2d
45 | [this]
46 | (let [canvas (reagent/dom-node this)
47 | ctx (.getContext canvas "2d")
48 | psys (.ccall js/Particles "initParticleSystem" "*"
49 | #js ["number" "number" "number" "number"]
50 | #js [10000 1000 (/ (.-width canvas) 2) -0.1 3])
51 | psys-update (.cwrap js/Particles "updateParticleSystem" "*" #js ["number"])
52 | psys-count (.cwrap js/Particles "getNumParticles" "number" #js ["number"])
53 | psys-get (.cwrap js/Particles "getParticleComponent" "number" #js ["number" "number" "number"])]
54 | (swap! app merge
55 | {:psys psys
56 | :psys-update psys-update
57 | :psys-count psys-count
58 | :psys-get psys-get
59 | :canvas canvas
60 | :ctx ctx})))
61 |
62 | (defn update-app-2d
63 | [this]
64 | (fn [t frame]
65 | (let [{:keys [canvas ctx psys psys-update psys-count psys-get]} @app
66 | _ (psys-update psys)
67 | num (psys-count psys)]
68 | (set! (.-width canvas) (.-width canvas))
69 | (set! (.-fillStyle ctx) "red")
70 | (loop [i 0]
71 | (when (< i num)
72 | (let [x (psys-get psys i 0)
73 | y (psys-get psys i 1)]
74 | (doto ctx
75 | (.beginPath)
76 | (.arc x y 2 0 m/TWO_PI)
77 | (.fill))
78 | (recur (inc i)))))
79 | (:active (reagent/state this)))))
80 |
81 | (def shader-spec
82 | {:vs "void main() {
83 | vCol = vec4(color, 1.0);
84 | gl_Position = proj * view * model * vec4(position, 1.0);
85 | gl_PointSize = 16.0 - gl_Position.w * 1.5;
86 | }"
87 | :fs "void main() {
88 | gl_FragColor = texture2D(tex, gl_PointCoord) * vCol;
89 | }"
90 | :uniforms {:model [:mat4 M44]
91 | :view :mat4
92 | :proj :mat4
93 | :tex [:sampler2D 0]}
94 | :attribs {:position :vec3
95 | :color :vec3}
96 | :varying {:vCol :vec4}
97 | :state {:depth-test false
98 | :blend true
99 | :blend-fn [glc/src-alpha glc/one]}})
100 |
101 | (defn attrib-buffer-view
102 | [ptr stride num]
103 | (js/Float32Array. (.-buffer (aget js/Particles "HEAPU8")) ptr (* stride num)))
104 |
105 | (defn update-attrib-buffer
106 | [gl attrib ptr stride num]
107 | (.bindBuffer gl glc/array-buffer
108 | (get-in (:scene @app) [:particles :attribs attrib :buffer]))
109 | (.bufferData gl glc/array-buffer
110 | (attrib-buffer-view ptr stride num)
111 | glc/dynamic-draw))
112 |
113 | (defn init-app-3d
114 | [this]
115 | (let [psys (.ccall js/Particles "initParticleSystem" "*"
116 | #js ["number" "number" "number" "number"]
117 | #js [10000 1000 0.0 -0.01 0.125])
118 | psys-update (.cwrap js/Particles "updateParticleSystem" "*" #js ["number"])
119 | psys-count (.cwrap js/Particles "getNumParticles" "number" #js ["number"])
120 | psys-get (.cwrap js/Particles "getParticleComponent" "number" #js ["number" "number" "number"])
121 | particle-ptr (.ccall js/Particles "getParticlesPointer" "number" #js ["number"] #js [psys])
122 | gl (gl/gl-context (reagent/dom-node this))
123 | view (gl/get-viewport-rect gl)
124 | tex (buf/load-texture
125 | gl {:callback (fn [tex img] (swap! app assoc :tex-ready true))
126 | :src "img/tex32.png"})
127 | particles (-> {:attribs {:position {:data (attrib-buffer-view particle-ptr 9 10000)
128 | :size 3
129 | :stride 36}
130 | :color {:data (attrib-buffer-view (+ particle-ptr 24) 9 10000)
131 | :size 3
132 | :stride 36}}
133 | :num-vertices 10000
134 | :mode glc/points}
135 | (gl/make-buffers-in-spec gl glc/dynamic-draw)
136 | (assoc :shader (sh/make-shader-from-spec gl shader-spec))
137 | (assoc-in [:shader :state :tex] tex)
138 | (update :uniforms merge
139 | {:view (mat/look-at (vec3 0 2 2) (vec3 0 1 0) (vec3 0 1 0))
140 | :proj (mat/perspective 90 view 0.1 100)}))]
141 | (swap! app merge
142 | {:psys psys
143 | :psys-update psys-update
144 | :psys-count psys-count
145 | :psys-get psys-get
146 | :gl gl
147 | :particle-ptr particle-ptr
148 | :scene {:particles particles}})))
149 |
150 | (defn update-app-3d
151 | [this]
152 | (fn [t frame]
153 | (when (:tex-ready @app)
154 | (let [{:keys [gl psys psys-update psys-count particle-ptr scene mpos]} @app
155 | _ (psys-update psys)
156 | num (psys-count psys)]
157 | (update-attrib-buffer gl :position particle-ptr 9 10000)
158 | (update-attrib-buffer gl :color (+ particle-ptr 24) 9 10000)
159 | (doto gl
160 | (gl/clear-color-and-depth-buffer (col/rgba 0 0 0.1) 1)
161 | (gl/draw-with-shader
162 | (-> (:particles scene)
163 | (assoc :num-vertices num)
164 | (assoc-in [:uniforms :model]
165 | (-> M44
166 | (g/rotate-x (* (mpos 1) 0.001))
167 | (g/rotate-y (* (mpos 0) 0.001))
168 | (g/scale 0.1))))))))
169 | (:active (reagent/state this))))
170 |
171 | (defn main
172 | []
173 | ;; first initialize C module
174 | (js/Particles)
175 | (reagent/render-component
176 | [canvas-component
177 | {:init init-app-3d
178 | :loop update-app-3d
179 | :on-mouse-move #(swap! app assoc :mpos [(.-clientX %) (.-clientY %)])}]
180 | (dom/by-id "app")))
181 |
182 | (main)
183 |
--------------------------------------------------------------------------------
/docs/GLSL_ES_Specification_1.0.17.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/docs/GLSL_ES_Specification_1.0.17.pdf
--------------------------------------------------------------------------------
/docs/WebGL1.0-Specification.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thi-ng/ws-ldn-8/8690d9970af02f2a50d37fe9a30db42f46c0fc36/docs/WebGL1.0-Specification.pdf
--------------------------------------------------------------------------------