rubysketch 0.3.20 → 0.3.22

Sign up to get free protection for your applications and to get access to all the features.
@@ -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