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,1807 @@
1
+
2
+ #include "matrix4x4.h"
3
+
4
+ void Init_matrix4x4(VALUE outer) {
5
+ rb_define_alloc_func(rb_cMatrix4x4, rb_matrix4x4_allocate);
6
+ rb_define_method(rb_cMatrix4x4, "initialize", rb_matrix4x4_initialize, -1);
7
+
8
+ // Instance
9
+ rb_define_method(rb_cMatrix4x4, "identity?", rb_matrix4x4_identity_p, 0);
10
+ rb_define_method(rb_cMatrix4x4, "translation", rb_matrix4x4_translation, 0);
11
+ rb_define_method(rb_cMatrix4x4, "translation=", rb_matrix4x4_translation_set, 1);
12
+ rb_define_method(rb_cMatrix4x4, "determinant", rb_matrix4x4_determinant, 0);
13
+ rb_define_method(rb_cMatrix4x4, "row", rb_matrix4x4_row, 1);
14
+ rb_define_method(rb_cMatrix4x4, "column", rb_matrix4x4_column, 1);
15
+ rb_define_method(rb_cMatrix4x4, "each_row", rb_matrix4x4_each_row, 0);
16
+ rb_define_method(rb_cMatrix4x4, "each_column", rb_matrix4x4_each_column, 0);
17
+ rb_define_method(rb_cMatrix4x4, "invert", rb_matrix4x4_invert, 0);
18
+ rb_define_method(rb_cMatrix4x4, "transform", rb_matrix4x4_transform, 1);
19
+ rb_define_method(rb_cMatrix4x4, "transform!", rb_matrix4x4_transform_bang, 1);
20
+ rb_define_method(rb_cMatrix4x4, "transpose", rb_matrix4x4_transpose, 0);
21
+ rb_define_method(rb_cMatrix4x4, "lerp", rb_matrix4x4_lerp, 2);
22
+ rb_define_method(rb_cMatrix4x4, "lerp!", rb_matrix4x4_lerp_bang, 2);
23
+ rb_define_method(rb_cMatrix4x4, "map", rb_matrix4x4_map, 0);
24
+ rb_define_method(rb_cMatrix4x4, "map2!", rb_matrix4x4_map_bang, 0);
25
+
26
+ // Alias
27
+ rb_define_alias(rb_cMatrix4x4, "collect", "map");
28
+ rb_define_alias(rb_cMatrix4x4, "collect2!", "map2!");
29
+
30
+ // Conversion
31
+ rb_define_method(rb_cMatrix4x4, "to_s", rb_matrix4x4_to_s, 0);
32
+ rb_define_method(rb_cMatrix4x4, "to_a", rb_matrix4x4_to_a, 0);
33
+ rb_define_method(rb_cMatrix4x4, "to_h", rb_matrix4x4_to_h, 0);
34
+ // to_mat3
35
+
36
+ // Operators
37
+ rb_define_method(rb_cMatrix4x4, "+", rb_matrix4x4_add, 1);
38
+ rb_define_method(rb_cMatrix4x4, "-", rb_matrix4x4_subtract, 1);
39
+ rb_define_method(rb_cMatrix4x4, "*", rb_matrix4x4_multiply, 1);
40
+ rb_define_method(rb_cMatrix4x4, "-@", rb_matrix4x4_negate, 0);
41
+ rb_define_method(rb_cMatrix4x4, "==", rb_matrix4x4_equal, 1);
42
+ rb_define_method(rb_cMatrix4x4, "[]", rb_matrix4x4_aref, -1);
43
+ rb_define_method(rb_cMatrix4x4, "[]=", rb_matrix4x4_aset, -1);
44
+ rb_define_method(rb_cMatrix4x4, "**", rb_matrix4x4_pow, 1);
45
+
46
+ // // Class
47
+ rb_define_singleton_method(rb_cMatrix4x4, "identity", rb_matrix4x4_identity, 0);
48
+ rb_define_singleton_method(rb_cMatrix4x4, "create_billboard", rb_matrix4x4_create_billboard, 4);
49
+ rb_define_singleton_method(rb_cMatrix4x4, "create_constrained_billboard", rb_matrix4x4_create_constrained_billboard, 5);
50
+ rb_define_singleton_method(rb_cMatrix4x4, "create_translation", rb_matrix4x4_create_translation, -1);
51
+ rb_define_singleton_method(rb_cMatrix4x4, "create_scale", rb_matrix4x4_create_scale, -1);
52
+ rb_define_singleton_method(rb_cMatrix4x4, "create_rotation_x", rb_matrix4x4_create_rotation_x, -1);
53
+ rb_define_singleton_method(rb_cMatrix4x4, "create_rotation_y", rb_matrix4x4_create_rotation_y, -1);
54
+ rb_define_singleton_method(rb_cMatrix4x4, "create_rotation_z", rb_matrix4x4_create_rotation_z, -1);
55
+ rb_define_singleton_method(rb_cMatrix4x4, "from_axis_angle", rb_matrix4x4_from_axis_angle, 2);
56
+ rb_define_singleton_method(rb_cMatrix4x4, "create_perspective_fov", rb_matrix4x4_create_perspective_fov, 4);
57
+ rb_define_singleton_method(rb_cMatrix4x4, "create_perspective", rb_matrix4x4_create_perspective_fov, 4);
58
+ rb_define_singleton_method(rb_cMatrix4x4, "create_perspective_off_center", rb_matrix4x4_create_perspective_off_center, 6);
59
+ rb_define_singleton_method(rb_cMatrix4x4, "create_orthographic", rb_matrix4x4_create_orthographic, 4);
60
+ rb_define_singleton_method(rb_cMatrix4x4, "create_orthographic_off_center", rb_matrix4x4_create_orthographic_off_center, 6);
61
+ rb_define_singleton_method(rb_cMatrix4x4, "create_look_at", rb_matrix4x4_create_look_at, 3);
62
+ rb_define_singleton_method(rb_cMatrix4x4, "create_world", rb_matrix4x4_create_world, 3);
63
+ rb_define_singleton_method(rb_cMatrix4x4, "from_quaternion", rb_matrix4x4_from_quaternion, 1);
64
+ rb_define_singleton_method(rb_cMatrix4x4, "from_yaw_pitch_roll", rb_matrix4x4_from_yaw_pitch_roll, 3);
65
+ rb_define_singleton_method(rb_cMatrix4x4, "create_shadow", rb_matrix4x4_create_shadow, 2);
66
+ rb_define_singleton_method(rb_cMatrix4x4, "create_reflection", rb_matrix4x4_create_reflection, 1);
67
+ rb_define_singleton_method(rb_cMatrix4x4, "lerp", rb_matrix4x4_lerp_s, 3);
68
+ }
69
+
70
+ static inline void numerix_cross_norm(Vector3 *v1, Vector3 *v2, Vector3 *result) {
71
+ float x = v1->y * v2->z - v1->z * v2->y;
72
+ float y = v1->z * v2->x - v1->x * v2->z;
73
+ float z = v1->x * v2->y - v1->y * v2->x;
74
+ float invLength = 1.0f / sqrtf(x * x + y * y + z * z);
75
+ result->x = x * invLength;
76
+ result->y = y * invLength;
77
+ result->z = z * invLength;
78
+ }
79
+
80
+ static inline void numerix_vec3_normalize(Vector3 *v) {
81
+ float invLength = 1.0f / sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
82
+ v->x *= invLength;
83
+ v->y *= invLength;
84
+ v->z *= invLength;
85
+ }
86
+
87
+ static inline void numerix_vec3_cross(Vector3 *v1, Vector3 *v2, Vector3 *result) {
88
+ result->x = v1->y * v2->z - v1->z * v2->y;
89
+ result->y = v1->z * v2->x - v1->x * v2->z;
90
+ result->z = v1->x * v2->y - v1->y * v2->x;
91
+ }
92
+
93
+ static inline float numerix_vec3_dot(Vector3 *v1, Vector3 *v2) {
94
+ return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
95
+ }
96
+
97
+ static VALUE rb_matrix4x4_allocate(VALUE klass) {
98
+ Matrix4x4 *m = ALLOC(Matrix4x4);
99
+ memset(m, 0, sizeof(Matrix4x4));
100
+ return NUMERIX_WRAP(klass, m);
101
+ }
102
+
103
+ VALUE rb_matrix4x4_initialize(int argc, VALUE *argv, VALUE self) {
104
+ MATRIX4X4();
105
+ if (argc == 16) {
106
+ m->m11 = NUM2FLT(argv[0]);
107
+ m->m12 = NUM2FLT(argv[1]);
108
+ m->m13 = NUM2FLT(argv[2]);
109
+ m->m14 = NUM2FLT(argv[3]);
110
+ m->m21 = NUM2FLT(argv[4]);
111
+ m->m22 = NUM2FLT(argv[5]);
112
+ m->m23 = NUM2FLT(argv[6]);
113
+ m->m24 = NUM2FLT(argv[7]);
114
+ m->m31 = NUM2FLT(argv[8]);
115
+ m->m32 = NUM2FLT(argv[9]);
116
+ m->m33 = NUM2FLT(argv[10]);
117
+ m->m34 = NUM2FLT(argv[11]);
118
+ m->m41 = NUM2FLT(argv[12]);
119
+ m->m42 = NUM2FLT(argv[13]);
120
+ m->m43 = NUM2FLT(argv[14]);
121
+ m->m44 = NUM2FLT(argv[15]);
122
+ } else if (argc == 1) {
123
+ if (NUMERIX_TYPE_P(argv[0], rb_cMatrix3x2)) {
124
+ Matrix3x2 *value;
125
+ Data_Get_Struct(argv[0], Matrix3x2, value);
126
+ m->m11 = value->m11;
127
+ m->m12 = value->m12;
128
+ m->m13 = 0.0f;
129
+ m->m14 = 0.0f;
130
+ m->m21 = value->m21;
131
+ m->m22 = value->m22;
132
+ m->m23 = 0.0f;
133
+ m->m24 = 0.0f;
134
+ m->m31 = 0.0f;
135
+ m->m32 = 0.0f;
136
+ m->m33 = 1.0f;
137
+ m->m34 = 0.0f;
138
+ m->m41 = value->m31;
139
+ m->m42 = value->m32;
140
+ m->m43 = 0.0f;
141
+ m->m44 = 1.0f;
142
+ } else {
143
+ float value = NUM2FLT(argv[0]);
144
+ float *p = (float *)m;
145
+ for (int i = 0; i < 16; i++)
146
+ p[i] = value;
147
+ }
148
+ } else if (argc != 0)
149
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 0, 16)", argc);
150
+
151
+ return Qnil;
152
+ }
153
+
154
+ VALUE rb_matrix4x4_lerp(VALUE self, VALUE other, VALUE amount) {
155
+ Matrix4x4 *m1, *m2, *result;
156
+ Data_Get_Struct(self, Matrix4x4, m1);
157
+ Data_Get_Struct(other, Matrix4x4, m2);
158
+ result = ALLOC(Matrix4x4);
159
+ float weight = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
160
+
161
+ // First row
162
+ result->m11 = m1->m11 + (m2->m11 - m1->m11) * weight;
163
+ result->m12 = m1->m12 + (m2->m12 - m1->m12) * weight;
164
+ result->m13 = m1->m13 + (m2->m13 - m1->m13) * weight;
165
+ result->m14 = m1->m14 + (m2->m14 - m1->m14) * weight;
166
+
167
+ // Second row
168
+ result->m21 = m1->m21 + (m2->m21 - m1->m21) * weight;
169
+ result->m22 = m1->m22 + (m2->m22 - m1->m22) * weight;
170
+ result->m23 = m1->m23 + (m2->m23 - m1->m23) * weight;
171
+ result->m24 = m1->m24 + (m2->m24 - m1->m24) * weight;
172
+
173
+ // Third row
174
+ result->m31 = m1->m31 + (m2->m31 - m1->m31) * weight;
175
+ result->m32 = m1->m32 + (m2->m32 - m1->m32) * weight;
176
+ result->m33 = m1->m33 + (m2->m33 - m1->m33) * weight;
177
+ result->m34 = m1->m34 + (m2->m34 - m1->m34) * weight;
178
+
179
+ // Fourth row
180
+ result->m41 = m1->m41 + (m2->m41 - m1->m41) * weight;
181
+ result->m42 = m1->m42 + (m2->m42 - m1->m42) * weight;
182
+ result->m43 = m1->m43 + (m2->m43 - m1->m43) * weight;
183
+ result->m44 = m1->m44 + (m2->m44 - m1->m44) * weight;
184
+
185
+ return NUMERIX_WRAP(CLASS_OF(self), result);
186
+ }
187
+
188
+ VALUE rb_matrix4x4_lerp_bang(VALUE self, VALUE other, VALUE amount) {
189
+ Matrix4x4 *m1, *m2;
190
+ Data_Get_Struct(self, Matrix4x4, m1);
191
+ Data_Get_Struct(other, Matrix4x4, m2);
192
+ float weight = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
193
+
194
+ // First row
195
+ m1->m11 = m1->m11 + (m2->m11 - m1->m11) * weight;
196
+ m1->m12 = m1->m12 + (m2->m12 - m1->m12) * weight;
197
+ m1->m13 = m1->m13 + (m2->m13 - m1->m13) * weight;
198
+ m1->m14 = m1->m14 + (m2->m14 - m1->m14) * weight;
199
+
200
+ // Second row
201
+ m1->m21 = m1->m21 + (m2->m21 - m1->m21) * weight;
202
+ m1->m22 = m1->m22 + (m2->m22 - m1->m22) * weight;
203
+ m1->m23 = m1->m23 + (m2->m23 - m1->m23) * weight;
204
+ m1->m24 = m1->m24 + (m2->m24 - m1->m24) * weight;
205
+
206
+ // Third row
207
+ m1->m31 = m1->m31 + (m2->m31 - m1->m31) * weight;
208
+ m1->m32 = m1->m32 + (m2->m32 - m1->m32) * weight;
209
+ m1->m33 = m1->m33 + (m2->m33 - m1->m33) * weight;
210
+ m1->m34 = m1->m34 + (m2->m34 - m1->m34) * weight;
211
+
212
+ // Fourth row
213
+ m1->m41 = m1->m41 + (m2->m41 - m1->m41) * weight;
214
+ m1->m42 = m1->m42 + (m2->m42 - m1->m42) * weight;
215
+ m1->m43 = m1->m43 + (m2->m43 - m1->m43) * weight;
216
+ m1->m44 = m1->m44 + (m2->m44 - m1->m44) * weight;
217
+
218
+ return self;
219
+ }
220
+
221
+ VALUE rb_matrix4x4_identity_p(VALUE self) {
222
+ MATRIX4X4();
223
+ // Check diagonal element first for early out.
224
+ return m->m11 == 1.0f && m->m22 == 1.0f && m->m33 == 1.0f && m->m44 == 1.0f &&
225
+ m->m12 == 0.0f && m->m13 == 0.0f && m->m14 == 0.0f && m->m21 == 0.0f &&
226
+ m->m23 == 0.0f && m->m24 == 0.0f && m->m31 == 0.0f && m->m32 == 0.0f &&
227
+ m->m34 == 0.0f && m->m41 == 0.0f && m->m42 == 0.0f && m->m43 == 0.0f
228
+ ? Qtrue
229
+ : Qfalse;
230
+ }
231
+
232
+ VALUE rb_matrix4x4_translation(VALUE self) {
233
+ MATRIX4X4();
234
+ Vector3 *v = ALLOC(Vector3);
235
+ v->x = m->m41;
236
+ v->y = m->m42;
237
+ v->z = m->m43;
238
+ return NUMERIX_WRAP(rb_cVector3, v);
239
+ }
240
+
241
+ VALUE rb_matrix4x4_translation_set(VALUE self, VALUE value) {
242
+ MATRIX4X4();
243
+ Vector3 *v;
244
+ Data_Get_Struct(value, Vector3, v);
245
+ m->m41 = v->x;
246
+ m->m42 = v->y;
247
+ m->m43 = v->z;
248
+ return value;
249
+ }
250
+
251
+ VALUE rb_matrix4x4_determinant(VALUE self) {
252
+ Matrix4x4 *matrix;
253
+ Data_Get_Struct(self, Matrix4x4, matrix);
254
+ // | a b c d | | f g h | | e g h | | e f h | | e f g |
255
+ // | e f g h | = a | j k l | - b | i k l | + c | i j l | - d | i j k |
256
+ // | i j k l | | n o p | | m o p | | m n p | | m n o |
257
+ // | m n o p |
258
+ //
259
+ // | f g h |
260
+ // a | j k l | = a ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) )
261
+ // | n o p |
262
+ //
263
+ // | e g h |
264
+ // b | i k l | = b ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) )
265
+ // | m o p |
266
+ //
267
+ // | e f h |
268
+ // c | i j l | = c ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) )
269
+ // | m n p |
270
+ //
271
+ // | e f g |
272
+ // d | i j k | = d ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) )
273
+ // | m n o |
274
+ //
275
+ // Cost of operation
276
+ // 17 adds and 28 muls.
277
+ //
278
+ // add: 6 + 8 + 3 = 17
279
+ // mul: 12 + 16 = 28
280
+
281
+ float a = matrix->m11, b = matrix->m12, c = matrix->m13, d = matrix->m14;
282
+ float e = matrix->m21, f = matrix->m22, g = matrix->m23, h = matrix->m24;
283
+ float i = matrix->m31, j = matrix->m32, k = matrix->m33, l = matrix->m34;
284
+ float m = matrix->m41, n = matrix->m42, o = matrix->m43, p = matrix->m44;
285
+
286
+ float kp_lo = k * p - l * o;
287
+ float jp_ln = j * p - l * n;
288
+ float jo_kn = j * o - k * n;
289
+ float ip_lm = i * p - l * m;
290
+ float io_km = i * o - k * m;
291
+ float in_jm = i * n - j * m;
292
+
293
+ return DBL2NUM(a * (f * kp_lo - g * jp_ln + h * jo_kn) -
294
+ b * (e * kp_lo - g * ip_lm + h * io_km) +
295
+ c * (e * jp_ln - f * ip_lm + h * in_jm) -
296
+ d * (e * jo_kn - f * io_km + g * in_jm));
297
+ }
298
+
299
+ VALUE rb_matrix4x4_to_s(VALUE self) {
300
+ MATRIX4X4();
301
+ return rb_sprintf("{{%f, %f, %f, %f}, {%f, %f, %f, %f}, {%f, %f, %f, %f}, {%f, %f, %f, %f}}",
302
+ m->m11, m->m12, m->m13, m->m14, m->m21, m->m22, m->m23, m->m24,
303
+ m->m31, m->m32, m->m33, m->m34, m->m41, m->m42, m->m43, m->m44);
304
+ }
305
+
306
+ VALUE rb_matrix4x4_equal(VALUE self, VALUE other) {
307
+ if (CLASS_OF(other) != CLASS_OF(self))
308
+ return Qfalse;
309
+ Matrix4x4 *m1, *m2;
310
+ Data_Get_Struct(self, Matrix4x4, m1);
311
+ Data_Get_Struct(other, Matrix4x4, m2);
312
+ return FLT_EQUAL(m1->m11, m2->m11) && FLT_EQUAL(m1->m12, m2->m12) && FLT_EQUAL(m1->m13, m2->m13) && FLT_EQUAL(m1->m14, m2->m14) &&
313
+ FLT_EQUAL(m1->m21, m2->m21) && FLT_EQUAL(m1->m22, m2->m22) && FLT_EQUAL(m1->m23, m2->m23) && FLT_EQUAL(m1->m24, m2->m24) &&
314
+ FLT_EQUAL(m1->m31, m2->m31) && FLT_EQUAL(m1->m32, m2->m32) && FLT_EQUAL(m1->m33, m2->m33) && FLT_EQUAL(m1->m34, m2->m34) &&
315
+ FLT_EQUAL(m1->m41, m2->m41) && FLT_EQUAL(m1->m42, m2->m42) && FLT_EQUAL(m1->m43, m2->m43) && FLT_EQUAL(m1->m44, m2->m44)
316
+ ? Qtrue
317
+ : Qfalse;
318
+ }
319
+
320
+ VALUE rb_matrix4x4_pow(VALUE self, VALUE exponent) {
321
+ struct RData *rdata = RDATA(self);
322
+ const int count = 16;
323
+ float *result = ruby_xmalloc(sizeof(float) * count);
324
+ float *m = (float *)rdata->data;
325
+ float e = fabsf(NUM2FLT(exponent));
326
+ for (int i = 0; i < count; i++)
327
+ result[i] = powf(fabsf(m[i]), e);
328
+
329
+ return NUMERIX_WRAP(rdata->basic.klass, result);
330
+ }
331
+
332
+ VALUE rb_matrix4x4_to_a(VALUE self) {
333
+ MATRIX4X4();
334
+ VALUE array = rb_ary_new_capa(4);
335
+ // Row 1
336
+ VALUE r1 = rb_ary_new_capa(4);
337
+ rb_ary_store(r1, 0, DBL2NUM(m->m11));
338
+ rb_ary_store(r1, 1, DBL2NUM(m->m12));
339
+ rb_ary_store(r1, 2, DBL2NUM(m->m13));
340
+ rb_ary_store(r1, 3, DBL2NUM(m->m14));
341
+ rb_ary_push(array, r1);
342
+ // Row 2
343
+ VALUE r2 = rb_ary_new_capa(4);
344
+ rb_ary_store(r2, 0, DBL2NUM(m->m21));
345
+ rb_ary_store(r2, 1, DBL2NUM(m->m22));
346
+ rb_ary_store(r2, 2, DBL2NUM(m->m23));
347
+ rb_ary_store(r2, 3, DBL2NUM(m->m24));
348
+ rb_ary_push(array, r2);
349
+ // Row 3
350
+ VALUE r3 = rb_ary_new_capa(4);
351
+ rb_ary_store(r3, 0, DBL2NUM(m->m31));
352
+ rb_ary_store(r3, 1, DBL2NUM(m->m32));
353
+ rb_ary_store(r3, 2, DBL2NUM(m->m33));
354
+ rb_ary_store(r3, 3, DBL2NUM(m->m34));
355
+ rb_ary_push(array, r3);
356
+ // Row 4
357
+ VALUE r4 = rb_ary_new_capa(4);
358
+ rb_ary_store(r4, 0, DBL2NUM(m->m41));
359
+ rb_ary_store(r4, 1, DBL2NUM(m->m42));
360
+ rb_ary_store(r4, 2, DBL2NUM(m->m43));
361
+ rb_ary_store(r4, 3, DBL2NUM(m->m44));
362
+ rb_ary_push(array, r4);
363
+ return array;
364
+ }
365
+
366
+ VALUE rb_matrix4x4_row(VALUE self, VALUE row) {
367
+ MATRIX4X4();
368
+ VALUE args = rb_ary_new_capa(4);
369
+ int r = NUM2INT(row);
370
+ switch (r) {
371
+ case 0: {
372
+ rb_ary_push(args, DBL2NUM(m->m11));
373
+ rb_ary_push(args, DBL2NUM(m->m12));
374
+ rb_ary_push(args, DBL2NUM(m->m13));
375
+ rb_ary_push(args, DBL2NUM(m->m14));
376
+ break;
377
+ }
378
+ case 1: {
379
+ rb_ary_push(args, DBL2NUM(m->m21));
380
+ rb_ary_push(args, DBL2NUM(m->m22));
381
+ rb_ary_push(args, DBL2NUM(m->m23));
382
+ rb_ary_push(args, DBL2NUM(m->m24));
383
+ break;
384
+ }
385
+ case 2: {
386
+ rb_ary_push(args, DBL2NUM(m->m31));
387
+ rb_ary_push(args, DBL2NUM(m->m32));
388
+ rb_ary_push(args, DBL2NUM(m->m33));
389
+ rb_ary_push(args, DBL2NUM(m->m34));
390
+ break;
391
+ }
392
+ case 3: {
393
+ rb_ary_push(args, DBL2NUM(m->m41));
394
+ rb_ary_push(args, DBL2NUM(m->m42));
395
+ rb_ary_push(args, DBL2NUM(m->m43));
396
+ rb_ary_push(args, DBL2NUM(m->m44));
397
+ break;
398
+ }
399
+ default:
400
+ break;
401
+ }
402
+ return args;
403
+ }
404
+
405
+ VALUE rb_matrix4x4_column(VALUE self, VALUE column) {
406
+ MATRIX4X4();
407
+ VALUE args = rb_ary_new_capa(4);
408
+ int c = NUM2INT(column);
409
+ switch (c) {
410
+ case 0: {
411
+ rb_ary_push(args, DBL2NUM(m->m11));
412
+ rb_ary_push(args, DBL2NUM(m->m21));
413
+ rb_ary_push(args, DBL2NUM(m->m31));
414
+ rb_ary_push(args, DBL2NUM(m->m41));
415
+ break;
416
+ }
417
+ case 1: {
418
+ rb_ary_push(args, DBL2NUM(m->m12));
419
+ rb_ary_push(args, DBL2NUM(m->m22));
420
+ rb_ary_push(args, DBL2NUM(m->m32));
421
+ rb_ary_push(args, DBL2NUM(m->m42));
422
+ break;
423
+ }
424
+ case 2: {
425
+ rb_ary_push(args, DBL2NUM(m->m13));
426
+ rb_ary_push(args, DBL2NUM(m->m23));
427
+ rb_ary_push(args, DBL2NUM(m->m33));
428
+ rb_ary_push(args, DBL2NUM(m->m43));
429
+ break;
430
+ }
431
+ case 3: {
432
+ rb_ary_push(args, DBL2NUM(m->m14));
433
+ rb_ary_push(args, DBL2NUM(m->m24));
434
+ rb_ary_push(args, DBL2NUM(m->m34));
435
+ rb_ary_push(args, DBL2NUM(m->m44));
436
+ break;
437
+ }
438
+ default:
439
+ break;
440
+ }
441
+ return args;
442
+ }
443
+
444
+ VALUE rb_matrix4x4_map(VALUE self) {
445
+ const int count = 16;
446
+ struct RData *rdata = RDATA(self);
447
+ float *flt = (float *)rdata->data;
448
+ float *result = (float *)ruby_xmalloc(count * sizeof(float));
449
+
450
+ for (int i = 0; i < count; i++)
451
+ result[i] = NUM2FLT(rb_yield(DBL2NUM(flt[i])));
452
+
453
+ return NUMERIX_WRAP(rdata->basic.klass, result);
454
+ }
455
+
456
+ VALUE rb_matrix4x4_map_bang(VALUE self) {
457
+ const int count = 16;
458
+ float *flt = (float *)RDATA(self)->data;
459
+
460
+ for (int i = 0; i < count; i++)
461
+ flt[i] = NUM2FLT(rb_yield(DBL2NUM(flt[i])));
462
+
463
+ return self;
464
+ }
465
+
466
+ VALUE rb_matrix4x4_to_h(VALUE self) {
467
+ MATRIX4X4();
468
+ VALUE hash = rb_hash_new();
469
+ rb_hash_aset(hash, ID2SYM(rb_intern("m11")), DBL2NUM(m->m11));
470
+ rb_hash_aset(hash, ID2SYM(rb_intern("m12")), DBL2NUM(m->m12));
471
+ rb_hash_aset(hash, ID2SYM(rb_intern("m13")), DBL2NUM(m->m13));
472
+ rb_hash_aset(hash, ID2SYM(rb_intern("m14")), DBL2NUM(m->m14));
473
+
474
+ rb_hash_aset(hash, ID2SYM(rb_intern("m21")), DBL2NUM(m->m21));
475
+ rb_hash_aset(hash, ID2SYM(rb_intern("m22")), DBL2NUM(m->m22));
476
+ rb_hash_aset(hash, ID2SYM(rb_intern("m23")), DBL2NUM(m->m23));
477
+ rb_hash_aset(hash, ID2SYM(rb_intern("m24")), DBL2NUM(m->m24));
478
+
479
+ rb_hash_aset(hash, ID2SYM(rb_intern("m31")), DBL2NUM(m->m31));
480
+ rb_hash_aset(hash, ID2SYM(rb_intern("m32")), DBL2NUM(m->m32));
481
+ rb_hash_aset(hash, ID2SYM(rb_intern("m33")), DBL2NUM(m->m33));
482
+ rb_hash_aset(hash, ID2SYM(rb_intern("m34")), DBL2NUM(m->m34));
483
+
484
+ rb_hash_aset(hash, ID2SYM(rb_intern("m41")), DBL2NUM(m->m41));
485
+ rb_hash_aset(hash, ID2SYM(rb_intern("m42")), DBL2NUM(m->m42));
486
+ rb_hash_aset(hash, ID2SYM(rb_intern("m43")), DBL2NUM(m->m43));
487
+ rb_hash_aset(hash, ID2SYM(rb_intern("m44")), DBL2NUM(m->m44));
488
+ return hash;
489
+ }
490
+
491
+ VALUE rb_matrix4x4_each_row(VALUE self) {
492
+ MATRIX4X4();
493
+ for (int i = 0; i < 4; i++) {
494
+ VALUE index = INT2NUM(i);
495
+ rb_yield(rb_matrix4x4_row(self, index));
496
+ }
497
+ return self;
498
+ }
499
+
500
+ VALUE rb_matrix4x4_each_column(VALUE self) {
501
+ MATRIX4X4();
502
+ for (int i = 0; i < 4; i++) {
503
+ VALUE index = INT2NUM(i);
504
+ rb_yield(rb_matrix4x4_column(self, index));
505
+ }
506
+ return self;
507
+ }
508
+
509
+ VALUE rb_matrix4x4_aref(int argc, VALUE *argv, VALUE self) {
510
+ if (argc == 1) {
511
+ return rb_call_super(1, argv);
512
+ } else if (argc == 2) {
513
+ int r = NUM2INT(argv[0]);
514
+ int c = NUM2INT(argv[1]);
515
+ if (r < 0 || r > 3 || c < 0 || c > 3)
516
+ return Qnil;
517
+ argv[0] = INT2NUM(r + (c * 4));
518
+ return rb_call_super(1, argv);
519
+ }
520
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2)", argc);
521
+ return Qnil;
522
+ }
523
+
524
+ VALUE rb_matrix4x4_aset(int argc, VALUE *argv, VALUE self) {
525
+ if (argc == 2) {
526
+ return rb_call_super(2, argv);
527
+ } else if (argc == 3) {
528
+ int r = NUM2INT(argv[0]);
529
+ int c = NUM2INT(argv[1]);
530
+ if (r < 0 || r > 3 || c < 0 || c > 3)
531
+ return Qnil;
532
+ argv[1] = INT2NUM(r + (c * 4));
533
+ return rb_call_super(2, &argv[1]);
534
+ }
535
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 2, 3)", argc);
536
+ return Qnil;
537
+ }
538
+
539
+ VALUE rb_matrix4x4_identity(VALUE klass) {
540
+ Matrix4x4 *m = ALLOC(Matrix4x4);
541
+ m->m11 = 1.0f;
542
+ m->m12 = 0.0f;
543
+ m->m13 = 0.0f;
544
+ m->m14 = 0.0f;
545
+ m->m21 = 0.0f;
546
+ m->m22 = 1.0f;
547
+ m->m23 = 0.0f;
548
+ m->m24 = 0.0f;
549
+ m->m31 = 0.0f;
550
+ m->m32 = 0.0f;
551
+ m->m33 = 1.0f;
552
+ m->m34 = 0.0f;
553
+ m->m41 = 0.0f;
554
+ m->m42 = 0.0f;
555
+ m->m43 = 0.0f;
556
+ m->m44 = 1.0f;
557
+ return NUMERIX_WRAP(klass, m);
558
+ }
559
+
560
+ VALUE rb_matrix4x4_create_billboard(VALUE klass, VALUE position, VALUE camera, VALUE up, VALUE forward) {
561
+ const float epsilon = 1e-4f;
562
+ Vector3 *pos, *cam, *u, *f;
563
+ Data_Get_Struct(position, Vector3, pos);
564
+ Data_Get_Struct(camera, Vector3, cam);
565
+ Data_Get_Struct(up, Vector3, u);
566
+ Data_Get_Struct(forward, Vector3, f);
567
+
568
+ Vector3 *axis = xmalloc(sizeof(Vector3) * 3);
569
+
570
+ axis[2].x = pos->x - cam->x;
571
+ axis[2].y = pos->y - cam->y;
572
+ axis[2].z = pos->z - cam->z;
573
+
574
+ float norm = axis[2].x * axis[2].x + axis[2].y * axis[2].y + axis[2].z * axis[2].z;
575
+
576
+ if (norm < epsilon) {
577
+ axis[2].x = -f->x;
578
+ axis[2].y = -f->y;
579
+ axis[2].z = -f->z;
580
+ } else {
581
+ float inverseNorm = 1.0f / sqrtf(norm);
582
+ axis[2].x *= inverseNorm;
583
+ axis[2].y *= inverseNorm;
584
+ axis[2].z *= inverseNorm;
585
+ }
586
+
587
+ numerix_cross_norm(u, &axis[2], &axis[0]);
588
+ numerix_vec3_cross(&axis[2], &axis[0], &axis[1]);
589
+
590
+ Matrix4x4 *result = ALLOC(Matrix4x4);
591
+
592
+ result->m11 = axis[0].x;
593
+ result->m12 = axis[0].y;
594
+ result->m13 = axis[0].z;
595
+ result->m14 = 0.0f;
596
+ result->m21 = axis[1].x;
597
+ result->m22 = axis[1].y;
598
+ result->m23 = axis[1].z;
599
+ result->m24 = 0.0f;
600
+ result->m31 = axis[2].x;
601
+ result->m32 = axis[2].y;
602
+ result->m33 = axis[2].z;
603
+ result->m34 = 0.0f;
604
+
605
+ result->m41 = pos->x;
606
+ result->m42 = pos->y;
607
+ result->m43 = pos->z;
608
+ result->m44 = 1.0f;
609
+
610
+ xfree(axis);
611
+
612
+ return NUMERIX_WRAP(klass, result);
613
+ }
614
+
615
+ VALUE rb_matrix4x4_create_constrained_billboard(VALUE klass, VALUE position, VALUE rotate, VALUE camera, VALUE up, VALUE forward) {
616
+ const float epsilon = 1e-4f;
617
+ const float minAngle = 1.0f - (0.1f * (NUMERIX_PI / 180.0f)); // 0.1 degrees
618
+
619
+ Vector3 *pos, *cam, *r, *u, *f;
620
+ Data_Get_Struct(position, Vector3, pos);
621
+ Data_Get_Struct(camera, Vector3, cam);
622
+ Data_Get_Struct(rotate, Vector3, r);
623
+ Data_Get_Struct(up, Vector3, u);
624
+ Data_Get_Struct(forward, Vector3, f);
625
+
626
+ Vector3 *axis = xmalloc(sizeof(Vector3) * 3);
627
+ Vector3 *faceDir = xmalloc(sizeof(Vector3));
628
+
629
+ faceDir->x = pos->x - cam->x;
630
+ faceDir->y = pos->y - cam->y;
631
+ faceDir->z = pos->z - cam->z;
632
+
633
+ float norm = faceDir->x * faceDir->x + faceDir->y * faceDir->y + faceDir->z * faceDir->z;
634
+ if (norm < epsilon) {
635
+ faceDir->x = -f->x;
636
+ faceDir->y = -f->y;
637
+ faceDir->z = -f->z;
638
+ } else {
639
+ float invNorm = 1.0f / sqrtf(norm);
640
+ faceDir->x *= invNorm;
641
+ faceDir->y *= invNorm;
642
+ faceDir->z *= invNorm;
643
+ }
644
+
645
+ // Treat the case when angle between faceDir and rotateAxis is too close to 0.
646
+ float dot = numerix_vec3_dot(r, faceDir);
647
+
648
+ if (fabsf(dot) > minAngle) {
649
+ memcpy(&axis[2], f, sizeof(Vector2));
650
+ // Make sure passed values are useful for compute.
651
+ dot = numerix_vec3_dot(r, &axis[2]);
652
+
653
+ if (fabsf(dot) > minAngle) {
654
+ axis[2].y = 0.0f;
655
+ if (fabsf(r->z) > minAngle) {
656
+ axis[2].x = 1.0f;
657
+ axis[2].z = 0.0f;
658
+ } else {
659
+ axis[2].x = 0.0f;
660
+ axis[2].z = -1.0f;
661
+ }
662
+ }
663
+ numerix_cross_norm(r, &axis[2], &axis[0]);
664
+ numerix_cross_norm(&axis[0], r, &axis[2]);
665
+ } else {
666
+ numerix_cross_norm(r, faceDir, &axis[0]);
667
+ numerix_cross_norm(&axis[0], &axis[1], &axis[2]);
668
+ }
669
+
670
+ Matrix4x4 *result = ALLOC(Matrix4x4);
671
+
672
+ result->m11 = axis[0].x;
673
+ result->m12 = axis[0].y;
674
+ result->m13 = axis[0].z;
675
+ result->m14 = 0.0f;
676
+ result->m21 = axis[1].x;
677
+ result->m22 = axis[1].y;
678
+ result->m23 = axis[1].z;
679
+ result->m24 = 0.0f;
680
+ result->m31 = axis[2].x;
681
+ result->m32 = axis[2].y;
682
+ result->m33 = axis[2].z;
683
+ result->m34 = 0.0f;
684
+
685
+ result->m41 = pos->x;
686
+ result->m42 = pos->y;
687
+ result->m43 = pos->z;
688
+ result->m44 = 1.0f;
689
+
690
+ xfree(axis);
691
+ xfree(faceDir);
692
+
693
+ return NUMERIX_WRAP(klass, result);
694
+ }
695
+
696
+ VALUE rb_matrix4x4_create_translation(int argc, VALUE *argv, VALUE klass) {
697
+ float x, y, z;
698
+ if (argc == 1) {
699
+ Vector3 *v;
700
+ Data_Get_Struct(argv[0], Vector3, v);
701
+ x = v->x;
702
+ y = v->y;
703
+ z = v->z;
704
+ } else if (argc == 3) {
705
+ x = NUM2FLT(argv[0]);
706
+ y = NUM2FLT(argv[1]);
707
+ z = NUM2FLT(argv[2]);
708
+ } else
709
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 3)", argc);
710
+
711
+ Matrix4x4 *result = ALLOC(Matrix4x4);
712
+ result->m11 = 1.0f;
713
+ result->m12 = 0.0f;
714
+ result->m13 = 0.0f;
715
+ result->m14 = 0.0f;
716
+ result->m21 = 0.0f;
717
+ result->m22 = 1.0f;
718
+ result->m23 = 0.0f;
719
+ result->m24 = 0.0f;
720
+ result->m31 = 0.0f;
721
+ result->m32 = 0.0f;
722
+ result->m33 = 1.0f;
723
+ result->m34 = 0.0f;
724
+
725
+ result->m41 = x;
726
+ result->m42 = y;
727
+ result->m43 = z;
728
+ result->m44 = 1.0f;
729
+
730
+ return NUMERIX_WRAP(klass, result);
731
+ }
732
+
733
+ VALUE rb_matrix4x4_create_scale(int argc, VALUE *argv, VALUE klass) {
734
+ float xscale, yscale, zscale, tx = 0.0f, ty = 0.0f, tz = 0.0f;
735
+
736
+ switch (argc) {
737
+ case 1: {
738
+ if (NUMERIX_TYPE_P(argv[0], rb_cVector3)) // (vec3)
739
+ {
740
+ Vector3 *vec3;
741
+ Data_Get_Struct(argv[0], Vector3, vec3);
742
+ xscale = vec3->x;
743
+ yscale = vec3->y;
744
+ zscale = vec3->z;
745
+ } else // (float)
746
+ {
747
+ xscale = yscale = zscale = NUM2FLT(argv[0]);
748
+ }
749
+ break;
750
+ }
751
+ case 2: {
752
+ Vector3 *cp;
753
+ Data_Get_Struct(argv[1], Vector3, cp);
754
+ if (NUMERIX_TYPE_P(argv[0], rb_cVector3)) // (vec3, vec3)
755
+ {
756
+ Vector3 *v3;
757
+ Data_Get_Struct(argv[1], Vector3, v3);
758
+ xscale = v3->x;
759
+ yscale = v3->y;
760
+ zscale = v3->z;
761
+ } else // (float, vec3)
762
+ {
763
+ xscale = yscale = zscale = NUM2FLT(argv[0]);
764
+ }
765
+ tx = cp->x * (1.0f - xscale);
766
+ ty = cp->y * (1.0f - yscale);
767
+ tz = cp->z * (1.0f - zscale);
768
+ break;
769
+ }
770
+ case 3: // (float, float, float)
771
+ {
772
+ xscale = NUM2FLT(argv[0]);
773
+ yscale = NUM2FLT(argv[1]);
774
+ zscale = NUM2FLT(argv[2]);
775
+ break;
776
+ }
777
+ case 4: // (float, float, float, vec3)
778
+ {
779
+ xscale = NUM2FLT(argv[0]);
780
+ yscale = NUM2FLT(argv[1]);
781
+ zscale = NUM2FLT(argv[2]);
782
+ Vector3 *center;
783
+ Data_Get_Struct(argv[3], Vector3, center);
784
+ tx = center->x * (1.0f - xscale);
785
+ ty = center->y * (1.0f - yscale);
786
+ tz = center->z * (1.0f - zscale);
787
+ break;
788
+ }
789
+ default: {
790
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2, 3, 4)", argc);
791
+ break;
792
+ }
793
+ }
794
+ Matrix4x4 *result = ALLOC(Matrix4x4);
795
+ result->m11 = xscale;
796
+ result->m12 = 0.0f;
797
+ result->m13 = 0.0f;
798
+ result->m14 = 0.0f;
799
+ result->m21 = 0.0f;
800
+ result->m22 = yscale;
801
+ result->m23 = 0.0f;
802
+ result->m24 = 0.0f;
803
+ result->m31 = 0.0f;
804
+ result->m32 = 0.0f;
805
+ result->m33 = zscale;
806
+ result->m34 = 0.0f;
807
+ result->m41 = tx;
808
+ result->m42 = ty;
809
+ result->m43 = tz;
810
+ result->m44 = 1.0f;
811
+
812
+ return NUMERIX_WRAP(klass, result);
813
+ }
814
+
815
+ VALUE rb_matrix4x4_create_rotation_x(int argc, VALUE *argv, VALUE klass) {
816
+ if (argc != 1 && argc != 2)
817
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2)", argc);
818
+
819
+ float radians = NUM2FLT(argv[0]);
820
+ float c = cosf(radians);
821
+ float s = sinf(radians);
822
+ float y = 0.0f, z = 0.0f;
823
+ if (argc == 2) {
824
+ Vector3 *center;
825
+ Data_Get_Struct(argv[1], Vector3, center);
826
+ y = center->y * (1.0f - c) + center->z * s;
827
+ z = center->z * (1.0f - c) - center->y * s;
828
+ }
829
+
830
+ Matrix4x4 *result = ALLOC(Matrix4x4);
831
+ // [ 1 0 0 0 ]
832
+ // [ 0 c s 0 ]
833
+ // [ 0 -s c 0 ]
834
+ // [ 0 y z 1 ]
835
+ result->m11 = 1.0f;
836
+ result->m12 = 0.0f;
837
+ result->m13 = 0.0f;
838
+ result->m14 = 0.0f;
839
+ result->m21 = 0.0f;
840
+ result->m22 = c;
841
+ result->m23 = s;
842
+ result->m24 = 0.0f;
843
+ result->m31 = 0.0f;
844
+ result->m32 = -s;
845
+ result->m33 = c;
846
+ result->m34 = 0.0f;
847
+ result->m41 = 0.0f;
848
+ result->m42 = y;
849
+ result->m43 = z;
850
+ result->m44 = 1.0f;
851
+
852
+ return NUMERIX_WRAP(klass, result);
853
+ }
854
+
855
+ VALUE rb_matrix4x4_create_rotation_y(int argc, VALUE *argv, VALUE klass) {
856
+ if (argc != 1 && argc != 2)
857
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2)", argc);
858
+
859
+ float radians = NUM2FLT(argv[0]);
860
+ float c = cosf(radians);
861
+ float s = sinf(radians);
862
+ float x = 0.0f, z = 0.0f;
863
+ if (argc == 2) {
864
+ Vector3 *center;
865
+ Data_Get_Struct(argv[1], Vector3, center);
866
+ x = center->x * (1.0f - c) - center->z * s;
867
+ z = center->z * (1.0f - c) + center->x * s;
868
+ }
869
+
870
+ Matrix4x4 *result = ALLOC(Matrix4x4);
871
+ // [ c 0 -s 0 ]
872
+ // [ 0 1 0 0 ]
873
+ // [ s 0 c 0 ]
874
+ // [ x 0 z 1 ]
875
+ result->m11 = c;
876
+ result->m12 = 0.0f;
877
+ result->m13 = -s;
878
+ result->m14 = 0.0f;
879
+ result->m21 = 0.0f;
880
+ result->m22 = 1.0f;
881
+ result->m23 = 0.0f;
882
+ result->m24 = 0.0f;
883
+ result->m31 = s;
884
+ result->m32 = 0.0f;
885
+ result->m33 = c;
886
+ result->m34 = 0.0f;
887
+ result->m41 = x;
888
+ result->m42 = 0.0f;
889
+ result->m43 = z;
890
+ result->m44 = 1.0f;
891
+
892
+ return NUMERIX_WRAP(klass, result);
893
+ }
894
+
895
+ VALUE rb_matrix4x4_create_rotation_z(int argc, VALUE *argv, VALUE klass) {
896
+ if (argc != 1 && argc != 2)
897
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2)", argc);
898
+
899
+ float radians = NUM2FLT(argv[0]);
900
+ float c = cosf(radians);
901
+ float s = sinf(radians);
902
+ float x = 0.0f, y = 0.0f;
903
+ if (argc == 2) {
904
+ Vector3 *center;
905
+ Data_Get_Struct(argv[1], Vector3, center);
906
+ x = center->x * (1.0f - c) + center->y * s;
907
+ y = center->y * (1.0f - c) - center->x * s;
908
+ }
909
+
910
+ Matrix4x4 *result = ALLOC(Matrix4x4);
911
+ // [ c s 0 0 ]
912
+ // [ -s c 0 0 ]
913
+ // [ 0 0 1 0 ]
914
+ // [ x y 0 1 ]
915
+ result->m11 = c;
916
+ result->m12 = s;
917
+ result->m13 = 0.0f;
918
+ result->m14 = 0.0f;
919
+ result->m21 = -s;
920
+ result->m22 = c;
921
+ result->m23 = 0.0f;
922
+ result->m24 = 0.0f;
923
+ result->m31 = 0.0f;
924
+ result->m32 = 0.0f;
925
+ result->m33 = 1.0f;
926
+ result->m34 = 0.0f;
927
+ result->m41 = x;
928
+ result->m42 = y;
929
+ result->m43 = 0.0f;
930
+ result->m44 = 1.0f;
931
+
932
+ return NUMERIX_WRAP(klass, result);
933
+ }
934
+
935
+ VALUE rb_matrix4x4_from_axis_angle(VALUE klass, VALUE axis, VALUE angle) {
936
+ // a: angle
937
+ // x, y, z: unit vector for axis.
938
+ //
939
+ // Rotation matrix M can compute by using below equation.
940
+ //
941
+ // T T
942
+ // M = uu + (cos a)( I-uu ) + (sin a)S
943
+ //
944
+ // Where:
945
+ //
946
+ // u = ( x, y, z )
947
+ //
948
+ // [ 0 -z y ]
949
+ // S = [ z 0 -x ]
950
+ // [ -y x 0 ]
951
+ //
952
+ // [ 1 0 0 ]
953
+ // I = [ 0 1 0 ]
954
+ // [ 0 0 1 ]
955
+ //
956
+ //
957
+ // [ xx+cosa*(1-xx) yx-cosa*yx-sina*z zx-cosa*xz+sina*y ]
958
+ // M = [ xy-cosa*yx+sina*z yy+cosa(1-yy) yz-cosa*yz-sina*x ]
959
+ // [ zx-cosa*zx-sina*y zy-cosa*zy+sina*x zz+cosa*(1-zz) ]
960
+ //
961
+
962
+ float ang = NUM2FLT(angle);
963
+ Vector3 *v;
964
+ Data_Get_Struct(axis, Vector3, v);
965
+
966
+ float x = v->x, y = v->y, z = v->z;
967
+ float sa = sinf(ang), ca = cosf(ang);
968
+ float xx = x * x, yy = y * y, zz = z * z;
969
+ float xy = x * y, xz = x * z, yz = y * z;
970
+
971
+ Matrix4x4 *result = ALLOC(Matrix4x4);
972
+
973
+ result->m11 = xx + ca * (1.0f - xx);
974
+ result->m12 = xy - ca * xy + sa * z;
975
+ result->m13 = xz - ca * xz - sa * y;
976
+ result->m14 = 0.0f;
977
+ result->m21 = xy - ca * xy - sa * z;
978
+ result->m22 = yy + ca * (1.0f - yy);
979
+ result->m23 = yz - ca * yz + sa * x;
980
+ result->m24 = 0.0f;
981
+ result->m31 = xz - ca * xz + sa * y;
982
+ result->m32 = yz - ca * yz - sa * x;
983
+ result->m33 = zz + ca * (1.0f - zz);
984
+ result->m34 = 0.0f;
985
+ result->m41 = 0.0f;
986
+ result->m42 = 0.0f;
987
+ result->m43 = 0.0f;
988
+ result->m44 = 1.0f;
989
+
990
+ return NUMERIX_WRAP(klass, result);
991
+ }
992
+
993
+ VALUE rb_matrix4x4_create_perspective_fov(VALUE klass, VALUE fieldOfView, VALUE aspectRatio, VALUE nearDist, VALUE farDist) {
994
+ float n = NUM2FLT(nearDist);
995
+ float f = NUM2FLT(farDist);
996
+ if (n <= 0.0f)
997
+ rb_raise(rb_eRangeError, "near plane distance must be value greater than 0.0 (given %f)", n);
998
+ if (f <= 0.0f)
999
+ rb_raise(rb_eRangeError, "far plane distance must be value greater than 0.0 (given %f)", n);
1000
+ if (n <= 0.0f)
1001
+ rb_raise(rb_eRangeError, "near plane distance must be less than far plane distance");
1002
+
1003
+ float ratio = NUM2FLT(aspectRatio);
1004
+ float fov = NUM2FLT(fieldOfView);
1005
+ if (fov <= 0.0f || fov >= NUMERIX_PI)
1006
+ rb_raise(rb_eRangeError, "field of view must be value greater than 0.0 and less than PI (given %f)", fov);
1007
+
1008
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1009
+
1010
+ float yscale = 1.0f / tanf(fov * 0.5f);
1011
+ float xscale = yscale / ratio;
1012
+
1013
+ result->m11 = xscale;
1014
+ result->m12 = result->m13 = result->m14 = 0.0f;
1015
+
1016
+ result->m22 = yscale;
1017
+ result->m21 = result->m23 = result->m24 = 0.0f;
1018
+
1019
+ result->m31 = result->m32 = 0.0f;
1020
+ result->m33 = f / (n - f);
1021
+ result->m34 = -1.0f;
1022
+
1023
+ result->m41 = result->m42 = result->m44 = 0.0f;
1024
+ result->m43 = n * f / (n - f);
1025
+
1026
+ return NUMERIX_WRAP(klass, result);
1027
+ }
1028
+
1029
+ VALUE rb_matrix4x4_create_perspective(VALUE klass, VALUE width, VALUE height, VALUE nearDist, VALUE farDist) {
1030
+ float n = NUM2FLT(nearDist);
1031
+ float f = NUM2FLT(farDist);
1032
+ if (n <= 0.0f)
1033
+ rb_raise(rb_eRangeError, "near plane distance must be value greater than 0.0 (given %f)", n);
1034
+ if (f <= 0.0f)
1035
+ rb_raise(rb_eRangeError, "far plane distance must be value greater than 0.0 (given %f)", n);
1036
+ if (n <= 0.0f)
1037
+ rb_raise(rb_eRangeError, "near plane distance must be less than far plane distance");
1038
+
1039
+ float w = NUM2FLT(width);
1040
+ float h = NUM2FLT(height);
1041
+
1042
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1043
+
1044
+ result->m11 = 2.0f * n / w;
1045
+ result->m12 = result->m13 = result->m14 = 0.0f;
1046
+
1047
+ result->m22 = 2.0f * n / h;
1048
+ result->m21 = result->m23 = result->m24 = 0.0f;
1049
+
1050
+ result->m33 = f / (n - f);
1051
+ result->m31 = result->m32 = 0.0f;
1052
+ result->m34 = -1.0f;
1053
+
1054
+ result->m41 = result->m42 = result->m44 = 0.0f;
1055
+ result->m43 = n * f / (n - f);
1056
+
1057
+ return NUMERIX_WRAP(klass, result);
1058
+ }
1059
+
1060
+ VALUE rb_matrix4x4_create_perspective_off_center(VALUE klass, VALUE left, VALUE right, VALUE bottom, VALUE top, VALUE nearDist, VALUE farDist) {
1061
+ float n = NUM2FLT(nearDist);
1062
+ float f = NUM2FLT(farDist);
1063
+ if (n <= 0.0f)
1064
+ rb_raise(rb_eRangeError, "near plane distance must be value greater than 0.0 (given %f)", n);
1065
+ if (f <= 0.0f)
1066
+ rb_raise(rb_eRangeError, "far plane distance must be value greater than 0.0 (given %f)", n);
1067
+ if (n <= 0.0f)
1068
+ rb_raise(rb_eRangeError, "near plane distance must be less than far plane distance");
1069
+
1070
+ float l = NUM2FLT(left);
1071
+ float r = NUM2FLT(right);
1072
+ float t = NUM2FLT(top);
1073
+ float b = NUM2FLT(bottom);
1074
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1075
+
1076
+ result->m11 = 2.0f * n / (r - l);
1077
+ result->m12 = result->m13 = result->m14 = 0.0f;
1078
+
1079
+ result->m22 = 2.0f * n / (t - b);
1080
+ result->m21 = result->m23 = result->m24 = 0.0f;
1081
+
1082
+ result->m31 = (l + r) / (r - l);
1083
+ result->m32 = (t + b) / (t - b);
1084
+ result->m33 = f / (n - f);
1085
+ result->m34 = -1.0f;
1086
+
1087
+ result->m43 = n * f / (n - f);
1088
+ result->m41 = result->m42 = result->m44 = 0.0f;
1089
+
1090
+ return NUMERIX_WRAP(klass, result);
1091
+ }
1092
+
1093
+ VALUE rb_matrix4x4_create_orthographic(VALUE klass, VALUE width, VALUE height, VALUE zNearPlane, VALUE zFarPlane) {
1094
+ float n = NUM2FLT(zNearPlane);
1095
+ float f = NUM2FLT(zFarPlane);
1096
+
1097
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1098
+
1099
+ result->m11 = 2.0f / NUM2FLT(width);
1100
+ result->m12 = result->m13 = result->m14 = 0.0f;
1101
+
1102
+ result->m22 = 2.0f / NUM2FLT(height);
1103
+ result->m21 = result->m23 = result->m24 = 0.0f;
1104
+
1105
+ result->m33 = 1.0f / (n - f);
1106
+ result->m31 = result->m32 = result->m34 = 0.0f;
1107
+
1108
+ result->m41 = result->m42 = 0.0f;
1109
+ result->m43 = n / (n - f);
1110
+ result->m44 = 1.0f;
1111
+
1112
+ return NUMERIX_WRAP(klass, result);
1113
+ }
1114
+
1115
+ VALUE rb_matrix4x4_create_orthographic_off_center(VALUE klass, VALUE left, VALUE right, VALUE bottom, VALUE top, VALUE zNearPlane, VALUE zFarPlane) {
1116
+ float n = NUM2FLT(zNearPlane);
1117
+ float f = NUM2FLT(zFarPlane);
1118
+ float l = NUM2FLT(left);
1119
+ float r = NUM2FLT(right);
1120
+ float t = NUM2FLT(top);
1121
+ float b = NUM2FLT(bottom);
1122
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1123
+
1124
+ result->m11 = 2.0f / (r - l);
1125
+ result->m12 = result->m13 = result->m14 = 0.0f;
1126
+
1127
+ result->m22 = 2.0f / (t - b);
1128
+ result->m21 = result->m23 = result->m24 = 0.0f;
1129
+
1130
+ result->m33 = 1.0f / (n - f);
1131
+ result->m31 = result->m32 = result->m34 = 0.0f;
1132
+
1133
+ result->m41 = (l + r) / (l - r);
1134
+ result->m42 = (t + b) / (b - t);
1135
+ result->m43 = n / (n - f);
1136
+ result->m44 = 1.0f;
1137
+
1138
+ return NUMERIX_WRAP(klass, result);
1139
+ }
1140
+
1141
+ VALUE rb_matrix4x4_create_look_at(VALUE klass, VALUE camPos, VALUE camTarget, VALUE camUp) {
1142
+ Vector3 *cam, *target, *up;
1143
+ Data_Get_Struct(camPos, Vector3, cam);
1144
+ Data_Get_Struct(camTarget, Vector3, target);
1145
+ Data_Get_Struct(camUp, Vector3, up);
1146
+
1147
+ Vector3 *axis = xmalloc(sizeof(Vector3) * 3);
1148
+ axis[2].x = cam->x - target->x;
1149
+ axis[2].y = cam->y - target->y;
1150
+ axis[2].z = cam->z - target->z;
1151
+ numerix_vec3_normalize(&axis[2]);
1152
+
1153
+ numerix_cross_norm(up, &axis[2], &axis[0]);
1154
+ numerix_cross_norm(&axis[2], &axis[0], &axis[1]);
1155
+
1156
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1157
+
1158
+ result->m11 = axis[0].x;
1159
+ result->m12 = axis[1].x;
1160
+ result->m13 = axis[2].x;
1161
+ result->m14 = 0.0f;
1162
+ result->m21 = axis[0].y;
1163
+ result->m22 = axis[1].y;
1164
+ result->m23 = axis[2].y;
1165
+ result->m24 = 0.0f;
1166
+ result->m31 = axis[0].z;
1167
+ result->m32 = axis[1].z;
1168
+ result->m33 = axis[2].z;
1169
+ result->m34 = 0.0f;
1170
+ result->m41 = -(numerix_vec3_dot(&axis[0], cam));
1171
+ result->m42 = -(numerix_vec3_dot(&axis[1], cam));
1172
+ result->m43 = -(numerix_vec3_dot(&axis[2], cam));
1173
+ result->m44 = 1.0f;
1174
+
1175
+ xfree(axis);
1176
+
1177
+ return NUMERIX_WRAP(klass, result);
1178
+ }
1179
+
1180
+ VALUE rb_matrix4x4_create_world(VALUE klass, VALUE position, VALUE forward, VALUE up) {
1181
+ Vector3 *pos, *f, *u;
1182
+ Data_Get_Struct(position, Vector3, pos);
1183
+ Data_Get_Struct(forward, Vector3, f);
1184
+ Data_Get_Struct(up, Vector3, u);
1185
+
1186
+ Vector3 *axis = xmalloc(sizeof(Vector3) * 3);
1187
+
1188
+ axis[2].x = -f->x;
1189
+ axis[2].y = -f->y;
1190
+ axis[2].z = -f->z;
1191
+ numerix_vec3_normalize(&axis[2]);
1192
+ numerix_cross_norm(u, &axis[2], &axis[0]);
1193
+ numerix_vec3_cross(&axis[2], &axis[0], &axis[1]);
1194
+
1195
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1196
+
1197
+ result->m11 = axis[0].x;
1198
+ result->m12 = axis[0].y;
1199
+ result->m13 = axis[0].z;
1200
+ result->m14 = 0.0f;
1201
+ result->m21 = axis[1].x;
1202
+ result->m22 = axis[1].y;
1203
+ result->m23 = axis[1].z;
1204
+ result->m24 = 0.0f;
1205
+ result->m31 = axis[2].x;
1206
+ result->m32 = axis[2].y;
1207
+ result->m33 = axis[2].z;
1208
+ result->m34 = 0.0f;
1209
+ result->m41 = pos->x;
1210
+ result->m42 = pos->y;
1211
+ result->m43 = pos->z;
1212
+ result->m44 = 1.0f;
1213
+
1214
+ xfree(axis);
1215
+
1216
+ return NUMERIX_WRAP(klass, result);
1217
+ }
1218
+
1219
+ VALUE rb_matrix4x4_from_quaternion(VALUE klass, VALUE quaternion) {
1220
+ Quaternion *q;
1221
+ Data_Get_Struct(quaternion, Quaternion, q);
1222
+
1223
+ float xx = q->x * q->x;
1224
+ float yy = q->y * q->y;
1225
+ float zz = q->z * q->z;
1226
+
1227
+ float xy = q->x * q->y;
1228
+ float wz = q->z * q->w;
1229
+ float xz = q->z * q->x;
1230
+ float wy = q->y * q->w;
1231
+ float yz = q->y * q->z;
1232
+ float wx = q->x * q->w;
1233
+
1234
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1235
+
1236
+ result->m11 = 1.0f - 2.0f * (yy + zz);
1237
+ result->m12 = 2.0f * (xy + wz);
1238
+ result->m13 = 2.0f * (xz - wy);
1239
+ result->m14 = 0.0f;
1240
+ result->m21 = 2.0f * (xy - wz);
1241
+ result->m22 = 1.0f - 2.0f * (zz + xx);
1242
+ result->m23 = 2.0f * (yz + wx);
1243
+ result->m24 = 0.0f;
1244
+ result->m31 = 2.0f * (xz + wy);
1245
+ result->m32 = 2.0f * (yz - wx);
1246
+ result->m33 = 1.0f - 2.0f * (yy + xx);
1247
+ result->m34 = 0.0f;
1248
+ result->m41 = 0.0f;
1249
+ result->m42 = 0.0f;
1250
+ result->m43 = 0.0f;
1251
+ result->m44 = 1.0f;
1252
+
1253
+ return NUMERIX_WRAP(klass, result);
1254
+ }
1255
+
1256
+ VALUE rb_matrix4x4_from_yaw_pitch_roll(VALUE klass, VALUE yaw, VALUE pitch, VALUE roll) {
1257
+ VALUE q = rb_quaternion_from_yaw_pitch_roll(rb_cQuaternion, yaw, pitch, roll);
1258
+ return rb_matrix4x4_from_quaternion(klass, q);
1259
+ }
1260
+
1261
+ VALUE rb_matrix4x4_create_shadow(VALUE klass, VALUE lightDir, VALUE plane) {
1262
+ Vector3 *light;
1263
+ Data_Get_Struct(lightDir, Vector3, light);
1264
+
1265
+ VALUE normPlane = rb_plane_normalize(plane);
1266
+ Plane *p;
1267
+ Data_Get_Struct(normPlane, Plane, p);
1268
+
1269
+ float dot = p->normal.x * light->x + p->normal.y * light->y + p->normal.z * light->z;
1270
+ float a = -p->normal.x;
1271
+ float b = -p->normal.y;
1272
+ float c = -p->normal.z;
1273
+ float d = -p->distance;
1274
+
1275
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1276
+
1277
+ result->m11 = a * light->x + dot;
1278
+ result->m21 = b * light->x;
1279
+ result->m31 = c * light->x;
1280
+ result->m41 = d * light->x;
1281
+
1282
+ result->m12 = a * light->y;
1283
+ result->m22 = b * light->y + dot;
1284
+ result->m32 = c * light->y;
1285
+ result->m42 = d * light->y;
1286
+
1287
+ result->m13 = a * light->z;
1288
+ result->m23 = b * light->z;
1289
+ result->m33 = c * light->z + dot;
1290
+ result->m43 = d * light->z;
1291
+
1292
+ result->m14 = 0.0f;
1293
+ result->m24 = 0.0f;
1294
+ result->m34 = 0.0f;
1295
+ result->m44 = dot;
1296
+
1297
+ return NUMERIX_WRAP(klass, result);
1298
+ }
1299
+
1300
+ VALUE rb_matrix4x4_create_reflection(VALUE klass, VALUE plane) {
1301
+ VALUE normPlane = rb_plane_normalize(plane);
1302
+ Plane *p;
1303
+ Data_Get_Struct(normPlane, Plane, p);
1304
+
1305
+ float a = p->normal.x;
1306
+ float b = p->normal.y;
1307
+ float c = p->normal.z;
1308
+
1309
+ float fa = -2.0f * a;
1310
+ float fb = -2.0f * b;
1311
+ float fc = -2.0f * c;
1312
+
1313
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1314
+
1315
+ result->m11 = fa * a + 1.0f;
1316
+ result->m12 = fb * a;
1317
+ result->m13 = fc * a;
1318
+ result->m14 = 0.0f;
1319
+
1320
+ result->m21 = fa * b;
1321
+ result->m22 = fb * b + 1.0f;
1322
+ result->m23 = fc * b;
1323
+ result->m24 = 0.0f;
1324
+
1325
+ result->m31 = fa * c;
1326
+ result->m32 = fb * c;
1327
+ result->m33 = fc * c + 1.0f;
1328
+ result->m34 = 0.0f;
1329
+
1330
+ result->m41 = fa * p->distance;
1331
+ result->m42 = fb * p->distance;
1332
+ result->m43 = fc * p->distance;
1333
+ result->m44 = 1.0f;
1334
+
1335
+ return NUMERIX_WRAP(klass, result);
1336
+ }
1337
+
1338
+ VALUE rb_matrix4x4_transform(VALUE self, VALUE quaternion) {
1339
+ Matrix4x4 *m, *result;
1340
+ Quaternion *rotation;
1341
+ Data_Get_Struct(self, Matrix4x4, m);
1342
+ Data_Get_Struct(quaternion, Quaternion, rotation);
1343
+
1344
+ // Compute rotation matrix.
1345
+ float x2 = rotation->x + rotation->x;
1346
+ float y2 = rotation->y + rotation->y;
1347
+ float z2 = rotation->z + rotation->z;
1348
+
1349
+ float wx2 = rotation->w * x2;
1350
+ float wy2 = rotation->w * y2;
1351
+ float wz2 = rotation->w * z2;
1352
+ float xx2 = rotation->x * x2;
1353
+ float xy2 = rotation->x * y2;
1354
+ float xz2 = rotation->x * z2;
1355
+ float yy2 = rotation->y * y2;
1356
+ float yz2 = rotation->y * z2;
1357
+ float zz2 = rotation->z * z2;
1358
+
1359
+ float q11 = 1.0f - yy2 - zz2;
1360
+ float q21 = xy2 - wz2;
1361
+ float q31 = xz2 + wy2;
1362
+
1363
+ float q12 = xy2 + wz2;
1364
+ float q22 = 1.0f - xx2 - zz2;
1365
+ float q32 = yz2 - wx2;
1366
+
1367
+ float q13 = xz2 - wy2;
1368
+ float q23 = yz2 + wx2;
1369
+ float q33 = 1.0f - xx2 - yy2;
1370
+
1371
+ result = ALLOC(Matrix4x4);
1372
+
1373
+ // First row
1374
+ result->m11 = m->m11 * q11 + m->m12 * q21 + m->m13 * q31;
1375
+ result->m12 = m->m11 * q12 + m->m12 * q22 + m->m13 * q32;
1376
+ result->m13 = m->m11 * q13 + m->m12 * q23 + m->m13 * q33;
1377
+ result->m14 = m->m14;
1378
+
1379
+ // Second row
1380
+ result->m21 = m->m21 * q11 + m->m22 * q21 + m->m23 * q31;
1381
+ result->m22 = m->m21 * q12 + m->m22 * q22 + m->m23 * q32;
1382
+ result->m23 = m->m21 * q13 + m->m22 * q23 + m->m23 * q33;
1383
+ result->m24 = m->m24;
1384
+
1385
+ // Third row
1386
+ result->m31 = m->m31 * q11 + m->m32 * q21 + m->m33 * q31;
1387
+ result->m32 = m->m31 * q12 + m->m32 * q22 + m->m33 * q32;
1388
+ result->m33 = m->m31 * q13 + m->m32 * q23 + m->m33 * q33;
1389
+ result->m34 = m->m34;
1390
+
1391
+ // Fourth row
1392
+ result->m41 = m->m41 * q11 + m->m42 * q21 + m->m43 * q31;
1393
+ result->m42 = m->m41 * q12 + m->m42 * q22 + m->m43 * q32;
1394
+ result->m43 = m->m41 * q13 + m->m42 * q23 + m->m43 * q33;
1395
+ result->m44 = m->m44;
1396
+
1397
+ return NUMERIX_WRAP(CLASS_OF(self), result);
1398
+ }
1399
+
1400
+ VALUE rb_matrix4x4_transform_bang(VALUE self, VALUE quaternion) {
1401
+ MATRIX4X4();
1402
+ Quaternion *rotation;
1403
+ Data_Get_Struct(quaternion, Quaternion, rotation);
1404
+
1405
+ // Compute rotation matrix.
1406
+ float x2 = rotation->x + rotation->x;
1407
+ float y2 = rotation->y + rotation->y;
1408
+ float z2 = rotation->z + rotation->z;
1409
+
1410
+ float wx2 = rotation->w * x2;
1411
+ float wy2 = rotation->w * y2;
1412
+ float wz2 = rotation->w * z2;
1413
+ float xx2 = rotation->x * x2;
1414
+ float xy2 = rotation->x * y2;
1415
+ float xz2 = rotation->x * z2;
1416
+ float yy2 = rotation->y * y2;
1417
+ float yz2 = rotation->y * z2;
1418
+ float zz2 = rotation->z * z2;
1419
+
1420
+ float q11 = 1.0f - yy2 - zz2;
1421
+ float q21 = xy2 - wz2;
1422
+ float q31 = xz2 + wy2;
1423
+
1424
+ float q12 = xy2 + wz2;
1425
+ float q22 = 1.0f - xx2 - zz2;
1426
+ float q32 = yz2 - wx2;
1427
+
1428
+ float q13 = xz2 - wy2;
1429
+ float q23 = yz2 + wx2;
1430
+ float q33 = 1.0f - xx2 - yy2;
1431
+
1432
+ // First row
1433
+ m->m11 = m->m11 * q11 + m->m12 * q21 + m->m13 * q31;
1434
+ m->m12 = m->m11 * q12 + m->m12 * q22 + m->m13 * q32;
1435
+ m->m13 = m->m11 * q13 + m->m12 * q23 + m->m13 * q33;
1436
+ m->m14 = m->m14;
1437
+
1438
+ // Second row
1439
+ m->m21 = m->m21 * q11 + m->m22 * q21 + m->m23 * q31;
1440
+ m->m22 = m->m21 * q12 + m->m22 * q22 + m->m23 * q32;
1441
+ m->m23 = m->m21 * q13 + m->m22 * q23 + m->m23 * q33;
1442
+ m->m24 = m->m24;
1443
+
1444
+ // Third row
1445
+ m->m31 = m->m31 * q11 + m->m32 * q21 + m->m33 * q31;
1446
+ m->m32 = m->m31 * q12 + m->m32 * q22 + m->m33 * q32;
1447
+ m->m33 = m->m31 * q13 + m->m32 * q23 + m->m33 * q33;
1448
+ m->m34 = m->m34;
1449
+
1450
+ // Fourth row
1451
+ m->m41 = m->m41 * q11 + m->m42 * q21 + m->m43 * q31;
1452
+ m->m42 = m->m41 * q12 + m->m42 * q22 + m->m43 * q32;
1453
+ m->m43 = m->m41 * q13 + m->m42 * q23 + m->m43 * q33;
1454
+ m->m44 = m->m44;
1455
+
1456
+ return self;
1457
+ }
1458
+
1459
+ VALUE rb_matrix4x4_transpose(VALUE self) {
1460
+ MATRIX4X4();
1461
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1462
+
1463
+ result->m11 = m->m11;
1464
+ result->m12 = m->m21;
1465
+ result->m13 = m->m31;
1466
+ result->m14 = m->m41;
1467
+ result->m21 = m->m12;
1468
+ result->m22 = m->m22;
1469
+ result->m23 = m->m32;
1470
+ result->m24 = m->m42;
1471
+ result->m31 = m->m13;
1472
+ result->m32 = m->m23;
1473
+ result->m33 = m->m33;
1474
+ result->m34 = m->m43;
1475
+ result->m41 = m->m14;
1476
+ result->m42 = m->m24;
1477
+ result->m43 = m->m34;
1478
+ result->m44 = m->m44;
1479
+
1480
+ return NUMERIX_WRAP(CLASS_OF(self), result);
1481
+ }
1482
+
1483
+ VALUE rb_matrix4x4_lerp_s(VALUE klass, VALUE matrix1, VALUE matrix2, VALUE amount) {
1484
+ Matrix4x4 *m1, *m2, *result;
1485
+ Data_Get_Struct(matrix1, Matrix4x4, m1);
1486
+ Data_Get_Struct(matrix2, Matrix4x4, m2);
1487
+ result = ALLOC(Matrix4x4);
1488
+ float weight = NUMERIX_CLAMP(NUM2FLT(amount), 0.0f, 1.0f);
1489
+
1490
+ // First row
1491
+ result->m11 = m1->m11 + (m2->m11 - m1->m11) * weight;
1492
+ result->m12 = m1->m12 + (m2->m12 - m1->m12) * weight;
1493
+ result->m13 = m1->m13 + (m2->m13 - m1->m13) * weight;
1494
+ result->m14 = m1->m14 + (m2->m14 - m1->m14) * weight;
1495
+
1496
+ // Second row
1497
+ result->m21 = m1->m21 + (m2->m21 - m1->m21) * weight;
1498
+ result->m22 = m1->m22 + (m2->m22 - m1->m22) * weight;
1499
+ result->m23 = m1->m23 + (m2->m23 - m1->m23) * weight;
1500
+ result->m24 = m1->m24 + (m2->m24 - m1->m24) * weight;
1501
+
1502
+ // Third row
1503
+ result->m31 = m1->m31 + (m2->m31 - m1->m31) * weight;
1504
+ result->m32 = m1->m32 + (m2->m32 - m1->m32) * weight;
1505
+ result->m33 = m1->m33 + (m2->m33 - m1->m33) * weight;
1506
+ result->m34 = m1->m34 + (m2->m34 - m1->m34) * weight;
1507
+
1508
+ // Fourth row
1509
+ result->m41 = m1->m41 + (m2->m41 - m1->m41) * weight;
1510
+ result->m42 = m1->m42 + (m2->m42 - m1->m42) * weight;
1511
+ result->m43 = m1->m43 + (m2->m43 - m1->m43) * weight;
1512
+ result->m44 = m1->m44 + (m2->m44 - m1->m44) * weight;
1513
+
1514
+ return NUMERIX_WRAP(klass, result);
1515
+ }
1516
+
1517
+ VALUE rb_matrix4x4_negate(VALUE self) {
1518
+ MATRIX4X4();
1519
+ Matrix4x4 *result = ALLOC(Matrix4x4);
1520
+
1521
+ result->m11 = -m->m11;
1522
+ result->m12 = -m->m12;
1523
+ result->m13 = -m->m13;
1524
+ result->m14 = -m->m14;
1525
+ result->m21 = -m->m21;
1526
+ result->m22 = -m->m22;
1527
+ result->m23 = -m->m23;
1528
+ result->m24 = -m->m24;
1529
+ result->m31 = -m->m31;
1530
+ result->m32 = -m->m32;
1531
+ result->m33 = -m->m33;
1532
+ result->m34 = -m->m34;
1533
+ result->m41 = -m->m41;
1534
+ result->m42 = -m->m42;
1535
+ result->m43 = -m->m43;
1536
+ result->m44 = -m->m44;
1537
+
1538
+ return NUMERIX_WRAP(CLASS_OF(self), result);
1539
+ }
1540
+
1541
+ VALUE rb_matrix4x4_add(VALUE self, VALUE other) {
1542
+ Matrix4x4 *m1, *m2, *result;
1543
+ Data_Get_Struct(self, Matrix4x4, m1);
1544
+ Data_Get_Struct(other, Matrix4x4, m2);
1545
+ result = ALLOC(Matrix4x4);
1546
+
1547
+ result->m11 = m1->m11 + m2->m11;
1548
+ result->m12 = m1->m12 + m2->m12;
1549
+ result->m13 = m1->m13 + m2->m13;
1550
+ result->m14 = m1->m14 + m2->m14;
1551
+ result->m21 = m1->m21 + m2->m21;
1552
+ result->m22 = m1->m22 + m2->m22;
1553
+ result->m23 = m1->m23 + m2->m23;
1554
+ result->m24 = m1->m24 + m2->m24;
1555
+ result->m31 = m1->m31 + m2->m31;
1556
+ result->m32 = m1->m32 + m2->m32;
1557
+ result->m33 = m1->m33 + m2->m33;
1558
+ result->m34 = m1->m34 + m2->m34;
1559
+ result->m41 = m1->m41 + m2->m41;
1560
+ result->m42 = m1->m42 + m2->m42;
1561
+ result->m43 = m1->m43 + m2->m43;
1562
+ result->m44 = m1->m44 + m2->m44;
1563
+
1564
+ return NUMERIX_WRAP(CLASS_OF(self), result);
1565
+ }
1566
+
1567
+ VALUE rb_matrix4x4_subtract(VALUE self, VALUE other) {
1568
+ Matrix4x4 *m1, *m2, *result;
1569
+ Data_Get_Struct(self, Matrix4x4, m1);
1570
+ Data_Get_Struct(other, Matrix4x4, m2);
1571
+ result = ALLOC(Matrix4x4);
1572
+
1573
+ result->m11 = m1->m11 - m2->m11;
1574
+ result->m12 = m1->m12 - m2->m12;
1575
+ result->m13 = m1->m13 - m2->m13;
1576
+ result->m14 = m1->m14 - m2->m14;
1577
+ result->m21 = m1->m21 - m2->m21;
1578
+ result->m22 = m1->m22 - m2->m22;
1579
+ result->m23 = m1->m23 - m2->m23;
1580
+ result->m24 = m1->m24 - m2->m24;
1581
+ result->m31 = m1->m31 - m2->m31;
1582
+ result->m32 = m1->m32 - m2->m32;
1583
+ result->m33 = m1->m33 - m2->m33;
1584
+ result->m34 = m1->m34 - m2->m34;
1585
+ result->m41 = m1->m41 - m2->m41;
1586
+ result->m42 = m1->m42 - m2->m42;
1587
+ result->m43 = m1->m43 - m2->m43;
1588
+ result->m44 = m1->m44 - m2->m44;
1589
+
1590
+ return NUMERIX_WRAP(CLASS_OF(self), result);
1591
+ }
1592
+
1593
+ VALUE rb_matrix4x4_multiply(VALUE self, VALUE other) {
1594
+ Matrix4x4 *m1, *result;
1595
+ Data_Get_Struct(self, Matrix4x4, m1);
1596
+ result = ALLOC(Matrix4x4);
1597
+
1598
+ if (NUMERIX_TYPE_P(other, rb_cMatrix4x4)) {
1599
+ Matrix4x4 *m2;
1600
+ Data_Get_Struct(other, Matrix4x4, m2);
1601
+
1602
+ // First row
1603
+ result->m11 = m1->m11 * m2->m11 + m1->m12 * m2->m21 + m1->m13 * m2->m31 + m1->m14 * m2->m41;
1604
+ result->m12 = m1->m11 * m2->m12 + m1->m12 * m2->m22 + m1->m13 * m2->m32 + m1->m14 * m2->m42;
1605
+ result->m13 = m1->m11 * m2->m13 + m1->m12 * m2->m23 + m1->m13 * m2->m33 + m1->m14 * m2->m43;
1606
+ result->m14 = m1->m11 * m2->m14 + m1->m12 * m2->m24 + m1->m13 * m2->m34 + m1->m14 * m2->m44;
1607
+
1608
+ // Second row
1609
+ result->m21 = m1->m21 * m2->m11 + m1->m22 * m2->m21 + m1->m23 * m2->m31 + m1->m24 * m2->m41;
1610
+ result->m22 = m1->m21 * m2->m12 + m1->m22 * m2->m22 + m1->m23 * m2->m32 + m1->m24 * m2->m42;
1611
+ result->m23 = m1->m21 * m2->m13 + m1->m22 * m2->m23 + m1->m23 * m2->m33 + m1->m24 * m2->m43;
1612
+ result->m24 = m1->m21 * m2->m14 + m1->m22 * m2->m24 + m1->m23 * m2->m34 + m1->m24 * m2->m44;
1613
+
1614
+ // Third row
1615
+ result->m31 = m1->m31 * m2->m11 + m1->m32 * m2->m21 + m1->m33 * m2->m31 + m1->m34 * m2->m41;
1616
+ result->m32 = m1->m31 * m2->m12 + m1->m32 * m2->m22 + m1->m33 * m2->m32 + m1->m34 * m2->m42;
1617
+ result->m33 = m1->m31 * m2->m13 + m1->m32 * m2->m23 + m1->m33 * m2->m33 + m1->m34 * m2->m43;
1618
+ result->m34 = m1->m31 * m2->m14 + m1->m32 * m2->m24 + m1->m33 * m2->m34 + m1->m34 * m2->m44;
1619
+
1620
+ // Fourth row
1621
+ result->m41 = m1->m41 * m2->m11 + m1->m42 * m2->m21 + m1->m43 * m2->m31 + m1->m44 * m2->m41;
1622
+ result->m42 = m1->m41 * m2->m12 + m1->m42 * m2->m22 + m1->m43 * m2->m32 + m1->m44 * m2->m42;
1623
+ result->m43 = m1->m41 * m2->m13 + m1->m42 * m2->m23 + m1->m43 * m2->m33 + m1->m44 * m2->m43;
1624
+ result->m44 = m1->m41 * m2->m14 + m1->m42 * m2->m24 + m1->m43 * m2->m34 + m1->m44 * m2->m44;
1625
+ } else {
1626
+ float scalar = NUM2FLT(other);
1627
+ result->m11 = m1->m11 * scalar;
1628
+ result->m12 = m1->m12 * scalar;
1629
+ result->m13 = m1->m13 * scalar;
1630
+ result->m14 = m1->m14 * scalar;
1631
+ result->m21 = m1->m21 * scalar;
1632
+ result->m22 = m1->m22 * scalar;
1633
+ result->m23 = m1->m23 * scalar;
1634
+ result->m24 = m1->m24 * scalar;
1635
+ result->m31 = m1->m31 * scalar;
1636
+ result->m32 = m1->m32 * scalar;
1637
+ result->m33 = m1->m33 * scalar;
1638
+ result->m34 = m1->m34 * scalar;
1639
+ result->m41 = m1->m41 * scalar;
1640
+ result->m42 = m1->m42 * scalar;
1641
+ result->m43 = m1->m43 * scalar;
1642
+ result->m44 = m1->m44 * scalar;
1643
+ }
1644
+
1645
+ return NUMERIX_WRAP(CLASS_OF(self), result);
1646
+ }
1647
+
1648
+ VALUE rb_matrix4x4_invert(VALUE self) {
1649
+ Matrix4x4 *mat, *result;
1650
+ Data_Get_Struct(self, Matrix4x4, mat);
1651
+ result = ALLOC(Matrix4x4);
1652
+ // -1
1653
+ // If you have matrix M, inverse Matrix M can compute
1654
+ //
1655
+ // -1 1
1656
+ // M = --------- A
1657
+ // det(M)
1658
+ //
1659
+ // A is adjugate (adjoint) of M, where,
1660
+ //
1661
+ // T
1662
+ // A = C
1663
+ //
1664
+ // C is Cofactor matrix of M, where,
1665
+ // i + j
1666
+ // C = (-1) * det(M )
1667
+ // ij ij
1668
+ //
1669
+ // [ a b c d ]
1670
+ // M = [ e f g h ]
1671
+ // [ i j k l ]
1672
+ // [ m n o p ]
1673
+ //
1674
+ // First Row
1675
+ // 2 | f g h |
1676
+ // C = (-1) | j k l | = + ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) )
1677
+ // 11 | n o p |
1678
+ //
1679
+ // 3 | e g h |
1680
+ // C = (-1) | i k l | = - ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) )
1681
+ // 12 | m o p |
1682
+ //
1683
+ // 4 | e f h |
1684
+ // C = (-1) | i j l | = + ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) )
1685
+ // 13 | m n p |
1686
+ //
1687
+ // 5 | e f g |
1688
+ // C = (-1) | i j k | = - ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) )
1689
+ // 14 | m n o |
1690
+ //
1691
+ // Second Row
1692
+ // 3 | b c d |
1693
+ // C = (-1) | j k l | = - ( b ( kp - lo ) - c ( jp - ln ) + d ( jo - kn ) )
1694
+ // 21 | n o p |
1695
+ //
1696
+ // 4 | a c d |
1697
+ // C = (-1) | i k l | = + ( a ( kp - lo ) - c ( ip - lm ) + d ( io - km ) )
1698
+ // 22 | m o p |
1699
+ //
1700
+ // 5 | a b d |
1701
+ // C = (-1) | i j l | = - ( a ( jp - ln ) - b ( ip - lm ) + d ( in - jm ) )
1702
+ // 23 | m n p |
1703
+ //
1704
+ // 6 | a b c |
1705
+ // C = (-1) | i j k | = + ( a ( jo - kn ) - b ( io - km ) + c ( in - jm ) )
1706
+ // 24 | m n o |
1707
+ //
1708
+ // Third Row
1709
+ // 4 | b c d |
1710
+ // C = (-1) | f g h | = + ( b ( gp - ho ) - c ( fp - hn ) + d ( fo - gn ) )
1711
+ // 31 | n o p |
1712
+ //
1713
+ // 5 | a c d |
1714
+ // C = (-1) | e g h | = - ( a ( gp - ho ) - c ( ep - hm ) + d ( eo - gm ) )
1715
+ // 32 | m o p |
1716
+ //
1717
+ // 6 | a b d |
1718
+ // C = (-1) | e f h | = + ( a ( fp - hn ) - b ( ep - hm ) + d ( en - fm ) )
1719
+ // 33 | m n p |
1720
+ //
1721
+ // 7 | a b c |
1722
+ // C = (-1) | e f g | = - ( a ( fo - gn ) - b ( eo - gm ) + c ( en - fm ) )
1723
+ // 34 | m n o |
1724
+ //
1725
+ // Fourth Row
1726
+ // 5 | b c d |
1727
+ // C = (-1) | f g h | = - ( b ( gl - hk ) - c ( fl - hj ) + d ( fk - gj ) )
1728
+ // 41 | j k l |
1729
+ //
1730
+ // 6 | a c d |
1731
+ // C = (-1) | e g h | = + ( a ( gl - hk ) - c ( el - hi ) + d ( ek - gi ) )
1732
+ // 42 | i k l |
1733
+ //
1734
+ // 7 | a b d |
1735
+ // C = (-1) | e f h | = - ( a ( fl - hj ) - b ( el - hi ) + d ( ej - fi ) )
1736
+ // 43 | i j l |
1737
+ //
1738
+ // 8 | a b c |
1739
+ // C = (-1) | e f g | = + ( a ( fk - gj ) - b ( ek - gi ) + c ( ej - fi ) )
1740
+ // 44 | i j k |
1741
+ //
1742
+ // Cost of operation
1743
+ // 53 adds, 104 muls, and 1 div.
1744
+ float a = mat->m11, b = mat->m12, c = mat->m13, d = mat->m14;
1745
+ float e = mat->m21, f = mat->m22, g = mat->m23, h = mat->m24;
1746
+ float i = mat->m31, j = mat->m32, k = mat->m33, l = mat->m34;
1747
+ float m = mat->m41, n = mat->m42, o = mat->m43, p = mat->m44;
1748
+
1749
+ float kp_lo = k * p - l * o;
1750
+ float jp_ln = j * p - l * n;
1751
+ float jo_kn = j * o - k * n;
1752
+ float ip_lm = i * p - l * m;
1753
+ float io_km = i * o - k * m;
1754
+ float in_jm = i * n - j * m;
1755
+
1756
+ float a11 = +(f * kp_lo - g * jp_ln + h * jo_kn);
1757
+ float a12 = -(e * kp_lo - g * ip_lm + h * io_km);
1758
+ float a13 = +(e * jp_ln - f * ip_lm + h * in_jm);
1759
+ float a14 = -(e * jo_kn - f * io_km + g * in_jm);
1760
+
1761
+ float det = a * a11 + b * a12 + c * a13 + d * a14;
1762
+
1763
+ if (fabsf(det) < FLT_EPSILON) {
1764
+ // invalid
1765
+ float *matp = (float *)mat;
1766
+ for (int i = 0; i < 16; i++)
1767
+ matp[i] = NAN;
1768
+ } else {
1769
+ float invDet = 1.0f / det;
1770
+
1771
+ result->m11 = a11 * invDet;
1772
+ result->m21 = a12 * invDet;
1773
+ result->m31 = a13 * invDet;
1774
+ result->m41 = a14 * invDet;
1775
+
1776
+ result->m12 = -(b * kp_lo - c * jp_ln + d * jo_kn) * invDet;
1777
+ result->m22 = +(a * kp_lo - c * ip_lm + d * io_km) * invDet;
1778
+ result->m32 = -(a * jp_ln - b * ip_lm + d * in_jm) * invDet;
1779
+ result->m42 = +(a * jo_kn - b * io_km + c * in_jm) * invDet;
1780
+
1781
+ float gp_ho = g * p - h * o;
1782
+ float fp_hn = f * p - h * n;
1783
+ float fo_gn = f * o - g * n;
1784
+ float ep_hm = e * p - h * m;
1785
+ float eo_gm = e * o - g * m;
1786
+ float en_fm = e * n - f * m;
1787
+
1788
+ result->m13 = +(b * gp_ho - c * fp_hn + d * fo_gn) * invDet;
1789
+ result->m23 = -(a * gp_ho - c * ep_hm + d * eo_gm) * invDet;
1790
+ result->m33 = +(a * fp_hn - b * ep_hm + d * en_fm) * invDet;
1791
+ result->m43 = -(a * fo_gn - b * eo_gm + c * en_fm) * invDet;
1792
+
1793
+ float gl_hk = g * l - h * k;
1794
+ float fl_hj = f * l - h * j;
1795
+ float fk_gj = f * k - g * j;
1796
+ float el_hi = e * l - h * i;
1797
+ float ek_gi = e * k - g * i;
1798
+ float ej_fi = e * j - f * i;
1799
+
1800
+ result->m14 = -(b * gl_hk - c * fl_hj + d * fk_gj) * invDet;
1801
+ result->m24 = +(a * gl_hk - c * el_hi + d * ek_gi) * invDet;
1802
+ result->m34 = -(a * fl_hj - b * el_hi + d * ej_fi) * invDet;
1803
+ result->m44 = +(a * fk_gj - b * ek_gi + c * ej_fi) * invDet;
1804
+ }
1805
+
1806
+ return NUMERIX_WRAP(CLASS_OF(self), result);
1807
+ }