<commit_before>** Demo

#+BEGIN_SRC clojure :noweb-ref demo
  (defn mg-hex-sphere
    []
    (let [hex (mg/apply-recursively (mg/reflect :dir :e) 5 [1] 1)
          reflected-hex (mg/reflect :dir :n :out [{} hex])
          inject #(-> hex
                      (assoc-in (mg/child-path [1 1 0]) %)
                      (assoc-in (mg/child-path [1 1 1 1 0]) %))
          seed-clone (mg/reflect :dir :s :out [{} (inject reflected-hex)])
          tree (mg/reflect :dir :s :out [(inject seed-clone) (inject reflected-hex)])]
      (-> (mg/seed (mg/sphere-lattice-seg 6 0.25 0.0955 0.2))
          (mg/walk tree)
          (mg/union-mesh)
          (g/transform (-> M44 (g/rotate-x (- m/HALF_PI)) (g/scale 0.5))))))
  
  (defn ^:export demo
    []
    (enable-console-print!)
    (let [gl           (gl/gl-context "main")
          light-shader (sh/make-shader-from-spec gl shadow/light-pass-spec)
          cam-shader   (sh/make-shader-from-spec gl shadow/cam-pass-spec)
          mesh         (mg-hex-sphere)
          room         (-> (a/aabb 5)
                           (g/center (vec3 0 2.4 0))
                           (g/as-mesh)
                           (g/flip))
          mesh         (g/into mesh room)
          _ (prn (count (g/faces mesh)))
          spec         (gl/as-webgl-buffer-spec mesh {:tessellate true :fnormals true})
          model        {:attribs (buf/make-attribute-buffers
                                  gl gl/static-draw
                                  {:position {:data (:vertices spec) :size 3}
                                   :normal   {:data (:normals spec) :size 3}})
                        :mode gl/triangles
                        :count (:num-vertices spec)}
          ov-quad      (overlay/overlay-spec-from-rect gl)
          view-rect    (gl/get-viewport-rect gl)
          cam-proj     (gl/perspective 45 view-rect 0.1 100.0)
          light-proj   (gl/perspective 45 1 0.01 100)
          light-fbo    (shadow/init-light-fbo gl 512)
          stats        (js/Stats.)
          sdom         (.call (aget stats "getDomElement") stats)]
  
      (.appendChild (.-body js/document) sdom)
      (.setAttribute sdom "class" "stats")
  
      (anim/animate
       (fn [[t frame]]
         (let [y          (m/map-interval (Math/sin (* t 0.5)) -1 1 0 3)
               cam-view   (-> (vec3 0 y 2)
                              (g/rotate-y (* t 0.4))
                              (mat/look-at (vec3 0 0 0) (vec3 0 1 0)))
               model-tx   (-> M44 (g/translate 0 0 0) (g/rotate-x (* 0 0.15)))
               cone-angle (m/map-interval (Math/cos (* t 0.3)) -1 1 30 90)
               lr         (* (m/map-interval (Math/cos (* t 0.7)) -1 1 -0.85 0.85) m/PI)
               light-view (mat/look-at (g/rotate-y (vec3 0 2.4 2.4) lr) (vec3 0 0 0) (vec3 0 1 0))
               light-rot  (mat/matrix44->matrix33-rot light-view)]
  
           (shadow/draw-light-pass
            gl light-fbo
            #(buf/draw-arrays
              gl (assoc model
                   :shader  light-shader
                   :attribs (select-keys (:attribs model) [:position])
                   :uniforms {:model model-tx
                              :view  light-view
                              :proj  light-proj})))
           (gl/set-viewport gl view-rect)
           (gl/clear-color-buffer gl 0.08 0.1 0.12 1.0)
           (shadow/draw-cam-pass
            gl (:tex light-fbo)
            (fn [uniforms]
              (buf/draw-arrays
               gl (assoc model
                    :shader   cam-shader
                    :uniforms (assoc uniforms
                                :model     model-tx
                                :view      cam-view
                                :proj      cam-proj
                                :lightView light-view
                                :lightProj light-proj
                                :lightRot  light-rot
                                :coneAngle cone-angle)))))
  
           (gl/disable gl gl/depth-test)
           (gl/disable gl gl/cull-face)
           (overlay/draw-overlay2d
            gl (assoc ov-quad
                 :viewport view-rect
                 :pos [(m/map-interval (Math/sin t) -1 1 0 512) 352]
                 :width 128
                 :height 128))
  
           (.call (aget stats "update") stats)
           ;; keep animating...
           true)))
      {:ctx gl}))
  
  (demo)
#+END_SRC


