processing 0.5.31 → 0.5.33

Sign up to get free protection for your applications and to get access to all the features.
@@ -25,6 +25,14 @@ module Processing
25
25
  #
26
26
  TAU = PI * 2
27
27
 
28
+ # Processing mode for renderMode().
29
+ #
30
+ PROCESSING = :processing
31
+
32
+ # p5.js mode for renderMode().
33
+ #
34
+ P5JS = :p5js
35
+
28
36
  # RGBA format for createImage().
29
37
  #
30
38
  RGBA = :rgba
@@ -129,6 +137,18 @@ module Processing
129
137
  # Mode for textAlign().
130
138
  BASELINE = :baseline
131
139
 
140
+ # Mode for textureMode().
141
+ IMAGE = :image
142
+
143
+ # Mode for textureMode().
144
+ NORMAL = :normal
145
+
146
+ # Mode for textureWrap().
147
+ CLAMP = :clamp
148
+
149
+ # Mode for textureWrap().
150
+ REPEAT = :repeat
151
+
132
152
  # Filter type for filter()
133
153
  THRESHOLD = :threshold
134
154
 
@@ -247,29 +267,50 @@ module Processing
247
267
  # @private
248
268
  RAD2DEG__ = 180.0 / Math::PI
249
269
 
270
+ # @private
271
+ FONT_SIZE_DEFAULT__ = 12
272
+
273
+ # @private
274
+ FONT_SIZE_MAX__ = 256
275
+
250
276
  # @private
251
277
  def init__(image, painter)
252
- @drawing__ = false
253
- @colorMode__ = nil
254
- @hsbColor__ = false
255
- @colorMaxes__ = [1.0] * 4
256
- @angleMode__ = nil
257
- @angleScale__ = 1.0
258
- @rectMode__ = nil
259
- @ellipseMode__ = nil
260
- @imageMode__ = nil
261
- @shapeMode__ = nil
262
- @blendMode__ = nil
263
- @textAlignH__ = nil
264
- @textAlignV__ = nil
265
- @tint__ = nil
266
- @filter__ = nil
267
- @matrixStack__ = []
268
- @styleStack__ = []
269
- @fontCache__ = {}
278
+ @drawing__ = false
279
+ @renderMode__ = nil
280
+ @p5jsMode__ = false
281
+ @colorMode__ = nil
282
+ @hsbColor__ = false
283
+ @colorMaxes__ = [1.0] * 4
284
+ @angleMode__ = nil
285
+ @toRad__ = 1.0
286
+ @toDeg__ = 1.0
287
+ @fromRad__ = 1.0
288
+ @fromDeg__ = 1.0
289
+ @rectMode__ = nil
290
+ @ellipseMode__ = nil
291
+ @imageMode__ = nil
292
+ @shapeMode__ = nil
293
+ @blendMode__ = nil
294
+ @curveDetail__ = nil
295
+ @curveTightness__ = nil
296
+ @bezierDetail__ = nil
297
+ @textAlignH__ = nil
298
+ @textAlignV__ = nil
299
+ @textFont__ = nil
300
+ @tint__ = nil
301
+ @filter__ = nil
302
+ @pixels__ = nil
303
+ @random__ = nil
304
+ @nextGaussian__ = nil
305
+ @noiseSeed__ = nil
306
+ @noiseOctaves__ = nil
307
+ @noiseFallOff__ = nil
308
+ @matrixStack__ = []
309
+ @styleStack__ = []
270
310
 
271
311
  updateCanvas__ image, painter
272
312
 
313
+ renderMode PROCESSING
273
314
  colorMode RGB, 255
274
315
  angleMode RADIANS
275
316
  rectMode CORNER
@@ -280,11 +321,20 @@ module Processing
280
321
  strokeCap ROUND
281
322
  strokeJoin MITER
282
323
  textAlign LEFT
324
+ textFont createFont(nil, nil)
325
+ textureMode IMAGE
326
+ textureWrap CLAMP
283
327
 
284
- fill 255
285
- stroke 0
286
- strokeWeight 1
328
+ fill 255
329
+ stroke 0
330
+ strokeWeight 1
287
331
  noTint
332
+ curveDetail 20
333
+ curveTightness 0
334
+ bezierDetail 20
335
+ randomSeed Random.new_seed
336
+ noiseSeed Random.new_seed
337
+ noiseDetail 4, 0.5
288
338
  end
289
339
 
290
340
  # @private
@@ -300,6 +350,26 @@ module Processing
300
350
  @matrixStack__.clear
301
351
  @styleStack__.clear
302
352
  @drawing__ = true
353
+ setupMatrix__
354
+ end
355
+
356
+ # @private
357
+ def setupMatrix__()
358
+ w, h = width.to_f, height.to_f
359
+ x, y = w / 2.0, h / 2.0
360
+
361
+ fov, z = nil
362
+ if @p5jsMode__
363
+ z = 800
364
+ fov = degrees Math.atan(y / z) * 2.0
365
+ else
366
+ fov = 60
367
+ z = y / Math.tan(radians(fov) / 2.0)
368
+ end
369
+
370
+ @painter__.matrix =
371
+ Rays::Matrix.perspective(fov, w / h, z / 10.0, z * 10.0) *
372
+ Rays::Matrix.look_at(x, y, z, x, y, 0)
303
373
  end
304
374
 
305
375
  # @private
@@ -313,7 +383,7 @@ module Processing
313
383
  # @return [Numeric] width
314
384
  #
315
385
  def width()
316
- @image__.width
386
+ getInternal__.width
317
387
  end
318
388
 
319
389
  # Returns the height of the graphics object.
@@ -321,7 +391,7 @@ module Processing
321
391
  # @return [Numeric] height
322
392
  #
323
393
  def height()
324
- @image__.height
394
+ getInternal__.height
325
395
  end
326
396
 
327
397
  # Returns the width of the graphics object in pixels.
@@ -348,6 +418,20 @@ module Processing
348
418
  @painter__.pixel_density
349
419
  end
350
420
 
421
+ # Sets render mode.
422
+ #
423
+ # @param mode [PROCESSING, P5JS] compatible to Processing or p5.js
424
+ #
425
+ # @return [PROCESSING, P5JS] current mode
426
+ #
427
+ def renderMode(mode = nil)
428
+ if mode
429
+ @renderMode__ = mode
430
+ @p5jsMode__ = mode == P5JS
431
+ end
432
+ @renderMode__
433
+ end
434
+
351
435
  # Sets color mode and max color values.
352
436
  #
353
437
  # @overload colorMode(mode)
