-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathPaintAsm.a
executable file
·2738 lines (2366 loc) · 117 KB
/
PaintAsm.a
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
.INCLUDE MAC:GRAFTYPES.TEXT
.INCLUDE MAC:SYSEQU.TEXT
.INCLUDE MAC:SYSMACS.TEXT
.INCLUDE MAC:TOOLEQU.TEXT
.INCLUDE MAC:GRAFEQU.TEXT
.INCLUDE MAC:TOOLMACS.TEXT
;------------------------------------------------------
;
; --> PAINTASM.TEXT, ASSY LANGUAGE FOR MACPAINT
;
.SEG ' '
.PROC EjectReset
;---------------------------------------------------------------------
;
; PROCEDURE EjectReset;
;
; eject default drive and re-boot Macintosh
;
LINK A6,#-IOVQElSize ;allocate an IOBlock
MOVE.L SP,A0 ;point to IOBlock
CLR.L IOVNPtr(A0) ;Nil name pointer
CLR.W IOVolIndex(A0) ;not by index
CLR.W IOVDrvNum(A0) ;default drive
_EJECT ;call OS
JMP $40000A ;nasty ROM address
.PROC %%%INIT
.DEF %_BEGIN,%_END,%_INIT,%_TERM
%_BEGIN CLR.L $10(A7) ; fake out pascal LINK A5,...
RTS
%_END RTS
%_INIT MOVE.L (A7)+,A0 ; pop ret add
UNLK A5
JMP (A0)
%_TERM MOVE.L (SP)+,A0 ; get ret add
LINK A5,#0
JMP (A0)
.SEG ' '
.FUNC PixelTrue
;---------------------------------------------------------------------
;
; FUNCTION PixelTrue(h,v: INTEGER; bits: BitMap): BOOLEAN;
;
MOVE.L (SP)+,A0 ;POP RETURN ADDR
MOVE.L (SP)+,A1 ;POP ADDR OF BITMAP
MOVE (SP)+,D0 ;POP VERT COORD
SUB BOUNDS+TOP(A1),D0 ;CONVERT TO GLOBAL
MULS ROWBYTES(A1),D0 ;TIMES ROWBYTES
MOVE (SP)+,D1 ;GET HORIZ COORD
SUB BOUNDS+LEFT(A1),D1 ;CONVERT TO GLOBAL
MOVE.L BASEADDR(A1),A1 ;POINT TO BASEADDR
ADD.L D0,A1 ;ADD VERT OFFSET
MOVE D1,D0 ;COPY HORIZ
ASR #3,D1 ;DIV BY 8 FOR BYTE
NOT D0 ;INVERT BITNUM
BTST D0,0(A1,D1.L) ;TEST THE BIT
SNE (SP) ;STORE RESULT
NEG.B (SP) ;CONVERT TO PASCAL BOOLEAN
JMP (A0) ;AND RETURN
.SEG ' '
.FUNC Monkey
;---------------------------------------------------------------------
;
; FUNCTION Monkey: BOOLEAN;
;
TST MonkeyLives ;IS THE MONKEY ACTIVE ?
SGE 4(SP) ;YES IF >= ZERO
NEG.B 4(SP) ;CONVERT TO PASCAL BOOLEAN
RTS
.SEG 'SegPrint'
.PROC Stretch2x
;---------------------------------------------------------------
;
; PROCEDURE Stretch2x(srcBuf,dstBuf: QDPtr);
;
; FOR HI-RES PRINTING.
; TAKES AN 11 TALL BY 72 BYTES WIDE BITMAP, STRETCHES AND
; FILTERS IT TO MAKE A 21 TALL BY 144 BYTES WIDE RESULT.
;
PARAMSIZE .EQU 8 ;TOTAL BYTES OF PARAMS
SRCBUF .EQU PARAMSIZE+8-4 ;LONG
DSTBUF .EQU SRCBUF-4 ;LONG
BUF2END .EQU -4 ;LONG
BUF2 .EQU BUF2END-4 ;LONG
BUF1 .EQU BUF2-4 ;LONG
VARSIZE .EQU BUF1 ;TOTAL LOCALS
SRCHEIGHT .EQU 11 ;SRC IS 11 SCANLINES TALL
SRCROW .EQU 72 ;SRC IS 72 BYTES WIDE
DSTROW .EQU 144 ;DST IS 144 BYTES WIDE
LINK A6,#VARSIZE ;ALLOCATE STACK FRAME
MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGS
;
; SET UP ASSORTED HANDY VARIABLES IN REGS
;
MOVE.L SRCBUF(A6),A0 ;POINT TO SRCBUF
MOVE.L DSTBUF(A6),A1 ;POINT TO DSTBUF
MOVE #DSTROW,D4 ;GET DST ROWBYTES
MOVE D4,D5 ;COPY IT
ADD D5,D5 ;MAKE 2*DSTROW
;
; ALLOCATE BUF1 AND BUF2 SCANLINE BUFFERS
;
MOVE.L SP,BUF2END(A6) ;REMEMBER END OF BUF2
SUB D4,SP ;ALLOCATE BUF2
MOVE.L SP,BUF2(A6) ;REMEMBER START OF BUF2
SUB D4,SP ;ALLOCATE BUF1
MOVE.L SP,BUF1(A6) ;REMEMBER START OF BUF1
;
; STRETCH LINES HORIZONTALLY FOR SRCHEIGHT ROWS
;
MOVE #SRCHEIGHT-1,D3 ;INIT DBRA ROWCOUNT
NEXTROW CLR D0 ;GET READY FOR BYTES
MOVE #SRCROW,D2 ;GET SRC ROW
SUBQ #1,D2 ;INIT DBRA COUNT OF BYTES
NEXTBYTE MOVE.B (A0),D0 ;GET A BYTE FROM SRC
LSR #4,D0 ;GET HI NIBBLE
MOVE.B TABLE(D0),(A1)+ ;STRETCH TO A BYTE
MOVE.B (A0)+,D0 ;GET SAME BYTE OF SRC
AND #$F,D0 ;GET LO NIBBLE
MOVE.B TABLE(D0),(A1)+ ;STRETCH TO A BYTE
DBRA D2,NEXTBYTE ;LOOP FOR ALL BYTES IN ROW
BRA.S HTHIN ;CONTINUE
TABLE .BYTE $00,$03,$0C,$0F ;DOUBLING TABLE
.BYTE $30,$33,$3C,$3F
.BYTE $C0,$C3,$CC,$CF
.BYTE $F0,$F3,$FC,$FF
;-----------------------------------------------
;
; LOCAL ROUTINE TO SHIFT SCANLINE LEFT
; ENTER WITH SRCSTART IN A2, PUTS RESULT IN BUF1, CLOBBERING D0,D1,A3
; LEAVES WITH A2 UNCHANGED, A3 AT START OF BUF1
;
LSHIFT ADD D4,A2 ;POINT TO END OF SRC
MOVE.L BUF2(A6),A3 ;POINT TO END OF BUF1
MOVE D6,D1 ;INIT DBRA LONGCOUNT
SUB D0,D0 ;CLEAR X-BIT
LSHIFT2 MOVE.L -(A2),D0 ;GET A LONG
ROXL.L #1,D0 ;SHIFT LEFT WITH CARRY
MOVE.L D0,-(A3) ;STORE IN BUF1
DBRA D1,LSHIFT2 ;LOOP ALL LONGS
RTS ;AND RETURN
;-----------------------------------------------
;
; LOCAL ROUTINE TO SHIFT SCANLINE RIGHT
; ENTER WITH SRCPTR IN A2, PUTS RESULT IN BUF2, CLOBBERING D0,D1,A3
; LEAVES WITH A2 UNCHANGED, A3 AT END OF BUF2
;
RSHIFT MOVE.L BUF2(A6),A3 ;POINT TO START OF BUF1
MOVE D6,D1 ;INIT DBRA LONGCOUNT
SUB D0,D0 ;CLEAR X-BIT
RSHIFT2 MOVE.L (A2)+,D0 ;GET A LONG
ROXR.L #1,D0 ;SHIFT RIGHT WITH CARRY
MOVE.L D0,(A3)+ ;STORE IN BUF2
DBRA D1,RSHIFT2 ;LOOP ALL LONGS
SUB D4,A2 ;RESTORE SRCPTR
RTS ;AND RETURN
;
; THIN EACH ROW HORIZONTALLY, ODD BITS ONE ONLY IF BOTH NEIGHBORS ARE ONE
;
HTHIN MOVE D4,D6 ;COPY DSTROW
LSR #2,D6 ;DIV BY 4 FOR LONGS
SUB #1,D6 ;INIT DBRA COUNT, CLEAR X-BIT
MOVE D6,D2 ;INIT DBRA LONG COUNT
NEXTLONG MOVE.L -(A1),D0 ;GET A LONG OF DST
ADDX.L D0,D0 ;SHIFT LEFT WITH CARRY
AND.L D0,(A1) ;AND WITH ORIGINAL
DBRA D2,NEXTLONG ;LOOP ALL LONGS
ADD D5,A1 ;BUMP DSTPTR TWO ROWS DOWN
DBRA D3,NEXTROW ;LOOP FOR SRCHEIGHT ROWS
;
; COMPUTE ODD SCANLINES BY ANDING EVEN SCANS AND KILLING ODD BITS
;
MOVE #SRCHEIGHT-2,D3 ;INIT DBRA ROWCOUNT
MOVE.L DSTBUF(A6),A0 ;POINT TO TOP SCANLINE
LEA 0(A0,D4),A1 ;POINT TO THIS SCANLINE
VERTROW LEA 0(A1,D4),A2 ;POINT TO SCANLINE BELOW
MOVE D6,D2 ;INIT DBRA LONG COUNT
VERTLONG MOVE.L (A0)+,D0 ;GET FROM SCAN ABOVE
AND.L (A2)+,D0 ;AND WITH SCAN BELOW
AND.L #$AAAAAAAA,D0 ;KILL ALL THE ODD BITS
MOVE.L D0,(A1)+ ;STORE INTO SCAN BELOW
DBRA D2,VERTLONG ;LOOP ALL LONGS IN ROW
MOVE.L A1,A0
MOVE.L A2,A1
DBRA D3,VERTROW ;LOOP SRCHEIGHT-1 ROWS
;
; INTERPOLATE PIXELS ON LEFT AND RIGHT DIAGONALS
; (first for left slant, then loop back for right)
;
CLR D7 ;FIRST TIME THRU FLAG
AGAIN MOVE #SRCHEIGHT-2,D3 ;INIT DBRA ROW COUNT
MOVE.L DSTBUF(A6),A0 ;POINT TO TOP SCANLINE
SLANT LEA 0(A0,D4),A1 ;POINT TO THIS SCANLINE
LEA 0(A1,D4),A2 ;POINT TO SCANLINE BELOW
TST D7 ;FIRST TIME THRU ?
BEQ.S OK1 ;YES, CONTINUE
EXG A0,A2 ;NO, EXCHANGE ABOVE AND BELOW
OK1 BSR LSHIFT ;LEFT SHIFT SCAN BELOW INTO BUF1
MOVE D6,D2 ;INIT DBRA LONG COUNT
SUB D0,D0 ;CLEAR X-BIT
SLANT2 MOVE.L (A0)+,D0 ;GET FROM SCAN ABOVE
ROXR.L #1,D0 ;SHIFT RIGHT WITH CARRY
AND.L (A3)+,D0 ;AND WITH SCANBUF
AND.L #$55555555,D0 ;MASK FOR ODD BITS ONLY
EOR.L D0,(A1)+ ;XOR RESULT INTO DST
DBRA D2,SLANT2 ;LOOP ALL LONGS IN ROW
MOVE.L A1,A0 ;POINT TO NEW TOP LINE
DBRA D3,SLANT ;LOOP SRCHEIGHT-1 ROWS
NOT D7 ;WAS THIS THE FIRST TIME THRU ?
BNE AGAIN ;YES, GO AGAIN FOR RIGHT SLANT
;-------------------------------------------------------
;
; THE REST OF THIS PROCEDURE CLEARS OUT PIXELS
; THAT ARE ZERO SURROUNDED BY FOUR ONES
;
; FOR THIS WE NEED TO LOOK AT 5 EXPANDED SCANLINES
;
; ORIGINAL: RESULT:
;
; SCAN1 X 1 X X 1 X
; SCAN2 0 0 0
; SCAN3 1 0 1 --> 1 0 0 0 1
; SCAN4 0 0 0
; SCAN5 X 1 X X 1 X
;
MOVE #SRCHEIGHT-3,D3 ;INIT DBRA ROW COUNT
MOVE.L DSTBUF(A6),A0 ;POINT TO INITIAL SCAN1
;
; CALC LINE3 SHIFTED LEFT 2 INTO BUF1
;
CLEAR LEA 0(A0,D5),A2 ;POINT TO SCAN3
BSR LSHIFT ;LEFT SHIFT SCAN3 INTO BUF1
MOVE.L BUF1(A6),A2 ;POINT TO BUF1
BSR LSHIFT ;SHIFT LEFT A SECOND TIME
;
; CALC LINE3 SHIFTED RIGHT 2 INTO BUF2
;
LEA 0(A0,D5),A2 ;POINT TO SCAN3
BSR.S RSHIFT ;RIGHT SHIFT SCAN3 INTO BUF2
MOVE.L BUF2(A6),A2 ;POINT TO BUF2
BSR.S RSHIFT ;SHIFT LEFT A SECOND TIME
;
; CALC (LSHIFT AND RSHIFT) AND NOT ORIGINAL, PUT RESULT IN BUF1
;
MOVE.L BUF1(A6),A1 ;POINT TO LSHIFT
MOVE.L BUF2(A6),A2 ;POINT TO RSHIFT
LEA 0(A0,D5),A3 ;POINT TO SCAN3
MOVE D6,D2 ;INIT DBRA LONG COUNT
ANDLP MOVE.L (A3)+,D0 ;GET ORIGINAL
NOT.L D0 ;FORM NOT ORIGINAL
AND.L (A2)+,D0 ;AND WITH BUF2
AND.L D0,(A1)+ ;AND RESULT INTO BUF1
DBRA D2,ANDLP ;LOOP ALL LONGS IN ROW
;
; AND SCAN1 AND SCAN5 INTO RESULT IN BUF1, THEN SMEAR RIGHT
;
MOVE.L BUF1(A6),A1 ;POINT TO BUF1
MOVE.L A0,A2 ;POINT TO SCAN1
LEA 0(A0,D5),A3
ADD D5,A3 ;POINT TO SCAN5
MOVE D6,D2 ;INIT DBRA LONG COUNT
SUB D0,D0 ;CLEAR X-BIT
RSMEAR MOVE.L (A1),D0 ;GET FROM BUF1
AND.L (A2)+,D0 ;AND WITH SCAN1
AND.L (A3)+,D0 ;AND WITH SCAN5
MOVE.L D0,D1 ;COPY RESULT
ROXR.L #1,D1 ;SHIFT COPY RIGHT WITH CARRY
OR.L D1,D0 ;SMEAR RIGHT
MOVE.L D0,(A1)+ ;STORE RESULT IN BUF1
DBRA D2,RSMEAR ;LOOP ALL LONGS IN ROW
;
; SMEAR BUF1 LEFT AND USE IT TO TRIM SCAN2 AND SCAN 4
;
LEA 0(A0,D5),A2 ;POINT TO END OF SCAN2
LEA 0(A2,D5),A3 ;POINT TO END OF SCAN4
MOVE D6,D2 ;INIT DBRA LONG COUNT
SUB D0,D0 ;CLEAR X-BIT
LSMEAR MOVE.L -(A1),D0 ;GET FROM BUF1
MOVE.L D0,D1 ;COPY RESULT
ROXL.L #1,D1 ;SHIFT COPY LEFT WITH CARRY
OR.L D1,D0 ;SMEAR LEFT
NOT.L D0 ;FORM NOTMASK FOR BIC
AND.L D0,-(A2) ;TRIM SCAN2
AND.L D0,-(A3) ;TRIM SCAN4
DBRA D2,LSMEAR ;LOOP ALL LONGS IN ROW
;
; LOOP FOR ALL ROWS
;
ADD D5,A0 ;POINT TO NEW TOP LINE
DBRA D3,CLEAR ;LOOP SRCHEIGHT-2 ROWS
ADD D5,SP ;RELEASE BUF1 AND BUF2
MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE REGS
UNLK A6 ;RELEASE STACK FRAME
MOVE.L (SP)+,A0 ;POP RETURN ADDR
ADD #PARAMSIZE,SP ;STRIP PARAMS
JMP (A0) ;AND RETURN
.SEG ' '
.PROC MySetItemStyle
.REF SetItemStyle
;---------------------------------------------------------------------
;
; PROCEDURE MySetItemStyle(menu: menuHandle; item: INTEGER;
; txFace: INTEGER);
;
; *** just type-coerce txFace to INTEGER to avoid %_ADJ SET OPERATOR ***
;
JMP SetItemStyle
.SEG ' '
.PROC MyGetItem
.REF GetItem
;---------------------------------------------------------------------
;
; PROCEDURE MyGetItem(menu: menuHandle; item: INTEGER; VAR itemString: Str63);
;
; *** just type-coerce VAR Str255 to Str63 ***
;
JMP GetItem
.SEG ' '
.FUNC Trunc8
;---------------------------------------------------------------------
;
; FUNCTION Trunc8(i: INTEGER): INTEGER;
; truncate toward zero to the next multiple of eight.
;
MOVE.L (SP)+,A0 ;POP RETURN ADDR
MOVE.W (SP)+,D0 ;POP INPUT PARAM
BMI.S NEGVAL ;BRANCH IF NEGATIVE
AND #$FFF8,D0 ;MASK TO MULT OF 8
BRA.S DONE ;AND CONTINUE
NEGVAL NEG D0 ;TAKE ABS VALUE
AND #$FFF8,D0 ;MASK TO MULT OF 8
NEG D0 ;RESTORE TO NEG
DONE MOVE D0,(SP) ;STORE RESULT
JMP (A0) ;AND RETURN
.SEG ' '
.FUNC GetDoubleTime
;---------------------------------------------------------------------
;
; FUNCTION GetDoubleTime: LONGINT;
;
MOVE.L doubleTime,4(SP) ;just examine low mem
RTS ;and return
.SEG ' '
.FUNC GetCaretTime
;---------------------------------------------------------------------
;
; FUNCTION GetCaretTime: LONGINT;
;
MOVE.L caretTime,4(SP) ;just examine low mem
RTS ;and return
.SEG ' '
.FUNC DiskSpace
;---------------------------------------------------------------------
;
; FUNCTION DiskSpace(drive: INTEGER): LongInt;
;
; returns total bytes free on the specified drive
;
PARAMSIZE .EQU 2
RESULT .EQU PARAMSIZE+8
DRIVE .EQU RESULT-2 ;WORD
LINK A6,#-IOVQElSize ;allocate an IOBlock
MOVE.L SP,A0 ;point to IOBlock
CLR.L IOVNPtr(A0) ;Nil name pointer
CLR.W IOVolIndex(A0) ;not by index
MOVE.W DRIVE(A6),IOVDrvNum(A0) ;specified drive
_GetVolInfo ;call OS
MOVE.W IOVFrBlk(A0),D0 ;get count of free blocks
MOVE.L IOVAlBlkSize(A0),D1 ;get bytes per block
MULU D1,D0 ;calc total bytes free
MOVE.L D0,RESULT(A6) ;store into function result
UNLK A6 ;release stack frame
MOVE.L (SP)+,A0 ;pop return addr
ADD #PARAMSIZE,SP ;strip param
JMP (A0) ;and return
.SEG 'SegSym '
.FUNC MapSym
;---------------------------------------------------------------------
;
; FUNCTION MapSym(hSym,vSym,hvSym,vhSym: BOOLEAN): QDByte;
;
; maps 4 symmetry flags into an 8 bit code telling
; which of 8 possible positions to plot.
;
MOVE.L (SP)+,A1 ;pop return addr
CLR D0
ADD.B (SP)+,D0 ;add boolean to sum
ADD D0,D0 ;shift left
ADD.B (SP)+,D0 ;repeat all 4 booleans
ADD D0,D0
ADD.B (SP)+,D0
ADD D0,D0
ADD.B (SP)+,D0
MOVE.B TABLE(D0),(SP) ;look up result
JMP (A1) ;and return
TABLE .BYTE $80,$C0,$A0,$F0
.BYTE $88,$FF,$FF,$FF
.BYTE $81,$FF,$FF,$FF
.BYTE $99,$FF,$FF,$FF
.SEG ' '
.FUNC StackPtr
;---------------------------------------------------------------------
;
; FUNCTION StackPtr: LongInt;
;
MOVE.L SP,4(SP)
RTS
.SEG ' '
.PROC FlushVol
;---------------------------------------------------------------------
;
; PROCEDURE FlushVol(driveNum: INTEGER);
;
MOVE.L (SP)+,A1 ;pop return addr
MOVE (SP)+,D0 ;pop driveNum
LINK A6,#-IOQElSize ;allocate a command block
MOVE.L SP,A0 ;point to the cmd block
CLR.L IOFileName(A0) ;ptr to vol name = Nil
MOVE D0,IODrvNum(A0) ;install driveNum
_FlushVol ;flush file buffers
UNLK A6 ;release command block
JMP (A1) ;and return
.SEG ' '
.PROC FlushEvents
;---------------------------------------------------------------------
;
; PROCEDURE FlushEvents(whichMask,stopMask: INTEGER);
;
MOVE.L (SP)+,A0 ;pop return addr
MOVE.L (SP)+,D0 ;get whichMask and stopMask
MOVE.L A0,-(SP) ;push return addr
_FlushEvents ;flush event queue
RTS ;and return
.SEG ' '
.FUNC EqualString
;---------------------------------------------------------------------
;
; FUNCTION EqualString(str1,str2: Str255): BOOLEAN;
;
MOVE.L (SP)+,D0 ;POP RETURN ADDR
MOVE.L (SP)+,A1 ;POP ADDR OF STR2
MOVE.L (SP)+,A0 ;POP ADDR OF STR1
CLR D1 ;GET READY FOR BYTE
MOVE.B (A0),D1 ;GET LENGTH BYTE 0..255
LOOP CMPM.B (A0)+,(A1)+ ;IS THIS BYTE THE SAME ?
DBNE D1,LOOP ;LOOP TILL LENGTH+1 OR <>
SEQ (SP) ;RETURN RESULT
NEG.B (SP) ;CONVERT $FF TO $01
MOVE.L D0,A0 ;GET RETURN ADDR
JMP (A0) ;AND RETURN
.SEG ' '
.PROC ExpandPat
;--------------------------------------------------------------------------
;
; PROCEDURE ExpandPat(pat: Pattern; VAR exPat: Longs24; hShift: INTEGER);
;
; pre-rotate, invert, and expand pattern into 24 longs
;
MOVE.L (SP)+,D0 ;pop return addr
MOVE (SP)+,D2 ;pop shift count
MOVE.L (SP)+,A1 ;pop addr of exPat
MOVE.L (SP)+,A0 ;pop addr of pat
MOVE.L D0,-(SP) ;push return addr
MOVEQ #7,D1 ;init count of 8 bytes
AND D1,D2 ;treat shiftcount mod 8
exLoop MOVE.B (A0)+,D0 ;get a byte of pattern
NOT.B D0 ;make inverse of pattern
ROL.B D2,D0 ;align to local coords
MOVE.B D0,(A1)+ ;put one byte
MOVE.B D0,(A1)+ ;put another to make a word
MOVE.W -2(A1),(A1)+ ;stretch word out to long
MOVE.L -4(A1),32-4(A1) ;duplicate it 8 longs later
MOVE.L -4(A1),64-4(A1) ;duplicate it 16 longs later
DBRA D1,exLoop ;loop all 8 bytes
RTS ;and return
.SEG ' '
.PROC DrawBrush
;------------------------------------------------------------
;
; PROCEDURE DrawBrush(brush: Bits16; exPat: Longs24;
; hCenter,vCenter: INTEGER;
; dstBits: BitMap; clip: Rect; orMode: BOOLEAN);
;
; Draw 16 by 16 image centered at h,v
;
paramSize .EQU 22 ;total bytes of parameters
brush .EQU paramSize+8-4 ;long, addr of Bits16
exPat .EQU brush-4 ;long, addr of pattern
horiz .EQU exPat-2 ;word
vert .EQU horiz-2 ;word
dstBits .EQU vert-4 ;long, addr of bitMap
clipRect .EQU dstBits-4 ;long, addr of rect
orMode .EQU clipRect-2 ;byte, BOOLEAN
LINK A6,#0 ;allocate stack frame
MOVEM.L D3-D6/A2-A4,-(SP) ;save registers
SUB #8,horiz(A6) ;convert hCenter to left
SUB #8,vert(A6) ;convert vCenter to top
MOVE.L dstBits(A6),A3 ;point to dstBits
MOVE.L clipRect(A6),A0 ;point to clipRect
MOVE rowBytes(A3),D6 ;get dstBits.rowBytes
;
; check for clipping at left
;
MOVEQ #-1,D5 ;init mask = all ones
MOVE horiz(A6),D0 ;get brush left
CMP left(A0),D0 ;is brush left < clip Left ?
BGE.S LEFTOK ;no, continue
MOVE.L #$0000FFFF,D5 ;yes, new mask
ADD #16,D0 ;calc brush right
CMP left(A0),D0 ;is brush right < clip left ?
BLE GOHOME ;yes, ignore whole thing
LEFTOK
;
; check for clipping at right
;
MOVE horiz(A6),D0 ;get brush left
CMP right(A0),D0 ;is brush left > clip right ?
BGE GOHOME ;yes, ignore whole thing
ADD #16,D0 ;calc brush right
CMP right(A0),D0 ;is brush right > clip right ?
BLE.S RIGHTOK ;no, continue
CLR.W D5 ;yes, mask = $FFFF0000
CMP #8,D6 ;are we drawing into fatBits ?
BNE.S RIGHTOK ;no, continue
MOVE.W #$F000,D5 ;yes, mask = $FFFFF000
RIGHTOK
;
; check for clipping at top
;
MOVE.L brush(A6),A4 ;point to brush data
MOVE #16,D3 ;init height = 16
MOVE top(A0),D0 ;get clip top
SUB vert(A6),D0 ;skip := clipTop - brush top
BLE.S TOPOK ;continue if skip <= 0
ADD D0,vert(A6) ;else trim brush top
SUB D0,D3 ;trim height to match
ADD D0,A4 ;adjust brush pointer too
ADD D0,A4 ;twice for brush rowbytes = 2
TOPOK
;
; check for clipping at bottom
;
MOVE vert(A6),D0 ;get brush top
ADD D3,D0 ;add height for brush bottom
SUB bottom(A0),D0 ;skip := brushBot - clipBot
BLE.S BOTOK ;continue if skip <= 0
SUB D0,D3 ;else trim height
BOTOK
;
; set up dstPtr
;
MOVE.L baseAddr(A3),A2 ;dstPtr := dstBits.baseAddr
MOVE horiz(A6),D0 ;get horiz coord
SUB bounds+left(A3),D0 ;convert to global coords
ASR #4,D0 ;div by 16 for word
ADD D0,D0 ;double for bytes
ADD D0,A2 ;add horiz offset to dstPtr
MOVE vert(A6),D0 ;get vert coord
SUB bounds+top(A3),D0 ;convert to global coords
MULU D6,D0 ;mult times dst rowBytes
ADD.L D0,A2 ;add vert offset to dstPtr
;
; set up shiftcount (and adjust dstPtr)
;
MOVE bounds+left(A3),D2 ;get dstBits.bounds.left
SUB horiz(A6),D2 ;calc -1*(global coords)
AND #$F,D2 ;treat mod 16 for shift
BNE.S notZero ;continue if not zero
SUB #2,A2 ;else back up dstPtr
notZero MOVE.L exPat(A6),A1 ;point to expanded pattern
MOVE vert(A6),D0 ;get dst vert
AND #7,D0 ;treat mod 8
LSL #2,D0 ;quad for longs
ADD D0,A1 ;add vert offset to pat ptr
SUB #1,D3 ;dbra count = height - 1
BLT.S GOHOME ;quit if count neg
TST.B ORMODE(A6) ;are we in OR-mode ?
BEQ.S NXTROW ;no, do normal loop
;
; loop all 16 rows, using mask to deposit pattern in or-mode
;
orRow CLR.L D0 ;get ready for word
MOVE (A4)+,D0 ;get word of brush
LSL.L D2,D0 ;align mask to dst
AND.L D5,D0 ;clip mask
MOVE.L (A1)+,D1 ;get long of inverse pattern
NOT.L D1 ;invert back to normal
AND.L D1,D0 ;and with pattern data
OR.L D0,(A2) ;or result into dst
ADD D6,A2 ;bump to next row down
DBRA D3,orRow ;loop 16 rows
BRA.S GOHOME ;and quit
;
; loop all 16 rows, using mask to deposit pattern
;
nxtRow MOVE.L (A1)+,D4 ;get a long of pattern data
MOVE.L (A2),D0 ;read data from dst
EOR.L D4,D0 ;xor with inverse pattern data
CLR.L D1 ;get ready for word
MOVE (A4)+,D1 ;get word of brush
LSL.L D2,D1 ;align mask to dst
AND.L D5,D1 ;clip mask
OR.L D1,D0 ;use mask to punch hole
EOR.L D4,D0 ;xor with inverse pattern data
MOVE.L D0,(A2) ;write result to dst
ADD D6,A2 ;bump to next row down
DBRA D3,nxtRow ;loop 16 rows
GOHOME MOVEM.L (SP)+,D3-D6/A2-A4 ;restore registers
UNLK A6 ;release stack frame
MOVE.L (SP)+,A0 ;pop return addr
ADD #paramSize,SP ;strip parameters
JMP (A0) ;and return
.SEG ' '
.FUNC NearPt
;-----------------------------------------------------------
;
; FUNCTION NearPt(pt1,pt2: Point; tol: INTEGER): BOOLEAN;
;
; NearPt:=((ABS(pt1.h-pt2.h) < tol) AND (ABS(pt1.v-pt2.v) < tol));
;
MOVE.L (SP)+,A0 ;pop return addr
MOVE (SP)+,D0 ;pop tolerance
MOVE.L (SP)+,D1 ;pop pt2
MOVE.L (SP)+,D2 ;pop pt1
CLR.B (SP) ;assume result FALSE
SUB.W D1,D2 ;calc delta horiz
BGE.S DHPOS ;continue if dh positive
NEG.W D2 ;else negate for abs value
DHPOS CMP.W D0,D2 ;is ABS(dh) < tol ?
BGE.S FALSE ;no, return false
SWAP D1 ;get pt2.v
SWAP D2 ;get pt1.v
SUB.W D1,D2 ;calc delta vert
BGE.S DVPOS ;continue if dv positive
NEG.W D2 ;else negate for abs value
DVPOS CMP.W D0,D2 ;is ABS(dv) < tol ?
BGE.S FALSE ;no, return FALSE
MOVE.B #1,(SP) ;result := TRUE
FALSE JMP (A0) ;and return
.SEG ' '
.FUNC FinderDoc
;----------------------------------------------------------------
;
; FUNCTION FinderDoc(VAR drive,version: INTEGER; strPtr: QDPtr): INTEGER;
;
paramSize .EQU 12
result .EQU paramSize+8 ;word
drive .EQU result-4 ;long, pointer to integer
version .EQU drive-4 ;long, pointer to integer
fileName .EQU version-4 ;long, pointer to string
LINK A6,#0 ;no locals
MOVE.L AppParmHandle,A0 ;get AppParmHandle
MOVE.L (A0),A0 ;de-reference it
MOVE.W (A0)+,result(A6) ;get finder message
MOVE.W (A0)+,D1 ;get docCount
MOVE.L DRIVE(A6),A1 ;point to drive
BRA.S TRYDOC ;go to loop start
NXTDOC MOVE.W (A0)+,(A1) ;get drive number
CMP.L #'PNTG',(A0)+ ;is this a 'PNTG' document ?
BEQ.S FOUND ;yes, we found one.
ADD #2,A0 ;no, skip version
MOVE.B (A0),D0 ;get string length
ADD #2,D0 ;round (length+1) up
AND #$00FE,D0 ;to next mult of 2
ADD D0,A0 ;skip past the string
TRYDOC DBRA D1,NXTDOC ;loop for all documents
MOVE #-1,RESULT(A6) ;result = failure
CLR (A1) ;return drive = 0
MOVE.L version(A6),A1 ;point to version
CLR (A1) ;return version = 0
MOVE.L fileName(A6),A1 ;point to string
CLR.B (A1) ;return empty string
BRA.S GOHOME
FOUND CLR.L -4(A0) ;clear docType for next time
MOVE (A0)+,D0 ;get version (in hi byte)
LSR #8,D0 ;put in lo byte
MOVE.L version(A6),A1 ;point to version
MOVE D0,(A1) ;return version
MOVE.B (A0),D0 ;get str len (hi byte 0 from above)
MOVE.L fileName(A6),A1 ;point to result string
NXTBYTE MOVE.B (A0)+,(A1)+ ;copy a byte
DBRA D0,NXTBYTE ;copy (length+1) bytes
GOHOME UNLK A6 ;release stack frame
MOVE.L (SP)+,A0 ;pop return addr
ADD #paramsize,SP ;strip params
JMP (A0) ;and return
.SEG 'SegPrint'
.FUNC CountFiles
;----------------------------------------------------------------
;
; FUNCTION CountFiles( drive: INTEGER; VAR str: STR255 ): INTEGER;
;
; Returns total number of files on given drive. (0 if no drive)
;
; A6 offsets of params and locals after link:
;
paramSize .EQU 6
Result .EQU paramSize+8 ; return number of files
DriveNum .EQU Result-2 ; disk drive number
DiskName .EQU DriveNum-4 ; address to store name of disk
ioBlk .EQU -IOFQElSize
locals .EQU ioBlk
LINK A6,#locals ; set up frame, etc.
LEA ioBlk(A6),A0 ; point to IO buffer
MOVE.L DiskName(A6),IOfileName(A0) ; Set the volume name ptr
CLR.W IOVolIndex(A0) ; Use drive number(not index mode)
MOVE.W DriveNum(A6),IODrvNum(A0) ; use the given volume
_GetVolInfo ; call OS for vol info
BEQ.S noError ; did volume exist ?
CLR IOVNmFls(A0) ; no, set number of files to zero
noError MOVE.W IOVNmFls(A0),Result(A6) ; return number of files
UNLK A6
MOVE.L (SP)+,A0
ADD #paramSize,SP
JMP (A0)
.SEG 'SegPrint'
.FUNC NextFile
;--------------------------------------------------------------
;
; FUNCTION NextFile(drive,index: INTEGER; fileType: ResType;
; VAR str: STR255; VAR version: INTEGER): BOOLEAN;
;
; Returns file name(index) and boolean if matches given type.
;
; A6 offsets of params and locals after link:
;
paramSize .EQU 16
Result .EQU paramSize+8 ; word, number of files
DriveNum .EQU Result-2 ; word, drive number
Index .EQU DriveNum-2 ; word, index of next file
FileType .EQU Index-4 ; long, restype of file needed
FileName .EQU FileType-4 ; long, addr of fileName string
version .EQU fileName-4 ; long, addr of integer
ioBlk .EQU -IOFQElSize
locals .EQU ioBlk
LINK A6,#locals ; allocate stack frame
LEA ioBlk(A6),A0 ; point to IO buffer
MOVE.L FileName(A6),IOfileName(A0) ; Set the file name ptr
MOVE.W DriveNum(A6),IODrvNum(A0) ; use the given volume
MOVE.W Index(A6), IOFDirIndex(A0) ; And use the given index.
_GetFileInfo ; get info about this file
CLR D0 ; get ready for byte
MOVE.B IOFFlType(A0),D0 ; get output version byte
MOVE.L VERSION(A6),A1 ; point to VAR version
MOVE.W D0,(A1) ; store into version
MOVE.L FileType(A6),D0 ; get passed file type
CMP.L IOFlUsrWds(A0),D0 ; see if type matches
SEQ Result(A6) ; return true if match
NEG.B Result(A6) ; convert to Pascal boolean
UNLK A6 ; release stack frame
MOVE.L (SP)+,A0 ; pop return addr
ADD #paramSize,SP ; strip params
JMP (A0) ; and return
.SEG ' '
.PROC SetDocType
;--------------------------------------------------------------------------------
;
; PROCEDURE SetDocType(drive,version: INTEGER; docName: Str255);
;
paramSize .EQU 8
drive .EQU paramSize+8-2 ;word
version .EQU drive-2 ;word, lo byte used
fName .EQU version-4 ;long, pointer to string
LINK A6,#-IOFQElSize ;allocate command block
MOVE.L SP,A0 ;Point to command block
MOVE.L fName(A6),IOFileName(A0) ;install file name pointer
MOVE.B version+1(A6),IOFileType(A0) ;install version byte
MOVE drive(A6),IODrvNum(A0) ;use the specified drive.
CLR.W IOFDirIndex(A0) ;And use the given file name.
_GetFileInfo ;Call OS GetInfo
MOVE.L #'PNTG',IOFlUsrWds(A0) ;install file type
MOVE.L #'MPNT',IOFlUsrWds+4(A0) ;install creator
_SetFileInfo ;Call OS SetInfo
UNLK A6
MOVE.L (SP)+, A0 ;Get return address
ADD #paramSize,SP ;Pop parameters
JMP (A0) ;and return.
.SEG ' '
.FUNC CheckPntg
;--------------------------------------------------------------------------------
;
; FUNCTION CheckPntg(drive,version: INTEGER; docName: Str255): BOOLEAN;
; returns true if given file is of type 'PNTG'
;
paramSize .EQU 8
result .EQU paramsize+8 ;boolean
drive .EQU result-2 ;word
version .EQU drive-2 ;word, lo byte used
fName .EQU version-4 ;long, pointer to string
LINK A6,#-IOFQElSize ;allocate command block
MOVE.L SP,A0 ;Point to command block
MOVE.L fName(A6),IOFileName(A0) ;install file name pointer
MOVE.B version+1(A6),IOFileType(A0) ;install version byte
MOVE drive(A6),IODrvNum(A0) ;use the specified drive.
CLR.W IOFDirIndex(A0) ;And use the given file name.
_GetFileInfo ;Call OS GetInfo
CMP.L #'PNTG',IOFlUsrWds(A0) ;is type PNTG ?
SEQ result(A6) ;update result
NEG.B result(A6) ;adjust for Pascal boolean
UNLK A6
MOVE.L (SP)+, A0 ;Get return address
ADD #paramSize,SP ;Pop parameters
JMP (A0) ;and return.
.SEG ' '
.PROC FileInfo
;--------------------------------------------------------------
;
; PROCEDURE FileInfo(drive,version: INTEGER; fName: Str63;
; VAR fileDate,fileSize: LongInt);
;
paramSize .EQU 16
drive .EQU paramsize+8-2 ;word
version .EQU drive-2 ;word, lo byte used
fName .EQU version-4 ;long, pointer to string
fDate .EQU fName-4 ;long, pointer to long
fSize .EQU fDate-4 ;long, pointer to long
LINK A6,#-IOFQElSize ;allocate command block
MOVE.L SP,A0 ;Point to command block
MOVE.L fName(A6),IOFileName(A0) ;install file name pointer
MOVE.B version+1(A6),IOFileType(A0) ;install version byte
MOVE drive(A6),IODrvNum(A0) ;use the specified drive.
CLR.W IOFDirIndex(A0) ;And use the given file name.
_GetFileInfo ;Call OS GetInfo
MOVE.L fDate(A6),A1 ;get var addr
MOVE.L IOFlMdDat(A0),(A1) ;get modification data
MOVE.L fSize(A6),A1 ;get var addr
MOVE.L IOFlPyLen(A0),(A1) ;get physical length
UNLK A6 ;release stack frame
MOVE.L (SP)+,A0 ;pop return addr
ADD #paramSize,SP ;strip params
JMP (A0) ;and return
.SEG 'SegPrint'
.PROC HToneRow
;----------------------------------------------------
;
; PROCEDURE HToneRow(thisRow,nextRow: QDPtr;
; dstBits: BitMap;
; hStart,vStart,hSize: INTEGER;
; whiteLevel,blackLevel: INTEGER;
; threshold: BOOLEAN);
;
;
; A6 OFFSETS OF PARAMETERS AND VARIABLES AFTER LINK:
;
paramSize .EQU 24
thisRow .EQU paramSize+8-4 ;Pointer
nextRow .EQU thisRow-4 ;Pointer
dstBits .EQU nextRow-4 ;Pointer
hStart .EQU dstBits-2 ;Integer
vStart .EQU hStart-2 ;Integer
hSize .EQU vStart-2 ;Integer
whiteLevel .EQU hSize-2 ;Integer
blackLevel .EQU whiteLevel-2 ;Integer
threshold .EQU blackLevel-2 ;Boolean
fullScale .EQU -2 ;blackLevel-whiteLevel
halfScale .EQU fullScale-2 ;fullScale/2
varSize .EQU halfScale
LINK A6,#varSize ;ALLOCATE STACK FRAME
MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGS
MOVE.L dstBits(A6),A3 ;get dst bitmap
MOVE hSize(A6),D1 ;get horizontal size
BLE GOHOME ;quit if no pixels
MOVE hStart(A6),D0 ;get horiz start coord
SUB bounds+left(A3),D0 ;make it global
ASR #4,D0 ;div by 16 for word
ADD D0,D0 ;double for byte offset
MOVE.L baseAddr(A3),A0 ;get baseAddr
ADD D0,A0 ;add offset for hStart
MOVE vStart(A6),D0 ;get vert start
SUB bounds+top(A3),D0 ;make it global
MULU rowBytes(A3),D0 ;times rowBytes for offset
ADD.L D0,A0 ;add vertical offset
MOVE.L thisRow(A6),A1 ;point to thisRow
MOVE.L nextRow(A6),A2 ;point to nextRow