rubysketch 0.3.3 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90fb6bf8a945c62f9ac122dc4df7515aa2ebf271cb100836c76cb8cc1d4f7c50
4
- data.tar.gz: 53e61d592dbc5090d98e3c6bb015d406f018683767997c3f2f4d53462a9f27b4
3
+ metadata.gz: b5824abb04b555aa085934c3eefb32dc0cf5a79c6bc48945d5706a260c46269d
4
+ data.tar.gz: 35d88e63413027b4c8c574b860c2dd9e443cb29f140e9820ec73bacaaf800f05
5
5
  SHA512:
6
- metadata.gz: deb1f851efbcfd3feff20a7495ad55c9ef3a2d1e9ee416d6b87de89069197cc397a64303c69929f212cb0dda658f739a6ca1f1e83bea3050afa219b889509a9d
7
- data.tar.gz: ba13f0ce8a03a0b86f1ad20078e0b473d2e6058a446a3059c21f8c9e5ccabcaa72f065bcbfee13bb7b105960f0e658b1ee3e609c44c1429f1d4a9851ce122eab
6
+ metadata.gz: 34eaeef4a6992cfa326e16bd58b07e27b4757876129d03d246b717d334620d87d6a412f61757545bd4db561f83f38d8dd9303d255276ae0a544a4731759d853c
7
+ data.tar.gz: f0f4d8498f19da6a602cb4b120e91cdaebb718e66d4980433cb2386e0ed45e47aeefd25adb2c03974a93fefe2f862783325cd8c1cf923174f8467825172d647b
@@ -0,0 +1,62 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ['v[0-9]*']
6
+
7
+ jobs:
8
+ release:
9
+ runs-on: macos-latest
10
+
11
+ steps:
12
+ - name: checkout
13
+ uses: actions/checkout@v2
14
+
15
+ - name: ruby 2.6
16
+ uses: actions/setup-ruby@v1
17
+ with:
18
+ ruby-version: 2.6.x
19
+
20
+ - name: install gems
21
+ run: |
22
+ gem install bundler
23
+ bundle install --jobs 4 --retry 3
24
+
25
+ - name: version
26
+ id: version
27
+ run: |
28
+ echo ::set-output name=value::$(ruby -e 'print "${{ github.ref }}"[/\/v([\w\.\-]+)/, 1]')
29
+
30
+ - name: create gem
31
+ run: rake clean gem
32
+
33
+ - name: create release
34
+ id: create_release
35
+ uses: actions/create-release@v1
36
+ env:
37
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38
+ with:
39
+ tag_name: ${{ github.ref }}
40
+ release_name: ${{ github.ref }}
41
+ draft: false
42
+ prerelease: false
43
+
44
+ - name: upload to releases
45
+ uses: actions/upload-release-asset@v1
46
+ env:
47
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48
+ with:
49
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
50
+ asset_path: ./rubysketch-${{ steps.version.outputs.value }}.gem
51
+ asset_name: rubysketch-${{ steps.version.outputs.value }}.gem
52
+ asset_content_type: application/zip
53
+
54
+ - name: upload to rubygems
55
+ env:
56
+ GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }}
57
+ run: |
58
+ mkdir -p $HOME/.gem
59
+ touch $HOME/.gem/credentials
60
+ chmod 0600 $HOME/.gem/credentials
61
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
62
+ rake upload
@@ -0,0 +1,27 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: macos-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+
16
+ - name: ruby 2.6
17
+ uses: actions/setup-ruby@v1
18
+ with:
19
+ ruby-version: 2.6.x
20
+
21
+ - name: install gems
22
+ run: |
23
+ gem install bundler
24
+ bundle install --jobs 4 --retry 3
25
+
26
+ - name: test
27
+ run: rake test
@@ -1,6 +1,40 @@
1
1
  # RubySketch ChangeLog
2
2
 
3
3
 
4
+ ## [0.3.8] - 2020-11-27
5
+
6
+ - Capture#initialize() can take requestWidth, requestHeight and cameraName
7
+ - add Capture#width and Capture#height
8
+
9
+
10
+ ## [0.3.7] - 2020-11-18
11
+
12
+ - add Capture class
13
+ - add log(), exp(), sqrt() and PI
14
+ - add examples/camera.rb
15
+ - add examples/breakout.rb
16
+ - fix error on calling image()
17
+
18
+
19
+ ## [0.3.6] - 2020-08-02
20
+
21
+ - random() can take array or nothing
22
+ - use github actions to release gem package
23
+
24
+
25
+ ## [0.3.5] - 2020-08-02
26
+
27
+ - add random()
28
+ - add sin(), cos(), tan(), asin(), acos(), atan() and atan2()
29
+ - make Vector class accessible from user script context
30
+ - fix error on calling rotate()
31
+
32
+
33
+ ## [0.3.4] - 2020-08-02
34
+
35
+ - delete Utility module
36
+
37
+
4
38
  ## [0.3.3] - 2020-08-01
5
39
 
