rubysketch 0.3.2 → 0.3.7

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: 83aecf951db1320693714768446ccc95aa0a87f23012e02fff31b032c88be3c6
4
- data.tar.gz: 6d1f67cbe65c15468cb606666acceacf19f56bf8c83dd1abae2a1b21d7daf94b
3
+ metadata.gz: 41b3a75aeb6c8bdc443d2d87e44c60361a527e4d6b8b3918e8b1eaa2503f92e4
4
+ data.tar.gz: 7f373d0f3fdb31d38bb76d8e8ed88ce2f3cedca0c696d8a5f571ded1e78fb15d
5
5
  SHA512:
6
- metadata.gz: 9946ba3029ce56a90042daa9be9e6c2f74f5d7ef7d318b5263b10c03ca35c26f5f7e67c61e6f78bd90f4224c267f732dcb937d86030adbe2b0ac51350a225f6e
7
- data.tar.gz: 627eb17aa1e83da474f9ab9457b449b278ecf95d84956f98b82d3185c6bc87fa9b5788ad65c1144f80364171b14a4f7322d86a42066925ccbca8f2e19ff46cc3
6
+ metadata.gz: ffcba1a2e5ae98525c4c1512230d249995071e6be9183918b6f62ed5293d9ac8f530d38aa5f544d2d4fc431ca17f38c7746955df313e9609e0ee528551045a51
7
+ data.tar.gz: cb49daa453cdf6dd9027a59c508363a63fed2e210b0acbcfa311e66334b107a88471e5b8b59dac7f77b5aa04423aaa2d0cd2b2fa0c4b1221b76997a93ce89e79
@@ -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,39 @@
1
1
  # RubySketch ChangeLog
2
2
 
3
3
 
4
+ ## [0.3.7] - 2020-11-18
5
+
6
+ - add Capture class
7
+ - add log(), exp(), sqrt() and PI
8
+ - add examples/camera.rb
9
+ - add examples/breakout.rb
10
+ - fix error on calling image()
11
+
12
+
13
+ ## [0.3.6] - 2020-08-02
14
+
15
+ - random() can take array or nothing
16
+ - use github actions to release gem package
17
+
18
+
19
+ ## [0.3.5] - 2020-08-02
20
+
21
+ - add random()
22
+ - add sin(), cos(), tan(), asin(), acos(), atan() and atan2()
23
+ - make Vector class accessible from user script context
24
+ - fix error on calling rotate()
25
+
26
+
27
+ ## [0.3.4] - 2020-08-02
28
+
29
+ - delete Utility module
30
+
31
+
32
+ ## [0.3.3] - 2020-08-01
33
+
34
+ - add Vector class
35
+
36
+
4
37
  ## [0.3.2] - 2020-07-22
5
38
 
6
39
  - text() draws to the baseline by default
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'yard'
4
+ gem 'reflexion'
data/Rakefile CHANGED
@@ -18,6 +18,7 @@ MODULES = [Xot, Rucy, Rays, Reflex, RubySketch]
18
18
 
19
19
  ENV['RDOC'] = 'yardoc --no-private'
20
20
 
21
+ test_ruby_extension
21
22
  generate_documents
22
23
  build_ruby_gem
