-
Notifications
You must be signed in to change notification settings - Fork 65
/
BalloonEnginePlugin.class.st
3445 lines (2940 loc) · 118 KB
/
BalloonEnginePlugin.class.st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"
This class adds the plugin functionality for the Balloon graphics engine.
BalloonEnginePlugin should be translated but its superclass should not since it is incorporated within this class's translation process. Nor should the simulation subclass be translated
"
Class {
#name : #BalloonEnginePlugin,
#superclass : #BalloonEngineBase,
#category : #'VMMaker-Plugins'
}
{ #category : #'class initialization' }
BalloonEnginePlugin class >> declareCVarsIn: cg [
"Nothing to declare"
]
{ #category : #private }
BalloonEnginePlugin >> absoluteSquared8Dot24: value [
"Compute the squared value of a 8.24 number with 0.0 <= value < 1.0,
e.g., compute (value * value) bitShift: -24"
| word1 word2 |
<inline: true>
<var: 'word1' type: #'unsigned int'>
<var: 'word2' type: #'unsigned int'>
word1 := value bitAnd: 16rFFFF.
word2 := (value bitShift: -16) bitAnd: 255.
^(( (word1 * word1) bitShift: -16) +
((word1 * word2) * 2) +
((word2 * word2) bitShift: 16)) bitShift: -8
]
{ #category : #'beziers-wide' }
BalloonEnginePlugin >> adjustWideBezierLeft: bezier width: lineWidth offset: lineOffset endX: endX [
"Adjust the wide bezier curve (dx < 0) to start/end at the right point"
| lastX lastY |
<inline: false>
(self bezierUpdateDataOf: bezier) at: GBUpdateX put:
(((self bezierUpdateDataOf: bezier) at: GBUpdateX) - (lineOffset * 256)).
"Set the lastX/Y value of the second curve lineWidth pixels right/down"
lastX := (self wideBezierUpdateDataOf: bezier) at: GBUpdateX.
(self wideBezierUpdateDataOf: bezier) at: GBUpdateX put: lastX + (lineWidth - lineOffset * 256).
"Set lineWidth pixels down"
lastY := (self wideBezierUpdateDataOf: bezier) at: GBUpdateY.
(self wideBezierUpdateDataOf: bezier) at: GBUpdateY put: lastY + (lineWidth * 256).
"Record the last X value"
self bezierFinalXOf: bezier put: endX - lineOffset.
]
{ #category : #'beziers-wide' }
BalloonEnginePlugin >> adjustWideBezierRight: bezier width: lineWidth offset: lineOffset endX: endX [
"Adjust the wide bezier curve (dx >= 0) to start/end at the right point"
| lastX lastY |
<inline: false>
(self bezierUpdateDataOf: bezier) at: GBUpdateX put:
(((self bezierUpdateDataOf: bezier) at: GBUpdateX) + (lineOffset * 256)).
"Set the lastX/Y value of the second curve lineWidth pixels right/down"
"Set lineWidth-lineOffset pixels left"
lastX := (self wideBezierUpdateDataOf: bezier) at: GBUpdateX.
(self wideBezierUpdateDataOf: bezier) at: GBUpdateX put: lastX - (lineWidth - lineOffset * 256).
lastY := (self wideBezierUpdateDataOf: bezier) at: GBUpdateY.
"Set lineWidth pixels down"
(self wideBezierUpdateDataOf: bezier) at: GBUpdateY put: lastY + (lineWidth * 256).
"Record the last X value"
self bezierFinalXOf: bezier put: endX - lineOffset + lineWidth.
]
{ #category : #'lines-wide' }
BalloonEnginePlugin >> adjustWideLine: line afterSteppingFrom: lastX to: nextX [
"Adjust the wide line after it has been stepped from lastX to nextX.
Special adjustments of line width and start position are made here
to simulate a rectangular brush"
| yEntry yExit lineWidth lineOffset deltaX xDir baseWidth |
<inline: false> "Don't inline this"
"Fetch the values the adjustment decisions are based on"
yEntry := (self wideLineEntryOf: line).
yExit := (self wideLineExitOf: line).
baseWidth := self wideLineExtentOf: line.
lineOffset := self offsetFromWidth: baseWidth.
lineWidth := self wideLineWidthOf: line.
xDir := self lineXDirectionOf: line.
deltaX := nextX - lastX.
"Adjust the start of the line to fill an entire rectangle"
yEntry < baseWidth ifTrue:[
xDir < 0
ifTrue:[ lineWidth := lineWidth - deltaX] "effectively adding"
ifFalse:[ lineWidth := lineWidth + deltaX.
self edgeXValueOf: line put: lastX].
].
"Adjust the end of x-major lines"
((yExit + lineOffset) = 0) ifTrue:[
xDir > 0
ifTrue:[lineWidth := lineWidth - (self lineXIncrementOf: line)]
ifFalse:[lineWidth := lineWidth + (self lineXIncrementOf: line). "effectively subtracting"
self edgeXValueOf: line put: lastX].
].
"Adjust the end of the line to fill an entire rectangle"
(yExit + lineOffset) > 0 ifTrue:[
xDir < 0
ifTrue:[ lineWidth := lineWidth + deltaX. "effectively subtracting"
self edgeXValueOf: line put: lastX]
ifFalse:[ lineWidth := lineWidth - deltaX]
].
"Store the manipulated line width back"
self wideLineWidthOf: line put: lineWidth.
]
{ #category : #allocation }
BalloonEnginePlugin >> allocateBezier [
| bezier |
(self allocateObjEntry: GBBaseSize) ifFalse:[^0].
bezier := objUsed.
objUsed := bezier + GBBaseSize.
self objectTypeOf: bezier put: GEPrimitiveBezier.
self objectIndexOf: bezier put: 0.
self objectLengthOf: bezier put: GBBaseSize.
^bezier
]
{ #category : #allocation }
BalloonEnginePlugin >> allocateBezierStackEntry [
self wbStackPush: 6.
^self wbStackSize
]
{ #category : #allocation }
BalloonEnginePlugin >> allocateBitmapFill: cmSize colormap: cmBits [
| fill fillSize cm |
<var:#cm type:'int *'>
<var:#cmBits type:'int *'>
fillSize := GBMBaseSize + cmSize.
(self allocateObjEntry: fillSize) ifFalse:[^0].
fill := objUsed.
objUsed := fill + fillSize.
self objectTypeOf: fill put: GEPrimitiveClippedBitmapFill.
self objectIndexOf: fill put: 0.
self objectLengthOf: fill put: fillSize.
cm := self colormapOf: fill.
self hasColorTransform ifTrue:[
0 to: cmSize-1 do:[:i| cm at: i put: (self transformColor: (cmBits at: i))].
] ifFalse:[
0 to: cmSize-1 do:[:i| cm at: i put: (cmBits at: i)].
].
self bitmapCmSizeOf: fill put: cmSize.
^fill
]
{ #category : #allocation }
BalloonEnginePlugin >> allocateGradientFill: ramp rampWidth: rampWidth isRadial: isRadial [
| fill fillSize rampPtr |
<var:#ramp type:'int *'>
<var:#rampPtr type:'int *'>
fillSize := GGBaseSize + rampWidth.
(self allocateObjEntry: fillSize) ifFalse:[^0].
fill := objUsed.
objUsed := fill + fillSize.
isRadial
ifTrue:[self objectTypeOf: fill put: GEPrimitiveRadialGradientFill]
ifFalse:[self objectTypeOf: fill put: GEPrimitiveLinearGradientFill].
self objectIndexOf: fill put: 0.
self objectLengthOf: fill put: fillSize.
rampPtr := self gradientRampOf: fill.
self hasColorTransform ifTrue:[
0 to: rampWidth-1 do:[:i| rampPtr at: i put: (self transformColor: (ramp at: i))].
] ifFalse:[
0 to: rampWidth-1 do:[:i| rampPtr at: i put: (ramp at: i)].
].
self gradientRampLengthOf: fill put: rampWidth.
^fill
]
{ #category : #allocation }
BalloonEnginePlugin >> allocateLine [
| line |
(self allocateObjEntry: GLBaseSize) ifFalse:[^0].
line := objUsed.
objUsed := line + GLBaseSize.
self objectTypeOf: line put: GEPrimitiveLine.
self objectIndexOf: line put: 0.
self objectLengthOf: line put: GLBaseSize.
^line
]
{ #category : #allocation }
BalloonEnginePlugin >> allocateWideBezier [
| bezier |
(self allocateObjEntry: GBWideSize) ifFalse:[^0].
bezier := objUsed.
objUsed := bezier + GBWideSize.
self objectTypeOf: bezier put: GEPrimitiveWideBezier.
self objectIndexOf: bezier put: 0.
self objectLengthOf: bezier put: GBWideSize.
^bezier
]
{ #category : #allocation }
BalloonEnginePlugin >> allocateWideLine [
| line |
(self allocateObjEntry: GLWideSize) ifFalse:[^0].
line := objUsed.
objUsed := line + GLWideSize.
self objectTypeOf: line put: GEPrimitiveWideLine.
self objectIndexOf: line put: 0.
self objectLengthOf: line put: GLWideSize.
^line
]
{ #category : #'bezier-loading' }
BalloonEnginePlugin >> assureValue: val1 between: val2 and: val3 [
"Make sure that val1 is between val2 and val3."
<inline: true>
val2 > val3 ifTrue:[
val1 > val2 ifTrue:[^val2].
val1 < val3 ifTrue:[^val3].
] ifFalse:[
val1 < val2 ifTrue:[^val2].
val1 > val3 ifTrue:[^val3].
].
^val1
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierEndXOf: bezier [
^self obj: bezier at: GBEndX
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierEndXOf: bezier put: value [
^self obj: bezier at: GBEndX put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierEndYOf: bezier [
^self obj: bezier at: GBEndY
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierEndYOf: bezier put: value [
^self obj: bezier at: GBEndY put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierFinalXOf: bezier [
^self obj: bezier at: GBFinalX
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierFinalXOf: bezier put: value [
^self obj: bezier at: GBFinalX put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierUpdateDataOf: bezier [
<returnTypeC: 'int *'>
^objBuffer + bezier + GBUpdateData
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierViaXOf: bezier [
^self obj: bezier at: GBViaX
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierViaXOf: bezier put: value [
^self obj: bezier at: GBViaX put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierViaYOf: bezier [
^self obj: bezier at: GBViaY
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bezierViaYOf: bezier put: value [
^self obj: bezier at: GBViaY put: value
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapCmSizeOf: bmFill [
^self obj: bmFill at: GBColormapSize
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapCmSizeOf: bmFill put: value [
^self obj: bmFill at: GBColormapSize put: value
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapDepthOf: bmFill [
^self obj: bmFill at: GBBitmapDepth
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapDepthOf: bmFill put: value [
^self obj: bmFill at: GBBitmapDepth put: value
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapHeightOf: bmFill [
^self obj: bmFill at: GBBitmapHeight
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapHeightOf: bmFill put: value [
^self obj: bmFill at: GBBitmapHeight put: value
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapRasterOf: bmFill [
^self obj: bmFill at: GBBitmapRaster
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapRasterOf: bmFill put: value [
^self obj: bmFill at: GBBitmapRaster put: value
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapSizeOf: bmFill [
^self obj: bmFill at: GBBitmapSize
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapSizeOf: bmFill put: value [
^self obj: bmFill at: GBBitmapSize put: value
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapTileFlagOf: bmFill [
^self obj: bmFill at: GBTileFlag
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapTileFlagOf: bmFill put: value [
^self obj: bmFill at: GBTileFlag put: value
]
{ #category : #'fills-bitmaps' }
BalloonEnginePlugin >> bitmapValue: bmFill bits: bits atX: xp y: yp [
| bmDepth bmRaster value rShift cMask r g b a |
<inline: true>
bmDepth := self bitmapDepthOf: bmFill.
bmRaster := self bitmapRasterOf: bmFill.
bmDepth = 32 ifTrue: [
value := (self cCoerce: bits to:'int*') at: (bmRaster * yp) + xp.
(value ~= 0 and: [(value bitAnd: 16rFF000000) = 0])
ifTrue: [value := value bitOr: 16rFF000000].
^self uncheckedTransformColor: value].
"rShift - shift value to convert from pixel to word index"
rShift := self rShiftTable at: bmDepth.
value := self makeUnsignedFrom:
((self cCoerce: bits to:'int*') at: (bmRaster * yp) + (xp >> rShift)).
"cMask - mask out the pixel from the word"
cMask := (1 << bmDepth) - 1.
"rShift - shift value to move the pixel in the word to the lowest bit position"
rShift := 32 - bmDepth - ((xp bitAnd: (1 << rShift - 1)) * bmDepth).
value := (value >> rShift) bitAnd: cMask.
bmDepth = 16 ifTrue: [
"Must convert by expanding bits"
value = 0 ifFalse: [
b := (value bitAnd: 31) << 3. b := b + (b >> 5).
g := (value >> 5 bitAnd: 31) << 3. g := g + (g >> 5).
r := (value >> 10 bitAnd: 31) << 3. r := r + (r >> 5).
a := 255.
value := b + (g << 8) + (r << 16) + (a << 24)].
] ifFalse: [
"Must convert by using color map"
(self bitmapCmSizeOf: bmFill) = 0
ifTrue: [value := 0]
ifFalse: [value := self makeUnsignedFrom: ((self colormapOf: bmFill) at: value)].
].
^self uncheckedTransformColor: value.
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapWidthOf: bmFill [
^self obj: bmFill at: GBBitmapWidth
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> bitmapWidthOf: bmFill put: value [
^self obj: bmFill at: GBBitmapWidth put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzEndX: index [
^self wbStackValue: self wbStackSize - index + 4
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzEndX: index put: value [
^self wbStackValue: self wbStackSize - index + 4 put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzEndY: index [
^self wbStackValue: self wbStackSize - index + 5
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzEndY: index put: value [
^self wbStackValue: self wbStackSize - index + 5 put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzStartX: index [
^self wbStackValue: self wbStackSize - index + 0
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzStartX: index put: value [
^self wbStackValue: self wbStackSize - index + 0 put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzStartY: index [
^self wbStackValue: self wbStackSize - index + 1
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzStartY: index put: value [
^self wbStackValue: self wbStackSize - index + 1 put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzViaX: index [
^self wbStackValue: self wbStackSize - index + 2
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzViaX: index put: value [
^self wbStackValue: self wbStackSize - index + 2 put: value
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzViaY: index [
^self wbStackValue: self wbStackSize - index + 3
]
{ #category : #'accessing beziers' }
BalloonEnginePlugin >> bzViaY: index put: value [
^self wbStackValue: self wbStackSize - index + 3 put: value
]
{ #category : #'shapes-compressed' }
BalloonEnginePlugin >> checkCompressedFillIndexList: fillList max: maxIndex segments: nSegs [
"Check the fill indexes in the run-length encoded fillList"
| length runLength runValue nFills fillPtr |
<inline: false>
<var: #fillPtr type:'int *'>
length := interpreterProxy slotSizeOf: fillList.
fillPtr := interpreterProxy firstIndexableField: fillList.
nFills := 0.
0 to: length-1 do:[:i |
runLength := self shortRunLengthAt: i from: fillPtr.
runValue := self shortRunValueAt: i from: fillPtr.
(runValue >= 0 and:[runValue <= maxIndex]) ifFalse:[^false].
nFills := nFills + runLength.
].
^nFills = nSegs
]
{ #category : #'shapes-compressed' }
BalloonEnginePlugin >> checkCompressedFills: indexList [
"Check if the indexList (containing fill handles) is okay."
| fillPtr length fillIndex |
<inline: false>
<var: #fillPtr type:'int *'>
"First check if the oops have the right format"
(interpreterProxy isWords: indexList) ifFalse:[^false].
"Then check the fill entries"
length := interpreterProxy slotSizeOf: indexList.
fillPtr := interpreterProxy firstIndexableField: indexList.
0 to: length-1 do:[:i |
fillIndex := fillPtr at: i.
"Make sure the fill is okay"
(self isFillOkay: fillIndex) ifFalse:[^false]].
^ true
]
{ #category : #'shapes-compressed' }
BalloonEnginePlugin >> checkCompressedLineWidths: lineWidthList segments: nSegments [
"Check the run-length encoded lineWidthList matches nSegments"
| length runLength nItems ptr |
<inline: false>
<var: #ptr type:'int *'>
length := interpreterProxy slotSizeOf: lineWidthList.
ptr := interpreterProxy firstIndexableField: lineWidthList.
nItems := 0.
0 to: length-1 do:[:i|
runLength := self shortRunLengthAt: i from: ptr.
nItems := nItems + runLength.
].
^nItems = nSegments
]
{ #category : #'shapes-compressed' }
BalloonEnginePlugin >> checkCompressedPoints: points segments: nSegments [
"Check if the given point array can be handled by the engine."
| pSize |
<inline: false>
(interpreterProxy isWords: points) ifFalse:[^false].
pSize := interpreterProxy slotSizeOf: points.
"The points must be either in PointArray format or ShortPointArray format.
Also, we currently handle only quadratic segments (e.g., 3 points each) and thus either
pSize = nSegments * 3, for ShortPointArrays or,
pSize = nSegments * 6, for PointArrays"
(pSize = (nSegments * 3) or:[pSize = (nSegments * 6)])
ifFalse:[^false]. "Can't handle this"
^true
]
{ #category : #'shapes-compressed' }
BalloonEnginePlugin >> checkCompressedShape: points segments: nSegments leftFills: leftFills rightFills: rightFills lineWidths: lineWidths lineFills: lineFills fillIndexList: fillIndexList [
"Check if the given shape can be handled by the engine.
Since there are a number of requirements this is an extra method."
| maxFillIndex |
<inline: false>
(self checkCompressedPoints: points segments: nSegments)
ifFalse:[^false].
(self checkCompressedFills: fillIndexList)
ifFalse:[^false].
maxFillIndex := interpreterProxy slotSizeOf: fillIndexList.
(self checkCompressedFillIndexList: leftFills max: maxFillIndex segments: nSegments)
ifFalse:[^false].
(self checkCompressedFillIndexList: rightFills max: maxFillIndex segments: nSegments)
ifFalse:[^false].
(self checkCompressedFillIndexList: lineFills max: maxFillIndex segments: nSegments)
ifFalse:[^false].
(self checkCompressedLineWidths: lineWidths segments: nSegments)
ifFalse:[^false].
^true
]
{ #category : #'GET processing' }
BalloonEnginePlugin >> checkedAddBezierToGET: bezier [
"Add the bezier to the global edge table if it intersects the clipping region"
| lineWidth |
<inline: true>
(self isWide: bezier)
ifTrue:[lineWidth := (self wideBezierExtentOf: bezier)]
ifFalse:[lineWidth := 0].
(self bezierEndYOf: bezier) + lineWidth < (self fillMinYGet) ifTrue:[^0].
"Overlaps in Y but may still be entirely right of clip region"
((self edgeXValueOf: bezier) - lineWidth >= self fillMaxXGet and:[
(self bezierEndXOf: bezier) - lineWidth >= self fillMaxXGet]) ifTrue:[^0].
self addEdgeToGET: bezier.
]
{ #category : #'GET processing' }
BalloonEnginePlugin >> checkedAddEdgeToGET: edge [
"Add the edge to the global edge table.
For known edge types, check if the edge intersects the visible region"
<inline: true>
(self isLine: edge) ifTrue:[^self checkedAddLineToGET: edge].
(self isBezier: edge) ifTrue:[^self checkedAddBezierToGET: edge].
self addEdgeToGET: edge.
]
{ #category : #'GET processing' }
BalloonEnginePlugin >> checkedAddLineToGET: line [
"Add the line to the global edge table if it intersects the clipping region"
| lineWidth |
<inline: true>
(self isWide: line)
ifTrue:[lineWidth := (self wideLineExtentOf: line)]
ifFalse:[lineWidth := 0].
(self lineEndYOf: line) + lineWidth < (self fillMinYGet) ifTrue:[^0].
"Overlaps in Y but may still be entirely right of clip region"
((self edgeXValueOf: line) - lineWidth >= self fillMaxXGet and:[
(self lineEndXOf: line) - lineWidth >= self fillMaxXGet]) ifTrue:[^0].
self addEdgeToGET: line.
]
{ #category : #private }
BalloonEnginePlugin >> circleCosTable [
| theTable |
<returnTypeC:'double *'>
<inline: false>
<var:#theTable declareC:'static double theTable[33] =
{1.0, 0.98078528040323, 0.923879532511287, 0.831469612302545,
0.7071067811865475, 0.555570233019602, 0.38268343236509, 0.1950903220161286,
0.0, -0.1950903220161283, -0.3826834323650896, -0.555570233019602,
-0.707106781186547, -0.831469612302545, -0.9238795325112865, -0.98078528040323,
-1.0, -0.98078528040323, -0.923879532511287, -0.831469612302545,
-0.707106781186548, -0.555570233019602, -0.3826834323650903, -0.1950903220161287,
0.0, 0.1950903220161282, 0.38268343236509, 0.555570233019602,
0.707106781186547, 0.831469612302545, 0.9238795325112865, 0.98078528040323,
1.0 }'>
^theTable
]
{ #category : #private }
BalloonEnginePlugin >> circleSinTable [
| theTable |
<returnTypeC:'double *'>
<inline: false>
<var:#theTable declareC:'static double theTable[33] =
{0.0, 0.1950903220161282, 0.3826834323650897, 0.555570233019602,
0.707106781186547, 0.831469612302545, 0.923879532511287, 0.98078528040323,
1.0, 0.98078528040323, 0.923879532511287, 0.831469612302545,
0.7071067811865475, 0.555570233019602, 0.38268343236509, 0.1950903220161286,
0.0, -0.1950903220161283, -0.3826834323650896, -0.555570233019602,
-0.707106781186547, -0.831469612302545, -0.9238795325112865, -0.98078528040323,
-1.0, -0.98078528040323, -0.923879532511287, -0.831469612302545,
-0.707106781186548, -0.555570233019602, -0.3826834323650903, -0.1950903220161287,
0.0 }'>
^theTable
]
{ #category : #'fills-bitmaps' }
BalloonEnginePlugin >> clampValue: value max: maxValue [
<inline: true>
value < 0
ifTrue:[^0]
ifFalse:[value >= maxValue
ifTrue:[^maxValue-1]
ifFalse:[^value]]
]
{ #category : #'accessing bitmaps' }
BalloonEnginePlugin >> colormapOf: bmFill [
<returnTypeC:'int *'>
^objBuffer + bmFill + GBColormapOffset
]
{ #category : #'bezier-loading' }
BalloonEnginePlugin >> computeBezier: index splitAt: param [
"Split the bezier curve at the given parametric value.
Note: Since this method is only invoked to make non-monoton
beziers monoton we must check for the resulting y values
to be *really* between the start and end value."
| startX startY viaX viaY endX endY newIndex
leftViaX leftViaY rightViaX rightViaY sharedX sharedY |
<inline: false>
<var: #param type:'double '>
leftViaX := startX := self bzStartX: index.
leftViaY := startY := self bzStartY: index.
rightViaX := viaX := self bzViaX: index.
rightViaY := viaY := self bzViaY: index.
endX := self bzEndX: index.
endY := self bzEndY: index.
"Compute intermediate points"
sharedX := leftViaX := leftViaX + ((viaX - startX) asFloat * param) asInteger.
sharedY := leftViaY := leftViaY + ((viaY - startY) asFloat * param) asInteger.
rightViaX := rightViaX + ((endX - viaX) asFloat * param) asInteger.
rightViaY := rightViaY + ((endY - viaY) asFloat * param) asInteger.
"Compute new shared point"
sharedX := sharedX + ((rightViaX - leftViaX) asFloat * param) asInteger.
sharedY := sharedY + ((rightViaY - leftViaY) asFloat * param) asInteger.
"Check the new via points"
leftViaY := self assureValue: leftViaY between: startY and: sharedY.
rightViaY := self assureValue: rightViaY between: sharedY and: endY.
newIndex := self allocateBezierStackEntry.
engineStopped ifTrue:[^0]. "Something went wrong"
"Store the first part back"
self bzViaX: index put: leftViaX.
self bzViaY: index put: leftViaY.
self bzEndX: index put: sharedX.
self bzEndY: index put: sharedY.
"Store the second point back"
self bzStartX: newIndex put: sharedX.
self bzStartY: newIndex put: sharedY.
self bzViaX: newIndex put: rightViaX.
self bzViaY: newIndex put: rightViaY.
self bzEndX: newIndex put: endX.
self bzEndY: newIndex put: endY.
^newIndex
]
{ #category : #'bezier-loading' }
BalloonEnginePlugin >> computeBezierSplitAtHalf: index [
"Split the bezier curve at 0.5."
| startX startY viaX viaY endX endY newIndex
leftViaX leftViaY rightViaX rightViaY sharedX sharedY |
<inline: false>
newIndex := self allocateBezierStackEntry.
engineStopped ifTrue:[^0]. "Something went wrong"
leftViaX := startX := self bzStartX: index.
leftViaY := startY := self bzStartY: index.
rightViaX := viaX := self bzViaX: index.
rightViaY := viaY := self bzViaY: index.
endX := self bzEndX: index.
endY := self bzEndY: index.
"Compute intermediate points"
leftViaX := leftViaX + ((viaX - startX) // 2).
leftViaY := leftViaY + ((viaY - startY) // 2).
sharedX := rightViaX := rightViaX + ((endX - viaX) // 2).
sharedY := rightViaY := rightViaY + ((endY - viaY) // 2).
"Compute new shared point"
sharedX := sharedX + ((leftViaX - rightViaX) // 2).
sharedY := sharedY + ((leftViaY - rightViaY) // 2).
"Store the first part back"
self bzViaX: index put: leftViaX.
self bzViaY: index put: leftViaY.
self bzEndX: index put: sharedX.
self bzEndY: index put: sharedY.
"Store the second point back"
self bzStartX: newIndex put: sharedX.
self bzStartY: newIndex put: sharedY.
self bzViaX: newIndex put: rightViaX.
self bzViaY: newIndex put: rightViaY.
self bzEndX: newIndex put: endX.
self bzEndY: newIndex put: endY.
^newIndex
]
{ #category : #'beziers-wide' }
BalloonEnginePlugin >> computeFinalWideBezierValues: bezier width: lineWidth [
"Get both values from the two boundaries of the given bezier
and compute the actual position/width of the line"
| leftX rightX temp |
leftX := ((self bezierUpdateDataOf: bezier) at: GBUpdateX) // 256.
rightX := ((self wideBezierUpdateDataOf: bezier) at: GBUpdateX) // 256.
leftX > rightX ifTrue:[temp := leftX. leftX := rightX. rightX := temp].
self edgeXValueOf: bezier put: leftX.
(rightX - leftX) > lineWidth ifTrue:[
self wideBezierWidthOf: bezier put: (rightX - leftX).
] ifFalse:[
self wideBezierWidthOf: bezier put: lineWidth.
].
]
{ #category : #'fills-bitmaps' }
BalloonEnginePlugin >> fillBitmapSpan [
<inline: true>
^self fillBitmapSpan: self lastExportedFillGet from: self lastExportedLeftXGet to: self lastExportedRightXGet at: self currentYGet
]
{ #category : #'fills-bitmaps' }
BalloonEnginePlugin >> fillBitmapSpan: bmFill from: leftX to: rightX at: yValue [
| x x1 dsX ds dtX dt deltaX deltaY bits xp yp bmWidth bmHeight fillValue tileFlag |
<inline: false>
<var: #bits type:'int *'>
self aaLevelGet = 1
ifFalse:[^self fillBitmapSpanAA: bmFill from: leftX to: rightX at: yValue].
bits := self loadBitsFrom: bmFill.
bits == nil ifTrue:[^nil].
bmWidth := self bitmapWidthOf: bmFill.
bmHeight := self bitmapHeightOf: bmFill.
tileFlag := (self bitmapTileFlagOf: bmFill) = 1.
deltaX := leftX - (self fillOriginXOf: bmFill).
deltaY := yValue - (self fillOriginYOf: bmFill).
dsX := self fillDirectionXOf: bmFill.
dtX := self fillNormalXOf: bmFill.
ds := (deltaX * dsX) + (deltaY * (self fillDirectionYOf: bmFill)).
dt := (deltaX * dtX) + (deltaY * (self fillNormalYOf: bmFill)).
x := leftX.
x1 := rightX.
[x < x1] whileTrue:[
tileFlag ifTrue:[
ds := self repeatValue: ds max: bmWidth << 16.
dt := self repeatValue: dt max: bmHeight << 16].
xp := ds // 16r10000.
yp := dt // 16r10000.
tileFlag ifFalse:[
xp := self clampValue: xp max: bmWidth.
yp := self clampValue: yp max: bmHeight].
(xp >= 0 and:[yp >= 0 and:[xp < bmWidth and:[yp < bmHeight]]]) ifTrue:[
fillValue := self bitmapValue: bmFill bits: bits atX: xp y: yp.
spanBuffer at: x put: fillValue.
].
ds := ds + dsX.
dt := dt + dtX.
x := x + 1.
].
]
{ #category : #'fills-bitmaps' }
BalloonEnginePlugin >> fillBitmapSpanAA: bmFill from: leftX to: rightX at: yValue [
| x dsX ds dtX dt deltaX deltaY bits xp yp bmWidth bmHeight fillValue baseShift cMask cShift idx aaLevel firstPixel lastPixel tileFlag |
<inline: false>
<var: #bits type:'int *'>
bits := self loadBitsFrom: bmFill.
bits == nil ifTrue:[^nil].
bmWidth := self bitmapWidthOf: bmFill.
bmHeight := self bitmapHeightOf: bmFill.
tileFlag := (self bitmapTileFlagOf: bmFill) = 1.
deltaX := leftX - (self fillOriginXOf: bmFill).
deltaY := yValue - (self fillOriginYOf: bmFill).
dsX := self fillDirectionXOf: bmFill.
dtX := self fillNormalXOf: bmFill.
ds := (deltaX * dsX) + (deltaY * (self fillDirectionYOf: bmFill)).
dt := (deltaX * dtX) + (deltaY * (self fillNormalYOf: bmFill)).
aaLevel := self aaLevelGet.
firstPixel := self aaFirstPixelFrom: leftX to: rightX.
lastPixel := self aaLastPixelFrom: leftX to: rightX.
baseShift := self aaShiftGet.
cMask := self aaColorMaskGet.
cShift := self aaColorShiftGet.
x := leftX.
[x < firstPixel] whileTrue:[
tileFlag ifTrue:[
ds := self repeatValue: ds max: bmWidth << 16.
dt := self repeatValue: dt max: bmHeight << 16].
xp := ds // 16r10000.
yp := dt // 16r10000.
tileFlag ifFalse:[
xp := self clampValue: xp max: bmWidth.
yp := self clampValue: yp max: bmHeight].
(xp >= 0 and:[yp >= 0 and:[xp < bmWidth and:[yp < bmHeight]]]) ifTrue:[
fillValue := self bitmapValue: bmFill bits: bits atX: xp y: yp.
fillValue := (fillValue bitAnd: cMask) >> cShift.
idx := x >> baseShift.
spanBuffer at: idx put: (spanBuffer at: idx) + fillValue.
].
ds := ds + dsX.
dt := dt + dtX.
x := x + 1.
].
cMask := (self aaColorMaskGet >> self aaShiftGet) bitOr: 16rF0F0F0F0.
cShift := self aaShiftGet.
[x < lastPixel] whileTrue:[
tileFlag ifTrue:[
ds := self repeatValue: ds max: bmWidth << 16.
dt := self repeatValue: dt max: bmHeight << 16].
xp := ds // 16r10000.
yp := dt // 16r10000.
tileFlag ifFalse:[
xp := self clampValue: xp max: bmWidth.
yp := self clampValue: yp max: bmHeight].
(xp >= 0 and:[yp >= 0 and:[xp < bmWidth and:[yp < bmHeight]]]) ifTrue:[
fillValue := self bitmapValue: bmFill bits: bits atX: xp y: yp.
fillValue := (fillValue bitAnd: cMask) >> cShift.
idx := x >> baseShift.
spanBuffer at: idx put: (spanBuffer at: idx) + fillValue.
].
ds := ds + (dsX << cShift).
dt := dt + (dtX << cShift).
x := x + aaLevel.
].
cMask := self aaColorMaskGet.
cShift := self aaColorShiftGet.
[x < rightX] whileTrue:[
tileFlag ifTrue:[
ds := self repeatValue: ds max: bmWidth << 16.
dt := self repeatValue: dt max: bmHeight << 16].
xp := ds // 16r10000.
yp := dt // 16r10000.
tileFlag ifFalse:[
xp := self clampValue: xp max: bmWidth.
yp := self clampValue: yp max: bmHeight].
(xp >= 0 and:[yp >= 0 and:[xp < bmWidth and:[yp < bmHeight]]]) ifTrue:[
fillValue := self bitmapValue: bmFill bits: bits atX: xp y: yp.
fillValue := (fillValue bitAnd: cMask) >> cShift.
idx := x >> baseShift.
spanBuffer at: idx put: (spanBuffer at: idx) + fillValue.
].
ds := ds + dsX.
dt := dt + dtX.
x := x + 1.
].
]
{ #category : #'accessing fills' }
BalloonEnginePlugin >> fillDirectionXOf: fill [
^self obj: fill at: GFDirectionX
]
{ #category : #'accessing fills' }
BalloonEnginePlugin >> fillDirectionXOf: fill put: value [
^self obj: fill at: GFDirectionX put: value
]
{ #category : #'accessing fills' }
BalloonEnginePlugin >> fillDirectionYOf: fill [
^self obj: fill at: GFDirectionY
]
{ #category : #'accessing fills' }
BalloonEnginePlugin >> fillDirectionYOf: fill put: value [
^self obj: fill at: GFDirectionY put: value
]
{ #category : #'fills-gradient' }
BalloonEnginePlugin >> fillLinearGradient [
<inline: true>
^self fillLinearGradient: self lastExportedFillGet from: self lastExportedLeftXGet to: self lastExportedRightXGet at: self currentYGet
]
{ #category : #'fills-gradient' }
BalloonEnginePlugin >> fillLinearGradient: fill from: leftX to: rightX at: yValue [
"Draw a linear gradient fill."
| x0 x1 ramp rampSize dsX ds x rampIndex |
<inline: false>
<var: #ramp type:'int *'>
ramp := self gradientRampOf: fill.
rampSize := self gradientRampLengthOf: fill.
dsX := self fillDirectionXOf: fill.
ds := ((leftX - (self fillOriginXOf: fill)) * dsX) +
((yValue - (self fillOriginYOf: fill)) * (self fillDirectionYOf: fill)).
x := x0 := leftX.
x1 := rightX.
"Note: The inner loop has been divided into three parts for speed"
"Part one: Fill everything outside the left boundary"
[((rampIndex := ds // 16r10000) < 0 or:[rampIndex >= rampSize]) and:[x < x1]]
whileTrue:[ x := x + 1.
ds := ds + dsX].
x > x0 ifTrue:[
rampIndex < 0 ifTrue:[rampIndex := 0].
rampIndex >= rampSize ifTrue:[rampIndex := rampSize - 1].
self fillColorSpan: (self makeUnsignedFrom: (ramp at: rampIndex)) from: x0 to: x].
"Part two: Fill everything inside the boundaries"
self aaLevelGet = 1 ifTrue:[
"Fast version w/o anti-aliasing"
[((rampIndex := ds // 16r10000) < rampSize and:[rampIndex >= 0]) and:[x < x1]] whileTrue:[
spanBuffer at: x put: (self makeUnsignedFrom: (ramp at: rampIndex)).
x := x + 1.
ds := ds + dsX.
].
] ifFalse:[x := self fillLinearGradientAA: fill ramp: ramp ds: ds dsX: dsX from: x to: rightX].
"Part three fill everything outside right boundary"
x < x1 ifTrue:[
rampIndex < 0 ifTrue:[rampIndex := 0].
rampIndex >= rampSize ifTrue:[rampIndex := rampSize-1].
self fillColorSpan: (self makeUnsignedFrom: (ramp at: rampIndex)) from: x to: x1].
]
{ #category : #'fills-gradient' }
BalloonEnginePlugin >> fillLinearGradientAA: fill ramp: ramp ds: deltaS dsX: dsX from: leftX to: rightX [
"This is the AA version of linear gradient filling."
| colorMask colorShift baseShift rampIndex ds rampSize x idx rampValue
aaLevel firstPixel lastPixel |
<inline: false>
<var: #ramp type:'int *'>
aaLevel := self aaLevelGet.
baseShift := self aaShiftGet.
rampSize := self gradientRampLengthOf: fill.
ds := deltaS.
x := leftX.
rampIndex := ds // 16r10000.
firstPixel := self aaFirstPixelFrom: leftX to: rightX.