** Complete namespace definition

#+BEGIN_SRC clojure :tangle ../babel/test/thi/ng/geom/webgl/example01.cljs :noweb yes :mkdirp yes :padline no
(ns thi.ng.geom.webgl.example01
  (:require
    [thi.ng.geom.webgl.core :as gl]
    [thi.ng.geom.webgl.arrays :as arrays]
    [thi.ng.geom.webgl.animator :as anim]
    [thi.ng.geom.webgl.buffers :as buf]
    [thi.ng.geom.webgl.shaders :as sh]
    ;;[thi.ng.geom.webgl.shaders.phong :as phong]
    ;;[thi.ng.geom.webgl.shaders.spotlight :as spotlight]
    [thi.ng.geom.webgl.shaders.shadow :as shadow]
    [thi.ng.geom.webgl.shaders.overlay :as overlay]
    [thi.ng.geom.webgl.utils :as u]
    [thi.ng.geom.core :as g]
    [thi.ng.geom.core.vector :as v :refer [vec2 vec3]]
    [thi.ng.geom.core.matrix :as mat :refer [M44]]
    [thi.ng.geom.types]
    [thi.ng.geom.aabb :as a]
    [thi.ng.geom.sphere :as s]
    [thi.ng.geom.gmesh]
    [thi.ng.geom.mesh.csg :as csg]
    ;;[thi.ng.geom.mesh.subdivision :as sd]
    [thi.ng.morphogen.core :as mg]
    [thi.ng.common.math.core :as m]
    [thi.ng.common.error :as err])
  (:require-macros
    [thi.ng.macromath.core :as mm]))

  <<demo>>
#+END_SRC<commit_msg>add & refactor demos (add 2d polygon example & 3d version w/ phong shading)<commit_after>** Templates for namespace setup
#+BEGIN_SRC clojure :noweb-ref require-macros
  (:require-macros
   [thi.ng.macromath.core :as mm])
#+END_SRC

#+BEGIN_SRC clojure :noweb-ref default-requires
  [thi.ng.geom.webgl.core :as gl]
  [thi.ng.geom.webgl.arrays :as arrays]
  [thi.ng.geom.webgl.animator :as anim]
  [thi.ng.geom.webgl.buffers :as buf]
  [thi.ng.geom.webgl.shaders :as sh]
  [thi.ng.geom.webgl.utils :as glu]
  [thi.ng.geom.core :as g]
  [thi.ng.geom.core.vector :as v :refer [vec2 vec3]]
  [thi.ng.geom.core.matrix :as mat :refer [M44]]
  [thi.ng.geom.types]
  [thi.ng.common.math.core :as m :refer [PI HALF_PI TWO_PI]]
#+END_SRC

#+BEGIN_SRC clojure :noweb-ref stats
  (defn init-stats
    []
    (let [stats (js/Stats.)
          sdom  (.call (aget stats "getDomElement") stats)]
      (.appendChild (.-body js/document) sdom)
      (.setAttribute sdom "class" "stats")
      stats))

  (defn update-stats
   [stats]
   (.call (aget stats "update") stats))
#+END_SRC

** 2D polygons

This demo utilizes the [[file:shaders.org::Basic][basic color shader]] to draw two filled, rotating
2d polygons. The shader itself is generated based on given parameters
and the example shows some alternatives:

- =shader1= is requesting to specify the color as a uniform value
- =shader2= is requesting to specify the color as a vertex attribute
  and we generate the required attribute buffer in the call to
  =as-webgl-buffer-spec=.

If we're only after displaying a model with a single color,
specifying it as shader uniform is much more efficient. However,
having an attribute buffer allows us to specify colors per vertex and
hence provides more flexibility.

For both cases we set the =:3d= option to =false= in order to save on
bandwidth since our polygons are only 2d entities anyhow. Another
implication of this is that we don't need to specify a view matrix,
which has to be given for the 3d case though. Please see the above
link for more discussion about these options.