23
24
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.3.7
@@ -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
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,13 +6,574 @@ 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
+
16
+ # Vector class.
17
+ #
18
+ class Vector
19
+
20
+ include Comparable
21
+
22
+ # Initialize vector object.
23
+ #
24
+ # @overload new()
25
+ # @overload new(x)
26
+ # @overload new(x, y)
27
+ # @overload new(x, y, z)
28
+ # @overload new(v)
29
+ # @overload new(a)
30
+ #
31
+ # @param x [Numeric] x of vector
32
+ # @param y [Numeric] y of vector
33
+ # @param z [Numeric] z of vector
34
+ # @param v [Vector] vector object to copy
35
+ # @param a [Array] array like [x, y, z]
36
+ #
37
+ def initialize (x = 0, y = 0, z = 0, context: nil)
38
+ @point = case x
39
+ when Rays::Point then x.dup
40
+ when Vector then x.getInternal__.dup
41
+ when Array then Rays::Point.new x[0] || 0, x[1] || 0, x[2] || 0
42
+ else Rays::Point.new x || 0, y || 0, z || 0
43
+ end
44
+ @context = context || Context.context__
45
+ end
46
+
47
+ # Initializer for dup or clone
48
+ #
49
+ def initialize_copy (o)
50
+ @point = o.getInternal__.dup
51
+ end
52
+
53
+ # Copy vector object
54
+ #
55
+ # @return [Vector] duplicated vector object
56
+ #
57
+ alias copy dup
58
+
59
+ # Sets x, y and z.
60
+ #
61
+ # @overload set(x)
62
+ # @overload set(x, y)
63
+ # @overload set(x, y, z)
64
+ # @overload set(v)
65
+ # @overload set(a)
66
+ #
67
+ # @param x [Numeric] x of vector
68
+ # @param y [Numeric] y of vector
69
+ # @param z [Numeric] z of vector
70
+ # @param v [Vector] vector object to copy
71
+ # @param a [Array] array with x, y, z
72
+ #
73
+ # @return [nil] nil
74
+ #
75
+ def set (*args)
76
+ initialize *args
77
+ self
78
+ end
79
+
80
+ # Gets x value.
81
+ #
82
+ # @return [Numeric] x value of vector
83
+ #
84
+ def x ()
85
+ @point.x
86
+ end
87
+
88
+ # Gets y value.
89
+ #
90
+ # @return [Numeric] y value of vector
91
+ #
92
+ def y ()
93
+ @point.y
94
+ end
95
+
96
+ # Gets z value.
97
+ #
98
+ # @return [Numeric] z value of vector
99
+ #
100
+ def z ()
101
+ @point.z
102
+ end
103
+
104
+ # Sets x value.
105
+ #
106
+ # @return [Numeric] x value of vector
107
+ #
108
+ def x= (x)
109
+ @point.x = x
110
+ end
111
+
112
+ # Sets y value.
113
+ #
114
+ # @return [Numeric] y value of vector
115
+ #
116
+ def y= (y)
117
+ @point.y = y
118
+ end
119
+
120
+ # Sets z value.
121
+ #
122
+ # @return [Numeric] z value of vector
123
+ #
124
+ def z= (z)
125
+ @point.z = z
126
+ end
127
+
128
+ # Returns the interpolated vector between 2 vectors.
129
+ #
130
+ # @overload lerp(v, amount)
131
+ # @overload lerp(x, y, amount)
132
+ # @overload lerp(x, y, z, amount)
133
+ #
134
+ # @param v [Vector] vector to interpolate
135
+ # @param x [Numeric] x of vector to interpolate
136
+ # @param y [Numeric] y of vector to interpolate
137
+ # @param z [Numeric] z of vector to interpolate
138
+ # @param amount [Numeric] amount to interpolate
139
+ #
140
+ # @return [Vector] interporated vector
141
+ #
142
+ def lerp (*args, amount)
143
+ v = toVector__ *args
144
+ self.x = x + (v.x - x) * amount
145
+ self.y = y + (v.y - y) * amount
146
+ self.z = z + (v.z - z) * amount
147
+ self
148
+ end
149
+
150
+ # Returns the interpolated vector between 2 vectors.
151
+ #
152
+ # @param v1 [Vector] vector to interpolate
153
+ # @param v2 [Vector] vector to interpolate
154
+ # @param amount [Numeric] amount to interpolate
155
+ #
156
+ # @return [Vector] interporated vector
157
+ #
158
+ def self.lerp (v1, v2, amount)
159
+ v1.dup.lerp v2, amount
160
+ end
161
+
162
+ # Returns x, y, z as an array
163
+ #
164
+ # @return [Array] array of x, y, z
165
+ #
166
+ def array ()
167
+ @point.to_a 3
168
+ end
169
+
170
+ # Adds a vector.
171
+ #
172
+ # @overload add(v)
173
+ # @overload add(x, y)
174
+ # @overload add(x, y, z)
175
+ #
176
+ # @param v [Vector] vector to add
177
+ # @param x [Vector] x of vector to add
178
+ # @param y [Vector] y of vector to add
179
+ # @param z [Vector] z of vector to add
180
+ #
181
+ # @return [Vector] added vector
182
+ #
183
+ def add (*args)
184
+ @point += toVector__(*args).getInternal__
185
+ self
186
+ end
187
+
188
+ # Subtracts a vector.
189
+ #
190
+ # @overload sub(v)
191
+ # @overload sub(x, y)
192
+ # @overload sub(x, y, z)
193
+ #
194
+ # @param v [Vector] vector to subtract
195
+ # @param x [Vector] x of vector to subtract
196
+ # @param y [Vector] y of vector to subtract
197
+ # @param z [Vector] z of vector to subtract
198
+ #
199
+ # @return [Vector] subtracted vector
200
+ #
201
+ def sub (*args)
202
+ @point -= toVector__(*args).getInternal__
203
+ self
204
+ end
205
+
206
+ # Multiplies a vector by scalar.
207
+ #
208
+ # @param num [Numeric] number to multiply the vector
209
+ #
210
+ # @return [Vector] multiplied vector
211
+ #
212
+ def mult (num)
213
+ @point *= num
214
+ self
215
+ end
216
+
217
+ # Divides a vector by scalar.
218
+ #
219
+ # @param num [Numeric] number to divide the vector
220
+ #
221
+ # @return [Vector] divided vector
222
+ #
223
+ def div (num)
224
+ @point /= num
225
+ self
226
+ end
227
+
228
+ # Adds a vector.
229
+ #
230
+ # @param v [Vector] vector to add
231
+ #
232
+ # @return [Vector] added vector
233
+ #
234
+ def + (v)
235
+ dup.add v
236
+ end
237
+
238
+ # Subtracts a vector.
239
+ #
240
+ # @param v [Vector] vector to subtract
241
+ #
242
+ # @return [Vector] subtracted vector
243
+ #
244
+ def - (v)
245
+ dup.sub v
246
+ end
247
+
248
+ # Multiplies a vector by scalar.
249
+ #
250
+ # @param num [Numeric] number to multiply the vector
251
+ #
252
+ # @return [Vector] multiplied vector
253
+ #
254
+ def * (num)
255
+ dup.mult num
256
+ end
257
+
258
+ # Divides a vector by scalar.
259
+ #
260
+ # @param num [Numeric] number to divide the vector
261
+ #
262
+ # @return [Vector] divided vector
263
+ #
264
+ def / (num)
265
+ dup.div num
266
+ end
267
+
268
+ # Adds 2 vectors.
269
+ #
270
+ # @overload add(v1, v2)
271
+ # @overload add(v1, v2, target)
272
+ #
273
+ # @param v1 [Vector] a vector
274
+ # @param v2 [Vector] another vector
275
+ # @param target [Vector] vector to store added vector
276
+ #
277
+ # @return [Vector] added vector
278
+ #
279
+ def self.add (v1, v2, target = nil)
280
+ v = v1 + v2
281
+ target.set v if self === target
282
+ v
283
+ end
284
+
285
+ # Subtracts 2 vectors.
286
+ #
287
+ # @overload sub(v1, v2)
288
+ # @overload sub(v1, v2, target)
289
+ #
290
+ # @param v1 [Vector] a vector
291
+ # @param v2 [Vector] another vector
292
+ # @param target [Vector] vector to store subtracted vector
293
+ #
294
+ # @return [Vector] subtracted vector
295
+ #
296
+ def self.sub (v1, v2, target = nil)
297
+ v = v1 - v2
298
+ target.set v if self === target
299
+ v
300
+ end
301
+
302
+ # Multiplies a vector by scalar.
303
+ #
304
+ # @overload mult(v, num)
305
+ # @overload mult(v, num, target)
306
+ #
307
+ # @param v [Vector] a vector
308
+ # @param num [Numeric] number to multiply the vector
309
+ # @param target [Vector] vector to store multiplied vector
310
+ #
311
+ # @return [Vector] multiplied vector
312
+ #
313
+ def self.mult (v1, num, target = nil)
314
+ v = v1 * num
315
+ target.set v if self === target
316
+ v
317
+ end
318
+
319
+ # Divides a vector by scalar.
320
+ #
321
+ # @overload div(v, num)
322
+ # @overload div(v, num, target)
323
+ #
324
+ # @param v [Vector] a vector
325
+ # @param num [Numeric] number to divide the vector
326
+ # @param target [Vector] vector to store divided vector
327
+ #
328
+ # @return [Vector] divided vector
329
+ #
330
+ def self.div (v1, num, target = nil)
331
+ v = v1 / num
332
+ target.set v if self === target
333
+ v
334
+ end
335
+
336
+ # Returns the length of the vector.
337
+ #
338
+ # @return [Numeric] length
339
+ #
340
+ def mag ()
341
+ @point.length
342
+ end
343
+
344
+ # Returns squared length of the vector.
345
+ #
346
+ # @return [Numeric] squared length
347
+ #
348
+ def magSq ()
349
+ Rays::Point::dot(@point, @point)
350
+ end
351
+
352
+ # Changes the length of the vector.
353
+ #
354
+ # @overload setMag(len)
355
+ # @overload setMag(target, len)
356
+ #
357
+ # @param len [Numeric] length of new vector
358
+ # @param target [Vector] vector to store new vector
359
+ #
360
+ # @return [Vector] vector with new length
361
+ #
362
+ def setMag (target = nil, len)
363
+ (target || self).set @point.normal * len
364
+ end
365
+
366
+ # Changes the length of the vector to 1.0.
367
+ #
368
+ # @param target [Vector] vector to store the normalized vector
369
+ #
370
+ # @return [Vector] normalized vector
371
+ #
372
+ def normalize (target = nil)
373
+ (target || self).set @point.normal
374
+ end
375
+
376
+ # Changes the length of the vector if it's length is greater than the max value.
377
+ #
378
+ # @param max [Numeric] max length
379
+ #
380
+ # @return [Vector] new vector
381
+ #
382
+ def limit (max)
383
+ setMag max if magSq > max ** 2
384
+ self
385
+ end
386
+
387
+ # Returns the distance of 2 vectors.
388
+ #
389
+ # @param v [Vector] a vector
390
+ #
391
+ # @return [Numeric] the distance
392
+ #
393
+ def dist (v)
394
+ (self - v).mag
395
+ end
396
+
397
+ # Returns the distance of 2 vectors.
398
+ #
399
+ # @param v1 [Vector] a vector
400
+ # @param v2 [Vector] another vector
401
+ #
402
+ # @return [Numeric] the distance
403
+ #
404
+ def self.dist (v1, v2)
405
+ v1.dist v2
406
+ end
407
+
408
+ # Calculates the dot product of 2 vectors.
409
+ #
410
+ # @overload dot(v)
411
+ # @overload dot(x, y)
412
+ # @overload dot(x, y, z)
413
+ #
414
+ # @param v [Vector] a vector
415
+ # @param x [Numeric] x of vector
416
+ # @param y [Numeric] y of vector
417
+ # @param z [Numeric] z of vector
418
+ #
419
+ # @return [Numeric] result of dot product
420
+ #
421
+ def dot (*args)
422
+ Rays::Point::dot getInternal__, toVector__(*args).getInternal__
423
+ end
424
+
425
+ # Calculates the dot product of 2 vectors.
426
+ #
427
+ # @param v1 [Vector] a vector
428
+ # @param v2 [Vector] another vector
429
+ #
430
+ # @return [Numeric] result of dot product
431
+ #
432
+ def self.dot (v1, v2)
433
+ v1.dot v2
434
+ end
435
+
436
+ # Calculates the cross product of 2 vectors.
437
+ #
438
+ # @overload cross(v)
439
+ # @overload cross(x, y)
440
+ # @overload cross(x, y, z)
441
+ #
442
+ # @param v [Vector] a vector
443
+ # @param x [Numeric] x of vector
444
+ # @param y [Numeric] y of vector
445
+ # @param z [Numeric] z of vector
446
+ #
447
+ # @return [Numeric] result of cross product
448
+ #
449
+ def cross (a, *rest)
450
+ target = self.class === rest.last ? rest.pop : nil
451
+ v = self.class.new Rays::Point::cross getInternal__, toVector__(a, *rest).getInternal__
452
+ target.set v if self.class === target
453
+ v
454
+ end
455
+
456
+ # Calculates the cross product of 2 vectors.
457
+ #
458
+ # @param v1 [Vector] a vector
459
+ # @param v2 [Vector] another vector
460
+ #
461
+ # @return [Numeric] result of cross product
462
+ #
463
+ def self.cross (v1, v2, target = nil)
464
+ v1.cross v2, target
465
+ end
466
+
467
+ # Rotate the vector.
468
+ #
469
+ # @param angle [Numeric] the angle of rotation
470
+ #
471
+ # @return [Vector] rotated this object
472
+ #
473
+ def rotate (angle)
474
+ angle = @context ? @context.toAngle__(angle) : angle * RAD2DEG__
475
+ @point.rotate! angle
476
+ self
477
+ end
478
+
479
+ # Returns the angle of rotation for this vector.
480
+ #
481
+ # @return [Numeric] the angle in radians
482
+ #
483
+ def heading ()
484
+ Math.atan2 y, x
485
+ end
486
+
487
+ # Returns rotated new vector.
488
+ #
489
+ # @param angle [Numeric] the angle of rotation
490
+ # @param target [Vector] vector to store new vector
491
+ #
492
+ # @return [Vector] rotated vector
493
+ #
494
+ def self.fromAngle (angle, target = nil)
495
+ v = self.new(1, 0, 0).rotate(angle)
496
+ target.set v if target
497
+ v
498
+ end
499
+
500
+ # Returns angle between 2 vectors.
501
+ #
502
+ # @param v1 [Vector] a vector
503
+ # @param v2 [Vector] another vector
504
+ #
505
+ # @return [Numeric] angle in radians
506
+ #
507
+ def self.angleBetween (v1, v2)
508
+ x1, y1, z1 = v1.array
509
+ x2, y2, z2 = v2.array
510
+ return 0 if (x1 == 0 && y1 == 0 && z1 == 0) || (x2 == 0 && y2 == 0 && z2 == 0)
511
+
512
+ x = dot(v1, v2) / (v1.mag * v2.mag)
513
+ return Math::PI if x <= -1
514
+ return 0 if x >= 1
515
+ return Math.acos x
516
+ end
517
+
518
+ # Returns a new 2D unit vector with a random direction.
519
+ #
520
+ # @param target [Vector] a vector to store the new vector
521
+ #
522
+ # @return [Vector] a random vector
523
+ #
524
+ def self.random2D (target = nil)
525
+ v = self.fromAngle rand 0.0...(Math::PI * 2)
526
+ target.set v if target
527
+ v
528
+ end
529
+
530
+ # Returns a new 3D unit vector with a random direction.
531
+ #
532
+ # @param target [Vector] a vector to store the new vector
533
+ #
534
+ # @return [Vector] a random vector
535
+ #
536
+ def self.random3D (target = nil)
537
+ angle = rand 0.0...(Math::PI * 2)
538
+ z = rand -1.0..1.0
539
+ z2 = z ** 2
540
+ x = Math.sqrt(1.0 - z2) * Math.cos(angle)
541
+ y = Math.sqrt(1.0 - z2) * Math.sin(angle)
542
+ v = self.new x, y, z
543
+ target.set v if target
544
+ v
545
+ end
546
+
547
+ # @private
548
+ def inspect ()
549
+ "<##{self.class.name} #{x}, #{y}, #{z}>"
550
+ end
551
+
552
+ # @private
553
+ def <=> (o)
554
+ @point <=> o.getInternal__
555
+ end
556
+
557
+ # @private
558
+ protected def getInternal__ ()
559
+ @point
560
+ end
561
+
562
+ # @private
563
+ private def toVector__ (*args)
564
+ self.class === args.first ? args.first : self.class.new(*args)
565
+ end
566
+
567
+ end# Vector
568
+
569
+
9
570
  # Image object.
