larb 0.1.0 → 1.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -1
  3. data/README.md +63 -1
  4. data/ext/larb/color.c +449 -0
  5. data/ext/larb/color.h +35 -0
  6. data/ext/larb/extconf.rb +11 -0
  7. data/ext/larb/larb.c +27 -0
  8. data/ext/larb/larb.h +31 -0
  9. data/ext/larb/mat2.c +303 -0
  10. data/ext/larb/mat2.h +30 -0
  11. data/ext/larb/mat2d.c +397 -0
  12. data/ext/larb/mat2d.h +35 -0
  13. data/ext/larb/mat3.c +455 -0
  14. data/ext/larb/mat3.h +33 -0
  15. data/ext/larb/mat4.c +651 -0
  16. data/ext/larb/mat4.h +31 -0
  17. data/ext/larb/matrix_utils.h +97 -0
  18. data/ext/larb/quat.c +567 -0
  19. data/ext/larb/quat.h +39 -0
  20. data/ext/larb/quat2.c +511 -0
  21. data/ext/larb/quat2.h +39 -0
  22. data/ext/larb/vec2.c +365 -0
  23. data/ext/larb/vec2.h +43 -0
  24. data/ext/larb/vec3.c +538 -0
  25. data/ext/larb/vec3.h +52 -0
  26. data/ext/larb/vec4.c +361 -0
  27. data/ext/larb/vec4.h +38 -0
  28. data/lib/larb/version.rb +5 -0
  29. data/lib/larb.rb +2 -14
  30. data/test/larb/color_test.rb +299 -0
  31. data/test/larb/mat2_test.rb +144 -0
  32. data/test/larb/mat2d_test.rb +197 -0
  33. data/test/larb/mat3_test.rb +147 -0
  34. data/test/larb/mat4_test.rb +347 -0
  35. data/test/larb/matrix_test.rb +135 -0
  36. data/test/larb/native_value_test.rb +157 -0
  37. data/test/larb/quat2_test.rb +254 -0
  38. data/test/larb/quat_test.rb +284 -0
  39. data/test/larb/vec2_test.rb +274 -0
  40. data/test/larb/vec3_test.rb +373 -0
  41. data/test/larb/vec4_test.rb +196 -0
  42. data/test/test_helper.rb +4 -0
  43. metadata +60 -18
  44. data/Rakefile +0 -11
  45. data/lib/larb/color.rb +0 -148
  46. data/lib/larb/mat2.rb +0 -119
  47. data/lib/larb/mat2d.rb +0 -180
  48. data/lib/larb/mat3.rb +0 -238
  49. data/lib/larb/mat4.rb +0 -329
  50. data/lib/larb/quat.rb +0 -238
  51. data/lib/larb/quat2.rb +0 -193
  52. data/lib/larb/vec2.rb +0 -150
  53. data/lib/larb/vec3.rb +0 -218
  54. data/lib/larb/vec4.rb +0 -125