@@ -441,19 +525,56 @@ module Processing
441
525
  ((color >> 24) & 0xff) / 255.0 * @colorMaxes__[3]
442
526
  end
443
527
 
528
+ # Returns the hue value of the color.
529
+ #
530
+ # @param color [Numeric] color value
531
+ #
532
+ # @return [Numeric] the hue value
533
+ #
534
+ def hue(color)
535
+ h, = toRawColor__(color).to_hsv
536
+ h * (@hsbColor__ ? @colorMaxes__[0] : 1)
537
+ end
538
+
539
+ # Returns the saturation value of the color.
540
+ #
541
+ # @param color [Numeric] color value
542
+ #
543
+ # @return [Numeric] the saturation value
544
+ #
545
+ def saturation(color)
546
+ _, s, = toRawColor__(color).to_hsv
547
+ s * (@hsbColor__ ? @colorMaxes__[1] : 1)
548
+ end
549
+
550
+ # Returns the brightness value of the color.
551
+ #
552
+ # @param color [Numeric] color value
553
+ #
554
+ # @return [Numeric] the brightness value
555
+ #
556
+ def brightness(color)
557
+ _, _, b = toRawColor__(color).to_hsv
558
+ b * (@hsbColor__ ? @colorMaxes__[2] : 1)
559
+ end
560
+
444
561
  # @private
445
562
  private def toRGBA__(*args)
446
- a, b, c, d = args
563
+ a, b = args
447
564
  return parseColor__(a, b || alphaMax__) if a.kind_of?(String)
565
+ rawColor__(*args).to_a
566
+ end
448
567
 
568
+ # @private
569
+ def rawColor__(*args)
570
+ a, b, c, d = args
449
571
  rgba = case args.size
450
572
  when 1, 2 then [a, a, a, b || alphaMax__]
451
573
  when 3, 4 then [a, b, c, d || alphaMax__]
452
574
  else raise ArgumentError
453
575
  end
454
- rgba = rgba.map.with_index {|value, i| value / @colorMaxes__[i]}
455
- color = @hsbColor__ ? Rays::Color.hsv(*rgba) : Rays::Color.new(*rgba)
456
- color.to_a
576
+ rgba = rgba.map.with_index {|value, i| value / @colorMaxes__[i]}
577
+ @hsbColor__ ? Rays::Color.hsv(*rgba) : Rays::Color.new(*rgba)
457
578
  end
458
579
 
459
580
  # @private
@@ -470,6 +591,15 @@ module Processing
470
591
  @colorMaxes__[3]
471
592
  end
472
593
 
594
+ # @private
595
+ private def toRawColor__(color)
596
+ Rays::Color.new(
597
+ ((color >> 16) & 0xff) / 255.0,
598
+ ((color >> 8) & 0xff) / 255.0,
599
+ ( color & 0xff) / 255.0,
600
+ ((color >> 24) & 0xff) / 255.0)
601
+ end
602
+
473
603
  # Sets angle mode.
474
604
  #
475
605
  # @param mode [RADIANS, DEGREES] RADIANS or DEGREES
@@ -479,37 +609,34 @@ module Processing
479
609
  def angleMode(mode = nil)
480
610
  if mode != nil
481
611
  @angleMode__ = mode
482
- @angleScale__ =
612
+ @toRad__, @toDeg__, @fromRad__, @fromDeg__ =
483
613
  case mode.downcase.to_sym
484
- when RADIANS then RAD2DEG__
485
- when DEGREES then 1.0
614
+ when RADIANS then [1.0, RAD2DEG__, 1.0, DEG2RAD__]
615
+ when DEGREES then [DEG2RAD__, 1.0, RAD2DEG__, 1.0]
486
616
  else raise ArgumentError, "invalid angle mode: #{mode}"
487
617
  end
488
618
  end
489
619
  @angleMode__
490
620
  end
491
621
 
622
+ # @private
623
+ def toRadians__(angle)
624
+ angle * @toRad__
625
+ end
626
+
492
627
  # @private
493
628
  def toDegrees__(angle)
494
- angle * @angleScale__
629
+ angle * @toDeg__
495
630
  end
496
631
 
497
632
  # @private
498
633
  def fromRadians__(radians)
499
- case @angleMode__
500
- when RADIANS then radians
501
- when DEGREES then radians * RAD2DEG__
502
- else raise "invalid angle mode: #{mode}"
503
- end
634
+ radians * @fromRad__
504
635
  end
505
636
 
506
637
  # @private
507
638
  def fromDegrees__(degrees)
508
- case @angleMode__
509
- when RADIANS then degrees * DEG2RAD__
510
- when DEGREES then degrees
511
- else raise "invalid angle mode: #{mode}"
512
- end
639
+ degrees * @fromDeg__
513
640
  end
514
641
 
515
642
  # Sets rect mode. Default is CORNER.
@@ -618,6 +745,11 @@ module Processing
618
745
  nil
619
746
  end
620
747
 
748
+ # @private
749
+ def getFill__()
750
+ @painter__.fill
751
+ end
752
+
621
753
  # Disables filling.
622
754
  #
623
755
  # @return [nil] nil
@@ -692,6 +824,52 @@ module Processing
692
824
  nil
693
825
  end
694
826
 
827
+ # Sets the resolution at which curves display.
828
+ # The default value is 20 while the minimum value is 3.
829
+ #
830
+ # @param detail [Numeric] resolution of the curves
831
+ #
832
+ # @return [nil] nil
833
+ #
834
+ # @see https://processing.org/reference/curveDetail_.html
835
+ # @see https://p5js.org/reference/#/p5/curveDetail
836
+ #
837
+ def curveDetail(detail)
838
+ detail = 3 if detail < 3
839
+ @curveDetail__ = detail
840
+ nil
841
+ end
842
+
843
+ # Sets the quality of curve forms.
844
+ #
845
+ # @param tightness [Numeric] determines how the curve fits to the vertex points
846
+ #
847
+ # @return [nil] nil
848
+ #
849
+ # @see https://processing.org/reference/curveTightness_.html
850
+ # @see https://p5js.org/reference/#/p5/curveTightness
851
+ #
852
+ def curveTightness(tightness)
853
+ @curveTightness__ = tightness
854
+ nil
855
+ end
856
+
857
+ # Sets the resolution at which Bezier's curve is displayed.
858
+ # The default value is 20.
859
+ #
860
+ # @param detail [Numeric] resolution of the curves
861
+ #
862
+ # @return [nil] nil
863
+ #
864
+ # @see https://processing.org/reference/bezierDetail_.html
865
+ # @see https://p5js.org/reference/#/p5/bezierDetail
866
+ #
867
+ def bezierDetail(detail)
868
+ detail = 1 if detail < 1
869
+ @bezierDetail__ = detail
870
+ nil
871
+ end
872
+
695
873
  # Sets fill color for drawing images.
