numerix 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }