summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--chickadee/math/quaternion.scm96
-rw-r--r--doc/api.texi40
3 files changed, 137 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index d39cf38..6400ab2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -50,6 +50,7 @@ SOURCES = \
chickadee/math.scm \
chickadee/math/vector.scm \
chickadee/math/matrix.scm \
+ chickadee/math/quaternion.scm \
chickadee/math/rect.scm \
chickadee/math/easings.scm \
chickadee/render/color.scm \
diff --git a/chickadee/math/quaternion.scm b/chickadee/math/quaternion.scm
new file mode 100644
index 0000000..893ccd7
--- /dev/null
+++ b/chickadee/math/quaternion.scm
@@ -0,0 +1,96 @@
+;;; Chickadee Game Toolkit
+;;; Copyright © 2017 David Thompson <davet@gnu.org>
+;;;
+;;; Chickadee is free software: you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published
+;;; by the Free Software Foundation, either version 3 of the License,
+;;; or (at your option) any later version.
+;;;
+;;; Chickadee is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Useful representation of 3D rotations.
+;;
+;;; Code:
+
+(define-module (chickadee math quaternion)
+ #:use-module (chickadee math)
+ #:use-module (srfi srfi-9)
+ #:use-module (system foreign)
+ #:export (quaternion
+ quaternion?
+ quaternion-w
+ quaternion-x
+ quaternion-y
+ quaternion-z
+ make-identity-quaternion))
+
+(define-record-type <quaternion>
+ (wrap-quaternion bv pointer)
+ quaternion?
+ (bv unwrap-quaternion)
+ (pointer quaternion-pointer set-quaternion-pointer!))
+
+(define (quaternion->pointer q)
+ "Return a foreign pointer to Q."
+ ;; Create foreign pointer lazily.
+ (or (quaternion-pointer q)
+ (let ((pointer (bytevector->pointer (unwrap-quaternion q))))
+ (set-quaternion-pointer! q pointer)
+ pointer)))
+
+(define-inlinable (quaternion-ref q i)
+ (f32vector-ref (unwrap-quaternion q) i))
+
+(define-inlinable (quaternion-set! q i x)
+ (f32vector-set! (unwrap-quaternion q) i x))
+
+(define-syntax-rule (with-new-quaternion name body ...)
+ (let ((name (make-null-quaternion))) body ... name))
+
+(define-inlinable (quaternion x y z w)
+ "Return a new quaternion with values X, Y, Z, and W."
+ (with-new-quaternion q
+ (quaternion-set! q 0 x)
+ (quaternion-set! q 1 y)
+ (quaternion-set! q 2 z)
+ (quaternion-set! q 3 w)))
+
+(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-x q)
+ "Return the X coordinate of the quaternion Q."
+ (quaternion-ref q 0))
+
+(define-inlinable (quaternion-y q)
+ "Return the Y coordinate of the quaternion Q."
+ (quaternion-ref q 1))
+
+(define-inlinable (quaternion-z q)
+ "Return the Z coordinate of the quaternion Q."
+ (quaternion-ref q 2))
+
+(define-inlinable (quaternion-w q)
+ "Return the W coordinate of the quaternion Q."
+ (quaternion-ref q 3))
+
+(define-inlinable (quaternion-magnitude q)
+ "Return the magnitude of the quaternion Q."
+ (sqrt
+ (+ (square (quaternion-w q))
+ (square (quaternion-x q))
+ (square (quaternion-y q))
+ (square (quaternion-z q)))))
diff --git a/doc/api.texi b/doc/api.texi
index eaad84e..f5a2400 100644
--- a/doc/api.texi
+++ b/doc/api.texi
@@ -410,6 +410,7 @@ detection.
* Basics:: Commonly used, miscellaneous things.
* Vectors:: Euclidean vectors.
* Matrices:: Transformation matrices.
+* Quaternions:: Rotations.
* Rectangles:: Axis-aligned bounding boxes.
* Easings:: Easing functions for interesting animations.
@end menu
@@ -434,6 +435,45 @@ Half of @var{pi}.
@node Matrices
@subsection Matrices
+@node Quaternions
+@subsection Quaternions
+
+In game development, the quaternion is most often used to represent
+rotations. Why not use a matrix for that, you may ask. Unlike
+matrices, quaternions can be interpolated (animated) and produce a
+meaningful result. When interpolating two quaternions, there is a
+smooth transition from one rotation to another, whereas interpolating
+two matrices would yield garbage.
+
+@deffn {Procedure} quaternion @var{x} @var{y} @var{z} @var{w}
+Return a new quaternion with values @var{x}, @var{y}, @var{z}, and
+@var{w}.
+@end deffn
+
+@deffn {Procedure} quaternion? @var{obj}
+Return @code{#t} if @var{obj} is a quaternion.
+@end deffn
+
+@deffn {Procedure} quaternion-w @var{q}
+Return the W component of the quaternion @var{q}.
+@end deffn
+
+@deffn {Procedure} quaternion-x @var{q}
+Return the X component of the quaternion @var{q}.
+@end deffn
+
+@deffn {Procedure} quaternion-y @var{q}
+Return the Y component of the quaternion @var{q}.
+@end deffn
+
+@deffn {Procedure} quaternion-z @var{q}
+Return the Z component of the quaternion @var{q}.
+@end deffn
+
+@deffn {Procedure} make-identity-quaternion
+Return the identity quaternion.
+@end deffn
+
@node Rectangles
@subsection Rectangles