696
874
  #
697
875
  # @overload tint(rgb)
@@ -723,6 +901,11 @@ module Processing
723
901
  @tint__ = nil
724
902
  end
725
903
 
904
+ # @private
905
+ def getTint__()
906
+ @tint__ ? toRGBA__(*@tint__) : 1
907
+ end
908
+
726
909
  # Limits the drawable rectangle.
727
910
  #
728
911
  # The parameters a, b, c, and d are determined by rectMode().
@@ -749,12 +932,14 @@ module Processing
749
932
  nil
750
933
  end
751
934
 
752
- # Sets font.
935
+ # Sets text font.
936
+ # (Passing a font name as the first parameter is deprecated)
753
937
  #
938
+ # @overload textFont()
754
939
  # @overload textFont(font)
755
- # @overload textFont(name)
940
+ # @overload textFont(name) [DEPRECATED]
756
941
  # @overload textFont(font, size)
757
- # @overload textFont(name, size)
942
+ # @overload textFont(name, size) [DEPRECATED]
758
943
  #
759
944
  # @param font [Font] font
760
945
  # @param name [String] font name
@@ -763,8 +948,17 @@ module Processing
763
948
  # @return [Font] current font
764
949
  #
765
950
  def textFont(font = nil, size = nil)
766
- setFont__ font, size if font || size
767
- Font.new @painter__.font
951
+ if font != nil || size != nil
952
+ size = FONT_SIZE_MAX__ if size && size > FONT_SIZE_MAX__
953
+ if font.nil? || font.kind_of?(String)
954
+ font = createFont font, size
955
+ elsif size
956
+ font.setSize__ size
957
+ end
958
+ @painter__.font = font.getInternal__
959
+ @textFont__ = font
960
+ end
961
+ @textFont__
768
962
  end
769
963
 
770
964
  # Sets text size.
@@ -774,8 +968,7 @@ module Processing
774
968
  # @return [nil] nil
775
969
  #
776
970
  def textSize(size)
777
- setFont__ nil, size
778
- nil
971
+ textFont @textFont__, size
779
972
  end
780
973
 
781
974
  def textWidth(str)
@@ -795,16 +988,60 @@ module Processing
795
988
  @textAlignV__ = vertical
796
989
  end
797
990
 
991
+ # Sets the spacing between lines of text in units of pixels.
992
+ #
993
+ # @overload textLeading()
994
+ # @overload textLeading(leading)
995
+ #
996
+ # @param leading [Numeric] the size in pixels for spacing between lines
997
+ #
998
+ # @return [Numeric] current spacing
999
+ #
1000
+ def textLeading(leading = nil)
1001
+ @painter__.line_height = leading if leading
1002
+ @painter__.line_height
1003
+ end
1004
+
1005
+ def texture(image)
1006
+ @painter__.texture image&.getInternal__
1007
+ nil
1008
+ end
1009
+
798
1010
  # @private
799
- def setFont__(fontOrName, size)
800
- name = case fontOrName
801
- when Font then fontOrName.name
802
- else fontOrName || @painter__.font.name
803
- end
804
- size ||= @painter__.font.size
805
- size = 256 if size > 256
806
- font = @fontCache__[[name, size]] ||= Rays::Font.new name, size
807
- @painter__.font = font
1011
+ def drawWithTexture__(&block)
1012
+ if @painter__.texture
1013
+ @painter__.push fill: getTint__, &block
1014
+ else
1015
+ block.call
1016
+ end
1017
+ end
1018
+
1019
+ # Sets the coordinate space for texture mapping.
1020
+ #
1021
+ # @param mode [IMAGE, NORMAL] image coordinate, or normalized coordinate
1022
+ #
1023
+ # @return [nil] nil
1024
+ #
1025
+ # @see https://processing.org/reference/textureMode_.html
1026
+ # @see https://p5js.org/reference/#/p5/textureMode
1027
+ #
1028
+ def textureMode(mode)
1029
+ @painter__.texcoord_mode = mode
1030
+ nil
1031
+ end
1032
+
1033
+ # Sets the texture wrapping mode.
1034
+ #
1035
+ # @param wrap [CLAMP, REPEAT] how texutres behave when go outside of the range
1036
+ #
1037
+ # @return [nil] nil
1038
+ #
1039
+ # @see https://processing.org/reference/textureWrap_.html
1040
+ # @see https://p5js.org/reference/#/p5/textureWrap
1041
+ #
1042
+ def textureWrap(wrap)
1043
+ @painter__.texcoord_wrap = wrap
1044
+ nil
808
1045
  end
809
1046
 
810
1047
  # Sets shader.
@@ -887,7 +1124,7 @@ module Processing
887
1124
  #
888
1125
  def point(x, y)
889
1126
  assertDrawing__
890
- @painter__.line x, y, x, y
1127
+ @painter__.point x, y
891
1128
  nil
892
1129
  end
893
1130
 
@@ -1070,7 +1307,9 @@ module Processing
1070
1307
  #
1071
1308
  def curve(cx1, cy1, x1, y1, x2, y2, cx2, cy2)
1072
1309
  assertDrawing__
1310
+ @painter__.nsegment = @curveDetail__
1073
1311
  @painter__.curve cx1, cy1, x1, y1, x2, y2, cx2, cy2
1312
+ @painter__.nsegment = 0
1074
1313
  nil
1075
1314
  end
1076
1315
 
@@ -1091,7 +1330,9 @@ module Processing
1091
1330
  #
1092
1331
  def bezier(x1, y1, cx1, cy1, cx2, cy2, x2, y2)
1093
1332
  assertDrawing__
1333
+ @painter__.nsegment = @bezierDetail__
1094
1334
  @painter__.bezier x1, y1, cx1, cy1, cx2, cy2, x2, y2
1335
+ @painter__.nsegment = 0
1095
1336
  nil
1096
1337
  end
1097
1338
 
@@ -1156,8 +1397,7 @@ module Processing
1156
1397
  def image(img, a, b, c = nil, d = nil)
1157
1398
  assertDrawing__
1158
1399
  x, y, w, h = toXYWH__ @imageMode__, a, b, c || img.width, d || img.height
1159
- tint = @tint__ ? toRGBA__(*@tint__) : 1
1160
- img.drawImage__ @painter__, x, y, w, h, fill: tint, stroke: :none
1400
+ img.drawImage__ @painter__, x, y, w, h, fill: getTint__, stroke: :none
1161
1401
  nil
1162
1402
  end
