(defn
disc
[{:keys [radius divisions stacks inner-radius stack-power],
:or {stacks 1, inner-radius 0, stack-power 1}}]
(let
[num-vertices
(* (inc divisions) (inc stacks))
radius-span
(- radius inner-radius)
points-per-stack
(inc divisions)]
(->
(fn
[m stack]
(let
[stack-radius
(+
inner-radius
(* radius-span (math pow (/ stack stacks) stack-power)))]
(->
(fn
[m i]
(let
[first-index
(:first-index m)
theta
(-> 2 (* (math PI)) (* i) (/ divisions))
x
(* stack-radius (math cos theta))
z
(* stack-radius (math sin theta))]
(->
m
(update
:positions
(fn
[positions]
(-> positions (conj! x) (conj! 0) (conj! z))))
(update
:normals
(fn [normals] (-> normals (conj! 0) (conj! 1) (conj! 0))))
(update
:texcoords
(fn
[texcoords]
(->
texcoords
(conj! (- 1 (/ i divisions)))
(conj! (/ stack stacks)))))
(update
:indices
(fn
[indices]
(if
(and (pos? stack) (not= i divisions))
(let
[a
(+ first-index i 1)
b
(+ first-index i)
c
(-> first-index (+ i) (- points-per-stack))
d
(-> first-index (+ (inc i)) (- points-per-stack))]
(->
indices
(conj! a)
(conj! b)
(conj! c)
(conj! a)
(conj! c)
(conj! d)))
indices))))))
(reduce m (range (inc divisions)))
(update :first-index + (inc divisions)))))
(reduce
{:first-index 0,
:positions (transient []),
:normals (transient []),
:texcoords (transient []),
:indices (transient [])}
(range (inc stacks)))
(dissoc :first-index)
(update :positions persistent!)
(update :normals persistent!)
(update :texcoords persistent!)
(update :indices persistent!))))