processing 0.5.31 → 0.5.33

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.
@@ -10,6 +10,7 @@ module Processing
10
10
  # @private
11
11
  def initialize(image)
12
12
  @image = image
13
+ @pixels, @error = nil, false
13
14
  end
14
15
 
15
16
  # Gets width of image.
@@ -17,7 +18,7 @@ module Processing
17
18
  # @return [Numeric] width of image
18
19
  #
19
20
  def width()
20
- @image.width
21
+ @image&.width || (@error ? -1 : 0)
21
22
  end
22
23
 
23
24
  # Gets height of image.
@@ -25,7 +26,7 @@ module Processing
25
26
  # @return [Numeric] height of image
26
27
  #
27
28
  def height()
28
- @image.height
29
+ @image&.height || (@error ? -1 : 0)
29
30
  end
30
31
 
31
32
  alias w width
@@ -36,7 +37,7 @@ module Processing
36
37
  # @return [Array<Numeric>] [width, height]
37
38
  #
38
39
  def size()
39
- @image.size
40
+ [width, height]
40
41
  end
41
42
 
42
43
  # Sets the color of the pixel.
@@ -48,21 +49,43 @@ module Processing
48
49
  # @return [nil] nil
49
50
  #
50
51
  def set(x, y, c)
51
- @image.bitmap[x, y] = self.class.fromColor__ c
52
+ getInternal__.bitmap(true)[x, y] = self.class.fromColor__(c).map {|n| n / 255.0}
52
53
  nil
53
54
  end
54
55
 
55
-
56
56
  # Returns the color of the pixel.
57
57
  #
58
58
  # @return [Integer] color value (0xAARRGGBB)
59
59
  #
60
60
  def get(x, y)
61
- @image.bitmap[x, y]
61
+ getInternal__.bitmap[x, y]
62
62
  .map {|n| (n * 255).to_i.clamp 0, 255}
63
63
  .then {|r, g, b, a| self.class.toColor__ r, g, b, a}
64
64
  end
65
65
 
66
+ # Loads all pixels to the 'pixels' array.
67
+ #
68
+ # @return [nil] nil
69
+ #
70
+ def loadPixels()
71
+ @pixels = getInternal__.pixels
72
+ end
73
+
74
+ # Update the image pixels with the 'pixels' array.
75
+ #
76
+ # @return [nil] nil
77
+ #
78
+ def updatePixels()
79
+ return unless @pixels
80
+ getInternal__.pixels = @pixels
81
+ @pixels = nil
82
+ end
83
+
84
+ # An array of all pixels.
85
+ # Call loadPixels() before accessing the array.
86
+ #
87
+ attr_reader :pixels
88
+
66
89
  # Applies an image filter.
67
90
  #
68
91
  # overload filter(shader)
@@ -86,7 +109,7 @@ module Processing
86
109
  #
87
110
  def resize(width, height)
88
111
  @image = Rays::Image.new(width, height).paint do |painter|
89
- painter.image @image, 0, 0, width, height
112
+ painter.image getInternal__, 0, 0, width, height
90
113
  end
91
114
  nil
92
115
  end
@@ -132,7 +155,7 @@ module Processing
132
155
  #
133
156
  def blend(img = nil, sx, sy, sw, sh, dx, dy, dw, dh, mode)
134
157
  img ||= self
135
- @image.paint do |painter|
158
+ getInternal__.paint do |painter|
136
159
  img.drawImage__ painter, sx, sy, sw, sh, dx, dy, dw, dh, blend_mode: mode
137
160
  end
138
161
  nil
@@ -145,13 +168,18 @@ module Processing
145
168
  # @return [nil] nil
146
169
  #
147
170
  def save(filename)
148
- @image.save filename
171
+ getInternal__.save filename
149
172
  nil
150
173
  end
151
174
 
152
175
  # @private
153
176
  def getInternal__()
