numerix 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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +5 -0
  4. data/.yardopts +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +66 -0
  9. data/Rakefile +18 -0
  10. data/TODO.txt +25 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/ext/numerix/common.h +107 -0
  14. data/ext/numerix/extconf.rb +3 -0
  15. data/ext/numerix/matrix3x2.c +638 -0
  16. data/ext/numerix/matrix3x2.h +52 -0
  17. data/ext/numerix/matrix4x4.c +1807 -0
  18. data/ext/numerix/matrix4x4.h +90 -0
  19. data/ext/numerix/matrix_base.c +307 -0
  20. data/ext/numerix/matrix_base.h +70 -0
  21. data/ext/numerix/numerix.c +33 -0
  22. data/ext/numerix/numerix.h +19 -0
  23. data/ext/numerix/plane.c +311 -0
  24. data/ext/numerix/plane.h +34 -0
  25. data/ext/numerix/quaternion.c +712 -0
  26. data/ext/numerix/quaternion.h +53 -0
  27. data/ext/numerix/structure.c +154 -0
  28. data/ext/numerix/structure.h +24 -0
  29. data/ext/numerix/vector.c +326 -0
  30. data/ext/numerix/vector.h +57 -0
  31. data/ext/numerix/vector2.c +641 -0
  32. data/ext/numerix/vector2.h +64 -0
  33. data/ext/numerix/vector3.c +805 -0
  34. data/ext/numerix/vector3.h +68 -0
  35. data/ext/numerix/vector4.c +727 -0
  36. data/ext/numerix/vector4.h +63 -0
  37. data/ext/numerix/vector_base.c +94 -0
  38. data/ext/numerix/vector_base.h +30 -0
  39. data/extra/numerix128.png +0 -0
  40. data/extra/numerix24.png +0 -0
  41. data/extra/numerix32.png +0 -0
  42. data/extra/numerix320.png +0 -0
  43. data/extra/numerix48.png +0 -0
  44. data/extra/numerix96.png +0 -0
  45. data/lib/numerix/error.rb +36 -0
  46. data/lib/numerix/matrix3x2.rb +420 -0
  47. data/lib/numerix/matrix4x4.rb +676 -0
  48. data/lib/numerix/matrix_base.rb +14 -0
  49. data/lib/numerix/plane.rb +154 -0
  50. data/lib/numerix/quaternion.rb +355 -0
  51. data/lib/numerix/structure.rb +124 -0
  52. data/lib/numerix/vector.rb +13 -0
  53. data/lib/numerix/vector2.rb +534 -0
  54. data/lib/numerix/vector3.rb +572 -0
  55. data/lib/numerix/vector4.rb +551 -0
  56. data/lib/numerix/vector_base.rb +14 -0
  57. data/lib/numerix/version.rb +6 -0
  58. data/lib/numerix.rb +10 -0
  59. data/numerix.gemspec +30 -0
  60. metadata +167 -0
