summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCedric BAIL <cedric@osg.samsung.com>2015-05-29 17:18:23 +0200
committerCedric BAIL <cedric@osg.samsung.com>2015-05-29 17:20:29 +0200
commit0acf23857fccc300727c32aa5ef0583953528d5d (patch)
tree34104bab144076975df7829952a65fc5809cec73 /src
parentc937aab8c071102710bf0856f0197c18a96ced35 (diff)
eina: beginning of a generic quaternion API.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile_Eina.am9
-rw-r--r--src/lib/eina/Eina.h1
-rw-r--r--src/lib/eina/eina_quaternion.c609
-rw-r--r--src/lib/eina/eina_quaternion.h128
-rw-r--r--src/lib/evas/canvas/evas_map.c42
-rw-r--r--src/tests/eina/eina_test_quaternion.c133
6 files changed, 897 insertions, 25 deletions
diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am
index 6cf5ae5a04..316542ceaa 100644
--- a/src/Makefile_Eina.am
+++ b/src/Makefile_Eina.am
@@ -90,7 +90,8 @@ lib/eina/eina_matrix.h \
90lib/eina/eina_quad.h \ 90lib/eina/eina_quad.h \
91lib/eina/eina_crc.h \ 91lib/eina/eina_crc.h \
92lib/eina/eina_evlog.h \ 92lib/eina/eina_evlog.h \
93lib/eina/eina_util.h 93lib/eina/eina_util.h \
94lib/eina/eina_quaternion.h
94 95
95lib_eina_libeina_la_SOURCES = \ 96lib_eina_libeina_la_SOURCES = \
96lib/eina/eina_abi.c \ 97lib/eina/eina_abi.c \
@@ -158,7 +159,8 @@ lib/eina/eina_xattr.c \
158lib/eina/eina_debug.h \ 159lib/eina/eina_debug.h \
159lib/eina/eina_private.h \ 160lib/eina/eina_private.h \
160lib/eina/eina_share_common.h \ 161lib/eina/eina_share_common.h \
161lib/eina/eina_strbuf_common.h 162lib/eina/eina_strbuf_common.h \
163lib/eina/eina_quaternion.c
162 164
163if HAVE_WIN32 165if HAVE_WIN32
164lib_eina_libeina_la_SOURCES += lib/eina/eina_file_win32.c 166lib_eina_libeina_la_SOURCES += lib/eina/eina_file_win32.c
@@ -311,7 +313,8 @@ tests/eina/eina_test_lock.c \
311tests/eina/eina_test_xattr.c \ 313tests/eina/eina_test_xattr.c \
312tests/eina/eina_test_crc.c \ 314tests/eina/eina_test_crc.c \
313tests/eina/eina_test_quad.c \ 315tests/eina/eina_test_quad.c \
314tests/eina/eina_test_matrix.c 316tests/eina/eina_test_matrix.c \
317tests/eina/eina_test_quaternion.c
315 318
316tests_eina_eina_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ 319tests_eina_eina_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
317-DTESTS_WD=\"`pwd`\" \ 320-DTESTS_WD=\"`pwd`\" \
diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h
index c35820a8a8..9e1918c6d5 100644
--- a/src/lib/eina/Eina.h
+++ b/src/lib/eina/Eina.h
@@ -266,6 +266,7 @@ extern "C" {
266#include <eina_crc.h> 266#include <eina_crc.h>
267#include <eina_evlog.h> 267#include <eina_evlog.h>
268#include <eina_util.h> 268#include <eina_util.h>
269#include <eina_quaternion.h>
269 270
270#undef EAPI 271#undef EAPI
271#define EAPI 272#define EAPI
diff --git a/src/lib/eina/eina_quaternion.c b/src/lib/eina/eina_quaternion.c
new file mode 100644
index 0000000000..18e9046496
--- /dev/null
+++ b/src/lib/eina/eina_quaternion.c
@@ -0,0 +1,609 @@
1/* EINA - Drawing Library
2 * Copyright (C) 2007-2014 Jorge Luis Zapata
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library.
16 * If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include "eina_private.h"
24
25#include <math.h>
26
27#include "eina_fp.h"
28#include "eina_matrix.h"
29#include "eina_quaternion.h"
30
31EAPI Eina_F16p16
32eina_quaternion_f16p16_norm(const Eina_Quaternion_F16p16 *q)
33{
34 Eina_F16p16 s;
35
36 s = eina_f16p16_add(eina_f16p16_add(eina_f16p16_mul(q->w, q->w),
37 eina_f16p16_mul(q->x, q->x)),
38 eina_f16p16_add(eina_f16p16_mul(q->y, q->y),
39 eina_f16p16_mul(q->z, q->z)));
40
41 return eina_f16p16_sqrt(s);
42}
43
44EAPI void
45eina_quaternion_f16p16_negative(Eina_Quaternion_F16p16 *out,
46 const Eina_Quaternion_F16p16 *in)
47{
48 out->w = eina_f16p16_sub(0, in->w);
49 out->x = eina_f16p16_sub(0, in->x);
50 out->y = eina_f16p16_sub(0, in->y);
51 out->z = eina_f16p16_sub(0, in->z);
52}
53
54EAPI void
55eina_quaternion_f16p16_add(Eina_Quaternion_F16p16 *out,
56 const Eina_Quaternion_F16p16 *a,
57 const Eina_Quaternion_F16p16 *b)
58{
59 out->w = eina_f16p16_add(a->w, b->w);
60 out->x = eina_f16p16_add(a->x, b->x);
61 out->y = eina_f16p16_add(a->y, b->y);
62 out->z = eina_f16p16_add(a->z, b->z);
63}
64
65EAPI void
66eina_quaternion_f16p16_mul(Eina_Quaternion_F16p16 *out,
67 const Eina_Quaternion_F16p16 *a,
68 const Eina_Quaternion_F16p16 *b)
69{
70 out->w = eina_f16p16_sub(eina_f16p16_sub(eina_f16p16_mul(a->w, b->w),
71 eina_f16p16_mul(a->x, b->x)),
72 eina_f16p16_sub(eina_f16p16_mul(a->y, b->y),
73 eina_f16p16_mul(a->z, b->z)));
74 out->x = eina_f16p16_add(eina_f16p16_add(eina_f16p16_mul(a->w, b->x),
75 eina_f16p16_mul(a->x, b->w)),
76 eina_f16p16_sub(eina_f16p16_mul(a->y, b->z),
77 eina_f16p16_mul(a->z, b->y)));
78 out->y = eina_f16p16_add(eina_f16p16_sub(eina_f16p16_mul(a->w, b->y),
79 eina_f16p16_mul(a->x, b->z)),
80 eina_f16p16_add(eina_f16p16_mul(a->y, b->w),
81 eina_f16p16_mul(a->z, b->x)));
82 out->z = eina_f16p16_add(eina_f16p16_add(eina_f16p16_mul(a->w, b->z),
83 eina_f16p16_mul(a->x, b->y)),
84 eina_f16p16_sub(eina_f16p16_mul(a->z, b->w),
85 eina_f16p16_mul(a->y, b->y)));
86}
87
88EAPI void
89eina_quaternion_f16p16_scale(Eina_Quaternion_F16p16 *out,
90 const Eina_Quaternion_F16p16 *a,
91 Eina_F16p16 b)
92{
93 out->w = eina_f16p16_scale(a->w, b);
94 out->x = eina_f16p16_scale(a->x, b);
95 out->y = eina_f16p16_scale(a->y, b);
96 out->z = eina_f16p16_scale(a->z, b);
97}
98
99EAPI void
100eina_quaternion_f16p16_conjugate(Eina_Quaternion_F16p16 *out,
101 const Eina_Quaternion_F16p16 *in)
102{
103 out->w = in->w;
104 out->x = eina_f16p16_sub(0, in->x);
105 out->y = eina_f16p16_sub(0, in->y);
106 out->z = eina_f16p16_sub(0, in->z);
107}
108
109EAPI Eina_F16p16
110eina_quaternion_f16p16_dot(const Eina_Quaternion_F16p16 *a,
111 const Eina_Quaternion_F16p16 *b)
112{
113 return eina_f16p16_add(eina_f16p16_add(eina_f16p16_mul(a->w, b->w),
114 eina_f16p16_mul(a->x, b->x)),
115 eina_f16p16_add(eina_f16p16_mul(a->y, b->y),
116 eina_f16p16_mul(a->z, b->z)));
117}
118
119EAPI void
120eina_quaternion_f16p16_normalized(Eina_Quaternion_F16p16 *out,
121 const Eina_Quaternion_F16p16 *in)
122{
123 Eina_F16p16 norm;
124
125 norm = eina_quaternion_f16p16_norm(in);
126 eina_quaternion_f16p16_scale(out, in,
127 eina_f16p16_div(eina_f16p16_int_from(1),
128 norm));
129}
130
131EAPI void
132eina_quaternion_f16p16_lerp(Eina_Quaternion_F16p16 *out,
133 const Eina_Quaternion_F16p16 *a,
134 const Eina_Quaternion_F16p16 *b,
135 Eina_F16p16 pos)
136{
137 if (pos == 0)
138 {
139 *out = *a;
140 return ;
141 }
142 else if (pos == eina_f16p16_int_from(1))
143 {
144 *out = *b;
145 return ;
146 }
147
148 out->w = eina_f16p16_add(a->w,
149 eina_f16p16_mul(eina_f16p16_sub(b->w, a->w),
150 pos));
151 out->x = eina_f16p16_add(a->x,
152 eina_f16p16_mul(eina_f16p16_sub(b->x, a->x),
153 pos));
154 out->y = eina_f16p16_add(a->y,
155 eina_f16p16_mul(eina_f16p16_sub(b->y, a->y),
156 pos));
157 out->z = eina_f16p16_add(a->z,
158 eina_f16p16_mul(eina_f16p16_sub(b->z, a->z),
159 pos));
160}
161
162EAPI void
163eina_quaternion_f16p16_slerp(Eina_Quaternion_F16p16 *out,
164 const Eina_Quaternion_F16p16 *a,
165 const Eina_Quaternion_F16p16 *b,
166 Eina_F16p16 pos)
167{
168 Eina_Quaternion_F16p16 bp;
169 Eina_Quaternion_F16p16 left, right;
170 Eina_F16p16 dot;
171 Eina_F16p16 pos1, pos2;
172
173 if (pos == 0)
174 {
175 *out = *a;
176 return ;
177 }
178 else if (pos == eina_f16p16_int_from(1))
179 {
180 *out = *b;
181 return ;
182 }
183
184 dot = eina_quaternion_f16p16_dot(a, b);
185 if (dot >= eina_f16p16_int_from(0))
186 {
187 bp = *b;
188 }
189 else
190 {
191 eina_quaternion_f16p16_negative(&bp, b);
192 dot = eina_f16p16_sub(0, dot);
193 }
194
195 pos1 = eina_f16p16_sub(eina_f16p16_int_from(1), pos);
196 pos2 = pos;
197 if (eina_f16p16_sub(eina_f16p16_int_from(1), dot) > eina_f16p16_float_from(0.0000001))
198 {
199 Eina_F32p32 angle;
200 Eina_F16p16 sangle;
201
202 angle = eina_f32p32_double_from(acos(eina_f16p16_double_to(dot)));
203 sangle = eina_f32p32_to_f16p16(eina_f32p32_sin(angle));
204 if (sangle > eina_f16p16_float_from(0.0000001))
205 {
206 pos1 = eina_f32p32_to_f16p16(eina_f32p32_div(eina_f32p32_sin(eina_f32p32_mul(eina_f16p16_to_f32p32(pos1), angle)),
207 eina_f16p16_to_f32p32(sangle)));
208 pos2 = eina_f32p32_to_f16p16(eina_f32p32_div(eina_f32p32_sin(eina_f32p32_mul(eina_f16p16_to_f32p32(pos2), angle)),
209 eina_f16p16_to_f32p32(sangle)));
210 }
211 }
212
213 eina_quaternion_f16p16_scale(&left, a, pos1);
214 eina_quaternion_f16p16_scale(&right, b, pos2);
215 eina_quaternion_f16p16_add(out, &left, &right);
216}
217
218EAPI void
219eina_quaternion_f16p16_nlerp(Eina_Quaternion_F16p16 *out,
220 const Eina_Quaternion_F16p16 *a,
221 const Eina_Quaternion_F16p16 *b,
222 Eina_F16p16 pos)
223{
224 Eina_Quaternion_F16p16 bp, left, right;
225 Eina_Quaternion_F16p16 not_normalize;
226 double dot;
227
228 if (pos == 0)
229 {
230 *out = *a;
231 return ;
232 }
233 else if (pos == eina_f16p16_int_from(1))
234 {
235 *out = *b;
236 return ;
237 }
238
239 dot = eina_quaternion_f16p16_dot(a, b);
240 if (dot >= eina_f16p16_int_from(0))
241 {
242 bp = *b;
243 }
244 else
245 {
246 eina_quaternion_f16p16_negative(&bp, b);
247 dot = -dot;
248 }
249
250 eina_quaternion_f16p16_scale(&left, a,
251 eina_f16p16_sub(eina_f16p16_int_from(1), pos));
252 eina_quaternion_f16p16_scale(&right, b, pos);
253 eina_quaternion_f16p16_add(&not_normalize, &left, &right);
254 eina_quaternion_f16p16_normalized(out, &not_normalize);
255}
256
257EAPI void
258eina_quaternion_f16p16_rotate(Eina_Point_3D_F16p16 *p,
259 const Eina_Point_3D_F16p16 *center,
260 const Eina_Quaternion_F16p16 *q)
261{
262 const Eina_Point_3D_F16p16 zero = { 0, 0, 0 };
263 Eina_F16p16 x, y, z;
264 Eina_F16p16 uvx, uvy, uvz;
265 Eina_F16p16 uuvx, uuvy, uuvz;
266
267 if (!center) center = &zero;
268
269 x = eina_f16p16_sub(p->x, center->x);
270 y = eina_f16p16_sub(p->y, center->y);
271 z = eina_f16p16_sub(p->z, center->z);
272
273 uvx = eina_f16p16_sub(eina_f16p16_mul(q->y, z),
274 eina_f16p16_mul(q->z, y));
275 uvy = eina_f16p16_sub(eina_f16p16_mul(q->z, x),
276 eina_f16p16_mul(q->x, z));
277 uvz = eina_f16p16_sub(eina_f16p16_mul(q->x, y),
278 eina_f16p16_mul(q->y, x));
279
280 uuvx = eina_f16p16_sub(eina_f16p16_mul(q->y, uvz),
281 eina_f16p16_mul(q->z, uvy));
282 uuvy = eina_f16p16_sub(eina_f16p16_mul(q->z, uvx),
283 eina_f16p16_mul(q->x, uvz));
284 uuvz = eina_f16p16_sub(eina_f16p16_mul(q->x, uvy),
285 eina_f16p16_mul(q->y, uvx));
286
287 uvx = eina_f16p16_mul(eina_f16p16_scale(q->w, 2), uvx);
288 uvy = eina_f16p16_mul(eina_f16p16_scale(q->w, 2), uvy);
289 uvz = eina_f16p16_mul(eina_f16p16_scale(q->w, 2), uvz);
290
291 uuvx = eina_f16p16_scale(uuvx, 2);
292 uuvy = eina_f16p16_scale(uuvy, 2);
293 uuvz = eina_f16p16_scale(uuvz, 2);
294
295 p->x = eina_f16p16_add(eina_f16p16_add(center->x, x),
296 eina_f16p16_add(uvx, uuvx));
297 p->y = eina_f16p16_add(eina_f16p16_add(center->y, y),
298 eina_f16p16_add(uvy, uuvy));
299 p->z = eina_f16p16_add(eina_f16p16_add(center->z, z),
300 eina_f16p16_add(uvz, uuvz));
301}
302
303EAPI void
304eina_quaternion_f16p16_rotation_matrix3_get(Eina_Matrix3_F16p16 *m,
305 const Eina_Quaternion_F16p16 *q)
306{
307 Eina_F16p16 x, y, z;
308 Eina_F16p16 xx, xy, xz;
309 Eina_F16p16 yy, yz;
310 Eina_F16p16 zz;
311 Eina_F16p16 wx, wy, wz;
312
313 x = eina_f16p16_scale(q->x, 2);
314 y = eina_f16p16_scale(q->y, 2);
315 z = eina_f16p16_scale(q->z, 2);
316
317 xx = eina_f16p16_mul(q->x, x);
318 xy = eina_f16p16_mul(q->x, y);
319 xz = eina_f16p16_mul(q->x, z);
320 yy = eina_f16p16_mul(q->y, y);
321 yz = eina_f16p16_mul(q->y, z);
322 zz = eina_f16p16_mul(q->z, z);
323 wx = eina_f16p16_mul(q->w, x);
324 wy = eina_f16p16_mul(q->w, y);
325 wz = eina_f16p16_mul(q->w, z);
326
327 m->xx = eina_f16p16_sub(eina_f16p16_int_to(1),
328 eina_f16p16_add(yy, zz));
329 m->xy = eina_f16p16_add(xy, wz);
330 m->xz = eina_f16p16_sub(xz, wy);
331 m->yx = eina_f16p16_sub(xy, wz);
332 m->yy = eina_f16p16_sub(eina_f16p16_int_to(1),
333 eina_f16p16_add(xx, zz));
334 m->yz = eina_f16p16_add(yz, wx);
335 m->zx = eina_f16p16_add(xz, wy);
336 m->zy = eina_f16p16_add(yz, wx);
337 m->zz = eina_f16p16_sub(eina_f16p16_int_to(1),
338 eina_f16p16_add(xx, yy));
339}
340
341EAPI double
342eina_quaternion_norm(const Eina_Quaternion *q)
343{
344 double s;
345
346 s = q->w * q->w + q->x * q->x + q->y * q->y + q->z * q->z;
347
348 return sqrt(s);
349}
350
351EAPI void
352eina_quaternion_negative(Eina_Quaternion *out,
353 const Eina_Quaternion *in)
354{
355 out->w = - in->w;
356 out->x = - in->x;
357 out->y = - in->y;
358 out->z = - in->z;
359}
360
361EAPI void
362eina_quaternion_add(Eina_Quaternion *out,
363 const Eina_Quaternion *a,
364 const Eina_Quaternion *b)
365{
366 out->w = a->w + b->w;
367 out->x = a->x + b->x;
368 out->y = a->y + b->y;
369 out->z = a->z + b->z;
370}
371
372EAPI void
373eina_quaternion_mul(Eina_Quaternion *out,
374 const Eina_Quaternion *a,
375 const Eina_Quaternion *b)
376{
377 out->w = a->w * b->w - a->x * b->x - a->y * b->y - a->z * b->z;
378 out->x = a->w * b->x + a->x * b->w + a->y * b->z - a->z * b->y;
379 out->y = a->w * b->y - a->x * b->z + a->y * b->w + a->z * b->x;
380 out->z = a->w * b->z + a->x * b->y - a->y * b->y + a->z * b->w;
381}
382
383EAPI void
384eina_quaternion_scale(Eina_Quaternion *out,
385 const Eina_Quaternion *a,
386 double b)
387{
388 out->w = a->w * b;
389 out->x = a->x * b;
390 out->y = a->y * b;
391 out->z = a->z * b;
392}
393
394EAPI void
395eina_quaternion_conjugate(Eina_Quaternion *out,
396 const Eina_Quaternion *in)
397{
398 out->w = in->w;
399 out->x = - in->x;
400 out->y = - in->y;
401 out->z = - in->z;
402}
403
404EAPI double
405eina_quaternion_dot(const Eina_Quaternion *a,
406 const Eina_Quaternion *b)
407{
408 return a->w * b->w + a->x * b->x + a->y * b->y + a->z * b->z;
409}
410
411EAPI void
412eina_quaternion_normalized(Eina_Quaternion *out,
413 const Eina_Quaternion *in)
414{
415 double norm;
416
417 norm = eina_quaternion_norm(in);
418 eina_quaternion_scale(out, in, 1.0 / norm);
419}
420
421EAPI void
422eina_quaternion_lerp(Eina_Quaternion *out,
423 const Eina_Quaternion *a,
424 const Eina_Quaternion *b,
425 double pos)
426{
427 if (pos == 0)
428 {
429 *out = *a;
430 return ;
431 }
432 else if (pos == 1.0)
433 {
434 *out = *b;
435 return ;
436 }
437
438 out->w = a->w + pos * (b->w - a->w);
439 out->x = a->x + pos * (b->x - a->x);
440 out->y = a->y + pos * (b->y - a->y);
441 out->z = a->z + pos * (b->z - a->z);
442}
443
444EAPI void
445eina_quaternion_slerp(Eina_Quaternion *out,
446 const Eina_Quaternion *a,
447 const Eina_Quaternion *b,
448 double pos)
449{
450 Eina_Quaternion bp;
451 Eina_Quaternion left, right;
452 double dot;
453 double pos1, pos2;
454
455 if (pos == 0)
456 {
457 *out = *a;
458 return ;
459 }
460 else if (pos == 1.0)
461 {
462 *out = *b;
463 return ;
464 }
465
466 dot = eina_quaternion_dot(a, b);
467 if (dot >= 0)
468 {
469 bp = *b;
470 }
471 else
472 {
473 eina_quaternion_negative(&bp, b);
474 dot = -dot;
475 }
476
477 pos1 = 1.0 - pos;
478 pos2 = pos;
479 if ((1.0 - dot) > 0.0000001)
480 {
481 double angle;
482 double sangle;
483
484 angle = acos(dot);
485 sangle = sin(angle);
486 if (sangle > 0.0000001)
487 {
488 pos1 = sin(pos1 * angle) / sangle;
489 pos2 = sin(pos2 * angle) / sangle;
490 }
491 }
492
493 eina_quaternion_scale(&left, a, pos1);
494 eina_quaternion_scale(&right, b, pos2);
495 eina_quaternion_add(out, &left, &right);
496}
497
498EAPI void
499eina_quaternion_nlerp(Eina_Quaternion *out,
500 const Eina_Quaternion *a,
501 const Eina_Quaternion *b,
502 double pos)
503{
504 Eina_Quaternion bp, left, right;
505 Eina_Quaternion not_normalize;
506 double dot;
507
508 if (pos == 0)
509 {
510 *out = *a;
511 return ;
512 }
513 else if (pos == 1.0)
514 {
515 *out = *b;
516 return ;
517 }
518
519 dot = eina_quaternion_dot(a, b);
520 if (dot >= 0)
521 {
522 bp = *b;
523 }
524 else
525 {
526 eina_quaternion_negative(&bp, b);
527 dot = -dot;
528 }
529
530 eina_quaternion_scale(&left, a, 1.0 - pos);
531 eina_quaternion_scale(&right, b, pos);
532 eina_quaternion_add(&not_normalize, &left, &right);
533 eina_quaternion_normalized(out, &not_normalize);
534}
535
536EAPI void
537eina_quaternion_rotate(Eina_Point_3D *p,
538 const Eina_Point_3D *center,
539 const Eina_Quaternion *q)
540{
541 double x, y, z;
542 double uvx, uvy, uvz;
543 double uuvx, uuvy, uuvz;
544
545 x = p->x - center->x;
546 y = p->y - center->y;
547 z = p->z - center->z;
548
549 uvx = q->y * z - q->z * y;
550 uvy = q->z * x - q->x * z;
551 uvz = q->x * y - q->y * x;
552
553 uuvx = q->y * uvz - q->z * uvy;
554 uuvy = q->z * uvx - q->x * uvz;
555 uuvz = q->x * uvy - q->y * uvx;
556
557 uvx *= (2.0f * q->w);
558 uvy *= (2.0f * q->w);
559 uvz *= (2.0f * q->w);
560
561 uuvx *= 2.0f;
562 uuvy *= 2.0f;
563 uuvz *= 2.0f;
564
565 p->x = center->x + x + uvx + uuvx;
566 p->y = center->y + y + uvy + uuvy;
567 p->z = center->z + z + uvz + uuvz;
568}
569
570EAPI void
571eina_quaternion_rotation_matrix3_get(Eina_Matrix3 *m,
572 const Eina_Quaternion *q)
573{
574 double x, y, z;
575 double xx, xy, xz;
576 double yy, yz;
577 double zz;
578 double wx, wy, wz;
579
580 x = 2.0 * q->x;
581 y = 2.0 * q->y;
582 z = 2.0 * q->z;
583
584 xx = q->x * x;
585 xy = q->x * y;
586 xz = q->x * z;
587 yy = q->y * y;
588 yz = q->y * z;
589 zz = q->z * z;
590 wx = q->w * x;
591 wy = q->w * y;
592 wz = q->w * z;
593
594 m->xx = 1.0 - yy - zz;
595 m->xy = xy + wz;
596 m->xz = xz - wy;
597 m->yx = xy - wz;
598 m->yy = 1.0 - xx - zz;
599 m->yz = yz + wx;
600 m->zx = xz + wy;
601 m->zy = yz - wx;
602 m->zz = 1.0 - xx - yy;
603}
604
605EAPI void
606eina_matrix3_quaternion_get(Eina_Quaternion *q,
607 const Eina_Matrix3 *m)
608{
609}
diff --git a/src/lib/eina/eina_quaternion.h b/src/lib/eina/eina_quaternion.h
new file mode 100644
index 0000000000..7191c96f43
--- /dev/null
+++ b/src/lib/eina/eina_quaternion.h
@@ -0,0 +1,128 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2015 Cedric Bail
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library.
16 * If not, see <http://www.gnu.org/licenses/>.
17 */
18#ifndef EINA_QUATERNION_H_
19#define EINA_QUATERNION_H_
20
21typedef struct _Eina_Quaternion_F16p16 Eina_Quaternion_F16p16;
22typedef struct _Eina_Quaternion Eina_Quaternion;
23typedef struct _Eina_Point_3D Eina_Point_3D;
24typedef struct _Eina_Point_3D_F16p16 Eina_Point_3D_F16p16;
25
26struct _Eina_Quaternion
27{
28 double x;
29 double y;
30 double z;
31 double w;
32};
33
34struct _Eina_Quaternion_F16p16
35{
36 Eina_F16p16 x;
37 Eina_F16p16 y;
38 Eina_F16p16 z;
39 Eina_F16p16 w;
40};
41
42struct _Eina_Point_3D
43{
44 double x;
45 double y;
46 double z;
47};
48
49struct _Eina_Point_3D_F16p16
50{
51 Eina_F16p16 x;
52 Eina_F16p16 y;
53 Eina_F16p16 z;
54};
55
56EAPI Eina_F16p16 eina_quaternion_f16p16_norm(const Eina_Quaternion_F16p16 *q);
57EAPI void eina_quaternion_f16p16_negative(Eina_Quaternion_F16p16 *out,
58 const Eina_Quaternion_F16p16 *in);
59EAPI void eina_quaternion_f16p16_add(Eina_Quaternion_F16p16 *out,
60 const Eina_Quaternion_F16p16 *a,
61 const Eina_Quaternion_F16p16 *b);
62EAPI void eina_quaternion_f16p16_mul(Eina_Quaternion_F16p16 *out,
63 const Eina_Quaternion_F16p16 *a,
64 const Eina_Quaternion_F16p16 *b);
65EAPI void eina_quaternion_f16p16_scale(Eina_Quaternion_F16p16 *out,
66 const Eina_Quaternion_F16p16 *a,
67 Eina_F16p16 b);
68EAPI void eina_quaternion_f16p16_conjugate(Eina_Quaternion_F16p16 *out,
69 const Eina_Quaternion_F16p16 *in);
70EAPI Eina_F16p16 eina_quaternion_f16p16_dot(const Eina_Quaternion_F16p16 *a,
71 const Eina_Quaternion_F16p16 *b);
72EAPI void eina_quaternion_f16p16_lerp(Eina_Quaternion_F16p16 *out,
73 const Eina_Quaternion_F16p16 *a,
74 const Eina_Quaternion_F16p16 *b,
75 Eina_F16p16 pos);
76EAPI void eina_quaternion_f16p16_slerp(Eina_Quaternion_F16p16 *out,
77 const Eina_Quaternion_F16p16 *a,
78 const Eina_Quaternion_F16p16 *b,
79 Eina_F16p16 pos);
80EAPI void eina_quaternion_f16p16_nlerp(Eina_Quaternion_F16p16 *out,
81 const Eina_Quaternion_F16p16 *a,
82 const Eina_Quaternion_F16p16 *b,
83 Eina_F16p16 pos);
84EAPI void eina_quaternion_f16p16_rotate(Eina_Point_3D_F16p16 *p,
85 const Eina_Point_3D_F16p16 *center,
86 const Eina_Quaternion_F16p16 *q);
87EAPI void eina_quaternion_f16p16_rotation_matri3_get(Eina_Matrix3_F16p16 *m,
88 const Eina_Quaternion_F16p16 *q);
89
90EAPI double eina_quaternion_norm(const Eina_Quaternion *q);
91EAPI void eina_quaternion_negative(Eina_Quaternion *out,
92 const Eina_Quaternion *in);
93EAPI void eina_quaternion_add(Eina_Quaternion *out,
94 const Eina_Quaternion *a,
95 const Eina_Quaternion *b);
96EAPI void eina_quaternion_mul(Eina_Quaternion *out,
97 const Eina_Quaternion *a,
98 const Eina_Quaternion *b);
99EAPI void eina_quaternion_scale(Eina_Quaternion *out,
100 const Eina_Quaternion *a,
101 double b);
102EAPI void eina_quaternion_conjugate(Eina_Quaternion *out,
103 const Eina_Quaternion *in);
104EAPI double eina_quaternion_dot(const Eina_Quaternion *a,
105 const Eina_Quaternion *b);
106EAPI void eina_quaternion_normalized(Eina_Quaternion *out,
107 const Eina_Quaternion *in);
108EAPI void eina_quaternion_lerp(Eina_Quaternion *out,
109 const Eina_Quaternion *a,
110 const Eina_Quaternion *b,
111 double pos);
112EAPI void eina_quaternion_slerp(Eina_Quaternion *out,
113 const Eina_Quaternion *a,
114 const Eina_Quaternion *b,
115 double pos);
116EAPI void eina_quaternion_nlerp(Eina_Quaternion *out,
117 const Eina_Quaternion *a,
118 const Eina_Quaternion *b,
119 double pos);
120EAPI void eina_quaternion_rotate(Eina_Point_3D *p,
121 const Eina_Point_3D *center,
122 const Eina_Quaternion *q);
123EAPI void eina_quaternion_rotation_matrix3_get(Eina_Matrix3 *m,
124 const Eina_Quaternion *q);
125EAPI void eina_matrix3_quaternion_get(Eina_Quaternion *q,
126 const Eina_Matrix3 *m);
127
128#endif
diff --git a/src/lib/evas/canvas/evas_map.c b/src/lib/evas/canvas/evas_map.c
index 86ceebeba5..bd7e51b99b 100644
--- a/src/lib/evas/canvas/evas_map.c
+++ b/src/lib/evas/canvas/evas_map.c
@@ -1047,6 +1047,9 @@ EAPI void
1047evas_map_util_quat_rotate(Evas_Map *m, double qx, double qy, double qz, 1047evas_map_util_quat_rotate(Evas_Map *m, double qx, double qy, double qz,
1048 double qw, double cx, double cy, double cz) 1048 double qw, double cx, double cy, double cz)
1049{ 1049{
1050 Eina_Quaternion q;
1051 Eina_Point_3D c;
1052
1050 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); 1053 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
1051 return; 1054 return;
1052 MAGIC_CHECK_END(); 1055 MAGIC_CHECK_END();
@@ -1056,33 +1059,28 @@ evas_map_util_quat_rotate(Evas_Map *m, double qx, double qy, double qz,
1056 p = m->points; 1059 p = m->points;
1057 p_end = p + m->count; 1060 p_end = p + m->count;
1058 1061
1059 for (; p < p_end; p++) 1062 q.x = qx;
1060 { 1063 q.y = qy;
1061 double x, y, z, uvx, uvy, uvz, uuvx, uuvy, uuvz; 1064 q.z = qz;
1062 1065 q.w = qw;
1063 x = p->x - cx;
1064 y = p->y - cy;
1065 z = p->z - cz;
1066 1066
1067 uvx = qy * z - qz * y; 1067 c.x = cx;
1068 uvy = qz * x - qx * z; 1068 c.y = cy;
1069 uvz = qx * y - qy * x; 1069 c.z = cz;
1070 1070
1071 uuvx = qy * uvz - qz * uvy; 1071 for (; p < p_end; p++)
1072 uuvy = qz * uvx - qx * uvz; 1072 {
1073 uuvz = qx * uvy - qy * uvx; 1073 Eina_Point_3D current;
1074 1074
1075 uvx *= (2.0f * qw); 1075 current.x = p->x;
1076 uvy *= (2.0f * qw); 1076 current.y = p->y;
1077 uvz *= (2.0f * qw); 1077 current.z = p->z;
1078 1078
1079 uuvx *= 2.0f; 1079 eina_quaternion_rotate(&current, &c, &q);
1080 uuvy *= 2.0f;
1081 uuvz *= 2.0f;
1082 1080
1083 p->px = p->x = cx + x + uvx + uuvx; 1081 p->px = p->x = current.x;
1084 p->py = p->y = cy + y + uvy + uuvy; 1082 p->py = p->y = current.y;
1085 p->z = cz + z + uvz + uuvz; 1083 p->z = current.z;
1086 } 1084 }
1087} 1085}
1088 1086
diff --git a/src/tests/eina/eina_test_quaternion.c b/src/tests/eina/eina_test_quaternion.c
new file mode 100644
index 0000000000..55e1c9fd4d
--- /dev/null
+++ b/src/tests/eina/eina_test_quaternion.c
@@ -0,0 +1,133 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2015 Cedric Bail
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include <math.h>
24#include <float.h>
25#include <limits.h>
26
27#include "eina_suite.h"
28#include "Eina.h"
29
30#define FLOAT_CMP(a, b) (fabs(a - b) <= DBL_MIN)
31
32static inline Eina_Bool
33eina_quaternion_cmp(const Eina_Quaternion *a, const Eina_Quaternion *b)
34{
35 if (FLOAT_CMP(a->x, b->x) &&
36 FLOAT_CMP(a->y, b->y) &&
37 FLOAT_CMP(a->z, b->z) &&
38 FLOAT_CMP(a->w, b->w))
39 return EINA_TRUE;
40 return EINA_FALSE;
41}
42
43static inline Eina_Bool
44eina_matrix3_cmp(const Eina_Matrix3 *a, const Eina_Matrix3 *b)
45{
46 if (FLOAT_CMP(a->xx, b->xx) &&
47 FLOAT_CMP(a->xy, b->xy) &&
48 FLOAT_CMP(a->xz, b->xz) &&
49 FLOAT_CMP(a->yx, b->yx) &&
50 FLOAT_CMP(a->yy, b->yy) &&
51 FLOAT_CMP(a->yz, b->yz) &&
52 FLOAT_CMP(a->zx, b->zx) &&
53 FLOAT_CMP(a->zy, b->zy) &&
54 FLOAT_CMP(a->zz, b->zz))
55 return EINA_TRUE;
56 return EINA_FALSE;
57}
58
59START_TEST(eina_test_quaternion_norm)
60{
61 static const Eina_Quaternion q = { 1, 3, 4, 5 };
62
63 eina_init();
64
65 fail_if(FLOAT_CMP(eina_quaternion_norm(&q), sqrt(51)));
66
67 eina_shutdown();
68}
69END_TEST
70
71START_TEST(eina_test_quaternion_conjugate)
72{
73 static const Eina_Quaternion q1 = { 1, -1, -1, 3 }, q2 = { 1, 3, 4, 3 };
74 static const Eina_Quaternion r1 = { 1, 1, 1, -3 }, r2 = { 1, -3, -4, -3 };
75 Eina_Quaternion t1, t2;
76
77 eina_init();
78
79 eina_quaternion_conjugate(&t1, &q1);
80 eina_quaternion_conjugate(&t2, &q2);
81
82 fail_if(!eina_quaternion_cmp(&t1, &r1));
83 fail_if(!eina_quaternion_cmp(&t2, &r2));
84
85 eina_shutdown();
86}
87END_TEST
88
89START_TEST(eina_test_quaternion_matrix)
90{
91 Eina_Quaternion q = { 7, 9, 5, 1 };
92 Eina_Matrix3 m = {
93 104, 76, 8,
94 104, -8, -116,
95 -52, 136, -56
96 };
97 Eina_Quaternion tq;
98 Eina_Matrix3 tm;
99
100 eina_init();
101
102 eina_quaternion_rotation_matrix3_get(&tm, &q);
103 fail_if(!eina_matrix3_cmp(&tm, &m));
104
105 eina_shutdown();
106}
107END_TEST
108
109START_TEST(eina_test_quaternion_op)
110{
111 Eina_Quaternion q = { 7, 9, 5, 1 };
112 Eina_Quaternion z = { 0, 0, 0, 0 };
113 Eina_Quaternion neg, r;
114
115 eina_init();
116
117 eina_quaternion_negative(&neg, &q);
118 eina_quaternion_add(&r, &q, &neg);
119
120 fail_if(!eina_quaternion_cmp(&z, &r));
121
122 eina_shutdown();
123}
124END_TEST
125
126void
127eina_test_quaternion(TCase *tc)
128{
129 tcase_add_test(tc, eina_test_quaternion_norm);
130 tcase_add_test(tc, eina_test_quaternion_conjugate);
131 tcase_add_test(tc, eina_test_quaternion_matrix);
132 tcase_add_test(tc, eina_test_quaternion_op);
133}