154
- @image
177
+ @image or raise 'Invalid image object'
178
+ end
179
+
180
+ # @private
181
+ def setInternal__(image, error = false)
182
+ @image, @error = image, error
155
183
  end
156
184
 
157
185
  # @private
@@ -7,10 +7,11 @@ module Processing
7
7
 
8
8
  # @private
9
9
  def initialize(polygon = nil, children = nil, context: nil)
10
- @polygon, @children = polygon, children
11
- @context = context || Context.context__
12
- @visible, @matrix = true, nil
13
- @mode = @points = @closed = nil
10
+ @polygon, @children = polygon, children
11
+ @context = context || Context.context__
12
+ @visible, @fill, @matrix = true, nil, nil
13
+ @type = @points = @curvePoints = @colors = @texcoords = @close = nil
14
+ @contours = @contourPoints = @contourColors = @contourTexCoords = nil
14
15
  end
15
16
 
16
17
  # Gets width of shape.
@@ -53,22 +54,105 @@ module Processing
53
54
  nil
54
55
  end
55
56
 
56
- def beginShape(mode = nil)
57
- @mode = mode
58
- @points ||= []
59
- @polygon = nil# clear cache
57
+ def beginShape(type = nil)
58
+ raise "beginShape() cannot be called twice" if drawingShape__
59
+ @type = type
60
+ @points ||= []
61
+ @curvePoints = []
62
+ @colors ||= []
63
+ @texcoords ||= []
64
+ @close = nil
65
+ @contours ||= []
66
+ clearCache__
60
67
  nil
61
68
  end
62
69
 
63
70
  def endShape(close = nil)
64
- raise "endShape() must be called after beginShape()" unless @points
65
- @closed = close == GraphicsContext::CLOSE
71
+ raise "endShape() must be called after beginShape()" unless drawingShape__
72
+ @close = close == GraphicsContext::CLOSE || @contours.size > 0
73
+ if @close && @curvePoints.size >= 8
74
+ x, y = @curvePoints[0, 2]
75
+ 2.times {curveVertex x, y}
76
+ end
77
+ @curvePoints = nil
78
+ nil
79
+ end
80
+
81
+ def beginContour()
82
+ raise "beginContour() must be called after beginShape()" unless drawingShape__
83
+ @contourPoints, @contourColors, @contourTexCoords = [], [], []
84
+ nil
85
+ end
86
+
87
+ def endContour()
88
+ raise "endContour() must be called after beginContour()" unless drawingContour__
89
+ @contours << Rays::Polyline.new(
90
+ *@contourPoints, colors: @contourColors, texcoords: @contourTexCoords,
91
+ loop: true, hole: true)
92
+ @contoursPoints = @contoursColors = @contoursTexCoords = nil
93
+ nil
94
+ end
95
+
96
+ def vertex(x, y, u = nil, v = nil)
97
+ raise "vertex() must be called after beginShape()" unless drawingShape__
98
+ raise "Either 'u' or 'v' is missing" if (u == nil) != (v == nil)
99
+ u ||= x
100
+ v ||= y
101
+ color = @fill || @context.getFill__
102
+ if drawingContour__
103
+ @contourPoints << x << y
104
+ @contourColors << color
105
+ @contourTexCoords << u << v
106
+ else
107
+ @points << x << y
108
+ @colors << color
109
+ @texcoords << u << v
110
+ end
111
+ end
112
+
113
+ def curveVertex(x, y)
114
+ raise "curveVertex() must be called after beginShape()" unless drawingShape__
115
+ @curvePoints << x << y
116
+ if @curvePoints.size >= 8
117
+ Rays::Polygon.curve(*@curvePoints[-8, 8])
118
+ .first.to_a.tap {|a| a.shift if @curvePoints.size > 8}
119
+ .each {|p| vertex p.x, p.y}
120
+ end
121
+ nil
122
+ end
123
+
124
+ def bezierVertex(x2, y2, x3, y3, x4, y4)
125
+ raise "bezierVertex() must be called after beginShape()" unless drawingShape__
126
+ x1, y1 = @points[-2, 2]
127
+ raise "vertex() is required before calling bezierVertex()" unless x1 && y1
128
+ Rays::Polygon.bezier(x1, y1, x2, y2, x3, y3, x4, y4)
129
+ .first.to_a.tap {|a| a.shift}
130
+ .each {|p| vertex p.x, p.y}
131
+ nil
132
+ end
133
+
134
+ def quadraticVertex(cx, cy, x3, y3)
135
+ x1, y1 = @points[-2, 2]
136
+ raise "vertex() is required before calling quadraticVertex()" unless x1 && y1
137
+ bezierVertex(
138
+ x1 + (cx - x1) * 2.0 / 3.0, y1 + (cy - y1) * 2.0 / 3.0,
139
+ x3 + (cx - x3) * 2.0 / 3.0, y3 + (cy - y3) * 2.0 / 3.0,
140
+ x3, y3)
66
141
  nil
