rubysketch 0.3.20 → 0.3.22

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.
@@ -555,7 +555,7 @@ module RubySketch
555
555
  end
556
556
 
557
557
  # @private
558
- protected def getInternal__()
558
+ def getInternal__()
559
559
  @point
560
560
  end
561
561
 
@@ -592,6 +592,20 @@ module RubySketch
592
592
  @image.height
593
593
  end
594
594
 
595
+ # Applies an image filter.
596
+ #
597
+ # overload filter(shader)
598
+ # overload filter(type)
599
+ # overload filter(type, param)
600
+ #
601
+ # @param shader [Shader] a fragment shader to apply
602
+ # @param type [THRESHOLD, GRAY, INVERT, BLUR] filter type
603
+ # @param param [Numeric] a parameter for each filter
604
+ #
605
+ def filter(*args)
606
+ @filter = Shader.createFilter__(*args)
607
+ end
608
+
595
609
  # Resizes image.
596
610
  #
597
611
  # @param width [Numeric] width for resized image
@@ -624,10 +638,33 @@ module RubySketch
624
638
  # @return [nil] nil
625
639
  #
626
640
  def copy(img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
641
+ blend img, sx, sy, sw, sh, dx, dy, dw, dh, :normal
642
+ end
643
+
644
+ # Blends image.
645
+ #
646
+ # @overload blend(sx, sy, sw, sh, dx, dy, dw, dh, mode)
647
+ # @overload blend(img, sx, sy, sw, sh, dx, dy, dw, dh, mode)
648
+ #
649
+ # @param img [Image] image for blend source
650
+ # @param sx [Numeric] x position of source region
651
+ # @param sy [Numeric] y position of source region
652
+ # @param sw [Numeric] width of source region
653
+ # @param sh [Numeric] height of source region
654
+ # @param dx [Numeric] x position of destination region
655
+ # @param dy [Numeric] y position of destination region
656
+ # @param dw [Numeric] width of destination region
657
+ # @param dh [Numeric] height of destination region
658
+ # @param mode [BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, EXCLUSION, MULTIPLY, SCREEN, REPLACE] blend mode
659
+ #
660
+ # @return [nil] nil
661
+ #
662
+ def blend(img = nil, sx, sy, sw, sh, dx, dy, dw, dh, mode)
627
663
  img ||= self
628
664
  @image.paint do |painter|
629
- painter.image img.getInternal__, sx, sy, sw, sh, dx, dy, dw, dh
665
+ img.drawImage__ painter, sx, sy, sw, sh, dx, dy, dw, dh, blend_mode: mode
630
666
  end
667
+ nil
631
668
  end
632
669
 
633
670
  # Saves image to file.
@@ -643,6 +680,14 @@ module RubySketch
643
680
  @image
644
681
  end
645
682
 
683
+ # @private
684
+ def drawImage__(painter, *args, **states)
685
+ shader = painter.shader || @filter&.getInternal__
686
+ painter.push shader: shader, **states do |_|
687
+ painter.image getInternal__, *args
688
+ end
689
+ end
690
+
646
691
  end# Image
647
692
 
648
693
 
@@ -728,6 +773,159 @@ module RubySketch
728
773
  end# Touch
729
774
 
730
775
 
776
+ # Shader object.
777
+ #
778
+ class Shader
779
+
780
+ # Initialize shader object.
781
+ #
782
+ # @param vertSrc [String] vertex shader source
783
+ # @param fragSrc [String] fragment shader source
784
+ #
785
+ def initialize(vertSrc, fragSrc)
786
+ @shader = Rays::Shader.new fragSrc, vertSrc, ENV__
787
+ end
788
+
789
+ # Sets uniform variables.
790
+ #
791
+ # @overload set(name, a)
792
+ # @overload set(name, a, b)
793
+ # @overload set(name, a, b, c)
794
+ # @overload set(name, a, b, c, d)
795
+ # @overload set(name, nums)
796
+ # @overload set(name, vec)
797
+ # @overload set(name, vec, ncoords)
798
+ # @overload set(name, tex)
799
+ #
800
+ # @param name [String] uniform variable name
801
+ # @param a [Numeric] int or float value
802
+ # @param b [Numeric] int or float value
803
+ # @param c [Numeric] int or float value
804
+ # @param d [Numeric] int or float value
805
+ # @param nums [Array] int or float array
806
+ # @param vec [Vector] vector
807
+ # @param ncoords [Integer] number of coordinates, max 4
808
+ # @param tex [Image] texture image
809
+ #
810
+ def setUniform(name, *args)
811
+ arg = args.first
812
+ case
813
+ when Array === arg
814
+ @shader.uniform name, *arg
815
+ when Numeric === arg
816
+ @shader.uniform name, *args
817
+ when Vector === arg
818
+ vec, ncoords = args
819
+ @shader.uniform name, vec.getInternal__.to_a(ncoords || 3)
820
+ when arg.respond_to?(:getInternal__)
821
+ @shader.uniform name, arg.getInternal__
822
+ else
823
+ raise ArgumentError
824
+ end
825
+ end
826
+
827
+ alias set setUniform
828
+
829
+ # @private
830
+ def getInternal__()
831
+ @shader
832
+ end
833
+
834
+ # @private
835
+ ENV__ = {
836
+ attribute_position: [:vertex, :position],
837
+ attribute_texcoord: :texCoord,
838
+ attribute_color: :color,
839
+ varying_position: :vertPosition,
840
+ varying_texcoord: :vertTexCoord,
841
+ varying_color: :vertColor,
842
+ uniform_position_matrix: [:transform, :transformMatrix],
843
+ uniform_texcoord_matrix: :texMatrix,
844
+ uniform_texcoord_min: :texMin,
845
+ uniform_texcoord_max: :texMax,
846
+ uniform_texcoord_offset: :texOffset,
847
+ uniform_texture: [:texMap, :texture]
848
+ }.freeze
849
+
850
+ # @private
851
+ def self.createFilter__(*args)
852
+ case arg = args.shift
853
+ when Shader
854
+ arg
855
+ when :threshold
856
+ self.new(nil, <<~END).tap {|sh| sh.set :threshold, (args.shift || 0.5)}
857
+ uniform float threshold;
858
+ uniform sampler2D texMap;
859
+ varying vec4 vertTexCoord;
860
+ varying vec4 vertColor;
861
+ void main() {
862
+ vec4 col = texture2D(texMap, vertTexCoord.xy) * vertColor;
863
+ float gray = col.r * 0.3 + col.g * 0.59 + col.b * 0.11;
864
+ gl_FragColor = vec4(vec3(gray > threshold ? 1.0 : 0.0), 1.0);
865
+ }
866
+ END
867
+ when :gray
868
+ self.new nil, <<~END
869
+ uniform sampler2D texMap;
870
+ varying vec4 vertTexCoord;
871
+ varying vec4 vertColor;
872
+ void main() {
873
+ vec4 col = texture2D(texMap, vertTexCoord.xy);
874
+ float gray = col.r * 0.3 + col.g * 0.59 + col.b * 0.11;
875
+ gl_FragColor = vec4(vec3(gray), 1.0) * vertColor;
876
+ }
877
+ END
878
+ when :invert
879
+ self.new nil, <<~END
880
+ uniform sampler2D texMap;
881
+ varying vec4 vertTexCoord;
882
+ varying vec4 vertColor;
883
+ void main() {
884
+ vec4 col = texture2D(texMap, vertTexCoord.xy);
885
+ gl_FragColor = vec4(vec3(1.0 - col.rgb), 1.0) * vertColor;
886
+ }
887
+ END
888
+ when :blur
889
+ self.new(nil, <<~END).tap {|sh| sh.set :radius, (args.shift || 1).to_f}
890
+ #define PI 3.1415926538
891
+ uniform float radius;
892
+ uniform sampler2D texMap;
893
+ uniform vec3 texMin;
894
+ uniform vec3 texMax;
895
+ uniform vec3 texOffset;
896
+ varying vec4 vertTexCoord;
897
+ varying vec4 vertColor;
898
+ float gaussian(vec2 pos, float sigma) {
899
+ float s2 = sigma * sigma;
900
+ return 1.0 / (2.0 * PI * s2) * exp(-(dot(pos, pos) / (2.0 * s2)));
901
+ }
902
+ void main() {
903
+ float sigma = radius * 0.5;
904
+ vec3 color = vec3(0.0);
905
+ float total_weight = 0.0;
906
+ for (float y = -radius; y < radius; y += 1.0)
907
+ for (float x = -radius; x < radius; x += 1.0) {
908
+ vec2 offset = vec2(x, y);
909
+ float weight = gaussian(offset, sigma);
910
+ vec2 texcoord = vertTexCoord.xy + offset * texOffset.xy;
911
+ if (
912
+ texcoord.x < texMin.x || texMax.x < texcoord.x ||
913
+ texcoord.y < texMin.y || texMax.y < texcoord.y
914
+ ) continue;
915
+ color += texture2D(texMap, texcoord).rgb * weight;
916
+ total_weight += weight;
917
+ }
918
+ gl_FragColor = vec4(color / total_weight, 1.0) * vertColor;
919
+ }
920
+ END
921
+ else
922
+ nil
923
+ end
924
+ end
925
+
926
+ end# Shader
927
+
928
+
731
929
  # Camera object.
732
930
  #
733
931
  class Capture
@@ -813,14 +1011,31 @@ module RubySketch
813
1011
  @camera.image&.height || 0
814
1012
  end
815
1013
 
1014
+ # Applies an image filter.
1015
+ #
1016
+ # overload filter(shader)
1017
+ # overload filter(type)
1018
+ # overload filter(type, param)
1019
+ #
1020
+ # @param shader [Shader] a fragment shader to apply
1021
+ # @param type [THRESHOLD, GRAY, INVERT, BLUR] filter type
1022
+ # @param param [Numeric] a parameter for each filter
1023
+ #
1024
+ def filter(*args)
1025
+ @filter = Shader.createFilter__(*args)
1026
+ end
1027
+
816
1028
  # @private
817
1029
  def getInternal__()
818
- @camera.image || dummyImage__
1030
+ @camera.image || (@dummyImage ||= Rays::Image.new 1, 1)
819
1031
  end
820
1032
 
821
1033
  # @private
822
- private def dummyImage__()
823
- @dummy ||= Rays::Image.new 1, 1
1034
+ def drawImage__(painter, *args, **states)
1035
+ shader = painter.shader || @filter&.getInternal__
1036
+ painter.push shader: shader, **states do |_|
1037
+ painter.image getInternal__, *args
1038
+ end
824
1039
  end
825
1040
 
826
1041
  end# Capture
@@ -850,13 +1065,17 @@ module RubySketch
850
1065
  #
851
1066
  TAU = PI * 2
852
1067
 
853
- # RGB mode for colorMode().
1068
+ # RGBA format for createImage().
1069
+ #
1070
+ RGBA = :rgba
1071
+
1072
+ # RGB format for createImage, or RGB mode for colorMode().
854
1073
  #
855
- RGB = :rgb
1074
+ RGB = :rgb
856
1075
 
857
1076
  # HSB mode for colorMode().
858
1077
  #
859
- HSB = :hsb
1078
+ HSB = :hsb
860
1079
 
861
1080
  # Radian mode for angleMode().
862
1081
  #
@@ -949,6 +1168,18 @@ module RubySketch
949
1168
  # Mode for textAlign().
950
1169
  BASELINE = :baseline
951
1170
 
1171
+ # Filter type for filter()
1172
+ THRESHOLD = :threshold
1173
+
1174
+ # Filter type for filter()
1175
+ GRAY = :gray
1176
+
1177
+ # Filter type for filter()
1178
+ INVERT = :invert
1179
+
1180
+ # Filter type for filter()
1181
+ BLUR = :blur
1182
+
952
1183
  # Key codes.
953
1184
  ENTER = :enter
954
1185
  SPACE = :space
@@ -1009,6 +1240,8 @@ module RubySketch
1009
1240
  @imageMode__ = nil
1010
1241
  @textAlignH__ = nil
1011
1242
  @textAlignV__ = nil
1243
+ @tint__ = nil
1244
+ @filter__ = nil
1012
1245
  @matrixStack__ = []
1013
1246
  @styleStack__ = []
1014
1247
  @fontCache__ = {}
@@ -1021,11 +1254,14 @@ module RubySketch
1021
1254
  ellipseMode CENTER
1022
1255
  imageMode CORNER
1023
1256
  blendMode BLEND
1257
+ strokeCap ROUND
1258
+ strokeJoin MITER
1024
1259
  textAlign LEFT
1025
1260
 
1026
1261
  fill 255
1027
1262
  stroke 0
1028
1263
  strokeWeight 1
1264
+ noTint
1029
1265
  end
1030
1266
 
1031
1267
  # @private
@@ -1035,6 +1271,7 @@ module RubySketch
1035
1271
 
1036
1272
  # @private
1037
1273
  def beginDraw__()
1274
+ raise "call beginDraw() before drawing" if @drawing__
1038
1275
  @matrixStack__.clear
1039
1276
  @styleStack__.clear
1040
1277
  @drawing__ = true
@@ -1042,6 +1279,7 @@ module RubySketch
1042
1279
 
1043
1280
  # @private
1044
1281
  def endDraw__()
1282
+ raise unless @drawing__
1045
1283
  @drawing__ = false
1046
1284
  end
1047
1285
 
@@ -1186,6 +1424,17 @@ module RubySketch
1186
1424
  end
1187
1425
  end
1188
1426
 
1427
+ # Sets blend mode. Default is BLEND.
1428
+ #
1429
+ # @param mode [BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, EXCLUSION, MULTIPLY, SCREEN, REPLACE]
1430
+ #
1431
+ # @return [nil] nil
1432
+ #
1433
+ def blendMode(mode)
1434
+ @painter__.blend_mode = mode
1435
+ nil
1436
+ end
1437
+
1189
1438
  # Sets fill color.
1190
1439
  #
1191
1440
  # @overload fill(rgb)
@@ -1283,6 +1532,37 @@ module RubySketch
1283
1532
  nil
1284
1533
  end
1285
1534
 
1535
+ # Sets fill color for drawing images.
1536
+ #
1537
+ # @overload tint(rgb)
1538
+ # @overload tint(rgb, alpha)
1539
+ # @overload tint(gray)
1540
+ # @overload tint(gray, alpha)
1541
+ # @overload tint(r, g, b)
1542
+ # @overload tint(r, g, b, alpha)
1543
+ #
1544
+ # @param rgb [String] color code like '#00AAFF'
1545
+ # @param gray [Integer] gray value (0..255)
1546
+ # @param r [Integer] red value (0..255)
1547
+ # @param g [Integer] green value (0..255)
1548
+ # @param b [Integer] blue value (0..255)
1549
+ # @param alpha [Integer] alpha value (0..255)
1550
+ #
1551
+ # @return [nil] nil
1552
+ #
1553
+ def tint(*args)
1554
+ @tint__ = args
1555
+ nil
1556
+ end
1557
+
1558
+ # Resets tint color.
1559
+ #
1560
+ # @return [nil] nil
1561
+ #
1562
+ def noTint()
1563
+ @tint__ = nil
1564
+ end
1565
+
1286
1566
  # Limits the drawable rectangle.
1287
1567
  #
1288
1568
  # The parameters a, b, c, and d are determined by rectMode().
@@ -1309,17 +1589,6 @@ module RubySketch
1309
1589
  nil
1310
1590
  end
1311
1591
 
1312
- # Sets blend mode. Default is BLEND.
1313
- #
1314
- # @param mode [BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, EXCLUSION, MULTIPLY, SCREEN, REPLACE]
1315
- #
1316
- # @return [nil] nil
1317
- #
1318
- def blendMode(mode)
1319
- @painter__.blend_mode = mode
1320
- nil
1321
- end
1322
-
1323
1592
  # Sets font.
1324
1593
  #
1325
1594
  # @overload textFont(font)
@@ -1378,6 +1647,40 @@ module RubySketch
1378
1647
  @painter__.font = font
1379
1648
  end
1380
1649
 
1650
+ # Sets shader.
1651
+ #
1652
+ # @param shader [Shader] a shader to apply
1653
+ #
1654
+ # @return [nil] nil
1655
+ #
1656
+ def shader(shader)
1657
+ @painter__.shader shader&.getInternal__
1658
+ nil
1659
+ end
1660
+
1661
+ # Resets shader.
1662
+ #
1663
+ # @return [nil] nil
1664
+ #
1665
+ def resetShader()
1666
+ @painter__.no_shader
1667
+ nil
1668
+ end
1669
+
1670
+ # Applies an image filter to screen.
1671
+ #
1672
+ # overload filter(shader)
1673
+ # overload filter(type)
1674
+ # overload filter(type, param)
1675
+ #
1676
+ # @param shader [Shader] a shader to apply
1677
+ # @param type [THRESHOLD, GRAY, INVERT, BLUR] filter type
1678
+ # @param param [Numeric] a parameter for each filter
1679
+ #
1680
+ def filter(*args)
1681
+ @filter__ = Shader.createFilter__(*args)
1682
+ end
1683
+
1381
1684
  # Clears screen.
1382
1685
  #
1383
1686
  # @overload background(str)
@@ -1402,7 +1705,7 @@ module RubySketch
1402
1705
  if rgba[3] == 1
1403
1706
  @painter__.background(*rgba)
1404
1707
  else
1405
- @painter__.push fill: rgba, stroke: nil do |_|
1708
+ @painter__.push fill: rgba, stroke: :none do |_|
1406
1709
  @painter__.rect 0, 0, width, height
1407
1710
  end
1408
1711
  end
@@ -1418,9 +1721,7 @@ module RubySketch
1418
1721
  #
1419
1722
  def point(x, y)
1420
1723
  assertDrawing__
1421
- w = @painter__.stroke_width
1422
- w = 1 if w == 0
1423
- @painter__.ellipse x - (w / 2.0), y - (w / 2.0), w, w
1724
+ @painter__.line x, y, x, y
1424
1725
  nil
1425
1726
  end
1426
1727
 
@@ -1498,9 +1799,7 @@ module RubySketch
1498
1799
  # @return [nil] nil
1499
1800
  #
1500
1801
  def circle(x, y, extent)
1501
- assertDrawing__
1502
- @painter__.ellipse x, y, extent, extent
1503
- nil
1802
+ ellipse x, y, extent, extent
1504
1803
  end
1505
1804
 
1506
1805
  # Draws an arc.
@@ -1667,9 +1966,9 @@ module RubySketch
1667
1966
  #
1668
1967
  def image(img, a, b, c = nil, d = nil)
1669
1968
  assertDrawing__
1670
- i = img.getInternal__
1671
- x, y, w, h = toXYWH__ @imageMode__, a, b, c || i.width, d || i.height
1672
- @painter__.image i, x, y, w, h
1969
+ x, y, w, h = toXYWH__ @imageMode__, a, b, c || img.width, d || img.height
1970
+ tint = @tint__ ? toRGBA__(*@tint__) : 1
1971
+ img.drawImage__ @painter__, x, y, w, h, fill: tint, stroke: :none
1673
1972
  nil
1674
1973
  end
1675
1974
 
@@ -1691,9 +1990,39 @@ module RubySketch
1691
1990
  # @return [nil] nil
1692
1991
  #
1693
1992
  def copy(img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
1993
+ blend img, sx, sy, sw, sh, dx, dy, dw, dh, BLEND
1994
+ end
1995
+
1996
+ # Blends image.
1997
+ #
1998
+ # @overload blend(sx, sy, sw, sh, dx, dy, dw, dh, mode)
1999
+ # @overload blend(img, sx, sy, sw, sh, dx, dy, dw, dh, mode)
2000
+ #
2001
+ # @param img [Image] image for blend source
2002
+ # @param sx [Numrtic] x position of source region
2003
+ # @param sy [Numrtic] y position of source region
2004
+ # @param sw [Numrtic] width of source region
2005
+ # @param sh [Numrtic] height of source region
2006
+ # @param dx [Numrtic] x position of destination region
2007
+ # @param dy [Numrtic] y position of destination region
2008
+ # @param dw [Numrtic] width of destination region
2009
+ # @param dh [Numrtic] height of destination region
2010
+ # @param mode [BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, EXCLUSION, MULTIPLY, SCREEN, REPLACE] blend mode
2011
+ #
2012
+ # @return [nil] nil
2013
+ #
2014
+ def blend(img = nil, sx, sy, sw, sh, dx, dy, dw, dh, mode)
1694
2015
  assertDrawing__
1695
- src = img&.getInternal__ || @window__.canvas_image
1696
- @painter__.image src, sx, sy, sw, sh, dx, dy, dw, dh
2016
+ img ||= self
2017
+ img.drawImage__ @painter__, sx, sy, sw, sh, dx, dy, dw, dh, blend_mode: mode
2018
+ end
2019
+
2020
+ # Saves screen image to file.
2021
+ #
2022
+ # @param filename [String] file name to save image
2023
+ #
2024
+ def save(filename)
2025
+ @window__.canvas_image.save filename
1697
2026
  end
1698
2027
 
1699
2028
  # Applies translation matrix to current transformation matrix.
@@ -1749,11 +2078,10 @@ module RubySketch
1749
2078
  def pushMatrix(&block)
1750
2079
  assertDrawing__
1751
2080
  @matrixStack__.push @painter__.matrix
1752
- if block
1753
- block.call
1754
- popMatrix
1755
- end
2081
+ block.call if block
1756
2082
  nil
2083
+ ensure
2084
+ popMatrix if block
1757
2085
  end
1758
2086
 
1759
2087
  # Pops the current transformation matrix from stack.
@@ -1792,18 +2120,22 @@ module RubySketch
1792
2120
  @painter__.clip,
1793
2121
  @painter__.blend_mode,
1794
2122
  @painter__.font,
2123
+ @painter__.shader,
1795
2124
  @hsbColor__,
1796
2125
  @colorMaxes__,
1797
2126
  @angleScale__,
1798
2127
  @rectMode__,
1799
2128
  @ellipseMode__,
1800
- @imageMode__
2129
+ @imageMode__,
2130
+ @textAlignH__,
2131
+ @textAlignV__,
2132
+ @tint__,
2133
+ @filter__,
1801
2134
  ]
1802
- if block
1803
- block.call
1804
- popStyle
1805
- end
2135
+ block.call if block
1806
2136
  nil
2137
+ ensure
2138
+ popStyle if block
1807
2139
  end
1808
2140
 
1809
2141
  # Restore style values from the style stack.
@@ -1821,12 +2153,17 @@ module RubySketch
1821
2153
  @painter__.clip,
1822
2154
  @painter__.blend_mode,
1823
2155
  @painter__.font,
2156
+ @painter__.shader,
1824
2157
  @hsbColor__,
1825
2158
  @colorMaxes__,
1826
2159
  @angleScale__,
1827
2160
  @rectMode__,
1828
2161
  @ellipseMode__,
1829
- @imageMode__ = @styleStack__.pop
2162
+ @imageMode__,
2163
+ @textAlignH__,
2164
+ @textAlignV__,
2165
+ @tint__,
2166
+ @filter__ = @styleStack__.pop
1830
2167
  nil
1831
2168
  end
1832
2169
 
@@ -1837,10 +2174,9 @@ module RubySketch
1837
2174
  def push(&block)
1838
2175
  pushMatrix
1839
2176
  pushStyle
1840
- if block
1841
- block.call
1842
- pop
1843
- end
2177
+ block.call if block
2178
+ ensure
2179
+ pop if block
1844
2180
  end
1845
2181
 
1846
2182
  # Restore styles and transformations from stack.
@@ -1857,923 +2193,993 @@ module RubySketch
1857
2193
  @image__
1858
2194
  end
1859
2195
 
2196
+ # @private
2197
+ def drawImage__(painter, *args, **states)
2198
+ shader = painter.shader || @filter__&.getInternal__
2199
+ painter.push shader: shader, **states do |_|
2200
+ painter.image getInternal__, *args
2201
+ end
2202
+ end
2203
+
1860
2204
  # @private
1861
2205
  private def assertDrawing__()
1862
2206
  raise "call beginDraw() before drawing" unless @drawing__
1863
2207
  end
1864
2208
 
1865
- end# GraphicsContext
1866
-
1867
-
1868
- # Draws graphics into an offscreen buffer
1869
- #
1870
- class Graphics
1871
-
1872
- include GraphicsContext
2209
+ #
2210
+ # Utilities
2211
+ #
1873
2212
 
1874
- # Initialize graphics object.
2213
+ # Returns the absolute number of the value.
1875
2214
  #
1876
- def initialize(width, height)
1877
- image = Rays::Image.new width, height
1878
- init__ image, image.painter
2215
+ # @param value [Numeric] number
2216
+ #
2217
+ # @return [Numeric] absolute number
2218
+ #
2219
+ def abs(value)
2220
+ value.abs
1879
2221
  end
1880
2222
 
1881
- # Start drawing.
2223
+ # Returns the closest integer number greater than or equal to the value.
1882
2224
  #
1883
- def beginDraw(&block)
1884
- @painter__.__send__ :begin_paint
1885
- beginDraw__
1886
- push
1887
- if block
1888
- block.call
1889
- endDraw
1890
- end
2225
+ # @param value [Numeric] number
2226
+ #
2227
+ # @return [Numeric] rounded up number
2228
+ #
2229
+ def ceil(value)
2230
+ value.ceil
1891
2231
  end
1892
2232
 
1893
- # End drawing.
2233
+ # Returns the closest integer number less than or equal to the value.
1894
2234
  #
1895
- def endDraw()
1896
- pop
1897
- endDraw__
1898
- @painter__.__send__ :end_paint
2235
+ # @param value [Numeric] number
2236
+ #
2237
+ # @return [Numeric] rounded down number
2238
+ #
2239
+ def floor(value)
2240
+ value.floor
1899
2241
  end
1900
2242
 
1901
- end# Graphics
1902
-
2243
+ # Returns the closest integer number.
2244
+ #
2245
+ # @param value [Numeric] number
2246
+ #
2247
+ # @return [Numeric] rounded number
2248
+ #
2249
+ def round(value)
2250
+ value.round
2251
+ end
1903
2252
 
1904
- # Processing context
1905
- #
1906
- class Context
2253
+ # Returns the natural logarithm (the base-e logarithm) of a number.
2254
+ #
2255
+ # @param value [Numeric] number (> 0.0)
2256
+ #
2257
+ # @return [Numeric] result number
2258
+ #
2259
+ def log(n)
2260
+ Math.log n
2261
+ end
1907
2262
 
1908
- include GraphicsContext
2263
+ # Returns Euler's number e raised to the power of value.
2264
+ #
2265
+ # @param value [Numeric] number
2266
+ #
2267
+ # @return [Numeric] result number
2268
+ #
2269
+ def exp(n)
2270
+ Math.exp n
2271
+ end
1909
2272
 
1910
- Vector = Processing::Vector
1911
- Capture = Processing::Capture
1912
- Graphics = Processing::Graphics
2273
+ # Returns value raised to the power of exponent.
2274
+ #
2275
+ # @param value [Numeric] base number
2276
+ # @param exponent [Numeric] exponent number
2277
+ #
2278
+ # @return [Numeric] value ** exponent
2279
+ #
2280
+ def pow(value, exponent)
2281
+ value ** exponent
2282
+ end
1913
2283
 
1914
- # @private
1915
- @@context__ = nil
2284
+ # Returns squared value.
2285
+ #
2286
+ # @param value [Numeric] number
2287
+ #
2288
+ # @return [Numeric] squared value
2289
+ #
2290
+ def sq(value)
2291
+ value * value
2292
+ end
1916
2293
 
1917
- # @private
1918
- def self.context__()
1919
- @@context__
2294
+ # Returns squared value.
2295
+ #
2296
+ # @param value [Numeric] number
2297
+ #
2298
+ # @return [Numeric] squared value
2299
+ #
2300
+ def sqrt(value)
2301
+ Math.sqrt value
1920
2302
  end
1921
2303
 
1922
- # @private
1923
- def initialize(window)
1924
- @@context__ = self
1925
-
1926
- tmpdir__.tap {|dir| FileUtils.rm_r dir.to_s if dir.directory?}
1927
-
1928
- @window__ = window
1929
- init__(
1930
- @window__.canvas_image,
1931
- @window__.canvas_painter.paint {background 0.8})
1932
-
1933
- @loop__ = true
1934
- @redraw__ = false
1935
- @frameCount__ = 0
1936
- @key__ = nil
1937
- @keyCode__ = nil
1938
- @keysPressed__ = Set.new
1939
- @pointerPos__ =
1940
- @pointerPrevPos__ = Rays::Point.new 0
1941
- @pointersPressed__ = []
1942
- @touches__ = []
1943
- @motionGravity__ = createVector 0, 0
1944
-
1945
- @window__.before_draw = proc {beginDraw__}
1946
- @window__.after_draw = proc {endDraw__}
1947
-
1948
- drawFrame = -> {
1949
- updateCanvas__ @window__.canvas_image, @window__.canvas_painter
1950
- begin
1951
- push
1952
- @drawBlock__.call if @drawBlock__
1953
- ensure
1954
- pop
1955
- @frameCount__ += 1
1956
- end
1957
- }
1958
-
1959
- @window__.draw = proc do |e|
1960
- if @loop__ || @redraw__
1961
- @redraw__ = false
1962
- drawFrame.call
1963
- end
1964
- end
1965
-
1966
- updateKeyStates = -> event, pressed {
1967
- @key__ = event.chars
1968
- @keyCode__ = event.key
1969
- if pressed != nil
1970
- set, key = @keysPressed__, event.key
1971
- pressed ? set.add(key) : set.delete(key)
1972
- end
1973
- }
1974
-
1975
- mouseButtonMap = {
1976
- mouse_left: LEFT,
1977
- mouse_right: RIGHT,
1978
- mouse_middle: CENTER
1979
- }
1980
-
1981
- updatePointerStates = -> event, pressed = nil {
1982
- @pointerPrevPos__ = @pointerPos__
1983
- @pointerPos__ = event.pos.dup
1984
- @touches__ = event.pointers.map {|p| Touch.new(p.id, *p.pos.to_a)}
1985
- if pressed != nil
1986
- array = @pointersPressed__
1987
- event.types
1988
- .tap {|types| types.delete :mouse}
1989
- .map {|type| mouseButtonMap[type] || type}
1990
- .each {|type| pressed ? array.push(type) : array.delete(type)}
1991
- end
1992
- }
1993
-
1994
- @window__.key_down = proc do |e|
1995
- updateKeyStates.call e, true
1996
- @keyPressedBlock__&.call
1997
- @keyTypedBlock__&.call if @key__ && !@key__.empty?
1998
- end
1999
-
2000
- @window__.key_up = proc do |e|
2001
- updateKeyStates.call e, false
2002
- @keyReleasedBlock__&.call
2003
- end
2004
-
2005
- @window__.pointer_down = proc do |e|
2006
- updatePointerStates.call e, true
2007
- @pointerDownStartPos__ = @pointerPos__.dup
2008
- (@touchStartedBlock__ || @mousePressedBlock__)&.call
2009
- end
2010
-
2011
- @window__.pointer_up = proc do |e|
2012
- updatePointerStates.call e, false
2013
- (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
2014
- if startPos = @pointerDownStartPos__
2015
- @mouseClickedBlock__&.call if (@pointerPos__ - startPos).length < 3
2016
- @pointerDownStartPos__ = nil
2017
- end
2018
- end
2019
-
2020
- @window__.pointer_move = proc do |e|
2021
- updatePointerStates.call e
2022
- (@touchMovedBlock__ || @mouseMovedBlock__)&.call
2023
- end
2024
-
2025
- @window__.pointer_drag = proc do |e|
2026
- updatePointerStates.call e
2027
- (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
2028
- end
2029
-
2030
- @window__.motion = proc do |e|
2031
- @motionGravity__ = createVector(*e.gravity.to_a(3))
2032
- @motionBlock__&.call
2304
+ # Returns the magnitude (or length) of a vector.
2305
+ #
2306
+ # @overload mag(x, y)
2307
+ # @overload mag(x, y, z)
2308
+ #
2309
+ # @param x [Numeric] x of point
2310
+ # @param y [Numeric] y of point
2311
+ # @param z [Numeric] z of point
2312
+ #
2313
+ # @return [Numeric] magnitude
2314
+ #
2315
+ def mag(*args)
2316
+ x, y, z = *args
2317
+ case args.size
2318
+ when 2 then Math.sqrt x * x + y * y
2319
+ when 3 then Math.sqrt x * x + y * y + z * z
2320
+ else raise ArgumentError
2033
2321
  end
2034
2322
  end
2035
2323
 
2036
- # Defines setup block.
2324
+ # Returns distance between 2 points.
2037
2325
  #
2038
- # @return [nil] nil
2326
+ # @overload dist(x1, y1, x2, y2)
2327
+ # @overload dist(x1, y1, z1, x2, y2, z2)
2039
2328
  #
2040
- def setup(&block)
2041
- @window__.setup = block
2042
- nil
2329
+ # @param x1 [Numeric] x of first point
2330
+ # @param y1 [Numeric] y of first point
2331
+ # @param z1 [Numeric] z of first point
2332
+ # @param x2 [Numeric] x of second point
2333
+ # @param y2 [Numeric] y of second point
2334
+ # @param z2 [Numeric] z of second point
2335
+ #
2336
+ # @return [Numeric] distance between 2 points
2337
+ #
2338
+ def dist(*args)
2339
+ case args.size
2340
+ when 4
2341
+ x1, y1, x2, y2 = *args
2342
+ xx, yy = x2 - x1, y2 - y1
2343
+ Math.sqrt xx * xx + yy * yy
2344
+ when 3
2345
+ x1, y1, z1, x2, y2, z2 = *args
2346
+ xx, yy, zz = x2 - x1, y2 - y1, z2 - z1
2347
+ Math.sqrt xx * xx + yy * yy + zz * zz
2348
+ else raise ArgumentError
2349
+ end
2043
2350
  end
2044
2351
 
2045
- # Defines draw block.
2352
+ # Normalize the value from range start..stop into 0..1.
2046
2353
  #
2047
- # @return [nil] nil
2354
+ # @param value [Numeric] number to be normalized
2355
+ # @param start [Numeric] lower bound of the range
2356
+ # @param stop [Numeric] upper bound of the range
2048
2357
  #
2049
- def draw(&block)
2050
- @drawBlock__ = block if block
2051
- nil
2358
+ # @return [Numeric] normalized value between 0..1
2359
+ #
2360
+ def norm(value, start, stop)
2361
+ (value.to_f - start.to_f) / (stop.to_f - start.to_f)
2052
2362
  end
2053
2363
 
2054
- # Defines keyPressed block.
2364
+ # Returns the interpolated number between range start..stop.
2055
2365
  #
2056
- # @return [Boolean] is any key pressed or not
2366
+ # @param start [Numeric] lower bound of the range
2367
+ # @param stop [Numeric] upper bound of the range
2368
+ # @param amount [Numeric] amount to interpolate
2057
2369
  #
2058
- def keyPressed(&block)
2059
- @keyPressedBlock__ = block if block
2060
- not @keysPressed__.empty?
2370
+ # @return [Numeric] interporated number
2371
+ #
2372
+ def lerp(start, stop, amount)
2373
+ start + (stop - start) * amount
2061
2374
  end
2062
2375
 
2063
- # Defines keyReleased block.
2376
+ # Maps a number from range start1..stop1 to range start2..stop2.
2064
2377
  #
2065
- # @return [nil] nil
2378
+ # @param value [Numeric] number to be mapped
2379
+ # @param start1 [Numeric] lower bound of the range1
2380
+ # @param stop1 [Numeric] upper bound of the range1
2381
+ # @param start2 [Numeric] lower bound of the range2
2382
+ # @param stop2 [Numeric] upper bound of the range2
2066
2383
  #
2067
- def keyReleased(&block)
2068
- @keyReleasedBlock__ = block if block
2069
- nil
2384
+ # @return [Numeric] mapped number
2385
+ #
2386
+ def map(value, start1, stop1, start2, stop2)
2387
+ lerp start2, stop2, norm(value, start1, stop1)
2070
2388
  end
2071
2389
 
2072
- # Defines keyTyped block.
2390
+ # Returns minimum value.
2073
2391
  #
2074
- # @return [nil] nil
2392
+ # @overload min(a, b)
2393
+ # @overload min(a, b, c)
2394
+ # @overload min(array)
2075
2395
  #
2076
- def keyTyped(&block)
2077
- @keyTypedBlock__ = block if block
2078
- nil
2396
+ # @param a [Numeric] value to compare
2397
+ # @param b [Numeric] value to compare
2398
+ # @param c [Numeric] value to compare
2399
+ # @param array [Numeric] values to compare
2400
+ #
2401
+ # @return [Numeric] minimum value
2402
+ #
2403
+ def min(*args)
2404
+ args.flatten.min
2079
2405
  end
2080
2406
 
2081
- # Defines mousePressed block.
2407
+ # Returns maximum value.
2082
2408
  #
2083
- # @return [Boolean] is any mouse button pressed or not
2409
+ # @overload max(a, b)
2410
+ # @overload max(a, b, c)
2411
+ # @overload max(array)
2084
2412
  #
2085
- def mousePressed(&block)
2086
- @mousePressedBlock__ = block if block
2087
- not @pointersPressed__.empty?
2413
+ # @param a [Numeric] value to compare
2414
+ # @param b [Numeric] value to compare
2415
+ # @param c [Numeric] value to compare
2416
+ # @param array [Numeric] values to compare
2417
+ #
2418
+ # @return [Numeric] maximum value
2419
+ #
2420
+ def max(*args)
2421
+ args.flatten.max
2088
2422
  end
2089
2423
 
2090
- # Defines mouseReleased block.
2424
+ # Constrains the number between min..max.
2091
2425
  #
2092
- # @return [nil] nil
2426
+ # @param value [Numeric] number to be constrained
2427
+ # @param min [Numeric] lower bound of the range
2428
+ # @param max [Numeric] upper bound of the range
2093
2429
  #
2094
- def mouseReleased(&block)
2095
- @mouseReleasedBlock__ = block if block
2096
- nil
2430
+ # @return [Numeric] constrained number
2431
+ #
2432
+ def constrain(value, min, max)
2433
+ value < min ? min : (value > max ? max : value)
2097
2434
  end
2098
2435
 
2099
- # Defines mouseMoved block.
2436
+ # Converts degree to radian.
2100
2437
  #
2101
- # @return [nil] nil
2438
+ # @param degree [Numeric] degree to convert
2102
2439
  #
2103
- def mouseMoved(&block)
2104
- @mouseMovedBlock__ = block if block
2105
- nil
2440
+ # @return [Numeric] radian
2441
+ #
2442
+ def radians(degree)
2443
+ degree * DEG2RAD__
2106
2444
  end
2107
2445
 
2108
- # Defines mouseDragged block.
2446
+ # Converts radian to degree.
2109
2447
  #
2110
- # @return [nil] nil
2448
+ # @param radian [Numeric] radian to convert
2111
2449
  #
2112
- def mouseDragged(&block)
2113
- @mouseDraggedBlock__ = block if block
2114
- nil
2450
+ # @return [Numeric] degree
2451
+ #
2452
+ def degrees(radian)
2453
+ radian * RAD2DEG__
2115
2454
  end
2116
2455
 
2117
- # Defines mouseClicked block.
2456
+ # Returns the sine of an angle.
2118
2457
  #
2119
- # @return [nil] nil
2458
+ # @param angle [Numeric] angle in radians
2120
2459
  #
2121
- def mouseClicked(&block)
2122
- @mouseClickedBlock__ = block if block
2123
- nil
2460
+ # @return [Numeric] the sine
2461
+ #
2462
+ def sin(angle)
2463
+ Math.sin angle
2124
2464
  end
2125
2465
 
2126
- # Defines touchStarted block.
2466
+ # Returns the cosine of an angle.
2127
2467
  #
2128
- # @return [nil] nil
2468
+ # @param angle [Numeric] angle in radians
2129
2469
  #
2130
- def touchStarted(&block)
2131
- @touchStartedBlock__ = block if block
2132
- nil
2470
+ # @return [Numeric] the cosine
2471
+ #
2472
+ def cos(angle)
2473
+ Math.cos angle
2133
2474
  end
2134
2475
 
2135
- # Defines touchEnded block.
2476
+ # Returns the ratio of the sine and cosine of an angle.
2136
2477
  #
2137
- # @return [nil] nil
2478
+ # @param angle [Numeric] angle in radians
2138
2479
  #
2139
- def touchEnded(&block)
2140
- @touchEndedBlock__ = block if block
2141
- nil
2480
+ # @return [Numeric] the tangent
2481
+ #
2482
+ def tan(angle)
2483
+ Math.tan angle
2142
2484
  end
2143
2485
 
2144
- # Defines touchMoved block.
2486
+ # Returns the inverse of sin().
2145
2487
  #
2146
- # @return [nil] nil
2488
+ # @param value [Numeric] value for calculation
2147
2489
  #
2148
- def touchMoved(&block)
2149
- @touchMovedBlock__ = block if block
2150
- nil
2490
+ # @return [Numeric] the arc sine
2491
+ #
2492
+ def asin(value)
2493
+ Math.asin value
2151
2494
  end
2152
2495
 
2153
- # Defines motion block.
2496
+ # Returns the inverse of cos().
2154
2497
  #
2155
- # @return [nil] nil
2498
+ # @param value [Numeric] value for calculation
2156
2499
  #
2157
- def motion(&block)
2158
- @motionBlock__ = block if block
2159
- nil
2500
+ # @return [Numeric] the arc cosine
2501
+ #
2502
+ def acos(value)
2503
+ Math.acos value
2160
2504
  end
2161
2505
 
2162
- # Changes canvas size.
2506
+ # Returns the inverse of tan().
2163
2507
  #
2164
- # @param width [Integer] new width
2165
- # @param height [Integer] new height
2166
- # @param pixelDensity [Numeric] new pixel density
2508
+ # @param value [Numeric] value for valculation
2167
2509
  #
2168
- # @return [nil] nil
2510
+ # @return [Numeric] the arc tangent
2169
2511
  #
2170
- def size(width, height, pixelDensity: self.pixelDensity)
2171
- resizeCanvas__ :size, width, height, pixelDensity
2172
- nil
2512
+ def atan(value)
2513
+ Math.atan value
2173
2514
  end
2174
2515
 
2175
- # Changes canvas size.
2516
+ # Returns the angle from a specified point.
2176
2517
  #
2177
- # @param width [Integer] new width
2178
- # @param height [Integer] new height
2179
- # @param pixelDensity [Numeric] new pixel density
2518
+ # @param y [Numeric] y of the point
2519
+ # @param x [Numeric] x of the point
2180
2520
  #
2181
- # @return [nil] nil
2521
+ # @return [Numeric] the angle in radians
2182
2522
  #
2183
- def createCanvas(width, height, pixelDensity: self.pixelDensity)
2184
- resizeCanvas__ :createCanvas, width, height, pixelDensity
2185
- nil
2523
+ def atan2(y, x)
2524
+ Math.atan2 y, x
2186
2525
  end
2187
2526
 
2188
- # Changes and returns canvas pixel density.
2527
+ # Returns the perlin noise value.
2189
2528
  #
2190
- # @param density [Numeric] new pixel density
2529
+ # @overload noise(x)
2530
+ # @overload noise(x, y)
2531
+ # @overload noise(x, y, z)
2191
2532
  #
2192
- # @return [Numeric] current pixel density
2533
+ # @param x [Numeric] horizontal point in noise space
2534
+ # @param y [Numeric] vertical point in noise space
2535
+ # @param z [Numeric] depth point in noise space
2193
2536
  #
2194
- def pixelDensity(density = nil)
2195
- resizeCanvas__ :pixelDensity, width, height, density if density
2196
- @painter__.pixel_density
2537
+ # @return [Numeric] noise value (0.0..1.0)
2538
+ #
2539
+ def noise(x, y = 0, z = 0)
2540
+ Rays.perlin(x, y, z) / 2.0 + 0.5
2197
2541
  end
2198
2542
 
2199
- # @private
2200
- def resizeCanvas__(name, width, height, pixelDensity)
2201
- raise '#{name}() must be called on startup or setup block' if @started__
2202
-
2203
- @painter__.__send__ :end_paint
2204
- begin
2205
- @window__.__send__ :resize_canvas, width, height, pixelDensity
2206
- updateCanvas__ @window__.canvas_image, @window__.canvas_painter
2207
- ensure
2208
- @painter__.__send__ :begin_paint
2209
- end
2210
-
2211
- @window__.auto_resize = false
2543
+ # Returns a random number in range low...high
2544
+ #
2545
+ # @overload random()
2546
+ # @overload random(high)
2547
+ # @overload random(low, high)
2548
+ # @overload random(choices)
2549
+ #
2550
+ # @param low [Numeric] lower limit
2551
+ # @param high [Numeric] upper limit
2552
+ # @param choices [Array] array to choose from
2553
+ #
2554
+ # @return [Float] random number
2555
+ #
2556
+ def random(*args)
2557
+ return args.first.sample if args.first.kind_of? Array
2558
+ high, low = args.reverse
2559
+ rand (low || 0).to_f...(high || 1).to_f
2212
2560
  end
2213
2561
 
2214
- # Returns pixel density of display.
2562
+ # Creates a new vector.
2215
2563
  #
2216
- # @return [Numeric] pixel density
2564
+ # @overload createVector()
2565
+ # @overload createVector(x, y)
2566
+ # @overload createVector(x, y, z)
2217
2567
  #
2218
- def displayDensity()
2219
- @window__.painter.pixel_density
2220
- end
2221
-
2222
- # Returns window width.
2568
+ # @param x [Numeric] x of new vector
2569
+ # @param y [Numeric] y of new vector
2570
+ # @param z [Numeric] z of new vector
2223
2571
  #
2224
- # @return [Numeric] window width
2572
+ # @return [Vector] new vector
2225
2573
  #
2226
- def windowWidth()
2227
- @window__.width
2574
+ def createVector(*args)
2575
+ Vector.new(*args, context: self)
2228
2576
  end
2229
2577
 
2230
- # Returns window height.
2578
+ # Creates a new image.
2231
2579
  #
2232
- # @return [Numeric] window height
2580
+ # @overload createImage(w, h)
2581
+ # @overload createImage(w, h, format)
2233
2582
  #
2234
- def windowHeight()
2235
- @window__.height
2236
- end
2237
-
2238
- # Returns number of frames since program started.
2583
+ # @param w [Numeric] width of new image
2584
+ # @param h [Numeric] height of new image
2585
+ # @param format [RGB, RGBA] image format
2239
2586
  #
2240
- # @return [Integer] total number of frames
2587
+ # @return [Image] new image
2241
2588
  #
2242
- def frameCount()
2243
- @frameCount__
2589
+ def createImage(w, h, format = RGBA)
2590
+ colorspace = {RGB => Rays::RGB, RGBA => Rays::RGBA}[format]
2591
+ raise ArgumentError, "Unknown image format" unless colorspace
2592
+ Image.new Rays::Image.new(w, h, colorspace).paint {background 0, 0}
2244
2593
  end
2245
2594
 
2246
- # Returns number of frames per second.
2595
+ # Creates a new off-screen graphics context object.
2247
2596
  #
2248
- # @return [Float] frames per second
2597
+ # @param width [Numeric] width of graphics image
2598
+ # @param height [Numeric] height of graphics image
2249
2599
  #
2250
- def frameRate()
2251
- @window__.event.fps
2600
+ # @return [Graphics] graphics object
2601
+ #
2602
+ def createGraphics(width, height)
2603
+ Graphics.new width, height
2252
2604
  end
2253
2605
 
2254
- # Returns the last key that was pressed or released.
2606
+ # Creates a shader object.
2255
2607
  #
2256
- # @return [String] last key
2608
+ # @overload createShader(vertPath, fragPath)
2609
+ # @overload createShader(vertSource, fragSource)
2257
2610
  #
2258
- def key()
2259
- @key__
2260
- end
2261
-
2262
- # Returns the last key code that was pressed or released.
2611
+ # @param vertPath [String] vertex shader file path
2612
+ # @param fragPath [String] fragment shader file path
2613
+ # @param vertSource [String] vertex shader source
2614
+ # @param fragSource [String] fragment shader source
2263
2615
  #
2264
- # @return [Symbol] last key code
2616
+ # @return [Shader] shader object
2265
2617
  #
2266
- def keyCode()
2267
- @keyCode__
2618
+ def createShader(vert, frag)
2619
+ vert = File.read if vert && File.exist?(vert)
2620
+ frag = File.read if frag && File.exist?(frag)
2621
+ Shader.new vert, frag
2268
2622
  end
2269
2623
 
2270
- # Returns mouse x position
2624
+ # Creates a camera object as a video input device.
2271
2625
  #
2272
- # @return [Numeric] horizontal position of mouse
2626
+ # @return [Capture] camera object
2273
2627
  #
2274
- def mouseX()
2275
- @pointerPos__.x
2628
+ def createCapture(*args)
2629
+ Capture.new(*args)
2276
2630
  end
2277
2631
 
2278
- # Returns mouse y position
2632
+ # Loads image.
2279
2633
  #
2280
- # @return [Numeric] vertical position of mouse
2634
+ # @param filename [String] file name to load image
2635
+ # @param extension [String] type of image to load (ex. 'png')
2281
2636
  #
2282
- def mouseY()
2283
- @pointerPos__.y
2637
+ # @return [Image] loaded image object
2638
+ #
2639
+ def loadImage(filename, extension = nil)
2640
+ filename = getImage__ filename, extension if filename =~ %r|^https?://|
2641
+ Image.new Rays::Image.load filename
2284
2642
  end
2285
2643
 
2286
- # Returns mouse x position in previous frame
2644
+ # Loads shader file.
2287
2645
  #
2288
- # @return [Numeric] horizontal position of mouse
2646
+ # @overload loadShader(fragPath)
2647
+ # @overload loadShader(fragPath, vertPath)
2289
2648
  #
2290
- def pmouseX()
2291
- @pointerPrevPos__.x
2292
- end
2293
-
2294
- # Returns mouse y position in previous frame
2649
+ # @param fragPath [String] fragment shader file path
2650
+ # @param vertPath [String] vertex shader file path
2295
2651
  #
2296
- # @return [Numeric] vertical position of mouse
2652
+ # @return [Shader] loaded shader object
2297
2653
  #
2298
- def pmouseY()
2299
- @pointerPrevPos__.y
2654
+ def loadShader(fragPath, vertPath = nil)
2655
+ createShader vertPath, fragPath
2300
2656
  end
2301
2657
 
2302
- # Returns which mouse button was pressed
2303
- #
2304
- # @return [Numeric] LEFT, RIGHT, CENTER or 0
2305
- #
2306
- def mouseButton()
2307
- (@pointersPressed__ & [LEFT, RIGHT, CENTER]).last || 0
2658
+ # @private
2659
+ private def getImage__(uri, ext)
2660
+ ext ||= File.extname uri
2661
+ raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png|jpg|gif)$/i
2662
+
2663
+ tmpdir = tmpdir__
2664
+ path = tmpdir + Digest::SHA1.hexdigest(uri)
2665
+ path = path.sub_ext ext
2666
+
2667
+ unless path.file?
2668
+ URI.open uri do |input|
2669
+ input.set_encoding nil# disable default_internal
2670
+ tmpdir.mkdir unless tmpdir.directory?
2671
+ path.open('w') do |output|
2672
+ output.set_encoding Encoding::ASCII_8BIT
2673
+ while buf = input.read(2 ** 16)
2674
+ output.write buf
2675
+ end
2676
+ end
2677
+ end
2678
+ end
2679
+ path.to_s
2308
2680
  end
2309
2681
 
2310
- # Returns array of touches
2311
- #
2312
- # @return [Array] Touch objects
2313
- #
2314
- def touches()
2315
- @touches__
2682
+ # @private
2683
+ private def tmpdir__()
2684
+ Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
2316
2685
  end
2317
2686
 
2318
- # Returns vector for real world gravity
2319
- #
2320
- # @return [Vector] gravity vector
2687
+ end# GraphicsContext
2688
+
2689
+
2690
+ # Draws graphics into an offscreen buffer
2691
+ #
2692
+ class Graphics
2693
+
2694
+ include GraphicsContext
2695
+
2696
+ # Initialize graphics object.
2321
2697
  #
2322
- def motionGravity()
2323
- @motionGravity__
2698
+ def initialize(width, height)
2699
+ image = Rays::Image.new width, height
2700
+ init__ image, image.painter
2324
2701
  end
2325
2702
 
2326
- # Enables calling draw block on every frame.
2327
- #
2328
- # @return [nil] nil
2703
+ # Start drawing.
2329
2704
  #
2330
- def loop()
2331
- @loop__ = true
2705
+ def beginDraw(&block)
2706
+ beginDraw__
2707
+ @painter__.__send__ :begin_paint
2708
+ push
2709
+ if block
2710
+ block.call
2711
+ endDraw
2712
+ end
2332
2713
  end
2333
2714
 
2334
- # Disables calling draw block on every frame.
2335
- #
2336
- # @return [nil] nil
2715
+ # End drawing.
2337
2716
  #
2338
- def noLoop()
2339
- @loop__ = false
2717
+ def endDraw()
2718
+ pop
2719
+ @painter__.__send__ :end_paint
2720
+ endDraw__
2721
+ end
2722
+
2723
+ end# Graphics
2724
+
2725
+
2726
+ # Processing context
2727
+ #
2728
+ class Context
2729
+
2730
+ include GraphicsContext
2731
+
2732
+ Vector = Processing::Vector
2733
+ Capture = Processing::Capture
2734
+ Graphics = Processing::Graphics
2735
+ Shader = Processing::Shader
2736
+
2737
+ # @private
2738
+ @@context__ = nil
2739
+
2740
+ # @private
2741
+ def self.context__()
2742
+ @@context__
2340
2743
  end
2341
2744
 
2342
- # Calls draw block to redraw frame.
2343
- #
2344
- # @return [nil] nil
2345
- #
2346
- def redraw()
2347
- @redraw__ = true
2348
- end
2745
+ # @private
2746
+ def initialize(window)
2747
+ @@context__ = self
2748
+
2749
+ tmpdir__.tap {|dir| FileUtils.rm_r dir.to_s if dir.directory?}
2750
+
2751
+ @window__ = window
2752
+ init__(
2753
+ @window__.canvas_image,
2754
+ @window__.canvas_painter.paint {background 0.8})
2755
+
2756
+ @loop__ = true
2757
+ @redraw__ = false
2758
+ @frameCount__ = 0
2759
+ @key__ = nil
2760
+ @keyCode__ = nil
2761
+ @keysPressed__ = Set.new
2762
+ @pointerPos__ =
2763
+ @pointerPrevPos__ = Rays::Point.new 0
2764
+ @pointersPressed__ = []
2765
+ @touches__ = []
2766
+ @motionGravity__ = createVector 0, 0
2767
+
2768
+ @window__.before_draw = proc {beginDraw__}
2769
+ @window__.after_draw = proc {endDraw__}
2770
+ @window__.update_canvas = proc {|i, p| updateCanvas__ i, p}
2771
+
2772
+ @window__.instance_variable_set :@context, self
2773
+ def @window__.draw_screen(painter)
2774
+ @context.drawImage__ painter
2775
+ end
2776
+
2777
+ drawFrame = -> {
2778
+ begin
2779
+ push
2780
+ @drawBlock__.call if @drawBlock__
2781
+ ensure
2782
+ pop
2783
+ @frameCount__ += 1
2784
+ end
2785
+ }
2786
+
2787
+ @window__.draw = proc do |e|
2788
+ if @loop__ || @redraw__
2789
+ @redraw__ = false
2790
+ drawFrame.call
2791
+ end
2792
+ end
2793
+
2794
+ updateKeyStates = -> event, pressed {
2795
+ @key__ = event.chars
2796
+ @keyCode__ = event.key
2797
+ if pressed != nil
2798
+ set, key = @keysPressed__, event.key
2799
+ pressed ? set.add(key) : set.delete(key)
2800
+ end
2801
+ }
2802
+
2803
+ mouseButtonMap = {
2804
+ mouse_left: LEFT,
2805
+ mouse_right: RIGHT,
2806
+ mouse_middle: CENTER
2807
+ }
2808
+
2809
+ updatePointerStates = -> event, pressed = nil {
2810
+ @pointerPrevPos__ = @pointerPos__
2811
+ @pointerPos__ = event.pos.dup
2812
+ @touches__ = event.pointers.map {|p| Touch.new(p.id, *p.pos.to_a)}
2813
+ if pressed != nil
2814
+ array = @pointersPressed__
2815
+ event.types
2816
+ .tap {|types| types.delete :mouse}
2817
+ .map {|type| mouseButtonMap[type] || type}
2818
+ .each {|type| pressed ? array.push(type) : array.delete(type)}
2819
+ end
2820
+ }
2821
+
2822
+ @window__.key_down = proc do |e|
2823
+ updateKeyStates.call e, true
2824
+ @keyPressedBlock__&.call
2825
+ @keyTypedBlock__&.call if @key__ && !@key__.empty?
2826
+ end
2827
+
2828
+ @window__.key_up = proc do |e|
2829
+ updateKeyStates.call e, false
2830
+ @keyReleasedBlock__&.call
2831
+ end
2349
2832
 
2350
- #
2351
- # Utilities
2352
- #
2833
+ @window__.pointer_down = proc do |e|
2834
+ updatePointerStates.call e, true
2835
+ @pointerDownStartPos__ = @pointerPos__.dup
2836
+ (@touchStartedBlock__ || @mousePressedBlock__)&.call
2837
+ end
2353
2838
 
2354
- # Returns the absolute number of the value.
2355
- #
2356
- # @param value [Numeric] number
2357
- #
2358
- # @return [Numeric] absolute number
2359
- #
2360
- def abs(value)
2361
- value.abs
2362
- end
2839
+ @window__.pointer_up = proc do |e|
2840
+ updatePointerStates.call e, false
2841
+ (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
2842
+ if startPos = @pointerDownStartPos__
2843
+ @mouseClickedBlock__&.call if (@pointerPos__ - startPos).length < 3
2844
+ @pointerDownStartPos__ = nil
2845
+ end
2846
+ end
2363
2847
 
2364
- # Returns the closest integer number greater than or equal to the value.
2365
- #
2366
- # @param value [Numeric] number
2367
- #
2368
- # @return [Numeric] rounded up number
2369
- #
2370
- def ceil(value)
2371
- value.ceil
2372
- end
2848
+ @window__.pointer_move = proc do |e|
2849
+ updatePointerStates.call e
2850
+ (@touchMovedBlock__ || @mouseMovedBlock__)&.call
2851
+ end
2373
2852
 
2374
- # Returns the closest integer number less than or equal to the value.
2375
- #
2376
- # @param value [Numeric] number
2377
- #
2378
- # @return [Numeric] rounded down number
2379
- #
2380
- def floor(value)
2381
- value.floor
2853
+ @window__.pointer_drag = proc do |e|
2854
+ updatePointerStates.call e
2855
+ (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
2856
+ end
2857
+
2858
+ @window__.motion = proc do |e|
2859
+ @motionGravity__ = createVector(*e.gravity.to_a(3))
2860
+ @motionBlock__&.call
2861
+ end
2382
2862
  end
2383
2863
 
2384
- # Returns the closest integer number.
2385
- #
2386
- # @param value [Numeric] number
2864
+ # Defines setup block.
2387
2865
  #
2388
- # @return [Numeric] rounded number
2866
+ # @return [nil] nil
2389
2867
  #
2390
- def round(value)
2391
- value.round
2868
+ def setup(&block)
2869
+ @window__.setup = block
2870
+ nil
2392
2871
  end
2393
2872
 
2394
- # Returns the natural logarithm (the base-e logarithm) of a number.
2395
- #
2396
- # @param value [Numeric] number (> 0.0)
2873
+ # Defines draw block.
2397
2874
  #
2398
- # @return [Numeric] result number
2875
+ # @return [nil] nil
2399
2876
  #
2400
- def log(n)
2401
- Math.log n
2877
+ def draw(&block)
2878
+ @drawBlock__ = block if block
2879
+ nil
2402
2880
  end
2403
2881
 
2404
- # Returns Euler's number e raised to the power of value.
2405
- #
2406
- # @param value [Numeric] number
2882
+ # Defines keyPressed block.
2407
2883
  #
2408
- # @return [Numeric] result number
2884
+ # @return [Boolean] is any key pressed or not
2409
2885
  #
2410
- def exp(n)
2411
- Math.exp n
2886
+ def keyPressed(&block)
2887
+ @keyPressedBlock__ = block if block
2888
+ not @keysPressed__.empty?
2412
2889
  end
2413
2890
 
2414
- # Returns value raised to the power of exponent.
2415
- #
2416
- # @param value [Numeric] base number
2417
- # @param exponent [Numeric] exponent number
2891
+ # Defines keyReleased block.
2418
2892
  #
2419
- # @return [Numeric] value ** exponent
2893
+ # @return [nil] nil
2420
2894
  #
2421
- def pow(value, exponent)
2422
- value ** exponent
2895
+ def keyReleased(&block)
2896
+ @keyReleasedBlock__ = block if block
2897
+ nil
2423
2898
  end
2424
2899
 
2425
- # Returns squared value.
2426
- #
2427
- # @param value [Numeric] number
2900
+ # Defines keyTyped block.
2428
2901
  #
2429
- # @return [Numeric] squared value
2902
+ # @return [nil] nil
2430
2903
  #
2431
- def sq(value)
2432
- value * value
2904
+ def keyTyped(&block)
2905
+ @keyTypedBlock__ = block if block
2906
+ nil
2433
2907
  end
2434
2908
 
2435
- # Returns squared value.
2436
- #
2437
- # @param value [Numeric] number
2909
+ # Defines mousePressed block.
2438
2910
  #
2439
- # @return [Numeric] squared value
2911
+ # @return [Boolean] is any mouse button pressed or not
2440
2912
  #
2441
- def sqrt(value)
2442
- Math.sqrt value
2913
+ def mousePressed(&block)
2914
+ @mousePressedBlock__ = block if block
2915
+ not @pointersPressed__.empty?
2443
2916
  end
2444
2917
 
2445
- # Returns the magnitude (or length) of a vector.
2446
- #
2447
- # @overload mag(x, y)
2448
- # @overload mag(x, y, z)
2449
- #
2450
- # @param x [Numeric] x of point
2451
- # @param y [Numeric] y of point
2452
- # @param z [Numeric] z of point
2918
+ # Defines mouseReleased block.
2453
2919
  #
2454
- # @return [Numeric] magnitude
2920
+ # @return [nil] nil
2455
2921
  #
2456
- def mag(*args)
2457
- x, y, z = *args
2458
- case args.size
2459
- when 2 then Math.sqrt x * x + y * y
2460
- when 3 then Math.sqrt x * x + y * y + z * z
2461
- else raise ArgumentError
2462
- end
2922
+ def mouseReleased(&block)
2923
+ @mouseReleasedBlock__ = block if block
2924
+ nil
2463
2925
  end
2464
2926
 
2465
- # Returns distance between 2 points.
2466
- #
2467
- # @overload dist(x1, y1, x2, y2)
2468
- # @overload dist(x1, y1, z1, x2, y2, z2)
2469
- #
2470
- # @param x1 [Numeric] x of first point
2471
- # @param y1 [Numeric] y of first point
2472
- # @param z1 [Numeric] z of first point
2473
- # @param x2 [Numeric] x of second point
2474
- # @param y2 [Numeric] y of second point
2475
- # @param z2 [Numeric] z of second point
2927
+ # Defines mouseMoved block.
2476
2928
  #
2477
- # @return [Numeric] distance between 2 points
2929
+ # @return [nil] nil
2478
2930
  #
2479
- def dist(*args)
2480
- case args.size
2481
- when 4
2482
- x1, y1, x2, y2 = *args
2483
- xx, yy = x2 - x1, y2 - y1
2484
- Math.sqrt xx * xx + yy * yy
2485
- when 3
2486
- x1, y1, z1, x2, y2, z2 = *args
2487
- xx, yy, zz = x2 - x1, y2 - y1, z2 - z1
2488
- Math.sqrt xx * xx + yy * yy + zz * zz
2489
- else raise ArgumentError
2490
- end
2931
+ def mouseMoved(&block)
2932
+ @mouseMovedBlock__ = block if block
2933
+ nil
2491
2934
  end
2492
2935
 
2493
- # Normalize the value from range start..stop into 0..1.
2494
- #
2495
- # @param value [Numeric] number to be normalized
2496
- # @param start [Numeric] lower bound of the range
2497
- # @param stop [Numeric] upper bound of the range
2936
+ # Defines mouseDragged block.
2498
2937
  #
2499
- # @return [Numeric] normalized value between 0..1
2938
+ # @return [nil] nil
2500
2939
  #
2501
- def norm(value, start, stop)
2502
- (value.to_f - start.to_f) / (stop.to_f - start.to_f)
2940
+ def mouseDragged(&block)
2941
+ @mouseDraggedBlock__ = block if block
2942
+ nil
2503
2943
  end
2504
2944
 
2505
- # Returns the interpolated number between range start..stop.
2506
- #
2507
- # @param start [Numeric] lower bound of the range
2508
- # @param stop [Numeric] upper bound of the range
2509
- # @param amount [Numeric] amount to interpolate
2945
+ # Defines mouseClicked block.
2510
2946
  #
2511
- # @return [Numeric] interporated number
2947
+ # @return [nil] nil
2512
2948
  #
2513
- def lerp(start, stop, amount)
2514
- start + (stop - start) * amount
2949
+ def mouseClicked(&block)
2950
+ @mouseClickedBlock__ = block if block
2951
+ nil
2515
2952
  end
2516
2953
 
2517
- # Maps a number from range start1..stop1 to range start2..stop2.
2518
- #
2519
- # @param value [Numeric] number to be mapped
2520
- # @param start1 [Numeric] lower bound of the range1
2521
- # @param stop1 [Numeric] upper bound of the range1
2522
- # @param start2 [Numeric] lower bound of the range2
2523
- # @param stop2 [Numeric] upper bound of the range2
2954
+ # Defines touchStarted block.
2524
2955
  #
2525
- # @return [Numeric] mapped number
2956
+ # @return [nil] nil
2526
2957
  #
2527
- def map(value, start1, stop1, start2, stop2)
2528
- lerp start2, stop2, norm(value, start1, stop1)
2958
+ def touchStarted(&block)
2959
+ @touchStartedBlock__ = block if block
2960
+ nil
2529
2961
  end
2530
2962
 
2531
- # Returns minimum value.
2532
- #
2533
- # @overload min(a, b)
2534
- # @overload min(a, b, c)
2535
- # @overload min(array)
2536
- #
2537
- # @param a [Numeric] value to compare
2538
- # @param b [Numeric] value to compare
2539
- # @param c [Numeric] value to compare
2540
- # @param array [Numeric] values to compare
2963
+ # Defines touchEnded block.
2541
2964
  #
2542
- # @return [Numeric] minimum value
2965
+ # @return [nil] nil
2543
2966
  #
2544
- def min(*args)
2545
- args.flatten.min
2967
+ def touchEnded(&block)
2968
+ @touchEndedBlock__ = block if block
2969
+ nil
2546
2970
  end
2547
2971
 
2548
- # Returns maximum value.
2972
+ # Defines touchMoved block.
2549
2973
  #
2550
- # @overload max(a, b)
2551
- # @overload max(a, b, c)
2552
- # @overload max(array)
2974
+ # @return [nil] nil
2553
2975
  #
2554
- # @param a [Numeric] value to compare
2555
- # @param b [Numeric] value to compare
2556
- # @param c [Numeric] value to compare
2557
- # @param array [Numeric] values to compare
2976
+ def touchMoved(&block)
2977
+ @touchMovedBlock__ = block if block
2978
+ nil
2979
+ end
2980
+
2981
+ # Defines motion block.
2558
2982
  #
2559
- # @return [Numeric] maximum value
2983
+ # @return [nil] nil
2560
2984
  #
2561
- def max(*args)
2562
- args.flatten.max
2985
+ def motion(&block)
2986
+ @motionBlock__ = block if block
2987
+ nil
2563
2988
  end
2564
2989
 
2565
- # Constrains the number between min..max.
2990
+ # Changes canvas size.
2566
2991
  #
2567
- # @param value [Numeric] number to be constrained
2568
- # @param min [Numeric] lower bound of the range
2569
- # @param max [Numeric] upper bound of the range
2992
+ # @param width [Integer] new width
2993
+ # @param height [Integer] new height
2994
+ # @param pixelDensity [Numeric] new pixel density
2570
2995
  #
2571
- # @return [Numeric] constrained number
2996
+ # @return [nil] nil
2572
2997
  #
2573
- def constrain(value, min, max)
2574
- value < min ? min : (value > max ? max : value)
2998
+ def size(width, height, pixelDensity: self.pixelDensity)
2999
+ resizeCanvas__ :size, width, height, pixelDensity
3000
+ nil
2575
3001
  end
2576
3002
 
2577
- # Converts degree to radian.
3003
+ # Changes canvas size.
2578
3004
  #
2579
- # @param degree [Numeric] degree to convert
3005
+ # @param width [Integer] new width
3006
+ # @param height [Integer] new height
3007
+ # @param pixelDensity [Numeric] new pixel density
2580
3008
  #
2581
- # @return [Numeric] radian
3009
+ # @return [nil] nil
2582
3010
  #
2583
- def radians(degree)
2584
- degree * DEG2RAD__
3011
+ def createCanvas(width, height, pixelDensity: self.pixelDensity)
3012
+ resizeCanvas__ :createCanvas, width, height, pixelDensity
3013
+ nil
2585
3014
  end
2586
3015
 
2587
- # Converts radian to degree.
3016
+ # Changes title of window.
2588
3017
  #
2589
- # @param radian [Numeric] radian to convert
3018
+ # @param title [String] new title
2590
3019
  #
2591
- # @return [Numeric] degree
3020
+ # @return [nil] nil
2592
3021
  #
2593
- def degrees(radian)
2594
- radian * RAD2DEG__
3022
+ def setTitle(title)
3023
+ @window__.title = title
3024
+ nil
2595
3025
  end
2596
3026
 
2597
- # Returns the sine of an angle.
3027
+ # Changes and returns canvas pixel density.
2598
3028
  #
2599
- # @param angle [Numeric] angle in radians
3029
+ # @param density [Numeric] new pixel density
2600
3030
  #
2601
- # @return [Numeric] the sine
3031
+ # @return [Numeric] current pixel density
2602
3032
  #
2603
- def sin(angle)
2604
- Math.sin angle
3033
+ def pixelDensity(density = nil)
3034
+ resizeCanvas__ :pixelDensity, width, height, density if density
3035
+ @painter__.pixel_density
2605
3036
  end
2606
3037
 
2607
- # Returns the cosine of an angle.
2608
- #
2609
- # @param angle [Numeric] angle in radians
3038
+ # @private
3039
+ def resizeCanvas__(name, width, height, pixelDensity)
3040
+ raise '#{name}() must be called on startup or setup block' if @started__
3041
+
3042
+ @painter__.__send__ :end_paint
3043
+ @window__.resize_canvas width, height, pixelDensity
3044
+ @window__.auto_resize = false
3045
+ ensure
3046
+ @painter__.__send__ :begin_paint
3047
+ end
3048
+
3049
+ # Returns pixel density of display.
2610
3050
  #
2611
- # @return [Numeric] the cosine
3051
+ # @return [Numeric] pixel density
2612
3052
  #
2613
- def cos(angle)
2614
- Math.cos angle
3053
+ def displayDensity()
3054
+ @window__.painter.pixel_density
2615
3055
  end
2616
3056
 
2617
- # Returns the ratio of the sine and cosine of an angle.
2618
- #
2619
- # @param angle [Numeric] angle in radians
3057
+ # Returns window width.
2620
3058
  #
2621
- # @return [Numeric] the tangent
3059
+ # @return [Numeric] window width
2622
3060
  #
2623
- def tan(angle)
2624
- Math.tan angle
3061
+ def windowWidth()
3062
+ @window__.width
2625
3063
  end
2626
3064
 
2627
- # Returns the inverse of sin().
2628
- #
2629
- # @param value [Numeric] value for calculation
3065
+ # Returns window height.
2630
3066
  #
2631
- # @return [Numeric] the arc sine
3067
+ # @return [Numeric] window height
2632
3068
  #
2633
- def asin(value)
2634
- Math.asin value
3069
+ def windowHeight()
3070
+ @window__.height
2635
3071
  end
2636
3072
 
2637
- # Returns the inverse of cos().
2638
- #
2639
- # @param value [Numeric] value for calculation
3073
+ # Returns number of frames since program started.
2640
3074
  #
2641
- # @return [Numeric] the arc cosine
3075
+ # @return [Integer] total number of frames
2642
3076
  #
2643
- def acos(value)
2644
- Math.acos value
3077
+ def frameCount()
3078
+ @frameCount__
2645
3079
  end
2646
3080
 
2647
- # Returns the inverse of tan().
2648
- #
2649
- # @param value [Numeric] value for valculation
3081
+ # Returns number of frames per second.
2650
3082
  #
2651
- # @return [Numeric] the arc tangent
3083
+ # @return [Float] frames per second
2652
3084
  #
2653
- def atan(value)
2654
- Math.atan value
3085
+ def frameRate()
3086
+ @window__.event.fps
2655
3087
  end
2656
3088
 
2657
- # Returns the angle from a specified point.
2658
- #
2659
- # @param y [Numeric] y of the point
2660
- # @param x [Numeric] x of the point
3089
+ # Returns the last key that was pressed or released.
2661
3090
  #
2662
- # @return [Numeric] the angle in radians
3091
+ # @return [String] last key
2663
3092
  #
2664
- def atan2(y, x)
2665
- Math.atan2 y, x
3093
+ def key()
3094
+ @key__
2666
3095
  end
2667
3096
 
2668
- # Returns the perlin noise value.
3097
+ # Returns the last key code that was pressed or released.
2669
3098
  #
2670
- # @overload noise(x)
2671
- # @overload noise(x, y)
2672
- # @overload noise(x, y, z)
3099
+ # @return [Symbol] last key code
2673
3100
  #
2674
- # @param x [Numeric] horizontal point in noise space
2675
- # @param y [Numeric] vertical point in noise space
2676
- # @param z [Numeric] depth point in noise space
3101
+ def keyCode()
3102
+ @keyCode__
3103
+ end
3104
+
3105
+ # Returns mouse x position
2677
3106
  #
2678
- # @return [Numeric] noise value (0.0..1.0)
3107
+ # @return [Numeric] horizontal position of mouse
2679
3108
  #
2680
- def noise(x, y = 0, z = 0)
2681
- Rays.perlin(x, y, z) / 2.0 + 0.5
3109
+ def mouseX()
3110
+ @pointerPos__.x
2682
3111
  end
2683
3112
 
2684
- # Returns a random number in range low...high
3113
+ # Returns mouse y position
2685
3114
  #
2686
- # @overload random()
2687
- # @overload random(high)
2688
- # @overload random(low, high)
2689
- # @overload random(choices)
3115
+ # @return [Numeric] vertical position of mouse
2690
3116
  #
2691
- # @param low [Numeric] lower limit
2692
- # @param high [Numeric] upper limit
2693
- # @param choices [Array] array to choose from
3117
+ def mouseY()
3118
+ @pointerPos__.y
3119
+ end
3120
+
3121
+ # Returns mouse x position in previous frame
2694
3122
  #
2695
- # @return [Float] random number
3123
+ # @return [Numeric] horizontal position of mouse
2696
3124
  #
2697
- def random(*args)
2698
- return args.first.sample if args.first.kind_of? Array
2699
- high, low = args.reverse
2700
- rand (low || 0).to_f...(high || 1).to_f
3125
+ def pmouseX()
3126
+ @pointerPrevPos__.x
2701
3127
  end
2702
3128
 
2703
- # Creates a new vector.
3129
+ # Returns mouse y position in previous frame
2704
3130
  #
2705
- # @overload createVector()
2706
- # @overload createVector(x, y)
2707
- # @overload createVector(x, y, z)
3131
+ # @return [Numeric] vertical position of mouse
2708
3132
  #
2709
- # @param x [Numeric] x of new vector
2710
- # @param y [Numeric] y of new vector
2711
- # @param z [Numeric] z of new vector
3133
+ def pmouseY()
3134
+ @pointerPrevPos__.y
3135
+ end
3136
+
3137
+ # Returns which mouse button was pressed
2712
3138
  #
2713
- # @return [Vector] new vector
3139
+ # @return [Numeric] LEFT, RIGHT, CENTER or 0
2714
3140
  #
2715
- def createVector(*args)
2716
- Vector.new(*args, context: self)
3141
+ def mouseButton()
3142
+ (@pointersPressed__ & [LEFT, RIGHT, CENTER]).last || 0
2717
3143
  end
2718
3144
 
2719
- # Creates a camera object as a video input device.
3145
+ # Returns array of touches
2720
3146
  #
2721
- # @return [Capture] camera object
3147
+ # @return [Array] Touch objects
2722
3148
  #
2723
- def createCapture(*args)
2724
- Capture.new(*args)
3149
+ def touches()
3150
+ @touches__
2725
3151
  end
2726
3152
 
2727
- # Creates a new off-screen graphics context object.
2728
- #
2729
- # @param width [Numeric] width of graphics image
2730
- # @param height [Numeric] height of graphics image
3153
+ # Returns vector for real world gravity
2731
3154
  #
2732
- # @return [Graphics] graphics object
3155
+ # @return [Vector] gravity vector
2733
3156
  #
2734
- def createGraphics(width, height)
2735
- Graphics.new width, height
3157
+ def motionGravity()
3158
+ @motionGravity__
2736
3159
  end
2737
3160
 
2738
- # Loads image.
2739
- #
2740
- # @param filename [String] file name to load image
2741
- # @param extension [String] type of image to load (ex. 'png')
3161
+ # Enables calling draw block on every frame.
2742
3162
  #
2743
- # @return [Image] loaded image object
3163
+ # @return [nil] nil
2744
3164
  #
2745
- def loadImage(filename, extension = nil)
2746
- filename = getImage__ filename, extension if filename =~ %r|^https?://|
2747
- Image.new Rays::Image.load filename
3165
+ def loop()
3166
+ @loop__ = true
2748
3167
  end
2749
3168
 
2750
- # @private
2751
- private def getImage__(uri, ext)
2752
- ext ||= File.extname uri
2753
- raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
2754
-
2755
- tmpdir = tmpdir__
2756
- path = tmpdir + Digest::SHA1.hexdigest(uri)
2757
- path = path.sub_ext ext
2758
-
2759
- unless path.file?
2760
- URI.open uri do |input|
2761
- input.set_encoding nil# disable default_internal
2762
- tmpdir.mkdir unless tmpdir.directory?
2763
- path.open('w') do |output|
2764
- output.set_encoding Encoding::ASCII_8BIT
2765
- while buf = input.read(2 ** 16)
2766
- output.write buf
2767
- end
2768
- end
2769
- end
2770
- end
2771
- path.to_s
3169
+ # Disables calling draw block on every frame.
3170
+ #
3171
+ # @return [nil] nil
3172
+ #
3173
+ def noLoop()
3174
+ @loop__ = false
2772
3175
  end
2773
3176
 
2774
- # @private
2775
- private def tmpdir__()
2776
- Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
3177
+ # Calls draw block to redraw frame.
3178
+ #
3179
+ # @return [nil] nil
3180
+ #
3181
+ def redraw()
3182
+ @redraw__ = true
2777
3183
  end
2778
3184
 
2779
3185
  end# Context