Skip to content

Latest commit

 

History

History
2262 lines (2064 loc) · 70.6 KB

vector.org

File metadata and controls

2262 lines (2064 loc) · 70.6 KB

Contents

thi.ng.geom.vector

Vec2

(deftype Vec2
    #?(:clj
        [^doubles buf ^:unsynchronized-mutable _hash _meta]
        :cljs
        [buf ^:mutable _hash _meta])

Templates

assoc

(replace-regexp-in-string
 "{{fn}}" fn
 "(cond
    (number? k)  (if (or (== k 0) (== k 1))
                   (let [^doubles b ({{fn}} buf)]
                     (aset b k (double v)) (Vec2. b nil _meta))
                   (if (== k 2) (conj _ v) (err/key-error! k)))
    (keyword? k) (if (= :z k)
                   (conj _ v)
                   (Vec2. (swizzle-assoc* buf ({{fn}} buf) {\\x 0 \\y 1} k v) nil _meta)))")

compare

(if (instance? Vec2 o)
  (let [^doubles b' (.-buf ^Vec2 o)
        c (compare (aget buf 0) (aget b' 0))]
    (if (== 0 c) (compare (aget buf 1) (aget b' 1)) c))
  (let [c (count o)]
    (if (== 2 c) (- (compare o _)) (- 2 c))))

contains-key?

(if (number? k)
  (and (>= k 0) (< k 2))
  (if (swizzle2-fns k) true false))

equals / equiv

(replace-regexp-in-string
 "{{fn}}" fn
 "(if (instance? Vec2 o)
    (let [^doubles b' (.-buf ^Vec2 o)]
      (and (== (aget buf 0) (aget b' 0)) (== (aget buf 1) (aget b' 1))))
    (and (sequential? o) (== 2 (count o))
         ({{fn}} (aget buf 0) (first o))
         ({{fn}} (aget buf 1) (nth o 1))))")

hashCode

(-> 31
    (unchecked-add-int (hash (aget buf 0)))
    (unchecked-multiply-int 31)
    (unchecked-add-int (hash (aget buf 1))))

invoke

(if (keyword? k)
  (if-let [f (swizzle2-fns k)]
    (f _)
    (err/key-error! k))
  (if (and (>= k 0) (< k 2))
    (aget buf k)
    (err/key-error! k)))
(if (keyword? k)
  (if-let [f (swizzle2-fns k)] (f _) nf)
  (if (and (>= k 0) (< k 2)) (aget buf k) nf))

reduce

(let [acc (f (aget buf 0) (aget buf 1))] (if (reduced? acc) @acc acc))
(let [acc (f start (aget buf 0))]
  (if (reduced? acc)
    @acc
    (let [acc (f acc (aget buf 1))]
      (if (reduced? acc)
        @acc
        acc))))

Clojure protocols

#?@(:clj
    [clojure.lang.IObj
     (meta
      [_] _meta)
     (withMeta
      [_ m] (Vec2. (double-array buf) _hash m))
     Cloneable
     (clone
      [_]
      (let [^doubles buf' (double-array 2)]
        (aset buf' 0 (aget buf 0))
        (aset buf' 1 (aget buf 1))
        (Vec2. buf' _hash _meta)))
     clojure.lang.ILookup
     (valAt
      [_ k]
      <<tpl-invoke2>>)
     (valAt
      [_ k nf]
      <<tpl-invoke2-nf>>)
     java.util.concurrent.Callable
     (call
      [_] (.invoke ^clojure.lang.IFn _))
     java.lang.Runnable
     (run
       [_] (.invoke ^clojure.lang.IFn _))
     clojure.lang.IFn
     (invoke
      [_ k]
      <<tpl-invoke2>>)
     (invoke
      [_ k nf]
      <<tpl-invoke2-nf>>)
     (applyTo
      [_ args]
      (case (count args)
        1 (.invoke ^clojure.lang.IFn _ (first args))
        2 (.invoke ^clojure.lang.IFn _ (first args) (nth args 1))
        (err/illegal-arg! (str "wrong number of args (" (count args) ")"))))
     clojure.lang.Associative
     clojure.lang.IPersistentVector
     (count
      [_] 2)
     (length
      [_] 2)
     (containsKey
      [_ k]
      <<tpl-contains2>>)
     (entryAt
      [_ k] (clojure.lang.MapEntry. k (aget buf k)))
     (assoc
      [_ k v]
      <<tpl-assoc2(fn="double-array")>>)
     (assocN
      [_ k v]
      (let [b (double-array buf)] (aset b k (double v)) (Vec2. b nil _meta)))
     java.util.Collection
     (isEmpty
      [_] false)
     (iterator
      [_] (.iterator ^java.util.Collection (list (aget buf 0) (aget buf 1))))
     (toArray
      [_] (object-array _))
     (size
      [_] 2)
     clojure.lang.IPersistentCollection
     clojure.lang.Indexed
     clojure.lang.Sequential
     clojure.lang.Seqable
     clojure.lang.Reversible
     java.util.List
     (seq
      [_] (seq buf))
     (empty
      [_] (err/unsupported!))
     (cons
      [_ x] (with-meta (vec3 (aget buf 0) (aget buf 1) x) _meta))
     (peek
      [_] (aget buf 1))
     (pop
      [_] (with-meta [(aget buf 0)] _meta))
     (rseq
      [_] (seq ((swizzle2-fns :yx) _)))
     (get
      [_ n] (aget buf n))
     (nth
      [_ n] (aget buf n))
     (nth
      [_ n nf] (if (>= n 0) (if (< n 2) (aget buf n) nf)))
     (equiv
      [_ o]
      <<tpl-equals2(fn="clojure.lang.Util/equiv")>>)
     (equals
      [_ o]
      <<tpl-equals2(fn="clojure.lang.Util/equals")>>)
     Comparable
     (compareTo
      [_ o]
      <<tpl-compare2>>)
     (hashCode
      [_]
      <<tpl-hashcode2>>)
     clojure.lang.IHashEq
     (hasheq
      [_]
      (or _hash
          (set! _hash
                (mix-collection-hash
                 <<tpl-hashcode2>>
                 2))))
     cp/InternalReduce
     (internal-reduce
      [_ f start]
      <<tpl-reduce2-start>>)
     cp/CollReduce
     (coll-reduce
      [_ f]
      <<tpl-reduce2>>)
     (coll-reduce
      [_ f start]
      <<tpl-reduce2-start>>)]
    :cljs
    [IMeta
     (-meta [_] _meta)
     IWithMeta
     (-with-meta [_ m] (Vec2. (js/Float32Array. buf) _hash m))
     ICloneable
     (-clone
      [_] (Vec2. (js/Float32Array. buf) _hash _meta))
     ILookup
     (-lookup
      [_ k]
      <<tpl-invoke2>>)
     (-lookup
      [_ k nf]
      <<tpl-invoke2-nf>>)
     IFn
     (-invoke
      [_ k]
      <<tpl-invoke2>>)
     (-invoke
      [_ k nf]
      <<tpl-invoke2-nf>>)
     ICounted
     (-count [_] 2)
     IAssociative
     (-contains-key?
      [_ k]
      <<tpl-contains2>>)
     (-assoc
      [_ k v]
      <<tpl-assoc2(fn="js/Float32Array.")>>)
     IVector
     (-assoc-n
      [_ n v]
      (let [b (js/Float32Array. buf)] (aset b n v) (Vec2. b nil _meta)))
     ISequential
     ISeq
     (-first
      [_] (aget buf 0))
     (-rest
      [_] (cons (aget buf 1) nil))
     INext
     (-next
      [_] (cons (aget buf 1) nil))
     ISeqable
     (-seq [_] _)
     IReversible
     (-rseq [_] ((swizzle2-fns :yx) _))
     IIndexed
     (-nth [_ n] (if (>= n 0) (if (< n 2) (aget buf n) (err/key-error! n))))
     (-nth [_ n nf] (if (>= n 0) (if (< n 2) (aget buf n) nf)))
     ICollection
     (-conj [_ x] (with-meta (vec3 (aget buf 0) (aget buf 1) x) _meta))
     IStack
     (-peek [_] (aget buf 1))
     (-pop [_] (with-meta [(aget buf 0)] _meta))
     IComparable
     (-compare
      [_ o]
      <<tpl-compare2>>)
     IHash
     (-hash
      [_]
      (or _hash
          (set! (.-_hash _)
                (mix-collection-hash
                 (-> 31 (+ (hash (aget buf 0)))
                     (bit-or 0)
                     (imul 31) (+ (hash (aget buf 1)))
                     (bit-or 0))
                 2))))
     IEquiv
     (-equiv
      [_ o]
      <<tpl-equals2(fn="=")>>)
     IReduce
     (-reduce
      [coll f]
      <<tpl-reduce2>>)
     (-reduce
      [coll f start]
      <<tpl-reduce2-start>>)
     IPrintWithWriter
     (-pr-writer
      [_ writer opts]
      (pr-sequential-writer writer pr-writer "#vec2 [" " " "]" opts (seq _)))
     ])

Object (toString)

Object
(toString [_] (str "[" (aget buf 0) " " (aget buf 1) "]"))

IBuffer

streams/IBuffer
(get-float-buffer
 [_]
 #?(:clj
    (doto (FloatBuffer/allocate 2)
      (.put (float (aget buf 0)))
      (.put (float (aget buf 1)))
      (.rewind))
    :cljs buf))
streams/IIntoBuffer
(into-float-buffer
 [_ dest stride idx]
 #?@(:clj
     [(.position ^FloatBuffer dest (int idx))
      (.put ^FloatBuffer dest (float (aget buf 0)))
      (.put ^FloatBuffer dest (float (aget buf 1)))]
     :cljs
     [(.set dest buf idx)])
 (unchecked-add-int idx stride))

IMathOps

m/IMathOps
(+ [_] _)
(+ [_ v]       (vm/v2-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) + buf v _meta))
(+ [_ v1 v2]   (vm/v2-op1-xy #?(:clj (double-array) :cljs (new js/Float32Array)) + buf v1 v2 0.0 _meta))
(- [_]         (vm/v2-op0 #?(:clj (double-array) :cljs (new js/Float32Array)) - buf _meta))
(- [_ v]       (vm/v2-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) - buf v _meta))
(- [_ v1 v2]   (vm/v2-op1-xy #?(:clj (double-array) :cljs (new js/Float32Array)) - buf v1 v2 0.0 _meta))
(* [_] _)
(* [_ v]       (vm/v2-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) * buf v _meta))
(* [_ v1 v2]   (vm/v2-op1-xy #?(:clj (double-array) :cljs (new js/Float32Array)) * buf v1 v2 1.0 _meta))
(div [_]       (vm/v2-op0 #?(:clj (double-array) :cljs (new js/Float32Array)) / buf _meta))
(div [_ v]     (vm/v2-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) / buf v _meta))
(div [_ v1 v2] (vm/v2-op1-xy #?(:clj (double-array) :cljs (new js/Float32Array)) / buf v1 v2 0.0 _meta))
(madd [_ a b]  (vm/v2-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) * + buf a b 1.0 0.0 _meta))
(addm [_ a b]  (vm/v2-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) + * buf a b 0.0 1.0 _meta))
(msub [_ a b]  (vm/v2-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) * - buf a b 1.0 0.0 _meta))
(subm [_ a b]  (vm/v2-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) - * buf a b 0.0 1.0 _meta))
(abs [_]       (vm/v2-op0 #?(:clj (double-array) :cljs (new js/Float32Array)) m/abs* buf _meta))

m/IMutableMathOps
(+! [_]         _)
(+! [_ v]       (vm/v2-op1! + buf v) _)
(+! [_ v1 v2]   (vm/v2-op1-xy! + buf v1 v2 0.0) _)
(-! [_]         (vm/vec-op0! - buf 2) _)
(-! [_ v]       (vm/v2-op1! - buf v) _)
(-! [_ v1 v2]   (vm/v2-op1-xy! - buf v1 v2 0.0) _)
(*! [_]         _)
(*! [_ v]       (vm/v2-op1! * buf v) _)
(*! [_ v1 v2]   (vm/v2-op1-xy! * buf v1 v2 0.0) _)
(div! [_]       (vm/vec-op0! / buf 2) _)
(div! [_ v]     (vm/v2-op1! / buf v) _)
(div! [_ v1 v2] (vm/v2-op1-xy! / buf v1 v2 0.0) _)
(madd! [_ a b]  (vm/v2-op2! * + buf a b 1.0 0.0) _)
(addm! [_ a b]  (vm/v2-op2! + * buf a b 0.0 1.0) _)
(msub! [_ a b]  (vm/v2-op2! * - buf a b 1.0 0.0) _)
(subm! [_ a b]  (vm/v2-op2! - * buf a b 0.0 1.0) _)
(abs! [_]       (vm/vec-op0! m/abs* buf 2) _)

IClear

g/IClear
(clear* [_] (Vec2. #?(:clj (double-array 2) :cljs (js/Float32Array. 2)) nil nil))
(clear! [_] (aset buf 0 0.0) (aset buf 1 0.0) (set! _hash nil) _)

ICrossProduct

m/ICrossProduct
(cross [_ v] (vm/rewrite-v2-v-no-let buf v 0.0 (mm/msub x vy y vx)))

IDeltaEquals

m/IDeltaEquals
(delta=
 [_ v] (m/delta= _ v *eps*))
(delta=
 [_ v eps]
 (if (sequential? v)
   (if (== 2 (count v))
     (vm/rewrite-v2-v-no-let
      buf v 0.0 (if (m/delta= x vx eps) (m/delta= y vy eps))))))

IDistance

g/IDistance
(dist
 [_ v] (Math/sqrt (g/dist-squared _ v)))
(dist-squared
 [_ v]
 (vm/rewrite-v2-v buf v 0.0
   (let [dx (- x vx)
         dy (- y vy)]
     (mm/madd dx dx dy dy))))

IDotProduct

m/IDotProduct
(dot [_ v] (vm/rewrite-v2-v-no-let buf v 0.0 (mm/madd x vx y vy)))

IHeading

g/IHeading
(heading
 [_]
 (let [t (Math/atan2 (aget buf 1) (aget buf 0))]
   (if (neg? t) (+ t TWO_PI) t)))
(heading-xy [_] (g/heading _))
(angle-between
 [_ a]
 (let [t (- (g/heading a) (g/heading _))]
   (if (neg? t) (+ t TWO_PI) t)))
(slope-xy [_] (/ (aget buf 1) (aget buf 0)))

IInterpolate

m/IInterpolate
(mix
 [_ v]
 (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (vm/rewrite-v2-nv-no-let
    buf v 0.0
    (aset b 0 (double (* (+ x vx) 0.5)))
    (aset b 1 (double (* (+ y vy) 0.5))))
   (Vec2. b nil _meta)))
(mix
 [_ v t]
 (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (vm/rewrite-v2-nv-nv
    buf v t 0.0 0.0
    (aset b 0 (double (+ (* (- bx x) cx) x)))
    (aset b 1 (double (+ (* (- by y) cy) y))))
   (Vec2. b nil _meta)))
(mix
 [_ b c d u v]
 (let [^doubles b' #?(:clj (double-array 2) :cljs (js/Float32Array. 2))
       dv? (instance? Vec2 d)
       dn? (number? d)
       ^doubles dv (if dv? (.-buf ^Vec2 d))
       dx (if dv? (aget dv 0) (if dn? d (nth d 0 0.0)))
       dy (if dv? (aget dv 1) (if dn? d (nth d 1 0.0)))]
   (vm/rewrite-v2-nv-nv
    buf b c 0.0 0.0
    (let [x1 (+ (* (- bx x) u) x)
          y1 (+ (* (- by y) u) y)]
      (aset b' 0 (double (+ (* (- (+ (* (- dx cx) u) cx) x1) v) x1)))
      (aset b' 1 (double (+ (* (- (+ (* (- dy cy) u) cy) y1) v) y1)))))
   (Vec2. b' nil _meta)))
(mix-with
 [_ v t f]
 (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (vm/rewrite-v2-nv-nv
    buf v t 0.0 0.0
    (aset b 0 (double (f x bx cx)))
    (aset b 1 (double (f y by cy))))
   (Vec2. b nil _meta)))
(step
 [_ e]
 (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (vm/rewrite-v2-nv-no-let
    buf e 0.0
    (aset b 0 (double (m/step* vx x)))
    (aset b 1 (double (m/step* vy y))))
   (Vec2. b nil _meta)))
(smoothstep
 [_ e1 e2]
 (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (vm/rewrite-v2-nv-nv
    buf e1 e2 0.0 0.0
    (aset b 0 (double (m/smoothstep* bx cx x)))
    (aset b 1 (double (m/smoothstep* bx cy y))))
   (Vec2. b nil _meta)))

IInvert

m/IInvert
(invert [_] (m/- _))

ILimit

m/ILimit
(limit
 [_ len]
 (if (> (m/mag-squared _) (* len len))
   (m/normalize _ len)
   _))

IMagnitude

m/IMagnitude
(mag
 [_] (vm/rewrite-v2 buf (Math/sqrt (mm/madd x x y y))))
(mag-squared
 [_] (vm/rewrite-v2 buf (mm/madd x x y y)))

IMinMax

m/IMinMax
(min
 [_ v] (vm/v2-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) mm/min buf v _meta))
(min
 [_ v v2] (vm/v2-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) mm/min mm/min buf v v2 0.0 0.0 _meta))
(max
 [_ v] (vm/v2-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) mm/max buf v _meta))
(max
 [_ v v2] (vm/v2-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) mm/max mm/max buf v v2 0.0 0.0 _meta))

INormal

g/INormal
(normal
 [_]
 (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (aset b 0 (double (- (aget buf 1))))
   (aset b 1 (double (aget buf 0)))
   (Vec2. b nil _meta)))

INormalize

m/INormalize
(normalize
 [_]
 (vm/rewrite-v2
  buf
  (let [l (Math/sqrt (mm/madd x x y y))]
    (if (pos? l)
      (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
        (aset b 0 (double (/ x l)))
        (aset b 1 (double (/ y l)))
        (Vec2. b nil _meta))
      _))))
(normalize
 [_ len]
 (vm/rewrite-v2
  buf
  (let [l (Math/sqrt (mm/madd x x y y))]
    (if (pos? l)
      (let [l (/ len l)
            ^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
        (aset b 0 (double (* x l)))
        (aset b 1 (double (* y l)))
        (Vec2. b nil _meta))
      _))))
(normalized?
 [_] (m/delta= 1.0 (m/mag-squared _)))

IPolar

g/IPolar
(as-polar
 [_]
 (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (aset b 0 (double (m/mag _)))
   (aset b 1 (double (g/heading _)))
   (Vec2. b nil _meta)))
(as-cartesian
 [_]
 (vm/rewrite-v2
  buf
  (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
    (aset b 0 (double (* x (Math/cos y))))
    (aset b 1 (double (* x (Math/sin y))))
    (Vec2. b nil _meta))))

IReflect

g/IReflect
(reflect
 [_ v]
 (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (vm/rewrite-v2-v buf v 0.0
     (let [d (* (+ (* x vx) (* y vy)) 2.0)]
       (aset b 0 (double (mm/msub vx d x)))
       (aset b 1 (double (mm/msub vy d y)))
       (Vec2. b nil _meta)))))

Transformations

g/IScale
(scale
 [_ v]
 (vm/v2-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) * buf v _meta))

g/ITranslate
(translate
 [_ v]
 (vm/v2-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) + buf v _meta))

g/IRotate
(rotate
 [_ theta]
 (let [s (Math/sin theta) c (Math/cos theta)
       ^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
   (vm/rewrite-v2
    buf
    (aset b 0 (double (mm/msub x c y s)))
    (aset b 1 (double (mm/madd x s y c)))
    (Vec2. b nil _meta))))

g/ITransform
(transform
 [_ m] (g/transform-vector m _))

IVectorReduce

g/IVectorReduce
(reduce-vector
 [_ f xs]
 (let [^doubles buf' #?(:clj (double-array 2) :cljs (js/Float32Array. buf))]
   #?@(:clj
       [(aset buf' 0 (aget buf 0))
        (aset buf' 1 (aget buf 1))])
   (Vec2. (vec2-reduce* f buf' xs) nil _meta)))
(reduce-vector
 [_ f f2 xs]
 (let [^doubles buf' #?(:clj (double-array 2) :cljs (js/Float32Array. buf))]
   #?@(:clj
       [(aset buf' 0 (aget buf 0))
        (aset buf' 1 (aget buf 1))])
   (vec2-reduce* f buf' xs)
   (aset buf' 0 (double (f2 (aget buf' 0) 0)))
   (aset buf' 1 (double (f2 (aget buf' 1) 1)))
   (Vec2. buf' nil _meta)))

End implementation

)

Vec3

(deftype Vec3
    #?(:clj
        [^doubles buf ^:unsynchronized-mutable _hash _meta]
        :cljs
        [buf ^:mutable _hash _meta])

Templates

assoc

(replace-regexp-in-string
 "{{fn}}" fn
 "(cond
    (number? k)  (if (and (>= k 0) (<= k 2))
                   (let [^doubles b ({{fn}} buf)]
                     (aset b k (double v)) (Vec3. b nil _meta))
                   (if (== k 3) (conj _ v) (err/key-error! k)))
    (keyword? k) (if (= :w k)
                   (conj _ v)
                   (Vec3. (swizzle-assoc* buf ({{fn}} buf) {\\x 0 \\y 1 \\z 2} k v) nil _meta)))")

compare

(if (instance? Vec3 o)
  (let [^doubles b' (.-buf ^Vec3 o)
        c (compare (aget buf 0) (aget b' 0))]
    (if (== 0 c)
      (let [c (compare (aget buf 1) (aget b' 1))]
        (if (== 0 c)
          (compare  (aget buf 2) (aget b' 2))
          c))
      c))
  (let [c (count o)]
    (if (== 3 c) (- (compare o _)) (- 3 c))))

contains-key?

(if (number? k)
  (and (>= k 0) (<= k 2))
  (if (swizzle3-fns k) true false))

equals / equiv

(replace-regexp-in-string
 "{{fn}}" fn
 "(if (instance? Vec3 o)
    (let [^doubles b' (.-buf ^Vec3 o)]
      (and (== (aget buf 0) (aget b' 0)) (== (aget buf 1) (aget b' 1)) (== (aget buf 2) (aget b' 2))))
    (and (sequential? o) (== 3 (count o))
         ({{fn}} (aget buf 0) (first o))
         ({{fn}} (aget buf 1) (nth o 1))
         ({{fn}} (aget buf 2) (nth o 2))))")

hashCode

(-> 31
    (unchecked-add-int (hash (aget buf 0)))
    (unchecked-multiply-int 31)
    (unchecked-add-int (hash (aget buf 1)))
    (unchecked-multiply-int 31)
    (unchecked-add-int (hash (aget buf 2))))

invoke

(if (keyword? k)
  (if-let [f (swizzle3-fns k)]
    (f _)
    (err/key-error! k))
  (if (and (>= k 0) (<= k 2))
    (aget buf k)
    (err/key-error! k)))
(if (keyword? k)
  (if-let [f (swizzle3-fns k)] (f _) nf)
  (if (and (>= k 0) (<= k 2)) (aget buf k) nf))

reduce

(let [acc (f (aget buf 0) (aget buf 1))]
  (if (reduced? acc)
    @acc
    (let [acc (f acc (aget buf 2))]
      (if (reduced? acc)
        @acc
        acc))))

reduce w/ init

(let [acc (f start (aget buf 0))]
  (if (reduced? acc)
    @acc
    (let [acc (f acc (aget buf 1))]
      (if (reduced? acc)
        @acc
        (let [acc (f acc (aget buf 2))]
          (if (reduced? acc)
            @acc
            acc))))))

Clojure protocols

#?@(:clj
    [clojure.lang.IObj
     (meta
      [_] _meta)
     (withMeta
      [_ m] (Vec3. (double-array buf) _hash m))
     Cloneable
     (clone
      [_]
      (let [^doubles buf' (double-array 3)]
        (aset buf' 0 (aget buf 0))
        (aset buf' 1 (aget buf 1))
        (aset buf' 2 (aget buf 2))
        (Vec2. buf' _hash _meta)))
     clojure.lang.ILookup
     (valAt
      [_ k]
      <<tpl-invoke3>>)
     (valAt
      [_ k nf]
      <<tpl-invoke3-nf>>)
     java.util.concurrent.Callable
     (call
      [_] (.invoke ^clojure.lang.IFn _))
     java.lang.Runnable
     (run
       [_] (.invoke ^clojure.lang.IFn _))
     clojure.lang.IFn
     (invoke
      [_ k]
      <<tpl-invoke3>>)
     (invoke
      [_ k nf]
      <<tpl-invoke3-nf>>)
     (applyTo
      [_ args]
      (case (count args)
        1 (.invoke ^clojure.lang.IFn _ (first args))
        2 (.invoke ^clojure.lang.IFn _ (first args) (nth args 1))
        (err/illegal-arg! (str "wrong number of args (" (count args) ")"))))
     clojure.lang.Associative
     clojure.lang.IPersistentVector
     (count
      [_] 3)
     (length
      [_] 3)
     (containsKey
      [_ k]
      <<tpl-contains3>>)
     (entryAt
      [_ k] (clojure.lang.MapEntry. k (aget buf k)))
     (assoc
      [_ k v]
      <<tpl-assoc3(fn="double-array")>>)
     (assocN
      [_ k v]
      (let [b (double-array buf)] (aset b k (double v)) (Vec3. b nil _meta)))
     java.util.Collection
     (isEmpty
      [_] false)
     (iterator
      [_] (.iterator ^java.util.Collection (list (aget buf 0) (aget buf 1) (aget buf 2))))
     (toArray
      [_] (object-array _))
     (size
      [_] 3)
     clojure.lang.IPersistentCollection
     clojure.lang.Indexed
     clojure.lang.Sequential
     clojure.lang.Seqable
     java.util.List
     (seq
      [_] (seq buf))
     (empty
      [_] (err/unsupported!))
     (cons
      [_ x] (with-meta [(aget buf 0) (aget buf 1) (aget buf 2) x] _meta))
     (peek
      [_] (aget buf 2))
     (pop
      [_]
      (let [^doubles b (double-array 2)]
        (aset b 0 (aget buf 0))
        (aset b 1 (aget buf 1))
        (Vec2. b nil _meta)))
     (rseq
      [_] (seq ((swizzle3-fns :zyx) _)))
     (get
      [_ n] (aget buf n))
     (nth
      [_ n] (aget buf n))
     (nth
      [_ n nf] (if (>= n 0) (if (< n 3) (aget buf n) nf)))
     (equiv
      [_ o]
      <<tpl-equals3(fn="clojure.lang.Util/equiv")>>)
     (equals
      [_ o]
      <<tpl-equals3(fn="clojure.lang.Util/equals")>>)
     Comparable
     (compareTo
      [_ o]
      <<tpl-compare3>>)
     (hashCode
      [_]
      <<tpl-hashcode3>>)
     clojure.lang.IHashEq
     (hasheq
      [_]
      (or _hash
          (set! _hash
                (mix-collection-hash
                 <<tpl-hashcode3>>
                 3))))
     cp/InternalReduce
     (internal-reduce
      [_ f start]
      <<tpl-reduce3-start>>)
     cp/CollReduce
     (coll-reduce
      [_ f]
      <<tpl-reduce3>>)
     (coll-reduce
      [_ f start]
      <<tpl-reduce3-start>>)]
    :cljs
    [IMeta
     (-meta
      [_] _meta)
     IWithMeta
     (-with-meta
      [_ m] (Vec3. (js/Float32Array. buf) _hash m))
     ICloneable
     (-clone
      [_] (Vec3. (js/Float32Array. buf) _hash _meta))
     ILookup
     (-lookup
      [_ k]
      <<tpl-invoke3>>)
     (-lookup
      [_ k nf]
      <<tpl-invoke3>>)
     IFn
     (-invoke
      [_ k]
      <<tpl-invoke3>>)
     (-invoke
      [_ k nf]
      <<tpl-invoke3-nf>>)
     ICounted
     (-count
      [_] 3)
     IAssociative
     (-contains-key?
      [_ k]
      <<tpl-contains3>>)
     (-assoc
      [_ k v]
      <<tpl-assoc3(fn="js/Float32Array.")>>)
     IVector
     (-assoc-n
      [_ n v]
      (let [b (js/Float32Array. buf)] (aset b n v) (Vec3. b nil _meta)))
     ISequential
     ISeq
     (-first
      [_] (aget buf 0))
     (-rest
      [_] (cons (aget buf 1) (cons (aget buf 2) nil)))
     INext
     (-next
      [_] (cons (aget buf 1) (cons (aget buf 2) nil)))
     ISeqable
     (-seq
      [_] _)
     IReversible
     (-rseq
      [_] ((swizzle3-fns :zyx) _))
     IIndexed
     (-nth
      [_ n] (if (>= n 0) (if (< n 3) (aget buf n) (err/key-error! n))))
     (-nth
      [_ n nf] (if (>= n 0) (if (< n 3) (aget buf n) nf)))
     ICollection
     (-conj
      [_ x] (with-meta [(aget buf 0) (aget buf 1) (aget buf 2) x] _meta))
     IStack
     (-peek
      [_] (aget buf 2))
     (-pop
      [_]
      (let [b (js/Float32Array. 2)]
        (aset b 0 (aget buf 0))
        (aset b 1 (aget buf 1))
        (Vec2. b nil _meta)))
     IComparable
     (-compare
      [_ o]
      <<tpl-compare3>>)
     IHash
     (-hash
      [_]
      (or _hash
          (set! (.-_hash _)
                (mix-collection-hash
                 (-> 31 (+ (hash (aget buf 0)))
                     (bit-or 0)
                     (imul 31) (+ (hash (aget buf 1)))
                     (bit-or 0)
                     (imul 31) (+ (hash (aget buf 2)))
                     (bit-or 0))
                 3))))
     IEquiv
     (-equiv
      [_ o]
      <<tpl-equals3(fn="=")>>)
     IReduce
     (-reduce
      [coll f]
      <<tpl-reduce3>>)
     (-reduce
      [coll f start]
      <<tpl-reduce3-start>>)
     IPrintWithWriter
     (-pr-writer
      [_ writer opts]
      (pr-sequential-writer writer pr-writer "#vec3 [" " " "]" opts (seq _)))])

Object (toString)

Object
(toString
 [_] (str "[" (aget buf 0) " " (aget buf 1) " " (aget buf 2) "]"))

IBuffer

streams/IBuffer
(get-float-buffer
 [_]
 #?(:clj
    (doto (FloatBuffer/allocate 3)
      (.put (float (aget buf 0)))
      (.put (float (aget buf 1)))
      (.put (float (aget buf 2)))
      (.rewind))
    :cljs buf))
streams/IIntoBuffer
(into-float-buffer
   [_ dest stride idx]
   #?@(:clj
       [(.position ^FloatBuffer dest (int idx))
        (.put ^FloatBuffer dest (float (aget buf 0)))
        (.put ^FloatBuffer dest (float (aget buf 1)))
        (.put ^FloatBuffer dest (float (aget buf 2)))]
       :cljs
       [(.set dest buf idx)])
   (unchecked-add-int idx stride))

IMathOps

m/IMathOps
(+ [_] _)
(+ [_ v]       (vm/v3-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) + buf v _meta))
(+ [_ v1 v2]   (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) + + buf v1 v2 0.0 0.0 _meta))
(+ [_ x y z]   (vm/v3-op1-xyz #?(:clj (double-array) :cljs (new js/Float32Array)) + buf x y z _meta))
(- [_]         (vm/v3-op0 #?(:clj (double-array) :cljs (new js/Float32Array)) - buf _meta))
(- [_ v]       (vm/v3-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) - buf v _meta))
(- [_ v1 v2]   (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) - - buf v1 v2 0.0 0.0 _meta))
(- [_ x y z]   (vm/v3-op1-xyz #?(:clj (double-array) :cljs (new js/Float32Array)) - buf x y z _meta))
(* [_] _)
(* [_ v]       (vm/v3-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) * buf v _meta))
(* [_ v1 v2]   (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) * * buf v1 v2 0.0 0.0 _meta))
(* [_ x y z]   (vm/v3-op1-xyz #?(:clj (double-array) :cljs (new js/Float32Array)) * buf x y z _meta))
(div [_]       (vm/v3-op0 #?(:clj (double-array) :cljs (new js/Float32Array)) / buf _meta))
(div [_ v]     (vm/v3-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) / buf v _meta))
(div [_ v1 v2] (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) / / buf v1 v2 0.0 0.0 _meta))
(div [_ x y z] (vm/v3-op1-xyz #?(:clj (double-array) :cljs (new js/Float32Array)) / buf x y z _meta))
(madd [_ a b]  (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) * + buf a b 1.0 0.0 _meta))
(addm [_ a b]  (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) + * buf a b 0.0 1.0 _meta))
(msub [_ a b]  (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) * - buf a b 1.0 0.0 _meta))
(subm [_ a b]  (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) - * buf a b 0.0 1.0 _meta))
(abs [_]       (vm/v3-op0 #?(:clj (double-array) :cljs (new js/Float32Array)) m/abs* buf _meta))

m/IMutableMathOps
(+! [_]         _)
(+! [_ v]       (vm/v3-op1! + buf v) _)
(+! [_ v1 v2]   (vm/v3-op2! + + buf v1 v2 0.0 0.0) _)
(+! [_ x y z]   (vm/v3-op1-xyz! + buf x y z) _)
(-! [_]         (vm/vec-op0! - buf 3) _)
(-! [_ v]       (vm/v3-op1! - buf v) _)
(-! [_ v1 v2]   (vm/v3-op2! - - buf v1 v2 0.0 0.0) _)
(-! [_ x y z]   (vm/v3-op1-xyz! - buf x y z) _)
(*! [_]         _)
(*! [_ v]       (vm/v3-op1! * buf v) _)
(*! [_ v1 v2]   (vm/v3-op2! * * buf v1 v2 0.0 0.0) _)
(*! [_ x y z]   (vm/v3-op1-xyz! * buf x y z) _)
(div! [_]       (vm/vec-op0! / buf 3) _)
(div! [_ v]     (vm/v3-op1! / buf v) _)
(div! [_ v1 v2] (vm/v3-op2! / / buf v1 v2 0.0 0.0) _)
(div! [_ x y z] (vm/v3-op1-xyz! / buf x y z) _)
(madd! [_ a b]  (vm/v3-op2! * + buf a b 1.0 0.0) _)
(addm! [_ a b]  (vm/v3-op2! + * buf a b 0.0 1.0) _)
(msub! [_ a b]  (vm/v3-op2! * - buf a b 1.0 0.0) _)
(subm! [_ a b]  (vm/v3-op2! - * buf a b 0.0 1.0) _)
(abs! [_]       (vm/vec-op0! m/abs* buf 3) _)

IClear

g/IClear
(clear* [_] (Vec3. #?(:clj (double-array 3) :cljs (js/Float32Array. 3)) nil nil))
(clear! [_] (aset buf 0 0.0) (aset buf 1 0.0) (aset buf 2 0.0) (set! _hash nil) _)

ICrossProduct

m/ICrossProduct
(cross
 [_ v]
 (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3-v buf v 0.0
     (aset b 0 (double (mm/msub y vz vy z)))
     (aset b 1 (double (mm/msub z vx vz x)))
     (aset b 2 (double (mm/msub x vy vx y))))
   (Vec3. b nil _meta)))

IDeltaEquals

m/IDeltaEquals
(delta=
 [_ v] (m/delta= _ v *eps*))
(delta=
 [_ v eps]
 (if (sequential? v)
   (if (== 3 (count v))
     (vm/rewrite-v3-v-no-let
      buf v 0.0
      (if (m/delta= x vx eps)
        (if (m/delta= y vy eps)
          (m/delta= z vz eps)))))))

IDistance

g/IDistance
(dist
 [_ v] (Math/sqrt (g/dist-squared _ v)))
(dist-squared
 [_ v]
 (vm/rewrite-v3-v buf v 0.0
   (let [dx (- x vx)
         dy (- y vy)
         dz (- z vz)]
     (mm/madd dx dx dy dy dz dz))))

IDotProduct

m/IDotProduct
(dot [_ v] (vm/rewrite-v3-v-no-let buf v 0.0 (+ (+ (* x vx) (* y vy)) (* z vz))))

IHeading

g/IHeading
(heading [_] (g/heading-xy _))
(heading-xy
 [_]
 (let [t (Math/atan2 (aget buf 1) (aget buf 0))]
   (if (neg? t) (+ t TWO_PI) t)))
(heading-xz
 [_]
 (let [t (Math/atan2 (aget buf 2) (aget buf 0))]
   (if (neg? t) (+ t TWO_PI) t)))
(heading-yz
 [_]
 (let [t (Math/atan2 (aget buf 2) (aget buf 1))]
   (if (neg? t) (+ t TWO_PI) t)))
(angle-between
 [_ v]
 (let [v (if (instance? Vec3 v) v (vec3 v))]
   (Math/acos (m/dot (m/normalize _) (m/normalize v)))))
(slope-xy [_] (/ (aget buf 1) (aget buf 0)))
(slope-xz [_] (/ (aget buf 2) (aget buf 0)))
(slope-yz [_] (/ (aget buf 2) (aget buf 1)))

IInterpolate

m/IInterpolate
(mix
 [_ v]
 (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3-nv-no-let
    buf v 0.0
    (aset b 0 (double (* (+ x vx) 0.5)))
    (aset b 1 (double (* (+ y vy) 0.5)))
    (aset b 2 (double (* (+ z vz) 0.5))))
   (Vec3. b nil _meta)))
(mix
 [_ v t]
 (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3-nv-nv
    buf v t 0.0 0.0
    (aset b 0 (double (+ (* (- bx x) cx) x)))
    (aset b 1 (double (+ (* (- by y) cy) y)))
    (aset b 2 (double (+ (* (- bz z) cz) z))))
   (Vec3. b nil _meta)))
(mix
 [_ b c d u v]
 (let [^doubles b' #?(:clj (double-array 3) :cljs (js/Float32Array. 3))
       dv? (instance? Vec3 d)
       dn? (number? d)
       ^doubles dv (if dv? (.-buf ^Vec3 d))
       dx (if dv? (aget dv 0) (if dn? d (nth d 0 0.0)))
       dy (if dv? (aget dv 1) (if dn? d (nth d 1 0.0)))
       dz (if dv? (aget dv 2) (if dn? d (nth d 2 0.0)))]
   (vm/rewrite-v3-nv-nv
    buf b c 0.0 0.0
    (let [x1 (+ (* (- bx x) u) x)
          y1 (+ (* (- by y) u) y)
          z1 (+ (* (- bz z) u) z)]
      (aset b' 0 (double (+ (* (- (+ (* (- dx cx) u) cx) x1) v) x1)))
      (aset b' 1 (double (+ (* (- (+ (* (- dy cy) u) cy) y1) v) y1)))
      (aset b' 2 (double (+ (* (- (+ (* (- dz cz) u) cz) z1) v) z1)))))
   (Vec3. b' nil _meta)))
(mix-with
 [_ v t f]
 (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3-nv-nv
    buf v t 0.0 0.0
    (aset b 0 (double (f x bx cx)))
    (aset b 1 (double (f y by cy)))
    (aset b 2 (double (f z bz cz))))
   (Vec2. b nil _meta)))
(step
 [_ e]
 (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3-nv-no-let
    buf e 0.0
    (aset b 0 (double (m/step* vx x)))
    (aset b 1 (double (m/step* vy y)))
    (aset b 2 (double (m/step* vz z))))
   (Vec2. b nil _meta)))
(smoothstep
 [_ e1 e2]
 (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3-nv-nv
    buf e1 e2 0.0 0.0
    (aset b 0 (double (m/smoothstep* bx cx x)))
    (aset b 1 (double (m/smoothstep* by cy y)))
    (aset b 2 (double (m/smoothstep* bz cz z))))
   (Vec2. b nil _meta)))

IInvert

m/IInvert
(invert [_] (m/- _))

ILimit

m/ILimit
(limit
 [_ len]
 (if (> (m/mag-squared _) (* len len))
   (m/normalize _ len)
   _))

IMagnitude

m/IMagnitude
(mag
 [_] (vm/rewrite-v3 buf (Math/sqrt (mm/madd x x y y z z))))
(mag-squared
 [_] (vm/rewrite-v3 buf (mm/madd x x y y z z)))

IMinMax

m/IMinMax
(min
 [_ v] (vm/v3-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) mm/min buf v _meta))
(min
 [_ v v2] (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) mm/min mm/min buf v v2 0.0 0.0 _meta))
(max
 [_ v] (vm/v3-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) mm/max buf v _meta))
(max
 [_ v v2] (vm/v3-op2 #?(:clj (double-array) :cljs (new js/Float32Array)) mm/max mm/max buf v v2 0.0 0.0 _meta))

INormalize

m/INormalize
(normalize
 [_]
 (vm/rewrite-v3
  buf
  (let [l (Math/sqrt (mm/madd x x y y z z))]
    (if (pos? l)
      (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
        (aset b 0 (double (/ x l)))
        (aset b 1 (double (/ y l)))
        (aset b 2 (double (/ z l)))
        (Vec3. b nil _meta))
      _))))
(normalize
 [_ len]
 (vm/rewrite-v3
  buf
  (let [l (Math/sqrt (mm/madd x x y y z z))]
    (if (pos? l)
      (let [l (/ len l)
            ^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
        (aset b 0 (double (* x l)))
        (aset b 1 (double (* y l)))
        (aset b 2 (double (* z l)))
        (Vec3. b nil _meta))
      _))))
(normalized?
 [_] (m/delta= 1.0 (m/mag-squared _)))

IPolar

g/IPolar
(as-polar
 [_]
 (let [r (m/mag _)
       ^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (aset b 0 (double r))
   (aset b 1 (double (Math/asin (/ (aget buf 2) r))))
   (aset b 2 (double (Math/atan2 (aget buf 1) (aget buf 0))))
   (Vec3. b nil _meta)))
(as-cartesian
 [_]
 (let [b buf
       x (aget b 0)
       y (aget b 1)
       z (aget b 2)
       rcos (* x (Math/cos y))
       ^doubles b' #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (aset b' 0 (double (* rcos (Math/cos z))))
   (aset b' 1 (double (* rcos (Math/sin z))))
   (aset b' 2 (double (* x    (Math/sin y))))
   (Vec3. b' nil _meta)))

IReflect

g/IReflect
(reflect
 [_ v]
 (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3-v buf v 0.0
     (let [d (* (+ (+ (* x vx) (* y vy)) (* z vz)) 2.0)]
       (aset b 0 (double (mm/msub vx d x)))
       (aset b 1 (double (mm/msub vy d y)))
       (aset b 2 (double (mm/msub vz d z)))
       (Vec3. b nil _meta)))))

Transformations

g/IScale
(scale
 [_ v]
 (vm/v3-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) * buf v _meta))

g/ITranslate
(translate
 [_ v]
 (vm/v3-op1 #?(:clj (double-array) :cljs (new js/Float32Array)) + buf v _meta))

g/IRotate
(rotate [_ theta] (g/rotate-z _ theta))

g/IRotate3D
(rotate-x
 [_ theta]
 (let [s (Math/sin theta) c (Math/cos theta)
       ^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3
    buf
    (aset b 0 (double x))
    (aset b 1 (double (mm/msub y c z s)))
    (aset b 2 (double (mm/madd y s z c)))
    (Vec3. b nil _meta))))
(rotate-y
 [_ theta]
 (let [s (Math/sin theta) c (Math/cos theta)
       ^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3
    buf
    (aset b 0 (double (mm/madd x c z s)))
    (aset b 1 (double y))
    (aset b 2 (double (mm/msub z c x s)))
    (Vec3. b nil _meta))))
(rotate-z
 [_ theta]
 (let [s (Math/sin theta) c (Math/cos theta)
       ^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
   (vm/rewrite-v3
    buf
    (aset b 0 (double (mm/msub x c y s)))
    (aset b 1 (double (mm/madd x s y c)))
    (aset b 2 (double z))
    (Vec3. b nil _meta))))
(rotate-around-axis
 [_ v theta]
 (vm/rewrite-v3-v
  buf v 0.0
  (let [ux' (* vx x), uy' (* vx y), uz' (* vx z)
        vx' (* vy x), vy' (* vy y), vz' (* vy z)
        wx' (* vz x), wy' (* vz y), wz' (* vz z)
        vx2 (* vx vx), vy2 (* vy vy), vz2 (* vz vz)
        s (Math/sin theta), c (Math/cos theta)
        uvw (mm/add ux' vy' wz')
        ^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
    (aset b 0 (double (mm/madd uvw vx
                               (mm/msub (+ vy2 vz2) x (+ vy' wz') vx) c
                               (mm/subm vz' wy' s))))

    (aset b 1 (double (mm/madd uvw vy
                               (mm/msub (+ vx2 vz2) y (+ ux' wz') vy) c
                               (mm/subm wx' uz' s))))

    (aset b 2 (double (mm/madd uvw vz
                               (mm/msub (+ vx2 vy2) z (+ ux' vy') vz) c
                               (mm/subm uy' vx' s))))
    (Vec3. b nil _meta))))

g/ITransform
(transform
 [_ m] (g/transform-vector m _))

IVectorReduce

g/IVectorReduce
(reduce-vector
 [_ f xs]
 (let [^doubles buf' #?(:clj (double-array 3) :cljs (js/Float32Array. buf))]
   #?@(:clj
       [(aset buf' 0 (aget buf 0))
        (aset buf' 1 (aget buf 1))
        (aset buf' 2 (aget buf 2))])
   (Vec3. (vec3-reduce* f buf' xs) nil _meta)))
(reduce-vector
 [_ f f2 xs]
 (let [^doubles buf' #?(:clj (double-array 3) :cljs (js/Float32Array. buf))]
   #?@(:clj
       [(aset buf' 0 (aget buf 0))
        (aset buf' 1 (aget buf 1))
        (aset buf' 2 (aget buf 2))])
   (vec3-reduce* f buf' xs)
   (aset buf' 0 (double (f2 (aget buf' 0) 0)))
   (aset buf' 1 (double (f2 (aget buf' 1) 1)))
   (aset buf' 2 (double (f2 (aget buf' 2) 2)))
   (Vec3. buf' nil _meta)))

End implementation

)

Swizzling

(def ^:private swizzle-keys
  {\x 0 \y 1 \z 2 \w 3})

(def ^:private swizzle-perms
  (->> [(d/cartesian-product '#{x y z} '#{x y z} '#{x y z})
        (d/cartesian-product '#{x y} '#{x y})
        (d/cartesian-product '#{x z} '#{x z})
        (d/cartesian-product '#{y z} '#{y z})
        '((x) (y) (z))]
       (apply concat)
       (map #(symbol (apply str %)))))

(defmacro defswizzle
  [btype key]
  (let [id (str key)
        [a b v] (repeatedly 3 gensym)
        c (count id)
        type (if (== 3 c) 'Vec3 'Vec2)
        ;;pre (if (>= (.indexOf id "z") 0) {:pre [`(instance? ~'Vec3 ~v)]} {})
        ]
    (if (== 1 c)
      `(defn ~key
         [~v]
         ;;~pre
         (let [~(with-meta a {:tag "doubles"}) (if (instance? ~'Vec2 ~v)
                                                 (.-buf ~(with-meta v {:tag "Vec2"}))
                                                 (.-buf ~(with-meta v {:tag "Vec3"})))]
           (aget ~a ~(swizzle-keys (first id)))))
      `(defn ~key
         [~v]
         ;;~pre
         (let [~(with-meta a {:tag "doubles"}) (if (instance? ~'Vec2 ~v)
                                                 (.-buf ~(with-meta v {:tag "Vec2"}))
                                                 (.-buf ~(with-meta v {:tag "Vec3"})))
               ~(with-meta b {:tag "doubles"}) (~@btype ~c)]
           ~@(map-indexed
              (fn [i ch]
                (list 'aset b i (list 'double (list 'aget a (swizzle-keys ch)))))
              id)
           (new ~type ~b nil (meta ~v)))))))
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) x)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xxx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xxy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xxz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xyx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xyy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xyz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xzx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xzy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) xzz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) y)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yxx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yxy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yxz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yyx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yyy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yyz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yzx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yzy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) yzz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) z)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zxx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zxy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zxz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zyx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zyy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zyz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zz)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zzx)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zzy)
(defswizzle #?(:clj (double-array) :cljs (new js/Float32Array)) zzz)

(def swizzle2-fns
  {:x x :xx xx :xy xy :y y :yx yx :yy yy})

(def swizzle3-fns
  {:x x, :xx xx, :xxx xxx, :xxy xxy, :xxz xxz, :xy xy, :xyx xyx,
   :xyy xyy, :xyz xyz, :xz xz, :xzx xzx, :xzy xzy, :xzz xzz,
   :y y, :yx yx, :yxx yxx, :yxy yxy, :yxz yxz, :yy yy, :yyx yyx,
   :yyy yyy, :yyz yyz, :yz yz, :yzx yzx, :yzy yzy, :yzz yzz,
   :z z, :zx zx, :zxx zxx, :zxy zxy, :zxz zxz, :zy zy, :zyx zyx,
   :zyy zyy, :zyz zyz, :zz zz, :zzx zzx, :zzy zzy, :zzz zzz})

(defn swizzle-assoc*
  #?(:clj [^doubles src ^doubles dest keymap k v] :cljs [src dest keymap k v])
  (let [n (name k)
        c (count n)]
    (if-let [idx (and (== 1 c) (keymap (first n)))]
      (do (aset dest (int idx) (double v)) dest)
      (if (and (<= c (count keymap)) (== c (count v) (count (into #{} n))))
        (loop [i 0, n n]
          (if n
            (if-let [idx (keymap (first n))]
              (do (aset dest (int idx) (double (v i)))
                  (recur (inc i) (next n)))
              (err/key-error! k))
            dest))
        (err/key-error! k)))))

Reductions

(defn vec2-reduce*
  [op ^doubles acc xs]
  (transduce
   (map (fn [^Vec2 x] (.-buf x)))
   (fn
     ([a] a)
     ([^doubles a ^doubles b]
      (aset a 0 (double (op (aget a 0) (aget b 0))))
      (aset a 1 (double (op (aget a 1) (aget b 1))))
      a))
   acc xs))

(defn vec3-reduce*
  [op ^doubles acc xs]
  (transduce
   (map (fn [^Vec3 x] (.-buf x)))
   (fn
     ([a] a)
     ([^doubles a ^doubles b]
      (aset a 0 (double (op (aget a 0) (aget b 0))))
      (aset a 1 (double (op (aget a 1) (aget b 1))))
      (aset a 2 (double (op (aget a 2) (aget b 2))))
      a))
   acc xs))

Constructors

(def V2 (Vec2. #?(:clj (double-array 2) :cljs (js/Float32Array. 2)) nil nil))
(def V3 (Vec3. #?(:clj (double-array 3) :cljs (js/Float32Array. 3)) nil nil))

(defn vec2
  ([] V2)
  ([v]
     (cond
      (instance? Vec2 v) v
      (number? v)        (vec2 v v)
      (sequential? v)    (vec2 (nth v 0 0.0) (nth v 1 0.0))
      (map? v)           (vec2 (get v :x 0) (get v :y 0))
      :else              (err/type-error! "Vec2" v)))
  ([x y]
     (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
       (aset b 0 (double x))
       (aset b 1 (double y))
       (Vec2. b nil nil))))

(defn vec3
  ([] V3)
  ([v]
     (cond
      (instance? Vec3 v) v
      (number? v)        (vec3 v v v)
      (sequential? v)    (vec3 (nth v 0 0.0) (nth v 1 0.0) (nth v 2 0.0))
      (map? v)           (vec3 (get v :x 0.0) (get v :y 0.0) (get v :z 0.0))
      :else              (err/type-error! "Vec3" v)))
  ([v z]
     (cond
      (sequential? v) (vec3 (nth v 0 0.0) (nth v 1 0.0) z)
      (map? v)        (vec3 (get v :x 0.0) (get v :y 0.0) z)
      (number? v)     (vec3 v z 0)
      :else           (err/type-error! "Vec3" v)))
  ([x y z]
     (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
       (aset b 0 (double x))
       (aset b 1 (double y))
       (aset b 2 (double z))
       (Vec3. b nil nil))))

(defn vec2-with-meta
  ([v meta]
     (cond
      (instance? Vec2 v) (with-meta v meta)
      (number? v)        (vec2-with-meta v v meta)
      (sequential? v)    (vec2-with-meta (nth v 0 0.0) (nth v 1 0.0) meta)
      (map? v)           (vec2-with-meta (get v :x 0.0) (get v :y 0.0) meta)
      :else              (err/type-error! "Vec2" v)))
  ([x y meta]
     (let [^doubles b #?(:clj (double-array 2) :cljs (js/Float32Array. 2))]
       (aset b 0 (double x))
       (aset b 1 (double y))
       (Vec2. b nil meta))))

(defn vec3-with-meta
  ([v meta]
     (cond
      (instance? Vec3 v) (with-meta v meta)
      (number? v)        (vec3-with-meta v v v meta)
      (sequential? v)    (vec3-with-meta (nth v 0 0.0) (nth v 1 0.0) (nth v 2 0.0) meta)
      (map? v)           (vec3-with-meta (get v :x 0.0) (get v :y 0.0) (get v :z 0.0) meta)
      :else              (err/type-error! "Vec3" v)))
  ([x y z meta]
     (let [^doubles b #?(:clj (double-array 3) :cljs (js/Float32Array. 3))]
       (aset b 0 (double x))
       (aset b 1 (double y))
       (aset b 2 (double z))
       (Vec3. b nil meta))))

(defn vec2? [x] (instance? Vec2 x))
(defn vec3? [x] (instance? Vec3 x))

(def V2X (vec2 1 0))
(def V2Y (vec2 0 1))

(def V3X (vec3 1 0 0))
(def V3Y (vec3 0 1 0))
(def V3Z (vec3 0 0 1))

(def V2INF- (vec2 INF-))
(def V2INF+ (vec2 INF+))

(def V3INF- (vec3 INF-))
(def V3INF+ (vec3 INF+))

Random vectors

(defn randvec2
  ([] (m/normalize (vec2 (m/randnorm) (m/randnorm))))
  ([n] (m/normalize (vec2 (m/randnorm) (m/randnorm)) n)))

(defn randvec3
  ([] (m/normalize (vec3 (m/randnorm) (m/randnorm) (m/randnorm))))
  ([n] (m/normalize (vec3 (m/randnorm) (m/randnorm) (m/randnorm)) n)))

Code rewriting macros

Vec2

(defmacro lookup2
  [src k nf]
  `(if (= ~k \x)
     (aget ~src 0)
     (if (= ~k \y)
       (aget ~src 1)
       (or ~nf (err/key-error! ~k)))))

(defmacro rewrite-v2
  [src & body]
  (let [[a x y] (repeatedly gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src
           ~x (aget ~a 0)
           ~y (aget ~a 1)]
       ~@(postwalk-replace {'x x 'y y} body))))

(defmacro rewrite-v2-no-let
  [src & body]
  (let [a (gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src]
       ~@(postwalk-replace {'x `(aget ~a 0) 'y `(aget ~a 1)} body))))

(defmacro rewrite-v2-v-no-let
  [src v default & body]
  (let [a (gensym)
        b (gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src]
       (if (instance? ~'Vec2 ~v)
         (let [~(with-meta b {:tag "doubles"}) (.-buf ~(with-meta v {:tag "Vec2"}))]
           ~@(postwalk-replace
              {'x `(aget ~a 0) 'y `(aget ~a 1) 'vx `(aget ~b 0) 'vy `(aget ~b 1)}
              body))
         (do ~@(postwalk-replace
                {'x `(aget ~a 0) 'y `(aget ~a 1) 'vx `(nth ~v 0 ~default) 'vy `(nth ~v 1 ~default)}
                body))))))

(defmacro rewrite-v2-v
  [src v default & body]
  (let [[a b x y vx vy] (repeatedly gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src
           ~x (aget ~a 0)
           ~y (aget ~a 1)]
       (if (instance? ~'Vec2 ~v)
         (let [~(with-meta b {:tag "doubles"}) (.-buf ~(with-meta v {:tag "Vec2"}))
               ~vx (aget ~b 0)
               ~vy (aget ~b 1)]
           ~@(postwalk-replace {'x x 'y y 'vx vx 'vy vy} body))
         (let [~vx (nth ~v 0 ~default), ~vy (nth ~v 1 ~default)]
           ~@(postwalk-replace {'x x 'y y 'vx vx 'vy vy} body))))))

(defmacro rewrite-v2-nv
  [src v default & body]
  (let [[a v? nv vx vy] (repeatedly gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src
           ~v? (instance? ~'Vec2 ~v)
           ~nv (if ~v? (.-buf ~(with-meta v {:tag "Vec2"})) (number? ~v))
           ~vx (if ~v? (aget ~nv 0) (if ~nv ~v (nth ~v 0 ~default)))
           ~vy (if ~v? (aget ~nv 1) (if ~nv ~v (nth ~v 1 ~default)))]
       ~@(postwalk-replace
          {'x `(aget ~a 0) 'y `(aget ~a 1) 'vx vx 'vy vy}
          body))))

(defmacro rewrite-v2-nv-no-let
  [src v default & body]
  (let [a (gensym), b (gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src]
       (if (instance? ~'Vec2 ~v)
         (let [~(with-meta b {:tag "doubles"}) (.-buf ~(with-meta v {:tag "Vec2"}))]
           ~@(postwalk-replace
              {'x `(aget ~a 0) 'y `(aget ~a 1) 'vx `(aget ~b 0) 'vy `(aget ~b 1)}
              body))
         (if (number? ~v)
           (do ~@(postwalk-replace
                  {'x `(aget ~a 0) 'y `(aget ~a 1) 'vx v 'vy v} body))
           (do ~@(postwalk-replace
                  {'x `(aget ~a 0) 'y `(aget ~a 1)
                   'vx `(nth ~v 0 ~default) 'vy `(nth ~v 1 ~default)}
                  body)))))))

(defmacro rewrite-v2-nv-nv
  [src v v2 d1 d2 & body]
  (let [[a b c x y bx by cx cy v1? v2? n1? n2?] (repeatedly gensym)]
    `(let [~v1? (instance? ~'Vec2 ~v)
           ~v2? (instance? ~'Vec2 ~v2)
           ~n1? (if-not ~v1? (number? ~v))
           ~n2? (if-not ~v2? (number? ~v2))
           ~(with-meta a {:tag "doubles"}) ~src
           ~(with-meta b {:tag "doubles"}) (if ~v1? (.-buf ~(with-meta v {:tag "Vec2"})))
           ~(with-meta c {:tag "doubles"}) (if ~v2? (.-buf ~(with-meta v2 {:tag "Vec2"})))
           ~x (aget ~a 0)
           ~y (aget ~a 1)
           ~bx (if ~v1? (aget ~b 0) (if ~n1? ~v (nth ~v 0 ~d1)))
           ~by (if ~v1? (aget ~b 1) (if ~n1? ~v (nth ~v 1 ~d1)))
           ~cx (if ~v2? (aget ~c 0) (if ~n2? ~v2 (nth ~v2 0 ~d2)))
           ~cy (if ~v2? (aget ~c 1) (if ~n2? ~v2 (nth ~v2 1 ~d2)))]
       ~@(postwalk-replace {'x x 'y y 'bx bx 'by by 'cx cx 'cy cy} body))))

(defmacro v2-op0
  [btype op src meta]
  `(let [dest# (~@btype 2)]
     (rewrite-v2-no-let
      ~src
      (aset dest# 0 (double (~op ~'x)))
      (aset dest# 1 (double (~op ~'y))))
     (new ~'Vec2 dest# nil ~meta)))

(defmacro vec-op0!
  [op src n]
  `(do
     ~@(map #(list 'aset src % (list 'double (list op (list 'aget src %)))) (range n))
     (set! ~'_hash nil)))

(defmacro v2-op1-xy
  [btype op src v v2 d meta]
  (let [[a b c dest x y bx by cx cy n1? n2? v1? v2?] (repeatedly gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src
           ~dest (~@btype 2)
           ~x (aget ~a 0)
           ~y (aget ~a 1)
           ~n1? (number? ~v)
           ~n2? (number? ~v2)]
       (if (if ~n1? ~n2? false)
         (do (aset ~dest 0 (double (~op ~x ~v)))
             (aset ~dest 1 (double (~op ~y ~v2))))
         (let [~v1? (if-not ~n1? (instance? ~'Vec2 ~v))
               ~v2? (if-not ~n2? (instance? ~'Vec2 ~v2))
               ~(with-meta b {:tag "doubles"}) (if ~v1? (.-buf ~(with-meta v {:tag "Vec2"})))
               ~(with-meta c {:tag "doubles"}) (if ~v2? (.-buf ~(with-meta v2 {:tag "Vec2"})))
               ~bx (if ~v1? (aget ~b 0) (if ~n1? ~v (nth ~v 0 ~d)))
               ~by (if ~v1? (aget ~b 1) (if ~n1? ~v (nth ~v 1 ~d)))
               ~cx (if ~v2? (aget ~c 0) (if ~n2? ~v2 (nth ~v2 0 ~d)))
               ~cy (if ~v2? (aget ~c 1) (if ~n2? ~v2 (nth ~v2 1 ~d)))]
           (aset ~dest 0 (double (~op (~op ~x ~bx) ~cx)))
           (aset ~dest 1 (double (~op (~op ~y ~by) ~cy)))))
       (new ~'Vec2 ~dest nil ~meta))))

(defmacro v2-op1-xy!
  [op src v v2 d]
  (let [[a b c bx by cx cy n1? n2? v1? v2?] (repeatedly gensym)]
    `(let [~n1? (number? ~v)
           ~n2? (number? ~v2)]
       (if (if ~n1? ~n2? false)
         (do (aset ~src 0 (double (~op (aget ~src 0) ~v)))
             (aset ~src 1 (double (~op (aget ~src 1) ~v2))))
         (let [~v1? (if-not ~n1? (instance? ~'Vec2 ~v))
               ~v2? (if-not ~n2? (instance? ~'Vec2 ~v2))
               ~(with-meta b {:tag "doubles"}) (if ~v1? (.-buf ~(with-meta v {:tag "Vec2"})))
               ~(with-meta c {:tag "doubles"}) (if ~v2? (.-buf ~(with-meta v2 {:tag "Vec2"})))
               ~bx (if ~v1? (aget ~b 0) (if ~n1? ~v (nth ~v 0 ~d)))
               ~by (if ~v1? (aget ~b 1) (if ~n1? ~v (nth ~v 1 ~d)))
               ~cx (if ~v2? (aget ~c 0) (if ~n2? ~v2 (nth ~v2 0 ~d)))
               ~cy (if ~v2? (aget ~c 1) (if ~n2? ~v2 (nth ~v2 1 ~d)))]
           (aset ~src 0 (double (~op (~op (aget ~src 0) ~bx) ~cx)))
           (aset ~src 1 (double (~op (~op (aget ~src 1) ~by) ~cy)))))
       (set! ~'_hash nil))))

(defmacro v2-op1
  [btype op src v meta]
  `(let [dest# (~@btype 2)]
     (rewrite-v2-nv-no-let
      ~src ~v 0.0
      (aset dest# 0 (double (~op ~'x ~'vx)))
      (aset dest# 1 (double (~op ~'y ~'vy))))
     (new ~'Vec2 dest# nil ~meta)))

(defmacro v2-op1!
  [op src v]
  `(rewrite-v2-nv-no-let
    ~src ~v 0.0
    (aset ~src 0 (double (~op ~'x ~'vx)))
    (aset ~src 1 (double (~op ~'y ~'vy)))
    (set! ~'_hash nil)))

(defmacro v2-op2
  [btype op op2 src v v2 d1 d2 meta]
  `(let [dest# (~@btype 2)]
     (rewrite-v2-nv-nv
      ~src ~v ~v2 ~d1 ~d2
      (aset dest# 0 (double (~op2 (~op ~'x ~'bx) ~'cx)))
      (aset dest# 1 (double (~op2 (~op ~'y ~'by) ~'cy))))
     (new ~'Vec2 dest# nil ~meta)))

(defmacro v2-op2!
  [op op2 src v v2 d1 d2]
  `(rewrite-v2-nv-nv
    ~src ~v ~v2 ~d1 ~d2
    (aset ~src 0 (double (~op2 (~op ~'x ~'bx) ~'cx)))
    (aset ~src 1 (double (~op2 (~op ~'y ~'by) ~'cy)))
    (set! ~'_hash nil)))

(defmacro v2-op2-no-let
  [btype op op2 src v v2 d1 d2 meta]
  `(let [dest# (~@btype 2)]
     (rewrite-v2-nv-nv-no-let
      ~src ~v ~v2 ~d1 ~d2
      (aset dest# 0 (double (~op2 (~op ~'x ~'bx) ~'cx)))
      (aset dest# 1 (double (~op2 (~op ~'y ~'by) ~'cy))))
     (new ~'Vec2 dest# nil ~meta)))

Vec3

(defmacro lookup3
  [src k nf]
  `(case ~k
     \x (aget ~src 0)
     \y (aget ~src 1)
     \z (aget ~src 2)
     (or ~nf (err/key-error! ~k))))

(defmacro rewrite-v3
  [src & body]
  (let [[a x y z] (repeatedly 4 gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src, ~x (aget ~a 0), ~y (aget ~a 1), ~z (aget ~a 2)]
       ~@(postwalk-replace {'x x 'y y 'z z} body))))

(defmacro rewrite-v3-no-let
  [src & body]
  (let [a (gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src]
       ~@(postwalk-replace
          {'x `(aget ~a 0) 'y `(aget ~a 1) 'z `(aget ~a 2)}
          body))))

(defmacro rewrite-v3-v-no-let
  [src v default & body]
  (let [a (gensym)
        b (gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src]
       (if (instance? ~'Vec3 ~v)
         (let [~(with-meta b {:tag "doubles"}) (.-buf ~(with-meta v {:tag "Vec3"}))]
           ~@(postwalk-replace
              {'x `(aget ~a 0) 'y `(aget ~a 1) 'z `(aget ~a 2)
               'vx `(aget ~b 0) 'vy `(aget ~b 1) 'vz `(aget ~b 2)}
              body))
         (do ~@(postwalk-replace
                {'x `(aget ~a 0) 'y `(aget ~a 1) 'z `(aget ~a 2)
                 'vx `(nth ~v 0 ~default) 'vy `(nth ~v 1 ~default) 'vz `(nth ~v 2 ~default)}
                body))))))

(defmacro rewrite-v3-v
  [src v default & body]
  (let [[a b x y z vx vy vz] (repeatedly 8 gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src, ~x (aget ~a 0), ~y (aget ~a 1), ~z (aget ~a 2)]
       (if (instance? ~'Vec3 ~v)
         (let [~(with-meta b {:tag "doubles"}) (.-buf ~(with-meta v {:tag "Vec3"})), ~vx (aget ~b 0), ~vy (aget ~b 1), ~vz (aget ~b 2)]
           ~@(postwalk-replace {'x x 'y y 'z z 'vx vx 'vy vy 'vz vz} body))
         (let [~vx (nth ~v 0 ~default), ~vy (nth ~v 1 ~default), ~vz (nth ~v 2 ~default)]
           ~@(postwalk-replace {'x x 'y y 'z z 'vx vx 'vy vy 'vz vz} body))))))

(defmacro rewrite-v3-nv
  [src v default & body]
  (let [[a v? nv vx vy vz] (repeatedly 6 gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src
           ~v? (instance? ~'Vec3 ~v)
           ~nv (if ~v? (.-buf ~(with-meta v {:tag "Vec3"})) (number? ~v))
           ~vx (if ~v? (aget ~nv 0) (if ~nv ~v (nth ~v 0 ~default)))
           ~vy (if ~v? (aget ~nv 1) (if ~nv ~v (nth ~v 1 ~default)))
           ~vz (if ~v? (aget ~nv 2) (if ~nv ~v (nth ~v 2 ~default)))]
       ~@(postwalk-replace
          {'x `(aget ~a 0) 'y `(aget ~a 1) 'z `(aget ~a 2) 'vx vx 'vy vy 'vz vz}
          body))))

(defmacro rewrite-v3-nv-no-let
  [src v default & body]
  (let [a (gensym), b (gensym)]
    `(let [~(with-meta a {:tag "doubles"}) ~src]
       (if (instance? ~'Vec3 ~v)
         (let [~(with-meta b {:tag "doubles"}) (.-buf ~(with-meta v {:tag "Vec3"}))]
           ~@(postwalk-replace
              {'x `(aget ~a 0) 'y `(aget ~a 1) 'z `(aget ~a 2)
               'vx `(aget ~b 0) 'vy `(aget ~b 1) 'vz `(aget ~b 2)}
              body))
         (if (number? ~v)
           (do ~@(postwalk-replace
                  {'x `(aget ~a 0) 'y `(aget ~a 1) 'z `(aget ~a 2) 'vx v 'vy v 'vz v} body))
           (do ~@(postwalk-replace
                  {'x `(aget ~a 0) 'y `(aget ~a 1) 'z `(aget ~a 2)
                   'vx `(nth ~v 0 ~default) 'vy `(nth ~v 1 ~default) 'vz `(nth ~v 2 ~default)}
                  body)))))))

(defmacro rewrite-v3-nv-nv
  [src v v2 d1 d2 & body]
  (let [[a b c x y z bx by bz cx cy cz v1? v2? n1? n2?] (repeatedly 16 gensym)]
    `(let [~v1? (instance? ~'Vec3 ~v)
           ~v2? (instance? ~'Vec3 ~v2)
           ~n1? (if-not ~v1? (number? ~v))
           ~n2? (if-not ~v2? (number? ~v2))
           ~(with-meta a {:tag "doubles"}) ~src
           ~(with-meta b {:tag "doubles"}) (if ~v1? (.-buf ~(with-meta v {:tag "Vec3"})))
           ~(with-meta c {:tag "doubles"}) (if ~v2? (.-buf ~(with-meta v2 {:tag "Vec3"})))
           ~x (aget ~a 0), ~y (aget ~a 1), ~z (aget ~a 2)
           ~bx (if ~v1? (aget ~b 0) (if ~n1? ~v (nth ~v 0 ~d1)))
           ~by (if ~v1? (aget ~b 1) (if ~n1? ~v (nth ~v 1 ~d1)))
           ~bz (if ~v1? (aget ~b 2) (if ~n1? ~v (nth ~v 2 ~d1)))
           ~cx (if ~v2? (aget ~c 0) (if ~n2? ~v2 (nth ~v2 0 ~d2)))
           ~cy (if ~v2? (aget ~c 1) (if ~n2? ~v2 (nth ~v2 1 ~d2)))
           ~cz (if ~v2? (aget ~c 2) (if ~n2? ~v2 (nth ~v2 2 ~d2)))]
       ~@(postwalk-replace
          {'x x 'y y 'z z 'bx bx 'by by 'bz bz 'cx cx 'cy cy 'cz cz} body))))

(defmacro rewrite-v3-nv-nv-no-let
  [src v v2 d1 d2 & body]
  (let [[a b c x y z bx by bz cx cy cz v1? v2? n1? n2?] (repeatedly 16 gensym)]
    `(let [~v1? (instance? ~'Vec3 ~v)
           ~v2? (instance? ~'Vec3 ~v2)
           ~n1? (if-not ~v1? (number? ~v))
           ~n2? (if-not ~v2? (number? ~v2))
           ~(with-meta a {:tag "doubles"}) ~src
           ~(with-meta b {:tag "doubles"}) (if ~v1? (.-buf ~(with-meta v {:tag "Vec3"})))
           ~(with-meta c {:tag "doubles"}) (if ~v2? (.-buf ~(with-meta v2 {:tag "Vec3"})))]
       ~@(postwalk-replace
          {'x `(aget ~a 0) 'y `(aget ~a 1) 'z `(aget ~a 2)
           'bx `(if ~v1? (aget ~b 0) (if ~n1? ~v (nth ~v 0 ~d1)))
           'by `(if ~v1? (aget ~b 1) (if ~n1? ~v (nth ~v 1 ~d1)))
           'bz `(if ~v1? (aget ~b 2) (if ~n1? ~v (nth ~v 2 ~d1)))
           'cx `(if ~v2? (aget ~c 0) (if ~n2? ~v2 (nth ~v2 0 ~d2)))
           'cy `(if ~v2? (aget ~c 1) (if ~n2? ~v2 (nth ~v2 1 ~d2)))
           'cz `(if ~v2? (aget ~c 2) (if ~n2? ~v2 (nth ~v2 2 ~d2)))}
          body))))

(defmacro v3-op0
  [btype op src meta]
  `(let [dest# (~@btype 3)]
     (rewrite-v3-no-let
      ~src
      (aset dest# 0 (double (~op ~'x)))
      (aset dest# 1 (double (~op ~'y)))
      (aset dest# 2 (double (~op ~'z))))
     (new ~'Vec3 dest# nil ~meta)))

(defmacro v3-op1-xyz
  ([btype op src vs meta]
     `(v3-op1-xyz ~op ~btype ~src (nth ~vs 0 0.0) (nth ~vs 1 0.0) (nth ~vs 2 0.0) ~meta))
  ([btype op src x y z meta]
     (let [a (gensym)]
       `(let [~(with-meta a {:tag "doubles"}) ~src
              dest# (~@btype 3)]
          (aset dest# 0 (double (~op (aget ~a 0) ~x)))
          (aset dest# 1 (double (~op (aget ~a 1) ~y)))
          (aset dest# 2 (double (~op (aget ~a 2) ~z)))
          (new ~'Vec3 dest# nil ~meta)))))

(defmacro v3-op1-xyz!
  ([op src vs]
     `(v3-op1-xyz ~op ~src (nth ~vs 0 0.0) (nth ~vs 1 0.0) (nth ~vs 2 0.0)))
  ([op src x y z]
     `(do
        (aset ~src 0 (double (~op (aget ~src 0) ~x)))
        (aset ~src 1 (double (~op (aget ~src 1) ~y)))
        (aset ~src 2 (double (~op (aget ~src 2) ~z)))
        (set! ~'_hash nil))))

(defmacro v3-op1
  [btype op src v meta]
  `(let [dest# (~@btype 3)]
     (rewrite-v3-nv-no-let
      ~src ~v 0.0
      (aset dest# 0 (double (~op ~'x ~'vx)))
      (aset dest# 1 (double (~op ~'y ~'vy)))
      (aset dest# 2 (double (~op ~'z ~'vz))))
     (new ~'Vec3 dest# nil ~meta)))

(defmacro v3-op1!
  [op src v]
  `(rewrite-v3-nv-no-let
    ~src ~v 0.0
    (aset ~src 0 (double (~op ~'x ~'vx)))
    (aset ~src 1 (double (~op ~'y ~'vy)))
    (aset ~src 2 (double (~op ~'z ~'vz)))
    (set! ~'_hash nil)))

(defmacro v3-op2
  [btype op op2 src v v2 d1 d2 meta]
  `(let [dest# (~@btype 3)]
     (rewrite-v3-nv-nv
      ~src ~v ~v2 ~d1 ~d2
      (aset dest# 0 (double (~op2 (~op ~'x ~'bx) ~'cx)))
      (aset dest# 1 (double (~op2 (~op ~'y ~'by) ~'cy)))
      (aset dest# 2 (double (~op2 (~op ~'z ~'bz) ~'cz))))
     (new ~'Vec3 dest# nil ~meta)))

(defmacro v3-op2!
  [op op2 src v v2 d1 d2]
  `(rewrite-v3-nv-nv
    ~src ~v ~v2 ~d1 ~d2
    (aset ~src 0 (double (~op2 (~op ~'x ~'bx) ~'cx)))
    (aset ~src 1 (double (~op2 (~op ~'y ~'by) ~'cy)))
    (aset ~src 2 (double (~op2 (~op ~'z ~'bz) ~'cz)))
    (set! ~'_hash nil)))

(defmacro v3-op2-no-let
  [btype op op2 src v v2 d1 d2 meta]
  `(let [dest# (~@btype 3)]
     (rewrite-v3-nv-nv-no-let
      ~src ~v ~v2 ~d1 ~d2
      (aset dest# 0 (double (~op2 (~op ~'x ~'bx) ~'cx)))
      (aset dest# 1 (double (~op2 (~op ~'y ~'by) ~'cy)))
      (aset dest# 2 (double (~op2 (~op ~'z ~'bz) ~'cz))))
     (new ~'Vec3 dest# nil ~meta)))

Complete namespace definitions

(ns thi.ng.geom.vector
  #?(:clj
     (:import
      [java.nio FloatBuffer])
     :cljs
     (:require-macros
      [thi.ng.geom.macros.vector :as vm :refer [defswizzle]]
      [thi.ng.math.macros :as mm]))
  (:require
   [thi.ng.geom.core :as g]
   [thi.ng.math.core :as m :refer [*eps* PI TWO_PI INF- INF+]]
   [thi.ng.dstruct.streams :as streams]
   [thi.ng.xerror.core :as err]
   #?@(:clj
       [[thi.ng.geom.macros.vector :as vm :refer [defswizzle]]
        [thi.ng.math.macros :as mm]
        [clojure.core.protocols :as cp]])))

(declare V2 V3 vec2 vec3 vec2-reduce* vec3-reduce* swizzle-assoc* swizzle2-fns swizzle3-fns)

<<vec2>>

<<vec3>>

<<swizzle-fns>>

<<ops>>

<<ctors>>
(ns thi.ng.geom.macros.vector
  (:require
   [clojure.walk :refer :all]
   [thi.ng.dstruct.core :as d]
   [thi.ng.xerror.core :as err]))

<<swizzle-macros>>

<<v2-macros>>

<<v3-macros>>