6
40
  - add Vector class
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'yard'
4
+ gem 'reflexion'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.3
1
+ 0.3.8
@@ -0,0 +1,212 @@
1
+ %w[xot rays reflex rubysketch]
2
+ .map {|s| File.expand_path "../../#{s}/lib", __dir__}
3
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
4
+
5
+ require 'rubysketch-processing'
6
+
7
+
8
+ PADDING = 50
9
+ BRICK_COUNT = 10
10
+
11
+ $objs = []
12
+ $bar = nil
13
+ $gameover = false
14
+
15
+ setup do
16
+ addWalls
17
+ addBricks
18
+
19
+ colorMode HSB, 360, 100, 100
20
+ ellipseMode CORNER
21
+ background 0
22
+ noStroke
23
+ fill 0, 0, 100
24
+ end
25
+
26
+ draw do
27
+ background 0
28
+ $objs.each do |o|
29
+ o.update
30
+ o.draw
31
+ end
32
+ drawTexts
33
+ end
34
+
35
+ mousePressed do
36
+ start unless started?
37
+ end
38
+
39
+ mouseDragged do
40
+ $bar.pos.x = mouseX - $bar.w / 2 if $bar
41
+ end
42
+
43
+ def start()
44
+ $bar = Bar.new
45
+ $objs += [$bar, Ball.new($bar)]
46
+ end
47
+
48
+ def started?()
49
+ $bar
50
+ end
51
+
52
+ def gameover?()
53
+ started? &&
54
+ $objs.count {|o| o.kind_of? Ball} == 0
55
+ end
56
+
57
+ def cleared?()
58
+ started? && !gameover? &&
59
+ $objs.count {|o| o.kind_of? Brick} == 0
60
+ end
61
+
62
+ def addWalls()
63
+ left = Obj.new 0, 0, 10, height
64
+ top = Obj.new 0, 0, width, 10
65
+ right = Obj.new width - 10, 0, 10, height
66
+ bottom = Bottom.new 0, height - 10, width, 10
67
+ $objs += [top, bottom, left, right]
68
+ end
69
+
70
+ def addBricks()
71
+ brickW = (width - PADDING * 2) / BRICK_COUNT
72
+ 5.times do |y|
73
+ BRICK_COUNT.times do |x|
74
+ xx = PADDING + brickW * x
75
+ yy = PADDING + 30 * y
76
+ $objs.push Brick.new(xx, yy, brickW - 5, 20, y * 60)
77
+ end
78
+ end
79
+ end
80
+
81
+ def drawTexts()
82
+ push do
83
+ textAlign CENTER, CENTER
84
+
85
+ if !started?
86
+ fill 50, 100, 100
87
+ textSize 50
88
+ text "BREAKOUT", 0, 0, width, height
89
+ textSize 20
90
+ translate 0, 100
91
+ text "Tap to start!", 0, 0, width, height
92
+ elsif cleared?
93
+ fill 100, 80, 100
94
+ textSize 50
95
+ text "CLEAR!", 0, 0, width, height
96
+ elsif gameover?
97
+ fill 0, 20, 100
98
+ textSize 50
99
+ text "GAMEOVER", 0, 0, width, height
100
+ end
101
+ end
102
+ end
103
+
104
+ class Obj
105
+ attr_reader :pos, :w, :h, :vel
106
+
107
+ def initialize(x, y, w, h, vx = 0, vy = 0)
108
+ @pos = createVector x, y
109
+ @w, @h = w, h
110
+ @vel = createVector vx, vy
111
+ end
112
+
113
+ def update()
114
+ @pos.add @vel
115
+ end
116
+
117
+ def draw()
118
+ rect @pos.x, @pos.y, @w, @h
119
+ end
120
+
121
+ def bounds()
122
+ x, y = @pos.x, @pos.y
123
+ return x, y, x + @w, y + @h
124
+ end
125
+
126
+ def center()
127
+ createVector @pos.x + @w / 2, @pos.y + @h / 2
128
+ end
129
+ end
130
+
131
+ class Ball < Obj
132
+ def initialize(bar)
133
+ super bar.pos.x, bar.pos.y - bar.h, 20, 20
134
+ self.vel = createVector random(-1, 1), -1
135
+ end
136
+
137
+ def vel=(v)
138
+ @vel = v.dup.normalize.mult 8
139
+ end
140
+
141
+ def update()
142
+ b = bounds.dup
143
+ super
144
+ checkHit b
145
+ end
146
+
147
+ def checkHit(prevBounds)
148
+ x1, y1, x2, y2 = prevBounds
149
+ hitH = hitV = false
150
+ hits = []
151
+ $objs.each do |o|
152
+ next if o == self
153
+ next unless intersect? o
154
+ hits.push o
155
+ ox1, oy1, ox2, oy2 = o.bounds
156
+ hitH ||= !overlap?(x1, x2, ox1, ox2)
157
+ hitV ||= !overlap?(y1, y2, oy1, oy2)
158
+ end
159
+ vel.x *= -1 if hitH
160
+ vel.y *= -1 if hitV
161
+
162
+ hits.each {|o| hit o}
163
+ end
164
+
165
+ def intersect?(o)
166
+ x1, y1, x2, y2 = bounds
167
+ ox1, oy1, ox2, oy2 = o.bounds
168
+ overlap?(x1, x2, ox1, ox2) && overlap?(y1, y2, oy1, oy2)
169
+ end
170
+
171
+ def overlap?(a1, a2, b1, b2)
172
+ a1 <= b2 && b1 <= a2
173
+ end
174
+
175
+ def hit(o)
176
+ case o
177
+ when Bar then self.vel = center.sub o.center
178
+ when Brick then $objs.delete o
179
+ when Bottom then $objs.delete self unless cleared?
180
+ end
181
+ end
182
+ end
183
+
184
+ class Bar < Obj
185
+ def initialize()
186
+ w = 100
187
+ super (width - w) / 2, height - 50, w, 20
188
+ end
189
+ end
190
+
191
+ class Brick < Obj
192
+ def initialize(x, y, w, h, hue)
193
+ super x, y, w, h
194
+ @hue = hue
195
+ end
196
+
197
+ def draw()
198
+ push do
199
+ fill @hue, 50, 100
200
+ super
201
+ end
202
+ end
203
+ end
204
+
205
+ class Bottom < Obj
206
+ def draw()
207
+ push do
208
+ fill 0, 0, 50
209
+ super
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,14 @@
1
+ %w[xot rays reflex rubysketch]
2
+ .map {|s| File.expand_path "../../#{s}/lib", __dir__}
3
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
4
+
5
+ require 'rubysketch-processing'
6
+
7
+
8
+ cam = Capture.new 300, 200, Capture.list.last
9
+ cam.start
10
+
11
+ draw do
12
+ background 0
13
+ image cam, 0, 0
14
+ end
@@ -2,10 +2,18 @@ require 'rubysketch'
2
2
 
