processing 0.5.31 → 0.5.32

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[x, y] = self.class.fromColor__ c
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
66
121
  nil
67
122
  end
68
123
 
69
- def vertex(x, y)
70
- raise "vertex() must be called after beginShape()" unless @points
71
- @points << x << y
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)
141
+ nil
142
+ end
143
+
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.toRaysColor__(*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.toRaysColor__(*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
@@ -125,6 +226,11 @@ module Processing
125
226
  def rotateY = nil
126
227
  def rotateZ = nil
127
228
 
229
+ # @private
230
+ def clearCache__()
231
+ @polygon = nil# clear cache
232
+ end
233
+
128
234
  # @private
129
235
  def matrix__()
130
236
  @matrix ||= Rays::Matrix.new
@@ -133,8 +239,10 @@ module Processing
133
239
  # @private
134
240
  def getInternal__()
135
241
  unless @polygon
136
- return nil unless @points && @closed != nil
137
- @polygon = self.class.createPolygon__ @mode, @points, @closed
242
+ return nil unless @points && @close != nil
243
+ @polygon = self.class.createPolygon__(
244
+ @type, @points, @close, @colors, @texcoords)
245
+ @polygon += @contours if @polygon
138
246
  end
139
247
  @polygon
140
248
  end
@@ -162,18 +270,21 @@ module Processing
162
270
  end
163
271
 
164
272
  # @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}'"
273
+ def self.createPolygon__(
274
+ type, points, close = false, colors = nil, texcoords = nil)
275
+
276
+ kwargs = {colors: colors, texcoords: texcoords}
277
+ g, p = GraphicsContext, Rays::Polygon
278
+ case type
279
+ when g::POINTS then p.points( *points)
280
+ when g::LINES then p.lines( *points)
281
+ when g::TRIANGLES then p.triangles( *points, **kwargs)
282
+ when g::TRIANGLE_FAN then p.triangle_fan( *points, **kwargs)
283
+ when g::TRIANGLE_STRIP then p.triangle_strip(*points, **kwargs)
284
+ when g::QUADS then p.quads( *points, **kwargs)
285
+ when g::QUAD_STRIP then p.quad_strip( *points, **kwargs)
286
+ when g::TESS, nil then p.new( *points, **kwargs, loop: close)
287
+ else raise ArgumentError, "invalid polygon type '#{type}'"
177
288
  end
178
289
  end
179
290
 
data/processing.gemspec CHANGED
@@ -26,9 +26,9 @@ Gem::Specification.new do |s|
26
26
  s.required_ruby_version = '>= 3.0.0'
27
27
 
28
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'
29
+ s.add_runtime_dependency 'rucy', '~> 0.1.43'
30
+ s.add_runtime_dependency 'rays', '~> 0.1.48'
31
+ s.add_runtime_dependency 'reflexion', '~> 0.1.56'
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
@@ -59,7 +59,6 @@ def get_pixels(image)
59
59
  .map {image.instance_variable_get _1}
60
60
  .compact
61
61
  .first
62
- .bitmap
63
62
  .pixels
64
63
  end
65
64
 
@@ -107,14 +106,14 @@ end
107
106
 
108
107
  def assert_p5_draw(
109
108
  *sources, default_header: DEFAULT_DRAW_HEADER,
110
- width: 1000, height: 1000, threshold: 0.99, label: test_label)
109
+ width: 1000, height: 1000, threshold: 0.99, label: test_label, **kwargs)
111
110
 
112
111
  return unless test_with_p5?
113
112
 
114
113
  source = [default_header, *sources].compact.join("\n")
115
114
  path = draw_output_path "#{label}_expected", source
116
115
 
117
- pd = draw_p5rb width, height, source, path, headless: true
116
+ pd = draw_p5rb width, height, source, path, **kwargs
118
117
  actual = test_draw source, width: width, height: height, pixelDensity: pd
119
118
  actual.save path.sub('_expected', '_actual')
120
119
 
data/test/p5.rb CHANGED
@@ -13,7 +13,7 @@ def browser(width, height, headless: true)
13
13
  hash[key] ||= Ferrum::Browser.new headless: headless, window_size: [width, height]
14
14
  end
15
15
 
16
- def get_p5rb_html(width, height, draw_src)
16
+ def get_p5rb_html(width, height, draw_src, webgl: false)
17
17
  <<~END
18
18
  <html>
19
19
  <head>
@@ -34,9 +34,10 @@ def get_p5rb_html(width, height, draw_src)
34
34
  </script>
35
35
  <script type="text/ruby">
36
36
  def setup()
37
- createCanvas #{width}, #{height}
37
+ createCanvas #{width}, #{height}#{webgl ? ', WEBGL' : ''}
38
38
  end
39
39
  def draw()
40
+ #{webgl ? 'translate -width / 2, -height / 2' : ''}
40
41
  #{draw_src}
41
42
  JS.global.completed
42
43
  end
@@ -62,11 +63,11 @@ def sleep_until (try: 3, timeout: 10, &block)
62
63
  end
63
64
  end
64
65
 
65
- def draw_p5rb(width, height, draw_src, path, headless: true)
66
+ def draw_p5rb(width, height, draw_src, path, headless: true, webgl: false)
66
67
  b = browser width, height, headless: headless
67
68
  unless File.exist? path
68
69
  b.reset
69
- b.main_frame.content = get_p5rb_html width, height, draw_src
70
+ b.main_frame.content = get_p5rb_html width, height, draw_src, webgl: webgl
70
71
  sleep_until do
71
72
  b.evaluate 'document.querySelector("#completed") != null'
72
73
  end
data/test/test_font.rb CHANGED
@@ -5,12 +5,43 @@ class TestFont < Test::Unit::TestCase
5
5
 
6
6
  P = Processing
7
7
 
8
- def font()
9
- P::Font.new Rays::Font.new(nil, 10)
8
+ def font(*args)
9
+ P::Font.new(Rays::Font.new *args).tap {|font|
10
+ def font.intern()
11
+ getInternal__
12
+ end
13
+ }
14
+ end
15
+
16
+ def test_initialize()
17
+ assert_not_nil font(nil) .intern.name
18
+ assert_equal 'Arial', font('Arial').intern.name
19
+
20
+ assert_equal 12, font .intern.size
21
+ assert_equal 10, font(nil, 10).intern.size
22
+ end
23
+
24
+ def test_size()
25
+ f = font nil, 10
26
+ id = f.intern.object_id
27
+
28
+ assert_equal 10, f.intern.size
29
+
30
+ f.setSize__ 11
31
+ assert_equal 11, f.intern.size
32
+ assert_not_equal id, f.intern.object_id
33
+
34
+ f.setSize__ 10
35
+ assert_equal 10, f.intern.size
36
+ assert_equal id, f.intern.object_id
10
37
  end
11
38
 
12
39
  def test_inspect()
13
40
  assert_match %r|#<Processing::Font: name:'[\w\s]+' size:[\d\.]+>|, font.inspect
14
41
  end
15
42
 
43
+ def test_list()
44
+ assert_not P::Font.list.empty?
45
+ end
46
+
16
47
  end# TestFont
@@ -76,6 +76,67 @@ class TestGraphicsContext < Test::Unit::TestCase
76
76
  END
77
77
  end
78
78
 
79
+ def test_textFont()
80
+ graphics do |g|
81
+ arial10 = g.createFont 'Arial', 10
82
+ helvetica11 = g.createFont 'Helvetica', 11
83
+
84
+ font = -> {g.instance_variable_get(:@textFont__).getInternal__}
85
+ painterFont = -> {g.instance_variable_get(:@painter__).font}
86
+
87
+ assert_not_nil font[] .name
88
+ assert_not_equal 'Arial', font[] .name
89
+ assert_equal 12, font[] .size
90
+ assert_equal 12, painterFont[].size
91
+
92
+ g.textFont arial10
93
+ assert_equal 'Arial', font[] .name
94
+ assert_equal 10, font[] .size
95
+ assert_equal 10, painterFont[].size
96
+
97
+ g.push do
98
+ g.textFont helvetica11
99
+ assert_equal 'Helvetica', font[] .name
100
+ assert_equal 11, font[] .size
101
+ assert_equal 11, painterFont[].size
102
+ end
103
+
104
+ assert_equal 'Arial', font[] .name
105
+ assert_equal 10, font[] .size
106
+ assert_equal 10, painterFont[].size
107
+
108
+ g.push do
109
+ g.textFont arial10, 13
110
+ assert_equal 'Arial', font[] .name
111
+ assert_equal 13, font[] .size
112
+ assert_equal 13, painterFont[].size
113
+ end
114
+
115
+ assert_equal 'Arial', font[] .name
116
+ assert_equal 10, font[] .size
117
+ assert_equal 10, painterFont[].size
118
+ end
119
+ end
120
+
121
+ def test_textSize()
122
+ graphics do |g|
123
+ font = -> {g.instance_variable_get(:@textFont__).getInternal__}
124
+ painterFont = -> {g.instance_variable_get(:@painter__).font}
125
+
126
+ assert_equal 12, font[] .size
127
+ assert_equal 12, painterFont[].size
128
+
129
+ g.push do
130
+ g.textSize 10
131
+ assert_equal 10, font[] .size
132
+ assert_equal 10, painterFont[].size
133
+ end
134
+
135
+ assert_equal 12, font[] .size
136
+ assert_equal 12, painterFont[].size
137
+ end
138
+ end
139
+
79
140
  def test_clear()
80
141
  colors = -> g {get_pixels(g).uniq}
81
142
 
@@ -468,6 +529,155 @@ class TestGraphicsContext < Test::Unit::TestCase
468
529
  assert_p5_fill_stroke src, 'endShape CLOSE'
469
530
  end
470
531
 
532
+ def test_beginShape_with_fill()
533
+ assert_equal_draw <<~HEADER, <<~EXPECTED, <<~ACTUAL
534
+ noStroke
535
+ HEADER
536
+ fill 0, 255, 0
537
+ rect 100, 100, 500, 400
538
+ EXPECTED
539
+ beginShape
540
+ fill 0, 255, 0
541
+ vertex 100, 100
542
+ vertex 600, 100
543
+ vertex 600, 500
544
+ vertex 100, 500
545
+ endShape
546
+ ACTUAL
547
+ end
548
+
549
+ def test_curveVertex()
550
+ src = <<~END
551
+ beginShape
552
+ curveVertex 100, 100
553
+ curveVertex 800, 100
554
+ curveVertex 800, 800
555
+ curveVertex 100, 800
556
+ END
557
+ assert_p5_fill src, 'endShape'
558
+ assert_p5_stroke src, 'endShape'
559
+ assert_p5_fill_stroke src, 'endShape'
560
+ assert_p5_fill src, 'endShape CLOSE'
561
+ assert_p5_stroke src, 'endShape CLOSE'
562
+ assert_p5_fill_stroke src, 'endShape CLOSE'
563
+
564
+ src = <<~END
565
+ beginShape
566
+ curveVertex 200, 200
567
+ curveVertex 200, 200
568
+ curveVertex 800, 200
569
+ curveVertex 800, 400
570
+ curveVertex 200, 400
571
+ curveVertex 200, 800
572
+ curveVertex 800, 800
573
+ curveVertex 800, 700
574
+ curveVertex 800, 700
575
+ END
576
+ assert_p5_fill src, 'endShape', threshold: THRESHOLD_TO_BE_FIXED
577
+ assert_p5_stroke src, 'endShape'
578
+ assert_p5_fill_stroke src, 'endShape', threshold: THRESHOLD_TO_BE_FIXED
579
+ assert_p5_fill src, 'endShape CLOSE', threshold: THRESHOLD_TO_BE_FIXED
580
+ assert_p5_stroke src, 'endShape CLOSE'
581
+ assert_p5_fill_stroke src, 'endShape CLOSE', threshold: THRESHOLD_TO_BE_FIXED
582
+ end
583
+
584
+ def test_bezierVertex()
585
+ src = <<~END
586
+ beginShape
587
+ vertex 100, 100
588
+ bezierVertex 900, 100, 900, 900, 200, 500
589
+ END
590
+ assert_p5_fill src, 'endShape'
591
+ assert_p5_stroke src, 'endShape'
592
+ assert_p5_fill_stroke src, 'endShape'
593
+ assert_p5_fill src, 'endShape CLOSE'
594
+ assert_p5_stroke src, 'endShape CLOSE'
595
+ assert_p5_fill_stroke src, 'endShape CLOSE'
596
+
597
+ src = <<~END
598
+ beginShape
599
+ vertex 100, 100
600
+ bezierVertex 900, 100, 900, 500, 300, 500
601
+ bezierVertex 100, 900, 900, 900, 900, 600
602
+ END
603
+ assert_p5_fill src, 'endShape', threshold: THRESHOLD_TO_BE_FIXED
604
+ assert_p5_stroke src, 'endShape'
605
+ assert_p5_fill_stroke src, 'endShape', threshold: THRESHOLD_TO_BE_FIXED
606
+ assert_p5_fill src, 'endShape CLOSE', threshold: THRESHOLD_TO_BE_FIXED
607
+ assert_p5_stroke src, 'endShape CLOSE'
608
+ assert_p5_fill_stroke src, 'endShape CLOSE', threshold: THRESHOLD_TO_BE_FIXED
609
+ end
610
+
611
+ def test_quadraticVertex()
612
+ src = <<~END
613
+ beginShape
614
+ vertex 100, 100
615
+ quadraticVertex 800, 500, 200, 800
616
+ END
617
+ assert_p5_fill src, 'endShape'
618
+ assert_p5_stroke src, 'endShape'
619
+ assert_p5_fill_stroke src, 'endShape'
620
+ assert_p5_fill src, 'endShape CLOSE'
621
+ assert_p5_stroke src, 'endShape CLOSE'
622
+ assert_p5_fill_stroke src, 'endShape CLOSE'
623
+
624
+ src = <<~END
625
+ beginShape
626
+ vertex 100, 100
627
+ quadraticVertex 800, 100, 500, 500
628
+ quadraticVertex 100, 800, 800, 800
629
+ END
630
+ assert_p5_fill src, 'endShape', threshold: THRESHOLD_TO_BE_FIXED
631
+ assert_p5_stroke src, 'endShape'
632
+ assert_p5_fill_stroke src, 'endShape', threshold: THRESHOLD_TO_BE_FIXED
633
+ assert_p5_fill src, 'endShape CLOSE', threshold: THRESHOLD_TO_BE_FIXED
634
+ assert_p5_stroke src, 'endShape CLOSE'
635
+ assert_p5_fill_stroke src, 'endShape CLOSE', threshold: THRESHOLD_TO_BE_FIXED
636
+ end
637
+
638
+ def test_contour()
639
+ src = <<~END
640
+ beginShape
641
+ vertex 100, 100
642
+ vertex 100, 900
643
+ vertex 900, 900
644
+ vertex 900, 100
645
+ beginContour
646
+ vertex 200, 200
647
+ vertex 800, 200
648
+ vertex 700, 700
649
+ vertex 200, 800
650
+ endContour
651
+ END
652
+ assert_p5_fill src, 'endShape'
653
+ assert_p5_stroke src, 'endShape'
654
+ assert_p5_fill_stroke src, 'endShape'
655
+ assert_p5_fill src, 'endShape CLOSE'
656
+ assert_p5_stroke src, 'endShape CLOSE'
657
+ assert_p5_fill_stroke src, 'endShape CLOSE'
658
+ end
659
+
660
+ def test_pixels()
661
+ g = graphics 2, 2
662
+
663
+ g.loadPixels
664
+ assert_equal [0] * 4, g.pixels
665
+ assert_equal [0] * 4, g.getInternal__.pixels
666
+
667
+ g.pixels.replace [0xffff0000, 0xff00ff00, 0xff0000ff, 0xff000000]
668
+ assert_equal [0xffff0000, 0xff00ff00, 0xff0000ff, 0xff000000], g.pixels
669
+ assert_equal [0] * 4, g.getInternal__.pixels
670
+
671
+ g.updatePixels
672
+ assert_nil g.pixels
673
+ assert_equal [0xffff0000, 0xff00ff00, 0xff0000ff, 0xff000000], g.getInternal__.pixels
674
+ assert_nothing_raised {g.updatePixels}
675
+
676
+ g.loadPixels
677
+ g.pixels.replace [0xff000000]
678
+ assert_raise(ArgumentError) {g.updatePixels}
679
+ end
680
+
471
681
  def test_lerp()
472
682
  g = graphics
473
683
 
@@ -491,6 +701,16 @@ class TestGraphicsContext < Test::Unit::TestCase
491
701
  assert_equal c[ 70, 80, 90], g.lerpColor(c[10, 20, 30], c[50, 60, 70], 1.5)
492
702
  end
493
703
 
704
+ def test_createFont()
705
+ g = graphics
706
+
707
+ assert_not_nil g.createFont(nil, nil).getInternal__.name
708
+ assert_equal 'Arial', g.createFont('Arial', nil).getInternal__.name
709
+
710
+ assert_equal 12, g.createFont(nil, nil).getInternal__.size
711
+ assert_equal 10, g.createFont(nil, 10) .getInternal__.size
712
+ end
713
+
494
714
  def test_createShape_line()
495
715
  assert_equal_draw <<~EXPECTED, <<~ACTUAL
496
716
  line 100, 200, 800, 900