snow-math 0.0.1
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.
- checksums.yaml +7 -0
- data/ext/extconf.rb +17 -0
- data/ext/snow-math/mat4.c +739 -0
- data/ext/snow-math/maths.c +2 -0
- data/ext/snow-math/maths_local.h +257 -0
- data/ext/snow-math/quat.c +187 -0
- data/ext/snow-math/snow-math.c +2117 -0
- data/ext/snow-math/vec3.c +144 -0
- data/ext/snow-math/vec4.c +145 -0
- data/lib/snow-math.rb +14 -0
- data/lib/snow-math/inspect.rb +20 -0
- data/lib/snow-math/line.rb +0 -0
- data/lib/snow-math/mat3.rb +0 -0
- data/lib/snow-math/mat4.rb +80 -0
- data/lib/snow-math/plane.rb +0 -0
- data/lib/snow-math/ptr.rb +25 -0
- data/lib/snow-math/quat.rb +114 -0
- data/lib/snow-math/swizzle.rb +57 -0
- data/lib/snow-math/to_a.rb +51 -0
- data/lib/snow-math/vec2.rb +0 -0
- data/lib/snow-math/vec3.rb +111 -0
- data/lib/snow-math/vec4.rb +113 -0
- metadata +71 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
/*
|
2
|
+
3D math types & macros
|
3
|
+
Written by Noel Cower
|
4
|
+
|
5
|
+
See COPYING for license information
|
6
|
+
*/
|
7
|
+
|
8
|
+
#ifndef __SNOW__MATHS_H__
|
9
|
+
#define __SNOW__MATHS_H__
|
10
|
+
|
11
|
+
#ifdef __cplusplus
|
12
|
+
#include <cmath>
|
13
|
+
#else
|
14
|
+
#include <math.h>
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#ifdef __SNOW__MATHS_C__
|
18
|
+
#define S_INLINE
|
19
|
+
#else
|
20
|
+
#define S_INLINE inline
|
21
|
+
#endif
|
22
|
+
|
23
|
+
#if defined(__cplusplus)
|
24
|
+
extern "C" {
|
25
|
+
#endif /* __cplusplus */
|
26
|
+
|
27
|
+
/* Typedefs and macros for specific floating point types */
|
28
|
+
#ifdef USE_FLOAT
|
29
|
+
typedef float s_float_t;
|
30
|
+
#define s_cos cosf
|
31
|
+
#define s_sin sinf
|
32
|
+
#define s_tan tanf
|
33
|
+
#define s_acos acosf
|
34
|
+
#define s_asin asinf
|
35
|
+
#define s_atan atanf
|
36
|
+
#define s_fabs fabsf
|
37
|
+
#else
|
38
|
+
typedef double s_float_t;
|
39
|
+
#define s_cos cos
|
40
|
+
#define s_sin sin
|
41
|
+
#define s_tan tan
|
42
|
+
#define s_acos acos
|
43
|
+
#define s_asin asin
|
44
|
+
#define s_atan atan
|
45
|
+
#define s_fabs fabs
|
46
|
+
#endif
|
47
|
+
|
48
|
+
typedef s_float_t mat4_t[16];
|
49
|
+
typedef s_float_t vec4_t[4];
|
50
|
+
typedef s_float_t vec3_t[3];
|
51
|
+
typedef s_float_t vec2_t[2];
|
52
|
+
typedef s_float_t quat_t[4];
|
53
|
+
|
54
|
+
|
55
|
+
/*!
|
56
|
+
* Floating point epsilon for double comparisons. This is, more or less, the
|
57
|
+
* limit to accuracy. If the difference between two floating point values is
|
58
|
+
* less than the epsilon, they are for all intents and purposes the same.
|
59
|
+
*
|
60
|
+
* It should be stressed that this is absolutely not an accurate epsilon.
|
61
|
+
*/
|
62
|
+
#define S_FLOAT_EPSILON (1.0e-9)
|
63
|
+
|
64
|
+
#define S_DEG2RAD (0.01745329)
|
65
|
+
#define S_RAD2DEG (57.2957795)
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
/* Float comparison functions */
|
70
|
+
|
71
|
+
S_INLINE int float_is_zero(const s_float_t x)
|
72
|
+
{
|
73
|
+
return (s_fabs(x) < S_FLOAT_EPSILON);
|
74
|
+
}
|
75
|
+
|
76
|
+
S_INLINE int float_equals(const s_float_t x, const s_float_t y)
|
77
|
+
{
|
78
|
+
return float_is_zero(x - y);
|
79
|
+
}
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
/*==============================================================================
|
84
|
+
|
85
|
+
3-Component Vector (vec3_t)
|
86
|
+
|
87
|
+
==============================================================================*/
|
88
|
+
|
89
|
+
extern const vec3_t g_vec3_zero;
|
90
|
+
extern const vec3_t g_vec3_one;
|
91
|
+
|
92
|
+
void vec3_copy(const vec3_t in, vec3_t out);
|
93
|
+
void vec3_set(s_float_t x, s_float_t y, s_float_t z, vec3_t v);
|
94
|
+
|
95
|
+
/*!
|
96
|
+
* Gets the squared length of a vector. Useful for approximations and when
|
97
|
+
* you don't need the actual magnitude.
|
98
|
+
*/
|
99
|
+
s_float_t vec3_length_squared(const vec3_t v);
|
100
|
+
/*!
|
101
|
+
* Gets the length/magnitude of a vector.
|
102
|
+
*/
|
103
|
+
s_float_t vec3_length(const vec3_t v);
|
104
|
+
void vec3_normalize(const vec3_t in, vec3_t out);
|
105
|
+
|
106
|
+
void vec3_subtract(const vec3_t left, const vec3_t right, vec3_t out);
|
107
|
+
void vec3_add(const vec3_t left, const vec3_t right, vec3_t out);
|
108
|
+
void vec3_multiply(const vec3_t left, const vec3_t right, vec3_t out);
|
109
|
+
void vec3_negate(const vec3_t v, vec3_t out);
|
110
|
+
void vec3_inverse(const vec3_t v, vec3_t out);
|
111
|
+
|
112
|
+
void vec3_cross_product(const vec3_t left, const vec3_t right, vec3_t out);
|
113
|
+
s_float_t vec3_dot_product(const vec3_t left, const vec3_t right);
|
114
|
+
|
115
|
+
void vec3_scale(const vec3_t v, s_float_t scalar, vec3_t out);
|
116
|
+
int vec3_divide(const vec3_t v, s_float_t divisor, vec3_t out);
|
117
|
+
|
118
|
+
int vec3_equals(const vec3_t left, const vec3_t right);
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
/*==============================================================================
|
123
|
+
|
124
|
+
4-Component Vector (vec4_t)
|
125
|
+
|
126
|
+
==============================================================================*/
|
127
|
+
|
128
|
+
extern const vec4_t g_vec4_zero;
|
129
|
+
extern const vec4_t g_vec4_one;
|
130
|
+
extern const vec4_t g_vec4_identity;
|
131
|
+
|
132
|
+
void vec4_copy(const vec4_t in, vec4_t out);
|
133
|
+
void vec4_set(s_float_t x, s_float_t y, s_float_t z, s_float_t w, vec4_t v);
|
134
|
+
|
135
|
+
/*!
|
136
|
+
* Gets the squared length of a vector. Useful for approximations and when
|
137
|
+
* you don't need the actual magnitude.
|
138
|
+
*/
|
139
|
+
s_float_t vec4_length_squared(const vec4_t v);
|
140
|
+
/*!
|
141
|
+
* Gets the length/magnitude of a vector.
|
142
|
+
*/
|
143
|
+
s_float_t vec4_length(const vec4_t v);
|
144
|
+
void vec4_normalize(const vec4_t in, vec4_t out);
|
145
|
+
|
146
|
+
void vec4_subtract(const vec4_t left, const vec4_t right, vec4_t out);
|
147
|
+
void vec4_add(const vec4_t left, const vec4_t right, vec4_t out);
|
148
|
+
void vec4_multiply(const vec4_t left, const vec4_t right, vec4_t out);
|
149
|
+
void vec4_negate(const vec4_t v, vec4_t out);
|
150
|
+
void vec4_inverse(const vec4_t v, vec4_t out);
|
151
|
+
|
152
|
+
s_float_t vec4_dot_product(const vec4_t left, const vec4_t right);
|
153
|
+
|
154
|
+
void vec4_scale(const vec4_t v, s_float_t scalar, vec4_t out);
|
155
|
+
int vec4_divide(const vec4_t v, s_float_t divisor, vec4_t out);
|
156
|
+
|
157
|
+
int vec4_equals(const vec4_t left, const vec4_t right);
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
/*==============================================================================
|
162
|
+
|
163
|
+
4x4 Matrix (mat4_t)
|
164
|
+
|
165
|
+
==============================================================================*/
|
166
|
+
|
167
|
+
extern const mat4_t g_mat4_identity;
|
168
|
+
|
169
|
+
void mat4_identity(mat4_t out);
|
170
|
+
void mat4_copy(const mat4_t in, mat4_t out);
|
171
|
+
void mat4_set(
|
172
|
+
s_float_t m00, s_float_t m01, s_float_t m02, s_float_t m03,
|
173
|
+
s_float_t m04, s_float_t m05, s_float_t m06, s_float_t m07,
|
174
|
+
s_float_t m08, s_float_t m09, s_float_t m10, s_float_t m11,
|
175
|
+
s_float_t m12, s_float_t m13, s_float_t m14, s_float_t m15,
|
176
|
+
mat4_t out);
|
177
|
+
|
178
|
+
void mat4_set_axes3(const vec3_t x, const vec3_t y, const vec3_t z, const vec3_t w, mat4_t out);
|
179
|
+
void mat4_get_axes3(const mat4_t m, vec3_t x, vec3_t y, vec3_t z, vec3_t w);
|
180
|
+
void mat4_set_axes4(const vec4_t x, const vec4_t y, const vec4_t z, const vec4_t w, mat4_t out);
|
181
|
+
void mat4_get_axes4(const mat4_t m, vec4_t x, vec4_t y, vec4_t z, vec4_t w);
|
182
|
+
|
183
|
+
/*! Builds a rotation matrix with the given angle and axis. */
|
184
|
+
void mat4_rotation(s_float_t angle, s_float_t x, s_float_t y, s_float_t z, mat4_t out);
|
185
|
+
void mat4_frustum(s_float_t left, s_float_t right, s_float_t bottom, s_float_t top, s_float_t near, s_float_t far, mat4_t out);
|
186
|
+
void mat4_orthographic(s_float_t left, s_float_t right, s_float_t bottom, s_float_t top, s_float_t near, s_float_t far, mat4_t out);
|
187
|
+
void mat4_perspective(s_float_t fov_y, s_float_t aspect, s_float_t near, s_float_t far, mat4_t out);
|
188
|
+
void mat4_look_at(const vec3_t eye, const vec3_t center, const vec3_t up, mat4_t out);
|
189
|
+
void mat4_from_quat(const quat_t quat, mat4_t out);
|
190
|
+
|
191
|
+
void mat4_get_row4(const mat4_t in, int row, vec4_t out);
|
192
|
+
void mat4_get_row3(const mat4_t in, int row, vec3_t out);
|
193
|
+
void mat4_get_column4(const mat4_t in, int column, vec4_t out);
|
194
|
+
void mat4_get_column3(const mat4_t in, int column, vec3_t out);
|
195
|
+
|
196
|
+
void mat4_set_row4(int row, const vec4_t value, mat4_t inout);
|
197
|
+
void mat4_set_row3(int row, const vec3_t value, mat4_t inout);
|
198
|
+
void mat4_set_column4(int column, const vec4_t value, mat4_t inout);
|
199
|
+
void mat4_set_column3(int column, const vec3_t value, mat4_t inout);
|
200
|
+
|
201
|
+
int mat4_equals(const mat4_t left, const mat4_t right);
|
202
|
+
|
203
|
+
void mat4_transpose(const mat4_t in, mat4_t out);
|
204
|
+
void mat4_inverse_orthogonal(const mat4_t in, mat4_t out);
|
205
|
+
/*!
|
206
|
+
* Writes the inverse affine of the input matrix to the output matrix.
|
207
|
+
* \returns Non-zero if an inverse affine matrix can be created, otherwise
|
208
|
+
* zero if not. If zero, the output matrix is the identity matrix.
|
209
|
+
*/
|
210
|
+
int mat4_inverse_affine(const mat4_t in, mat4_t out);
|
211
|
+
void mat4_adjoint(const mat4_t in, mat4_t out);
|
212
|
+
s_float_t mat4_determinant(const mat4_t m);
|
213
|
+
int mat4_inverse_general(const mat4_t in, mat4_t out);
|
214
|
+
|
215
|
+
/*! Translates the given matrix by <X, Y, Z>. */
|
216
|
+
void mat4_translate(s_float_t x, s_float_t y, s_float_t z, const mat4_t in, mat4_t out);
|
217
|
+
void mat4_translation(s_float_t x, s_float_t y, s_float_t z, mat4_t out);
|
218
|
+
void mat4_multiply(const mat4_t left, const mat4_t right, mat4_t out);
|
219
|
+
void mat4_multiply_vec4(const mat4_t left, const vec4_t right, vec4_t out);
|
220
|
+
void mat4_transform_vec3(const mat4_t left, const vec3_t right, vec3_t out);
|
221
|
+
void mat4_rotate_vec3(const mat4_t left, const vec3_t right, vec3_t out);
|
222
|
+
void mat4_inv_rotate_vec3(const mat4_t left, const vec3_t right, vec3_t out);
|
223
|
+
void mat4_scale(const mat4_t in, s_float_t x, s_float_t y, s_float_t z, mat4_t out);
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
/*==============================================================================
|
228
|
+
|
229
|
+
Quaternion (quat_t)
|
230
|
+
|
231
|
+
==============================================================================*/
|
232
|
+
|
233
|
+
extern const quat_t g_quat_identity;
|
234
|
+
|
235
|
+
/* note: all methods assume that input quaternions are unit quaternions */
|
236
|
+
|
237
|
+
void quat_set(s_float_t x, s_float_t y, s_float_t z, s_float_t w, quat_t out);
|
238
|
+
void quat_copy(const quat_t in, quat_t out);
|
239
|
+
void quat_identity(quat_t q);
|
240
|
+
|
241
|
+
void quat_inverse(const quat_t in, quat_t out);
|
242
|
+
void quat_negate(const quat_t in, quat_t out);
|
243
|
+
|
244
|
+
void quat_multiply(const quat_t left, const quat_t right, quat_t out);
|
245
|
+
void quat_multiply_vec3(const quat_t left, const vec3_t right, vec3_t out);
|
246
|
+
|
247
|
+
void quat_from_angle_axis(s_float_t angle, s_float_t x, s_float_t y, s_float_t z, quat_t out);
|
248
|
+
void quat_from_mat4(const mat4_t mat, quat_t out);
|
249
|
+
|
250
|
+
void quat_slerp(const quat_t from, const quat_t to, s_float_t delta, quat_t out);
|
251
|
+
|
252
|
+
#if defined(__cplusplus)
|
253
|
+
}
|
254
|
+
#endif /* __cplusplus */
|
255
|
+
|
256
|
+
#endif /* end of include guard: __SNOW__MATHS_H__ */
|
257
|
+
|
@@ -0,0 +1,187 @@
|
|
1
|
+
/*
|
2
|
+
Quaternion maths
|
3
|
+
Written by Noel Cower
|
4
|
+
|
5
|
+
See COPYING for license information
|
6
|
+
*/
|
7
|
+
|
8
|
+
#define __SNOW__QUAT_C__
|
9
|
+
|
10
|
+
#include "maths_local.h"
|
11
|
+
|
12
|
+
#if defined(__cplusplus)
|
13
|
+
extern "C"
|
14
|
+
{
|
15
|
+
#endif /* __cplusplus */
|
16
|
+
|
17
|
+
const quat_t g_quat_identity = {0.0, 0.0, 0.0, 1.0};
|
18
|
+
|
19
|
+
void quat_set(s_float_t x, s_float_t y, s_float_t z, s_float_t w, quat_t out)
|
20
|
+
{
|
21
|
+
out[0] = x;
|
22
|
+
out[1] = y;
|
23
|
+
out[2] = z;
|
24
|
+
out[3] = w;
|
25
|
+
}
|
26
|
+
|
27
|
+
void quat_copy(const quat_t in, quat_t out)
|
28
|
+
{
|
29
|
+
if (in == out) return;
|
30
|
+
|
31
|
+
out[0] = in[0];
|
32
|
+
out[1] = in[1];
|
33
|
+
out[2] = in[2];
|
34
|
+
out[3] = in[3];
|
35
|
+
}
|
36
|
+
|
37
|
+
void quat_identity(quat_t q)
|
38
|
+
{
|
39
|
+
q[0] = q[1] = q[2] = 0.0;
|
40
|
+
q[3] = 1.0;
|
41
|
+
}
|
42
|
+
|
43
|
+
void quat_inverse(const quat_t in, quat_t out)
|
44
|
+
{
|
45
|
+
out[0] = -in[0];
|
46
|
+
out[1] = -in[1];
|
47
|
+
out[2] = -in[2];
|
48
|
+
out[3] = in[3];
|
49
|
+
}
|
50
|
+
|
51
|
+
void quat_negate(const quat_t in, quat_t out)
|
52
|
+
{
|
53
|
+
out[0] = -in[0];
|
54
|
+
out[1] = -in[1];
|
55
|
+
out[2] = -in[2];
|
56
|
+
out[3] = -in[3];
|
57
|
+
}
|
58
|
+
|
59
|
+
void quat_multiply(const quat_t left, const quat_t right, quat_t out)
|
60
|
+
{
|
61
|
+
s_float_t w;
|
62
|
+
s_float_t w1, w2;
|
63
|
+
vec3_t t1, t2;
|
64
|
+
w1 = left[3];
|
65
|
+
w2 = right[3];
|
66
|
+
|
67
|
+
w = (w1 * w2) - vec3_dot_product(left, right);
|
68
|
+
vec3_copy(right, t1);
|
69
|
+
vec3_scale(t1, w1, t1);
|
70
|
+
vec3_copy(left, t2);
|
71
|
+
vec3_scale(t2, w2, t2);
|
72
|
+
vec3_add(t1, t2, t1);
|
73
|
+
vec3_cross_product(right, left, t2);
|
74
|
+
vec3_add(t1, t2, t1);
|
75
|
+
vec3_copy(t1, out);
|
76
|
+
out[3] = w;
|
77
|
+
}
|
78
|
+
|
79
|
+
void quat_multiply_vec3(const quat_t left, const vec3_t right, vec3_t out)
|
80
|
+
{
|
81
|
+
vec3_t lxr_cross, lxlr_cross;
|
82
|
+
vec3_cross_product(left, right, lxr_cross);
|
83
|
+
vec3_cross_product(left, lxr_cross, lxlr_cross);
|
84
|
+
vec3_scale(lxr_cross, 2.0 * left[3], lxr_cross);
|
85
|
+
vec3_scale(lxlr_cross, 2.0, lxlr_cross);
|
86
|
+
vec3_add(lxr_cross, lxlr_cross, lxr_cross);
|
87
|
+
vec3_add(right, lxr_cross, out);
|
88
|
+
}
|
89
|
+
|
90
|
+
void quat_from_angle_axis(s_float_t angle, s_float_t x, s_float_t y, s_float_t z, quat_t out)
|
91
|
+
{
|
92
|
+
vec3_t v = {x, y, z};
|
93
|
+
vec3_normalize(v, v);
|
94
|
+
|
95
|
+
angle *= (S_DEG2RAD * 0.5);
|
96
|
+
const s_float_t s = s_sin(angle);
|
97
|
+
|
98
|
+
out[0] = v[0] * s;
|
99
|
+
out[1] = v[1] * s;
|
100
|
+
out[2] = v[2] * s;
|
101
|
+
out[3] = s_cos(angle);
|
102
|
+
}
|
103
|
+
|
104
|
+
void quat_from_mat4(const mat4_t mat, quat_t out)
|
105
|
+
{
|
106
|
+
s_float_t trace, r;
|
107
|
+
int index;
|
108
|
+
|
109
|
+
trace = mat[0] + mat[5] + mat[10];
|
110
|
+
if (trace > 0) {
|
111
|
+
r = sqrtf(trace + 1.0);
|
112
|
+
out[3] = r * 0.5;
|
113
|
+
r = 0.5 / r;
|
114
|
+
out[0] = (mat[9] - mat[6]) * r;
|
115
|
+
out[1] = (mat[2] - mat[8]) * r;
|
116
|
+
out[2] = (mat[4] - mat[1]) * r;
|
117
|
+
} else {
|
118
|
+
index = 0;
|
119
|
+
if (mat[5] > mat[0]) index = 1;
|
120
|
+
if (mat[10] > mat[index * 5]) index = 2;
|
121
|
+
|
122
|
+
r = sqrtf(mat[index * 5] - (mat[((index + 1)) % 3 * 5] + mat[((index + 2) % 3) * 5]) + 1.0);
|
123
|
+
out[index] = r * 0.5;
|
124
|
+
|
125
|
+
if (r) r = 0.5 / r;
|
126
|
+
|
127
|
+
switch (index)
|
128
|
+
{
|
129
|
+
case 0:
|
130
|
+
out[1] = (mat[1] + mat[4]) * r;
|
131
|
+
out[2] = (mat[2] + mat[8]) * r;
|
132
|
+
out[3] = (mat[9] - mat[6]) * r;
|
133
|
+
break;
|
134
|
+
|
135
|
+
case 1:
|
136
|
+
out[3] = (mat[2] + mat[8]) * r;
|
137
|
+
out[2] = (mat[9] + mat[6]) * r;
|
138
|
+
out[0] = (mat[1] - mat[4]) * r;
|
139
|
+
break;
|
140
|
+
|
141
|
+
case 2:
|
142
|
+
out[3] = (mat[4] + mat[1]) * r;
|
143
|
+
out[0] = (mat[2] + mat[8]) * r;
|
144
|
+
out[1] = (mat[6] - mat[9]) * r;
|
145
|
+
break;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
void quat_slerp(const quat_t from, const quat_t to, s_float_t delta, quat_t out)
|
151
|
+
{
|
152
|
+
s_float_t dot, scale0, scale1, angle, inverse_sin;
|
153
|
+
s_float_t dx, dy, dz, dw;
|
154
|
+
|
155
|
+
dot = vec4_dot_product((const s_float_t *)from, (const s_float_t *)to);
|
156
|
+
|
157
|
+
if (dot < 0.0) {
|
158
|
+
dot = -dot;
|
159
|
+
dx = -to[0];
|
160
|
+
dy = -to[1];
|
161
|
+
dz = -to[2];
|
162
|
+
dw = -to[3];
|
163
|
+
} else {
|
164
|
+
dx = to[0];
|
165
|
+
dy = to[1];
|
166
|
+
dz = to[2];
|
167
|
+
dw = to[3];
|
168
|
+
}
|
169
|
+
|
170
|
+
delta = fminf(fmaxf(delta, 0.0), 1.0);
|
171
|
+
|
172
|
+
angle = s_acos(dot);
|
173
|
+
inverse_sin = 1.0 / s_sin(dot);
|
174
|
+
|
175
|
+
scale0 = s_sin((1.0 - delta) * angle) * inverse_sin;
|
176
|
+
scale1 = s_sin(delta * angle) * inverse_sin;
|
177
|
+
|
178
|
+
out[0] = (from[0] * scale0) + (dx * scale1);
|
179
|
+
out[1] = (from[1] * scale0) + (dy * scale1);
|
180
|
+
out[2] = (from[2] * scale0) + (dz * scale1);
|
181
|
+
out[3] = (from[3] * scale0) + (dw * scale1);
|
182
|
+
}
|
183
|
+
|
184
|
+
#if defined(__cplusplus)
|
185
|
+
}
|
186
|
+
#endif /* __cplusplus */
|
187
|
+
|
@@ -0,0 +1,2117 @@
|
|
1
|
+
/*
|
2
|
+
Maths bindings for Ruby
|
3
|
+
Written by Noel Cower
|
4
|
+
|
5
|
+
See COPYING for license information
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include "maths_local.h"
|
9
|
+
#include "ruby.h"
|
10
|
+
|
11
|
+
/*
|
12
|
+
Generates a label within the current function with the given name. Should be
|
13
|
+
as unique as anyone needs.
|
14
|
+
*/
|
15
|
+
#define SM_LABEL(NAME) __FUNCTION__##NAME
|
16
|
+
|
17
|
+
/*
|
18
|
+
Returns the Ruby class value's identifier
|
19
|
+
*/
|
20
|
+
#define SM_KLASS(TYPE) s_sm_##TYPE##_klass
|
21
|
+
|
22
|
+
/*
|
23
|
+
Returns the wrap identifier for a given type. Only useful in functions
|
24
|
+
generated by macros. The wrapping function will always be sm_wrap_TYPE.
|
25
|
+
*/
|
26
|
+
#define SM_WRAP(TYPE) sm_wrap_##TYPE
|
27
|
+
|
28
|
+
/*
|
29
|
+
Same as SM_WRAP but for unwrapping. Will always be sm_unwrap_TYPE
|
30
|
+
*/
|
31
|
+
#define SM_UNWRAP(TYPE) sm_unwrap_##TYPE
|
32
|
+
|
33
|
+
/*
|
34
|
+
Defines the static class value for a type.
|
35
|
+
*/
|
36
|
+
#define DEF_SM_TYPE_KLASS(TYPE) static VALUE SM_KLASS(TYPE) = Qnil
|
37
|
+
|
38
|
+
/*
|
39
|
+
Returns whether a given ruby value is a kind of RB_TYPE (a Ruby value for a
|
40
|
+
class).
|
41
|
+
*/
|
42
|
+
#define SM_RB_IS_A(RB_VALUE, RB_TYPE) (RTEST(rb_obj_is_kind_of((RB_VALUE), (RB_TYPE))))
|
43
|
+
|
44
|
+
/*
|
45
|
+
Wrapper around SM_RB_IS_A that checks for SM_RB_IS_A(value, SM_KLASS(type)).
|
46
|
+
Vaguely convenient.
|
47
|
+
*/
|
48
|
+
#define SM_IS_A(SM_VALUE, SM_TYPE) SM_RB_IS_A(SM_VALUE, SM_KLASS(SM_TYPE))
|
49
|
+
|
50
|
+
/*
|
51
|
+
Convenience macro to raise an exception if a value isn't of a given type. Only
|
52
|
+
useful for a few things, as vec3, vec4, and quat are semi-compatible due to
|
53
|
+
having similar sizes. So any vec4/quat can be used as a vec3 in some cases and
|
54
|
+
any quat can be used in place of a vec4 except in the case of a few binary ops
|
55
|
+
and such (because the binary op macro doesn't check for much -- so that might
|
56
|
+
need rewriting later).
|
57
|
+
*/
|
58
|
+
#define SM_RAISE_IF_NOT_TYPE(SM_VALUE, SM_TYPE) do { \
|
59
|
+
if (!SM_IS_A(SM_VALUE, SM_TYPE)) { \
|
60
|
+
rb_raise(rb_eTypeError, "Expected %s, got %s", \
|
61
|
+
rb_class2name(SM_KLASS(SM_TYPE)), \
|
62
|
+
rb_obj_classname((SM_VALUE))); \
|
63
|
+
} } while (0)
|
64
|
+
|
65
|
+
/* Declares the wrap function for a type. */
|
66
|
+
#define DECL_SM_WRAP_OP(TYPE) \
|
67
|
+
static VALUE SM_WRAP(TYPE) (const TYPE##_t value, VALUE klass)
|
68
|
+
|
69
|
+
/* Declares the unwrap function for a type. */
|
70
|
+
#define DECL_SM_UNWRAP_OP(TYPE) \
|
71
|
+
static TYPE##_t * SM_UNWRAP(TYPE) (VALUE sm_value, TYPE##_t store)
|
72
|
+
|
73
|
+
|
74
|
+
/*
|
75
|
+
Note about generated wrap / unwrap functions:
|
76
|
+
Neither function actually cares about its input. It will not verify that a
|
77
|
+
quat is passed to sm_unwrap_quat and you can similarly pass a vec4 to
|
78
|
+
sm_wrap_vec3 or sm_wrap_quat, so the types are mostly interchangeable provided
|
79
|
+
they're of the same size.
|
80
|
+
|
81
|
+
This allows some flexibility when passing Quats to Vec4 functions and so on,
|
82
|
+
though it's a better idea to simply create a new Vec4 or Quat when you need to
|
83
|
+
pass one to another's function. The conversion is easy enough, so it's not a
|
84
|
+
huge deal.
|
85
|
+
*/
|
86
|
+
|
87
|
+
/* Defines the wrap function for a type. */
|
88
|
+
#define DEF_SM_WRAP_OP(TYPE) \
|
89
|
+
DECL_SM_WRAP_OP(TYPE) \
|
90
|
+
{ \
|
91
|
+
TYPE##_t *copy; \
|
92
|
+
if (!RTEST(klass)) { \
|
93
|
+
klass = SM_KLASS(TYPE); \
|
94
|
+
} \
|
95
|
+
VALUE sm_wrapped = Data_Make_Struct(klass, TYPE##_t, 0, free, copy); \
|
96
|
+
if (value) { \
|
97
|
+
TYPE##_copy(value, *copy); \
|
98
|
+
} \
|
99
|
+
return sm_wrapped; \
|
100
|
+
}
|
101
|
+
|
102
|
+
/* Defines the unwrap function for a type. */
|
103
|
+
#define DEF_SM_UNWRAP_OP(TYPE) \
|
104
|
+
DECL_SM_UNWRAP_OP(TYPE) \
|
105
|
+
{ \
|
106
|
+
TYPE##_t *value; \
|
107
|
+
Data_Get_Struct(sm_value, TYPE##_t, value); \
|
108
|
+
if(store) TYPE##_copy(*value, store); \
|
109
|
+
return value; \
|
110
|
+
}
|
111
|
+
|
112
|
+
/*
|
113
|
+
Defines a binary op for a given type (defined as
|
114
|
+
TYPE_FUNC(input_rhs, input_lhs, output) where input_rhs is self, input_lhs
|
115
|
+
is an arbitrary value, and output is either nil or a value of OTYPE to store
|
116
|
+
the result of the op in).
|
117
|
+
|
118
|
+
Binary ops are strict about the input/output types. You cannot pass a vec4 to
|
119
|
+
a quat function and vice versa. This is slightly contrary to other functions
|
120
|
+
that are hand-written for the type because I obviously know more about the
|
121
|
+
input than I do in the case of a macro-generated function. In the future, I'll
|
122
|
+
probably replace all generated functions with hand-written ones, but in the
|
123
|
+
meantime, just be aware that you can get exceptions for otherwise compatible
|
124
|
+
types.
|
125
|
+
|
126
|
+
By default, if no output object is provided, a new one is created and
|
127
|
+
returned. If an output object is provided, it is returned.
|
128
|
+
*/
|
129
|
+
#define DEF_SM_BINARY_OP(FUNC, TYPE, RHSTYPE, OTYPE) \
|
130
|
+
static VALUE sm_##TYPE##_##FUNC (int argc, VALUE *argv, VALUE sm_self) \
|
131
|
+
{ \
|
132
|
+
VALUE sm_rhs; \
|
133
|
+
VALUE sm_out; \
|
134
|
+
TYPE##_t *self; \
|
135
|
+
RHSTYPE##_t *rhs; \
|
136
|
+
rb_scan_args(argc, argv, "11", &sm_rhs, &sm_out); \
|
137
|
+
self = SM_UNWRAP(TYPE)(sm_self, NULL); \
|
138
|
+
SM_RAISE_IF_NOT_TYPE(sm_rhs, RHSTYPE); \
|
139
|
+
rhs = SM_UNWRAP(RHSTYPE)(sm_rhs, NULL); \
|
140
|
+
if (argc == 2) { \
|
141
|
+
if (!RTEST(sm_out)) { \
|
142
|
+
goto SM_LABEL(skip_output); \
|
143
|
+
} \
|
144
|
+
SM_RAISE_IF_NOT_TYPE(sm_out, OTYPE); \
|
145
|
+
OTYPE##_t *output = SM_UNWRAP(OTYPE)(sm_out, NULL); \
|
146
|
+
TYPE##_##FUNC (*self, *rhs, *output); \
|
147
|
+
} else if (argc == 1) { \
|
148
|
+
SM_LABEL(skip_output): { \
|
149
|
+
OTYPE##_t output; \
|
150
|
+
TYPE##_##FUNC (*self, *rhs, output); \
|
151
|
+
sm_out = SM_WRAP(OTYPE)(output, (SM_KLASS(OTYPE) == SM_KLASS(TYPE) \
|
152
|
+
? rb_obj_class(sm_self) \
|
153
|
+
: (SM_KLASS(OTYPE) == SM_KLASS(RHSTYPE) \
|
154
|
+
? rb_obj_class(sm_rhs) \
|
155
|
+
: SM_KLASS(OTYPE)))); \
|
156
|
+
rb_obj_call_init(sm_out, 0, 0); \
|
157
|
+
}} else { \
|
158
|
+
rb_raise(rb_eArgError, "Invalid number of arguments to " #FUNC); \
|
159
|
+
} \
|
160
|
+
return sm_out; \
|
161
|
+
}
|
162
|
+
|
163
|
+
/*
|
164
|
+
Defines a unary op for the given type (defined as TYPE_FUNC(input, output)
|
165
|
+
where input is self and output is either nil or an arbitrary value of type
|
166
|
+
OTYPE to store the result in).
|
167
|
+
|
168
|
+
By default, if no output object is provided, a new one is created and
|
169
|
+
returned. If an output object is provided, it is returned.
|
170
|
+
*/
|
171
|
+
#define DEF_SM_UNARY_OP(FUNC, TYPE, OTYPE) \
|
172
|
+
static VALUE sm_##TYPE##_##FUNC (int argc, VALUE *argv, VALUE sm_self) \
|
173
|
+
{ \
|
174
|
+
VALUE sm_out; \
|
175
|
+
TYPE##_t *self; \
|
176
|
+
rb_scan_args(argc, argv, "01", &sm_out); \
|
177
|
+
self = SM_UNWRAP(TYPE)(sm_self, NULL); \
|
178
|
+
if (argc == 1) { \
|
179
|
+
if (!RTEST(sm_out)) { \
|
180
|
+
goto SM_LABEL(skip_output); \
|
181
|
+
} \
|
182
|
+
SM_RAISE_IF_NOT_TYPE(sm_out, OTYPE); \
|
183
|
+
OTYPE##_t *output = SM_UNWRAP(OTYPE)(sm_out, NULL); \
|
184
|
+
TYPE##_##FUNC (*self, *output); \
|
185
|
+
} else if (argc == 0) { \
|
186
|
+
SM_LABEL(skip_output): { \
|
187
|
+
OTYPE##_t output; \
|
188
|
+
TYPE##_##FUNC (*self, output); \
|
189
|
+
sm_out = SM_WRAP(OTYPE)(output, (SM_KLASS(OTYPE) == SM_KLASS(TYPE) \
|
190
|
+
? rb_obj_class(sm_self) \
|
191
|
+
: SM_KLASS(OTYPE))); \
|
192
|
+
rb_obj_call_init(sm_out, 0, 0); \
|
193
|
+
}} else { \
|
194
|
+
rb_raise(rb_eArgError, "Invalid number of arguments to " #FUNC); \
|
195
|
+
} \
|
196
|
+
return sm_out; \
|
197
|
+
}
|
198
|
+
|
199
|
+
/* Deref/fetch op for a given type. Does bounds-checking. */
|
200
|
+
#define DEF_SM_FETCH_OP(TYPE) \
|
201
|
+
static VALUE sm_##TYPE##_fetch (VALUE sm_self, VALUE sm_index) \
|
202
|
+
{ \
|
203
|
+
static const int max_index = sizeof(TYPE##_t) / sizeof(s_float_t); \
|
204
|
+
const TYPE##_t *self = SM_UNWRAP(TYPE)(sm_self, NULL); \
|
205
|
+
int index = NUM2INT(sm_index); \
|
206
|
+
if (index < 0 || index >= max_index) { \
|
207
|
+
rb_raise(rb_eRangeError, \
|
208
|
+
"Index %d is out of bounds, must be from 0 through %d", index, max_index - 1); \
|
209
|
+
} \
|
210
|
+
return rb_float_new(self[0][NUM2INT(sm_index)]); \
|
211
|
+
}
|
212
|
+
|
213
|
+
/* Deref-assignment/store op for a given type. Does bounds-checking. */
|
214
|
+
#define DEF_SM_STORE_OP(TYPE) \
|
215
|
+
static VALUE sm_##TYPE##_store (VALUE sm_self, VALUE sm_index, VALUE sm_value) \
|
216
|
+
{ \
|
217
|
+
static const int max_index = sizeof(TYPE##_t) / sizeof(s_float_t); \
|
218
|
+
TYPE##_t *self = SM_UNWRAP(TYPE)(sm_self, NULL); \
|
219
|
+
int index = NUM2INT(sm_index); \
|
220
|
+
if (index < 0 || index >= max_index) { \
|
221
|
+
rb_raise(rb_eRangeError, \
|
222
|
+
"Index %d is out of bounds, must be from 0 through %d", index, max_index - 1); \
|
223
|
+
} \
|
224
|
+
self[0][index] = (s_float_t)rb_num2dbl(sm_value); \
|
225
|
+
return sm_value; \
|
226
|
+
}
|
227
|
+
|
228
|
+
/* Size op. Returns the size in bytes of a given type. */
|
229
|
+
#define DEF_SM_SIZE_OP(TYPE) \
|
230
|
+
static VALUE sm_##TYPE##_size (VALUE self) \
|
231
|
+
{ \
|
232
|
+
return SIZET2NUM(sizeof(TYPE##_t)); \
|
233
|
+
}
|
234
|
+
|
235
|
+
/* Length op. Returns the size in s_float_t elements of the given type. */
|
236
|
+
#define DEF_SM_LENGTH_OP(TYPE) \
|
237
|
+
static VALUE sm_##TYPE##_length (VALUE self) \
|
238
|
+
{ \
|
239
|
+
return SIZET2NUM(sizeof(TYPE##_t) / sizeof(s_float_t)); \
|
240
|
+
}
|
241
|
+
|
242
|
+
|
243
|
+
|
244
|
+
/*
|
245
|
+
Array types -- optional if BUILD_ARRAY_TYPE isn't defined.
|
246
|
+
|
247
|
+
All array types are defined as something like this in Ruby:
|
248
|
+
|
249
|
+
class TypeArray
|
250
|
+
def fetch(index) -> Type
|
251
|
+
Returns an Object of Type that references array data (non-const)
|
252
|
+
|
253
|
+
def store(index, value) -> value
|
254
|
+
Copies value object of Type's data to the array's data. This is a nop if
|
255
|
+
the value already references the array's data.
|
256
|
+
end
|
257
|
+
*/
|
258
|
+
#define BUILD_ARRAY_TYPE
|
259
|
+
#ifdef BUILD_ARRAY_TYPE
|
260
|
+
|
261
|
+
static ID kRB_IVAR_MATHARRAY_LENGTH;
|
262
|
+
static ID kRB_IVAR_MATHARRAY_SOURCE;
|
263
|
+
|
264
|
+
static VALUE sm_mathtype_array_length(VALUE sm_self)
|
265
|
+
{
|
266
|
+
return rb_ivar_get(sm_self, kRB_IVAR_MATHARRAY_LENGTH);
|
267
|
+
}
|
268
|
+
|
269
|
+
#define SM_ARR_KLASS(ELEM_TYPE) SM_KLASS(ELEM_TYPE##_array)
|
270
|
+
|
271
|
+
#define REG_SM_ARR_TYPE(ELEM_TYPE, NAME) do { \
|
272
|
+
VALUE klass_ = \
|
273
|
+
SM_ARR_KLASS(ELEM_TYPE) = rb_define_class_under(s_sm_snowmath_mod, NAME, rb_cObject); \
|
274
|
+
rb_define_singleton_method(klass_, "new", sm_##ELEM_TYPE##_array_new, 1); \
|
275
|
+
rb_define_method(klass_, "fetch", sm_##ELEM_TYPE##_array_fetch, 1); \
|
276
|
+
rb_define_method(klass_, "store", sm_##ELEM_TYPE##_array_store, 2); \
|
277
|
+
rb_define_method(klass_, "size", sm_##ELEM_TYPE##_array_size, 0); \
|
278
|
+
rb_define_method(klass_, "length", sm_mathtype_array_length, 0); \
|
279
|
+
rb_define_method(klass_, "address", sm_get_address, 0); \
|
280
|
+
} while (0)
|
281
|
+
|
282
|
+
#define DEF_SM_ARR_TYPE(ELEM_TYPE) \
|
283
|
+
static VALUE SM_ARR_KLASS(ELEM_TYPE) = Qnil; \
|
284
|
+
\
|
285
|
+
static VALUE sm_##ELEM_TYPE##_array_new(VALUE sm_self, VALUE sm_length) \
|
286
|
+
{ \
|
287
|
+
int length = 0; \
|
288
|
+
ELEM_TYPE##_t *arr; \
|
289
|
+
VALUE sm_type_array; \
|
290
|
+
int copy_array = 0; \
|
291
|
+
if ((copy_array = SM_IS_A(sm_length, ELEM_TYPE##_array))) { \
|
292
|
+
length = NUM2INT(sm_mathtype_array_length(sm_length)); \
|
293
|
+
} else { \
|
294
|
+
length = NUM2INT(sm_length); \
|
295
|
+
} \
|
296
|
+
if (length <= 0) { \
|
297
|
+
return Qnil; \
|
298
|
+
} \
|
299
|
+
arr = ALLOC_N(ELEM_TYPE##_t, length); \
|
300
|
+
if (copy_array) { \
|
301
|
+
const ELEM_TYPE##_t *source; \
|
302
|
+
Data_Get_Struct(sm_length, ELEM_TYPE##_t, source); \
|
303
|
+
MEMCPY(arr, source, ELEM_TYPE##_t, length); \
|
304
|
+
sm_length = sm_mathtype_array_length(sm_length); \
|
305
|
+
} \
|
306
|
+
sm_type_array = Data_Wrap_Struct(sm_self, 0, free, arr); \
|
307
|
+
rb_ivar_set(sm_type_array, kRB_IVAR_MATHARRAY_LENGTH, sm_length); \
|
308
|
+
rb_obj_call_init(sm_type_array, 0, 0); \
|
309
|
+
return sm_type_array; \
|
310
|
+
} \
|
311
|
+
\
|
312
|
+
static VALUE sm_##ELEM_TYPE##_array_fetch(VALUE sm_self, VALUE sm_index) \
|
313
|
+
{ \
|
314
|
+
ELEM_TYPE##_t *arr; \
|
315
|
+
int length = NUM2INT(sm_mathtype_array_length(sm_self)); \
|
316
|
+
int index = NUM2INT(sm_index); \
|
317
|
+
VALUE sm_inner; \
|
318
|
+
if (index < 0 || index >= length) { \
|
319
|
+
rb_raise(rb_eRangeError, \
|
320
|
+
"Index %d out of bounds for array with length %d", \
|
321
|
+
index, length); \
|
322
|
+
} \
|
323
|
+
Data_Get_Struct(sm_self, ELEM_TYPE##_t, arr); \
|
324
|
+
sm_inner = Data_Wrap_Struct(SM_KLASS(ELEM_TYPE), 0, 0, arr[index]); \
|
325
|
+
rb_ivar_set(sm_inner, kRB_IVAR_MATHARRAY_SOURCE, sm_self); \
|
326
|
+
return sm_inner; \
|
327
|
+
} \
|
328
|
+
\
|
329
|
+
static VALUE sm_##ELEM_TYPE##_array_store(VALUE sm_self, VALUE sm_index, VALUE sm_value) \
|
330
|
+
{ \
|
331
|
+
ELEM_TYPE##_t *arr; \
|
332
|
+
ELEM_TYPE##_t *value; \
|
333
|
+
int length = NUM2INT(sm_mathtype_array_length(sm_self)); \
|
334
|
+
int index = NUM2INT(sm_index); \
|
335
|
+
if (index < 0 || index >= length) { \
|
336
|
+
rb_raise(rb_eRangeError, \
|
337
|
+
"Index %d out of bounds for array with length %d", \
|
338
|
+
index, length); \
|
339
|
+
} else if (!SM_IS_A(sm_value, ELEM_TYPE)) { \
|
340
|
+
rb_raise(rb_eTypeError, \
|
341
|
+
"Invalid value to store: expected %s, got %s", \
|
342
|
+
rb_class2name(SM_KLASS(ELEM_TYPE)), \
|
343
|
+
rb_obj_classname(sm_value)); \
|
344
|
+
} \
|
345
|
+
Data_Get_Struct(sm_self, ELEM_TYPE##_t, arr); \
|
346
|
+
value = SM_UNWRAP(ELEM_TYPE)(sm_value, NULL); \
|
347
|
+
if ((void *)value >= (void *)arr && (void *)value < (void *)(&arr[length])) { \
|
348
|
+
return sm_value; \
|
349
|
+
} \
|
350
|
+
ELEM_TYPE##_copy(*value, arr[index]); \
|
351
|
+
return sm_value; \
|
352
|
+
} \
|
353
|
+
\
|
354
|
+
static VALUE sm_##ELEM_TYPE##_array_size(VALUE sm_self) \
|
355
|
+
{ \
|
356
|
+
int length = NUM2INT(sm_mathtype_array_length(sm_self)); \
|
357
|
+
return SIZET2NUM(length * sizeof(ELEM_TYPE##_t)); \
|
358
|
+
}
|
359
|
+
|
360
|
+
#endif
|
361
|
+
|
362
|
+
|
363
|
+
/*==============================================================================
|
364
|
+
|
365
|
+
Static Ruby class / module values
|
366
|
+
|
367
|
+
==============================================================================*/
|
368
|
+
|
369
|
+
static VALUE s_sm_snowmath_mod = Qnil;
|
370
|
+
DEF_SM_TYPE_KLASS(vec3);
|
371
|
+
DEF_SM_TYPE_KLASS(vec4);
|
372
|
+
DEF_SM_TYPE_KLASS(quat);
|
373
|
+
DEF_SM_TYPE_KLASS(mat4);
|
374
|
+
|
375
|
+
// Declare wrapping operations
|
376
|
+
DECL_SM_UNWRAP_OP(vec3);
|
377
|
+
DECL_SM_UNWRAP_OP(vec4);
|
378
|
+
DECL_SM_UNWRAP_OP(quat);
|
379
|
+
DECL_SM_UNWRAP_OP(mat4);
|
380
|
+
|
381
|
+
// Declare unwrapping operations
|
382
|
+
DECL_SM_WRAP_OP(vec3);
|
383
|
+
DECL_SM_WRAP_OP(vec4);
|
384
|
+
DECL_SM_WRAP_OP(quat);
|
385
|
+
DECL_SM_WRAP_OP(mat4);
|
386
|
+
|
387
|
+
|
388
|
+
|
389
|
+
/*==============================================================================
|
390
|
+
|
391
|
+
Array types
|
392
|
+
|
393
|
+
==============================================================================*/
|
394
|
+
|
395
|
+
#ifdef BUILD_ARRAY_TYPE
|
396
|
+
DEF_SM_ARR_TYPE(vec3);
|
397
|
+
DEF_SM_ARR_TYPE(vec4);
|
398
|
+
DEF_SM_ARR_TYPE(quat);
|
399
|
+
DEF_SM_ARR_TYPE(mat4);
|
400
|
+
#endif
|
401
|
+
|
402
|
+
|
403
|
+
|
404
|
+
/*==============================================================================
|
405
|
+
|
406
|
+
vec3_t functions
|
407
|
+
|
408
|
+
==============================================================================*/
|
409
|
+
|
410
|
+
DEF_SM_WRAP_OP(vec3);
|
411
|
+
DEF_SM_UNWRAP_OP(vec3);
|
412
|
+
DEF_SM_SIZE_OP(vec3);
|
413
|
+
DEF_SM_LENGTH_OP(vec3);
|
414
|
+
DEF_SM_FETCH_OP(vec3);
|
415
|
+
DEF_SM_STORE_OP(vec3);
|
416
|
+
DEF_SM_UNARY_OP(copy, vec3, vec3);
|
417
|
+
DEF_SM_UNARY_OP(normalize, vec3, vec3);
|
418
|
+
DEF_SM_UNARY_OP(inverse, vec3, vec3);
|
419
|
+
DEF_SM_UNARY_OP(negate, vec3, vec3);
|
420
|
+
DEF_SM_BINARY_OP(cross_product, vec3, vec3, vec3);
|
421
|
+
DEF_SM_BINARY_OP(multiply, vec3, vec3, vec3);
|
422
|
+
DEF_SM_BINARY_OP(add, vec3, vec3, vec3);
|
423
|
+
DEF_SM_BINARY_OP(subtract, vec3, vec3, vec3);
|
424
|
+
|
425
|
+
static VALUE sm_vec3_dot_product(VALUE sm_self, VALUE sm_other)
|
426
|
+
{
|
427
|
+
if (!SM_IS_A(sm_other, vec3) &&
|
428
|
+
!SM_IS_A(sm_other, vec4) &&
|
429
|
+
!SM_IS_A(sm_other, quat)) {
|
430
|
+
rb_raise(rb_eArgError,
|
431
|
+
"Expected a Quat, Vec3, or Vec4, got %s",
|
432
|
+
rb_obj_classname(sm_other));
|
433
|
+
return Qnil;
|
434
|
+
}
|
435
|
+
return rb_float_new(
|
436
|
+
vec3_dot_product(
|
437
|
+
*sm_unwrap_vec3(sm_self, NULL),
|
438
|
+
*sm_unwrap_vec3(sm_other, NULL)));
|
439
|
+
}
|
440
|
+
|
441
|
+
|
442
|
+
|
443
|
+
static VALUE sm_vec3_new(int argc, VALUE *argv, VALUE self)
|
444
|
+
{
|
445
|
+
VALUE sm_vec = sm_wrap_vec3(g_vec3_zero, self);
|
446
|
+
rb_obj_call_init(sm_vec, argc, argv);
|
447
|
+
return sm_vec;
|
448
|
+
}
|
449
|
+
|
450
|
+
|
451
|
+
|
452
|
+
static VALUE sm_vec3_init(int argc, VALUE *argv, VALUE sm_self)
|
453
|
+
{
|
454
|
+
vec3_t *self = sm_unwrap_vec3(sm_self, NULL);
|
455
|
+
size_t arr_index = 0;
|
456
|
+
|
457
|
+
switch(argc) {
|
458
|
+
|
459
|
+
// Default value
|
460
|
+
case 0: { break; }
|
461
|
+
|
462
|
+
// Copy or by-array
|
463
|
+
case 1: {
|
464
|
+
if (SM_IS_A(argv[0], vec3) ||
|
465
|
+
SM_IS_A(argv[0], vec4) ||
|
466
|
+
SM_IS_A(argv[0], quat)) {
|
467
|
+
sm_unwrap_vec3(argv[0], *self);
|
468
|
+
break;
|
469
|
+
}
|
470
|
+
|
471
|
+
// Optional offset into array provided
|
472
|
+
if (0) {
|
473
|
+
case 2:
|
474
|
+
arr_index = NUM2SIZET(argv[1]);
|
475
|
+
}
|
476
|
+
|
477
|
+
// Array of values
|
478
|
+
if (SM_RB_IS_A(argv[0], rb_cArray)) {
|
479
|
+
VALUE arrdata = argv[0];
|
480
|
+
const size_t arr_end = arr_index + 3;
|
481
|
+
s_float_t *vec_elem = *self;
|
482
|
+
for (; arr_index < arr_end; ++arr_index, ++vec_elem) {
|
483
|
+
*vec_elem = (s_float_t)rb_num2dbl(rb_ary_entry(arrdata, (long)arr_index));
|
484
|
+
}
|
485
|
+
break;
|
486
|
+
}
|
487
|
+
|
488
|
+
rb_raise(rb_eArgError, "Expected either an array of Numerics or a Vec3");
|
489
|
+
break;
|
490
|
+
}
|
491
|
+
|
492
|
+
// X, Y, Z
|
493
|
+
case 3: {
|
494
|
+
self[0][0] = (s_float_t)rb_num2dbl(argv[0]);
|
495
|
+
self[0][1] = (s_float_t)rb_num2dbl(argv[1]);
|
496
|
+
self[0][2] = (s_float_t)rb_num2dbl(argv[2]);
|
497
|
+
break;
|
498
|
+
}
|
499
|
+
|
500
|
+
default: {
|
501
|
+
rb_raise(rb_eArgError, "Invalid arguments to Vec3.initialize");
|
502
|
+
break;
|
503
|
+
}
|
504
|
+
} // switch (argc)
|
505
|
+
|
506
|
+
return sm_self;
|
507
|
+
}
|
508
|
+
|
509
|
+
|
510
|
+
|
511
|
+
static VALUE sm_vec3_to_s(VALUE self)
|
512
|
+
{
|
513
|
+
const s_float_t *v;
|
514
|
+
v = (const s_float_t *)*sm_unwrap_vec3(self, NULL);
|
515
|
+
return rb_sprintf(
|
516
|
+
"{ "
|
517
|
+
"%f, %f, %f"
|
518
|
+
" }",
|
519
|
+
v[0], v[1], v[2]);
|
520
|
+
}
|
521
|
+
|
522
|
+
|
523
|
+
|
524
|
+
static VALUE sm_vec3_magnitude_squared(VALUE sm_self)
|
525
|
+
{
|
526
|
+
return rb_float_new(vec3_length_squared(*sm_unwrap_vec3(sm_self, NULL)));
|
527
|
+
}
|
528
|
+
|
529
|
+
|
530
|
+
|
531
|
+
static VALUE sm_vec3_magnitude(VALUE sm_self)
|
532
|
+
{
|
533
|
+
return rb_float_new(vec3_length(*sm_unwrap_vec3(sm_self, NULL)));
|
534
|
+
}
|
535
|
+
|
536
|
+
|
537
|
+
|
538
|
+
static VALUE sm_vec3_scale(int argc, VALUE *argv, VALUE sm_self)
|
539
|
+
{
|
540
|
+
VALUE sm_out;
|
541
|
+
VALUE sm_scalar;
|
542
|
+
s_float_t scalar;
|
543
|
+
vec3_t *self = sm_unwrap_vec3(sm_self, NULL);
|
544
|
+
|
545
|
+
rb_scan_args(argc, argv, "11", &sm_scalar, &sm_out);
|
546
|
+
scalar = rb_num2dbl(sm_scalar);
|
547
|
+
|
548
|
+
if (SM_IS_A(sm_out, vec3)) {
|
549
|
+
vec3_scale(*self, scalar, *sm_unwrap_vec3(sm_out, NULL));
|
550
|
+
} else {
|
551
|
+
vec3_t out;
|
552
|
+
vec3_scale(*self, scalar, out);
|
553
|
+
sm_out = sm_wrap_vec3(out, rb_obj_class(sm_self));
|
554
|
+
rb_obj_call_init(sm_out, 0, 0);
|
555
|
+
}
|
556
|
+
|
557
|
+
return sm_out;
|
558
|
+
}
|
559
|
+
|
560
|
+
|
561
|
+
|
562
|
+
static VALUE sm_vec3_divide(int argc, VALUE *argv, VALUE sm_self)
|
563
|
+
{
|
564
|
+
VALUE sm_out;
|
565
|
+
VALUE sm_scalar;
|
566
|
+
s_float_t scalar;
|
567
|
+
vec3_t *self = sm_unwrap_vec3(sm_self, NULL);
|
568
|
+
|
569
|
+
rb_scan_args(argc, argv, "11", &sm_scalar, &sm_out);
|
570
|
+
scalar = rb_num2dbl(sm_scalar);
|
571
|
+
|
572
|
+
if (SM_IS_A(sm_out, vec3)) {
|
573
|
+
vec3_divide(*self, scalar, *sm_unwrap_vec3(sm_out, NULL));
|
574
|
+
} else {
|
575
|
+
vec3_t out;
|
576
|
+
vec3_divide(*self, scalar, out);
|
577
|
+
sm_out = sm_wrap_vec3(out, rb_obj_class(sm_self));
|
578
|
+
rb_obj_call_init(sm_out, 0, 0);
|
579
|
+
}
|
580
|
+
|
581
|
+
return sm_out;
|
582
|
+
}
|
583
|
+
|
584
|
+
|
585
|
+
|
586
|
+
static VALUE sm_vec3_equals(VALUE sm_self, VALUE sm_other)
|
587
|
+
{
|
588
|
+
if (!RTEST(sm_other)) {
|
589
|
+
return Qfalse;
|
590
|
+
} else if (!SM_IS_A(sm_other, vec3) && !SM_IS_A(sm_other, vec4) && !SM_IS_A(sm_other, quat)) {
|
591
|
+
rb_raise(rb_eTypeError,
|
592
|
+
"Expected Vec3, Vec4, or Quat, got %s",
|
593
|
+
rb_obj_classname(sm_other));
|
594
|
+
}
|
595
|
+
|
596
|
+
return vec3_equals(*sm_unwrap_vec3(sm_self, NULL), *sm_unwrap_vec3(sm_other, NULL)) ? Qtrue : Qfalse;
|
597
|
+
}
|
598
|
+
|
599
|
+
|
600
|
+
|
601
|
+
/*==============================================================================
|
602
|
+
|
603
|
+
vec4_t functions
|
604
|
+
|
605
|
+
==============================================================================*/
|
606
|
+
|
607
|
+
DEF_SM_WRAP_OP(vec4);
|
608
|
+
DEF_SM_UNWRAP_OP(vec4);
|
609
|
+
DEF_SM_SIZE_OP(vec4);
|
610
|
+
DEF_SM_LENGTH_OP(vec4);
|
611
|
+
DEF_SM_FETCH_OP(vec4);
|
612
|
+
DEF_SM_STORE_OP(vec4);
|
613
|
+
DEF_SM_UNARY_OP(copy, vec4, vec4);
|
614
|
+
DEF_SM_UNARY_OP(normalize, vec4, vec4);
|
615
|
+
DEF_SM_UNARY_OP(inverse, vec4, vec4);
|
616
|
+
DEF_SM_UNARY_OP(negate, vec4, vec4);
|
617
|
+
DEF_SM_BINARY_OP(multiply, vec4, vec4, vec4);
|
618
|
+
DEF_SM_BINARY_OP(add, vec4, vec4, vec4);
|
619
|
+
DEF_SM_BINARY_OP(subtract, vec4, vec4, vec4);
|
620
|
+
|
621
|
+
static VALUE sm_vec4_dot_product(VALUE sm_self, VALUE sm_other)
|
622
|
+
{
|
623
|
+
if (!SM_IS_A(sm_other, vec4) &&
|
624
|
+
!SM_IS_A(sm_other, quat)) {
|
625
|
+
rb_raise(rb_eArgError,
|
626
|
+
"Expected a Quat or Vec4, got %s",
|
627
|
+
rb_obj_classname(sm_other));
|
628
|
+
return Qnil;
|
629
|
+
}
|
630
|
+
return rb_float_new(
|
631
|
+
vec4_dot_product(
|
632
|
+
*sm_unwrap_vec4(sm_self, NULL),
|
633
|
+
*sm_unwrap_vec4(sm_other, NULL)));
|
634
|
+
}
|
635
|
+
|
636
|
+
|
637
|
+
|
638
|
+
static VALUE sm_vec4_new(int argc, VALUE *argv, VALUE self)
|
639
|
+
{
|
640
|
+
VALUE sm_vec = sm_wrap_vec4(g_vec4_identity, self);
|
641
|
+
rb_obj_call_init(sm_vec, argc, argv);
|
642
|
+
return sm_vec;
|
643
|
+
}
|
644
|
+
|
645
|
+
|
646
|
+
|
647
|
+
static VALUE sm_vec4_init(int argc, VALUE *argv, VALUE sm_self)
|
648
|
+
{
|
649
|
+
vec4_t *self = sm_unwrap_vec4(sm_self, NULL);
|
650
|
+
size_t arr_index = 0;
|
651
|
+
|
652
|
+
switch(argc) {
|
653
|
+
|
654
|
+
// Default value
|
655
|
+
case 0: { break; }
|
656
|
+
|
657
|
+
// Copy or by-array
|
658
|
+
case 1: {
|
659
|
+
if (SM_IS_A(argv[0], quat) ||
|
660
|
+
SM_IS_A(argv[0], vec4)) {
|
661
|
+
sm_unwrap_quat(argv[0], *self);
|
662
|
+
break;
|
663
|
+
}
|
664
|
+
|
665
|
+
if (SM_IS_A(argv[0], vec3)) {
|
666
|
+
sm_unwrap_vec3(argv[0], *self);
|
667
|
+
break;
|
668
|
+
}
|
669
|
+
|
670
|
+
// Optional offset into array provided
|
671
|
+
if (0) {
|
672
|
+
case 2:
|
673
|
+
arr_index = NUM2SIZET(argv[1]);
|
674
|
+
}
|
675
|
+
|
676
|
+
// Array of values
|
677
|
+
if (SM_RB_IS_A(argv[0], rb_cArray)) {
|
678
|
+
VALUE arrdata = argv[0];
|
679
|
+
const size_t arr_end = arr_index + 4;
|
680
|
+
s_float_t *vec_elem = *self;
|
681
|
+
for (; arr_index < arr_end; ++arr_index, ++vec_elem) {
|
682
|
+
*vec_elem = (s_float_t)rb_num2dbl(rb_ary_entry(arrdata, (long)arr_index));
|
683
|
+
}
|
684
|
+
break;
|
685
|
+
}
|
686
|
+
|
687
|
+
rb_raise(rb_eArgError, "Expected either an array of Numerics or a Vec4");
|
688
|
+
break;
|
689
|
+
}
|
690
|
+
|
691
|
+
// W
|
692
|
+
case 4: {
|
693
|
+
self[0][3] = (s_float_t)rb_num2dbl(argv[3]);
|
694
|
+
case 3: // X, Y, Z
|
695
|
+
self[0][0] = (s_float_t)rb_num2dbl(argv[0]);
|
696
|
+
self[0][1] = (s_float_t)rb_num2dbl(argv[1]);
|
697
|
+
self[0][2] = (s_float_t)rb_num2dbl(argv[2]);
|
698
|
+
break;
|
699
|
+
}
|
700
|
+
|
701
|
+
default: {
|
702
|
+
rb_raise(rb_eArgError, "Invalid arguments to Vec4.initialize");
|
703
|
+
break;
|
704
|
+
}
|
705
|
+
} // switch (argc)
|
706
|
+
|
707
|
+
return sm_self;
|
708
|
+
}
|
709
|
+
|
710
|
+
|
711
|
+
|
712
|
+
static VALUE sm_vec4_to_s(VALUE self)
|
713
|
+
{
|
714
|
+
const s_float_t *v;
|
715
|
+
v = (const s_float_t *)*sm_unwrap_vec4(self, NULL);
|
716
|
+
return rb_sprintf(
|
717
|
+
"{ "
|
718
|
+
"%f, %f, %f, %f"
|
719
|
+
" }",
|
720
|
+
v[0], v[1], v[2], v[3]);
|
721
|
+
}
|
722
|
+
|
723
|
+
|
724
|
+
|
725
|
+
static VALUE sm_vec4_magnitude_squared(VALUE sm_self)
|
726
|
+
{
|
727
|
+
return rb_float_new(vec4_length_squared(*sm_unwrap_vec4(sm_self, NULL)));
|
728
|
+
}
|
729
|
+
|
730
|
+
|
731
|
+
|
732
|
+
static VALUE sm_vec4_magnitude(VALUE sm_self)
|
733
|
+
{
|
734
|
+
return rb_float_new(vec4_length(*sm_unwrap_vec4(sm_self, NULL)));
|
735
|
+
}
|
736
|
+
|
737
|
+
|
738
|
+
|
739
|
+
static VALUE sm_vec4_scale(int argc, VALUE *argv, VALUE sm_self)
|
740
|
+
{
|
741
|
+
VALUE sm_out;
|
742
|
+
VALUE sm_scalar;
|
743
|
+
s_float_t scalar;
|
744
|
+
vec4_t *self = sm_unwrap_vec4(sm_self, NULL);
|
745
|
+
|
746
|
+
rb_scan_args(argc, argv, "11", &sm_scalar, &sm_out);
|
747
|
+
scalar = rb_num2dbl(sm_scalar);
|
748
|
+
|
749
|
+
if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
|
750
|
+
vec4_scale(*self, scalar, *sm_unwrap_vec4(sm_out, NULL));
|
751
|
+
} else {
|
752
|
+
vec4_t out;
|
753
|
+
vec4_scale(*self, scalar, out);
|
754
|
+
sm_out = sm_wrap_vec4(out, rb_obj_class(sm_self));
|
755
|
+
rb_obj_call_init(sm_out, 0, 0);
|
756
|
+
}
|
757
|
+
|
758
|
+
return sm_out;
|
759
|
+
}
|
760
|
+
|
761
|
+
|
762
|
+
|
763
|
+
static VALUE sm_vec4_divide(int argc, VALUE *argv, VALUE sm_self)
|
764
|
+
{
|
765
|
+
VALUE sm_out;
|
766
|
+
VALUE sm_scalar;
|
767
|
+
s_float_t scalar;
|
768
|
+
vec4_t *self = sm_unwrap_vec4(sm_self, NULL);
|
769
|
+
|
770
|
+
rb_scan_args(argc, argv, "11", &sm_scalar, &sm_out);
|
771
|
+
scalar = rb_num2dbl(sm_scalar);
|
772
|
+
|
773
|
+
if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
|
774
|
+
vec4_divide(*self, scalar, *sm_unwrap_vec4(sm_out, NULL));
|
775
|
+
} else {
|
776
|
+
vec4_t out;
|
777
|
+
vec4_divide(*self, scalar, out);
|
778
|
+
sm_out = sm_wrap_vec4(out, rb_obj_class(sm_self));
|
779
|
+
rb_obj_call_init(sm_out, 0, 0);
|
780
|
+
}
|
781
|
+
|
782
|
+
return sm_out;
|
783
|
+
}
|
784
|
+
|
785
|
+
|
786
|
+
|
787
|
+
static VALUE sm_vec4_equals(VALUE sm_self, VALUE sm_other)
|
788
|
+
{
|
789
|
+
if (!RTEST(sm_other)) {
|
790
|
+
return Qfalse;
|
791
|
+
} else if (!SM_IS_A(sm_other, vec4) && !SM_IS_A(sm_other, quat)) {
|
792
|
+
rb_raise(rb_eTypeError,
|
793
|
+
"Expected Vec4 or Quat, got %s",
|
794
|
+
rb_obj_classname(sm_other));
|
795
|
+
}
|
796
|
+
|
797
|
+
return vec4_equals(*sm_unwrap_vec4(sm_self, NULL), *sm_unwrap_vec4(sm_other, NULL)) ? Qtrue : Qfalse;
|
798
|
+
}
|
799
|
+
|
800
|
+
|
801
|
+
|
802
|
+
/*==============================================================================
|
803
|
+
|
804
|
+
quat_t functions
|
805
|
+
|
806
|
+
==============================================================================*/
|
807
|
+
|
808
|
+
DEF_SM_WRAP_OP(quat);
|
809
|
+
DEF_SM_UNWRAP_OP(quat);
|
810
|
+
DEF_SM_SIZE_OP(quat);
|
811
|
+
DEF_SM_LENGTH_OP(quat);
|
812
|
+
DEF_SM_FETCH_OP(quat);
|
813
|
+
DEF_SM_STORE_OP(quat);
|
814
|
+
DEF_SM_UNARY_OP(copy, quat, quat);
|
815
|
+
DEF_SM_UNARY_OP(inverse, quat, quat);
|
816
|
+
DEF_SM_UNARY_OP(negate, quat, quat);
|
817
|
+
DEF_SM_BINARY_OP(multiply, quat, quat, quat);
|
818
|
+
DEF_SM_BINARY_OP(multiply_vec3, quat, vec3, vec3);
|
819
|
+
|
820
|
+
static VALUE sm_quat_new(int argc, VALUE *argv, VALUE self)
|
821
|
+
{
|
822
|
+
VALUE sm_quat = sm_wrap_quat(g_quat_identity, self);
|
823
|
+
rb_obj_call_init(sm_quat, argc, argv);
|
824
|
+
return sm_quat;
|
825
|
+
}
|
826
|
+
|
827
|
+
|
828
|
+
|
829
|
+
static VALUE sm_quat_init(int argc, VALUE *argv, VALUE sm_self)
|
830
|
+
{
|
831
|
+
quat_t *self = sm_unwrap_quat(sm_self, NULL);
|
832
|
+
size_t arr_index = 0;
|
833
|
+
|
834
|
+
switch(argc) {
|
835
|
+
|
836
|
+
// Default value
|
837
|
+
case 0: { break; }
|
838
|
+
|
839
|
+
// Copy or by-array
|
840
|
+
case 1: {
|
841
|
+
if (SM_IS_A(argv[0], vec3)) {
|
842
|
+
sm_unwrap_vec3(argv[0], *self);
|
843
|
+
break;
|
844
|
+
}
|
845
|
+
|
846
|
+
if (SM_IS_A(argv[0], quat) ||
|
847
|
+
SM_IS_A(argv[0], vec4)) {
|
848
|
+
sm_unwrap_quat(argv[0], *self);
|
849
|
+
break;
|
850
|
+
}
|
851
|
+
|
852
|
+
if (SM_IS_A(argv[0], mat4)) {
|
853
|
+
const mat4_t *mat = sm_unwrap_mat4(argv[0], NULL);
|
854
|
+
quat_from_mat4(*mat, *self);
|
855
|
+
break;
|
856
|
+
}
|
857
|
+
|
858
|
+
// Optional offset into array provided
|
859
|
+
if (0) {
|
860
|
+
case 2:
|
861
|
+
arr_index = NUM2SIZET(argv[1]);
|
862
|
+
}
|
863
|
+
|
864
|
+
// Array of values
|
865
|
+
if (SM_RB_IS_A(argv[0], rb_cArray)) {
|
866
|
+
VALUE arrdata = argv[0];
|
867
|
+
const size_t arr_end = arr_index + 3;
|
868
|
+
s_float_t *vec_elem = *self;
|
869
|
+
for (; arr_index < arr_end; ++arr_index, ++vec_elem) {
|
870
|
+
*vec_elem = (s_float_t)rb_num2dbl(rb_ary_entry(arrdata, (long)arr_index));
|
871
|
+
}
|
872
|
+
break;
|
873
|
+
}
|
874
|
+
|
875
|
+
rb_raise(rb_eArgError, "Expected either an array of Numerics or a Quat");
|
876
|
+
break;
|
877
|
+
}
|
878
|
+
|
879
|
+
// W
|
880
|
+
case 4: {
|
881
|
+
self[0][3] = (s_float_t)rb_num2dbl(argv[3]);
|
882
|
+
case 3: // X, Y, Z
|
883
|
+
self[0][0] = (s_float_t)rb_num2dbl(argv[0]);
|
884
|
+
self[0][1] = (s_float_t)rb_num2dbl(argv[1]);
|
885
|
+
self[0][2] = (s_float_t)rb_num2dbl(argv[2]);
|
886
|
+
break;
|
887
|
+
}
|
888
|
+
|
889
|
+
default: {
|
890
|
+
rb_raise(rb_eArgError, "Invalid arguments to Quat.initialize");
|
891
|
+
break;
|
892
|
+
}
|
893
|
+
} // switch (argc)
|
894
|
+
|
895
|
+
return sm_self;
|
896
|
+
}
|
897
|
+
|
898
|
+
|
899
|
+
|
900
|
+
static VALUE sm_quat_to_s(VALUE self)
|
901
|
+
{
|
902
|
+
const s_float_t *v;
|
903
|
+
v = (const s_float_t *)*sm_unwrap_quat(self, NULL);
|
904
|
+
return rb_sprintf(
|
905
|
+
"{ "
|
906
|
+
"%f, %f, %f, %f"
|
907
|
+
" }",
|
908
|
+
v[0], v[1], v[2], v[3]);
|
909
|
+
}
|
910
|
+
|
911
|
+
|
912
|
+
|
913
|
+
|
914
|
+
|
915
|
+
|
916
|
+
|
917
|
+
static VALUE sm_quat_angle_axis(int argc, VALUE *argv, VALUE self)
|
918
|
+
{
|
919
|
+
VALUE sm_angle;
|
920
|
+
VALUE sm_axis;
|
921
|
+
VALUE sm_out;
|
922
|
+
s_float_t angle;
|
923
|
+
const vec3_t *axis;
|
924
|
+
|
925
|
+
rb_scan_args(argc, argv, "21", &sm_angle, &sm_axis, &sm_out);
|
926
|
+
SM_RAISE_IF_NOT_TYPE(sm_axis, vec3);
|
927
|
+
|
928
|
+
angle = (s_float_t)rb_num2dbl(sm_angle);
|
929
|
+
axis = sm_unwrap_vec3(sm_axis, NULL);
|
930
|
+
|
931
|
+
if (SM_IS_A(sm_out, quat) || SM_IS_A(sm_out, vec4)) {
|
932
|
+
quat_t *out = sm_unwrap_quat(sm_out, NULL);
|
933
|
+
quat_from_angle_axis(angle, (*axis)[0], (*axis)[1], (*axis)[2], *out);
|
934
|
+
} else {
|
935
|
+
quat_t out;
|
936
|
+
quat_from_angle_axis(angle, (*axis)[0], (*axis)[1], (*axis)[2], out);
|
937
|
+
sm_out = sm_wrap_quat(out, self);
|
938
|
+
rb_obj_call_init(sm_out, 0, 0);
|
939
|
+
}
|
940
|
+
|
941
|
+
return sm_out;
|
942
|
+
}
|
943
|
+
|
944
|
+
|
945
|
+
|
946
|
+
static VALUE sm_quat_identity(VALUE sm_self)
|
947
|
+
{
|
948
|
+
quat_t *self = sm_unwrap_quat(sm_self, NULL);
|
949
|
+
quat_identity(*self);
|
950
|
+
return sm_self;
|
951
|
+
}
|
952
|
+
|
953
|
+
|
954
|
+
|
955
|
+
static VALUE sm_quat_scale(int argc, VALUE *argv, VALUE sm_self)
|
956
|
+
{
|
957
|
+
VALUE sm_out;
|
958
|
+
VALUE sm_scalar;
|
959
|
+
s_float_t scalar;
|
960
|
+
vec4_t *self = sm_unwrap_vec4(sm_self, NULL);
|
961
|
+
|
962
|
+
rb_scan_args(argc, argv, "11", &sm_scalar, &sm_out);
|
963
|
+
scalar = rb_num2dbl(sm_scalar);
|
964
|
+
|
965
|
+
if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
|
966
|
+
vec4_scale(*self, scalar, *sm_unwrap_vec4(sm_out, NULL));
|
967
|
+
} else {
|
968
|
+
vec4_t out;
|
969
|
+
vec4_scale(*self, scalar, out);
|
970
|
+
sm_out = sm_wrap_quat(out, rb_obj_class(sm_self));
|
971
|
+
rb_obj_call_init(sm_out, 0, 0);
|
972
|
+
}
|
973
|
+
|
974
|
+
return sm_out;
|
975
|
+
}
|
976
|
+
|
977
|
+
|
978
|
+
|
979
|
+
static VALUE sm_quat_divide(int argc, VALUE *argv, VALUE sm_self)
|
980
|
+
{
|
981
|
+
VALUE sm_out;
|
982
|
+
VALUE sm_scalar;
|
983
|
+
s_float_t scalar;
|
984
|
+
vec4_t *self = sm_unwrap_vec4(sm_self, NULL);
|
985
|
+
|
986
|
+
rb_scan_args(argc, argv, "11", &sm_scalar, &sm_out);
|
987
|
+
scalar = rb_num2dbl(sm_scalar);
|
988
|
+
|
989
|
+
if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
|
990
|
+
vec4_divide(*self, scalar, *sm_unwrap_vec4(sm_out, NULL));
|
991
|
+
} else {
|
992
|
+
vec4_t out;
|
993
|
+
vec4_divide(*self, scalar, out);
|
994
|
+
sm_out = sm_wrap_quat(out, rb_obj_class(sm_self));
|
995
|
+
rb_obj_call_init(sm_out, 0, 0);
|
996
|
+
}
|
997
|
+
|
998
|
+
return sm_out;
|
999
|
+
}
|
1000
|
+
|
1001
|
+
|
1002
|
+
|
1003
|
+
static VALUE sm_quat_slerp(int argc, VALUE *argv, VALUE sm_self)
|
1004
|
+
{
|
1005
|
+
VALUE sm_out;
|
1006
|
+
VALUE sm_destination;
|
1007
|
+
VALUE sm_alpha;
|
1008
|
+
quat_t *destination;
|
1009
|
+
quat_t *self = sm_unwrap_vec4(sm_self, NULL);
|
1010
|
+
s_float_t alpha;
|
1011
|
+
|
1012
|
+
rb_scan_args(argc, argv, "21", &sm_destination, &sm_alpha, &sm_out);
|
1013
|
+
alpha = rb_num2dbl(sm_alpha);
|
1014
|
+
|
1015
|
+
if (!SM_IS_A(sm_destination, vec4) && !SM_IS_A(sm_destination, quat)) {
|
1016
|
+
rb_raise(rb_eTypeError,
|
1017
|
+
"Expected either Vec4 or Quat, got %s",
|
1018
|
+
rb_obj_classname(sm_destination));
|
1019
|
+
return Qnil;
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
destination = sm_unwrap_quat(sm_destination, NULL);
|
1023
|
+
|
1024
|
+
if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
|
1025
|
+
quat_slerp(*self, *destination, alpha, *sm_unwrap_quat(sm_out, NULL));
|
1026
|
+
} else {
|
1027
|
+
quat_t out;
|
1028
|
+
quat_slerp(*self, *destination, alpha, out);
|
1029
|
+
sm_out = sm_wrap_quat(out, rb_obj_class(sm_self));
|
1030
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
return sm_out;
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
|
1037
|
+
|
1038
|
+
static VALUE sm_quat_normalize(int argc, VALUE *argv, VALUE sm_self)
|
1039
|
+
{
|
1040
|
+
VALUE sm_out;
|
1041
|
+
VALUE sm_scalar;
|
1042
|
+
s_float_t scalar;
|
1043
|
+
vec4_t *self = sm_unwrap_vec4(sm_self, NULL);
|
1044
|
+
|
1045
|
+
rb_scan_args(argc, argv, "01", &sm_scalar, &sm_out);
|
1046
|
+
scalar = rb_num2dbl(sm_scalar);
|
1047
|
+
|
1048
|
+
if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
|
1049
|
+
vec4_normalize(*self, *sm_unwrap_vec4(sm_out, NULL));
|
1050
|
+
} else {
|
1051
|
+
vec4_t out;
|
1052
|
+
vec4_normalize(*self, out);
|
1053
|
+
sm_out = sm_wrap_quat(out, rb_obj_class(sm_self));
|
1054
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1055
|
+
}
|
1056
|
+
|
1057
|
+
return sm_out;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
|
1061
|
+
|
1062
|
+
static VALUE sm_quat_add(int argc, VALUE *argv, VALUE sm_self)
|
1063
|
+
{
|
1064
|
+
VALUE sm_out;
|
1065
|
+
VALUE sm_left;
|
1066
|
+
vec4_t *self = sm_unwrap_vec4(sm_self, NULL);
|
1067
|
+
|
1068
|
+
rb_scan_args(argc, argv, "11", &sm_left, &sm_out);
|
1069
|
+
|
1070
|
+
if (!SM_IS_A(sm_left, vec4) && !SM_IS_A(sm_left, quat)) {
|
1071
|
+
rb_raise(rb_eTypeError,
|
1072
|
+
"Expected either Vec4 or Quat, got %s",
|
1073
|
+
rb_obj_classname(sm_left));
|
1074
|
+
return Qnil;
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
|
1078
|
+
vec4_add(*self, *sm_unwrap_vec4(sm_left, NULL), *sm_unwrap_vec4(sm_out, NULL));
|
1079
|
+
} else {
|
1080
|
+
vec4_t out;
|
1081
|
+
vec4_add(*self, *sm_unwrap_vec4(sm_left, NULL), out);
|
1082
|
+
sm_out = sm_wrap_quat(out, rb_obj_class(sm_self));
|
1083
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
return sm_out;
|
1087
|
+
}
|
1088
|
+
|
1089
|
+
|
1090
|
+
|
1091
|
+
static VALUE sm_quat_subtract(int argc, VALUE *argv, VALUE sm_self)
|
1092
|
+
{
|
1093
|
+
VALUE sm_out;
|
1094
|
+
VALUE sm_left;
|
1095
|
+
vec4_t *self = sm_unwrap_vec4(sm_self, NULL);
|
1096
|
+
|
1097
|
+
rb_scan_args(argc, argv, "11", &sm_left, &sm_out);
|
1098
|
+
|
1099
|
+
if (!SM_IS_A(sm_left, vec4) && !SM_IS_A(sm_left, quat)) {
|
1100
|
+
rb_raise(rb_eTypeError,
|
1101
|
+
"Expected either Vec4 or Quat, got %s",
|
1102
|
+
rb_obj_classname(sm_left));
|
1103
|
+
return Qnil;
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
if ((SM_IS_A(sm_out, vec4) || SM_IS_A(sm_out, quat))) {
|
1107
|
+
vec4_subtract(*self, *sm_unwrap_vec4(sm_left, NULL), *sm_unwrap_vec4(sm_out, NULL));
|
1108
|
+
} else {
|
1109
|
+
vec4_t out;
|
1110
|
+
vec4_subtract(*self, *sm_unwrap_vec4(sm_left, NULL), out);
|
1111
|
+
sm_out = sm_wrap_quat(out, rb_obj_class(sm_self));
|
1112
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1113
|
+
}
|
1114
|
+
|
1115
|
+
return sm_out;
|
1116
|
+
}
|
1117
|
+
|
1118
|
+
|
1119
|
+
|
1120
|
+
/*==============================================================================
|
1121
|
+
|
1122
|
+
mat4_t functions
|
1123
|
+
|
1124
|
+
==============================================================================*/
|
1125
|
+
|
1126
|
+
DEF_SM_WRAP_OP(mat4);
|
1127
|
+
DEF_SM_UNWRAP_OP(mat4);
|
1128
|
+
DEF_SM_SIZE_OP(mat4);
|
1129
|
+
DEF_SM_LENGTH_OP(mat4);
|
1130
|
+
DEF_SM_FETCH_OP(mat4);
|
1131
|
+
DEF_SM_STORE_OP(mat4);
|
1132
|
+
DEF_SM_UNARY_OP(copy, mat4, mat4);
|
1133
|
+
DEF_SM_UNARY_OP(transpose, mat4, mat4);
|
1134
|
+
DEF_SM_UNARY_OP(inverse_orthogonal, mat4, mat4);
|
1135
|
+
DEF_SM_UNARY_OP(adjoint, mat4, mat4);
|
1136
|
+
DEF_SM_BINARY_OP(multiply, mat4, mat4, mat4);
|
1137
|
+
DEF_SM_BINARY_OP(multiply_vec4, mat4, vec4, vec4);
|
1138
|
+
DEF_SM_BINARY_OP(transform_vec3, mat4, vec3, vec3);
|
1139
|
+
DEF_SM_BINARY_OP(rotate_vec3, mat4, vec3, vec3);
|
1140
|
+
DEF_SM_BINARY_OP(inv_rotate_vec3, mat4, vec3, vec3);
|
1141
|
+
|
1142
|
+
static VALUE sm_mat4_inverse_affine(int argc, VALUE *argv, VALUE sm_self)
|
1143
|
+
{
|
1144
|
+
VALUE sm_out = Qnil;
|
1145
|
+
mat4_t *self;
|
1146
|
+
|
1147
|
+
rb_scan_args(argc, argv, "01", &sm_out);
|
1148
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1149
|
+
|
1150
|
+
if (argc == 1) {
|
1151
|
+
mat4_t *output;
|
1152
|
+
|
1153
|
+
if (!RTEST(sm_out)) {
|
1154
|
+
goto SM_LABEL(output_lbl);
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
if (!SM_IS_A(sm_out, mat4)) {
|
1158
|
+
rb_raise(rb_eTypeError,
|
1159
|
+
"Invalid argument to output of inverse_affine: expected %s, got %s",
|
1160
|
+
rb_class2name(SM_KLASS(mat4)),
|
1161
|
+
rb_obj_classname(sm_out));
|
1162
|
+
return Qnil;
|
1163
|
+
}
|
1164
|
+
|
1165
|
+
output = sm_unwrap_mat4(sm_out, NULL);
|
1166
|
+
if (!mat4_inverse_affine(*self, *output)) {
|
1167
|
+
return Qnil;
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
} else if (argc == 0) {
|
1171
|
+
SM_LABEL(output_lbl): {
|
1172
|
+
mat4_t output;
|
1173
|
+
if (!mat4_inverse_affine(*self, output)) {
|
1174
|
+
return Qnil;
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
sm_out = sm_wrap_mat4(output, rb_obj_class(sm_self));
|
1178
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1179
|
+
}
|
1180
|
+
} else {
|
1181
|
+
rb_raise(rb_eArgError, "Invalid number of arguments to inverse_affine");
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
return sm_out;
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
|
1188
|
+
|
1189
|
+
static VALUE sm_mat4_inverse_general(int argc, VALUE *argv, VALUE sm_self)
|
1190
|
+
{
|
1191
|
+
VALUE sm_out = Qnil;
|
1192
|
+
mat4_t *self;
|
1193
|
+
|
1194
|
+
rb_scan_args(argc, argv, "01", &sm_out);
|
1195
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1196
|
+
|
1197
|
+
if (argc == 1) {
|
1198
|
+
mat4_t *output;
|
1199
|
+
|
1200
|
+
if (!RTEST(sm_out)) {
|
1201
|
+
goto SM_LABEL(skip_output);
|
1202
|
+
}
|
1203
|
+
|
1204
|
+
if (!SM_IS_A(sm_out, mat4)) {
|
1205
|
+
rb_raise(rb_eTypeError,
|
1206
|
+
"Invalid argument to output of inverse_general: expected %s, got %s",
|
1207
|
+
rb_class2name(SM_KLASS(mat4)),
|
1208
|
+
rb_obj_classname(sm_out));
|
1209
|
+
return Qnil;
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
output = sm_unwrap_mat4(sm_out, NULL);
|
1213
|
+
if (!mat4_inverse_general(*self, *output)) {
|
1214
|
+
return Qnil;
|
1215
|
+
}
|
1216
|
+
|
1217
|
+
} else if (argc == 0) {
|
1218
|
+
SM_LABEL(skip_output): {
|
1219
|
+
mat4_t output;
|
1220
|
+
if (!mat4_inverse_general(*self, output)) {
|
1221
|
+
return Qnil;
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
sm_out = sm_wrap_mat4(output, rb_obj_class(sm_self));
|
1225
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1226
|
+
}
|
1227
|
+
} else {
|
1228
|
+
rb_raise(rb_eArgError, "Invalid number of arguments to inverse_general");
|
1229
|
+
}
|
1230
|
+
|
1231
|
+
return sm_out;
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
|
1235
|
+
|
1236
|
+
static VALUE sm_mat4_determinant(VALUE sm_self)
|
1237
|
+
{
|
1238
|
+
return mat4_determinant(*sm_unwrap_mat4(sm_self, NULL));
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
|
1242
|
+
|
1243
|
+
static VALUE sm_mat4_translate(int argc, VALUE *argv, VALUE sm_self)
|
1244
|
+
{
|
1245
|
+
VALUE sm_out = Qnil;
|
1246
|
+
mat4_t *self = sm_unwrap_mat4(sm_self, NULL);
|
1247
|
+
vec3_t xyz;
|
1248
|
+
|
1249
|
+
SM_LABEL(argc_reconfig):
|
1250
|
+
switch (argc) {
|
1251
|
+
case 2: case 4: {
|
1252
|
+
sm_out = argv[--argc];
|
1253
|
+
if (RTEST(sm_out)) {
|
1254
|
+
SM_RAISE_IF_NOT_TYPE(sm_out, mat4);
|
1255
|
+
}
|
1256
|
+
goto SM_LABEL(argc_reconfig);
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
case 1: {
|
1260
|
+
sm_unwrap_vec3(argv[0], xyz);
|
1261
|
+
goto SM_LABEL(get_output);
|
1262
|
+
}
|
1263
|
+
|
1264
|
+
case 3: {
|
1265
|
+
xyz[0] = rb_num2dbl(argv[0]);
|
1266
|
+
xyz[1] = rb_num2dbl(argv[1]);
|
1267
|
+
xyz[2] = rb_num2dbl(argv[2]);
|
1268
|
+
|
1269
|
+
SM_LABEL(get_output):
|
1270
|
+
if (RTEST(sm_out)) {
|
1271
|
+
mat4_t *out = sm_unwrap_mat4(sm_out, NULL);
|
1272
|
+
mat4_translate(xyz[0], xyz[1], xyz[2], *self, *out);
|
1273
|
+
} else {
|
1274
|
+
mat4_t out;
|
1275
|
+
mat4_translate(xyz[0], xyz[1], xyz[2], *self, out);
|
1276
|
+
sm_out = sm_wrap_mat4(out, rb_obj_class(sm_self));
|
1277
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1278
|
+
}
|
1279
|
+
}
|
1280
|
+
}
|
1281
|
+
|
1282
|
+
return sm_out;
|
1283
|
+
}
|
1284
|
+
|
1285
|
+
|
1286
|
+
|
1287
|
+
static VALUE sm_mat4_translation(int argc, VALUE *argv, VALUE sm_self)
|
1288
|
+
{
|
1289
|
+
VALUE sm_out = Qnil;
|
1290
|
+
vec3_t xyz;
|
1291
|
+
|
1292
|
+
SM_LABEL(argc_reconfig):
|
1293
|
+
switch (argc) {
|
1294
|
+
case 2: case 4: {
|
1295
|
+
sm_out = argv[--argc];
|
1296
|
+
if (RTEST(sm_out)) {
|
1297
|
+
SM_RAISE_IF_NOT_TYPE(sm_out, mat4);
|
1298
|
+
}
|
1299
|
+
goto SM_LABEL(argc_reconfig);
|
1300
|
+
}
|
1301
|
+
|
1302
|
+
case 1: {
|
1303
|
+
sm_unwrap_vec3(argv[0], xyz);
|
1304
|
+
goto SM_LABEL(get_output);
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
case 3: {
|
1308
|
+
xyz[0] = rb_num2dbl(argv[0]);
|
1309
|
+
xyz[1] = rb_num2dbl(argv[1]);
|
1310
|
+
xyz[2] = rb_num2dbl(argv[2]);
|
1311
|
+
|
1312
|
+
SM_LABEL(get_output):
|
1313
|
+
if (RTEST(sm_out)) {
|
1314
|
+
mat4_t *out = sm_unwrap_mat4(sm_out, NULL);
|
1315
|
+
mat4_translation(xyz[0], xyz[1], xyz[2], *out);
|
1316
|
+
} else {
|
1317
|
+
mat4_t out;
|
1318
|
+
mat4_translation(xyz[0], xyz[1], xyz[2], out);
|
1319
|
+
sm_out = sm_wrap_mat4(out, sm_self);
|
1320
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1321
|
+
}
|
1322
|
+
}
|
1323
|
+
}
|
1324
|
+
|
1325
|
+
return sm_out;
|
1326
|
+
}
|
1327
|
+
|
1328
|
+
|
1329
|
+
|
1330
|
+
static VALUE sm_mat4_new(int argc, VALUE *argv, VALUE self)
|
1331
|
+
{
|
1332
|
+
VALUE sm_mat = sm_wrap_mat4(g_mat4_identity, self);
|
1333
|
+
rb_obj_call_init(sm_mat, argc, argv);
|
1334
|
+
return sm_mat;
|
1335
|
+
}
|
1336
|
+
|
1337
|
+
|
1338
|
+
|
1339
|
+
static VALUE sm_mat4_init(int argc, VALUE *argv, VALUE sm_self)
|
1340
|
+
{
|
1341
|
+
mat4_t *self = sm_unwrap_mat4(sm_self, NULL);
|
1342
|
+
size_t arr_index = 0;
|
1343
|
+
|
1344
|
+
switch (argc) {
|
1345
|
+
|
1346
|
+
case 0: {
|
1347
|
+
// Identity (handled in _new)
|
1348
|
+
break;
|
1349
|
+
}
|
1350
|
+
|
1351
|
+
// Copy Mat4 or provided [Numeric..]
|
1352
|
+
case 1: {
|
1353
|
+
// Copy Mat4
|
1354
|
+
if (SM_IS_A(argv[0], mat4)) {
|
1355
|
+
sm_unwrap_mat4(argv[0], *self);
|
1356
|
+
break;
|
1357
|
+
}
|
1358
|
+
|
1359
|
+
// Build from Quaternion
|
1360
|
+
if (SM_IS_A(argv[0], quat)) {
|
1361
|
+
mat4_from_quat(*sm_unwrap_quat(argv[0], NULL), *self);
|
1362
|
+
break;
|
1363
|
+
}
|
1364
|
+
|
1365
|
+
// Optional offset into array provided
|
1366
|
+
if (0) {
|
1367
|
+
case 2:
|
1368
|
+
arr_index = NUM2SIZET(argv[1]);
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
// Array of values
|
1372
|
+
if (SM_RB_IS_A(argv[0], rb_cArray)) {
|
1373
|
+
VALUE arrdata = argv[0];
|
1374
|
+
const size_t arr_end = arr_index + 16;
|
1375
|
+
s_float_t *mat_elem = *self;
|
1376
|
+
for (; arr_index < arr_end; ++arr_index, ++mat_elem) {
|
1377
|
+
*mat_elem = rb_num2dbl(rb_ary_entry(arrdata, (long)arr_index));
|
1378
|
+
}
|
1379
|
+
break;
|
1380
|
+
}
|
1381
|
+
|
1382
|
+
rb_raise(rb_eArgError, "Expected either an array of Numerics or a Mat4");
|
1383
|
+
break;
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
// Mat4(Vec4, Vec4, Vec4, Vec4)
|
1387
|
+
case 4: {
|
1388
|
+
size_t arg_index;
|
1389
|
+
s_float_t *mat_elem = *self;
|
1390
|
+
for (arg_index = 0; arg_index < 4; ++arg_index, mat_elem += 4) {
|
1391
|
+
if (!SM_IS_A(argv[arg_index], vec4) && !SM_IS_A(argv[arg_index], quat)) {
|
1392
|
+
rb_raise(
|
1393
|
+
rb_eArgError,
|
1394
|
+
"Argument %d must be a Vec4 or Quat when supplying four arguments to Mat4.initialize",
|
1395
|
+
(int)(arg_index + 1));
|
1396
|
+
}
|
1397
|
+
|
1398
|
+
sm_unwrap_vec4(argv[arg_index], mat_elem);
|
1399
|
+
}
|
1400
|
+
break;
|
1401
|
+
}
|
1402
|
+
|
1403
|
+
// Mat4(Numeric m00 .. m16)
|
1404
|
+
case 16: {
|
1405
|
+
s_float_t *mat_elem = *self;
|
1406
|
+
VALUE *argv_p = argv;
|
1407
|
+
for (; argc; --argc, ++argv_p, ++mat_elem) {
|
1408
|
+
*mat_elem = (s_float_t)rb_num2dbl(*argv_p);
|
1409
|
+
}
|
1410
|
+
break;
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
default: {
|
1414
|
+
rb_raise(rb_eArgError, "Invalid arguments to Mat4.initialize");
|
1415
|
+
break;
|
1416
|
+
}
|
1417
|
+
} // swtich (argc)
|
1418
|
+
|
1419
|
+
return sm_self;
|
1420
|
+
}
|
1421
|
+
|
1422
|
+
|
1423
|
+
|
1424
|
+
static VALUE sm_mat4_to_s(VALUE self)
|
1425
|
+
{
|
1426
|
+
const s_float_t *v;
|
1427
|
+
v = (const s_float_t *)*sm_unwrap_mat4(self, NULL);
|
1428
|
+
return rb_sprintf(
|
1429
|
+
"{ "
|
1430
|
+
"%f, %f, %f, %f" ", "
|
1431
|
+
"%f, %f, %f, %f" ", "
|
1432
|
+
"%f, %f, %f, %f" ", "
|
1433
|
+
"%f, %f, %f, %f"
|
1434
|
+
" }",
|
1435
|
+
v[0], v[1], v[2], v[3],
|
1436
|
+
v[4], v[5], v[6], v[7],
|
1437
|
+
v[8], v[9], v[10], v[11],
|
1438
|
+
v[12], v[13], v[14], v[15]);
|
1439
|
+
}
|
1440
|
+
|
1441
|
+
|
1442
|
+
|
1443
|
+
static VALUE sm_mat4_angle_axis(int argc, VALUE *argv, VALUE self)
|
1444
|
+
{
|
1445
|
+
VALUE sm_angle;
|
1446
|
+
VALUE sm_axis;
|
1447
|
+
VALUE sm_out;
|
1448
|
+
s_float_t angle;
|
1449
|
+
const vec3_t *axis;
|
1450
|
+
|
1451
|
+
rb_scan_args(argc, argv, "21", &sm_angle, &sm_axis, &sm_out);
|
1452
|
+
SM_RAISE_IF_NOT_TYPE(sm_axis, vec3);
|
1453
|
+
|
1454
|
+
angle = (s_float_t)rb_num2dbl(sm_angle);
|
1455
|
+
axis = sm_unwrap_vec3(sm_axis, NULL);
|
1456
|
+
|
1457
|
+
if (SM_IS_A(sm_out, mat4)) {
|
1458
|
+
mat4_t *out = sm_unwrap_mat4(sm_out, NULL);
|
1459
|
+
mat4_rotation(angle, (*axis)[0], (*axis)[1], (*axis)[2], *out);
|
1460
|
+
} else {
|
1461
|
+
mat4_t out;
|
1462
|
+
mat4_rotation(angle, (*axis)[0], (*axis)[1], (*axis)[2], out);
|
1463
|
+
sm_out = sm_wrap_mat4(out, self);
|
1464
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1465
|
+
}
|
1466
|
+
|
1467
|
+
return sm_out;
|
1468
|
+
}
|
1469
|
+
|
1470
|
+
|
1471
|
+
|
1472
|
+
static VALUE sm_mat4_get_row3(int argc, VALUE *argv, VALUE sm_self)
|
1473
|
+
{
|
1474
|
+
mat4_t *self;
|
1475
|
+
int index;
|
1476
|
+
VALUE sm_out;
|
1477
|
+
|
1478
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1479
|
+
index = NUM2INT(argv[0]);
|
1480
|
+
sm_out = Qnil;
|
1481
|
+
|
1482
|
+
if (index < 0 || index > 3) {
|
1483
|
+
rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 3)", index);
|
1484
|
+
return Qnil;
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
switch (argc) {
|
1488
|
+
case 2: {
|
1489
|
+
vec3_t *out;
|
1490
|
+
|
1491
|
+
sm_out = argv[1];
|
1492
|
+
|
1493
|
+
if (RTEST(sm_out)) {
|
1494
|
+
SM_RAISE_IF_NOT_TYPE(sm_out, vec3);
|
1495
|
+
} else {
|
1496
|
+
goto SM_LABEL(no_output);
|
1497
|
+
}
|
1498
|
+
|
1499
|
+
out = sm_unwrap_vec3(sm_out, NULL);
|
1500
|
+
mat4_get_row3(*self, index, *out);
|
1501
|
+
|
1502
|
+
break;
|
1503
|
+
}
|
1504
|
+
|
1505
|
+
case 1: SM_LABEL(no_output): {
|
1506
|
+
vec3_t out;
|
1507
|
+
mat4_get_row3(*self, index, out);
|
1508
|
+
sm_out = sm_wrap_vec3(out, Qnil);
|
1509
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1510
|
+
break;
|
1511
|
+
}
|
1512
|
+
|
1513
|
+
default: {
|
1514
|
+
rb_raise(rb_eArgError, "Invalid number of arguments to get_row3 - expected 1 or 2");
|
1515
|
+
break;
|
1516
|
+
}
|
1517
|
+
}
|
1518
|
+
|
1519
|
+
return sm_out;
|
1520
|
+
}
|
1521
|
+
|
1522
|
+
|
1523
|
+
|
1524
|
+
static VALUE sm_mat4_get_row4(int argc, VALUE *argv, VALUE sm_self)
|
1525
|
+
{
|
1526
|
+
mat4_t *self;
|
1527
|
+
int index;
|
1528
|
+
VALUE sm_out;
|
1529
|
+
|
1530
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1531
|
+
index = NUM2INT(argv[0]);
|
1532
|
+
sm_out = Qnil;
|
1533
|
+
|
1534
|
+
if (index < 0 || index > 3) {
|
1535
|
+
rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 3)", index);
|
1536
|
+
return Qnil;
|
1537
|
+
}
|
1538
|
+
|
1539
|
+
switch (argc) {
|
1540
|
+
case 2: {
|
1541
|
+
vec4_t *out;
|
1542
|
+
|
1543
|
+
sm_out = argv[1];
|
1544
|
+
|
1545
|
+
if (RTEST(sm_out)) {
|
1546
|
+
SM_RAISE_IF_NOT_TYPE(sm_out, vec4);
|
1547
|
+
} else {
|
1548
|
+
goto SM_LABEL(no_output);
|
1549
|
+
}
|
1550
|
+
|
1551
|
+
out = sm_unwrap_vec4(sm_out, NULL);
|
1552
|
+
mat4_get_row4(*self, index, *out);
|
1553
|
+
|
1554
|
+
break;
|
1555
|
+
}
|
1556
|
+
|
1557
|
+
case 1: SM_LABEL(no_output): {
|
1558
|
+
vec4_t out;
|
1559
|
+
mat4_get_row4(*self, index, out);
|
1560
|
+
sm_out = sm_wrap_vec4(out, Qnil);
|
1561
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1562
|
+
break;
|
1563
|
+
}
|
1564
|
+
|
1565
|
+
default: {
|
1566
|
+
rb_raise(rb_eArgError, "Invalid number of arguments to get_row4 - expected 1 or 2");
|
1567
|
+
break;
|
1568
|
+
}
|
1569
|
+
}
|
1570
|
+
|
1571
|
+
return sm_out;
|
1572
|
+
}
|
1573
|
+
|
1574
|
+
|
1575
|
+
|
1576
|
+
static VALUE sm_mat4_get_column3(int argc, VALUE *argv, VALUE sm_self)
|
1577
|
+
{
|
1578
|
+
mat4_t *self;
|
1579
|
+
int index;
|
1580
|
+
VALUE sm_out;
|
1581
|
+
|
1582
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1583
|
+
index = NUM2INT(argv[0]);
|
1584
|
+
sm_out = Qnil;
|
1585
|
+
|
1586
|
+
if (index < 0 || index > 3) {
|
1587
|
+
rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 3)", index);
|
1588
|
+
return Qnil;
|
1589
|
+
}
|
1590
|
+
|
1591
|
+
switch (argc) {
|
1592
|
+
case 2: {
|
1593
|
+
vec3_t *out;
|
1594
|
+
|
1595
|
+
sm_out = argv[1];
|
1596
|
+
|
1597
|
+
if (RTEST(sm_out)) {
|
1598
|
+
SM_RAISE_IF_NOT_TYPE(sm_out, vec3);
|
1599
|
+
} else {
|
1600
|
+
goto SM_LABEL(no_output);
|
1601
|
+
}
|
1602
|
+
|
1603
|
+
out = sm_unwrap_vec3(sm_out, NULL);
|
1604
|
+
mat4_get_column3(*self, index, *out);
|
1605
|
+
|
1606
|
+
break;
|
1607
|
+
}
|
1608
|
+
|
1609
|
+
case 1: SM_LABEL(no_output): {
|
1610
|
+
vec3_t out;
|
1611
|
+
mat4_get_column3(*self, index, out);
|
1612
|
+
sm_out = sm_wrap_vec3(out, Qnil);
|
1613
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1614
|
+
break;
|
1615
|
+
}
|
1616
|
+
|
1617
|
+
default: {
|
1618
|
+
rb_raise(rb_eArgError, "Invalid number of arguments to get_column3 - expected 1 or 2");
|
1619
|
+
break;
|
1620
|
+
}
|
1621
|
+
}
|
1622
|
+
|
1623
|
+
return sm_out;
|
1624
|
+
}
|
1625
|
+
|
1626
|
+
|
1627
|
+
|
1628
|
+
static VALUE sm_mat4_get_column4(int argc, VALUE *argv, VALUE sm_self)
|
1629
|
+
{
|
1630
|
+
mat4_t *self;
|
1631
|
+
int index;
|
1632
|
+
VALUE sm_out;
|
1633
|
+
|
1634
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1635
|
+
index = NUM2INT(argv[0]);
|
1636
|
+
sm_out = Qnil;
|
1637
|
+
|
1638
|
+
if (index < 0 || index > 3) {
|
1639
|
+
rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 3)", index);
|
1640
|
+
return Qnil;
|
1641
|
+
}
|
1642
|
+
|
1643
|
+
switch (argc) {
|
1644
|
+
case 2: {
|
1645
|
+
vec4_t *out;
|
1646
|
+
|
1647
|
+
sm_out = argv[1];
|
1648
|
+
|
1649
|
+
if (RTEST(sm_out)) {
|
1650
|
+
SM_RAISE_IF_NOT_TYPE(sm_out, vec4);
|
1651
|
+
} else {
|
1652
|
+
goto SM_LABEL(no_output);
|
1653
|
+
}
|
1654
|
+
|
1655
|
+
out = sm_unwrap_vec4(sm_out, NULL);
|
1656
|
+
mat4_get_column4(*self, index, *out);
|
1657
|
+
|
1658
|
+
break;
|
1659
|
+
}
|
1660
|
+
|
1661
|
+
case 1: SM_LABEL(no_output): {
|
1662
|
+
vec4_t out;
|
1663
|
+
mat4_get_column4(*self, index, out);
|
1664
|
+
sm_out = sm_wrap_vec4(out, Qnil);
|
1665
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1666
|
+
break;
|
1667
|
+
}
|
1668
|
+
|
1669
|
+
default: {
|
1670
|
+
rb_raise(rb_eArgError, "Invalid number of arguments to get_column4 - expected 1 or 2");
|
1671
|
+
break;
|
1672
|
+
}
|
1673
|
+
}
|
1674
|
+
|
1675
|
+
return sm_out;
|
1676
|
+
}
|
1677
|
+
|
1678
|
+
|
1679
|
+
|
1680
|
+
static VALUE sm_mat4_set_row3(VALUE sm_self, VALUE sm_index, VALUE sm_value)
|
1681
|
+
{
|
1682
|
+
const vec3_t *value;
|
1683
|
+
int index;
|
1684
|
+
mat4_t *self;
|
1685
|
+
|
1686
|
+
SM_RAISE_IF_NOT_TYPE(sm_value, vec3);
|
1687
|
+
|
1688
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1689
|
+
value = sm_unwrap_vec3(sm_value, NULL);
|
1690
|
+
index = NUM2INT(sm_index);
|
1691
|
+
|
1692
|
+
if (index < 0 || index > 3) {
|
1693
|
+
rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 3)", index);
|
1694
|
+
return Qnil;
|
1695
|
+
}
|
1696
|
+
|
1697
|
+
mat4_set_row3(index, *value, *self);
|
1698
|
+
|
1699
|
+
return sm_self;
|
1700
|
+
}
|
1701
|
+
|
1702
|
+
|
1703
|
+
|
1704
|
+
static VALUE sm_mat4_set_column3(VALUE sm_self, VALUE sm_index, VALUE sm_value)
|
1705
|
+
{
|
1706
|
+
const vec3_t *value;
|
1707
|
+
int index;
|
1708
|
+
mat4_t *self;
|
1709
|
+
|
1710
|
+
SM_RAISE_IF_NOT_TYPE(sm_value, vec3);
|
1711
|
+
|
1712
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1713
|
+
value = sm_unwrap_vec3(sm_value, NULL);
|
1714
|
+
index = NUM2INT(sm_index);
|
1715
|
+
|
1716
|
+
if (index < 0 || index > 3) {
|
1717
|
+
rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 3)", index);
|
1718
|
+
return Qnil;
|
1719
|
+
}
|
1720
|
+
|
1721
|
+
mat4_set_column3(index, *value, *self);
|
1722
|
+
|
1723
|
+
return sm_self;
|
1724
|
+
}
|
1725
|
+
|
1726
|
+
|
1727
|
+
|
1728
|
+
static VALUE sm_mat4_set_row4(VALUE sm_self, VALUE sm_index, VALUE sm_value)
|
1729
|
+
{
|
1730
|
+
const vec4_t *value;
|
1731
|
+
int index;
|
1732
|
+
mat4_t *self;
|
1733
|
+
|
1734
|
+
SM_RAISE_IF_NOT_TYPE(sm_value, vec4);
|
1735
|
+
|
1736
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1737
|
+
value = sm_unwrap_vec4(sm_value, NULL);
|
1738
|
+
index = NUM2INT(sm_index);
|
1739
|
+
|
1740
|
+
if (index < 0 || index > 3) {
|
1741
|
+
rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 3)", index);
|
1742
|
+
return Qnil;
|
1743
|
+
}
|
1744
|
+
|
1745
|
+
mat4_set_row4(index, *value, *self);
|
1746
|
+
|
1747
|
+
return sm_self;
|
1748
|
+
}
|
1749
|
+
|
1750
|
+
|
1751
|
+
|
1752
|
+
static VALUE sm_mat4_set_column4(VALUE sm_self, VALUE sm_index, VALUE sm_value)
|
1753
|
+
{
|
1754
|
+
const vec4_t *value;
|
1755
|
+
int index;
|
1756
|
+
mat4_t *self;
|
1757
|
+
|
1758
|
+
SM_RAISE_IF_NOT_TYPE(sm_value, vec4);
|
1759
|
+
|
1760
|
+
self = sm_unwrap_mat4(sm_self, NULL);
|
1761
|
+
value = sm_unwrap_vec4(sm_value, NULL);
|
1762
|
+
index = NUM2INT(sm_index);
|
1763
|
+
|
1764
|
+
if (index < 0 || index > 3) {
|
1765
|
+
rb_raise(rb_eRangeError, "Index %d is out of range, must be (0 .. 3)", index);
|
1766
|
+
return Qnil;
|
1767
|
+
}
|
1768
|
+
|
1769
|
+
mat4_set_column4(index, *value, *self);
|
1770
|
+
|
1771
|
+
return sm_self;
|
1772
|
+
}
|
1773
|
+
|
1774
|
+
|
1775
|
+
|
1776
|
+
static VALUE sm_mat4_identity(VALUE sm_self)
|
1777
|
+
{
|
1778
|
+
mat4_t *self = sm_unwrap_mat4(sm_self, NULL);
|
1779
|
+
mat4_identity(*self);
|
1780
|
+
return sm_self;
|
1781
|
+
}
|
1782
|
+
|
1783
|
+
|
1784
|
+
|
1785
|
+
static VALUE sm_mat4_frustum(int argc, VALUE *argv, VALUE self)
|
1786
|
+
{
|
1787
|
+
VALUE sm_left;
|
1788
|
+
VALUE sm_right;
|
1789
|
+
VALUE sm_bottom;
|
1790
|
+
VALUE sm_top;
|
1791
|
+
VALUE sm_z_near;
|
1792
|
+
VALUE sm_z_far;
|
1793
|
+
VALUE sm_out;
|
1794
|
+
s_float_t left;
|
1795
|
+
s_float_t right;
|
1796
|
+
s_float_t bottom;
|
1797
|
+
s_float_t top;
|
1798
|
+
s_float_t z_near;
|
1799
|
+
s_float_t z_far;
|
1800
|
+
|
1801
|
+
rb_scan_args(argc, argv, "61", &sm_left, &sm_right, &sm_bottom, &sm_top, &sm_z_near, &sm_z_far, &sm_out);
|
1802
|
+
|
1803
|
+
left = (s_float_t)rb_num2dbl(sm_left);
|
1804
|
+
right = (s_float_t)rb_num2dbl(sm_right);
|
1805
|
+
bottom = (s_float_t)rb_num2dbl(sm_bottom);
|
1806
|
+
top = (s_float_t)rb_num2dbl(sm_top);
|
1807
|
+
z_near = (s_float_t)rb_num2dbl(sm_z_near);
|
1808
|
+
z_far = (s_float_t)rb_num2dbl(sm_z_far);
|
1809
|
+
|
1810
|
+
if (SM_IS_A(sm_out, mat4)) {
|
1811
|
+
mat4_t *out = sm_unwrap_mat4(sm_out, NULL);
|
1812
|
+
mat4_frustum(left, right, bottom, top, z_near, z_far, *out);
|
1813
|
+
} else {
|
1814
|
+
mat4_t out;
|
1815
|
+
mat4_frustum(left, right, bottom, top, z_near, z_far, out);
|
1816
|
+
sm_out = sm_wrap_mat4(out, Qnil);
|
1817
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1818
|
+
}
|
1819
|
+
|
1820
|
+
return sm_out;
|
1821
|
+
}
|
1822
|
+
|
1823
|
+
|
1824
|
+
|
1825
|
+
static VALUE sm_mat4_orthographic(int argc, VALUE *argv, VALUE self)
|
1826
|
+
{
|
1827
|
+
VALUE sm_left;
|
1828
|
+
VALUE sm_right;
|
1829
|
+
VALUE sm_bottom;
|
1830
|
+
VALUE sm_top;
|
1831
|
+
VALUE sm_z_near;
|
1832
|
+
VALUE sm_z_far;
|
1833
|
+
VALUE sm_out;
|
1834
|
+
s_float_t left;
|
1835
|
+
s_float_t right;
|
1836
|
+
s_float_t bottom;
|
1837
|
+
s_float_t top;
|
1838
|
+
s_float_t z_near;
|
1839
|
+
s_float_t z_far;
|
1840
|
+
|
1841
|
+
rb_scan_args(argc, argv, "61", &sm_left, &sm_right, &sm_bottom, &sm_top, &sm_z_near, &sm_z_far, &sm_out);
|
1842
|
+
|
1843
|
+
left = (s_float_t)rb_num2dbl(sm_left);
|
1844
|
+
right = (s_float_t)rb_num2dbl(sm_right);
|
1845
|
+
bottom = (s_float_t)rb_num2dbl(sm_bottom);
|
1846
|
+
top = (s_float_t)rb_num2dbl(sm_top);
|
1847
|
+
z_near = (s_float_t)rb_num2dbl(sm_z_near);
|
1848
|
+
z_far = (s_float_t)rb_num2dbl(sm_z_far);
|
1849
|
+
|
1850
|
+
if (SM_IS_A(sm_out, mat4)) {
|
1851
|
+
mat4_t *out = sm_unwrap_mat4(sm_out, NULL);
|
1852
|
+
mat4_orthographic(left, right, bottom, top, z_near, z_far, *out);
|
1853
|
+
} else {
|
1854
|
+
mat4_t out;
|
1855
|
+
mat4_orthographic(left, right, bottom, top, z_near, z_far, out);
|
1856
|
+
sm_out = sm_wrap_mat4(out, self);
|
1857
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1858
|
+
}
|
1859
|
+
|
1860
|
+
return sm_out;
|
1861
|
+
}
|
1862
|
+
|
1863
|
+
|
1864
|
+
|
1865
|
+
static VALUE sm_mat4_perspective(int argc, VALUE *argv, VALUE self)
|
1866
|
+
{
|
1867
|
+
VALUE sm_fov_y;
|
1868
|
+
VALUE sm_aspect;
|
1869
|
+
VALUE sm_z_near;
|
1870
|
+
VALUE sm_z_far;
|
1871
|
+
VALUE sm_out;
|
1872
|
+
s_float_t fov_y;
|
1873
|
+
s_float_t aspect;
|
1874
|
+
s_float_t z_near;
|
1875
|
+
s_float_t z_far;
|
1876
|
+
|
1877
|
+
rb_scan_args(argc, argv, "41", &sm_fov_y, &sm_aspect, &sm_z_near, &sm_z_far, &sm_out);
|
1878
|
+
|
1879
|
+
fov_y = (s_float_t)rb_num2dbl(sm_fov_y);
|
1880
|
+
aspect = (s_float_t)rb_num2dbl(sm_aspect);
|
1881
|
+
z_near = (s_float_t)rb_num2dbl(sm_z_near);
|
1882
|
+
z_far = (s_float_t)rb_num2dbl(sm_z_far);
|
1883
|
+
|
1884
|
+
if (SM_IS_A(sm_out, mat4)) {
|
1885
|
+
mat4_t *out = sm_unwrap_mat4(sm_out, NULL);
|
1886
|
+
mat4_perspective(fov_y, aspect, z_near, z_far, *out);
|
1887
|
+
} else {
|
1888
|
+
mat4_t out;
|
1889
|
+
mat4_perspective(fov_y, aspect, z_near, z_far, out);
|
1890
|
+
sm_out = sm_wrap_mat4(out, self);
|
1891
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
return sm_out;
|
1895
|
+
}
|
1896
|
+
|
1897
|
+
|
1898
|
+
|
1899
|
+
static VALUE sm_mat4_look_at(int argc, VALUE *argv, VALUE self)
|
1900
|
+
{
|
1901
|
+
VALUE sm_eye;
|
1902
|
+
VALUE sm_center;
|
1903
|
+
VALUE sm_up;
|
1904
|
+
VALUE sm_out;
|
1905
|
+
const vec3_t *eye;
|
1906
|
+
const vec3_t *center;
|
1907
|
+
const vec3_t *up;
|
1908
|
+
|
1909
|
+
rb_scan_args(argc, argv, "31", &sm_eye, &sm_center, &sm_up, &sm_out);
|
1910
|
+
|
1911
|
+
eye = sm_unwrap_vec3(sm_eye, NULL);
|
1912
|
+
center = sm_unwrap_vec3(sm_center, NULL);
|
1913
|
+
up = sm_unwrap_vec3(sm_up, NULL);
|
1914
|
+
|
1915
|
+
if (SM_IS_A(sm_out, mat4)) {
|
1916
|
+
mat4_t *out = sm_unwrap_mat4(sm_out, NULL);
|
1917
|
+
mat4_look_at(*eye, *center, *up, *out);
|
1918
|
+
} else {
|
1919
|
+
mat4_t out;
|
1920
|
+
mat4_look_at(*eye, *center, *up, out);
|
1921
|
+
sm_out = sm_wrap_mat4(out, self);
|
1922
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1923
|
+
}
|
1924
|
+
|
1925
|
+
return sm_out;
|
1926
|
+
}
|
1927
|
+
|
1928
|
+
|
1929
|
+
|
1930
|
+
static VALUE sm_mat4_scale(int argc, VALUE *argv, VALUE sm_self)
|
1931
|
+
{
|
1932
|
+
VALUE sm_out;
|
1933
|
+
VALUE sm_x, sm_y, sm_z;
|
1934
|
+
s_float_t x, y, z;
|
1935
|
+
mat4_t *self = sm_unwrap_mat4(sm_self, NULL);
|
1936
|
+
|
1937
|
+
rb_scan_args(argc, argv, "31", &sm_x, &sm_y, &sm_z, &sm_out);
|
1938
|
+
x = rb_num2dbl(sm_x);
|
1939
|
+
y = rb_num2dbl(sm_y);
|
1940
|
+
z = rb_num2dbl(sm_z);
|
1941
|
+
|
1942
|
+
if (SM_IS_A(sm_out, mat4)) {
|
1943
|
+
mat4_scale(*self, x, y, z, *sm_unwrap_mat4(sm_out, NULL));
|
1944
|
+
} else {
|
1945
|
+
mat4_t out;
|
1946
|
+
mat4_scale(*self, x, y, z, out);
|
1947
|
+
sm_out = sm_wrap_mat4(out, rb_obj_class(sm_self));
|
1948
|
+
rb_obj_call_init(sm_out, 0, 0);
|
1949
|
+
}
|
1950
|
+
|
1951
|
+
return sm_out;
|
1952
|
+
}
|
1953
|
+
|
1954
|
+
|
1955
|
+
|
1956
|
+
static VALUE sm_mat4_equals(VALUE sm_self, VALUE sm_other)
|
1957
|
+
{
|
1958
|
+
if (!RTEST(sm_other)) {
|
1959
|
+
return Qfalse;
|
1960
|
+
} else {
|
1961
|
+
SM_RAISE_IF_NOT_TYPE(sm_other, mat4);
|
1962
|
+
}
|
1963
|
+
|
1964
|
+
return mat4_equals(*sm_unwrap_mat4(sm_self, NULL), *sm_unwrap_mat4(sm_other, NULL)) ? Qtrue : Qfalse;
|
1965
|
+
}
|
1966
|
+
|
1967
|
+
|
1968
|
+
|
1969
|
+
/*==============================================================================
|
1970
|
+
|
1971
|
+
General-purpose functions
|
1972
|
+
|
1973
|
+
==============================================================================*/
|
1974
|
+
|
1975
|
+
static VALUE sm_get_address(VALUE sm_self)
|
1976
|
+
{
|
1977
|
+
void *data_ptr = NULL;
|
1978
|
+
Data_Get_Struct(sm_self, void, data_ptr);
|
1979
|
+
return ULL2NUM((unsigned long long)data_ptr);
|
1980
|
+
}
|
1981
|
+
|
1982
|
+
|
1983
|
+
|
1984
|
+
void Init_bindings()
|
1985
|
+
{
|
1986
|
+
kRB_IVAR_MATHARRAY_LENGTH = rb_intern("__length");
|
1987
|
+
kRB_IVAR_MATHARRAY_SOURCE = rb_intern("__source");
|
1988
|
+
|
1989
|
+
s_sm_snowmath_mod = rb_define_module("Snow");
|
1990
|
+
SM_KLASS(vec3) = rb_define_class_under(s_sm_snowmath_mod, "Vec3", rb_cObject);
|
1991
|
+
SM_KLASS(vec4) = rb_define_class_under(s_sm_snowmath_mod, "Vec4", rb_cObject);
|
1992
|
+
SM_KLASS(quat) = rb_define_class_under(s_sm_snowmath_mod, "Quat", rb_cObject);
|
1993
|
+
SM_KLASS(mat4) = rb_define_class_under(s_sm_snowmath_mod, "Mat4", rb_cObject);
|
1994
|
+
|
1995
|
+
rb_define_singleton_method(SM_KLASS(vec3), "new", sm_vec3_new, -1);
|
1996
|
+
rb_define_method(SM_KLASS(vec3), "initialize", sm_vec3_init, -1);
|
1997
|
+
rb_define_method(SM_KLASS(vec3), "set", sm_vec3_init, -1);
|
1998
|
+
rb_define_method(SM_KLASS(vec3), "fetch", sm_vec3_fetch, 1);
|
1999
|
+
rb_define_method(SM_KLASS(vec3), "store", sm_vec3_store, 2);
|
2000
|
+
rb_define_method(SM_KLASS(vec3), "size", sm_vec3_size, 0);
|
2001
|
+
rb_define_method(SM_KLASS(vec3), "length", sm_vec3_length, 0);
|
2002
|
+
rb_define_method(SM_KLASS(vec3), "to_s", sm_vec3_to_s, 0);
|
2003
|
+
rb_define_method(SM_KLASS(vec3), "address", sm_get_address, 0);
|
2004
|
+
rb_define_method(SM_KLASS(vec3), "copy", sm_vec3_copy, -1);
|
2005
|
+
rb_define_method(SM_KLASS(vec3), "normalize", sm_vec3_normalize, -1);
|
2006
|
+
rb_define_method(SM_KLASS(vec3), "inverse", sm_vec3_inverse, -1);
|
2007
|
+
rb_define_method(SM_KLASS(vec3), "negate", sm_vec3_negate, -1);
|
2008
|
+
rb_define_method(SM_KLASS(vec3), "cross_product", sm_vec3_cross_product, -1);
|
2009
|
+
rb_define_method(SM_KLASS(vec3), "multiply_vec3", sm_vec3_multiply, -1);
|
2010
|
+
rb_define_method(SM_KLASS(vec3), "add", sm_vec3_add, -1);
|
2011
|
+
rb_define_method(SM_KLASS(vec3), "subtract", sm_vec3_subtract, -1);
|
2012
|
+
rb_define_method(SM_KLASS(vec3), "dot_product", sm_vec3_dot_product, 1);
|
2013
|
+
rb_define_method(SM_KLASS(vec3), "magnitude_squared", sm_vec3_magnitude_squared, 0);
|
2014
|
+
rb_define_method(SM_KLASS(vec3), "magnitude", sm_vec3_magnitude, 0);
|
2015
|
+
rb_define_method(SM_KLASS(vec3), "scale", sm_vec3_scale, -1);
|
2016
|
+
rb_define_method(SM_KLASS(vec3), "divide", sm_vec3_divide, -1);
|
2017
|
+
rb_define_method(SM_KLASS(vec3), "==", sm_vec3_equals, 1);
|
2018
|
+
|
2019
|
+
rb_define_singleton_method(SM_KLASS(vec4), "new", sm_vec4_new, -1);
|
2020
|
+
rb_define_method(SM_KLASS(vec4), "initialize", sm_vec4_init, -1);
|
2021
|
+
rb_define_method(SM_KLASS(vec4), "set", sm_vec4_init, -1);
|
2022
|
+
rb_define_method(SM_KLASS(vec4), "fetch", sm_vec4_fetch, 1);
|
2023
|
+
rb_define_method(SM_KLASS(vec4), "store", sm_vec4_store, 2);
|
2024
|
+
rb_define_method(SM_KLASS(vec4), "size", sm_vec4_size, 0);
|
2025
|
+
rb_define_method(SM_KLASS(vec4), "length", sm_vec4_length, 0);
|
2026
|
+
rb_define_method(SM_KLASS(vec4), "to_s", sm_vec4_to_s, 0);
|
2027
|
+
rb_define_method(SM_KLASS(vec4), "address", sm_get_address, 0);
|
2028
|
+
rb_define_method(SM_KLASS(vec4), "copy", sm_vec4_copy, -1);
|
2029
|
+
rb_define_method(SM_KLASS(vec4), "normalize", sm_vec4_normalize, -1);
|
2030
|
+
rb_define_method(SM_KLASS(vec4), "inverse", sm_vec4_inverse, -1);
|
2031
|
+
rb_define_method(SM_KLASS(vec4), "negate", sm_vec4_negate, -1);
|
2032
|
+
rb_define_method(SM_KLASS(vec4), "multiply_vec4", sm_vec4_multiply, -1);
|
2033
|
+
rb_define_method(SM_KLASS(vec4), "add", sm_vec4_add, -1);
|
2034
|
+
rb_define_method(SM_KLASS(vec4), "subtract", sm_vec4_subtract, -1);
|
2035
|
+
rb_define_method(SM_KLASS(vec4), "dot_product", sm_vec4_dot_product, 1);
|
2036
|
+
rb_define_method(SM_KLASS(vec4), "magnitude_squared", sm_vec4_magnitude_squared, 0);
|
2037
|
+
rb_define_method(SM_KLASS(vec4), "magnitude", sm_vec4_magnitude, 0);
|
2038
|
+
rb_define_method(SM_KLASS(vec4), "scale", sm_vec4_scale, -1);
|
2039
|
+
rb_define_method(SM_KLASS(vec4), "divide", sm_vec4_divide, -1);
|
2040
|
+
rb_define_method(SM_KLASS(vec4), "==", sm_vec4_equals, 1);
|
2041
|
+
|
2042
|
+
rb_define_singleton_method(SM_KLASS(quat), "new", sm_quat_new, -1);
|
2043
|
+
rb_define_singleton_method(SM_KLASS(quat), "angle_axis", sm_quat_angle_axis, -1);
|
2044
|
+
rb_define_method(SM_KLASS(quat), "initialize", sm_quat_init, -1);
|
2045
|
+
rb_define_method(SM_KLASS(quat), "set", sm_quat_init, -1);
|
2046
|
+
rb_define_method(SM_KLASS(quat), "load_identity", sm_quat_identity, 0);
|
2047
|
+
rb_define_method(SM_KLASS(quat), "fetch", sm_quat_fetch, 1);
|
2048
|
+
rb_define_method(SM_KLASS(quat), "store", sm_quat_store, 2);
|
2049
|
+
rb_define_method(SM_KLASS(quat), "size", sm_quat_size, 0);
|
2050
|
+
rb_define_method(SM_KLASS(quat), "length", sm_quat_length, 0);
|
2051
|
+
rb_define_method(SM_KLASS(quat), "to_s", sm_quat_to_s, 0);
|
2052
|
+
rb_define_method(SM_KLASS(quat), "address", sm_get_address, 0);
|
2053
|
+
rb_define_method(SM_KLASS(quat), "copy", sm_quat_copy, -1);
|
2054
|
+
rb_define_method(SM_KLASS(quat), "inverse", sm_quat_inverse, -1);
|
2055
|
+
rb_define_method(SM_KLASS(quat), "negate", sm_quat_negate, -1);
|
2056
|
+
rb_define_method(SM_KLASS(quat), "multiply_quat", sm_quat_multiply, -1);
|
2057
|
+
rb_define_method(SM_KLASS(quat), "multiply_vec3", sm_quat_multiply_vec3, -1);
|
2058
|
+
rb_define_method(SM_KLASS(quat), "normalize", sm_quat_normalize, -1);
|
2059
|
+
rb_define_method(SM_KLASS(quat), "scale", sm_quat_scale, -1);
|
2060
|
+
rb_define_method(SM_KLASS(quat), "divide", sm_quat_divide, -1);
|
2061
|
+
rb_define_method(SM_KLASS(quat), "add", sm_quat_add, -1);
|
2062
|
+
rb_define_method(SM_KLASS(quat), "subtract", sm_quat_subtract, -1);
|
2063
|
+
rb_define_method(SM_KLASS(quat), "slerp", sm_quat_slerp, -1);
|
2064
|
+
// Borrow some functions from vec4
|
2065
|
+
rb_define_method(SM_KLASS(quat), "dot_product", sm_vec4_dot_product, 1);
|
2066
|
+
rb_define_method(SM_KLASS(quat), "magnitude_squared", sm_vec4_magnitude_squared, 0);
|
2067
|
+
rb_define_method(SM_KLASS(quat), "magnitude", sm_vec4_magnitude, 0);
|
2068
|
+
rb_define_method(SM_KLASS(quat), "==", sm_vec4_equals, 1);
|
2069
|
+
|
2070
|
+
rb_define_singleton_method(SM_KLASS(mat4), "new", sm_mat4_new, -1);
|
2071
|
+
rb_define_singleton_method(SM_KLASS(mat4), "translation", sm_mat4_translation, -1);
|
2072
|
+
rb_define_singleton_method(SM_KLASS(mat4), "angle_axis", sm_mat4_angle_axis, -1);
|
2073
|
+
rb_define_singleton_method(SM_KLASS(mat4), "frustum", sm_mat4_frustum, -1);
|
2074
|
+
rb_define_singleton_method(SM_KLASS(mat4), "perspective", sm_mat4_perspective, -1);
|
2075
|
+
rb_define_singleton_method(SM_KLASS(mat4), "orthographic", sm_mat4_orthographic, -1);
|
2076
|
+
rb_define_singleton_method(SM_KLASS(mat4), "look_at", sm_mat4_look_at, -1);
|
2077
|
+
rb_define_method(SM_KLASS(mat4), "initialize", sm_mat4_init, -1);
|
2078
|
+
rb_define_method(SM_KLASS(mat4), "set", sm_mat4_init, -1);
|
2079
|
+
rb_define_method(SM_KLASS(mat4), "load_identity", sm_mat4_identity, 0);
|
2080
|
+
rb_define_method(SM_KLASS(mat4), "fetch", sm_mat4_fetch, 1);
|
2081
|
+
rb_define_method(SM_KLASS(mat4), "store", sm_mat4_store, 2);
|
2082
|
+
rb_define_method(SM_KLASS(mat4), "size", sm_mat4_size, 0);
|
2083
|
+
rb_define_method(SM_KLASS(mat4), "length", sm_mat4_length, 0);
|
2084
|
+
rb_define_method(SM_KLASS(mat4), "to_s", sm_mat4_to_s, 0);
|
2085
|
+
rb_define_method(SM_KLASS(mat4), "address", sm_get_address, 0);
|
2086
|
+
rb_define_method(SM_KLASS(mat4), "copy", sm_mat4_copy, -1);
|
2087
|
+
rb_define_method(SM_KLASS(mat4), "transpose", sm_mat4_transpose, -1);
|
2088
|
+
rb_define_method(SM_KLASS(mat4), "inverse_orthogonal", sm_mat4_inverse_orthogonal, -1);
|
2089
|
+
rb_define_method(SM_KLASS(mat4), "adjoint", sm_mat4_adjoint, -1);
|
2090
|
+
rb_define_method(SM_KLASS(mat4), "scale", sm_mat4_scale, -1);
|
2091
|
+
rb_define_method(SM_KLASS(mat4), "multiply_mat4", sm_mat4_multiply, -1);
|
2092
|
+
rb_define_method(SM_KLASS(mat4), "multiply_vec4", sm_mat4_multiply_vec4, -1);
|
2093
|
+
rb_define_method(SM_KLASS(mat4), "transform_vec3", sm_mat4_transform_vec3, -1);
|
2094
|
+
rb_define_method(SM_KLASS(mat4), "rotate_vec3", sm_mat4_rotate_vec3, -1);
|
2095
|
+
rb_define_method(SM_KLASS(mat4), "inverse_rotate_vec3", sm_mat4_inv_rotate_vec3, -1);
|
2096
|
+
rb_define_method(SM_KLASS(mat4), "inverse_affine", sm_mat4_inverse_affine, -1);
|
2097
|
+
rb_define_method(SM_KLASS(mat4), "inverse_general", sm_mat4_inverse_general, -1);
|
2098
|
+
rb_define_method(SM_KLASS(mat4), "determinant", sm_mat4_determinant, 0);
|
2099
|
+
rb_define_method(SM_KLASS(mat4), "translate", sm_mat4_translate, -1);
|
2100
|
+
rb_define_method(SM_KLASS(mat4), "set_row3", sm_mat4_set_row3, 2);
|
2101
|
+
rb_define_method(SM_KLASS(mat4), "set_row4", sm_mat4_set_row4, 2);
|
2102
|
+
rb_define_method(SM_KLASS(mat4), "get_row3", sm_mat4_get_row3, -1);
|
2103
|
+
rb_define_method(SM_KLASS(mat4), "get_row4", sm_mat4_get_row4, -1);
|
2104
|
+
rb_define_method(SM_KLASS(mat4), "set_column3", sm_mat4_set_column3, 2);
|
2105
|
+
rb_define_method(SM_KLASS(mat4), "set_column4", sm_mat4_set_column4, 2);
|
2106
|
+
rb_define_method(SM_KLASS(mat4), "get_column3", sm_mat4_get_column3, -1);
|
2107
|
+
rb_define_method(SM_KLASS(mat4), "get_column4", sm_mat4_get_column4, -1);
|
2108
|
+
rb_define_method(SM_KLASS(mat4), "==", sm_mat4_equals, 1);
|
2109
|
+
|
2110
|
+
#ifdef BUILD_ARRAY_TYPE
|
2111
|
+
REG_SM_ARR_TYPE(vec3, "Vec3Array");
|
2112
|
+
REG_SM_ARR_TYPE(vec4, "Vec4Array");
|
2113
|
+
REG_SM_ARR_TYPE(quat, "QuatArray");
|
2114
|
+
REG_SM_ARR_TYPE(mat4, "Mat4Array");
|
2115
|
+
#endif
|
2116
|
+
|
2117
|
+
}
|