1163
1403
 
@@ -1182,11 +1422,13 @@ module Processing
1182
1422
  assertDrawing__
1183
1423
  return nil unless shp.isVisible
1184
1424
 
1185
- if c || d || @shapeMode__ != CORNER
1186
- x, y, w, h = toXYWH__ @shapeMode__, a, b, c || shp.width, d || shp.height
1187
- shp.draw__ @painter__, x, y, w, h
1188
- else
1189
- shp.draw__ @painter__, a, b
1425
+ drawWithTexture__ do |_|
1426
+ if c || d || @shapeMode__ != CORNER
1427
+ x, y, w, h = toXYWH__ @shapeMode__, a, b, c || shp.width, d || shp.height
1428
+ shp.draw__ @painter__, x, y, w, h
1429
+ else
1430
+ shp.draw__ @painter__, a, b
1431
+ end
1190
1432
  end
1191
1433
  nil
1192
1434
  end
@@ -1195,7 +1437,7 @@ module Processing
1195
1437
 
1196
1438
  # Begins drawing complex shapes.
1197
1439
  #
1198
- # @param mode [POINTS, LINES, TRIANGLES, TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, QUAD_STRIP, TESS]
1440
+ # @param type [POINTS, LINES, TRIANGLES, TRIANGLE_FAN, TRIANGLE_STRIP, QUADS, QUAD_STRIP, TESS]
1199
1441
  #
1200
1442
  # @return [nil] nil
1201
1443
  #
@@ -1217,9 +1459,10 @@ module Processing
1217
1459
  #
1218
1460
  # @see https://processing.org/reference/beginShape_.html
1219
1461
  #
1220
- def beginShape(mode = nil)
1221
- @shapeMode__, @shapePoints__ = mode, []
1222
- nil
1462
+ def beginShape(type = nil)
1463
+ raise "beginShape() cannot be called twice" if @drawingShape__
1464
+ @drawingShape__ = createShape
1465
+ @drawingShape__.beginShape type
1223
1466
  end
1224
1467
 
1225
1468
  # Ends drawing complex shapes.
@@ -1234,25 +1477,114 @@ module Processing
1234
1477
  # @see https://processing.org/reference/endShape_.html
1235
1478
  #
1236
1479
  def endShape(mode = nil)
1237
- raise "endShape() must be called after beginShape()" unless @shapePoints__
1238
- polygon = Shape.createPolygon__ @shapeMode__, @shapePoints__, mode == CLOSE
1239
- @painter__.polygon polygon if polygon
1240
- @shapeMode__ = @shapePoints__ = nil
1480
+ s = @drawingShape__ or raise "endShape() must be called after beginShape()"
1481
+ s.endShape mode
1482
+ shape s
1483
+ @drawingShape__ = nil
1241
1484
  nil
1242
1485
  end
1243
1486
 
1487
+ # Begins drawing a hole inside shape.
1488
+ #
1489
+ # @return [nil] nil
1490
+ #
1491
+ # @example
1492
+ # beginShape
1493
+ # vertex 10, 10
1494
+ # vertex 10, 50
1495
+ # vertex 50, 50
1496
+ # vertex 90, 10
1497
+ # beginContour
1498
+ # vertex 20, 20
1499
+ # vertex 30, 20
1500
+ # vertex 30, 30
1501
+ # vertex 20, 30
1502
+ # endContour
1503
+ # endShape CLOSE
1504
+ #
1505
+ # @see https://processing.org/reference/beginContour_.html
1506
+ # @see https://p5js.org/reference/#/p5/beginContour
1507
+ #
1508
+ def beginContour()
1509
+ (@drawingShape__ or raise "beginContour() must be called after beginShape()")
1510
+ .beginContour
1511
+ end
1512
+
1513
+ # Ends drawing a hole.
1514
+ #
1515
+ # @return [nil] nil
1516
+ #
1517
+ # @see https://processing.org/reference/endContour_.html
1518
+ # @see https://p5js.org/reference/#/p5/endContour
1519
+ #
1520
+ def endContour()
1521
+ (@drawingShape__ or raise "endContour() must be called after beginShape()")
1522
+ .endContour
1523
+ end
1524
+
1244
1525
  # Append vertex for shape polygon.
1245
1526
  #
1527
+ # @overload vertex(x, y)
1528
+ # @overload vertex(x, y, u, v)
1529
+ #
1246
1530
  # @param x [Numeric] x position of vertex
1247
1531
  # @param y [Numeric] y position of vertex
1532
+ # @param u [Numeric] u texture coordinate of vertex
1533
+ # @param v [Numeric] v texture coordinate of vertex
1248
1534
  #
1249
1535
  # @return [nil] nil
1250
1536
  #
1251
1537
  # @see https://processing.org/reference/vertex_.html
1538
+ # @see https://p5js.org/reference/#/p5/vertex
1539
+ #
1540
+ def vertex(x, y, u = nil, v = nil)
1541
+ (@drawingShape__ or raise "vertex() must be called after beginShape()")
1542
+ .vertex x, y, u, v
1543
+ end
1544
+
1545
+ # Append curve vertex for shape polygon.
1546
+ #
1547
+ # @param x [Numeric] x position of vertex
1548
+ # @param y [Numeric] y position of vertex
1549
+ #
1550
+ # @return [nil] nil
1551
+ #
1552
+ # @see https://processing.org/reference/curveVertex_.html
1553
+ # @see https://p5js.org/reference/#/p5/curveVertex
1252
1554
  #
1253
- def vertex(x, y)
1254
- raise "vertex() must be called after beginShape()" unless @shapePoints__
1255
- @shapePoints__ << x << y
1555
+ def curveVertex(x, y)
1556
+ (@drawingShape__ or raise "curveVertex() must be called after beginShape()")
1557
+ .curveVertex x, y
1558
+ end
1559
+
1560
+ # Append bezier vertex for shape polygon.
1561
+ #
1562
+ # @param x [Numeric] x position of vertex
1563
+ # @param y [Numeric] y position of vertex
1564
+ #
1565
+ # @return [nil] nil
1566
+ #
1567
+ # @see https://processing.org/reference/bezierVertex_.html
1568
+ # @see https://p5js.org/reference/#/p5/bezierVertex
1569
+ #
1570
+ def bezierVertex(x2, y2, x3, y3, x4, y4)
1571
+ (@drawingShape__ or raise "bezierVertex() must be called after beginShape()")
1572
+ .bezierVertex x2, y2, x3, y3, x4, y4
1573
+ end
1574
+
1575
+ # Append quadratic vertex for shape polygon.
1576
+ #
1577
+ # @param x [Numeric] x position of vertex
1578
+ # @param y [Numeric] y position of vertex
1579
+ #
1580
+ # @return [nil] nil
1581
+ #
1582
+ # @see https://processing.org/reference/quadraticVertex_.html
1583
+ # @see https://p5js.org/reference/#/p5/quadraticVertex
1584
+ #
1585
+ def quadraticVertex(cx, cy, x3, y3)
1586
+ (@drawingShape__ or raise "quadraticVertex() must be called after beginShape()")
1587
+ .quadraticVertex cx, cy, x3, y3
1256
1588
  end