3
3
 
4
4
  begin
5
- include RubySketch::Processing::Context
5
+ window = RubySketch::Window.new {start}
6
+ context = RubySketch::Processing::Context.new window
6
7
 
7
- window = RubySketch::Window.new {start}
8
- setup__ window
8
+ (context.methods - Object.instance_methods).each do |method|
9
+ define_method method do |*args, &block|
10
+ context.__send__ method, *args, &block
11
+ end
12
+ end
13
+
14
+ context.class.constants.each do |const|
15
+ self.class.const_set const, context.class.const_get(const)
16
+ end
9
17
 
10
18
  window.__send__ :begin_draw
11
19
  at_exit do
@@ -6,6 +6,13 @@ module RubySketch
6
6
  module Processing
7
7
 
8
8
 
9
+ # @private
10
+ DEG2RAD__ = Math::PI / 180.0
11
+
12
+ # @private
13
+ RAD2DEG__ = 180.0 / Math::PI
14
+
15
+
9
16
  # Vector class.
10
17
  #
11
18
  class Vector
@@ -27,14 +34,14 @@ module RubySketch
27
34
  # @param v [Vector] vector object to copy
28
35
  # @param a [Array] array like [x, y, z]
29
36
  #
30
- def initialize (x = 0, y = 0, z = 0, context: context)
37
+ def initialize (x = 0, y = 0, z = 0, context: nil)
31
38
  @point = case x
32
39
  when Rays::Point then x.dup
33
40
  when Vector then x.getInternal__.dup
34
41
  when Array then Rays::Point.new x[0] || 0, x[1] || 0, x[2] || 0
35
42
  else Rays::Point.new x || 0, y || 0, z || 0
36
43
  end
37
- @context = context
44
+ @context = context || Context.context__
38
45
  end
39
46
 
40
47
  # Initializer for dup or clone
@@ -464,7 +471,7 @@ module RubySketch
464
471
  # @return [Vector] rotated this object
465
472
  #
466
473
  def rotate (angle)
467
- angle = @context ? @context.toAngle__(angle) : angle * Utility::RAD2DEG__
474
+ angle = @context ? @context.toAngle__(angle) : angle * RAD2DEG__
468
475
  @point.rotate! angle
469
476
  self
470
477
  end
@@ -721,25 +728,127 @@ module RubySketch
721
728
  end# Touch
722
729
 
723
730
 
731
+ # Camera object.
732
+ #
733
+ class Capture
734
+
735
+ # Returns a list of available camera device names
736
+ #
737
+ # @return [Array] device name list
738
+ #
739
+ def self.list ()
740
+ Rays::Camera.device_names
741
+ end
742
+
743
+ # Initialize camera object.
744
+ #
745
+ # @overload Capture.new()
746
+ # @overload Capture.new(cameraName)
747
+ # @overload Capture.new(requestWidth, requestHeight)
748
+ # @overload Capture.new(requestWidth, requestHeight, cameraName)
749
+ #
750
+ # @param requestWidth [Integer] captured image width
751
+ # @param requestHeight [Integer] captured image height
752
+ # @param cameraName [String] camera device name
753
+ #
754
+ def initialize (*args)
755
+ width, height, name =
756
+ if args.empty?
757
+ [-1, -1, nil]
758
+ elsif args[0].kind_of?(String)
759
+ [-1, -1, args[0]]
760
+ elsif args[0].kind_of?(Numeric) && args[1].kind_of?(Numeric)
761
+ [args[0], args[1], args[2]]
762
+ else
763
+ raise ArgumentError
764
+ end
765
+ @camera = Rays::Camera.new width, height, device_name: name
766
+ end
767
+
768
+ # Start capturing.
769
+ #
770
+ # @return [Capture] self
771
+ #
772
+ def start ()
773
+ raise "Failed to start capture" unless @camera.start
774
+ self
775
+ end
776
+
777
+ # Stop capturing.
778
+ #
779
+ # @return [nil] nil
780
+ #
781
+ def stop ()
782
+ @camera.stop
783
+ nil
784
+ end
785
+
786
+ # Returns is the next captured image available?
787
+ #
788
+ # @return [Boolean] true means object has next frame
789
+ #
790
+ def available ()
791
+ @camera.active?
792
+ end
793
+
794
+ # Reads next frame image
795
+ #
796
+ def read ()
797
+ @camera.image
798
+ end
799
+
800
+ # Returns the width of captured image
801
+ #
802
+ # @return [Numeric] the width of captured image
803
+ #
804
+ def width ()
805
+ @camera.image&.width || 0
806
+ end
807
+
808
+ # Returns the height of captured image
809
+ #
810
+ # @return [Numeric] the height of captured image
811
+ #
812
+ def height ()
813
+ @camera.image&.height || 0
814
+ end
815
+
816
+ # @private
817
+ def getInternal__ ()
818
+ @camera.image || dummyImage__
819
+ end
820
+
821
+ # @private
822
+ private def dummyImage__ ()
823
+ @dummy ||= Rays::Image.new 1, 1
824
+ end
825
+
826
+ end# Capture
827
+
828
+
724
829
  # Drawing context
725
830
  #
726
831
  module GraphicsContext
727
832
 
833
+ # PI
834
+ #
835
+ PI = Math::PI
836
+
728
837
  # PI / 2
729
838
  #
730
- HALF_PI = Math::PI / 2
839
+ HALF_PI = PI / 2
731
840
 
732
841
  # PI / 4
733
842
  #
734
- QUARTER_PI = Math::PI / 4
843
+ QUARTER_PI = PI / 4
735
844
 
736
845
  # PI * 2
737
846
  #
738
- TWO_PI = Math::PI * 2
847
+ TWO_PI = PI * 2
739
848
 
740
849
  # PI * 2
741
850
  #
742
- TAU = Math::PI * 2
851
+ TAU = PI * 2
743
852
 