67
142
  end
68
143
 
69
- def vertex(x, y)
70
- raise "vertex() must be called after beginShape()" unless @points
71
- @points << x << y
144
+ # @private
145
+ def drawingShape__()
146
+ @curvePoints
147
+ end
148
+
149
+ # @private
150
+ def drawingContour__()
151
+ @contourPoints
152
+ end
153
+
154
+ def fill(*args)
155
+ @fill = @context.rawColor__(*args)
72
156
  end
73
157
 
74
158
  def setVertex(index, point)
@@ -88,6 +172,23 @@ module Processing
88
172
  @points.size / 2
89
173
  end
90
174
 
175
+ def setFill(*args)
176
+ color = @context.rawColor__(*args)
177
+ count = getVertexCount
178
+ if count > 0
179
+ if @colors
180
+ @colors.fill color
181
+ else
182
+ @colors = [color] * count
183
+ end
184
+ clearCache__
185
+ elsif @polygon
186
+ @polygon = @polygon.transform do |polylines|
187
+ polylines.map {|pl| pl.with colors: pl.points.map {color}}
188
+ end
189
+ end
190
+ end
191
+
91
192
  def addChild(child)
92
193
  return unless @children
93
194
  @children.push child
@@ -103,17 +204,17 @@ module Processing
103
204
  end
104
205
 
105
206
  def translate(x, y, z = 0)
106
- matrix__.translate x, y, z
207
+ matrix__.translate! x, y, z
107
208
  nil
108
209
  end
109
210
 
110
211
  def rotate(angle)
111
- matrix__.rotate @context.toDegrees__(angle)
212
+ matrix__.rotate! @context.toDegrees__(angle)
112
213
  nil
113
214
  end
114
215
 
115
216
  def scale(x, y, z = 1)
116
- matrix__.scale x, y, z
217
+ matrix__.scale! x, y, z
117
218
  nil
118
219
  end
119
220
 
@@ -121,9 +222,22 @@ module Processing
121
222
  @matrix = nil
122
223
  end
123
224
 
124
- def rotateX = nil
125
- def rotateY = nil
126
- def rotateZ = nil
225
+ def rotateX(angle)
226
+ matrix__.rotate! @context.toDegrees__(angle), 1, 0, 0
227
+ end
228
+
229
+ def rotateY(angle)
230
+ matrix__.rotate! @context.toDegrees__(angle), 0, 1, 0
231
+ end
232
+
233
+ def rotateZ(angle)
234
+ matrix__.rotate! @context.toDegrees__(angle), 0, 0, 1
235
+ end
236
+
237
+ # @private
238
+ def clearCache__()
239
+ @polygon = nil# clear cache
240
+ end
127
241
 
128
242
  # @private
129
243
  def matrix__()
@@ -133,8 +247,10 @@ module Processing
133
247
  # @private
134
248
  def getInternal__()
135
249
  unless @polygon
