From 75b77ee48f8ade8ead06b878aedb03a936a0a3ee Mon Sep 17 00:00:00 2001 From: Casey Link Date: Wed, 29 May 2024 11:11:00 +0200 Subject: [PATCH] Chapter 0 Example 7 Two-Dimensional Noise --- notebooks/chapter_0.md | 19 +++++++++++++++++++ src/noc/chapter_0_7.cljs | 26 ++++++++++++++++++++++++++ src/noc/sketch.cljs | 11 +++++++---- 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/noc/chapter_0_7.cljs diff --git a/notebooks/chapter_0.md b/notebooks/chapter_0.md index 7897f5c..7ca7b2c 100644 --- a/notebooks/chapter_0.md +++ b/notebooks/chapter_0.md @@ -206,3 +206,22 @@ around the edges, so I implemented movement wrapping so the paths generated by the perlin noise are more apparent. Toggle between movement wrapping and canvas-constrained movement by clicking the checkbox. + +## [Example: Two-Dimensional Noise](https://natureofcode.com/random/#two-dimensional-noise) + + +```clojure +^{::clerk/no-cache true ::clerk/viewer clerk/code} +(slurp "src/noc/chapter_0_7.cljs") +(show-sketch :c0.7) +``` + +This example doesn't have a number, but I thought I'd include it anyways. The +original JS implementation used a nested for loop that mutates the loop variable +on each iteration. + +Of course in clojure we can't do that [^um-actually], so I took the approach of pre-computing the `xoffs` and `yoffs` as a lazy sequence. + +Click that reset button to see it regenerated! + +[^um-actually]: Well, technically we can using dynamic vars or an atom, but that's pretty nasty and should only be used as an escape hatch when necessary. diff --git a/src/noc/chapter_0_7.cljs b/src/noc/chapter_0_7.cljs new file mode 100644 index 0000000..5f83a53 --- /dev/null +++ b/src/noc/chapter_0_7.cljs @@ -0,0 +1,26 @@ +(ns noc.chapter-0-7 + (:require + [quil.core :as q])) + +(def size [640 240]) + +(defn init-state [_] + {}) + +(defn setup! [{:keys [width height]}] + (q/noise-seed (rand-int (-> js/Number (.-MAX_SAFE_INTEGER)))) + (q/background 255) + (let [img (q/create-image width height) + xoffs (take width (iterate #(+ % 0.01) 0.0))] + (doseq [[x xoff] (map-indexed vector xoffs)] + (let [yoffs (take height (iterate #(+ % 0.01) 0.0))] + (doseq [[y yoff] (map-indexed vector yoffs)] + (let [bright (Math/floor (q/map-range (q/noise xoff yoff) 0 1 0 255))] + (q/set-pixel img x y bright))))) + (q/update-pixels img) + (q/image img 0 0))) + +(defn tick [state] + state) + +(defn draw! [_]) diff --git a/src/noc/sketch.cljs b/src/noc/sketch.cljs index 46f356b..944fb0c 100644 --- a/src/noc/sketch.cljs +++ b/src/noc/sketch.cljs @@ -14,7 +14,8 @@ [noc.chapter-0-5 :as c0.5] [noc.chapter-0-6e :as c0.6e] [noc.chapter-0-6 :as c0.6] - [noc.chapter-0-7e :as c0.7e])) + [noc.chapter-0-7e :as c0.7e] + [noc.chapter-0-7 :as c0.7])) (def sketches {:walker (sketch-> c0.1) :rand-dist (sketch-> c0.2) @@ -26,7 +27,8 @@ :c0.5 (sketch-> c0.5) :c0.6e (sketch-> c0.6e) :c0.6 (sketch-> c0.6) - :c0.7e (sketch-> c0.7e)}) + :c0.7e (sketch-> c0.7e) + :c0.7 (sketch-> c0.7)}) (defn load-sketch [s] (when-let [sk (get sketches s)] @@ -78,7 +80,8 @@ (defn setup-state [init-fn] (-> (default-state (time-now!)) (merge (init-fn {:width (q/width) :height (q/height)})) - (ui/prepare-ui))) + (ui/prepare-ui) + (assoc :width (q/width) :height (q/height)))) (defn reset [sketch*] (let [{:keys [applet opts]} @sketch* @@ -87,7 +90,7 @@ (let [state* (q/state-atom)] (ui/remove-all! @state*) (reset! state* (setup-state init)) - (setup))))) + (setup @state*))))) (defn pause [sketch*] (let [{:keys [applet]} @sketch*]