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,638 @@
1
+
2
+ #include "matrix3x2.h"
3
+
4
+ void Init_matrix3x2(VALUE outer) {
5
+ rb_define_alloc_func(rb_cMatrix3x2, rb_matrix3x2_allocate);
6
+ rb_define_method(rb_cMatrix3x2, "initialize", rb_matrix3x2_initialize, -1);
7
+
8
+ // Instance
9
+ rb_define_method(rb_cMatrix3x2, "identity?", rb_matrix3x2_identity_p, 0);
10
+ rb_define_method(rb_cMatrix3x2, "translation", rb_matrix3x2_translation, 0);
11
+ rb_define_method(rb_cMatrix3x2, "translation=", rb_matrix3x2_translation_set, 1);
12
+ rb_define_method(rb_cMatrix3x2, "determinant", rb_matrix3x2_determinant, 0);
13
+ rb_define_method(rb_cMatrix3x2, "row", rb_matrix3x2_row, 1);
14
+ rb_define_method(rb_cMatrix3x2, "column", rb_matrix3x2_column, 1);
15
+ rb_define_method(rb_cMatrix3x2, "each_row", rb_matrix3x2_each_row, 0);
16
+ rb_define_method(rb_cMatrix3x2, "each_column", rb_matrix3x2_each_column, 0);
17
+ rb_define_method(rb_cMatrix3x2, "invert", rb_matrix3x2_invert, 0);
18
+ rb_define_method(rb_cMatrix3x2, "lerp", rb_matrix3x2_lerp, 2);
19
+ rb_define_method(rb_cMatrix3x2, "lerp!", rb_matrix3x2_lerp_bang, 2);
20
+ rb_define_method(rb_cMatrix3x2, "map", rb_matrix3x2_map, 0);
21
+ rb_define_method(rb_cMatrix3x2, "map!", rb_matrix3x2_map_bang, 0);
22
+
23
+ // Alias
24
+ rb_define_alias(rb_cMatrix3x2, "collect", "map");
25
+ rb_define_alias(rb_cMatrix3x2, "collect!", "map!");
26
+
27
+ // Conversion
28
+ rb_define_method(rb_cMatrix3x2, "to_s", rb_matrix3x2_to_s, 0);
29
+ rb_define_method(rb_cMatrix3x2, "to_a", rb_matrix3x2_to_a, 0);
30
+ rb_define_method(rb_cMatrix3x2, "to_h", rb_matrix3x2_to_h, 0);
31
+
32
+ // Operators
33
+ rb_define_method(rb_cMatrix3x2, "-@", rb_matrix3x2_negate, 0);
34
+ rb_define_method(rb_cMatrix3x2, "+", rb_matrix3x2_add, 1);
35
+ rb_define_method(rb_cMatrix3x2, "-", rb_matrix3x2_subtract, 1);
36
+ rb_define_method(rb_cMatrix3x2, "*", rb_matrix3x2_multiply, 1);
37
+ rb_define_method(rb_cMatrix3x2, "==", rb_matrix3x2_equal, 1);
38
+ rb_define_method(rb_cMatrix3x2, "[]", rb_matrix3x2_aref, -1);
39
+ rb_define_method(rb_cMatrix3x2, "[]=", rb_matrix3x2_aset, -1);
40
+ rb_define_method(rb_cMatrix3x2, "**", rb_matrix3x2_pow, 1);
41
+
42
+ // Class
43
+ rb_define_singleton_method(rb_cMatrix3x2, "identity", rb_matrix3x2_identity, 0);
44
+ rb_define_singleton_method(rb_cMatrix3x2, "create_translation", rb_matrix3x2_create_translation, -1);
45
+ rb_define_singleton_method(rb_cMatrix3x2, "create_scale", rb_matrix3x2_create_scale, -1);
46
+ rb_define_singleton_method(rb_cMatrix3x2, "create_skew", rb_matrix3x2_create_skew, -1);
47
+ rb_define_singleton_method(rb_cMatrix3x2, "create_rotation", rb_matrix3x2_create_rotation, -1);
48
+ rb_define_singleton_method(rb_cMatrix3x2, "lerp", rb_matrix3x2_lerp_s, 3);
49
+ }
50
+
51
+ static VALUE rb_matrix3x2_allocate(VALUE klass) {
52
+ Matrix3x2 *m = ALLOC(Matrix3x2);
53
+ memset(m, 0, sizeof(Matrix3x2));
54
+ return NUMERIX_WRAP(klass, m);
55
+ }
56
+
57
+ VALUE rb_matrix3x2_initialize(int argc, VALUE *argv, VALUE self) {
58
+ MATRIX3X2();
59
+ if (argc == 6) {
60
+ m->m11 = NUM2FLT(argv[0]);
61
+ m->m12 = NUM2FLT(argv[1]);
62
+ m->m21 = NUM2FLT(argv[2]);
63
+ m->m22 = NUM2FLT(argv[3]);
64
+ m->m31 = NUM2FLT(argv[4]);
65
+ m->m32 = NUM2FLT(argv[5]);
66
+ } else if (argc != 0)
67
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 0, 6)", argc);
68
+
69
+ return Qnil;
70
+ }
71
+
72
+ VALUE rb_matrix3x2_identity_p(VALUE self) {
73
+ MATRIX3X2();
74
+ // Check diagonal element first for early out.
75
+ return m->m11 == 1.0f && m->m22 == 1.0f && m->m12 == 0.0f &&
76
+ m->m21 == 0.0f && m->m31 == 0.0f && m->m32 == 0.0f
77
+ ? Qtrue
78
+ : Qfalse;
79
+ }
80
+
81
+ VALUE rb_matrix3x2_identity(VALUE klass) {
82
+ Matrix3x2 *m = ALLOC(Matrix3x2);
83
+ m->m11 = 1.0f;
84
+ m->m12 = 0.0f;
85
+ m->m21 = 0.0f;
86
+ m->m22 = 1.0f;
87
+ m->m31 = 0.0f;
88
+ m->m32 = 0.0f;
89
+ return NUMERIX_WRAP(klass, m);
90
+ }
91
+
92
+ VALUE rb_matrix3x2_translation(VALUE self) {
93
+ MATRIX3X2();
94
+ Vector2 *v = ALLOC(Vector2);
95
+ v->x = m->m31;
96
+ v->y = m->m32;
97
+ return NUMERIX_WRAP(rb_cVector2, v);
98
+ }
99
+
100
+ VALUE rb_matrix3x2_translation_set(VALUE self, VALUE value) {
101
+ MATRIX3X2();
102
+ Vector2 *v;
103
+ Data_Get_Struct(value, Vector2, v);
104
+ m->m31 = v->x;
105
+ m->m32 = v->y;
106
+ return value;
107
+ }
108
+
109
+ VALUE rb_matrix3x2_create_translation(int argc, VALUE *argv, VALUE klass) {
110
+ Matrix3x2 *result = ALLOC(Matrix3x2);
111
+
112
+ if (argc == 1) {
113
+ Vector2 *v;
114
+ Data_Get_Struct(argv[0], Vector2, v);
115
+ result->m31 = v->x;
116
+ result->m32 = v->y;
117
+
118
+ } else if (argc == 2) {
119
+ result->m31 = NUM2FLT(argv[0]);
120
+ result->m32 = NUM2FLT(argv[1]);
121
+ } else
122
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2)", argc);
123
+
124
+ result->m11 = 1.0f;
125
+ result->m12 = 0.0f;
126
+ result->m21 = 0.0f;
127
+ result->m22 = 1.0f;
128
+
129
+ return NUMERIX_WRAP(klass, result);
130
+ }
131
+
132
+ VALUE rb_matrix3x2_negate(VALUE self) {
133
+ MATRIX4X4();
134
+ Matrix3x2 *result = ALLOC(Matrix3x2);
135
+
136
+ result->m11 = -m->m11;
137
+ result->m12 = -m->m12;
138
+ result->m21 = -m->m21;
139
+ result->m22 = -m->m22;
140
+ result->m31 = -m->m31;
141
+ result->m32 = -m->m32;
142
+
143
+ return NUMERIX_WRAP(CLASS_OF(self), result);
144
+ }
145
+
146
+ VALUE rb_matrix3x2_add(VALUE self, VALUE other) {
147
+ Matrix3x2 *m1, *m2, *result;
148
+ Data_Get_Struct(self, Matrix3x2, m1);
149
+ Data_Get_Struct(other, Matrix3x2, m2);
150
+ result = ALLOC(Matrix3x2);
151
+
152
+ result->m11 = m1->m11 + m2->m11;
153
+ result->m12 = m1->m12 + m2->m12;
154
+ result->m21 = m1->m21 + m2->m21;
155
+ result->m22 = m1->m22 + m2->m22;
156
+ result->m31 = m1->m31 + m2->m31;
157
+ result->m32 = m1->m32 + m2->m32;
158
+
159
+ return NUMERIX_WRAP(CLASS_OF(self), result);
160
+ }
161
+
162
+ VALUE rb_matrix3x2_subtract(VALUE self, VALUE other) {
163
+ Matrix3x2 *m1, *m2, *result;
164
+ Data_Get_Struct(self, Matrix3x2, m1);
165
+ Data_Get_Struct(other, Matrix3x2, m2);
166
+ result = ALLOC(Matrix3x2);
167
+
168
+ result->m11 = m1->m11 - m2->m11;
169
+ result->m12 = m1->m12 - m2->m12;
170
+ result->m21 = m1->m21 - m2->m21;
171
+ result->m22 = m1->m22 - m2->m22;
172
+ result->m31 = m1->m31 - m2->m31;
173
+ result->m32 = m1->m32 - m2->m32;
174
+
175
+ return NUMERIX_WRAP(CLASS_OF(self), result);
176
+ }
177
+
178
+ VALUE rb_matrix3x2_multiply(VALUE self, VALUE other) {
179
+ Matrix3x2 *m1, *result;
180
+ Data_Get_Struct(self, Matrix3x2, m1);
181
+ result = ALLOC(Matrix3x2);
182
+ VALUE klass = CLASS_OF(self);
183
+ if (NUMERIX_TYPE_P(other, klass)) {
184
+ Matrix3x2 *m2, *result;
185
+ Data_Get_Struct(other, Matrix3x2, m2);
186
+
187
+ // First row
188
+ result->m11 = m1->m11 * m2->m11 + m1->m12 * m2->m21;
189
+ result->m12 = m1->m11 * m2->m12 + m1->m12 * m2->m22;
190
+
191
+ // Second row
192
+ result->m21 = m1->m21 * m2->m11 + m1->m22 * m2->m21;
193
+ result->m22 = m1->m21 * m2->m12 + m1->m22 * m2->m22;
194
+
195
+ // Third row
196
+ result->m31 = m1->m31 * m2->m11 + m1->m32 * m2->m21 + m2->m31;
197
+ result->m32 = m1->m31 * m2->m12 + m1->m32 * m2->m22 + m2->m32;
198
+ } else {
199
+ float scalar = NUM2FLT(other);
200
+ result->m11 = m1->m11 * scalar;
201
+ result->m12 = m1->m12 * scalar;
202
+ result->m21 = m1->m21 * scalar;
203
+ result->m22 = m1->m22 * scalar;
204
+ result->m31 = m1->m31 * scalar;
205
+ result->m32 = m1->m32 * scalar;
206
+ }
207
+
208
+ return NUMERIX_WRAP(klass, result);
209
+ }
210
+
211
+ VALUE rb_matrix3x2_pow(VALUE self, VALUE exponent) {
212
+ struct RData *rdata = RDATA(self);
213
+ const int count = 6;
214
+ float *result = ruby_xmalloc(sizeof(float) * count);
215
+ float *m = (float *)rdata->data;
216
+ float e = fabsf(NUM2FLT(exponent));
217
+ for (int i = 0; i < count; i++)
218
+ result[i] = powf(fabsf(m[i]), e);
219
+
220
+ return NUMERIX_WRAP(rdata->basic.klass, result);
221
+ }
222
+
223
+ VALUE rb_matrix3x2_equal(VALUE self, VALUE other) {
224
+ if (CLASS_OF(other) != CLASS_OF(self))
225
+ return Qfalse;
226
+ Matrix3x2 *m1, *m2;
227
+ Data_Get_Struct(self, Matrix3x2, m1);
228
+ Data_Get_Struct(other, Matrix3x2, m2);
229
+ return FLT_EQUAL(m1->m11, m2->m11) && FLT_EQUAL(m1->m12, m2->m12) &&
230
+ FLT_EQUAL(m1->m21, m2->m21) && FLT_EQUAL(m1->m22, m2->m22) &&
231
+ FLT_EQUAL(m1->m31, m2->m31) && FLT_EQUAL(m1->m32, m2->m32)
232
+ ? Qtrue
233
+ : Qfalse;
234
+ }
235
+
236
+ VALUE rb_matrix3x2_row(VALUE self, VALUE row) {
237
+ MATRIX3X2();
238
+ VALUE args = rb_ary_new_capa(4);
239
+ int r = NUM2INT(row);
240
+ switch (r) {
241
+ case 0: {
242
+ rb_ary_push(args, DBL2NUM(m->m11));
243
+ rb_ary_push(args, DBL2NUM(m->m12));
244
+ break;
245
+ }
246
+ case 1: {
247
+ rb_ary_push(args, DBL2NUM(m->m21));
248
+ rb_ary_push(args, DBL2NUM(m->m22));
249
+ break;
250
+ }
251
+ case 2: {
252
+ rb_ary_push(args, DBL2NUM(m->m31));
253
+ rb_ary_push(args, DBL2NUM(m->m32));
254
+ break;
255
+ }
256
+ default:
257
+ break;
258
+ }
259
+ return args;
260
+ }
261
+
262
+ VALUE rb_matrix3x2_column(VALUE self, VALUE column) {
263
+ MATRIX3X2();
264
+ VALUE args = rb_ary_new_capa(3);
265
+ int c = NUM2INT(column);
266
+ if (c == 0) {
267
+ rb_ary_push(args, DBL2NUM(m->m11));
268
+ rb_ary_push(args, DBL2NUM(m->m21));
269
+ rb_ary_push(args, DBL2NUM(m->m31));
270
+ } else if (c == 1) {
271
+ rb_ary_push(args, DBL2NUM(m->m12));
272
+ rb_ary_push(args, DBL2NUM(m->m22));
273
+ rb_ary_push(args, DBL2NUM(m->m32));
274
+ }
275
+ return args;
276
+ }
277
+
278
+ VALUE rb_matrix3x2_map(VALUE self) {
279
+ const int count = 6;
280
+ RETURN_SIZED_ENUMERATOR(self, 0, 0, count);
281
+
282
+ struct RData *rdata = RDATA(self);
283
+ float *flt = (float *)rdata->data;
284
+ float *result = (float *)ruby_xmalloc(count * sizeof(float));
285
+
286
+ for (int i = 0; i < count; i++)
287
+ result[i] = NUM2FLT(rb_yield(DBL2NUM(flt[i])));
288
+
289
+ return NUMERIX_WRAP(rdata->basic.klass, result);
290
+ }
291
+
292
+ VALUE rb_matrix3x2_map_bang(VALUE self) {
293
+ const int count = 6;
294
+ RETURN_SIZED_ENUMERATOR(self, 0, 0, count);
295
+
296
+ float *flt = (float *)RDATA(self)->data;
297
+ for (int i = 0; i < count; i++)
298
+ flt[i] = NUM2FLT(rb_yield(DBL2NUM(flt[i])));
299
+
300
+ return self;
301
+ }
302
+
303
+ VALUE rb_matrix3x2_to_s(VALUE self) {
304
+ MATRIX3X2();
305
+ return rb_sprintf("{{%f, %f}, {%f, %f}, {%f, %f}}", m->m11, m->m12, m->m21, m->m22, m->m31, m->m32);
306
+ }
307
+
308
+ VALUE rb_matrix3x2_to_a(VALUE self) {
309
+ MATRIX3X2();
310
+ VALUE array = rb_ary_new_capa(3);
311
+ // Row 1
312
+ VALUE r1 = rb_ary_new_capa(2);
313
+ rb_ary_store(r1, 0, DBL2NUM(m->m11));
314
+ rb_ary_store(r1, 1, DBL2NUM(m->m12));
315
+ rb_ary_push(array, r1);
316
+ // Row 2
317
+ VALUE r2 = rb_ary_new_capa(2);
318
+ rb_ary_store(r2, 0, DBL2NUM(m->m21));
319
+ rb_ary_store(r2, 1, DBL2NUM(m->m22));
320
+ rb_ary_push(array, r2);
321
+ // Row 3
322
+ VALUE r3 = rb_ary_new_capa(2);
323
+ rb_ary_store(r3, 0, DBL2NUM(m->m31));
324
+ rb_ary_store(r3, 1, DBL2NUM(m->m32));
325
+ rb_ary_push(array, r3);
326
+ return array;
327
+ }
328
+
329
+ VALUE rb_matrix3x2_to_h(VALUE self) {
330
+ MATRIX3X2();
331
+ VALUE hash = rb_hash_new();
332
+ rb_hash_aset(hash, ID2SYM(rb_intern("m11")), DBL2NUM(m->m11));
333
+ rb_hash_aset(hash, ID2SYM(rb_intern("m12")), DBL2NUM(m->m12));
334
+ rb_hash_aset(hash, ID2SYM(rb_intern("m21")), DBL2NUM(m->m21));
335
+ rb_hash_aset(hash, ID2SYM(rb_intern("m22")), DBL2NUM(m->m22));
336
+ rb_hash_aset(hash, ID2SYM(rb_intern("m31")), DBL2NUM(m->m31));
337
+ rb_hash_aset(hash, ID2SYM(rb_intern("m32")), DBL2NUM(m->m32));
338
+ return hash;
339
+ }
340
+
341
+ VALUE rb_matrix3x2_create_scale(int argc, VALUE *argv, VALUE klass) {
342
+ Matrix3x2 *result = ALLOC(Matrix3x2);
343
+ result->m12 = 0.0f;
344
+ result->m21 = 0.0f;
345
+ switch (argc) {
346
+ case 1: {
347
+ result->m31 = 0.0f;
348
+ result->m32 = 0.0f;
349
+ if (NUMERIX_TYPE_P(argv[0], rb_cVector2)) {
350
+ Vector2 *vscale;
351
+ Data_Get_Struct(argv[0], Vector2, vscale);
352
+ result->m11 = vscale->x;
353
+ result->m22 = vscale->y;
354
+ } else {
355
+ float scale = NUM2FLT(argv[0]);
356
+ result->m11 = scale;
357
+ result->m22 = scale;
358
+ }
359
+ }
360
+ case 2: {
361
+ if (NUMERIX_TYPE_P(argv[0], rb_cVector2)) {
362
+ Vector2 *v1, *v2;
363
+ Data_Get_Struct(argv[0], Vector2, v1);
364
+ Data_Get_Struct(argv[1], Vector2, v2);
365
+ result->m11 = v1->x;
366
+ result->m22 = v1->y;
367
+ result->m31 = v2->x * (1.0f - v1->x);
368
+ result->m32 = v2->y * (1.0f - v1->y);
369
+ } else {
370
+ if (NUMERIX_TYPE_P(argv[1], rb_cVector2)) {
371
+ float s = NUM2FLT(argv[0]);
372
+ Vector2 *cp;
373
+ Data_Get_Struct(argv[1], Vector2, cp);
374
+ result->m11 = s;
375
+ result->m22 = s;
376
+ result->m31 = cp->x * (1.0f - s);
377
+ result->m32 = cp->y * (1.0f - s);
378
+ } else {
379
+ result->m11 = NUM2FLT(argv[0]);
380
+ result->m22 = NUM2FLT(argv[1]);
381
+ result->m31 = 0.0f;
382
+ result->m32 = 0.0f;
383
+ }
384
+ }
385
+ break;
386
+ }
387
+ case 3: {
388
+ Vector2 *vec2;
389
+ Data_Get_Struct(argv[2], Vector2, vec2);
390
+ float xscale = NUM2FLT(argv[0]);
391
+ float yscale = NUM2FLT(argv[1]);
392
+
393
+ result->m11 = xscale;
394
+ result->m22 = yscale;
395
+ result->m31 = vec2->x * (1.0f - xscale);
396
+ result->m32 = vec2->y * (1.0f - yscale);
397
+ }
398
+ default:
399
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2, 3)", argc);
400
+ }
401
+
402
+ return NUMERIX_WRAP(klass, result);
403
+ }
404
+
405
+ VALUE rb_matrix3x2_create_skew(int argc, VALUE *argv, VALUE klass) {
406
+ if (argc != 2 && argc != 3)
407
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3)", argc);
408
+
409
+ Matrix3x2 *result = ALLOC(Matrix3x2);
410
+
411
+ float xTan = tanf(NUM2FLT(argv[0]));
412
+ float yTan = tanf(NUM2FLT(argv[1]));
413
+
414
+ result->m12 = yTan;
415
+ result->m21 = xTan;
416
+ result->m11 = 1.0f;
417
+ result->m22 = 1.0f;
418
+
419
+ if (argc == 3) {
420
+ Vector2 *cp;
421
+ Data_Get_Struct(argv[2], Vector2, cp);
422
+ result->m31 = -cp->x * xTan;
423
+ result->m32 = -cp->y * yTan;
424
+ } else {
425
+ result->m31 = 0.0f;
426
+ result->m32 = 0.0f;
427
+ }
428
+
429
+ return NUMERIX_WRAP(klass, result);
430
+ }
431
+
432
+ VALUE rb_matrix3x2_create_rotation(int argc, VALUE *argv, VALUE klass) {
433
+ if (argc != 1 && argc != 2)
434
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2)", argc);
435
+
436
+ Matrix3x2 *result = ALLOC(Matrix3x2);
437
+ float radians = remainderf(NUM2FLT(argv[0]), NUMERIX_PI * 2.0f);
438
+ const float epsilon = 0.001f * NUMERIX_PI / 180.0f; // 0.1% of a degree
439
+ float c, s;
440
+
441
+ if (radians > -epsilon && radians < epsilon) {
442
+ // Exact case for zero rotation.
443
+ c = 1;
444
+ s = 0;
445
+ } else if (radians > NUMERIX_HALF_PI - epsilon && radians < NUMERIX_HALF_PI + epsilon) {
446
+ // Exact case for 90 degree rotation.
447
+ c = 0;
448
+ s = 1;
449
+ } else if (radians < -NUMERIX_PI + epsilon || radians > NUMERIX_PI - epsilon) {
450
+ // Exact case for 180 degree rotation.
451
+ c = -1;
452
+ s = 0;
453
+ } else if (radians > -NUMERIX_HALF_PI - epsilon && radians < -NUMERIX_HALF_PI + epsilon) {
454
+ // Exact case for 270 degree rotation.
455
+ c = 0;
456
+ s = -1;
457
+ } else {
458
+ // Arbitrary rotation.
459
+ c = cosf(radians);
460
+ s = sinf(radians);
461
+ }
462
+
463
+ // [ c s ]
464
+ // [ -s c ]
465
+ // [ 0 0 ]
466
+ result->m11 = c;
467
+ result->m12 = s;
468
+ result->m21 = -s;
469
+ result->m22 = c;
470
+ if (argc == 2) {
471
+ Vector2 *cp;
472
+ Data_Get_Struct(argv[1], Vector2, cp);
473
+ result->m31 = cp->x * (1.0f - c) + cp->y * s;
474
+ result->m32 = cp->y * (1.0f - c) - cp->x * s;
475
+ } else {
476
+ result->m31 = 0.0f;
477
+ result->m32 = 0.0f;
478
+ }
479
+
480
+ return NUMERIX_WRAP(klass, result);
481
+ }
482
+
483
+ VALUE rb_matrix3x2_determinant(VALUE self) {
484
+ MATRIX3X2();
485
+ // There isn't actually any such thing as a determinant for a non-square matrix,
486
+ // but this 3x2 type is really just an optimization of a 3x3 where we happen to
487
+ // know the rightmost column is always (0, 0, 1). So we expand to 3x3 format:
488
+ //
489
+ // [ M11, M12, 0 ]
490
+ // [ M21, M22, 0 ]
491
+ // [ M31, M32, 1 ]
492
+ //
493
+ // Sum the diagonal products:
494
+ // (M11 * M22 * 1) + (M12 * 0 * M31) + (0 * M21 * M32)
495
+ //
496
+ // Subtract the opposite diagonal products:
497
+ // (M31 * M22 * 0) + (M32 * 0 * M11) + (1 * M21 * M12)
498
+ //
499
+ // Collapse out the constants and oh look, this is just a 2x2 determinant!
500
+ return DBL2NUM((m->m11 * m->m22) - (m->m21 * m->m12));
501
+ }
502
+
503
+ VALUE rb_matrix3x2_each_row(VALUE self) {
504
+ MATRIX3X2();
505
+ for (int i = 0; i < 3; i++) {
506
+ VALUE index = INT2NUM(i);
507
+ rb_yield(rb_matrix3x2_row(self, index));
508
+ }
509
+ return self;
510
+ }
511
+
512
+ VALUE rb_matrix3x2_each_column(VALUE self) {
513
+ MATRIX3X2();
514
+ for (int i = 0; i < 2; i++) {
515
+ VALUE index = INT2NUM(i);
516
+ rb_yield(rb_matrix3x2_column(self, index));
517
+ }
518
+ return self;
519
+ }
520
+
521
+ VALUE rb_matrix3x2_aref(int argc, VALUE *argv, VALUE self) {
522
+ if (argc == 1) {
523
+ return rb_call_super(1, argv);
524
+ } else if (argc == 2) {
525
+ int r = NUM2INT(argv[0]);
526
+ int c = NUM2INT(argv[1]);
527
+ if (r < 0 || r > 2 || c < 0 || c > 1)
528
+ return Qnil;
529
+ VALUE arg = INT2NUM(r + (c * 4));
530
+ return rb_call_super(1, &arg);
531
+ }
532
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2)", argc);
533
+ return Qnil;
534
+ }
535
+
536
+ VALUE rb_matrix3x2_aset(int argc, VALUE *argv, VALUE self) {
537
+ if (argc == 2) {
538
+ return rb_call_super(2, argv);
539
+ } else if (argc == 3) {
540
+ int r = NUM2INT(argv[0]);
541
+ int c = NUM2INT(argv[1]);
542
+ if (r < 0 || r > 2 || c < 0 || c > 1)
543
+ return Qnil;
544
+ argv[1] = INT2NUM(r + (c * 3));
545
+ return rb_call_super(2, &argv[1]);
546
+ }
547
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 2, 3)", argc);
548
+ return Qnil;
549
+ }
550
+
551
+ VALUE rb_matrix3x2_invert(VALUE self) {
552
+ Matrix3x2 *m, *result;
553
+ Data_Get_Struct(self, Matrix3x2, m);
554
+ result = ALLOC(Matrix3x2);
555
+
556
+ float det = (m->m11 * m->m22) - (m->m21 * m->m12);
557
+
558
+ if (fabsf(det) < FLT_EPSILON) {
559
+ float *ptr = (float *)result;
560
+ for (int i = 0; i < 6; i++)
561
+ ptr[i] = NAN;
562
+ } else {
563
+ float invDet = 1.0f / det;
564
+ result->m11 = m->m22 * invDet;
565
+ result->m12 = -m->m12 * invDet;
566
+ result->m21 = -m->m21 * invDet;
567
+ result->m22 = m->m11 * invDet;
568
+ result->m31 = (m->m21 * m->m32 - m->m31 * m->m22) * invDet;
569
+ result->m32 = (m->m31 * m->m12 - m->m11 * m->m32) * invDet;
570
+ }
571
+
572
+ return NUMERIX_WRAP(CLASS_OF(self), result);
573
+ }
574
+
575
+ VALUE rb_matrix3x2_lerp(VALUE self, VALUE other, VALUE amount) {
576
+ Matrix3x2 *m1, *m2, *result;
577
+ Data_Get_Struct(self, Matrix3x2, m1);
578
+ Data_Get_Struct(other, Matrix3x2, m2);
579
+ result = ALLOC(Matrix3x2);
580
+
581
+ float weight = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
582
+ // First row
583
+ result->m11 = m1->m11 + (m2->m11 - m1->m11) * weight;
584
+ result->m12 = m1->m12 + (m2->m12 - m1->m12) * weight;
585
+
586
+ // Second row
587
+ result->m21 = m1->m21 + (m2->m21 - m1->m21) * weight;
588
+ result->m22 = m1->m22 + (m2->m22 - m1->m22) * weight;
589
+
590
+ // Third row
591
+ result->m31 = m1->m31 + (m2->m31 - m1->m31) * weight;
592
+ result->m32 = m1->m32 + (m2->m32 - m1->m32) * weight;
593
+
594
+ return NUMERIX_WRAP(CLASS_OF(self), result);
595
+ }
596
+
597
+ VALUE rb_matrix3x2_lerp_bang(VALUE self, VALUE other, VALUE amount) {
598
+ Matrix3x2 *m1, *m2;
599
+ Data_Get_Struct(self, Matrix3x2, m1);
600
+ Data_Get_Struct(other, Matrix3x2, m2);
601
+
602
+ float weight = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
603
+ // First row
604
+ m1->m11 = m1->m11 + (m2->m11 - m1->m11) * weight;
605
+ m1->m12 = m1->m12 + (m2->m12 - m1->m12) * weight;
606
+
607
+ // Second row
608
+ m1->m21 = m1->m21 + (m2->m21 - m1->m21) * weight;
609
+ m1->m22 = m1->m22 + (m2->m22 - m1->m22) * weight;
610
+
611
+ // Third row
612
+ m1->m31 = m1->m31 + (m2->m31 - m1->m31) * weight;
613
+ m1->m32 = m1->m32 + (m2->m32 - m1->m32) * weight;
614
+
615
+ return self;
616
+ }
617
+
618
+ static inline VALUE rb_matrix3x2_lerp_s(VALUE klass, VALUE matrix1, VALUE matrix2, VALUE amount) {
619
+ Matrix3x2 *m1, *m2, *result;
620
+ Data_Get_Struct(matrix1, Matrix3x2, m1);
621
+ Data_Get_Struct(matrix2, Matrix3x2, m2);
622
+ result = ALLOC(Matrix3x2);
623
+
624
+ float weight = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
625
+ // First row
626
+ result->m11 = m1->m11 + (m2->m11 - m1->m11) * weight;
627
+ result->m12 = m1->m12 + (m2->m12 - m1->m12) * weight;
628
+
629
+ // Second row
630
+ result->m21 = m1->m21 + (m2->m21 - m1->m21) * weight;
631
+ result->m22 = m1->m22 + (m2->m22 - m1->m22) * weight;
632
+
633
+ // Third row
634
+ result->m31 = m1->m31 + (m2->m31 - m1->m31) * weight;
635
+ result->m32 = m1->m32 + (m2->m32 - m1->m32) * weight;
636
+
637
+ return NUMERIX_WRAP(klass, result);
638
+ }
@@ -0,0 +1,52 @@
1
+ #ifndef NUMERIX_MATRIX3X2_H
2
+ #define NUMERIX_MATRIX3X2_H 1
3
+
4
+ #include "common.h"
5
+ #include "matrix_base.h"
6
+
7
+ #define MATRIX3X2() \
8
+ Matrix3x2 *m; \
9
+ Data_Get_Struct(self, Matrix3x2, m)
10
+
11
+ void Init_matrix3x2(VALUE outer);
12
+ static VALUE rb_matrix3x2_allocate(VALUE klass);
13
+ VALUE rb_matrix3x2_initialize(int argc, VALUE *argv, VALUE self);
14
+
15
+ // Instance
16
+ VALUE rb_matrix3x2_identity_p(VALUE self);
17
+ VALUE rb_matrix3x2_translation(VALUE self);
18
+ VALUE rb_matrix3x2_translation_set(VALUE self, VALUE value);
19
+ VALUE rb_matrix3x2_determinant(VALUE self);
20
+ VALUE rb_matrix3x2_negate(VALUE self);
21
+ VALUE rb_matrix3x2_add(VALUE self, VALUE other);
22
+ VALUE rb_matrix3x2_subtract(VALUE self, VALUE other);
23
+ VALUE rb_matrix3x2_multiply(VALUE self, VALUE other);
24
+ VALUE rb_matrix3x2_equal(VALUE self, VALUE other);
25
+ VALUE rb_matrix3x2_row(VALUE self, VALUE row);
26
+ VALUE rb_matrix3x2_column(VALUE self, VALUE column);
27
+ VALUE rb_matrix3x2_each_row(VALUE self);
28
+ VALUE rb_matrix3x2_each_column(VALUE self);
29
+ VALUE rb_matrix3x2_aref(int argc, VALUE *argv, VALUE self);
30
+ VALUE rb_matrix3x2_aset(int argc, VALUE *argv, VALUE self);
31
+ VALUE rb_matrix3x2_invert(VALUE self);
32
+ VALUE rb_matrix3x2_lerp(VALUE self, VALUE other, VALUE amount);
33
+ VALUE rb_matrix3x2_lerp_bang(VALUE self, VALUE other, VALUE amount);
34
+ VALUE rb_matrix3x2_pow(VALUE self, VALUE exponent);
35
+ VALUE rb_matrix3x2_map(VALUE self);
36
+ VALUE rb_matrix3x2_map_bang(VALUE self);
37
+
38
+ // Conversion
39
+ VALUE rb_matrix3x2_to_s(VALUE self);
40
+ VALUE rb_matrix3x2_to_a(VALUE self);
41
+ VALUE rb_matrix3x2_to_h(VALUE self);
42
+
43
+ // Class
44
+ VALUE rb_matrix3x2_identity(VALUE klass);
45
+ VALUE rb_matrix3x2_create_translation(int argc, VALUE *argv, VALUE klass);
46
+ VALUE rb_matrix3x2_create_scale(int argc, VALUE *argv, VALUE klass);
47
+ VALUE rb_matrix3x2_create_skew(int argc, VALUE *argv, VALUE klass);
48
+ VALUE rb_matrix3x2_create_rotation(int argc, VALUE *argv, VALUE klass);
49
+
50
+ static inline VALUE rb_matrix3x2_lerp_s(VALUE klass, VALUE matrix1, VALUE matrix2, VALUE amount);
51
+
52
+ #endif /* NUMERIX_MATRIX3X2_H */