136
- return nil unless @points && @closed != nil
137
- @polygon = self.class.createPolygon__ @mode, @points, @closed
250
+ return nil unless @points && @close != nil
251
+ @polygon = self.class.createPolygon__(
252
+ @type, @points, @close, @colors, @texcoords)
253
+ @polygon += @contours if @polygon
138
254
  end
139
255
  @polygon
140
256
  end
@@ -162,18 +278,21 @@ module Processing
162
278
  end
163
279
 
164
280
  # @private
165
- def self.createPolygon__(mode, points, close = false)
166
- g = GraphicsContext
167
- case mode
168
- when g::POINTS then Rays::Polygon.points( *points)
169
- when g::LINES then Rays::Polygon.lines( *points)
170
- when g::TRIANGLES then Rays::Polygon.triangles( *points)
171
- when g::TRIANGLE_FAN then Rays::Polygon.triangle_fan( *points)
172
- when g::TRIANGLE_STRIP then Rays::Polygon.triangle_strip(*points)
173
- when g::QUADS then Rays::Polygon.quads( *points)
174
- when g::QUAD_STRIP then Rays::Polygon.quad_strip( *points)
175
- when g::TESS, nil then Rays::Polygon.new(*points, loop: close)
176
- else raise ArgumentError, "invalid polygon mode '#{mode}'"
281
+ def self.createPolygon__(
282
+ type, points, close = false, colors = nil, texcoords = nil)
283
+
284
+ kwargs = {colors: colors, texcoords: texcoords}
285
+ g, p = GraphicsContext, Rays::Polygon
286
+ case type
287
+ when g::POINTS then p.points( *points)
288
+ when g::LINES then p.lines( *points)
289
+ when g::TRIANGLES then p.triangles( *points, **kwargs)
290
+ when g::TRIANGLE_FAN then p.triangle_fan( *points, **kwargs)
291
+ when g::TRIANGLE_STRIP then p.triangle_strip(*points, **kwargs)
292
+ when g::QUADS then p.quads( *points, **kwargs)
293
+ when g::QUAD_STRIP then p.quad_strip( *points, **kwargs)
294
+ when g::TESS, nil then p.new( *points, **kwargs, loop: close)
295
+ else raise ArgumentError, "invalid polygon type '#{type}'"
177
296
  end
178
297
  end
179
298
 
@@ -6,14 +6,6 @@ module Processing
6
6
 
7
7
  include Xot::Inspectable
8
8
 
9
- attr_accessor :setup, :update, :draw,
10
- :key_down, :key_up,
11
- :pointer_down, :pointer_up, :pointer_move,
12
- :move, :resize, :motion,
13
- :before_draw, :after_draw, :update_window, :update_canvas
14
-
15
- attr_accessor :auto_resize
16
-
17
9
  def initialize(width = 500, height = 500, *args, **kwargs, &block)
18
10
  Processing.instance_variable_set :@window, self
19
11
 
@@ -26,19 +18,16 @@ module Processing
26
18
  @overlay_view = @canvas_view.add Reflex::View.new name: :overlay
27
19
 
28
20
  super(*args, size: [width, height], **kwargs, &block)
21
+ self.center = screen.center
29
22
  end
30
23
 
31
- def canvas_image()
32
- @canvas.image
33
- end
24
+ attr_accessor :setup, :update, :draw, :move, :resize, :motion,
25
+ :key_down, :key_up, :pointer_down, :pointer_up, :pointer_move, :wheel,
26
+ :before_draw, :after_draw, :update_window, :update_canvas
34
27
 
35
- def canvas_painter()
36
- @canvas.painter
37
- end
28
+ attr_accessor :auto_resize
38
29
 
39
- def window_painter()
40
- self.painter
41
- end
30
+ attr_reader :canvas
42
31
 
43
32
  def event()
44
33
  @events.last
@@ -64,7 +53,9 @@ module Processing
64
53
  end
65
54
 
66
55
  def on_change_pixel_density(pixel_density)