744
853
  # RGB mode for colorMode().
745
854
  #
@@ -808,7 +917,7 @@ module RubySketch
808
917
  @painter__ = painter
809
918
  @painter__.miter_limit = 10
810
919
 
811
- @drawing = false
920
+ @drawing__ = false
812
921
  @hsbColor__ = false
813
922
  @colorMaxes__ = [1.0] * 4
814
923
  @angleScale__ = 1.0
@@ -834,11 +943,11 @@ module RubySketch
834
943
  def beginDraw ()
835
944
  @matrixStack__.clear
836
945
  @styleStack__.clear
837
- @drawing = true
946
+ @drawing__ = true
838
947
  end
839
948
 
840
949
  def endDraw ()
841
- @drawing = false
950
+ @drawing__ = false
842
951
  end
843
952
 
844
953
  def width ()
@@ -915,7 +1024,7 @@ module RubySketch
915
1024
  #
916
1025
  def angleMode (mode)
917
1026
  @angleScale__ = case mode.upcase.to_sym
918
- when RADIANS then Utility::RAD2DEG__
1027
+ when RADIANS then RAD2DEG__
919
1028
  when DEGREES then 1.0
920
1029
  else raise ArgumentError, "invalid angle mode: #{mode}"
921
1030
  end
@@ -923,7 +1032,7 @@ module RubySketch
923
1032
  end
924
1033
 
925
1034
  # @private
926
- protected def toAngle__ (angle)
1035
+ def toAngle__ (angle)
927
1036
  angle * @angleScale__
928
1037
  end
929
1038
 
@@ -1402,8 +1511,9 @@ module RubySketch
1402
1511
  #
1403
1512
  def image (img, a, b, c = nil, d = nil)
1404
1513
  assertDrawing__
1405
- x, y, w, h = toXYWH__ @imageMode__, a, b, c || img.width, d || img.height
1406
- @painter__.image img.getInternal__, x, y, w, h
1514
+ i = img.getInternal__
1515
+ x, y, w, h = toXYWH__ @imageMode__, a, b, c || i.width, d || i.height
1516
+ @painter__.image i, x, y, w, h
1407
1517
  nil
1408
1518
  end
1409
1519
 
@@ -1579,13 +1689,13 @@ module RubySketch
1579
1689
  end
1580
1690
 
1581
1691
  # @private
1582
- private def getInternal__ ()
1692
+ def getInternal__ ()
1583
1693
  @image__
1584
1694
  end
1585
1695
 
1586
1696
  # @private
1587
1697
  private def assertDrawing__ ()
1588
- raise "call beginDraw() before drawing" unless @drawing
1698
+ raise "call beginDraw() before drawing" unless @drawing__
1589
1699
  end
1590
1700
 
1591
1701
  end# GraphicsContext
@@ -1597,17 +1707,23 @@ module RubySketch
1597
1707
 
1598
1708
  include GraphicsContext
1599
1709
 
1710
+ # Initialize graphics object.
1711
+ #
1600
1712
  def initialize (width, height)
1601
1713
  @image__ = Rays::Image.new width, height
1602
1714
  setup__ @image__.painter
1603
1715
  end
1604
1716
 
1717
+ # Start drawing.
1718
+ #
1605
1719
  def beginDraw ()
1606
1720
  @painter__.__send__ :begin_paint
1607
1721
  super
1608
1722
  push
1609
1723
  end
1610
1724
 
1725
+ # End drawing.
1726
+ #
1611
1727
  def endDraw ()
1612
1728
  pop
1613
1729
  super
@@ -1617,77 +1733,316 @@ module RubySketch
1617
1733
  end# Graphics
1618
1734
 
1619
1735
 
1620
- module Utility
1736
+ # Processing context
1737
+ #
1738
+ class Context
1739
+
1740
+ include GraphicsContext
1621
1741
 
1622
- # @private
1623
- DEG2RAD__ = Math::PI / 180.0
1742
+ Vector = Processing::Vector
1743
+ Capture = Processing::Capture
1744
+ Graphics = Processing::Graphics
1745
+
1746
+ @@context__ = nil
1747
+
1748
+ def self.context__ ()
1749
+ @@context__
1750
+ end
1624
1751
 
1625
1752
  # @private
1626
- RAD2DEG__ = 180.0 / Math::PI
1753
+ def initialize (window)
1754
+ @@context__ = self
1627
1755
 
