snow-math 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/COPYING +26 -0
- data/README.md +613 -0
- data/ext/extconf.rb +8 -0
- data/ext/snow-math/snow-math.c +25 -15
- data/lib/snow-math/array_cache.rb +16 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46e87b537dadcdf09df7d18126a3fdd43bae0269
|
4
|
+
data.tar.gz: 48ac51001b1c24bf65e0916a2d8253745bf61680
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d69f5b6d5224531c115093013049b1273905fc66a9fd1628d1ecee557a24932fcdac3bf1851b9814415c60596d9be65e93265fce947cdeb3c820b1ff2bf0ea9c
|
7
|
+
data.tar.gz: be97770e8846a16d83746f28ec00334e7c472d8b19f6eaa54145ab70c181caa264ee21a96211b2c5f658813cdc443f7099d19c6078e1053a5f536bbb6798480b
|
data/COPYING
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2013, Noel Raymond Cower <ncower@gmail.com>.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
The views and conclusions contained in the software and documentation are those
|
25
|
+
of the authors and should not be interpreted as representing official policies,
|
26
|
+
either expressed or implied, of the FreeBSD Project.
|
data/README.md
ADDED
@@ -0,0 +1,613 @@
|
|
1
|
+
# snow-math
|
2
|
+
|
3
|
+
$ gem install snow-math [-- [--use-float | -F]]
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
## Intro
|
8
|
+
|
9
|
+
snow-math is a small, fairly simple library of 3D math routines implemented in
|
10
|
+
C with Ruby bindings. It's intended for use with OpenGL and such. Currently, it
|
11
|
+
provides four 3D math types:
|
12
|
+
|
13
|
+
- Snow::Vec3
|
14
|
+
- Snow::Vec4
|
15
|
+
- Snow::Quat
|
16
|
+
- Snow::Mat4
|
17
|
+
|
18
|
+
_Most_ of their functionality is implemented in the C bindings, particularly
|
19
|
+
anything that should be moderately performant.
|
20
|
+
|
21
|
+
By default, snow-math uses 64-bit native floats as its underlying type. So, a
|
22
|
+
Vec3 is literally a `doube[3]` (or a `vec3_t` in C). If you want it to use
|
23
|
+
32-bit floats, simply pass the `--use-float` option to gem when installing it.
|
24
|
+
This will cause the bindings to be compiled using floats instead of doubles.
|
25
|
+
Like so:
|
26
|
+
|
27
|
+
$ gem install snow-math -- --use-float
|
28
|
+
|
29
|
+
If you prefer shorter command-line options, `-F` is a synonym for `--use-float`.
|
30
|
+
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
In your Ruby scripts, you just need to `require 'snow-math'` and all of the
|
35
|
+
library will be pulled in _with the exception of `Fiddle::Pointer` support_.
|
36
|
+
To include the Fiddle support, you'll also need to `require 'snow-math/ptr'`.
|
37
|
+
This is to avoid dragging the entirety of Fiddle into your code when you're not
|
38
|
+
using it.
|
39
|
+
|
40
|
+
Because it's difficult to produce useful documentation for these bindings, this
|
41
|
+
is a brief outline of the classes and their functions in Ruby, sans function
|
42
|
+
bodies. Where a description of the functions is missing, the functions do what
|
43
|
+
they say on the tin.
|
44
|
+
|
45
|
+
### Notes
|
46
|
+
|
47
|
+
#### Outputs
|
48
|
+
|
49
|
+
Also, keep in mind that for any function provides an output argument, that
|
50
|
+
argument is optional. If output is non-nil, the function will must write its
|
51
|
+
the result of its operation to the output object.
|
52
|
+
|
53
|
+
When nil, the function will always return a new object. Providing an output
|
54
|
+
argument can be helpful when you want to avoid some unnecessary allocations.
|
55
|
+
|
56
|
+
Combined with the array types, you can either maintain a pool of 3D math objects
|
57
|
+
or use it to avoid cache misses (though right now the array objects are not the
|
58
|
+
most-optimized as they allocate a wrapper object per `fetch` -- something to
|
59
|
+
keep in mind).
|
60
|
+
|
61
|
+
In all cases where an output is provided, output may be the the object the
|
62
|
+
function is called on. So, for example, `vec.negate(vec)` is perfectly valid.
|
63
|
+
|
64
|
+
|
65
|
+
#### Shared by All Types
|
66
|
+
|
67
|
+
All types share the following functions. These are not included in the class
|
68
|
+
bodies below except where their behaviour is notably different.
|
69
|
+
|
70
|
+
|
71
|
+
- `fetch(index)` and `store(index, value)` - To get and set values at the given
|
72
|
+
component indices. For typed arrays, index is an array index. These do
|
73
|
+
bounds-checking. They are always aliased as `[]` and `[]=` respectively.
|
74
|
+
Typically, there are also simpler XYZW components for vectors and
|
75
|
+
quaternions. These behave a little differently for typed arrays, which you
|
76
|
+
can read about in their section below.
|
77
|
+
|
78
|
+
- `address` - Returns the memory address of the object's first component.
|
79
|
+
|
80
|
+
- `size` - Returns the size in bytes of the object in memory, not counting any
|
81
|
+
overhead introduced by Ruby. This varies depending on whether the gem was
|
82
|
+
built using floats or doubles. For typed arrays, this is the size of all
|
83
|
+
elements combined. So, a 16-length Mat4Array using doubles is 2048 bytes in
|
84
|
+
size, whereas a single Vec3 is 24 bytes.
|
85
|
+
|
86
|
+
- `length` - Returns the length in components of the object (3 for Vec3, 4 for
|
87
|
+
Vec4 and Quat, and 16 for Mat4). The result of this function should be
|
88
|
+
obvious for each type.
|
89
|
+
|
90
|
+
- `map(&block)` and `map` - In the first form, yields each component of an
|
91
|
+
object to the block and returns an object of the same type with the results.
|
92
|
+
In the second form, returns an Enumerator.
|
93
|
+
|
94
|
+
- `map!(&block)` and `map!` - Same as the above, but operates on self rather
|
95
|
+
than creating a new object.
|
96
|
+
|
97
|
+
- `each(&object)` and `each` - Does what you think it does. Second form returns
|
98
|
+
an Enumerator.
|
99
|
+
|
100
|
+
- `to_a` - Returns an array of all components in the given object.
|
101
|
+
|
102
|
+
- `to_ptr` - You have to `require 'snow-math/ptr'` for this. Returns a new
|
103
|
+
`Fiddle::Pointer` pointing to the object's address.
|
104
|
+
|
105
|
+
- `to_s` - Converts the object to a string that looks more or less like
|
106
|
+
`"{ fetch(0), fetch(1), ..., fetch(length - 1) }"`.
|
107
|
+
|
108
|
+
|
109
|
+
#### Swizzling
|
110
|
+
|
111
|
+
Vectors and quaternions generate swizzle methods on first use. So, by calling
|
112
|
+
`some_vector.zyx`, the some_vector's class, will generate a swizzle function
|
113
|
+
that returns a new Vec3 with components Z, Y, and X of the original vector, in
|
114
|
+
that order. The components you can use for swizzling on each type are fairly
|
115
|
+
obvious but are as follows:
|
116
|
+
|
117
|
+
- __Vec3__
|
118
|
+
Components: X, Y, and Z.
|
119
|
+
Swizzling three components returns a Vec3.
|
120
|
+
Swizzling four components returns a Vec4.
|
121
|
+
|
122
|
+
- __Vec4__
|
123
|
+
Components: X, Y, Z, and W.
|
124
|
+
Swizzling three components returns a Vec3.
|
125
|
+
Swizzling four components returns a Vec4.
|
126
|
+
|
127
|
+
- __Quat__
|
128
|
+
Components: X, Y, Z, and W.
|
129
|
+
Swizzling three components returns a Vec3.
|
130
|
+
Swizzling four components returns a Quat.
|
131
|
+
|
132
|
+
|
133
|
+
### Types
|
134
|
+
|
135
|
+
#### Snow::Vec3
|
136
|
+
|
137
|
+
class Snow::Vec3
|
138
|
+
|
139
|
+
def self.new() -> Vec3[0, 0, 0]
|
140
|
+
def self.new(x, y, z) -> Vec3[x, y, z]
|
141
|
+
def self.new(other: Vec3 | Vec4 | Quat) -> Vec3[other.x, other.y, other.z]
|
142
|
+
Aliased as :[], so you can use Vec3[0, 1, 2] to call Vec3.new(0, 1, 2).
|
143
|
+
|
144
|
+
self == rhs
|
145
|
+
Compares whether two Vec3s are equivalent. rhs may also be a Quat or Vec4,
|
146
|
+
in which case the first three components of either will be compared with
|
147
|
+
self.
|
148
|
+
|
149
|
+
def set() -> self [no-op]
|
150
|
+
def set(x, y, z) -> self
|
151
|
+
def set(other) -> self
|
152
|
+
Set takes the same arguments as self.new(...) and will call the same initialize
|
153
|
+
function as new(). If no arguments are provided to set, it does nothing.
|
154
|
+
|
155
|
+
def copy(output = nil) -> new vec3 or output
|
156
|
+
If output is nil, this is equivalent to calling o.dup or o.class.new(o).
|
157
|
+
With an output, the method copies self's components to other. For the most
|
158
|
+
part, you probably only want to use this with an output.
|
159
|
+
|
160
|
+
def inverse(output = nil) -> new vec3 or output
|
161
|
+
def inverse! -> self
|
162
|
+
Returns a vector whose components are the multiplicative inverse of the
|
163
|
+
vector's components.
|
164
|
+
Aliased as :~
|
165
|
+
|
166
|
+
def negate(output = nil) -> new vec3 or output
|
167
|
+
def negate! -> self
|
168
|
+
Returns a vector whose components are the negated form of the vector's
|
169
|
+
components. Beware of -0.0 here.
|
170
|
+
Aliased as :-@
|
171
|
+
|
172
|
+
def normalize(output = nil) -> new vec3 or output
|
173
|
+
def normalize!() -> self
|
174
|
+
|
175
|
+
def cross_product(rhs, output = nil) -> new vec3 or output
|
176
|
+
def cross_product!(rhs) -> self
|
177
|
+
|
178
|
+
def multiply_vec3(rhs, output = nil) -> new vec3 or output
|
179
|
+
Multiplies both vector's components together and returns the result.
|
180
|
+
|
181
|
+
def multiply(vec3, output = nil) -> same as multiply_vec3
|
182
|
+
def multiply(scalar, output = nil) -> same as scale
|
183
|
+
def multiply!(rhs) -> same as multiply(rhs, self)
|
184
|
+
Non-mutable form aliased as :*
|
185
|
+
|
186
|
+
def add(rhs, output = nil) -> new vec3 or output
|
187
|
+
def add!(rhs)
|
188
|
+
Aliased as :+
|
189
|
+
|
190
|
+
def subtract(rhs, output = nil) -> new vec3 or output
|
191
|
+
def subtract!(rhs) -> self
|
192
|
+
Aliased as :-
|
193
|
+
|
194
|
+
def dot_product(rhs) -> Float
|
195
|
+
Aliased as :**
|
196
|
+
|
197
|
+
def magnitude_squared -> Float
|
198
|
+
def magnitude -> Float
|
199
|
+
Returns the squared magnitude and the magnitude, respectively. To give you
|
200
|
+
an idea of the difference, magnitude == Math.sqrt(magnitude_squared). So
|
201
|
+
if you don't need the exact magnitude and only want to compare the magnitude
|
202
|
+
of two things, you can skip a call to sqrt and use the squared magnitude.
|
203
|
+
|
204
|
+
def scale(scalar, output = nil) -> new vec3 or output
|
205
|
+
def divide(scalar, output = nil) -> new vec3 or output
|
206
|
+
Multiplies or divides all components of the vector by a scalar. In the case
|
207
|
+
of divide, a scalar of 0 is undefined behaviour.
|
208
|
+
divide is aliased as :/
|
209
|
+
|
210
|
+
def size -> size in bytes
|
211
|
+
def length -> length in floats
|
212
|
+
size is either 24 or 12, depending on whether the gem was built to use
|
213
|
+
floats or doubles. length is always 3.
|
214
|
+
|
215
|
+
def x
|
216
|
+
def x=(new_x)
|
217
|
+
Same as fetch(0) and store(0, new_x) respectively
|
218
|
+
|
219
|
+
def y
|
220
|
+
def y=(new_y)
|
221
|
+
Same as fetch(1) and store(1, new_y) respectively
|
222
|
+
|
223
|
+
def z
|
224
|
+
def z=(new_z)
|
225
|
+
Same as fetch(2) and store(2, new_z) respectively
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
|
231
|
+
#### Snow::Vec4
|
232
|
+
|
233
|
+
Vec4 is fundamentally the same as Vec3, except it lacks a `cross_product`
|
234
|
+
function, has four components, and provides a `w` accessor for the fourth
|
235
|
+
component. In addition, it is at times interchangeable with Quat.
|
236
|
+
|
237
|
+
class Snow::Vec4
|
238
|
+
|
239
|
+
def self.new() -> Vec4[0, 0, 0, 1]
|
240
|
+
def self.new(x, y, z, w = 1) -> Vec4[x, y, z, w]
|
241
|
+
def self.new(other: Vec3 | Vec4 | Quat) -> Vec4[other.x, other.y, other.z, other.w | 1]
|
242
|
+
Aliased as :[], so you can use Vec4[0, 1, 2, 3] to call Vec4.new(0, 1, 2, 3).
|
243
|
+
When calling Vec4.new and supplying a Vec3 to copy from, the fourth component,
|
244
|
+
w, will be set to 1.
|
245
|
+
|
246
|
+
self == rhs
|
247
|
+
Compares whether two Vec4s are equivalent. rhs may also be a Quat.
|
248
|
+
|
249
|
+
def set() -> self [no-op]
|
250
|
+
def set(x, y, z, w = 1) -> self
|
251
|
+
def set(other) -> self
|
252
|
+
Set takes the same arguments as self.new(...) and will call the same initialize
|
253
|
+
function as new(). If no arguments are provided to set, it does nothing.
|
254
|
+
|
255
|
+
def copy(output = nil) -> new vec4 or output
|
256
|
+
If output is nil, this is equivalent to calling o.dup or o.class.new(o).
|
257
|
+
With an output, the method copies self's components to other. For the most
|
258
|
+
part, you probably only want to use this with an output.
|
259
|
+
|
260
|
+
def inverse(output = nil) -> new vec4 or output
|
261
|
+
def inverse! -> self
|
262
|
+
Returns a vector whose components are the multiplicative inverse of the
|
263
|
+
vector's components.
|
264
|
+
|
265
|
+
def negate(output = nil) -> new vec4 or output
|
266
|
+
def negate! -> self
|
267
|
+
Returns a vector whose components are the negated form of the vector's
|
268
|
+
components. Beware of -0.0 here.
|
269
|
+
|
270
|
+
def normalize(output = nil) -> new vec4 or output
|
271
|
+
def normalize!() -> self
|
272
|
+
|
273
|
+
def multiply_vec4(rhs, output = nil) -> new vec4 or output
|
274
|
+
def multiply_vec4!(rhs) -> self
|
275
|
+
Multiplies both vector's components together and returns the result.
|
276
|
+
|
277
|
+
def multiply(vec4, output = nil) -> same as multiply_vec4
|
278
|
+
def multiply(numeric, output = nil) -> same as scale
|
279
|
+
def multiply!(rhs) -> same as multiply(rhs, self)
|
280
|
+
Aliased as :*
|
281
|
+
|
282
|
+
def add(rhs, output = nil) -> new vec4 or output
|
283
|
+
def add!(rhs)
|
284
|
+
|
285
|
+
def subtract(rhs, output = nil) -> new vec4 or output
|
286
|
+
def subtract!(rhs) -> self
|
287
|
+
|
288
|
+
def dot_product(rhs) -> Float
|
289
|
+
|
290
|
+
def magnitude_squared -> Float
|
291
|
+
def magnitude -> Float
|
292
|
+
Returns the squared magnitude and the magnitude, respectively. To give you
|
293
|
+
an idea of the difference, magnitude == Math.sqrt(magnitude_squared). So
|
294
|
+
if you don't need the exact magnitude and only want to compare the magnitude
|
295
|
+
of two things, you can skip a call to sqrt and use the squared magnitude.
|
296
|
+
|
297
|
+
def scale(scalar, output = nil) -> new vec4 or output
|
298
|
+
def divide(scalar, output = nil) -> new vec4 or output
|
299
|
+
Multiplies or divides all components of the vector by a scalar. In the case
|
300
|
+
of divide, a scalar of 0 is undefined behaviour.
|
301
|
+
|
302
|
+
def size -> size in bytes
|
303
|
+
def length -> length in floats
|
304
|
+
size is either 32 or 16. depending on whether the gem was built to use
|
305
|
+
floats or doubles. length is always 4.
|
306
|
+
|
307
|
+
def x
|
308
|
+
def x=(new_x)
|
309
|
+
Same as fetch(0) and store(0, new_x) respectively
|
310
|
+
|
311
|
+
def y
|
312
|
+
def y=(new_y)
|
313
|
+
Same as fetch(1) and store(1, new_y) respectively
|
314
|
+
|
315
|
+
def z
|
316
|
+
def z=(new_z)
|
317
|
+
Same as fetch(2) and store(2, new_z) respectively
|
318
|
+
|
319
|
+
def w
|
320
|
+
def w=(new_w)
|
321
|
+
Same as fetch(3) and store(3, new_w) respectively
|
322
|
+
|
323
|
+
end
|
324
|
+
|
325
|
+
|
326
|
+
|
327
|
+
#### Snow::Quat
|
328
|
+
|
329
|
+
Quat is functionally similar to Vec4, except it provides some functions specific
|
330
|
+
to quaternions. Why these aren't just part of Vec4 is a mystery for the ages
|
331
|
+
and an attempt to make code more readable.
|
332
|
+
|
333
|
+
class Snow::Quat
|
334
|
+
|
335
|
+
def self.new() -> Quat[0, 0, 0, 1]
|
336
|
+
def self.new(x, y, z, w = 1) -> Quat[x, y, z, w]
|
337
|
+
def self.new(Mat4) -> Quat from Mat4
|
338
|
+
def self.new(other: Vec3 | Quat | Quat) -> Quat[other.x, other.y, other.z, other.w | 1]
|
339
|
+
Aliased as :[], so you can use Quat[0, 1, 2, 3] to call Quat.new(0, 1, 2, 3).
|
340
|
+
When calling Quat.new and supplying a Vec3 to copy from, the fourth component,
|
341
|
+
w, will be set to 1. If provided a Mat4, it will be converted to a Quat. Without
|
342
|
+
arguments, Quat.new will return an identity quaternion.
|
343
|
+
|
344
|
+
self == rhs
|
345
|
+
Compares whether two Quats are equivalent. rhs may be either a Quat or
|
346
|
+
Vec4.
|
347
|
+
|
348
|
+
def set() -> self [no-op]
|
349
|
+
def set(x, y, z, w = 1) -> self
|
350
|
+
def set(Mat4) -> self
|
351
|
+
def set(other) -> self
|
352
|
+
This takes the same arguments as self.new and in fact just calls the Quat's
|
353
|
+
initializer with the new arguments. The only difference is that calling set()
|
354
|
+
without arguments will not set this quaternion to the identity quaternion,
|
355
|
+
because the allocator is the one responsible for that. (To do that, use
|
356
|
+
load_identity)
|
357
|
+
|
358
|
+
load_identity() -> self
|
359
|
+
Resets self to the identity quaternion.
|
360
|
+
|
361
|
+
def copy(output = nil) -> new quat or output
|
362
|
+
If output is nil, this is equivalent to calling o.dup or o.class.new(o).
|
363
|
+
With an output, the method copies self's components to other. For the most
|
364
|
+
part, you probably only want to use this with an output.
|
365
|
+
|
366
|
+
def inverse(output = nil) -> new quat or output
|
367
|
+
def inverse! -> self
|
368
|
+
Returns the inverse of this quaternion (or writes the inverse to an output
|
369
|
+
or itself). This is not the same as a vector's inverse -- keep that in mind.
|
370
|
+
|
371
|
+
def negate(output = nil) -> new quat or output
|
372
|
+
def negate! -> self
|
373
|
+
Returns a quaternion whose components are the negated form of the vector's
|
374
|
+
components. Beware of -0.0 here. This is the same as negating a vector.
|
375
|
+
|
376
|
+
def normalize(output = nil) -> new quat or output
|
377
|
+
def normalize!() -> self
|
378
|
+
|
379
|
+
def multiply_quat(rhs: Quat, output = nil) -> new quat or output
|
380
|
+
def multiply!(rhs: Quat) -> self
|
381
|
+
The first form, multiply_quat, multiplies two quaternions and returns the
|
382
|
+
resulting quaternion. The second form, multiply!, is the same as calling
|
383
|
+
multiply_quat(rhs, self).
|
384
|
+
|
385
|
+
def mutliply_vec3(rhs: Vec3, output = nil) -> new vec3 or output
|
386
|
+
Multiplies a vec3 by a quat and returns the resulting vec3.
|
387
|
+
|
388
|
+
def multiply(vec3, output = nil) -> new vec3 or output
|
389
|
+
def multiply(quat, output = nil) -> new quat or output
|
390
|
+
def multiply(numeric, output = nil) -> new quat or output
|
391
|
+
In its first form, it's the same as #multiply_vec3. In its second, it's the
|
392
|
+
same as #multiply_quat. In its third, it's the same as #scale.
|
393
|
+
|
394
|
+
def add(rhs, output = nil) -> new quat or output
|
395
|
+
def add!(rhs)
|
396
|
+
Same as Vec4#add and Vec4#add!.
|
397
|
+
|
398
|
+
def subtract(rhs, output = nil) -> new quat or output
|
399
|
+
def subtract!(rhs) -> self
|
400
|
+
Same as Vec4#subtract and Vec4#subtract!.
|
401
|
+
|
402
|
+
def dot_product(rhs) -> Float
|
403
|
+
Same as Vec4#dot_product.
|
404
|
+
|
405
|
+
def magnitude_squared -> Float
|
406
|
+
def magnitude -> Float
|
407
|
+
Returns the squared magnitude and the magnitude, respectively. To give you
|
408
|
+
an idea of the difference, magnitude == Math.sqrt(magnitude_squared). So
|
409
|
+
if you don't need the exact magnitude and only want to compare the magnitude
|
410
|
+
of two things, you can skip a call to sqrt and use the squared magnitude.
|
411
|
+
|
412
|
+
def scale(scalar, output = nil) -> new quat or output
|
413
|
+
def divide(scalar, output = nil) -> new quat or output
|
414
|
+
Multiplies or divides all components of the quaternion by a scalar. In the
|
415
|
+
case of divide, a scalar of 0 is undefined behaviour.
|
416
|
+
|
417
|
+
def size -> size in bytes
|
418
|
+
def length -> length in floats
|
419
|
+
size is either 32 or 16. depending on whether the gem was built to use
|
420
|
+
floats or doubles. length is always 4.
|
421
|
+
|
422
|
+
def x
|
423
|
+
def x=(new_x)
|
424
|
+
Same as fetch(0) and store(0, new_x) respectively
|
425
|
+
|
426
|
+
def y
|
427
|
+
def y=(new_y)
|
428
|
+
Same as fetch(1) and store(1, new_y) respectively
|
429
|
+
|
430
|
+
def z
|
431
|
+
def z=(new_z)
|
432
|
+
Same as fetch(2) and store(2, new_z) respectively
|
433
|
+
|
434
|
+
def w
|
435
|
+
def w=(new_w)
|
436
|
+
Same as fetch(3) and store(3, new_w) respectively
|
437
|
+
|
438
|
+
end
|
439
|
+
|
440
|
+
|
441
|
+
|
442
|
+
#### Snow::Mat4
|
443
|
+
|
444
|
+
class Snow::Mat4
|
445
|
+
|
446
|
+
def self.new() -> identity mat4
|
447
|
+
def self.new(m1, m2, m3, ..., m16) -> mat4 with the given components
|
448
|
+
def self.new([Vec4, Vec4, Vec4, Vec4]) -> mat4 with rows defined by the given Vec4s
|
449
|
+
def self.new(Quat) -> Mat4 from Quat
|
450
|
+
def self.new(Mat4) -> copy of the given Mat4
|
451
|
+
Aliased as `[]`, so you can use Mat4[...] to create a new Mat4.
|
452
|
+
|
453
|
+
def self.translation(x, y, z, output = nil) -> new mat4 or output
|
454
|
+
def self.translation(Vec3, output = nil) -> new mat4 or output
|
455
|
+
Returns a translation matrix.
|
456
|
+
|
457
|
+
def self.angle_axis(angle_degrees, axis: Vec3, output = nil) -> new mat4 or output
|
458
|
+
Returns a new rotation matrix for the given angle and axis. The angle is in
|
459
|
+
degrees. This might offend some people, but I assure you, your sanity will
|
460
|
+
be preserved by doing this.
|
461
|
+
|
462
|
+
def self.frustum(left, right, bottom, top, z_near, z_far, output = nil) -> new mat4 or output
|
463
|
+
def self.orthographic(left, right, bottom, top, z_near, z_far, output = nil) -> new mat4 or output
|
464
|
+
def self.perspective(fov_y, aspect, z_near, z_far, output = nil) -> new mat4 or output
|
465
|
+
Returns the given kinds of projection matrices. In the case of perspective,
|
466
|
+
fov_y is specified in degrees. Again, your sanity will thank you.
|
467
|
+
|
468
|
+
def self.look_at(eye: Vec3, center: Vec3, up: Vec3, output = nil) -> new mat4 or output
|
469
|
+
Returns a look-at matrix.
|
470
|
+
|
471
|
+
def set(...)
|
472
|
+
Same variations and arguments as self.new(...)
|
473
|
+
|
474
|
+
def load_identity() -> self
|
475
|
+
Resets self to the identity matrix.
|
476
|
+
|
477
|
+
def copy(output = nil) -> new mat4 or output
|
478
|
+
Copies self to the given output matrix.
|
479
|
+
|
480
|
+
def transpose(output = nil) -> new mat4 or output
|
481
|
+
def transpose!() -> self
|
482
|
+
|
483
|
+
def inverse_orthogonal(output = nil) -> new mat4 or output
|
484
|
+
def inverse_affine(output = nil) -> new mat4 or output on success, nil on failure
|
485
|
+
def inverse_general(output = nil) -> new mat4 or output on success, nil on failure
|
486
|
+
def inverse_orthogonal!() -> self
|
487
|
+
def inverse_affine!() -> self on success, nil on failure
|
488
|
+
def inverse_general!() -> self on success, nil on failure
|
489
|
+
|
490
|
+
def translate(x, y, z, output = nil) -> new mat4 or output
|
491
|
+
def translate(vec3, output = nil) -> new mat4 or output
|
492
|
+
def translate!(x, y, z) -> self
|
493
|
+
def translate!(vec3) -> self
|
494
|
+
Essentially multiplies this matrix by a translation matrix with the given
|
495
|
+
translation and returns it.
|
496
|
+
|
497
|
+
def multiply_mat4(rhs, output = nil) -> new mat4 or output
|
498
|
+
def multiply_mat4!(rhs) -> self
|
499
|
+
Multiplies this and the rhs matrix and returns the result.
|
500
|
+
|
501
|
+
def multiply_vec4(rhs, output = nil) -> new vec4 or output
|
502
|
+
Transforms a vec4 by the matrix and returns the result.
|
503
|
+
|
504
|
+
def multiply_vec3(rhs, output = nil) -> new vec3 or output
|
505
|
+
def rotate_vec3(rhs, output = nil) -> new vec3 or output
|
506
|
+
In the first form, transforms a vec3 by the matrix and returns the result.
|
507
|
+
In the second form, rotates a vec3 by the matrix, ignoring any translation,
|
508
|
+
and returns the result.
|
509
|
+
|
510
|
+
def inverse_rotate_vec3(vec3, output = nil) -> new vec3 or output
|
511
|
+
Essentially just a convenience function.
|
512
|
+
|
513
|
+
def multiply(mat4, output = nil) -> same as mutliply_mat4
|
514
|
+
def multiply(vec3, output = nil) -> same as mutliply_vec3
|
515
|
+
def multiply(numeric, output = nil) -> same as scale(N, N, N, output)
|
516
|
+
def multiply!(rhs) -> same as multiply(rhs, self)
|
517
|
+
The fourth form, multiply!, will fail if attempting to multiply a vec3.
|
518
|
+
Aliased as `*`
|
519
|
+
|
520
|
+
def adjoint(output = nil) -> new mat4 or output
|
521
|
+
def adjoint!() -> new mat4 or output
|
522
|
+
|
523
|
+
def determinant -> Float
|
524
|
+
|
525
|
+
def scale(x, y, z, output = nil) -> new mat4 or output
|
526
|
+
def scale!(x, y, z) -> new mat4 or output
|
527
|
+
Returns a matrix with its inner 3x3 matrix's rows scaled by the given
|
528
|
+
components.
|
529
|
+
|
530
|
+
def set_row3, set_column3, set_row4, set_column4(index, V) -> self
|
531
|
+
V is a vector with the number of components in the function name. Sets the
|
532
|
+
Mat4's row or column to the components of the given vec3 or vec4.
|
533
|
+
|
534
|
+
def get_row3, get_column3, get_row4, get_column4(index, output = nil) -> row/column
|
535
|
+
Returns a vector with the number of components as specific by the name for
|
536
|
+
the given row or column in the Mat4.
|
537
|
+
|
538
|
+
end
|
539
|
+
|
540
|
+
|
541
|
+
|
542
|
+
#### Snow::Vec3Array, Snow::Vec4Array, Snow::QuatArray, Snow::Mat4Array
|
543
|
+
|
544
|
+
All typed arrays have the same interface and differ only in the kind of object
|
545
|
+
they contain. As such, this applies to all typed arrays.
|
546
|
+
|
547
|
+
class Snow::Vec3Array, Snow::Vec4Array, Snow::QuatArray, Snow::Mat4Array
|
548
|
+
|
549
|
+
def self.new(length) -> new array
|
550
|
+
def self.new(array) -> copy of array
|
551
|
+
Aliased as `[]`, so you can create an array, for example, by writing
|
552
|
+
`Vec3Array[16]`. The length provided must be greater than zero, otherwise
|
553
|
+
the returned array is nil.
|
554
|
+
|
555
|
+
Array elements are always uninitialized on allocation, so they will often
|
556
|
+
contain garbage values. It is your responsibility to initialize them as
|
557
|
+
needed.
|
558
|
+
|
559
|
+
def fetch(index) -> object of array element type
|
560
|
+
Returns an object that references the array's internal data. Manipulating
|
561
|
+
this object manipulates the data in the array -- it is not simply a copy of
|
562
|
+
the array's data. The returned object is cached, so subsequent calls to
|
563
|
+
fetch will return the same object (unless resized, in which case the cache
|
564
|
+
is destroyed and objects previously bound to the array are invalid -- use
|
565
|
+
of those objects following a resize is considered undefined behaviour).
|
566
|
+
|
567
|
+
def store(index, value) -> value
|
568
|
+
Copies a value object's data into the array's data. If the value object is
|
569
|
+
already part of the array -- that is, it was created using the array's
|
570
|
+
fetch function, this is a no-op.
|
571
|
+
|
572
|
+
def resize!(new_length) -> self
|
573
|
+
def resize(new_length) -> new array
|
574
|
+
Resizes the array and returns the value. In the first form, the underlying
|
575
|
+
buffer for the array is resized. In the second form, a new array is
|
576
|
+
allocated and returned.
|
577
|
+
|
578
|
+
end
|
579
|
+
|
580
|
+
|
581
|
+
|
582
|
+
## License
|
583
|
+
|
584
|
+
snow-math, like most of my gems, is licensed under a simplified BSD license.
|
585
|
+
And like most of my gems, I will say as usual that if this is a problem for
|
586
|
+
you, please contact me. The license is reproduced here:
|
587
|
+
|
588
|
+
Copyright (c) 2013, Noel Raymond Cower <ncower@gmail.com>.
|
589
|
+
All rights reserved.
|
590
|
+
|
591
|
+
Redistribution and use in source and binary forms, with or without
|
592
|
+
modification, are permitted provided that the following conditions are met:
|
593
|
+
|
594
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
595
|
+
list of conditions and the following disclaimer.
|
596
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
597
|
+
this list of conditions and the following disclaimer in the documentation
|
598
|
+
and/or other materials provided with the distribution.
|
599
|
+
|
600
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
601
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
602
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
603
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
604
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
605
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
606
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
607
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
608
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
609
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
610
|
+
|
611
|
+
The views and conclusions contained in the software and documentation are those
|
612
|
+
of the authors and should not be interpreted as representing official policies,
|
613
|
+
either expressed or implied, of the FreeBSD Project.
|
data/ext/extconf.rb
CHANGED
@@ -8,6 +8,14 @@ require 'mkmf'
|
|
8
8
|
# Compile as C99
|
9
9
|
$CFLAGS += " -std=c99"
|
10
10
|
|
11
|
+
if ARGV.include?("--debug") || ARGV.include?("-D")
|
12
|
+
$CFLAGS += " -g"
|
13
|
+
puts "Building extension source in debug mode"
|
14
|
+
else
|
15
|
+
$CFLAGS += " -O3 -fno-fast-math -fno-strict-aliasing"
|
16
|
+
puts "Building extension source in release mode"
|
17
|
+
end
|
18
|
+
|
11
19
|
if ARGV.include?("--use-float") || ARGV.include?("-F")
|
12
20
|
$CFLAGS += " -DUSE_FLOAT"
|
13
21
|
puts "Using float as base type"
|
data/ext/snow-math/snow-math.c
CHANGED
@@ -275,6 +275,7 @@ static VALUE sm_mathtype_array_length(VALUE sm_self)
|
|
275
275
|
rb_define_singleton_method(klass_, "new", sm_##ELEM_TYPE##_array_new, 1); \
|
276
276
|
rb_define_method(klass_, "fetch", sm_##ELEM_TYPE##_array_fetch, 1); \
|
277
277
|
rb_define_method(klass_, "store", sm_##ELEM_TYPE##_array_store, 2); \
|
278
|
+
rb_define_method(klass_, "resize!", sm_##ELEM_TYPE##_array_resize, 1); \
|
278
279
|
rb_define_method(klass_, "size", sm_##ELEM_TYPE##_array_size, 0); \
|
279
280
|
rb_define_method(klass_, "length", sm_mathtype_array_length, 0); \
|
280
281
|
rb_define_method(klass_, "address", sm_get_address, 0); \
|
@@ -283,16 +284,16 @@ static VALUE sm_mathtype_array_length(VALUE sm_self)
|
|
283
284
|
#define DEF_SM_ARR_TYPE(ELEM_TYPE) \
|
284
285
|
static VALUE SM_ARR_KLASS(ELEM_TYPE) = Qnil; \
|
285
286
|
\
|
286
|
-
static VALUE sm_##ELEM_TYPE##_array_new(VALUE sm_self, VALUE
|
287
|
+
static VALUE sm_##ELEM_TYPE##_array_new(VALUE sm_self, VALUE sm_length_or_copy) \
|
287
288
|
{ \
|
288
|
-
|
289
|
+
size_t length = 0; \
|
289
290
|
ELEM_TYPE##_t *arr; \
|
290
291
|
VALUE sm_type_array; \
|
291
292
|
int copy_array = 0; \
|
292
|
-
if ((copy_array = SM_IS_A(
|
293
|
-
length =
|
293
|
+
if ((copy_array = SM_IS_A(sm_length_or_copy, ELEM_TYPE##_array))) { \
|
294
|
+
length = NUM2SIZET(sm_mathtype_array_length(sm_length_or_copy)); \
|
294
295
|
} else { \
|
295
|
-
length =
|
296
|
+
length = NUM2SIZET(sm_length_or_copy); \
|
296
297
|
} \
|
297
298
|
if (length <= 0) { \
|
298
299
|
return Qnil; \
|
@@ -300,25 +301,34 @@ static VALUE sm_##ELEM_TYPE##_array_new(VALUE sm_self, VALUE sm_length)
|
|
300
301
|
arr = ALLOC_N(ELEM_TYPE##_t, length); \
|
301
302
|
if (copy_array) { \
|
302
303
|
const ELEM_TYPE##_t *source; \
|
303
|
-
Data_Get_Struct(
|
304
|
+
Data_Get_Struct(sm_length_or_copy, ELEM_TYPE##_t, source); \
|
304
305
|
MEMCPY(arr, source, ELEM_TYPE##_t, length); \
|
305
|
-
|
306
|
+
sm_length_or_copy = sm_mathtype_array_length(sm_length_or_copy); \
|
306
307
|
} \
|
307
308
|
sm_type_array = Data_Wrap_Struct(sm_self, 0, free, arr); \
|
308
|
-
rb_ivar_set(sm_type_array, kRB_IVAR_MATHARRAY_LENGTH,
|
309
|
+
rb_ivar_set(sm_type_array, kRB_IVAR_MATHARRAY_LENGTH, sm_length_or_copy); \
|
309
310
|
rb_obj_call_init(sm_type_array, 0, 0); \
|
310
311
|
return sm_type_array; \
|
311
312
|
} \
|
312
313
|
\
|
314
|
+
static VALUE sm_##ELEM_TYPE##_array_resize(VALUE sm_self, VALUE sm_new_length) \
|
315
|
+
{ \
|
316
|
+
size_t new_length; \
|
317
|
+
new_length = NUM2SIZET(sm_new_length); \
|
318
|
+
REALLOC_N(RDATA(sm_self)->data, ELEM_TYPE##_t, new_length); \
|
319
|
+
rb_ivar_set(sm_self, kRB_IVAR_MATHARRAY_LENGTH, sm_new_length); \
|
320
|
+
return sm_self; \
|
321
|
+
} \
|
322
|
+
\
|
313
323
|
static VALUE sm_##ELEM_TYPE##_array_fetch(VALUE sm_self, VALUE sm_index) \
|
314
324
|
{ \
|
315
325
|
ELEM_TYPE##_t *arr; \
|
316
|
-
|
317
|
-
|
326
|
+
size_t length = NUM2SIZET(sm_mathtype_array_length(sm_self)); \
|
327
|
+
size_t index = NUM2SIZET(sm_index); \
|
318
328
|
VALUE sm_inner; \
|
319
329
|
if (index < 0 || index >= length) { \
|
320
330
|
rb_raise(rb_eRangeError, \
|
321
|
-
"Index %
|
331
|
+
"Index %zu out of bounds for array with length %zu", \
|
322
332
|
index, length); \
|
323
333
|
} \
|
324
334
|
Data_Get_Struct(sm_self, ELEM_TYPE##_t, arr); \
|
@@ -331,11 +341,11 @@ static VALUE sm_##ELEM_TYPE##_array_store(VALUE sm_self, VALUE sm_index, VALUE s
|
|
331
341
|
{ \
|
332
342
|
ELEM_TYPE##_t *arr; \
|
333
343
|
ELEM_TYPE##_t *value; \
|
334
|
-
|
335
|
-
|
344
|
+
size_t length = NUM2SIZET(sm_mathtype_array_length(sm_self)); \
|
345
|
+
size_t index = NUM2SIZET(sm_index); \
|
336
346
|
if (index < 0 || index >= length) { \
|
337
347
|
rb_raise(rb_eRangeError, \
|
338
|
-
"Index %
|
348
|
+
"Index %zu out of bounds for array with length %zu", \
|
339
349
|
index, length); \
|
340
350
|
} else if (!SM_IS_A(sm_value, ELEM_TYPE)) { \
|
341
351
|
rb_raise(rb_eTypeError, \
|
@@ -354,7 +364,7 @@ static VALUE sm_##ELEM_TYPE##_array_store(VALUE sm_self, VALUE sm_index, VALUE s
|
|
354
364
|
\
|
355
365
|
static VALUE sm_##ELEM_TYPE##_array_size(VALUE sm_self) \
|
356
366
|
{ \
|
357
|
-
|
367
|
+
size_t length = NUM2SIZET(sm_mathtype_array_length(sm_self)); \
|
358
368
|
return SIZET2NUM(length * sizeof(ELEM_TYPE##_t)); \
|
359
369
|
}
|
360
370
|
|
@@ -7,6 +7,7 @@ module Snow
|
|
7
7
|
if const_defined?(klass_sym)
|
8
8
|
const_get(klass_sym).class_exec {
|
9
9
|
alias_method :__fetch__, :fetch
|
10
|
+
alias_method :__resize__!, :resize!
|
10
11
|
alias_method :__array_cache_initialize__, :initialize
|
11
12
|
|
12
13
|
def initialize(*args)
|
@@ -19,6 +20,21 @@ module Snow
|
|
19
20
|
end
|
20
21
|
|
21
22
|
alias_method :[], :fetch
|
23
|
+
|
24
|
+
def resize!(new_length)
|
25
|
+
@__cache__ = []
|
26
|
+
__resize__!(new_length)
|
27
|
+
end
|
28
|
+
|
29
|
+
def resize(new_length)
|
30
|
+
arr = self.class.new(new_length)
|
31
|
+
self_length = self.length
|
32
|
+
(0 ... (self_length < new_length ? self_length : new_length)).each {
|
33
|
+
|index|
|
34
|
+
arr.store(index, self.fetch(index))
|
35
|
+
}
|
36
|
+
return arr
|
37
|
+
end
|
22
38
|
}
|
23
39
|
end
|
24
40
|
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snow-math
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noel Raymond Cower
|
@@ -15,7 +15,9 @@ email: ncower@gmail.com
|
|
15
15
|
executables: []
|
16
16
|
extensions:
|
17
17
|
- ext/extconf.rb
|
18
|
-
extra_rdoc_files:
|
18
|
+
extra_rdoc_files:
|
19
|
+
- README.md
|
20
|
+
- COPYING
|
19
21
|
files:
|
20
22
|
- lib/snow-math/array_cache.rb
|
21
23
|
- lib/snow-math/inspect.rb
|
@@ -39,6 +41,8 @@ files:
|
|
39
41
|
- ext/snow-math/vec4.c
|
40
42
|
- ext/snow-math/maths_local.h
|
41
43
|
- ext/extconf.rb
|
44
|
+
- COPYING
|
45
|
+
- README.md
|
42
46
|
homepage: https://github.com/nilium/ruby-snowmath
|
43
47
|
licenses:
|
44
48
|
- Simplified BSD
|
@@ -69,4 +73,4 @@ signing_key:
|
|
69
73
|
specification_version: 4
|
70
74
|
summary: Snow Math Types
|
71
75
|
test_files: []
|
72
|
-
has_rdoc:
|
76
|
+
has_rdoc: true
|