67
- resize_canvas width, height, window_pixel_density: pixel_density
56
+ resize_canvas(
57
+ @canvas.width, @canvas.height,
58
+ window_pixel_density: pixel_density)
68
59
  end
69
60
 
70
61
  def on_activate(e)
@@ -80,7 +71,7 @@ module Processing
80
71
  end
81
72
 
82
73
  def on_draw(e)
83
- window_painter.pixel_density.tap do |pd|
74
+ painter.pixel_density.tap do |pd|
84
75
  prev, @prev_pixel_density = @prev_pixel_density, pd
85
76
  on_change_pixel_density pd if prev && pd != prev
86
77
  end
@@ -127,28 +118,35 @@ module Processing
127
118
  draw_canvas {call_block block, e} if block
128
119
  end
129
120
 
121
+ def on_canvas_wheel(e)
122
+ draw_canvas {call_block @wheel, e} if @wheel
123
+ end
124
+
130
125
  def on_canvas_resize(e)
131
126
  resize_canvas e.width, e.height if @auto_resize
132
127
  draw_canvas {call_block @resize, e} if @resize
133
128
  end
134
129
 
135
- def resize_canvas(width, height, pixel_density = nil, window_pixel_density: nil)
136
- painting = canvas_painter.painting?
137
- canvas_painter.__send__ :end_paint if painting
130
+ def resize_canvas(
131
+ width, height,
132
+ pixel_density = nil,
133
+ window_pixel_density: nil,
134
+ antialiasing: nil)
135
+
136
+ painting = @canvas.painter.painting?
137
+ @canvas.painter.__send__ :end_paint if painting
138
138
 
139
139
  @pixel_density = pixel_density if pixel_density
140
140
 
141
141
  resized =
142
142
  begin
143
- @canvas.resize width, height, @pixel_density || window_pixel_density
143
+ pd = @pixel_density || window_pixel_density
144
+ @canvas.resize width, height, pd, antialiasing
144
145
  ensure
145
- canvas_painter.__send__ :begin_paint if painting
146
+ @canvas.painter.__send__ :begin_paint if painting
146
147
  end
147
148
 
148
- if resized
149
- @update_canvas.call canvas_image, canvas_painter if @update_canvas
150
- size width, height
151
- end
149
+ @update_canvas&.call @canvas.image, @canvas.painter if resized
152
150
  end
153
151
 
154
152
  private
@@ -157,12 +155,12 @@ module Processing
157
155
  scrollx, scrolly, zoom = get_scroll_and_zoom
158
156
  @canvas_view.scroll_to scrollx, scrolly
159
157
  @canvas_view.zoom = zoom
160
- @overlay_view.size = canvas_image.size
158
+ @overlay_view.size = @canvas.image.size
161
159
  end
162
160
 
163
161
  def get_scroll_and_zoom()
164
- ww, wh = width.to_f, height.to_f
165
- cw, ch = canvas_image.width.to_f, canvas_image.height.to_f
162
+ ww, wh = width.to_f, height.to_f
163
+ cw, ch = @canvas.image.width.to_f, @canvas.image.height.to_f
166
164
  return [0, 0, 1] if ww == 0 || wh == 0 || cw == 0 || ch == 0
167
165
 
168
166
  wratio, cratio = ww / wh, cw / ch
@@ -184,21 +182,21 @@ module Processing
184
182
  end
185
183
 
186
184
  def begin_draw()
187
- canvas_painter.__send__ :begin_paint
185
+ @canvas.painter.__send__ :begin_paint
188
186
  @before_draw&.call
189
187
  end
190
188
 
191
189
  def end_draw()
192
190
  @after_draw&.call
193
- canvas_painter.__send__ :end_paint
191
+ @canvas.painter.__send__ :end_paint
194
192
  end
195
193
 
196
194
  def drawing?()
197
- canvas_painter.painting?
195
+ @canvas.painter.painting?
198
196
  end
199
197
 