1628
- # Converts degree to radian.
1629
- #
1630
- # @param degree [Numeric] degree to convert
1631
- #
1632
- # @return [Numeric] radian
1756
+ @window__ = window
1757
+ @image__ = @window__.canvas
1758
+ setup__ @window__.canvas_painter.paint {background 0.8}
1759
+
1760
+ @loop__ = true
1761
+ @redraw__ = false
1762
+ @frameCount__ = 0
1763
+ @mousePos__ =
1764
+ @mousePrevPos__ = Rays::Point.new 0
1765
+ @mousePressed__ = false
1766
+ @touches__ = []
1767
+
1768
+ @window__.before_draw = proc {beginDraw}
1769
+ @window__.after_draw = proc {endDraw}
1770
+
1771
+ drawFrame = -> {
1772
+ @image__ = @window__.canvas
1773
+ @painter__ = @window__.canvas_painter
1774
+ begin
1775
+ push
1776
+ @drawBlock__.call if @drawBlock__
1777
+ ensure
1778
+ pop
1779
+ @frameCount__ += 1
1780
+ end
1781
+ }
1782
+
1783
+ @window__.draw = proc do |e|
1784
+ if @loop__ || @redraw__
1785
+ @redraw__ = false
1786
+ drawFrame.call
1787
+ end
1788
+ @mousePrevPos__ = @mousePos__
1789
+ end
1790
+
1791
+ updatePointerStates = -> event, pressed = nil {
1792
+ @mousePos__ = event.pos
1793
+ @mousePressed__ = pressed if pressed != nil
1794
+ @touches__ = event.positions.map {|pos| Touch.new pos.x, pos.y}
1795
+ }
1796
+
1797
+ @window__.pointer_down = proc do |e|
1798
+ updatePointerStates.call e, true
1799
+ (@touchStartedBlock__ || @mousePressedBlock__)&.call
1800
+ end
1801
+
1802
+ @window__.pointer_up = proc do |e|
1803
+ updatePointerStates.call e, false
1804
+ (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
1805
+ end
1806
+
1807
+ @window__.pointer_move = proc do |e|
1808
+ updatePointerStates.call e
1809
+ (@touchMovedBlock__ || @mouseMovedBlock__)&.call
1810
+ end
1811
+
1812
+ @window__.pointer_drag = proc do |e|
1813
+ updatePointerStates.call e
1814
+ (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
1815
+ end
1816
+ end
1817
+
1818
+ # Define setup block.
1633
1819
  #
1634
- def radians (degree)
1635
- degree * DEG2RAD__
1820
+ def setup (&block)
1821
+ @window__.setup = block
1822
+ nil
1636
1823
  end
1637
1824
 
1638
- # Converts radian to degree.
1825
+ # Define draw block.
1639
1826
  #
1640
- # @param radian [Numeric] radian to convert
1827
+ def draw (&block)
1828
+ @drawBlock__ = block if block
1829
+ nil
1830
+ end
1831
+
1832
+ def key (&block)
1833
+ @window__.key = block
1834
+ nil
1835
+ end
1836
+
1837
+ def mousePressed (&block)
1838
+ @mousePressedBlock__ = block if block
1839
+ @mousePressed__
1840
+ end
1841
+
1842
+ def mouseReleased (&block)
1843
+ @mouseReleasedBlock__ = block if block
1844
+ nil
1845
+ end
1846
+
1847
+ def mouseMoved (&block)
1848
+ @mouseMovedBlock__ = block if block
1849
+ nil
1850
+ end
1851
+
1852
+ def mouseDragged (&block)
1853
+ @mouseDraggedBlock__ = block if block
1854
+ nil
1855
+ end
1856
+
1857
+ def touchStarted (&block)
1858
+ @touchStartedBlock__ = block if block
1859
+ nil
1860
+ end
1861
+
1862
+ def touchEnded (&block)
1863
+ @touchEndedBlock__ = block if block
1864
+ nil
1865
+ end
1866
+
1867
+ def touchMoved (&block)
1868
+ @touchMovedBlock__ = block if block
1869
+ nil
1870
+ end
1871
+
1872
+ # @private
1873
+ private def size__ (width, height)
1874
+ raise 'size() must be called on startup or setup block' if @started__
1875
+
1876
+ @painter__.__send__ :end_paint
1877
+ @window__.__send__ :reset_canvas, width, height
1878
+ @painter__.__send__ :begin_paint
1879
+
1880
+ @auto_resize__ = false
1881
+ end
1882
+
1883
+ def windowWidth ()
1884
+ @window__.width
1885
+ end
1886
+
1887
+ def windowHeight ()
1888
+ @window__.height
1889
+ end
1890
+
1891
+ # Returns number of frames since program started.
1641
1892
  #
1642
- # @return [Numeric] degree
1893
+ # @return [Integer] total number of frames
1643
1894
  #
1644
- def degrees (radian)
1645
- radian * RAD2DEG__
1895
+ def frameCount ()
1896
+ @frameCount__
1646
1897
  end
1647
1898
 
1648
- # Returns the absolute number of the value.
1649
- #
1650
- # @param value [Numeric] number
1899
+ # Returns number of frames per second.
1651
1900
  #
1652
- # @return [Numeric] absolute number
1901
+ # @return [Float] frames per second
1653
1902
  #
1654
- def abs (value)
1655
- value.abs
1903
+ def frameRate ()
1904
+ @window__.event.fps
1656
1905
  end
1657
1906
 
1658
- # Returns the closest integer number greater than or equal to the value.
1659
- #
1660
- # @param value [Numeric] number
1907
+ # Returns pixel density
1661
1908
  #
1662
- # @return [Numeric] rounded up number
1909
+ # @return [Numeric] pixel density
1663
1910
  #
1664
- def ceil (value)
1665
- value.ceil
1911
+ def displayDensity ()
1912
+ @painter__.pixel_density
1666
1913
  end
1667
1914
 
1668
- # Returns the closest integer number less than or equal to the value.
1669
- #
1670
- # @param value [Numeric] number
1915
+ # Returns mouse x position
1671
1916
  #
1672
- # @return [Numeric] rounded down number
1917
+ # @return [Numeric] horizontal position of mouse
1673
1918
  #
1674
- def floor (value)
1675
- value.floor
1919
+ def mouseX ()
1920
+ @mousePos__.x
1676
1921
  end
1677
1922
 
1678
- # Returns the closest integer number.
1679
- #
1680
- # @param value [Numeric] number
1923
+ # Returns mouse y position
1681
1924
  #
1682
- # @return [Numeric] rounded number
1925
+ # @return [Numeric] vertical position of mouse
1683
1926
  #
1684
- def round (value)
1685
- value.round
1927
+ def mouseY ()
1928
+ @mousePos__.y
1686
1929
  end
1687
1930
 
1688
- # Returns value raised to the power of exponent.
1931
+ # Returns mouse x position in previous frame
1689
1932
  #
1690
- # @param value [Numeric] base number
1933
+ # @return [Numeric] horizontal position of mouse
1934
+ #
1935
+ def pmouseX ()
1936
+ @mousePrevPos__.x
1937
+ end
1938
+
1939
+ # Returns mouse y position in previous frame
1940
+ #
1941
+ # @return [Numeric] vertical position of mouse
1942
+ #
1943
+ def pmouseY ()
1944
+ @mousePrevPos__.y
1945
+ end
1946
+
1947
+ # Returns array of touches
1948
+ #
1949
+ # @return [Array] Touch objects
1950
+ #
1951
+ def touches ()
1952
+ @touches__
1953
+ end
1954
+
1955
+ # Enables calling draw block on every frame.
1956
+ #
1957
+ # @return [nil] nil
1958
+ #
1959
+ def loop ()
1960
+ @loop__ = true
1961
+ end
1962
+
1963
+ # Disables calling draw block on every frame.
1964
+ #
1965
+ # @return [nil] nil
1966
+ #
1967
+ def noLoop ()
1968
+ @loop__ = false
1969
+ end
1970
+
1971
+ # Calls draw block to redraw frame.
1972
+ #
1973
+ # @return [nil] nil
1974
+ #
1975
+ def redraw ()
1976
+ @redraw__ = true
1977
+ end
1978
+
1979
+ #
1980
+ # Utilities
1981
+ #
1982
+
1983
+ # Returns the absolute number of the value.
1984
+ #
1985
+ # @param value [Numeric] number
1986
+ #
1987
+ # @return [Numeric] absolute number
1988
+ #
1989
+ def abs (value)
1990
+ value.abs
1991
+ end
1992
+
1993
+ # Returns the closest integer number greater than or equal to the value.
1994
+ #
1995
+ # @param value [Numeric] number
1996
+ #
1997
+ # @return [Numeric] rounded up number
1998
+ #
1999
+ def ceil (value)
2000
+ value.ceil
2001
+ end
2002
+
2003
+ # Returns the closest integer number less than or equal to the value.
2004
+ #
2005
+ # @param value [Numeric] number
2006
+ #
2007
+ # @return [Numeric] rounded down number
2008
+ #
2009
+ def floor (value)
2010
+ value.floor
2011
+ end
2012
+
2013
+ # Returns the closest integer number.
2014
+ #
2015
+ # @param value [Numeric] number
2016
+ #
2017
+ # @return [Numeric] rounded number
2018
+ #
2019
+ def round (value)
2020
+ value.round
2021
+ end
2022
+
2023
+ # Returns the natural logarithm (the base-e logarithm) of a number.
2024
+ #
2025
+ # @param value [Numeric] number (> 0.0)
2026
+ #
2027
+ # @return [Numeric] result number
2028
+ #
2029
+ def log (n)
2030
+ Math.log n
2031
+ end
2032
+
2033
+ # Returns Euler's number e raised to the power of value.
2034
+ #
2035
+ # @param value [Numeric] number
2036
+ #
2037
+ # @return [Numeric] result number
2038
+ #
2039
+ def exp (n)
2040
+ Math.exp n
2041
+ end
2042
+
2043
+ # Returns value raised to the power of exponent.
2044
+ #
2045
+ # @param value [Numeric] base number
1691
2046
  # @param exponent [Numeric] exponent number
1692
2047
  #
1693
2048
  # @return [Numeric] value ** exponent
@@ -1706,6 +2061,16 @@ module RubySketch
1706
2061
  value * value
1707
2062
  end
1708
2063
 
2064
+ # Returns squared value.
2065
+ #
2066
+ # @param value [Numeric] number
2067
+ #
2068
+ # @return [Numeric] squared value
2069
+ #
2070
+ def sqrt (value)
2071
+ Math.sqrt value
2072
+ end
2073
+
1709
2074
  # Returns the magnitude (or length) of a vector.
1710
2075
  #
1711
2076
  # @overload mag(x, y)
@@ -1838,292 +2203,199 @@ module RubySketch
1838
2203
  value < min ? min : (value > max ? max : value)
1839
2204
  end
1840
2205
 
1841
- # Returns the perlin noise value.
1842
- #
1843
- # @overload noise(x)
1844
- # @overload noise(x, y)
1845
- # @overload noise(x, y, z)
2206
+ # Converts degree to radian.
1846
2207
  #
1847
- # @param x [Numeric] horizontal point in noise space
1848
- # @param y [Numeric] vertical point in noise space
1849
- # @param z [Numeric] depth point in noise space
2208
+ # @param degree [Numeric] degree to convert
1850
2209
  #
1851
- # @return [Numeric] noise value (0.0..1.0)
2210
+ # @return [Numeric] radian
1852
2211
  #
1853
- def noise (x, y = 0, z = 0)
1854
- Rays.perlin(x, y, z) / 2.0 + 0.5
2212
+ def radians (degree)
2213
+ degree * DEG2RAD__
1855
2214
  end
1856
2215
 
1857
- # Loads image.
2216
+ # Converts radian to degree.
1858
2217
  #
1859
- # @param filename [String] file name to load image
1860
- # @param extension [String] type of image to load (ex. 'png')
2218
+ # @param radian [Numeric] radian to convert
1861
2219
  #
1862
- # @return [Image] loaded image object
2220
+ # @return [Numeric] degree
1863
2221
  #
1864
- def loadImage (filename, extension = nil)
1865
- filename = getImage__ filename, extension if filename =~ %r|^https?://|
1866
- Image.new Rays::Image.load filename
1867
- end
1868
-
1869
- # @private
1870
- private def getImage__ (uri, ext)
1871
- ext ||= File.extname uri
1872
- raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
1873
-
1874
- tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
1875
- path = tmpdir + Digest::SHA1.hexdigest(uri)
1876
- path = path.sub_ext ext
1877
-
1878
- unless path.file?
1879
- URI.open uri do |input|
1880
- tmpdir.mkdir unless tmpdir.directory?
1881
- path.open('w') do |output|
1882
- while buf = input.read(2 ** 16)
1883
- output.write buf
1884
- end
1885
- end
1886
- end
1887
- end
1888
- path.to_s
1889
- end
1890
-
1891
- def createGraphics (width, height)
1892
- Graphics.new width, height
1893
- end
1894
-
1895
- end# Utility
1896
-
1897
-
1898
- # Processing context
1899
- #
1900
- module Context
1901
-
1902
- include GraphicsContext, Utility, Math
1903
-
1904
- # @private
1905
- def setup__ (window)
1906
- @window__ = window
1907
- @image__ = @window__.canvas
1908
- super @window__.canvas_painter.paint {background 0.8}
1909
-
1910
- @loop__ = true
1911
- @redraw__ = false
1912
- @frameCount__ = 0
1913
- @mousePos__ =
1914
- @mousePrevPos__ = Rays::Point.new 0
1915
- @mousePressed__ = false
1916
- @touches__ = []
1917
-
1918
- @window__.before_draw = proc {beginDraw}
1919
- @window__.after_draw = proc {endDraw}
1920
-
1921
- drawFrame = -> {
1922
- @image__ = @window__.canvas
1923
- @painter__ = @window__.canvas_painter
1924
- begin
1925
- push
1926
- @drawBlock__.call if @drawBlock__
1927
- ensure
1928
- pop
1929
- @frameCount__ += 1
1930
- end
1931
- }
1932
-
1933
- @window__.draw = proc do |e|
1934
- if @loop__ || @redraw__
1935
- @redraw__ = false
1936
- drawFrame.call
1937
- end
1938
- @mousePrevPos__ = @mousePos__
1939
- end
1940
-
1941
- updatePointerStates = -> event, pressed = nil {
1942
- @mousePos__ = event.pos
1943
- @mousePressed__ = pressed if pressed != nil
1944
- @touches__ = event.positions.map {|pos| Touch.new pos.x, pos.y}
1945
- }
1946
-
1947
- @window__.pointer_down = proc do |e|
1948
- updatePointerStates.call e, true
1949
- (@touchStartedBlock__ || @mousePressedBlock__)&.call
1950
- end
1951
-
1952
- @window__.pointer_up = proc do |e|
1953
- updatePointerStates.call e, false
1954
- (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
1955
- end
1956
-
1957
- @window__.pointer_move = proc do |e|
1958
- updatePointerStates.call e
1959
- (@touchMovedBlock__ || @mouseMovedBlock__)&.call
1960
- end
1961
-
1962
- @window__.pointer_drag = proc do |e|
1963
- updatePointerStates.call e
1964
- (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
1965
- end
2222
+ def degrees (radian)
2223
+ radian * RAD2DEG__
1966
2224
  end
1967
2225
 
1968
- # Define setup block.
2226
+ # Returns the sine of an angle.
1969
2227
  #
1970
- def setup (&block)
1971
- @window__.setup = block
1972
- nil
1973
- end
1974
-
1975
- # Define draw block.
2228
+ # @param angle [Numeric] angle in radians
1976
2229
  #
1977
- def draw (&block)
1978
- @drawBlock__ = block if block
1979
- nil
1980
- end
1981
-
1982
- def key (&block)
1983
- @window__.key = block
1984
- nil
1985
- end
1986
-
1987
- def mousePressed (&block)
1988
- @mousePressedBlock__ = block if block
1989
- @mousePressed__
1990
- end
1991
-
1992
- def mouseReleased (&block)
1993
- @mouseReleasedBlock__ = block if block
1994
- nil
1995
- end
1996
-
1997
- def mouseMoved (&block)
1998
- @mouseMovedBlock__ = block if block
1999
- nil
2000
- end
2001
-
2002
- def mouseDragged (&block)
2003
- @mouseDraggedBlock__ = block if block
2004
- nil
2005
- end
2006
-
2007
- def touchStarted (&block)
2008
- @touchStartedBlock__ = block if block
2009
- nil
2010
- end
2011
-
2012
- def touchEnded (&block)
2013
- @touchEndedBlock__ = block if block
2014
- nil
2015
- end
2016
-
2017
- def touchMoved (&block)
2018
- @touchMovedBlock__ = block if block
2019
- nil
2020
- end
2021
-
2022
- # @private
2023
- private def size__ (width, height)
2024
- raise 'size() must be called on startup or setup block' if @started__
2025
-
2026
- @painter__.__send__ :end_paint
2027
- @window__.__send__ :reset_canvas, width, height
2028
- @painter__.__send__ :begin_paint
2029
-
2030
- @auto_resize__ = false
2031
- end
2032
-
2033
- def windowWidth ()
2034
- @window__.width
2230
+ # @return [Numeric] the sine
2231
+ #
2232
+ def sin (angle)
2233
+ Math.sin angle
2035
2234
  end
2036
2235
 
2037
- def windowHeight ()
2038
- @window__.height
2236
+ # Returns the cosine of an angle.
2237
+ #
2238
+ # @param angle [Numeric] angle in radians
2239
+ #
2240
+ # @return [Numeric] the cosine
2241
+ #
2242
+ def cos (angle)
2243
+ Math.cos angle
2039
2244
  end
2040
2245
 
2041
- # Returns number of frames since program started.
2246
+ # Returns the ratio of the sine and cosine of an angle.
2042
2247
  #
2043
- # @return [Integer] total number of frames
2248
+ # @param angle [Numeric] angle in radians
2044
2249
  #
2045
- def frameCount ()
2046
- @frameCount__
2250
+ # @return [Numeric] the tangent
2251
+ #
2252
+ def tan (angle)
2253
+ Math.tan angle
2047
2254
  end
2048
2255
 
2049
- # Returns number of frames per second.
2256
+ # Returns the inverse of sin().
2050
2257
  #
2051
- # @return [Float] frames per second
2258
+ # @param value [Numeric] value for calculation
2052
2259
  #
2053
- def frameRate ()
2054
- @window__.event.fps
2260
+ # @return [Numeric] the arc sine
2261
+ #
2262
+ def asin (value)
2263
+ Math.asin value
2055
2264
  end
2056
2265
 
2057
- # Returns pixel density
2266
+ # Returns the inverse of cos().
2058
2267
  #
2059
- # @return [Numeric] pixel density
2268
+ # @param value [Numeric] value for calculation
2060
2269
  #
2061
- def displayDensity ()
2062
- @painter__.pixel_density
2270
+ # @return [Numeric] the arc cosine
2271
+ #
2272
+ def acos (value)
2273
+ Math.acos value
2063
2274
  end
2064
2275
 
2065
- # Returns mouse x position
2276
+ # Returns the inverse of tan().
2066
2277
  #
2067
- # @return [Numeric] horizontal position of mouse
2278
+ # @param value [Numeric] value for valculation
2068
2279
  #
2069
- def mouseX ()
2070
- @mousePos__.x
2280
+ # @return [Numeric] the arc tangent
2281
+ #
2282
+ def atan (value)
2283
+ Math.atan value
2071
2284
  end
2072
2285
 
2073
- # Returns mouse y position
2286
+ # Returns the angle from a specified point.
2074
2287
  #
2075
- # @return [Numeric] vertical position of mouse
2288
+ # @param y [Numeric] y of the point
2289
+ # @param x [Numeric] x of the point
2076
2290
  #
2077
- def mouseY ()
2078
- @mousePos__.y
2291
+ # @return [Numeric] the angle in radians
2292
+ #
2293
+ def atan2 (y, x)
2294
+ Math.atan2 y, x
2079
2295
  end
2080
2296
 
2081
- # Returns mouse x position in previous frame
2297
+ # Returns the perlin noise value.
2082
2298
  #
2083
- # @return [Numeric] horizontal position of mouse
2299
+ # @overload noise(x)
2300
+ # @overload noise(x, y)
2301
+ # @overload noise(x, y, z)
2084
2302
  #
2085
- def pmouseX ()
2086
- @mousePrevPos__.x
2303
+ # @param x [Numeric] horizontal point in noise space
2304
+ # @param y [Numeric] vertical point in noise space
2305
+ # @param z [Numeric] depth point in noise space
2306
+ #
2307
+ # @return [Numeric] noise value (0.0..1.0)
2308
+ #
2309
+ def noise (x, y = 0, z = 0)
2310
+ Rays.perlin(x, y, z) / 2.0 + 0.5
2087
2311
  end
2088
2312
 
2089
- # Returns mouse y position in previous frame
2313
+ # Returns a random number in range low...high
2090
2314
  #
2091
- # @return [Numeric] vertical position of mouse
2315
+ # @overload random()
2316
+ # @overload random(high)
2317
+ # @overload random(low, high)
2318
+ # @overload random(choices)
2092
2319
  #
2093
- def pmouseY ()
2094
- @mousePrevPos__.y
2320
+ # @param low [Numeric] lower limit
2321
+ # @param high [Numeric] upper limit
2322
+ # @param choices [Array] array to choose from
2323
+ #
2324
+ # @return [Float] random number
2325
+ #
2326
+ def random (*args)
2327
+ return args.first.sample if args.first.kind_of? Array
2328
+ high, low = args.reverse
2329
+ rand (low || 0).to_f...(high || 1).to_f
2095
2330
  end
2096
2331
 
2097
- # Returns array of touches
2332
+ # Creates a new vector.
2098
2333
  #
2099
- # @return [Array] Touch objects
2334
+ # @overload createVector()
2335
+ # @overload createVector(x, y)
2336
+ # @overload createVector(x, y, z)
2100
2337
  #
2101
- def touches ()
2102
- @touches__
2338
+ # @param x [Numeric] x of new vector
2339
+ # @param y [Numeric] y of new vector
2340
+ # @param z [Numeric] z of new vector
2341
+ #
2342
+ # @return [Vector] new vector
2343
+ #
2344
+ def createVector (*args)
2345
+ Vector.new *args
2103
2346
  end
2104
2347
 
2105
- # Enables calling draw block on every frame.
2348
+ # Creates a camera object as a video input device.
2106
2349
  #
2107
- # @return [nil] nil
2350
+ # @return [Capture] camera object
2108
2351
  #
2109
- def loop ()
2110
- @loop__ = true
2352
+ def createCapture (*args)
2353
+ Capture.new *args
2111
2354
  end
2112
2355
 
2113
- # Disables calling draw block on every frame.
2356
+ # Creates a new off-screen graphics context object.
2114
2357
  #
2115
- # @return [nil] nil
2358
+ # @param width [Numeric] width of graphics image
2359
+ # @param height [Numeric] height of graphics image
2116
2360
  #
2117
- def noLoop ()
2118
- @loop__ = false
2361
+ # @return [Graphics] graphics object
2362
+ #
2363
+ def createGraphics (width, height)
2364
+ Graphics.new width, height
2119
2365
  end
2120
2366
 
2121
- # Calls draw block to redraw frame.
2367
+ # Loads image.
2122
2368
  #
2123
- # @return [nil] nil
2369
+ # @param filename [String] file name to load image
2370
+ # @param extension [String] type of image to load (ex. 'png')
2124
2371
  #
2125
- def redraw ()
2126
- @redraw__ = true
2372
+ # @return [Image] loaded image object
2373
+ #
2374
+ def loadImage (filename, extension = nil)
2375
+ filename = getImage__ filename, extension if filename =~ %r|^https?://|
2376
+ Image.new Rays::Image.load filename
2377
+ end
2378
+
2379
+ # @private
2380
+ private def getImage__ (uri, ext)
2381
+ ext ||= File.extname uri
2382
+ raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
2383
+
2384
+ tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
2385
+ path = tmpdir + Digest::SHA1.hexdigest(uri)
2386
+ path = path.sub_ext ext
2387
+
2388
+ unless path.file?
2389
+ URI.open uri do |input|
2390
+ tmpdir.mkdir unless tmpdir.directory?
2391
+ path.open('w') do |output|
2392
+ while buf = input.read(2 ** 16)
2393
+ output.write buf
2394
+ end
2395
+ end
2396
+ end
2397
+ end
2398
+ path.to_s
2127
2399
  end
2128
2400
 
2129
2401
  end# Context