(torus {:keys [radius thickness radial-subdivisions body-subdivisions start-angle end-angle], :or {start-angle 0, end-angle (* 2 (math PI))}})

Source

(defn torus [{:keys [radius thickness radial-subdivisions body-subdivisions start-angle end-angle], :or {start-angle 0, end-angle (* 2 (math PI))}}] (let [angle-range (- end-angle start-angle) radial-parts (inc radial-subdivisions) body-parts (inc body-subdivisions) num-vertices (* radial-parts body-parts)] (-> (fn [m slice] (let [v (/ slice body-subdivisions) slice-angle (* v (math PI) 2) slice-sin (math sin slice-angle) ring-radius (+ radius (* slice-sin thickness)) ny (math cos slice-angle) y (* ny thickness)] (reduce (fn [m ring] (let [u (/ ring radial-subdivisions) ring-angle (+ start-angle (* u angle-range)) x-sin (math sin ring-angle) z-cos (math cos ring-angle) x (* x-sin ring-radius) z (* z-cos ring-radius) nx (* x-sin slice-sin) nz (* z-cos slice-sin)] (-> m (update :positions (fn [positions] (-> positions (conj! x) (conj! y) (conj! z)))) (update :normals (fn [normals] (-> normals (conj! nx) (conj! ny) (conj! nz)))) (update :texcoords (fn [texcoords] (-> texcoords (conj! u) (conj! (- 1 v)))))))) m (range radial-parts)))) (reduce {:positions (transient []), :normals (transient []), :texcoords (transient [])} (range body-parts)) (assoc :indices (reduce (fn [indices slice] (reduce (fn [indices ring] (let [next-ring-index (inc ring) next-slice-index (inc slice)] (-> indices (conj! (+ (* radial-parts slice) ring)) (conj! (+ (* radial-parts next-slice-index) ring)) (conj! (+ (* radial-parts slice) next-ring-index)) (conj! (+ (* radial-parts next-slice-index) ring)) (conj! (+ (* radial-parts next-slice-index) next-ring-index)) (conj! (+ (* radial-parts slice) next-ring-index))))) indices (range radial-subdivisions))) (transient []) (range body-subdivisions))) (update :positions persistent!) (update :normals persistent!) (update :texcoords persistent!) (update :indices persistent!))))