├── .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 |
Workshop repo
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 |
10 |

WS-LDN-5

11 |
12 |
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 --------------------------------------------------------------------------------