rubysketch 0.3.0 → 0.3.5

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: 6a044fb62451ebcd69c89a5a9cb2781c747d4298142a9e6828f71cdbc63da999
4
- data.tar.gz: 6dade74829619df93d947160f930fdc19563cc9042b826ef7b8b4bd6015cfb00
3
+ metadata.gz: 0df24de4fc3eabd1c7880d51ff34ef8389b44bef43a8159c75e9e6c651953c0d
4
+ data.tar.gz: cf03a57e9ecbf8a63f0b089c4588c0cd041ef93e2b92c69a580b8aa1f013659e
5
5
  SHA512:
6
- metadata.gz: 7801ba15e151b5c519047b2145b71e820428b2b9601c9fccaffd1eb6d6b67ff344b6aa7b0cd12c9151d431df01d201c5cc63e3a8ffa92d854b5934a2357fb8ec
7
- data.tar.gz: 44f7ad0c273aa88974356dfcc3fbc7d080d8bccb023ab4137db23f2d7b85b0fa2b06b590a97b487f803575d903a87a8747f26ff3e0518b5c76623f26dcafd35d
6
+ metadata.gz: 953e09a5b8da7f8798186e3f0a4e4b9ca636a5c7a34cdd1eca26da30f09221ac31fe3c5ed9ebc8e498060f84b88de4bb14738ef8054e30544c38ca664522f050
7
+ data.tar.gz: 4c4ae42689cfda821c84617c2925fc48b6af3ad3672d8dd1c603b999427762b5439cbf7c879a06fdf8830f83632d5e01bd9197d1cf528f6ae948a38728063a2a
@@ -1,6 +1,44 @@
1
1
  # RubySketch ChangeLog
2
2
 
3
3
 
4
+ ## [0.3.5] - 2020-08-02
5
+
6
+ - add random()
7
+ - add sin(), cos(), tan(), asin(), acos(), atan() and atan2()
8
+ - make Vector class accessible from user script context
9
+ - fix error on calling rotate()
10
+
11
+
12
+ ## [0.3.4] - 2020-08-02
13
+
14
+ - delete Utility module
15
+
16
+
17
+ ## [0.3.3] - 2020-08-01
18
+
19
+ - add Vector class
20
+
21
+
22
+ ## [0.3.2] - 2020-07-22
23
+
24
+ - text() draws to the baseline by default
25
+ - add textWidth(), textAscent(), textDescent() and textAlign()
26
+ - change initial color for fill() and stroke()
27
+ - change initial background color to grayscale 0.8
28
+
29
+
30
+ ## [0.3.1] - 2020-07-17
31
+
32
+ - add touchStarted(), touchEnded(), touchMoved() and touches()
33
+ - make all event handler drawable
34
+ - limit font max size to 256
35
+
36
+
37
+ ## [0.3.0] - 2020-05-21
38
+
39
+ - add createGraphics()
40
+
41
+
4
42
  ## [0.2.7] - 2020-04-17
5
43
 
6
44
  - add strokeCap() and strokeJoin()
data/Rakefile CHANGED
@@ -18,6 +18,7 @@ MODULES = [Xot, Rucy, Rays, Reflex, RubySketch]
18
18
 
19
19
  ENV['RDOC'] = 'yardoc --no-private'
20
20
 
21
+ test_ruby_extension
21
22
  generate_documents
22
23
  build_ruby_gem
23
24
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.5
@@ -6,13 +6,574 @@ module RubySketch
6
6
  module Processing
7
7
 
8
8
 
