raylib-bindings 0.7.8-x64-mingw → 0.7.10-x64-mingw

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.
data/lib/raylib_helper.rb CHANGED
@@ -1,415 +1,431 @@
1
- # Yet another raylib wrapper for Ruby
2
- #
3
- # * https://github.com/vaiorabbit/raylib-bindings
4
-
5
- module Raylib
6
- #
7
- # Color helper
8
- #
9
-
10
- class Color
11
- def self.from_u8(r = 0, g = 0, b = 0, a = 255)
12
- Color.new.set(r, g, b, a)
13
- end
14
-
15
- def set(r, g, b, a)
16
- self[:r] = r
17
- self[:g] = g
18
- self[:b] = b
19
- self[:a] = a
20
- self
21
- end
22
-
23
- def copy(other)
24
- self[:r] = other.r
25
- self[:g] = other.g
26
- self[:b] = other.b
27
- self[:a] = other.a
28
- self
29
- end
30
- end
31
-
32
- LIGHTGRAY = Color.from_u8(200, 200, 200, 255)
33
- GRAY = Color.from_u8(130, 130, 130, 255)
34
- DARKGRAY = Color.from_u8(80, 80, 80, 255)
35
- YELLOW = Color.from_u8(253, 249, 0, 255)
36
- GOLD = Color.from_u8(255, 203, 0, 255)
37
- ORANGE = Color.from_u8(255, 161, 0, 255)
38
- PINK = Color.from_u8(255, 109, 194, 255)
39
- RED = Color.from_u8(230, 41, 55, 255)
40
- MAROON = Color.from_u8(190, 33, 55, 255)
41
- GREEN = Color.from_u8(0, 228, 48, 255)
42
- LIME = Color.from_u8(0, 158, 47, 255)
43
- DARKGREEN = Color.from_u8(0, 117, 44, 255)
44
- SKYBLUE = Color.from_u8(102, 191, 255, 255)
45
- BLUE = Color.from_u8(0, 121, 241, 255)
46
- DARKBLUE = Color.from_u8(0, 82, 172, 255)
47
- PURPLE = Color.from_u8(200, 122, 255, 255)
48
- VIOLET = Color.from_u8(135, 60, 190, 255)
49
- DARKPURPLE = Color.from_u8(112, 31, 126, 255)
50
- BEIGE = Color.from_u8(211, 176, 131, 255)
51
- BROWN = Color.from_u8(127, 106, 79, 255)
52
- DARKBROWN = Color.from_u8(76, 63, 47, 255)
53
-
54
- WHITE = Color.from_u8(255, 255, 255, 255)
55
- BLACK = Color.from_u8(0, 0, 0, 255)
56
- BLANK = Color.from_u8(0, 0, 0, 0)
57
- MAGENTA = Color.from_u8(255, 0, 255, 255)
58
- RAYWHITE = Color.from_u8(245, 245, 245, 255)
59
-
60
- #
61
- # Math helper
62
- #
63
-
64
- DEG2RAD = Math::PI / 180.0
65
- RAD2DEG = 180.0 / Math::PI
66
-
67
- class Vector2
68
- def self.create(x = 0, y = 0)
69
- Vector2.new.set(x, y)
70
- end
71
-
72
- def self.copy_from(vec)
73
- Vector2.create(vec[:x], vec[:y])
74
- end
75
-
76
- def set(x, y)
77
- self[:x] = x
78
- self[:y] = y
79
- self
80
- end
81
-
82
- def add(x, y)
83
- self[:x] = self[:x] + x
84
- self[:y] = self[:y] + y
85
- self
86
- end
87
-
88
- def add_vector(v)
89
- self[:x] = self[:x] + v[:x]
90
- self[:y] = self[:y] + v[:y]
91
- self
92
- end
93
-
94
- def to_a
95
- [x, y]
96
- end
97
- end
98
-
99
- class Vector3
100
- def self.create(x = 0, y = 0, z = 0)
101
- Vector3.new.set(x, y, z)
102
- end
103
-
104
- def self.copy_from(vec)
105
- Vector3.create(vec[:x], vec[:y], vec[:z])
106
- end
107
-
108
- def set(x, y, z)
109
- self[:x] = x
110
- self[:y] = y
111
- self[:z] = z
112
- self
113
- end
114
-
115
- def to_a
116
- [x, y, z]
117
- end
118
- end
119
-
120
- class Vector4
121
- def self.create(x = 0, y = 0, z = 0, w = 0)
122
- Vector4.new.set(x, y, z, w)
123
- end
124
-
125
- def self.copy_from(vec)
126
- Vector4.create(vec[:x], vec[:y], vec[:z], vec[:w])
127
- end
128
-
129
- def set(x, y, z, w)
130
- self[:x] = x
131
- self[:y] = y
132
- self[:z] = z
133
- self[:w] = w
134
- self
135
- end
136
-
137
- def to_a
138
- [x, y, z, w]
139
- end
140
- end
141
-
142
- class Quaternion
143
- def self.create(x = 0, y = 0, z = 0, w = 0)
144
- Quaternion.new.set(x, y, z, w)
145
- end
146
-
147
- def self.copy_from(quat)
148
- Quaternion.create(quat[:x], quat[:y], quat[:z], quat[:w])
149
- end
150
-
151
- def set(x, y, z, w)
152
- self[:x] = x
153
- self[:y] = y
154
- self[:z] = z
155
- self[:w] = w
156
- self
157
- end
158
-
159
- def to_a
160
- [x, y, z, w]
161
- end
162
- end
163
-
164
- class Rectangle
165
- def self.create(x = 0, y = 0, width = 0, height = 0)
166
- Rectangle.new.set(x, y, width, height)
167
- end
168
-
169
- def set(x, y, width, height)
170
- self[:x] = x
171
- self[:y] = y
172
- self[:width] = width
173
- self[:height] = height
174
- self
175
- end
176
- end
177
-
178
- class BoundingBox
179
- def self.create(*args)
180
- case args.size
181
- when 2
182
- instance = BoundingBox.new
183
- instance[:min] = args[0] # min
184
- instance[:max] = args[1] # max
185
- instance
186
- when 6
187
- instance = BoundingBox.new
188
- instance[:min] = Vector3.create(args[0], args[1], args[2]) # min_x, min_y, min_z
189
- instance[:max] = Vector3.create(args[3], args[4], args[5]) # max_x, max_y, max_z
190
- instance
191
- else
192
- raise ArgumentError.new 'BoundingBox.create : Number of arguments must be 2 or 6'
193
- end
194
- end
195
-
196
- def with_min(x, y, z)
197
- self[:min].set(x, y, z)
198
- self
199
- end
200
-
201
- def with_max(x, y, z)
202
- self[:max].set(x, y, z)
203
- self
204
- end
205
- end
206
-
207
- def Vector3ToFloat(vec)
208
- Vector3ToFloatV(vec)[:v].to_a
209
- end
210
-
211
- def MatrixToFloat(mat)
212
- MatrixToFloatV(mat)[:v].to_a
213
- end
214
-
215
- #
216
- # Camera helper
217
- #
218
-
219
- class Camera3D
220
- def with_position(x, y, z)
221
- self[:position].set(x, y, z)
222
- self
223
- end
224
-
225
- def with_target(x, y, z)
226
- self[:target].set(x, y, z)
227
- self
228
- end
229
-
230
- def with_up(x, y, z)
231
- self[:up].set(x, y, z)
232
- self
233
- end
234
-
235
- def with_fovy(fovy)
236
- self[:fovy] = fovy
237
- self
238
- end
239
-
240
- def with_projection(projection)
241
- self[:projection] = projection
242
- self
243
- end
244
- end
245
-
246
- class Camera2D
247
- def with_offset(x, y)
248
- self[:offset].set(x, y)
249
- self
250
- end
251
-
252
- def with_target(x, y)
253
- self[:target].set(x, y)
254
- self
255
- end
256
-
257
- def with_rotation(rotation)
258
- self[:rotation] = rotation
259
- self
260
- end
261
-
262
- def with_zoom(zoom)
263
- self[:zoom] = zoom
264
- self
265
- end
266
- end
267
-
268
- #
269
- # Transform helper
270
- #
271
-
272
- class Transform
273
- def t = self[:translation]
274
- def r = self[:rotation]
275
- def s = self[:scale]
276
- end
277
-
278
- #
279
- # Model helper
280
- #
281
-
282
- # DrawModelEx : Draw a model with extended parameters
283
- # @param model [Model]
284
- # @param position [Vector3]
285
- # @param rotationAxis [Vector3]
286
- # @param rotationAngle [float]
287
- # @param scale [Vector3]
288
- # @param tint [Color]
289
- # @return [void]
290
- def DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint)
291
- # [NOTE] Fixing unintended matrix modification
292
- # - In C, DrawModelEx uses the whole copy of `model` on stack, which will never affect the content of original `model`.
293
- # But Ruby FFI seems to pass the reference of `model` to DrawModelEx, which results in transform accumulation (e.g.:`model` get rotated by `rotationAngle` around `rotationAxis` every frame).
294
- # So here I copy the transform into `mtx_clone` and copy back this to the original after finished calling DrawModelEx.
295
- # - Other DrawXXX members (DrawModel, DrawModelWires, DrawModelWiresEx) are free from this problem.
296
- # - They call DrawModelEx in C layer, which will use the copy of `model` on stack.
297
- mtx_clone = model[:transform].clone
298
- internalDrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint)
299
- model[:transform] = mtx_clone
300
- end
301
-
302
- class Model
303
- # GetModelMaterial (ruby raylib original)
304
- # @param index [int] 0 ~ materialCount
305
- # @return [Material]
306
- def material(index = 0)
307
- Material.new(self[:materials] + index * Material.size)
308
- end
309
-
310
- # GetModelMaterialCount (ruby raylib original)
311
- # @return [int]
312
- def material_count
313
- self[:materialCount]
314
- end
315
-
316
- # GetModelBoneCount (ruby raylib original)
317
- # @return [int]
318
- def bone_count
319
- self[:boneCount]
320
- end
321
-
322
- # @return BoneInfo
323
- def bone_info(index)
324
- BoneInfo.new(self[:bones] + index * BoneInfo.size)
325
- end
326
-
327
- # @return Transform
328
- def bind_pose_transform(index)
329
- Transform.new(self[:bindPose] + index * Transform.size)
330
- end
331
- end
332
-
333
- class BoneInfo
334
- def parent_bone_index
335
- self[:parent]
336
- end
337
- end
338
-
339
- #
340
- # ModelAnimation helper
341
- #
342
-
343
- # Manages a set of ModelAnimation (ruby raylib original)
344
- class ModelAnimations
345
- attr_reader :anims, :anim_ptrs
346
-
347
- def initialize
348
- @anims = nil
349
- @anim_ptrs = nil
350
- @framePoses = nil # array of Transform**
351
- end
352
-
353
- def anim(index) = @anims[index]
354
- def anims_count = @anims.length
355
- def frame_count(index) = @anims[index][:frameCount]
356
-
357
- # @return BoneInfo
358
- def bone_info(anim_index, bone_index)
359
- BoneInfo.new(@anims[anim_index][:bones] + bone_index * BoneInfo.size)
360
- end
361
-
362
- # @return Transform*
363
- def frame_pose(index, frame)
364
- @framePoses[index] + frame * FFI::NativeType::POINTER.size # Transform*
365
- end
366
-
367
- # @return Transform
368
- def bone_transform(frame_pose, bone_index)
369
- Transform.new(frame_pose.read_pointer + bone_index * Transform.size)
370
- end
371
-
372
- # @return Transform
373
- def bone_transform_of_frame_pose(anim_index, frame, bone_index)
374
- bone_transform(frame_pose(anim_index, frame), bone_index)
375
- end
376
-
377
- # @return self
378
- def setup(fileName)
379
- @anims, @anim_ptrs = LoadAndAllocateModelAnimations(fileName)
380
- @framePoses = []
381
- @anims.each do |anim|
382
- @framePoses << anim[:framePoses]
383
- end
384
- self
385
- end
386
-
387
- def cleanup
388
- UnloadAndFreeModelAnimations(@anims, @anim_ptrs)
389
- end
390
- end
391
-
392
- # LoadAndAllocateModelAnimations : (ruby raylib original)
393
- # @param fileName [const char *]
394
- # @return array of ModelAnimation and pointer to loaded memory
395
- def LoadAndAllocateModelAnimations(fileName)
396
- animsCount_buf = FFI::MemoryPointer.new(:uint, 1)
397
- anim_ptrs = LoadModelAnimations(fileName, animsCount_buf)
398
- animsCount = animsCount_buf.read_uint
399
- anims = animsCount.times.map do |i|
400
- ModelAnimation.new(anim_ptrs + i * ModelAnimation.size)
401
- end
402
- return anims, anim_ptrs
403
- end
404
-
405
- # UnloadAndFreeModelAnimations : (ruby raylib original)
406
- # @param anims [array of ModelAnimation]
407
- # @param anim_ptrs [pointer to loaded memory]
408
- def UnloadAndFreeModelAnimations(anims, anim_ptrs)
409
- anims.each do |anim|
410
- UnloadModelAnimation(anim)
411
- end
412
- MemFree(anim_ptrs)
413
- end
414
-
415
- end
1
+ # Yet another raylib wrapper for Ruby
2
+ #
3
+ # * https://github.com/vaiorabbit/raylib-bindings
4
+
5
+ module Raylib
6
+ #
7
+ # Color helper
8
+ #
9
+
10
+ class Color
11
+ def self.from_u8(r = 0, g = 0, b = 0, a = 255)
12
+ Color.new.set(r, g, b, a)
13
+ end
14
+
15
+ def self.from_u32(rgba = 255)
16
+ r = (rgba >> 24) & 0xFF
17
+ g = (rgba >> 16) & 0xFF
18
+ b = (rgba >> 8) & 0xFF
19
+ a = (rgba >> 0) & 0xFF
20
+ Color.new.set(r, g, b, a)
21
+ end
22
+
23
+ def set(r, g, b, a)
24
+ self[:r] = r
25
+ self[:g] = g
26
+ self[:b] = b
27
+ self[:a] = a
28
+ self
29
+ end
30
+
31
+ def self.set(rgba)
32
+ self[:r] = (rgba >> 24) & 0xFF
33
+ self[:g] = (rgba >> 16) & 0xFF
34
+ self[:b] = (rgba >> 8) & 0xFF
35
+ self[:a] = (rgba >> 0) & 0xFF
36
+ self
37
+ end
38
+
39
+ def copy(other)
40
+ self[:r] = other.r
41
+ self[:g] = other.g
42
+ self[:b] = other.b
43
+ self[:a] = other.a
44
+ self
45
+ end
46
+ end
47
+
48
+ LIGHTGRAY = Color.from_u8(200, 200, 200, 255)
49
+ GRAY = Color.from_u8(130, 130, 130, 255)
50
+ DARKGRAY = Color.from_u8(80, 80, 80, 255)
51
+ YELLOW = Color.from_u8(253, 249, 0, 255)
52
+ GOLD = Color.from_u8(255, 203, 0, 255)
53
+ ORANGE = Color.from_u8(255, 161, 0, 255)
54
+ PINK = Color.from_u8(255, 109, 194, 255)
55
+ RED = Color.from_u8(230, 41, 55, 255)
56
+ MAROON = Color.from_u8(190, 33, 55, 255)
57
+ GREEN = Color.from_u8(0, 228, 48, 255)
58
+ LIME = Color.from_u8(0, 158, 47, 255)
59
+ DARKGREEN = Color.from_u8(0, 117, 44, 255)
60
+ SKYBLUE = Color.from_u8(102, 191, 255, 255)
61
+ BLUE = Color.from_u8(0, 121, 241, 255)
62
+ DARKBLUE = Color.from_u8(0, 82, 172, 255)
63
+ PURPLE = Color.from_u8(200, 122, 255, 255)
64
+ VIOLET = Color.from_u8(135, 60, 190, 255)
65
+ DARKPURPLE = Color.from_u8(112, 31, 126, 255)
66
+ BEIGE = Color.from_u8(211, 176, 131, 255)
67
+ BROWN = Color.from_u8(127, 106, 79, 255)
68
+ DARKBROWN = Color.from_u8(76, 63, 47, 255)
69
+
70
+ WHITE = Color.from_u8(255, 255, 255, 255)
71
+ BLACK = Color.from_u8(0, 0, 0, 255)
72
+ BLANK = Color.from_u8(0, 0, 0, 0)
73
+ MAGENTA = Color.from_u8(255, 0, 255, 255)
74
+ RAYWHITE = Color.from_u8(245, 245, 245, 255)
75
+
76
+ #
77
+ # Math helper
78
+ #
79
+
80
+ DEG2RAD = Math::PI / 180.0
81
+ RAD2DEG = 180.0 / Math::PI
82
+
83
+ class Vector2
84
+ def self.create(x = 0, y = 0)
85
+ Vector2.new.set(x, y)
86
+ end
87
+
88
+ def self.copy_from(vec)
89
+ Vector2.create(vec[:x], vec[:y])
90
+ end
91
+
92
+ def set(x, y)
93
+ self[:x] = x
94
+ self[:y] = y
95
+ self
96
+ end
97
+
98
+ def add(x, y)
99
+ self[:x] = self[:x] + x
100
+ self[:y] = self[:y] + y
101
+ self
102
+ end
103
+
104
+ def add_vector(v)
105
+ self[:x] = self[:x] + v[:x]
106
+ self[:y] = self[:y] + v[:y]
107
+ self
108
+ end
109
+
110
+ def to_a
111
+ [x, y]
112
+ end
113
+ end
114
+
115
+ class Vector3
116
+ def self.create(x = 0, y = 0, z = 0)
117
+ Vector3.new.set(x, y, z)
118
+ end
119
+
120
+ def self.copy_from(vec)
121
+ Vector3.create(vec[:x], vec[:y], vec[:z])
122
+ end
123
+
124
+ def set(x, y, z)
125
+ self[:x] = x
126
+ self[:y] = y
127
+ self[:z] = z
128
+ self
129
+ end
130
+
131
+ def to_a
132
+ [x, y, z]
133
+ end
134
+ end
135
+
136
+ class Vector4
137
+ def self.create(x = 0, y = 0, z = 0, w = 0)
138
+ Vector4.new.set(x, y, z, w)
139
+ end
140
+
141
+ def self.copy_from(vec)
142
+ Vector4.create(vec[:x], vec[:y], vec[:z], vec[:w])
143
+ end
144
+
145
+ def set(x, y, z, w)
146
+ self[:x] = x
147
+ self[:y] = y
148
+ self[:z] = z
149
+ self[:w] = w
150
+ self
151
+ end
152
+
153
+ def to_a
154
+ [x, y, z, w]
155
+ end
156
+ end
157
+
158
+ class Quaternion
159
+ def self.create(x = 0, y = 0, z = 0, w = 0)
160
+ Quaternion.new.set(x, y, z, w)
161
+ end
162
+
163
+ def self.copy_from(quat)
164
+ Quaternion.create(quat[:x], quat[:y], quat[:z], quat[:w])
165
+ end
166
+
167
+ def set(x, y, z, w)
168
+ self[:x] = x
169
+ self[:y] = y
170
+ self[:z] = z
171
+ self[:w] = w
172
+ self
173
+ end
174
+
175
+ def to_a
176
+ [x, y, z, w]
177
+ end
178
+ end
179
+
180
+ class Rectangle
181
+ def self.create(x = 0, y = 0, width = 0, height = 0)
182
+ Rectangle.new.set(x, y, width, height)
183
+ end
184
+
185
+ def set(x, y, width, height)
186
+ self[:x] = x
187
+ self[:y] = y
188
+ self[:width] = width
189
+ self[:height] = height
190
+ self
191
+ end
192
+ end
193
+
194
+ class BoundingBox
195
+ def self.create(*args)
196
+ case args.size
197
+ when 2
198
+ instance = BoundingBox.new
199
+ instance[:min] = args[0] # min
200
+ instance[:max] = args[1] # max
201
+ instance
202
+ when 6
203
+ instance = BoundingBox.new
204
+ instance[:min] = Vector3.create(args[0], args[1], args[2]) # min_x, min_y, min_z
205
+ instance[:max] = Vector3.create(args[3], args[4], args[5]) # max_x, max_y, max_z
206
+ instance
207
+ else
208
+ raise ArgumentError.new 'BoundingBox.create : Number of arguments must be 2 or 6'
209
+ end
210
+ end
211
+
212
+ def with_min(x, y, z)
213
+ self[:min].set(x, y, z)
214
+ self
215
+ end
216
+
217
+ def with_max(x, y, z)
218
+ self[:max].set(x, y, z)
219
+ self
220
+ end
221
+ end
222
+
223
+ def Vector3ToFloat(vec)
224
+ Vector3ToFloatV(vec)[:v].to_a
225
+ end
226
+
227
+ def MatrixToFloat(mat)
228
+ MatrixToFloatV(mat)[:v].to_a
229
+ end
230
+
231
+ #
232
+ # Camera helper
233
+ #
234
+
235
+ class Camera3D
236
+ def with_position(x, y, z)
237
+ self[:position].set(x, y, z)
238
+ self
239
+ end
240
+
241
+ def with_target(x, y, z)
242
+ self[:target].set(x, y, z)
243
+ self
244
+ end
245
+
246
+ def with_up(x, y, z)
247
+ self[:up].set(x, y, z)
248
+ self
249
+ end
250
+
251
+ def with_fovy(fovy)
252
+ self[:fovy] = fovy
253
+ self
254
+ end
255
+
256
+ def with_projection(projection)
257
+ self[:projection] = projection
258
+ self
259
+ end
260
+ end
261
+
262
+ class Camera2D
263
+ def with_offset(x, y)
264
+ self[:offset].set(x, y)
265
+ self
266
+ end
267
+
268
+ def with_target(x, y)
269
+ self[:target].set(x, y)
270
+ self
271
+ end
272
+
273
+ def with_rotation(rotation)
274
+ self[:rotation] = rotation
275
+ self
276
+ end
277
+
278
+ def with_zoom(zoom)
279
+ self[:zoom] = zoom
280
+ self
281
+ end
282
+ end
283
+
284
+ #
285
+ # Transform helper
286
+ #
287
+
288
+ class Transform
289
+ def t = self[:translation]
290
+ def r = self[:rotation]
291
+ def s = self[:scale]
292
+ end
293
+
294
+ #
295
+ # Model helper
296
+ #
297
+
298
+ # DrawModelEx : Draw a model with extended parameters
299
+ # @param model [Model]
300
+ # @param position [Vector3]
301
+ # @param rotationAxis [Vector3]
302
+ # @param rotationAngle [float]
303
+ # @param scale [Vector3]
304
+ # @param tint [Color]
305
+ # @return [void]
306
+ def DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint)
307
+ # [NOTE] Fixing unintended matrix modification
308
+ # - In C, DrawModelEx uses the whole copy of `model` on stack, which will never affect the content of original `model`.
309
+ # But Ruby FFI seems to pass the reference of `model` to DrawModelEx, which results in transform accumulation (e.g.:`model` get rotated by `rotationAngle` around `rotationAxis` every frame).
310
+ # So here I copy the transform into `mtx_clone` and copy back this to the original after finished calling DrawModelEx.
311
+ # - Other DrawXXX members (DrawModel, DrawModelWires, DrawModelWiresEx) are free from this problem.
312
+ # - They call DrawModelEx in C layer, which will use the copy of `model` on stack.
313
+ mtx_clone = model[:transform].clone
314
+ internalDrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint)
315
+ model[:transform] = mtx_clone
316
+ end
317
+
318
+ class Model
319
+ # GetModelMaterial (ruby raylib original)
320
+ # @param index [int] 0 ~ materialCount
321
+ # @return [Material]
322
+ def material(index = 0)
323
+ Material.new(self[:materials] + index * Material.size)
324
+ end
325
+
326
+ # GetModelMaterialCount (ruby raylib original)
327
+ # @return [int]
328
+ def material_count
329
+ self[:materialCount]
330
+ end
331
+
332
+ # GetModelBoneCount (ruby raylib original)
333
+ # @return [int]
334
+ def bone_count
335
+ self[:boneCount]
336
+ end
337
+
338
+ # @return BoneInfo
339
+ def bone_info(index)
340
+ BoneInfo.new(self[:bones] + index * BoneInfo.size)
341
+ end
342
+
343
+ # @return Transform
344
+ def bind_pose_transform(index)
345
+ Transform.new(self[:bindPose] + index * Transform.size)
346
+ end
347
+ end
348
+
349
+ class BoneInfo
350
+ def parent_bone_index
351
+ self[:parent]
352
+ end
353
+ end
354
+
355
+ #
356
+ # ModelAnimation helper
357
+ #
358
+
359
+ # Manages a set of ModelAnimation (ruby raylib original)
360
+ class ModelAnimations
361
+ attr_reader :anims, :anim_ptrs
362
+
363
+ def initialize
364
+ @anims = nil
365
+ @anim_ptrs = nil
366
+ @framePoses = nil # array of Transform**
367
+ end
368
+
369
+ def anim(index) = @anims[index]
370
+ def anims_count = @anims.length
371
+ def frame_count(index) = @anims[index][:frameCount]
372
+
373
+ # @return BoneInfo
374
+ def bone_info(anim_index, bone_index)
375
+ BoneInfo.new(@anims[anim_index][:bones] + bone_index * BoneInfo.size)
376
+ end
377
+
378
+ # @return Transform*
379
+ def frame_pose(index, frame)
380
+ @framePoses[index] + frame * FFI::NativeType::POINTER.size # Transform*
381
+ end
382
+
383
+ # @return Transform
384
+ def bone_transform(frame_pose, bone_index)
385
+ Transform.new(frame_pose.read_pointer + bone_index * Transform.size)
386
+ end
387
+
388
+ # @return Transform
389
+ def bone_transform_of_frame_pose(anim_index, frame, bone_index)
390
+ bone_transform(frame_pose(anim_index, frame), bone_index)
391
+ end
392
+
393
+ # @return self
394
+ def setup(fileName)
395
+ @anims, @anim_ptrs = LoadAndAllocateModelAnimations(fileName)
396
+ @framePoses = []
397
+ @anims.each do |anim|
398
+ @framePoses << anim[:framePoses]
399
+ end
400
+ self
401
+ end
402
+
403
+ def cleanup
404
+ UnloadAndFreeModelAnimations(@anims, @anim_ptrs)
405
+ end
406
+ end
407
+
408
+ # LoadAndAllocateModelAnimations : (ruby raylib original)
409
+ # @param fileName [const char *]
410
+ # @return array of ModelAnimation and pointer to loaded memory
411
+ def LoadAndAllocateModelAnimations(fileName)
412
+ animsCount_buf = FFI::MemoryPointer.new(:uint, 1)
413
+ anim_ptrs = LoadModelAnimations(fileName, animsCount_buf)
414
+ animsCount = animsCount_buf.read_uint
415
+ anims = animsCount.times.map do |i|
416
+ ModelAnimation.new(anim_ptrs + i * ModelAnimation.size)
417
+ end
418
+ return anims, anim_ptrs
419
+ end
420
+
421
+ # UnloadAndFreeModelAnimations : (ruby raylib original)
422
+ # @param anims [array of ModelAnimation]
423
+ # @param anim_ptrs [pointer to loaded memory]
424
+ def UnloadAndFreeModelAnimations(anims, anim_ptrs)
425
+ anims.each do |anim|
426
+ UnloadModelAnimation(anim)
427
+ end
428
+ MemFree(anim_ptrs)
429
+ end
430
+
431
+ end