rubysketch 0.2.7 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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