processing 0.4.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/{release.yml → release-gem.yml} +21 -21
  3. data/.github/workflows/tag.yml +35 -0
  4. data/.github/workflows/test.yml +8 -9
  5. data/.github/workflows/utils.rb +55 -0
  6. data/ChangeLog.md +40 -28
  7. data/LICENSE +1 -1
  8. data/Rakefile +9 -34
  9. data/RubyProcessing.podspec +1 -1
  10. data/VERSION +1 -1
  11. data/examples/breakout.rb +2 -1
  12. data/examples/camera.rb +2 -1
  13. data/examples/clock.rb +3 -1
  14. data/examples/delay_camera.rb +2 -1
  15. data/examples/hello.rb +2 -1
  16. data/examples/image.rb +2 -1
  17. data/examples/shapes.rb +2 -1
  18. data/lib/processing/all.rb +20 -0
  19. data/lib/processing/capture.rb +119 -0
  20. data/lib/processing/context.rb +471 -0
  21. data/lib/processing/{module.rb → extension.rb} +3 -3
  22. data/lib/processing/font.rb +62 -0
  23. data/lib/processing/graphics.rb +40 -0
  24. data/lib/processing/graphics_context.rb +1676 -0
  25. data/lib/processing/image.rb +128 -0
  26. data/lib/processing/shader.rb +157 -0
  27. data/lib/processing/touch.rb +28 -0
  28. data/lib/processing/vector.rb +559 -0
  29. data/lib/processing.rb +30 -11
  30. data/lib/rubysketch-processing.rb +2 -1
  31. data/lib/rubysketch.rb +1 -1
  32. data/processing.gemspec +12 -6
  33. data/src/RubyProcessing.mm +1 -1
  34. data/test/helper.rb +8 -2
  35. data/test/{processing/test_graphics.rb → test_graphics.rb} +3 -3
  36. data/test/{processing/test_shader.rb → test_shader.rb} +3 -3
  37. data/test/{processing/test_utility.rb → test_utility.rb} +3 -3
  38. data/test/{processing/test_vector.rb → test_vector.rb} +8 -4
  39. metadata +112 -20
  40. data/lib/processing/include.rb +0 -25
  41. data/lib/processing/processing.rb +0 -3211
  42. data/test/processing/helper.rb +0 -11