#+BEGIN_SRC clojure :tangle ../babel/test/thi/ng/geom/webgl/example01.cljs :noweb yes :mkdirp yes :padline no
  (ns thi.ng.geom.webgl.example01
    <<require-macros>>
    (:require
     <<default-requires>>
     [thi.ng.geom.webgl.shaders.basic :as basic]
     [thi.ng.geom.circle :as c]
     [thi.ng.geom.polygon :as poly]))

  <<stats>>

  (defn ^:export demo
    []
    (enable-console-print!)
    (let [gl         (gl/gl-context "main")
          shader1    (sh/make-shader-from-spec
                      gl (basic/make-color-shader-spec :attrib false :3d false))
          shader2    (sh/make-shader-from-spec
                      gl (basic/make-color-shader-spec :attrib true :3d false))
          teeth      20
          model      (-> (poly/cog 0.5 teeth [0.9 1 1 0.9])
                         (gl/as-webgl-buffer-spec {:normals false :color [1 0 0 1]})
                         (buf/make-attribute-buffers-in-spec gl gl/static-draw))
          view-rect  (gl/get-viewport-rect gl)
          proj       (gl/ortho view-rect)
          stats      (init-stats)]
      (anim/animate
       (fn [[t frame]]
         (gl/set-viewport gl view-rect)
         (gl/clear-color-buffer gl 1 0.98 0.95 1.0)
         ;; draw left polygon using color uniform (that's why we need to remove color attrib)
         (buf/draw-arrays
          gl (assoc model
               :shader  shader1
               :attribs (dissoc (:attribs model) :color)
               :uniforms {:model (-> M44 (g/translate -0.48 0 0) (g/rotate t))
                          :proj  proj
                          :color [0 1 1 1]}))
         ;; draw right polygon using color attribs
         (buf/draw-arrays
          gl (assoc model
               :shader  shader2
               :uniforms {:model (-> M44 (g/translate 0.48 0 0) (g/rotate (- (+ t (/ HALF_PI teeth)))))
                          :proj  proj}))
         (update-stats stats)
         true))))
#+END_SRC

** Extruded 2D polygons with Blinn-Phong shading

Using the same model setup as in the previous example, this time we
extrude the polygon and render the resulting 3D mesh. To better
appreciate the mesh structure, we make use of the Phong shader and see
how to combine transformation matrices: Each cog rotates around its
own axis, but is then also rotated around the global Y axis. This is
achieved with simple matrix multiplication (=rot= is the global
rotation / transformation).

#+BEGIN_SRC clojure :tangle ../babel/test/thi/ng/geom/webgl/example02.cljs :noweb yes :mkdirp yes :padline no
  (ns thi.ng.geom.webgl.example02
    <<require-macros>>
    (:require
     <<default-requires>>
     [thi.ng.geom.webgl.shaders.phong :as phong]
     [thi.ng.geom.circle :as c]
     [thi.ng.geom.polygon :as poly]))
  
  <<stats>>
  
  (defn ^:export demo
    []
    (enable-console-print!)
    (let [gl         (gl/gl-context "main")
          view-rect  (gl/get-viewport-rect gl)
          teeth      20
          model      (-> (poly/cog 0.5 teeth [0.9 1 1 0.9])
                         (g/extrude {:depth 0.1 :scale 0.9})
                         (gl/as-webgl-buffer-spec {:tessellate true :fnormals true})
                         (buf/make-attribute-buffers-in-spec gl gl/static-draw)
                         (assoc :shader (sh/make-shader-from-spec gl phong/shader-spec))
                         (update-in [:uniforms] merge
                                    {:proj (gl/perspective 45 view-rect 0.1 100.0)
                                     :lightPos (vec3 0 0.5 1)
                                     :shininess 64
                                     :useBlinnPhong true
                                     :wrap 0}))
          stats      (init-stats)]
      (anim/animate
       (fn [[t frame]]
         (let [model (assoc-in
                      model [:uniforms :view]
                      (mat/look-at (vec3 0 0 2) (vec3) (vec3 0 1 0)))
               rot   (g/rotate-y M44 (* t 0.5))
               tx1   (g/* rot (-> M44
                                  (g/translate -0.46 0 0)
                                  (g/rotate-y 0.3)
                                  (g/rotate-z t)))
               tx2   (g/* rot (-> M44
                                  (g/translate 0.46 0 0)
                                  (g/rotate-y -0.3)
                                  (g/rotate-z (- (+ t (/ HALF_PI teeth))))))]
  
           (gl/set-viewport gl view-rect)
           (gl/clear-color-buffer gl 1 0.98 0.95 1.0)
           (gl/clear-depth-buffer gl 1)
           (gl/enable gl gl/depth-test)  
           (phong/draw-phong gl (assoc-in model [:uniforms :model] tx1))
           (phong/draw-phong gl (assoc-in model [:uniforms :model] tx2))

           (update-stats stats)
           true)))))
#+END_SRC

** Shadow mapping

#+BEGIN_SRC clojure :tangle ../babel/test/thi/ng/geom/webgl/example03.cljs :noweb yes :mkdirp yes :padline no
  (ns thi.ng.geom.webgl.example03
    <<require-macros>>
    (:require
     <<default-requires>>
     [thi.ng.geom.webgl.shaders.shadow :as shadow]
     [thi.ng.geom.webgl.shaders.overlay :as overlay]
     [thi.ng.geom.aabb :as a]
     [thi.ng.morphogen.core :as mg]))

  <<stats>>

  (defn mg-hex-sphere
    []
    (let [hex           (mg/apply-recursively (mg/reflect :dir :e) 5 [1] 1)
          reflected-hex (mg/reflect :dir :n :out [{} hex])
          inject        #(-> hex
                             (assoc-in (mg/child-path [1 1 0]) %)
                             (assoc-in (mg/child-path [1 1 1 1 0]) %))
          seed-clone    (mg/reflect
                         :dir :s :out [{} (inject reflected-hex)])
          tree          (mg/reflect
                         :dir :s :out [(inject seed-clone) (inject reflected-hex)])]
      (-> (mg/seed (mg/sphere-lattice-seg 6 0.25 0.0955 0.2))
          (mg/walk tree)
          (mg/union-mesh)
          (g/transform (-> M44 (g/rotate-x (- HALF_PI)) (g/scale 0.5))))))

  (defn ^:export demo
    []
    (enable-console-print!)
    (let [gl           (gl/gl-context "main")
          light-shader (sh/make-shader-from-spec gl shadow/light-pass-spec)
          cam-shader   (sh/make-shader-from-spec gl shadow/cam-pass-spec)
          mesh         (mg-hex-sphere)
          room         (-> (a/aabb 5)
                           (g/center (vec3 0 2.4 0))
                           (g/as-mesh)
                           (g/flip))
          mesh         (g/into mesh room)
          model        (-> mesh
                           (gl/as-webgl-buffer-spec {:tessellate true :fnormals true})
                           (buf/make-attribute-buffers-in-spec gl gl/static-draw))
          ov-quad      (overlay/overlay-spec-from-rect gl)
          view-rect    (gl/get-viewport-rect gl)
          cam-proj     (gl/perspective 45 view-rect 0.1 100.0)
          light-proj   (gl/perspective 45 1 0.01 100)
          light-fbo    (shadow/init-light-fbo gl 512)
          stats        (init-stats)]

      (anim/animate
       (fn [[t frame]]
         (let [y          (m/map-interval (Math/sin (* t 0.5)) -1 1 0 3)
               cam-view   (-> (vec3 0 y 2)
                              (g/rotate-y (* t 0.4))
                              (mat/look-at (vec3 0 0 0) (vec3 0 1 0)))
               model-tx   (-> M44 (g/translate 0 0 0) (g/rotate-x (* 0 0.15)))
               cone-angle (m/map-interval (Math/cos (* t 0.3)) -1 1 30 90)
               lr         (* (m/map-interval (Math/cos (* t 0.7)) -1 1 -0.85 0.85) PI)
               light-view (mat/look-at (g/rotate-y (vec3 0 2.4 2.4) lr) (vec3 0 0 0) (vec3 0 1 0))
               light-rot  (mat/matrix44->matrix33-rot light-view)]

           (shadow/draw-light-pass
            gl light-fbo
            #(buf/draw-arrays
              gl (assoc model
                   :shader  light-shader
                   :attribs (select-keys (:attribs model) [:position])
                   :uniforms {:model model-tx
                              :view  light-view
                              :proj  light-proj})))
           (gl/set-viewport gl view-rect)
           (gl/clear-color-buffer gl 0.08 0.1 0.12 1.0)
           (shadow/draw-cam-pass
            gl (:tex light-fbo)
            (fn [uniforms]
              (buf/draw-arrays
               gl (assoc model
                    :shader   cam-shader
                    :uniforms (assoc uniforms
                                :model     model-tx
                                :view      cam-view
                                :proj      cam-proj
                                :lightView light-view
                                :lightProj light-proj
                                :lightRot  light-rot
                                :coneAngle cone-angle)))))

           (gl/disable gl gl/depth-test)
           (gl/disable gl gl/cull-face)
           (overlay/draw-overlay2d
            gl (assoc ov-quad
                 :viewport view-rect
                 :pos [(m/map-interval (Math/sin t) -1 1 0 512) 352]
                 :width 128
                 :height 128))

           (update-stats stats)
           ;; keep animating...
           true)))
      {:ctx gl}))
#+END_SRC
{'fraction_non_alphanumeric': 0.1266742067980237, 'fraction_numerical': 0.02637061729864873, 'mean_word_length': 1.4344297927836545, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2323506', 'n_tokens_mistral': 5916, 'n_tokens_neox': 5386, 'n_words': 1434}