200
198
  def draw_screen(painter)
201
- window_painter.image canvas_image
199
+ painter.image @canvas.render
202
200
  end
203
201
 
204
202
  def call_block(block, event, *args)
@@ -216,49 +214,84 @@ module Processing
216
214
 
217
215
  class Window::Canvas
218
216
 
219
- attr_reader :image, :painter
220
-
221
217
  def initialize(window, width, height)
222
- @image = nil
223
- @painter = window.painter
218
+ @framebuffer = nil
219
+ @paintable = nil
220
+ @painter = window.painter
221
+
222
+ @painter.miter_limit = 10
224
223
 
225
224
  resize width, height
226
- painter.miter_limit = 10
227
225
  end
228
226
 
229
- def resize(width, height, pixel_density = nil)
227
+ attr_reader :painter
228
+
229
+ def resize(width, height, pixel_density = nil, antialiasing = nil)
230
230
  return false if width <= 0 || height <= 0
231
231
 
232
+ cs = @framebuffer&.color_space || Rays::RGBA
233
+ pd = pixel_density || (@framebuffer || @painter).pixel_density
234
+ aa = antialiasing == nil ? antialiasing? : (antialiasing && pd < 2)
232
235
  return false if
233
- width == @image&.width &&
234
- height == @image&.height &&
235
- pixel_density == @painter.pixel_density
236
+ width == @framebuffer&.width &&
237
+ height == @framebuffer&.height &&
238
+ pd == @framebuffer&.pixel_density &&
239
+ aa == antialiasing?
236
240
 
237
- old_image = @image
238
- old_painter = @painter
239
- cs = old_image&.color_space || Rays::RGBA
240
- pd = pixel_density || old_painter.pixel_density
241
+ old_paintable, old_painter = @paintable, @painter
241
242
 
242
- @image = Rays::Image.new width, height, cs, pd
243
- @painter = @image.painter
243
+ @framebuffer = Rays::Image.new width, height, cs, pd
244
+ @paintable = aa ? Rays::Image.new(width, height, cs, pd * 2) : @framebuffer
245
+ @painter = @paintable.painter
244
246
 
245
- @painter.paint {image old_image} if old_image
247
+ @painter.paint {image old_paintable} if old_paintable
246
248
  copy_painter old_painter, @painter
247
249
 
248
250
  GC.start
249
251
  return true
250
252
  end
251
253
 
254
+ def render()
255
+ @framebuffer.paint {|p| p.image @paintable} if antialiasing?
256
+ @framebuffer
257
+ end
258
+
259
+ def image()
260
+ @paintable
261
+ end
262
+
263
+ def width()
264
+ @framebuffer.width
265
+ end
266
+
267
+ def height()
268
+ @framebuffer.height
269
+ end
270
+
271
+ def pixel_density()
272
+ @framebuffer.pixel_density
273
+ end
274
+
275
+ def antialiasing?()
276
+ !!@framebuffer && !!@paintable && @framebuffer != @paintable
277
+ end
278
+
252
279
  private
253
280
 
254
281
  def copy_painter(from, to)
255
- to.fill = from.fill
256
- to.stroke = from.stroke
257
- to.stroke_width = from.stroke_width
258
- to.stroke_cap = from.stroke_cap
259
- to.stroke_join = from.stroke_join
260
- to.miter_limit = from.miter_limit
261
- to.font = from.font
282
+ to.fill = from.fill
283
+ to.stroke = from.stroke
284
+ to.stroke_width = from.stroke_width
285
+ to.stroke_cap = from.stroke_cap
286
+ to.stroke_join = from.stroke_join
287
+ to.miter_limit = from.miter_limit
288
+ to.clip = from.clip
289
+ to.blend_mode = from.blend_mode
290
+ to.font = from.font
291
+ to.texture = from.texture
292
+ to.texcoord_mode = from.texcoord_mode
293
+ to.texcoord_wrap = from.texcoord_wrap
294
+ to.shader = from.shader
262
295
  end
