cglm 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }