Saturday, 4 April 2009

Implementing Minilight in Clojure (2)

Any 3D rendering rubbish seems to require a 3d vector class of some description. A quick Google Code Search brings up thousands of results.

The Minilight code is no exception.

For now, my Clojure version will just use the built in vec based sequence. I'm sure that I'll find I'll need raw Java array access, but it's inconvenient to start with the ugly stuff.

ANSI Common Lisp mentions this explicitly,
"Lisp is really two programming languages, a language for writing fast programs and a language for writing programs fast."
I think the same applies to Clojure, I know I can always get the raw speed of Java when I need it, but I can stay nice and high level for most of the time (80/20 rule and all that).

So here's the most basic set of vector like functions I could write for Clojure. The cross product definition is the ugliest out there. Probably because it's only valid in 3 (or 7 according to Wikipedia!) dimensions!

(defn dot
"Dot product of two vectors"
[v1 v2] (reduce + (map * v1 v2)))

(defn cross
"Cross product of two 3 vectors"
[v1 v2]
(- (* (get v1 1) (get v2 2)) (get v1 2) (get v2 1))
(- (* (get v1 2) (get v2 0)) (get v1 0) (get v2 2))
(- (* (get v1 0) (get v2 1)) (get v1 1) (get v2 0))))

(defn unary-minus
"Negation of a vector"
[v] (vec (map - v)))

(defn unitize
(let [len (Math/sqrt (dot v v))
overlen (if (not (zero? len)) (/ 1 len) 0)]
(vec (map (fn [x] (* overlen x)) v))))

(defn between
[mini maxi x]
(min (max x mini) maxi))

(defn get-clamped
"Clamp v within the bounds minimum and maximum"
[v mini maxi]
(vec (map between mini maxi v)))