 (ns quil.middlewares.navigation-3d
   (:require [quil.core :as q]))
 
-(defn- default-camera []
+(defn- default-position
+  "Default position configuration. Check default configuration in
+  'camera' function."
+  []
   {:position [(/ (q/width) 2.0)
               (/ (q/height) 2.0)
               (/ (q/height) 2.0 (q/tan (/ (* q/PI 60.0) 360.0)))]
    :straight [0 0 -1]
    :up [0 1 0]})
 
-; http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
-(defn- rotate-by-axis-and-angle [v axis angle]
+(defn- rotate-by-axis-and-angle
+  "Rotates vector v by angle with axis.
+  Formula is taken from wiki:
+  http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle"
+  [v axis angle]
   (let [[a-x a-y a-z] axis
         [x y z] v
         cs (q/cos angle)

     (+ (* d x) (* e y) (* f z))
     (+ (* g x) (* h y) (* i z))]))

(defn- rotate-lr [nav-3d angle]
  (update-in nav-3d [:straight] rotate-by-axis-and-angle (:up nav-3d) angle))

(defn- cross-product [[u1 u2 u3] [v1 v2 v3]]
  [(- (* u2 v3) (* u3 v2))
   (- (* u3 v1) (* u1 v3))
   (- (* u1 v2) (* u2 v1))])

(defn- v-mult [v mult]
  (mapv #(* % mult) v))

(defn- v-plus [v1 v2]
  (mapv + v1 v2))

(defn- v-opposite [v]
  (v-mult v -1))

(defn- v-normalize [v]
  (let [norm (->> (map q/sq v)
                  (apply +)
                  (q/sqrt))]
    (v-mult v (/ norm))))

(defn- rotate-ud [nav-3d angle]
  (let [axis (cross-product (:straight nav-3d) (:up nav-3d))
        rotate #(rotate-by-axis-and-angle % axis angle)]
    (-> nav-3d
        (update-in [:straight] rotate)
        (update-in [:up] rotate))))

(defn- rotate [state event pixels-in-360]
  (if (= 0 (:p-x event) (:p-y event))
    state
    (let [dx (- (:p-x event) (:x event))

                 #(v-plus % (v-mult dir step-size)))
      state)))

(defn- setup-3d-nav
  "Custom 'setup' function which creates initial position
  configuration and puts it to the state map."
  [user-setup user-settings]
  (let [initial-state (-> user-settings
                          (select-keys [:straight :up :position])
                          (->> (merge (default-camera)))