1257
1589
 
1258
1590
  # Copies image.
@@ -1296,11 +1628,41 @@ module Processing
1296
1628
  #
1297
1629
  def blend(img = nil, sx, sy, sw, sh, dx, dy, dw, dh, mode)
1298
1630
  assertDrawing__
1299
- tint = @tint__ ? toRGBA__(*@tint__) : 1
1300
- img ||= self
1301
- img.drawImage__(
1631
+ (img || self).drawImage__(
1302
1632
  @painter__, sx, sy, sw, sh, dx, dy, dw, dh,
1303
- fill: tint, stroke: :none, blend_mode: mode)
1633
+ fill: getTint__, stroke: :none, blend_mode: mode)
1634
+ end
1635
+
1636
+ # Loads all pixels to the 'pixels' array.
1637
+ #
1638
+ # @return [nil] nil
1639
+ #
1640
+ def loadPixels()
1641
+ @pixels__ = getInternal__.pixels
1642
+ end
1643
+
1644
+ # Update the image pixels with the 'pixels' array.
1645
+ #
1646
+ # @return [nil] nil
1647
+ #
1648
+ def updatePixels(&block)
1649
+ return if !block && !@pixels__
1650
+ if block
1651
+ loadPixels
1652
+ block.call pixels
1653
+ end
1654
+ getInternal__.tap do |img|
1655
+ img.pixels = @pixels__
1656
+ img.paint {} # update texture and set modifiied
1657
+ end
1658
+ @pixels__ = nil
1659
+ end
1660
+
1661
+ # An array of all pixels.
1662
+ # Call loadPixels() before accessing the array.
1663
+ #
1664
+ def pixels()
1665
+ @pixels__
1304
1666
  end
1305
1667
 
1306
1668
  # Saves screen image to file.
@@ -1310,7 +1672,7 @@ module Processing
1310
1672
  # @return [nil] nil
1311
1673
  #
1312
1674
  def save(filename)
1313
- @window__.canvas_image.save filename
1675
+ getInternal__.save filename
1314
1676
  nil
1315
1677
  end
1316
1678
 
@@ -1360,6 +1722,42 @@ module Processing
1360
1722
  nil
1361
1723
  end
1362
1724
 
1725
+ def rotateX(angle)
1726
+ assertDrawing__
1727
+ @painter__.rotate toDegrees__(angle), 1, 0, 0
1728
+ nil
1729
+ end
1730
+
1731
+ def rotateY(angle)
1732
+ assertDrawing__
1733
+ @painter__.rotate toDegrees__(angle), 0, 1, 0
1734
+ nil
1735
+ end
1736
+
1737
+ def rotateZ(angle)
1738
+ assertDrawing__
1739
+ @painter__.rotate toDegrees__(angle), 0, 0, 1
1740
+ nil
1741
+ end
1742
+
1743
+ def shearX(angle)
1744
+ t = Math.tan toRadians__(angle)
1745
+ @painter__.matrix *= Rays::Matrix.new(
1746
+ 1, t, 0, 0,
1747
+ 0, 1, 0, 0,
1748
+ 0, 0, 1, 0,
1749
+ 0, 0, 0, 1)
1750
+ end
1751
+
1752
+ def shearY(angle)
1753
+ t = Math.tan toRadians__(angle)
1754
+ @painter__.matrix *= Rays::Matrix.new(
1755
+ 1, 0, 0, 0,
1756
+ t, 1, 0, 0,
1757
+ 0, 0, 1, 0,
1758
+ 0, 0, 0, 1)
1759
+ end
1760
+
1363
1761
  # Pushes the current transformation matrix to stack.
1364
1762
  #
1365
1763
  # @return [Object] result of the expression at the end of the block
@@ -1383,6 +1781,51 @@ module Processing
1383
1781
  nil
1384
1782
  end
1385
1783
 
1784
+ # Reset current transformation matrix with 2x3, or 4x4 matrix.
1785
+ #
1786
+ # @overload applyMatrix(array)
1787
+ # @overload applyMatrix(a, b, c, d, e, f)
1788
+ # @overload applyMatrix(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
1789
+ #
1790
+ # @param array [Array] 6 or 16 numbers which define the matrix
1791
+ # @param a [Numeric] number which defines the matrix
1792
+ # @param b [Numeric] number which defines the matrix
1793
+ # @param c [Numeric] number which defines the matrix
1794
+ # @param d [Numeric] number which defines the matrix
1795
+ # @param e [Numeric] number which defines the matrix
1796
+ # @param f [Numeric] number which defines the matrix
1797
+ # @param g [Numeric] number which defines the matrix
1798
+ # @param h [Numeric] number which defines the matrix
1799
+ # @param i [Numeric] number which defines the matrix
1800
+ # @param j [Numeric] number which defines the matrix
1801
+ # @param k [Numeric] number which defines the matrix
1802
+ # @param l [Numeric] number which defines the matrix
1803
+ # @param m [Numeric] number which defines the matrix
1804
+ # @param n [Numeric] number which defines the matrix
1805
+ # @param o [Numeric] number which defines the matrix
1806
+ # @param p [Numeric] number which defines the matrix
1807
+ #
1808
+ # @return [nil] nil
1809
+ #
1810
+ def applyMatrix(*args)
1811
+ assertDrawing__
1812
+ args = args.first if args.first.kind_of?(Array)
1813
+ if args.size == 6
1814
+ a, b, c, d, e, f = args
1815
+ args = [
1816
+ a, b, 0, 0,
1817
+ c, d, 0, 0,
1818
+ 0, 0, 1, 0,
1819
+ e, f, 0, 1
1820
+ ]
1821
+ end
1822
+ raise ArgumentError unless args.size == 16
1823
+ m = Rays::Matrix.new(*args)
1824
+ m.transpose! if @p5jsMode__
1825
+ @painter__.matrix *= m
1826
+ nil
1827
+ end
1828
+
1386
1829
  # Reset current transformation matrix with identity matrix.
1387
1830
  #
1388
1831
  # @return [nil] nil
@@ -1393,6 +1836,17 @@ module Processing
1393
1836
  nil