@@ -0,0 +1,805 @@
1
+
2
+ #include "vector3.h"
3
+
4
+ void Init_vector3(VALUE outer) {
5
+ rb_define_alloc_func(rb_cVector3, rb_vector3_alloc);
6
+
7
+ // Instance Methods
8
+ rb_define_method(rb_cVector3, "initialize", rb_vector3_initialize, -1);
9
+ rb_define_method(rb_cVector3, "length", rb_vector3_length, 0);
10
+ rb_define_method(rb_cVector3, "length_squared", rb_vector3_length_squared, 0);
11
+ rb_define_method(rb_cVector3, "one?", rb_vector3_one_p, 0);
12
+ rb_define_method(rb_cVector3, "zero?", rb_vector3_zero_p, 0);
13
+ rb_define_method(rb_cVector3, "min_value", rb_vector3_min_value, 0);
14
+ rb_define_method(rb_cVector3, "max_value", rb_vector3_max_value, 0);
15
+ rb_define_method(rb_cVector3, "distance", rb_vector3_distance, 1);
16
+ rb_define_method(rb_cVector3, "distance_squared", rb_vector3_distance_squared, 1);
17
+ rb_define_method(rb_cVector3, "normalize", rb_vector3_normalize, 0);
18
+ rb_define_method(rb_cVector3, "normalize!", rb_vector3_normalize_bang, 0);
19
+ rb_define_method(rb_cVector3, "lerp", rb_vector3_lerp, 2);
20
+ rb_define_method(rb_cVector3, "lerp!", rb_vector3_lerp_bang, 2);
21
+ rb_define_method(rb_cVector3, "transform", rb_vector3_transform, 1);
22
+ rb_define_method(rb_cVector3, "transform!", rb_vector3_transform_bang, 1);
23
+ rb_define_method(rb_cVector3, "abs", rb_vector3_abs, 0);
24
+ rb_define_method(rb_cVector3, "sqrt", rb_vector3_sqrt, 0);
25
+ rb_define_method(rb_cVector3, "dot", rb_vector3_dot, 1);
26
+ rb_define_method(rb_cVector3, "clamp", rb_vector3_clamp, 2);
27
+ rb_define_method(rb_cVector3, "clamp!", rb_vector3_clamp_bang, 2);
28
+ rb_define_method(rb_cVector3, "cross", rb_vector3_cross, 1);
29
+ rb_define_method(rb_cVector3, "cross!", rb_vector3_cross_bang, 1);
30
+ rb_define_method(rb_cVector3, "reflect", rb_vector3_reflect, 1);
31
+ rb_define_method(rb_cVector3, "reflect!", rb_vector3_reflect_bang, 1);
32
+ rb_define_method(rb_cVector3, "angle", rb_vector3_angle, 1);
33
+ rb_define_method(rb_cVector3, "transform_normal", rb_vector3_transform_normal, 1);
34
+ rb_define_method(rb_cVector3, "transform_normal!", rb_vector3_transform_normal_bang, 1);
35
+ rb_define_method(rb_cVector3, "map", rb_vector3_map, 0);
36
+ rb_define_method(rb_cVector3, "map!", rb_vector3_map_bang, 0);
37
+
38
+ // Conversion
39
+ rb_define_method(rb_cVector3, "to_s", rb_vector3_to_s, 0);
40
+ rb_define_method(rb_cVector3, "to_a", rb_vector3_to_a, 0);
41
+ rb_define_method(rb_cVector3, "to_h", rb_vector3_to_h, 0);
42
+ rb_define_method(rb_cVector3, "to_quaternion", rb_vector3_to_quaternion, 0);
43
+ rb_define_method(rb_cVector3, "to_plane", rb_vector3_to_plane, 0);
44
+ rb_define_method(rb_cVector3, "to_vec2", rb_vector3_to_vec2, 0);
45
+ rb_define_method(rb_cVector3, "to_vec4", rb_vector3_to_vec4, 0);
46
+
47
+ // Operators
48
+ rb_define_method(rb_cVector3, "+", rb_vector3_add, 1);
49
+ rb_define_method(rb_cVector3, "-", rb_vector3_subtract, 1);
50
+ rb_define_method(rb_cVector3, "*", rb_vector3_multiply, 1);
51
+ rb_define_method(rb_cVector3, "/", rb_vector3_divide, 1);
52
+ rb_define_method(rb_cVector3, "==", rb_vector3_equal, 1);
53
+ rb_define_method(rb_cVector3, "-@", rb_vector3_negate, 0);
54
+ rb_define_method(rb_cVector3, "**", rb_vector3_pow, 1);
55
+
56
+ // Alias
57
+ rb_define_alias(rb_cVector3, "magnitude", "length");
58
+ rb_define_alias(rb_cVector3, "elements", "to_a");
59
+ rb_define_alias(rb_cVector3, "collect", "map");
60
+ rb_define_alias(rb_cVector3, "collect!", "map!");
61
+
62
+ // Singleton Methods
63
+ rb_define_singleton_method(rb_cVector3, "zero", rb_vector3_alloc, 0);
64
+ rb_define_singleton_method(rb_cVector3, "one", rb_vector3_one, 0);
65
+ rb_define_singleton_method(rb_cVector3, "unit_x", rb_vector3_unit_x, 0);
66
+ rb_define_singleton_method(rb_cVector3, "unit_y", rb_vector3_unit_y, 0);
67
+ rb_define_singleton_method(rb_cVector3, "unit_z", rb_vector3_unit_z, 0);
68
+ rb_define_singleton_method(rb_cVector3, "create_norm", rb_vector3_create_norm, 3);
69
+ rb_define_singleton_method(rb_cVector3, "clamp", rb_vector3_clamp_s, 3);
70
+ rb_define_singleton_method(rb_cVector3, "lerp", rb_vector3_lerp_s, 3);
71
+ rb_define_singleton_method(rb_cVector3, "min", rb_vector3_min_s, 2);
72
+ rb_define_singleton_method(rb_cVector3, "max", rb_vector3_max_s, 2);
73
+ }
74
+
75
+ static VALUE rb_vector3_alloc(VALUE klass) {
76
+ void *v = ALLOC(Vector3);
77
+ memset(v, 0, sizeof(Vector3));
78
+ return NUMERIX_WRAP(klass, v);
79
+ }
80
+
81
+ VALUE rb_vector3_initialize(int argc, VALUE *argv, VALUE self) {
82
+ VECTOR3();
83
+ switch (argc) {
84
+ case 0:
85
+ break;
86
+ case 1: {
87
+ float value = NUM2FLT(argv[0]);
88
+ v->x = value;
89
+ v->y = value;
90
+ v->z = value;
91
+ break;
92
+ }
93
+ case 2: {
94
+ Vector2 *v2;
95
+ Data_Get_Struct(argv[0], Vector2, v2);
96
+ v->x = v2->x;
97
+ v->y = v2->y;
98
+ v->z = NUM2FLT(argv[1]);
99
+ break;
100
+ }
101
+ case 3: {
102
+ v->x = NUM2FLT(argv[0]);
103
+ v->y = NUM2FLT(argv[1]);
104
+ v->z = NUM2FLT(argv[2]);
105
+ break;
106
+ }
107
+ default:
108
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 0, 1, 2, 3)", argc);
109
+ break;
110
+ }
111
+ return Qnil;
112
+ }
113
+
114
+ VALUE rb_vector3_one(VALUE klass) {
115
+ Vector3 *v = ALLOC(Vector3);
116
+ v->x = 1.0f;
117
+ v->y = 1.0f;
118
+ v->z = 1.0f;
119
+ return NUMERIX_WRAP(klass, v);
120
+ }
121
+
122
+ VALUE rb_vector3_unit_x(VALUE klass) {
123
+ Vector3 *v = ALLOC(Vector3);
124
+ v->x = 1.0f;
125
+ v->y = 0.0f;
126
+ v->z = 0.0f;
127
+ return NUMERIX_WRAP(klass, v);
128
+ }
129
+
130
+ VALUE rb_vector3_unit_y(VALUE klass) {
131
+ Vector3 *v = ALLOC(Vector3);
132
+ v->x = 0.0f;
133
+ v->y = 1.0f;
134
+ v->z = 0.0f;
135
+ return NUMERIX_WRAP(klass, v);
136
+ }
137
+
138
+ VALUE rb_vector3_unit_z(VALUE klass) {
139
+ Vector3 *v = ALLOC(Vector3);
140
+ v->x = 0.0f;
141
+ v->y = 0.0f;
142
+ v->z = 1.0f;
143
+ return NUMERIX_WRAP(klass, v);
144
+ }
145
+
146
+ VALUE rb_vector3_length(VALUE self) {
147
+ VECTOR3();
148
+ return DBL2NUM(sqrtf(v->x * v->x + v->y * v->y + v->z * v->z));
149
+ }
150
+
151
+ VALUE rb_vector3_length_squared(VALUE self) {
152
+ VECTOR3();
153
+ return DBL2NUM(v->x * v->x + v->y * v->y + v->z * v->z);
154
+ }
155
+
156
+ VALUE rb_vector3_add(VALUE self, VALUE other) {
157
+ Vector3 *v1, *v2, *result;
158
+ Data_Get_Struct(self, Vector3, v1);
159
+ Data_Get_Struct(other, Vector3, v2);
160
+ result = ALLOC(Vector3);
161
+
162
+ result->x = v1->x + v2->x;
163
+ result->y = v1->y + v2->y;
164
+ result->z = v1->z + v2->z;
165
+
166
+ return NUMERIX_WRAP(CLASS_OF(self), result);
167
+ }
168
+
169
+ VALUE rb_vector3_subtract(VALUE self, VALUE other) {
170
+ Vector3 *v1, *v2, *result;
171
+ Data_Get_Struct(self, Vector3, v1);
172
+ Data_Get_Struct(other, Vector3, v2);
173
+ result = ALLOC(Vector3);
174
+
175
+ result->x = v1->x - v2->x;
176
+ result->y = v1->y - v2->y;
177
+ result->z = v1->z - v2->z;
178
+
179
+ return NUMERIX_WRAP(CLASS_OF(self), result);
180
+ }
181
+
182
+ VALUE rb_vector3_multiply(VALUE self, VALUE other) {
183
+ Vector3 *v1, *result;
184
+ Data_Get_Struct(self, Vector3, v1);
185
+ result = ALLOC(Vector3);
186
+
187
+ if (NUMERIX_TYPE_P(other, rb_cVector3)) {
188
+ Vector3 *v2;
189
+ Data_Get_Struct(other, Vector3, v2);
190
+ result->x = v1->x * v2->x;
191
+ result->y = v1->x * v2->y;
192
+ result->z = v1->z * v2->z;
193
+ } else {
194
+ float scalar = NUM2FLT(other);
195
+ result->x = v1->x * scalar;
196
+ result->y = v1->y * scalar;
197
+ result->z = v1->z * scalar;
198
+ }
199
+ return NUMERIX_WRAP(CLASS_OF(self), result);
200
+ }
201
+
202
+ VALUE rb_vector3_divide(VALUE self, VALUE other) {
203
+ Vector3 *v1, *result;
204
+ Data_Get_Struct(self, Vector3, v1);
205
+ result = ALLOC(Vector3);
206
+
207
+ if (NUMERIX_TYPE_P(other, rb_cVector3)) {
208
+ Vector3 *v2;
209
+ Data_Get_Struct(other, Vector3, v2);
210
+ result->x = v1->x / v2->x;
211
+ result->y = v1->y / v2->y;
212
+ result->z = v1->z / v2->z;
213
+ } else {
214
+ float scalar = 1.0f / NUM2FLT(other);
215
+ result->x = v1->x * scalar;
216
+ result->y = v1->y * scalar;
217
+ result->z = v1->z * scalar;
218
+ }
219
+ return NUMERIX_WRAP(CLASS_OF(self), result);
220
+ }
221
+
222
+ VALUE rb_vector3_equal(VALUE self, VALUE other) {
223
+ if (CLASS_OF(other) != CLASS_OF(self))
224
+ return Qfalse;
225
+ Vector3 *v1, *v2;
226
+ Data_Get_Struct(self, Vector3, v1);
227
+ Data_Get_Struct(other, Vector3, v2);
228
+ return FLT_EQUAL(v1->x, v2->x) && FLT_EQUAL(v1->y, v2->y) && FLT_EQUAL(v1->z, v2->z) ? Qtrue : Qfalse;
229
+ }
230
+
231
+ VALUE rb_vector3_pow(VALUE self, VALUE exponent) {
232
+ VECTOR3();
233
+ Vector3 *result = ALLOC(Vector3);
234
+ float e = fabsf(NUM2FLT(exponent));
235
+
236
+ result->x = powf(fabsf(v->x), e);
237
+ result->y = powf(fabsf(v->y), e);
238
+ result->z = powf(fabsf(v->z), e);
239
+
240
+ return NUMERIX_WRAP(CLASS_OF(self), result);
241
+ }
242
+
243
+ VALUE rb_vector3_negate(VALUE self) {
244
+ Vector3 *v, *result;
245
+ Data_Get_Struct(self, Vector3, v);
246
+ result = ALLOC(Vector3);
247
+
248
+ result->x = -v->x;
249
+ result->y = -v->y;
250
+ result->z = -v->z;
251
+
252
+ return NUMERIX_WRAP(CLASS_OF(self), result);
253
+ }
254
+
255
+ VALUE rb_vector3_map(VALUE self) {
256
+ VECTOR3();
257
+ Vector3 *result = ALLOC(Vector3);
258
+
259
+ result->x = NUM2FLT(rb_yield(DBL2NUM(v->x)));
260
+ result->y = NUM2FLT(rb_yield(DBL2NUM(v->y)));
261
+ result->z = NUM2FLT(rb_yield(DBL2NUM(v->z)));
262
+
263
+ return NUMERIX_WRAP(CLASS_OF(self), result);
264
+ }
265
+
266
+ VALUE rb_vector3_map_bang(VALUE self) {
267
+ VECTOR3();
268
+
269
+ v->x = NUM2FLT(rb_yield(DBL2NUM(v->x)));
270
+ v->y = NUM2FLT(rb_yield(DBL2NUM(v->y)));
271
+ v->z = NUM2FLT(rb_yield(DBL2NUM(v->z)));
272
+
273
+ return self;
274
+ }
275
+
276
+ VALUE rb_vector3_to_s(VALUE self) {
277
+ VECTOR3();
278
+ return rb_sprintf("<%f, %f, %f>", v->x, v->y, v->z);
279
+ }
280
+
281
+ VALUE rb_vector3_to_a(VALUE self) {
282
+ VECTOR3();
283
+ VALUE ary = rb_ary_new_capa(3);
284
+ rb_ary_store(ary, 0, DBL2NUM(v->x));
285
+ rb_ary_store(ary, 1, DBL2NUM(v->y));
286
+ rb_ary_store(ary, 2, DBL2NUM(v->z));
287
+ return ary;
288
+ }
289
+
290
+ VALUE rb_vector3_to_h(VALUE self) {
291
+ VECTOR3();
292
+ VALUE hash = rb_hash_new();
293
+ rb_hash_aset(hash, ID2SYM(rb_intern("x")), DBL2NUM(v->x));
294
+ rb_hash_aset(hash, ID2SYM(rb_intern("y")), DBL2NUM(v->y));
295
+ rb_hash_aset(hash, ID2SYM(rb_intern("z")), DBL2NUM(v->z));
296
+ return hash;
297
+ }
298
+
299
+ VALUE rb_vector3_to_vec2(VALUE self) {
300
+ VECTOR3();
301
+ Vector2 *vec = ALLOC(Vector2);
302
+ vec->x = v->x;
303
+ vec->y = v->y;
304
+ return NUMERIX_WRAP(rb_cVector2, vec);
305
+ }
306
+
307
+ VALUE rb_vector3_to_vec4(VALUE self) {
308
+ VECTOR3();
309
+ Vector4 *vec = ALLOC(Vector4);
310
+ vec->x = v->x;
311
+ vec->y = v->y;
312
+ vec->z = v->z;
313
+ vec->w = 0.0f;
314
+ return NUMERIX_WRAP(rb_cVector4, vec);
315
+ }
316
+
317
+ VALUE rb_vector3_to_quaternion(VALUE self) {
318
+ VECTOR3();
319
+ Quaternion *q = ALLOC(Quaternion);
320
+ memcpy(q, v, sizeof(Vector3));
321
+ q->w = 0.0f;
322
+ return NUMERIX_WRAP(rb_cQuaternion, q);
323
+ }
324
+
325
+ VALUE rb_vector3_to_plane(VALUE self) {
326
+ VECTOR3();
327
+ Plane *p = ALLOC(Plane);
328
+ memcpy(p, v, sizeof(Vector3));
329
+ p->distance = 0.0f;
330
+ return NUMERIX_WRAP(rb_cPlane, p);
331
+ }
332
+
333
+ VALUE rb_vector3_min_value(VALUE self) {
334
+ VECTOR3();
335
+ float m = NUMERIX_MIN(v->x, NUMERIX_MIN(v->y, v->z));
336
+ return DBL2NUM(m);
337
+ }
338
+
339
+ VALUE rb_vector3_max_value(VALUE self) {
340
+ VECTOR3();
341
+ float m = NUMERIX_MAX(v->x, NUMERIX_MAX(v->y, v->z));
342
+ return DBL2NUM(m);
343
+ }
344
+
345
+ VALUE rb_vector3_distance(VALUE self, VALUE other) {
346
+ Vector3 *v1, *v2;
347
+ Data_Get_Struct(self, Vector3, v1);
348
+ Data_Get_Struct(other, Vector3, v2);
349
+
350
+ float dx = v1->x - v2->x;
351
+ float dy = v1->y - v2->y;
352
+ float dz = v1->z - v2->z;
353
+
354
+ return DBL2NUM(sqrtf(dx * dx + dy * dy + dz * dz));
355
+ }
356
+
357
+ VALUE rb_vector3_distance_squared(VALUE self, VALUE other) {
358
+ Vector3 *v1, *v2;
359
+ Data_Get_Struct(self, Vector3, v1);
360
+ Data_Get_Struct(other, Vector3, v2);
361
+
362
+ float dx = v1->x - v2->x;
363
+ float dy = v1->y - v2->y;
364
+ float dz = v1->z - v2->z;
365
+
366
+ return DBL2NUM(dx * dx + dy * dy + dz * dz);
367
+ }
368
+
369
+ VALUE rb_vector3_normalize(VALUE self) {
370
+ VECTOR3();
371
+ Vector3 *result = ALLOC(Vector3);
372
+
373
+ float inv = 1.0f / sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
374
+ result->x = v->x * inv;
375
+ result->y = v->y * inv;
376
+ result->z = v->z * inv;
377
+
378
+ return NUMERIX_WRAP(CLASS_OF(self), result);
379
+ }
380
+
381
+ VALUE rb_vector3_lerp(VALUE self, VALUE other, VALUE amount) {
382
+ Vector3 *v1, *v2, *result;
383
+ Data_Get_Struct(self, Vector3, v1);
384
+ Data_Get_Struct(other, Vector3, v2);
385
+ result = ALLOC(Vector3);
386
+
387
+ float w = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
388
+
389
+ result->x = v1->x + (v2->x - v1->x) * w;
390
+ result->y = v1->y + (v2->y - v1->y) * w;
391
+ result->z = v1->z + (v2->z - v1->z) * w;
392
+
393
+ return NUMERIX_WRAP(CLASS_OF(self), result);
394
+ }
395
+
396
+ VALUE rb_vector3_transform(VALUE self, VALUE other) {
397
+ Vector3 *v, *result;
398
+ Data_Get_Struct(self, Vector3, v);
399
+ result = ALLOC(Vector3);
400
+
401
+ if (NUMERIX_TYPE_P(other, rb_cMatrix4x4)) {
402
+ Matrix4x4 *m;
403
+ Data_Get_Struct(other, Matrix4x4, m);
404
+
405
+ result->x = v->x * m->m11 + v->y * m->m21 + v->z * m->m31 + m->m41;
406
+ result->y = v->x * m->m12 + v->y * m->m22 + v->z * m->m32 + m->m42;
407
+ result->z = v->x * m->m13 + v->y * m->m23 + v->z * m->m33 + m->m43;
408
+ } else {
409
+ Quaternion *q;
410
+ Data_Get_Struct(other, Quaternion, q);
411
+
412
+ float x2 = q->x + q->x;
413
+ float y2 = q->y + q->y;
414
+ float z2 = q->z + q->z;
415
+
416
+ float wx2 = q->w * x2;
417
+ float wy2 = q->w * y2;
418
+ float wz2 = q->w * z2;
419
+ float xx2 = q->x * x2;
420
+ float xy2 = q->x * y2;
421
+ float xz2 = q->x * z2;
422
+ float yy2 = q->y * y2;
423
+ float yz2 = q->y * z2;
424
+ float zz2 = q->z * z2;
425
+
426
+ result->x = v->x * (1.0f - yy2 - zz2) + v->y * (xy2 - wz2) + v->z * (xz2 + wy2);
427
+ result->y = v->x * (xy2 + wz2) + v->y * (1.0f - xx2 - zz2) + v->z * (yz2 - wx2);
428
+ result->z = v->x * (xz2 - wy2) + v->y * (yz2 + wx2) + v->z * (1.0f - xx2 - yy2);
429
+ }
430
+
431
+ return NUMERIX_WRAP(CLASS_OF(self), result);
432
+ }
433
+
434
+ VALUE rb_vector3_abs(VALUE self) {
435
+ VECTOR3();
436
+ Vector3 *result = ALLOC(Vector3);
437
+
438
+ result->x = fabsf(v->x);
439
+ result->y = fabsf(v->y);
440
+ result->z = fabsf(v->z);
441
+
442
+ return NUMERIX_WRAP(CLASS_OF(self), result);
443
+ }
444
+
445
+ VALUE rb_vector3_sqrt(VALUE self) {
446
+ VECTOR3();
447
+ Vector3 *result = ALLOC(Vector3);
448
+
449
+ result->x = sqrtf(v->x);
450
+ result->y = sqrtf(v->y);
451
+ result->z = sqrtf(v->z);
452
+
453
+ return NUMERIX_WRAP(CLASS_OF(self), result);
454
+ }
455
+
456
+ VALUE rb_vector3_dot(VALUE self, VALUE other) {
457
+ Vector3 *v1, *v2;
458
+ Data_Get_Struct(self, Vector3, v1);
459
+ Data_Get_Struct(other, Vector3, v2);
460
+
461
+ return DBL2NUM(v1->x * v2->x + v1->y * v2->y + v1->z * v2->z);
462
+ }
463
+
464
+ VALUE rb_vector3_clamp(VALUE self, VALUE min, VALUE max) {
465
+ return rb_vector3_clamp_s(CLASS_OF(self), self, min, max);
466
+ }
467
+
468
+ VALUE rb_vector3_normalize_bang(VALUE self) {
469
+ VECTOR3();
470
+ float inv = 1.0f / sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
471
+ v->x = v->x * inv;
472
+ v->y = v->y * inv;
473
+ v->z = v->z * inv;
474
+
475
+ return self;
476
+ }
477
+
478
+ VALUE rb_vector3_lerp_bang(VALUE self, VALUE other, VALUE amount) {
479
+ Vector3 *v1, *v2;
480
+ Data_Get_Struct(self, Vector3, v1);
481
+ Data_Get_Struct(other, Vector3, v2);
482
+ float w = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
483
+
484
+ v1->x = v1->x + (v2->x - v1->x) * w;
485
+ v1->y = v1->y + (v2->y - v1->y) * w;
486
+ v1->z = v1->z + (v2->z - v1->z) * w;
487
+
488
+ return self;
489
+ }
490
+
491
+ VALUE rb_vector3_transform_bang(VALUE self, VALUE other) {
492
+ VECTOR3();
493
+
494
+ if (NUMERIX_TYPE_P(other, rb_cMatrix4x4)) {
495
+ Matrix4x4 *m;
496
+ Data_Get_Struct(other, Matrix4x4, m);
497
+
498
+ v->x = v->x * m->m11 + v->y * m->m21 + v->z * m->m31 + m->m41;
499
+ v->y = v->x * m->m12 + v->y * m->m22 + v->z * m->m32 + m->m42;
500
+ v->z = v->x * m->m13 + v->y * m->m23 + v->z * m->m33 + m->m43;
501
+ } else {
502
+ Quaternion *q;
503
+ Data_Get_Struct(other, Quaternion, q);
504
+
505
+ float x2 = q->x + q->x;
506
+ float y2 = q->y + q->y;
507
+ float z2 = q->z + q->z;
508
+
509
+ float wx2 = q->w * x2;
510
+ float wy2 = q->w * y2;
511
+ float wz2 = q->w * z2;
512
+ float xx2 = q->x * x2;
513
+ float xy2 = q->x * y2;
514
+ float xz2 = q->x * z2;
515
+ float yy2 = q->y * y2;
516
+ float yz2 = q->y * z2;
517
+ float zz2 = q->z * z2;
518
+
519
+ v->x = v->x * (1.0f - yy2 - zz2) + v->y * (xy2 - wz2) + v->z * (xz2 + wy2);
520
+ v->y = v->x * (xy2 + wz2) + v->y * (1.0f - xx2 - zz2) + v->z * (yz2 - wx2);
521
+ v->z = v->x * (xz2 - wy2) + v->y * (yz2 + wx2) + v->z * (1.0f - xx2 - yy2);
522
+ }
523
+
524
+ return self;
525
+ }
526
+
527
+ VALUE rb_vector3_clamp_bang(VALUE self, VALUE min, VALUE max) {
528
+ struct RData *rdata = RDATA(self);
529
+ VALUE result = rb_vector3_clamp_s(rdata->basic.klass, self, min, max);
530
+ Vector3 *src;
531
+ Data_Get_Struct(result, Vector3, src);
532
+ memcpy(rdata->data, src, sizeof(Vector3));
533
+ return self;
534
+ }
535
+
536
+ VALUE rb_vector3_one_p(VALUE self) {
537
+ VECTOR3();
538
+ return v->x == 1.0f && v->y == 1.0f && v->z == 1.0f ? Qtrue : Qfalse;
539
+ }
540
+
541
+ VALUE rb_vector3_zero_p(VALUE self) {
542
+ VECTOR3();
543
+ return v->x == 0.0f && v->y == 0.0f && v->z == 0.0f ? Qtrue : Qfalse;
544
+ }
545
+
546
+ VALUE rb_vector3_cross(VALUE self, VALUE other) {
547
+ Vector3 *v1, *v2, *result;
548
+ Data_Get_Struct(self, Vector3, v1);
549
+ Data_Get_Struct(other, Vector3, v2);
550
+ result = ALLOC(Vector3);
551
+
552
+ result->x = v1->y * v2->z - v1->z * v2->y;
553
+ result->y = v1->z * v2->x - v1->x * v2->z;
554
+ result->z = v1->x * v2->y - v1->y * v2->x;
555
+
556
+ return NUMERIX_WRAP(CLASS_OF(self), result);
557
+ }
558
+
559
+ VALUE rb_vector3_cross_bang(VALUE self, VALUE other) {
560
+ Vector3 *v1, *v2;
561
+ Data_Get_Struct(self, Vector3, v1);
562
+ Data_Get_Struct(other, Vector3, v2);
563
+
564
+ v1->x = v1->y * v2->z - v1->z * v2->y;
565
+ v1->y = v1->z * v2->x - v1->x * v2->z;
566
+ v1->z = v1->x * v2->y - v1->y * v2->x;
567
+
568
+ return self;
569
+ }
570
+
571
+ VALUE rb_vector3_reflect(VALUE self, VALUE other) {
572
+ Vector3 *v1, *v2, *result;
573
+ Data_Get_Struct(self, Vector3, v1);
574
+ Data_Get_Struct(other, Vector3, v2);
575
+ result = ALLOC(Vector3);
576
+
577
+ float dot = v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
578
+ result->x = v1->x = (v2->x * dot * 2.0f);
579
+ result->y = v1->y = (v2->y * dot * 2.0f);
580
+ result->z = v1->z = (v2->z * dot * 2.0f);
581
+
582
+ return NUMERIX_WRAP(CLASS_OF(self), result);
583
+ }
584
+
585
+ VALUE rb_vector3_reflect_bang(VALUE self, VALUE other) {
586
+ Vector3 *v1, *v2;
587
+ Data_Get_Struct(self, Vector3, v1);
588
+ Data_Get_Struct(other, Vector3, v2);
589
+
590
+ float dot = v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
591
+ v1->x = v1->x = (v2->x * dot * 2.0f);
592
+ v1->y = v1->y = (v2->y * dot * 2.0f);
593
+ v1->z = v1->z = (v2->z * dot * 2.0f);
594
+
595
+ return self;
596
+ }
597
+
598
+ VALUE rb_vector3_angle(VALUE self, VALUE other) {
599
+ Vector3 *v1, *v2, *n1, *n2;
600
+ Data_Get_Struct(self, Vector3, v1);
601
+ Data_Get_Struct(other, Vector3, v2);
602
+
603
+ n1 = ruby_xmalloc(sizeof(Vector3));
604
+ n2 = ruby_xmalloc(sizeof(Vector3));
605
+
606
+ // Create normalized copies of the given vectors
607
+ float inv = 1.0f / sqrtf(v1->x * v1->x + v1->y * v1->y + v1->z * v1->z);
608
+ n1->x = v1->x * inv;
609
+ n1->y = v1->y * inv;
610
+ n1->z = v1->z * inv;
611
+
612
+ inv = 1.0f / sqrtf(v2->x * v2->x + v2->y * v2->y + v2->z * v2->z);
613
+ n2->x = v2->x * inv;
614
+ n2->y = v2->y * inv;
615
+ n2->z = v2->z * inv;
616
+
617
+ float ratio = n1->x * n2->x + n1->y * n2->y + n1->z * n2->z;
618
+
619
+ // The "straight forward" method of acos(u.v) has large precision
620
+ // issues when the dot product is near +/-1. This is due to the
621
+ // steep slope of the acos function as we approach +/- 1. Slight
622
+ // precision errors in the dot product calculation cause large
623
+ // variation in the output value.
624
+ //
625
+ // | |
626
+ // \__ |
627
+ // ---___ |
628
+ // ---___ |
629
+ // ---_|_
630
+ // | ---___
631
+ // | ---___
632
+ // | ---__
633
+ // | \
634
+ // | |
635
+ // -|-------------------+-------------------|-
636
+ // -1 0 1
637
+ //
638
+ // acos(x)
639
+ //
640
+ // To avoid this we use an alternative method which finds the
641
+ // angle bisector by (u-v)/2:
642
+ //
643
+ // _>
644
+ // u _- \ (u-v)/2
645
+ // _- __-v
646
+ // _=__--
647
+ // .=----------->
648
+ // v
649
+ //
650
+ // Because u and v and unit vectors, (u-v)/2 forms a right angle
651
+ // with the angle bisector. The hypotenuse is 1, therefore
652
+ // 2*asin(|u-v|/2) gives us the angle between u and v.
653
+ //
654
+ // The largest possible value of |u-v| occurs with perpendicular
655
+ // vectors and is sqrt(2)/2 which is well away from extreme slope
656
+ // at +/-1.
657
+
658
+ float theta;
659
+ float length, x, y, z;
660
+ if (ratio < 0.0f) {
661
+ // Compute length of difference
662
+ x = -n1->x - n2->x;
663
+ y = -n1->y - n2->y;
664
+ z = -n1->z - n2->z;
665
+ length = sqrtf(x * x + y * y + z * z);
666
+
667
+ theta = NUMERIX_PI - 2.0f * asinf(length / 2.0f);
668
+ } else {
669
+ // Compute length of difference
670
+ x = n1->x - n2->x;
671
+ y = n1->y - n2->y;
672
+ z = n1->z - n2->z;
673
+ length = sqrtf(x * x + y * y + z * z);
674
+
675
+ theta = 2.0f * asinf(length / 2.0f);
676
+ }
677
+
678
+ ruby_xfree(n1);
679
+ ruby_xfree(n2);
680
+
681
+ // Convert radians to degrees and return
682
+ const float rad = 180.0f / NUMERIX_PI;
683
+ return DBL2NUM(theta * rad);
684
+ }
685
+
686
+ VALUE rb_vector3_transform_normal(VALUE self, VALUE matrix) {
687
+ VECTOR3();
688
+ Vector3 *result = ALLOC(Vector3);
689
+ Matrix4x4 *m4;
690
+ Data_Get_Struct(matrix, Matrix4x4, m4);
691
+
692
+ result->x = v->x * m4->m11 + v->y * m4->m21 + v->z * m4->m31;
693
+ result->y = v->x * m4->m12 + v->y * m4->m22 + v->z * m4->m32;
694
+ result->z = v->x * m4->m13 + v->y * m4->m23 + v->z * m4->m33;
695
+
696
+ return NUMERIX_WRAP(CLASS_OF(self), result);
697
+ }
698
+
699
+ VALUE rb_vector3_transform_normal_bang(VALUE self, VALUE matrix) {
700
+ VECTOR3();
701
+ Matrix4x4 *m4;
702
+ Data_Get_Struct(matrix, Matrix4x4, m4);
703
+
704
+ v->x = v->x * m4->m11 + v->y * m4->m21 + v->z * m4->m31;
705
+ v->y = v->x * m4->m12 + v->y * m4->m22 + v->z * m4->m32;
706
+ v->z = v->x * m4->m13 + v->y * m4->m23 + v->z * m4->m33;
707
+
708
+ return self;
709
+ }
710
+
711
+ static inline VALUE rb_vector3_clamp_s(VALUE klass, VALUE vector, VALUE minimum, VALUE maximum) {
712
+ Vector3 *v, *result;
713
+ Data_Get_Struct(vector, Vector3, v);
714
+ result = ALLOC(Vector3);
715
+ float x = v->x, y = v->y, z = v->z;
716
+
717
+ // This compare order is very important!!!
718
+ // We must follow HLSL behavior in the case user specified min value is bigger than max value.
719
+ if (NUMERIX_TYPE_P(minimum, rb_cVector3) && NUMERIX_TYPE_P(maximum, rb_cVector3)) {
720
+ Vector3 *min, *max;
721
+ Data_Get_Struct(minimum, Vector3, min);
722
+ Data_Get_Struct(maximum, Vector3, max);
723
+
724
+ x = NUMERIX_MIN(x, max->x);
725
+ x = NUMERIX_MAX(x, min->x);
726
+
727
+ y = NUMERIX_MIN(y, max->y);
728
+ y = NUMERIX_MAX(y, min->y);
729
+
730
+ z = NUMERIX_MIN(z, max->z);
731
+ z = NUMERIX_MAX(z, min->z);
732
+ } else {
733
+ float minf = NUM2FLT(minimum);
734
+ float maxf = NUM2FLT(maximum);
735
+
736
+ x = NUMERIX_MIN(x, maxf);
737
+ x = NUMERIX_MAX(x, minf);
738
+
739
+ y = NUMERIX_MIN(y, maxf);
740
+ y = NUMERIX_MAX(y, minf);
741
+
742
+ z = NUMERIX_MIN(z, maxf);
743
+ z = NUMERIX_MAX(z, minf);
744
+ }
745
+
746
+ result->x = x;
747
+ result->y = y;
748
+ result->z = z;
749
+ return NUMERIX_WRAP(klass, result);
750
+ }
751
+
752
+ static inline VALUE rb_vector3_lerp_s(VALUE klass, VALUE vec1, VALUE vec2, VALUE amount) {
753
+ Vector3 *v1, *v2, *result;
754
+ Data_Get_Struct(vec1, Vector3, v1);
755
+ Data_Get_Struct(vec2, Vector3, v2);
756
+ result = ALLOC(Vector3);
757
+
758
+ float w = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
759
+
760
+ result->x = v1->x + (v2->x - v1->x) * w;
761
+ result->y = v1->y + (v2->y - v1->y) * w;
762
+ result->z = v1->z + (v2->z - v1->z) * w;
763
+
764
+ return NUMERIX_WRAP(klass, result);
765
+ }
766
+
767
+ static inline VALUE rb_vector3_min_s(VALUE klass, VALUE vec1, VALUE vec2) {
768
+ Vector3 *v1, *v2, *result;
769
+ Data_Get_Struct(vec1, Vector3, v1);
770
+ Data_Get_Struct(vec2, Vector3, v2);
771
+ result = ALLOC(Vector3);
772
+
773
+ result->x = NUMERIX_MIN(v1->x, v2->x);
774
+ result->y = NUMERIX_MIN(v1->y, v2->y);
775
+ result->z = NUMERIX_MIN(v1->z, v2->z);
776
+
777
+ return NUMERIX_WRAP(klass, result);
778
+ }
779
+
780
+ static inline VALUE rb_vector3_max_s(VALUE klass, VALUE vec1, VALUE vec2) {
781
+ Vector3 *v1, *v2, *result;
782
+ Data_Get_Struct(vec1, Vector3, v1);
783
+ Data_Get_Struct(vec2, Vector3, v2);
784
+ result = ALLOC(Vector3);
785
+
786
+ result->x = NUMERIX_MAX(v1->x, v2->x);
787
+ result->y = NUMERIX_MAX(v1->y, v2->y);
788
+ result->z = NUMERIX_MAX(v1->z, v2->z);
789
+
790
+ return NUMERIX_WRAP(klass, result);
791
+ }
792
+
793
+ VALUE rb_vector3_create_norm(VALUE klass, VALUE x, VALUE y, VALUE z) {
794
+ Vector3 *v = ALLOC(Vector3);
795
+ float vx = NUM2FLT(x);
796
+ float vy = NUM2FLT(y);
797
+ float vz = NUM2FLT(z);
798
+
799
+ float inv = 1.0f / sqrtf(vx * vx + vy * vy + vz * vz);
800
+ v->x = vx * inv;
801
+ v->y = vy * inv;
802
+ v->z = vz * inv;
803
+
804
+ return NUMERIX_WRAP(klass, v);
805
+ }