9
+ # @private
10
+ DEG2RAD__ = Math::PI / 180.0
11
+
12
+ # @private
13
+ RAD2DEG__ = 180.0 / Math::PI
14
+
15
+
16
+ # Vector class.
17
+ #
18
+ class Vector
19
+
20
+ include Comparable
21
+
22
+ # Initialize vector object.
23
+ #
24
+ # @overload new()
25
+ # @overload new(x)
26
+ # @overload new(x, y)
27
+ # @overload new(x, y, z)
28
+ # @overload new(v)
29
+ # @overload new(a)
30
+ #
31
+ # @param x [Numeric] x of vector
32
+ # @param y [Numeric] y of vector
33
+ # @param z [Numeric] z of vector
34
+ # @param v [Vector] vector object to copy
35
+ # @param a [Array] array like [x, y, z]
36
+ #
37
+ def initialize (x = 0, y = 0, z = 0, context: nil)
38
+ @point = case x
39
+ when Rays::Point then x.dup
40
+ when Vector then x.getInternal__.dup
41
+ when Array then Rays::Point.new x[0] || 0, x[1] || 0, x[2] || 0
42
+ else Rays::Point.new x || 0, y || 0, z || 0
43
+ end
44
+ @context = context || Context.context__
45
+ end
46
+
47
+ # Initializer for dup or clone
48
+ #
49
+ def initialize_copy (o)
50
+ @point = o.getInternal__.dup
51
+ end
52
+
53
+ # Copy vector object
54
+ #
55
+ # @return [Vector] duplicated vector object
56
+ #
57
+ alias copy dup
58
+
59
+ # Sets x, y and z.
60
+ #
61
+ # @overload set(x)
62
+ # @overload set(x, y)
63
+ # @overload set(x, y, z)
64
+ # @overload set(v)
65
+ # @overload set(a)
66
+ #
67
+ # @param x [Numeric] x of vector
68
+ # @param y [Numeric] y of vector
69
+ # @param z [Numeric] z of vector
70
+ # @param v [Vector] vector object to copy
71
+ # @param a [Array] array with x, y, z
72
+ #
73
+ # @return [nil] nil
74
+ #
75
+ def set (*args)
76
+ initialize *args
77
+ self
78
+ end
79
+
80
+ # Gets x value.
81
+ #
82
+ # @return [Numeric] x value of vector
83
+ #
84
+ def x ()
85
+ @point.x
86
+ end
87
+
88
+ # Gets y value.
89
+ #
90
+ # @return [Numeric] y value of vector
91
+ #
92
+ def y ()
93
+ @point.y
94
+ end
95
+
96
+ # Gets z value.
97
+ #
98
+ # @return [Numeric] z value of vector
99
+ #
100
+ def z ()
101
+ @point.z
102
+ end
103
+
104
+ # Sets x value.
105
+ #
106
+ # @return [Numeric] x value of vector
107
+ #
108
+ def x= (x)
109
+ @point.x = x
110
+ end
111
+
112
+ # Sets y value.
113
+ #
114
+ # @return [Numeric] y value of vector
115
+ #
116
+ def y= (y)
117
+ @point.y = y
118
+ end
119
+
120
+ # Sets z value.
121
+ #
122
+ # @return [Numeric] z value of vector
123
+ #
124
+ def z= (z)
125
+ @point.z = z
126
+ end
127
+
128
+ # Returns the interpolated vector between 2 vectors.
129
+ #
130
+ # @overload lerp(v, amount)
131
+ # @overload lerp(x, y, amount)
132
+ # @overload lerp(x, y, z, amount)
133
+ #
134
+ # @param v [Vector] vector to interpolate
135
+ # @param x [Numeric] x of vector to interpolate
136
+ # @param y [Numeric] y of vector to interpolate
137
+ # @param z [Numeric] z of vector to interpolate
138
+ # @param amount [Numeric] amount to interpolate
139
+ #
140
+ # @return [Vector] interporated vector
141
+ #
142
+ def lerp (*args, amount)
143
+ v = toVector__ *args
144
+ self.x = Context.lerp x, v.x, amount
145
+ self.y = Context.lerp y, v.y, amount
146
+ self.z = Context.lerp z, v.z, amount
147
+ self
148
+ end
149
+
150
+ # Returns the interpolated vector between 2 vectors.
151
+ #
152
+ # @param v1 [Vector] vector to interpolate
153
+ # @param v2 [Vector] vector to interpolate
154
+ # @param amount [Numeric] amount to interpolate
155
+ #
156
+ # @return [Vector] interporated vector
157
+ #
158
+ def self.lerp (v1, v2, amount)
159
+ v1.dup.lerp v2, amount
160
+ end
161
+
162
+ # Returns x, y, z as an array
163
+ #
164
+ # @return [Array] array of x, y, z
165
+ #
166
+ def array ()
167
+ @point.to_a 3
168
+ end
169
+
170
+ # Adds a vector.
171
+ #
172
+ # @overload add(v)
173
+ # @overload add(x, y)
174
+ # @overload add(x, y, z)
175
+ #
176
+ # @param v [Vector] vector to add
177
+ # @param x [Vector] x of vector to add
178
+ # @param y [Vector] y of vector to add
179
+ # @param z [Vector] z of vector to add
180
+ #
181
+ # @return [Vector] added vector
182
+ #
183
+ def add (*args)
184
+ @point += toVector__(*args).getInternal__
185
+ self
186
+ end
187
+
188
+ # Subtracts a vector.
189
+ #
190
+ # @overload sub(v)
191
+ # @overload sub(x, y)
192
+ # @overload sub(x, y, z)
193
+ #
194
+ # @param v [Vector] vector to subtract
195
+ # @param x [Vector] x of vector to subtract
196
+ # @param y [Vector] y of vector to subtract
197
+ # @param z [Vector] z of vector to subtract
198
+ #
199
+ # @return [Vector] subtracted vector
200
+ #
201
+ def sub (*args)
202
+ @point -= toVector__(*args).getInternal__
203
+ self
204
+ end
205
+
206
+ # Multiplies a vector by scalar.
207
+ #
208
+ # @param num [Numeric] number to multiply the vector
209
+ #
210
+ # @return [Vector] multiplied vector
211
+ #
212
+ def mult (num)
213
+ @point *= num
214
+ self
215
+ end
216
+
217
+ # Divides a vector by scalar.
218
+ #
219
+ # @param num [Numeric] number to divide the vector
220
+ #
221
+ # @return [Vector] divided vector
222
+ #
223
+ def div (num)
224
+ @point /= num
225
+ self
226
+ end
227
+
228
+ # Adds a vector.
229
+ #
230
+ # @param v [Vector] vector to add
231
+ #
232
+ # @return [Vector] added vector
233
+ #
234
+ def + (v)
235
+ dup.add v
236
+ end
237
+
238
+ # Subtracts a vector.
239
+ #
240
+ # @param v [Vector] vector to subtract
241
+ #
242
+ # @return [Vector] subtracted vector
243
+ #
244
+ def - (v)
245
+ dup.sub v
246
+ end
247
+
248
+ # Multiplies a vector by scalar.
249
+ #
250
+ # @param num [Numeric] number to multiply the vector
251
+ #
252
+ # @return [Vector] multiplied vector
253
+ #
254
+ def * (num)
255
+ dup.mult num
256
+ end
257
+
258
+ # Divides a vector by scalar.
259
+ #
260
+ # @param num [Numeric] number to divide the vector
261
+ #
262
+ # @return [Vector] divided vector
263
+ #
264
+ def / (num)
265
+ dup.div num
266
+ end
267
+
268
+ # Adds 2 vectors.
269
+ #
270
+ # @overload add(v1, v2)
271
+ # @overload add(v1, v2, target)
272
+ #
273
+ # @param v1 [Vector] a vector
274
+ # @param v2 [Vector] another vector
275
+ # @param target [Vector] vector to store added vector
276
+ #
277
+ # @return [Vector] added vector
278
+ #
279
+ def self.add (v1, v2, target = nil)
280
+ v = v1 + v2
281
+ target.set v if self === target
282
+ v
283
+ end
284
+
285
+ # Subtracts 2 vectors.
286
+ #
287
+ # @overload sub(v1, v2)
288
+ # @overload sub(v1, v2, target)
289
+ #
290
+ # @param v1 [Vector] a vector
291
+ # @param v2 [Vector] another vector
292
+ # @param target [Vector] vector to store subtracted vector
293
+ #
294
+ # @return [Vector] subtracted vector
295
+ #
296
+ def self.sub (v1, v2, target = nil)
297
+ v = v1 - v2
298
+ target.set v if self === target
299
+ v
300
+ end
301
+
302
+ # Multiplies a vector by scalar.
303
+ #
304
+ # @overload mult(v, num)
305
+ # @overload mult(v, num, target)
306
+ #
307
+ # @param v [Vector] a vector
308
+ # @param num [Numeric] number to multiply the vector
309
+ # @param target [Vector] vector to store multiplied vector
310
+ #
311
+ # @return [Vector] multiplied vector
312
+ #
313
+ def self.mult (v1, num, target = nil)
314
+ v = v1 * num
315
+ target.set v if self === target
316
+ v
317
+ end
318
+
319
+ # Divides a vector by scalar.
320
+ #
321
+ # @overload div(v, num)
322
+ # @overload div(v, num, target)
323
+ #
324
+ # @param v [Vector] a vector
325
+ # @param num [Numeric] number to divide the vector
326
+ # @param target [Vector] vector to store divided vector
327
+ #
328
+ # @return [Vector] divided vector
329
+ #
330
+ def self.div (v1, num, target = nil)
331
+ v = v1 / num
332
+ target.set v if self === target
333
+ v
334
+ end
335
+
336
+ # Returns the length of the vector.
337
+ #
338
+ # @return [Numeric] length
339
+ #
340
+ def mag ()
341
+ @point.length
342
+ end
343
+
344
+ # Returns squared length of the vector.
345
+ #
346
+ # @return [Numeric] squared length
347
+ #
348
+ def magSq ()
349
+ Rays::Point::dot(@point, @point)
350
+ end
351
+
352
+ # Changes the length of the vector.
353
+ #
354
+ # @overload setMag(len)
355
+ # @overload setMag(target, len)
356
+ #
357
+ # @param len [Numeric] length of new vector
358
+ # @param target [Vector] vector to store new vector
359
+ #
360
+ # @return [Vector] vector with new length
361
+ #
362
+ def setMag (target = nil, len)
363
+ (target || self).set @point.normal * len
364
+ end
365
+
366
+ # Changes the length of the vector to 1.0.
367
+ #
368
+ # @param target [Vector] vector to store the normalized vector
369
+ #
370
+ # @return [Vector] normalized vector
371
+ #
372
+ def normalize (target = nil)
373
+ (target || self).set @point.normal
374
+ end
375
+
376
+ # Changes the length of the vector if it's length is greater than the max value.
377
+ #
378
+ # @param max [Numeric] max length
379
+ #
380
+ # @return [Vector] new vector
381
+ #
382
+ def limit (max)
383
+ setMag max if magSq > max ** 2
384
+ self
385
+ end
386
+
387
+ # Returns the distance of 2 vectors.
388
+ #
389
+ # @param v [Vector] a vector
390
+ #
391
+ # @return [Numeric] the distance
392
+ #
393
+ def dist (v)
394
+ (self - v).mag
395
+ end
396
+
397
+ # Returns the distance of 2 vectors.
398
+ #
399
+ # @param v1 [Vector] a vector
400
+ # @param v2 [Vector] another vector
401
+ #
402
+ # @return [Numeric] the distance
403
+ #
404
+ def self.dist (v1, v2)
405
+ v1.dist v2
406
+ end
407
+
408
+ # Calculates the dot product of 2 vectors.
409
+ #
410
+ # @overload dot(v)
411
+ # @overload dot(x, y)
412
+ # @overload dot(x, y, z)
413
+ #
414
+ # @param v [Vector] a vector
415
+ # @param x [Numeric] x of vector
416
+ # @param y [Numeric] y of vector
417
+ # @param z [Numeric] z of vector
418
+ #
419
+ # @return [Numeric] result of dot product
420
+ #
421
+ def dot (*args)
422
+ Rays::Point::dot getInternal__, toVector__(*args).getInternal__
423
+ end
424
+
425
+ # Calculates the dot product of 2 vectors.
426
+ #
427
+ # @param v1 [Vector] a vector
428
+ # @param v2 [Vector] another vector
429
+ #
430
+ # @return [Numeric] result of dot product
431
+ #
432
+ def self.dot (v1, v2)
433
+ v1.dot v2
434
+ end
435
+
436
+ # Calculates the cross product of 2 vectors.
437
+ #
438
+ # @overload cross(v)
439
+ # @overload cross(x, y)
440
+ # @overload cross(x, y, z)
441
+ #
442
+ # @param v [Vector] a vector
443
+ # @param x [Numeric] x of vector
444
+ # @param y [Numeric] y of vector
445
+ # @param z [Numeric] z of vector
446
+ #
447
+ # @return [Numeric] result of cross product
448
+ #
449
+ def cross (a, *rest)
450
+ target = self.class === rest.last ? rest.pop : nil
451
+ v = self.class.new Rays::Point::cross getInternal__, toVector__(a, *rest).getInternal__
452
+ target.set v if self.class === target
453
+ v
454
+ end
455
+
456
+ # Calculates the cross product of 2 vectors.
457
+ #
458
+ # @param v1 [Vector] a vector
459
+ # @param v2 [Vector] another vector
460
+ #
461
+ # @return [Numeric] result of cross product
462
+ #
463
+ def self.cross (v1, v2, target = nil)
464
+ v1.cross v2, target
465
+ end
466
+
467
+ # Rotate the vector.
468
+ #
469
+ # @param angle [Numeric] the angle of rotation
470
+ #
471
+ # @return [Vector] rotated this object
472
+ #
473
+ def rotate (angle)
474
+ angle = @context ? @context.toAngle__(angle) : angle * RAD2DEG__
475
+ @point.rotate! angle
476
+ self
477
+ end
478
+
479
+ # Returns the angle of rotation for this vector.
480
+ #
481
+ # @return [Numeric] the angle in radians
482
+ #
483
+ def heading ()
484
+ Math.atan2 y, x
485
+ end
486
+
487
+ # Returns rotated new vector.
488
+ #
489
+ # @param angle [Numeric] the angle of rotation
490
+ # @param target [Vector] vector to store new vector
491
+ #
492
+ # @return [Vector] rotated vector
493
+ #
494
+ def self.fromAngle (angle, target = nil)
495
+ v = self.new(1, 0, 0).rotate(angle)
496
+ target.set v if target
497
+ v
498
+ end
499
+
500
+ # Returns angle between 2 vectors.
501
+ #
502
+ # @param v1 [Vector] a vector
503
+ # @param v2 [Vector] another vector
504
+ #
505
+ # @return [Numeric] angle in radians
506
+ #
507
+ def self.angleBetween (v1, v2)
508
+ x1, y1, z1 = v1.array
509
+ x2, y2, z2 = v2.array
510
+ return 0 if (x1 == 0 && y1 == 0 && z1 == 0) || (x2 == 0 && y2 == 0 && z2 == 0)
511
+
512
+ x = dot(v1, v2) / (v1.mag * v2.mag)
513
+ return Math::PI if x <= -1
514
+ return 0 if x >= 1
515
+ return Math.acos x
516
+ end
517
+
518
+ # Returns a new 2D unit vector with a random direction.
519
+ #
520
+ # @param target [Vector] a vector to store the new vector
521
+ #
522
+ # @return [Vector] a random vector
523
+ #
524
+ def self.random2D (target = nil)
525
+ v = self.fromAngle rand 0.0...(Math::PI * 2)
526
+ target.set v if target
527
+ v
528
+ end
529
+
530
+ # Returns a new 3D unit vector with a random direction.
531
+ #
532
+ # @param target [Vector] a vector to store the new vector
533
+ #
534
+ # @return [Vector] a random vector
535
+ #
536
+ def self.random3D (target = nil)
537
+ angle = rand 0.0...(Math::PI * 2)
538
+ z = rand -1.0..1.0
539
+ z2 = z ** 2
540
+ x = Math.sqrt(1.0 - z2) * Math.cos(angle)
541
+ y = Math.sqrt(1.0 - z2) * Math.sin(angle)
542
+ v = self.new x, y, z
543
+ target.set v if target
544
+ v
545
+ end
546
+
547
+ # @private
548
+ def inspect ()
549
+ "<##{self.class.name} #{x}, #{y}, #{z}>"
550
+ end
551
+
552
+ # @private
553
+ def <=> (o)
554
+ @point <=> o.getInternal__
555
+ end
556
+
557
+ # @private
558
+ protected def getInternal__ ()
559
+ @point
560
+ end
561
+
562
+ # @private
563
+ private def toVector__ (*args)
564
+ self.class === args.first ? args.first : self.class.new(*args)
565
+ end
566
+
567
+ end# Vector
568
+
569
+
9
570
  # Image object.
