blob: d2ec24c71368699ed6d0851907dd4a44fc9eca76 [file] [log] [blame]
Jason Sams044e2ee2011-08-08 16:52:30 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Robert Ly1f575412011-09-01 15:45:03 -070017/** @file rs_quaternion.rsh
Jason Sams044e2ee2011-08-08 16:52:30 -070018 * \brief Quaternion routines
19 *
20 *
21 */
22
23#ifndef __RS_QUATERNION_RSH__
24#define __RS_QUATERNION_RSH__
25
26
27/**
28 * Set the quaternion components
Jean-Luc Brouillet462e62c2014-12-12 13:42:24 -080029 * @param q destination quaternion
Jason Sams044e2ee2011-08-08 16:52:30 -070030 * @param w component
31 * @param x component
32 * @param y component
33 * @param z component
34 */
35static void __attribute__((overloadable))
36rsQuaternionSet(rs_quaternion *q, float w, float x, float y, float z) {
37 q->w = w;
38 q->x = x;
39 q->y = y;
40 q->z = z;
41}
42
43/**
44 * Set the quaternion from another quaternion
45 * @param q destination quaternion
46 * @param rhs source quaternion
47 */
48static void __attribute__((overloadable))
49rsQuaternionSet(rs_quaternion *q, const rs_quaternion *rhs) {
50 q->w = rhs->w;
51 q->x = rhs->x;
52 q->y = rhs->y;
53 q->z = rhs->z;
54}
55
56/**
57 * Multiply quaternion by a scalar
58 * @param q quaternion to multiply
59 * @param s scalar
60 */
61static void __attribute__((overloadable))
62rsQuaternionMultiply(rs_quaternion *q, float s) {
63 q->w *= s;
64 q->x *= s;
65 q->y *= s;
66 q->z *= s;
67}
68
69/**
Jason Sams044e2ee2011-08-08 16:52:30 -070070 * Add two quaternions
71 * @param q destination quaternion to add to
Jean-Luc Brouillet462e62c2014-12-12 13:42:24 -080072 * @param rhs right hand side quaternion to add
Jason Sams044e2ee2011-08-08 16:52:30 -070073 */
74static void
75rsQuaternionAdd(rs_quaternion *q, const rs_quaternion *rhs) {
76 q->w *= rhs->w;
77 q->x *= rhs->x;
78 q->y *= rhs->y;
79 q->z *= rhs->z;
80}
81
82/**
83 * Loads a quaternion that represents a rotation about an arbitrary unit vector
84 * @param q quaternion to set
85 * @param rot angle to rotate by
86 * @param x component of a vector
87 * @param y component of a vector
Jean-Luc Brouillet462e62c2014-12-12 13:42:24 -080088 * @param z component of a vector
Jason Sams044e2ee2011-08-08 16:52:30 -070089 */
90static void
91rsQuaternionLoadRotateUnit(rs_quaternion *q, float rot, float x, float y, float z) {
92 rot *= (float)(M_PI / 180.0f) * 0.5f;
93 float c = cos(rot);
94 float s = sin(rot);
95
96 q->w = c;
97 q->x = x * s;
98 q->y = y * s;
99 q->z = z * s;
100}
101
102/**
103 * Loads a quaternion that represents a rotation about an arbitrary vector
104 * (doesn't have to be unit)
105 * @param q quaternion to set
106 * @param rot angle to rotate by
107 * @param x component of a vector
108 * @param y component of a vector
Jean-Luc Brouillet462e62c2014-12-12 13:42:24 -0800109 * @param z component of a vector
Jason Sams044e2ee2011-08-08 16:52:30 -0700110 */
111static void
112rsQuaternionLoadRotate(rs_quaternion *q, float rot, float x, float y, float z) {
113 const float len = x*x + y*y + z*z;
114 if (len != 1) {
115 const float recipLen = 1.f / sqrt(len);
116 x *= recipLen;
117 y *= recipLen;
118 z *= recipLen;
119 }
120 rsQuaternionLoadRotateUnit(q, rot, x, y, z);
121}
122
123/**
124 * Conjugates the quaternion
125 * @param q quaternion to conjugate
126 */
127static void
128rsQuaternionConjugate(rs_quaternion *q) {
129 q->x = -q->x;
130 q->y = -q->y;
131 q->z = -q->z;
132}
133
134/**
135 * Dot product of two quaternions
136 * @param q0 first quaternion
137 * @param q1 second quaternion
138 * @return dot product between q0 and q1
139 */
140static float
141rsQuaternionDot(const rs_quaternion *q0, const rs_quaternion *q1) {
142 return q0->w*q1->w + q0->x*q1->x + q0->y*q1->y + q0->z*q1->z;
143}
144
145/**
146 * Normalizes the quaternion
147 * @param q quaternion to normalize
148 */
149static void
150rsQuaternionNormalize(rs_quaternion *q) {
151 const float len = rsQuaternionDot(q, q);
152 if (len != 1) {
153 const float recipLen = 1.f / sqrt(len);
154 rsQuaternionMultiply(q, recipLen);
155 }
156}
157
158/**
Alex Sakhartchoukbd7b1a92011-10-18 11:54:49 -0700159 * Multiply quaternion by another quaternion
160 * @param q destination quaternion
161 * @param rhs right hand side quaternion to multiply by
162 */
163static void __attribute__((overloadable))
164rsQuaternionMultiply(rs_quaternion *q, const rs_quaternion *rhs) {
165 rs_quaternion qtmp;
166 rsQuaternionSet(&qtmp, q);
167
168 q->w = qtmp.w*rhs->w - qtmp.x*rhs->x - qtmp.y*rhs->y - qtmp.z*rhs->z;
169 q->x = qtmp.w*rhs->x + qtmp.x*rhs->w + qtmp.y*rhs->z - qtmp.z*rhs->y;
170 q->y = qtmp.w*rhs->y + qtmp.y*rhs->w + qtmp.z*rhs->x - qtmp.x*rhs->z;
171 q->z = qtmp.w*rhs->z + qtmp.z*rhs->w + qtmp.x*rhs->y - qtmp.y*rhs->x;
172 rsQuaternionNormalize(q);
173}
174
175/**
Jason Sams044e2ee2011-08-08 16:52:30 -0700176 * Performs spherical linear interpolation between two quaternions
177 * @param q result quaternion from interpolation
178 * @param q0 first param
179 * @param q1 second param
180 * @param t how much to interpolate by
181 */
182static void
183rsQuaternionSlerp(rs_quaternion *q, const rs_quaternion *q0, const rs_quaternion *q1, float t) {
184 if (t <= 0.0f) {
185 rsQuaternionSet(q, q0);
186 return;
187 }
188 if (t >= 1.0f) {
189 rsQuaternionSet(q, q1);
190 return;
191 }
192
193 rs_quaternion tempq0, tempq1;
194 rsQuaternionSet(&tempq0, q0);
195 rsQuaternionSet(&tempq1, q1);
196
197 float angle = rsQuaternionDot(q0, q1);
198 if (angle < 0) {
199 rsQuaternionMultiply(&tempq0, -1.0f);
200 angle *= -1.0f;
201 }
202
203 float scale, invScale;
204 if (angle + 1.0f > 0.05f) {
205 if (1.0f - angle >= 0.05f) {
206 float theta = acos(angle);
207 float invSinTheta = 1.0f / sin(theta);
208 scale = sin(theta * (1.0f - t)) * invSinTheta;
209 invScale = sin(theta * t) * invSinTheta;
210 } else {
211 scale = 1.0f - t;
212 invScale = t;
213 }
214 } else {
215 rsQuaternionSet(&tempq1, tempq0.z, -tempq0.y, tempq0.x, -tempq0.w);
216 scale = sin(M_PI * (0.5f - t));
217 invScale = sin(M_PI * t);
218 }
219
220 rsQuaternionSet(q, tempq0.w*scale + tempq1.w*invScale, tempq0.x*scale + tempq1.x*invScale,
221 tempq0.y*scale + tempq1.y*invScale, tempq0.z*scale + tempq1.z*invScale);
222}
223
224/**
225 * Computes rotation matrix from the normalized quaternion
226 * @param m resulting matrix
Jean-Luc Brouillet462e62c2014-12-12 13:42:24 -0800227 * @param q normalized quaternion
Jason Sams044e2ee2011-08-08 16:52:30 -0700228 */
229static void rsQuaternionGetMatrixUnit(rs_matrix4x4 *m, const rs_quaternion *q) {
Alex Sakhartchoukbd7b1a92011-10-18 11:54:49 -0700230 float xx = q->x * q->x;
231 float xy = q->x * q->y;
232 float xz = q->x * q->z;
233 float xw = q->x * q->w;
234 float yy = q->y * q->y;
235 float yz = q->y * q->z;
236 float yw = q->y * q->w;
237 float zz = q->z * q->z;
238 float zw = q->z * q->w;
Jason Sams044e2ee2011-08-08 16:52:30 -0700239
Alex Sakhartchoukbd7b1a92011-10-18 11:54:49 -0700240 m->m[0] = 1.0f - 2.0f * ( yy + zz );
241 m->m[4] = 2.0f * ( xy - zw );
242 m->m[8] = 2.0f * ( xz + yw );
243 m->m[1] = 2.0f * ( xy + zw );
244 m->m[5] = 1.0f - 2.0f * ( xx + zz );
245 m->m[9] = 2.0f * ( yz - xw );
246 m->m[2] = 2.0f * ( xz - yw );
247 m->m[6] = 2.0f * ( yz + xw );
248 m->m[10] = 1.0f - 2.0f * ( xx + yy );
249 m->m[3] = m->m[7] = m->m[11] = m->m[12] = m->m[13] = m->m[14] = 0.0f;
Jason Sams044e2ee2011-08-08 16:52:30 -0700250 m->m[15] = 1.0f;
251}
252
253#endif