@@ -0,0 +1,119 @@
1
+ module Processing
2
+
3
+
4
+ # Camera object.
5
+ #
6
+ class Capture
7
+
8
+ # Returns a list of available camera device names
9
+ #
10
+ # @return [Array] device name list
11
+ #
12
+ def self.list()
13
+ Rays::Camera.device_names
14
+ end
15
+
16
+ # Initialize camera object.
17
+ #
18
+ # @overload Capture.new()
19
+ # @overload Capture.new(cameraName)
20
+ # @overload Capture.new(requestWidth, requestHeight)
21
+ # @overload Capture.new(requestWidth, requestHeight, cameraName)
22
+ #
23
+ # @param requestWidth [Integer] captured image width
24
+ # @param requestHeight [Integer] captured image height
25
+ # @param cameraName [String] camera device name
26
+ #
27
+ def initialize(*args)
28
+ width, height, name =
29
+ if args.empty?
30
+ [-1, -1, nil]
31
+ elsif args[0].kind_of?(String)
32
+ [-1, -1, args[0]]
33
+ elsif args[0].kind_of?(Numeric) && args[1].kind_of?(Numeric)
34
+ [args[0], args[1], args[2]]
35
+ else
36
+ raise ArgumentError
37
+ end
38
+ @camera = Rays::Camera.new width, height, device_name: name
39
+ end
40
+
41
+ # Start capturing.
42
+ #
43
+ # @return [nil] nil
44
+ #
45
+ def start()
46
+ raise "Failed to start capture" unless @camera.start
47
+ nil
48
+ end
49
+
50
+ # Stop capturing.
51
+ #
52
+ # @return [nil] nil
53
+ #
54
+ def stop()
55
+ @camera.stop
56
+ nil
57
+ end
58
+
59
+ # Returns is the next captured image available?
60
+ #
61
+ # @return [Boolean] true means object has next frame
62
+ #
63
+ def available()
64
+ @camera.active?
65
+ end
66
+
67
+ # Reads next frame image
68
+ #
69
+ def read()
70
+ @camera.image
71
+ end
72
+
73
+ # Returns the width of captured image
74
+ #
75
+ # @return [Numeric] the width of captured image
76
+ #
77
+ def width()
78
+ @camera.image&.width || 0
79
+ end
80
+
81
+ # Returns the height of captured image
82
+ #
83
+ # @return [Numeric] the height of captured image
84
+ #
85
+ def height()
86
+ @camera.image&.height || 0
87
+ end
88
+
89
+ # Applies an image filter.
90
+ #
91
+ # overload filter(shader)
92
+ # overload filter(type)
93
+ # overload filter(type, param)
94
+ #
95
+ # @param shader [Shader] a fragment shader to apply
96
+ # @param type [THRESHOLD, GRAY, INVERT, BLUR] filter type
97
+ # @param param [Numeric] a parameter for each filter
98
+ #
99
+ def filter(*args)
100
+ @filter = Shader.createFilter__(*args)
101
+ end
102
+
103
+ # @private
104
+ def getInternal__()
105
+ @camera.image || (@dummyImage ||= Rays::Image.new 1, 1)
106
+ end
107
+
108
+ # @private
109
+ def drawImage__(painter, *args, **states)
110
+ shader = painter.shader || @filter&.getInternal__
111
+ painter.push shader: shader, **states do |_|
112
+ painter.image getInternal__, *args
113
+ end
114
+ end
115
+
116
+ end# Capture
117
+
118
+
119
+ end# Processing
@@ -0,0 +1,471 @@
1
+ module Processing
2
+
3
+
4
+ # Processing context
5
+ #
6
+ class Context
7
+
8
+ include GraphicsContext
9
+
10
+ Vector = Processing::Vector
11
+ Capture = Processing::Capture
12
+ Graphics = Processing::Graphics
13
+ Shader = Processing::Shader
14
+
15
+ # @private
16
+ @@context__ = nil
17
+
18
+ # @private
19
+ def self.context__()
20
+ @@context__
21
+ end
22
+
23
+ # @private
24
+ def initialize(window)
25
+ @@context__ = self
26
+
27
+ tmpdir__.tap {|dir| FileUtils.rm_r dir.to_s if dir.directory?}
28
+
29
+ @window__ = window
30
+ init__(
31
+ @window__.canvas_image,
32
+ @window__.canvas_painter.paint {background 0.8})
33
+
34
+ @loop__ = true
35
+ @redraw__ = false
36
+ @frameCount__ = 0
37
+ @key__ = nil
38
+ @keyCode__ = nil
39
+ @keysPressed__ = Set.new
40
+ @pointerPos__ =
41
+ @pointerPrevPos__ = Rays::Point.new 0
42
+ @pointersPressed__ = []
43
+ @touches__ = []
44
+ @motionGravity__ = createVector 0, 0
45
+
46
+ @window__.before_draw = proc {beginDraw__}
47
+ @window__.after_draw = proc {endDraw__}
48
+ @window__.update_canvas = proc {|i, p| updateCanvas__ i, p}
49
+
50
+ @window__.instance_variable_set :@context, self
51
+ def @window__.draw_screen(painter)
52
+ @context.drawImage__ painter
53
+ end
54
+
55
+ drawFrame = -> {
56
+ begin
57
+ push
58
+ @drawBlock__.call if @drawBlock__
59
+ ensure
60
+ pop
61
+ @frameCount__ += 1
62
+ end
63
+ }
64
+
65
+ @window__.draw = proc do |e|
66
+ if @loop__ || @redraw__
67
+ @redraw__ = false
68
+ drawFrame.call
69
+ end
70
+ end
71
+
72
+ updateKeyStates = -> event, pressed {
73
+ @key__ = event.chars
74
+ @keyCode__ = event.key
75
+ if pressed != nil
76
+ set, key = @keysPressed__, event.key
77
+ pressed ? set.add(key) : set.delete(key)
78
+ end
79
+ }
80
+
81
+ mouseButtonMap = {
82
+ mouse_left: LEFT,
83
+ mouse_right: RIGHT,
84
+ mouse_middle: CENTER
85
+ }
86
+
87
+ updatePointerStates = -> event, pressed = nil {
88
+ @pointerPrevPos__ = @pointerPos__
89
+ @pointerPos__ = event.pos.dup
90
+ @touches__ = event.pointers.map {|p| Touch.new(p.id, *p.pos.to_a)}
91
+ if pressed != nil
92
+ array = @pointersPressed__
93
+ event.types
94
+ .tap {|types| types.delete :mouse}
95
+ .map {|type| mouseButtonMap[type] || type}
96
+ .each {|type| pressed ? array.push(type) : array.delete(type)}
97
+ end
98
+ }
99
+
100
+ @window__.key_down = proc do |e|
101
+ updateKeyStates.call e, true
102
+ @keyPressedBlock__&.call
103
+ @keyTypedBlock__&.call if @key__ && !@key__.empty?
104
+ end
105
+
106
+ @window__.key_up = proc do |e|
107
+ updateKeyStates.call e, false
108
+ @keyReleasedBlock__&.call
109
+ end
110
+
111
+ @window__.pointer_down = proc do |e|
112
+ updatePointerStates.call e, true
113
+ @pointerDownStartPos__ = @pointerPos__.dup
114
+ (@touchStartedBlock__ || @mousePressedBlock__)&.call
115
+ end
116
+
117
+ @window__.pointer_up = proc do |e|
118
+ updatePointerStates.call e, false
119
+ (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
120
+ if startPos = @pointerDownStartPos__
121
+ @mouseClickedBlock__&.call if (@pointerPos__ - startPos).length < 3
122
+ @pointerDownStartPos__ = nil
123
+ end
124
+ end
125
+
126
+ @window__.pointer_move = proc do |e|
127
+ updatePointerStates.call e
128
+ (@touchMovedBlock__ || @mouseMovedBlock__)&.call
129
+ end
130
+
131
+ @window__.pointer_drag = proc do |e|
132
+ updatePointerStates.call e
133
+ (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
134
+ end
135
+
136
+ @window__.motion = proc do |e|
137
+ @motionGravity__ = createVector(*e.gravity.to_a(3))
138
+ @motionBlock__&.call
139
+ end
140
+ end
141
+
142
+ # Defines setup block.
143
+ #
144
+ # @return [nil] nil
145
+ #
146
+ def setup(&block)
147
+ @window__.setup = block
148
+ nil
149
+ end
150
+
151
+ # Defines draw block.
152
+ #
153
+ # @return [nil] nil
154
+ #
155
+ def draw(&block)
156
+ @drawBlock__ = block if block
157
+ nil
158
+ end
159
+
160
+ # @private
161
+ def hasDrawBlock__()
162
+ @drawBlock__ != nil
163
+ end
164
+
165
+ # Defines keyPressed block.
166
+ #
167
+ # @return [Boolean] is any key pressed or not
168
+ #
169
+ def keyPressed(&block)
170
+ @keyPressedBlock__ = block if block
171
+ not @keysPressed__.empty?
172
+ end
173
+
174
+ # Defines keyReleased block.
175
+ #
176
+ # @return [nil] nil
177
+ #
178
+ def keyReleased(&block)
179
+ @keyReleasedBlock__ = block if block
180
+ nil
181
+ end
182
+
183
+ # Defines keyTyped block.
184
+ #
185
+ # @return [nil] nil
186
+ #
187
+ def keyTyped(&block)
188
+ @keyTypedBlock__ = block if block
189
+ nil
190
+ end
191
+
192
+ # Defines mousePressed block.
193
+ #
194
+ # @return [Boolean] is any mouse button pressed or not
195
+ #
196
+ def mousePressed(&block)
197
+ @mousePressedBlock__ = block if block
198
+ not @pointersPressed__.empty?
199
+ end
200
+
201
+ # Defines mouseReleased block.
202
+ #
203
+ # @return [nil] nil
204
+ #
205
+ def mouseReleased(&block)
206
+ @mouseReleasedBlock__ = block if block
207
+ nil
208
+ end
209
+
210
+ # Defines mouseMoved block.
211
+ #
212
+ # @return [nil] nil
213
+ #
214
+ def mouseMoved(&block)
215
+ @mouseMovedBlock__ = block if block
216
+ nil
217
+ end
218
+
219
+ # Defines mouseDragged block.
220
+ #
221
+ # @return [nil] nil
222
+ #
223
+ def mouseDragged(&block)
224
+ @mouseDraggedBlock__ = block if block
225
+ nil
226
+ end
227
+
228
+ # Defines mouseClicked block.
229
+ #
230
+ # @return [nil] nil
231
+ #
232
+ def mouseClicked(&block)
233
+ @mouseClickedBlock__ = block if block
234
+ nil
235
+ end
236
+
237
+ # Defines touchStarted block.
238
+ #
239
+ # @return [nil] nil
240
+ #
241
+ def touchStarted(&block)
242
+ @touchStartedBlock__ = block if block
243
+ nil
244
+ end
245
+
246
+ # Defines touchEnded block.
247
+ #
248
+ # @return [nil] nil
249
+ #
250
+ def touchEnded(&block)
251
+ @touchEndedBlock__ = block if block
252
+ nil
253
+ end
254
+
255
+ # Defines touchMoved block.
256
+ #
257
+ # @return [nil] nil
258
+ #
259
+ def touchMoved(&block)
260
+ @touchMovedBlock__ = block if block
261
+ nil
262
+ end
263
+
264
+ # Defines motion block.
265
+ #
266
+ # @return [nil] nil
267
+ #
268
+ def motion(&block)
269
+ @motionBlock__ = block if block
270
+ nil
271
+ end
272
+
273
+ # Changes canvas size.
274
+ #
275
+ # @param width [Integer] new width
276
+ # @param height [Integer] new height
277
+ # @param pixelDensity [Numeric] new pixel density
278
+ #
279
+ # @return [nil] nil
280
+ #
281
+ def size(width, height, pixelDensity: self.pixelDensity)
282
+ resizeCanvas__ :size, width, height, pixelDensity
283
+ nil
284
+ end
285
+
286
+ # Changes canvas size.
287
+ #
288
+ # @param width [Integer] new width
289
+ # @param height [Integer] new height
290
+ # @param pixelDensity [Numeric] new pixel density
291
+ #
292
+ # @return [nil] nil
293
+ #
294
+ def createCanvas(width, height, pixelDensity: self.pixelDensity)
295
+ resizeCanvas__ :createCanvas, width, height, pixelDensity
296
+ nil
297
+ end
298
+
299
+ # Changes title of window.
300
+ #
301
+ # @param title [String] new title
302
+ #
303
+ # @return [nil] nil
304
+ #
305
+ def setTitle(title)
306
+ @window__.title = title
307
+ nil
308
+ end
309
+
310
+ # Changes and returns canvas pixel density.
311
+ #
312
+ # @param density [Numeric] new pixel density
313
+ #
314
+ # @return [Numeric] current pixel density
315
+ #
316
+ def pixelDensity(density = nil)
317
+ resizeCanvas__ :pixelDensity, width, height, density if density
318
+ @painter__.pixel_density
319
+ end
320
+
321
+ # @private
322
+ def resizeCanvas__(name, width, height, pixelDensity)
323
+ raise '#{name}() must be called on startup or setup block' if @started__
324
+
325
+ @painter__.__send__ :end_paint
326
+ @window__.resize_canvas width, height, pixelDensity
327
+ @window__.auto_resize = false
328
+ ensure
329
+ @painter__.__send__ :begin_paint
330
+ end
331
+
332
+ # Returns pixel density of display.
333
+ #
334
+ # @return [Numeric] pixel density
335
+ #
336
+ def displayDensity()
337
+ @window__.painter.pixel_density
338
+ end
339
+
340
+ # Returns window width.
341
+ #
342
+ # @return [Numeric] window width
343
+ #
344
+ def windowWidth()
345
+ @window__.width
346
+ end
347
+
348
+ # Returns window height.
349
+ #
350
+ # @return [Numeric] window height
351
+ #
352
+ def windowHeight()
353
+ @window__.height
354
+ end
355
+
356
+ # Returns number of frames since program started.
357
+ #
358
+ # @return [Integer] total number of frames
359
+ #
360
+ def frameCount()
361
+ @frameCount__
362
+ end
363
+
364
+ # Returns number of frames per second.
365
+ #
366
+ # @return [Float] frames per second
367
+ #
368
+ def frameRate()
369
+ @window__.event.fps
370
+ end
371
+
372
+ # Returns the last key that was pressed or released.
373
+ #
374
+ # @return [String] last key
375
+ #
376
+ def key()
377
+ @key__
378
+ end
379
+
380
+ # Returns the last key code that was pressed or released.
381
+ #
382
+ # @return [Symbol] last key code
383
+ #
384
+ def keyCode()
385
+ @keyCode__
386
+ end
387
+
388
+ # Returns mouse x position
389
+ #
390
+ # @return [Numeric] horizontal position of mouse
391
+ #
392
+ def mouseX()
393
+ @pointerPos__.x
394
+ end
395
+
396
+ # Returns mouse y position
397
+ #
398
+ # @return [Numeric] vertical position of mouse
399
+ #
400
+ def mouseY()
401
+ @pointerPos__.y
402
+ end
403
+
404
+ # Returns mouse x position in previous frame
405
+ #
406
+ # @return [Numeric] horizontal position of mouse
407
+ #
408
+ def pmouseX()
409
+ @pointerPrevPos__.x
410
+ end
411
+
412
+ # Returns mouse y position in previous frame
413
+ #
414
+ # @return [Numeric] vertical position of mouse
415
+ #
416
+ def pmouseY()
417
+ @pointerPrevPos__.y
418
+ end
419
+
420
+ # Returns which mouse button was pressed
421
+ #
422
+ # @return [Numeric] LEFT, RIGHT, CENTER or 0
423
+ #
424
+ def mouseButton()
425
+ (@pointersPressed__ & [LEFT, RIGHT, CENTER]).last || 0
426
+ end
427
+
428
+ # Returns array of touches
429
+ #
430
+ # @return [Array] Touch objects
431
+ #
432
+ def touches()
433
+ @touches__
434
+ end
435
+
436
+ # Returns vector for real world gravity
437
+ #
438
+ # @return [Vector] gravity vector
439
+ #
440
+ def motionGravity()
441
+ @motionGravity__
442
+ end
443
+
444
+ # Enables calling draw block on every frame.
445
+ #
446
+ # @return [nil] nil
447
+ #
448
+ def loop()
449
+ @loop__ = true
450
+ end
451
+
452
+ # Disables calling draw block on every frame.
453
+ #
454
+ # @return [nil] nil
455
+ #
456
+ def noLoop()
457
+ @loop__ = false
458
+ end
459
+
460
+ # Calls draw block to redraw frame.
461
+ #
462
+ # @return [nil] nil
463
+ #
464
+ def redraw()
465
+ @redraw__ = true
466
+ end
467
+
468
+ end# Context
469
+
470
+
471
+ end# Processing
@@ -1,7 +1,7 @@
1
1
  module Processing
2
2
 
3
3
 
4
- module Module
4
+ module Extension
5
5
 
6
6
  module_function
7
7
 
@@ -10,14 +10,14 @@ module Processing
10
10
  end
11
11
 
12
12
  def version()
13
- open(root_dir 'VERSION') {|f| f.readline.chomp}
13
+ File.read(root_dir 'VERSION')[/[\d\.]+/]
14
14
  end
15
15
 
16
16
  def root_dir(path = '')
17
17
  File.expand_path "../../#{path}", __dir__
18
18
  end
19
19
 
20
- end# Module
20
+ end# Extension
21
21
 
22
22
 
23
23
  end# Processing
@@ -0,0 +1,62 @@
1
+ module Processing
2
+
3
+
4
+ # Font object.
5
+ #
6
+ class Font
7
+
8
+ # @private
9
+ def initialize(font)
10
+ @font = font
11
+ end
12
+
13
+ # Returns bounding box.
14
+ #
15
+ # @overload textBounds(str)
16
+ # @overload textBounds(str, x, y)
17
+ # @overload textBounds(str, x, y, fontSize)
18
+ #
19
+ # @param str [String] text to calculate bounding box
20
+ # @param x [Numeric] horizontal position of bounding box
21
+ # @param y [Numeric] vertical position of bounding box
22
+ # @param fontSize [Numeric] font size
23
+ #
24
+ # @return [TextBounds] bounding box for text
25
+ #
26
+ def textBounds(str, x = 0, y = 0, fontSize = nil)
27
+ f = fontSize ? Rays::Font.new(@font.name, fontSize) : @font
28
+ TextBounds.new x, y, x + f.width(str), y + f.height
29
+ end
30
+
31
+ end# Font
32
+
33
+
34
+ # Bounding box for text.
35
+ #
36
+ class TextBounds
37
+
38
+ # Horizontal position
39
+ #
40
+ attr_reader :x
41
+
42
+ # Vertical position
43
+ #
44
+ attr_reader :y
45
+
46
+ # Width of bounding box
47
+ #
48
+ attr_reader :w
49
+
50
+ # Height of bounding box
51
+ #
52
+ attr_reader :h
53
+
54
+ # @private
55
+ def initialize(x, y, w, h)
56
+ @x, @y, @w, @h = x, y, w, h
57
+ end
58
+
59
+ end# TextBounds
60
+
61
+
62
+ end# Processing
@@ -0,0 +1,40 @@
1
+ module Processing
2
+
3
+
4
+ # Draws graphics into an offscreen buffer
5
+ #
6
+ class Graphics
7
+
8
+ include GraphicsContext
9
+
10
+ # Initialize graphics object.
11
+ #
12
+ def initialize(width, height)
13
+ image = Rays::Image.new width, height
14
+ init__ image, image.painter
15
+ end
16
+
17
+ # Start drawing.
18
+ #
19
+ def beginDraw(&block)
20
+ beginDraw__
21
+ @painter__.__send__ :begin_paint
22
+ push
23
+ if block
24
+ block.call
25
+ endDraw
26
+ end
27
+ end
28
+
29
+ # End drawing.
30
+ #
31
+ def endDraw()
32
+ pop
33
+ @painter__.__send__ :end_paint
34
+ endDraw__
35
+ end
36
+
37
+ end# Graphics
38
+
39
+
40
+ end# Processing