cglm 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,308 @@
1
+ #include "rb_cglm.h"
2
+
3
+ /* call-seq: identity([dest]) => dest | new Mat4
4
+ *
5
+ * Sets `dest` to the identity if provided. If omitted, a new Mat4 is created
6
+ * and set to the identity. `dest` or the new Mat4 is returned.
7
+ */
8
+ VALUE rb_cglm_mat4_new_identity(int argc, VALUE *argv, VALUE self) {
9
+ VALUE dest;
10
+ rb_scan_args(argc, argv, "01", &dest);
11
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
12
+ glm_mat4_identity(VAL2MAT4(dest));
13
+ return dest;
14
+ }
15
+
16
+ /* call-seq: quat_rotate_at(quat, pivot_point[, dest]) => dest | new Mat4
17
+ *
18
+ * Creates a new transformation matrix using the quaternion at the pivot
19
+ * point. Places the result into `dest`, or creates a new Mat4 if `dest` is
20
+ * omitted. Returns `dest`.
21
+ */
22
+ VALUE rb_cglm_mat4_new_rotate_at(int argc, VALUE *argv, VALUE self) {
23
+ VALUE q, pivot, dest;
24
+ rb_scan_args(argc, argv, "21", &q, &pivot, &dest);
25
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
26
+ glm_quat_rotate_atm(VAL2MAT4(dest), VAL2QUAT(q), VAL2VEC3(pivot));
27
+ return dest;
28
+ }
29
+
30
+ VALUE rb_cglm_mat4_aref(VALUE self, VALUE index) {
31
+ CHECK_RANGE(index, 0, 3);
32
+ float *addr = (float *) VAL2MAT4(self);
33
+ return VEC4_NEW(addr + (NUM2INT(index) * 4));
34
+ }
35
+
36
+ VALUE rb_cglm_mat4_aset(VALUE self, VALUE index, VALUE val) {
37
+ CHECK_RANGE(index, 0, 3);
38
+ if (rb_funcall(val, rb_intern("kind_of?"), 1, rb_cVec4))
39
+ memcpy(&(VAL2MAT4(self)[NUM2INT(index)]), &VAL2VEC4(val), sizeof(vec4));
40
+ else if (rb_funcall(val, rb_intern("kind_of?"), 1, rb_cVec3))
41
+ memcpy(&(VAL2MAT4(self)[NUM2INT(index)]), &VAL2VEC3(val), sizeof(vec3));
42
+ else {
43
+ VALUE row = rb_cglm_mat4_aref(self, index);
44
+ for (int i = 0; i < 4; i++) {
45
+ VALUE v = rb_funcall(val, rb_intern("[]"), 1, INT2NUM(i));
46
+ if (!NIL_P(v)) {
47
+ rb_funcall(row, rb_intern("[]="), 2, INT2NUM(i), v);
48
+ }
49
+ }
50
+ }
51
+ return self;
52
+ }
53
+
54
+ VALUE rb_cglm_mat4_to_mat3(int argc, VALUE *argv, VALUE self) {
55
+ VALUE dest;
56
+ if (argc == 0) dest = MAT3_NEW(ALLOC_MAT3);
57
+ else dest = argv[0];
58
+ glm_mat4_pick3(VAL2MAT4(self), VAL2MAT3(dest));
59
+ return dest;
60
+ }
61
+
62
+ VALUE rb_cglm_mat4_to_transposed_mat3(int argc, VALUE *argv, VALUE self) {
63
+ VALUE dest;
64
+ if (argc == 0) dest = MAT3_NEW(ALLOC_MAT3);
65
+ dest = argv[0];
66
+ glm_mat4_pick3t(VAL2MAT4(self), VAL2MAT3(dest));
67
+ return dest;
68
+ }
69
+
70
+ VALUE rb_cglm_mat4_mul_mat4(int argc, VALUE *argv, VALUE self) {
71
+ VALUE other, dest;
72
+ rb_scan_args(argc, argv, "11", &other, &dest);
73
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
74
+ glm_mat4_mul(VAL2MAT4(self), VAL2MAT4(other), VAL2MAT4(dest));
75
+ return dest;
76
+ }
77
+
78
+ VALUE rb_cglm_mat4_mul_vec4(int argc, VALUE *argv, VALUE self) {
79
+ VALUE other, dest;
80
+ rb_scan_args(argc, argv, "11", &other, &dest);
81
+ if (NIL_P(dest)) dest = VEC4_NEW(ALLOC_VEC4);
82
+ glm_mat4_mulv(VAL2MAT4(self), VAL2VEC4(other), VAL2VEC4(dest));
83
+ return dest;
84
+ }
85
+
86
+ VALUE rb_cglm_mat4_mul_vec3(int argc, VALUE *argv, VALUE self) {
87
+ VALUE other, last, dest;
88
+ rb_scan_args(argc, argv, "12", &other, &last, &dest);
89
+ if (NIL_P(last)) last = DBL2NUM(1.0);
90
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
91
+ glm_mat4_mulv3(VAL2MAT4(self), VAL2VEC3(other), NUM2FLT(last), VAL2VEC3(dest));
92
+ return dest;
93
+ }
94
+
95
+ VALUE rb_cglm_mat4_to_quat(int argc, VALUE *argv, VALUE self) {
96
+ VALUE dest;
97
+ rb_scan_args(argc, argv, "01", &dest);
98
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
99
+ glm_mat4_quat(VAL2MAT4(self), VAL2QUAT(dest));
100
+ return dest;
101
+ }
102
+
103
+ VALUE rb_cglm_mat4_transpose(int argc, VALUE *argv, VALUE self) {
104
+ VALUE dest;
105
+ rb_scan_args(argc, argv, "01", &dest);
106
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
107
+ glm_mat4_transpose_to(VAL2MAT4(self), VAL2MAT4(dest));
108
+ return dest;
109
+ }
110
+
111
+ VALUE rb_cglm_mat4_transpose_self(VALUE self) {
112
+ glm_mat4_transpose(VAL2MAT4(self));
113
+ return self;
114
+ }
115
+
116
+ /* call-seq: mul_scalar(scalar[, dest]) => dest | new Mat3
117
+ *
118
+ * Multiplies each element in this matrix by the specified scalar amount.
119
+ * Places the result in `dest` and returns it, creating a new Mat4 if `dest`
120
+ * is omitted.
121
+ */
122
+ VALUE rb_cglm_mat4_mul_scalar(int argc, VALUE *argv, VALUE self) {
123
+ VALUE scalar, dest;
124
+ rb_scan_args(argc, argv, "11", &scalar, &dest);
125
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
126
+ memcpy(&VAL2MAT4(self), &VAL2MAT4(dest), sizeof(mat4));
127
+ glm_mat4_scale(VAL2MAT4(dest), NUM2FLT(scalar));
128
+ return dest;
129
+ }
130
+
131
+ /* call-seq: mul_scalar!(scalar) => self
132
+ *
133
+ * Multiplies each element in this matrix by the specified scalar amount,
134
+ * modifying `self` in-place and returning it.
135
+ */
136
+ VALUE rb_cglm_mat4_mul_scalar_self(VALUE self, VALUE scalar) {
137
+ glm_mat4_scale(VAL2MAT4(self), NUM2FLT(scalar));
138
+ return self;
139
+ }
140
+
141
+ /* call-seq: determinant => Numeric
142
+ */
143
+ VALUE rb_cglm_mat4_determinant(VALUE self) {
144
+ return DBL2NUM(glm_mat4_det(VAL2MAT4(self)));
145
+ }
146
+
147
+ /* call-seq: invert([dest]) => dest | new Mat4
148
+ *
149
+ * Computes the inverse of this matrix and stores it in `dest`, creating a
150
+ * new Mat4 if `dest` is omitted. Returns `dest`.
151
+ */
152
+ VALUE rb_cglm_mat4_invert(int argc, VALUE *argv, VALUE self) {
153
+ VALUE dest;
154
+ rb_scan_args(argc, argv, "01", &dest);
155
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
156
+ glm_mat4_inv(VAL2MAT4(self), VAL2MAT4(dest));
157
+ return dest;
158
+ }
159
+
160
+ /* call-seq: invert! => self
161
+ *
162
+ * Computes the inverse of this matrix in-place and returns `self`.
163
+ */
164
+ VALUE rb_cglm_mat4_invert_self(int argc, VALUE *argv, VALUE self) {
165
+ glm_mat4_inv(VAL2MAT4(self), VAL2MAT4(self));
166
+ return self;
167
+ }
168
+
169
+ /* call-seq: invert_fast([dest]) => dest | new Mat4
170
+ *
171
+ * Computes the inverse of this matrix and stores it in `dest`, creating a
172
+ * new Mat4 if `dest` is omitted. Returns `dest`.
173
+ *
174
+ * * NOTE: This method uses reciprocal approximation without extra corrections,
175
+ * e.g Newton-Raphson. This should work faster than normal, but will be less
176
+ * precise.
177
+ */
178
+ VALUE rb_cglm_mat4_invert_fast(int argc, VALUE *argv, VALUE self) {
179
+ VALUE dest;
180
+ rb_scan_args(argc, argv, "01", &dest);
181
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
182
+ glm_mat4_inv_fast(VAL2MAT4(self), VAL2MAT4(dest));
183
+ return dest;
184
+ }
185
+
186
+ /* call-seq: invert_fast!([dest]) => dest | new Mat4
187
+ *
188
+ * Computes the inverse of this matrix in-place and returns `self`.
189
+ *
190
+ * * NOTE: This method uses reciprocal approximation without extra corrections,
191
+ * e.g Newton-Raphson. This should work faster than normal, but will be less
192
+ * precise.
193
+ */
194
+ VALUE rb_cglm_mat4_invert_fast_self(int argc, VALUE *argv, VALUE self) {
195
+ glm_mat4_inv_fast(VAL2MAT4(self), VAL2MAT4(self));
196
+ return self;
197
+ }
198
+
199
+ /* call-seq: swap_col!(col1, col2) => self
200
+ *
201
+ * Swaps two matrix columns and returns `self`.
202
+ */
203
+ VALUE rb_cglm_mat4_swap_col_self(VALUE self, VALUE col1, VALUE col2) {
204
+ glm_mat4_swap_col(VAL2MAT4(self), NUM2INT(col1), NUM2INT(col2));
205
+ return self;
206
+ }
207
+
208
+ /* call-seq: swap_row!(row1, row2) => self
209
+ *
210
+ * Swaps two matrix rows and returns `self`.
211
+ */
212
+ VALUE rb_cglm_mat4_swap_row_self(VALUE self, VALUE row1, VALUE row2) {
213
+ glm_mat4_swap_row(VAL2MAT4(self), NUM2INT(row1), NUM2INT(row2));
214
+ return self;
215
+ }
216
+
217
+ VALUE rb_cglm_mat4_size_bytes(VALUE klass) { return SIZET2NUM(mat4_size()); }
218
+
219
+ VALUE rb_cglm_mat4_alignment_bytes(VALUE klass) { return SIZET2NUM(MAT4_ALIGNMENT); }
220
+
221
+ VALUE rb_cglm_mat4_equal(VALUE self, VALUE other) {
222
+ if (memcmp(&VAL2MAT4(self), &VAL2MAT4(other), sizeof(mat4))) return Qfalse;
223
+ return Qtrue;
224
+ }
225
+
226
+ /* call-seq: a =~ b => true|false
227
+ *
228
+ * Returns true if each member of `a` is very close to, but not necessarily
229
+ * exactly equal to, each corresponding member of `b`. This is useful in many
230
+ * circumstances because imprecision introduced by floating point calculations
231
+ * can lead to two expressions which are otherwise mathematically equivalent
232
+ * returning false.
233
+ */
234
+ VALUE rb_cglm_mat4_equalish(int argc, VALUE *argv, VALUE self) {
235
+ VALUE other, epsilon;
236
+ float feps = FLT_EPSILON;
237
+ rb_scan_args(argc, argv, "11", &other, &epsilon);
238
+ if (!NIL_P(epsilon)) feps = NUM2FLT(epsilon);
239
+ mat4 *a = &VAL2MAT4(self);
240
+ mat4 *b = &VAL2MAT4(other);
241
+ for (int i = 0; i < 4; i++) {
242
+ for (int j = 0; j < 4; j++) {
243
+ if (fabsf((*a)[i][j] - (*b)[i][j]) > feps)
244
+ return Qfalse;
245
+ }
246
+ }
247
+ return Qtrue;
248
+ }
249
+
250
+ /* call-seq: random([dest]) => dest | new Mat4
251
+ *
252
+ * Fills `dest` or a new Mat4 with a random translation and rotation, and
253
+ * returns it.
254
+ */
255
+ VALUE rb_cglm_mat4_new_random(int argc, VALUE *argv, VALUE self) {
256
+ VALUE dest;
257
+ rb_scan_args(argc, argv, "01", &dest);
258
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
259
+
260
+ glm_mat4_copy(GLM_MAT4_IDENTITY, VAL2MAT4(dest));
261
+
262
+ /* random position */
263
+ VAL2MAT4(dest)[3][0] = drand48();
264
+ VAL2MAT4(dest)[3][1] = drand48();
265
+ VAL2MAT4(dest)[3][2] = drand48();
266
+
267
+ /* random rotatation around random axis with random angle */
268
+ glm_rotate(VAL2MAT4(dest), drand48(), (vec3){drand48(), drand48(), drand48()});
269
+
270
+ /* random scale */
271
+ /* glm_scale(dest, (vec3){drand48(), drand48(), drand48()}); */
272
+
273
+ return dest;
274
+ }
275
+
276
+ void Init_cglm_mat4() {
277
+ rb_define_method(rb_cMat4, "equalish", rb_cglm_mat4_equalish, -1);
278
+ rb_define_method(rb_cMat4, "==", rb_cglm_mat4_equal, 1);
279
+ rb_define_method(rb_cMat4, "[]", rb_cglm_mat4_aref, 1);
280
+ rb_define_method(rb_cMat4, "[]=", rb_cglm_mat4_aset, 2);
281
+ rb_define_method(rb_cMat4, "to_mat3", rb_cglm_mat4_to_mat3, -1);
282
+ rb_define_method(rb_cMat4, "to_transposed_mat3", rb_cglm_mat4_to_transposed_mat3, -1);
283
+ rb_define_method(rb_cMat4, "to_quat", rb_cglm_mat4_to_quat, -1);
284
+ rb_define_method(rb_cMat4, "mul_mat4", rb_cglm_mat4_mul_mat4, -1);
285
+ rb_define_method(rb_cMat4, "mul_vec4", rb_cglm_mat4_mul_vec4, -1);
286
+ rb_define_method(rb_cMat4, "mul_vec3", rb_cglm_mat4_mul_vec3, -1);
287
+ rb_define_method(rb_cMat4, "mul_scalar", rb_cglm_mat4_mul_scalar, -1);
288
+ rb_define_method(rb_cMat4, "mul_scalar!", rb_cglm_mat4_mul_scalar_self, 0);
289
+ rb_define_method(rb_cMat4, "transpose", rb_cglm_mat4_transpose, -1);
290
+ rb_define_method(rb_cMat4, "transpose!", rb_cglm_mat4_transpose_self, 0);
291
+ rb_define_method(rb_cMat4, "determinant", rb_cglm_mat4_determinant, 0);
292
+ rb_define_method(rb_cMat4, "invert", rb_cglm_mat4_invert, -1);
293
+ rb_define_method(rb_cMat4, "invert_fast", rb_cglm_mat4_invert_fast, -1);
294
+ rb_define_method(rb_cMat4, "invert!", rb_cglm_mat4_invert_self, 0);
295
+ rb_define_method(rb_cMat4, "invert_fast!", rb_cglm_mat4_invert_fast_self, 0);
296
+ rb_define_method(rb_cMat4, "swap_col!", rb_cglm_mat4_swap_col_self, 2);
297
+ rb_define_method(rb_cMat4, "swap_row!", rb_cglm_mat4_swap_row_self, 2);
298
+
299
+ rb_define_alias(rb_cMat4, "det", "determinant");
300
+ rb_define_alias(rb_cMat4, "=~", "equalish");
301
+
302
+ rb_define_singleton_method(rb_cMat4, "random", rb_cglm_mat4_new_random, -1);
303
+ rb_define_singleton_method(rb_cMat4, "rand", rb_cglm_mat4_new_random, -1);
304
+ rb_define_singleton_method(rb_cMat4, "identity", rb_cglm_mat4_new_identity, -1);
305
+ rb_define_singleton_method(rb_cMat4, "quat_rotate_at", rb_cglm_mat4_new_rotate_at, -1);
306
+ rb_define_singleton_method(rb_cMat4, "size", rb_cglm_mat4_size_bytes, 0);
307
+ rb_define_singleton_method(rb_cMat4, "alignment", rb_cglm_mat4_alignment_bytes, 0);
308
+ }
@@ -0,0 +1,36 @@
1
+ #include "rb_cglm.h"
2
+
3
+ /* call-seq: normalize([dest]) => dest | new Plane
4
+ *
5
+ * Normalizes this plane and places the result in `dest`, or allocates a new
6
+ * Plane if `dest` is omitted.
7
+ */
8
+ VALUE rb_cglm_plane_normalize(int argc, VALUE *argv, VALUE self) {
9
+ VALUE dest;
10
+ rb_scan_args(argc, argv, "01", &dest);
11
+ if (NIL_P(dest)) dest = PLANE_NEW(ALLOC_PLANE);
12
+ memcpy(&(VAL2VEC4(self)), &(VAL2VEC4(dest)), sizeof(vec4));
13
+ glm_plane_normalize(VAL2VEC4(dest));
14
+ return dest;
15
+ }
16
+
17
+ /* call-seq: normalize! => self
18
+ *
19
+ * Normalizes this Vec4 (which represents a plane) and returns it.
20
+ */
21
+ VALUE rb_cglm_plane_normalize_self(VALUE self) {
22
+ glm_plane_normalize(VAL2VEC4(self));
23
+ return self;
24
+ }
25
+
26
+ VALUE rb_cglm_plane_size_bytes(VALUE klass) { return SIZET2NUM(plane_size()); }
27
+
28
+ VALUE rb_cglm_plane_alignment_bytes(VALUE klass) { return SIZET2NUM(PLANE_ALIGNMENT); }
29
+
30
+ void Init_cglm_plane() {
31
+ rb_define_method(rb_cPlane, "normalize", rb_cglm_plane_normalize, -1);
32
+ rb_define_method(rb_cPlane, "normalize!", rb_cglm_plane_normalize_self, 0);
33
+
34
+ rb_define_singleton_method(rb_cPlane, "size", rb_cglm_plane_size_bytes, 0);
35
+ rb_define_singleton_method(rb_cPlane, "alignment", rb_cglm_plane_alignment_bytes, 0);
36
+ }
@@ -0,0 +1,99 @@
1
+ #include "rb_cglm.h"
2
+
3
+ /* call-seq: unproject_i(pos, viewport[, dest]) => dest | new Vec3
4
+ *
5
+ * Maps the specified position into the space represented by this matrix,
6
+ * places it in `dest` or a new Vec3 if `dest` is omitted, and returns it.
7
+ *
8
+ * * NOTE: This method assumes that `self` represents the **inverse** of a
9
+ * projection matrix. It's faster than calling #unproject assuming you
10
+ * already have an inverse matrix. If you don't have an inverse, you should
11
+ * just rely on #unproject (to save the overhead of the extra method call),
12
+ * but if you have or need the inverse for other computations, you can use
13
+ * #unproject_i to save yourself the cost of the inversion.
14
+ *
15
+ * * If `self` is an `inverse(projection)` matrix, then the result will be
16
+ * in view space.
17
+ *
18
+ * * If `self` is an `inverse(projection * view)` matrix, then the result will
19
+ * be in world space.
20
+ *
21
+ * * If `self` is an `inverse(projection * view * model)` matrix, then the
22
+ * result will be in object space.
23
+ *
24
+ * * `pos` is a Vec3 specifying the coordinates to unproject.
25
+ *
26
+ * * `viewport` is a Vec4 specifying the dimensions of the viewport in
27
+ * `[x, y, width, height]` format.
28
+ *
29
+ * * `dest` is the Vec3 to place the results into, and will be created if
30
+ * omitted.
31
+ */
32
+ VALUE rb_cglm_project_unproject_i(int argc, VALUE *argv, VALUE self) {
33
+ VALUE pos, viewport, dest;
34
+ rb_scan_args(argc, argv, "21", &pos, &viewport, &dest);
35
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
36
+ glm_unprojecti(VAL2VEC3(pos), VAL2MAT4(self), VAL2VEC4(viewport), VAL2VEC3(dest));
37
+ return dest;
38
+ }
39
+
40
+ /* call-seq: unproject(pos, viewport[, dest]) => dest | new Vec3
41
+ *
42
+ * Maps the specified position into the space represented by this matrix,
43
+ * places it in `dest` or a new Vec3 if `dest` is omitted, and returns it.
44
+ *
45
+ * * NOTE: This method must calculate the inverse of the current matrix. If
46
+ * you already have the inverse handy, you should use #unproject_i for
47
+ * better performance.
48
+ *
49
+ * * If `self` is a `projection` matrix, then the result will be
50
+ * in view space.
51
+ *
52
+ * * If `self` is a `projection * view` matrix, then the result will
53
+ * be in world space.
54
+ *
55
+ * * If `self` is an `projection * view * model` matrix, then the
56
+ * result will be in object space.
57
+ *
58
+ * * `pos` is a Vec3 specifying the coordinates to unproject.
59
+ *
60
+ * * `viewport` is a Vec4 specifying the dimensions of the viewport in
61
+ * `[x, y, width, height]` format.
62
+ *
63
+ * * `dest` is the Vec3 to place the results into, and will be created if
64
+ * omitted.
65
+ */
66
+ VALUE rb_cglm_project_unproject(int argc, VALUE *argv, VALUE self) {
67
+ VALUE pos, viewport, dest;
68
+ rb_scan_args(argc, argv, "21", &pos, &viewport, &dest);
69
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
70
+ glm_unproject(VAL2VEC3(pos), VAL2MAT4(self), VAL2VEC4(viewport), VAL2VEC3(dest));
71
+ return dest;
72
+ }
73
+
74
+ /* call-seq: project(pos, viewport[, dest]) => dest | new Vec3
75
+ *
76
+ * Maps the given object-space coordinates into window coordinates using
77
+ * `self` as the projection matrix.
78
+ *
79
+ * * `pos` is a Vec3 specifying the object-space coordinates.
80
+ *
81
+ * * `viewport` is a Vec4 specifying the dimensions of the viewport in
82
+ * `[x, y, width, height]` format.
83
+ *
84
+ * * `dest` is the Vec3 to place the results into, and will be created if
85
+ * omitted.
86
+ */
87
+ VALUE rb_cglm_project_project(int argc, VALUE *argv, VALUE self) {
88
+ VALUE pos, viewport, dest;
89
+ rb_scan_args(argc, argv, "21", &pos, &viewport, &dest);
90
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
91
+ glm_project(VAL2VEC3(pos), VAL2MAT4(self), VAL2VEC4(viewport), VAL2VEC3(dest));
92
+ return dest;
93
+ }
94
+
95
+ void Init_cglm_project() {
96
+ rb_define_method(rb_cMat4, "unproject_i", rb_cglm_project_unproject_i, -1);
97
+ rb_define_method(rb_cMat4, "unproject", rb_cglm_project_unproject, -1);
98
+ rb_define_method(rb_cMat4, "project", rb_cglm_project_project, -1);
99
+ }
@@ -0,0 +1,358 @@
1
+ #include "rb_cglm.h"
2
+
3
+ /* call-seq: identity([dest]) => dest | new Quat */
4
+ VALUE rb_cglm_quat_new_identity(int argc, VALUE *argv, VALUE self) {
5
+ VALUE dest;
6
+ rb_scan_args(argc, argv, "01", &dest);
7
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
8
+ glm_quat_identity(VAL2QUAT(dest));
9
+ return dest;
10
+ }
11
+
12
+ /* call-seq: axis_angle(axis, angle[, dest]) => dest | new Quat */
13
+ VALUE rb_cglm_quat_new_axis_angle(int argc, VALUE *argv, VALUE self) {
14
+ VALUE axis, angle, dest;
15
+ rb_scan_args(argc, argv, "21", &axis, &angle, &dest);
16
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
17
+ glm_quatv(VAL2QUAT(dest), NUM2FLT(angle), VAL2VEC3(axis));
18
+ return dest;
19
+ }
20
+
21
+ /* call-seq: copy_to(dest) => dest */
22
+ VALUE rb_cglm_quat_copy_to(VALUE self, VALUE dest) {
23
+ glm_quat_copy(VAL2QUAT(self), VAL2QUAT(dest));
24
+ return dest;
25
+ }
26
+
27
+ /* call-seq: normalize([dest]) => dest */
28
+ VALUE rb_cglm_quat_normalize(int argc, VALUE *argv, VALUE self) {
29
+ VALUE dest;
30
+ rb_scan_args(argc, argv, "01", &dest);
31
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
32
+ glm_quat_normalize_to(VAL2QUAT(self), VAL2QUAT(dest));
33
+ return dest;
34
+ }
35
+
36
+ /* call-seq: normalize! => self */
37
+ VALUE rb_cglm_quat_normalize_self(VALUE self) {
38
+ glm_quat_normalize(VAL2QUAT(self));
39
+ return self;
40
+ }
41
+
42
+ /* call-seq: conjugate([dest]) => dest | new Quat */
43
+ VALUE rb_cglm_quat_conjugate(int argc, VALUE *argv, VALUE self) {
44
+ VALUE dest;
45
+ rb_scan_args(argc, argv, "01", &dest);
46
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
47
+ glm_quat_conjugate(VAL2QUAT(self), VAL2QUAT(dest));
48
+ return dest;
49
+ }
50
+
51
+ /* call-seq: invert([dest]) => dest | new Quat */
52
+ VALUE rb_cglm_quat_invert(int argc, VALUE *argv, VALUE self) {
53
+ VALUE dest;
54
+ rb_scan_args(argc, argv, "01", &dest);
55
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
56
+ glm_quat_inv(VAL2QUAT(self), VAL2QUAT(dest));
57
+ return dest;
58
+ }
59
+
60
+ /* call-seq: invert! => self */
61
+ VALUE rb_cglm_quat_invert_self(VALUE self) {
62
+ glm_quat_inv(VAL2QUAT(self), VAL2QUAT(self));
63
+ return self;
64
+ }
65
+
66
+ /* call-seq: real => Numeric
67
+ *
68
+ * Returns the real part of the quaternion.
69
+ */
70
+ VALUE rb_cglm_quat_real(VALUE self) {
71
+ return DBL2NUM(glm_quat_real(VAL2QUAT(self)));
72
+ }
73
+
74
+ /* call-seq: imag([dest]) => dest | new Vec3
75
+ *
76
+ * Returns the imaginary part of the quaternion in `dest`.
77
+ */
78
+ VALUE rb_cglm_quat_imag(int argc, VALUE *argv, VALUE self) {
79
+ VALUE dest;
80
+ rb_scan_args(argc, argv, "01", &dest);
81
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
82
+ glm_quat_imag(VAL2QUAT(self), VAL2VEC3(dest));
83
+ return dest;
84
+ }
85
+
86
+ /* call-seq: imagn([dest]) => dest | new Vec3
87
+ *
88
+ * Returns the imaginary part of the quaternion in `dest`, normalized.
89
+ */
90
+ VALUE rb_cglm_quat_imagn(int argc, VALUE *argv, VALUE self) {
91
+ VALUE dest;
92
+ rb_scan_args(argc, argv, "01", &dest);
93
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
94
+ glm_quat_imagn(VAL2QUAT(self), VAL2VEC3(dest));
95
+ return dest;
96
+ }
97
+
98
+ /* call-seq: imaglen => Numeric
99
+ *
100
+ * Returns the length of the imaginary part of the quaternion.
101
+ */
102
+ VALUE rb_cglm_quat_imaglen(VALUE self) {
103
+ return DBL2NUM(glm_quat_imaglen(VAL2QUAT(self)));
104
+ }
105
+
106
+ /* call-seq: angle => Numeric
107
+ *
108
+ * Returns the angle of the quaternion.
109
+ */
110
+ VALUE rb_cglm_quat_angle(VALUE self) {
111
+ return DBL2NUM(glm_quat_angle(VAL2QUAT(self)));
112
+ }
113
+
114
+ /* call-seq: axis([dest]) => dest | new Vec3
115
+ *
116
+ * Returns the axis of the quaternion in `dest`.
117
+ */
118
+ VALUE rb_cglm_quat_axis(int argc, VALUE *argv, VALUE self) {
119
+ VALUE dest;
120
+ rb_scan_args(argc, argv, "01", &dest);
121
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
122
+ glm_quat_axis(VAL2QUAT(self), VAL2VEC3(dest));
123
+ return dest;
124
+ }
125
+
126
+ /* call-seq: mul_quat(other[, dest]) => dest | new Quat
127
+ *
128
+ * Multiplies `self` by `other` and stores the result in `dest`. If `dest`
129
+ * is omitted, a new Quat is created. `dest` or the new Quat is returned.
130
+ */
131
+ VALUE rb_cglm_quat_mul_quat(int argc, VALUE *argv, VALUE self) {
132
+ VALUE other, dest;
133
+ rb_scan_args(argc, argv, "11", &other, &dest);
134
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
135
+ glm_quat_mul(VAL2QUAT(self), VAL2QUAT(other), VAL2QUAT(dest));
136
+ return dest;
137
+ }
138
+
139
+ /* call-seq: mul_quat!(other) => self
140
+ *
141
+ * Multiplies `self` by `other`. Modifies `self` in-place and returns `self`.
142
+ */
143
+ VALUE rb_cglm_quat_mul_quat_self(VALUE self, VALUE other) {
144
+ quat dest;
145
+ glm_quat_mul(VAL2QUAT(self), VAL2QUAT(other), dest);
146
+ memcpy(&VAL2QUAT(self), &dest, sizeof(quat));
147
+ return self;
148
+ }
149
+
150
+ /* call-seq: to_mat4([dest]) => dest | new Mat4
151
+ *
152
+ * Converts this quaternion into a Mat4. Places the result into `dest` or
153
+ * creates a new Mat4.
154
+ */
155
+ VALUE rb_cglm_quat_to_mat4(int argc, VALUE *argv, VALUE self) {
156
+ VALUE dest;
157
+ rb_scan_args(argc, argv, "01", &dest);
158
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
159
+ glm_quat_mat4(VAL2QUAT(self), VAL2MAT4(dest));
160
+ return dest;
161
+ }
162
+
163
+ /* call-seq: to_transposed_mat4([dest]) => dest | new Mat4
164
+ *
165
+ * Converts this quaternion into a transposed Mat4. Places the result into
166
+ * `dest` or creates a new Mat4.
167
+ */
168
+ VALUE rb_cglm_quat_to_mat4t(int argc, VALUE *argv, VALUE self) {
169
+ VALUE dest;
170
+ rb_scan_args(argc, argv, "01", &dest);
171
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
172
+ glm_quat_mat4t(VAL2QUAT(self), VAL2MAT4(dest));
173
+ return dest;
174
+ }
175
+
176
+ /* call-seq: to_mat3([dest]) => dest | new Mat3
177
+ *
178
+ * Converts this quaternion into a Mat3. Places the result into `dest` or
179
+ * creates a new Mat3.
180
+ */
181
+ VALUE rb_cglm_quat_to_mat3(int argc, VALUE *argv, VALUE self) {
182
+ VALUE dest;
183
+ rb_scan_args(argc, argv, "01", &dest);
184
+ if (NIL_P(dest)) dest = MAT3_NEW(ALLOC_MAT3);
185
+ glm_quat_mat3(VAL2QUAT(self), VAL2MAT3(dest));
186
+ return dest;
187
+ }
188
+
189
+ /* call-seq: to_transposed_mat3([dest]) => dest | new Mat3
190
+ *
191
+ * Converts this quaternion into a transposed Mat3. Places the result into
192
+ * `dest` or creates a new Mat3.
193
+ */
194
+ VALUE rb_cglm_quat_to_mat3t(int argc, VALUE *argv, VALUE self) {
195
+ VALUE dest;
196
+ rb_scan_args(argc, argv, "01", &dest);
197
+ if (NIL_P(dest)) dest = MAT3_NEW(ALLOC_MAT3);
198
+ glm_quat_mat3t(VAL2QUAT(self), VAL2MAT3(dest));
199
+ return dest;
200
+ }
201
+
202
+ /* call-seq: lerp!(from, to, amount) => self */
203
+ VALUE rb_cglm_quat_lerp_self(VALUE self, VALUE from, VALUE to, VALUE amount) {
204
+ glm_quat_lerp(VAL2QUAT(from), VAL2QUAT(to), NUM2FLT(to), VAL2QUAT(self));
205
+ return self;
206
+ }
207
+
208
+ /* call-seq: slerp!(from, to, amount) => self */
209
+ VALUE rb_cglm_quat_slerp_self(VALUE self, VALUE from, VALUE to, VALUE amount) {
210
+ glm_quat_slerp(VAL2QUAT(from), VAL2QUAT(to), NUM2FLT(to), VAL2QUAT(self));
211
+ return self;
212
+ }
213
+
214
+ /* call-seq: look(position[, dest]) => dest | new Mat4
215
+ *
216
+ * Creates a view matrix, stored in `dest`, using this quaternion as the
217
+ * camera orientation. Returns `dest`. Creates a new Mat4 if `dest` is
218
+ * omitted.
219
+ */
220
+ VALUE rb_cglm_quat_look(int argc, VALUE *argv, VALUE self) {
221
+ VALUE position, dest;
222
+ rb_scan_args(argc, argv, "11", &position, &dest);
223
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
224
+ glm_quat_look(VAL2VEC3(position), VAL2QUAT(self), VAL2MAT4(dest));
225
+ return dest;
226
+ }
227
+
228
+ /* call-seq: look(dir, fwd, up[, dest]) => dest | new Quat
229
+ *
230
+ * Creates a rotation quaternion that has the specified orientation. Places
231
+ * the result in `dest`, or creates a new Quat if `dest` was omitted. Returns
232
+ * `dest`.
233
+ *
234
+ * * `dir` is the direction to look (a Vec3).
235
+ *
236
+ * * `fwd` is the forward vector (a Vec3).
237
+ *
238
+ * * `up` is the up vector (a Vec3).
239
+ */
240
+ VALUE rb_cglm_quat_new_look(int argc, VALUE *argv, VALUE self) {
241
+ VALUE dir, fwd, up, dest;
242
+ rb_scan_args(argc, argv, "31", &dir, &fwd, &up, &dest);
243
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
244
+ glm_quat_for(VAL2VEC3(dir), VAL2VEC3(fwd), VAL2VEC3(up), VAL2QUAT(dest));
245
+ return dest;
246
+ }
247
+
248
+ /* call-seq: look_at(position, target, fwd, up[, dest]) => dest | new Quat
249
+ *
250
+ * Creates a rotation quaternion that has the specified orientation. Places
251
+ * the result in `dest`, or creates a new Quat if `dest` was omitted. Returns
252
+ * `dest`.
253
+ *
254
+ * * `position` is the current position to look from (a Vec3).
255
+ *
256
+ * * `target` is the position to look toward (a Vec3).
257
+ *
258
+ * * `fwd` is the forward vector (a Vec3).
259
+ *
260
+ * * `up` is the up vector (a Vec3).
261
+ */
262
+ VALUE rb_cglm_quat_new_look_at(int argc, VALUE *argv, VALUE self) {
263
+ VALUE position, target, fwd, up, dest;
264
+ rb_scan_args(argc, argv, "41", &position, &target, &fwd, &up, &dest);
265
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
266
+ glm_quat_forp(VAL2VEC3(position), VAL2VEC3(target), VAL2VEC3(fwd), VAL2VEC3(up), VAL2QUAT(dest));
267
+ return dest;
268
+ }
269
+
270
+ /* call-seq: rotate_vec3(vec[, dest]) => dest | new Vec3
271
+ *
272
+ * Rotates the given Vec3 by this quaternion. Returns the result in `dest`,
273
+ * or a new Vec3 if `dest` was omitted.
274
+ */
275
+ VALUE rb_cglm_quat_rotate_vec3(int argc, VALUE *argv, VALUE self) {
276
+ VALUE vec, dest;
277
+ rb_scan_args(argc, argv, "11", &vec, &dest);
278
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
279
+ glm_quat_rotatev(VAL2QUAT(self), VAL2VEC3(vec), VAL2VEC3(dest));
280
+ return dest;
281
+ }
282
+
283
+ /* call-seq: rotate_mat4(vec[, dest]) => dest | new Mat4
284
+ *
285
+ * Rotates the given Mat4 by this quaternion. Returns the result in `dest`,
286
+ * or a new Mat4 if `dest` was omitted.
287
+ */
288
+ VALUE rb_cglm_quat_rotate_mat4(int argc, VALUE *argv, VALUE self) {
289
+ VALUE mat, dest;
290
+ rb_scan_args(argc, argv, "11", &mat, &dest);
291
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
292
+ glm_quat_rotate(VAL2MAT4(mat), VAL2QUAT(self), VAL2MAT4(dest));
293
+ return dest;
294
+ }
295
+
296
+ /* call-seq: pivot_mat4(mat, pivot_point[, dest]) => dest | new Mat4
297
+ *
298
+ * Rotates the given transform matrix using this quaternion at the pivot
299
+ * point (a Vec3). Places the resultant Mat4 into `dest`, or creates a new
300
+ * Mat4 if `dest` is omitted. Returns `dest`.
301
+ */
302
+ VALUE rb_cglm_quat_pivot_mat4(int argc, VALUE *argv, VALUE self) {
303
+ VALUE mat, pivot, dest;
304
+ rb_scan_args(argc, argv, "21", &mat, &pivot, &dest);
305
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
306
+ memcpy(&VAL2MAT4(dest), &VAL2MAT4(mat), sizeof(mat4));
307
+ glm_quat_rotate_at(VAL2MAT4(dest), VAL2QUAT(self), VAL2VEC3(pivot));
308
+ return dest;
309
+ }
310
+
311
+ /* call-seq: random([dest]) => dest | new Quat
312
+ *
313
+ * Fills `dest` or a new Quat with a random orientation, and returns it.
314
+ */
315
+ VALUE rb_cglm_quat_new_random(int argc, VALUE *argv, VALUE self) {
316
+ VALUE dest;
317
+ rb_scan_args(argc, argv, "01", &dest);
318
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
319
+
320
+ glm_quat(VAL2QUAT(dest), drand48(), drand48(), drand48(), drand48());
321
+ glm_quat_normalize(VAL2QUAT(dest));
322
+
323
+ return dest;
324
+ }
325
+
326
+ void Init_cglm_quat() {
327
+ rb_define_method(rb_cQuat, "copy_to", rb_cglm_quat_copy_to, 1);
328
+ rb_define_method(rb_cQuat, "normalize", rb_cglm_quat_normalize, -1);
329
+ rb_define_method(rb_cQuat, "normalize!", rb_cglm_quat_normalize_self, 0);
330
+ rb_define_method(rb_cQuat, "conjugate", rb_cglm_quat_conjugate, -1);
331
+ rb_define_method(rb_cQuat, "invert", rb_cglm_quat_invert, -1);
332
+ rb_define_method(rb_cQuat, "invert!", rb_cglm_quat_invert_self, 0);
333
+ rb_define_method(rb_cQuat, "real", rb_cglm_quat_real, 0);
334
+ rb_define_method(rb_cQuat, "imag", rb_cglm_quat_imag, -1);
335
+ rb_define_method(rb_cQuat, "imagn", rb_cglm_quat_imagn, -1);
336
+ rb_define_method(rb_cQuat, "imaglen", rb_cglm_quat_imaglen, 0);
337
+ rb_define_method(rb_cQuat, "angle", rb_cglm_quat_angle, 0);
338
+ rb_define_method(rb_cQuat, "axis", rb_cglm_quat_axis, -1);
339
+ rb_define_method(rb_cQuat, "mul_quat", rb_cglm_quat_mul_quat, -1);
340
+ rb_define_method(rb_cQuat, "mul_quat!", rb_cglm_quat_mul_quat_self, 1);
341
+ rb_define_method(rb_cQuat, "to_mat4", rb_cglm_quat_to_mat4, -1);
342
+ rb_define_method(rb_cQuat, "to_transposed_mat4", rb_cglm_quat_to_mat4t, -1);
343
+ rb_define_method(rb_cQuat, "to_mat3", rb_cglm_quat_to_mat3, -1);
344
+ rb_define_method(rb_cQuat, "to_transposed_mat3", rb_cglm_quat_to_mat3t, -1);
345
+ rb_define_method(rb_cQuat, "lerp!", rb_cglm_quat_lerp_self, 3);
346
+ rb_define_method(rb_cQuat, "slerp!", rb_cglm_quat_slerp_self, 3);
347
+ rb_define_method(rb_cQuat, "look", rb_cglm_quat_look, -1);
348
+ rb_define_method(rb_cQuat, "rotate_vec3", rb_cglm_quat_rotate_vec3, -1);
349
+ rb_define_method(rb_cQuat, "rotate_mat4", rb_cglm_quat_rotate_mat4, -1);
350
+ rb_define_method(rb_cQuat, "pivot_mat4", rb_cglm_quat_pivot_mat4, -1);
351
+
352
+ rb_define_singleton_method(rb_cQuat, "random", rb_cglm_quat_new_random, -1);
353
+ rb_define_singleton_method(rb_cQuat, "rand", rb_cglm_quat_new_random, -1);
354
+ rb_define_singleton_method(rb_cQuat, "identity", rb_cglm_quat_new_identity, -1);
355
+ rb_define_singleton_method(rb_cQuat, "axis_angle", rb_cglm_quat_new_axis_angle, -1);
356
+ rb_define_singleton_method(rb_cQuat, "look", rb_cglm_quat_new_look, -1);
357
+ rb_define_singleton_method(rb_cQuat, "look_at", rb_cglm_quat_new_look_at, -1);
358
+ }