rubysketch 0.2.7 → 0.3.0

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: 35b603297108689f78cc6cd1b7c1577c314e3658763889cd751c57351d0ded11
4
- data.tar.gz: adf06019c19a710d427c39ccf6febfa7aa01b8c01e748cd6061fff27bf286445
3
+ metadata.gz: 6a044fb62451ebcd69c89a5a9cb2781c747d4298142a9e6828f71cdbc63da999
4
+ data.tar.gz: 6dade74829619df93d947160f930fdc19563cc9042b826ef7b8b4bd6015cfb00
5
5
  SHA512:
6
- metadata.gz: a427610a5a9c648ce0b301d903f2c7b70a9fc18ae9b9286fe896151485d6df7ef3a2b15cb823d978b790f267367c42686e3fc651d86a21168f5a24d4cd76c7ab
7
- data.tar.gz: 17a16b9259156c098ba2a34db1aac50cd7483481734b0c1bcb839870313fdb08c216ae0421c21324f59366e1c5b72bfccee35b81bd426edaba05db0d03acaa6e
6
+ metadata.gz: 7801ba15e151b5c519047b2145b71e820428b2b9601c9fccaffd1eb6d6b67ff344b6aa7b0cd12c9151d431df01d201c5cc63e3a8ffa92d854b5934a2357fb8ec
7
+ data.tar.gz: 44f7ad0c273aa88974356dfcc3fbc7d080d8bccb023ab4137db23f2d7b85b0fa2b06b590a97b487f803575d903a87a8747f26ff3e0518b5c76623f26dcafd35d
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.7
1
+ 0.3.0
@@ -2,32 +2,14 @@ require 'rubysketch'
2
2
 
3
3
 
4
4
  begin
5
- context = RubySketch::Processing.new
6
- methods = context.class.instance_methods(false)
7
- .reject {|name| name =~ /__$/}
8
- consts = context.class.constants
9
- .reject {|name| name =~ /__$/}
10
- .each_with_object({}) {|name, h| h[name] = context.class.const_get name}
5
+ include RubySketch::Processing::Context
11
6
 
12
- self.class.class_eval do
13
- methods.each do |name|
14
- define_method name do |*args, &block|
15
- context.__send__ name, *args, &block
16
- end
17
- end
18
- consts.each do |(name, value)|
19
- const_set name, value
20
- end
21
- end
22
-
23
- window = RubySketch::Window.new do |_|
24
- window.start
25
- end
26
- context.setup__ window
7
+ window = RubySketch::Window.new {start}
8
+ setup__ window
27
9
 
28
- window.canvas_painter.__send__ :begin_paint
10
+ window.__send__ :begin_draw
29
11
  at_exit do
30
- window.canvas_painter.__send__ :end_paint
31
- Reflex.start {window.show}
12
+ window.__send__ :end_draw
13
+ Reflex.start {window.show} unless $!
32
14
  end
33
15
  end
@@ -3,1112 +3,898 @@ module RubySketch
3
3
 
4
4
  # Processing compatible API
5
5
  #
6
- class Processing
6
+ module Processing
7
7
 
8
- include Math
9
8
 
10
- HALF_PI = PI / 2
11
- QUARTER_PI = PI / 4
12
- TWO_PI = PI * 2
13
- TAU = PI * 2
14
-
15
- # RGB mode for colorMode().
9
+ # Image object.
16
10
  #
17
- RGB = :RGB
11
+ class Image
18
12
 
19
- # HSB mode for colorMode().
20
- #
21
- HSB = :HSB
13
+ # @private
14
+ def initialize (image)
15
+ @image__ = image
16
+ end
22
17
 
23
- # Radian mode for angleMode().
24
- #
25
- RADIANS = :RADIANS
18
+ # Gets width of image.
19
+ #
20
+ # @return [Numeric] width of image
21
+ #
22
+ def width ()
23
+ @image__.width
24
+ end
26
25
 
27
- # Degree mode for angleMode().
28
- #
29
- DEGREES = :DEGREES
26
+ # Gets height of image.
27
+ #
28
+ # @return [Numeric] height of image
29
+ #
30
+ def height ()
31
+ @image__.height
32
+ end
30
33
 
31
- # Mode for rectMode(), ellipseMode() and imageMode().
32
- #
33
- CORNER = :CORNER
34
+ # Resizes image.
35
+ #
36
+ # @param width [Numeric] width for resized image
37
+ # @param height [Numeric] height for resized image
38
+ #
39
+ # @return [nil] nil
40
+ #
41
+ def resize (width, height)
42
+ @image__ = Rays::Image.new(width, height).paint do |painter|
43
+ painter.image @image__, 0, 0, width, height
44
+ end
45
+ nil
46
+ end
34
47
 
