summaryrefslogtreecommitdiff
path: root/chickadee/math/quaternion.scm
blob: 17a9810a7b435f55e585f380acdcd106547328cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
;;; Chickadee Game Toolkit
;;; Copyright © 2017 David Thompson <dthompson2@worcester.edu>
;;;
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at
;;;
;;;    http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.

;;; Commentary:
;;
;; Useful representation of 3D rotations.
;;
;;; Code:

(define-module (chickadee math quaternion)
  #:use-module (chickadee data bytestruct)
  #:use-module (chickadee math)
  #:use-module (chickadee math vector)
  #:use-module (ice-9 format)
  #:use-module (srfi srfi-9)
  #:use-module (srfi srfi-9 gnu)
  #:use-module (system foreign)
  #:export (quaternion
            quaternion?
            quaternion-x
            quaternion-y
            quaternion-z
            quaternion-w
            make-identity-quaternion
            rotation->quaternion))

;; Should this even be its own type?  Should probably just be a
;; generic 4D vector.
(define-byterecord-type <quaternion>
  (quaternion x y z w)
  quaternion?
  (x f32 quaternion-x set-quaternion-x!)
  (y f32 quaternion-y set-quaternion-y!)
  (z f32 quaternion-z set-quaternion-z!)
  (w f32 quaternion-w set-quaternion-w!))

(define-syntax-rule (with-new-quaternion name body ...)
  (let ((name (quaternion 0.0 0.0 0.0 0.0)))
    body ... name))

(define-inlinable (make-identity-quaternion)
  "Return the identity quaternion."
  (quaternion 0.0 0.0 0.0 1.0))

(define-inlinable (make-null-quaternion)
  (quaternion 0.0 0.0 0.0 0.0))

(define-inlinable (quaternion-magnitude q)
  "Return the magnitude of the quaternion Q."
  (let ((w (quaternion-w q))
        (x (quaternion-x q))
        (y (quaternion-y q))
        (z (quaternion-z q)))
    (sqrt (+ (* w w) (* x x) (* y y) (* z z)))))

(define-inlinable (rotation->quaternion axis angle)
  ;; Math taken from here:
  ;; http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/
  (let* ((a (/ angle 2.0))
         (s (sin a))
         (c (cos a))
         (n (vec3-magnitude axis)))
    (if (= n 0.0)
        (make-identity-quaternion)
        (quaternion (* (/ (vec3-x axis) n) s)
                    (* (/ (vec3-y axis) n) s)
                    (* (/ (vec3-z axis) n) s)
                    c))))