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