1394
1837
  end
1395
1838
 
1839
+ # Prints matrix elements to console.
1840
+ #
1841
+ # @return [nil] nil
1842
+ #
1843
+ def printMatrix()
1844
+ m = @painter__.matrix
1845
+ m.transpose! if @p5jsMode__
1846
+ print "%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n" % m.to_a
1847
+ nil
1848
+ end
1849
+
1396
1850
  # Save current style values to the style stack.
1397
1851
  #
1398
1852
  # @return [Object] result of the expression at the end of the block
@@ -1405,19 +1859,34 @@ module Processing
1405
1859
  @painter__.stroke_width,
1406
1860
  @painter__.stroke_cap,
1407
1861
  @painter__.stroke_join,
1862
+ @painter__.miter_limit,
1863
+ @painter__.line_height!,
1408
1864
  @painter__.clip,
1409
1865
  @painter__.blend_mode,
1410
1866
  @painter__.font,
1867
+ @painter__.texture,
1868
+ @painter__.texcoord_mode,
1869
+ @painter__.texcoord_wrap,
1411
1870
  @painter__.shader,
1871
+ @colorMode__,
1412
1872
  @hsbColor__,
1413
1873
  @colorMaxes__,
1414
- @angleScale__,
1874
+ @angleMode__,
1875
+ @toRad__,
1876
+ @toDeg__,
1877
+ @fromRad__,
1878
+ @fromDeg__,
1415
1879
  @rectMode__,
1416
1880
  @ellipseMode__,
1417
1881
  @imageMode__,
1418
1882
  @shapeMode__,
1883
+ @blendMode__,
1884
+ @curveDetail__,
1885
+ @curveTightness__,
1886
+ @bezierDetail__,
1419
1887
  @textAlignH__,
1420
1888
  @textAlignV__,
1889
+ @textFont__,
1421
1890
  @tint__,
1422
1891
  ]
1423
1892
  block.call if block
@@ -1437,20 +1906,36 @@ module Processing
1437
1906
  @painter__.stroke_width,
1438
1907
  @painter__.stroke_cap,
1439
1908
  @painter__.stroke_join,
1909
+ @painter__.miter_limit,
1910
+ @painter__.line_height,
1440
1911
  @painter__.clip,
1441
1912
  @painter__.blend_mode,
1442
1913
  @painter__.font,
1914
+ @painter__.texture,
1915
+ @painter__.texcoord_mode,
1916
+ @painter__.texcoord_wrap,
1443
1917
  @painter__.shader,
1918
+ @colorMode__,
1444
1919
  @hsbColor__,
1445
1920
  @colorMaxes__,
1446
- @angleScale__,
1921
+ @angleMode__,
1922
+ @toRad__,
1923
+ @toDeg__,
1924
+ @fromRad__,
1925
+ @fromDeg__,
1447
1926
  @rectMode__,
1448
1927
  @ellipseMode__,
1449
1928
  @imageMode__,
1450
1929
  @shapeMode__,
1930
+ @blendMode__,
1931
+ @curveDetail__,
1932
+ @curveTightness__,
1933
+ @bezierDetail__,
1451
1934
  @textAlignH__,
1452
1935
  @textAlignV__,
1936
+ @textFont__,
1453
1937
  @tint__ = @styleStack__.pop
1938
+ @textFont__.setSize__ @painter__.font.size
1454
1939
  nil
1455
1940
  end
1456
1941
 
@@ -1481,10 +1966,10 @@ module Processing
1481
1966
  end
1482
1967
 
1483
1968
  # @private
1484
- def drawImage__(painter, *args, **states)
1969
+ def drawImage__(painter, *args, image__: getInternal__, **states)
1485
1970
  shader = painter.shader || @filter__&.getInternal__
1486
1971
  painter.push shader: shader, **states do |_|
1487
- painter.image getInternal__, *args
1972
+ painter.image image__, *args
1488
1973
  end
1489
1974
  end
1490
1975
 
@@ -1827,6 +2312,98 @@ module Processing
1827
2312
  Math.atan2 y, x
1828
2313
  end
1829
2314
 