10
571
  #
11
572
  class Image
12
573
 
13
574
  # @private
14
575
  def initialize (image)
15
- @image__ = image
576
+ @image = image
16
577
  end
17
578
 
18
579
  # Gets width of image.
@@ -20,7 +581,7 @@ module RubySketch
20
581
  # @return [Numeric] width of image
21
582
  #
22
583
  def width ()
23
- @image__.width
584
+ @image.width
24
585
  end
25
586
 
26
587
  # Gets height of image.
@@ -28,7 +589,7 @@ module RubySketch
28
589
  # @return [Numeric] height of image
29
590
  #
30
591
  def height ()
31
- @image__.height
592
+ @image.height
32
593
  end
33
594
 
34
595
  # Resizes image.
@@ -39,8 +600,8 @@ module RubySketch
39
600
  # @return [nil] nil
40
601
  #
41
602
  def resize (width, height)
42
- @image__ = Rays::Image.new(width, height).paint do |painter|
43
- painter.image @image__, 0, 0, width, height
603
+ @image = Rays::Image.new(width, height).paint do |painter|
604
+ painter.image @image, 0, 0, width, height
44
605
  end
45
606
  nil
46
607
  end
@@ -64,7 +625,7 @@ module RubySketch
64
625
  #
65
626
  def copy (img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
66
627
  img ||= self
67
- @image__.paint do |painter|
628
+ @image.paint do |painter|
68
629
  painter.image img.getInternal__, sx, sy, sw, sh, dx, dy, dw, dh
69
630
  end
70
631
  end
@@ -74,12 +635,12 @@ module RubySketch
74
635
  # @param filename [String] file name to save image
75
636
  #
76
637
  def save (filename)
77
- @image__.save filename
638
+ @image.save filename
78
639
  end
79
640
 
80
641
  # @private
81
642
  def getInternal__ ()
82
- @image__
643
+ @image
83
644
  end
84
645
 
85
646
  end# Image
@@ -167,43 +728,110 @@ module RubySketch
167
728
  end# Touch
168
729
 
169
730
 
170
- # Drawing context
731
+ # Camera object.
171
732
  #
172
- module GraphicsContext
733
+ class Capture
173
734
 
174
- # PI / 2
735
+ # Returns a list of available camera device names
175
736
  #
176
- HALF_PI = Math::PI / 2
177
-
178
- # PI / 4
737
+ # @return [Array] device name list
179
738
  #
180
- QUARTER_PI = Math::PI / 4
739
+ def self.list ()
740
+ ['default']
741
+ end
181
742
 
182
- # PI * 2
743
+ # Initialize camera object.
183
744
  #
184
- TWO_PI = Math::PI * 2
745
+ def initialize ()
746
+ @camera = Rays::Camera.new
747
+ end
185
748
 
186
- # PI * 2
749
+ # Start capturing.
187
750
  #
188
- TAU = Math::PI * 2
189
-
190
- # RGB mode for colorMode().
751
+ # @return [Capture] self
191
752
  #
192
- RGB = :RGB
753
+ def start ()
754
+ raise "Failed to start capture" unless @camera.start
755
+ self
756
+ end
193
757
 
194
- # HSB mode for colorMode().
758
+ # Stop capturing.
195
759
  #
196
- HSB = :HSB
197
-
198
- # Radian mode for angleMode().
760
+ # @return [nil] nil
199
761
  #
200
- RADIANS = :RADIANS
762
+ def stop ()
763
+ @camera.stop
764
+ nil
765
+ end
201
766
 
202
- # Degree mode for angleMode().
767
+ # Returns is the next captured image available?
203
768
  #
204
- DEGREES = :DEGREES
205
-
206
- # Mode for rectMode(), ellipseMode() and imageMode().
769
+ # @return [Boolean] true means object has next frame
770
+ #
771
+ def available ()
772
+ @camera.active?
773
+ end
774
+
775
+ # Reads next frame image
776
+ #
777
+ def read ()
778
+ @camera.image
779
+ end
780
+
781
+ # @private
782
+ def getInternal__ ()
783
+ @camera.image || dummyImage__
784
+ end
785
+
786
+ # @private
787
+ private def dummyImage__ ()
788
+ @dummy ||= Rays::Image.new 1, 1
789
+ end
790
+
791
+ end# Capture
792
+
793
+
794
+ # Drawing context
795
+ #
796
+ module GraphicsContext
797
+
798
+ # PI
799
+ #
800
+ PI = Math::PI
801
+
802
+ # PI / 2
803
+ #
804
+ HALF_PI = PI / 2
805
+
806
+ # PI / 4
807
+ #
808
+ QUARTER_PI = PI / 4
809
+
810
+ # PI * 2
811
+ #
812
+ TWO_PI = PI * 2
813
+
814
+ # PI * 2
815
+ #
816
+ TAU = PI * 2
817
+
818
+ # RGB mode for colorMode().
819
+ #
820
+ RGB = :RGB
821
+
822
+ # HSB mode for colorMode().
823
+ #
824
+ HSB = :HSB
825
+
826
+ # Radian mode for angleMode().
827
+ #
828
+ RADIANS = :RADIANS
829
+
830
+ # Degree mode for angleMode().
831
+ #
832
+ DEGREES = :DEGREES
833
+
834
+ # Mode for rectMode(), ellipseMode() and imageMode().
207
835
  #
208
836
  CORNER = :CORNER
209
837
 
@@ -254,7 +882,7 @@ module RubySketch
254
882
  @painter__ = painter
255
883
  @painter__.miter_limit = 10
256
884
 
257
- @drawing = false
885
+ @drawing__ = false
258
886
  @hsbColor__ = false
259
887
  @colorMaxes__ = [1.0] * 4
260
888
  @angleScale__ = 1.0
@@ -280,11 +908,11 @@ module RubySketch
280
908
  def beginDraw ()
281
909
  @matrixStack__.clear
282
910
  @styleStack__.clear
283
- @drawing = true
911
+ @drawing__ = true
284
912
  end
285
913
 
286
914
  def endDraw ()
287
- @drawing = false
915
+ @drawing__ = false
288
916
  end
289
917
 
290
918
  def width ()
@@ -361,7 +989,7 @@ module RubySketch
361
989
  #
362
990
  def angleMode (mode)
363
991
  @angleScale__ = case mode.upcase.to_sym
364
- when RADIANS then Utility::RAD2DEG__
992
+ when RADIANS then RAD2DEG__
365
993
  when DEGREES then 1.0
366
994
  else raise ArgumentError, "invalid angle mode: #{mode}"
367
995
  end
@@ -369,7 +997,7 @@ module RubySketch
369
997
  end
370
998
 
371
999
  # @private
372
- private def toAngle__ (angle)
1000
+ def toAngle__ (angle)
373
1001
  angle * @angleScale__
374
1002
  end
375
1003
 
@@ -848,8 +1476,9 @@ module RubySketch
848
1476
  #
849
1477
  def image (img, a, b, c = nil, d = nil)
850
1478
  assertDrawing__
851
- x, y, w, h = toXYWH__ @imageMode__, a, b, c || img.width, d || img.height
852
- @painter__.image img.getInternal__, x, y, w, h
1479
+ i = img.getInternal__
1480
+ x, y, w, h = toXYWH__ @imageMode__, a, b, c || i.width, d || i.height
1481
+ @painter__.image i, x, y, w, h
853
1482
  nil
854
1483
  end
855
1484
 
@@ -1030,8 +1659,8 @@ module RubySketch
1030
1659
  end
1031
1660
 
1032
1661
  # @private
1033
- def assertDrawing__ ()
1034
- raise "call beginDraw() before drawing" unless @drawing
1662
+ private def assertDrawing__ ()
1663
+ raise "call beginDraw() before drawing" unless @drawing__
1035
1664
  end
1036
1665
 
1037
1666
  end# GraphicsContext
@@ -1043,17 +1672,23 @@ module RubySketch
1043
1672
 
1044
1673
  include GraphicsContext
1045
1674
 
1675
+ # Initialize graphics object.
1676
+ #
1046
1677
  def initialize (width, height)
1047
1678
  @image__ = Rays::Image.new width, height
1048
1679
  setup__ @image__.painter
1049
1680
  end
1050
1681
 
1682
+ # Start drawing.
1683
+ #
1051
1684
  def beginDraw ()
1052
1685
  @painter__.__send__ :begin_paint
1053
1686
  super
1054
1687
  push
1055
1688
  end
1056
1689
 
1690
+ # End drawing.
1691
+ #
1057
1692
  def endDraw ()
1058
1693
  pop
1059
1694
  super
@@ -1063,86 +1698,325 @@ module RubySketch
1063
1698
  end# Graphics
1064
1699
 
1065
1700
 
1066
- module Utility
1701
+ # Processing context
1702
+ #
1703
+ class Context
1067
1704
 
1068
- # @private
1069
- DEG2RAD__ = Math::PI / 180.0
1705
+ include GraphicsContext
1706
+
1707
+ Vector = Processing::Vector
1708
+ Capture = Processing::Capture
1709
+ Graphics = Processing::Graphics
1710
+
1711
+ @@context__ = nil
1712
+
1713
+ def self.context__ ()
1714
+ @@context__
1715
+ end
1070
1716
 
1071
1717
  # @private
1072
- RAD2DEG__ = 180.0 / Math::PI
1718
+ def initialize (window)
1719
+ @@context__ = self
1073
1720
 
1074
- # Converts degree to radian.
1075
- #
1076
- # @param degree [Numeric] degree to convert
1077
- #
1078
- # @return [Numeric] radian
1079
- #
1080
- def radians (degree)
1081
- degree * DEG2RAD__
1721
+ @window__ = window
1722
+ @image__ = @window__.canvas
1723
+ setup__ @window__.canvas_painter.paint {background 0.8}
1724
+
1725
+ @loop__ = true
1726
+ @redraw__ = false
1727
+ @frameCount__ = 0
1728
+ @mousePos__ =
1729
+ @mousePrevPos__ = Rays::Point.new 0
1730
+ @mousePressed__ = false
1731
+ @touches__ = []
1732
+
1733
+ @window__.before_draw = proc {beginDraw}
1734
+ @window__.after_draw = proc {endDraw}
1735
+
1736
+ drawFrame = -> {
1737
+ @image__ = @window__.canvas
1738
+ @painter__ = @window__.canvas_painter
1739
+ begin
1740
+ push
1741
+ @drawBlock__.call if @drawBlock__
1742
+ ensure
1743
+ pop
1744
+ @frameCount__ += 1
1745
+ end
1746
+ }
1747
+
1748
+ @window__.draw = proc do |e|
1749
+ if @loop__ || @redraw__
1750
+ @redraw__ = false
1751
+ drawFrame.call
1752
+ end
1753
+ @mousePrevPos__ = @mousePos__
1754
+ end
1755
+
1756
+ updatePointerStates = -> event, pressed = nil {
1757
+ @mousePos__ = event.pos
1758
+ @mousePressed__ = pressed if pressed != nil
1759
+ @touches__ = event.positions.map {|pos| Touch.new pos.x, pos.y}
1760
+ }
1761
+
1762
+ @window__.pointer_down = proc do |e|
1763
+ updatePointerStates.call e, true
1764
+ (@touchStartedBlock__ || @mousePressedBlock__)&.call
1765
+ end
1766
+
1767
+ @window__.pointer_up = proc do |e|
1768
+ updatePointerStates.call e, false
1769
+ (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
1770
+ end
1771
+
1772
+ @window__.pointer_move = proc do |e|
1773
+ updatePointerStates.call e
1774
+ (@touchMovedBlock__ || @mouseMovedBlock__)&.call
1775
+ end
1776
+
1777
+ @window__.pointer_drag = proc do |e|
1778
+ updatePointerStates.call e
1779
+ (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
1780
+ end
1082
1781
  end
1083
1782
 
1084
- # Converts radian to degree.
1085
- #
1086
- # @param radian [Numeric] radian to convert
1087
- #
1088
- # @return [Numeric] degree
1783
+ # Define setup block.
1089
1784
  #
1090
- def degrees (radian)
1091
- radian * RAD2DEG__
1785
+ def setup (&block)
1786
+ @window__.setup = block
1787
+ nil
1092
1788
  end
1093
1789
 
1094
- # Returns the absolute number of the value.
1790
+ # Define draw block.
1095
1791
  #
1096
- # @param value [Numeric] number
1792
+ def draw (&block)
1793
+ @drawBlock__ = block if block
1794
+ nil
1795
+ end
1796
+
1797
+ def key (&block)
1798
+ @window__.key = block
1799
+ nil
1800
+ end
1801
+
1802
+ def mousePressed (&block)
1803
+ @mousePressedBlock__ = block if block
1804
+ @mousePressed__
1805
+ end
1806
+
1807
+ def mouseReleased (&block)
1808
+ @mouseReleasedBlock__ = block if block
1809
+ nil
1810
+ end
1811
+
1812
+ def mouseMoved (&block)
1813
+ @mouseMovedBlock__ = block if block
1814
+ nil
1815
+ end
1816
+
1817
+ def mouseDragged (&block)
1818
+ @mouseDraggedBlock__ = block if block
1819
+ nil
1820
+ end
1821
+
1822
+ def touchStarted (&block)
1823
+ @touchStartedBlock__ = block if block
1824
+ nil
1825
+ end
1826
+
1827
+ def touchEnded (&block)
1828
+ @touchEndedBlock__ = block if block
1829
+ nil
1830
+ end
1831
+
1832
+ def touchMoved (&block)
1833
+ @touchMovedBlock__ = block if block
1834
+ nil
1835
+ end
1836
+
1837
+ # @private
1838
+ private def size__ (width, height)
1839
+ raise 'size() must be called on startup or setup block' if @started__
1840
+
1841
+ @painter__.__send__ :end_paint
1842
+ @window__.__send__ :reset_canvas, width, height
1843
+ @painter__.__send__ :begin_paint
1844
+
1845
+ @auto_resize__ = false
1846
+ end
1847
+
1848
+ def windowWidth ()
1849
+ @window__.width
1850
+ end
1851
+
1852
+ def windowHeight ()
1853
+ @window__.height
1854
+ end
1855
+
1856
+ # Returns number of frames since program started.
1097
1857
  #
1098
- # @return [Numeric] absolute number
1858
+ # @return [Integer] total number of frames
1099
1859
  #
1100
- def abs (value)
1101
- value.abs
1860
+ def frameCount ()
1861
+ @frameCount__
1102
1862
  end
1103
1863
 
1104
- # Returns the closest integer number greater than or equal to the value.
1105
- #
1106
- # @param value [Numeric] number
1864
+ # Returns number of frames per second.
1107
1865
  #
1108
- # @return [Numeric] rounded up number
1866
+ # @return [Float] frames per second
1109
1867
  #
1110
- def ceil (value)
1111
- value.ceil
1868
+ def frameRate ()
1869
+ @window__.event.fps
1112
1870
  end
1113
1871
 
1114
- # Returns the closest integer number less than or equal to the value.
1115
- #
1116
- # @param value [Numeric] number
1872
+ # Returns pixel density
1117
1873
  #
1118
- # @return [Numeric] rounded down number
1874
+ # @return [Numeric] pixel density
1119
1875
  #
1120
- def floor (value)
1121
- value.floor
1876
+ def displayDensity ()
1877
+ @painter__.pixel_density
1122
1878
  end
1123
1879
 
1124
- # Returns the closest integer number.
1125
- #
1126
- # @param value [Numeric] number
1880
+ # Returns mouse x position
1127
1881
  #
1128
- # @return [Numeric] rounded number
1882
+ # @return [Numeric] horizontal position of mouse
1129
1883
  #
1130
- def round (value)
1131
- value.round
1884
+ def mouseX ()
1885
+ @mousePos__.x
1132
1886
  end
1133
1887
 
1134
- # Returns value raised to the power of exponent.
1135
- #
1136
- # @param value [Numeric] base number
1137
- # @param exponent [Numeric] exponent number
1888
+ # Returns mouse y position
1138
1889
  #
1139
- # @return [Numeric] value ** exponent
1890
+ # @return [Numeric] vertical position of mouse
1140
1891
  #
1141
- def pow (value, exponent)
1142
- value ** exponent
1892
+ def mouseY ()
1893
+ @mousePos__.y
1143
1894
  end
1144
1895
 
1145
- # Returns squared value.
1896
+ # Returns mouse x position in previous frame
1897
+ #
1898
+ # @return [Numeric] horizontal position of mouse
1899
+ #
1900
+ def pmouseX ()
1901
+ @mousePrevPos__.x
1902
+ end
1903
+
1904
+ # Returns mouse y position in previous frame
1905
+ #
1906
+ # @return [Numeric] vertical position of mouse
1907
+ #
1908
+ def pmouseY ()
1909
+ @mousePrevPos__.y
1910
+ end
1911
+
1912
+ # Returns array of touches
1913
+ #
1914
+ # @return [Array] Touch objects
1915
+ #
1916
+ def touches ()
1917
+ @touches__
1918
+ end
1919
+
1920
+ # Enables calling draw block on every frame.
1921
+ #
1922
+ # @return [nil] nil
1923
+ #
1924
+ def loop ()
1925
+ @loop__ = true
1926
+ end
1927
+
1928
+ # Disables calling draw block on every frame.
1929
+ #
1930
+ # @return [nil] nil
1931
+ #
1932
+ def noLoop ()
1933
+ @loop__ = false
1934
+ end
1935
+
1936
+ # Calls draw block to redraw frame.
1937
+ #
1938
+ # @return [nil] nil
1939
+ #
1940
+ def redraw ()
1941
+ @redraw__ = true
1942
+ end
1943
+
1944
+ #
1945
+ # Utilities
1946
+ #
1947
+
1948
+ # Returns the absolute number of the value.
1949
+ #
1950
+ # @param value [Numeric] number
1951
+ #
1952
+ # @return [Numeric] absolute number
1953
+ #
1954
+ def abs (value)
1955
+ value.abs
1956
+ end
1957
+
1958
+ # Returns the closest integer number greater than or equal to the value.
1959
+ #
1960
+ # @param value [Numeric] number
1961
+ #
1962
+ # @return [Numeric] rounded up number
1963
+ #
1964
+ def ceil (value)
1965
+ value.ceil
1966
+ end
1967
+
1968
+ # Returns the closest integer number less than or equal to the value.
1969
+ #
1970
+ # @param value [Numeric] number
1971
+ #
1972
+ # @return [Numeric] rounded down number
1973
+ #
1974
+ def floor (value)
1975
+ value.floor
1976
+ end
1977
+
1978
+ # Returns the closest integer number.
1979
+ #
1980
+ # @param value [Numeric] number
1981
+ #
1982
+ # @return [Numeric] rounded number
1983
+ #
1984
+ def round (value)
1985
+ value.round
1986
+ end
1987
+
1988
+ # Returns the natural logarithm (the base-e logarithm) of a number.
1989
+ #
1990
+ # @param value [Numeric] number (> 0.0)
1991
+ #
1992
+ # @return [Numeric] result number
1993
+ #
1994
+ def log (n)
1995
+ Math.log n
1996
+ end
1997
+
1998
+ # Returns Euler's number e raised to the power of value.
1999
+ #
2000
+ # @param value [Numeric] number
2001
+ #
2002
+ # @return [Numeric] result number
2003
+ #
2004
+ def exp (n)
2005
+ Math.exp n
2006
+ end
2007
+
2008
+ # Returns value raised to the power of exponent.
2009
+ #
2010
+ # @param value [Numeric] base number
2011
+ # @param exponent [Numeric] exponent number
2012
+ #
2013
+ # @return [Numeric] value ** exponent
2014
+ #
2015
+ def pow (value, exponent)
2016
+ value ** exponent
2017
+ end
2018
+
2019
+ # Returns squared value.
1146
2020
  #
1147
2021
  # @param value [Numeric] number
1148
2022
  #
@@ -1152,6 +2026,16 @@ module RubySketch
1152
2026
  value * value
1153
2027
  end
1154
2028
 
2029
+ # Returns squared value.
2030
+ #
2031
+ # @param value [Numeric] number
2032
+ #
2033
+ # @return [Numeric] squared value
2034
+ #
2035
+ def sqrt (value)
2036
+ Math.sqrt value
2037
+ end
2038
+
1155
2039
  # Returns the magnitude (or length) of a vector.
1156
2040
  #
1157
2041
  # @overload mag(x, y)
@@ -1284,292 +2168,199 @@ module RubySketch
1284
2168
  value < min ? min : (value > max ? max : value)
1285
2169
  end
1286
2170
 
1287
- # Returns the perlin noise value.
1288
- #
1289
- # @overload noise(x)
1290
- # @overload noise(x, y)
1291
- # @overload noise(x, y, z)
2171
+ # Converts degree to radian.
1292
2172
  #
1293
- # @param x [Numeric] horizontal point in noise space
1294
- # @param y [Numeric] vertical point in noise space
1295
- # @param z [Numeric] depth point in noise space
2173
+ # @param degree [Numeric] degree to convert
1296
2174
  #
1297
- # @return [Numeric] noise value (0.0..1.0)
2175
+ # @return [Numeric] radian
1298
2176
  #
1299
- def noise (x, y = 0, z = 0)
1300
- Rays.perlin(x, y, z) / 2.0 + 0.5
2177
+ def radians (degree)
2178
+ degree * DEG2RAD__
1301
2179
  end
1302
2180
 
1303
- # Loads image.
2181
+ # Converts radian to degree.
1304
2182
  #
1305
- # @param filename [String] file name to load image
1306
- # @param extension [String] type of image to load (ex. 'png')
2183
+ # @param radian [Numeric] radian to convert
1307
2184
  #
1308
- # @return [Image] loaded image object
2185
+ # @return [Numeric] degree
1309
2186
  #
1310
- def loadImage (filename, extension = nil)
1311
- filename = getImage__ filename, extension if filename =~ %r|^https?://|
1312
- Image.new Rays::Image.load filename
1313
- end
1314
-
1315
- # @private
1316
- private def getImage__ (uri, ext)
1317
- ext ||= File.extname uri
1318
- raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
1319
-
1320
- tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
1321
- path = tmpdir + Digest::SHA1.hexdigest(uri)
1322
- path = path.sub_ext ext
1323
-
1324
- unless path.file?
1325
- URI.open uri do |input|
1326
- tmpdir.mkdir unless tmpdir.directory?
1327
- path.open('w') do |output|
1328
- while buf = input.read(2 ** 16)
1329
- output.write buf
1330
- end
1331
- end
1332
- end
1333
- end
1334
- path.to_s
1335
- end
1336
-
1337
- def createGraphics (width, height)
1338
- Graphics.new width, height
1339
- end
1340
-
1341
- end# Utility
1342
-
1343
-
1344
- # Processing context
1345
- #
1346
- module Context
1347
-
1348
- include GraphicsContext, Utility, Math
1349
-
1350
- # @private
1351
- def setup__ (window)
1352
- @window__ = window
1353
- @image__ = @window__.canvas
1354
- super @window__.canvas_painter.paint {background 0.8}
1355
-
1356
- @loop__ = true
1357
- @redraw__ = false
1358
- @frameCount__ = 0
1359
- @mousePos__ =
1360
- @mousePrevPos__ = Rays::Point.new 0
1361
- @mousePressed__ = false
1362
- @touches__ = []
1363
-
1364
- @window__.before_draw = proc {beginDraw}
1365
- @window__.after_draw = proc {endDraw}
1366
-
1367
- drawFrame = -> {
1368
- @image__ = @window__.canvas
1369
- @painter__ = @window__.canvas_painter
1370
- begin
1371
- push
1372
- @drawBlock__.call if @drawBlock__
1373
- ensure
1374
- pop
1375
- @frameCount__ += 1
1376
- end
1377
- }
1378
-
1379
- @window__.draw = proc do |e|
1380
- if @loop__ || @redraw__
1381
- @redraw__ = false
1382
- drawFrame.call
1383
- end
1384
- @mousePrevPos__ = @mousePos__
1385
- end
1386
-
1387
- updatePointerStates = -> event, pressed = nil {
1388
- @mousePos__ = event.pos
1389
- @mousePressed__ = pressed if pressed != nil
1390
- @touches__ = event.positions.map {|pos| Touch.new pos.x, pos.y}
1391
- }
1392
-
1393
- @window__.pointer_down = proc do |e|
1394
- updatePointerStates.call e, true
1395
- (@touchStartedBlock__ || @mousePressedBlock__)&.call
1396
- end
1397
-
1398
- @window__.pointer_up = proc do |e|
1399
- updatePointerStates.call e, false
1400
- (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
1401
- end
1402
-
1403
- @window__.pointer_move = proc do |e|
1404
- updatePointerStates.call e
1405
- (@touchMovedBlock__ || @mouseMovedBlock__)&.call
1406
- end
1407
-
1408
- @window__.pointer_drag = proc do |e|
1409
- updatePointerStates.call e
1410
- (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
1411
- end
2187
+ def degrees (radian)
2188
+ radian * RAD2DEG__
1412
2189
  end
1413
2190
 
1414
- # Define setup block.
2191
+ # Returns the sine of an angle.
1415
2192
  #
1416
- def setup (&block)
1417
- @window__.setup = block
1418
- nil
1419
- end
1420
-
1421
- # Define draw block.
2193
+ # @param angle [Numeric] angle in radians
1422
2194
  #
1423
- def draw (&block)
1424
- @drawBlock__ = block if block
1425
- nil
1426
- end
1427
-
1428
- def key (&block)
1429
- @window__.key = block
1430
- nil
1431
- end
1432
-
1433
- def mousePressed (&block)
1434
- @mousePressedBlock__ = block if block
1435
- @mousePressed__
1436
- end
1437
-
1438
- def mouseReleased (&block)
1439
- @mouseReleasedBlock__ = block if block
1440
- nil
1441
- end
1442
-
1443
- def mouseMoved (&block)
1444
- @mouseMovedBlock__ = block if block
1445
- nil
1446
- end
1447
-
1448
- def mouseDragged (&block)
1449
- @mouseDraggedBlock__ = block if block
1450
- nil
1451
- end
1452
-
1453
- def touchStarted (&block)
1454
- @touchStartedBlock__ = block if block
1455
- nil
1456
- end
1457
-
1458
- def touchEnded (&block)
1459
- @touchEndedBlock__ = block if block
1460
- nil
1461
- end
1462
-
1463
- def touchMoved (&block)
1464
- @touchMovedBlock__ = block if block
1465
- nil
1466
- end
1467
-
1468
- # @private
1469
- private def size__ (width, height)
1470
- raise 'size() must be called on startup or setup block' if @started__
1471
-
1472
- @painter__.__send__ :end_paint
1473
- @window__.__send__ :reset_canvas, width, height
1474
- @painter__.__send__ :begin_paint
1475
-
1476
- @auto_resize__ = false
1477
- end
1478
-
1479
- def windowWidth ()
1480
- @window__.width
2195
+ # @return [Numeric] the sine
2196
+ #
2197
+ def sin (angle)
2198
+ Math.sin angle
1481
2199
  end
1482
2200
 
1483
- def windowHeight ()
1484
- @window__.height
2201
+ # Returns the cosine of an angle.
2202
+ #
2203
+ # @param angle [Numeric] angle in radians
2204
+ #
2205
+ # @return [Numeric] the cosine
2206
+ #
2207
+ def cos (angle)
2208
+ Math.cos angle
1485
2209
  end
1486
2210
 
1487
- # Returns number of frames since program started.
2211
+ # Returns the ratio of the sine and cosine of an angle.
1488
2212
  #
1489
- # @return [Integer] total number of frames
2213
+ # @param angle [Numeric] angle in radians
1490
2214
  #
1491
- def frameCount ()
1492
- @frameCount__
2215
+ # @return [Numeric] the tangent
2216
+ #
2217
+ def tan (angle)
2218
+ Math.tan angle
1493
2219
  end
1494
2220
 
1495
- # Returns number of frames per second.
2221
+ # Returns the inverse of sin().
1496
2222
  #
1497
- # @return [Float] frames per second
2223
+ # @param value [Numeric] value for calculation
1498
2224
  #
1499
- def frameRate ()
1500
- @window__.event.fps
2225
+ # @return [Numeric] the arc sine
2226
+ #
2227
+ def asin (value)
2228
+ Math.asin value
1501
2229
  end
1502
2230
 
1503
- # Returns pixel density
2231
+ # Returns the inverse of cos().
1504
2232
  #
1505
- # @return [Numeric] pixel density
2233
+ # @param value [Numeric] value for calculation
1506
2234
  #
1507
- def displayDensity ()
1508
- @painter__.pixel_density
2235
+ # @return [Numeric] the arc cosine
2236
+ #
2237
+ def acos (value)
2238
+ Math.acos value
1509
2239
  end
1510
2240
 
1511
- # Returns mouse x position
2241
+ # Returns the inverse of tan().
1512
2242
  #
1513
- # @return [Numeric] horizontal position of mouse
2243
+ # @param value [Numeric] value for valculation
1514
2244
  #
1515
- def mouseX ()
1516
- @mousePos__.x
2245
+ # @return [Numeric] the arc tangent
2246
+ #
2247
+ def atan (value)
2248
+ Math.atan value
1517
2249
  end
1518
2250
 
1519
- # Returns mouse y position
2251
+ # Returns the angle from a specified point.
1520
2252
  #
1521
- # @return [Numeric] vertical position of mouse
2253
+ # @param y [Numeric] y of the point
2254
+ # @param x [Numeric] x of the point
1522
2255
  #
1523
- def mouseY ()
1524
- @mousePos__.y
2256
+ # @return [Numeric] the angle in radians
2257
+ #
2258
+ def atan2 (y, x)
2259
+ Math.atan2 y, x
1525
2260
  end
1526
2261
 
1527
- # Returns mouse x position in previous frame
2262
+ # Returns the perlin noise value.
1528
2263
  #
1529
- # @return [Numeric] horizontal position of mouse
2264
+ # @overload noise(x)
2265
+ # @overload noise(x, y)
2266
+ # @overload noise(x, y, z)
1530
2267
  #
1531
- def pmouseX ()
1532
- @mousePrevPos__.x
2268
+ # @param x [Numeric] horizontal point in noise space
2269
+ # @param y [Numeric] vertical point in noise space
2270
+ # @param z [Numeric] depth point in noise space
2271
+ #
2272
+ # @return [Numeric] noise value (0.0..1.0)
2273
+ #
2274
+ def noise (x, y = 0, z = 0)
2275
+ Rays.perlin(x, y, z) / 2.0 + 0.5
1533
2276
  end
1534
2277
 
1535
- # Returns mouse y position in previous frame
2278
+ # Returns a random number in range low...high
1536
2279
  #
1537
- # @return [Numeric] vertical position of mouse
2280
+ # @overload random()
2281
+ # @overload random(high)
2282
+ # @overload random(low, high)
2283
+ # @overload random(choices)
1538
2284
  #
1539
- def pmouseY ()
1540
- @mousePrevPos__.y
2285
+ # @param low [Numeric] lower limit
2286
+ # @param high [Numeric] upper limit
2287
+ # @param choices [Array] array to choose from
2288
+ #
2289
+ # @return [Float] random number
2290
+ #
2291
+ def random (*args)
2292
+ return args.first.sample if args.first.kind_of? Array
2293
+ high, low = args.reverse
2294
+ rand (low || 0).to_f...(high || 1).to_f
1541
2295
  end
1542
2296
 
1543
- # Returns array of touches
2297
+ # Creates a new vector.
1544
2298
  #
1545
- # @return [Array] Touch objects
2299
+ # @overload createVector()
2300
+ # @overload createVector(x, y)
2301
+ # @overload createVector(x, y, z)
1546
2302
  #
1547
- def touches ()
1548
- @touches__
2303
+ # @param x [Numeric] x of new vector
2304
+ # @param y [Numeric] y of new vector
2305
+ # @param z [Numeric] z of new vector
2306
+ #
2307
+ # @return [Vector] new vector
2308
+ #
2309
+ def createVector (*args)
2310
+ Vector.new *args
1549
2311
  end
1550
2312
 
1551
- # Enables calling draw block on every frame.
2313
+ # Creates a camera object as a video input device.
1552
2314
  #
1553
- # @return [nil] nil
2315
+ # @return [Capture] camera object
1554
2316
  #
1555
- def loop ()
1556
- @loop__ = true
2317
+ def createCapture (*args)
2318
+ Capture.new *args
1557
2319
  end
1558
2320
 
1559
- # Disables calling draw block on every frame.
2321
+ # Creates a new off-screen graphics context object.
1560
2322
  #
1561
- # @return [nil] nil
2323
+ # @param width [Numeric] width of graphics image
2324
+ # @param height [Numeric] height of graphics image
1562
2325
  #
1563
- def noLoop ()
1564
- @loop__ = false
2326
+ # @return [Graphics] graphics object
2327
+ #
2328
+ def createGraphics (width, height)
2329
+ Graphics.new width, height
1565
2330
  end
1566
2331
 
1567
- # Calls draw block to redraw frame.
2332
+ # Loads image.
1568
2333
  #
1569
- # @return [nil] nil
2334
+ # @param filename [String] file name to load image
2335
+ # @param extension [String] type of image to load (ex. 'png')
1570
2336
  #
1571
- def redraw ()
1572
- @redraw__ = true
2337
+ # @return [Image] loaded image object
2338
+ #
2339
+ def loadImage (filename, extension = nil)
2340
+ filename = getImage__ filename, extension if filename =~ %r|^https?://|
2341
+ Image.new Rays::Image.load filename
2342
+ end
2343
+
2344
+ # @private
2345
+ private def getImage__ (uri, ext)
2346
+ ext ||= File.extname uri
2347
+ raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
2348
+
2349
+ tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
2350
+ path = tmpdir + Digest::SHA1.hexdigest(uri)
2351
+ path = path.sub_ext ext
2352
+
2353
+ unless path.file?
2354
+ URI.open uri do |input|
2355
+ tmpdir.mkdir unless tmpdir.directory?
2356
+ path.open('w') do |output|
2357
+ while buf = input.read(2 ** 16)
2358
+ output.write buf
2359
+ end
2360
+ end
2361
+ end
2362
+ end
2363
+ path.to_s
1573
2364
  end
1574
2365
 
1575
2366
  end# Context