rubysketch 0.3.3 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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