35
- # Mode for rectMode(), ellipseMode() and imageMode().
36
- #
37
- CORNERS = :CORNERS
48
+ # Copies image.
49
+ #
50
+ # @overload copy(sx, sy, sw, sh, dx, dy, dw, dh)
51
+ # @overload copy(img, sx, sy, sw, sh, dx, dy, dw, dh)
52
+ #
53
+ # @param img [Image] image for copy source
54
+ # @param sx [Numrtic] x position of source region
55
+ # @param sy [Numrtic] y position of source region
56
+ # @param sw [Numrtic] width of source region
57
+ # @param sh [Numrtic] height of source region
58
+ # @param dx [Numrtic] x position of destination region
59
+ # @param dy [Numrtic] y position of destination region
60
+ # @param dw [Numrtic] width of destination region
61
+ # @param dh [Numrtic] height of destination region
62
+ #
63
+ # @return [nil] nil
64
+ #
65
+ def copy (img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
66
+ img ||= self
67
+ @image__.paint do |painter|
68
+ painter.image img.getInternal__, sx, sy, sw, sh, dx, dy, dw, dh
69
+ end
70
+ end
38
71
 
39
- # Mode for rectMode(), ellipseMode() and imageMode().
40
- #
41
- CENTER = :CENTER
72
+ # Saves image to file.
73
+ #
74
+ # @param filename [String] file name to save image
75
+ #
76
+ def save (filename)
77
+ @image__.save filename
78
+ end
42
79
 
43
- # Mode for rectMode() and ellipseMode().
44
- #
45
- RADIUS = :RADIUS
80
+ # @private
81
+ def getInternal__ ()
82
+ @image__
83
+ end
46
84
 
47
- # Mode for strokeCap().
48
- #
49
- BUTT = :butt
85
+ end# Image
50
86
 
51
- # Mode for strokeJoin().
52
- #
53
- MITER = :miter
54
87
 
55
- # Mode for strokeCap() and strokeJoin().
88
+ # Font object.
56
89
  #
57
- ROUND = :round
90
+ class Font
58
91
 
59
- # Mode for strokeCap() and strokeJoin().
60
- #
61
- SQUARE = :square
62
-
63
- # @private
64
- DEG2RAD__ = PI / 180.0
65
-
66
- # @private
67
- RAD2DEG__ = 180.0 / PI
68
-
69
- # @private
70
- def initialize ()
71
- @loop__ = true
72
- @redraw__ = false
73
- @matrixStack__ = []
74
- @styleStack__ = []
75
- @frameCount__ = 0
76
- @hsbColor__ = false
77
- @colorMaxes__ = [1.0] * 4
78
- @angleScale__ = 1.0
79
- @mouseX__ =
80
- @mouseY__ =
81
- @mousePrevX__ =
82
- @mousePrevY__ = 0
83
- @mousePressed__ = false
84
-
85
- colorMode RGB, 255
86
- angleMode RADIANS
87
- rectMode CORNER
88
- ellipseMode CENTER
89
- imageMode CORNER
90
- end
91
-
92
- # @private
93
- def setup__ (window)
94
- @window__ = window
95
- @painter__ = window.canvas_painter.tap do |o|
96
- o.miter_limit = 10
97
- end
98
-
99
- drawFrame = -> event {
100
- @painter__ = window.canvas_painter
101
- @matrixStack__.clear
102
- @styleStack__.clear
103
- begin
104
- push
105
- @drawBlock__.call event if @drawBlock__
106
- ensure
107
- pop
108
- end
109
- @frameCount__ += 1
110
- }
111
-
112
- updateMouseState = -> x, y, pressed = nil {
113
- @mouseX__ = x
114
- @mouseY__ = y
115
- @mousePressed__ = pressed if pressed != nil
116
- }
117
-
118
- updateMousePrevPos = -> {
119
- @mousePrevX__ = @mouseX__
120
- @mousePrevY__ = @mouseY__
121
- }
122
-
123
- @window__.draw = proc do |e|
124
- if @loop__ || @redraw__
125
- @redraw__ = false
126
- drawFrame.call e
127
- end
128
- updateMousePrevPos.call
92
+ # @private
93
+ def initialize (font)
94
+ @font = font
129
95
  end
130
96
 
131
- @window__.pointer_down = proc do |e|
132
- updateMouseState.call e.x, e.y, true
133
- @mousePressedBlock__.call e if @mousePressedBlock__
97
+ # Returns bounding box.
98
+ #
99
+ # @overload textBounds(str)
100
+ # @overload textBounds(str, x, y)
101
+ # @overload textBounds(str, x, y, fontSize)
102
+ #
103
+ # @param str [String] text to calculate bounding box
104
+ # @param x [Numeric] horizontal position of bounding box
105
+ # @param y [Numeric] vertical position of bounding box
106
+ # @param fontSize [Numeric] font size
107
+ #
108
+ # @return [TextBounds] bounding box for text
109
+ #
110
+ def textBounds (str, x = 0, y = 0, fontSize = nil)
111
+ f = fontSize ? Rays::Font.new(@font.name, fontSize) : @font
112
+ TextBounds.new x, y, x + f.width(str), y + f.height
134
113
  end
135
114
 
136
- @window__.pointer_up = proc do |e|
137
- updateMouseState.call e.x, e.y, false
138
- @mouseReleasedBlock__.call e if @mouseReleasedBlock__
139
- end
115
+ end# Font
140
116
 
141
- @window__.pointer_move = proc do |e|
142
- updateMouseState.call e.x, e.y
143
- @mouseMovedBlock__.call e if @mouseMovedBlock__
144
- end
145
117
 
146
- @window__.pointer_drag = proc do |e|
147
- updateMouseState.call e.x, e.y
148
- @mouseDraggedBlock__.call e if @mouseDraggedBlock__
118
+ # Bounding box for text.
119
+ #
120
+ class TextBounds
121
+
122
+ # Horizontal position
123
+ #
124
+ attr_reader :x
125
+
126
+ # Vertical position
127
+ #
128
+ attr_reader :y
129
+
130
+ # Width of bounding box
131
+ #
132
+ attr_reader :w
133
+
134
+ # Height of bounding box
135
+ #
136
+ attr_reader :h
137
+
138
+ # @private
139
+ def initialize (x, y, w, h)
140
+ @x, @y, @w, @h = x, y, w, h
149
141
  end
150
- end
151
142
 
152
- # Returns the absolute number of the value.
153
- #
154
- # @param value [Numeric] number
155
- #
156
- # @return [Numeric] absolute number
157
- #
158
- def abs (value)
159
- value.abs
160
- end
143
+ end# TextBounds
161
144
 
162
- # Returns the closest integer number greater than or equal to the value.
163
- #
164
- # @param value [Numeric] number
165
- #
166
- # @return [Numeric] rounded up number
167
- #
168
- def ceil (value)
169
- value.ceil
170
- end
171
145
 
172
- # Returns the closest integer number less than or equal to the value.
146
+ # Drawing context
173
147
  #
174
- # @param value [Numeric] number
175
- #
176
- # @return [Numeric] rounded down number
177
- #
178
- def floor (value)
179
- value.floor
180
- end
148
+ module GraphicsContext
181
149
 
182
- # Returns the closest integer number.
183
- #
184
- # @param value [Numeric] number
185
- #
186
- # @return [Numeric] rounded number
187
- #
188
- def round (value)
189
- value.round
190
- end
150
+ # PI / 2
151
+ #
152
+ HALF_PI = Math::PI / 2
191
153
 
192
- # Returns value raised to the power of exponent.
193
- #
194
- # @param value [Numeric] base number
195
- # @param exponent [Numeric] exponent number
196
- #
197
- # @return [Numeric] value ** exponent
198
- #
199
- def pow (value, exponent)
200
- value ** exponent
201
- end
154
+ # PI / 4
155
+ #
156
+ QUARTER_PI = Math::PI / 4
202
157
 
203
- # Returns squared value.
204
- #
205
- # @param value [Numeric] number
206
- #
207
- # @return [Numeric] squared value
208
- #
209
- def sq (value)
210
- value * value
211
- end
158
+ # PI * 2
159
+ #
160
+ TWO_PI = Math::PI * 2
212
161
 
213
- # Returns the magnitude (or length) of a vector.
214
- #
215
- # @overload mag(x, y)
216
- # @overload mag(x, y, z)
217
- #
218
- # @param x [Numeric] x of point
219
- # @param y [Numeric] y of point
220
- # @param z [Numeric] z of point
221
- #
222
- # @return [Numeric] magnitude
223
- #
224
- def mag (*args)
225
- x, y, z = *args
226
- case args.size
227
- when 2 then sqrt x * x + y * y
228
- when 3 then sqrt x * x + y * y + z * z
229
- else raise ArgumentError
230
- end
231
- end
162
+ # PI * 2
163
+ #
164
+ TAU = Math::PI * 2
232
165
 
233
- # Returns distance between 2 points.
234
- #
235
- # @overload dist(x1, y1, x2, y2)
236
- # @overload dist(x1, y1, z1, x2, y2, z2)
237
- #
238
- # @param x1 [Numeric] x of first point
239
- # @param y1 [Numeric] y of first point
240
- # @param z1 [Numeric] z of first point
241
- # @param x2 [Numeric] x of second point
242
- # @param y2 [Numeric] y of second point
243
- # @param z2 [Numeric] z of second point
244
- #
245
- # @return [Numeric] distance between 2 points
246
- #
247
- def dist (*args)
248
- case args.size
249
- when 4
250
- x1, y1, x2, y2 = *args
251
- xx, yy = x2 - x1, y2 - y1
252
- sqrt xx * xx + yy * yy
253
- when 3
254
- x1, y1, z1, x2, y2, z2 = *args
255
- xx, yy, zz = x2 - x1, y2 - y1, z2 - z1
256
- sqrt xx * xx + yy * yy + zz * zz
257
- else raise ArgumentError
258
- end
259
- end
166
+ # RGB mode for colorMode().
167
+ #
168
+ RGB = :RGB
260
169
 
261
- # Normalize the value from range start..stop into 0..1.
262
- #
263
- # @param value [Numeric] number to be normalized
264
- # @param start [Numeric] lower bound of the range
265
- # @param stop [Numeric] upper bound of the range
266
- #
267
- # @return [Numeric] normalized value between 0..1
268
- #
269
- def norm (value, start, stop)
270
- (value.to_f - start.to_f) / (stop.to_f - start.to_f)
271
- end
170
+ # HSB mode for colorMode().
171
+ #
172
+ HSB = :HSB
272
173
 
273
- # Returns the interpolated number between range start..stop.
274
- #
275
- # @param start [Numeric] lower bound of the range
276
- # @param stop [Numeric] upper bound of the range
277
- # @param amount [Numeric] amount to interpolate
278
- #
279
- # @return [Numeric] interporated number
280
- #
281
- def lerp (start, stop, amount)
282
- start + (stop - start) * amount
283
- end
174
+ # Radian mode for angleMode().
175
+ #
176
+ RADIANS = :RADIANS
284
177
 
285
- # Maps a number from range start1..stop1 to range start2..stop2.
286
- #
287
- # @param value [Numeric] number to be mapped
288
- # @param start1 [Numeric] lower bound of the range1
289
- # @param stop1 [Numeric] upper bound of the range1
290
- # @param start2 [Numeric] lower bound of the range2
291
- # @param stop2 [Numeric] upper bound of the range2
292
- #
293
- # @return [Numeric] mapped number
294
- #
295
- def map (value, start1, stop1, start2, stop2)
296
- lerp start2, stop2, norm(value, start1, stop1)
297
- end
178
+ # Degree mode for angleMode().
179
+ #
180
+ DEGREES = :DEGREES
298
181
 
299
- # Returns minimum value.
300
- #
301
- # @overload min(a, b)
302
- # @overload min(a, b, c)
303
- # @overload min(array)
304
- #
305
- # @param a [Numeric] value to compare
306
- # @param b [Numeric] value to compare
307
- # @param c [Numeric] value to compare
308
- # @param array [Numeric] values to compare
309
- #
310
- # @return [Numeric] minimum value
311
- #
312
- def min (*args)
313
- args.flatten.min
314
- end
182
+ # Mode for rectMode(), ellipseMode() and imageMode().
183
+ #
184
+ CORNER = :CORNER
315
185
 
316
- # Returns maximum value.
317
- #
318
- # @overload max(a, b)
319
- # @overload max(a, b, c)
320
- # @overload max(array)
321
- #
322
- # @param a [Numeric] value to compare
323
- # @param b [Numeric] value to compare
324
- # @param c [Numeric] value to compare
325
- # @param array [Numeric] values to compare
326
- #
327
- # @return [Numeric] maximum value
328
- #
329
- def max (*args)
330
- args.flatten.max
331
- end
186
+ # Mode for rectMode(), ellipseMode() and imageMode().
187
+ #
188
+ CORNERS = :CORNERS
332
189
 
333
- # Constrains the number between min..max.
334
- #
335
- # @param value [Numeric] number to be constrained
336
- # @param min [Numeric] lower bound of the range
337
- # @param max [Numeric] upper bound of the range
338
- #
339
- # @return [Numeric] constrained number
340
- #
341
- def constrain (value, min, max)
342
- value < min ? min : (value > max ? max : value)
343
- end
190
+ # Mode for rectMode(), ellipseMode() and imageMode().
191
+ #
192
+ CENTER = :CENTER
344
193
 
345
- # Converts degree to radian.
346
- #
347
- # @param degree [Numeric] degree to convert
348
- #
349
- # @return [Numeric] radian
350
- #
351
- def radians (degree)
352
- degree * DEG2RAD__
353
- end
194
+ # Mode for rectMode() and ellipseMode().
195
+ #
196
+ RADIUS = :RADIUS
354
197
 
355
- # Converts radian to degree.
356
- #
357
- # @param radian [Numeric] radian to convert
358
- #
359
- # @return [Numeric] degree
360
- #
361
- def degrees (radian)
362
- radian * RAD2DEG__
363
- end
198
+ # Mode for strokeCap().
199
+ #
200
+ BUTT = :butt
364
201
 
365
- # Define setup block.
366
- #
367
- def setup (&block)
368
- @window__.setup = block
369
- nil
370
- end
202
+ # Mode for strokeJoin().
203
+ #
204
+ MITER = :miter
371
205
 
372
- # Define draw block.
373
- #
374
- def draw (&block)
375
- @drawBlock__ = block if block
376
- nil
377
- end
378
-
379
- def key (&block)
380
- @window__.key = block
381
- nil
382
- end
383
-
384
- def mousePressed (&block)
385
- @mousePressedBlock__ = block if block
386
- @mousePressed__
387
- end
388
-
389
- def mouseReleased (&block)
390
- @mouseReleasedBlock__ = block if block
391
- nil
392
- end
393
-
394
- def mouseMoved (&block)
395
- @mouseMovedBlock__ = block if block
396
- nil
397
- end
398
-
399
- def mouseDragged (&block)
400
- @mouseDraggedBlock__ = block if block
401
- nil
402
- end
403
-
404
- # @private
405
- private def size__ (width, height)
406
- raise 'size() must be called on startup or setup block' if @started__
407
-
408
- @painter__.send :end_paint
409
- reset_canvas width, height
410
- @painter__.send :begin_paint
411
-
412
- @auto_resize__ = false
413
- end
414
-
415
- def width ()
416
- @window__.canvas.width
417
- end
418
-
419
- def height ()
420
- @window__.canvas.height
421
- end
422
-
423
- def windowWidth ()
424
- @window__.width
425
- end
426
-
427
- def windowHeight ()
428
- @window__.height
429
- end
430
-
431
- # Returns number of frames since program started.
432
- #
433
- # @return [Integer] total number of frames
434
- #
435
- def frameCount ()
436
- @frameCount__
437
- end
206
+ # Mode for strokeCap() and strokeJoin().
207
+ #
208
+ ROUND = :round
438
209
 
439
- # Returns number of frames per second.
440
- #
441
- # @return [Float] frames per second
442
- #
443
- def frameRate ()
444
- @window__.event.fps
445
- end
210
+ # Mode for strokeCap() and strokeJoin().
211
+ #
212
+ SQUARE = :square
446
213
 
447
- # Returns pixel density
448
- #
449
- # @return [Numeric] pixel density
450
- #
451
- def displayDensity ()
452
- @painter__.pixel_density
453
- end
214
+ def setup__ ()
215
+ @drawing = false
216
+ @hsbColor__ = false
217
+ @colorMaxes__ = [1.0] * 4
218
+ @angleScale__ = 1.0
219
+ @rectMode__ = nil
220
+ @ellipseMode__ = nil
221
+ @imageMode__ = nil
222
+ @matrixStack__ = []
223
+ @styleStack__ = []
454
224
 
455
- # Returns mouse x position
456
- #
457
- # @return [Numeric] horizontal position of mouse
458
- #
459
- def mouseX ()
460
- @mouseX__
461
- end
225
+ colorMode RGB, 255
226
+ angleMode RADIANS
227
+ rectMode CORNER
228
+ ellipseMode CENTER
229
+ imageMode CORNER
230
+ end
462
231
 
463
- # Returns mouse y position
464
- #
465
- # @return [Numeric] vertical position of mouse
466
- #
467
- def mouseY ()
468
- @mouseY__
469
- end
232
+ def beginDraw ()
233
+ @matrixStack__.clear
234
+ @styleStack__.clear
235
+ @drawing = true
236
+ end
470
237
 
471
- # Returns mouse x position in previous frame
472
- #
473
- # @return [Numeric] horizontal position of mouse
474
- #
475
- def pmouseX ()
476
- @mousePrevX__
477
- end
238
+ def endDraw ()
239
+ @drawing = false
240
+ end
478
241
 
479
- # Returns mouse y position in previous frame
480
- #
481
- # @return [Numeric] vertical position of mouse
482
- #
483
- def pmouseY ()
484
- @mousePrevY__
485
- end
242
+ def width ()
243
+ @image__.width
244
+ end
486
245
 
487
- # Sets color mode and max color values.
488
- #
489
- # @overload colorMode(mode)
490
- # @overload colorMode(mode, max)
491
- # @overload colorMode(mode, max1, max2, max3)
492
- # @overload colorMode(mode, max1, max2, max3, maxA)
493
- #
494
- # @param mode [RGB, HSB] RGB or HSB
495
- # @param max [Numeric] max values for all color values
496
- # @param max1 [Numeric] max value for red or hue
497
- # @param max2 [Numeric] max value for green or saturation
498
- # @param max3 [Numeric] max value for blue or brightness
499
- # @param maxA [Numeric] max value for alpha
500
- #
501
- # @return [nil] nil
502
- #
503
- def colorMode (mode, *maxes)
504
- raise ArgumentError, "invalid color mode: #{mode}" unless [RGB, HSB].include?(mode)
505
- raise ArgumentError unless [0, 1, 3, 4].include?(maxes.size)
246
+ def height ()
247
+ @image__.height
248
+ end
506
249
 
507
- @hsbColor__ = mode.upcase == HSB
508
- case maxes.size
250
+ # Sets color mode and max color values.
251
+ #
252
+ # @overload colorMode(mode)
253
+ # @overload colorMode(mode, max)
254
+ # @overload colorMode(mode, max1, max2, max3)
255
+ # @overload colorMode(mode, max1, max2, max3, maxA)
256
+ #
257
+ # @param mode [RGB, HSB] RGB or HSB
258
+ # @param max [Numeric] max values for all color values
259
+ # @param max1 [Numeric] max value for red or hue
260
+ # @param max2 [Numeric] max value for green or saturation
261
+ # @param max3 [Numeric] max value for blue or brightness
262
+ # @param maxA [Numeric] max value for alpha
263
+ #
264
+ # @return [nil] nil
265
+ #
266
+ def colorMode (mode, *maxes)
267
+ raise ArgumentError, "invalid color mode: #{mode}" unless [RGB, HSB].include?(mode)
268
+ raise ArgumentError unless [0, 1, 3, 4].include?(maxes.size)
269
+
270
+ @hsbColor__ = mode.upcase == HSB
271
+ case maxes.size
509
272
  when 1 then @colorMaxes__ = [maxes.first.to_f] * 4
510
273
  when 3, 4 then @colorMaxes__[0...maxes.size] = maxes.map &:to_f
274
+ end
275
+ nil
511
276
  end
512
- nil
513
- end
514
277
 
515
- # @private
516
- private def toRGBA__ (*args)
517
- a, b, c, d = args
518
- return parseColor__(a, b || alphaMax__) if a.kind_of?(String)
278
+ # @private
279
+ private def toRGBA__ (*args)
280
+ a, b, c, d = args
281
+ return parseColor__(a, b || alphaMax__) if a.kind_of?(String)
519
282
 
520
- rgba = case args.size
521
- when 1, 2 then [a, a, a, b || alphaMax__]
522
- when 3, 4 then [a, b, c, d || alphaMax__]
523
- else raise ArgumentError
283
+ rgba = case args.size
284
+ when 1, 2 then [a, a, a, b || alphaMax__]
285
+ when 3, 4 then [a, b, c, d || alphaMax__]
286
+ else raise ArgumentError
287
+ end
288
+ rgba = rgba.map.with_index {|value, i| value / @colorMaxes__[i]}
289
+ color = @hsbColor__ ? Rays::Color.hsv(*rgba) : Rays::Color.new(*rgba)
290
+ color.to_a
524
291
  end
525
- rgba = rgba.map.with_index {|value, i| value / @colorMaxes__[i]}
526
- color = @hsbColor__ ? Rays::Color.hsv(*rgba) : Rays::Color.new(*rgba)
527
- color.to_a
528
- end
529
292
 
530
- # @private
531
- private def parseColor__ (str, alpha)
532
- result = str.match /^\s*##{'([0-9a-f]{2})' * 3}\s*$/i
533
- raise ArgumentError, "invalid color code: '#{str}'" unless result
293
+ # @private
294
+ private def parseColor__ (str, alpha)
295
+ result = str.match /^\s*##{'([0-9a-f]{2})' * 3}\s*$/i
296
+ raise ArgumentError, "invalid color code: '#{str}'" unless result
534
297
 
535
- rgb = result[1..3].map.with_index {|hex, i| hex.to_i(16) / 255.0}
536
- return *rgb, (alpha / alphaMax__)
537
- end
298
+ rgb = result[1..3].map.with_index {|hex, i| hex.to_i(16) / 255.0}
299
+ return *rgb, (alpha / alphaMax__)
300
+ end
538
301
 
539
- # @private
540
- private def alphaMax__ ()
541
- @colorMaxes__[3]
542
- end
302
+ # @private
303
+ private def alphaMax__ ()
304
+ @colorMaxes__[3]
305
+ end
543
306
 
544
- # Sets angle mode.
545
- #
546
- # @param mode [RADIANS, DEGREES] RADIANS or DEGREES
547
- #
548
- # @return [nil] nil
549
- #
550
- def angleMode (mode)
551
- @angleScale__ = case mode
552
- when RADIANS then RAD2DEG__
553
- when DEGREES then 1.0
554
- else raise ArgumentError, "invalid angle mode: #{mode}"
307
+ # Sets angle mode.
308
+ #
309
+ # @param mode [RADIANS, DEGREES] RADIANS or DEGREES
310
+ #
311
+ # @return [nil] nil
312
+ #
313
+ def angleMode (mode)
314
+ @angleScale__ = case mode
315
+ when RADIANS then Utility::RAD2DEG__
316
+ when DEGREES then 1.0
317
+ else raise ArgumentError, "invalid angle mode: #{mode}"
318
+ end
319
+ nil
555
320
  end
556
- nil
557
- end
558
321
 
559
- # @private
560
- private def toAngle__ (angle)
561
- angle * @angleScale__
562
- end
322
+ # @private
323
+ private def toAngle__ (angle)
324
+ angle * @angleScale__
325
+ end
563
326
 
564
- # Sets rect mode. Default is CORNER.
565
- #
566
- # CORNER -> rect(left, top, width, height)
567
- # CORNERS -> rect(left, top, right, bottom)
568
- # CENTER -> rect(center_x, center_y, width, height)
569
- # RADIUS -> rect(center_x, center_y, radius_h, radius_v)
570
- #
571
- # @param mode [CORNER, CORNERS, CENTER, RADIUS]
572
- #
573
- # @return [nil] nil
574
- #
575
- def rectMode (mode)
576
- @rectMode__ = mode
577
- end
327
+ # Sets rect mode. Default is CORNER.
328
+ #
329
+ # CORNER -> rect(left, top, width, height)
330
+ # CORNERS -> rect(left, top, right, bottom)
331
+ # CENTER -> rect(center_x, center_y, width, height)
332
+ # RADIUS -> rect(center_x, center_y, radius_h, radius_v)
333
+ #
334
+ # @param mode [CORNER, CORNERS, CENTER, RADIUS]
335
+ #
336
+ # @return [nil] nil
337
+ #
338
+ def rectMode (mode)
339
+ @rectMode__ = mode
340
+ end
578
341
 
579
- # Sets ellipse mode. Default is CENTER.
580
- #
581
- # CORNER -> ellipse(left, top, width, height)
582
- # CORNERS -> ellipse(left, top, right, bottom)
583
- # CENTER -> ellipse(center_x, center_y, width, height)
584
- # RADIUS -> ellipse(center_x, center_y, radius_h, radius_v)
585
- #
586
- # @param mode [CORNER, CORNERS, CENTER, RADIUS]
587
- #
588
- # @return [nil] nil
589
- #
590
- def ellipseMode (mode)
591
- @ellipseMode__ = mode
592
- end
342
+ # Sets ellipse mode. Default is CENTER.
343
+ #
344
+ # CORNER -> ellipse(left, top, width, height)
345
+ # CORNERS -> ellipse(left, top, right, bottom)
346
+ # CENTER -> ellipse(center_x, center_y, width, height)
347
+ # RADIUS -> ellipse(center_x, center_y, radius_h, radius_v)
348
+ #
349
+ # @param mode [CORNER, CORNERS, CENTER, RADIUS]
350
+ #
351
+ # @return [nil] nil
352
+ #
353
+ def ellipseMode (mode)
354
+ @ellipseMode__ = mode
355
+ end
593
356
 
594
- # Sets image mode. Default is CORNER.
595
- #
596
- # CORNER -> image(img, left, top, width, height)
597
- # CORNERS -> image(img, left, top, right, bottom)
598
- # CENTER -> image(img, center_x, center_y, width, height)
599
- #
600
- # @param mode [CORNER, CORNERS, CENTER]
601
- #
602
- # @return [nil] nil
603
- #
604
- def imageMode (mode)
605
- @imageMode__ = mode
606
- end
607
-
608
- # @private
609
- private def toXYWH__ (mode, a, b, c, d)
610
- case mode
611
- when CORNER then [a, b, c, d]
612
- when CORNERS then [a, b, c - a, d - b]
613
- when CENTER then [a - c / 2.0, b - d / 2.0, c, d]
614
- when RADIUS then [a - c, b - d, c * 2, d * 2]
615
- else raise ArgumentError # ToDo: refine error message
616
- end
617
- end
618
-
619
- # Enables calling draw block on every frame.
620
- #
621
- # @return [nil] nil
622
- #
623
- def loop ()
624
- @loop__ = true
625
- end
357
+ # Sets image mode. Default is CORNER.
358
+ #
359
+ # CORNER -> image(img, left, top, width, height)
360
+ # CORNERS -> image(img, left, top, right, bottom)
361
+ # CENTER -> image(img, center_x, center_y, width, height)
362
+ #
363
+ # @param mode [CORNER, CORNERS, CENTER]
364
+ #
365
+ # @return [nil] nil
366
+ #
367
+ def imageMode (mode)
368
+ @imageMode__ = mode
369
+ end
626
370
 
627
- # Disables calling draw block on every frame.
628
- #
629
- # @return [nil] nil
630
- #
631
- def noLoop ()
632
- @loop__ = false
633
- end
371
+ # @private
372
+ private def toXYWH__ (mode, a, b, c, d)
373
+ case mode
374
+ when CORNER then [a, b, c, d]
375
+ when CORNERS then [a, b, c - a, d - b]
376
+ when CENTER then [a - c / 2.0, b - d / 2.0, c, d]
377
+ when RADIUS then [a - c, b - d, c * 2, d * 2]
378
+ else raise ArgumentError # ToDo: refine error message
379
+ end
380
+ end
634
381
 
635
- # Calls draw block to redraw frame.
636
- #
637
- # @return [nil] nil
638
- #
639
- def redraw ()
640
- @redraw__ = true
641
- end
382
+ # Sets fill color.
383
+ #
384
+ # @overload fill(rgb)
385
+ # @overload fill(rgb, alpha)
386
+ # @overload fill(gray)
387
+ # @overload fill(gray, alpha)
388
+ # @overload fill(r, g, b)
389
+ # @overload fill(r, g, b, alpha)
390
+ #
391
+ # @param rgb [String] color code like '#00AAFF'
392
+ # @param gray [Integer] gray value (0..255)
393
+ # @param r [Integer] red value (0..255)
394
+ # @param g [Integer] green value (0..255)
395
+ # @param b [Integer] blue value (0..255)
396
+ # @param alpha [Integer] alpha value (0..255)
397
+ #
398
+ # @return [nil] nil
399
+ #
400
+ def fill (*args)
401
+ @painter__.fill(*toRGBA__(*args))
402
+ nil
403
+ end
642
404
 
643
- # Clears screen.
644
- #
645
- # @overload background(str)
646
- # @overload background(str, alpha)
647
- # @overload background(gray)
648
- # @overload background(gray, alpha)
649
- # @overload background(r, g, b)
650
- # @overload background(r, g, b, alpha)
651
- #
652
- # @param str [String] color code like '#00AAFF'
653
- # @param gray [Integer] gray value (0..255)
654
- # @param r [Integer] red value (0..255)
655
- # @param g [Integer] green value (0..255)
656
- # @param b [Integer] blue value (0..255)
657
- # @param alpha [Integer] alpha value (0..255)
658
- #
659
- # @return [nil] nil
660
- #
661
- def background (*args)
662
- rgba = toRGBA__ *args
663
- if rgba[3] == 1
664
- @painter__.background *rgba
665
- else
666
- @painter__.push fill: rgba, stroke: nil do |_|
667
- @painter__.rect 0, 0, width, height
668
- end
405
+ # Sets stroke color.
406
+ #
407
+ # @overload stroke(rgb)
408
+ # @overload stroke(rgb, alpha)
409
+ # @overload stroke(gray)
410
+ # @overload stroke(gray, alpha)
411
+ # @overload stroke(r, g, b)
412
+ # @overload stroke(r, g, b, alpha)
413
+ #
414
+ # @param rgb [String] color code like '#00AAFF'
415
+ # @param gray [Integer] gray value (0..255)
416
+ # @param r [Integer] red value (0..255)
417
+ # @param g [Integer] green value (0..255)
418
+ # @param b [Integer] blue value (0..255)
419
+ # @param alpha [Integer] alpha value (0..255)
420
+ #
421
+ # @return [nil] nil
422
+ #
423
+ def stroke (*args)
424
+ @painter__.stroke(*toRGBA__(*args))
425
+ nil
669
426
  end
670
- nil
671
- end
672
427
 
673
- # Sets fill color.
674
- #
675
- # @overload fill(rgb)
676
- # @overload fill(rgb, alpha)
677
- # @overload fill(gray)
678
- # @overload fill(gray, alpha)
679
- # @overload fill(r, g, b)
680
- # @overload fill(r, g, b, alpha)
681
- #
682
- # @param rgb [String] color code like '#00AAFF'
683
- # @param gray [Integer] gray value (0..255)
684
- # @param r [Integer] red value (0..255)
685
- # @param g [Integer] green value (0..255)
686
- # @param b [Integer] blue value (0..255)
687
- # @param alpha [Integer] alpha value (0..255)
688
- #
689
- # @return [nil] nil
690
- #
691
- def fill (*args)
692
- @painter__.fill(*toRGBA__(*args))
693
- nil
694
- end
428
+ # Sets stroke weight.
429
+ #
430
+ # @param weight [Numeric] width of stroke
431
+ #
432
+ # @return [nil] nil
433
+ #
434
+ def strokeWeight (weight)
435
+ @painter__.stroke_width weight
436
+ nil
437
+ end
695
438
 
696
- # Sets stroke color.
697
- #
698
- # @overload stroke(rgb)
699
- # @overload stroke(rgb, alpha)
700
- # @overload stroke(gray)
701
- # @overload stroke(gray, alpha)
702
- # @overload stroke(r, g, b)
703
- # @overload stroke(r, g, b, alpha)
704
- #
705
- # @param rgb [String] color code like '#00AAFF'
706
- # @param gray [Integer] gray value (0..255)
707
- # @param r [Integer] red value (0..255)
708
- # @param g [Integer] green value (0..255)
709
- # @param b [Integer] blue value (0..255)
710
- # @param alpha [Integer] alpha value (0..255)
711
- #
712
- # @return [nil] nil
713
- #
714
- def stroke (*args)
715
- @painter__.stroke(*toRGBA__(*args))
716
- nil
717
- end
439
+ # Sets stroke cap mode.
440
+ #
441
+ # @param cap [BUTT, ROUND, SQUARE]
442
+ #
443
+ # @return [nil] nil
444
+ #
445
+ def strokeCap (cap)
446
+ @painter__.stroke_cap cap
447
+ nil
448
+ end
718
449
 
719
- # Sets stroke weight.
720
- #
721
- # @param weight [Numeric] width of stroke
722
- #
723
- # @return [nil] nil
724
- #
725
- def strokeWeight (weight)
726
- @painter__.stroke_width weight
727
- nil
728
- end
450
+ # Sets stroke join mode.
451
+ #
452
+ # @param join [MITER, ROUND, SQUARE]
453
+ #
454
+ # @return [nil] nil
455
+ #
456
+ def strokeJoin (join)
457
+ @painter__.stroke_join join
458
+ nil
459
+ end
729
460
 
730
- # Sets stroke cap mode.
731
- #
732
- # @param cap [BUTT, ROUND, SQUARE]
733
- #
734
- # @return [nil] nil
735
- #
736
- def strokeCap (cap)
737
- @painter__.stroke_cap cap
738
- nil
739
- end
461
+ # Disables filling.
462
+ #
463
+ # @return [nil] nil
464
+ #
465
+ def noFill ()
466
+ @painter__.fill nil
467
+ nil
468
+ end
740
469
 
741
- # Sets stroke join mode.
742
- #
743
- # @param join [MITER, ROUND, SQUARE]
744
- #
745
- # @return [nil] nil
746
- #
747
- def strokeJoin (join)
748
- @painter__.stroke_join join
749
- nil
750
- end
470
+ # Disables drawing stroke.
471
+ #
472
+ # @return [nil] nil
473
+ #
474
+ def noStroke ()
475
+ @painter__.stroke nil
476
+ nil
477
+ end
751
478
 
752
- # Disables filling.
753
- #
754
- # @return [nil] nil
755
- #
756
- def noFill ()
757
- @painter__.fill nil
758
- nil
759
- end
479
+ # Sets font.
480
+ #
481
+ # @param name [String] font name
482
+ # @param size [Numeric] font size
483
+ #
484
+ # @return [Font] current font
485
+ #
486
+ def textFont (name = nil, size = nil)
487
+ @painter__.font name, size if name || size
488
+ Font.new @painter__.font
489
+ end
760
490
 
761
- # Disables drawing stroke.
762
- #
763
- # @return [nil] nil
764
- #
765
- def noStroke ()
766
- @painter__.stroke nil
767
- nil
768
- end
491
+ # Sets text size.
492
+ #
493
+ # @param size [Numeric] font size
494
+ #
495
+ # @return [nil] nil
496
+ #
497
+ def textSize (size)
498
+ @painter__.font @painter__.font.name, size
499
+ nil
500
+ end
769
501
 
770
- # Sets font.
771
- #
772
- # @param name [String] font name
773
- # @param size [Numeric] font size
774
- #
775
- # @return [Font] current font
776
- #
777
- def textFont (name = nil, size = nil)
778
- @painter__.font name, size if name || size
779
- Font.new @painter__.font
780
- end
502
+ # Clears screen.
503
+ #
504
+ # @overload background(str)
505
+ # @overload background(str, alpha)
506
+ # @overload background(gray)
507
+ # @overload background(gray, alpha)
508
+ # @overload background(r, g, b)
509
+ # @overload background(r, g, b, alpha)
510
+ #
511
+ # @param str [String] color code like '#00AAFF'
512
+ # @param gray [Integer] gray value (0..255)
513
+ # @param r [Integer] red value (0..255)
514
+ # @param g [Integer] green value (0..255)
515
+ # @param b [Integer] blue value (0..255)
516
+ # @param alpha [Integer] alpha value (0..255)
517
+ #
518
+ # @return [nil] nil
519
+ #
520
+ def background (*args)
521
+ assertDrawing__
522
+ rgba = toRGBA__ *args
523
+ if rgba[3] == 1
524
+ @painter__.background *rgba
525
+ else
526
+ @painter__.push fill: rgba, stroke: nil do |_|
527
+ @painter__.rect 0, 0, width, height
528
+ end
529
+ end
530
+ nil
531
+ end
781
532
 
782
- # Sets text size.
783
- #
784
- # @param size [Numeric] font size
785
- #
786
- # @return [nil] nil
787
- #
788
- def textSize (size)
789
- @painter__.font @painter__.font.name, size
790
- nil
791
- end
533
+ # Draws a point.
534
+ #
535
+ # @param x [Numeric] horizontal position
536
+ # @param y [Numeric] vertical position
537
+ #
538
+ # @return [nil] nil
539
+ #
540
+ def point (x, y)
541
+ assertDrawing__
542
+ w = @painter__.stroke_width
543
+ w = 1 if w == 0
544
+ @painter__.ellipse x - (w / 2.0), y - (w / 2.0), w, w
545
+ nil
546
+ end
792
547
 
793
- # Draws a point.
794
- #
795
- # @param x [Numeric] horizontal position
796
- # @param y [Numeric] vertical position
797
- #
798
- # @return [nil] nil
799
- #
800
- def point (x, y)
801
- w = @painter__.stroke_width
802
- w = 1 if w == 0
803
- @painter__.ellipse x - (w / 2.0), y - (w / 2.0), w, w
804
- nil
805
- end
806
-
807
- # Draws a line.
808
- #
809
- # @param x1 [Numeric] horizontal position of first point
810
- # @param y1 [Numeric] vertical position of first point
811
- # @param x2 [Numeric] horizontal position of second point
812
- # @param y2 [Numeric] vertical position of second point
813
- #
814
- # @return [nil] nil
815
- #
816
- def line (x1, y1, x2, y2)
817
- @painter__.line x1, y1, x2, y2
818
- nil
819
- end
548
+ # Draws a line.
549
+ #
550
+ # @param x1 [Numeric] horizontal position of first point
551
+ # @param y1 [Numeric] vertical position of first point
552
+ # @param x2 [Numeric] horizontal position of second point
553
+ # @param y2 [Numeric] vertical position of second point
554
+ #
555
+ # @return [nil] nil
556
+ #
557
+ def line (x1, y1, x2, y2)
558
+ assertDrawing__
559
+ @painter__.line x1, y1, x2, y2
560
+ nil
561
+ end
820
562
 
821
- # Draws a rectangle.
822
- #
823
- # @overload rect(a, b, c, d)
824
- # @overload rect(a, b, c, d, r)
825
- # @overload rect(a, b, c, d, tl, tr, br, bl)
826
- #
827
- # @param a [Numeric] horizontal position of the shape by default
828
- # @param b [Numeric] vertical position of the shape by default
829
- # @param c [Numeric] width of the shape by default
830
- # @param d [Numeric] height of the shape by default
831
- # @param r [Numeric] radius for all corners
832
- # @param tl [Numeric] radius for top-left corner
833
- # @param tr [Numeric] radius for top-right corner
834
- # @param br [Numeric] radius for bottom-right corner
835
- # @param bl [Numeric] radius for bottom-left corner
836
- #
837
- # @return [nil] nil
838
- #
839
- def rect (a, b, c, d, *args)
840
- x, y, w, h = toXYWH__ @rectMode__, a, b, c, d
841
- case args.size
563
+ # Draws a rectangle.
564
+ #
565
+ # @overload rect(a, b, c, d)
566
+ # @overload rect(a, b, c, d, r)
567
+ # @overload rect(a, b, c, d, tl, tr, br, bl)
568
+ #
569
+ # @param a [Numeric] horizontal position of the shape by default
570
+ # @param b [Numeric] vertical position of the shape by default
571
+ # @param c [Numeric] width of the shape by default
572
+ # @param d [Numeric] height of the shape by default
573
+ # @param r [Numeric] radius for all corners
574
+ # @param tl [Numeric] radius for top-left corner
575
+ # @param tr [Numeric] radius for top-right corner
576
+ # @param br [Numeric] radius for bottom-right corner
577
+ # @param bl [Numeric] radius for bottom-left corner
578
+ #
579
+ # @return [nil] nil
580
+ #
581
+ def rect (a, b, c, d, *args)
582
+ assertDrawing__
583
+ x, y, w, h = toXYWH__ @rectMode__, a, b, c, d
584
+ case args.size
842
585
  when 0 then @painter__.rect x, y, w, h
843
586
  when 1 then @painter__.rect x, y, w, h, round: args[0]
844
587
  when 4 then @painter__.rect x, y, w, h, lt: args[0], rt: args[1], rb: args[2], lb: args[3]
845
588
  else raise ArgumentError # ToDo: refine error message
589
+ end
590
+ nil
846
591
  end
847
- nil
848
- end
849
592
 
850
- # Draws an ellipse.
851
- #
852
- # @param a [Numeric] horizontal position of the shape
853
- # @param b [Numeric] vertical position of the shape
854
- # @param c [Numeric] width of the shape
855
- # @param d [Numeric] height of the shape
856
- #
857
- # @return [nil] nil
858
- #
859
- def ellipse (a, b, c, d)
860
- x, y, w, h = toXYWH__ @ellipseMode__, a, b, c, d
861
- @painter__.ellipse x, y, w, h
862
- nil
863
- end
593
+ # Draws an ellipse.
594
+ #
595
+ # @param a [Numeric] horizontal position of the shape
596
+ # @param b [Numeric] vertical position of the shape
597
+ # @param c [Numeric] width of the shape
598
+ # @param d [Numeric] height of the shape
599
+ #
600
+ # @return [nil] nil
601
+ #
602
+ def ellipse (a, b, c, d)
603
+ assertDrawing__
604
+ x, y, w, h = toXYWH__ @ellipseMode__, a, b, c, d
605
+ @painter__.ellipse x, y, w, h
606
+ nil
607
+ end
864
608
 
865
- # Draws a circle.
866
- #
867
- # @param x [Numeric] horizontal position of the shape
868
- # @param y [Numeric] vertical position of the shape
869
- # @param extent [Numeric] width and height of the shape
870
- #
871
- # @return [nil] nil
872
- #
873
- def circle (x, y, extent)
874
- ellipse x, y, extent, extent
875
- end
609
+ # Draws a circle.
610
+ #
611
+ # @param x [Numeric] horizontal position of the shape
612
+ # @param y [Numeric] vertical position of the shape
613
+ # @param extent [Numeric] width and height of the shape
614
+ #
615
+ # @return [nil] nil
616
+ #
617
+ def circle (x, y, extent)
618
+ ellipse x, y, extent, extent
619
+ end
876
620
 
877
- # Draws an arc.
878
- #
879
- # @param a [Numeric] horizontal position of the shape
880
- # @param b [Numeric] vertical position of the shape
881
- # @param c [Numeric] width of the shape
882
- # @param d [Numeric] height of the shape
883
- # @param start [Numeric] angle to start the arc
884
- # @param stop [Numeric] angle to stop the arc
885
- #
886
- # @return [nil] nil
887
- #
888
- def arc (a, b, c, d, start, stop)
889
- x, y, w, h = toXYWH__ @ellipseMode__, a, b, c, d
890
- start = toAngle__ start
891
- stop = toAngle__ stop
892
- @painter__.ellipse x, y, w, h, from: start, to: stop
893
- nil
894
- end
895
-
896
- # Draws a square.
897
- #
898
- # @param x [Numeric] horizontal position of the shape
899
- # @param y [Numeric] vertical position of the shape
900
- # @param extent [Numeric] width and height of the shape
901
- #
902
- # @return [nil] nil
903
- #
904
- def square (x, y, extent)
905
- rect x, y, extent, extent
906
- end
621
+ # Draws an arc.
622
+ #
623
+ # @param a [Numeric] horizontal position of the shape
624
+ # @param b [Numeric] vertical position of the shape
625
+ # @param c [Numeric] width of the shape
626
+ # @param d [Numeric] height of the shape
627
+ # @param start [Numeric] angle to start the arc
628
+ # @param stop [Numeric] angle to stop the arc
629
+ #
630
+ # @return [nil] nil
631
+ #
632
+ def arc (a, b, c, d, start, stop)
633
+ assertDrawing__
634
+ x, y, w, h = toXYWH__ @ellipseMode__, a, b, c, d
635
+ start = toAngle__ start
636
+ stop = toAngle__ stop
637
+ @painter__.ellipse x, y, w, h, from: start, to: stop
638
+ nil
639
+ end
907
640
 
908
- # Draws a triangle.
909
- #
910
- # @param x1 [Numeric] horizontal position of first point
911
- # @param y1 [Numeric] vertical position of first point
912
- # @param x2 [Numeric] horizontal position of second point
913
- # @param y2 [Numeric] vertical position of second point
914
- # @param x3 [Numeric] horizontal position of third point
915
- # @param y3 [Numeric] vertical position of third point
916
- #
917
- # @return [nil] nil
918
- #
919
- def triangle (x1, y1, x2, y2, x3, y3)
920
- @painter__.line x1, y1, x2, y2, x3, y3, loop: true
921
- nil
922
- end
641
+ # Draws a square.
642
+ #
643
+ # @param x [Numeric] horizontal position of the shape
644
+ # @param y [Numeric] vertical position of the shape
645
+ # @param extent [Numeric] width and height of the shape
646
+ #
647
+ # @return [nil] nil
648
+ #
649
+ def square (x, y, extent)
650
+ rect x, y, extent, extent
651
+ end
923
652
 
924
- # Draws a quad.
925
- #
926
- # @param x1 [Numeric] horizontal position of first point
927
- # @param y1 [Numeric] vertical position of first point
928
- # @param x2 [Numeric] horizontal position of second point
929
- # @param y2 [Numeric] vertical position of second point
930
- # @param x3 [Numeric] horizontal position of third point
931
- # @param y3 [Numeric] vertical position of third point
932
- # @param x4 [Numeric] horizontal position of fourth point
933
- # @param y4 [Numeric] vertical position of fourth point
934
- #
935
- # @return [nil] nil
936
- #
937
- def quad (x1, y1, x2, y2, x3, y3, x4, y4)
938
- @painter__.line x1, y1, x2, y2, x3, y3, x4, y4, loop: true
939
- nil
940
- end
653
+ # Draws a triangle.
654
+ #
655
+ # @param x1 [Numeric] horizontal position of first point
656
+ # @param y1 [Numeric] vertical position of first point
657
+ # @param x2 [Numeric] horizontal position of second point
658
+ # @param y2 [Numeric] vertical position of second point
659
+ # @param x3 [Numeric] horizontal position of third point
660
+ # @param y3 [Numeric] vertical position of third point
661
+ #
662
+ # @return [nil] nil
663
+ #
664
+ def triangle (x1, y1, x2, y2, x3, y3)
665
+ assertDrawing__
666
+ @painter__.line x1, y1, x2, y2, x3, y3, loop: true
667
+ nil
668
+ end
941
669
 
942
- # Draws a Catmull-Rom spline curve.
943
- #
944
- # @param cx1 [Numeric] horizontal position of beginning control point
945
- # @param cy1 [Numeric] vertical position of beginning control point
946
- # @param x1 [Numeric] horizontal position of first point
947
- # @param y1 [Numeric] vertical position of first point
948
- # @param x2 [Numeric] horizontal position of second point
949
- # @param y2 [Numeric] vertical position of second point
950
- # @param cx2 [Numeric] horizontal position of ending control point
951
- # @param cy2 [Numeric] vertical position of ending control point
952
- #
953
- # @return [nil] nil
954
- #
955
- def curve (cx1, cy1, x1, y1, x2, y2, cx2, cy2)
956
- @painter__.curve cx1, cy1, x1, y1, x2, y2, cx2, cy2
957
- nil
958
- end
670
+ # Draws a quad.
671
+ #
672
+ # @param x1 [Numeric] horizontal position of first point
673
+ # @param y1 [Numeric] vertical position of first point
674
+ # @param x2 [Numeric] horizontal position of second point
675
+ # @param y2 [Numeric] vertical position of second point
676
+ # @param x3 [Numeric] horizontal position of third point
677
+ # @param y3 [Numeric] vertical position of third point
678
+ # @param x4 [Numeric] horizontal position of fourth point
679
+ # @param y4 [Numeric] vertical position of fourth point
680
+ #
681
+ # @return [nil] nil
682
+ #
683
+ def quad (x1, y1, x2, y2, x3, y3, x4, y4)
684
+ assertDrawing__
685
+ @painter__.line x1, y1, x2, y2, x3, y3, x4, y4, loop: true
686
+ nil
687
+ end
959
688
 
960
- # Draws a Bezier spline curve.
961
- #
962
- # @param x1 [Numeric] horizontal position of first point
963
- # @param y1 [Numeric] vertical position of first point
964
- # @param cx1 [Numeric] horizontal position of first control point
965
- # @param cy1 [Numeric] vertical position of first control point
966
- # @param cx2 [Numeric] horizontal position of second control point
967
- # @param cy2 [Numeric] vertical position of second control point
968
- # @param x2 [Numeric] horizontal position of second point
969
- # @param y2 [Numeric] vertical position of second point
970
- #
971
- # @return [nil] nil
972
- #
973
- def bezier (x1, y1, cx1, cy1, cx2, cy2, x2, y2)
974
- @painter__.bezier x1, y1, cx1, cy1, cx2, cy2, x2, y2
975
- nil
976
- end
689
+ # Draws a Catmull-Rom spline curve.
690
+ #
691
+ # @param cx1 [Numeric] horizontal position of beginning control point
692
+ # @param cy1 [Numeric] vertical position of beginning control point
693
+ # @param x1 [Numeric] horizontal position of first point
694
+ # @param y1 [Numeric] vertical position of first point
695
+ # @param x2 [Numeric] horizontal position of second point
696
+ # @param y2 [Numeric] vertical position of second point
697
+ # @param cx2 [Numeric] horizontal position of ending control point
698
+ # @param cy2 [Numeric] vertical position of ending control point
699
+ #
700
+ # @return [nil] nil
701
+ #
702
+ def curve (cx1, cy1, x1, y1, x2, y2, cx2, cy2)
703
+ assertDrawing__
704
+ @painter__.curve cx1, cy1, x1, y1, x2, y2, cx2, cy2
705
+ nil
706
+ end
977
707
 
978
- # Draws a text.
979
- #
980
- # @overload text(str)
981
- # @overload text(str, x, y)
982
- #
983
- # @param str [String] text to draw
984
- # @param x [Numeric] horizontal position of the text
985
- # @param y [Numeric] vertical position of the text
986
- #
987
- # @return [nil] nil
988
- #
989
- def text (str, x, y)
990
- @painter__.text str, x, y
991
- nil
992
- end
708
+ # Draws a Bezier spline curve.
709
+ #
710
+ # @param x1 [Numeric] horizontal position of first point
711
+ # @param y1 [Numeric] vertical position of first point
712
+ # @param cx1 [Numeric] horizontal position of first control point
713
+ # @param cy1 [Numeric] vertical position of first control point
714
+ # @param cx2 [Numeric] horizontal position of second control point
715
+ # @param cy2 [Numeric] vertical position of second control point
716
+ # @param x2 [Numeric] horizontal position of second point
717
+ # @param y2 [Numeric] vertical position of second point
718
+ #
719
+ # @return [nil] nil
720
+ #
721
+ def bezier (x1, y1, cx1, cy1, cx2, cy2, x2, y2)
722
+ assertDrawing__
723
+ @painter__.bezier x1, y1, cx1, cy1, cx2, cy2, x2, y2
724
+ nil
725
+ end
993
726
 
994
- # Draws an image.
995
- #
996
- # @overload image(img, a, b)
997
- # @overload image(img, a, b, c, d)
998
- #
999
- # @param img [Image] image to draw
1000
- # @param a [Numeric] horizontal position of the image
1001
- # @param b [Numeric] vertical position of the image
1002
- # @param c [Numeric] width of the image
1003
- # @param d [Numeric] height of the image
1004
- #
1005
- # @return [nil] nil
1006
- #
1007
- def image (img, a, b, c = nil, d = nil)
1008
- x, y, w, h = toXYWH__ @imageMode__, a, b, c || img.width, d || img.height
1009
- @painter__.image img.to_internal__, x, y, w, h
1010
- nil
1011
- end
727
+ # Draws a text.
728
+ #
729
+ # @overload text(str)
730
+ # @overload text(str, x, y)
731
+ #
732
+ # @param str [String] text to draw
733
+ # @param x [Numeric] horizontal position of the text
734
+ # @param y [Numeric] vertical position of the text
735
+ #
736
+ # @return [nil] nil
737
+ #
738
+ def text (str, x, y)
739
+ assertDrawing__
740
+ @painter__.text str, x, y
741
+ nil
742
+ end
1012
743
 
1013
- # Copies image.
1014
- #
1015
- # @overload copy(sx, sy, sw, sh, dx, dy, dw, dh)
1016
- # @overload copy(img, sx, sy, sw, sh, dx, dy, dw, dh)
1017
- #
1018
- # @param img [Image] image for copy source
1019
- # @param sx [Numrtic] x position of source region
1020
- # @param sy [Numrtic] y position of source region
1021
- # @param sw [Numrtic] width of source region
1022
- # @param sh [Numrtic] height of source region
1023
- # @param dx [Numrtic] x position of destination region
1024
- # @param dy [Numrtic] y position of destination region
1025
- # @param dw [Numrtic] width of destination region
1026
- # @param dh [Numrtic] height of destination region
1027
- #
1028
- # @return [nil] nil
1029
- #
1030
- def copy (img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
1031
- src = img&.to_internal__ || @window__.canvas
1032
- @painter__.image src, sx, sy, sw, sh, dx, dy, dw, dh
1033
- end
744
+ # Draws an image.
745
+ #
746
+ # @overload image(img, a, b)
747
+ # @overload image(img, a, b, c, d)
748
+ #
749
+ # @param img [Image] image to draw
750
+ # @param a [Numeric] horizontal position of the image
751
+ # @param b [Numeric] vertical position of the image
752
+ # @param c [Numeric] width of the image
753
+ # @param d [Numeric] height of the image
754
+ #
755
+ # @return [nil] nil
756
+ #
757
+ def image (img, a, b, c = nil, d = nil)
758
+ assertDrawing__
759
+ x, y, w, h = toXYWH__ @imageMode__, a, b, c || img.width, d || img.height
760
+ @painter__.image img.getInternal__, x, y, w, h
761
+ nil
762
+ end
1034
763
 
1035
- # Applies translation matrix to current transformation matrix.
1036
- #
1037
- # @param x [Numeric] horizontal transformation
1038
- # @param y [Numeric] vertical transformation
1039
- #
1040
- # @return [nil] nil
1041
- #
1042
- def translate (x, y)
1043
- @painter__.translate x, y
1044
- nil
1045
- end
764
+ # Copies image.
765
+ #
766
+ # @overload copy(sx, sy, sw, sh, dx, dy, dw, dh)
767
+ # @overload copy(img, sx, sy, sw, sh, dx, dy, dw, dh)
768
+ #
769
+ # @param img [Image] image for copy source
770
+ # @param sx [Numrtic] x position of source region
771
+ # @param sy [Numrtic] y position of source region
772
+ # @param sw [Numrtic] width of source region
773
+ # @param sh [Numrtic] height of source region
774
+ # @param dx [Numrtic] x position of destination region
775
+ # @param dy [Numrtic] y position of destination region
776
+ # @param dw [Numrtic] width of destination region
777
+ # @param dh [Numrtic] height of destination region
778
+ #
779
+ # @return [nil] nil
780
+ #
781
+ def copy (img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
782
+ assertDrawing__
783
+ src = img&.getInternal__ || @window__.canvas
784
+ @painter__.image src, sx, sy, sw, sh, dx, dy, dw, dh
785
+ end
1046
786
 
1047
- # Applies scale matrix to current transformation matrix.
1048
- #
1049
- # @overload scale(s)
1050
- # @overload scale(x, y)
1051
- #
1052
- # @param s [Numeric] horizontal and vertical scale
1053
- # @param x [Numeric] horizontal scale
1054
- # @param y [Numeric] vertical scale
1055
- #
1056
- # @return [nil] nil
1057
- #
1058
- def scale (x, y)
1059
- @painter__.scale x, y
1060
- nil
1061
- end
787
+ # Applies translation matrix to current transformation matrix.
788
+ #
789
+ # @param x [Numeric] horizontal transformation
790
+ # @param y [Numeric] vertical transformation
791
+ #
792
+ # @return [nil] nil
793
+ #
794
+ def translate (x, y)
795
+ assertDrawing__
796
+ @painter__.translate x, y
797
+ nil
798
+ end
1062
799
 
1063
- # Applies rotation matrix to current transformation matrix.
1064
- #
1065
- # @param angle [Numeric] angle for rotation
1066
- #
1067
- # @return [nil] nil
1068
- #
1069
- def rotate (angle)
1070
- @painter__.rotate toAngle__ angle
1071
- nil
1072
- end
800
+ # Applies scale matrix to current transformation matrix.
801
+ #
802
+ # @overload scale(s)
803
+ # @overload scale(x, y)
804
+ #
805
+ # @param s [Numeric] horizontal and vertical scale
806
+ # @param x [Numeric] horizontal scale
807
+ # @param y [Numeric] vertical scale
808
+ #
809
+ # @return [nil] nil
810
+ #
811
+ def scale (x, y)
812
+ assertDrawing__
813
+ @painter__.scale x, y
814
+ nil
815
+ end
1073
816
 
1074
- # Pushes the current transformation matrix to stack.
1075
- #
1076
- # @return [nil] nil
1077
- #
1078
- def pushMatrix (&block)
1079
- @matrixStack__.push @painter__.matrix
1080
- if block
1081
- block.call
1082
- popMatrix
817
+ # Applies rotation matrix to current transformation matrix.
818
+ #
819
+ # @param angle [Numeric] angle for rotation
820
+ #
821
+ # @return [nil] nil
822
+ #
823
+ def rotate (angle)
824
+ assertDrawing__
825
+ @painter__.rotate toAngle__ angle
826
+ nil
1083
827
  end
1084
- nil
1085
- end
1086
828
 
1087
- # Pops the current transformation matrix from stack.
1088
- #
1089
- # @return [nil] nil
1090
- #
1091
- def popMatrix ()
1092
- raise "matrix stack underflow" if @matrixStack__.empty?
1093
- @painter__.matrix = @matrixStack__.pop
1094
- nil
1095
- end
829
+ # Pushes the current transformation matrix to stack.
830
+ #
831
+ # @return [nil] nil
832
+ #
833
+ def pushMatrix (&block)
834
+ assertDrawing__
835
+ @matrixStack__.push @painter__.matrix
836
+ if block
837
+ block.call
838
+ popMatrix
839
+ end
840
+ nil
841
+ end
1096
842
 
1097
- # Reset current transformation matrix with identity matrix.
1098
- #
1099
- # @return [nil] nil
1100
- #
1101
- def resetMatrix ()
1102
- @painter__.matrix = 1
1103
- nil
1104
- end
843
+ # Pops the current transformation matrix from stack.
844
+ #
845
+ # @return [nil] nil
846
+ #
847
+ def popMatrix ()
848
+ assertDrawing__
849
+ raise "matrix stack underflow" if @matrixStack__.empty?
850
+ @painter__.matrix = @matrixStack__.pop
851
+ nil
852
+ end
1105
853
 
1106
- # Save current style values to the style stack.
1107
- #
1108
- # @return [nil] nil
1109
- #
1110
- def pushStyle (&block)
1111
- @styleStack__.push [
854
+ # Reset current transformation matrix with identity matrix.
855
+ #
856
+ # @return [nil] nil
857
+ #
858
+ def resetMatrix ()
859
+ assertDrawing__
860
+ @painter__.matrix = 1
861
+ nil
862
+ end
863
+
864
+ # Save current style values to the style stack.
865
+ #
866
+ # @return [nil] nil
867
+ #
868
+ def pushStyle (&block)
869
+ assertDrawing__
870
+ @styleStack__.push [
871
+ @painter__.fill,
872
+ @painter__.stroke,
873
+ @painter__.stroke_width,
874
+ @painter__.stroke_cap,
875
+ @painter__.stroke_join,
876
+ @painter__.font,
877
+ @hsbColor__,
878
+ @colorMaxes__,
879
+ @angleScale__,
880
+ @rectMode__,
881
+ @ellipseMode__,
882
+ @imageMode__
883
+ ]
884
+ if block
885
+ block.call
886
+ popStyle
887
+ end
888
+ nil
889
+ end
890
+
891
+ # Restore style values from the style stack.
892
+ #
893
+ # @return [nil] nil
894
+ #
895
+ def popStyle ()
896
+ assertDrawing__
897
+ raise "style stack underflow" if @styleStack__.empty?
1112
898
  @painter__.fill,
1113
899
  @painter__.stroke,
1114
900
  @painter__.stroke_width,
@@ -1120,246 +906,571 @@ module RubySketch
1120
906
  @angleScale__,
1121
907
  @rectMode__,
1122
908
  @ellipseMode__,
1123
- @imageMode__
1124
- ]
1125
- if block
1126
- block.call
909
+ @imageMode__ = @styleStack__.pop
910
+ nil
911
+ end
912
+
913
+ # Save current styles and transformations to stack.
914
+ #
915
+ # @return [nil] nil
916
+ #
917
+ def push (&block)
918
+ pushMatrix
919
+ pushStyle
920
+ if block
921
+ block.call
922
+ pop
923
+ end
924
+ end
925
+
926
+ # Restore styles and transformations from stack.
927
+ #
928
+ # @return [nil] nil
929
+ #
930
+ def pop ()
931
+ popMatrix
1127
932
  popStyle
1128
933
  end
1129
- nil
1130
- end
1131
934
 
1132
- # Restore style values from the style stack.
1133
- #
1134
- # @return [nil] nil
1135
- #
1136
- def popStyle ()
1137
- raise "style stack underflow" if @styleStack__.empty?
1138
- @painter__.fill,
1139
- @painter__.stroke,
1140
- @painter__.stroke_width,
1141
- @painter__.stroke_cap,
1142
- @painter__.stroke_join,
1143
- @painter__.font,
1144
- @hsbColor__,
1145
- @colorMaxes__,
1146
- @angleScale__,
1147
- @rectMode__,
1148
- @ellipseMode__,
1149
- @imageMode__ = @styleStack__.pop
1150
- nil
1151
- end
1152
-
1153
- # Save current styles and transformations to stack.
1154
- #
1155
- # @return [nil] nil
935
+ # @private
936
+ def getInternal__ ()
937
+ @image__
938
+ end
939
+
940
+ # @private
941
+ def assertDrawing__ ()
942
+ raise "call beginDraw() before drawing" unless @drawing
943
+ end
944
+
945
+ end# GraphicsContext
946
+
947
+
948
+ # Draws graphics into an offscreen buffer
1156
949
  #
1157
- def push (&block)
1158
- pushMatrix
1159
- pushStyle
1160
- if block
1161
- block.call
950
+ class Graphics
951
+
952
+ include GraphicsContext
953
+
954
+ def initialize (width, height)
955
+ setup__
956
+ @image__ = Rays::Image.new width, height
957
+ @painter__ = @image__.painter
958
+ end
959
+
960
+ def beginDraw ()
961
+ @painter__.__send__ :begin_paint
962
+ super
963
+ push
964
+ end
965
+
966
+ def endDraw ()
1162
967
  pop
968
+ super
969
+ @painter__.__send__ :end_paint
1163
970
  end
1164
- end
1165
971
 
1166
- # Restore styles and transformations from stack.
1167
- #
1168
- # @return [nil] nil
1169
- #
1170
- def pop ()
1171
- popMatrix
1172
- popStyle
1173
- end
972
+ end# Graphics
1174
973
 
1175
- # Returns the perlin noise value.
1176
- #
1177
- # @overload noise(x)
1178
- # @overload noise(x, y)
1179
- # @overload noise(x, y, z)
1180
- #
1181
- # @param x [Numeric] horizontal point in noise space
1182
- # @param y [Numeric] vertical point in noise space
1183
- # @param z [Numeric] depth point in noise space
1184
- #
1185
- # @return [Numeric] noise value (0.0..1.0)
1186
- #
1187
- def noise (x, y = 0, z = 0)
1188
- Rays.perlin(x, y, z) / 2.0 + 0.5
1189
- end
1190
974
 
1191
- # Loads image.
1192
- #
1193
- # @param filename [String] file name to load image
1194
- # @param extension [String] type of image to load (ex. 'png')
1195
- #
1196
- # @return [Image] loaded image object
1197
- #
1198
- def loadImage (filename, extension = nil)
1199
- filename = getImage__ filename, extension if filename =~ %r|^https?://|
1200
- Image.new Rays::Image.load filename
1201
- end
1202
-
1203
- # @private
1204
- private def getImage__ (uri, ext)
1205
- ext ||= File.extname uri
1206
- raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
1207
-
1208
- tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
1209
- path = tmpdir + Digest::SHA1.hexdigest(uri)
1210
- path = path.sub_ext ext
1211
-
1212
- unless path.file?
1213
- URI.open uri do |input|
1214
- tmpdir.mkdir unless tmpdir.directory?
1215
- path.open('w') do |output|
1216
- while buf = input.read(2 ** 16)
1217
- output.write buf
975
+ module Utility
976
+
977
+ # @private
978
+ DEG2RAD__ = Math::PI / 180.0
979
+
980
+ # @private
981
+ RAD2DEG__ = 180.0 / Math::PI
982
+
983
+ # Converts degree to radian.
984
+ #
985
+ # @param degree [Numeric] degree to convert
986
+ #
987
+ # @return [Numeric] radian
988
+ #
989
+ def radians (degree)
990
+ degree * DEG2RAD__
991
+ end
992
+
993
+ # Converts radian to degree.
994
+ #
995
+ # @param radian [Numeric] radian to convert
996
+ #
997
+ # @return [Numeric] degree
998
+ #
999
+ def degrees (radian)
1000
+ radian * RAD2DEG__
1001
+ end
1002
+
1003
+ # Returns the absolute number of the value.
1004
+ #
1005
+ # @param value [Numeric] number
1006
+ #
1007
+ # @return [Numeric] absolute number
1008
+ #
1009
+ def abs (value)
1010
+ value.abs
1011
+ end
1012
+
1013
+ # Returns the closest integer number greater than or equal to the value.
1014
+ #
1015
+ # @param value [Numeric] number
1016
+ #
1017
+ # @return [Numeric] rounded up number
1018
+ #
1019
+ def ceil (value)
1020
+ value.ceil
1021
+ end
1022
+
1023
+ # Returns the closest integer number less than or equal to the value.
1024
+ #
1025
+ # @param value [Numeric] number
1026
+ #
1027
+ # @return [Numeric] rounded down number
1028
+ #
1029
+ def floor (value)
1030
+ value.floor
1031
+ end
1032
+
1033
+ # Returns the closest integer number.
1034
+ #
1035
+ # @param value [Numeric] number
1036
+ #
1037
+ # @return [Numeric] rounded number
1038
+ #
1039
+ def round (value)
1040
+ value.round
1041
+ end
1042
+
1043
+ # Returns value raised to the power of exponent.
1044
+ #
1045
+ # @param value [Numeric] base number
1046
+ # @param exponent [Numeric] exponent number
1047
+ #
1048
+ # @return [Numeric] value ** exponent
1049
+ #
1050
+ def pow (value, exponent)
1051
+ value ** exponent
1052
+ end
1053
+
1054
+ # Returns squared value.
1055
+ #
1056
+ # @param value [Numeric] number
1057
+ #
1058
+ # @return [Numeric] squared value
1059
+ #
1060
+ def sq (value)
1061
+ value * value
1062
+ end
1063
+
1064
+ # Returns the magnitude (or length) of a vector.
1065
+ #
1066
+ # @overload mag(x, y)
1067
+ # @overload mag(x, y, z)
1068
+ #
1069
+ # @param x [Numeric] x of point
1070
+ # @param y [Numeric] y of point
1071
+ # @param z [Numeric] z of point
1072
+ #
1073
+ # @return [Numeric] magnitude
1074
+ #
1075
+ def mag (*args)
1076
+ x, y, z = *args
1077
+ case args.size
1078
+ when 2 then Math.sqrt x * x + y * y
1079
+ when 3 then Math.sqrt x * x + y * y + z * z
1080
+ else raise ArgumentError
1081
+ end
1082
+ end
1083
+
1084
+ # Returns distance between 2 points.
1085
+ #
1086
+ # @overload dist(x1, y1, x2, y2)
1087
+ # @overload dist(x1, y1, z1, x2, y2, z2)
1088
+ #
1089
+ # @param x1 [Numeric] x of first point
1090
+ # @param y1 [Numeric] y of first point
1091
+ # @param z1 [Numeric] z of first point
1092
+ # @param x2 [Numeric] x of second point
1093
+ # @param y2 [Numeric] y of second point
1094
+ # @param z2 [Numeric] z of second point
1095
+ #
1096
+ # @return [Numeric] distance between 2 points
1097
+ #
1098
+ def dist (*args)
1099
+ case args.size
1100
+ when 4
1101
+ x1, y1, x2, y2 = *args
1102
+ xx, yy = x2 - x1, y2 - y1
1103
+ Math.sqrt xx * xx + yy * yy
1104
+ when 3
1105
+ x1, y1, z1, x2, y2, z2 = *args
1106
+ xx, yy, zz = x2 - x1, y2 - y1, z2 - z1
1107
+ Math.sqrt xx * xx + yy * yy + zz * zz
1108
+ else raise ArgumentError
1109
+ end
1110
+ end
1111
+
1112
+ # Normalize the value from range start..stop into 0..1.
1113
+ #
1114
+ # @param value [Numeric] number to be normalized
1115
+ # @param start [Numeric] lower bound of the range
1116
+ # @param stop [Numeric] upper bound of the range
1117
+ #
1118
+ # @return [Numeric] normalized value between 0..1
1119
+ #
1120
+ def norm (value, start, stop)
1121
+ (value.to_f - start.to_f) / (stop.to_f - start.to_f)
1122
+ end
1123
+
1124
+ # Returns the interpolated number between range start..stop.
1125
+ #
1126
+ # @param start [Numeric] lower bound of the range
1127
+ # @param stop [Numeric] upper bound of the range
1128
+ # @param amount [Numeric] amount to interpolate
1129
+ #
1130
+ # @return [Numeric] interporated number
1131
+ #
1132
+ def lerp (start, stop, amount)
1133
+ start + (stop - start) * amount
1134
+ end
1135
+
1136
+ # Maps a number from range start1..stop1 to range start2..stop2.
1137
+ #
1138
+ # @param value [Numeric] number to be mapped
1139
+ # @param start1 [Numeric] lower bound of the range1
1140
+ # @param stop1 [Numeric] upper bound of the range1
1141
+ # @param start2 [Numeric] lower bound of the range2
1142
+ # @param stop2 [Numeric] upper bound of the range2
1143
+ #
1144
+ # @return [Numeric] mapped number
1145
+ #
1146
+ def map (value, start1, stop1, start2, stop2)
1147
+ lerp start2, stop2, norm(value, start1, stop1)
1148
+ end
1149
+
1150
+ # Returns minimum value.
1151
+ #
1152
+ # @overload min(a, b)
1153
+ # @overload min(a, b, c)
1154
+ # @overload min(array)
1155
+ #
1156
+ # @param a [Numeric] value to compare
1157
+ # @param b [Numeric] value to compare
1158
+ # @param c [Numeric] value to compare
1159
+ # @param array [Numeric] values to compare
1160
+ #
1161
+ # @return [Numeric] minimum value
1162
+ #
1163
+ def min (*args)
1164
+ args.flatten.min
1165
+ end
1166
+
1167
+ # Returns maximum value.
1168
+ #
1169
+ # @overload max(a, b)
1170
+ # @overload max(a, b, c)
1171
+ # @overload max(array)
1172
+ #
1173
+ # @param a [Numeric] value to compare
1174
+ # @param b [Numeric] value to compare
1175
+ # @param c [Numeric] value to compare
1176
+ # @param array [Numeric] values to compare
1177
+ #
1178
+ # @return [Numeric] maximum value
1179
+ #
1180
+ def max (*args)
1181
+ args.flatten.max
1182
+ end
1183
+
1184
+ # Constrains the number between min..max.
1185
+ #
1186
+ # @param value [Numeric] number to be constrained
1187
+ # @param min [Numeric] lower bound of the range
1188
+ # @param max [Numeric] upper bound of the range
1189
+ #
1190
+ # @return [Numeric] constrained number
1191
+ #
1192
+ def constrain (value, min, max)
1193
+ value < min ? min : (value > max ? max : value)
1194
+ end
1195
+
1196
+ # Returns the perlin noise value.
1197
+ #
1198
+ # @overload noise(x)
1199
+ # @overload noise(x, y)
1200
+ # @overload noise(x, y, z)
1201
+ #
1202
+ # @param x [Numeric] horizontal point in noise space
1203
+ # @param y [Numeric] vertical point in noise space
1204
+ # @param z [Numeric] depth point in noise space
1205
+ #
1206
+ # @return [Numeric] noise value (0.0..1.0)
1207
+ #
1208
+ def noise (x, y = 0, z = 0)
1209
+ Rays.perlin(x, y, z) / 2.0 + 0.5
1210
+ end
1211
+
1212
+ # Loads image.
1213
+ #
1214
+ # @param filename [String] file name to load image
1215
+ # @param extension [String] type of image to load (ex. 'png')
1216
+ #
1217
+ # @return [Image] loaded image object
1218
+ #
1219
+ def loadImage (filename, extension = nil)
1220
+ filename = getImage__ filename, extension if filename =~ %r|^https?://|
1221
+ Image.new Rays::Image.load filename
1222
+ end
1223
+
1224
+ # @private
1225
+ private def getImage__ (uri, ext)
1226
+ ext ||= File.extname uri
1227
+ raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
1228
+
1229
+ tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
1230
+ path = tmpdir + Digest::SHA1.hexdigest(uri)
1231
+ path = path.sub_ext ext
1232
+
1233
+ unless path.file?
1234
+ URI.open uri do |input|
1235
+ tmpdir.mkdir unless tmpdir.directory?
1236
+ path.open('w') do |output|
1237
+ while buf = input.read(2 ** 16)
1238
+ output.write buf
1239
+ end
1218
1240
  end
1219
1241
  end
1220
1242
  end
1243
+ path.to_s
1221
1244
  end
1222
- path.to_s
1223
- end
1224
-
1225
- end# Processing
1226
1245
 
1246
+ def createGraphics (width, height)
1247
+ Graphics.new width, height
1248
+ end
1227
1249
 
1228
- # Image object.
1229
- #
1230
- class Processing::Image
1250
+ end# Utility
1231
1251
 
1232
- # @private
1233
- def initialize (image)
1234
- @image = image
1235
- end
1236
1252
 
1237
- # Gets width of image.
1238
- #
1239
- # @return [Numeric] width of image
1253
+ # Processing context
1240
1254
  #
1241
- def width ()
1242
- @image.width
1243
- end
1255
+ module Context
1244
1256
 
1245
- # Gets height of image.
1246
- #
1247
- # @return [Numeric] height of image
1248
- #
1249
- def height ()
1250
- @image.height
1251
- end
1257
+ include GraphicsContext, Utility, Math
1252
1258
 
1253
- # Resizes image.
1254
- #
1255
- # @param width [Numeric] width for resized image
1256
- # @param height [Numeric] height for resized image
1257
- #
1258
- # @return [nil] nil
1259
- #
1260
- def resize (width, height)
1261
- @image = Rays::Image.new(width, height).paint do |painter|
1262
- painter.image @image, 0, 0, width, height
1259
+ # @private
1260
+ def setup__ (window)
1261
+ super()
1262
+ @loop__ = true
1263
+ @redraw__ = false
1264
+ @frameCount__ = 0
1265
+ @mouseX__ =
1266
+ @mouseY__ =
1267
+ @mousePrevX__ =
1268
+ @mousePrevY__ = 0
1269
+ @mousePressed__ = false
1270
+
1271
+ @window__ = window
1272
+ @image__ = @window__.canvas
1273
+ @painter__ = @window__.canvas_painter
1274
+
1275
+ @painter__.miter_limit = 10
1276
+
1277
+ drawFrame = -> event {
1278
+ @image__ = @window__.canvas
1279
+ @painter__ = @window__.canvas_painter
1280
+ begin
1281
+ push
1282
+ @drawBlock__.call event if @drawBlock__
1283
+ ensure
1284
+ pop
1285
+ @frameCount__ += 1
1286
+ end
1287
+ }
1288
+
1289
+ updateMouseState = -> x, y, pressed = nil {
1290
+ @mouseX__ = x
1291
+ @mouseY__ = y
1292
+ @mousePressed__ = pressed if pressed != nil
1293
+ }
1294
+
1295
+ updateMousePrevPos = -> {
1296
+ @mousePrevX__ = @mouseX__
1297
+ @mousePrevY__ = @mouseY__
1298
+ }
1299
+
1300
+ @window__.before_draw = proc {beginDraw}
1301
+ @window__.after_draw = proc {endDraw}
1302
+
1303
+ @window__.draw = proc do |e|
1304
+ if @loop__ || @redraw__
1305
+ @redraw__ = false
1306
+ drawFrame.call e
1307
+ end
1308
+ updateMousePrevPos.call
1309
+ end
1310
+
1311
+ @window__.pointer_down = proc do |e|
1312
+ updateMouseState.call e.x, e.y, true
1313
+ @mousePressedBlock__.call e if @mousePressedBlock__
1314
+ end
1315
+
1316
+ @window__.pointer_up = proc do |e|
1317
+ updateMouseState.call e.x, e.y, false
1318
+ @mouseReleasedBlock__.call e if @mouseReleasedBlock__
1319
+ end
1320
+
1321
+ @window__.pointer_move = proc do |e|
1322
+ updateMouseState.call e.x, e.y
1323
+ @mouseMovedBlock__.call e if @mouseMovedBlock__
1324
+ end
1325
+
1326
+ @window__.pointer_drag = proc do |e|
1327
+ updateMouseState.call e.x, e.y
1328
+ @mouseDraggedBlock__.call e if @mouseDraggedBlock__
1329
+ end
1263
1330
  end
1264
- nil
1265
- end
1266
1331
 
1267
- # Copies image.
1268
- #
1269
- # @overload copy(sx, sy, sw, sh, dx, dy, dw, dh)
1270
- # @overload copy(img, sx, sy, sw, sh, dx, dy, dw, dh)
1271
- #
1272
- # @param img [Image] image for copy source
1273
- # @param sx [Numrtic] x position of source region
1274
- # @param sy [Numrtic] y position of source region
1275
- # @param sw [Numrtic] width of source region
1276
- # @param sh [Numrtic] height of source region
1277
- # @param dx [Numrtic] x position of destination region
1278
- # @param dy [Numrtic] y position of destination region
1279
- # @param dw [Numrtic] width of destination region
1280
- # @param dh [Numrtic] height of destination region
1281
- #
1282
- # @return [nil] nil
1283
- #
1284
- def copy (img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
1285
- img ||= self
1286
- @image.paint do |painter|
1287
- painter.image img.to_internal__, sx, sy, sw, sh, dx, dy, dw, dh
1332
+ # Define setup block.
1333
+ #
1334
+ def setup (&block)
1335
+ @window__.setup = block
1336
+ nil
1288
1337
  end
1289
- end
1290
1338
 
1291
- # Saves image to file.
1292
- #
1293
- # @param filename [String] file name to save image
1294
- #
1295
- def save (filename)
1296
- @image.save filename
1297
- end
1339
+ # Define draw block.
1340
+ #
1341
+ def draw (&block)
1342
+ @drawBlock__ = block if block
1343
+ nil
1344
+ end
1298
1345
 
1299
- # @private
1300
- def to_internal__ ()
1301
- @image
1302
- end
1346
+ def key (&block)
1347
+ @window__.key = block
1348
+ nil
1349
+ end
1303
1350
 
1304
- end# Processing::Image
1351
+ def mousePressed (&block)
1352
+ @mousePressedBlock__ = block if block
1353
+ @mousePressed__
1354
+ end
1305
1355
 
1356
+ def mouseReleased (&block)
1357
+ @mouseReleasedBlock__ = block if block
1358
+ nil
1359
+ end
1306
1360
 
1307
- # Font object.
1308
- #
1309
- class Processing::Font
1361
+ def mouseMoved (&block)
1362
+ @mouseMovedBlock__ = block if block
1363
+ nil
1364
+ end
1310
1365
 
1311
- # @private
1312
- def initialize (font)
1313
- @font = font
1314
- end
1366
+ def mouseDragged (&block)
1367
+ @mouseDraggedBlock__ = block if block
1368
+ nil
1369
+ end
1315
1370
 
1316
- # Returns bounding box.
1317
- #
1318
- # @overload textBounds(str)
1319
- # @overload textBounds(str, x, y)
1320
- # @overload textBounds(str, x, y, fontSize)
1321
- #
1322
- # @param str [String] text to calculate bounding box
1323
- # @param x [Numeric] horizontal position of bounding box
1324
- # @param y [Numeric] vertical position of bounding box
1325
- # @param fontSize [Numeric] font size
1326
- #
1327
- # @return [TextBounds] bounding box for text
1328
- #
1329
- def textBounds (str, x = 0, y = 0, fontSize = nil)
1330
- f = fontSize ? Rays::Font.new(@font.name, fontSize) : @font
1331
- TextBounds.new x, y, x + f.width(str), y + f.height
1332
- end
1371
+ # @private
1372
+ private def size__ (width, height)
1373
+ raise 'size() must be called on startup or setup block' if @started__
1333
1374
 
1334
- end# Processing::Font
1375
+ @painter__.__send__ :end_paint
1376
+ @window__.__send__ :reset_canvas, width, height
1377
+ @painter__.__send__ :begin_paint
1335
1378
 
1379
+ @auto_resize__ = false
1380
+ end
1336
1381
 
1337
- # Bounding box for text.
1338
- #
1339
- class Processing::TextBounds
1382
+ def windowWidth ()
1383
+ @window__.width
1384
+ end
1340
1385
 
1341
- # Horizontal position
1342
- #
1343
- attr_reader :x
1386
+ def windowHeight ()
1387
+ @window__.height
1388
+ end
1344
1389
 
1345
- # Vertical position
1346
- #
1347
- attr_reader :y
1390
+ # Returns number of frames since program started.
1391
+ #
1392
+ # @return [Integer] total number of frames
1393
+ #
1394
+ def frameCount ()
1395
+ @frameCount__
1396
+ end
1348
1397
 
1349
- # Width of bounding box
1350
- #
1351
- attr_reader :w
1398
+ # Returns number of frames per second.
1399
+ #
1400
+ # @return [Float] frames per second
1401
+ #
1402
+ def frameRate ()
1403
+ @window__.event.fps
1404
+ end
1352
1405
 
1353
- # Height of bounding box
1354
- #
1355
- attr_reader :h
1406
+ # Returns pixel density
1407
+ #
1408
+ # @return [Numeric] pixel density
1409
+ #
1410
+ def displayDensity ()
1411
+ @painter__.pixel_density
1412
+ end
1356
1413
 
1357
- # @private
1358
- def initialize (x, y, w, h)
1359
- @x, @y, @w, @h = x, y, w, h
1360
- end
1414
+ # Returns mouse x position
1415
+ #
1416
+ # @return [Numeric] horizontal position of mouse
1417
+ #
1418
+ def mouseX ()
1419
+ @mouseX__
1420
+ end
1421
+
1422
+ # Returns mouse y position
1423
+ #
1424
+ # @return [Numeric] vertical position of mouse
1425
+ #
1426
+ def mouseY ()
1427
+ @mouseY__
1428
+ end
1361
1429
 
1362
- end# Processing::TextBounds
1430
+ # Returns mouse x position in previous frame
1431
+ #
1432
+ # @return [Numeric] horizontal position of mouse
1433
+ #
1434
+ def pmouseX ()
1435
+ @mousePrevX__
1436
+ end
1437
+
1438
+ # Returns mouse y position in previous frame
1439
+ #
1440
+ # @return [Numeric] vertical position of mouse
1441
+ #
1442
+ def pmouseY ()
1443
+ @mousePrevY__
1444
+ end
1445
+
1446
+ # Enables calling draw block on every frame.
1447
+ #
1448
+ # @return [nil] nil
1449
+ #
1450
+ def loop ()
1451
+ @loop__ = true
1452
+ end
1453
+
1454
+ # Disables calling draw block on every frame.
1455
+ #
1456
+ # @return [nil] nil
1457
+ #
1458
+ def noLoop ()
1459
+ @loop__ = false
1460
+ end
1461
+
1462
+ # Calls draw block to redraw frame.
1463
+ #
1464
+ # @return [nil] nil
1465
+ #
1466
+ def redraw ()
1467
+ @redraw__ = true
1468
+ end
1469
+
1470
+ end# Context
1471
+
1472
+
1473
+ end# Processing
1363
1474
 
1364
1475
 
1365
1476
  end# RubySketch