raylib-bindings 0.1.4 → 0.3.0

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