raylib-bindings 0.7.9-x86_64-darwin → 0.7.10-x86_64-darwin

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