rubysketch 0.3.21 → 0.5.1

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.
@@ -1,2910 +0,0 @@
1
- module RubySketch
2
-
3
-
4
- # Processing compatible API
5
- #
6
- module Processing
7
-
8
-
9
- # @private
10
- DEG2RAD__ = Math::PI / 180.0
11
-
12
- # @private
13
- RAD2DEG__ = 180.0 / Math::PI
14
-
15
-
16
- # Vector class.
17
- #
18
- class Vector
19
-
20
- include Comparable
21
-
22
- # Initialize vector object.
23
- #
24
- # @overload new()
25
- # @overload new(x)
26
- # @overload new(x, y)
27
- # @overload new(x, y, z)
28
- # @overload new(v)
29
- # @overload new(a)
30
- #
31
- # @param x [Numeric] x of vector
32
- # @param y [Numeric] y of vector
33
- # @param z [Numeric] z of vector
34
- # @param v [Vector] vector object to copy
35
- # @param a [Array] array like [x, y, z]
36
- #
37
- def initialize(x = 0, y = 0, z = 0, context: nil)
38
- @point = case x
39
- when Rays::Point then x.dup
40
- when Vector then x.getInternal__.dup
41
- when Array then Rays::Point.new x[0] || 0, x[1] || 0, x[2] || 0
42
- else Rays::Point.new x || 0, y || 0, z || 0
43
- end
44
- @context = context || Context.context__
45
- end
46
-
47
- # Initializer for dup or clone
48
- #
49
- def initialize_copy(o)
50
- @point = o.getInternal__.dup
51
- end
52
-
53
- # Copy vector object
54
- #
55
- # @return [Vector] duplicated vector object
56
- #
57
- alias copy dup
58
-
59
- # Sets x, y and z.
60
- #
61
- # @overload set(x)
62
- # @overload set(x, y)
63
- # @overload set(x, y, z)
64
- # @overload set(v)
65
- # @overload set(a)
66
- #
67
- # @param x [Numeric] x of vector
68
- # @param y [Numeric] y of vector
69
- # @param z [Numeric] z of vector
70
- # @param v [Vector] vector object to copy
71
- # @param a [Array] array with x, y, z
72
- #
73
- # @return [nil] nil
74
- #
75
- def set(*args)
76
- initialize(*args)
77
- self
78
- end
79
-
80
- # Gets x value.
81
- #
82
- # @return [Numeric] x value of vector
83
- #
84
- def x()
85
- @point.x
86
- end
87
-
88
- # Gets y value.
89
- #
90
- # @return [Numeric] y value of vector
91
- #
92
- def y()
93
- @point.y
94
- end
95
-
96
- # Gets z value.
97
- #
98
- # @return [Numeric] z value of vector
99
- #
100
- def z()
101
- @point.z
102
- end
103
-
104
- # Sets x value.
105
- #
106
- # @return [Numeric] x value of vector
107
- #
108
- def x=(x)
109
- @point.x = x
110
- end
111
-
112
- # Sets y value.
113
- #
114
- # @return [Numeric] y value of vector
115
- #
116
- def y=(y)
117
- @point.y = y
118
- end
119
-
120
- # Sets z value.
121
- #
122
- # @return [Numeric] z value of vector
123
- #
124
- def z=(z)
125
- @point.z = z
126
- end
127
-
128
- # Returns the interpolated vector between 2 vectors.
129
- #
130
- # @overload lerp(v, amount)
131
- # @overload lerp(x, y, amount)
132
- # @overload lerp(x, y, z, amount)
133
- #
134
- # @param v [Vector] vector to interpolate
135
- # @param x [Numeric] x of vector to interpolate
136
- # @param y [Numeric] y of vector to interpolate
137
- # @param z [Numeric] z of vector to interpolate
138
- # @param amount [Numeric] amount to interpolate
139
- #
140
- # @return [Vector] interporated vector
141
- #
142
- def lerp(*args, amount)
143
- v = toVector__(*args)
144
- self.x = x + (v.x - x) * amount
145
- self.y = y + (v.y - y) * amount
146
- self.z = z + (v.z - z) * amount
147
- self
148
- end
149
-
150
- # Returns the interpolated vector between 2 vectors.
151
- #
152
- # @param v1 [Vector] vector to interpolate
153
- # @param v2 [Vector] vector to interpolate
154
- # @param amount [Numeric] amount to interpolate
155
- #
156
- # @return [Vector] interporated vector
157
- #
158
- def self.lerp(v1, v2, amount)
159
- v1.dup.lerp v2, amount
160
- end
161
-
162
- # Returns x, y, z as an array
163
- #
164
- # @return [Array] array of x, y, z
165
- #
166
- def array()
167
- @point.to_a 3
168
- end
169
-
170
- # Adds a vector.
171
- #
172
- # @overload add(v)
173
- # @overload add(x, y)
174
- # @overload add(x, y, z)
175
- #
176
- # @param v [Vector] vector to add
177
- # @param x [Vector] x of vector to add
178
- # @param y [Vector] y of vector to add
179
- # @param z [Vector] z of vector to add
180
- #
181
- # @return [Vector] added vector
182
- #
183
- def add(*args)
184
- @point += toVector__(*args).getInternal__
185
- self
186
- end
187
-
188
- # Subtracts a vector.
189
- #
190
- # @overload sub(v)
191
- # @overload sub(x, y)
192
- # @overload sub(x, y, z)
193
- #
194
- # @param v [Vector] vector to subtract
195
- # @param x [Vector] x of vector to subtract
196
- # @param y [Vector] y of vector to subtract
197
- # @param z [Vector] z of vector to subtract
198
- #
199
- # @return [Vector] subtracted vector
200
- #
201
- def sub(*args)
202
- @point -= toVector__(*args).getInternal__
203
- self
204
- end
205
-
206
- # Multiplies a vector by scalar.
207
- #
208
- # @param num [Numeric] number to multiply the vector
209
- #
210
- # @return [Vector] multiplied vector
211
- #
212
- def mult(num)
213
- @point *= num
214
- self
215
- end
216
-
217
- # Divides a vector by scalar.
218
- #
219
- # @param num [Numeric] number to divide the vector
220
- #
221
- # @return [Vector] divided vector
222
- #
223
- def div(num)
224
- @point /= num
225
- self
226
- end
227
-
228
- # Adds a vector.
229
- #
230
- # @param v [Vector] vector to add
231
- #
232
- # @return [Vector] added vector
233
- #
234
- def +(v)
235
- dup.add v
236
- end
237
-
238
- # Subtracts a vector.
239
- #
240
- # @param v [Vector] vector to subtract
241
- #
242
- # @return [Vector] subtracted vector
243
- #
244
- def -(v)
245
- dup.sub v
246
- end
247
-
248
- # Multiplies a vector by scalar.
249
- #
250
- # @param num [Numeric] number to multiply the vector
251
- #
252
- # @return [Vector] multiplied vector
253
- #
254
- def *(num)
255
- dup.mult num
256
- end
257
-
258
- # Divides a vector by scalar.
259
- #
260
- # @param num [Numeric] number to divide the vector
261
- #
262
- # @return [Vector] divided vector
263
- #
264
- def /(num)
265
- dup.div num
266
- end
267
-
268
- # Adds 2 vectors.
269
- #
270
- # @overload add(v1, v2)
271
- # @overload add(v1, v2, target)
272
- #
273
- # @param v1 [Vector] a vector
274
- # @param v2 [Vector] another vector
275
- # @param target [Vector] vector to store added vector
276
- #
277
- # @return [Vector] added vector
278
- #
279
- def self.add(v1, v2, target = nil)
280
- v = v1 + v2
281
- target.set v if self === target
282
- v
283
- end
284
-
285
- # Subtracts 2 vectors.
286
- #
287
- # @overload sub(v1, v2)
288
- # @overload sub(v1, v2, target)
289
- #
290
- # @param v1 [Vector] a vector
291
- # @param v2 [Vector] another vector
292
- # @param target [Vector] vector to store subtracted vector
293
- #
294
- # @return [Vector] subtracted vector
295
- #
296
- def self.sub(v1, v2, target = nil)
297
- v = v1 - v2
298
- target.set v if self === target
299
- v
300
- end
301
-
302
- # Multiplies a vector by scalar.
303
- #
304
- # @overload mult(v, num)
305
- # @overload mult(v, num, target)
306
- #
307
- # @param v [Vector] a vector
308
- # @param num [Numeric] number to multiply the vector
309
- # @param target [Vector] vector to store multiplied vector
310
- #
311
- # @return [Vector] multiplied vector
312
- #
313
- def self.mult(v1, num, target = nil)
314
- v = v1 * num
315
- target.set v if self === target
316
- v
317
- end
318
-
319
- # Divides a vector by scalar.
320
- #
321
- # @overload div(v, num)
322
- # @overload div(v, num, target)
323
- #
324
- # @param v [Vector] a vector
325
- # @param num [Numeric] number to divide the vector
326
- # @param target [Vector] vector to store divided vector
327
- #
328
- # @return [Vector] divided vector
329
- #
330
- def self.div(v1, num, target = nil)
331
- v = v1 / num
332
- target.set v if self === target
333
- v
334
- end
335
-
336
- # Returns the length of the vector.
337
- #
338
- # @return [Numeric] length
339
- #
340
- def mag()
341
- @point.length
342
- end
343
-
344
- # Returns squared length of the vector.
345
- #
346
- # @return [Numeric] squared length
347
- #
348
- def magSq()
349
- Rays::Point::dot(@point, @point)
350
- end
351
-
352
- # Changes the length of the vector.
353
- #
354
- # @overload setMag(len)
355
- # @overload setMag(target, len)
356
- #
357
- # @param len [Numeric] length of new vector
358
- # @param target [Vector] vector to store new vector
359
- #
360
- # @return [Vector] vector with new length
361
- #
362
- def setMag(target = nil, len)
363
- (target || self).set @point.normal * len
364
- end
365
-
366
- # Changes the length of the vector to 1.0.
367
- #
368
- # @param target [Vector] vector to store the normalized vector
369
- #
370
- # @return [Vector] normalized vector
371
- #
372
- def normalize(target = nil)
373
- (target || self).set @point.normal
374
- end
375
-
376
- # Changes the length of the vector if it's length is greater than the max value.
377
- #
378
- # @param max [Numeric] max length
379
- #
380
- # @return [Vector] new vector
381
- #
382
- def limit(max)
383
- setMag max if magSq > max ** 2
384
- self
385
- end
386
-
387
- # Returns the distance of 2 vectors.
388
- #
389
- # @param v [Vector] a vector
390
- #
391
- # @return [Numeric] the distance
392
- #
393
- def dist(v)
394
- (self - v).mag
395
- end
396
-
397
- # Returns the distance of 2 vectors.
398
- #
399
- # @param v1 [Vector] a vector
400
- # @param v2 [Vector] another vector
401
- #
402
- # @return [Numeric] the distance
403
- #
404
- def self.dist(v1, v2)
405
- v1.dist v2
406
- end
407
-
408
- # Calculates the dot product of 2 vectors.
409
- #
410
- # @overload dot(v)
411
- # @overload dot(x, y)
412
- # @overload dot(x, y, z)
413
- #
414
- # @param v [Vector] a vector
415
- # @param x [Numeric] x of vector
416
- # @param y [Numeric] y of vector
417
- # @param z [Numeric] z of vector
418
- #
419
- # @return [Numeric] result of dot product
420
- #
421
- def dot(*args)
422
- Rays::Point::dot getInternal__, toVector__(*args).getInternal__
423
- end
424
-
425
- # Calculates the dot product of 2 vectors.
426
- #
427
- # @param v1 [Vector] a vector
428
- # @param v2 [Vector] another vector
429
- #
430
- # @return [Numeric] result of dot product
431
- #
432
- def self.dot(v1, v2)
433
- v1.dot v2
434
- end
435
-
436
- # Calculates the cross product of 2 vectors.
437
- #
438
- # @overload cross(v)
439
- # @overload cross(x, y)
440
- # @overload cross(x, y, z)
441
- #
442
- # @param v [Vector] a vector
443
- # @param x [Numeric] x of vector
444
- # @param y [Numeric] y of vector
445
- # @param z [Numeric] z of vector
446
- #
447
- # @return [Numeric] result of cross product
448
- #
449
- def cross(a, *rest)
450
- target = self.class === rest.last ? rest.pop : nil
451
- v = self.class.new Rays::Point::cross getInternal__, toVector__(a, *rest).getInternal__
452
- target.set v if self.class === target
453
- v
454
- end
455
-
456
- # Calculates the cross product of 2 vectors.
457
- #
458
- # @param v1 [Vector] a vector
459
- # @param v2 [Vector] another vector
460
- #
461
- # @return [Numeric] result of cross product
462
- #
463
- def self.cross(v1, v2, target = nil)
464
- v1.cross v2, target
465
- end
466
-
467
- # Rotate the vector.
468
- #
469
- # @param angle [Numeric] the angle of rotation
470
- #
471
- # @return [Vector] rotated this object
472
- #
473
- def rotate(angle)
474
- angle = @context ? @context.toAngle__(angle) : angle * RAD2DEG__
475
- @point.rotate! angle
476
- self
477
- end
478
-
479
- # Returns the angle of rotation for this vector.
480
- #
481
- # @return [Numeric] the angle in radians
482
- #
483
- def heading()
484
- Math.atan2 y, x
485
- end
486
-
487
- # Returns rotated new vector.
488
- #
489
- # @param angle [Numeric] the angle of rotation
490
- # @param target [Vector] vector to store new vector
491
- #
492
- # @return [Vector] rotated vector
493
- #
494
- def self.fromAngle(angle, target = nil)
495
- v = self.new(1, 0, 0).rotate(angle)
496
- target.set v if target
497
- v
498
- end
499
-
500
- # Returns angle between 2 vectors.
501
- #
502
- # @param v1 [Vector] a vector
503
- # @param v2 [Vector] another vector
504
- #
505
- # @return [Numeric] angle in radians
506
- #
507
- def self.angleBetween(v1, v2)
508
- x1, y1, z1 = v1.array
509
- x2, y2, z2 = v2.array
510
- return 0 if (x1 == 0 && y1 == 0 && z1 == 0) || (x2 == 0 && y2 == 0 && z2 == 0)
511
-
512
- x = dot(v1, v2) / (v1.mag * v2.mag)
513
- return Math::PI if x <= -1
514
- return 0 if x >= 1
515
- return Math.acos x
516
- end
517
-
518
- # Returns a new 2D unit vector with a random direction.
519
- #
520
- # @param target [Vector] a vector to store the new vector
521
- #
522
- # @return [Vector] a random vector
523
- #
524
- def self.random2D(target = nil)
525
- v = self.fromAngle rand 0.0...(Math::PI * 2)
526
- target.set v if target
527
- v
528
- end
529
-
530
- # Returns a new 3D unit vector with a random direction.
531
- #
532
- # @param target [Vector] a vector to store the new vector
533
- #
534
- # @return [Vector] a random vector
535
- #
536
- def self.random3D(target = nil)
537
- angle = rand 0.0...(Math::PI * 2)
538
- z = rand(-1.0..1.0)
539
- z2 = z ** 2
540
- x = Math.sqrt(1.0 - z2) * Math.cos(angle)
541
- y = Math.sqrt(1.0 - z2) * Math.sin(angle)
542
- v = self.new x, y, z
543
- target.set v if target
544
- v
545
- end
546
-
547
- # @private
548
- def inspect()
549
- "<##{self.class.name} #{x}, #{y}, #{z}>"
550
- end
551
-
552
- # @private
553
- def <=>(o)
554
- @point <=> o.getInternal__
555
- end
556
-
557
- # @private
558
- protected def getInternal__()
559
- @point
560
- end
561
-
562
- # @private
563
- private def toVector__(*args)
564
- self.class === args.first ? args.first : self.class.new(*args)
565
- end
566
-
567
- end# Vector
568
-
569
-
570
- # Image object.
571
- #
572
- class Image
573
-
574
- # @private
575
- def initialize(image)
576
- @image = image
577
- end
578
-
579
- # Gets width of image.
580
- #
581
- # @return [Numeric] width of image
582
- #
583
- def width()
584
- @image.width
585
- end
586
-
587
- # Gets height of image.
588
- #
589
- # @return [Numeric] height of image
590
- #
591
- def height()
592
- @image.height
593
- end
594
-
595
- # Resizes image.
596
- #
597
- # @param width [Numeric] width for resized image
598
- # @param height [Numeric] height for resized image
599
- #
600
- # @return [nil] nil
601
- #
602
- def resize(width, height)
603
- @image = Rays::Image.new(width, height).paint do |painter|
604
- painter.image @image, 0, 0, width, height
605
- end
606
- nil
607
- end
608
-
609
- # Copies image.
610
- #
611
- # @overload copy(sx, sy, sw, sh, dx, dy, dw, dh)
612
- # @overload copy(img, sx, sy, sw, sh, dx, dy, dw, dh)
613
- #
614
- # @param img [Image] image for copy source
615
- # @param sx [Numrtic] x position of source region
616
- # @param sy [Numrtic] y position of source region
617
- # @param sw [Numrtic] width of source region
618
- # @param sh [Numrtic] height of source region
619
- # @param dx [Numrtic] x position of destination region
620
- # @param dy [Numrtic] y position of destination region
621
- # @param dw [Numrtic] width of destination region
622
- # @param dh [Numrtic] height of destination region
623
- #
624
- # @return [nil] nil
625
- #
626
- def copy(img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
627
- blend img, sx, sy, sw, sh, dx, dy, dw, dh, :normal
628
- end
629
-
630
- # Blends image.
631
- #
632
- # @overload blend(sx, sy, sw, sh, dx, dy, dw, dh, mode)
633
- # @overload blend(img, sx, sy, sw, sh, dx, dy, dw, dh, mode)
634
- #
635
- # @param img [Image] image for blend source
636
- # @param sx [Numrtic] x position of source region
637
- # @param sy [Numrtic] y position of source region
638
- # @param sw [Numrtic] width of source region
639
- # @param sh [Numrtic] height of source region
640
- # @param dx [Numrtic] x position of destination region
641
- # @param dy [Numrtic] y position of destination region
642
- # @param dw [Numrtic] width of destination region
643
- # @param dh [Numrtic] height of destination region
644
- # @param mode [BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, EXCLUSION, MULTIPLY, SCREEN, REPLACE] blend mode
645
- #
646
- # @return [nil] nil
647
- #
648
- def blend(img = nil, sx, sy, sw, sh, dx, dy, dw, dh, mode)
649
- img ||= self
650
- @image.paint do |painter|
651
- current = painter.blend_mode
652
- painter.blend_mode = mode
653
- painter.image img.getInternal__, sx, sy, sw, sh, dx, dy, dw, dh
654
- painter.blend_mode = current
655
- end
656
- end
657
-
658
- # Saves image to file.
659
- #
660
- # @param filename [String] file name to save image
661
- #
662
- def save(filename)
663
- @image.save filename
664
- end
665
-
666
- # @private
667
- def getInternal__()
668
- @image
669
- end
670
-
671
- end# Image
672
-
673
-
674
- # Font object.
675
- #
676
- class Font
677
-
678
- # @private
679
- def initialize(font)
680
- @font = font
681
- end
682
-
683
- # Returns bounding box.
684
- #
685
- # @overload textBounds(str)
686
- # @overload textBounds(str, x, y)
687
- # @overload textBounds(str, x, y, fontSize)
688
- #
689
- # @param str [String] text to calculate bounding box
690
- # @param x [Numeric] horizontal position of bounding box
691
- # @param y [Numeric] vertical position of bounding box
692
- # @param fontSize [Numeric] font size
693
- #
694
- # @return [TextBounds] bounding box for text
695
- #
696
- def textBounds(str, x = 0, y = 0, fontSize = nil)
697
- f = fontSize ? Rays::Font.new(@font.name, fontSize) : @font
698
- TextBounds.new x, y, x + f.width(str), y + f.height
699
- end
700
-
701
- end# Font
702
-
703
-
704
- # Bounding box for text.
705
- #
706
- class TextBounds
707
-
708
- # Horizontal position
709
- #
710
- attr_reader :x
711
-
712
- # Vertical position
713
- #
714
- attr_reader :y
715
-
716
- # Width of bounding box
717
- #
718
- attr_reader :w
719
-
720
- # Height of bounding box
721
- #
722
- attr_reader :h
723
-
724
- # @private
725
- def initialize(x, y, w, h)
726
- @x, @y, @w, @h = x, y, w, h
727
- end
728
-
729
- end# TextBounds
730
-
731
-
732
- # Touch object.
733
- #
734
- class Touch
735
-
736
- # Identifier of each touch
737
- #
738
- attr_reader :id
739
-
740
- # Horizontal position of touch
741
- #
742
- attr_reader :x
743
-
744
- # Vertical position of touch
745
- #
746
- attr_reader :y
747
-
748
- # @private
749
- def initialize(id, x, y)
750
- @id, @x, @y = id, x, y
751
- end
752
-
753
- end# Touch
754
-
755
-
756
- # Camera object.
757
- #
758
- class Capture
759
-
760
- # Returns a list of available camera device names
761
- #
762
- # @return [Array] device name list
763
- #
764
- def self.list()
765
- Rays::Camera.device_names
766
- end
767
-
768
- # Initialize camera object.
769
- #
770
- # @overload Capture.new()
771
- # @overload Capture.new(cameraName)
772
- # @overload Capture.new(requestWidth, requestHeight)
773
- # @overload Capture.new(requestWidth, requestHeight, cameraName)
774
- #
775
- # @param requestWidth [Integer] captured image width
776
- # @param requestHeight [Integer] captured image height
777
- # @param cameraName [String] camera device name
778
- #
779
- def initialize(*args)
780
- width, height, name =
781
- if args.empty?
782
- [-1, -1, nil]
783
- elsif args[0].kind_of?(String)
784
- [-1, -1, args[0]]
785
- elsif args[0].kind_of?(Numeric) && args[1].kind_of?(Numeric)
786
- [args[0], args[1], args[2]]
787
- else
788
- raise ArgumentError
789
- end
790
- @camera = Rays::Camera.new width, height, device_name: name
791
- end
792
-
793
- # Start capturing.
794
- #
795
- # @return [nil] nil
796
- #
797
- def start()
798
- raise "Failed to start capture" unless @camera.start
799
- nil
800
- end
801
-
802
- # Stop capturing.
803
- #
804
- # @return [nil] nil
805
- #
806
- def stop()
807
- @camera.stop
808
- nil
809
- end
810
-
811
- # Returns is the next captured image available?
812
- #
813
- # @return [Boolean] true means object has next frame
814
- #
815
- def available()
816
- @camera.active?
817
- end
818
-
819
- # Reads next frame image
820
- #
821
- def read()
822
- @camera.image
823
- end
824
-
825
- # Returns the width of captured image
826
- #
827
- # @return [Numeric] the width of captured image
828
- #
829
- def width()
830
- @camera.image&.width || 0
831
- end
832
-
833
- # Returns the height of captured image
834
- #
835
- # @return [Numeric] the height of captured image
836
- #
837
- def height()
838
- @camera.image&.height || 0
839
- end
840
-
841
- # @private
842
- def getInternal__()
843
- @camera.image || dummyImage__
844
- end
845
-
846
- # @private
847
- private def dummyImage__()
848
- @dummy ||= Rays::Image.new 1, 1
849
- end
850
-
851
- end# Capture
852
-
853
-
854
- # Drawing context
855
- #
856
- module GraphicsContext
857
-
858
- # PI
859
- #
860
- PI = Math::PI
861
-
862
- # PI / 2
863
- #
864
- HALF_PI = PI / 2
865
-
866
- # PI / 4
867
- #
868
- QUARTER_PI = PI / 4
869
-
870
- # PI * 2
871
- #
872
- TWO_PI = PI * 2
873
-
874
- # PI * 2
875
- #
876
- TAU = PI * 2
877
-
878
- # RGBA format for createImage().
879
- #
880
- RGBA = :rgba
881
-
882
- # RGB format for createImage, or RGB mode for colorMode().
883
- #
884
- RGB = :rgb
885
-
886
- # HSB mode for colorMode().
887
- #
888
- HSB = :hsb
889
-
890
- # Radian mode for angleMode().
891
- #
892
- RADIANS = :radians
893
-
894
- # Degree mode for angleMode().
895
- #
896
- DEGREES = :degrees
897
-
898
- # Mode for rectMode(), ellipseMode() and imageMode().
899
- #
900
- CORNER = :corner
901
-
902
- # Mode for rectMode(), ellipseMode() and imageMode().
903
- #
904
- CORNERS = :corners
905
-
906
- # Mode for rectMode(), ellipseMode(), imageMode() and textAlign().
907
- #
908
- CENTER = :center
909
-
910
- # Mode for rectMode() and ellipseMode().
911
- #
912
- RADIUS = :radius
913
-
914
- # Mode for strokeCap().
915
- #
916
- BUTT = :butt
917
-
918
- # Mode for strokeJoin().
919
- #
920
- MITER = :miter
921
-
922
- # Mode for strokeCap() and strokeJoin().
923
- #
924
- ROUND = :round
925
-
926
- # Mode for strokeCap() and strokeJoin().
927
- #
928
- SQUARE = :square
929
-
930
- # Mode for blendMode().
931
- #
932
- BLEND = :normal
933
-
934
- # Mode for blendMode().
935
- #
936
- ADD = :add
937
-
938
- # Mode for blendMode().
939
- #
940
- SUBTRACT = :subtract
941
-
942
- # Mode for blendMode().
943
- #
944
- LIGHTEST = :lightest
945
-
946
- # Mode for blendMode().
947
- #
948
- DARKEST = :darkest
949
-
950
- # Mode for blendMode().
951
- #
952
- EXCLUSION = :exclusion
953
-
954
- # Mode for blendMode().
955
- #
956
- MULTIPLY = :multiply
957
-
958
- # Mode for blendMode().
959
- #
960
- SCREEN = :screen
961
-
962
- # Mode for blendMode().
963
- #
964
- REPLACE = :replace
965
-
966
- # Key code or Mode for textAlign().
967
- LEFT = :left
968
-
969
- # Key code or Mode for textAlign().
970
- RIGHT = :right
971
-
972
- # Mode for textAlign().
973
- TOP = :top
974
-
975
- # Mode for textAlign().
976
- BOTTOM = :bottom
977
-
978
- # Mode for textAlign().
979
- BASELINE = :baseline
980
-
981
- # Key codes.
982
- ENTER = :enter
983
- SPACE = :space
984
- TAB = :tab
985
- DELETE = :delete
986
- BACKSPACE = :backspace
987
- ESC = :escape
988
- HOME = :home
989
- #END = :end
990
- PAGEUP = :pageup
991
- PAGEDOWN = :pagedown
992
- CLEAR = :clear
993
- SHIFT = :shift
994
- CONTROL = :control
995
- ALT = :alt
996
- WIN = :win
997
- COMMAND = :command
998
- OPTION = :option
999
- FUNCTION = :function
1000
- CAPSLOCK = :capslock
1001
- SECTION = :section
1002
- HELP = :help
1003
- F1 = :f1
1004
- F2 = :f2
1005
- F3 = :f3
1006
- F4 = :f4
1007
- F5 = :f5
1008
- F6 = :f6
1009
- F7 = :f7
1010
- F8 = :f8
1011
- F9 = :f9
1012
- F10 = :f10
1013
- F11 = :f11
1014
- F12 = :f12
1015
- F13 = :f13
1016
- F14 = :f14
1017
- F15 = :f15
1018
- F16 = :f16
1019
- F17 = :f17
1020
- F18 = :f18
1021
- F19 = :f19
1022
- F20 = :f20
1023
- F21 = :f21
1024
- F22 = :f22
1025
- F23 = :f23
1026
- F24 = :f24
1027
- UP = :up
1028
- DOWN = :down
1029
-
1030
- # @private
1031
- def init__(image, painter)
1032
- @drawing__ = false
1033
- @hsbColor__ = false
1034
- @colorMaxes__ = [1.0] * 4
1035
- @angleScale__ = 1.0
1036
- @rectMode__ = nil
1037
- @ellipseMode__ = nil
1038
- @imageMode__ = nil
1039
- @tint__ = nil
1040
- @textAlignH__ = nil
1041
- @textAlignV__ = nil
1042
- @matrixStack__ = []
1043
- @styleStack__ = []
1044
- @fontCache__ = {}
1045
-
1046
- updateCanvas__ image, painter
1047
-
1048
- colorMode RGB, 255
1049
- angleMode RADIANS
1050
- rectMode CORNER
1051
- ellipseMode CENTER
1052
- imageMode CORNER
1053
- blendMode BLEND
1054
- strokeCap ROUND
1055
- strokeJoin MITER
1056
- textAlign LEFT
1057
-
1058
- fill 255
1059
- stroke 0
1060
- strokeWeight 1
1061
- noTint
1062
- end
1063
-
1064
- # @private
1065
- def updateCanvas__(image, painter)
1066
- @image__, @painter__ = image, painter
1067
- end
1068
-
1069
- # @private
1070
- def beginDraw__()
1071
- @matrixStack__.clear
1072
- @styleStack__.clear
1073
- @drawing__ = true
1074
- end
1075
-
1076
- # @private
1077
- def endDraw__()
1078
- @drawing__ = false
1079
- end
1080
-
1081
- def width()
1082
- @image__.width
1083
- end
1084
-
1085
- def height()
1086
- @image__.height
1087
- end
1088
-
1089
- # Sets color mode and max color values.
1090
- #
1091
- # @overload colorMode(mode)
1092
- # @overload colorMode(mode, max)
1093
- # @overload colorMode(mode, max1, max2, max3)
1094
- # @overload colorMode(mode, max1, max2, max3, maxA)
1095
- #
1096
- # @param mode [RGB, HSB] RGB or HSB
1097
- # @param max [Numeric] max values for all color values
1098
- # @param max1 [Numeric] max value for red or hue
1099
- # @param max2 [Numeric] max value for green or saturation
1100
- # @param max3 [Numeric] max value for blue or brightness
1101
- # @param maxA [Numeric] max value for alpha
1102
- #
1103
- # @return [nil] nil
1104
- #
1105
- def colorMode(mode, *maxes)
1106
- mode = mode.downcase.to_sym
1107
- raise ArgumentError, "invalid color mode: #{mode}" unless [RGB, HSB].include?(mode)
1108
- raise ArgumentError unless [0, 1, 3, 4].include?(maxes.size)
1109
-
1110
- @hsbColor__ = mode == HSB
1111
- case maxes.size
1112
- when 1 then @colorMaxes__ = [maxes.first.to_f] * 4
1113
- when 3, 4 then @colorMaxes__[0...maxes.size] = maxes.map &:to_f
1114
- end
1115
- nil
1116
- end
1117
-
1118
- # @private
1119
- private def toRGBA__(*args)
1120
- a, b, c, d = args
1121
- return parseColor__(a, b || alphaMax__) if a.kind_of?(String)
1122
-
1123
- rgba = case args.size
1124
- when 1, 2 then [a, a, a, b || alphaMax__]
1125
- when 3, 4 then [a, b, c, d || alphaMax__]
1126
- else raise ArgumentError
1127
- end
1128
- rgba = rgba.map.with_index {|value, i| value / @colorMaxes__[i]}
1129
- color = @hsbColor__ ? Rays::Color.hsv(*rgba) : Rays::Color.new(*rgba)
1130
- color.to_a
1131
- end
1132
-
1133
- # @private
1134
- private def parseColor__(str, alpha)
1135
- result = str.match(/^\s*##{'([0-9a-f]{2})' * 3}\s*$/i)
1136
- raise ArgumentError, "invalid color code: '#{str}'" unless result
1137
-
1138
- rgb = result[1..3].map.with_index {|hex, i| hex.to_i(16) / 255.0}
1139
- return *rgb, (alpha / alphaMax__)
1140
- end
1141
-
1142
- # @private
1143
- private def alphaMax__()
1144
- @colorMaxes__[3]
1145
- end
1146
-
1147
- # Sets angle mode.
1148
- #
1149
- # @param mode [RADIANS, DEGREES] RADIANS or DEGREES
1150
- #
1151
- # @return [nil] nil
1152
- #
1153
- def angleMode(mode)
1154
- @angleScale__ = case mode.downcase.to_sym
1155
- when RADIANS then RAD2DEG__
1156
- when DEGREES then 1.0
1157
- else raise ArgumentError, "invalid angle mode: #{mode}"
1158
- end
1159
- nil
1160
- end
1161
-
1162
- # @private
1163
- def toAngle__(angle)
1164
- angle * @angleScale__
1165
- end
1166
-
1167
- # Sets rect mode. Default is CORNER.
1168
- #
1169
- # CORNER -> rect(left, top, width, height)
1170
- # CORNERS -> rect(left, top, right, bottom)
1171
- # CENTER -> rect(center_x, center_y, width, height)
1172
- # RADIUS -> rect(center_x, center_y, radius_h, radius_v)
1173
- #
1174
- # @param mode [CORNER, CORNERS, CENTER, RADIUS]
1175
- #
1176
- # @return [nil] nil
1177
- #
1178
- def rectMode(mode)
1179
- @rectMode__ = mode
1180
- end
1181
-
1182
- # Sets ellipse mode. Default is CENTER.
1183
- #
1184
- # CORNER -> ellipse(left, top, width, height)
1185
- # CORNERS -> ellipse(left, top, right, bottom)
1186
- # CENTER -> ellipse(center_x, center_y, width, height)
1187
- # RADIUS -> ellipse(center_x, center_y, radius_h, radius_v)
1188
- #
1189
- # @param mode [CORNER, CORNERS, CENTER, RADIUS]
1190
- #
1191
- # @return [nil] nil
1192
- #
1193
- def ellipseMode(mode)
1194
- @ellipseMode__ = mode
1195
- end
1196
-
1197
- # Sets image mode. Default is CORNER.
1198
- #
1199
- # CORNER -> image(img, left, top, width, height)
1200
- # CORNERS -> image(img, left, top, right, bottom)
1201
- # CENTER -> image(img, center_x, center_y, width, height)
1202
- #
1203
- # @param mode [CORNER, CORNERS, CENTER]
1204
- #
1205
- # @return [nil] nil
1206
- #
1207
- def imageMode(mode)
1208
- @imageMode__ = mode
1209
- end
1210
-
1211
- # @private
1212
- private def toXYWH__(mode, a, b, c, d)
1213
- case mode
1214
- when CORNER then [a, b, c, d]
1215
- when CORNERS then [a, b, c - a, d - b]
1216
- when CENTER then [a - c / 2.0, b - d / 2.0, c, d]
1217
- when RADIUS then [a - c, b - d, c * 2, d * 2]
1218
- else raise ArgumentError # ToDo: refine error message
1219
- end
1220
- end
1221
-
1222
- # Sets blend mode. Default is BLEND.
1223
- #
1224
- # @param mode [BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, EXCLUSION, MULTIPLY, SCREEN, REPLACE]
1225
- #
1226
- # @return [nil] nil
1227
- #
1228
- def blendMode(mode)
1229
- @painter__.blend_mode = mode
1230
- nil
1231
- end
1232
-
1233
- # Sets fill color.
1234
- #
1235
- # @overload fill(rgb)
1236
- # @overload fill(rgb, alpha)
1237
- # @overload fill(gray)
1238
- # @overload fill(gray, alpha)
1239
- # @overload fill(r, g, b)
1240
- # @overload fill(r, g, b, alpha)
1241
- #
1242
- # @param rgb [String] color code like '#00AAFF'
1243
- # @param gray [Integer] gray value (0..255)
1244
- # @param r [Integer] red value (0..255)
1245
- # @param g [Integer] green value (0..255)
1246
- # @param b [Integer] blue value (0..255)
1247
- # @param alpha [Integer] alpha value (0..255)
1248
- #
1249
- # @return [nil] nil
1250
- #
1251
- def fill(*args)
1252
- @painter__.fill(*toRGBA__(*args))
1253
- nil
1254
- end
1255
-
1256
- # Disables filling.
1257
- #
1258
- # @return [nil] nil
1259
- #
1260
- def noFill()
1261
- @painter__.fill nil
1262
- nil
1263
- end
1264
-
1265
- # Sets stroke color.
1266
- #
1267
- # @overload stroke(rgb)
1268
- # @overload stroke(rgb, alpha)
1269
- # @overload stroke(gray)
1270
- # @overload stroke(gray, alpha)
1271
- # @overload stroke(r, g, b)
1272
- # @overload stroke(r, g, b, alpha)
1273
- #
1274
- # @param rgb [String] color code like '#00AAFF'
1275
- # @param gray [Integer] gray value (0..255)
1276
- # @param r [Integer] red value (0..255)
1277
- # @param g [Integer] green value (0..255)
1278
- # @param b [Integer] blue value (0..255)
1279
- # @param alpha [Integer] alpha value (0..255)
1280
- #
1281
- # @return [nil] nil
1282
- #
1283
- def stroke(*args)
1284
- @painter__.stroke(*toRGBA__(*args))
1285
- nil
1286
- end
1287
-
1288
- # Disables drawing stroke.
1289
- #
1290
- # @return [nil] nil
1291
- #
1292
- def noStroke()
1293
- @painter__.stroke nil
1294
- nil
1295
- end
1296
-
1297
- # Sets stroke weight.
1298
- #
1299
- # @param weight [Numeric] width of stroke
1300
- #
1301
- # @return [nil] nil
1302
- #
1303
- def strokeWeight(weight)
1304
- @painter__.stroke_width weight
1305
- nil
1306
- end
1307
-
1308
- # Sets stroke cap mode.
1309
- #
1310
- # @param cap [BUTT, ROUND, SQUARE]
1311
- #
1312
- # @return [nil] nil
1313
- #
1314
- def strokeCap(cap)
1315
- @painter__.stroke_cap cap
1316
- nil
1317
- end
1318
-
1319
- # Sets stroke join mode.
1320
- #
1321
- # @param join [MITER, ROUND, SQUARE]
1322
- #
1323
- # @return [nil] nil
1324
- #
1325
- def strokeJoin(join)
1326
- @painter__.stroke_join join
1327
- nil
1328
- end
1329
-
1330
- # Sets fill color for drawing images.
1331
- #
1332
- # @overload tint(rgb)
1333
- # @overload tint(rgb, alpha)
1334
- # @overload tint(gray)
1335
- # @overload tint(gray, alpha)
1336
- # @overload tint(r, g, b)
1337
- # @overload tint(r, g, b, alpha)
1338
- #
1339
- # @param rgb [String] color code like '#00AAFF'
1340
- # @param gray [Integer] gray value (0..255)
1341
- # @param r [Integer] red value (0..255)
1342
- # @param g [Integer] green value (0..255)
1343
- # @param b [Integer] blue value (0..255)
1344
- # @param alpha [Integer] alpha value (0..255)
1345
- #
1346
- # @return [nil] nil
1347
- #
1348
- def tint(*args)
1349
- @tint__ = args
1350
- nil
1351
- end
1352
-
1353
- # Resets tint color.
1354
- #
1355
- # @return [nil] nil
1356
- #
1357
- def noTint()
1358
- @tint__ = nil
1359
- end
1360
-
1361
- # Limits the drawable rectangle.
1362
- #
1363
- # The parameters a, b, c, and d are determined by rectMode().
1364
- #
1365
- # @param a [Numeric] horizontal position of the drawable area, by default
1366
- # @param b [Numeric] vertical position of the drawable area, by default
1367
- # @param c [Numeric] width of the drawable area, by default
1368
- # @param d [Numeric] height of the drawable area, by default
1369
- #
1370
- # @return [nil] nil
1371
- #
1372
- def clip(a, b, c, d)
1373
- x, y, w, h = toXYWH__ @imageMode__, a, b, c, d
1374
- @painter__.clip x, y, w, h
1375
- nil
1376
- end
1377
-
1378
- # Disables clipping.
1379
- #
1380
- # @return [nil] nil
1381
- #
1382
- def noClip()
1383
- @painter__.no_clip
1384
- nil
1385
- end
1386
-
1387
- # Sets font.
1388
- #
1389
- # @overload textFont(font)
1390
- # @overload textFont(name)
1391
- # @overload textFont(font, size)
1392
- # @overload textFont(name, size)
1393
- #
1394
- # @param font [Font] font
1395
- # @param name [String] font name
1396
- # @param size [Numeric] font size (max 256)
1397
- #
1398
- # @return [Font] current font
1399
- #
1400
- def textFont(font = nil, size = nil)
1401
- setFont__ font, size if font || size
1402
- Font.new @painter__.font
1403
- end
1404
-
1405
- # Sets text size.
1406
- #
1407
- # @param size [Numeric] font size (max 256)
1408
- #
1409
- # @return [nil] nil
1410
- #
1411
- def textSize(size)
1412
- setFont__ nil, size
1413
- nil
1414
- end
1415
-
1416
- def textWidth(str)
1417
- @painter__.font.width str
1418
- end
1419
-
1420
- def textAscent()
1421
- @painter__.font.ascent
1422
- end
1423
-
1424
- def textDescent()
1425
- @painter__.font.descent
1426
- end
1427
-
1428
- def textAlign(horizontal, vertical = BASELINE)
1429
- @textAlignH__ = horizontal
1430
- @textAlignV__ = vertical
1431
- end
1432
-
1433
- # @private
1434
- def setFont__(fontOrName, size)
1435
- name = case fontOrName
1436
- when Font then fontOrName.name
1437
- else fontOrName || @painter__.font.name
1438
- end
1439
- size ||= @painter__.font.size
1440
- size = 256 if size > 256
1441
- font = @fontCache__[[name, size]] ||= Rays::Font.new name, size
1442
- @painter__.font = font
1443
- end
1444
-
1445
- # Clears screen.
1446
- #
1447
- # @overload background(str)
1448
- # @overload background(str, alpha)
1449
- # @overload background(gray)
1450
- # @overload background(gray, alpha)
1451
- # @overload background(r, g, b)
1452
- # @overload background(r, g, b, alpha)
1453
- #
1454
- # @param str [String] color code like '#00AAFF'
1455
- # @param gray [Integer] gray value (0..255)
1456
- # @param r [Integer] red value (0..255)
1457
- # @param g [Integer] green value (0..255)
1458
- # @param b [Integer] blue value (0..255)
1459
- # @param alpha [Integer] alpha value (0..255)
1460
- #
1461
- # @return [nil] nil
1462
- #
1463
- def background(*args)
1464
- assertDrawing__
1465
- rgba = toRGBA__(*args)
1466
- if rgba[3] == 1
1467
- @painter__.background(*rgba)
1468
- else
1469
- @painter__.push fill: rgba, stroke: :none do |_|
1470
- @painter__.rect 0, 0, width, height
1471
- end
1472
- end
1473
- nil
1474
- end
1475
-
1476
- # Draws a point.
1477
- #
1478
- # @param x [Numeric] horizontal position
1479
- # @param y [Numeric] vertical position
1480
- #
1481
- # @return [nil] nil
1482
- #
1483
- def point(x, y)
1484
- assertDrawing__
1485
- @painter__.line x, y, x, y
1486
- nil
1487
- end
1488
-
1489
- # Draws a line.
1490
- #
1491
- # @param x1 [Numeric] horizontal position of first point
1492
- # @param y1 [Numeric] vertical position of first point
1493
- # @param x2 [Numeric] horizontal position of second point
1494
- # @param y2 [Numeric] vertical position of second point
1495
- #
1496
- # @return [nil] nil
1497
- #
1498
- def line(x1, y1, x2, y2)
1499
- assertDrawing__
1500
- @painter__.line x1, y1, x2, y2
1501
- nil
1502
- end
1503
-
1504
- # Draws a rectangle.
1505
- #
1506
- # The parameters a, b, c, and d are determined by rectMode().
1507
- #
1508
- # @overload rect(a, b, c, d)
1509
- # @overload rect(a, b, c, d, r)
1510
- # @overload rect(a, b, c, d, tl, tr, br, bl)
1511
- #
1512
- # @param a [Numeric] horizontal position of the shape, by default
1513
- # @param b [Numeric] vertical position of the shape, by default
1514
- # @param c [Numeric] width of the shape, by default
1515
- # @param d [Numeric] height of the shape, by default
1516
- # @param r [Numeric] radius for all corners
1517
- # @param tl [Numeric] radius for top-left corner
1518
- # @param tr [Numeric] radius for top-right corner
1519
- # @param br [Numeric] radius for bottom-right corner
1520
- # @param bl [Numeric] radius for bottom-left corner
1521
- #
1522
- # @return [nil] nil
1523
- #
1524
- def rect(a, b, c, d, *args)
1525
- assertDrawing__
1526
- x, y, w, h = toXYWH__ @rectMode__, a, b, c, d
1527
- case args.size
1528
- when 0 then @painter__.rect x, y, w, h
1529
- when 1 then @painter__.rect x, y, w, h, round: args[0]
1530
- when 4 then @painter__.rect x, y, w, h, lt: args[0], rt: args[1], rb: args[2], lb: args[3]
1531
- else raise ArgumentError # ToDo: refine error message
1532
- end
1533
- nil
1534
- end
1535
-
1536
- # Draws an ellipse.
1537
- #
1538
- # The parameters a, b, c, and d are determined by ellipseMode().
1539
- #
1540
- # @param a [Numeric] horizontal position of the shape, by default
1541
- # @param b [Numeric] vertical position of the shape, by default
1542
- # @param c [Numeric] width of the shape, by default
1543
- # @param d [Numeric] height of the shape, by default
1544
- #
1545
- # @return [nil] nil
1546
- #
1547
- def ellipse(a, b, c, d)
1548
- assertDrawing__
1549
- x, y, w, h = toXYWH__ @ellipseMode__, a, b, c, d
1550
- @painter__.ellipse x, y, w, h
1551
- nil
1552
- end
1553
-
1554
- # Draws a circle.
1555
- #
1556
- # @param x [Numeric] horizontal position of the shape
1557
- # @param y [Numeric] vertical position of the shape
1558
- # @param extent [Numeric] width and height of the shape
1559
- #
1560
- # @return [nil] nil
1561
- #
1562
- def circle(x, y, extent)
1563
- ellipse x, y, extent, extent
1564
- end
1565
-
1566
- # Draws an arc.
1567
- #
1568
- # The parameters a, b, c, and d are determined by ellipseMode().
1569
- #
1570
- # @param a [Numeric] horizontal position of the shape, by default
1571
- # @param b [Numeric] vertical position of the shape, by default
1572
- # @param c [Numeric] width of the shape, by default
1573
- # @param d [Numeric] height of the shape, by default
1574
- # @param start [Numeric] angle to start the arc
1575
- # @param stop [Numeric] angle to stop the arc
1576
- #
1577
- # @return [nil] nil
1578
- #
1579
- def arc(a, b, c, d, start, stop)
1580
- assertDrawing__
1581
- x, y, w, h = toXYWH__ @ellipseMode__, a, b, c, d
1582
- start = toAngle__(-start)
1583
- stop = toAngle__(-stop)
1584
- @painter__.ellipse x, y, w, h, from: start, to: stop
1585
- nil
1586
- end
1587
-
1588
- # Draws a square.
1589
- #
1590
- # @param x [Numeric] horizontal position of the shape
1591
- # @param y [Numeric] vertical position of the shape
1592
- # @param extent [Numeric] width and height of the shape
1593
- #
1594
- # @return [nil] nil
1595
- #
1596
- def square(x, y, extent)
1597
- rect x, y, extent, extent
1598
- end
1599
-
1600
- # Draws a triangle.
1601
- #
1602
- # @param x1 [Numeric] horizontal position of first point
1603
- # @param y1 [Numeric] vertical position of first point
1604
- # @param x2 [Numeric] horizontal position of second point
1605
- # @param y2 [Numeric] vertical position of second point
1606
- # @param x3 [Numeric] horizontal position of third point
1607
- # @param y3 [Numeric] vertical position of third point
1608
- #
1609
- # @return [nil] nil
1610
- #
1611
- def triangle(x1, y1, x2, y2, x3, y3)
1612
- assertDrawing__
1613
- @painter__.line x1, y1, x2, y2, x3, y3, loop: true
1614
- nil
1615
- end
1616
-
1617
- # Draws a quad.
1618
- #
1619
- # @param x1 [Numeric] horizontal position of first point
1620
- # @param y1 [Numeric] vertical position of first point
1621
- # @param x2 [Numeric] horizontal position of second point
1622
- # @param y2 [Numeric] vertical position of second point
1623
- # @param x3 [Numeric] horizontal position of third point
1624
- # @param y3 [Numeric] vertical position of third point
1625
- # @param x4 [Numeric] horizontal position of fourth point
1626
- # @param y4 [Numeric] vertical position of fourth point
1627
- #
1628
- # @return [nil] nil
1629
- #
1630
- def quad(x1, y1, x2, y2, x3, y3, x4, y4)
1631
- assertDrawing__
1632
- @painter__.line x1, y1, x2, y2, x3, y3, x4, y4, loop: true
1633
- nil
1634
- end
1635
-
1636
- # Draws a Catmull-Rom spline curve.
1637
- #
1638
- # @param cx1 [Numeric] horizontal position of beginning control point
1639
- # @param cy1 [Numeric] vertical position of beginning control point
1640
- # @param x1 [Numeric] horizontal position of first point
1641
- # @param y1 [Numeric] vertical position of first point
1642
- # @param x2 [Numeric] horizontal position of second point
1643
- # @param y2 [Numeric] vertical position of second point
1644
- # @param cx2 [Numeric] horizontal position of ending control point
1645
- # @param cy2 [Numeric] vertical position of ending control point
1646
- #
1647
- # @return [nil] nil
1648
- #
1649
- def curve(cx1, cy1, x1, y1, x2, y2, cx2, cy2)
1650
- assertDrawing__
1651
- @painter__.curve cx1, cy1, x1, y1, x2, y2, cx2, cy2
1652
- nil
1653
- end
1654
-
1655
- # Draws a Bezier spline curve.
1656
- #
1657
- # @param x1 [Numeric] horizontal position of first point
1658
- # @param y1 [Numeric] vertical position of first point
1659
- # @param cx1 [Numeric] horizontal position of first control point
1660
- # @param cy1 [Numeric] vertical position of first control point
1661
- # @param cx2 [Numeric] horizontal position of second control point
1662
- # @param cy2 [Numeric] vertical position of second control point
1663
- # @param x2 [Numeric] horizontal position of second point
1664
- # @param y2 [Numeric] vertical position of second point
1665
- #
1666
- # @return [nil] nil
1667
- #
1668
- def bezier(x1, y1, cx1, cy1, cx2, cy2, x2, y2)
1669
- assertDrawing__
1670
- @painter__.bezier x1, y1, cx1, cy1, cx2, cy2, x2, y2
1671
- nil
1672
- end
1673
-
1674
- # Draws a text.
1675
- #
1676
- # The parameters a, b, c, and d are determined by rectMode().
1677
- #
1678
- # @overload text(str)
1679
- # @overload text(str, x, y)
1680
- # @overload text(str, a, b, c, d)
1681
- #
1682
- # @param str [String] text to draw
1683
- # @param x [Numeric] horizontal position of the text
1684
- # @param y [Numeric] vertical position of the text
1685
- # @param a [Numeric] horizontal position of the text, by default
1686
- # @param b [Numeric] vertical position of the text, by default
1687
- # @param c [Numeric] width of the text, by default
1688
- # @param d [Numeric] height of the text, by default
1689
- #
1690
- # @return [nil] nil
1691
- #
1692
- def text(str, x, y, x2 = nil, y2 = nil)
1693
- assertDrawing__
1694
- if x2
1695
- raise ArgumentError, "missing y2 parameter" unless y2
1696
- x, y, w, h = toXYWH__ @rectMode__, x, y, x2, y2
1697
- case @textAlignH__
1698
- when RIGHT then x += w - @painter__.font.width(str)
1699
- when CENTER then x += (w - @painter__.font.width(str)) / 2
1700
- end
1701
- case @textAlignV__
1702
- when BOTTOM then y += h - @painter__.font.height
1703
- when CENTER then y += (h - @painter__.font.height) / 2
1704
- else
1705
- end
1706
- else
1707
- y -= @painter__.font.ascent
1708
- end
1709
- @painter__.text str, x, y
1710
- nil
1711
- end
1712
-
1713
- # Draws an image.
1714
- #
1715
- # The parameters a, b, c, and d are determined by imageMode().
1716
- #
1717
- # @overload image(img, a, b)
1718
- # @overload image(img, a, b, c, d)
1719
- #
1720
- # @param img [Image] image to draw
1721
- # @param a [Numeric] horizontal position of the image, by default
1722
- # @param b [Numeric] vertical position of the image, by default
1723
- # @param c [Numeric] width of the image, by default
1724
- # @param d [Numeric] height of the image, by default
1725
- #
1726
- # @return [nil] nil
1727
- #
1728
- def image(img, a, b, c = nil, d = nil)
1729
- assertDrawing__
1730
- i = img.getInternal__
1731
- x, y, w, h = toXYWH__ @imageMode__, a, b, c || i.width, d || i.height
1732
- tint = @tint__ ? toRGBA__(*@tint__) : 1
1733
- @painter__.push fill: tint, stroke: :none do |_|
1734
- @painter__.image i, x, y, w, h
1735
- end
1736
- nil
1737
- end
1738
-
1739
- # Copies image.
1740
- #
1741
- # @overload copy(sx, sy, sw, sh, dx, dy, dw, dh)
1742
- # @overload copy(img, sx, sy, sw, sh, dx, dy, dw, dh)
1743
- #
1744
- # @param img [Image] image for copy source
1745
- # @param sx [Numrtic] x position of source region
1746
- # @param sy [Numrtic] y position of source region
1747
- # @param sw [Numrtic] width of source region
1748
- # @param sh [Numrtic] height of source region
1749
- # @param dx [Numrtic] x position of destination region
1750
- # @param dy [Numrtic] y position of destination region
1751
- # @param dw [Numrtic] width of destination region
1752
- # @param dh [Numrtic] height of destination region
1753
- #
1754
- # @return [nil] nil
1755
- #
1756
- def copy(img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
1757
- blend img, sx, sy, sw, sh, dx, dy, dw, dh, BLEND
1758
- end
1759
-
1760
- # Blends image.
1761
- #
1762
- # @overload blend(sx, sy, sw, sh, dx, dy, dw, dh, mode)
1763
- # @overload blend(img, sx, sy, sw, sh, dx, dy, dw, dh, mode)
1764
- #
1765
- # @param img [Image] image for blend source
1766
- # @param sx [Numrtic] x position of source region
1767
- # @param sy [Numrtic] y position of source region
1768
- # @param sw [Numrtic] width of source region
1769
- # @param sh [Numrtic] height of source region
1770
- # @param dx [Numrtic] x position of destination region
1771
- # @param dy [Numrtic] y position of destination region
1772
- # @param dw [Numrtic] width of destination region
1773
- # @param dh [Numrtic] height of destination region
1774
- # @param mode [BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, EXCLUSION, MULTIPLY, SCREEN, REPLACE] blend mode
1775
- #
1776
- # @return [nil] nil
1777
- #
1778
- def blend(img = nil, sx, sy, sw, sh, dx, dy, dw, dh, mode)
1779
- assertDrawing__
1780
- src = img&.getInternal__ || @window__.canvas_image
1781
- current = @painter__.blend_mode
1782
-
1783
- @painter__.blend_mode = mode
1784
- @painter__.image src, sx, sy, sw, sh, dx, dy, dw, dh
1785
- @painter__.blend_mode = current
1786
- end
1787
-
1788
- # Saves screen image to file.
1789
- #
1790
- # @param filename [String] file name to save image
1791
- #
1792
- def save(filename)
1793
- @window__.canvas_image.save filename
1794
- end
1795
-
1796
- # Applies translation matrix to current transformation matrix.
1797
- #
1798
- # @overload translate(x, y)
1799
- # @overload translate(x, y, z)
1800
- #
1801
- # @param x [Numeric] left/right translation
1802
- # @param y [Numeric] up/down translation
1803
- # @param y [Numeric] forward/backward translation
1804
- #
1805
- # @return [nil] nil
1806
- #
1807
- def translate(x, y, z = 0)
1808
- assertDrawing__
1809
- @painter__.translate x, y, z
1810
- nil
1811
- end
1812
-
1813
- # Applies scale matrix to current transformation matrix.
1814
- #
1815
- # @overload scale(s)
1816
- # @overload scale(x, y)
1817
- #
1818
- # @param s [Numeric] horizontal and vertical scale
1819
- # @param x [Numeric] horizontal scale
1820
- # @param y [Numeric] vertical scale
1821
- #
1822
- # @return [nil] nil
1823
- #
1824
- def scale(x, y)
1825
- assertDrawing__
1826
- @painter__.scale x, y
1827
- nil
1828
- end
1829
-
1830
- # Applies rotation matrix to current transformation matrix.
1831
- #
1832
- # @param angle [Numeric] angle for rotation
1833
- #
1834
- # @return [nil] nil
1835
- #
1836
- def rotate(angle)
1837
- assertDrawing__
1838
- @painter__.rotate toAngle__ angle
1839
- nil
1840
- end
1841
-
1842
- # Pushes the current transformation matrix to stack.
1843
- #
1844
- # @return [nil] nil
1845
- #
1846
- def pushMatrix(&block)
1847
- assertDrawing__
1848
- @matrixStack__.push @painter__.matrix
1849
- if block
1850
- block.call
1851
- popMatrix
1852
- end
1853
- nil
1854
- end
1855
-
1856
- # Pops the current transformation matrix from stack.
1857
- #
1858
- # @return [nil] nil
1859
- #
1860
- def popMatrix()
1861
- assertDrawing__
1862
- raise "matrix stack underflow" if @matrixStack__.empty?
1863
- @painter__.matrix = @matrixStack__.pop
1864
- nil
1865
- end
1866
-
1867
- # Reset current transformation matrix with identity matrix.
1868
- #
1869
- # @return [nil] nil
1870
- #
1871
- def resetMatrix()
1872
- assertDrawing__
1873
- @painter__.matrix = 1
1874
- nil
1875
- end
1876
-
1877
- # Save current style values to the style stack.
1878
- #
1879
- # @return [nil] nil
1880
- #
1881
- def pushStyle(&block)
1882
- assertDrawing__
1883
- @styleStack__.push [
1884
- @painter__.fill,
1885
- @painter__.stroke,
1886
- @painter__.stroke_width,
1887
- @painter__.stroke_cap,
1888
- @painter__.stroke_join,
1889
- @painter__.clip,
1890
- @painter__.blend_mode,
1891
- @painter__.font,
1892
- @hsbColor__,
1893
- @colorMaxes__,
1894
- @angleScale__,
1895
- @rectMode__,
1896
- @ellipseMode__,
1897
- @imageMode__
1898
- ]
1899
- if block
1900
- block.call
1901
- popStyle
1902
- end
1903
- nil
1904
- end
1905
-
1906
- # Restore style values from the style stack.
1907
- #
1908
- # @return [nil] nil
1909
- #
1910
- def popStyle()
1911
- assertDrawing__
1912
- raise "style stack underflow" if @styleStack__.empty?
1913
- @painter__.fill,
1914
- @painter__.stroke,
1915
- @painter__.stroke_width,
1916
- @painter__.stroke_cap,
1917
- @painter__.stroke_join,
1918
- @painter__.clip,
1919
- @painter__.blend_mode,
1920
- @painter__.font,
1921
- @hsbColor__,
1922
- @colorMaxes__,
1923
- @angleScale__,
1924
- @rectMode__,
1925
- @ellipseMode__,
1926
- @imageMode__ = @styleStack__.pop
1927
- nil
1928
- end
1929
-
1930
- # Save current styles and transformations to stack.
1931
- #
1932
- # @return [nil] nil
1933
- #
1934
- def push(&block)
1935
- pushMatrix
1936
- pushStyle
1937
- if block
1938
- block.call
1939
- pop
1940
- end
1941
- end
1942
-
1943
- # Restore styles and transformations from stack.
1944
- #
1945
- # @return [nil] nil
1946
- #
1947
- def pop()
1948
- popMatrix
1949
- popStyle
1950
- end
1951
-
1952
- # @private
1953
- def getInternal__()
1954
- @image__
1955
- end
1956
-
1957
- # @private
1958
- private def assertDrawing__()
1959
- raise "call beginDraw() before drawing" unless @drawing__
1960
- end
1961
-
1962
- end# GraphicsContext
1963
-
1964
-
1965
- # Draws graphics into an offscreen buffer
1966
- #
1967
- class Graphics
1968
-
1969
- include GraphicsContext
1970
-
1971
- # Initialize graphics object.
1972
- #
1973
- def initialize(width, height)
1974
- image = Rays::Image.new width, height
1975
- init__ image, image.painter
1976
- end
1977
-
1978
- # Start drawing.
1979
- #
1980
- def beginDraw(&block)
1981
- @painter__.__send__ :begin_paint
1982
- beginDraw__
1983
- push
1984
- if block
1985
- block.call
1986
- endDraw
1987
- end
1988
- end
1989
-
1990
- # End drawing.
1991
- #
1992
- def endDraw()
1993
- pop
1994
- endDraw__
1995
- @painter__.__send__ :end_paint
1996
- end
1997
-
1998
- end# Graphics
1999
-
2000
-
2001
- # Processing context
2002
- #
2003
- class Context
2004
-
2005
- include GraphicsContext
2006
-
2007
- Vector = Processing::Vector
2008
- Capture = Processing::Capture
2009
- Graphics = Processing::Graphics
2010
-
2011
- # @private
2012
- @@context__ = nil
2013
-
2014
- # @private
2015
- def self.context__()
2016
- @@context__
2017
- end
2018
-
2019
- # @private
2020
- def initialize(window)
2021
- @@context__ = self
2022
-
2023
- tmpdir__.tap {|dir| FileUtils.rm_r dir.to_s if dir.directory?}
2024
-
2025
- @window__ = window
2026
- init__(
2027
- @window__.canvas_image,
2028
- @window__.canvas_painter.paint {background 0.8})
2029
-
2030
- @loop__ = true
2031
- @redraw__ = false
2032
- @frameCount__ = 0
2033
- @key__ = nil
2034
- @keyCode__ = nil
2035
- @keysPressed__ = Set.new
2036
- @pointerPos__ =
2037
- @pointerPrevPos__ = Rays::Point.new 0
2038
- @pointersPressed__ = []
2039
- @touches__ = []
2040
- @motionGravity__ = createVector 0, 0
2041
-
2042
- @window__.before_draw = proc {beginDraw__}
2043
- @window__.after_draw = proc {endDraw__}
2044
-
2045
- drawFrame = -> {
2046
- updateCanvas__ @window__.canvas_image, @window__.canvas_painter
2047
- begin
2048
- push
2049
- @drawBlock__.call if @drawBlock__
2050
- ensure
2051
- pop
2052
- @frameCount__ += 1
2053
- end
2054
- }
2055
-
2056
- @window__.draw = proc do |e|
2057
- if @loop__ || @redraw__
2058
- @redraw__ = false
2059
- drawFrame.call
2060
- end
2061
- end
2062
-
2063
- updateKeyStates = -> event, pressed {
2064
- @key__ = event.chars
2065
- @keyCode__ = event.key
2066
- if pressed != nil
2067
- set, key = @keysPressed__, event.key
2068
- pressed ? set.add(key) : set.delete(key)
2069
- end
2070
- }
2071
-
2072
- mouseButtonMap = {
2073
- mouse_left: LEFT,
2074
- mouse_right: RIGHT,
2075
- mouse_middle: CENTER
2076
- }
2077
-
2078
- updatePointerStates = -> event, pressed = nil {
2079
- @pointerPrevPos__ = @pointerPos__
2080
- @pointerPos__ = event.pos.dup
2081
- @touches__ = event.pointers.map {|p| Touch.new(p.id, *p.pos.to_a)}
2082
- if pressed != nil
2083
- array = @pointersPressed__
2084
- event.types
2085
- .tap {|types| types.delete :mouse}
2086
- .map {|type| mouseButtonMap[type] || type}
2087
- .each {|type| pressed ? array.push(type) : array.delete(type)}
2088
- end
2089
- }
2090
-
2091
- @window__.key_down = proc do |e|
2092
- updateKeyStates.call e, true
2093
- @keyPressedBlock__&.call
2094
- @keyTypedBlock__&.call if @key__ && !@key__.empty?
2095
- end
2096
-
2097
- @window__.key_up = proc do |e|
2098
- updateKeyStates.call e, false
2099
- @keyReleasedBlock__&.call
2100
- end
2101
-
2102
- @window__.pointer_down = proc do |e|
2103
- updatePointerStates.call e, true
2104
- @pointerDownStartPos__ = @pointerPos__.dup
2105
- (@touchStartedBlock__ || @mousePressedBlock__)&.call
2106
- end
2107
-
2108
- @window__.pointer_up = proc do |e|
2109
- updatePointerStates.call e, false
2110
- (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
2111
- if startPos = @pointerDownStartPos__
2112
- @mouseClickedBlock__&.call if (@pointerPos__ - startPos).length < 3
2113
- @pointerDownStartPos__ = nil
2114
- end
2115
- end
2116
-
2117
- @window__.pointer_move = proc do |e|
2118
- updatePointerStates.call e
2119
- (@touchMovedBlock__ || @mouseMovedBlock__)&.call
2120
- end
2121
-
2122
- @window__.pointer_drag = proc do |e|
2123
- updatePointerStates.call e
2124
- (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
2125
- end
2126
-
2127
- @window__.motion = proc do |e|
2128
- @motionGravity__ = createVector(*e.gravity.to_a(3))
2129
- @motionBlock__&.call
2130
- end
2131
- end
2132
-
2133
- # Defines setup block.
2134
- #
2135
- # @return [nil] nil
2136
- #
2137
- def setup(&block)
2138
- @window__.setup = block
2139
- nil
2140
- end
2141
-
2142
- # Defines draw block.
2143
- #
2144
- # @return [nil] nil
2145
- #
2146
- def draw(&block)
2147
- @drawBlock__ = block if block
2148
- nil
2149
- end
2150
-
2151
- # Defines keyPressed block.
2152
- #
2153
- # @return [Boolean] is any key pressed or not
2154
- #
2155
- def keyPressed(&block)
2156
- @keyPressedBlock__ = block if block
2157
- not @keysPressed__.empty?
2158
- end
2159
-
2160
- # Defines keyReleased block.
2161
- #
2162
- # @return [nil] nil
2163
- #
2164
- def keyReleased(&block)
2165
- @keyReleasedBlock__ = block if block
2166
- nil
2167
- end
2168
-
2169
- # Defines keyTyped block.
2170
- #
2171
- # @return [nil] nil
2172
- #
2173
- def keyTyped(&block)
2174
- @keyTypedBlock__ = block if block
2175
- nil
2176
- end
2177
-
2178
- # Defines mousePressed block.
2179
- #
2180
- # @return [Boolean] is any mouse button pressed or not
2181
- #
2182
- def mousePressed(&block)
2183
- @mousePressedBlock__ = block if block
2184
- not @pointersPressed__.empty?
2185
- end
2186
-
2187
- # Defines mouseReleased block.
2188
- #
2189
- # @return [nil] nil
2190
- #
2191
- def mouseReleased(&block)
2192
- @mouseReleasedBlock__ = block if block
2193
- nil
2194
- end
2195
-
2196
- # Defines mouseMoved block.
2197
- #
2198
- # @return [nil] nil
2199
- #
2200
- def mouseMoved(&block)
2201
- @mouseMovedBlock__ = block if block
2202
- nil
2203
- end
2204
-
2205
- # Defines mouseDragged block.
2206
- #
2207
- # @return [nil] nil
2208
- #
2209
- def mouseDragged(&block)
2210
- @mouseDraggedBlock__ = block if block
2211
- nil
2212
- end
2213
-
2214
- # Defines mouseClicked block.
2215
- #
2216
- # @return [nil] nil
2217
- #
2218
- def mouseClicked(&block)
2219
- @mouseClickedBlock__ = block if block
2220
- nil
2221
- end
2222
-
2223
- # Defines touchStarted block.
2224
- #
2225
- # @return [nil] nil
2226
- #
2227
- def touchStarted(&block)
2228
- @touchStartedBlock__ = block if block
2229
- nil
2230
- end
2231
-
2232
- # Defines touchEnded block.
2233
- #
2234
- # @return [nil] nil
2235
- #
2236
- def touchEnded(&block)
2237
- @touchEndedBlock__ = block if block
2238
- nil
2239
- end
2240
-
2241
- # Defines touchMoved block.
2242
- #
2243
- # @return [nil] nil
2244
- #
2245
- def touchMoved(&block)
2246
- @touchMovedBlock__ = block if block
2247
- nil
2248
- end
2249
-
2250
- # Defines motion block.
2251
- #
2252
- # @return [nil] nil
2253
- #
2254
- def motion(&block)
2255
- @motionBlock__ = block if block
2256
- nil
2257
- end
2258
-
2259
- # Changes canvas size.
2260
- #
2261
- # @param width [Integer] new width
2262
- # @param height [Integer] new height
2263
- # @param pixelDensity [Numeric] new pixel density
2264
- #
2265
- # @return [nil] nil
2266
- #
2267
- def size(width, height, pixelDensity: self.pixelDensity)
2268
- resizeCanvas__ :size, width, height, pixelDensity
2269
- nil
2270
- end
2271
-
2272
- # Changes canvas size.
2273
- #
2274
- # @param width [Integer] new width
2275
- # @param height [Integer] new height
2276
- # @param pixelDensity [Numeric] new pixel density
2277
- #
2278
- # @return [nil] nil
2279
- #
2280
- def createCanvas(width, height, pixelDensity: self.pixelDensity)
2281
- resizeCanvas__ :createCanvas, width, height, pixelDensity
2282
- nil
2283
- end
2284
-
2285
- # Changes title of window.
2286
- #
2287
- # @param title [String] new title
2288
- #
2289
- # @return [nil] nil
2290
- #
2291
- def setTitle(title)
2292
- @window__.title = title
2293
- nil
2294
- end
2295
-
2296
- # Changes and returns canvas pixel density.
2297
- #
2298
- # @param density [Numeric] new pixel density
2299
- #
2300
- # @return [Numeric] current pixel density
2301
- #
2302
- def pixelDensity(density = nil)
2303
- resizeCanvas__ :pixelDensity, width, height, density if density
2304
- @painter__.pixel_density
2305
- end
2306
-
2307
- # @private
2308
- def resizeCanvas__(name, width, height, pixelDensity)
2309
- raise '#{name}() must be called on startup or setup block' if @started__
2310
-
2311
- @painter__.__send__ :end_paint
2312
- begin
2313
- @window__.__send__ :resize_canvas, width, height, pixelDensity
2314
- updateCanvas__ @window__.canvas_image, @window__.canvas_painter
2315
- ensure
2316
- @painter__.__send__ :begin_paint
2317
- end
2318
-
2319
- @window__.auto_resize = false
2320
- end
2321
-
2322
- # Returns pixel density of display.
2323
- #
2324
- # @return [Numeric] pixel density
2325
- #
2326
- def displayDensity()
2327
- @window__.painter.pixel_density
2328
- end
2329
-
2330
- # Returns window width.
2331
- #
2332
- # @return [Numeric] window width
2333
- #
2334
- def windowWidth()
2335
- @window__.width
2336
- end
2337
-
2338
- # Returns window height.
2339
- #
2340
- # @return [Numeric] window height
2341
- #
2342
- def windowHeight()
2343
- @window__.height
2344
- end
2345
-
2346
- # Returns number of frames since program started.
2347
- #
2348
- # @return [Integer] total number of frames
2349
- #
2350
- def frameCount()
2351
- @frameCount__
2352
- end
2353
-
2354
- # Returns number of frames per second.
2355
- #
2356
- # @return [Float] frames per second
2357
- #
2358
- def frameRate()
2359
- @window__.event.fps
2360
- end
2361
-
2362
- # Returns the last key that was pressed or released.
2363
- #
2364
- # @return [String] last key
2365
- #
2366
- def key()
2367
- @key__
2368
- end
2369
-
2370
- # Returns the last key code that was pressed or released.
2371
- #
2372
- # @return [Symbol] last key code
2373
- #
2374
- def keyCode()
2375
- @keyCode__
2376
- end
2377
-
2378
- # Returns mouse x position
2379
- #
2380
- # @return [Numeric] horizontal position of mouse
2381
- #
2382
- def mouseX()
2383
- @pointerPos__.x
2384
- end
2385
-
2386
- # Returns mouse y position
2387
- #
2388
- # @return [Numeric] vertical position of mouse
2389
- #
2390
- def mouseY()
2391
- @pointerPos__.y
2392
- end
2393
-
2394
- # Returns mouse x position in previous frame
2395
- #
2396
- # @return [Numeric] horizontal position of mouse
2397
- #
2398
- def pmouseX()
2399
- @pointerPrevPos__.x
2400
- end
2401
-
2402
- # Returns mouse y position in previous frame
2403
- #
2404
- # @return [Numeric] vertical position of mouse
2405
- #
2406
- def pmouseY()
2407
- @pointerPrevPos__.y
2408
- end
2409
-
2410
- # Returns which mouse button was pressed
2411
- #
2412
- # @return [Numeric] LEFT, RIGHT, CENTER or 0
2413
- #
2414
- def mouseButton()
2415
- (@pointersPressed__ & [LEFT, RIGHT, CENTER]).last || 0
2416
- end
2417
-
2418
- # Returns array of touches
2419
- #
2420
- # @return [Array] Touch objects
2421
- #
2422
- def touches()
2423
- @touches__
2424
- end
2425
-
2426
- # Returns vector for real world gravity
2427
- #
2428
- # @return [Vector] gravity vector
2429
- #
2430
- def motionGravity()
2431
- @motionGravity__
2432
- end
2433
-
2434
- # Enables calling draw block on every frame.
2435
- #
2436
- # @return [nil] nil
2437
- #
2438
- def loop()
2439
- @loop__ = true
2440
- end
2441
-
2442
- # Disables calling draw block on every frame.
2443
- #
2444
- # @return [nil] nil
2445
- #
2446
- def noLoop()
2447
- @loop__ = false
2448
- end
2449
-
2450
- # Calls draw block to redraw frame.
2451
- #
2452
- # @return [nil] nil
2453
- #
2454
- def redraw()
2455
- @redraw__ = true
2456
- end
2457
-
2458
- #
2459
- # Utilities
2460
- #
2461
-
2462
- # Returns the absolute number of the value.
2463
- #
2464
- # @param value [Numeric] number
2465
- #
2466
- # @return [Numeric] absolute number
2467
- #
2468
- def abs(value)
2469
- value.abs
2470
- end
2471
-
2472
- # Returns the closest integer number greater than or equal to the value.
2473
- #
2474
- # @param value [Numeric] number
2475
- #
2476
- # @return [Numeric] rounded up number
2477
- #
2478
- def ceil(value)
2479
- value.ceil
2480
- end
2481
-
2482
- # Returns the closest integer number less than or equal to the value.
2483
- #
2484
- # @param value [Numeric] number
2485
- #
2486
- # @return [Numeric] rounded down number
2487
- #
2488
- def floor(value)
2489
- value.floor
2490
- end
2491
-
2492
- # Returns the closest integer number.
2493
- #
2494
- # @param value [Numeric] number
2495
- #
2496
- # @return [Numeric] rounded number
2497
- #
2498
- def round(value)
2499
- value.round
2500
- end
2501
-
2502
- # Returns the natural logarithm (the base-e logarithm) of a number.
2503
- #
2504
- # @param value [Numeric] number (> 0.0)
2505
- #
2506
- # @return [Numeric] result number
2507
- #
2508
- def log(n)
2509
- Math.log n
2510
- end
2511
-
2512
- # Returns Euler's number e raised to the power of value.
2513
- #
2514
- # @param value [Numeric] number
2515
- #
2516
- # @return [Numeric] result number
2517
- #
2518
- def exp(n)
2519
- Math.exp n
2520
- end
2521
-
2522
- # Returns value raised to the power of exponent.
2523
- #
2524
- # @param value [Numeric] base number
2525
- # @param exponent [Numeric] exponent number
2526
- #
2527
- # @return [Numeric] value ** exponent
2528
- #
2529
- def pow(value, exponent)
2530
- value ** exponent
2531
- end
2532
-
2533
- # Returns squared value.
2534
- #
2535
- # @param value [Numeric] number
2536
- #
2537
- # @return [Numeric] squared value
2538
- #
2539
- def sq(value)
2540
- value * value
2541
- end
2542
-
2543
- # Returns squared value.
2544
- #
2545
- # @param value [Numeric] number
2546
- #
2547
- # @return [Numeric] squared value
2548
- #
2549
- def sqrt(value)
2550
- Math.sqrt value
2551
- end
2552
-
2553
- # Returns the magnitude (or length) of a vector.
2554
- #
2555
- # @overload mag(x, y)
2556
- # @overload mag(x, y, z)
2557
- #
2558
- # @param x [Numeric] x of point
2559
- # @param y [Numeric] y of point
2560
- # @param z [Numeric] z of point
2561
- #
2562
- # @return [Numeric] magnitude
2563
- #
2564
- def mag(*args)
2565
- x, y, z = *args
2566
- case args.size
2567
- when 2 then Math.sqrt x * x + y * y
2568
- when 3 then Math.sqrt x * x + y * y + z * z
2569
- else raise ArgumentError
2570
- end
2571
- end
2572
-
2573
- # Returns distance between 2 points.
2574
- #
2575
- # @overload dist(x1, y1, x2, y2)
2576
- # @overload dist(x1, y1, z1, x2, y2, z2)
2577
- #
2578
- # @param x1 [Numeric] x of first point
2579
- # @param y1 [Numeric] y of first point
2580
- # @param z1 [Numeric] z of first point
2581
- # @param x2 [Numeric] x of second point
2582
- # @param y2 [Numeric] y of second point
2583
- # @param z2 [Numeric] z of second point
2584
- #
2585
- # @return [Numeric] distance between 2 points
2586
- #
2587
- def dist(*args)
2588
- case args.size
2589
- when 4
2590
- x1, y1, x2, y2 = *args
2591
- xx, yy = x2 - x1, y2 - y1
2592
- Math.sqrt xx * xx + yy * yy
2593
- when 3
2594
- x1, y1, z1, x2, y2, z2 = *args
2595
- xx, yy, zz = x2 - x1, y2 - y1, z2 - z1
2596
- Math.sqrt xx * xx + yy * yy + zz * zz
2597
- else raise ArgumentError
2598
- end
2599
- end
2600
-
2601
- # Normalize the value from range start..stop into 0..1.
2602
- #
2603
- # @param value [Numeric] number to be normalized
2604
- # @param start [Numeric] lower bound of the range
2605
- # @param stop [Numeric] upper bound of the range
2606
- #
2607
- # @return [Numeric] normalized value between 0..1
2608
- #
2609
- def norm(value, start, stop)
2610
- (value.to_f - start.to_f) / (stop.to_f - start.to_f)
2611
- end
2612
-
2613
- # Returns the interpolated number between range start..stop.
2614
- #
2615
- # @param start [Numeric] lower bound of the range
2616
- # @param stop [Numeric] upper bound of the range
2617
- # @param amount [Numeric] amount to interpolate
2618
- #
2619
- # @return [Numeric] interporated number
2620
- #
2621
- def lerp(start, stop, amount)
2622
- start + (stop - start) * amount
2623
- end
2624
-
2625
- # Maps a number from range start1..stop1 to range start2..stop2.
2626
- #
2627
- # @param value [Numeric] number to be mapped
2628
- # @param start1 [Numeric] lower bound of the range1
2629
- # @param stop1 [Numeric] upper bound of the range1
2630
- # @param start2 [Numeric] lower bound of the range2
2631
- # @param stop2 [Numeric] upper bound of the range2
2632
- #
2633
- # @return [Numeric] mapped number
2634
- #
2635
- def map(value, start1, stop1, start2, stop2)
2636
- lerp start2, stop2, norm(value, start1, stop1)
2637
- end
2638
-
2639
- # Returns minimum value.
2640
- #
2641
- # @overload min(a, b)
2642
- # @overload min(a, b, c)
2643
- # @overload min(array)
2644
- #
2645
- # @param a [Numeric] value to compare
2646
- # @param b [Numeric] value to compare
2647
- # @param c [Numeric] value to compare
2648
- # @param array [Numeric] values to compare
2649
- #
2650
- # @return [Numeric] minimum value
2651
- #
2652
- def min(*args)
2653
- args.flatten.min
2654
- end
2655
-
2656
- # Returns maximum value.
2657
- #
2658
- # @overload max(a, b)
2659
- # @overload max(a, b, c)
2660
- # @overload max(array)
2661
- #
2662
- # @param a [Numeric] value to compare
2663
- # @param b [Numeric] value to compare
2664
- # @param c [Numeric] value to compare
2665
- # @param array [Numeric] values to compare
2666
- #
2667
- # @return [Numeric] maximum value
2668
- #
2669
- def max(*args)
2670
- args.flatten.max
2671
- end
2672
-
2673
- # Constrains the number between min..max.
2674
- #
2675
- # @param value [Numeric] number to be constrained
2676
- # @param min [Numeric] lower bound of the range
2677
- # @param max [Numeric] upper bound of the range
2678
- #
2679
- # @return [Numeric] constrained number
2680
- #
2681
- def constrain(value, min, max)
2682
- value < min ? min : (value > max ? max : value)
2683
- end
2684
-
2685
- # Converts degree to radian.
2686
- #
2687
- # @param degree [Numeric] degree to convert
2688
- #
2689
- # @return [Numeric] radian
2690
- #
2691
- def radians(degree)
2692
- degree * DEG2RAD__
2693
- end
2694
-
2695
- # Converts radian to degree.
2696
- #
2697
- # @param radian [Numeric] radian to convert
2698
- #
2699
- # @return [Numeric] degree
2700
- #
2701
- def degrees(radian)
2702
- radian * RAD2DEG__
2703
- end
2704
-
2705
- # Returns the sine of an angle.
2706
- #
2707
- # @param angle [Numeric] angle in radians
2708
- #
2709
- # @return [Numeric] the sine
2710
- #
2711
- def sin(angle)
2712
- Math.sin angle
2713
- end
2714
-
2715
- # Returns the cosine of an angle.
2716
- #
2717
- # @param angle [Numeric] angle in radians
2718
- #
2719
- # @return [Numeric] the cosine
2720
- #
2721
- def cos(angle)
2722
- Math.cos angle
2723
- end
2724
-
2725
- # Returns the ratio of the sine and cosine of an angle.
2726
- #
2727
- # @param angle [Numeric] angle in radians
2728
- #
2729
- # @return [Numeric] the tangent
2730
- #
2731
- def tan(angle)
2732
- Math.tan angle
2733
- end
2734
-
2735
- # Returns the inverse of sin().
2736
- #
2737
- # @param value [Numeric] value for calculation
2738
- #
2739
- # @return [Numeric] the arc sine
2740
- #
2741
- def asin(value)
2742
- Math.asin value
2743
- end
2744
-
2745
- # Returns the inverse of cos().
2746
- #
2747
- # @param value [Numeric] value for calculation
2748
- #
2749
- # @return [Numeric] the arc cosine
2750
- #
2751
- def acos(value)
2752
- Math.acos value
2753
- end
2754
-
2755
- # Returns the inverse of tan().
2756
- #
2757
- # @param value [Numeric] value for valculation
2758
- #
2759
- # @return [Numeric] the arc tangent
2760
- #
2761
- def atan(value)
2762
- Math.atan value
2763
- end
2764
-
2765
- # Returns the angle from a specified point.
2766
- #
2767
- # @param y [Numeric] y of the point
2768
- # @param x [Numeric] x of the point
2769
- #
2770
- # @return [Numeric] the angle in radians
2771
- #
2772
- def atan2(y, x)
2773
- Math.atan2 y, x
2774
- end
2775
-
2776
- # Returns the perlin noise value.
2777
- #
2778
- # @overload noise(x)
2779
- # @overload noise(x, y)
2780
- # @overload noise(x, y, z)
2781
- #
2782
- # @param x [Numeric] horizontal point in noise space
2783
- # @param y [Numeric] vertical point in noise space
2784
- # @param z [Numeric] depth point in noise space
2785
- #
2786
- # @return [Numeric] noise value (0.0..1.0)
2787
- #
2788
- def noise(x, y = 0, z = 0)
2789
- Rays.perlin(x, y, z) / 2.0 + 0.5
2790
- end
2791
-
2792
- # Returns a random number in range low...high
2793
- #
2794
- # @overload random()
2795
- # @overload random(high)
2796
- # @overload random(low, high)
2797
- # @overload random(choices)
2798
- #
2799
- # @param low [Numeric] lower limit
2800
- # @param high [Numeric] upper limit
2801
- # @param choices [Array] array to choose from
2802
- #
2803
- # @return [Float] random number
2804
- #
2805
- def random(*args)
2806
- return args.first.sample if args.first.kind_of? Array
2807
- high, low = args.reverse
2808
- rand (low || 0).to_f...(high || 1).to_f
2809
- end
2810
-
2811
- # Creates a new vector.
2812
- #
2813
- # @overload createVector()
2814
- # @overload createVector(x, y)
2815
- # @overload createVector(x, y, z)
2816
- #
2817
- # @param x [Numeric] x of new vector
2818
- # @param y [Numeric] y of new vector
2819
- # @param z [Numeric] z of new vector
2820
- #
2821
- # @return [Vector] new vector
2822
- #
2823
- def createVector(*args)
2824
- Vector.new(*args, context: self)
2825
- end
2826
-
2827
- # Creates a new image.
2828
- #
2829
- # @overload createImage(w, h)
2830
- # @overload createImage(w, h, format)
2831
- #
2832
- # @param w [Numeric] width of new image
2833
- # @param h [Numeric] height of new image
2834
- # @param format [RGB, RGBA] image format
2835
- #
2836
- # @return [Image] new image
2837
- #
2838
- def createImage(w, h, format = RGBA)
2839
- colorspace = {RGB => Rays::RGB, RGBA => Rays::RGBA}[format]
2840
- raise ArgumentError, "Unknown image format" unless colorspace
2841
- Image.new Rays::Image.new(w, h, colorspace).paint {background 0, 0}
2842
- end
2843
-
2844
- # Creates a camera object as a video input device.
2845
- #
2846
- # @return [Capture] camera object
2847
- #
2848
- def createCapture(*args)
2849
- Capture.new(*args)
2850
- end
2851
-
2852
- # Creates a new off-screen graphics context object.
2853
- #
2854
- # @param width [Numeric] width of graphics image
2855
- # @param height [Numeric] height of graphics image
2856
- #
2857
- # @return [Graphics] graphics object
2858
- #
2859
- def createGraphics(width, height)
2860
- Graphics.new width, height
2861
- end
2862
-
2863
- # Loads image.
2864
- #
2865
- # @param filename [String] file name to load image
2866
- # @param extension [String] type of image to load (ex. 'png')
2867
- #
2868
- # @return [Image] loaded image object
2869
- #
2870
- def loadImage(filename, extension = nil)
2871
- filename = getImage__ filename, extension if filename =~ %r|^https?://|
2872
- Image.new Rays::Image.load filename
2873
- end
2874
-
2875
- # @private
2876
- private def getImage__(uri, ext)
2877
- ext ||= File.extname uri
2878
- raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
2879
-
2880
- tmpdir = tmpdir__
2881
- path = tmpdir + Digest::SHA1.hexdigest(uri)
2882
- path = path.sub_ext ext
2883
-
2884
- unless path.file?
2885
- URI.open uri do |input|
2886
- input.set_encoding nil# disable default_internal
2887
- tmpdir.mkdir unless tmpdir.directory?
2888
- path.open('w') do |output|
2889
- output.set_encoding Encoding::ASCII_8BIT
2890
- while buf = input.read(2 ** 16)
2891
- output.write buf
2892
- end
2893
- end
2894
- end
2895
- end
2896
- path.to_s
2897
- end
2898
-
2899
- # @private
2900
- private def tmpdir__()
2901
- Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
2902
- end
2903
-
2904
- end# Context
2905
-
2906
-
2907
- end# Processing
2908
-
2909
-
2910
- end# RubySketch