2315
+ # Evaluates the curve at point t for points a, b, c, d.
2316
+ #
2317
+ # @param a [Numeric] coordinate of first control point
2318
+ # @param b [Numeric] coordinate of first point on the curve
2319
+ # @param c [Numeric] coordinate of second point on the curve
2320
+ # @param d [Numeric] coordinate of second control point
2321
+ # @param t [Numeric] value between 0.0 and 1.0
2322
+ #
2323
+ # @return [Numeric] interpolated value
2324
+ #
2325
+ # @see https://processing.org/reference/curvePoint_.html
2326
+ # @see https://p5js.org/reference/#/p5/curvePoint
2327
+ #
2328
+ def curvePoint(a, b, c, d, t)
2329
+ s = @curveTightness__
2330
+ t3 = t * t * t
2331
+ t2 = t * t
2332
+ f1 = ( s - 1.0) / 2.0 * t3 + ( 1.0 - s) * t2 + (s - 1.0) / 2.0 * t
2333
+ f2 = ( s + 3.0) / 2.0 * t3 + (-5.0 - s) / 2.0 * t2 + 1.0
2334
+ f3 = (-3.0 - s) / 2.0 * t3 + ( s + 2.0) * t2 + (1.0 - s) / 2.0 * t
2335
+ f4 = ( 1.0 - s) / 2.0 * t3 + ( s - 1.0) / 2.0 * t2
2336
+ a * f1 + b * f2 + c * f3 + d * f4
2337
+ end
2338
+
2339
+ # Calculates the tangent of a point on a curve.
2340
+ #
2341
+ # @param a [Numeric] coordinate of first control point
2342
+ # @param b [Numeric] coordinate of first point on the curve
2343
+ # @param c [Numeric] coordinate of second point on the curve
2344
+ # @param d [Numeric] coordinate of second control point
2345
+ # @param t [Numeric] value between 0.0 and 1.0
2346
+ #
2347
+ # @return [Numeric] tangent value
2348
+ #
2349
+ # @see https://processing.org/reference/curveTangent_.html
2350
+ # @see https://p5js.org/reference/#/p5/curveTangent
2351
+ #
2352
+ def curveTangent(a, b, c, d, t)
2353
+ s = @curveTightness__
2354
+ tt3 = t * t * 3.0
2355
+ t2 = t * 2.0
2356
+ f1 = ( s - 1.0) / 2.0 * tt3 + ( 1.0 - s) * t2 + (s - 1.0) / 2.0
2357
+ f2 = ( s + 3.0) / 2.0 * tt3 + (-5.0 - s) / 2.0 * t2
2358
+ f3 = (-3.0 - s) / 2.0 * tt3 + ( s + 2.0) * t2 + (1.0 - s) / 2.0
2359
+ f4 = ( 1.0 - s) / 2.0 * tt3 + ( s - 1.0) / 2.0 * t2
2360
+ a * f1 + b * f2 + c * f3 + d * f4
2361
+ end
2362
+
2363
+ # Evaluates the Bezier at point t for points a, b, c, d.
2364
+ #
2365
+ # @param a [Numeric] coordinate of first point on the curve
2366
+ # @param b [Numeric] coordinate of first control point
2367
+ # @param c [Numeric] coordinate of second control point
2368
+ # @param d [Numeric] coordinate of second point on the curve
2369
+ # @param t [Numeric] value between 0.0 and 1.0
2370
+ #
2371
+ # @return [Numeric] interpolated value
2372
+ #
2373
+ # @see https://processing.org/reference/bezierPoint_.html
2374
+ # @see https://p5js.org/reference/#/p5/bezierPoint
2375
+ #
2376
+ def bezierPoint(a, b, c, d, t)
2377
+ tt = 1.0 - t
2378
+ tt ** 3.0 * a +
2379
+ tt ** 2.0 * b * 3.0 * t +
2380
+ t ** 2.0 * c * 3.0 * tt +
2381
+ t ** 3.0 * d
2382
+ end
2383
+
2384
+ # Calculates the tangent of a point on a Bezier curve.
2385
+ #
2386
+ # @param a [Numeric] coordinate of first point on the curve
2387
+ # @param b [Numeric] coordinate of first control point
2388
+ # @param c [Numeric] coordinate of second control point
2389
+ # @param d [Numeric] coordinate of second point on the curve
2390
+ # @param t [Numeric] value between 0.0 and 1.0
2391
+ #
2392
+ # @return [Numeric] tangent value
2393
+ #
2394
+ # @see https://processing.org/reference/bezierTangent_.html
2395
+ # @see https://p5js.org/reference/#/p5/bezierTangent
2396
+ #
2397
+ def bezierTangent(a, b, c, d, t)
2398
+ tt = 1.0 - t
2399
+ 3.0 * d * t ** 2.0 -
2400
+ 3.0 * c * t ** 2.0 +
2401
+ 6.0 * c * tt * t -
2402
+ 6.0 * b * tt * t +
2403
+ 3.0 * b * tt ** 2.0 -
2404
+ 3.0 * a * tt ** 2.0
2405
+ end
2406
+
1830
2407
  # Returns the perlin noise value.
1831
2408
  #
1832
2409
  # @overload noise(x)
@@ -1839,13 +2416,52 @@ module Processing
1839
2416
  #
1840
2417
  # @return [Numeric] noise value (0.0..1.0)
1841
2418
  #
2419
+ # @see https://processing.org/reference/noise_.html
2420
+ # @see https://p5js.org/reference/#/p5/noise
2421
+ #
1842
2422
  def noise(x, y = 0, z = 0)
1843
- Rays.perlin(x, y, z) / 2.0 + 0.5
2423
+ seed, falloff = @noiseSeed__, @noiseFallOff__
2424
+ amp = 0.5
2425
+ @noiseOctaves__.times.reduce(0) do |sum|
2426
+ value = (Rays.perlin(x, y, z, seed) / 2.0 + 0.5) * amp
2427
+ x *= 2
2428
+ y *= 2
2429
+ z *= 2
2430
+ amp *= falloff
2431
+ sum + value
2432
+ end
2433
+ end
2434
+
2435
+ # Sets the seed value for noise()
2436
+ #
2437
+ # @param seed [Numeric] seed value
2438
+ #
2439
+ # @return [nil] nil
2440
+ #
2441
+ # @see https://processing.org/reference/noiseSeed_.html
2442
+ # @see https://p5js.org/reference/#/p5/noiseSeed
2443
+ #
2444
+ def noiseSeed(seed)
2445
+ @noiseSeed__ = Random.new(seed).rand 0.0..1.0
2446
+ end
2447
+
2448
+ # Adjusts the character and level of detail produced by the Perlin noise function.
2449
+ #
2450
+ # @param lod [Numeric] number of octaves to be used by the noise
2451
+ # @param falloff [Numeric] falloff factor for each octave
2452
+ #
2453
+ # @return [nil] nil
2454
+ #
2455
+ # @see https://processing.org/reference/noiseDetail_.html
2456
+ # @see https://p5js.org/reference/#/p5/noiseDetail
2457
+ #
2458
+ def noiseDetail(lod, falloff = nil)
2459
+ @noiseOctaves__ = lod if lod && lod > 0
2460
+ @noiseFallOff__ = falloff if falloff && falloff > 0
1844
2461
  end
1845
2462
 
1846
2463
  # Returns a random number in range low...high
1847
2464
  #
1848
- # @overload random()
1849
2465
  # @overload random(high)
1850
2466
  # @overload random(low, high)
1851
2467
  # @overload random(choices)
@@ -1856,13 +2472,63 @@ module Processing
1856
2472
  #
1857
2473
  # @return [Float] random number
1858
2474
  #
2475
+ # @see https://processing.org/reference/random_.html
2476
+ # @see https://p5js.org/reference/#/p5/random
2477
+ #
1859
2478
  def random(*args)
1860
- return args.first.sample if args.first.kind_of? Array
1861
- high, low = args.reverse
1862
- rand (low || 0).to_f...(high || 1).to_f
2479
+ if args.first.kind_of? Array
2480
+ a = args.first
2481
+ a.empty? ? nil : a[@random__.rand a.size]
2482
+ else
2483
+ high, low = args.reverse
2484
+ @random__.rand (low || 0).to_f...(high || 1).to_f
2485
+ end
2486
+ end
2487
+
2488
+ # Sets the seed value for random()
2489
+ #
2490
+ # @param seed [Numeric] seed value
2491
+ #
2492
+ # @return [nil] nil
2493
+ #
2494
+ # @see https://processing.org/reference/randomSeed_.html
2495
+ # @see https://p5js.org/reference/#/p5/randomSeed
2496
+ #
2497
+ def randomSeed(seed)
2498
+ @random__ = Random.new seed
2499
+ @nextGaussian__ = nil
1863
2500
  end
1864
2501
 
