larb 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +14 -1
- data/ext/larb/color.c +446 -0
- data/ext/larb/color.h +35 -0
- data/ext/larb/extconf.rb +11 -0
- data/ext/larb/larb.c +27 -0
- data/ext/larb/larb.h +8 -0
- data/ext/larb/mat2.c +300 -0
- data/ext/larb/mat2.h +30 -0
- data/ext/larb/mat2d.c +380 -0
- data/ext/larb/mat2d.h +35 -0
- data/ext/larb/mat3.c +469 -0
- data/ext/larb/mat3.h +33 -0
- data/ext/larb/mat4.c +671 -0
- data/ext/larb/mat4.h +31 -0
- data/ext/larb/quat.c +523 -0
- data/ext/larb/quat.h +39 -0
- data/ext/larb/quat2.c +473 -0
- data/ext/larb/quat2.h +39 -0
- data/ext/larb/vec2.c +342 -0
- data/ext/larb/vec2.h +43 -0
- data/ext/larb/vec3.c +503 -0
- data/ext/larb/vec3.h +52 -0
- data/ext/larb/vec4.c +340 -0
- data/ext/larb/vec4.h +38 -0
- data/lib/larb/version.rb +5 -0
- data/lib/larb.rb +2 -14
- data/test/larb/color_test.rb +278 -0
- data/test/larb/mat2_test.rb +144 -0
- data/test/larb/mat2d_test.rb +172 -0
- data/test/larb/mat3_test.rb +147 -0
- data/test/larb/mat4_test.rb +270 -0
- data/test/larb/quat2_test.rb +161 -0
- data/test/larb/quat_test.rb +224 -0
- data/test/larb/vec2_test.rb +251 -0
- data/test/larb/vec3_test.rb +310 -0
- data/test/larb/vec4_test.rb +189 -0
- data/test/test_helper.rb +4 -0
- metadata +53 -14
- data/Rakefile +0 -11
- data/lib/larb/color.rb +0 -148
- data/lib/larb/mat2.rb +0 -119
- data/lib/larb/mat2d.rb +0 -180
- data/lib/larb/mat3.rb +0 -238
- data/lib/larb/mat4.rb +0 -329
- data/lib/larb/quat.rb +0 -238
- data/lib/larb/quat2.rb +0 -193
- data/lib/larb/vec2.rb +0 -150
- data/lib/larb/vec3.rb +0 -218
- data/lib/larb/vec4.rb +0 -125
data/ext/larb/quat.c
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
#include "quat.h"
|
|
2
|
+
|
|
3
|
+
#include <math.h>
|
|
4
|
+
|
|
5
|
+
static void quat_free(void *ptr) {
|
|
6
|
+
xfree(ptr);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static size_t quat_memsize(const void *ptr) {
|
|
10
|
+
return sizeof(QuatData);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static const rb_data_type_t quat_type = {
|
|
14
|
+
"Quat",
|
|
15
|
+
{0, quat_free, quat_memsize},
|
|
16
|
+
0,
|
|
17
|
+
0,
|
|
18
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
static VALUE cQuat = Qnil;
|
|
22
|
+
static VALUE cVec3 = Qnil;
|
|
23
|
+
|
|
24
|
+
static double value_to_double(VALUE value) {
|
|
25
|
+
VALUE coerced = rb_funcall(value, rb_intern("to_f"), 0);
|
|
26
|
+
return NUM2DBL(coerced);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static QuatData *quat_get(VALUE obj) {
|
|
30
|
+
QuatData *data = NULL;
|
|
31
|
+
TypedData_Get_Struct(obj, QuatData, &quat_type, data);
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static VALUE quat_build(VALUE klass, double x, double y, double z, double w) {
|
|
36
|
+
VALUE obj = quat_alloc(klass);
|
|
37
|
+
QuatData *data = quat_get(obj);
|
|
38
|
+
data->x = x;
|
|
39
|
+
data->y = y;
|
|
40
|
+
data->z = z;
|
|
41
|
+
data->w = w;
|
|
42
|
+
return obj;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static double clamp_double(double value, double min, double max) {
|
|
46
|
+
if (value < min) {
|
|
47
|
+
return min;
|
|
48
|
+
}
|
|
49
|
+
if (value > max) {
|
|
50
|
+
return max;
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static void normalize_quat(double *x, double *y, double *z, double *w) {
|
|
56
|
+
double len = sqrt((*x) * (*x) + (*y) * (*y) + (*z) * (*z) + (*w) * (*w));
|
|
57
|
+
*x /= len;
|
|
58
|
+
*y /= len;
|
|
59
|
+
*z /= len;
|
|
60
|
+
*w /= len;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
VALUE quat_alloc(VALUE klass) {
|
|
64
|
+
QuatData *data = ALLOC(QuatData);
|
|
65
|
+
data->x = 0.0;
|
|
66
|
+
data->y = 0.0;
|
|
67
|
+
data->z = 0.0;
|
|
68
|
+
data->w = 1.0;
|
|
69
|
+
return TypedData_Wrap_Struct(klass, &quat_type, data);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
VALUE quat_initialize(int argc, VALUE *argv, VALUE self) {
|
|
73
|
+
VALUE vx = Qnil;
|
|
74
|
+
VALUE vy = Qnil;
|
|
75
|
+
VALUE vz = Qnil;
|
|
76
|
+
VALUE vw = Qnil;
|
|
77
|
+
QuatData *data = quat_get(self);
|
|
78
|
+
|
|
79
|
+
rb_scan_args(argc, argv, "04", &vx, &vy, &vz, &vw);
|
|
80
|
+
data->x = NIL_P(vx) ? 0.0 : value_to_double(vx);
|
|
81
|
+
data->y = NIL_P(vy) ? 0.0 : value_to_double(vy);
|
|
82
|
+
data->z = NIL_P(vz) ? 0.0 : value_to_double(vz);
|
|
83
|
+
data->w = NIL_P(vw) ? 1.0 : value_to_double(vw);
|
|
84
|
+
|
|
85
|
+
return self;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static VALUE quat_class_bracket(VALUE klass, VALUE x, VALUE y, VALUE z,
|
|
89
|
+
VALUE w) {
|
|
90
|
+
return quat_build(klass, value_to_double(x), value_to_double(y),
|
|
91
|
+
value_to_double(z), value_to_double(w));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static VALUE quat_class_identity(VALUE klass) {
|
|
95
|
+
return quat_build(klass, 0.0, 0.0, 0.0, 1.0);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static VALUE quat_class_from_axis_angle(VALUE klass, VALUE axis,
|
|
99
|
+
VALUE radians) {
|
|
100
|
+
double half = value_to_double(radians) * 0.5;
|
|
101
|
+
double s = sin(half);
|
|
102
|
+
VALUE normalized = rb_funcall(axis, rb_intern("normalize"), 0);
|
|
103
|
+
double x = value_to_double(rb_funcall(normalized, rb_intern("x"), 0));
|
|
104
|
+
double y = value_to_double(rb_funcall(normalized, rb_intern("y"), 0));
|
|
105
|
+
double z = value_to_double(rb_funcall(normalized, rb_intern("z"), 0));
|
|
106
|
+
return quat_build(klass, x * s, y * s, z * s, cos(half));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static VALUE quat_class_from_euler(VALUE klass, VALUE x, VALUE y, VALUE z) {
|
|
110
|
+
double rx = value_to_double(x) * 0.5;
|
|
111
|
+
double ry = value_to_double(y) * 0.5;
|
|
112
|
+
double rz = value_to_double(z) * 0.5;
|
|
113
|
+
double cx = cos(rx);
|
|
114
|
+
double sx = sin(rx);
|
|
115
|
+
double cy = cos(ry);
|
|
116
|
+
double sy = sin(ry);
|
|
117
|
+
double cz = cos(rz);
|
|
118
|
+
double sz = sin(rz);
|
|
119
|
+
|
|
120
|
+
return quat_build(klass, sx * cy * cz - cx * sy * sz,
|
|
121
|
+
cx * sy * cz + sx * cy * sz,
|
|
122
|
+
cx * cy * sz - sx * sy * cz,
|
|
123
|
+
cx * cy * cz + sx * sy * sz);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static VALUE quat_class_look_rotation(int argc, VALUE *argv, VALUE klass) {
|
|
127
|
+
VALUE forward = Qnil;
|
|
128
|
+
VALUE up = Qnil;
|
|
129
|
+
rb_scan_args(argc, argv, "11", &forward, &up);
|
|
130
|
+
|
|
131
|
+
VALUE forward_norm = rb_funcall(forward, rb_intern("normalize"), 0);
|
|
132
|
+
VALUE up_vec = NIL_P(up) ? rb_funcall(cVec3, rb_intern("up"), 0) : up;
|
|
133
|
+
VALUE right =
|
|
134
|
+
rb_funcall(rb_funcall(up_vec, rb_intern("cross"), 1, forward_norm),
|
|
135
|
+
rb_intern("normalize"), 0);
|
|
136
|
+
VALUE up_final =
|
|
137
|
+
rb_funcall(forward_norm, rb_intern("cross"), 1, right);
|
|
138
|
+
|
|
139
|
+
double m00 = value_to_double(rb_funcall(right, rb_intern("x"), 0));
|
|
140
|
+
double m01 = value_to_double(rb_funcall(up_final, rb_intern("x"), 0));
|
|
141
|
+
double m02 = value_to_double(rb_funcall(forward_norm, rb_intern("x"), 0));
|
|
142
|
+
double m10 = value_to_double(rb_funcall(right, rb_intern("y"), 0));
|
|
143
|
+
double m11 = value_to_double(rb_funcall(up_final, rb_intern("y"), 0));
|
|
144
|
+
double m12 = value_to_double(rb_funcall(forward_norm, rb_intern("y"), 0));
|
|
145
|
+
double m20 = value_to_double(rb_funcall(right, rb_intern("z"), 0));
|
|
146
|
+
double m21 = value_to_double(rb_funcall(up_final, rb_intern("z"), 0));
|
|
147
|
+
double m22 = value_to_double(rb_funcall(forward_norm, rb_intern("z"), 0));
|
|
148
|
+
|
|
149
|
+
double trace = m00 + m11 + m22;
|
|
150
|
+
if (trace > 0.0) {
|
|
151
|
+
double s = 0.5 / sqrt(trace + 1.0);
|
|
152
|
+
return quat_build(klass, (m21 - m12) * s, (m02 - m20) * s,
|
|
153
|
+
(m10 - m01) * s, 0.25 / s);
|
|
154
|
+
}
|
|
155
|
+
if (m00 > m11 && m00 > m22) {
|
|
156
|
+
double s = 2.0 * sqrt(1.0 + m00 - m11 - m22);
|
|
157
|
+
return quat_build(klass, 0.25 * s, (m01 + m10) / s, (m02 + m20) / s,
|
|
158
|
+
(m21 - m12) / s);
|
|
159
|
+
}
|
|
160
|
+
if (m11 > m22) {
|
|
161
|
+
double s = 2.0 * sqrt(1.0 + m11 - m00 - m22);
|
|
162
|
+
return quat_build(klass, (m01 + m10) / s, 0.25 * s, (m12 + m21) / s,
|
|
163
|
+
(m02 - m20) / s);
|
|
164
|
+
}
|
|
165
|
+
double s = 2.0 * sqrt(1.0 + m22 - m00 - m11);
|
|
166
|
+
return quat_build(klass, (m02 + m20) / s, (m12 + m21) / s, 0.25 * s,
|
|
167
|
+
(m10 - m01) / s);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
static VALUE quat_get_x(VALUE self) {
|
|
171
|
+
QuatData *data = quat_get(self);
|
|
172
|
+
return DBL2NUM(data->x);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static VALUE quat_set_x(VALUE self, VALUE value) {
|
|
176
|
+
QuatData *data = quat_get(self);
|
|
177
|
+
data->x = value_to_double(value);
|
|
178
|
+
return value;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static VALUE quat_get_y(VALUE self) {
|
|
182
|
+
QuatData *data = quat_get(self);
|
|
183
|
+
return DBL2NUM(data->y);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
static VALUE quat_set_y(VALUE self, VALUE value) {
|
|
187
|
+
QuatData *data = quat_get(self);
|
|
188
|
+
data->y = value_to_double(value);
|
|
189
|
+
return value;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static VALUE quat_get_z(VALUE self) {
|
|
193
|
+
QuatData *data = quat_get(self);
|
|
194
|
+
return DBL2NUM(data->z);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
static VALUE quat_set_z(VALUE self, VALUE value) {
|
|
198
|
+
QuatData *data = quat_get(self);
|
|
199
|
+
data->z = value_to_double(value);
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static VALUE quat_get_w(VALUE self) {
|
|
204
|
+
QuatData *data = quat_get(self);
|
|
205
|
+
return DBL2NUM(data->w);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static VALUE quat_set_w(VALUE self, VALUE value) {
|
|
209
|
+
QuatData *data = quat_get(self);
|
|
210
|
+
data->w = value_to_double(value);
|
|
211
|
+
return value;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
VALUE quat_mul(VALUE self, VALUE other) {
|
|
215
|
+
QuatData *a = quat_get(self);
|
|
216
|
+
|
|
217
|
+
if (rb_obj_is_kind_of(other, cQuat)) {
|
|
218
|
+
QuatData *b = quat_get(other);
|
|
219
|
+
return quat_build(
|
|
220
|
+
rb_obj_class(self), a->w * b->x + a->x * b->w + a->y * b->z - a->z * b->y,
|
|
221
|
+
a->w * b->y - a->x * b->z + a->y * b->w + a->z * b->x,
|
|
222
|
+
a->w * b->z + a->x * b->y - a->y * b->x + a->z * b->w,
|
|
223
|
+
a->w * b->w - a->x * b->x - a->y * b->y - a->z * b->z);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (rb_obj_is_kind_of(other, cVec3)) {
|
|
227
|
+
double vx = value_to_double(rb_funcall(other, rb_intern("x"), 0));
|
|
228
|
+
double vy = value_to_double(rb_funcall(other, rb_intern("y"), 0));
|
|
229
|
+
double vz = value_to_double(rb_funcall(other, rb_intern("z"), 0));
|
|
230
|
+
|
|
231
|
+
double uvx = a->y * vz - a->z * vy;
|
|
232
|
+
double uvy = a->z * vx - a->x * vz;
|
|
233
|
+
double uvz = a->x * vy - a->y * vx;
|
|
234
|
+
|
|
235
|
+
double uuvx = a->y * uvz - a->z * uvy;
|
|
236
|
+
double uuvy = a->z * uvx - a->x * uvz;
|
|
237
|
+
double uuvz = a->x * uvy - a->y * uvx;
|
|
238
|
+
|
|
239
|
+
double rx = vx + (uvx * a->w + uuvx) * 2.0;
|
|
240
|
+
double ry = vy + (uvy * a->w + uuvy) * 2.0;
|
|
241
|
+
double rz = vz + (uvz * a->w + uuvz) * 2.0;
|
|
242
|
+
|
|
243
|
+
return rb_funcall(cVec3, rb_intern("new"), 3, DBL2NUM(rx), DBL2NUM(ry),
|
|
244
|
+
DBL2NUM(rz));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (rb_obj_is_kind_of(other, rb_cNumeric)) {
|
|
248
|
+
double s = value_to_double(other);
|
|
249
|
+
return quat_build(rb_obj_class(self), a->x * s, a->y * s, a->z * s,
|
|
250
|
+
a->w * s);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return Qnil;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
VALUE quat_add(VALUE self, VALUE other) {
|
|
257
|
+
QuatData *a = quat_get(self);
|
|
258
|
+
QuatData *b = quat_get(other);
|
|
259
|
+
return quat_build(rb_obj_class(self), a->x + b->x, a->y + b->y,
|
|
260
|
+
a->z + b->z, a->w + b->w);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
VALUE quat_sub(VALUE self, VALUE other) {
|
|
264
|
+
QuatData *a = quat_get(self);
|
|
265
|
+
QuatData *b = quat_get(other);
|
|
266
|
+
return quat_build(rb_obj_class(self), a->x - b->x, a->y - b->y,
|
|
267
|
+
a->z - b->z, a->w - b->w);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
VALUE quat_negate(VALUE self) {
|
|
271
|
+
QuatData *a = quat_get(self);
|
|
272
|
+
return quat_build(rb_obj_class(self), -a->x, -a->y, -a->z, -a->w);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
VALUE quat_dot(VALUE self, VALUE other) {
|
|
276
|
+
QuatData *a = quat_get(self);
|
|
277
|
+
QuatData *b = quat_get(other);
|
|
278
|
+
return DBL2NUM(a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
VALUE quat_length(VALUE self) {
|
|
282
|
+
QuatData *a = quat_get(self);
|
|
283
|
+
return DBL2NUM(sqrt(a->x * a->x + a->y * a->y + a->z * a->z + a->w * a->w));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
VALUE quat_length_squared(VALUE self) {
|
|
287
|
+
QuatData *a = quat_get(self);
|
|
288
|
+
return DBL2NUM(a->x * a->x + a->y * a->y + a->z * a->z + a->w * a->w);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
VALUE quat_normalize(VALUE self) {
|
|
292
|
+
QuatData *a = quat_get(self);
|
|
293
|
+
double x = a->x;
|
|
294
|
+
double y = a->y;
|
|
295
|
+
double z = a->z;
|
|
296
|
+
double w = a->w;
|
|
297
|
+
normalize_quat(&x, &y, &z, &w);
|
|
298
|
+
return quat_build(rb_obj_class(self), x, y, z, w);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
VALUE quat_normalize_bang(VALUE self) {
|
|
302
|
+
QuatData *a = quat_get(self);
|
|
303
|
+
normalize_quat(&a->x, &a->y, &a->z, &a->w);
|
|
304
|
+
return self;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
VALUE quat_conjugate(VALUE self) {
|
|
308
|
+
QuatData *a = quat_get(self);
|
|
309
|
+
return quat_build(rb_obj_class(self), -a->x, -a->y, -a->z, a->w);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
VALUE quat_inverse(VALUE self) {
|
|
313
|
+
QuatData *a = quat_get(self);
|
|
314
|
+
double len_sq = a->x * a->x + a->y * a->y + a->z * a->z + a->w * a->w;
|
|
315
|
+
return quat_build(rb_obj_class(self), -a->x / len_sq, -a->y / len_sq,
|
|
316
|
+
-a->z / len_sq, a->w / len_sq);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
VALUE quat_lerp(VALUE self, VALUE other, VALUE t) {
|
|
320
|
+
QuatData *a = quat_get(self);
|
|
321
|
+
QuatData *b = quat_get(other);
|
|
322
|
+
double s = value_to_double(t);
|
|
323
|
+
double x = a->x + (b->x - a->x) * s;
|
|
324
|
+
double y = a->y + (b->y - a->y) * s;
|
|
325
|
+
double z = a->z + (b->z - a->z) * s;
|
|
326
|
+
double w = a->w + (b->w - a->w) * s;
|
|
327
|
+
normalize_quat(&x, &y, &z, &w);
|
|
328
|
+
return quat_build(rb_obj_class(self), x, y, z, w);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
VALUE quat_slerp(VALUE self, VALUE other, VALUE t) {
|
|
332
|
+
QuatData *a = quat_get(self);
|
|
333
|
+
QuatData *b = quat_get(other);
|
|
334
|
+
double s = value_to_double(t);
|
|
335
|
+
double dot = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
|
|
336
|
+
|
|
337
|
+
double ox = b->x;
|
|
338
|
+
double oy = b->y;
|
|
339
|
+
double oz = b->z;
|
|
340
|
+
double ow = b->w;
|
|
341
|
+
if (dot < 0.0) {
|
|
342
|
+
dot = -dot;
|
|
343
|
+
ox = -ox;
|
|
344
|
+
oy = -oy;
|
|
345
|
+
oz = -oz;
|
|
346
|
+
ow = -ow;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (dot > 0.9995) {
|
|
350
|
+
double x = a->x + (ox - a->x) * s;
|
|
351
|
+
double y = a->y + (oy - a->y) * s;
|
|
352
|
+
double z = a->z + (oz - a->z) * s;
|
|
353
|
+
double w = a->w + (ow - a->w) * s;
|
|
354
|
+
normalize_quat(&x, &y, &z, &w);
|
|
355
|
+
return quat_build(rb_obj_class(self), x, y, z, w);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
double theta0 = acos(clamp_double(dot, -1.0, 1.0));
|
|
359
|
+
double theta = theta0 * s;
|
|
360
|
+
double sin_theta = sin(theta);
|
|
361
|
+
double sin_theta0 = sin(theta0);
|
|
362
|
+
double s0 = cos(theta) - dot * sin_theta / sin_theta0;
|
|
363
|
+
double s1 = sin_theta / sin_theta0;
|
|
364
|
+
|
|
365
|
+
return quat_build(rb_obj_class(self), a->x * s0 + ox * s1,
|
|
366
|
+
a->y * s0 + oy * s1, a->z * s0 + oz * s1,
|
|
367
|
+
a->w * s0 + ow * s1);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
VALUE quat_to_axis_angle(VALUE self) {
|
|
371
|
+
QuatData *a = quat_get(self);
|
|
372
|
+
double w = clamp_double(a->w, -1.0, 1.0);
|
|
373
|
+
double angle = 2.0 * acos(w);
|
|
374
|
+
double s = sqrt(1.0 - w * w);
|
|
375
|
+
VALUE axis;
|
|
376
|
+
if (s < 0.001) {
|
|
377
|
+
axis = rb_funcall(cVec3, rb_intern("new"), 3, DBL2NUM(1.0), DBL2NUM(0.0),
|
|
378
|
+
DBL2NUM(0.0));
|
|
379
|
+
} else {
|
|
380
|
+
axis = rb_funcall(cVec3, rb_intern("new"), 3, DBL2NUM(a->x / s),
|
|
381
|
+
DBL2NUM(a->y / s), DBL2NUM(a->z / s));
|
|
382
|
+
}
|
|
383
|
+
VALUE ary = rb_ary_new_capa(2);
|
|
384
|
+
rb_ary_push(ary, axis);
|
|
385
|
+
rb_ary_push(ary, DBL2NUM(angle));
|
|
386
|
+
return ary;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
VALUE quat_to_euler(VALUE self) {
|
|
390
|
+
QuatData *a = quat_get(self);
|
|
391
|
+
double sinr_cosp = 2.0 * (a->w * a->x + a->y * a->z);
|
|
392
|
+
double cosr_cosp = 1.0 - 2.0 * (a->x * a->x + a->y * a->y);
|
|
393
|
+
double roll = atan2(sinr_cosp, cosr_cosp);
|
|
394
|
+
|
|
395
|
+
double sinp = 2.0 * (a->w * a->y - a->z * a->x);
|
|
396
|
+
double pitch;
|
|
397
|
+
double pi = acos(-1.0);
|
|
398
|
+
if (fabs(sinp) >= 1.0) {
|
|
399
|
+
pitch = copysign(pi / 2.0, sinp);
|
|
400
|
+
} else {
|
|
401
|
+
pitch = asin(sinp);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
double siny_cosp = 2.0 * (a->w * a->z + a->x * a->y);
|
|
405
|
+
double cosy_cosp = 1.0 - 2.0 * (a->y * a->y + a->z * a->z);
|
|
406
|
+
double yaw = atan2(siny_cosp, cosy_cosp);
|
|
407
|
+
|
|
408
|
+
return rb_funcall(cVec3, rb_intern("new"), 3, DBL2NUM(roll), DBL2NUM(pitch),
|
|
409
|
+
DBL2NUM(yaw));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
VALUE quat_to_mat4(VALUE self) {
|
|
413
|
+
VALUE mat4_class = rb_const_get(mLarb, rb_intern("Mat4"));
|
|
414
|
+
return rb_funcall(mat4_class, rb_intern("from_quaternion"), 1, self);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
VALUE quat_to_a(VALUE self) {
|
|
418
|
+
QuatData *a = quat_get(self);
|
|
419
|
+
VALUE ary = rb_ary_new_capa(4);
|
|
420
|
+
rb_ary_push(ary, DBL2NUM(a->x));
|
|
421
|
+
rb_ary_push(ary, DBL2NUM(a->y));
|
|
422
|
+
rb_ary_push(ary, DBL2NUM(a->z));
|
|
423
|
+
rb_ary_push(ary, DBL2NUM(a->w));
|
|
424
|
+
return ary;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
VALUE quat_aref(VALUE self, VALUE index) {
|
|
428
|
+
VALUE ary = quat_to_a(self);
|
|
429
|
+
return rb_ary_entry(ary, NUM2LONG(index));
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
VALUE quat_equal(VALUE self, VALUE other) {
|
|
433
|
+
if (!rb_obj_is_kind_of(other, cQuat)) {
|
|
434
|
+
return Qfalse;
|
|
435
|
+
}
|
|
436
|
+
QuatData *a = quat_get(self);
|
|
437
|
+
QuatData *b = quat_get(other);
|
|
438
|
+
return (a->x == b->x && a->y == b->y && a->z == b->z && a->w == b->w)
|
|
439
|
+
? Qtrue
|
|
440
|
+
: Qfalse;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
VALUE quat_near(int argc, VALUE *argv, VALUE self) {
|
|
444
|
+
VALUE other = Qnil;
|
|
445
|
+
VALUE epsilon = Qnil;
|
|
446
|
+
|
|
447
|
+
rb_scan_args(argc, argv, "11", &other, &epsilon);
|
|
448
|
+
QuatData *a = quat_get(self);
|
|
449
|
+
QuatData *b = quat_get(other);
|
|
450
|
+
double eps = NIL_P(epsilon) ? 1e-6 : value_to_double(epsilon);
|
|
451
|
+
|
|
452
|
+
if (fabs(a->x - b->x) < eps && fabs(a->y - b->y) < eps &&
|
|
453
|
+
fabs(a->z - b->z) < eps && fabs(a->w - b->w) < eps) {
|
|
454
|
+
return Qtrue;
|
|
455
|
+
}
|
|
456
|
+
return Qfalse;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
VALUE quat_inspect(VALUE self) {
|
|
460
|
+
QuatData *a = quat_get(self);
|
|
461
|
+
VALUE sx = rb_funcall(DBL2NUM(a->x), rb_intern("to_s"), 0);
|
|
462
|
+
VALUE sy = rb_funcall(DBL2NUM(a->y), rb_intern("to_s"), 0);
|
|
463
|
+
VALUE sz = rb_funcall(DBL2NUM(a->z), rb_intern("to_s"), 0);
|
|
464
|
+
VALUE sw = rb_funcall(DBL2NUM(a->w), rb_intern("to_s"), 0);
|
|
465
|
+
VALUE str = rb_str_new_cstr("Quat[");
|
|
466
|
+
rb_str_concat(str, sx);
|
|
467
|
+
rb_str_cat_cstr(str, ", ");
|
|
468
|
+
rb_str_concat(str, sy);
|
|
469
|
+
rb_str_cat_cstr(str, ", ");
|
|
470
|
+
rb_str_concat(str, sz);
|
|
471
|
+
rb_str_cat_cstr(str, ", ");
|
|
472
|
+
rb_str_concat(str, sw);
|
|
473
|
+
rb_str_cat_cstr(str, "]");
|
|
474
|
+
return str;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
void Init_quat(VALUE module) {
|
|
478
|
+
cQuat = rb_define_class_under(module, "Quat", rb_cObject);
|
|
479
|
+
cVec3 = rb_const_get(mLarb, rb_intern("Vec3"));
|
|
480
|
+
|
|
481
|
+
rb_define_alloc_func(cQuat, quat_alloc);
|
|
482
|
+
rb_define_method(cQuat, "initialize", quat_initialize, -1);
|
|
483
|
+
|
|
484
|
+
rb_define_singleton_method(cQuat, "[]", quat_class_bracket, 4);
|
|
485
|
+
rb_define_singleton_method(cQuat, "identity", quat_class_identity, 0);
|
|
486
|
+
rb_define_singleton_method(cQuat, "from_axis_angle",
|
|
487
|
+
quat_class_from_axis_angle, 2);
|
|
488
|
+
rb_define_singleton_method(cQuat, "from_euler", quat_class_from_euler, 3);
|
|
489
|
+
rb_define_singleton_method(cQuat, "look_rotation", quat_class_look_rotation,
|
|
490
|
+
-1);
|
|
491
|
+
|
|
492
|
+
rb_define_method(cQuat, "x", quat_get_x, 0);
|
|
493
|
+
rb_define_method(cQuat, "x=", quat_set_x, 1);
|
|
494
|
+
rb_define_method(cQuat, "y", quat_get_y, 0);
|
|
495
|
+
rb_define_method(cQuat, "y=", quat_set_y, 1);
|
|
496
|
+
rb_define_method(cQuat, "z", quat_get_z, 0);
|
|
497
|
+
rb_define_method(cQuat, "z=", quat_set_z, 1);
|
|
498
|
+
rb_define_method(cQuat, "w", quat_get_w, 0);
|
|
499
|
+
rb_define_method(cQuat, "w=", quat_set_w, 1);
|
|
500
|
+
|
|
501
|
+
rb_define_method(cQuat, "*", quat_mul, 1);
|
|
502
|
+
rb_define_method(cQuat, "+", quat_add, 1);
|
|
503
|
+
rb_define_method(cQuat, "-", quat_sub, 1);
|
|
504
|
+
rb_define_method(cQuat, "-@", quat_negate, 0);
|
|
505
|
+
rb_define_method(cQuat, "dot", quat_dot, 1);
|
|
506
|
+
rb_define_method(cQuat, "length", quat_length, 0);
|
|
507
|
+
rb_define_method(cQuat, "length_squared", quat_length_squared, 0);
|
|
508
|
+
rb_define_method(cQuat, "normalize", quat_normalize, 0);
|
|
509
|
+
rb_define_method(cQuat, "normalize!", quat_normalize_bang, 0);
|
|
510
|
+
rb_define_method(cQuat, "conjugate", quat_conjugate, 0);
|
|
511
|
+
rb_define_method(cQuat, "inverse", quat_inverse, 0);
|
|
512
|
+
rb_define_method(cQuat, "lerp", quat_lerp, 2);
|
|
513
|
+
rb_define_method(cQuat, "slerp", quat_slerp, 2);
|
|
514
|
+
rb_define_method(cQuat, "to_axis_angle", quat_to_axis_angle, 0);
|
|
515
|
+
rb_define_method(cQuat, "to_euler", quat_to_euler, 0);
|
|
516
|
+
rb_define_method(cQuat, "to_mat4", quat_to_mat4, 0);
|
|
517
|
+
rb_define_method(cQuat, "to_a", quat_to_a, 0);
|
|
518
|
+
rb_define_method(cQuat, "[]", quat_aref, 1);
|
|
519
|
+
rb_define_method(cQuat, "==", quat_equal, 1);
|
|
520
|
+
rb_define_method(cQuat, "near?", quat_near, -1);
|
|
521
|
+
rb_define_method(cQuat, "inspect", quat_inspect, 0);
|
|
522
|
+
rb_define_alias(cQuat, "to_s", "inspect");
|
|
523
|
+
}
|
data/ext/larb/quat.h
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#ifndef QUAT_H
|
|
2
|
+
#define QUAT_H
|
|
3
|
+
|
|
4
|
+
#include "larb.h"
|
|
5
|
+
|
|
6
|
+
typedef struct {
|
|
7
|
+
double x;
|
|
8
|
+
double y;
|
|
9
|
+
double z;
|
|
10
|
+
double w;
|
|
11
|
+
} QuatData;
|
|
12
|
+
|
|
13
|
+
void Init_quat(VALUE module);
|
|
14
|
+
VALUE quat_alloc(VALUE klass);
|
|
15
|
+
VALUE quat_initialize(int argc, VALUE *argv, VALUE self);
|
|
16
|
+
|
|
17
|
+
VALUE quat_mul(VALUE self, VALUE other);
|
|
18
|
+
VALUE quat_add(VALUE self, VALUE other);
|
|
19
|
+
VALUE quat_sub(VALUE self, VALUE other);
|
|
20
|
+
VALUE quat_negate(VALUE self);
|
|
21
|
+
VALUE quat_dot(VALUE self, VALUE other);
|
|
22
|
+
VALUE quat_length(VALUE self);
|
|
23
|
+
VALUE quat_length_squared(VALUE self);
|
|
24
|
+
VALUE quat_normalize(VALUE self);
|
|
25
|
+
VALUE quat_normalize_bang(VALUE self);
|
|
26
|
+
VALUE quat_conjugate(VALUE self);
|
|
27
|
+
VALUE quat_inverse(VALUE self);
|
|
28
|
+
VALUE quat_lerp(VALUE self, VALUE other, VALUE t);
|
|
29
|
+
VALUE quat_slerp(VALUE self, VALUE other, VALUE t);
|
|
30
|
+
VALUE quat_to_axis_angle(VALUE self);
|
|
31
|
+
VALUE quat_to_euler(VALUE self);
|
|
32
|
+
VALUE quat_to_mat4(VALUE self);
|
|
33
|
+
VALUE quat_to_a(VALUE self);
|
|
34
|
+
VALUE quat_aref(VALUE self, VALUE index);
|
|
35
|
+
VALUE quat_equal(VALUE self, VALUE other);
|
|
36
|
+
VALUE quat_near(int argc, VALUE *argv, VALUE self);
|
|
37
|
+
VALUE quat_inspect(VALUE self);
|
|
38
|
+
|
|
39
|
+
#endif
|