10
571
  #
11
572
  class Image
12
573
 
13
574
  # @private
14
575
  def initialize (image)
15
- @image__ = image
576
+ @image = image
16
577
  end
17
578
 
18
579
  # Gets width of image.
@@ -20,7 +581,7 @@ module RubySketch
20
581
  # @return [Numeric] width of image
21
582
  #
22
583
  def width ()
23
- @image__.width
584
+ @image.width
24
585
  end
25
586
 
26
587
  # Gets height of image.
@@ -28,7 +589,7 @@ module RubySketch
28
589
  # @return [Numeric] height of image
29
590
  #
30
591
  def height ()
31
- @image__.height
592
+ @image.height
32
593
  end
33
594
 
34
595
  # Resizes image.
@@ -39,8 +600,8 @@ module RubySketch
39
600
  # @return [nil] nil
40
601
  #
41
602
  def resize (width, height)
42
- @image__ = Rays::Image.new(width, height).paint do |painter|
43
- painter.image @image__, 0, 0, width, height
603
+ @image = Rays::Image.new(width, height).paint do |painter|
604
+ painter.image @image, 0, 0, width, height
44
605
  end
45
606
  nil
46
607
  end
@@ -64,7 +625,7 @@ module RubySketch
64
625
  #
65
626
  def copy (img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
66
627
  img ||= self
67
- @image__.paint do |painter|
628
+ @image.paint do |painter|
68
629
  painter.image img.getInternal__, sx, sy, sw, sh, dx, dy, dw, dh
69
630
  end
70
631
  end
@@ -74,12 +635,12 @@ module RubySketch
74
635
  # @param filename [String] file name to save image
75
636
  #
76
637
  def save (filename)
77
- @image__.save filename
638
+ @image.save filename
78
639
  end
79
640
 
80
641
  # @private
81
642
  def getInternal__ ()
82
- @image__
643
+ @image
83
644
  end
84
645
 
85
646
  end# Image
@@ -143,10 +704,36 @@ module RubySketch
143
704
  end# TextBounds
144
705
 
145
706
 
707
+ # Touch object.
708
+ #
709
+ class Touch
710
+
711
+ # Horizontal position of touch
712
+ #
713
+ attr_reader :x
714
+
715
+ # Vertical position of touch
716
+ #
717
+ attr_reader :y
718
+
719
+ # @private
720
+ def initialize (x, y)
721
+ @x, @y = x, y
722
+ end
723
+
724
+ def id ()
725
+ raise NotImplementedError
726
+ end
727
+
728
+ end# Touch
729
+
730
+
146
731
  # Drawing context
147
732
  #
148
733
  module GraphicsContext
149
734
 
735
+ Vector = Processing::Vector
736
+
150
737
  # PI / 2
151
738
  #
152
739
  HALF_PI = Math::PI / 2
@@ -187,7 +774,7 @@ module RubySketch
187
774
  #
188
775
  CORNERS = :CORNERS
189
776
 
190
- # Mode for rectMode(), ellipseMode() and imageMode().
777
+ # Mode for rectMode(), ellipseMode(), imageMode() and textAlign().
191
778
  #
192
779
  CENTER = :CENTER
193
780
 
@@ -195,6 +782,21 @@ module RubySketch
195
782
  #
196
783
  RADIUS = :RADIUS
197
784
 
785
+ # Mode for textAlign().
786
+ LEFT = :LEFT
787
+
788
+ # Mode for textAlign().
789
+ RIGHT = :RIGHT
790
+
791
+ # Mode for textAlign().
792
+ TOP = :TOP
793
+
794
+ # Mode for textAlign().
795
+ BOTTOM = :BOTTOM
796
+
797
+ # Mode for textAlign().
798
+ BASELINE = :BASELINE
799
+
198
800
  # Mode for strokeCap().
199
801
  #
200
802
  BUTT = :butt
@@ -211,7 +813,10 @@ module RubySketch
211
813
  #
212
814
  SQUARE = :square
213
815
 
214
- def setup__ ()
816
+ def setup__ (painter)
817
+ @painter__ = painter
818
+ @painter__.miter_limit = 10
819
+
215
820
  @drawing = false
216
821
  @hsbColor__ = false
217
822
  @colorMaxes__ = [1.0] * 4
@@ -219,6 +824,8 @@ module RubySketch
219
824
  @rectMode__ = nil
220
825
  @ellipseMode__ = nil
221
826
  @imageMode__ = nil
827
+ @textAlignH__ = nil
828
+ @textAlignV__ = nil
222
829
  @matrixStack__ = []
223
830
  @styleStack__ = []
224
831
 
@@ -227,6 +834,10 @@ module RubySketch
227
834
  rectMode CORNER
228
835
  ellipseMode CENTER
229
836
  imageMode CORNER
837
+ textAlign LEFT
838
+
839
+ fill 255
840
+ stroke 0
230
841
  end
231
842
 
232
843
  def beginDraw ()
@@ -264,10 +875,11 @@ module RubySketch
264
875
  # @return [nil] nil
265
876
  #
266
877
  def colorMode (mode, *maxes)
878
+ mode = mode.upcase.to_sym
267
879
  raise ArgumentError, "invalid color mode: #{mode}" unless [RGB, HSB].include?(mode)
268
880
  raise ArgumentError unless [0, 1, 3, 4].include?(maxes.size)
269
881
 
270
- @hsbColor__ = mode.upcase == HSB
882
+ @hsbColor__ = mode == HSB
271
883
  case maxes.size
272
884
  when 1 then @colorMaxes__ = [maxes.first.to_f] * 4
273
885
  when 3, 4 then @colorMaxes__[0...maxes.size] = maxes.map &:to_f
@@ -311,8 +923,8 @@ module RubySketch
311
923
  # @return [nil] nil
312
924
  #
313
925
  def angleMode (mode)
314
- @angleScale__ = case mode
315
- when RADIANS then Utility::RAD2DEG__
926
+ @angleScale__ = case mode.upcase.to_sym
927
+ when RADIANS then RAD2DEG__
316
928
  when DEGREES then 1.0
317
929
  else raise ArgumentError, "invalid angle mode: #{mode}"
318
930
  end
@@ -320,7 +932,7 @@ module RubySketch
320
932
  end
321
933
 
322
934
  # @private
323
- private def toAngle__ (angle)
935
+ def toAngle__ (angle)
324
936
  angle * @angleScale__
325
937
  end
326
938
 
@@ -479,26 +1091,49 @@ module RubySketch
479
1091
  # Sets font.
480
1092
  #
481
1093
  # @param name [String] font name
482
- # @param size [Numeric] font size
1094
+ # @param size [Numeric] font size (max 256)
483
1095
  #
484
1096
  # @return [Font] current font
485
1097
  #
486
1098
  def textFont (name = nil, size = nil)
487
- @painter__.font name, size if name || size
1099
+ setFont__ name, size if name || size
488
1100
  Font.new @painter__.font
489
1101
  end
490
1102
 
491
1103
  # Sets text size.
492
1104
  #
493
- # @param size [Numeric] font size
1105
+ # @param size [Numeric] font size (max 256)
494
1106
  #
495
1107
  # @return [nil] nil
496
1108
  #
497
1109
  def textSize (size)
498
- @painter__.font @painter__.font.name, size
1110
+ setFont__ @painter__.font.name, size
499
1111
  nil
500
1112
  end
501
1113
 
1114
+ def textWidth (str)
1115
+ @painter__.font.width str
1116
+ end
1117
+
1118
+ def textAscent ()
1119
+ @painter__.font.ascent
1120
+ end
1121
+
1122
+ def textDescent ()
1123
+ @painter__.font.descent
1124
+ end
1125
+
1126
+ def textAlign (horizontal, vertical = BASELINE)
1127
+ @textAlignH__ = horizontal
1128
+ @textAlignV__ = vertical
1129
+ end
1130
+
1131
+ # @private
1132
+ def setFont__ (name, size)
1133
+ size = 256 if size && size > 256
1134
+ @painter__.font name, size
1135
+ end
1136
+
502
1137
  # Clears screen.
503
1138
  #
504
1139
  # @overload background(str)
@@ -728,15 +1363,35 @@ module RubySketch
728
1363
  #
729
1364
  # @overload text(str)
730
1365
  # @overload text(str, x, y)
1366
+ # @overload text(str, a, b, c, d)
731
1367
  #
732
1368
  # @param str [String] text to draw
733
1369
  # @param x [Numeric] horizontal position of the text
734
1370
  # @param y [Numeric] vertical position of the text
1371
+ # @param a [Numeric] equivalent to parameters of the rect(), see rectMode()
1372
+ # @param b [Numeric] equivalent to parameters of the rect(), see rectMode()
1373
+ # @param c [Numeric] equivalent to parameters of the rect(), see rectMode()
1374
+ # @param d [Numeric] equivalent to parameters of the rect(), see rectMode()
735
1375
  #
736
1376
  # @return [nil] nil
737
1377
  #
738
- def text (str, x, y)
1378
+ def text (str, x, y, x2 = nil, y2 = nil)
739
1379
  assertDrawing__
1380
+ if x2
1381
+ raise ArgumentError, "missing y2 parameter" unless y2
1382
+ x, y, w, h = toXYWH__ @rectMode__, x, y, x2, y2
1383
+ case @textAlignH__
1384
+ when RIGHT then x += w - @painter__.font.width(str)
1385
+ when CENTER then x += (w - @painter__.font.width(str)) / 2
1386
+ end
1387
+ case @textAlignV__
1388
+ when BOTTOM then y += h - @painter__.font.height
1389
+ when CENTER then y += (h - @painter__.font.height) / 2
1390
+ else
1391
+ end
1392
+ else
1393
+ y -= @painter__.font.ascent
1394
+ end
740
1395
  @painter__.text str, x, y
741
1396
  nil
742
1397
  end
@@ -933,12 +1588,12 @@ module RubySketch
933
1588
  end
934
1589
 
935
1590
  # @private
936
- def getInternal__ ()
1591
+ private def getInternal__ ()
937
1592
  @image__
938
1593
  end
939
1594
 
940
1595
  # @private
941
- def assertDrawing__ ()
1596
+ private def assertDrawing__ ()
942
1597
  raise "call beginDraw() before drawing" unless @drawing
943
1598
  end
944
1599
 
@@ -952,9 +1607,8 @@ module RubySketch
952
1607
  include GraphicsContext
953
1608
 
954
1609
  def initialize (width, height)
955
- setup__
956
- @image__ = Rays::Image.new width, height
957
- @painter__ = @image__.painter
1610
+ @image__ = Rays::Image.new width, height
1611
+ setup__ @image__.painter
958
1612
  end
959
1613
 
960
1614
  def beginDraw ()
@@ -972,34 +1626,247 @@ module RubySketch
972
1626
  end# Graphics
973
1627
 
974
1628
 
975
- module Utility
1629
+ # Processing context
1630
+ #
1631
+ module Context
1632
+
1633
+ include GraphicsContext, Math
1634
+
1635
+ @@context__ = nil
1636
+
1637
+ def self.context__ ()
1638
+ @@context__
1639
+ end
976
1640
 
977
1641
  # @private
978
- DEG2RAD__ = Math::PI / 180.0
1642
+ def setup__ (window)
1643
+ @@context__ = self
1644
+
1645
+ @window__ = window
1646
+ @image__ = @window__.canvas
1647
+ super @window__.canvas_painter.paint {background 0.8}
1648
+
1649
+ @loop__ = true
1650
+ @redraw__ = false
1651
+ @frameCount__ = 0
1652
+ @mousePos__ =
1653
+ @mousePrevPos__ = Rays::Point.new 0
1654
+ @mousePressed__ = false
1655
+ @touches__ = []
1656
+
1657
+ @window__.before_draw = proc {beginDraw}
1658
+ @window__.after_draw = proc {endDraw}
1659
+
1660
+ drawFrame = -> {
1661
+ @image__ = @window__.canvas
1662
+ @painter__ = @window__.canvas_painter
1663
+ begin
1664
+ push
1665
+ @drawBlock__.call if @drawBlock__
1666
+ ensure
1667
+ pop
1668
+ @frameCount__ += 1
1669
+ end
1670
+ }
1671
+
1672
+ @window__.draw = proc do |e|
1673
+ if @loop__ || @redraw__
1674
+ @redraw__ = false
1675
+ drawFrame.call
1676
+ end
1677
+ @mousePrevPos__ = @mousePos__
1678
+ end
1679
+
1680
+ updatePointerStates = -> event, pressed = nil {
1681
+ @mousePos__ = event.pos
1682
+ @mousePressed__ = pressed if pressed != nil
1683
+ @touches__ = event.positions.map {|pos| Touch.new pos.x, pos.y}
1684
+ }
1685
+
1686
+ @window__.pointer_down = proc do |e|
1687
+ updatePointerStates.call e, true
1688
+ (@touchStartedBlock__ || @mousePressedBlock__)&.call
1689
+ end
1690
+
1691
+ @window__.pointer_up = proc do |e|
1692
+ updatePointerStates.call e, false
1693
+ (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
1694
+ end
1695
+
1696
+ @window__.pointer_move = proc do |e|
1697
+ updatePointerStates.call e
1698
+ (@touchMovedBlock__ || @mouseMovedBlock__)&.call
1699
+ end
1700
+
1701
+ @window__.pointer_drag = proc do |e|
1702
+ updatePointerStates.call e
1703
+ (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
1704
+ end
1705
+ end
1706
+
1707
+ # Define setup block.
1708
+ #
1709
+ def setup (&block)
1710
+ @window__.setup = block
1711
+ nil
1712
+ end
1713
+
1714
+ # Define draw block.
1715
+ #
1716
+ def draw (&block)
1717
+ @drawBlock__ = block if block
1718
+ nil
1719
+ end
1720
+
1721
+ def key (&block)
1722
+ @window__.key = block
1723
+ nil
1724
+ end
1725
+
1726
+ def mousePressed (&block)
1727
+ @mousePressedBlock__ = block if block
1728
+ @mousePressed__
1729
+ end
1730
+
1731
+ def mouseReleased (&block)
1732
+ @mouseReleasedBlock__ = block if block
1733
+ nil
1734
+ end
1735
+
1736
+ def mouseMoved (&block)
1737
+ @mouseMovedBlock__ = block if block
1738
+ nil
1739
+ end
1740
+
1741
+ def mouseDragged (&block)
1742
+ @mouseDraggedBlock__ = block if block
1743
+ nil
1744
+ end
1745
+
1746
+ def touchStarted (&block)
1747
+ @touchStartedBlock__ = block if block
1748
+ nil
1749
+ end
1750
+
1751
+ def touchEnded (&block)
1752
+ @touchEndedBlock__ = block if block
1753
+ nil
1754
+ end
1755
+
1756
+ def touchMoved (&block)
1757
+ @touchMovedBlock__ = block if block
1758
+ nil
1759
+ end
979
1760
 
980
1761
  # @private
981
- RAD2DEG__ = 180.0 / Math::PI
1762
+ private def size__ (width, height)
1763
+ raise 'size() must be called on startup or setup block' if @started__
982
1764
 
983
- # Converts degree to radian.
1765
+ @painter__.__send__ :end_paint
1766
+ @window__.__send__ :reset_canvas, width, height
1767
+ @painter__.__send__ :begin_paint
1768
+
1769
+ @auto_resize__ = false
1770
+ end
1771
+
1772
+ def windowWidth ()
1773
+ @window__.width
1774
+ end
1775
+
1776
+ def windowHeight ()
1777
+ @window__.height
1778
+ end
1779
+
1780
+ # Returns number of frames since program started.
984
1781
  #
985
- # @param degree [Numeric] degree to convert
1782
+ # @return [Integer] total number of frames
986
1783
  #
987
- # @return [Numeric] radian
1784
+ def frameCount ()
1785
+ @frameCount__
1786
+ end
1787
+
1788
+ # Returns number of frames per second.
988
1789
  #
989
- def radians (degree)
990
- degree * DEG2RAD__
1790
+ # @return [Float] frames per second
1791
+ #
1792
+ def frameRate ()
1793
+ @window__.event.fps
991
1794
  end
992
1795
 
993
- # Converts radian to degree.
1796
+ # Returns pixel density
994
1797
  #
995
- # @param radian [Numeric] radian to convert
1798
+ # @return [Numeric] pixel density
996
1799
  #
997
- # @return [Numeric] degree
1800
+ def displayDensity ()
1801
+ @painter__.pixel_density
1802
+ end
1803
+
1804
+ # Returns mouse x position
998
1805
  #
999
- def degrees (radian)
1000
- radian * RAD2DEG__
1806
+ # @return [Numeric] horizontal position of mouse
1807
+ #
1808
+ def mouseX ()
1809
+ @mousePos__.x
1810
+ end
1811
+
1812
+ # Returns mouse y position
1813
+ #
1814
+ # @return [Numeric] vertical position of mouse
1815
+ #
1816
+ def mouseY ()
1817
+ @mousePos__.y
1818
+ end
1819
+
1820
+ # Returns mouse x position in previous frame
1821
+ #
1822
+ # @return [Numeric] horizontal position of mouse
1823
+ #
1824
+ def pmouseX ()
1825
+ @mousePrevPos__.x
1001
1826
  end
1002
1827
 
1828
+ # Returns mouse y position in previous frame
1829
+ #
1830
+ # @return [Numeric] vertical position of mouse
1831
+ #
1832
+ def pmouseY ()
1833
+ @mousePrevPos__.y
1834
+ end
1835
+
1836
+ # Returns array of touches
1837
+ #
1838
+ # @return [Array] Touch objects
1839
+ #
1840
+ def touches ()
1841
+ @touches__
1842
+ end
1843
+
1844
+ # Enables calling draw block on every frame.
1845
+ #
1846
+ # @return [nil] nil
1847
+ #
1848
+ def loop ()
1849
+ @loop__ = true
1850
+ end
1851
+
1852
+ # Disables calling draw block on every frame.
1853
+ #
1854
+ # @return [nil] nil
1855
+ #
1856
+ def noLoop ()
1857
+ @loop__ = false
1858
+ end
1859
+
1860
+ # Calls draw block to redraw frame.
1861
+ #
1862
+ # @return [nil] nil
1863
+ #
1864
+ def redraw ()
1865
+ @redraw__ = true
1866
+ end
1867
+
1868
+ module_function
1869
+
1003
1870
  # Returns the absolute number of the value.
1004
1871
  #
1005
1872
  # @param value [Numeric] number
@@ -1193,278 +2060,186 @@ module RubySketch
1193
2060
  value < min ? min : (value > max ? max : value)
1194
2061
  end
1195
2062
 
1196
- # Returns the perlin noise value.
1197
- #
1198
- # @overload noise(x)
1199
- # @overload noise(x, y)
1200
- # @overload noise(x, y, z)
2063
+ # Converts degree to radian.
1201
2064
  #
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
2065
+ # @param degree [Numeric] degree to convert
1205
2066
  #
1206
- # @return [Numeric] noise value (0.0..1.0)
2067
+ # @return [Numeric] radian
1207
2068
  #
1208
- def noise (x, y = 0, z = 0)
1209
- Rays.perlin(x, y, z) / 2.0 + 0.5
2069
+ def radians (degree)
2070
+ degree * DEG2RAD__
1210
2071
  end
1211
2072
 
1212
- # Loads image.
2073
+ # Converts radian to degree.
1213
2074
  #
1214
- # @param filename [String] file name to load image
1215
- # @param extension [String] type of image to load (ex. 'png')
2075
+ # @param radian [Numeric] radian to convert
1216
2076
  #
1217
- # @return [Image] loaded image object
2077
+ # @return [Numeric] degree
1218
2078
  #
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
1240
- end
1241
- end
1242
- end
1243
- path.to_s
1244
- end
1245
-
1246
- def createGraphics (width, height)
1247
- Graphics.new width, height
1248
- end
1249
-
1250
- end# Utility
1251
-
1252
-
1253
- # Processing context
1254
- #
1255
- module Context
1256
-
1257
- include GraphicsContext, Utility, Math
1258
-
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
2079
+ def degrees (radian)
2080
+ radian * RAD2DEG__
1330
2081
  end
1331
2082
 
1332
- # Define setup block.
2083
+ # Returns the sine of an angle.
1333
2084
  #
1334
- def setup (&block)
1335
- @window__.setup = block
1336
- nil
1337
- end
1338
-
1339
- # Define draw block.
2085
+ # @param angle [Numeric] angle in radians
1340
2086
  #
1341
- def draw (&block)
1342
- @drawBlock__ = block if block
1343
- nil
1344
- end
1345
-
1346
- def key (&block)
1347
- @window__.key = block
1348
- nil
1349
- end
1350
-
1351
- def mousePressed (&block)
1352
- @mousePressedBlock__ = block if block
1353
- @mousePressed__
1354
- end
1355
-
1356
- def mouseReleased (&block)
1357
- @mouseReleasedBlock__ = block if block
1358
- nil
1359
- end
1360
-
1361
- def mouseMoved (&block)
1362
- @mouseMovedBlock__ = block if block
1363
- nil
1364
- end
1365
-
1366
- def mouseDragged (&block)
1367
- @mouseDraggedBlock__ = block if block
1368
- nil
1369
- end
1370
-
1371
- # @private
1372
- private def size__ (width, height)
1373
- raise 'size() must be called on startup or setup block' if @started__
1374
-
1375
- @painter__.__send__ :end_paint
1376
- @window__.__send__ :reset_canvas, width, height
1377
- @painter__.__send__ :begin_paint
1378
-
1379
- @auto_resize__ = false
1380
- end
1381
-
1382
- def windowWidth ()
1383
- @window__.width
2087
+ # @return [Numeric] the sine
2088
+ #
2089
+ def sin (angle)
2090
+ Math.sin angle
1384
2091
  end
1385
2092
 
1386
- def windowHeight ()
1387
- @window__.height
2093
+ # Returns the cosine of an angle.
2094
+ #
2095
+ # @param angle [Numeric] angle in radians
2096
+ #
2097
+ # @return [Numeric] the cosine
2098
+ #
2099
+ def cos (angle)
2100
+ Math.cos angle
1388
2101
  end
1389
2102
 
1390
- # Returns number of frames since program started.
2103
+ # Returns the ratio of the sine and cosine of an angle.
1391
2104
  #
1392
- # @return [Integer] total number of frames
2105
+ # @param angle [Numeric] angle in radians
1393
2106
  #
1394
- def frameCount ()
1395
- @frameCount__
2107
+ # @return [Numeric] the tangent
2108
+ #
2109
+ def tan (angle)
2110
+ Math.tan angle
1396
2111
  end
1397
2112
 
1398
- # Returns number of frames per second.
2113
+ # Returns the inverse of sin().
1399
2114
  #
1400
- # @return [Float] frames per second
2115
+ # @param value [Numeric] value for calculation
1401
2116
  #
1402
- def frameRate ()
1403
- @window__.event.fps
2117
+ # @return [Numeric] the arc sine
2118
+ #
2119
+ def asin (value)
2120
+ Math.asin value
1404
2121
  end
1405
2122
 
1406
- # Returns pixel density
2123
+ # Returns the inverse of cos().
1407
2124
  #
1408
- # @return [Numeric] pixel density
2125
+ # @param value [Numeric] value for calculation
1409
2126
  #
1410
- def displayDensity ()
1411
- @painter__.pixel_density
2127
+ # @return [Numeric] the arc cosine
2128
+ #
2129
+ def acos (value)
2130
+ Math.acos value
1412
2131
  end
1413
2132
 
1414
- # Returns mouse x position
2133
+ # Returns the inverse of tan().
1415
2134
  #
1416
- # @return [Numeric] horizontal position of mouse
2135
+ # @param value [Numeric] value for valculation
1417
2136
  #
1418
- def mouseX ()
1419
- @mouseX__
2137
+ # @return [Numeric] the arc tangent
2138
+ #
2139
+ def atan (value)
2140
+ Math.atan value
1420
2141
  end
1421
2142
 
1422
- # Returns mouse y position
2143
+ # Returns the angle from a specified point.
1423
2144
  #
1424
- # @return [Numeric] vertical position of mouse
2145
+ # @param y [Numeric] y of the point
2146
+ # @param x [Numeric] x of the point
1425
2147
  #
1426
- def mouseY ()
1427
- @mouseY__
2148
+ # @return [Numeric] the angle in radians
2149
+ #
2150
+ def atan2 (y, x)
2151
+ Math.atan2 y, x
1428
2152
  end
1429
2153
 
1430
- # Returns mouse x position in previous frame
2154
+ # Returns the perlin noise value.
1431
2155
  #
1432
- # @return [Numeric] horizontal position of mouse
2156
+ # @overload noise(x)
2157
+ # @overload noise(x, y)
2158
+ # @overload noise(x, y, z)
1433
2159
  #
1434
- def pmouseX ()
1435
- @mousePrevX__
2160
+ # @param x [Numeric] horizontal point in noise space
2161
+ # @param y [Numeric] vertical point in noise space
2162
+ # @param z [Numeric] depth point in noise space
2163
+ #
2164
+ # @return [Numeric] noise value (0.0..1.0)
2165
+ #
2166
+ def noise (x, y = 0, z = 0)
2167
+ Rays.perlin(x, y, z) / 2.0 + 0.5
1436
2168
  end
1437
2169
 
1438
- # Returns mouse y position in previous frame
2170
+ # Returns a random number in range low...high
1439
2171
  #
1440
- # @return [Numeric] vertical position of mouse
2172
+ # @overload random(high)
2173
+ # @overload random(low, high)
1441
2174
  #
1442
- def pmouseY ()
1443
- @mousePrevY__
2175
+ # @param low [Numeric] lower limit
2176
+ # @param high [Numeric] upper limit
2177
+ #
2178
+ # @return [Float] random number
2179
+ #
2180
+ def random (low = nil, high)
2181
+ rand (low || 0).to_f...high.to_f
1444
2182
  end
1445
2183
 
1446
- # Enables calling draw block on every frame.
2184
+ # Creates a new vector.
1447
2185
  #
1448
- # @return [nil] nil
2186
+ # @overload createVector()
2187
+ # @overload createVector(x, y)
2188
+ # @overload createVector(x, y, z)
1449
2189
  #
1450
- def loop ()
1451
- @loop__ = true
2190
+ # @param x [Numeric] x of new vector
2191
+ # @param y [Numeric] y of new vector
2192
+ # @param z [Numeric] z of new vector
2193
+ #
2194
+ # @return [Vector] new vector
2195
+ #
2196
+ def createVector (*args)
2197
+ Vector.new *args
1452
2198
  end
1453
2199
 
1454
- # Disables calling draw block on every frame.
2200
+ # Creates a new off-screen graphics context object.
1455
2201
  #
1456
- # @return [nil] nil
2202
+ # @param width [Numeric] width of graphics image
2203
+ # @param height [Numeric] height of graphics image
1457
2204
  #
1458
- def noLoop ()
1459
- @loop__ = false
2205
+ # @return [Graphics] graphics object
2206
+ #
2207
+ def createGraphics (width, height)
2208
+ Graphics.new width, height
1460
2209
  end
1461
2210
 
1462
- # Calls draw block to redraw frame.
2211
+ # Loads image.
1463
2212
  #
1464
- # @return [nil] nil
2213
+ # @param filename [String] file name to load image
2214
+ # @param extension [String] type of image to load (ex. 'png')
1465
2215
  #
1466
- def redraw ()
1467
- @redraw__ = true
2216
+ # @return [Image] loaded image object
2217
+ #
2218
+ def loadImage (filename, extension = nil)
2219
+ filename = getImage__ filename, extension if filename =~ %r|^https?://|
2220
+ Image.new Rays::Image.load filename
2221
+ end
2222
+
2223
+ # @private
2224
+ private def getImage__ (uri, ext)
2225
+ ext ||= File.extname uri
2226
+ raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
2227
+
2228
+ tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
2229
+ path = tmpdir + Digest::SHA1.hexdigest(uri)
2230
+ path = path.sub_ext ext
2231
+
2232
+ unless path.file?
2233
+ URI.open uri do |input|
2234
+ tmpdir.mkdir unless tmpdir.directory?
2235
+ path.open('w') do |output|
2236
+ while buf = input.read(2 ** 16)
2237
+ output.write buf
2238
+ end
2239
+ end
2240
+ end
2241
+ end
2242
+ path.to_s
1468
2243
  end
1469
2244
 
1470
2245
  end# Context