263
296
 
264
297
  end# Window::Canvas
@@ -268,6 +301,7 @@ module Processing
268
301
 
269
302
  def on_update(e)
270
303
  window.on_canvas_update e
304
+ Thread.pass
271
305
  end
272
306
 
273
307
  def on_draw(e)
@@ -278,6 +312,10 @@ module Processing
278
312
  window.on_canvas_pointer e
279
313
  end
280
314
 
315
+ def on_wheel(e)
316
+ window.on_canvas_wheel e
317
+ end
318
+
281
319
  def on_resize(e)
282
320
  window.on_canvas_resize e
283
321
  end
data/processing.gemspec CHANGED
@@ -25,10 +25,10 @@ Gem::Specification.new do |s|
25
25
  s.platform = Gem::Platform::RUBY
26
26
  s.required_ruby_version = '>= 3.0.0'
27
27
 
28
- s.add_runtime_dependency 'xot', '~> 0.1.41'
29
- s.add_runtime_dependency 'rucy', '~> 0.1.42'
30
- s.add_runtime_dependency 'rays', '~> 0.1.47'
31
- s.add_runtime_dependency 'reflexion', '~> 0.1.55'
28
+ s.add_runtime_dependency 'xot', '~> 0.1.42'
29
+ s.add_runtime_dependency 'rucy', '~> 0.1.44'
30
+ s.add_runtime_dependency 'rays', '~> 0.1.49'
31
+ s.add_runtime_dependency 'reflexion', '~> 0.1.57'
32
32
 
33
33
  s.files = `git ls-files`.split $/
34
34
  s.test_files = s.files.grep %r{^(test|spec|features)/}
data/test/helper.rb CHANGED
@@ -34,8 +34,10 @@ def mkdir(dir: nil, filename: nil)
34
34
  FileUtils.mkdir_p path unless File.exist? path
35
35
  end
36
36
 
37
- def test_label(index = 1)
38
- caller_locations[index].then {|loc| "#{loc.label}_#{loc.lineno}"}
37
+ def test_label(frame_offset = 1, suffix: nil)
38
+ suffix = suffix ? "_#{suffix}" : ''
39
+ caller_locations[frame_offset]
40
+ .then {|loc| "#{loc.label}_#{loc.lineno}#{suffix}"}
39
41
  end
40
42
 
41
43
  def temp_path(ext: nil, &block)
@@ -59,7 +61,6 @@ def get_pixels(image)
59
61
  .map {image.instance_variable_get _1}
60
62
  .compact
61
63
  .first
62
- .bitmap
63
64
  .pixels
64
65
  end
65
66
 
@@ -71,6 +72,7 @@ end
71
72
 
72
73
  def test_draw(*sources, width: 1000, height: 1000, pixelDensity: 1, label: nil)
73
74
  graphics(width, height, pixelDensity).tap do |g|
75
+ g.renderMode :p5js
74
76
  g.beginDraw {g.instance_eval sources.compact.join("\n")}
75
77
  g.save draw_output_path(label, *sources) if label
76
78
  end
@@ -107,14 +109,14 @@ end
107
109
 
108
110
  def assert_p5_draw(
109
111
  *sources, default_header: DEFAULT_DRAW_HEADER,
110
- width: 1000, height: 1000, threshold: 0.99, label: test_label)
112
+ width: 1000, height: 1000, threshold: 0.99, label: test_label, **kwargs)
111
113
 
112
114
  return unless test_with_p5?
113
115
 
114
116
  source = [default_header, *sources].compact.join("\n")
115
117
  path = draw_output_path "#{label}_expected", source
116
118
 
117
- pd = draw_p5rb width, height, source, path, headless: true
119
+ pd = draw_p5rb width, height, source, path, **kwargs
118
120
  actual = test_draw source, width: width, height: height, pixelDensity: pd
119
121
  actual.save path.sub('_expected', '_actual')
120
122