1865
- # Creates a new vector.
2502
+ # Returns a random number fitting a Gaussian, or normal, distribution.
2503
+ #
2504
+ # @param mean [Numeric] mean
2505
+ # @param sd [Numeric] standard deviation
2506
+ #
2507
+ # @return [Float] random number
2508
+ #
2509
+ # @see https://processing.org/reference/randomGaussian_.html
2510
+ # @see https://p5js.org/reference/#/p5/randomGaussian
2511
+ #
2512
+ def randomGaussian(mean = 0, sd = 1)
2513
+ value =
2514
+ if @nextGaussian__
2515
+ x, @nextGaussian__ = @nextGaussian__, nil
2516
+ x
2517
+ else
2518
+ a, b, w = 0, 0, 1
2519
+ until w < 1
2520
+ a = random(2) - 1
2521
+ b = random(2) - 1
2522
+ w = a ** 2 + b ** 2
2523
+ end
2524
+ w = Math.sqrt(-2 * Math.log(w) / w)
2525
+ @randomGaussian__ = a * w
2526
+ b * w
2527
+ end
2528
+ value * sd + mean
2529
+ end
2530
+
2531
+ # Creates a new vector object.
1866
2532
  #
1867
2533
  # @overload createVector()
1868
2534
  # @overload createVector(x, y)
@@ -1878,7 +2544,17 @@ module Processing
1878
2544
  Vector.new(*args, context: self)
1879
2545
  end
1880
2546
 
1881
- # Creates a new image.
2547
+ # Creates a new font object.
2548
+ #
2549
+ # @param name [String] font name
2550
+ # @param size [Numeric] font size (max 256)
2551
+ #
2552
+ def createFont(name, size)
2553
+ size = FONT_SIZE_MAX__ if size && size > FONT_SIZE_MAX__
2554
+ Font.new Rays::Font.new(name, size || FONT_SIZE_DEFAULT__)
2555
+ end
2556
+
2557
+ # Creates a new image object.
1882
2558
  #
1883
2559
  # @overload createImage(w, h)
1884
2560
  # @overload createImage(w, h, format)
@@ -1895,7 +2571,7 @@ module Processing
1895
2571
  Image.new Rays::Image.new(w, h, colorspace).paint {background 0, 0}
1896
2572
  end
1897
2573
 
1898
- # Creates a new shape.
2574
+ # Creates a new shape object.
1899
2575
  #
1900
2576
  # @overload createShape()
1901
2577
  # @overload createShape(LINE, x1, y1, x2, y2)
@@ -1924,7 +2600,7 @@ module Processing
1924
2600
 
1925
2601
  # @private
1926
2602
  private def createLineShape__(x1, y1, x2, y2)
1927
- Shape.new Rays::Polygon.lines(x1, y1, x2, y2), context: self
2603
+ Shape.new Rays::Polygon.line(x1, y1, x2, y2), context: self
1928
2604
  end
1929
2605
 
1930
2606
  # @private
@@ -2014,6 +2690,23 @@ module Processing
2014
2690
  Capture.new(*args)
2015
2691
  end
2016
2692
 
2693
+ # Loads font from file.
2694
+ #
2695
+ # @param filename [String] file name to load font file
2696
+ #
2697
+ # @return [Font] loaded font object
2698
+ #
2699
+ # @see https://processing.org/reference/loadFont_.html
2700
+ # @see https://p5js.org/reference/#/p5/loadFont
2701
+ #
2702
+ def loadFont(filename)
2703
+ ext = File.extname filename
2704
+ raise "unsupported font type -- '#{ext}'" unless ext =~ /^\.?(ttf|otf)$/i
2705
+
2706
+ filename = httpGet__ filename, ext if filename =~ %r|^https?://|
2707
+ Font.new Rays::Font.load filename
2708
+ end
2709
+
2017
2710
  # Loads image.
2018
2711
  #
2019
2712
  # @param filename [String] file name to load image
@@ -2021,11 +2714,39 @@ module Processing
2021
2714
  #
2022
2715
  # @return [Image] loaded image object
2023
2716
  #
2717
+ # @see https://processing.org/reference/loadImage_.html
2718
+ # @see https://p5js.org/reference/#/p5/loadImage
2719
+ #
2024
2720
  def loadImage(filename, extension = nil)
2025
- filename = getImage__ filename, extension if filename =~ %r|^https?://|
2721
+ ext = extension || File.extname(filename)
2722
+ raise "unsupported image type -- '#{ext}'" unless ext =~ /^\.?(png|jpg|gif)$/i
2723
+
2724
+ filename = httpGet__ filename, ext if filename =~ %r|^https?://|
2026
2725
  Image.new Rays::Image.load filename
2027
2726
  end
2028
2727
 
2728
+ # Loads image on a new thread.
2729
+ # When the image is loading, its width and height will be 0.
2730
+ # If an error occurs while loading the image, its width and height wil be -1.
2731
+ #
2732
+ # @param filename [String] file name to load image
2733
+ # @param extension [String] type of image to load (ex. 'png')
2734
+ #
2735
+ # @return [Image] loading image object
2736
+ #
2737
+ # @see https://processing.org/reference/requestImage_.html
2738
+ #
2739
+ def requestImage(filename, extension = nil)
2740
+ img = Image.new nil
2741
+ Thread.new filename, extension do |fn, ext|
2742
+ loaded = loadImage(fn, ext) or raise
2743
+ img.setInternal__ loaded.getInternal__
2744
+ rescue
2745
+ img.setInternal__ nil, true
2746
+ end
2747
+ img
2748
+ end
2749
+
2029
2750
  # Loads shader file.
2030
2751
  #
2031
2752
  # @overload loadShader(fragPath)
@@ -2041,24 +2762,16 @@ module Processing
2041
2762
  end
2042
2763
 
2043
2764
  # @private
2044
- private def getImage__(uri, ext)
2045
- ext ||= File.extname uri
2046
- raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png|jpg|gif)$/i
2047
-
2765
+ private def httpGet__(uri, ext)
2048
2766
  tmpdir = tmpdir__
2049
2767
  path = tmpdir + Digest::SHA1.hexdigest(uri)
2050
2768
  path = path.sub_ext ext
2051
2769
 
2052
2770
  unless path.file?
2053
- URI.open uri do |input|
2054
- input.set_encoding nil# disable default_internal
2771
+ Net::HTTP.get_response URI.parse(uri) do |res|
2772
+ res.value # raise an error unless successful
2055
2773
  tmpdir.mkdir unless tmpdir.directory?
2056
- path.open('w') do |output|
2057
- output.set_encoding Encoding::ASCII_8BIT
2058
- while buf = input.read(2 ** 16)
2059
- output.write buf
2060
- end
2061
- end
2774
+ path.open('wb') {|file| res.read_body {|body| file.write body}}
2062
2775
  end
2063
2776
  end
2064
2777
  path.to_s