data/ext/larb/vec2.c ADDED
@@ -0,0 +1,365 @@
1
+ #include "vec2.h"
2
+
3
+ #include <math.h>
4
+
5
+ static void vec2_free(void *ptr) {
6
+ xfree(ptr);
7
+ }
8
+
9
+ static size_t vec2_memsize(const void *ptr) {
10
+ return sizeof(Vec2Data);
11
+ }
12
+
13
+ static const rb_data_type_t vec2_type = {
14
+ "Vec2",
15
+ {0, vec2_free, vec2_memsize},
16
+ 0,
17
+ 0,
18
+ RUBY_TYPED_FREE_IMMEDIATELY,
19
+ };
20
+
21
+ static VALUE cVec2 = Qnil;
22
+
23
+ static Vec2Data *vec2_get(VALUE obj) {
24
+ Vec2Data *data = NULL;
25
+ TypedData_Get_Struct(obj, Vec2Data, &vec2_type, data);
26
+ return data;
27
+ }
28
+
29
+ static VALUE vec2_build(VALUE klass, double x, double y) {
30
+ VALUE obj = vec2_alloc(klass);
31
+ Vec2Data *data = vec2_get(obj);
32
+ data->x = x;
33
+ data->y = y;
34
+ return obj;
35
+ }
36
+
37
+ VALUE vec2_alloc(VALUE klass) {
38
+ Vec2Data *data = ALLOC(Vec2Data);
39
+ data->x = 0.0;
40
+ data->y = 0.0;
41
+ return TypedData_Wrap_Struct(klass, &vec2_type, data);
42
+ }
43
+
44
+ VALUE vec2_initialize(int argc, VALUE *argv, VALUE self) {
45
+ rb_check_frozen(self);
46
+ VALUE vx = Qnil;
47
+ VALUE vy = Qnil;
48
+ rb_scan_args(argc, argv, "02", &vx, &vy);
49
+ Vec2Data value = {
50
+ argc > 0 ? NUM2DBL(vx) : 0.0,
51
+ argc > 1 ? NUM2DBL(vy) : 0.0
52
+ };
53
+ rb_check_frozen(self);
54
+ *vec2_get(self) = value;
55
+ return self;
56
+ }
57
+
58
+ static VALUE vec2_class_bracket(VALUE klass, VALUE x, VALUE y) {
59
+ return vec2_build(klass, NUM2DBL(x), NUM2DBL(y));
60
+ }
61
+
62
+ static VALUE vec2_class_zero(VALUE klass) {
63
+ return vec2_build(klass, 0.0, 0.0);
64
+ }
65
+
66
+ static VALUE vec2_class_one(VALUE klass) {
67
+ return vec2_build(klass, 1.0, 1.0);
68
+ }
69
+
70
+ static VALUE vec2_get_x(VALUE self) {
71
+ Vec2Data *data = vec2_get(self);
72
+ return DBL2NUM(data->x);
73
+ }
74
+
75
+ static VALUE vec2_set_x(VALUE self, VALUE value) {
76
+ rb_check_frozen(self);
77
+ Vec2Data *data = vec2_get(self);
78
+ double component = NUM2DBL(value);
79
+ rb_check_frozen(self);
80
+ data->x = component;
81
+ return value;
82
+ }
83
+
84
+ static VALUE vec2_get_y(VALUE self) {
85
+ Vec2Data *data = vec2_get(self);
86
+ return DBL2NUM(data->y);
87
+ }
88
+
89
+ static VALUE vec2_set_y(VALUE self, VALUE value) {
90
+ rb_check_frozen(self);
91
+ Vec2Data *data = vec2_get(self);
92
+ double component = NUM2DBL(value);
93
+ rb_check_frozen(self);
94
+ data->y = component;
95
+ return value;
96
+ }
97
+
98
+ VALUE vec2_add(VALUE self, VALUE other) {
99
+ Vec2Data *a = vec2_get(self);
100
+ Vec2Data *b = vec2_get(other);
101
+ return vec2_build(rb_obj_class(self), a->x + b->x, a->y + b->y);
102
+ }
103
+
104
+ VALUE vec2_sub(VALUE self, VALUE other) {
105
+ Vec2Data *a = vec2_get(self);
106
+ Vec2Data *b = vec2_get(other);
107
+ return vec2_build(rb_obj_class(self), a->x - b->x, a->y - b->y);
108
+ }
109
+
110
+ VALUE vec2_mul(VALUE self, VALUE scalar) {
111
+ Vec2Data *a = vec2_get(self);
112
+ double s = NUM2DBL(scalar);
113
+ return vec2_build(rb_obj_class(self), a->x * s, a->y * s);
114
+ }
115
+
116
+ VALUE vec2_div(VALUE self, VALUE scalar) {
117
+ Vec2Data *a = vec2_get(self);
118
+ double s = NUM2DBL(scalar);
119
+ return vec2_build(rb_obj_class(self), a->x / s, a->y / s);
120
+ }
121
+
122
+ VALUE vec2_negate(VALUE self) {
123
+ Vec2Data *a = vec2_get(self);
124
+ return vec2_build(rb_obj_class(self), -a->x, -a->y);
125
+ }
126
+
127
+ VALUE vec2_dot(VALUE self, VALUE other) {
128
+ Vec2Data *a = vec2_get(self);
129
+ Vec2Data *b = vec2_get(other);
130
+ return DBL2NUM(a->x * b->x + a->y * b->y);
131
+ }
132
+
133
+ VALUE vec2_length(VALUE self) {
134
+ Vec2Data *a = vec2_get(self);
135
+ return DBL2NUM(hypot(a->x, a->y));
136
+ }
137
+
138
+ VALUE vec2_length_squared(VALUE self) {
139
+ Vec2Data *a = vec2_get(self);
140
+ return DBL2NUM(a->x * a->x + a->y * a->y);
141
+ }
142
+
143
+ VALUE vec2_normalize(VALUE self) {
144
+ Vec2Data *a = vec2_get(self);
145
+ double values[] = {a->x, a->y};
146
+ larb_normalize(values, 2);
147
+ return vec2_build(rb_obj_class(self), values[0], values[1]);
148
+ }
149
+
150
+ VALUE vec2_normalize_bang(VALUE self) {
151
+ rb_check_frozen(self);
152
+ Vec2Data *a = vec2_get(self);
153
+ double values[] = {a->x, a->y};
154
+ larb_normalize(values, 2);
155
+ a->x = values[0];
156
+ a->y = values[1];
157
+ return self;
158
+ }
159
+
160
+ VALUE vec2_lerp(VALUE self, VALUE other, VALUE t) {
161
+ Vec2Data *a = vec2_get(self);
162
+ Vec2Data *b = vec2_get(other);
163
+ double s = NUM2DBL(t);
164
+ return vec2_build(rb_obj_class(self), a->x + (b->x - a->x) * s,
165
+ a->y + (b->y - a->y) * s);
166
+ }
167
+
168
+ VALUE vec2_to_a(VALUE self) {
169
+ Vec2Data *a = vec2_get(self);
170
+ VALUE ary = rb_ary_new_capa(2);
171
+ rb_ary_push(ary, DBL2NUM(a->x));
172
+ rb_ary_push(ary, DBL2NUM(a->y));
173
+ return ary;
174
+ }
175
+
176
+ VALUE vec2_aref(VALUE self, VALUE index) {
177
+ VALUE ary = vec2_to_a(self);
178
+ return rb_ary_entry(ary, NUM2LONG(index));
179
+ }
180
+
181
+ VALUE vec2_aset(VALUE self, VALUE index, VALUE value) {
182
+ rb_check_frozen(self);
183
+ Vec2Data *a = vec2_get(self);
184
+ long idx = NUM2LONG(index);
185
+ if (idx < 0) idx += 2;
186
+ if (idx < 0 || idx >= 2) rb_raise(rb_eIndexError, "Index out of range");
187
+ double component = NUM2DBL(value);
188
+ rb_check_frozen(self);
189
+ if (idx == 0) {
190
+ a->x = component;
191
+ } else {
192
+ a->y = component;
193
+ }
194
+ return value;
195
+ }
196
+
197
+ VALUE vec2_equal(VALUE self, VALUE other) {
198
+ if (!rb_obj_is_kind_of(other, cVec2)) {
199
+ return Qfalse;
200
+ }
201
+ Vec2Data *a = vec2_get(self);
202
+ Vec2Data *b = vec2_get(other);
203
+ return (a->x == b->x && a->y == b->y) ? Qtrue : Qfalse;
204
+ }
205
+
206
+ VALUE vec2_near(int argc, VALUE *argv, VALUE self) {
207
+ VALUE other = Qnil;
208
+ VALUE epsilon = Qnil;
209
+
210
+ rb_scan_args(argc, argv, "11", &other, &epsilon);
211
+ Vec2Data *a = vec2_get(self);
212
+ Vec2Data *b = vec2_get(other);
213
+ double eps = argc < 2 ? 1e-6 : NUM2DBL(epsilon);
214
+ if (!isfinite(eps) || eps <= 0.0) {
215
+ rb_raise(rb_eArgError, "epsilon must be finite and positive");
216
+ }
217
+
218
+ if (fabs(a->x - b->x) < eps && fabs(a->y - b->y) < eps) {
219
+ return Qtrue;
220
+ }
221
+ return Qfalse;
222
+ }
223
+
224
+ VALUE vec2_angle(VALUE self) {
225
+ Vec2Data *a = vec2_get(self);
226
+ return DBL2NUM(atan2(a->y, a->x));
227
+ }
228
+
229
+ VALUE vec2_angle_to(VALUE self, VALUE other) {
230
+ Vec2Data *a = vec2_get(self);
231
+ Vec2Data *b = vec2_get(other);
232
+ return DBL2NUM(atan2(b->y - a->y, b->x - a->x));
233
+ }
234
+
235
+ VALUE vec2_rotate(VALUE self, VALUE radians) {
236
+ Vec2Data *a = vec2_get(self);
237
+ double r = NUM2DBL(radians);
238
+ double c = cos(r);
239
+ double s = sin(r);
240
+ return vec2_build(rb_obj_class(self), a->x * c - a->y * s,
241
+ a->x * s + a->y * c);
242
+ }
243
+
244
+ VALUE vec2_distance(VALUE self, VALUE other) {
245
+ Vec2Data *a = vec2_get(self);
246
+ Vec2Data *b = vec2_get(other);
247
+ double dx = a->x - b->x;
248
+ double dy = a->y - b->y;
249
+ return DBL2NUM(hypot(dx, dy));
250
+ }
251
+
252
+ VALUE vec2_distance_squared(VALUE self, VALUE other) {
253
+ Vec2Data *a = vec2_get(self);
254
+ Vec2Data *b = vec2_get(other);
255
+ double dx = a->x - b->x;
256
+ double dy = a->y - b->y;
257
+ return DBL2NUM(dx * dx + dy * dy);
258
+ }
259
+
260
+ VALUE vec2_cross(VALUE self, VALUE other) {
261
+ Vec2Data *a = vec2_get(self);
262
+ Vec2Data *b = vec2_get(other);
263
+ return DBL2NUM(a->x * b->y - a->y * b->x);
264
+ }
265
+
266
+ VALUE vec2_perpendicular(VALUE self) {
267
+ Vec2Data *a = vec2_get(self);
268
+ return vec2_build(rb_obj_class(self), -a->y, a->x);
269
+ }
270
+
271
+ VALUE vec2_reflect(VALUE self, VALUE normal) {
272
+ Vec2Data *a = vec2_get(self);
273
+ Vec2Data *n = vec2_get(normal);
274
+ double dot = a->x * n->x + a->y * n->y;
275
+ return vec2_build(rb_obj_class(self), a->x - n->x * (2.0 * dot),
276
+ a->y - n->y * (2.0 * dot));
277
+ }
278
+
279
+ VALUE vec2_clamp_length(VALUE self, VALUE max_length) {
280
+ Vec2Data *a = vec2_get(self);
281
+ double max_len = NUM2DBL(max_length);
282
+ if (!isfinite(max_len) || max_len < 0.0) {
283
+ rb_raise(rb_eArgError, "max_length must be finite and nonnegative");
284
+ }
285
+ if (hypot(a->x, a->y) <= max_len) return self;
286
+ double values[] = {a->x, a->y};
287
+ larb_normalize(values, 2);
288
+ return vec2_build(rb_obj_class(self), values[0] * max_len, values[1] * max_len);
289
+ }
290
+
291
+ VALUE vec2_to_vec3(int argc, VALUE *argv, VALUE self) {
292
+ VALUE vz = Qnil;
293
+ Vec2Data *a = vec2_get(self);
294
+
295
+ rb_scan_args(argc, argv, "01", &vz);
296
+ VALUE vec3_class = rb_const_get(mLarb, rb_intern("Vec3"));
297
+ return rb_funcall(vec3_class, rb_intern("new"), 3, DBL2NUM(a->x),
298
+ DBL2NUM(a->y), argc == 0 ? DBL2NUM(0.0) : vz);
299
+ }
300
+
301
+ VALUE vec2_inspect(VALUE self) {
302
+ Vec2Data *a = vec2_get(self);
303
+ VALUE sx = rb_funcall(DBL2NUM(a->x), rb_intern("to_s"), 0);
304
+ VALUE sy = rb_funcall(DBL2NUM(a->y), rb_intern("to_s"), 0);
305
+ VALUE str = rb_str_new_cstr("Vec2[");
306
+ rb_str_concat(str, sx);
307
+ rb_str_cat_cstr(str, ", ");
308
+ rb_str_concat(str, sy);
309
+ rb_str_cat_cstr(str, "]");
310
+ return str;
311
+ }
312
+
313
+ static VALUE vec2_initialize_copy(VALUE self, VALUE other) {
314
+ if (self == other) return self;
315
+ rb_obj_init_copy(self, other);
316
+ *vec2_get(self) = *vec2_get(other);
317
+ return self;
318
+ }
319
+
320
+ void Init_vec2(VALUE module) {
321
+ cVec2 = rb_define_class_under(module, "Vec2", rb_cObject);
322
+
323
+ rb_define_alloc_func(cVec2, vec2_alloc);
324
+ rb_define_method(cVec2, "initialize", vec2_initialize, -1);
325
+ rb_define_method(cVec2, "initialize_copy", vec2_initialize_copy, 1);
326
+
327
+ rb_define_singleton_method(cVec2, "[]", vec2_class_bracket, 2);
328
+ rb_define_singleton_method(cVec2, "zero", vec2_class_zero, 0);
329
+ rb_define_singleton_method(cVec2, "one", vec2_class_one, 0);
330
+
331
+ rb_define_method(cVec2, "x", vec2_get_x, 0);
332
+ rb_define_method(cVec2, "x=", vec2_set_x, 1);
333
+ rb_define_method(cVec2, "y", vec2_get_y, 0);
334
+ rb_define_method(cVec2, "y=", vec2_set_y, 1);
335
+
336
+ rb_define_method(cVec2, "+", vec2_add, 1);
337
+ rb_define_method(cVec2, "-", vec2_sub, 1);
338
+ rb_define_method(cVec2, "*", vec2_mul, 1);
339
+ rb_define_method(cVec2, "/", vec2_div, 1);
340
+ rb_define_method(cVec2, "-@", vec2_negate, 0);
341
+
342
+ rb_define_method(cVec2, "dot", vec2_dot, 1);
343
+ rb_define_method(cVec2, "length", vec2_length, 0);
344
+ rb_define_method(cVec2, "length_squared", vec2_length_squared, 0);
345
+ rb_define_method(cVec2, "normalize", vec2_normalize, 0);
346
+ rb_define_method(cVec2, "normalize!", vec2_normalize_bang, 0);
347
+ rb_define_method(cVec2, "lerp", vec2_lerp, 2);
348
+ rb_define_method(cVec2, "to_a", vec2_to_a, 0);
349
+ rb_define_method(cVec2, "[]", vec2_aref, 1);
350
+ rb_define_method(cVec2, "[]=", vec2_aset, 2);
351
+ rb_define_method(cVec2, "==", vec2_equal, 1);
352
+ rb_define_method(cVec2, "near?", vec2_near, -1);
353
+ rb_define_method(cVec2, "angle", vec2_angle, 0);
354
+ rb_define_method(cVec2, "angle_to", vec2_angle_to, 1);
355
+ rb_define_method(cVec2, "rotate", vec2_rotate, 1);
356
+ rb_define_method(cVec2, "distance", vec2_distance, 1);
357
+ rb_define_method(cVec2, "distance_squared", vec2_distance_squared, 1);
358
+ rb_define_method(cVec2, "cross", vec2_cross, 1);
359
+ rb_define_method(cVec2, "perpendicular", vec2_perpendicular, 0);
360
+ rb_define_method(cVec2, "reflect", vec2_reflect, 1);
361
+ rb_define_method(cVec2, "clamp_length", vec2_clamp_length, 1);
362
+ rb_define_method(cVec2, "to_vec3", vec2_to_vec3, -1);
363
+ rb_define_method(cVec2, "inspect", vec2_inspect, 0);
364
+ rb_define_alias(cVec2, "to_s", "inspect");
365
+ }
data/ext/larb/vec2.h ADDED
@@ -0,0 +1,43 @@
1
+ #ifndef VEC2_H
2
+ #define VEC2_H
3
+
4
+ #include "larb.h"
5
+
6
+ typedef struct {
7
+ double x;
8
+ double y;
9
+ } Vec2Data;
10
+
11
+ void Init_vec2(VALUE module);
12
+ VALUE vec2_alloc(VALUE klass);
13
+ VALUE vec2_initialize(int argc, VALUE *argv, VALUE self);
14
+
15
+ VALUE vec2_add(VALUE self, VALUE other);
16
+ VALUE vec2_sub(VALUE self, VALUE other);
17
+ VALUE vec2_mul(VALUE self, VALUE scalar);
18
+ VALUE vec2_div(VALUE self, VALUE scalar);
19
+ VALUE vec2_negate(VALUE self);
20
+ VALUE vec2_dot(VALUE self, VALUE other);
21
+ VALUE vec2_length(VALUE self);
22
+ VALUE vec2_length_squared(VALUE self);
23
+ VALUE vec2_normalize(VALUE self);
24
+ VALUE vec2_normalize_bang(VALUE self);
25
+ VALUE vec2_lerp(VALUE self, VALUE other, VALUE t);
26
+ VALUE vec2_to_a(VALUE self);
27
+ VALUE vec2_aref(VALUE self, VALUE index);
28
+ VALUE vec2_aset(VALUE self, VALUE index, VALUE value);
29
+ VALUE vec2_equal(VALUE self, VALUE other);
30
+ VALUE vec2_near(int argc, VALUE *argv, VALUE self);
31
+ VALUE vec2_angle(VALUE self);
32
+ VALUE vec2_angle_to(VALUE self, VALUE other);
33
+ VALUE vec2_rotate(VALUE self, VALUE radians);
34
+ VALUE vec2_distance(VALUE self, VALUE other);
35
+ VALUE vec2_distance_squared(VALUE self, VALUE other);
36
+ VALUE vec2_cross(VALUE self, VALUE other);
37
+ VALUE vec2_perpendicular(VALUE self);
38
+ VALUE vec2_reflect(VALUE self, VALUE normal);
39
+ VALUE vec2_clamp_length(VALUE self, VALUE max_length);
40
+ VALUE vec2_to_vec3(int argc, VALUE *argv, VALUE self);
41
+ VALUE vec2_inspect(VALUE self);
42
+
43
+ #endif