raylib-bindings 0.1.4 → 0.3.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.
Binary file
data/lib/raylib.rb CHANGED
@@ -1,178 +1,59 @@
1
- # Yet another raylib wrapper for Ruby
2
- #
3
- # * https://github.com/vaiorabbit/raylib-bindings
4
-
5
- require 'ffi'
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'
12
-
13
- module Raylib
14
-
15
- extend FFI::Library
16
-
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)
83
-
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
111
-
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
119
- end
120
-
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
153
- end
154
-
155
- #
156
- # Generate sample code
157
- #
158
- def self.template
159
- # 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'
162
- unless File.exist? template_code_src
163
- $stderr.puts "[Error] Raylib.template : Template source #{template_code_src} not found"
164
- return false
165
- end
166
-
167
- template_code_dst = Dir.getwd + '/template.rb'
168
- if File.exist? template_code_dst
169
- $stderr.puts "[Error] Raylib.template : Template destination #{template_code_dst} already exists"
170
- return false
171
- end
172
-
173
- $stderr.puts "[Info] Raylib.template : #{template_code_src} => #{template_code_dst}"
174
- FileUtils.copy template_code_src, template_code_dst
175
- $stderr.puts "[Info] Raylib.template : Done"
176
- end
177
-
178
- end
1
+ # Yet another raylib wrapper for Ruby
2
+ #
3
+ # * https://github.com/vaiorabbit/raylib-bindings
4
+
5
+ require 'ffi'
6
+ require 'fileutils'
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'
14
+
15
+ module Raylib
16
+ extend FFI::Library
17
+
18
+ def self.load_lib(libpath, raygui_libpath: nil, physac_libpath: nil)
19
+ lib_paths = [libpath, raygui_libpath, physac_libpath].compact
20
+
21
+ ffi_lib_flags :now, :global
22
+ ffi_lib(*lib_paths)
23
+ setup_symbols
24
+
25
+ setup_raygui_symbols unless raygui_libpath.nil?
26
+ setup_physac_symbols unless physac_libpath.nil?
27
+ rescue LoadError => e
28
+ warn e
29
+ end
30
+
31
+ def self.setup_symbols
32
+ setup_raylib_symbols
33
+ setup_raymath_symbols
34
+ setup_rlgl_symbols
35
+ end
36
+
37
+ #
38
+ # Generate sample code
39
+ #
40
+ def self.template
41
+ # Copy template code to user's current directory
42
+ example_path = "#{Gem::Specification.find_by_name('raylib-bindings').full_gem_path}/examples"
43
+ template_code_src = "#{example_path}/template.rb"
44
+ unless File.exist? template_code_src
45
+ warn "[Error] Raylib.template : Template source #{template_code_src} not found"
46
+ return false
47
+ end
48
+
49
+ template_code_dst = "#{Dir.getwd}/template.rb"
50
+ if File.exist? template_code_dst
51
+ warn "[Error] Raylib.template : Template destination #{template_code_dst} already exists"
52
+ return false
53
+ end
54
+
55
+ warn "[Info] Raylib.template : #{template_code_src} => #{template_code_dst}"
56
+ FileUtils.copy template_code_src, template_code_dst
57
+ warn '[Info] Raylib.template : Done'
58
+ end
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