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,271 @@
1
+ #include "rb_cglm.h"
2
+
3
+ /* call-seq: transform(mat4[, dest]) => dest | new AABB
4
+ *
5
+ * Applies transform to an axis-aligned bounding box, placing the result in
6
+ * `dest` and allocating it if necessary.
7
+ */
8
+ VALUE rb_cglm_aabb_transform(int argc, VALUE *argv, VALUE self) {
9
+ VALUE matr, dest;
10
+ rb_scan_args(argc, argv, "11", &matr, &dest);
11
+ if (NIL_P(dest)) dest = AABB_NEW(ALLOC_AABB);
12
+ mat4 *m;
13
+ aabb *a, *b;
14
+ m = &VAL2MAT4(matr);
15
+ a = &VAL2AABB(self);
16
+ b = &VAL2AABB(dest);
17
+ glm_aabb_transform(a->corners, *m, a->corners);
18
+ return dest;
19
+ }
20
+
21
+ /* call-seq: merge(other[, dest]) => dest | new AABB
22
+ *
23
+ * Merges two axis-aligned bounding boxes, storing the result in `dest`. If
24
+ * `dest` is omitted, a new AABB is created. Returns `dest`.
25
+ *
26
+ * Both boxes must be in the same space.
27
+ */
28
+ VALUE rb_cglm_aabb_merge(int argc, VALUE *argv, VALUE self) {
29
+ VALUE other, dest;
30
+ rb_scan_args(argc, argv, "11", &other, &dest);
31
+ if (NIL_P(dest)) dest = AABB_NEW(ALLOC_AABB);
32
+ aabb *a, *b, *out;
33
+ a = &VAL2AABB(self);
34
+ b = &VAL2AABB(other);
35
+ out = &VAL2AABB(dest);
36
+ glm_aabb_merge(a->corners, b->corners, out->corners);
37
+ return dest;
38
+ }
39
+
40
+ /* call-seq: crop(crop[, dest]) => dest | new AABB
41
+ *
42
+ * Crops this AABB by `crop`, placing the result in `dest` or creating a new
43
+ * one. Returns `dest`.
44
+ *
45
+ * This could be useful for gettng an AABB which fits with view frustum and
46
+ * object bounding boxes. In this case you crop view frustum box with object's
47
+ * box.
48
+ */
49
+ VALUE rb_cglm_aabb_crop(int argc, VALUE *argv, VALUE self) {
50
+ VALUE other, dest;
51
+ rb_scan_args(argc, argv, "11", &other, &dest);
52
+ if (NIL_P(dest)) dest = AABB_NEW(ALLOC_AABB);
53
+ aabb *a, *b, *out;
54
+ a = &VAL2AABB(self);
55
+ b = &VAL2AABB(other);
56
+ out = &VAL2AABB(dest);
57
+ glm_aabb_crop(a->corners, b->corners, out->corners);
58
+ return dest;
59
+ }
60
+
61
+ /* call-seq: crop_until(crop, clamp[, dest]) => dest | new AABB
62
+ *
63
+ * Crops this AABB by `crop`, placing the result in `dest` or creating a new
64
+ * one. Returns `dest`. If the result would be smaller than `clamp`, it is
65
+ * restricted to the extents of `clamp` instead.
66
+ *
67
+ * This could be useful for gettng a bbox which fits with view frustum and
68
+ * object bounding boxes. In this case you crop view frustum box with objects
69
+ * box.
70
+ */
71
+ VALUE rb_cglm_aabb_crop_until(int argc, VALUE *argv, VALUE self) {
72
+ VALUE other, clamp, dest;
73
+ rb_scan_args(argc, argv, "21", &other, &clamp, &dest);
74
+ if (NIL_P(dest)) dest = AABB_NEW(ALLOC_AABB);
75
+ aabb *a, *b, *c, *out;
76
+ a = &VAL2AABB(self);
77
+ b = &VAL2AABB(other);
78
+ c = &VAL2AABB(clamp);
79
+ out = &VAL2AABB(dest);
80
+ glm_aabb_crop_until(a->corners, b->corners, c->corners, out->corners);
81
+ return dest;
82
+ }
83
+
84
+ /* call-seq: intersects_frustum?(frustum) => true|false
85
+ *
86
+ * Returns true if this AABB intersects the given Frustum, false otherwise.
87
+ */
88
+ VALUE rb_cglm_aabb_intersect_frustum(VALUE self, VALUE frstm) {
89
+ aabb *a;
90
+ frustum *f;
91
+ a = &VAL2AABB(self);
92
+ f = &VAL2FRUSTUM(frstm);
93
+ return glm_aabb_frustum(a->corners, f->planes) ? Qtrue : Qfalse;
94
+ }
95
+
96
+ /* call-seq: invalidate => self
97
+ *
98
+ * Invalidates the AABB min and max values.
99
+ */
100
+ VALUE rb_cglm_aabb_invalidate_self(VALUE self) {
101
+ aabb *a;
102
+ a = &VAL2AABB(self);
103
+ glm_aabb_invalidate(a->corners);
104
+ return self;
105
+ }
106
+
107
+ /* call-seq: valid? => true|false
108
+ *
109
+ * Returns true if this AABB is valid, false otherwise.
110
+ */
111
+ VALUE rb_cglm_aabb_is_valid(VALUE self) {
112
+ aabb *a;
113
+ a = &VAL2AABB(self);
114
+ glm_aabb_isvalid(a->corners);
115
+ return self;
116
+ }
117
+
118
+ /* call-seq: size => number
119
+ *
120
+ * Returns the length of the diagonal line between the corners of this AABB.
121
+ */
122
+ VALUE rb_cglm_aabb_size(VALUE self) {
123
+ aabb *a;
124
+ a = &VAL2AABB(self);
125
+ return DBL2NUM(glm_aabb_size(a->corners));
126
+ }
127
+
128
+ /* call-seq: radius => number
129
+ *
130
+ * Returns the radius of a sphere which surrounds this AABB.
131
+ */
132
+ VALUE rb_cglm_aabb_radius(VALUE self) {
133
+ aabb *a;
134
+ a = &VAL2AABB(self);
135
+ return DBL2NUM(glm_aabb_radius(a->corners));
136
+ }
137
+
138
+ /* call-seq: center([dest]) => dest | new Vec3
139
+ *
140
+ * Computes the center point of the AABB and places it into the Vec3 `dest`,
141
+ * creating a new one if `dest` is omitted.
142
+ */
143
+ VALUE rb_cglm_aabb_center(int argc, VALUE *argv, VALUE self) {
144
+ VALUE dest;
145
+ rb_scan_args(argc, argv, "01", &dest);
146
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
147
+ aabb *a;
148
+ vec3 *b;
149
+ a = &VAL2AABB(self);
150
+ b = &VAL2VEC3(dest);
151
+ glm_aabb_center(a->corners, *b);
152
+ return dest;
153
+ }
154
+
155
+ /* call-seq: intersects_aabb?(aabb) => true|false
156
+ *
157
+ * Returns true if the two AABB's overlap, false otherwise.
158
+ */
159
+ VALUE rb_cglm_aabb_intersect_aabb(VALUE self, VALUE other) {
160
+ aabb *a, *b;
161
+ a = &VAL2AABB(self);
162
+ b = &VAL2AABB(other);
163
+ return glm_aabb_aabb(a->corners, b->corners) ? Qtrue : Qfalse;
164
+ }
165
+
166
+ /* call-seq: intersects_sphere?(vec4) => true|false
167
+ *
168
+ * Returns true if the sphere described by the given Vec4 intersects this
169
+ * AABB, false otherwise.
170
+ */
171
+ VALUE rb_cglm_aabb_intersect_sphere(VALUE self, VALUE sphere) {
172
+ aabb *a;
173
+ vec4 *b;
174
+ a = &VAL2AABB(self);
175
+ b = &VAL2VEC4(sphere);
176
+ return glm_aabb_sphere(a->corners, *b) ? Qtrue : Qfalse;
177
+ }
178
+
179
+ /* call-seq: contains_point?(vec3) => true|false
180
+ *
181
+ * Returns true if this AABB contains the specified point (inclusive), false
182
+ * otherwise.
183
+ */
184
+ VALUE rb_cglm_aabb_contains_point(VALUE self, VALUE point) {
185
+ aabb *a;
186
+ vec3 *b;
187
+ a = &VAL2AABB(self);
188
+ b = &VAL2VEC3(point);
189
+ return glm_aabb_point(a->corners, *b) ? Qtrue : Qfalse;
190
+ }
191
+
192
+ /* call-seq: contains_aabb?(aabb) => true|false
193
+ *
194
+ * Returns true if this AABB contains the specified AABB, false otherwise.
195
+ */
196
+ VALUE rb_cglm_aabb_contains_aabb(VALUE self, VALUE other) {
197
+ aabb *a, *b;
198
+ a = &VAL2AABB(self);
199
+ b = &VAL2AABB(other);
200
+ return glm_aabb_contains(a->corners, b->corners) ? Qtrue : Qfalse;
201
+ }
202
+
203
+ VALUE rb_cglm_aabb_aref(VALUE self, VALUE corner_index) {
204
+ CHECK_RANGE(corner_index, 0, 1);
205
+ return VEC3_NEW(VAL2AABB(self).corners[NUM2INT(corner_index)]);
206
+ }
207
+
208
+ VALUE rb_cglm_aabb_aset(VALUE self, VALUE index, VALUE val) {
209
+ CHECK_RANGE(index, 0, 1);
210
+ memcpy(VAL2AABB(self).corners[NUM2INT(index)], VAL2VEC3(val), sizeof(vec3));
211
+ return self;
212
+ }
213
+
214
+ VALUE rb_cglm_aabb_size_bytes(VALUE klass) { return SIZET2NUM(aabb_size()); }
215
+
216
+ VALUE rb_cglm_aabb_alignment_bytes(VALUE klass) { return SIZET2NUM(AABB_ALIGNMENT); }
217
+
218
+ VALUE rb_cglm_aabb_equals_aabb(VALUE self, VALUE other) {
219
+ if (memcmp(&VAL2AABB(self), &VAL2AABB(other), sizeof(aabb))) return Qfalse;
220
+ return Qtrue;
221
+ }
222
+
223
+ /* call-seq: a =~ b => true|false
224
+ *
225
+ * Returns true if each member of `a` is very close to, but not necessarily
226
+ * exactly equal to, each corresponding member of `b`. This is useful in many
227
+ * circumstances because imprecision introduced by floating point calculations
228
+ * can lead to two expressions which are otherwise mathematically equivalent
229
+ * returning false.
230
+ */
231
+ VALUE rb_cglm_aabb_equalish_aabb(int argc, VALUE *argv, VALUE self) {
232
+ VALUE other, epsilon;
233
+ float feps = FLT_EPSILON;
234
+ rb_scan_args(argc, argv, "11", &other, &epsilon);
235
+ if (!NIL_P(epsilon)) feps = NUM2FLT(epsilon);
236
+ aabb *a = &VAL2AABB(self);
237
+ aabb *b = &VAL2AABB(other);
238
+ for (int i = 0; i < 2; i++) {
239
+ for (int j = 0; j < 3; j++) {
240
+ if (fabsf((*a).corners[i][j] - (*b).corners[i][j]) > feps)
241
+ return Qfalse;
242
+ }
243
+ }
244
+ return Qtrue;
245
+ }
246
+
247
+ void Init_cglm_box() {
248
+ rb_define_method(rb_cAABB, "==", rb_cglm_aabb_equals_aabb, 1);
249
+ rb_define_method(rb_cAABB, "equalish", rb_cglm_aabb_equalish_aabb, -1);
250
+ rb_define_method(rb_cAABB, "transform", rb_cglm_aabb_transform, -1);
251
+ rb_define_method(rb_cAABB, "merge", rb_cglm_aabb_merge, -1);
252
+ rb_define_method(rb_cAABB, "crop", rb_cglm_aabb_crop, -1);
253
+ rb_define_method(rb_cAABB, "crop_until", rb_cglm_aabb_crop_until, -1);
254
+ rb_define_method(rb_cAABB, "intersects_frustum?", rb_cglm_aabb_intersect_frustum, 1);
255
+ rb_define_method(rb_cAABB, "invalidate!", rb_cglm_aabb_invalidate_self, 0);
256
+ rb_define_method(rb_cAABB, "valid?", rb_cglm_aabb_is_valid, 0);
257
+ rb_define_method(rb_cAABB, "size", rb_cglm_aabb_size, 0);
258
+ rb_define_method(rb_cAABB, "radius", rb_cglm_aabb_radius, 0);
259
+ rb_define_method(rb_cAABB, "center", rb_cglm_aabb_center, -1);
260
+ rb_define_method(rb_cAABB, "intersects_aabb?", rb_cglm_aabb_intersect_aabb, 1);
261
+ rb_define_method(rb_cAABB, "intersects_sphere?", rb_cglm_aabb_intersect_sphere, 1);
262
+ rb_define_method(rb_cAABB, "contains_point?", rb_cglm_aabb_contains_point, 1);
263
+ rb_define_method(rb_cAABB, "contains_aabb?", rb_cglm_aabb_contains_aabb, 1);
264
+ rb_define_method(rb_cAABB, "[]", rb_cglm_aabb_aref, 1);
265
+ rb_define_method(rb_cAABB, "[]=", rb_cglm_aabb_aset, 2);
266
+
267
+ rb_define_alias(rb_cAABB, "=~", "equalish");
268
+
269
+ rb_define_singleton_method(rb_cAABB, "size", rb_cglm_aabb_size_bytes, 0);
270
+ rb_define_singleton_method(rb_cAABB, "alignment", rb_cglm_aabb_alignment_bytes, 0);
271
+ }
@@ -0,0 +1,325 @@
1
+ #include "rb_cglm.h"
2
+
3
+ /*
4
+ * call-seq: affine_mul_rot(m[, dest]) => dest | new Mat4
5
+ *
6
+ * This is similar to #mul but specialized to affine transform.
7
+ *
8
+ * Right Matrix format should be:
9
+ *
10
+ * R R R 0
11
+ * R R R 0
12
+ * R R R 0
13
+ * 0 0 0 1
14
+ *
15
+ * This reduces some multiplications. It should be faster than #mul.
16
+ * if you are not sure about matrix format then DON'T use this! use #mul.
17
+ *
18
+ * * `m` is the second affine Mat4 to multiply `self` against.
19
+ * * `dest` is the out Mat4 to place the result in, and will be allocated if
20
+ * omitted.
21
+ *
22
+ */
23
+ VALUE rb_cglm_affine_mul_rot(int argc, VALUE *argv, VALUE self) {
24
+ VALUE m_v, dest_v;
25
+ rb_scan_args(argc, argv, "11", &m_v, &dest_v);
26
+ if (NIL_P(dest_v)) dest_v = MAT4_NEW(ALLOC_MAT4);
27
+
28
+ mat4 *m1 = NULL, *m2 = NULL, *dest = NULL;
29
+ m1 = &VAL2MAT4(self);
30
+ m2 = &VAL2MAT4(m_v);
31
+ dest = &VAL2MAT4(dest_v);
32
+ glm_mul_rot(*m1, *m2, *dest);
33
+ return dest_v;
34
+ }
35
+
36
+ /*
37
+ * call-seq: inv_tr() => self
38
+ *
39
+ * inverse orthonormal rotation + translation matrix (ridgid-body)
40
+ *
41
+ * X = | R T | X' = | R' -R'T |
42
+ * | 0 1 | | 0 1 |
43
+ *
44
+ */
45
+ VALUE rb_cglm_affine_inv_tr(VALUE mat) {
46
+ mat4 *m = NULL;
47
+ m = &VAL2MAT4(mat);
48
+ glm_inv_tr(*m);
49
+ return mat;
50
+ }
51
+
52
+ /*
53
+ * call-seq: affine_mul(m[, dest]) => dest | new Mat4
54
+ *
55
+ * This is similar to #mul but specialized to affine transform.
56
+ *
57
+ * Right Matrix format should be:
58
+ *
59
+ * R R R X
60
+ * R R R Y
61
+ * R R R Z
62
+ * 0 0 0 W
63
+ *
64
+ * This reduces some multiplications. It should be faster than #mul.
65
+ * if you are not sure about matrix format then DON'T use this! use #mul.
66
+ *
67
+ * * `m` is the second affine Mat4 to multiply `self` against.
68
+ * * `dest` is the out Mat4 to place the result in, and will be allocated if
69
+ * omitted.
70
+ *
71
+ */
72
+ VALUE rb_cglm_affine_mul(int argc, VALUE *argv, VALUE self) {
73
+ VALUE m_v, dest_v;
74
+ rb_scan_args(argc, argv, "11", &m_v, &dest_v);
75
+ if (NIL_P(dest_v)) dest_v = MAT4_NEW(ALLOC_MAT4);
76
+ mat4 *m1 = NULL, *m2 = NULL, *dest = NULL;
77
+ m1 = &VAL2MAT4(self);
78
+ m2 = &VAL2MAT4(m_v);
79
+ dest = &VAL2MAT4(dest_v);
80
+ glm_mul(*m1, *m2, *dest);
81
+ return dest_v;
82
+ }
83
+
84
+ /* call-seq: translate(vec3[, dest]) => dest | new Mat4 */
85
+ VALUE rb_cglm_translate(int argc, VALUE *argv, VALUE self) {
86
+ VALUE vec_v, dest_v;
87
+ rb_scan_args(argc, argv, "11", &vec_v, &dest_v);
88
+ if (NIL_P(dest_v)) dest_v = MAT4_NEW(ALLOC_MAT4);
89
+ mat4 *m1 = NULL, *dest = NULL;
90
+ vec3 *vec = NULL;
91
+ m1 = &VAL2MAT4(self);
92
+ vec = &VAL2VEC3(vec_v);
93
+ dest = &VAL2MAT4(dest_v);
94
+ glm_translate_to(*m1, *vec, *dest);
95
+ return dest_v;
96
+ }
97
+
98
+ /* call-seq: translate!(vec3) => self */
99
+ VALUE rb_cglm_translate_self(VALUE self, VALUE vec_v) {
100
+ mat4 *m1 = NULL;
101
+ vec3 *vec = NULL;
102
+ m1 = &VAL2MAT4(self);
103
+ vec = &VAL2VEC3(vec_v);
104
+ glm_translate(*m1, *vec);
105
+ return self;
106
+ }
107
+
108
+ /* call-seq: translate_x!(float) => self */
109
+ VALUE rb_cglm_translate_x_self(VALUE self, VALUE flt) {
110
+ mat4 *m1 = NULL;
111
+ m1 = &VAL2MAT4(self);
112
+ glm_translate_x(*m1, (float) NUM2DBL(flt));
113
+ return self;
114
+ }
115
+
116
+ /* call-seq: mat4.translate_y!(float) => mat4 */
117
+ VALUE rb_cglm_translate_y_self(VALUE self, VALUE flt) {
118
+ mat4 *m1 = NULL;
119
+ m1 = &VAL2MAT4(self);
120
+ glm_translate_y(*m1, (float) NUM2DBL(flt));
121
+ return self;
122
+ }
123
+
124
+ /* call-seq: translate_z!(float) => self */
125
+ VALUE rb_cglm_translate_z_self(VALUE self, VALUE flt) {
126
+ mat4 *m1 = NULL;
127
+ m1 = &VAL2MAT4(self);
128
+ glm_translate_z(*m1, (float) NUM2DBL(flt));
129
+ return self;
130
+ }
131
+
132
+ /* call-seq: translate(vec3) => new Mat4 */
133
+ VALUE rb_cglm_translate_new(VALUE klass, VALUE vec_v) {
134
+ VALUE dest = MAT4_NEW(ALLOC_MAT4);
135
+ glm_translate_make(VAL2MAT4(dest), VAL2VEC3(vec_v));
136
+ return dest;
137
+ }
138
+
139
+ /* call-seq: scale(vec3) => new Mat4 */
140
+ VALUE rb_cglm_scale_new(VALUE klass, VALUE vec_v) {
141
+ VALUE dest = MAT4_NEW(ALLOC_MAT4);
142
+ glm_scale_make(VAL2MAT4(dest), VAL2VEC3(vec_v));
143
+ return dest;
144
+ }
145
+
146
+ /* call-seq: rotate(axis, angle) => new Mat4 */
147
+ VALUE rb_cglm_rotate_new(VALUE klass, VALUE axis, VALUE angle) {
148
+ VALUE dest = MAT4_NEW(ALLOC_MAT4);
149
+ glm_rotate_make(VAL2MAT4(dest), (float) NUM2DBL(angle), VAL2VEC3(axis));
150
+ return dest;
151
+ }
152
+
153
+ /* call-seq: scale(vec3|float[, dest]) => dest | new Mat4 */
154
+ VALUE rb_cglm_scale(int argc, VALUE *argv, VALUE self) {
155
+ VALUE factor, dest;
156
+ rb_scan_args(argc, argv, "11", &factor, &dest);
157
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
158
+
159
+ if (RB_FLOAT_TYPE_P(factor) || RB_INTEGER_TYPE_P(factor)) {
160
+ memcpy(&VAL2MAT4(dest), &VAL2MAT4(self), sizeof(mat4));
161
+ glm_scale_uni(VAL2MAT4(dest), (float) NUM2DBL(factor));
162
+ } else {
163
+ glm_scale_to(VAL2MAT4(self), VAL2VEC3(factor), VAL2MAT4(dest));
164
+ }
165
+
166
+ return dest;
167
+ }
168
+
169
+ /* call-seq: scale!(vec3|float) => self */
170
+ VALUE rb_cglm_scale_self(VALUE self, VALUE factor) {
171
+ mat4 *m1 = NULL;
172
+ m1 = &VAL2MAT4(self);
173
+ if (RB_FLOAT_TYPE_P(factor) || RB_INTEGER_TYPE_P(factor)) {
174
+ glm_scale_uni(*m1, (float) NUM2DBL(factor));
175
+ } else {
176
+ vec3 *vec = NULL;
177
+ vec = &VAL2VEC3(factor);
178
+ glm_scale(*m1, *vec);
179
+ }
180
+ return self;
181
+ }
182
+
183
+ /* call-seq: rotate_x(float[, dest]) => dest | new Mat4 */
184
+ VALUE rb_cglm_rotate_x(int argc, VALUE *argv, VALUE self) {
185
+ VALUE angle, dest;
186
+ rb_scan_args(argc, argv, "11", &angle, &dest);
187
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
188
+ mat4 *m1, *m2;
189
+ m1 = &VAL2MAT4(self);
190
+ m2 = &VAL2MAT4(dest);
191
+ glm_rotate_x(*m1, (float) NUM2DBL(angle), *m2);
192
+ return dest;
193
+ }
194
+
195
+ /* call-seq: rotate_y(float[, dest]) => dest | new Mat4 */
196
+ VALUE rb_cglm_rotate_y(int argc, VALUE *argv, VALUE self) {
197
+ VALUE angle, dest;
198
+ rb_scan_args(argc, argv, "11", &angle, &dest);
199
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
200
+ mat4 *m1, *m2;
201
+ m1 = &VAL2MAT4(self);
202
+ m2 = &VAL2MAT4(dest);
203
+ glm_rotate_y(*m1, (float) NUM2DBL(angle), *m2);
204
+ return dest;
205
+ }
206
+
207
+ /* call-seq: rotate_z(float[, dest]) => dest | new Mat4 */
208
+ VALUE rb_cglm_rotate_z(int argc, VALUE *argv, VALUE self) {
209
+ VALUE angle, dest;
210
+ rb_scan_args(argc, argv, "11", &angle, &dest);
211
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
212
+ mat4 *m1, *m2;
213
+ m1 = &VAL2MAT4(self);
214
+ m2 = &VAL2MAT4(dest);
215
+ glm_rotate_z(*m1, (float) NUM2DBL(angle), *m2);
216
+ return dest;
217
+ }
218
+
219
+ /* call-seq: rotate!(axis, angle) => self */
220
+ VALUE rb_cglm_rotate_self(VALUE self, VALUE axis, VALUE angle) {
221
+ mat4 *mat;
222
+ vec3 *vec;
223
+ mat = &VAL2MAT4(self);
224
+ vec = &VAL2VEC3(axis);
225
+ glm_rotate(*mat, (float) NUM2DBL(angle), *vec);
226
+ return self;
227
+ }
228
+
229
+ /* call-seq: rotate_at!(pivot_point, axis, angle) => self */
230
+ VALUE rb_cglm_rotate_self_at(VALUE self, VALUE pivot, VALUE axis, VALUE angle) {
231
+ mat4 *m;
232
+ vec3 *v1, *v2;
233
+ m = &VAL2MAT4(self);
234
+ v1 = &VAL2VEC3(pivot);
235
+ v2 = &VAL2VEC3(axis);
236
+ glm_rotate_at(*m, *v1, (float) NUM2DBL(angle), *v2);
237
+ return self;
238
+ }
239
+
240
+ /* call-seq: axis_angle_rotate_at(pivot_point, axis, angle) => new Mat4 */
241
+ VALUE rb_cglm_rotate_at_new(VALUE klass, VALUE pivot, VALUE axis, VALUE angle) {
242
+ VALUE self = MAT4_NEW(ALLOC_MAT4);
243
+ mat4 *m;
244
+ vec3 *v1, *v2;
245
+ m = &VAL2MAT4(self);
246
+ v1 = &VAL2VEC3(pivot);
247
+ v2 = &VAL2VEC3(axis);
248
+ glm_rotate_atm(*m, *v1, (float) NUM2DBL(angle), *v2);
249
+ return self;
250
+ }
251
+
252
+ /* call-seq: decompose_scale(vec3) => vec3 */
253
+ VALUE rb_cglm_decompose_scale(VALUE self, VALUE out) {
254
+ mat4 *m;
255
+ vec3 *v;
256
+ m = &VAL2MAT4(self);
257
+ v = &VAL2VEC3(self);
258
+ glm_decompose_scalev(*m, *v);
259
+ return out;
260
+ }
261
+
262
+ /* call-seq: uniform_scale? => true|false */
263
+ VALUE rb_cglm_is_uniform_scale(VALUE self) {
264
+ mat4 *m;
265
+ m = &VAL2MAT4(self);
266
+ return glm_uniscaled(*m) ? Qtrue : Qfalse;
267
+ }
268
+
269
+ /* call-seq: decompose_rs(r, s) => self
270
+ *
271
+ * Decomposes `self` into a rotation Mat4 `r` and scale Vec3 `s`.
272
+ */
273
+ VALUE rb_cglm_decompose_rs(VALUE self, VALUE rot, VALUE scale) {
274
+ mat4 *m, *r;
275
+ vec3 *s;
276
+ m = &VAL2MAT4(self);
277
+ r = &VAL2MAT4(rot);
278
+ s = &VAL2VEC3(scale);
279
+ glm_decompose_rs(*m, *r, *s);
280
+ return self;
281
+ }
282
+
283
+ /* call-seq: decompose(t, r, s) => self
284
+ *
285
+ * Decomposes `self` into a translation Vec4 `t`, rotation Mat4 `r` and scale
286
+ * Vec3 `s`.
287
+ */
288
+ VALUE rb_cglm_decompose(VALUE self, VALUE trans, VALUE rot, VALUE scale) {
289
+ mat4 *m, *r;
290
+ vec3 *s;
291
+ vec4 *t;
292
+ m = &VAL2MAT4(self);
293
+ t = &VAL2VEC4(trans);
294
+ r = &VAL2MAT4(rot);
295
+ s = &VAL2VEC3(scale);
296
+ glm_decompose(*m, *t, *r, *s);
297
+ return self;
298
+ }
299
+
300
+ void Init_cglm_affine() {
301
+ rb_define_method(rb_cMat4, "affine_inv_tr", rb_cglm_affine_inv_tr, 0);
302
+ rb_define_method(rb_cMat4, "affine_mul_rot", rb_cglm_affine_mul_rot, -1);
303
+ rb_define_method(rb_cMat4, "affine_mul", rb_cglm_affine_mul, -1);
304
+ rb_define_method(rb_cMat4, "translate_to", rb_cglm_translate, -1);
305
+ rb_define_method(rb_cMat4, "translate!", rb_cglm_translate_self, 1);
306
+ rb_define_method(rb_cMat4, "translate_x!", rb_cglm_translate_x_self, 1);
307
+ rb_define_method(rb_cMat4, "translate_y!", rb_cglm_translate_y_self, 1);
308
+ rb_define_method(rb_cMat4, "translate_z!", rb_cglm_translate_z_self, 1);
309
+ rb_define_method(rb_cMat4, "scale", rb_cglm_scale, -1);
310
+ rb_define_method(rb_cMat4, "scale!", rb_cglm_scale_self, 1);
311
+ rb_define_method(rb_cMat4, "rotate_x", rb_cglm_rotate_x, -1);
312
+ rb_define_method(rb_cMat4, "rotate_y", rb_cglm_rotate_y, -1);
313
+ rb_define_method(rb_cMat4, "rotate_z", rb_cglm_rotate_z, -1);
314
+ rb_define_method(rb_cMat4, "rotate!", rb_cglm_rotate_self, 2);
315
+ rb_define_method(rb_cMat4, "rotate_at!", rb_cglm_rotate_self_at, 3);
316
+ rb_define_method(rb_cMat4, "decompose_scale",rb_cglm_decompose_scale, 1);
317
+ rb_define_method(rb_cMat4, "uniform_scale?", rb_cglm_is_uniform_scale, 0);
318
+ rb_define_method(rb_cMat4, "decompose_rs", rb_cglm_decompose_rs, 2);
319
+ rb_define_method(rb_cMat4, "decompose", rb_cglm_decompose, 3);
320
+
321
+ rb_define_singleton_method(rb_cMat4, "translate", rb_cglm_translate_new, 1);
322
+ rb_define_singleton_method(rb_cMat4, "scale", rb_cglm_scale_new, 1);
323
+ rb_define_singleton_method(rb_cMat4, "rotate", rb_cglm_rotate_new, 2);
324
+ rb_define_singleton_method(rb_cMat4, "axis_angle_rotate_at", rb_cglm_rotate_at_new, 3);
325
+ }