rubysketch 0.3.21 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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