cglm 0.1.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.
@@ -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
+ }