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,141 @@
1
+ #include "rb_cglm.h"
2
+
3
+ /* call-seq: angles(mat4[, dest]) => dest or new Vec3
4
+ *
5
+ * Extracts euler angles (in radians) using xyz order.
6
+ */
7
+ VALUE rb_cglm_euler_angles(int argc, VALUE *argv, VALUE self) {
8
+ VALUE m, dest;
9
+ rb_scan_args(argc, argv, "11", &m, &dest);
10
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
11
+ glm_euler_angles(VAL2MAT4(m), VAL2VEC3(dest));
12
+ return dest;
13
+ }
14
+
15
+ /* call-seq: xyz(angles[, dest]) => dest or new Mat4
16
+ *
17
+ * Builds a rotation matrix from the specified angles, in xyz order. `angles`
18
+ * must be a Vec3 specifying the X, Y and Z angles (in that order).
19
+ */
20
+ VALUE rb_cglm_euler_xyz(int argc, VALUE *argv, VALUE self) {
21
+ VALUE angles, dest;
22
+ rb_scan_args(argc, argv, "11", &angles, &dest);
23
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
24
+ glm_euler_xyz(VAL2VEC3(angles), VAL2MAT4(dest));
25
+ return dest;
26
+ }
27
+
28
+ /* call-seq: zyx(angles[, dest]) => dest or new Mat4
29
+ *
30
+ * Builds a rotation matrix from the specified angles, in zyx order. `angles`
31
+ * must be a Vec3 specifying the X, Y and Z angles (in that order).
32
+ */
33
+ VALUE rb_cglm_euler_zyx(int argc, VALUE *argv, VALUE self) {
34
+ VALUE angles, dest;
35
+ rb_scan_args(argc, argv, "11", &angles, &dest);
36
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
37
+ glm_euler_zyx(VAL2VEC3(angles), VAL2MAT4(dest));
38
+ return dest;
39
+ }
40
+
41
+ /* call-seq: zxy(angles[, dest]) => dest or new Mat4
42
+ *
43
+ * Builds a rotation matrix from the specified angles, in zxy order. `angles`
44
+ * must be a Vec3 specifying the X, Y and Z angles (in that order).
45
+ */
46
+ VALUE rb_cglm_euler_zxy(int argc, VALUE *argv, VALUE self) {
47
+ VALUE angles, dest;
48
+ rb_scan_args(argc, argv, "11", &angles, &dest);
49
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
50
+ glm_euler_zxy(VAL2VEC3(angles), VAL2MAT4(dest));
51
+ return dest;
52
+ }
53
+
54
+ /* call-seq: xzy(angles[, dest]) => dest or new Mat4
55
+ *
56
+ * Builds a rotation matrix from the specified angles, in xzy order. `angles`
57
+ * must be a Vec3 specifying the X, Y and Z angles (in that order).
58
+ */
59
+ VALUE rb_cglm_euler_xzy(int argc, VALUE *argv, VALUE self) {
60
+ VALUE angles, dest;
61
+ rb_scan_args(argc, argv, "11", &angles, &dest);
62
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
63
+ glm_euler_xzy(VAL2VEC3(angles), VAL2MAT4(dest));
64
+ return dest;
65
+ }
66
+
67
+ /* call-seq: yzx(angles[, dest]) => dest or new Mat4
68
+ *
69
+ * Builds a rotation matrix from the specified angles, in yzx order. `angles`
70
+ * must be a Vec3 specifying the X, Y and Z angles (in that order).
71
+ */
72
+ VALUE rb_cglm_euler_yzx(int argc, VALUE *argv, VALUE self) {
73
+ VALUE angles, dest;
74
+ rb_scan_args(argc, argv, "11", &angles, &dest);
75
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
76
+ glm_euler_yzx(VAL2VEC3(angles), VAL2MAT4(dest));
77
+ return dest;
78
+ }
79
+
80
+ /* call-seq: yxz(angles[, dest]) => dest or new Mat4
81
+ *
82
+ * Builds a rotation matrix from the specified angles, in yxz order. `angles`
83
+ * must be a Vec3 specifying the X, Y and Z angles (in that order).
84
+ */
85
+ VALUE rb_cglm_euler_yxz(int argc, VALUE *argv, VALUE self) {
86
+ VALUE angles, dest;
87
+ rb_scan_args(argc, argv, "11", &angles, &dest);
88
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
89
+ glm_euler_yxz(VAL2VEC3(angles), VAL2MAT4(dest));
90
+ return dest;
91
+ }
92
+
93
+ /* call-seq: by_order(axis, angles[, dest]) => dest or new Mat4
94
+ *
95
+ * Builds a rotation matrix from the specified angles, in the specified order,
96
+ * which can be one of the constants from the Euler module, or computed using
97
+ * #order. `angles` must be a Vec3 specifying the X, Y and Z angles (in that
98
+ * order).
99
+ */
100
+ VALUE rb_cglm_euler_by_order(int argc, VALUE *argv, VALUE self) {
101
+ VALUE angles, axis, dest;
102
+ rb_scan_args(argc, argv, "21", &axis, &angles, &dest);
103
+ if (NIL_P(dest)) dest = MAT4_NEW(ALLOC_MAT4);
104
+ glm_euler_by_order(VAL2VEC3(angles), NUM2INT(axis), VAL2MAT4(dest));
105
+ return dest;
106
+ }
107
+
108
+
109
+ /* call-seq: order(axis) => Numeric
110
+ *
111
+ * Returns a numeric handle representing the specified axis order. `axis` is
112
+ * an array containing axis indices (0 for X, 1 for Y, 2 for Z).
113
+ *
114
+ * Example:
115
+ *
116
+ * order([0, 2, 1]) #=> first X, then Z, then Y
117
+ */
118
+ VALUE rb_cglm_euler_order(VALUE klass, VALUE order_ary) {
119
+ int order[3] = { NUM2INT(rb_ary_entry(order_ary, 0)),
120
+ NUM2INT(rb_ary_entry(order_ary, 1)),
121
+ NUM2INT(rb_ary_entry(order_ary, 2)) };
122
+ return INT2NUM(glm_euler_order(order));
123
+ }
124
+
125
+ void Init_cglm_euler() {
126
+ rb_define_const(rb_mEuler, "XYZ", INT2NUM(GLM_EULER_XYZ));
127
+ rb_define_const(rb_mEuler, "XZY", INT2NUM(GLM_EULER_XZY));
128
+ rb_define_const(rb_mEuler, "YZX", INT2NUM(GLM_EULER_YZX));
129
+ rb_define_const(rb_mEuler, "YXZ", INT2NUM(GLM_EULER_YXZ));
130
+ rb_define_const(rb_mEuler, "ZXY", INT2NUM(GLM_EULER_ZXY));
131
+ rb_define_const(rb_mEuler, "ZYX", INT2NUM(GLM_EULER_ZYX));
132
+ rb_define_singleton_method(rb_mEuler, "order", rb_cglm_euler_order, 1);
133
+ rb_define_singleton_method(rb_mEuler, "xyz", rb_cglm_euler_xyz, -1);
134
+ rb_define_singleton_method(rb_mEuler, "zyx", rb_cglm_euler_zyx, -1);
135
+ rb_define_singleton_method(rb_mEuler, "zxy", rb_cglm_euler_zxy, -1);
136
+ rb_define_singleton_method(rb_mEuler, "xzy", rb_cglm_euler_xzy, -1);
137
+ rb_define_singleton_method(rb_mEuler, "yzx", rb_cglm_euler_yzx, -1);
138
+ rb_define_singleton_method(rb_mEuler, "yxz", rb_cglm_euler_yxz, -1);
139
+ rb_define_singleton_method(rb_mEuler, "by_order", rb_cglm_euler_by_order, -1);
140
+ rb_define_singleton_method(rb_mEuler, "angles", rb_cglm_euler_angles, -1);
141
+ }
@@ -0,0 +1,306 @@
1
+ #define GLM_CUSTOM_CLIPSPACE 1
2
+ #include "cglm/types.h"
3
+
4
+ #undef near
5
+ #undef far
6
+
7
+ /* near */
8
+ static float CSCOORD_LBN[4] = {-1.0f, -1.0f, -1.0f, 1.0f};
9
+ static float CSCOORD_LTN[4] = {-1.0f, 1.0f, -1.0f, 1.0f};
10
+ static float CSCOORD_RTN[4] = { 1.0f, 1.0f, -1.0f, 1.0f};
11
+ static float CSCOORD_RBN[4] = { 1.0f, -1.0f, -1.0f, 1.0f};
12
+
13
+ /* far */
14
+ static float CSCOORD_LBF[4] = {-1.0f, -1.0f, 1.0f, 1.0f};
15
+ static float CSCOORD_LTF[4] = {-1.0f, 1.0f, 1.0f, 1.0f};
16
+ static float CSCOORD_RTF[4] = { 1.0f, 1.0f, 1.0f, 1.0f};
17
+ static float CSCOORD_RBF[4] = { 1.0f, -1.0f, 1.0f, 1.0f};
18
+
19
+ #define GLM_CSCOORD_LBN { CSCOORD_LBN[0], CSCOORD_LBN[1], CSCOORD_LBN[2], CSCOORD_LBN[3] }
20
+ #define GLM_CSCOORD_LTN { CSCOORD_LTN[0], CSCOORD_LTN[1], CSCOORD_LTN[2], CSCOORD_LTN[3] }
21
+ #define GLM_CSCOORD_RTN { CSCOORD_RTN[0], CSCOORD_RTN[1], CSCOORD_RTN[2], CSCOORD_RTN[3] }
22
+ #define GLM_CSCOORD_RBN { CSCOORD_RBN[0], CSCOORD_RBN[1], CSCOORD_RBN[2], CSCOORD_RBN[3] }
23
+ #define GLM_CSCOORD_LBF { CSCOORD_LBF[0], CSCOORD_LBF[1], CSCOORD_LBF[2], CSCOORD_LBF[3] }
24
+ #define GLM_CSCOORD_LTF { CSCOORD_LTF[0], CSCOORD_LTF[1], CSCOORD_LTF[2], CSCOORD_LTF[3] }
25
+ #define GLM_CSCOORD_RTF { CSCOORD_RTF[0], CSCOORD_RTF[1], CSCOORD_RTF[2], CSCOORD_RTF[3] }
26
+ #define GLM_CSCOORD_RBF { CSCOORD_RBF[0], CSCOORD_RBF[1], CSCOORD_RBF[2], CSCOORD_RBF[3] }
27
+
28
+ #include "rb_cglm.h"
29
+ #define SYMBOL(cstr) ID2SYM(rb_intern(cstr))
30
+
31
+ /* call-seq: planes(space[, dest]) => dest | new Hash
32
+ *
33
+ * Extracts the 6 view frustum planes into an hash of 6 Vec4's. If `dest` is
34
+ * omitted, a new Hash is allocated.
35
+ *
36
+ * * `space` is the Mat4 representing the space in which the 6 frustum planes
37
+ * are defined. If it's a `projection` matrix, the result is in view space. If
38
+ * it's a `(view * projection)` matrix, the result is in world space. If it's
39
+ * a `(model * view * projection)` matrix, the result is in object space.
40
+ *
41
+ * * `dest` is a Hash containing the following keys: `:left`, `:right`, `:bottom`,
42
+ * `:top`, `:near`, `:far`. Each value is a Vec4.
43
+ *
44
+ * You probably want to extract planes in world space, so use `(view * projection)`
45
+ * as `space`.
46
+ */
47
+ VALUE rb_cglm_frustum_singleton_planes(int argc, VALUE *argv, VALUE self) {
48
+ VALUE mat, dest;
49
+ rb_scan_args(argc, argv, "11", &mat, &dest);
50
+ if (NIL_P(dest)) dest = rb_hash_new();
51
+ vec4 planes[6];
52
+ glm_frustum_planes(VAL2MAT4(mat), planes);
53
+
54
+ #define HASH_GET_OR_SET(index, name, str) \
55
+ VALUE name = rb_hash_aref(dest, SYMBOL(str)); \
56
+ if (NIL_P(name)) { \
57
+ name = VEC4_NEW(ALLOC_VEC4); \
58
+ rb_hash_aset(dest, SYMBOL(str), name); \
59
+ } \
60
+ memcpy(&VAL2VEC4(name), &planes[index], sizeof(vec4));
61
+
62
+ HASH_GET_OR_SET(GLM_LEFT, left, "left");
63
+ HASH_GET_OR_SET(GLM_RIGHT, right, "right");
64
+ HASH_GET_OR_SET(GLM_BOTTOM, bottom, "bottom");
65
+ HASH_GET_OR_SET(GLM_TOP, top, "top");
66
+ HASH_GET_OR_SET(GLM_NEAR, n, "near");
67
+ HASH_GET_OR_SET(GLM_FAR, f, "far");
68
+ #undef HASH_GET_OR_SET
69
+
70
+ return dest;
71
+ }
72
+
73
+
74
+ /* call-seq: corners(inv_space[, dest]) => dest | new Hash
75
+ *
76
+ * Extracts the view frustum corners using clip-space coordinates.
77
+ *
78
+ * * `inv_space` is the inverse of the Mat4 representing the space in which
79
+ * the 8 frustum corners are defined. If it's an `(inverse(view * projection))`
80
+ * matrix, the result is in world space. If it's an `(inverse(model * view * projection))`
81
+ * matrix, the result is in object space.
82
+ *
83
+ * * You probably want to extract planes in world space, so use
84
+ * `(inverse(view * projection))` as `inv_space`.
85
+ *
86
+ * * `dest` is a Hash containing the following keys: `:lbn`, `:ltn`, `:rtn`,
87
+ * `:rbn`, `:lbf`, `:ltf`, `:rtf`, `:rbf`. Each value is a Vec4.
88
+ *
89
+ * * The `dest` hash, if created, is ordered such that you can index into
90
+ * the array of values with the Frustum class constants. For example,
91
+ * `hash.values[Frustum::RTN]`.
92
+ *
93
+ * * If you know the index of a near coord, you can get its far coord by
94
+ * adding 4. For example,
95
+ * `hash.values[Frustum::RTN + 4] == hash.values[Frustum::RTF]`.
96
+ *
97
+ */
98
+ VALUE rb_cglm_frustum_singleton_corners(int argc, VALUE *argv, VALUE self) {
99
+ VALUE mat, dest;
100
+ rb_scan_args(argc, argv, "11", &mat, &dest);
101
+ if (NIL_P(dest)) dest = rb_hash_new();
102
+ vec4 corners[8];
103
+ glm_frustum_corners(VAL2MAT4(mat), corners);
104
+
105
+ #define HASH_GET_OR_SET(index, name) \
106
+ VALUE name = rb_hash_aref(dest, SYMBOL(#name)); \
107
+ if (NIL_P(name)) { \
108
+ name = VEC4_NEW(ALLOC_VEC4); \
109
+ rb_hash_aset(dest, SYMBOL(#name), name); \
110
+ } \
111
+ memcpy(&VAL2VEC4(name), &corners[index], sizeof(vec4));
112
+
113
+ HASH_GET_OR_SET(GLM_LBN, lbn);
114
+ HASH_GET_OR_SET(GLM_LTN, ltn);
115
+ HASH_GET_OR_SET(GLM_RTN, rtn);
116
+ HASH_GET_OR_SET(GLM_RBN, rbn);
117
+ HASH_GET_OR_SET(GLM_LBF, lbf);
118
+ HASH_GET_OR_SET(GLM_LTF, ltf);
119
+ HASH_GET_OR_SET(GLM_RTF, rtf);
120
+ HASH_GET_OR_SET(GLM_RBF, rbf);
121
+ #undef HASH_GET_OR_SET
122
+
123
+ return dest;
124
+ }
125
+
126
+ #define hash_to_corner(corners, corners_v, index, name) \
127
+ { \
128
+ VALUE v = rb_hash_aref(corners_v, SYMBOL(name)); \
129
+ if (NIL_P(v)) v = VEC4_NEW(ALLOC_VEC4); \
130
+ memcpy(&corners[index][0], &VAL2VEC4(v), sizeof(vec4)); \
131
+ }
132
+
133
+ #define hash_to_corners(corners, corners_v) \
134
+ hash_to_corner(corners, corners_v, GLM_LBN, "lbn"); \
135
+ hash_to_corner(corners, corners_v, GLM_LTN, "ltn"); \
136
+ hash_to_corner(corners, corners_v, GLM_RTN, "rtn"); \
137
+ hash_to_corner(corners, corners_v, GLM_RBN, "rbn"); \
138
+ hash_to_corner(corners, corners_v, GLM_LBF, "lbf"); \
139
+ hash_to_corner(corners, corners_v, GLM_LTF, "ltf"); \
140
+ hash_to_corner(corners, corners_v, GLM_RTF, "rtf"); \
141
+ hash_to_corner(corners, corners_v, GLM_RBF, "rbf");
142
+
143
+ /* call-seq: center(corners[, dest]) => dest | new vec4
144
+ *
145
+ * Returns the center of the view frustum described by the hash `corners`,
146
+ * which must follow the format returned by {corners}.
147
+ */
148
+ VALUE rb_cglm_frustum_singleton_center(int argc, VALUE *argv, VALUE self) {
149
+ VALUE corners_v, dest;
150
+ rb_scan_args(argc, argv, "11", &corners_v, &dest);
151
+ if (NIL_P(dest)) dest = VEC4_NEW(ALLOC_VEC4);
152
+ vec4 corners[8];
153
+ hash_to_corners(corners, corners_v);
154
+ glm_frustum_center(corners, VAL2VEC4(dest));
155
+ return dest;
156
+ }
157
+
158
+ /* call-seq: aabb(matr, corners[, dest]) => dest | new AABB
159
+ *
160
+ * Finds a bounding box for the frustum defined by `corners` relative to the
161
+ * givn matrix (e.g. a view matrix). Places the result in `dest` and returns
162
+ * `dest`, or a new AABB if `dest` is omitted.
163
+ */
164
+ VALUE rb_cglm_frustum_singleton_aabb(int argc, VALUE *argv, VALUE self) {
165
+ VALUE matr, corners_v, dest;
166
+ rb_scan_args(argc, argv, "21", &matr, &corners_v, &dest);
167
+ if (NIL_P(dest)) dest = rb_funcall(rb_cAABB, rb_intern("new"), 0);
168
+ vec4 corners[8];
169
+ hash_to_corners(corners, corners_v);
170
+ glm_frustum_box(corners, VAL2MAT4(matr), VAL2AABB(dest).corners);
171
+ return dest;
172
+ }
173
+
174
+ /* call-seq: corners_at(corners, split, far[, dest]) => dest | new Hash
175
+ *
176
+ * Finds the corners of a plane which lies between the near and far planes of
177
+ * the frustum.
178
+ *
179
+ * This will be helpful if you want to split a frustum, e.g. CSM/PSSM.
180
+ *
181
+ * * `corners` are the 8 corners of the frustum and follow the same format as
182
+ * is returned by {corners}.
183
+ *
184
+ * * `split` is the distance at which to calculate the 4 corners.
185
+ *
186
+ * * `far` is the far distance of the frustum.
187
+ *
188
+ * * `dest` is a Hash containing :lb, :lt, :rt, and :rb (all of which are
189
+ * Vec4's). If omitted, one will be created.
190
+ */
191
+ VALUE rb_cglm_frustum_singleton_corners_at(int argc, VALUE *argv, VALUE self) {
192
+ VALUE corners_v, split, f, dest;
193
+ rb_scan_args(argc, argv, "31", &corners_v, &split, &f, &dest);
194
+ if (NIL_P(dest)) dest = rb_hash_new();
195
+ vec4 corners[8];
196
+ hash_to_corners(corners, corners_v);
197
+ vec4 plane_corners[4];
198
+ glm_frustum_corners_at(corners, NUM2FLT(split), NUM2FLT(f), plane_corners);
199
+
200
+ #define HASH_GET_OR_SET(index, name) \
201
+ VALUE name = rb_hash_aref(dest, SYMBOL(#name)); \
202
+ if (NIL_P(name)) { \
203
+ name = VEC4_NEW(ALLOC_VEC4); \
204
+ rb_hash_aset(dest, SYMBOL(#name), name); \
205
+ } \
206
+ memcpy(&VAL2VEC4(name), &plane_corners[index], sizeof(vec4));
207
+
208
+ HASH_GET_OR_SET(0, lb);
209
+ HASH_GET_OR_SET(1, lt);
210
+ HASH_GET_OR_SET(2, rt);
211
+ HASH_GET_OR_SET(3, rb);
212
+ #undef HASH_GET_OR_SET
213
+
214
+ return dest;
215
+ }
216
+
217
+ /* call-seq: planes([dest]) => dest | new Hash
218
+ *
219
+ * Same as calling {planes} with `self.matrix` as the first argument.
220
+ */
221
+ VALUE rb_cglm_frustum_planes(int argc, VALUE *argv, VALUE self) {
222
+ VALUE mat = rb_ivar_get(self, rb_intern("@matrix"));
223
+ VALUE dest;
224
+ rb_scan_args(argc, argv, "01", &dest);
225
+ return rb_funcall(rb_cFrustum, rb_intern("planes"), 2, mat, dest);
226
+ }
227
+
228
+ /* call-seq: corners([dest]) => dest | new Hash
229
+ *
230
+ * Same as calling {corners} with `self.matrix.inverse` as the first argument.
231
+ */
232
+ VALUE rb_cglm_frustum_corners(int argc, VALUE *argv, VALUE self) {
233
+ VALUE mat = rb_funcall(rb_ivar_get(self, rb_intern("@matrix")), rb_intern("inverse"), 0);
234
+ VALUE dest;
235
+ rb_scan_args(argc, argv, "01", &dest);
236
+ return rb_funcall(rb_cFrustum, rb_intern("corners"), 2, mat, dest);
237
+ }
238
+
239
+ /* call-seq: center([dest]) => dest | new Hash
240
+ *
241
+ * Same as calling {center} with #corners as the first argument.
242
+ */
243
+ VALUE rb_cglm_frustum_center(int argc, VALUE *argv, VALUE self) {
244
+ VALUE corners = rb_funcall(self, rb_intern("corners"), 0);
245
+ VALUE dest;
246
+ rb_scan_args(argc, argv, "01", &dest);
247
+ return rb_funcall(rb_cFrustum, rb_intern("center"), 2, corners, dest);
248
+ }
249
+
250
+ /* call-seq: to_aabb(matr[, dest]) => dest | new AABB
251
+ *
252
+ * Same as calling {aabb} with #corners as the first argument.
253
+ */
254
+ VALUE rb_cglm_frustum_to_aabb(int argc, VALUE *argv, VALUE self) {
255
+ VALUE corners = rb_funcall(self, rb_intern("corners"), 0);
256
+ VALUE split, f, dest;
257
+ rb_scan_args(argc, argv, "21", &split, &f, &dest);
258
+ return rb_funcall(rb_cFrustum, rb_intern("aabb"), 4, corners, split, f, dest);
259
+ }
260
+
261
+ /* call-seq: corners_at(split, far[, dest]) => dest | new Hash
262
+ *
263
+ * Same as calling {corners_at} with #corners as the first argument.
264
+ */
265
+ VALUE rb_cglm_frustum_corners_at(int argc, VALUE *argv, VALUE self) {
266
+ VALUE corners = rb_funcall(self, rb_intern("corners"), 0);
267
+ VALUE split, f, dest;
268
+ rb_scan_args(argc, argv, "21", &split, &f, &dest);
269
+ return rb_funcall(rb_cFrustum, rb_intern("corners_at"), 4, corners, split, f, dest);
270
+ }
271
+
272
+ void Init_cglm_frustum() {
273
+ /* left bottom near */ rb_define_const(rb_cFrustum, "LBN", GLM_LBN);
274
+ /* left top near */ rb_define_const(rb_cFrustum, "LTN", GLM_LTN);
275
+ /* right top near */ rb_define_const(rb_cFrustum, "RTN", GLM_RTN);
276
+ /* right bottom near */ rb_define_const(rb_cFrustum, "RBN", GLM_RBN);
277
+ /* left bottom far */ rb_define_const(rb_cFrustum, "LBF", GLM_LBF);
278
+ /* left top far */ rb_define_const(rb_cFrustum, "LTF", GLM_LTF);
279
+ /* right top far */ rb_define_const(rb_cFrustum, "RTF", GLM_RTF);
280
+ /* right bottom far */ rb_define_const(rb_cFrustum, "RBF", GLM_RBF);
281
+ rb_define_const(rb_cFrustum, "LEFT", GLM_LEFT);
282
+ rb_define_const(rb_cFrustum, "RIGHT", GLM_RIGHT);
283
+ rb_define_const(rb_cFrustum, "BOTTOM", GLM_BOTTOM);
284
+ rb_define_const(rb_cFrustum, "TOP", GLM_TOP);
285
+ rb_define_const(rb_cFrustum, "NEAR", GLM_NEAR);
286
+ rb_define_const(rb_cFrustum, "FAR", GLM_FAR);
287
+ /* left bottom near */ rb_define_const(rb_cFrustum, "CLIPSPACE_COORD_LBN", VEC4_NEW(CSCOORD_LBN));
288
+ /* left top near */ rb_define_const(rb_cFrustum, "CLIPSPACE_COORD_LTN", VEC4_NEW(CSCOORD_LTN));
289
+ /* right top near */ rb_define_const(rb_cFrustum, "CLIPSPACE_COORD_RTN", VEC4_NEW(CSCOORD_RTN));
290
+ /* right bottom near */ rb_define_const(rb_cFrustum, "CLIPSPACE_COORD_RBN", VEC4_NEW(CSCOORD_RBN));
291
+ /* left bottom far */ rb_define_const(rb_cFrustum, "CLIPSPACE_COORD_LBF", VEC4_NEW(CSCOORD_LBF));
292
+ /* left top far */ rb_define_const(rb_cFrustum, "CLIPSPACE_COORD_LTF", VEC4_NEW(CSCOORD_LTF));
293
+ /* right top far */ rb_define_const(rb_cFrustum, "CLIPSPACE_COORD_RTF", VEC4_NEW(CSCOORD_RTF));
294
+ /* right bottom far */ rb_define_const(rb_cFrustum, "CLIPSPACE_COORD_RBF", VEC4_NEW(CSCOORD_RBF));
295
+
296
+ rb_define_method(rb_cFrustum, "planes", rb_cglm_frustum_planes, -1);
297
+ rb_define_method(rb_cFrustum, "corners", rb_cglm_frustum_corners, -1);
298
+ rb_define_method(rb_cFrustum, "center", rb_cglm_frustum_center, -1);
299
+ rb_define_method(rb_cFrustum, "aabb", rb_cglm_frustum_to_aabb, -1);
300
+ rb_define_method(rb_cFrustum, "corners_at", rb_cglm_frustum_to_aabb, -1);
301
+
302
+ rb_define_singleton_method(rb_cFrustum, "planes", rb_cglm_frustum_singleton_planes, -1);
303
+ rb_define_singleton_method(rb_cFrustum, "corners", rb_cglm_frustum_singleton_corners, -1);
304
+ rb_define_singleton_method(rb_cFrustum, "to_aabb", rb_cglm_frustum_singleton_aabb, -1);
305
+ rb_define_singleton_method(rb_cFrustum, "corners_at", rb_cglm_frustum_singleton_corners_at, -1);
306
+ }
@@ -0,0 +1,252 @@
1
+ #include "rb_cglm.h"
2
+
3
+ /* call-seq: identity([dest]) => dest | new Mat3
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 Mat3 is returned.
7
+ */
8
+ VALUE rb_cglm_mat3_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 = MAT3_NEW(ALLOC_MAT3);
12
+ glm_mat3_identity(VAL2MAT3(dest));
13
+ return dest;
14
+ }
15
+
16
+ /* call-seq: mul_mat3(other[, dest]) => dest | new Mat3
17
+ *
18
+ * Multiplies this Mat3 with `other`, returning the result.
19
+ */
20
+ VALUE rb_cglm_mat3_mul_mat3(int argc, VALUE *argv, VALUE self) {
21
+ VALUE other, dest;
22
+ rb_scan_args(argc, argv, "11", &other, &dest);
23
+ if (NIL_P(dest)) dest = MAT3_NEW(ALLOC_MAT3);
24
+ glm_mat3_mul(VAL2MAT3(self), VAL2MAT3(other), VAL2MAT3(dest));
25
+ return dest;
26
+ }
27
+
28
+ /* call-seq: mul_vec3(other[, dest]) => dest | new Vec3
29
+ *
30
+ * Multiplies this Vec3 with `other`, returning the result.
31
+ */
32
+ VALUE rb_cglm_mat3_mul_vec3(int argc, VALUE *argv, VALUE self) {
33
+ VALUE other, dest;
34
+ rb_scan_args(argc, argv, "11", &other, &dest);
35
+ if (NIL_P(dest)) dest = VEC3_NEW(ALLOC_VEC3);
36
+ glm_mat3_mulv(VAL2MAT3(self), VAL2VEC3(other), VAL2VEC3(dest));
37
+ return dest;
38
+ }
39
+
40
+ /* call-seq: transpose([dest]) => dest | new Mat3
41
+ *
42
+ * Transposes this matrix and places it into `dest`. If `dest` is omitted, a
43
+ * new Mat3 will be allocated.
44
+ */
45
+ VALUE rb_cglm_mat3_transpose(int argc, VALUE *argv, VALUE self) {
46
+ VALUE dest;
47
+ rb_scan_args(argc, argv, "01", &dest);
48
+ if (NIL_P(dest)) dest = MAT3_NEW(ALLOC_MAT3);
49
+ glm_mat3_transpose_to(VAL2MAT3(self), VAL2MAT3(dest));
50
+ return dest;
51
+ }
52
+
53
+ /* call-seq: transpose! => self
54
+ *
55
+ * Transposes this matrix in-place and returns `self`.
56
+ */
57
+ VALUE rb_cglm_mat3_transpose_self(int argc, VALUE *argv, VALUE self) {
58
+ glm_mat3_transpose(VAL2MAT3(self));
59
+ return self;
60
+ }
61
+
62
+ /* call-seq: to_quat([dest]) => dest | new Quat
63
+ *
64
+ * Converts `self` to a Quat. If `dest` is omitted, a new Quat is created.
65
+ */
66
+ VALUE rb_cglm_mat3_to_quat(int argc, VALUE *argv, VALUE self) {
67
+ VALUE dest;
68
+ rb_scan_args(argc, argv, "01", &dest);
69
+ if (NIL_P(dest)) dest = QUAT_NEW(ALLOC_QUAT);
70
+ glm_mat3_quat(VAL2MAT3(self), VAL2QUAT(dest));
71
+ return dest;
72
+ }
73
+
74
+ /* call-seq: mul_scalar(scalar[, dest]) => dest | new Mat3
75
+ *
76
+ * Multiplies each element in this matrix by the specified scalar amount.
77
+ * Places the result in `dest` and returns it, creating a new Mat3 if `dest`
78
+ * is omitted.
79
+ */
80
+ VALUE rb_cglm_mat3_mul_scalar(int argc, VALUE *argv, VALUE self) {
81
+ VALUE scalar, dest;
82
+ rb_scan_args(argc, argv, "11", &scalar, &dest);
83
+ if (NIL_P(dest)) dest = MAT3_NEW(ALLOC_MAT3);
84
+ glm_mat3_scale(VAL2MAT3(dest), NUM2FLT(scalar));
85
+ return dest;
86
+ }
87
+
88
+ /* call-seq: mul_scalar!(scalar) => self
89
+ *
90
+ * Multiplies each element in this matrix by the specified scalar amount,
91
+ * modifying `self` in-place and returning it.
92
+ */
93
+ VALUE rb_cglm_mat3_mul_scalar_self(VALUE self, VALUE scalar) {
94
+ glm_mat3_scale(VAL2MAT3(self), NUM2FLT(scalar));
95
+ return self;
96
+ }
97
+
98
+ VALUE rb_cglm_mat3_determinant(VALUE self) {
99
+ return glm_mat3_det(VAL2MAT3(self));
100
+ }
101
+
102
+ /* call-seq: inverse([dest]) => dest | new Mat3
103
+ *
104
+ * Places the inverse of `self` into `dest`, creating a new Mat3 if `dest` is
105
+ * omitted. Returns `dest`.
106
+ */
107
+ VALUE rb_cglm_mat3_inverse(int argc, VALUE *argv, VALUE self) {
108
+ VALUE dest;
109
+ rb_scan_args(argc, argv, "01", &dest);
110
+ if (NIL_P(dest)) dest = MAT3_NEW(ALLOC_MAT3);
111
+ glm_mat3_inv(VAL2MAT3(self), VAL2MAT3(dest));
112
+ return dest;
113
+ }
114
+
115
+ /* call-seq: invert! => self
116
+ *
117
+ * Calcaultes the inverse of `self`, modifies `self` in-place, and returns
118
+ * `self`.
119
+ */
120
+ VALUE rb_cglm_mat3_inverse_self(int argc, VALUE *argv, VALUE self) {
121
+ glm_mat3_inv(VAL2MAT3(self), VAL2MAT3(self));
122
+ return self;
123
+ }
124
+
125
+ /* call-seq: swap_col!(col1, col2) => self
126
+ *
127
+ * Swaps two matrix columns and returns `self`.
128
+ */
129
+ VALUE rb_cglm_mat3_swap_col_self(VALUE self, VALUE col1, VALUE col2) {
130
+ glm_mat3_swap_col(VAL2MAT3(self), NUM2INT(col1), NUM2INT(col2));
131
+ return self;
132
+ }
133
+
134
+ /* call-seq: swap_row!(row1, row2) => self
135
+ *
136
+ * Swaps two matrix rows and returns `self`.
137
+ */
138
+ VALUE rb_cglm_mat3_swap_row_self(VALUE self, VALUE row1, VALUE row2) {
139
+ glm_mat3_swap_row(VAL2MAT3(self), NUM2INT(row1), NUM2INT(row2));
140
+ return self;
141
+ }
142
+
143
+ VALUE rb_cglm_mat3_aref(VALUE self, VALUE index) {
144
+ CHECK_RANGE(index, 0, 2);
145
+ float *addr = (float *) VAL2MAT3(self);
146
+ return VEC3_NEW(addr + (NUM2INT(index) * 3));
147
+ }
148
+
149
+ VALUE rb_cglm_mat3_aset(VALUE self, VALUE index, VALUE val) {
150
+ CHECK_RANGE(index, 0, 2);
151
+ if (rb_funcall(val, rb_intern("kind_of?"), 1, rb_cVec4))
152
+ memcpy(&(VAL2MAT4(self)[NUM2INT(index)]), &VAL2VEC4(val), sizeof(vec3));
153
+ else if (rb_funcall(val, rb_intern("kind_of?"), 1, rb_cVec3))
154
+ memcpy(&(VAL2MAT4(self)[NUM2INT(index)]), &VAL2VEC3(val), sizeof(vec3));
155
+ else {
156
+ VALUE row = rb_cglm_mat3_aref(self, index);
157
+ for (int i = 0; i < 3; i++) {
158
+ VALUE v = rb_funcall(val, rb_intern("[]"), 1, INT2NUM(i));
159
+ if (!NIL_P(v)) {
160
+ rb_funcall(row, rb_intern("[]="), 2, INT2NUM(i), v);
161
+ }
162
+ }
163
+ }
164
+ return self;
165
+ }
166
+
167
+ VALUE rb_cglm_mat3_to_mat4(int argc, VALUE *argv, VALUE self) {
168
+ VALUE dest;
169
+ if (argc == 0) dest = MAT4_NEW(ALLOC_MAT4);
170
+ dest = argv[0];
171
+ glm_mat4_ins3(VAL2MAT3(self), VAL2MAT4(dest));
172
+ return dest;
173
+ }
174
+
175
+ VALUE rb_cglm_mat3_size_bytes(VALUE klass) { return SIZET2NUM(mat3_size()); }
176
+
177
+ VALUE rb_cglm_mat3_alignment_bytes(VALUE klass) { return SIZET2NUM(MAT3_ALIGNMENT); }
178
+
179
+ VALUE rb_cglm_mat3_equal(VALUE self, VALUE other) {
180
+ if (memcmp(&VAL2MAT3(self), &VAL2MAT3(other), sizeof(mat3))) return Qfalse;
181
+ return Qtrue;
182
+ }
183
+
184
+ /* call-seq: a =~ b => true|false
185
+ *
186
+ * Returns true if each member of `a` is very close to, but not necessarily
187
+ * exactly equal to, each corresponding member of `b`. This is useful in many
188
+ * circumstances because imprecision introduced by floating point calculations
189
+ * can lead to two expressions which are otherwise mathematically equivalent
190
+ * returning false.
191
+ */
192
+ VALUE rb_cglm_mat3_equalish(int argc, VALUE *argv, VALUE self) {
193
+ VALUE other, epsilon;
194
+ float feps = FLT_EPSILON;
195
+ rb_scan_args(argc, argv, "11", &other, &epsilon);
196
+ if (!NIL_P(epsilon)) feps = NUM2FLT(epsilon);
197
+ mat3 *a = &VAL2MAT3(self);
198
+ mat3 *b = &VAL2MAT3(other);
199
+ for (int i = 0; i < 3; i++) {
200
+ for (int j = 0; j < 3; j++) {
201
+ if (fabsf((*a)[i][j] - (*b)[i][j]) > feps)
202
+ return Qfalse;
203
+ }
204
+ }
205
+ return Qtrue;
206
+ }
207
+
208
+ /* call-seq: random([dest]) => dest | new Mat3
209
+ *
210
+ * Fills `dest` or a new Mat3 with a random rotation about a random axis with
211
+ * a random angle, and returns it.
212
+ */
213
+ VALUE rb_cglm_mat3_new_random(int argc, VALUE *argv, VALUE self) {
214
+ VALUE dest;
215
+ rb_scan_args(argc, argv, "01", &dest);
216
+ if (NIL_P(dest)) dest = MAT3_NEW(ALLOC_MAT3);
217
+
218
+ mat4 m4;
219
+ glm_rotate_make(m4, drand48(), (vec3){drand48(), drand48(), drand48()});
220
+ glm_mat4_pick3(m4, VAL2MAT3(dest));
221
+
222
+ return dest;
223
+ }
224
+
225
+ void Init_cglm_mat3() {
226
+ rb_define_method(rb_cMat3, "equalish", rb_cglm_mat3_equalish, -1);
227
+ rb_define_method(rb_cMat3, "==", rb_cglm_mat3_equal, 1);
228
+ rb_define_method(rb_cMat3, "[]", rb_cglm_mat3_aref, 1);
229
+ rb_define_method(rb_cMat3, "[]=", rb_cglm_mat3_aset, 2);
230
+ rb_define_method(rb_cMat3, "mul_mat3", rb_cglm_mat3_mul_mat3, -1);
231
+ rb_define_method(rb_cMat3, "mul_vec3", rb_cglm_mat3_mul_vec3, -1);
232
+ rb_define_method(rb_cMat3, "mul_scalar", rb_cglm_mat3_mul_scalar, -1);
233
+ rb_define_method(rb_cMat3, "mul_scalar!", rb_cglm_mat3_mul_scalar_self, 0);
234
+ rb_define_method(rb_cMat3, "transpose", rb_cglm_mat3_transpose, -1);
235
+ rb_define_method(rb_cMat3, "transpose!", rb_cglm_mat3_transpose_self, 0);
236
+ rb_define_method(rb_cMat3, "to_quat", rb_cglm_mat3_to_quat, -1);
237
+ rb_define_method(rb_cMat3, "determinant", rb_cglm_mat3_determinant, 0);
238
+ rb_define_method(rb_cMat3, "invert", rb_cglm_mat3_inverse, -1);
239
+ rb_define_method(rb_cMat3, "invert!", rb_cglm_mat3_inverse_self, 0);
240
+ rb_define_method(rb_cMat3, "swap_col!", rb_cglm_mat3_swap_col_self, 2);
241
+ rb_define_method(rb_cMat3, "swap_row!", rb_cglm_mat3_swap_row_self, 2);
242
+ rb_define_method(rb_cMat3, "to_mat4", rb_cglm_mat3_to_mat4, -1);
243
+
244
+ rb_define_alias(rb_cMat3, "=~", "equalish");
245
+ rb_define_alias(rb_cMat3, "det", "determinant");
246
+
247
+ rb_define_singleton_method(rb_cMat3, "identity", rb_cglm_mat3_new_identity, -1);
248
+ rb_define_singleton_method(rb_cMat3, "size", rb_cglm_mat3_size_bytes, 0);
249
+ rb_define_singleton_method(rb_cMat3, "alignment", rb_cglm_mat3_alignment_bytes, 0);
250
+ rb_define_singleton_method(rb_cMat3, "random", rb_cglm_mat3_new_random, -1);
251
+ rb_define_singleton_method(rb_cMat3, "rand", rb_cglm_mat3_new_random, -1);
252
+ }