From 646aa270df7eddc1928f82c3f4e2fc87b02167c9 Mon Sep 17 00:00:00 2001 From: Jonathan Ragan-Kelley Date: Tue, 20 Jul 2010 21:37:29 -0700 Subject: [PATCH] initial import --- Angles.a | 293 ++++++++ Arcs.a | 164 +++++ BitBlt.a | 796 ++++++++++++++++++++++ Bitmaps.a | 1018 ++++++++++++++++++++++++++++ COPYRIGHT.TXT | 3 + DrawArc.a | 1086 +++++++++++++++++++++++++++++ DrawLine.a | 745 ++++++++++++++++++++ DrawText.a | 933 +++++++++++++++++++++++++ FixMove.p | 45 ++ Graf3D.p | 477 +++++++++++++ GrafAsm.a | 507 ++++++++++++++ GrafTypes.a | 375 ++++++++++ GrafUtil.p | 47 ++ LCursor.a | 122 ++++ Lines.a | 347 ++++++++++ Ovals.a | 163 +++++ PackRgn.a | 159 +++++ PicFormat.txt | 120 ++++ Pictures.a | 1807 +++++++++++++++++++++++++++++++++++++++++++++++++ Polygons.a | 417 ++++++++++++ PutLine.a | 205 ++++++ PutOval.a | 249 +++++++ PutRgn.a | 79 +++ QDPatch.a | 1028 ++++++++++++++++++++++++++++ QuickDraw.p | 418 ++++++++++++ QuickDraw2.p | 267 ++++++++ QuickGlue.a | 145 ++++ RRects.a | 177 +++++ Rects.a | 675 ++++++++++++++++++ Regions.a | 1170 ++++++++++++++++++++++++++++++++ RgnBlt.a | 825 ++++++++++++++++++++++ RgnOp.a | 444 ++++++++++++ SeekRgn.a | 192 ++++++ SortPoints.a | 180 +++++ Stretch.a | 1164 +++++++++++++++++++++++++++++++ TestGraf.p | 971 ++++++++++++++++++++++++++ Text.a | 740 ++++++++++++++++++++ Util.a | 837 +++++++++++++++++++++++ 38 files changed, 19390 insertions(+) create mode 100755 Angles.a create mode 100755 Arcs.a create mode 100755 BitBlt.a create mode 100755 Bitmaps.a create mode 100755 COPYRIGHT.TXT create mode 100755 DrawArc.a create mode 100755 DrawLine.a create mode 100755 DrawText.a create mode 100755 FixMove.p create mode 100755 Graf3D.p create mode 100755 GrafAsm.a create mode 100755 GrafTypes.a create mode 100755 GrafUtil.p create mode 100755 LCursor.a create mode 100755 Lines.a create mode 100755 Ovals.a create mode 100755 PackRgn.a create mode 100755 PicFormat.txt create mode 100755 Pictures.a create mode 100755 Polygons.a create mode 100755 PutLine.a create mode 100755 PutOval.a create mode 100755 PutRgn.a create mode 100755 QDPatch.a create mode 100755 QuickDraw.p create mode 100755 QuickDraw2.p create mode 100755 QuickGlue.a create mode 100755 RRects.a create mode 100755 Rects.a create mode 100755 Regions.a create mode 100755 RgnBlt.a create mode 100755 RgnOp.a create mode 100755 SeekRgn.a create mode 100755 SortPoints.a create mode 100755 Stretch.a create mode 100755 TestGraf.p create mode 100755 Text.a create mode 100755 Util.a diff --git a/Angles.a b/Angles.a new file mode 100755 index 0000000..6975a04 --- /dev/null +++ b/Angles.a @@ -0,0 +1,293 @@ + .INCLUDE GrafTypes.text + + .FUNC AngleFromSlope,1 + .DEF SlopeFromAngle +;----------------------------------------------------- +; +; FUNCTION AngleFromSlope(slope: Fixed): INTEGER; +; +; Scans slope table for angle and returns angle 0..180 +; + MOVE.L 4(SP),D0 ;GET SLOPE + SMI D2 ;REMEMBER IF IT WAS NEGATIVE + BPL.S NOTNEG ;CONTINUE IF POSITIVE + NEG.L D0 ;ELSE MAKE SLOPE POS +NOTNEG SUB.L #500,D0 ;BIAS THE COMPARE + MOVE.L D0,4(SP) + LEA CONTINUE,A0 ;POINT TO TABLE OF SLOPES + MOVEQ #-1,D1 ;INIT ANGLE COUNT +SCAN ADD.W #1,D1 + MOVE.W D1,D0 + CLR.L -(SP) + BRA.S A2SLOPE +CONTINUE + MOVE.L 8(SP),D0 ;GET SLOPE + CMP.L (SP)+,D0 ;SCAN THRU SLOPE TABLE + BGT.S SCAN + MOVE #180,D0 + SUB D1,D0 ;CALC 180-ANGLE = 90..180 + TST.B D2 ;WAS DH POS ? + BPL.S DONE ;NO, RETURN 90..180 + MOVE D1,D0 ;YES, RETURN 0..90 +DONE MOVE.L (SP)+,(SP) ;STRIP PARAM + MOVE.W D0,4(SP) ;RETURN FUNCTION RESULT + RTS + + + +;---------------------------------------------------------------- +; +; FUNCTION SlopeFromAngle(angle: INTEGER): Fixed; +; +; calculate the fixed point slope of a line, DH/DV = -65536 * Tan(angle). +; Input angle is treated MOD 180. +; +SlopeFromAngle + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE (SP)+,D0 ;GET INTEGER ANGLE + EXT.L D0 ;SIGN EXTEND FOR DIVIDE + DIVS #180,D0 ;TREAT ANGLE MOD 180 + SWAP D0 ;GET THE REMAINDER + TST D0 ;WAS IT NEGATIVE ? + BPL.S OK1 ;NO, CONTINUE + ADD #180,D0 ;YES, PUT IN RANGE 0..179 +OK1 MOVE #$8000,(SP) +A2SLOPE CMP #90,D0 + BLE.S OK2 + CLR.W (SP) + SUB #180,D0 + NEG D0 +OK2 CMP #45,D0 + BLT.S SHARE + ADD #1,(SP) + CMP #64,D0 + BLT.S SHARE + MOVE.B SLOPE-91(D0),1(SP) + BPL.S SHARE + OR.B #$7F,(SP) +SHARE ADD D0,D0 + MOVE.W SLOPE(D0),2(SP) +CHECK BCLR #7,(SP) + BEQ.S OK3 + NEG.L (SP) +OK3 JMP (A0) + + + +; .BYTE $01 ;45 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 ;50 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 ;55 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 +; .BYTE $01 ;60 +; .BYTE $01 +; .BYTE $01 + .BYTE $01 + .BYTE $02 + .BYTE $02 ;65 + .BYTE $02 + .BYTE $02 + .BYTE $02 + .BYTE $02 + .BYTE $02 ;70 + .BYTE $02 + .BYTE $03 + .BYTE $03 + .BYTE $03 + .BYTE $03 ;75 + .BYTE $04 + .BYTE $04 + .BYTE $04 + .BYTE $05 + .BYTE $05 ;80 + .BYTE $06 + .BYTE $07 + .BYTE $08 + .BYTE $09 + .BYTE $0B ;85 + .BYTE $0E + .BYTE $13 + .BYTE $1C + .BYTE $39 + .BYTE $FF ;90 +SLOPE + .WORD $0000 ;0 + .WORD $0478 + .WORD $08F1 + .WORD $0D6B + .WORD $11E7 + .WORD $1666 ;5 + .WORD $1AE8 + .WORD $1F6F + .WORD $23FA + .WORD $288C + .WORD $2D24 ;10 + .WORD $31C3 + .WORD $366A + .WORD $3B1A + .WORD $3FD4 + .WORD $4498 ;15 + .WORD $4968 + .WORD $4E44 + .WORD $532E + .WORD $5826 + .WORD $5D2D ;20 + .WORD $6245 + .WORD $676E + .WORD $6CAA + .WORD $71FB + .WORD $7760 ;25 + .WORD $7CDC + .WORD $8270 + .WORD $881E + .WORD $8DE7 + .WORD $93CD ;30 + .WORD $99D2 + .WORD $9FF7 + .WORD $A640 + .WORD $ACAD + .WORD $B341 ;35 + .WORD $B9FF + .WORD $C0E9 + .WORD $C802 + .WORD $CF4E + .WORD $D6CF ;40 + .WORD $DE8A + .WORD $E681 + .WORD $EEB9 + .WORD $F737 + .WORD $0000 ;45 + .WORD $0919 + .WORD $1287 + .WORD $1C51 + .WORD $267F + .WORD $3117 ;50 + .WORD $3C22 + .WORD $47AA + .WORD $53B9 + .WORD $605B + .WORD $6D9B ;55 + .WORD $7B89 + .WORD $8A35 + .WORD $99AF + .WORD $AA0E + .WORD $BB68 ;60 + .WORD $CDD6 + .WORD $E177 + .WORD $F66E + .WORD $0CE1 + .WORD $24FE ;65 + .WORD $3EFC + .WORD $5B19 + .WORD $799F + .WORD $9AE7 + .WORD $BF5B ;70 + .WORD $E77A + .WORD $13E3 + .WORD $4556 + .WORD $7CC7 + .WORD $BB68 ;75 + .WORD $02C2 + .WORD $54DB + .WORD $B462 + .WORD $2501 + .WORD $ABD9 ;80 + .WORD $5051 + .WORD $1D88 + .WORD $24F3 + .WORD $83AD + .WORD $6E17 ;85 + .WORD $4CF5 + .WORD $14BD + .WORD $A2D7 + .WORD $4A30 + .WORD $FFFF ;90 + + + .PROC PtToAngle,3 + .REF AngleFromSlope +;-------------------------------------------------------------- +; +; PROCEDURE PtToAngle(r: Rect; pt: Point; VAR angle: INTEGER); +; +; Given a rectangle and a point, return the angle subtended by pt. +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 12 ;TOTAL BYTES OF PARAMS +RECT .EQU PARAMSIZE+8-4 ;ADDR OF RECT +PT .EQU RECT-4 ;POINT +ANGLE .EQU PT-4 ;ADDR OF INTEGER; + + LINK A6,#0 ;NO LOCALS + MOVEM.L D6-D7/A4,-(SP) ;SAVE REGS + MOVE.L RECT(A6),A4 ;POINT TO RECT + + MOVE BOTTOM(A4),D0 + ADD TOP(A4),D0 + ASR #1,D0 ;CENTER.V := (TOP+BOTTOM)/2 + MOVE PT+V(A6),D1 + SUB D0,D1 ;DV := PT.V - CENTER.V + + MOVE RIGHT(A4),D0 + ADD LEFT(A4),D0 + ASR #1,D0 ;CENTER.H := (LEFT+RIGHT)/2 + MOVE PT+H(A6),D7 + SUB D0,D7 ;DH := PT.H - CENTER.H + BNE.S DHOK ;CONTINUE IF DH <> 0 + TST D1 ;WAS DV > 0 ? + BLE.S ZERO ;NO, RETURN ANGLE = 0 + MOVE #180,D0 ;YES, RETURN ANGLE = 180 + BRA.S DONE + +DHOK CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE D7,-(SP) ;PUSH DH + MOVE D1,-(SP) ;PUSH DV + _FixRatio ;CALC SLOPE := DH/DV + MOVE.L (SP)+,D6 ;GET SLOPE RESULT + + CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE BOTTOM(A4),D0 + SUB TOP(A4),D0 + MOVE D0,-(SP) ;PUSH HEIGHT + MOVE RIGHT(A4),D0 + SUB LEFT(A4),D0 + MOVE D0,-(SP) ;PUSH WIDTH + _FixRatio ;CALC ASPECT := HT/WD + MOVE.L (SP)+,D0 ;GET ASPECT RESULT + + CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE.L D6,-(SP) ;PUSH SLOPE + MOVE.L D0,-(SP) ;PUSH ASPECT + _FixMul ;CALC SLOPE*ASPECT + MOVE.L (SP)+,D0 ;GET RESULT SLOPE2 + + CLR.W -(SP) ;ROOM FOR FCN RESULT + MOVE.L D0,-(SP) ;PUSH SLOPE2 + JSR AngleFromSlope ;SCAN FOR ARCTAN + MOVE (SP)+,D0 ;GET RESULT ANGLE + + TST D7 ;WAS DH POSITIVE ? + BPL.S DONE ;YES, CONTINUE + ADD #180,D0 ;NO, ADD 180 TO ANG + CMP #360,D0 ;IS RESULT = 360 ? + BNE.S DONE ;NO, CONTINUE +ZERO CLR D0 ;YES, ANGLE := 0 +DONE MOVE.L ANGLE(A6),A0 ;GET VAR ADDR + MOVE D0,(A0) ;STORE INTO ANGLE + MOVEM.L (SP)+,D6-D7/A4 ;RESTORE REGS + UNLINK PARAMSIZE,'PTTOANGL' + + + + .END diff --git a/Arcs.a b/Arcs.a new file mode 100755 index 0000000..671f9ce --- /dev/null +++ b/Arcs.a @@ -0,0 +1,164 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; +; * ***** *** *** +; * * * * * * * * +; * * * * * * +; * * ***** * *** +; ***** * * * * +; * * * * * * * * +; * * * * *** *** +; +; Procedures for drawing Arcs: +; + + + .PROC StdArc,4 + .REF CheckPic,PutPicVerb,PutPicWord,PutPicRect + .REF PushVerb,DrawArc +;--------------------------------------------------------------- +; +; PROCEDURE StdArc(verb: GrafVerb; r: Rect; startAngle,arcAngle: INTEGER); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 10 +VERB .EQU PARAMSIZE+8-2 ;GRAFVERB +RECT .EQU VERB-4 ;LONG, ADDR OF RECT +STARTANG .EQU RECT-2 ;WORD +ARCANG .EQU STARTANG-2 ;WORD + +OVWD .EQU -2 ;WORD +OVHT .EQU OVWD-2 ;WORD +VARSIZE .EQU OVHT ;TOTAL BYTES OF LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D4/D7/A3-A4,-(SP) ;SAVE REGS + MOVE.B VERB(A6),D7 ;GET VERB + JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE.S NOTPIC ;BRANCH IF NOT PICSAVE + + MOVE.B D7,-(SP) + JSR PutPicVerb ;PUT ADDIONAL PARAMS TO THEPIC + MOVEQ #$60,D0 ;PUT ARCNOUN IN HI NIBBLE + ADD D7,D0 ;PUT VERB IN LO NIBBLE + MOVE.B D0,-(SP) ;PUSH OPCODE + MOVE.L RECT(A6),-(SP) ;PUSH ADDR OF RECT + JSR PutPicRect ;PUT OPCODE AND RECTANGLE + MOVE STARTANG(A6),-(SP) + JSR PutPicWord ;PUT STARTANGLE + MOVE ARCANG(A6),-(SP) + JSR PutPicWord ;PUT ARCANGLE + +NOTPIC MOVE.L RECT(A6),A0 ;POINT TO RECT + MOVE RIGHT(A0),D0 + SUB LEFT(A0),D0 + MOVE D0,OVWD(A6) ;OVWD := R.RIGHT - R.LEFT + MOVE BOTTOM(A0),D0 + SUB TOP(A0),D0 + MOVE D0,OVHT(A6) ;OVHT := R.BOTTOM - R.TOP + + MOVE.L A0,-(SP) ;PUSH ADDR OF RECT + CLR.B -(SP) ;PUSH HOLLOW = FALSE + TST.B D7 ;IS VERB FRAME ? + BNE.S DOIT ;NO, CONTINUE +; +; Currently, FrameArc does not put inversion points to theRgn. +; If this changes, add test and call to PutArc here. +; + MOVE.B #1,(SP) ;REPLACE, PUSH HOLLOW = TRUE +DOIT MOVE.L OVHT(A6),-(SP) ;PUSH OVWD,OVHT + JSR PushVerb ;PUSH MODE AND PATTERN + MOVE STARTANG(A6),-(SP) ;PUSH STARTANGLE + MOVE ARCANG(A6),-(SP) ;PUSH ARCANGLE + +; DrawArc(r,hollow,ovWd,ovHt,mode,pat,startAng,arcAng); + + JSR DrawArc + MOVEM.L (SP)+,D4/D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDARC ' + + + + .PROC FrameArc,3 + .DEF CallArc,PaintArc,EraseArc,InvertArc,FillArc + .REF STDARC +;----------------------------------------------------- +; +; PROCEDURE FrameArc(* r: Rect; startAngle,arcAngle: INTEGER *); +; + MOVEQ #FRAME,D0 ;VERB = FRAME + BRA.S CallArc ;SHARE COMMON CODE + + +;----------------------------------------------------- +; +; PROCEDURE PaintArc(* r: Rect; startAngle,arcAngle: INTEGER *); +; +PaintArc + MOVEQ #PAINT,D0 ;VERB = PAINT + BRA.S CallArc ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE EraseArc(* r: Rect; startAngle,arcAngle: INTEGER *); +; +EraseArc + MOVEQ #ERASE,D0 ;VERB = ERASE + BRA.S CallArc ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE InvertArc(* r: Rect; startAngle,arcAngle: INTEGER *); +; +InvertArc + MOVEQ #INVERT,D0 ;VERB = INVERT + BRA.S CallArc ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE FillArc(* r: Rect; startAngle,arcAngle: INTEGER; pat: Pattern *); +; +FillArc MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF PATTERN + MOVE.L A0,-(SP) ;PUT RETURN ADDR BACK + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA FILLPAT(A0),A0 ;POINT TO FILLPAT + MOVE.L (A1)+,(A0)+ ;COPY PAT INTO FILLPAT + MOVE.L (A1)+,(A0)+ ;ALL EIGHT BYTES + MOVEQ #FILL,D0 ;VERB = FILL + BRA.S CallArc ;SHARE COMMON CODE + + +;--------------------------------------------------------------- +; +; PROCEDURE CallArc(r: Rect; startAngle,arcAngle: INTEGER); +; +; code shared by FrameArc, PaintArc, EraseArc, InvertArc, and FillArc. +; enter with verb in D0. +; +CallArc MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D1 ;POP BOTH ANGLES + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + MOVE.B D0,-(SP) ;PUSH VERB + MOVE.L A1,-(SP) ;PUSH ADDR OF RECT + MOVE.L D1,-(SP) ;PUSH BOTH ANGLES + MOVE.L A0,-(SP) ;PUSH RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDARC,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L ARCPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;GO TO IT + + + + .END diff --git a/BitBlt.a b/BitBlt.a new file mode 100755 index 0000000..3acd988 --- /dev/null +++ b/BitBlt.a @@ -0,0 +1,796 @@ + .INCLUDE GRAFTYPES.TEXT +;--------------------------------------------------------------- +; +; --> BITBLT.TEXT +; +; Low-level bit boundary block transfer. +; + + + .PROC BITBLT,7 + .REF LEFTMASK,RIGHTMASK,PATEXPAND +;-------------------------------------------------------------- +; +; PROCEDURE BitBlt(srcBits,dstBits: BitMap; +; srcRect,dstRect: Rect; +; mode: INTEGER; pat: Pattern); +; +; TRANSFERS A RECTANGULAR BLOCK OF BITS WITH NO CLIPPING AT ALL. +; MODE SPECIFIES THE COMBINATION MODE AND WHETHER THE SOURCE SHOULD COME +; FROM THE SOURCE BITMAP OR FROM A REPEATING PATTERN. +; +; COPYRIGHT APPLE COMPUTER INC. +; WRITTEN BY BILL ATKINSON +; +; POSITION INDEPENDENT AND RE-ENTRANT, CLOBBERS ONLY A0. +; +; MODES: 0 SRC --> DST +; 1 SRC OR DST --> DST +; 2 SRC XOR DST --> DST +; 3 SRC BIC DST --> DST +; +; 4 (NOT SRC) --> DST +; 5 (NOT SRC) OR DST --> DST +; 6 (NOT SRC) XOR DST --> DST +; 7 (NOT SRC) BIC DST --> DST +; +; 8 PATTERN --> DST +; 9 PATTERN OR DST --> DST +; 10 PATTERN XOR DST --> DST +; 11 PATTERN BIC DST --> DST +; +; 12 (NOT PATTERN) --> DST +; 13 (NOT PATTERN) OR DST --> DST +; 14 (NOT PATTERN) XOR DST --> DST +; 15 (NOT PATTERN) BIC DST --> DST +; +; + + +;---------------------------------------------------- +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 22 ;SIZE OF PARAMETERS +SRCBITS .EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP +DSTBITS .EQU SRCBITS-4 ;LONG, ADDR OF BITMAP +SRCRECT .EQU DSTBITS-4 ;LONG, ADDR OF RECT +DSTRECT .EQU SRCRECT-4 ;LONG, ADDR OF RECT +MODE .EQU DSTRECT-2 ;WORD +PAT .EQU MODE-4 ;LONG, ADDR OF PATTERN + + +;---------------------------------------------------- +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +EXPAT .EQU -64 ;16 LONGS +SRCV .EQU EXPAT-2 ;WORD +DSTV .EQU SRCV-2 ;WORD +SRCROW .EQU DSTV-2 ;WORD +DSTROW .EQU SRCROW-2 ;WORD +srcBump .EQU DSTROW-2 ;WORD +HEIGHT .EQU srcBump-2 ;WORD +WORDCNT .EQU HEIGHT-2 ;WORD +SAVEA5 .EQU WORDCNT-4 ;LONG +VARSIZE .EQU SAVEA5 ;SIZE OF LOCAL VARIABLES + + +;------------------------------------------------------------------- +; +; ENTER HERE. CALLER TAKES CARE OF CURSOR. +; + LINK A6,#VARSIZE ;ALLOCATE LOCAL VARIABLES + MOVEM.L D3-D7/A2-A5,-(SP) ;SAVE REGS + MOVE.L A5,SAVEA5(A6) ;SAVE GLOBAL POINTER + + +;---------------------------------------------------------------------- +; +; GET PARAMETER POINTERS IN REGISTERS +; + MOVE.L SRCRECT(A6),A2 ;A2 POINTS TO SRCRECT + MOVE.L DSTRECT(A6),A3 ;A3 POINTS TO DSTRECT + MOVE.L SRCBITS(A6),A4 ;A4 POINTS TO SRCBITS + MOVE.L DSTBITS(A6),A5 ;A5 POINTS TO DSTBITS + + +;------------------------------------------------------------- +; +; CALC HEIGHT OF DSTRECT. QUIT IF HEIGHT <= 0 +; + MOVE BOTTOM(A3),D0 ;GET BOTTOM + SUB TOP(A3),D0 ;CALC HEIGHT + BLE GOHOME ;QUIT IF HEIGHT <= 0 + MOVE D0,HEIGHT(A6) ;SAVE FOR LATER + + +;-------------------------------------------------------------- +; +; SET UP FOR TOP TO BOTTOM, LEFT TO RIGHT +; GET SRC AND DST TOP AND ROWBYTES +; + MOVEQ #2,D3 ;BUMP:=2 (TRANSFER LEFT TO RIGHT) + MOVE TOP(A2),D0 ;GET SRC TOP + SUB BOUNDS+TOP(A4),D0 ;CONVERT SRC TOP TO GLOBAL + MOVE D0,SRCV(A6) ;SAVE FOR LATER + + MOVE TOP(A3),D0 ;GET DST TOP + SUB BOUNDS+TOP(A5),D0 ;CONVERT DST TOP TO GLOBAL + MOVE D0,DSTV(A6) ;SAVE FOR LATER + + MOVE ROWBYTES(A4),SRCROW(A6) ;SRCROW:=SRCBITS.ROWBYTES + MOVE ROWBYTES(A5),DSTROW(A6) ;DSTROW:=DSTBITS.ROWBYTES + + +;-------------------------------------------------------------------- +; +; SET UP INVERT FLAG, IN CASE SRC OR PATTERN WILL BE INVERTED +; + CLR D7 ;SAY NOT INVERTED + MOVE MODE(A6),D0 ;GET TRANSFER MODE + BTST #2,D0 ;IS MODE AN INV. ONE ? + BEQ.S MODEOK ;NOT INVERTED, CONTINUE + NOT D7 ;INVERTED, PUT -1 IN INVERT REG +MODEOK BTST #3,D0 ;WILL WE USE PATTERN ? + BEQ.S DIREC ;NO, DON'T BOTHER TO SET UP + + +;------------------------------------------------------------ +; +; PATTERN WILL BE USED. EXPAND 8 BYTE PATTERN TO 16 LONGS. +; + MOVE BOUNDS+LEFT(A5),D2 ;GET GLOBAL-LOCAL OFFSET + MOVE.L PAT(A6),A0 ;POINT TO BYTE WIDE PATTERN + LEA EXPAT(A6),A1 ;POINT TO EXPANDED PATTERN + MOVE.L SAVEA5(A6),A5 ;GET GLOBAL POINTER + JSR PATEXPAND ;EXPAND 8 BYTES TO 16 LONGS + MOVE.L DSTBITS(A6),A5 ;RESTORE A5 TO DSTBITS + + +;------------------------------------------------------------ +; +; SET UP (VERT * 4) MOD 64 AS PATTERN SELECTOR +; + MOVEQ #$F,D7 ;TREAT COORD MOD 16 + AND TOP(A3),D7 ;GET DST TOP LOCAL COORD + LSL #2,D7 ;QUAD FOR LONG PATTERNS + MOVE.L EXPAT(A6,D7),D6 ;GET FIRST PATTERN DATA + BRA.S NOTSRC ;NOT USING SRC, SKIP OVER + + +;----------------------------------------------------------- +; +; SOURCE WILL BE USED, SO SET UP VERT AND HORIZ DIRECTIONS +; SUCH THAT SRC WON'T GET CLOBBERED TILL AFTER IT HAS BEEN USED +; +DIREC MOVE.L BASEADDR(A4),D0 ;GET SRC BASEADDR + CMP.L BASEADDR(A5),D0 ;ARE SRC AND DST ARRAYS THE SAME ? + BNE.S GETSRC ;NO, DONT WORRY ABOUT OVERLAP + MOVE SRCV(A6),D0 ;GET SRCV + CMP DSTV(A6),D0 ;IS SRCV > DSTV ? + BGT.S GETSRC ;YES, CONTINUE WITH TOP TO BOTTOM + BLT.S UPSIDE ;NO, DO UPSIDE DOWN + MOVE LEFT(A2),D0 ;SAME VERT, CHOOSE HORIZ DIRECTION + SUB BOUNDS+LEFT(A4),D0 ;CONVERT SRC LEFT TO GLOBAL + MOVE LEFT(A3),D1 ;GET DST LEFT + SUB BOUNDS+LEFT(A5),D1 ;CONVERT TO GLOBAL + CMP D1,D0 ;IS SRCLEFT < DSTLEFT ? + BGE.S GETSRC ;NO, DO LEFT TO RIGHT + NEG D3 ;YES, BUMP:=-2 (RIGHT TO LEFT) + BRA.S GETSRC ;CONTINUE + + +;---------------------------------------------------------- +; +; DO UPSIDE DOWN TO AVOID CLOBBERING SRC +; +UPSIDE MOVE HEIGHT(A6),D0 ;GET HEIGHT + SUB #1,D0 ;CALC HEIGHT-1 + ADD D0,SRCV(A6) ;SRCVERT:=SRCV+HEIGHT-1 + ADD D0,DSTV(A6) ;DSTVERT:=DSTV+HEIGHT-1 + NEG SRCROW(A6) ;SRCROW:=-SRCROW + NEG DSTROW(A6) ;DSTROW:=-DSTROW + + +;----------------------------------------------------- +; +; SET UP SHIFTCNT IN D6 (RELATIVE SHIFT BETWEEN SRC & DST) +; +GETSRC MOVE LEFT(A3),D6 ;GET DST LEFT + SUB BOUNDS+LEFT(A5),D6 ;CONVERT TO GLOBAL + MOVE LEFT(A2),D1 ;GET SRC LEFT + SUB BOUNDS+LEFT(A4),D1 ;CONVERT TO GLOBAL + SUB D1,D6 ;CALC DELTA HORIZ + AND #$F,D6 ;SHIFTCNT:=DELTA HORIZ MOD 16 + + +;------------------------------------------------------------ +; +; SET UP SRCLEFT IN A4, ADDR OF LEFTMOST SRC WORD +; (GOODBYE SRCBITS PTR) +; + MOVE SRCV(A6),D0 ;GET FIRST SRC VERT + MULU ROWBYTES(A4),D0 ;CALC SRC ROWBYTES * FIRST SRC VERT + MOVE.L BASEADDR(A4),A4 ;GET START OF SRC BITMAP + ADD.L D0,A4 ;ADD TO BITMAP START + ADD D6,D1 ;CALC SRCH+SHIFTCNT + ASR #3,D1 ;CONVERT BITS TO BYTE OFFSET + AND #$FFFE,D1 ;TRUNC TO WORD BOUNDARY + ADD D1,A4 ;LEAVE SRCLEFT IN A4 + + +;------------------------------------------------------------ +; +; SET UP DSTLEFT IN A5, ADDR OF LEFTMOST DST WORD +; (GOODBYE DSTBITS PTR) +; +NOTSRC MOVE LEFT(A3),D1 ;GET DST LEFT + SUB BOUNDS+LEFT(A5),D1 ;CONVERT TO GLOBAL + MOVE DSTV(A6),D0 ;GET FIRST DST VERT + MULU ROWBYTES(A5),D0 ;CALC DSTROW * FIRST DST VERT + MOVE.L BASEADDR(A5),A5 ;GET START OF DST BITMAP + ADD.L D0,A5 ;ADD DSTV*DSTROW + MOVE D1,D0 ;COPY DSTLEFT GLOBAL + ASR #4,D1 ;CONVERT FROM DOTS TO WORDS + ADD D1,D1 ;DOUBLE FOR BYTES + ADD D1,A5 ;LEAVE DSTLEFT IN A5 + + +;------------------------------------- +; +; SET UP LEFTMASK IN D4 +; (GOODBYE SRCRECT PTR) +; + MOVE D0,D1 ;SAVE DSTH + JSR LEFTMASK ;GET LEFTMASK + MOVE D0,D4 ;PUT IN D4 + + +;------------------------------------- +; +; SET UP RIGHTMASK IN D5 +; (GOODBYE DSTRECT PTR) +; + AND #$F,D1 ;TREAT DSTH MOD 16 + MOVE RIGHT(A3),D0 ;GET DST RIGHT + SUB LEFT(A3),D0 ;CALC WIDTH + BLE GOHOME ;QUIT IF WIDTH <= 0 + ADD D1,D0 ;CALC (DSTH MOD 16) + WIDTH + MOVE D0,D1 ;MAKE AN EXTRA COPY + JSR RIGHTMASK ;GET RIGHT MASK + MOVE D0,D5 ;SAVE RIGHTMASK IN D5 + + +;------------------------------------------------ +; +; CALC TOTAL NUMBER OF DST WORDS-1 +; + ASR #4,D1 ;CALC ((DSTH MOD 16)+WIDTH) DIV 16 + MOVE D1,WORDCNT(A6) ;SAVE AS WORDCNT + MOVE D1,D2 ;set up for below + +; +; Set up srcBump and dstBump, assuming bumping to the right +; + ADD D1,D1 ;calc 2*wordCount + MOVE D1,D0 ;make a copy + ADD #2,D0 ;adjust for total bytesNeeded + +;-------------------------------------------------------------------------- +; +; IF DRAWING BACKWARDS FROM RIGHT, then adjust dstBump, +; ADJUST SRCADDR,DSTADDR TO FIRST WORD, +; AND SWAP LEFT AND RIGHT MASKS FOR FIRSTMASK AND LASTMASK. +; + MOVE D3,A0 ;put hBump (+-2) into A0 + TST D3 ;ARE WE STARTING ON THE LEFT ? + BPL.S DIROK ;YES, CONTINUE + NEG D0 ;calc -1 * bytesNeeded + ADD D1,A5 ;ADJUST DSTADDR TO RIGHTMOST + ADD D1,A4 ;ADJUST SRCADDR TO RIGHTMOST + EXG D4,D5 ;FIRSTMASK=RIGHT,LASTMASK=LEFT + +DIROK MOVE srcRow(A6),srcBump(A6) + SUB D0,srcBump(A6) ;srcBump := srcRow +- bytesBumped + MOVE dstRow(A6),A3 + SUB D0,A3 ;dstBump := dstRow +- bytesBumped + + +;---------------------------------------------- +; +; SET UP MODE CASE JUMP IN A1 +; +GETMODE MOVE MODE(A6),D0 ;GET TRANSFER MODE + BNE.S NOTFAST ;BR IF NOT MODE 0 + TST D6 ;IS SHIFTCNT 0 ? + BNE.S NOTFAST ;NO, CONTINUE + TST WORDCNT(A6) ;IS WORDCNT > 0 ? + BLE.S NOTFAST ;NO, CONTINUE + LEA SETUP0,A1 ;USE FAST COPY. + TST D3 ;ARE WE BUMPING LEFT TO RIGHT ? + BPL.S NEXTROW ;YES, ALL SET + LEA LEFT0,A1 ;NO, USE BACKWARDS LOOP + BRA.S NEXTROW + +NOTFAST AND #$B,D0 ;TREAT MODE MOD 16 AND KILL INVERT BIT + MOVE D0,D1 ;MAKE A COPY + AND #3,D0 ;MASK FOR LOW BITS ONLY + ADD D0,D1 ;MAKE MODIFIED MODE * 2 FOR INDEX + TST D2 ;IS DST ALL IN ONE WORD ? + BNE.S DOMAIN ;NO, USE FIRST JUMP TABLE + ADD #16,D1 ;YES, USE SECOND JUMP TABLE +DOMAIN LEA MODETAB,A1 ;GET ADDRESS OF MODE TABLE + ADD 0(A1,D1),A1 ;POINT TO THIS MODE'S ROW LOOP + + +;--------------------------------------------------------- +; +; OUTER LOOP: DO EACH SCAN LINE AND COME BACK TO NXTSRC OR NXTPAT. +; SOME MODES OPTIMIZE AND DO WHOLE OUTER LOOP AND COME BACK TO GOHOME. +; +NEXTROW MOVE HEIGHT(A6),D3 ;get height + SUB #1,D3 ;init DBRA rowcount + +ROWLOOP MOVE D4,D1 ;MASK:=FIRSTMASK + MOVE WORDCNT(A6),D2 ;GET WORDCOUNT + JMP (A1) ;DO THIS ROW AND COME BACK + +NXTSRC ADD srcBump(A6),A4 ;bump srcPtr to next row + ADD A3,A5 ;BUMP DSTADDR TO NEXT ROW + DBRA D3,ROWLOOP ;loop for all srcRows + BRA.S GOHOME ;then quit + +NXTPAT ADD #4,D7 ;BUMP PATTERN SELECTOR + AND #$3F,D7 ;MOD 64 FOR 16 LONG REPEAT + MOVE.L EXPAT(A6,D7),D6 ;GET PATTERN DATA FOR NEXT ROW + ADD A3,A5 ;BUMP DSTADDR TO NEXT ROW + DBRA D3,ROWLOOP ;loop for all srcRows + ;then quit + +GOHOME MOVEM.L (SP)+,D3-D7/A2-A5 ;RESTORE REGS + UNLINK PARAMSIZE,'BITBLT ' + + + +;---------------------------------------------------------------; +; ; +; INTERFACE TO EACH BITBLT SCANLINE LOOP: ; +; ; +; REGISTERS: A0: hBump (+-2) D0: scratch ; +; A1: MODE CASE JUMP D1: FIRSTMASK ; +; A2: used for loop jmp D2: WORDCNT ; +; A3: dstBump D3: height-1 ; +; A4: SRCPTR D4: FIRSTMASK ; +; A5: DSTPTR D5: LASTMASK ; +; A6: LOCALS D6: SHIFTCNT OR PATTERN ; +; A7: STACK PTR D7: INVERT OR PAT-SEL ; +; ; +;---------------------------------------------------------------; + +MODETAB .WORD MAIN0-MODETAB ;JUMP TABLE USED IF DST WIDER THAN ONE WORD + .WORD MAIN1-MODETAB + .WORD MAIN2-MODETAB + .WORD MAIN3-MODETAB + .WORD SETUP8-MODETAB + .WORD MAIN9-MODETAB + .WORD SETUP10-MODETAB + .WORD MAIN11-MODETAB + + .WORD END0-MODETAB ;JUMP TABLE USED IF DST FITS IN ONE WORD WIDE + .WORD END1-MODETAB + .WORD END2-MODETAB + .WORD END3-MODETAB + .WORD WORD8-MODETAB + .WORD END9-MODETAB + .WORD END10-MODETAB + .WORD END11-MODETAB + + +;------------------------------------------------------------ +; +; OPTIMIZE RIGHT HORIZONTAL SCROLL IF NO SHIFT. +; ONLY IF MODE 0, BUMPING RIGHT TO LEFT, WORDCNT > 0, AND NO SHIFT. +; +LEFT0 MOVE (A4),D0 ;GET SRC FROM BITMAP + ADD A0,A4 ;BUMP LEFT + AND D1,D0 ;MASK FIRST WORD + NOT D1 ;MAKE NOTMASK + AND (A5),D1 ;GET DATA FROM DST + OR D1,D0 ;MERGE WITH SRC DATA + MOVE D0,(A5) ;PUT RESULT TO DST + ADD A0,A5 ;BUMP LEFT + MOVEQ #-1,D1 ;FLUSH MASK FOR END0 + SUB #1,D2 ;DEC WORD COUNT + BEQ.S END0 ;BR IF NO UNMASKED WORDS + SUB A0,A4 ;GET READY FOR PRE-DECREMENT + SUB A0,A5 ;GET READY FOR PRE-DECREMENT + LSR #1,D2 ;HALVE WORDCOUNT FOR LONGCOUNT + BCC.S LONE0 ;BR IF EVEN # WORDS LEFT + MOVE -(A4),-(A5) ;ELSE MAKE EVEN BY DOING A WORD + SUB #1,D2 ;ADJUST LONGCOUNT + BRA.S LMORE0 ;SEE IF ANY LONGS LEFT TO DO +LTWO0 MOVE.L -(A4),-(A5) ;MOVE A LONG WORD +LONE0 MOVE.L -(A4),-(A5) ;MOVE ANOTHER LONG + SUB #2,D2 ;ANY UNMASKED LONGS LEFT IN ROW ? +LMORE0 BGT LTWO0 ;YES, AT LEAST 2 LONGS LEFT + BEQ LONE0 ;YES, FINISH UP LAST LONG + ADD A0,A4 ;RETURN TO NORMAL AFTER PRE-DECREMENT + ADD A0,A5 ;RETURN TO NORMAL AFTER PRE-DECREMENT + BRA.S END0 ;DO LAST WORD WITH MASK + + +;------------------------------------------------------------ +; +; OPTIMIZE VERTICAL AND LEFT HORIZONTAL SCROLL IF SHIFT = 0. +; ONLY IF MODE 0, BUMPING LEFT TO RIGHT, WORDCNT > 0, AND NO SHIFT. +; +SETUP0 LEA FAST0,A1 ;only do setup once + LEA COPYBIG,A2 ;point to big copy + BRA CALCLP ;share loop calc + +FAST0 MOVE (A4)+,D0 ;GET SRC FROM BITMAP + AND D1,D0 ;MASK FIRST WORD + NOT D1 ;MAKE NOTMASK + AND (A5),D1 ;GET DST DATA + OR D1,D0 ;MERGE WITH SRC DATA + MOVE D0,(A5)+ ;PUT RESULT TO DST + MOVEQ #-1,D1 ;FLUSH MASK FOR END0 + SUB #1,D2 ;DEC WORD COUNT + BEQ.S END0 ;BR IF NO UNMASKED WORDS + + JSR (A2) ;call unwound copy loop + MOVEQ #-1,D2 ;force finish up below + +;------------------------------------------------------- +; +; MODE 0 OR 4: SRC --> DST +; +END0 AND D5,D1 ;MASK:=MASK AND LASTMASK +MAIN0 MOVE.L -2(A4),D0 ;GET SRC FROM BITMAP + ADD A0,A4 ;BUMP SRCPTR LEFT OR RIGHT + LSR.L D6,D0 ;ALIGN TO DST + EOR D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND D1,D0 ;MASK SRC + NOT D1 ;FORM NOTMASK + AND (A5),D1 ;GET DST DATA + OR D1,D0 ;MERGE WITH SRC DATA + MOVE D0,(A5) ;PUT RESULT TO DST + ADD A0,A5 ;BUMP DSTPTR LEFT OR RIGHT + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT + BGT MAIN0 ;BR IF UNMASKED WORDS LEFT + BEQ END0 ;DO LAST WORD WITH LASTMASK + BRA NXTSRC ;LOOP BACK FOR MORE + + +;---------------------------------------------------------- +; +; Call copybig with wordcount in D2 (clobbered) +; +COPYBIG BCLR #0,D2 ;is wordcount even ? + BEQ.S @1 ;yes, continue + MOVE.W (A4)+,(A5)+ ;no, make it even +@1 SUB #32,D2 ;calc wordcount-32 + BLE.S @2 ;continue if wordcount <= 32 + BSR.S COPY32 ;else copy 32 words + BRA.S @1 ;and loop for more +@2 NEG D2 ;calc 32-wordcount + JMP COPY32(D2) ;jump into loop + +COPY32 MOVE.L (A4)+,(A5)+ ;TABLE TO COPY 0..32 WORDS + MOVE.L (A4)+,(A5)+ ;wordCount = 30 + MOVE.L (A4)+,(A5)+ ;wordCount = 28 + MOVE.L (A4)+,(A5)+ ;wordCount = 26 + MOVE.L (A4)+,(A5)+ ;wordCount = 24 + MOVE.L (A4)+,(A5)+ ;wordCount = 22 + MOVE.L (A4)+,(A5)+ ;wordCount = 20 + MOVE.L (A4)+,(A5)+ ;wordCount = 18 + MOVE.L (A4)+,(A5)+ ;wordCount = 16 + MOVE.L (A4)+,(A5)+ ;wordCount = 14 + MOVE.L (A4)+,(A5)+ ;wordCount = 12 + MOVE.L (A4)+,(A5)+ ;wordCount = 10 + MOVE.L (A4)+,(A5)+ ;wordCount = 8 + MOVE.L (A4)+,(A5)+ ;wordCount = 6 + MOVE.L (A4)+,(A5)+ ;wordCount = 4 + MOVE.L (A4)+,(A5)+ ;wordCount = 2 +COPY0 RTS ;wordCount = 0 + + +COPY31 MOVE.L (A4)+,(A5)+ ;TABLE TO COPY 1..31 WORDS + MOVE.L (A4)+,(A5)+ ;wordCount = 29 + MOVE.L (A4)+,(A5)+ ;wordCount = 27 + MOVE.L (A4)+,(A5)+ ;wordCount = 25 + MOVE.L (A4)+,(A5)+ ;wordCount = 23 + MOVE.L (A4)+,(A5)+ ;wordCount = 21 + MOVE.L (A4)+,(A5)+ ;wordCount = 19 + MOVE.L (A4)+,(A5)+ ;wordCount = 17 + MOVE.L (A4)+,(A5)+ ;wordCount = 15 + MOVE.L (A4)+,(A5)+ ;wordCount = 13 + MOVE.L (A4)+,(A5)+ ;wordCount = 11 + MOVE.L (A4)+,(A5)+ ;wordCount = 9 + MOVE.L (A4)+,(A5)+ ;wordCount = 7 + MOVE.L (A4)+,(A5)+ ;wordCount = 5 + MOVE.L (A4)+,(A5)+ ;wordCount = 3 +COPY1 MOVE.W (A4)+,(A5)+ ;wordCount = 1 + RTS + + + +;------------------------------------------------------- +; +; MODE 1 OR 5: SRC OR DST --> DST +; +END1 AND D5,D1 ;MASK:=MASK AND LASTMASK +MAIN1 MOVE.L -2(A4),D0 ;GET SRC FROM BITMAP + ADD A0,A4 ;BUMP SRCPTR LEFT OR RIGHT + LSR.L D6,D0 ;ALIGN TO DST + EOR D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND D1,D0 ;MASK SRC + OR D0,(A5) ;OR SRC INTO DST + ADD A0,A5 ;BUMP DSTPTR LEFT OR RIGHT + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT + BGT MAIN1 ;LOOP TILL LAST WORD + BEQ END1 ;DO LAST WORD WITH LASTMASK + BRA NXTSRC ;LOOP BACK FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 2 OR 6: SRC XOR DST --> DST +; +END2 AND D5,D1 ;MASK:=MASK AND LASTMASK +MAIN2 MOVE.L -2(A4),D0 ;GET SRC FROM BITMAP + ADD A0,A4 ;BUMP SRCPTR LEFT OR RIGHT + LSR.L D6,D0 ;ALIGN TO DST + EOR D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND D1,D0 ;MASK SRC + EOR D0,(A5) ;XOR SRC INTO DST + ADD A0,A5 ;BUMP DSTPTR LEFT OR RIGHT + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT + BGT MAIN2 ;LOOP TILL LAST WORD + BEQ END2 ;DO LAST WORD WITH LASTMASK + BRA NXTSRC ;LOOP BACK FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 3 OR 7: SRC BIC DST --> DST +; +END3 AND D5,D1 ;MASK:=MASK AND LASTMASK +MAIN3 MOVE.L -2(A4),D0 ;GET SRC FROM BITMAP + ADD A0,A4 ;BUMP SRCPTR LEFT OR RIGHT + LSR.L D6,D0 ;ALIGN TO DST + EOR D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND D1,D0 ;MASK SRC + NOT D0 ;INVERT SRC + AND D0,(A5) ;BIT CLEAR SRC INTO DST + ADD A0,A5 ;BUMP DSTPTR LEFT OR RIGHT + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT + BGT MAIN3 ;LOOP TILL LAST WORD + BEQ END3 ;DO LAST WORD WITH LASTMASK + BRA NXTSRC ;LOOP BACK FOR NEXT ROW + + +;----------------------------------------------------------- +; +; OPTIMIZE MODE 8 OR 12 IF DST FITS IN ONE WORD (VERT LINES ETC) +; +WORD8 AND D5,D1 ;COMBINE LEFT AND RIGHT MASKS + MOVE D1,D5 ;COPY COMBINED MASK + NOT D5 ;FORM NOTMASK +WORD8A AND D1,D6 ;MASK EXTRA PATTERN TO ZEROS + MOVE (A5),D0 ;GET DST DATA + AND D5,D0 ;AND WITH NOTMASK + OR D6,D0 ;MERGE WITH SRC DATA + MOVE D0,(A5)+ ;PUT RESULT TO DST + ADD A3,A5 ;BUMP DSTPTR TO NEXT ROW + ADD #4,D7 ;BUMP PATTERN SELECTOR + AND #$3F,D7 ;MOD 64 FOR 16 LONG REPEAT + MOVE EXPAT(A6,D7),D6 ;GET PATTERN FOR NEXT ROW + DBRA D3,WORD8A ;LOOP ALL ROWS + BRA GOHOME + + +;------------------------------------------------------- +; +; MODE 8 OR 12: PATTERN --> DST (FILLING AREAS, DRAWING LINES) +; +SETUP8 LEA FAST8,A1 ;only do setup once + LEA FILLBIG,A2 ;point to big fill +CALCLP CMP #32,D2 ;is wordcnt > 32 ? + BGT.S @2 ;yes use fillbig + + ADD #COPY0+1-COPYBIG,A2 ;no, point to even table + BTST #0,D2 ;will wordcount-1 be even ? + BNE.S @1 ;yes, use even table + ADD #COPY1+1-COPY0,A2 ;no, point to odd table +@1 SUB D2,A2 ;adjust loop jump +@2 JMP (A1) ;re-connect with shared code + + +FAST8 MOVE D6,D0 ;GET PATTERN DATA + AND D1,D0 ;MASK FIRST WORD + NOT D1 ;MAKE NOTMASK + AND (A5),D1 ;GET DST DATA + OR D1,D0 ;MERGE WITH PAT DATA + MOVE D0,(A5)+ ;PUT RESULT TO DST + SUB #1,D2 ;DEC WORD COUNT + BEQ.S END8 ;BR IF NO UNMASKED WORDS + + JSR (A2) ;call unwound loop + +END8 MOVE D5,D1 ;MASK:= RIGHTMASK + AND D1,D6 ;MASK PATTERN + NOT D1 ;MAKE NOTMASK + AND (A5),D1 ;GET DST DATA + OR D1,D6 ;MERGE WITH PAT DATA + MOVE D6,(A5)+ ;PUT RESULT TO DST + BRA NXTPAT ;LOOP BACK FOR NEXT ROW + + +;---------------------------------------------------------- +; +; Call fillbig with wordcount in D2 (clobbered) +; +FILLBIG BCLR #0,D2 ;is wordcount even ? + BEQ.S @1 ;yes, continue + MOVE.W D6,(A5)+ ;no, make it even +@1 SUB #32,D2 ;calc wordcount-32 + BLE.S @2 ;continue if wordcount <= 32 + BSR.S FILL32 ;elsae fill 32 words + BRA.S @1 ;and loop for more +@2 NEG D2 ;calc 32-wordcount + JMP FILL32(D2) ;jump into loop + +FILL32 MOVE.L D6,(A5)+ ;TABLE TO FILL 0..32 WORDS + MOVE.L D6,(A5)+ ;wordCount = 30 + MOVE.L D6,(A5)+ ;wordCount = 28 + MOVE.L D6,(A5)+ ;wordCount = 26 + MOVE.L D6,(A5)+ ;wordCount = 24 + MOVE.L D6,(A5)+ ;wordCount = 22 + MOVE.L D6,(A5)+ ;wordCount = 20 + MOVE.L D6,(A5)+ ;wordCount = 18 + MOVE.L D6,(A5)+ ;wordCount = 16 + MOVE.L D6,(A5)+ ;wordCount = 14 + MOVE.L D6,(A5)+ ;wordCount = 12 + MOVE.L D6,(A5)+ ;wordCount = 10 + MOVE.L D6,(A5)+ ;wordCount = 8 + MOVE.L D6,(A5)+ ;wordCount = 6 + MOVE.L D6,(A5)+ ;wordCount = 4 + MOVE.L D6,(A5)+ ;wordCount = 2 + RTS ;wordCount = 0 + +FILL31 MOVE.L D6,(A5)+ ;TABLE TO FILL 1..31 WORDS + MOVE.L D6,(A5)+ ;wordCount = 29 + MOVE.L D6,(A5)+ ;wordCount = 27 + MOVE.L D6,(A5)+ ;wordCount = 25 + MOVE.L D6,(A5)+ ;wordCount = 23 + MOVE.L D6,(A5)+ ;wordCount = 21 + MOVE.L D6,(A5)+ ;wordCount = 19 + MOVE.L D6,(A5)+ ;wordCount = 17 + MOVE.L D6,(A5)+ ;wordCount = 15 + MOVE.L D6,(A5)+ ;wordCount = 13 + MOVE.L D6,(A5)+ ;wordCount = 11 + MOVE.L D6,(A5)+ ;wordCount = 9 + MOVE.L D6,(A5)+ ;wordCount = 7 + MOVE.L D6,(A5)+ ;wordCount = 5 + MOVE.L D6,(A5)+ ;wordCount = 3 + MOVE.W D6,(A5)+ ;wordCount = 1 + RTS + + +;------------------------------------------------------- +; +; MODE 9 OR 13: PATTERN OR DST --> DST +; +END9 AND D5,D1 ;MASK:=MASK AND LASTMASK +MAIN9 MOVE D6,D0 ;GET PATTERN DATA + AND D1,D0 ;MASK PATTERN + OR D0,(A5)+ ;OR PATTERN INTO DST + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT + BGT MAIN9 ;LOOP TILL LAST WORD + BEQ END9 ;DO LAST WORD WITH LASTMASK + BRA NXTPAT ;LOOP BACK FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 10 OR 14: PATTERN XOR DST --> DST (INVERTING AREAS, XOR LINES) +; +SETUP10 LEA FAST10,A1 ;only do setup once + LEA XORBIG,A2 ;point to big fill + BRA CALCLP ;share loop calc + +FAST10 MOVE D6,D0 ;GET PATTERN DATA + AND D1,D0 ;MASK FIRST WORD + EOR D0,(A5)+ ;XOR PATTERN INTO DST + MOVEQ #-1,D1 ;FLUSH MASK FOR END10 + SUB #1,D2 ;DEC WORD COUNT + BEQ.S END10 ;BR IF NO UNMASKED WORDS + + JSR (A2) ;call unwound loop + MOVEQ #-1,D2 ;force finish up below + +END10 AND D5,D1 ;MASK:=MASK AND LASTMASK + AND D1,D6 ;MASK PATTERN + EOR D6,(A5)+ ;XOR PATTERN DATA INTO DST + BRA NXTPAT ;LOOP BACK FOR NEXT ROW + + +;---------------------------------------------------------- +; +; Call XORbig with wordcount in D2 (clobbered) +; +XORBIG BCLR #0,D2 ;is wordcount even ? + BEQ.S @1 ;yes, continue + EOR.W D6,(A5)+ ;no, make it even +@1 SUB #32,D2 ;calc wordcount-32 + BLE.S @2 ;continue if wordcount <= 32 + BSR.S XOR32 ;else XOR 32 words + BRA @1 ;and loop for more +@2 NEG D2 ;calc 32-wordcount + JMP XOR32(D2) ;jump into loop + +XOR32 EOR.L D6,(A5)+ ;TABLE TO XOR 0..32 WORDS + EOR.L D6,(A5)+ ;wordCount = 30 + EOR.L D6,(A5)+ ;wordCount = 28 + EOR.L D6,(A5)+ ;wordCount = 26 + EOR.L D6,(A5)+ ;wordCount = 24 + EOR.L D6,(A5)+ ;wordCount = 22 + EOR.L D6,(A5)+ ;wordCount = 20 + EOR.L D6,(A5)+ ;wordCount = 18 + EOR.L D6,(A5)+ ;wordCount = 16 + EOR.L D6,(A5)+ ;wordCount = 14 + EOR.L D6,(A5)+ ;wordCount = 12 + EOR.L D6,(A5)+ ;wordCount = 10 + EOR.L D6,(A5)+ ;wordCount = 8 + EOR.L D6,(A5)+ ;wordCount = 6 + EOR.L D6,(A5)+ ;wordCount = 4 + EOR.L D6,(A5)+ ;wordCount = 2 + RTS ;wordCount = 0 + +XOR31 EOR.L D6,(A5)+ ;TABLE TO XOR 1..31 WORDS + EOR.L D6,(A5)+ ;wordCount = 29 + EOR.L D6,(A5)+ ;wordCount = 27 + EOR.L D6,(A5)+ ;wordCount = 25 + EOR.L D6,(A5)+ ;wordCount = 23 + EOR.L D6,(A5)+ ;wordCount = 21 + EOR.L D6,(A5)+ ;wordCount = 19 + EOR.L D6,(A5)+ ;wordCount = 17 + EOR.L D6,(A5)+ ;wordCount = 15 + EOR.L D6,(A5)+ ;wordCount = 13 + EOR.L D6,(A5)+ ;wordCount = 11 + EOR.L D6,(A5)+ ;wordCount = 9 + EOR.L D6,(A5)+ ;wordCount = 7 + EOR.L D6,(A5)+ ;wordCount = 5 + EOR.L D6,(A5)+ ;wordCount = 3 + EOR.W D6,(A5)+ ;wordCount = 1 + RTS + + +;------------------------------------------------------- +; +; MODE 11 OR 15: PATTERN BIC DST --> DST +; +END11 AND D5,D1 ;MASK:=MASK AND LASTMASK +MAIN11 MOVE D6,D0 ;GET PATTERN DATA + AND D1,D0 ;MASK PATTERN + NOT D0 ;INVERT PATTERN + AND D0,(A5)+ ;BIC PATTERN INTO DST + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT + BGT MAIN11 ;LOOP TILL LAST WORD + BEQ END11 ;DO LAST WITH LASTMASK + BRA NXTPAT ;LOOP BACK FOR NEXT ROW + + + + .ASCII 'CopyRight 1983 Apple Computer Inc.' + + + .END diff --git a/Bitmaps.a b/Bitmaps.a new file mode 100755 index 0000000..0d75033 --- /dev/null +++ b/Bitmaps.a @@ -0,0 +1,1018 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; +; **** *** ***** * * * **** *** +; * * * * ** ** * * * * * * +; * * * * * * * * * * * * * +; **** * * * * * * * **** *** +; * * * * * * ***** * * +; * * * * * * * * * * * +; **** *** * * * * * * *** +; +; +; +; QuickDraw Routines to operate on BitMaps. +; + + .PROC StdBits,5 + .REF CheckPic,PutPicByte,PutPicWord,PutPicRgn,PutPicData + .REF StretchBits,PackBits +;--------------------------------------------------------------- +; +; PROCEDURE StdBits(VAR srcBits: BitMap; +; VAR srcRect: Rect; +; VAR dstRect: Rect; +; mode: INTEGER; +; maskRgn: RgnHandle); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 18 +SRCBITS .EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP +SRCRECT .EQU SRCBITS-4 ;LONG, ADDR OF RECT +DSTRECT .EQU SRCRECT-4 ;LONG, ADDR OF RECT +MODE .EQU DSTRECT-2 ;WORD +MASKRGN .EQU MODE-4 ;LONG, RGNHANDLE + +MYBITS .EQU -14 ;BITMAP +PACKBUF .EQU MYBITS-256 ;SCANLINE PACKING BUFFER +SRCPTR .EQU PACKBUF-4 ;LONG +DSTPTR .EQU SRCPTR-4 ;LONG +VARSIZE .EQU DSTPTR ;TOTAL BYTES OF LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGS + JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE NOTPIC ;BRANCH IF NOT PICSAVE + + MOVEQ #8,D6 +; +; TRIM SRCBITS +; + MOVE.L SRCBITS(A6),A0 ;GET ADDR OF SRCBITS + LEA MYBITS(A6),A1 ;POINT TO MY COPY + MOVE.L BASEADDR(A0),A3 ;GET BASEADDR (CLOBBERS A3) + MOVE ROWBYTES(A0),D4 ;GET OLD ROWBYTES + MOVE.L BOUNDS+TOPLEFT(A0),BOUNDS+TOPLEFT(A1) ;COPY BOUNDS TOPLEFT + MOVE.L BOUNDS+BOTRIGHT(A0),BOUNDS+BOTRIGHT(A1) ;COPY BOUNDS BOTRIGHT + MOVE.L SRCRECT(A6),A0 ;POINT TO SRCRECT + MOVE TOP(A0),D0 ;GET SRCRECT.TOP + SUB BOUNDS+TOP(A1),D0 ;SKIPTOP:=SRCRECT.TOP-BOUNDS.TOP + BLE.S TOPOK ;CONTINUE IF SKIPTOP NEG + ADD D0,BOUNDS+TOP(A1) ;NEWTOP := SRCRECT TOP + MULU D4,D0 ;CALC VERT OFFSET + ADD.L D0,A3 ;ADJUST BASEADDR + +TOPOK MOVE BOTTOM(A0),D0 ;GET SRCRECT.BOTTOM + CMP BOUNDS+BOTTOM(A1),D0 ;IS SRCRECT BOT < BOUNDS BOT ? + BGE.S BOTOK ;NO, CONTINUE + MOVE D0,BOUNDS+BOTTOM(A1) ;YES, TRIM BOUNDS BOTTOM + +BOTOK MOVE LEFT(A0),D0 ;GET SRCRECT.LEFT + SUB BOUNDS+LEFT(A1),D0 ;CALC SKIPLEFT + BLE.S LEFTOK ;CONTINUE IF SKIPLEFT NEG + LSR #3,D0 ;DIV BY 8 FOR SKIP BYTES + ADD D0,A3 ;OFFSET BASEADDR HORIZ + LSL #3,D0 ;BYTES TIMES 8 FOR DOTS + ADD D0,BOUNDS+LEFT(A1) ;ADD DOTS TO BOUNDS.LEFT + +LEFTOK MOVE RIGHT(A0),D0 ;GET SRCRECT.RIGHT + SUB BOUNDS+LEFT(A1),D0 ;CONVERT TO GLOBAL + ADD #7,D0 ;ROUND UP + LSR #3,D0 ;TO NEXT MULT OF 8 + LSL #3,D0 + ADD BOUNDS+LEFT(A1),D0 ;RETURN TO LOCAL + CMP BOUNDS+RIGHT(A1),D0 ;IS RESULT < BOUNDS.RIGHT ? + BGE.S RIGHTOK ;NO, CONTINUE + MOVE D0,BOUNDS+RIGHT(A1) ;YES, TRIM RIGHT +RIGHTOK +; +; CALC NEW ROWBYTES AFTER TRIMMING +; + MOVE BOUNDS+RIGHT(A1),D5 ;GET TRIMMED RIGHT + SUB BOUNDS+LEFT(A1),D5 ;CALC WIDTH + ADD #15,D5 ;ROUND UP + LSR #4,D5 ;DIV BY 16 + BLE BITSOK ;IGNORE IF NEWROW <= 0 + ADD D5,D5 ;DOUBLE FOR NEW ROWBYTES + MOVE D5,ROWBYTES(A1) ;COPY ROWBYTES + + MOVE.B #$90,-(SP) ;PUSH OPCODE=BITSRECT + TST.L MASKRGN(A6) ;IS MASKRGN NIL ? + BEQ.S NOTRGN ;YES, CONTINUE + ADD.B #1,(SP) ;REPLACE OPCODE=BITSRGN (IE. $91) + ;FIXED BUG 12/3/83, RP +NOTRGN CMP D6,D5 ;IS NEWROW < 8 ? + BLT.S NOPACK ;YES, DONT BITPACK + ADD.B #8,(SP) ;SET BIT 3 FOR BITPACK +NOPACK JSR PutPicByte ;PUT OPCODE TO THEPIC + + PEA MYBITS+ROWBYTES(A6) ;PUSH ADDR OF ROWBYTYES,BOUNDS + MOVE #10,-(SP) ;PUSH BYTECOUNT = 10 + JSR PutPicData ;PUT ROWBYTES,BOUNDS TO THEPIC + + MOVE.L SRCRECT(A6),-(SP) + MOVE D6,-(SP) + JSR PutPicData ;PUT SRCRECT + MOVE.L DSTRECT(A6),-(SP) + MOVE D6,-(SP) + JSR PutPicData ;PUT DSTRECT + MOVE MODE(A6),-(SP) + JSR PutPicWord ;PUT MODE + + TST.L MASKRGN(A6) ;IS MASKRGN NIL ? + BEQ.S NOMASK ;YES, SKIP IT + MOVE.L MASKRGN(A6),-(SP) ;NO, PUSH MASKRGN + JSR PutPicRgn ;PUT MASKRGN TO THEPIC +NOMASK +; +; NOW PUT THE BITMAP DATA: IF NEWROW >= 8 THEN USE PACKBITS +; + LEA MYBITS(A6),A2 ;POINT TO (TRIMMED) BITMAP + MOVE BOUNDS+BOTTOM(A2),D7 + SUB BOUNDS+TOP(A2),D7 ;HEIGHT := BOUNDS BOT - TOP + + CMP D6,D5 ;IS NEWROW < 8 ? + BLT.S START2 ;YES, DONT TRY TO PACK + BRA.S START1 ;GO TO LOOP START +MORE1 MOVE.L A3,SRCPTR(A6) ;SRCPTR := ^SCANLINE DATA + LEA PACKBUF(A6),A0 + MOVE.L A0,DSTPTR(A6) ;DSTPTR := @PACKBUF + PEA SRCPTR(A6) ;PUSH VAR SRCPTR + PEA DSTPTR(A6) ;PUSH VAR DSTPTR + MOVE D5,-(SP) ;PUSH SRCBYTES = NEWROW + JSR PackBits ;PACK ROW INTO PACKBUF + MOVE.L DSTPTR(A6),D6 ;GET UPDATED DSTPTR + LEA PACKBUF(A6),A0 ;POINT TO PACKBUF + SUB.L A0,D6 ;CALC PACKED BYTECOUNT + MOVE.B D6,-(SP) + JSR PutPicByte ;PUT PACKED BYTECOUNT TO THEPIC + PEA PACKBUF(A6) + MOVE D6,-(SP) + JSR PutPicData ;PUT PACKED DATA TO THEPIC + ADD D4,A3 ;ADD OLDROW TO BITS PTR +START1 DBRA D7,MORE1 ;LOOP FOR HEIGHT ROWS + BRA.S BITSOK + +; +; ROWBYTES < 8, DONT USE PACKBITS +; +MORE2 MOVE.L A3,-(SP) ;PUSH ADDR OF BITS + MOVE D5,-(SP) ;PUSH BYTECOUNT = NEWROW + JSR PutPicData ;PUT ONE ROW OF BITMAP DATA + ADD D4,A3 ;ADD OLDROW TO BITS PTR +START2 DBRA D7,MORE2 ;LOOP FOR HEIGHT ROWS + + +BITSOK MOVE.L THEPORT(A4),A3 ;RESTORE THEPORT PTR +NOTPIC TST PNVIS(A3) ;IS PNVIS >= 0 ? + BLT.S GOHOME ;NO, QUIT + MOVE.L SRCBITS(A6),-(SP) ;PUSH SRCBITS + PEA PORTBITS(A3) ;PUSH DSTBITS = PORTBITS + MOVE.L SRCRECT(A6),-(SP) ;PUSH SRCRECT + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + MOVE MODE(A6),-(SP) ;PUSH MODE + MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN + MOVE.L VISRGN(A3),-(SP) ;PUSH VISRGN + MOVE.L MASKRGN(A6),-(SP) ;PUSH MASKRGN + BNE.S MASKOK ;WAS IT NIL ? + MOVE.L WIDEOPEN(A4),(SP) ;YES, REPLACE WITH WIDEOPEN +MASKOK JSR STRETCHBITS ;CALL STRETCHBITS + +GOHOME MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDBITS ' + + + + .PROC CopyBits,6 + .REF StdBits,ShieldCursor,ShowCursor,StretchBits +;--------------------------------------------------------------- +; +; PROCEDURE CopyBits(srcBits,dstBits: BitMap; +; srcRect,dstRect: Rect; +; mode: INTEGER; +; maskRgn: RgnHandle *); +; +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 22 ;TOTAL BYTES OF PARAMS +SRCBITS .EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP +DSTBITS .EQU SRCBITS-4 ;LONG, ADDR OF BITMAP +SRCRECT .EQU DSTBITS-4 ;LONG, ADDR OF RECT +DSTRECT .EQU SRCRECT-4 ;LONG, ADDR OF RECT +MODE .EQU DSTRECT-2 ;WORD +MASKRGN .EQU MODE-4 ;LONG, RGNHANDLE + + + LINK A6,#0 ;NO LOCAL VARS + MOVEM.L D6-D7/A2-A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;POINT TO CURRENT GRAFPORT + MOVE.L SRCBITS(A6),A2 ;POINT TO SRCBITS + MOVE.L BASEADDR(A2),D7 ;GET SRCBITS.BASEADDR + MOVE.L SCREENBITS+BASEADDR(A4),D6 ;GET SCREENBITS.BASEADDR + CMP.L D6,D7 ;IS SRC FROM THE SCREEN ? + BNE.S SRCOK ;NO, CONTINUE + MOVE.L SRCRECT(A6),-(SP) ;YES, PUSH SRCRECT + MOVE.L BOUNDS+TOPLEFT(A2),-(SP) ;PUSH OFFSET POINT + JSR SHIELDCURSOR ;HIDE THE CURSOR IF IN SRCRECT + +;----------------------------------------------------- +; +; TEST IF DST IS TO THEPORT, (IF SO WE CLIP) +; +SRCOK MOVE.L DSTBITS(A6),A1 ;POINT TO DSTBITS + MOVE.L A3,D0 ;IS THEPORT NIL ? + BEQ.S NOTPORT ;YES, NOT TO THEPORT + BTST #0,D0 ;IS THEPORT ODD ? + BNE.S NOTPORT ;YES, NOT TO THEPORT + MOVE.L PORTBITS+BASEADDR(A3),D0 ;GET PORTBITS.BASEADDR + CMP.L BASEADDR(A1),D0 ;IS DST BASEADDR SAME ? + BNE.S NOTPORT ;NO, NOT TO THEPORT + MOVE.L PORTBOUNDS(A3),D0 ;GET PORT BOUNDS TOPLEFT + CMP.L BOUNDS(A1),D0 ;IS BOUNDS TOPLEFT SAME ? + BEQ.S TOPORT ;YES, ITS PROBABLY TO THEPORT +; +; DST IS DEFINITELY NOT TO THEPORT, SO WE CAN'T USE THE CAPTURE PROC. +; StretchBits(srcBits,dstBits,srcRect,dstRect,mode,wideOpen,wideOpen,maskRgn); +; +NOTPORT MOVE.L A2,-(SP) ;PUSH SRCBITS + MOVE.L A1,-(SP) ;PUSH DSTBITS + MOVE.L SRCRECT(A6),-(SP) ;PUSH SRCRECT + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + MOVE MODE(A6),-(SP) ;PUSH MODE + MOVE.L WIDEOPEN(A4),-(SP) ;PUSH WIDEOPEN + MOVE.L (SP),-(SP) ;PUSH WIDEOPEN + MOVE.L MASKRGN(A6),-(SP) ;PUSH MASKRGN + BNE.S MASKOK ;WAS IT NIL ? + MOVE.L WIDEOPEN(A4),(SP) ;YES, REPLACE WITH WIDEOPEN +MASKOK JSR STRETCHBITS ;CALL STRETCHBITS + BRA.S CLEANUP ;AND CONTINUE + +; +; DST IS PROBABLY TO THEPORT, SO WE USE THE CAPTURE PROC. +; CallBits(srcBits,srcRect,dstRect,mode,maskRgn) +; +TOPORT MOVE.L A2,-(SP) ;PUSH SRCBITS + MOVE.L SRCRECT(A6),-(SP) ;PUSH SRCRECT + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + MOVE MODE(A6),-(SP) ;PUSH MODE + MOVE.L MASKRGN(A6),-(SP) ;PUSH MASKRGN (NIL OK) + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + LEA STDBITS,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L BITSPROC(A0),A0 ;NO, GET PROC PTR +USESTD JSR (A0) ;CALL IT + +CLEANUP CMP.L D6,D7 ;WAS SRC FROM THE SCREEN ? + BNE.S DONE ;NO, CONTINUE + JSR SHOWCURSOR ;YES, REPLACE CURSOR +DONE MOVEM.L (SP)+,D6-D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'COPYBITS' + + + + + .PROC CopyMask + .REF RSect,HideCursor,ShowCursor,InitRgn,SeekRgn,XorSlab +;-------------------------------------------------------------- +; +; PROCEDURE CopyMask(srcBits,maskBits,dstBits: BitMap; +; srcRect,maskRect,dstRect: Rect); +; +; NEW ROUTINE ADDED TO QUICKDRAW April 28, 1985 +; +; Written by Bill Atkinson. CopyRight 1985 Apple Computer Inc. +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +paramSize .EQU 24 ;total bytes of params +srcBits .EQU paramSize+8-4 ;long, addr of BitMap +maskBits .EQU srcBits-4 ;long, addr of BitMap +dstBits .EQU maskBits-4 ;long, addr of BitMap +srcRect .EQU dstBits-4 ;long, addr of Rect +maskRect .EQU srcRect-4 ;long, addr of Rect +dstRect .EQU maskRect-4 ;long, addr of Rect + + +;------------------------------------------------- +; +; A6 OFFSETS OF LOCALS AFTER LINK: +; +MINRECT .EQU -8 ;RECT +RGNA .EQU MINRECT-4 ;RgnHandle +RGNB .EQU RGNA-4 ;RgnHandle +STATEA .EQU RGNB-RGNREC ;REGION STATE RECORD +STATEB .EQU STATEA-RGNREC ;REGION STATE RECORD +BUFLEFT .EQU STATEB-2 ;WORD +SRCADDR .EQU BUFLEFT-4 ;LONG +MASKADDR .EQU SRCADDR-4 ;LONG +DSTADDR .EQU MASKADDR-4 ;LONG +SRCROW .EQU DSTADDR-4 ;LONG +MASKROW .EQU SRCROW-4 ;LONG +DSTROW .EQU MASKROW-4 ;LONG +SAVESTK .EQU DSTROW-4 ;LONG +VARSIZE .EQU SAVESTK ;SIZE OF LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D0-D7/A1-A4,-(SP) ;SAVE REGS + MOVE.L SP,SAVESTK(A6) ;REMEMBER STACK FOR LATER + MOVE.L GRAFGLOBALS(A5),A2 ;point to QuickDraw globals + MOVE.L WIDEOPEN(A2),RGNA(A6) ;init RGNA to wideOpen + MOVE.L WIDEOPEN(A2),RGNB(A6) ;init RGNB to wideOpen + MOVE.L THEPORT(A2),A2 ;point to thePort + MOVE.L DSTBITS(A6),A4 ;A4 POINTS TO DSTBITS + MOVE.L DSTRECT(A6),A3 ;A3 POINTS TO DSTRECT +; +; if dst is in thePort, then clip to visRgn and clipRgn +; + MOVE.L portBits+baseAddr(A2),D0 ;get thePort^.portBits + CMP.L baseAddr(A4),D0 ;is dst on screen ? + BNE.S NOTPORT ;no, continue + MOVE.L CLIPRGN(A2),RGNA(A6) ;yes, clip to clipRgn + MOVE.L VISRGN(A2),RGNB(A6) ;and to visRgn +NOTPORT +; +; CALC MINRECT, THE INTERSECTION OF DSTRECT, DSTBITS.BOUNDS, +; AND TWO REGION BOUNDING BOXES. QUIT IF RESULT IS EMPTY. +; + MOVE.L A3,-(SP) ;PUSH DSTRECT + PEA BOUNDS(A4) ;PUSH DSTBITS.BOUNDS + MOVE.L RGNA(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + PEA RGNBBOX(A0) ;PUSH BOUNDING BOX + MOVE.L RGNB(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + PEA RGNBBOX(A0) ;PUSH BOUNDING BOX + MOVE #4,-(SP) ;PUSH NRECTS = 4 +DOSECT PEA MINRECT(A6) ;PUSH WHERE TO PUT RESULT + JSR RSECT ;INTERSECT 4 RECTS + BEQ GOHOME ;QUIT IF EMPTY + JSR HideCursor ;ELSE HIDE THE CURSOR + +; +; CALC BUFLEFT SO THAT RGNBUF WILL ALIGN TO DSTBITS +; + MOVE MINRECT+LEFT(A6),D1 ;GET MINRECT LEFT + SUB BOUNDS+LEFT(A4),D1 ;CONVERT TO GLOBAL COORDS + AND #$FFF0,D1 ;TRUNC TO MULT OF 16 + ADD BOUNDS+LEFT(A4),D1 ;CONVERT BACK TO LOCAL + MOVE D1,BUFLEFT(A6) ;SAVE AS BUFLEFT + +; +; INIT BOTH REGION STATE RECORDS AND ALLOCATE BUFFERS +; + MOVE.L RGNA(A6),A0 ;GET RGNHANDLE + LEA STATEA(A6),A1 ;POINT TO STATE RECORD +AGAIN MOVE.L (A0),A0 ;DE-REFERENCE RGNHANDLE + CMP #10,RGNSIZE(A0) ;IS IT RECTANGULAR ? + SEQ D7 ;REMEMBER FOR BELOW + MOVE MINRECT+LEFT(A6),D0 ;GET MINH + MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH + MOVE BUFLEFT(A6),D2 ;GET BUFLEFT + JSR INITRGN ;INIT STATE, ALLOC BUFFER +; +; IF REGION WAS RECTANGULAR, DRAW TOP SCANLINE INTO ITS BUFFER +; AND SET UP THISV AND NEXTV SO SEEKRGN DOES NOTHING +; + TST.B D7 ;was region rectangular ? + BEQ.S NOTRECT ;no, continue + MOVE #-32767,THISV(A1) ;yes, say we're at infinity + MOVE #32767,NEXTV(A1) ;and next change is never + MOVE.L SCANBUF(A1),A0 ;point to buffer + MOVE MINRECT+LEFT(A6),D3 ;get minrect.left + SUB BUFLEFT(A6),D3 ;make buffer relative + MOVE MINRECT+RIGHT(A6),D4 ;get minrect.right + SUB BUFLEFT(A6),D4 ;make buffer relative + JSR XorSlab ;draw into buffer +NOTRECT LEA STATEB(A6),A0 ;point to state record B + CMP.L A0,A1 ;did we just do RGNB ? + BEQ.S GETDST ;yes, continue + MOVE.L A0,A1 ;no, point to STATEB + MOVE.L RGNB(A6),A0 ;get RGNB handle + BRA AGAIN ;and loop to init STATEB +; +; Set up dstRow and starting dstAddr +; +GETDST MOVE ROWBYTES(A4),D1 ;get dst rowBytes + EXT.L D1 ;make it long + MOVE.L D1,DSTROW(A6) ;save dstRow for later + MOVE MINRECT+TOP(A6),D0 ;get dst top + SUB BOUNDS+TOP(A4),D0 ;convert to global + MULU D1,D0 ;mult by rowbytes + MOVE.L BASEADDR(A4),A0 ;get dst baseAddr + ADD.L D0,A0 ;add vertical offset + MOVE MINRECT+LEFT(A6),D0 ;get dst left + SUB BOUNDS+LEFT(A4),D0 ;convert to global + LSR #4,D0 ;convert dots to words + ADD D0,D0 ;double for bytes + ADD D0,A0 ;add horizontal offset + MOVE.L A0,DSTADDR(A6) ;save result in dstAddr + +; +; Set up srcRow, srcShift, and starting srcAddr +; + MOVE.L SRCRECT(A6),A1 ;point to srcRect + MOVE.L SRCBITS(A6),A2 ;point to srcBits + MOVE ROWBYTES(A2),D1 ;get src rowBytes + EXT.L D1 ;make it long + MOVE.L D1,SRCROW(A6) ;save srcRow for later + + MOVE LEFT(A3),D6 ;get dst left + SUB BOUNDS+LEFT(A4),D6 ;convert to global + MOVE LEFT(A1),D1 ;get src left + SUB BOUNDS+LEFT(A2),D1 ;convert to global + SUB D1,D6 ;calc delta horiz + AND #$F,D6 ;mod 16 for srcShift + + MOVE MINRECT+TOP(A6),D0 ;get clipped dst top + SUB TOP(A3),D0 ;convert from dst coords + ADD TOP(A1),D0 ;to src coords + SUB BOUNDS+TOP(A2),D0 ;convert to global + MULU ROWBYTES(A2),D0 ;mult by src rowbytes + MOVE.L BASEADDR(A2),A0 ;get src baseAddr + ADD.L D0,A0 ;add vertical offset + + MOVE MINRECT+LEFT(A6),D0 ;get clipped dstLeft + SUB LEFT(A3),D0 ;convert from dst coords + ADD LEFT(A1),D0 ;to src coords + SUB BOUNDS+LEFT(A2),D0 ;convert to global + ADD D6,D0 ;add srcShift + LSR #4,D0 ;convert dots to words + ADD D0,D0 ;double for bytes + ADD D0,A0 ;add horiz offset + MOVE.L A0,SRCADDR(A6) ;save srcAddr for later + +; +; Set up maskRow, maskShift, and starting maskAddr +; + MOVE.L MASKRECT(A6),A1 ;point to maskRect + MOVE.L MASKBITS(A6),A2 ;point to maskBits + MOVE ROWBYTES(A2),D1 ;get mask rowBytes + EXT.L D1 ;make it long + MOVE.L D1,MASKROW(A6) ;save maskRow for later + + MOVE LEFT(A3),D7 ;get dst left + SUB BOUNDS+LEFT(A4),D7 ;convert to global + MOVE LEFT(A1),D1 ;get mask left + SUB BOUNDS+LEFT(A2),D1 ;convert to global + SUB D1,D7 ;calc delta horiz + AND #$F,D7 ;mod 16 for maskShift + + MOVE MINRECT+TOP(A6),D0 ;get clipped dst top + SUB TOP(A3),D0 ;convert from dst coords + ADD TOP(A1),D0 ;to mask coords + SUB BOUNDS+TOP(A2),D0 ;convert to global + MULU ROWBYTES(A2),D0 ;mult by mask rowbytes + MOVE.L BASEADDR(A2),A0 ;get mask baseAddr + ADD.L D0,A0 ;add vertical offset + + MOVE MINRECT+LEFT(A6),D0 ;get clipped dstLeft + SUB LEFT(A3),D0 ;convert from dst coords + ADD LEFT(A1),D0 ;to mask coords + SUB BOUNDS+LEFT(A2),D0 ;convert to global + ADD D7,D0 ;add maskShift + LSR #4,D0 ;convert dots to words + ADD D0,D0 ;double for bytes + ADD D0,A0 ;add horiz offset + MOVE.L A0,MASKADDR(A6) ;save maskAddr for later + +; +; MAKE REGION BUFFERS CURRENT FOR THIS VERTICAL. +; THEN SET UP AND DRAW CURRENT SCANLINE. +; + MOVE MINRECT+TOP(A6),D5 ;init CURRENT VERTICAL +NEXTROW MOVE D5,D0 ;get current vert + LEA STATEA(A6),A1 ;point to state record A + JSR SEEKRGN ;seek region to current vert + MOVE D5,D0 ;get current vert + LEA STATEB(A6),A1 ;point to state record B + JSR SEEKRGN ;seek region to current vert + MOVE.L STATEA+SCANBUF(A6),A0 ;init REGION A PTR + MOVE.L STATEB+SCANBUF(A6),A1 ;init REGION B PTR + MOVE.L SRCADDR(A6),A2 ;init SRCPTR + MOVE.L MASKADDR(A6),A3 ;init MASKPTR + MOVE.L DSTADDR(A6),A4 ;init DSTPTR + MOVE STATEA+SCANSIZE(A6),D3 ;init LONGCOUNT + +NEXTLONG MOVE.L -2(A2),D0 ;get a long of src + LSR.L D6,D0 ;align to dst + SWAP D0 ;put result in hi word + MOVE.L (A2)+,D1 ;get second long of src + LSR.L D6,D1 ;align to dst + MOVE.W D1,D0 ;assemble one long of src + MOVE.L -2(A3),D1 ;get a long of mask + LSR.L D7,D1 ;align to dst + SWAP D1 ;put result in hi word + MOVE.L (A3)+,D2 ;get second long of mask + LSR.L D7,D2 ;align to dst + MOVE.W D2,D1 ;assemble one long of mask + AND.L (A0)+,D1 ;and with RGNA buffer + AND.L (A1)+,D1 ;and with RGNB buffer + AND.L D1,D0 ;mask src data + NOT.L D1 ;form notmask + AND.L (A4),D1 ;get dst data + OR.L D1,D0 ;merge with src data + MOVE.L D0,(A4)+ ;store result into dst + DBRA D3,NEXTLONG ;loop all longs this scanline +; +; bump vertically and loop for all scanlines +; + MOVE.L SRCROW(A6),D0 ;GET SRC ROWBYTES + ADD.L D0,SRCADDR(A6) ;BUMP SRC TO NEXT ROW + MOVE.L MASKROW(A6),D0 ;GET MASK ROWBYTES + ADD.L D0,MASKADDR(A6) ;BUMP MASK TO NEXT ROW + MOVE.L DSTROW(A6),D0 ;GET DST ROWBYTES + ADD.L D0,DSTADDR(A6) ;BUMP DST TO NEXT ROW + ADD #1,D5 ;ADD ONE TO VERT + CMP MINRECT+BOTTOM(A6),D5 ;ARE WE AT THE BOTTOM ? + BNE NEXTROW ;NO, LOOP FOR ALL SCAN LINES + + JSR SHOWCURSOR ;RESTORE CURSOR +GOHOME MOVE.L SAVESTK(A6),SP ;STRIP VARIABLE SIZED BUFFER + MOVEM.L (SP)+,D0-D7/A1-A4 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'CopyMask' + + + + + .PROC SeedFill + .DEF CalcMask +;------------------------------------------------------------------------- +; +; PROCEDURE SeedFill(srcPtr,dstPtr: Ptr; +; srcRow,dstRow,height,words: INTEGER; +; seedH,seedV: INTEGER) +; + MOVE.L (SP)+,A0 ;pop return addr + MOVEQ #-1,D0 ;get a long of -1 + MOVE.L D0,-(SP) ;push edge = all ones + BRA.S SHARE ;share common code + + +;------------------------------------------------------------------------- +; +; PROCEDURE CalcMask(srcPtr,dstPtr: Ptr; +; srcRow,dstRow,height,words: INTEGER); +; +CalcMask MOVE.L (SP)+,A0 ;pop return addr + MOVEQ #-1,D0 ;get a long of -1 + MOVE.L D0,-(SP) ;push seed = (-1,-1) + CLR.L -(SP) ;push edge = zeros +SHARE MOVE.L A0,-(SP) ;restore return addr + + + +;------------------------------------------------------------------------- +; +; LOCAL PROCEDURE MakeMask(srcPtr,dstPtr: Ptr; +; srcRow,dstRow,height,words: INTEGER; +; seedH,seedV: INTEGER; +; edge: LongInt); +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +params .EQU 24 +srcPtr .EQU params+8-4 ;long +dstPtr .EQU srcPtr-4 ;long +srcRow .EQU dstPtr-2 ;word +dstRow .EQU srcRow-2 ;word +height .EQU dstRow-2 ;word +words .EQU height-2 ;word +seedH .EQU words-2 ;word +seedV .EQU seedH-2 ;word +edge .EQU seedV-4 ;long + + +dstBump .EQU -2 ;word +saveStk .EQU dstBump-4 ;long +varSize .EQU saveStk ;total locals + + + LINK A6,#varSize ;allocate stack frame + MOVEM.L D3-D7/A2-A4,-(SP) ;save regs + MOVE.L SP,saveStk(A6) ;save stack pointer + +; +; prepare height and words for DBRA count. Quit if either <= 0. +; + MOVE words(A6),D5 ;get count of words + BLE GOHOME ;quit if words <= 0 + SUB #1,D5 ;subtract 1 for DBRA count + SUB #1,height(A6) ;convert height to DBRA + BLT GOHOME ;quit if height <= 0 + +; +; init dst to all ones: +; + MOVE words(A6),D0 ;get # of words + ADD D0,D0 ;double for bytes + MOVE dstRow(A6),D1 ;get dstRow + SUB D0,D1 ;subtract bytes for dstBump + MOVE D1,dstBump(A6) ;save dstBump for later + MOVE.L dstPtr(A6),A2 ;point to dst + MOVEQ #-1,D0 ;get some black + MOVE height(A6),D3 ;init DBRA rowCount +BLACK1 MOVE D5,D2 ;init DBRA wordCount +BLACK2 MOVE D0,(A2)+ ;put a word of black + DBRA D2,BLACK2 ;loop all words in row + ADD D1,A2 ;bump to next row + DBRA D3,BLACK1 ;loop height rows + +; +; clear one dst pixel at seedH,seedV +; + MOVE seedV(A6),D0 ;get seed vert coord + BLT.S NOSEED ;skip if neg (no seed) + MULU dstRow(A6),D0 ;mul times dst row + MOVE.L dstPtr(A6),A0 ;point to dst + ADD D0,A0 ;add vertical offset + MOVE seedH(A6),D0 ;get seed horiz coord + MOVE D0,D1 ;copy seedH + LSR #3,D0 ;div by 8 for byte + NOT D1 ;invert bit number + BCLR D1,0(A0,D0) ;clear seed pixel +NOSEED +; +; allocate a scanline buffer of ones or zeros on the stack: +; + MOVE.L edge(A6),D6 ;get zero or all ones + MOVE D5,D1 ;get longCount +NEXTBUF MOVE D6,-(SP) ;write a word of ones or zeros + DBRA D1,NEXTBUF ;loop all words + + MOVE.L srcPtr(A6),A0 ;point to top of src + MOVE.L dstPtr(A6),A2 ;point to top of dst +NXTPASS SF D7 ;clear dirty flag + MOVE height(A6),D4 ;get DBRA rowCount + MOVE.L SP,A1 ;point dst above to edgeBuf + +; +; smear dst zeros down and to the right, smear limited by src. +; +NEXTROW MOVE.L D6,D1 ;init prev dst to edge + MOVE D5,D3 ;get DBRA wordCount +RNEXT MOVE (A2),D1 ;get dst word + BNE.S RDSTOK ;is it already zero ? + ADD #2,A0 ;yes, bump srcPtr + ADD #2,A1 ;bump dstAbove ptr + ADD #2,A2 ;bump dst ptr + SWAP D1 ;put prev dst in hi word + DBRA D3,RNEXT ;loop all words in row + BRA RDONE ;and continue below +RDSTOK MOVE (A0)+,D2 ;get src word + AND (A1)+,D1 ;smear zeros down + OR D2,D1 ;limit vertical smear by src + BRA.S RSTART ;go to loop start +RMORE MOVE D0,D1 ;update dst +RSTART MOVE.L D1,D0 ;copy dst and prev dst word + LSR.L #1,D0 ;shift right with carry from prev + AND D1,D0 ;smear zeros to the right + OR D2,D0 ;limit smear by src + CMP D1,D0 ;any changes ? + BNE RMORE ;yes, keep smearing + CMP (A2),D1 ;has dst changed ? + BEQ.S RSAME ;no, leave it alone + ST D7 ;yes, set dirty flag +RSAME MOVE D1,(A2)+ ;write dst to memory + SWAP D1 ;put prev dst in hi word + DBRA D3,RNEXT ;loop all words in row +RDONE + + +; +; smear dst zeros down and to the left, smear limited by src. +; +LSMEAR MOVE.L D6,D1 ;init prev dst to edge + MOVE D5,D3 ;get DBRA wordCount +LNEXT MOVE -(A2),D1 ;get dst word + BNE.S LDSTOK ;is dst already zero ? + SUB #2,A0 ;yes, just bump srcPtr + SUB #2,A1 ;bump dstAbove ptr + SWAP D1 ;put prev dst in hi word + DBRA D3,LNEXT ;loop all words in row + BRA.S LDONE ;and continue +LDSTOK MOVE -(A0),D2 ;get src word + AND -(A1),D1 ;smear zeros down + OR D2,D1 ;limit vertical smear by src + BRA.S LSTART ;go to loop start +LMORE MOVE D0,D1 ;update dst +LSTART MOVE.L D1,D0 ;copy dst and prev dst word + ROL.L #1,D0 ;shift left with carry from prev + AND D1,D0 ;smear zeros to the left + OR D2,D0 ;limit smear by src + CMP D1,D0 ;any changes ? + BNE LMORE ;yes, keep smearing + CMP (A2),D1 ;has dst changed ? + BEQ.S LSAME ;no, leave it alone + ST D7 ;yes, set dirty flag + MOVE D1,(A2) ;write dst to memory +LSAME SWAP D1 ;put prev dst in hi word + DBRA D3,LNEXT ;loop all words in row +LDONE +; +; bump three pointers down and loop for height scanlines +; + ADD srcRow(A6),A0 ;bump srcPtr down a row + ADD dstRow(A6),A2 ;bump dstPtr down a row + MOVE.L A2,A1 ;copy dstPtr + SUB dstRow(A6),A1 ;point to dst above + DBRA D4,NEXTROW ;loop all rows +; +; switch directions, adjust pointers, and loop till no change +; + NEG srcRow(A6) ;reverse src bump + NEG dstRow(A6) ;reverse dst bump + ADD srcRow(A6),A0 ;offset first src scanline + ADD dstRow(A6),A2 ;offset first dst scanline + TST.B D7 ;did anything change this pass ? + BNE NXTPASS ;yes go for another pass +; +; if seedFill, then invert dst +; + TST D6 ;is edge = black ? + BPL.S GOHOME ;no, we're done + MOVE dstBump(A6),D1 ;get dstBump + MOVE.L dstPtr(A6),A2 ;point to dst + MOVE height(A6),D3 ;init DBRA rowCount +INVERT1 MOVE D5,D2 ;init DBRA wordCount +INVERT2 NOT (A2)+ ;invert a word of dst + DBRA D2,INVERT2 ;loop all words in row + ADD D1,A2 ;bump to next row + DBRA D3,INVERT1 ;loop height rows + +GOHOME MOVE.L saveStk(A6),SP ;restore stack pointer + MOVEM.L (SP)+,D3-D7/A2-A4 ;restore regs + UNLK A6 ;release stack frame + MOVE.L (SP)+,A0 ;pop return addr + ADD #params,SP ;strip params + JMP (A0) ;and return + + + + + .PROC ScrollRect,4 + .REF NewRgn,RectRgn,SectRgn,CopyRgn,OffsetRgn,SetEmptyRgn + .REF DiffRgn,ShieldCursor,RgnBlt,ShowCursor +;--------------------------------------------------------------------- +; +; PROCEDURE ScrollRect(dstRect: Rect; dh,dv: INTEGER; updateRgn: RgnHandle); +; +; Scroll a rectangular block of bits, erase and return an update region +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 12 ;TOTAL BYTES OF PARAMS +DSTRECT .EQU PARAMSIZE+8-4 ;LONG, ADDR OF RECT +DH .EQU DSTRECT-2 ;WORD +DV .EQU DH-2 ;WORD +UPDATERGN .EQU DV-4 ;LONG, RGNHANDLE + +SRCRECT .EQU -8 ;RECT +VARSIZE .EQU SRCRECT ;TOTAL LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D6-D7/A3-A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;POINT TO CURRENT GRAFPORT + TST PNVIS(A3) ;IS PNVIS < 0 ? + BLT ABORT ;YES, QUIT FAST + TST.L DV(A6) ;ARE DH AND DV BOTH 0 ? + BEQ ABORT ;YES, QUIT FAST + + CLR.L -(SP) ;ROOM FOR FCN RESULT + JSR NEWRGN ;ALLOCATE SRCRGN + MOVE.L (SP)+,D7 ;GET SRCRGN HANDLE IN D7 + CLR.L -(SP) ;ROOM FOR FCN RESULT + JSR NEWRGN ;ALLOCATE DSTRGN + MOVE.L (SP)+,D6 ;GET DSTRGN HANDLE IN D6 +; +; srcRgn := dstRect SECT visRgn SECT clipRgn +; + MOVE.L D7,-(SP) ;PUSH SRCRGN + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + JSR RECTRGN ;RectRgn(srcRgn,dstRect); + + MOVE.L D7,-(SP) ;PUSH SRCRGN + MOVE.L VISRGN(A3),-(SP) ;PUSH VISRGN + MOVE.L D7,-(SP) ;PUSH SRCRGN + JSR SECTRGN ;SectRgn(srcRgn,visRgn,srcRgn); + + MOVE.L D7,-(SP) ;PUSH SRCRGN + MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN + MOVE.L D7,-(SP) ;PUSH SRCRGN + JSR SECTRGN ;SectRgn(srcRgn,clipRgn,srcRgn); +; +; dstRgn := offset srcRgn +; + MOVE.L D7,-(SP) ;PUSH SRCRGN + MOVE.L D6,-(SP) ;PUSH DSTRGN + JSR COPYRGN ;CopyRgn(srcRgn,dstRgn); + MOVE.L D6,-(SP) ;PUSH DSTRGN + MOVE.L DV(A6),-(SP) ;PUSH DH,DV + JSR OFFSETRGN ;OffsetRgn(dstRgn,dh,dv); + + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + MOVE.L (A0)+,SRCRECT(A6) ;COPY DSTRECT INTO SRCRECT + MOVE.L (A0)+,SRCRECT+4(A6) + MOVE.L DV(A6),D0 ;GET DH,DV + SUB D0,SRCRECT+LEFT(A6) ;OFFSET SRCRECT (-DH,-DV) + SUB D0,SRCRECT+RIGHT(A6) + SWAP D0 ;GET DV IN LO WORD + SUB D0,SRCRECT+TOP(A6) + SUB D0,SRCRECT+BOTTOM(A6) + +; +; Compute updateRgn := srcRgn - dstRgn +; + MOVE.L D7,-(SP) ;PUSH SRCRGN + MOVE.L D6,-(SP) ;PUSH DSTRGN + MOVE.L UPDATERGN(A6),-(SP) ;PUSH UPDATERGN + JSR DIFFRGN ;DiffRgn(srcRgn,dstRgn,updateRgn); +; +; ShieldCursor(dstRect,portBits.bounds.topLeft); { protect source } +; + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + MOVE.L PORTBITS+BOUNDS+TOPLEFT(A3),-(SP) ;PUSH OFFSET POINT + JSR SHIELDCURSOR ;REMOVE CRSR IF INTERSECTS +; +; Copy all bits which are in both srcRgn and dstRgn. +; RgnBlt(portBits,portBits,srcRect,dstRect,0,white,dstRgn,srcRgn,wideOpen); +; + PEA PORTBITS(A3) ;PUSH SRCBITS + MOVE.L (SP),-(SP) ;PUSH DSTBITS + PEA SRCRECT(A6) ;PUSH SRCRECT + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + CLR -(SP) ;PUSH MODE = SRCCOPY + CLR.L -(SP) ;PAT NOT USED + MOVE.L D6,-(SP) ;PUSH DSTRGN + MOVE.L D7,-(SP) ;PUSH SRCRGN + MOVE.L WIDEOPEN(A4),-(SP) ;PUSH WIDEOPEN + JSR RGNBLT ;COPY THE BITS +; +; Erase the update region +; RgnBlt(portBits,portBits,dstRect,dstRect,8,bkPat,updateRgn,wideOpen,wideOpen); +; + PEA PORTBITS(A3) ;PUSH SRCBITS + MOVE.L (SP),-(SP) ;PUSH DSTBITS + MOVE.L DSTRECT(A6),-(SP) ;PUSH SRCRECT + MOVE.L (SP),-(SP) ;PUSH DSTRECT + MOVE #8,-(SP) ;PUSH MODE = PATCOPY + PEA BKPAT(A3) ;PUSH PAT = BKPAT + MOVE.L UPDATERGN(A6),-(SP) ;PUSH UPDATERGN + MOVE.L WIDEOPEN(A4),-(SP) ;PUSH WIDEOPEN + MOVE.L (SP),-(SP) ;PUSH WIDEOPEN + JSR RGNBLT ;ERASE THE UPDATE RGN + + JSR SHOWCURSOR ;RESTORE THE CURSOR + MOVE.L D7,A0 ;GET SRCRGN + _DisposHandle ;DISCARD IT + MOVE.L D6,A0 ;PUSH DSTRGN + _DisposHandle ;DISCARD IT + BRA.S DONE + +ABORT MOVE.L UPDATERGN(A6),-(SP) ;PUSH UPDATERGN HANDLE + JSR SETEMPTYRGN ;SET IT TO EMPTY + +DONE MOVEM.L (SP)+,D6-D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'SCROLLRE' + + + + + .PROC PackBits + .DEF UnpackBits +;--------------------------------------------------------------------- +; +; PROCEDURE PackBits(VAR srcPtr,dstPtr: Ptr; srcBytes: INTEGER); +; +; Packs one scanline of data, compressing equal bytes. +; Returns updated srcPtr and dstPtr. +; +; Equates for parameters are shared with UnpackBits +; +PARAMSIZE .EQU 10 ;TOTAL BYTES OF PARAMS +SRCPTR .EQU PARAMSIZE+4-4 ;LONG, VAR +DSTPTR .EQU SRCPTR-4 ;LONG,VAR +SRCBYTES .EQU DSTPTR-2 ;WORD +DSTBYTES .EQU SRCBYTES ;ALIAS + + MOVE.L A2,-(SP) ;SAVE REGS + MOVE.L SRCPTR+4(SP),A0 ;GET VAR ADDR + MOVE.L (A0),A0 ;GET SRCPTR ITSELF + MOVE.L DSTPTR+4(SP),A1 ;GET VAR ADDR + MOVE.L (A1),A1 ;GET DSTPTR ITSELF + MOVE SRCBYTES+4(SP),D1 ;GET SRCBYTES + SUB #1,D1 ;INIT SRC DBRA COUNT + BLT.S DONE ;QUIT IF SRCBYTES <= 0 + MOVE.B (A0)+,D0 ;GET FIRST BYTE OF SRC + BRA.S START ;AND GO TO LOOP START + +FILLOP MOVE.B -1(A0),D0 ;PUT SRCDATA IN DO + SUB A0,D2 ;COMPUTE FILLOP + ADD #1,D2 + MOVE.B D2,(A2) ;STORE FILLOP + +START MOVE A0,D2 ;REMEMBER SRCSTART + MOVE.L A1,A2 ;REMEMBER OPLOC + CLR.B (A1)+ ;RESERVE ROOM FOR OPCODE + CMP.B (A0),D0 ;IS NEXT SRC THE SAME ? + BNE.S DOCOPY ;NO, USE COPY LOOP + CMP.B 1(A0),D0 ;THREE IN A ROW ? + BNE.S DOCOPY ;NO, USE COPY LOOP + BRA.S DOFILL ;YES, USE FILL LOOP + +NXTCOPY MOVE.B (A0)+,D0 ;GET BYTE OF SRC + CMP.B (A0),D0 ;IS THE NEXT THE SAME ? + BNE.S DOCOPY ;NO, CONTINUE + CMP.B 1(A0),D0 ;THREE IN A ROW ? + BEQ.S COPYOP ;YES, END OF COPY RUN +DOCOPY MOVE.B D0,(A1)+ ;COPY DATA TO DST + DBRA D1,NXTCOPY ;AND LOOP FOR MORE + +ENDCOPY SUB A0,D2 ;COMPUTE COPYOP + NEG D2 ;NEGATE ONLY + MOVE.B D2,(A2) ;INSTALL COPYOP + BRA.S DONE ;AND QUIT + +COPYOP TST D1 ;IS THIS THE LAST SRC BYTE ? + BEQ DOCOPY ;YES, FINISH OFF COPY RUN + SUB A0,D2 ;COMPUTE COPYOP + NOT D2 ;NEGATE AND SUBTRACT 1 + MOVE.B D2,(A2) ;STORE COPYOP + MOVE.L A0,D2 ;REMEMBER SRCSTART + MOVE.L A1,A2 ;REMEMBER OPLOC + CLR.B (A1)+ ;RESERVE ROOM FOR OPCODE + +DOFILL MOVE.B D0,(A1)+ ;COPY THE DATA BYTE +NXTFILL CMP.B (A0)+,D0 ;IS NEXT BYTE THE SAME ? + DBNE D1,NXTFILL ;LOOP TILL NOT SAME OR END SRC + BEQ.S ENDFILL ;BRANCH IF SRC EXHAUSTED + SUB #1,D1 ;COMPENSATE FOR DBNE DIDNT SUB + BGE FILLOP ;BR IF SRC NOT EXHAUSTED + +ENDFILL SUB A0,D2 ;COMPUTE FILLOP + ADD #1,D2 + MOVE.B D2,(A2) ;INSTALL FILLOP + +DONE CLR.L D0 ;GET READY FOR WORD + MOVE SRCBYTES+4(SP),D0 ;GET SRCBYTES + MOVE.L SRCPTR+4(SP),A0 ;GET VAR ADDR OF SRCPTR + ADD.L D0,(A0) ;BUMP SRCPTR + MOVE.L DSTPTR+4(SP),A2 ;GET VAR ADDR OF DSTPTR + MOVE.L A1,(A2) ;UPDATE DSTPTR + MOVE.L (SP)+,A2 ;RESTORE REGS +SHARE MOVE.L (SP)+,A0 ;POP RETURN ADDR + ADD #PARAMSIZE,SP ;STRIP PARAMS + JMP (A0) ;AND RETURN + + +;-------------------------------------------------------- +; +; PROCEDURE UnpackBits(VAR srcPtr,dstPtr: Ptr; dstBytes: INTEGER); +; +; Unpacks one scanline of data, as compressed by PackBits. +; Returns updated srcPtr and dstPtr. +; +; Equates for parameters are the same as PackBits! +; +UnpackBits + MOVE.L SRCPTR(SP),A0 ;GET ADDR OF SRCPTR + MOVE.L (A0),A0 ;GET SRCPTR ITSELF + MOVE.L DSTPTR(SP),A1 ;GET ADDR OF DSTPTR + MOVE.L (A1),A1 ;GET DSTPTR ITSELF + MOVE DSTBYTES(SP),D2 ;GET DSTBYTES + EXT.L D2 ;MAKE IT LONG + ADD.L A1,D2 ;LIMIT := DSTPTR + BYTECOUNT + BRA.S @3 ;GO TO LOOP START +@1 EXT.W D1 ;CLEAR HI BYTE OF COUNT +@2 MOVE.B (A0)+,(A1)+ ;COPY A BYTE OF DATA + DBRA D1,@2 ;LOOP ALL COPY BYTES +@3 CMP.L D2,A1 ;IS DSTPTR >= LIMIT ? + BHS.S @5 ;YES, WE'RE DONE + MOVE.B (A0)+,D1 ;NO, GET OPCODE + BPL.S @1 ;0..127 --> COPY 1..128 BYTES + NEG.B D1 ;-1..-127 --> FILL 2..128 BYTES + BVS.S @3 ;IGNORE $80 FOR BACKWARD COMPAT + EXT.W D1 ;CLEAR HI BYTE OF COUNT + MOVE.B (A0)+,D0 ;GET FILL DATA BYTE +@4 MOVE.B D0,(A1)+ ;COPY IT TO DST + DBRA D1,@4 ;LOOP ALL FILL BYTES + BRA.S @3 ;THEN GET NEXT OPCODE +@5 MOVE.L A0,D0 ;STASH SRCPTR + MOVE.L SRCPTR(SP),A0 ;GET VAR ADDR + MOVE.L D0,(A0) ;UPDATE VAR SRCPTR + MOVE.L DSTPTR(SP),A0 ;GET VAR ADDR + MOVE.L A1,(A0) ;UPDATE VAR DSTPTR + BRA.S SHARE + + + + + .END diff --git a/COPYRIGHT.TXT b/COPYRIGHT.TXT new file mode 100755 index 0000000..087e4f8 --- /dev/null +++ b/COPYRIGHT.TXT @@ -0,0 +1,3 @@ + +Copyright +This Material is Copyright © 1984 Apple Inc. and is made available only for non-commercial use. \ No newline at end of file diff --git a/DrawArc.a b/DrawArc.a new file mode 100755 index 0000000..968d7da --- /dev/null +++ b/DrawArc.a @@ -0,0 +1,1086 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; --> DRAWARC.TEXT +; +; Routine to draw solid or hollow Ovals, RoundRects or Arcs. +; + + +;------------------------------------------------------ +; +; OFFSETS IN AN OVAL STATE RECORD: +; +OVALTOP .EQU 0 ;INTEGER +OVALBOT .EQU OVALTOP+2 ;INTEGER +OVALY .EQU OVALBOT+2 ;INTEGER +RSQYSQ .EQU OVALY+2 ;LONGINT +SQUARE .EQU RSQYSQ+4 ;64 BIT LONGFIX +ODDNUM .EQU SQUARE+8 ;64 BIT LONGFIX +ODDBUMP .EQU ODDNUM+8 ;64 BIT LONGFIX +LEFTEDGE .EQU ODDBUMP+8 ;32 BIT FIXED POINT +RIGHTEDGE .EQU LEFTEDGE+4 ;32 BIT FIXED POINT +ONEHALF .EQU RIGHTEDGE+4 ;32 BIT FIXED POINT +OVALSIZE .EQU ONEHALF+4 ;SIZE OF AN OVALREC + + + + .PROC DrawArc,8 + .REF InitOval,BumpOval,SlopeFromAngle + .REF RSect,ShieldCursor,ShowCursor,TrimRect + .REF InitRgn,SeekRgn,PatExpand,ColorMap + .REF XorSlab,DrawSlab,SlabMode,FastSlabMode,MaskTab +;---------------------------------------------------------------- +; +; PROCEDURE DrawArc(dstRect: Rect; +; hollow: BOOLEAN; +; ovalWidth,ovalHeight,mode: INTEGER; +; pat: Pattern; +; startAngle,arcAngle: INTEGER); +; + + +;------------------------------------------------ +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 20 ;TOTAL SIZE OF PARAMETERS +DSTRECT .EQU PARAMSIZE+8-4 ;ADDR OF RECT +HOLLOW .EQU DSTRECT-2 ;BOOLEAN +OVALWIDTH .EQU HOLLOW-2 ;INTEGER +OVALHEIGHT .EQU OVALWIDTH-2 ;INTEGER +MODE .EQU OVALHEIGHT-2 ;INTEGER +PAT .EQU MODE-4 ;LONG, ADDR OF PATTERN +STARTANGLE .EQU PAT-2 ;INTEGER +ARCANGLE .EQU STARTANGLE-2 ;INTEGER + + +;------------------------------------------------- +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +EXPAT .EQU -64 ;16 LONGS +MINRECT .EQU EXPAT-8 ;RECT +STATEA .EQU MINRECT-RGNREC ;RGN STATE RECORD +STATEB .EQU STATEA-RGNREC ;RGN STATE RECORD +STATEC .EQU STATEB-RGNREC ;RGN STATE RECORD +SAVESTK .EQU STATEC-4 ;LONG +RECTFLAG .EQU SAVESTK-2 ;WORD +MASKBUF .EQU RECTFLAG-4 ;LONG +BUFLEFT .EQU MASKBUF-2 ;WORD +BUFSIZE .EQU BUFLEFT-2 ;WORD +MODECASE .EQU BUFSIZE-4 ;LONG +DSTLEFT .EQU MODECASE-4 ;LONG +SAVEA5 .EQU DSTLEFT-4 ;LONG +PORT .EQU SAVEA5-4 ;LONG +FASTFLAG .EQU PORT-2 ;BYTE +TEMPRECT .EQU FASTFLAG-8 ;RECT +INNEROVAL .EQU TEMPRECT-OVALSIZE ;OVAL RECORD +OUTEROVAL .EQU INNEROVAL-OVALSIZE ;OVAL RECORD +SKIPTOP .EQU OUTEROVAL-2 ;WORD +SKIPBOT .EQU SKIPTOP-2 ;WORD +ARCFLAG .EQU SKIPBOT-1 ;BYTE FLAG +SKIPFLAG .EQU ARCFLAG-1 ;BYTE FLAG +STOPANGLE .EQU SKIPFLAG-2 ;INTEGER +MIDVERT .EQU STOPANGLE-2 ;INTEGER +MIDHORIZ .EQU MIDVERT-2 ;INTEGER +WIDTH .EQU MIDHORIZ-2 ;INTEGER +HEIGHT .EQU WIDTH-2 ;INTEGER +SLOPE1 .EQU HEIGHT-4 ;LONG, FIXED POINT +SLOPE2 .EQU SLOPE1-4 ;LONG, FIXED POINT +LINE1 .EQU SLOPE2-4 ;LONG, FIXED POINT +LINE2 .EQU LINE1-4 ;LONG, FIXED POINT +FLAG1 .EQU LINE2-2 ;WORD +FLAG2 .EQU FLAG1-2 ;WORD +OUTERLEFT .EQU FLAG2-2 ;WORD +OUTERRIGHT .EQU OUTERLEFT-2 ;WORD +INNERLEFT .EQU OUTERRIGHT-2 ;WORD +INNERRIGHT .EQU INNERLEFT-2 ;WORD +PATINDEX .EQU INNERRIGHT-2 ;WORD +VARSIZE .EQU PATINDEX ;SIZE OF LOCAL VARIABLES + + + LINK A6,#VARSIZE ;ALLOCATE LOCAL VARS + MOVEM.L D0-D7/A1-A5,-(SP) ;SAVE REGS + MOVE.L SP,SAVESTK(A6) ;REMEMBER STACK FOR LATER + MOVE.L A5,SAVEA5(A6) ;REMEMBER GLOBAL PTR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A3 ;GET CURRENT GRAFPORT + TST PNVIS(A3) ;IS PNVIS NEG ? + BLT GOHOME ;YES, QUIT + MOVE.L A3,PORT(A6) ;SAVE CURRENT GRAFPORT + + +;------------------------------------------------------- +; +; QUIT IF MODE NOT IN 8..15 +; + MOVEQ #-8,D0 ;MASK TO KILL BOTTOM 3 BITS + AND MODE(A6),D0 ;GET ALL BUT 3 BITS OF MODE + CMP #8,D0 ;IS PEN MODE 8..15 ? + BNE GOHOME ;NO, QUIT + + +;---------------------------------------------------------------- +; +; ADJUST MODE AND PATTERN IF COLOR FILTERING. +; + TST COLRBIT(A3) ;IS COLORBIT = 0 ? + BEQ.S NOCOLOR ;YES, DON'T MAP + MOVE MODE(A6),-(SP) ;PUSH INPUT MODE + MOVE.L PAT(A6),-(SP) ;PUSH ADDR OF INPUT PATTERN + JSR COLORMAP ;ALTER BY THECOLOR, THEFILTER + MOVE.L (SP)+,PAT(A6) ;GET (ALTERED) PATTERN + MOVE (SP)+,MODE(A6) ;GET (ALTERED) MODE +NOCOLOR MOVE.L A3,A5 ;PUT GRAFPORT IN A5 + + +;--------------------------------------------------------- +; +; GET CLIPRGN AND VISRGN HANDLES AND DE-REFERENCE THEM +; + MOVE.L CLIPRGN(A5),A2 ;GET CLIPRGN HANDLE + MOVE.L (A2),A2 ;GET CLIPRGN POINTER + MOVE.L VISRGN(A5),A3 ;GET VISRGN HANDLE + MOVE.L (A3),A3 ;GET VISRGN POINTER + + +;----------------------------------------------------------------------- +; +; CALC MINRECT, THE INTERSECTION OF DSTRECT, BITMAP BOUNDS, +; CLIPRGN BBOX, AND VISRGN BBOX. QUIT IF NO INTERSECTION. +; + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + PEA PORTBITS+BOUNDS(A5) ;PUSH BITMAP BOUNDS + PEA RGNBBOX(A2) ;PUSH CLIPRGN BBOX + PEA RGNBBOX(A3) ;PUSH VISRGN BBOX + MOVE #4,-(SP) ;PUSH NRECTS=4 + PEA MINRECT(A6) ;PUSH DST ADDR + JSR RSECT ;CALC INTERSECTION + BEQ GOHOME ;QUIT IF NO INTERSECT + +; +; CHECK FOR BOTH VISRGN AND CLIPRGN RECTANGULAR +; + CLR.B FASTFLAG(A6) ;FASTFLAG := FALSE + CMP #10,RGNSIZE(A2) ;IS CLIPRGN RECTANGULAR ? + BNE.S FLAGOK ;NO, CONTINUE + CMP #10,RGNSIZE(A3) ;IS VISRGN RECTANGULAR ? + BEQ.S CKPAT ;YES, CONTINUE +; +; If only visRgn is non-rectangular, then check if +; its intersection with minrect would be rectangular. +; IF TrimRect(visRgn,minRect) then treat as rectangular. +; + MOVE.L visRgn(A5),-(SP) ;push rgnHandle + PEA minRect(A6) ;push addr of minRect + JSR TrimRect ;call trimRect + BLT GOHOME ;quit if intersection empty + BGT.S FLAGOK ;continue if non-rectangular +; +; CHECK FOR BLACK OR WHITE PATTERN +; +CKPAT MOVE.L PAT(A6),A0 ;POINT TO PATTERN + MOVE.L (A0)+,D0 ;GET 1ST HALF OF PATTERN + CMP.L (A0)+,D0 ;IS IT SAME AS 2ND HALF ? + BNE.S FLAGOK ;NO, CONTINUE + NOT.L D0 ;IS PATTERN BLACK ? + BEQ.S YESFLAG ;YES, WE MADE IT + NOT.L D0 ;IS PATTERN WHITE ? + BNE.S FLAGOK ;NO, CONTINUE + EOR #4,MODE(A6) ;YES, ALTER MODE AS IF BLACK +YESFLAG ST FASTFLAG(A6) ;REMEMBER RECT CLIPPED AND BLACK +; +; fast case: map mode into black,xor,white, or do-nothing +; + MOVEQ #7,D0 ;GET 3 BIT MASK + AND MODE(A6),D0 ;GET 3 BITS OF MODE + MOVE.B MODEMAP(D0),D0 ;MAP TO BLACK,XOR,WHITE,NOP + BMI GOHOME ;QUIT IF DO-NOTHING MODE + MOVE D0,MODE(A6) ;UPDATE MODE + BRA.S FLAGOK ;AND CONTINUE +MODEMAP .BYTE 0,0,1,2,2,255,255,255 +FLAGOK + + + CLR.B SKIPFLAG(A6) ;INIT TO NOT SKIPPING + +;-------------------------------------------------- +; +; ADJUST IF ARCANGLE NEGATIVE, QUIT IF ARC = 0 +; NOTE WHETHER FULL CIRCLE OR ARC +; + MOVE ARCANGLE(A6),D0 ;GET ARC ANGLE + BEQ GOHOME ;QUIT IF ARC ANGLE = 0 + BPL.S POSANG ;IS ANGLE NEG ? + ADD D0,STARTANGLE(A6) ;YES, ADJUST START ANGLE + NEG D0 ;AND MAKE ARC ANGLE POSITIVE + MOVE D0,ARCANGLE(A6) ;UPDATE INPUT PARAM +POSANG CMP #360,D0 ;IS ARC ANGLE < 360 ? + SLT ARCFLAG(A6) ;REMEMBER FOR LATER + BGE NOTARC ;NO, SKIP SETUP + + +;--------------------------------------------------------------- +; +; IF ARCANGLE < 360 THEN SET UP ARC STUFF +; +; TREAT STARTANGLE MOD 360 +; + MOVE STARTANGLE(A6),D0 ;GET STARTANGLE + EXT.L D0 ;SIGN EXTEND FOR DIVIDE + DIVS #360,D0 ;TREAT STARTANGLE MOD 360 + SWAP D0 ;GET THE REMAINDER + TST D0 ;WAS IT NEGATIVE ? + BPL.S STARTOK ;NO, CONTINUE + ADD #360,D0 ;YES, PUT IN RANGE 0..359 +STARTOK MOVE D0,STARTANGLE(A6) ;REPLACE INPUT PARAM + + ADD ARCANGLE(A6),D0 ;CALC STOPANGLE + CMP #360,D0 ;IS IT >= 360 ? + BLT.S STOPOK ;NO, CONTINUE + SUB #360,D0 ;YES, PUT IN RANGE 0..359 +STOPOK MOVE D0,STOPANGLE(A6) ;SAVE STOPANGLE FOR LATER + + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + MOVE TOP(A0),D0 + ADD BOTTOM(A0),D0 + ASR #1,D0 + MOVE D0,MIDVERT(A6) ;MID VERT := (DSTBOT+DSTTOP)/2 + + MOVE LEFT(A0),D0 + ADD RIGHT(A0),D0 + ASR #1,D0 + MOVE D0,MIDHORIZ(A6) ;MID HORIZ := (DSTLEFT+DSTRIGHT)/2 + + MOVE RIGHT(A0),D0 + SUB LEFT(A0),D0 + MOVE D0,WIDTH(A6) ;WIDTH := DSTRIGHT - DSTLEFT + + MOVE BOTTOM(A0),D0 + SUB TOP(A0),D0 + MOVE D0,HEIGHT(A6) ;HEIGHT := DSTBOTTOM -DSTTOP + + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE WIDTH(A6),-(SP) + MOVE HEIGHT(A6),-(SP) + + _FixRatio ;CALC ASPECT RATIO + MOVE.L (SP)+,D7 ;SAVE RESULT IN D7 + + +;-------------------------------------------- +; +; CALC SLOPE1 FROM STARTANGLE +; + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE STARTANGLE(A6),-(SP) ;PUSH STARTANG + JSR SlopeFromAngle ;CALC SLOPE1 + MOVE.L (SP)+,D0 ;POP SLOPE1 + CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE.L D0,-(SP) ;PUSH SLOPE1 + MOVE.L D7,-(SP) ;PUSH ASPECT RATIO + _FixMul ;scale slope1 + MOVE.L (SP)+,SLOPE1(A6) ;SAVE RESULT FOR LATER + + +;-------------------------------------------- +; +; CALC SLOPE2 FROM STOPANGLE +; + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE STOPANGLE(A6),-(SP) ;PUSH STOPANGLE + JSR SlopeFromAngle ;CALC SLOPE2 + MOVE.L (SP)+,D0 ;POP SLOPE2 + CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE.L D0,-(SP) ;PUSH SLOPE + MOVE.L D7,-(SP) ;PUSH ASPECT RATIO + _FixMul ;SCALE SLOPE2 + MOVE.L (SP)+,SLOPE2(A6) ;SAVE RESULT FOR LATER + + +;--------------------------------------------------------- +; +; CALC HORIZ COORDS OF LINE1 AND LINE2 AT TOP OF DSTRECT +; + MOVE MIDHORIZ(A6),D6 + SWAP D6 + CLR.W D6 ;CALC MIDHORIZ*64K + MOVE HEIGHT(A6),D7 + LSR #1,D7 ;CALC HEIGHT DIV 2 + + MOVE SLOPE1+2(A6),D0 ;GET LO WORD OF SLOPE + MULU D7,D0 ;CALC LO PARTIAL PRODUCT + MOVE.L D0,LINE1(A6) ;ACCUMULATE IT + MOVE.W SLOPE1(A6),D0 ;GET HI WORD OF SLOPE + MULS D7,D0 ;CALC HI PARTIAL PRODUCT + ADD.W D0,LINE1(A6) ;ADD TO HI WORD OF ACCUMULATOR + MOVE.L D6,D0 ;COPY MIDHORIZ*64K + SUB.L LINE1(A6),D0 ;CALC MIDH*64K-SLOPE*(HT DIV 2) + MOVE.L D0,LINE1(A6) ;STORE AS LINE1 HORIZ AT TOP + + MOVE SLOPE2+2(A6),D0 ;GET LO WORD OF SLOPE + MULU D7,D0 ;CALC LO PARTIAL PRODUCT + MOVE.L D0,LINE2(A6) ;ACCUMULATE IT + MOVE.W SLOPE2(A6),D0 ;GET HI WORD OF SLOPE + MULS D7,D0 ;CALC HI PARTIAL PRODUCT + ADD.W D0,LINE2(A6) ;ADD TO HI WORD OF ACCUMULATOR + SUB.L LINE2(A6),D6 ;CALC MIDH*64K-SLOPE*(HT DIV 2) + MOVE.L D6,LINE2(A6) ;STORE AS LINE2 HORIZ AT TOP + + +;---------------------------------------------------------- +; +; SET UP FLAG1 AND FLAG2 TO TELL WHICH HALF EACH LINE IS ACTIVE IN: +; CODE IS: NEG = ACTIVE IN TOP, POS = ACTIVE IN BOTTOM, 0 = HORIZONTAL +; + MOVE STARTANGLE(A6),D0 + CMP #180,D0 ;IS STARTANGLE < 180 ? + BGE.S @1 ;NO, CONTINUE + SUB #90,D0 ;YES, FLAG1:=STARTANGLE-90 + BRA.S @2 ;CONTINUE +@1 SUB #270,D0 + NEG D0 ;FLAG1 := 270-STARTANGLE +@2 MOVE D0,FLAG1(A6) ;SAVE FOR LATER + + MOVE STOPANGLE(A6),D0 + CMP #180,D0 ;IS STOPANGLE < 180 ? + BGE.S @3 ;NO, CONTINUE + SUB #90,D0 ;YES, FLAG2:=STOPANGLE-90 + BRA.S @4 ;CONTINUE +@3 SUB #270,D0 + NEG D0 ;FLAG2 := 270-STOPANGLE +@4 MOVE D0,FLAG2(A6) ;SAVE FOR LATER + + +; +; SET UP SKIPFLAG TO SKIP OVER UNUSED ARC PORTIONS +; + MOVE ARCANGLE(A6),D0 + CMP #180,D0 ;IS ARC ANGLE > 180 ? + BGT.S OBTUSE ;SKIP IF ANGLE > 180 + BLT.S ACUTE ;DEAL WITH ACUTE ANGLE + CMP #90,STARTANGLE(A6) ;OTHERWISE ANGLE=180 + SEQ SKIPFLAG(A6) ;SO SKIP IF START=90 + BRA.S OBTUSE +ACUTE MOVE FLAG1(A6),D0 + OR FLAG2(A6),D0 + SPL SKIPFLAG(A6) ;SKIP:=FLAG1 AND FLAG2 BOTH >= 0 +OBTUSE + + +NOTARC + + +;--------------------------------------------------------------- +; +; INIT OUTER OVAL STATE RECORD +; + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + LEA OUTEROVAL(A6),A1 ;POINT TO OUTER OVAL RECORD + MOVE OVALHEIGHT(A6),D1 ;GET OVALHEIGHT + MOVE OVALWIDTH(A6),D2 ;GET OVALWIDTH + JSR INITOVAL ;INITIALIZE OUTER OVAL RECORD + + MOVE OVALHEIGHT(A6),D0 ;GET OVALHEIGHT + ASR #1,D0 ;CALC OVAL HEIGHT DIV 2 + ADD OUTEROVAL+OVALTOP(A6),D0 ;ADD OUTEROVAL TOP + MOVE D0,SKIPTOP(A6) ;SAVE SKIPTOP + + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + ADD BOTTOM(A0),D0 ;ADD BOTTOM + SUB TOP(A0),D0 ;SUBTRACT TOP + SUB OVALHEIGHT(A6),D0 ;SUBTRACT OVALHEIGHT + MOVE D0,SKIPBOT(A6) ;SAVE SKIPBOT + + +;--------------------------------------------------- +; +; IF THIS IS A HOLLOW OVAL, THEN CALC DSTRECT INSET BY PENSIZE, +; AND INIT INNEROVAL. (IF INNEROVAL EMPTY, SWITCH TO SOLID). +; + MOVE #32767,INNEROVAL+OVALTOP(A6) ;INIT INNEROVAL NOT USED + TST.B HOLLOW(A6) ;IS HOLLOWFLAG TRUE ? + BEQ.S SOLID ;NO, SKIP INNER OVAL + + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + MOVEM.W (A0),D0-D3 ;GET DSTRECT INTO REGS + MOVE.L PNSIZE(A5),D4 ;GET THEPORT^.PNSIZE + + ADD D4,D1 ;LEFT := DSTLEFT + PENWIDTH + SUB D4,D3 ;RIGHT := DSTRIGHT - PENWIDTH + CMP D3,D1 ;IS LEFT >= TOP ? + BGE.S SOLID ;YES, EMPTY RECT + + SWAP D4 ;GET PNSIZE.V + ADD D4,D0 ;TOP := DSTTOP + PENHEIGHT + SUB D4,D2 ;BOTTOM := DSTBOTTOM - PENHEIGHT + CMP D2,D0 ;IS TOP >= BOTTOM ? + BGE.S SOLID ;YES, EMPTY RECT + + MOVEM.W D0-D3,TEMPRECT(A6) ;STORE RESULTS INTO TEMPRECT + + LEA TEMPRECT(A6),A0 ;POINT TO DSTRECT INSET BY PENSIZE + LEA INNEROVAL(A6),A1 ;POINT TO INNER OVAL RECORD + MOVE OVALHEIGHT(A6),D1 + SUB D4,D1 ;INNER HEIGHT:=OUTER-2*PENHEIGHT + SUB D4,D1 + MOVE OVALWIDTH(A6),D2 + SWAP D4 ;GET PEN WIDTH + SUB D4,D2 ;INNER WIDTH:=OUTER-2*PENWIDTH + SUB D4,D2 + JSR INITOVAL ;INITIALIZE INNER OVAL RECORD +SOLID + + +;---------------------------------------------------------------- +; +; HIDE CURSOR IF CURSOR INTERSECTS MINRECT. +; + PEA MINRECT(A6) ;PUSH SHIELDRECT PARAMETER + MOVE.L PORTBITS+BOUNDS+TOPLEFT(A5),-(SP) ;PUSH DELTA TO CONVERT TO GLOBAL + MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR + JSR SHIELDCURSOR ;HIDE CURSOR IF IT INTERSECTS + MOVE.L PORT(A6),A5 ;RESTORE GRAFPORT IN A5 + + +;------------------------------------ +; +; CALC BUFLEFT +; + MOVE MINRECT+LEFT(A6),D2 ;GET MINRECT LEFT + SUB PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT TO GLOBAL COORDS + AND #$FFF0,D2 ;TRUNC TO MULT OF 16 + ADD PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT BACK TO GLOBAL + MOVE D2,BUFLEFT(A6) ;SAVE AS BUFLEFT +; +; IF FASTFLAG, THEN SKIP REGION SETUP +; + TST.B FASTFLAG(A6) ;RECT CLIPPED AND BLACK ? + BNE SKIPSETUP ;YES, DON'T WASTE TIME WITH SETUP +; +; CALC BUFSIZE +; + MOVE MINRECT+RIGHT(A6),D0 ;GET MINRECT RIGHT + SUB D2,D0 ;CALC MAXH-BUFLEFT + LSR #5,D0 ;DIV BY 32 FOR LONGS + MOVE D0,BUFSIZE(A6) ;BUFSIZE = # LONGS - 1 + + +;------------------------------------------------------------------------- +; +; ALLOCATE AND CLEAR A SCANLINE BUFFER FOR THE COMPOSITE MASK +; +CLRMASK CLR.L -(SP) ;ALLOCATE AND CLEAR ONE LONG + DBRA D0,CLRMASK ;LOOP TILL DONE + MOVE.L SP,MASKBUF(A6) ;REMEMBER WHERE MASKBUF IS + + +;------------------------------------------------------------------------- +; +; INIT STATE RECORDS AND ALLOCATE BUFFERS FOR EACH NON-RECTANGULAR REGION +; + CLR D5 ;INIT BOTH ARE RECT + MOVE #-32767,STATEA+THISV(A6) ;INIT REGION STATEA + MOVE #32767,STATEA+NEXTV(A6) ;TO HARMLESS IN CASE RECT + CMP #10,RGNSIZE(A2) ;IS CLIPRGN RECTANGULAR ? + BEQ.S ARECT ;YES, CONTINUE + ADD #2,D5 ;NO, SET ITS FLAG + MOVE.L A2,A0 ;POINT TO CLIPRGN + LEA STATEA(A6),A1 ;POINT TO STATE RECORD A + BSR.S INITONE ;INIT STATE, ALLOC BUFFER +ARECT + MOVE #-32767,STATEB+THISV(A6) ;INIT REGION STATEB + MOVE #32767,STATEB+NEXTV(A6) ;TO HARMLESS IN CASE RECT + CMP #10,RGNSIZE(A3) ;IS VISRGN RECTANGULAR ? + BEQ.S BRECT ;YES, CONTINUE + ADD #4,D5 ;NO, SET ITS FLAG + MOVE.L A3,A0 ;POINT TO VISRGN + LEA STATEB(A6),A1 ;POINT TO STATE RECORD B + PEA BRECT ;PUSH FAKE RETURN ADDR +INITONE MOVE MINRECT+LEFT(A6),D0 ;GET MINH + MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH + MOVE BUFLEFT(A6),D2 ;GET BUFLEFT + JMP INITRGN ;INIT STATE, ALLOC BUFFER +BRECT + + +;-------------------------------------------------------------------- +; +; IF BOTH REGIONS ARE RECTANGULAR, THEN DRAW MINRECT INTO MASK BUFFER +; + MOVE.W D5,RECTFLAG(A6) ;ARE ALL RGNS RECT ? + BNE.S NOTRECT ;NO, CONTNUE + MOVE.L MASKBUF(A6),A0 ;YES, POINT TO MASK BUFFER + MOVE MINRECT+LEFT(A6),D3 ;SET UP LEFT + SUB BUFLEFT(A6),D3 ;MAKE IT BUFFER RELATIVE + MOVE MINRECT+RIGHT(A6),D4 ;SET UP RIGHT + SUB BUFLEFT(A6),D4 ;MAKE IT BUFFER RELATIVE + JSR XorSlab ;AND XOR BETWEEN THEM +NOTRECT + +SKIPSETUP + + +;------------------------------------ +; +; CALC STARTING DSTLEFT +; + MOVE MINRECT+TOP(A6),D1 ;GET MINRECT TOP + SUB PORTBITS+BOUNDS+TOP(A5),D1 ;CONVERT TO GLOBAL COORDS + MULU PORTBITS+ROWBYTES(A5),D1 ;MULT BY DST ROWBYTES + ADD.L PORTBITS+BASEADDR(A5),D1 ;ADD START OF BITMAP + SUB PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT BUFLEFT TO GLOBAL + LSR #3,D2 ;CALC BUFLEFT DIV 8 + EXT.L D2 ;CLR HI WORD + ADD.L D2,D1 ;ADD HORIZ BYTE OFFSET + MOVE.L D1,DSTLEFT(A6) ;SAVE AS DSTLEFT + + +;---------------------------------------------------- +; +; MAKE ALL HORIZONTAL COORDINATES RELATIVE TO BUFFER +; + MOVE BUFLEFT(A6),D1 + SUB D1,MINRECT+LEFT(A6) + SUB D1,MINRECT+RIGHT(A6) + SUB.W D1,OUTEROVAL+LEFTEDGE(A6) ;ADJUST OUTEROVAL LEFTEDGE.INT + SUB.W D1,OUTEROVAL+RIGHTEDGE(A6) ;ADJUST OUTEROVAL RIGHTEDGE.INT + SUB.W D1,INNEROVAL+LEFTEDGE(A6) ;ADJUST INNEROVAL LEFTEDGE.INT + SUB.W D1,INNEROVAL+RIGHTEDGE(A6) ;ADJUST INNEROVAL RIGHTEDGE.INT + SUB.W D1,LINE1(A6) ;ADJUST LINE1 + SUB.W D1,LINE2(A6) ;ADJUST LINE2 + + +;--------------------------------------------------- +; +; SET UP CASE JUMP BASED ON MODE AND FASTFLAG +; + MOVE MODE(A6),D2 ;GET (ALTERED) PEN MODE + TST.B FastFlag(A6) ;Rect clipoped and black ? + BEQ.S @1 ;no, use slow drawslab loop + JSR FastSlabMode ;yes, get fast modeCase in A4 + MOVE.L A4,MODECASE(A6) ;SAVE FOR LATER + CLR PATINDEX(A6) ;MAKE UNUSED PATINDEX EVEN + BRA GOFORIT ;SKIP PATTERN STUFF +@1 JSR SlabMode ;get slow modeCase in A4 + MOVE.L A4,MODECASE(A6) ;SAVE FOR LATER + + +;------------------------------------------------------------------ +; +; EXPAND 8 BYTE PATTERN TO 16 LONGS AND INIT PATTERN SELECTOR +; + CLR.L D7 ;SAY NOT INVERTED + MOVE MODE(A6),D2 ;GET MODE + BCLR #2,D2 ;TEST AND CLR INVERT BIT + BEQ.S NOTINV ;SKIP IF NOT INVERTED + NOT.L D7 ;INVERTED; D7 GETS ALL 1'S +NOTINV MOVE PORTBITS+BOUNDS+LEFT(A5),D2 ;GET GLOBAL-LOCAL OFFSET + MOVE.L PAT(A6),A0 ;POINT TO BYTE WIDE PATTERN + LEA EXPAT(A6),A1 ;POINT TO EXPANDED PATTERN + MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR + JSR PATEXPAND ;EXPAND 8 BYTE PATTERN TO 16 LONGS + MOVE.L PORT(A6),A5 ;RESTORE GRAFPORT IN A5 + MOVEQ #$F,D0 ;TREAT COORD MOD 16 + AND MINRECT+TOP(A6),D0 ;GET TOP VERT LOCAL COORD + LSL #2,D0 ;QUAD FOR 4 BYTE PATTERNS + MOVE D0,PATINDEX(A6) ;SET UP PATTERN INDEX + + + +;------------------------------------------------------------ +; +; BUMP OVAL STATE RECORDS UNLESS VERT IS BETWEEN SKIPTOP AND SKIPBOT +; +GOFORIT MOVE OUTEROVAL+OVALTOP(A6),D7 ;START VERT:= OUTER OVAL TOP +NEXTROW CMP SKIPTOP(A6),D7 ;IS VERT < SKIPTOP ? + BLT.S YESBUMP ;YES, OK TO BUMP OVALS + CMP SKIPBOT(A6),D7 ;IS VERT >= SKIPBOT ? + BLT.S NOBUMP ;NO, SKIP BUMPING +YESBUMP MOVE D7,-(SP) ;STASH CURRENT VERT + MOVE D7,D0 ;COPY CURRENT VERTICAL + LEA OUTEROVAL(A6),A3 ;POINT TO OUTER OVAL STATE RECORD + JSR BUMPOVAL ;BUMP IT TO NEXT SCANLINE + MOVE (SP),D0 ;COPY CURRENT VERT + LEA INNEROVAL(A6),A3 ;POINT TO INNER OVAL STATE RECORD + JSR BUMPOVAL ;BUMP IT TO NEXT SCANLINE + MOVE (SP)+,D7 ;RECOVER SAVED CURRENT VERT + + +;-------------------------------------------------- +; +; ADJUST ARC STUFF AS WE CROSS THE MIDDLE VERTICALLY +; +NOBUMP CMP MIDVERT(A6),D7 ;IS CURRENT VERT = MIDVERT ? + BNE.S NOTMID ;NO, CONTINUE + TST.B ARCFLAG(A6) ;ARE WE DOING AN ARC ? + BEQ.S NOTMID ;NO, SKIP + NEG FLAG1(A6) ;YES, INVERT FLAGS AS WE CROSS + NEG FLAG2(A6) +; +; RE-CALCULATE SKIPFLAG, AND QUIT IF IT BECOMES TRUE +; + CLR.B SKIPFLAG(A6) + MOVE ARCANGLE(A6),D0 + CMP #180,D0 ;IS ARC ANGLE > 180 ? + BGT.S OBTUSE1 ;SKIP IF ANGLE > 180 + BLT.S ACUTE1 ;DEAL WITH ACUTE ANGLE + CMP #270,STARTANGLE(A6) ;IS STARTANGLE = 270 ? + BNE.S OBTUSE1 ;NO, CONTINUE + BRA DONE ;YES, WE'RE ALL DONE +ACUTE1 MOVE FLAG1(A6),D0 + OR FLAG2(A6),D0 + BPL DONE ;QUIT IF BOTH FLAG1 AND FLAG2>=0 +OBTUSE1 + +; +; NOW SWAP THE ROLES OF LINE1 AND LINE2 AS THEY CROSS THE MIDDLE +; + MOVE FLAG1(A6),D0 ;SWAP FLAG1 AND FLAG2 + MOVE FLAG2(A6),FLAG1(A6) + MOVE D0,FLAG2(A6) + MOVE.L LINE1(A6),D0 ;SWAP LINE1 AND LINE2 + MOVE.L LINE2(A6),LINE1(A6) + MOVE.L D0,LINE2(A6) + MOVE.L SLOPE1(A6),D0 ;SWAP SLOPE1 AND SLOPE2 + MOVE.L SLOPE2(A6),SLOPE1(A6) + MOVE.L D0,SLOPE2(A6) + +NOTMID CMP MINRECT+TOP(A6),D7 ;IS CURRENT VERT < MINV ? + BLT NODRAW ;YES, DON'T DRAW + TST.B SKIPFLAG(A6) ;ARE WE SKIPPING ? + BNE NEXTPAT ;YES, SKIP + + +;------------------------------------------------ +; +; SEEK MASK TO THE CURRENT VERTICAL, AND +; BRANCH BASED ON SOLID OR HOLLOW OVAL OR ARC. +; + TST.B FASTFLAG(A6) ;RECT CLIPPED AND BLACK ? + BNE.S NOMASK ;YES, DON'T BOTHER WITH MASK + BSR SEEKMASK ;MAKE MASKBUF CURRENT +NOMASK TST.B ARCFLAG(A6) ;ARE WE DOING AN ARC ? + BNE.S DOARC ;YES, GO TO IT + CMP INNEROVAL+OVALTOP(A6),D7 ;IS VERT >= INNEROVAL OVALTOP ? + BLT SOVAL ;NO, TREAT AS SOLID OVAL + CMP INNEROVAL+OVALBOT(A6),D7 ;IS VERT < INNEROVAL OVALTOP ? + BGE SOVAL ;NO, TREAT AS SOLID OVAL + BRA HOVAL ;YES, PROCESS HOLLOW OVAL + + +;---------------------------------------------- +; +; SOLID OR HOLLOW ARC: CALC OUTERLEFT AND OUTERRIGHT +; +DOARC MOVE.W OUTEROVAL+LEFTEDGE(A6),D1 ;GET HI WORD OF OUTEROVAL LEFT + TST FLAG1(A6) ;IS LINE1 ACTIVE ? + BPL.S @1 ;NO, CONTINUE + CMP.W LINE1(A6),D1 ;YES, CHECK LINE1 HORIZ COORD + BGE.S @1 + MOVE.W LINE1(A6),D1 ;CALC MAX(OVALLEFT,LINE1) +@1 MOVE D1,OUTERLEFT(A6) ;SAVE OUTER LEFT + + MOVE.W OUTEROVAL+RIGHTEDGE(A6),D2 ;GET HI WORD OF OUTEROVAL RIGHT + TST FLAG2(A6) ;IS LINE2 ACTIVE ? + BPL.S @2 ;NO, CONTINUE + CMP.W LINE2(A6),D2 ;YES, CHECK LINE2 HORIZ COORD + BLE.S @2 + MOVE.W LINE2(A6),D2 ;CALC MIN(OVALRIGHT,LINE2) +@2 MOVE D2,OUTERRIGHT(A6) ;SAVE OUTER RIGHT + + CMP INNEROVAL+OVALTOP(A6),D7 ;IS VERT >= INNEROVAL OVALTOP ? + BLT SARC ;NO, PROCESS SOLID ARC + CMP INNEROVAL+OVALBOT(A6),D7 ;IS VERT < INNEROVAL OVALTOP ? + BGE SARC ;NO, PROCESS SOLID ARC + + +;-------------------------------------------------- +; +; HOLLOW ARC: CALC INNERLEFT AND INNERRIGHT +; +HARC MOVE.W INNEROVAL+LEFTEDGE(A6),D0 ;GET HI WORD OF INNEROVAL LEFT + TST FLAG2(A6) ;IS LINE2 ACTIVE ? + BPL.S @1 ;NO, CONTINUE + CMP.W LINE2(A6),D0 ;YES, CHECK LINE2 HORIZ COORD + BLE.S @1 + MOVE.W LINE2(A6),D0 ;CALC MIN(OVALLEFT,LINE2) +@1 MOVE D0,INNERLEFT(A6) ;SAVE INNER LEFT + + MOVE.W INNEROVAL+RIGHTEDGE(A6),D0 ;GET HI WORD OF INNEROVAL RIGHT + TST FLAG1(A6) ;IS LINE1 ACTIVE ? + BPL.S @2 ;NO, CONTINUE + CMP.W LINE1(A6),D0 ;YES, CHECK LINE1 HORIZ COORD + BGE.S @2 + MOVE.W LINE1(A6),D0 ;CALC MAX(OVALRIGHT,LINE1) +@2 MOVE D0,INNERRIGHT(A6) ;SAVE INNER RIGHT + + +;-------------------------------------------------- +; +; IF OUTERLEFT < OUTERRIGHT THEN PAINT TWO SLABS +; + CMP D2,D1 ;IS OUTERLEFT < OUTERRIGHT ? + BGE.S @3 ;NO, CONTINUE + MOVE INNERLEFT(A6),D2 + BSR.S ONESLAB + MOVE INNERRIGHT(A6),D1 + MOVE OUTERRIGHT(A6),D2 + BRA DOSLAB +@3 +; +; ELSE IF BOTH LINES ACTIVE AND ANGLE > 180 THEN PAINT TWO OR THREE SLABS +; + MOVE FLAG1(A6),D0 + AND FLAG2(A6),D0 ;ARE BOTH LINES ACTIVE ? + BPL NEXTPAT ;NO, CONTINUE + CMP #180,ARCANGLE(A6) ;IS THE ANGLE > 180 ? + BLE NEXTPAT ;NO, CONTINUE + + CMP INNERLEFT(A6),D2 ;IS INNERLEFT=OUTERRIGHT? + BNE.S @4 ;NO, CONTINUE + MOVE.W INNEROVAL+LEFTEDGE(A6),D2 ;YES DRAW A THIRD SLAB + BRA.S @5 + +@4 MOVE OUTERLEFT(A6),D0 + CMP INNERRIGHT(A6),D0 ;IS INNERRIGHT=OUTERLEFT ? + BNE.S NOT3 ;NO, CONTINUE + MOVE.W INNEROVAL+RIGHTEDGE(A6),D1 ;YES, DRAW A THIRD SLAB + MOVE OUTERRIGHT(A6),D2 +@5 BSR.S ONESLAB +NOT3 + + MOVE OUTEROVAL+LEFTEDGE(A6),D1 + MOVE INNERLEFT(A6),D2 + BSR.S ONESLAB + MOVE INNERRIGHT(A6),D1 + MOVE.W OUTEROVAL+RIGHTEDGE(A6),D2 + BRA.S DOSLAB + + +;--------------------------------------------------------- +; +; LOCAL PROCEDURE TO SET UP AND DRAW ONE SLAB +; +ONESLAB MOVEQ #$3F,D6 ;GET WRAP-AROUND MASK + AND PATINDEX(A6),D6 ;GET PATINDEX MOD 64 + MOVE.L EXPAT(A6,D6),D6 ;GET THIS ROW'S PATTERN + LEA MaskTab,A0 ;POINT TO MASK TABLE + MOVE.L DSTLEFT(A6),A1 ;INIT DSTPTR TO LEFT + MOVE.L MASKBUF(A6),A2 ;INIT MASKPTR TO LEFT + LEA MINRECT(A6),A3 ;POINT TO MINRECT + MOVE.L MODECASE(A6),A4 ;GET MODE CASE JUMP + JMP DrawSlab + + +;---------------------------------------------------- +; +; SOLID ARC: IF OUTERLEFT < OUTERRIGHT THEN PAINT ONE SLAB +; +SARC CMP D2,D1 ;IS OUTERLEFT < OUTERRIGHT ? + BLT.S DOSLAB ;YES, DO ONE SLAB BETWEEN THEM +; +; ELSE IF BOTH LINES ACTIVE AND ANGLE > 180 THEN PAINT TWO SLABS +; + MOVE FLAG1(A6),D0 + AND FLAG2(A6),D0 ;ARE BOTH LINES ACTIVE ? + BPL.S NEXTPAT ;NO, CONTINUE + CMP #180,ARCANGLE(A6) ;IS THE ANGLE > 180 ? + BLE.S NEXTPAT ;NO, CONTINUE + MOVE OUTEROVAL+LEFTEDGE(A6),D1 + BSR ONESLAB + MOVE OUTERLEFT(A6),D1 + MOVE.W OUTEROVAL+RIGHTEDGE(A6),D2 + BRA.S DOSLAB + + +;-------------------------------------------------- +; +; HOLLOW OVAL: DRAW TWO SLABS BETWEEN OUTER AND INNER OVALS +; +HOVAL MOVE.W OUTEROVAL+LEFTEDGE(A6),D1 ;GET OUTEROVAL LEFTEDGE.INT + MOVE.W INNEROVAL+LEFTEDGE(A6),D2 ;GET INNEROVAL LEFTEDGE.INT + BSR ONESLAB ;DRAW HORIZ SLAB BETWEEN THEM + MOVE.W INNEROVAL+RIGHTEDGE(A6),D1 ;GET OUTEROVAL RIGHTEDGE.INT + MOVE.W OUTEROVAL+RIGHTEDGE(A6),D2 ;GET INNEROVAL RIGHTEDGE.INT + BSR ONESLAB ;DRAW HORIZ SLAB BETWEEN THEM + BRA.S NEXTPAT + + +;---------------------------------------------------- +; +; SOLID OVAL: DRAW ONE SLAB BETWEEN LEFT AND RIGHT EDGES OF OUTER OVAL +; +SOVAL MOVE.W OUTEROVAL+LEFTEDGE(A6),D1 ;GET OUTEROVAL LEFTEDGE.INT + MOVE.W OUTEROVAL+RIGHTEDGE(A6),D2 ;GET OUTEROVAL RIGHTEDGE.INT +DOSLAB BSR ONESLAB ;DRAW HORIZ SLAB BETWEEN THEM + + + +;------------------------------------------------------------------- +; +; BUMP DESTINATION VERTICALLY AND LOOP FOR ALL SCAN LINES +; +NEXTPAT ADD #4,PATINDEX(A6) ;BUMP PATTERN INDEX + MOVE PORTBITS+ROWBYTES(A5),D0 ;GET DST ROWBYTES + EXT.L D0 ;MAKE IT LONG + ADD.L D0,DSTLEFT(A6) ;BUMP DST TO NEXT ROW + + +NODRAW MOVE.L SLOPE1(A6),D0 ;BUMP LINE1 AND LINE2 + ADD.L D0,LINE1(A6) + MOVE.L SLOPE2(A6),D0 + ADD.L D0,LINE2(A6) + ADD #1,D7 ;BUMP CURRENT VERT + CMP MINRECT+BOTTOM(A6),D7 ;HAVE WE REACHED THE BOTTOM YET ? + BLT NEXTROW ;NO, LOOP FOR MORE + +DONE MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR + JSR SHOWCURSOR ;RESTORE CURSOR +GOHOME MOVE.L SAVESTK(A6),SP ;STRIP BUFFER + MOVEM.L (SP)+,D0-D7/A1-A5 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'DRAWARC ' + + + +;----------------------------------------------------------------------------- +; +; LOCAL ROUTINE TO UPDATE THE MASK BUFFER +; BASED ON WHICH REGIONS ARE RECTANGULAR +; +SEEKMASK MOVE D7,D0 ;GET CURRENT VERT COORD + MOVE RECTFLAG(A6),D1 ;GET RECTFLAG = 0,2,4 + MOVE RECTJMP(D1),D1 ;GET OFFSET FROM TABLE + JMP RECTJMP(D1) ;TAKE CASE JUMP + +RECTJMP .WORD IGNORE-RECTJMP ;DO NOTHING IF BOTH RECT + .WORD A-RECTJMP + .WORD B-RECTJMP + .WORD AB-RECTJMP + +; +; ONLY REGION A IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +A LEA STATEA(A6),A1 +JSRSEEK JSR SEEKRGN + MOVE.L SCANBUF(A1),MASKBUF(A6) +IGNORE RTS + + +; +; ONLY REGION B IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +B LEA STATEB(A6),A1 + BRA.S JSRSEEK + +; +; REGIONS A AND B ARE NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +AB LEA STATEA(A6),A1 + JSR SEEKRGN + LEA STATEB(A6),A1 + JSR SEEKRGN + MOVE.L STATEA+SCANBUF(A6),A0 + MOVE.L STATEB+SCANBUF(A6),A1 + MOVE.L MASKBUF(A6),A2 + MOVE BUFSIZE(A6),D1 +ABLOOP MOVE.L (A0)+,D0 + AND.L (A1)+,D0 + MOVE.L D0,(A2)+ + DBRA D1,ABLOOP + RTS + + + + + .PROC INITOVAL,4 +;------------------------------------------------------------ +; +; PROCEDURE InitOval(dstRect: Rect; VAR oval: OvalRec; +; ovalWidth,ovalHeight: INTEGER); +; +; initialize an oval state record to fit the given rectangle. +; +; INPUTS: A0: dstRect +; A1: ovalRec +; D1: ovalHeight +; D2: ovalWidth +; +; CLOBBERS D0,D1,D2 +; + + +;----------------------------------------------------------- +; +; INIT OVAL TOP AND BOTTOM TO DSTRECT TOP AND BOTTOM +; + MOVE TOP(A0),OVALTOP(A1) ;INIT OVAL TOP + MOVE BOTTOM(A0),OVALBOT(A1) ;INIT OVAL BOTTOM + +; CHECK OVALWIDTH AND OVALHEIGHT, PIN AT 0 + + TST D2 ;IS OVALWIDTH NEGATIVE ? + BPL.S OK1 ;NO, CONTINUE + CLR D2 ;YES, PIN IT TO 0 +OK1 TST D1 ;IS OVALHEIGHT NEGATIVE ? + BPL.S OK2 ;NO, CONTINUE + CLR D1 ;YES, PIN IT TO 0 +OK2 + +; CHECK OVALWIDTH AND OVALHEIGHT, TRIM IF BIGGER THAN DSTRECT + + MOVE RIGHT(A0),D0 + SUB LEFT(A0),D0 ;CALC DSTRECT WIDTH + CMP D0,D2 ;IS OVALWIDTH > DSTWIDTH ? + BLE.S OK3 ;NO,CONTINUE + MOVE D0,D2 ;YES, OVALWIDTH:= DSTWIDTH +OK3 MOVE BOTTOM(A0),D0 + SUB TOP(A0),D0 ;CALC DSTRECT HEIGHT + CMP D0,D1 ;IS OVALHEIGHT > DSTHEIGHT ? + BLE.S OK4 ;NO,CONTINUE + MOVE D0,D1 ;YES, OVALHEIGHT:= DSTHEIGHT +OK4 +; SET UP OVAL LEFT EDGE AND OVAL RIGHT EDGE, FIXED POINT NUMBERS + + MOVE.W RIGHT(A0),RIGHTEDGE(A1) ;RIGHTEDGE.INT := DSTRECT.RIGHT + CLR.W RIGHTEDGE+2(A1) ;RIGHTEDGE.FRACT := 0 + MOVE.W LEFT(A0),LEFTEDGE(A1) ;LEFTEDGE.INT := DSTRECT.LEFT + CLR.W LEFTEDGE+2(A1) ;LEFTEDGE.FRACT := 0 + MOVE D2,D0 ;GET OVAL WIDTH + SWAP D0 ;PUT IN HI WORD + CLR D0 ;CLEAR LO WORD FOR FIXED POINT + LSR.L #1,D0 ;CALC OVAL WIDTH DIV 2 + ADD.L D0,LEFTEDGE(A1) ;ADD OVALWD/2 TO LEFTEDGE + SUB.L D0,RIGHTEDGE(A1) ;SUBTRACT OVALWD/2 FROM LEFTEDGE + MOVE.L #$00008000,D0 ;GET FIXED POINT 1/2 + MOVE.L D0,ONEHALF(A1) ;SAVE IN OVAL STATE RECORD + ADD.L D0,RIGHTEDGE(A1) ;BIAS RIGHT EDGE +1/2 + +; INIT OVALY TO -OVALHEIGHT + 1 (SCALED BY 2, BIASED 1/2 SCANLINE) + + MOVEQ #1,D0 + SUB D1,D0 + MOVE D0,OVALY(A1) ;OVALY:=1-HEIGHT + +; INIT RSQYSQ TO 2*OVALHEIGHT-1 + + MOVE D1,D0 ;GET HEIGHT + EXT.L D0 ;CLEAR OUT HI WORD + ADD.L D0,D0 ;CALC 2*HEIGHT + SUB.L #1,D0 ;CALC 2*HEIGHT - 1 + MOVE.L D0,RSQYSQ(A1) ;RSQYSQ:=2*HEIGHT-1 + +; INIT SQUARE TO 0.0 + + CLR.L SQUARE(A1) ;SQUARE:=0 + CLR.L SQUARE+4(A1) ;FRACT PART := 0 TOO + +; ODDNUM:= 1 TIMES ASPECT RATIO SQUARED + + CLR.L -(SP) ;GET READY FOR FUNCTION RESULT + MOVE D1,-(SP) ;PUSH NUMERATOR=HEIGHT + MOVE D2,-(SP) ;PUSH DENOMINATOR=WIDTH + _FixRatio ;CALC FIXED POINT HEIGHT/WIDTH + MOVE.L (SP),-(SP) ;DUPLICATE RESULT + PEA ODDNUM(A1) ;PUSH ADDR FOR RESULT + _LongMul ;CALC 64BIT (HEIGHT/WIDTH) SQUARED + +; ODDBUMP:= 2 TIMES ASPECT RATIO SQUARED + + MOVE.L ODDNUM+4(A1),D0 ;GET LO LONG OF RESULT + ADD.L D0,D0 ;DOUBLE IT + MOVE.L D0,ODDBUMP+4(A1) ;STORE INTO LO LONG OF ODDBUMP + MOVE.L ODDNUM(A1),D0 + ADDX.L D0,D0 ;DOUBLE HI LONG WITH CARRY + MOVE.L D0,ODDBUMP(A1) + RTS + + + + + .PROC BUMPOVAL,2 +;------------------------------------------------------------ +; +; LOCAL PROCEDURE BumpOval(VAR oval: OvalRec; vert: INTEGER); +; +; bump an oval state record to the next scanline down. +; +; INPUTS: A3 POINTS TO OVAL STATE RECORD +; D0 CONTAINS CURRENT VERT +; +; CLOBBERS D0-D7,A0-A3 +; +; + + +;------------------------------------------------------- +; +; ONLY BUMP IF VERT IS BETWEEN OVALTOP AND OVALBOT +; + CMP (A3)+,D0 ;IS VERT < OVAL TOP ? + BLT.S GOHOME ;YES, IGNORE + CMP (A3)+,D0 ;IS VERT >= OVAL BOTTOM ? + BGE.S GOHOME ;YES, IGNORE + MOVE (A3),D0 ;GET OVALY + ADD #2,(A3)+ ;ADD 2 TO OVALY FOR NEXT TIME + MOVEM.L (A3),D1-D7/A0-A2 ;GET REST OF THE OVAL RECORD + BRA.S WHILE1 ;GO TO LOOP START + + +;------------------------------------------ +; +; register usage: +; +; D0: vert +; D1: RSQYSQ +; D2,D3: SQUARE +; D4,D5: ODDNUM +; D6,D7: ODDBUMP +; A0: LEFTEDGE +; A1: RIGHTEDGE +; A2: #$00008000 +; A3: modified oval ptr +; + + +;----------------------------------------------- +; +; WHILE SQUARE < RSQYSQ DO MAKE OVAL BIGGER +; +MORE1 ADD.L A2,A1 ;RIGHTEDGE := RIGHTEDGE + 1/2 + SUB.L A2,A0 ;LEFTEDGE := LEFTEDGE - 1/2 + ADD.L D5,D3 ;SQUARE := SQUARE + ODDNUM + ADDX.L D4,D2 ;ALL 64 BITS OF IT + ADD.L D7,D5 ;ODDNUM := ODDNUM + ODDBUMP + ADDX.L D6,D4 ;ALL 64 BITS OF IT +WHILE1 CMP.L D1,D2 ;IS SQUARE < RSQYSQ ? + BLT MORE1 ;YES, LOOP + BRA.S WHILE2 ;NO, GO TO NEXT LOOP START + + +;----------------------------------------------- +; +; WHILE SQUARE > RSQYSQ DO MAKE OVAL SMALLER +; +MORE2 SUB.L A2,A1 ;RIGHTEDGE := RIGHTEDGE - 1/2 + ADD.L A2,A0 ;LEFTEDGE := LEFTEDGE + 1/2 + SUB.L D7,D5 ;ODDNUM := ODDNUM - ODDBUMP + SUBX.L D6,D4 ;ALL 64 BITS OF IT + SUB.L D5,D3 ;SQUARE := SQUARE + ODDNUM + SUBX.L D4,D2 ;ALL 64 BITS OF IT +WHILE2 CMP.L D1,D2 ;IS SQUARE > RSQYSQ ? + BGT MORE2 ;YES, LOOP + + ADD #1,D0 ;CALC OVALY+1 + EXT.L D0 ;SIGN EXTEND TO A LONG + ASL.L #2,D0 ;CALC 4*(OVALY+1) + SUB.L D0,D1 ;RSQYSQ := RSQYSQ-4*(OVALY+1) + MOVEM.L D1-D7/A0-A2,(A3) ;UPDATE OVAL RECORD +GOHOME RTS + + + + + .END diff --git a/DrawLine.a b/DrawLine.a new file mode 100755 index 0000000..f2e58e7 --- /dev/null +++ b/DrawLine.a @@ -0,0 +1,745 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------------- +; +; --> DRAWLINE.TEXT +; + + + .PROC DrawLine + .REF RgnBlt,RSect,ShieldCursor,ShowCursor,TrimRect + .REF InitRgn,SeekRgn,PatExpand,ColorMap + .REF XorSlab,DrawSlab,SlabMode,FastSlabMode,MaskTab +;---------------------------------------------------------------- +; +; PROCEDURE DRAWLINE(P1,P2: POINT); +; +; DRAWS A LINE CLIPPED TO CURRENT PORT'S CLIPRGN AND VISRGN +; +; P1 AND P2 ARE GIVEN IN LOCAL COORDINATES OF THEPORT. +; + + +;------------------------------------------------ +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 8 ;SIZE OF PARAMETERS +P1 .EQU PARAMSIZE+8-4 ;POINT +P2 .EQU P1-4 ;POINT + + +;------------------------------------------------- +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +EXPAT .EQU -64 ;16 LONGS +LINERECT .EQU EXPAT-8 ;RECT +MINRECT .EQU LINERECT-8 ;RECT +STATEA .EQU MINRECT-RGNREC ;RGN STATE RECORD +STATEB .EQU STATEA-RGNREC ;RGN STATE RECORD +STATEC .EQU STATEB-RGNREC ;RGN STATE RECORD +SAVESTK .EQU STATEC-4 ;LONG +RECTFLAG .EQU SAVESTK-2 ;WORD +MASKBUF .EQU RECTFLAG-4 ;LONG +BUFLEFT .EQU MASKBUF-2 ;WORD +BUFSIZE .EQU BUFLEFT-2 ;WORD +VERT .EQU BUFSIZE-2 ;WORD +MODECASE .EQU VERT-4 ;LONG +PAT .EQU MODECASE-4 ;LONG, ADDR OF PAT +LEFTEDGE .EQU PAT-4 ;LONG, FIXED POINT +RIGHTEDGE .EQU LEFTEDGE-4 ;LONG, FIXED POINT +SLOPE .EQU RIGHTEDGE-4 ;LONG, FIXED POINT +DSTLEFT .EQU SLOPE-4 ;LONG +SAVEA5 .EQU DSTLEFT-4 ;LONG +PORT .EQU SAVEA5-4 ;LONG +MODE .EQU PORT-2 ;WORD +FASTFLAG .EQU MODE-2 ;BYTE +BIGRGN .EQU FASTFLAG-4 ;LONG, RgnHandle +VARSIZE .EQU BIGRGN ;SIZE OF LOCAL VARIABLES + + + + LINK A6,#VARSIZE ;ALLOCATE LOCAL VARS + MOVEM.L D0-D7/A1-A5,-(SP) ;SAVE REGS + MOVE.L SP,SAVESTK(A6) ;REMEMBER STACK FOR LATER + MOVE.L A5,SAVEA5(A6) ;REMEMBER GLOBAL PTR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L WIDEOPEN(A0),BIGRGN(A6) ;STASH WIDEOPEN IN BIGRGN + MOVE.L THEPORT(A0),A3 ;POINT TO CURRENT GRAFPORT + TST PNVIS(A3) ;IS PNVIS NEGATIVE ? + BLT GOHOME ;YES, QUIT + MOVE.L A3,PORT(A6) ;SAVE PORT FOR LATER + + +;------------------------------------------------------- +; +; QUIT IF PEN MODE NOT IN 8..15 +; + MOVEQ #-8,D0 + AND PNMODE(A3),D0 ;GET ALL BUT 3 BITS OF PEN MODE + CMP #8,D0 ;IS PEN MODE 8..15 ? + BNE GOHOME ;NO, QUIT + + +;------------------------------------------------------- +; +; Check for color filtering. Alter mode and pattern accordingly. +; + MOVE PNMODE(A3),-(SP) ;PUSH PEN MODE + PEA PNPAT(A3) ;PUSH ADDR OF PEN PATTERN + TST COLRBIT(A3) ;IS COLORBIT = 0 ? + BEQ.S NOCOLOR ;YES, DON'T MAP + JSR COLORMAP ;CHECK AGAINST THECOLOR, THEFILTER +NOCOLOR MOVE.L (SP)+,PAT(A6) ;GET (ALTERED) PATTERN + MOVE (SP)+,MODE(A6) ;AND (ALTERED) MODE + + +;--------------------------------------------------------- +; +; GET CLIPRGN AND VISRGN HANDLES AND DE-REFERENCE THEM +; + MOVE.L A3,A5 ;PUT GRAFPTR IN A5 + MOVE.L CLIPRGN(A5),A2 ;GET CLIPRGN HANDLE + MOVE.L (A2),A2 ;GET CLIPRGN POINTER + MOVE.L VISRGN(A5),A3 ;GET VISRGN HANDLE + MOVE.L (A3),A3 ;GET VISRGN POINTER + + +;------------------------------------------------------------- +; +; SET UP LINERECT, THE RECTANGLE BOUNDING THE LINE AND PEN +; + MOVEM.W P2(A6),D1/D2/D3/D4 ;GET D1=V1, D2=H1, D3=V2, D4=H2 + CMP D3,D1 ;IS V1 > V2 ? + BLE.S VOK2 ;NO, CONTINUE + EXG D1,D3 ;YES, SWAP VERT +VOK2 CMP D4,D2 ;IS H1 > H2 ? + BLE.S HOK2 ;NO, CONTINUE + EXG D2,D4 ;NO SWAP HORIZ +HOK2 ADD PNSIZE+H(A5),D4 ;ADD PEN WIDTH TO RIGHT + ADD PNSIZE+V(A5),D3 ;ADD PEN HEIGHT TO BOTTOM + MOVEM.W D1/D2/D3/D4,LINERECT(A6) ;STORE TOP, LEFT, BOTTOM, RIGHT + + +;----------------------------------------------------------------------- +; +; CALC MINRECT, THE INTERSECTION OF LINERECT, BITMAP BOUNDS, +; CLIPRGN BBOX, AND VISRGN BBOX. QUIT IF NO INTERSECTION. +; + PEA LINERECT(A6) ;PUSH LINE RECT + PEA PORTBITS+BOUNDS(A5) ;PUSH BITMAP BOUNDS + PEA RGNBBOX(A2) ;PUSH CLIPRGN BBOX + PEA RGNBBOX(A3) ;PUSH VISRGN BBOX + MOVE #4,-(SP) ;PUSH NRECTS=4 + PEA MINRECT(A6) ;PUSH DST ADDR + JSR RSECT ;CALC INTERSECTION + BEQ GOHOME ;QUIT IF NO INTERSECT + +; +; HIDE CURSOR IF CURSOR INTERSECTS MINRECT. +; + PEA MINRECT(A6) ;PUSH SHIELDRECT PARAMETER + MOVE.L PORTBITS+BOUNDS+TOPLEFT(A5),-(SP) ;PUSH DELTA TO CONVERT TO GLOBAL + MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR + JSR SHIELDCURSOR ;HIDE CURSOR IF IT INTERSECTS + MOVE.L PORT(A6),A5 ;GET BACK THEPORT + +; +; CHECK FOR BOTH VISRGN AND CLIPRGN RECTANGULAR +; + CLR.B FASTFLAG(A6) ;FASTFLAG := FALSE + CMP #10,RGNSIZE(A2) ;IS CLIPRGN RECTANGULAR ? + BNE.S FLAGOK ;NO, CONTINUE + CMP #10,RGNSIZE(A3) ;IS VISRGN RECTANGULAR ? + BEQ.S CKPAT ;YES, CONTINUE +; +; If only visRgn is non-rectangular, then check if +; its intersection with minrect would be rectangular. +; IF TrimRect(visRgn,minRect) then treat as rectangular. +; + MOVE.L visRgn(A5),-(SP) ;push rgnHandle + PEA minRect(A6) ;push addr of minRect + JSR TrimRect ;call trimRect + BLT DONE ;quit if intersection empty + BGT.S FLAGOK ;continue if non-rectangular +; +; CHECK FOR BLACK OR WHITE PATTERN +; +CKPAT MOVE.L PAT(A6),A0 ;POINT TO PATTERN + MOVE.L (A0)+,D0 ;GET 1ST HALF OF PATTERN + CMP.L (A0)+,D0 ;IS IT SAME AS 2ND HALF ? + BNE.S FLAGOK ;NO, CONTINUE + NOT.L D0 ;IS PATTERN BLACK ? + BEQ.S YESFLAG ;YES, WE MADE IT + NOT.L D0 ;IS PATTERN WHITE ? + BNE.S FLAGOK ;NO, CONTINUE + EOR #4,MODE(A6) ;YES, ALTER MODE AS IF BLACK +YESFLAG ST FASTFLAG(A6) ;RECT CLIPPED AND BLACK +; +; fast case: map mode into black,xor,white, or do-nothing +; + MOVEQ #7,D0 ;GET 3 BIT MASK + AND MODE(A6),D0 ;GET 3 BITS OF MODE + MOVE.B MODEMAP(D0),D0 ;MAP TO BLACK,XOR,WHITE,NOP + BMI DONE ;QUIT IF DO-NOTHING MODE + MOVE D0,MODE(A6) ;UPDATE MODE + BRA.S FLAGOK ;AND CONTINUE +MODEMAP .BYTE 0,0,1,2,2,255,255,255 +FLAGOK + + +; +; GET THE TWO LINE ENDPOINTS INTO REGISTERS +; AND CHECK FOR HORIZONTAL OR VERTICAL LINE +; + MOVEM.W P2(A6),D1/D2/D3/D4 ;GET D1=V2, D2=H2, D3=V1, D4=H1 + CMP D2,D4 ;H1=H2 ? + BEQ.S HVLINE ;YES, DO VERTICAL LINE + CMP D1,D3 ;NO, IS V2 > V1 ? + BGT.S SLANTED ;YES, DRAW SLANTED LINE + BLT.S VSWAP ;SWAP POINTS AND DRAW SLANTED + ;ELSE V1=V2, DO HORIZONTAL + +;----------------------------------------------------------- +; +; LINE IS EITHER HORIZONTAL OR VERTICAL. +; CHECK FOR ONE DOT LINE, BLACK OR WHITE PATTERN, AND +; CLIPRGN AND VISRGN BOTH RECTANGULAR. IF SO, OPTIMIZE FAST LINES. +; +HVLINE TST.B FASTFLAG(A6) ;RECT CLIPPED AND BLACK ? + BEQ.S NOTFAST ;NO, CONTINUE + CMP.L #$00010001,PNSIZE(A5) ;IS PEN 1 BY 1 ? + BEQ FASTLINE ;YES, DO IT FAST ! + + +;-------------------------------------------------------------------- +; +; NOT FASTLINE. PUSH PARAMS AND CALL RGNBLT FOR HORIZ OR VERT LINE. +; +NOTFAST PEA PORTBITS(A5) ;PUSH SRCBITS = DSTBITS + MOVE.L (SP),-(SP) ;PUSH DSTBITS + PEA MINRECT(A6) ;PUSH SRCRECT = DSTRECT + MOVE.L (SP),-(SP) ;PUSH DSTRECT + MOVE PNMODE(A5),-(SP) ;PUSH MODE + PEA PNPAT(A5) ;PUSH PATTERN + MOVE.L CLIPRGN(A5),-(SP) ;PUSH CLIPRGN HANDLE + MOVE.L VISRGN(A5),-(SP) ;PUSH VISRGN HANDLE + MOVE.L BIGRGN(A6),-(SP) ;PUSH SAVED WIDEOPEN + MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR + JSR RGNBLT ;DRAW THE HORIZ OR VERT LINE + BRA DONE ;RESTORE CURSOR AND QUIT + + +;------------------------------------------------------------- +; +; THE LINE IS SLANTED. SORT VERTICALLY +; AND DRAW TOP TO BOTTOM AS HORIZONTAL SLABS. +; +VSWAP EXG D1,D3 ;SORT POINTS BY VERTICAL + EXG D2,D4 ;SWAP HORIZ TO MATCH +SLANTED MOVE D3,D0 ;COPY LINE BOTTOM + ADD PNSIZE+V(A5),D0 ;ADD PEN HEIGHT + CMP RGNBBOX+TOP(A2),D0 ;IS RESULT <= CLIP TOP ? + BLE DONE ;YES, RESTORE CURSOR AND QUIT + CMP RGNBBOX+BOTTOM(A2),D1 ;IS TOP >= CLIP BOTTOM ? + BGE DONE ;YES, RESTORE CURSOR AND QUIT + + +;------------------------------------------------------------- +; +; SET UP INITIAL FIXED POINT LEFTEDGE AND RIGHTEDGE +; AND CHECK FOR ZERO PENSIZE. +; + MOVE.W D2,LEFTEDGE(A6) ;LEFTEDGE.INT := TOP HORIZ + MOVE.W #$8000,LEFTEDGE+2(A6) ;LEFTEDGE.FRACT := 1/2 + MOVE.L LEFTEDGE(A6),RIGHTEDGE(A6) ;RIGHTEDGE:=LEFTEDGE + MOVE PNSIZE+H(A5),D0 ;GET PEN WIDTH + BLE DONE ;QUIT IF PENWIDTH <= 0 + ADD.W D0,RIGHTEDGE(A6) ;ADD TO RIGHTEDGE.INT + MOVE PNSIZE+V(A5),D6 ;GET PEN HEIGHT + BLE DONE ;QUIT IF PEN HEIGHT <= 0 + + +;---------------------------------------------------- +; +; CALC FIXED POINT SLOPE = FixRatio(dh,dv); +; + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE D4,-(SP) ;PUSH BOTTOM HORIZ + SUB D2,(SP) ;CALC DH + MOVE D3,-(SP) ;PUSH BOTTOM VERT + SUB D1,(SP) ;CALC DV + _FixRatio ;CALC FIXED POINT SLOPE DH/DV + MOVE.L (SP)+,D7 ;POP RESULT + MOVE.L D7,SLOPE(A6) ;SAVE FOR LATER + +; +; CALC adjust := pen height * slope +; + CLR.L -(SP) ;PUSH ROOM FOR FCN RESULT + CLR.W -(SP) ;PUSH LOWORD = 0 + MOVE.W D6,-(SP) ;PUSH HIWORD = PEN HEIGHT + MOVE.L D7,-(SP) ;PUSH SLOPE + _FixMul ;CALC FixMul(pnSize.v,slope) + MOVE.L (SP)+,D6 ;POP ANSWER INTO D6 + +; +; ADJUST LEFTEDGE AND RIGHTEDGE DEPENDING ON SIGN AND MAGNITUDE OF SLOPE +; + MOVE.L D7,D0 ;COPY SLOPE + ASR.L #1,D0 ;CALC SLOPE/2 + ADD.L D0,LEFTEDGE(A6) ;ADD SLOPE/2 TO LEFT EDGE + ADD.L D0,RIGHTEDGE(A6) ;ADD SLOPE/2 TO RIGHT EDGE + + TST.L D7 ;IS SLOPE NEGATIVE ? + BMI.S NEGSLOPE ;YES, CONTINUE + SUB.L D6,LEFTEDGE(A6) ;SUBTRACT ADJUST FROM LEFTEDGE + CMP.L #$00010000,D7 ;IS SLOPE < ONE ? + BGE.S LESSV1 ;NO, BRANCH + +MOREV1 ADD.L D7,LEFTEDGE(A6) ;ADD SLOPE TO LEFTEDGE + BRA.S SLOPEOK ;CONTINUE + +LESSV1 SUB.W #1,RIGHTEDGE(A6) ;RIGHTEDGE := RIGHTEDGE - 1 + BRA.S SLOPEOK ;CONTINUE + + +;---------------------------------------------------- +; +; SLOPE IS NEGATIVE +; +NEGSLOPE SUB.L D6,RIGHTEDGE(A6) ;SUBTRACT ADJUST FROM RIGHTEDGE + CMP.L #$FFFF0000,D7 ;IS SLOPE > -ONE ? + + BLT.S LESSV2 ;NO, CONTINUE + +MOREV2 ADD.L D7,RIGHTEDGE(A6) ;ADD SLOPE TO RIGHTEDGE + BRA.S SLOPEOK + +LESSV2 ADD.W #1,LEFTEDGE(A6) ;LEFTEDGE := LEFTEDGE + 1 + + + +SLOPEOK MOVEM.W MINRECT(A6),D1/D2/D3/D4 ;GET MINRECT TOP,LEFT,BOTTOM,RIGHT +; +; ADJUST LEFTEDGE AND RIGHTEDGE IF LINE WAS CLIPPED VERTICALLY +; + CMP LINERECT+TOP(A6),D1 ;DID TOP GET CLIPPED ? + BEQ.S TOPOK ;NO, CONTINUE + MOVE D1,D0 + SUB LINERECT+TOP(A6),D0 ;CALC DISCARD AMMOUNT + MOVE.L D7,D5 ;GET 32 BIT SLOPE + SWAP D5 ;GET HI WORD OF SLOPE + MULS D0,D5 ;MULT TIMES DISCARD + SWAP D5 ;PUT RESULT IN HI WORD + CLR.W D5 ;CLEAR LO WORD + MOVE.L D7,D6 ;GET NEW COPY OF SLOPE + MULU D0,D6 ;MULT LO WORD TIMES DISCARD + ADD.L D6,D5 ;CALC 32BIT SLOPE*DISCARD + ADD.L D5,LEFTEDGE(A6) ;BUMP LEFTEDGE TO NEW TOP + ADD.L D5,RIGHTEDGE(A6) ;BUMP RIGHTEDGE TO NEW TOP +TOPOK +; +; CALC BUFLEFT +; + MOVE MINRECT+LEFT(A6),D2 ;GET MINRECT LEFT + SUB PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT TO GLOBAL COORDS + AND #$FFF0,D2 ;TRUNC TO MULT OF 16 + ADD PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT BACK TO GLOBAL + MOVE D2,BUFLEFT(A6) ;SAVE AS BUFLEFT +; +; IF FASTFLAG, THEN SKIP REGION SETUP +; + TST.B FASTFLAG(A6) ;RECT CLIPPED AND BLACK ? + BNE SKIPSETUP ;YES, DON'T WASTE TIME WITH SETUP +; +; CALC BUFSIZE +; + MOVE MINRECT+RIGHT(A6),D0 ;GET MINRECT RIGHT + SUB D2,D0 ;CALC MAXH-BUFLEFT + LSR #5,D0 ;DIV BY 32 FOR LONGS + MOVE D0,BUFSIZE(A6) ;BUFSIZE = # LONGS - 1 +; +; ALLOCATE AND CLEAR A SCANLINE BUFFER FOR THE COMPOSITE MASK +; +CLRMASK CLR.L -(SP) ;ALLOCATE AND CLEAR ONE LONG + DBRA D0,CLRMASK ;LOOP TILL DONE + MOVE.L SP,MASKBUF(A6) ;REMEMBER WHERE MASKBUF IS + + +;------------------------------------------------------------------------- +; +; INIT STATE RECORDS AND ALLOCATE BUFFERS FOR EACH NON-RECTANGULAR REGION +; + CLR D5 ;INIT BOTH ARE RECT + MOVE #-32767,STATEA+THISV(A6) ;INIT HARMLESS STATE + MOVE #32767,STATEA+NEXTV(A6) ;IN CASE RECTANGULAR + CMP #10,RGNSIZE(A2) ;IS CLIPRGN RECTANGULAR ? + BEQ.S ARECT ;YES, CONTINUE + ADD #2,D5 ;NO, SET ITS FLAG + MOVE.L A2,A0 ;POINT TO CLIPRGN + LEA STATEA(A6),A1 ;POINT TO STATE RECORD A + BSR.S INITONE ;INIT STATE, ALLOC BUFFER +ARECT + MOVE #-32767,STATEB+THISV(A6) ;INIT HARMLESS STATE + MOVE #32767,STATEB+NEXTV(A6) ;IN CASE RECTANGULAR + CMP #10,RGNSIZE(A3) ;IS VISRGN RECTANGULAR ? + BEQ.S BRECT ;YES, CONTINUE + ADD #4,D5 ;NO, SET ITS FLAG + MOVE.L A3,A0 ;POINT TO VISRGN + LEA STATEB(A6),A1 ;POINT TO STATE RECORD B + PEA BRECT ;PUSH FAKE RETURN ADDR +INITONE MOVE MINRECT+LEFT(A6),D0 ;GET MINH + MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH + MOVE BUFLEFT(A6),D2 ;GET BUFLEFT + JMP INITRGN ;INIT STATE, ALLOC BUFFER +BRECT + + +;-------------------------------------------------------------------- +; +; IF BOTH REGIONS ARE RECTANGULAR, THEN DRAW MINRECT INTO MASK BUFFER +; + MOVE.W D5,RECTFLAG(A6) ;ARE BOTH RGNS RECT ? + BNE.S NOTRECT ;NO, CONTNUE + MOVE.L MASKBUF(A6),A0 ;YES, POINT TO MASK BUFFER + MOVE MINRECT+LEFT(A6),D3 ;SET UP LEFT + SUB BUFLEFT(A6),D3 ;MAKE IT BUFFER RELATIVE + MOVE MINRECT+RIGHT(A6),D4 ;SET UP RIGHT + SUB BUFLEFT(A6),D4 ;MAKE IT BUFFER RELATIVE + JSR XorSlab ;AND XOR BETWEEN THEM +NOTRECT + + +SKIPSETUP + +;------------------------------------ +; +; CALC STARTING DSTLEFT +; + MOVE MINRECT+TOP(A6),D1 + SUB PORTBITS+BOUNDS+TOP(A5),D1 ;CONVERT MINV TO GLOBAL COORDS + MULU PORTBITS+ROWBYTES(A5),D1 ;MULT BY DST ROWBYTES + ADD.L PORTBITS+BASEADDR(A5),D1 ;ADD START OF BITMAP + SUB PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT BUFLEFT TO GLOBAL + LSR #3,D2 ;CALC BUFLEFT DIV 8 + EXT.L D2 ;CLR HI WORD + ADD.L D2,D1 ;ADD HORIZ BYTE OFFSET + MOVE.L D1,DSTLEFT(A6) ;SAVE AS DSTLEFT + + +;---------------------------------------------------- +; +; MAKE LEFTEDGE,RIGHTEDGE,MINRECT RELATIVE TO BUFFER LEFT +; + MOVE BUFLEFT(A6),D1 + SUB.W D1,LEFTEDGE(A6) ;ADJUST LEFTEDGE.INT + SUB.W D1,RIGHTEDGE(A6) ;ADJUST RIGHTEDGE.INT + SUB D1,MINRECT+LEFT(A6) + SUB D1,MINRECT+RIGHT(A6) + + +;------------------------------------------------------------ +; +; TAKE FAST OR SLOW OUTER CONTROL LOOP FOR SLANTED LINES: +; + TST.B fastFlag(A6) ;ARE WE RECT CLIPPED BLACK ? + BEQ.S GOSLOW ;NO, CONTINUE + MOVE MODE(A6),D2 ;GET (ALTERED) PEN MODE + JSR FastSlabMode ;Get fast case jump in A4 + LEA MaskTab,A0 ;point to mask table + LEA MINRECT(A6),A3 ;POINT TO MINRECT + MOVE.L SLOPE(A6),D7 ;GET FIXED POINT SLOPE + MOVE PORTBITS+ROWBYTES(A5),D6 ;GET DST ROWBYTES + MOVE.L DSTLEFT(A6),A5 ;GET DSTLEFT + MOVE MINRECT+BOTTOM(A6),D5 ;GET MINRECT BOTTOM + SUB MINRECT+TOP(A6),D5 ;CALC HEIGHT + SUB #1,D5 ;MINUS 1 FOR DBRA COUNT + +NXTFAST MOVE.W LEFTEDGE(A6),D1 ;GET LEFTEDGE.INT + MOVE.W RIGHTEDGE(A6),D2 ;GET RIGHTEDGE.INT + MOVE.L A5,A1 ;INIT DSTPTR TO LEFT + JSR DrawSlab ;DRAW ONE SLAB IN PENMODE + ADD D6,A5 ;BUMP DST TO NEXT ROW + ADD.L D7,LEFTEDGE(A6) ;ADD SLOPE TO LEFT EDGE + ADD.L D7,RIGHTEDGE(A6) ;ADD SLOPE TO RIGHT EDGE + DBRA D5,NXTFAST ;LOOP FOR ALL SCANLINES + BRA DONE ;AND QUIT + + + +GOSLOW MOVE MODE(A6),D2 ;GET (ALTERED) PEN MODE + JSR SlabMode ;GET DrawSlab CASE JUMP IN A4 + + +;------------------------------------------------------------------ +; +; EXPAND 8 BYTE PATTERN TO 16 LONGS AND INIT PATTERN SELECTOR +; + CLR.L D7 ;SAY NOT INVERTED + MOVE MODE(A6),D2 ;GET (ALTERED) PEN MODE + BCLR #2,D2 ;TEST AND CLR INVERT BIT + BEQ.S NOTINV ;SKIP IF NOT INVERTED + NOT.L D7 ;INVERTED; D7 GETS ALL 1'S +NOTINV MOVE PORTBITS+BOUNDS+LEFT(A5),D2 ;GET GLOBAL-LOCAL OFFSET + MOVE.L PAT(A6),A0 ;POINT TO BYTE WIDE PATTERN + LEA EXPAT(A6),A1 ;POINT TO EXPANDED PATTERN + MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR + JSR PATEXPAND ;EXPAND 8 BYTES TO 16 LONGS + MOVE.L PORT(A6),A5 ;RESTORE GRAFPTR IN A5 + MOVEQ #$F,D7 ;TREAT COORD MOD 16 + AND MINRECT+TOP(A6),D7 ;GET TOP VERT LOCAL COORD + LSL #2,D7 ;QUAD FOR LONG INDEX + + +; +; FOR EACH SLAB, MAKE MASK BUFFER CURRENT AND DRAW SLAB +; + LEA MINRECT(A6),A3 ;POINT TO MINRECT + MOVE PORTBITS+ROWBYTES(A5),D5 ;GET DST ROWBYTES + MOVE.L DSTLEFT(A6),A5 ;GET DSTLEFT + MOVE.L SLOPE(A6),D4 ;GET FIXED POINT SLOPE + MOVE MINRECT+TOP(A6),VERT(A6) ;INIT CURRENT VERT:=MINV +NXTMASK BSR.S SEEKMASK ;MAKE MASK BUFFER CURRENT + MOVE.L EXPAT(A6,D7),D6 ;GET PATTERN DATA + MOVE.W LEFTEDGE(A6),D1 ;GET LEFTEDGE.INT + MOVE.W RIGHTEDGE(A6),D2 ;GET RIGHTEDGE.INT + LEA MaskTab,A0 ;point to mask table + MOVE.L A5,A1 ;INIT DSTPTR TO LEFT + MOVE.L MASKBUF(A6),A2 ;INIT MASKPTR TO LEFT + JSR DrawSlab ;DRAW ONE SLAB IN PENMODE + ADD #4,D7 ;BUMP PATTERN SELECTOR + AND #$3F,D7 ;MOD 64 FOR 16 LONG REPEAT + ADD D5,A5 ;BUMP DST TO NEXT ROW + ADD.L D4,LEFTEDGE(A6) ;ADD SLOPE TO LEFT EDGE + ADD.L D4,RIGHTEDGE(A6) ;ADD SLOPE TO RIGHT EDGE + ADD #1,VERT(A6) ;BUMP CURRENT VERT + MOVE VERT(A6),D0 ;GET CURRENT VERT + CMP MINRECT+BOTTOM(A6),D0 ;ARE WE AT BOTTOM YET ? + BLT NXTMASK ;NO, LOOP ALL SCAN LINES + + +DONE MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR + JSR SHOWCURSOR ;RESTORE CURSOR +GOHOME MOVE.L SAVESTK(A6),SP ;STRIP BUFFER + MOVEM.L (SP)+,D0-D7/A1-A5 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'DRAWLINE' + + + +;----------------------------------------------------------------------------- +; +; LOCAL ROUTINE TO UPDATE THE MASK BUFFER +; BASED ON WHICH REGIONS ARE RECTANGULAR +; +SEEKMASK MOVE VERT(A6),D0 ;GET CURRENT VERT COORD + MOVE RECTFLAG(A6),D1 ;GET RECTFLAG = 0,2,4 + MOVE RECTJMP(D1),D1 ;GET OFFSET FROM TABLE + JMP RECTJMP(D1) ;TAKE CASE JUMP + +RECTJMP .WORD IGNORE-RECTJMP ;DO NOTHING IF BOTH RECT + .WORD A-RECTJMP + .WORD B-RECTJMP + .WORD AB-RECTJMP + + +;-------------------------------------------------------------------- +; +; ONLY REGION A IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +A LEA STATEA(A6),A1 +JSRSEEK JSR SEEKRGN + MOVE.L SCANBUF(A1),MASKBUF(A6) +IGNORE RTS + + +;-------------------------------------------------------------------- +; +; ONLY REGION B IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +B LEA STATEB(A6),A1 + BRA.S JSRSEEK + + +;------------------------------------------------------------------- +; +; REGIONS A AND B ARE NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +AB LEA STATEA(A6),A1 + JSR SEEKRGN + LEA STATEB(A6),A1 + JSR SEEKRGN + MOVE.L STATEA+SCANBUF(A6),A0 + MOVE.L STATEB+SCANBUF(A6),A1 + MOVE.L MASKBUF(A6),A2 + MOVE BUFSIZE(A6),D1 +ABLOOP MOVE.L (A0)+,D0 + AND.L (A1)+,D0 + MOVE.L D0,(A2)+ + DBRA D1,ABLOOP + RTS + + +;------------------------------------------------------- +; +; SET UP AND DRAW A FAST HORIZONTAL OR VERTICAL LINE. +; +FASTLINE CMP D1,D3 ;IS LINE HORIZONTAL ? + BNE VLINE ;NO, MUST BE VERTICAL + BSR HVSETUP ;GET DSTPTR,ROWBYTES,HGLOBAL + MOVE 32(A0,D0),D6 ;GET LEFTMASK IN D6 + MOVE MINRECT+RIGHT(A6),D2 ;GET MINRECT RIGHT + SUB PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT TO GLOBAL + MOVE D2,D0 ;MAKE A COPY OF RIGHT + AND #$F,D0 ;TREAT RIGHT MOD 16 + ADD D0,D0 ;DOUBLE FOR TABLE + MOVE 0(A0,D0),D3 ;GET RIGHTMASK IN D3 + LSR #4,D2 ;CONVERT DOTS TO WORDS + CMP #1,MODE(A6) ;WHICH MODIFIED MODE ? + BLT.S HSET ;BR IF BLACK + BEQ.S HTOGL ;BR IF XOR + ;ELSE WHITE + +;------------------------------------------------------ +; +; DRAW A WHITE HORIZONTAL LINE +; + NOT D6 ;MAKE NOT LEFTMASK + NOT D3 ;MAKE NOT RIGHTMASK + SUB D1,D2 ;CALC WORDCOUNT + BEQ.S ENDCLR ;BR IF ALL IN ONE WORD + AND D6,(A4)+ ;DO LEFT WORD WITH MASK + CLR.L D6 ;FLUSH LEFTMASK FOR END + SUB #1,D2 ;DEC WORD COUNT + BEQ.S ENDCLR ;BR IF NO UNMASKED WORDS + LSR #1,D2 ;HALVE WORDCOUNT FOR LONGCOUNT + BCC.S CLRONE ;BR IF EVEN # WORDS LEFT + MOVE D6,(A4)+ ;ELSE MAKE EVEN BY DOING A WORD + SUB #1,D2 ;ADJUST LONGCOUNT + BRA.S CLRMORE ;SEE IF ANY LONGS LEFT TO DO +CLRTWO MOVE.L D6,(A4)+ ;FILL A LONG WITH BLACK +CLRONE MOVE.L D6,(A4)+ ;FILL ANOTHER LONG + SUB #2,D2 ;ANY UNMASKED LONGS LEFT ? +CLRMORE BGT CLRTWO ;YES, AT LEAST TWO LONGS + BEQ CLRONE ;YES, FINISH UP LAST LONG +ENDCLR OR D3,D6 ;COMBINE LEFT AND RIGHT MASK + AND D6,(A4) ;DRAW LINE + BRA.S DONE ;RESTORE CURSOR AND QUIT + + +;-------------------------------------------------- +; +; DRAW AN XOR HORIZONTAL LINE +; +HTOGL SUB D1,D2 ;CALC WORDCOUNT + BEQ.S ENDTOGL ;BR IF ALL IN ONE WORD + EOR D6,(A4)+ ;DO LEFT WORD WITH MASK + MOVEQ #-1,D6 ;FLUSH LEFTMASK FOR END + SUB #1,D2 ;DEC WORD COUNT + BEQ.S ENDTOGL ;BR IF NO UNMASKED WORDS + LSR #1,D2 ;HALVE WORDCOUNT FOR LONGCOUNT + BCC.S TOGLONE ;BR IF EVEN # WORDS LEFT + EOR D6,(A4)+ ;ELSE MAKE EVEN BY DOING A WORD + SUB #1,D2 ;ADJUST LONGCOUNT + BRA.S TOGLMORE ;SEE IF ANY LONGS LEFT TO DO +TOGLTWO NOT.L (A4)+ ;INVERT A LONG +TOGLONE NOT.L (A4)+ ;INVERT ANOTHER LONG + SUB #2,D2 ;ANY UNMASKED LONGS LEFT ? +TOGLMORE BGT TOGLTWO ;YES, AT LEAST TWO LONGS + BEQ TOGLONE ;YES, FINISH UP LAST LONG +ENDTOGL AND D3,D6 ;COMBINE LEFT AND RIGHT MASK + EOR D6,(A4) ;DRAW LINE + BRA.S DONE ;RESTORE CURSOR AND QUIT + + +;-------------------------------------------- +; +; DRAW A BLACK HORIZONTAL LINE +; +HSET SUB D1,D2 ;CALC WORDCOUNT + BEQ.S ENDSET ;BR IF ALL IN ONE WORD + OR D6,(A4)+ ;DO LEFT WORD WITH MASK + MOVEQ #-1,D6 ;FLUSH LEFTMASK FOR END + SUB #1,D2 ;DEC WORD COUNT + BEQ.S ENDSET ;BR IF NO UNMASKED WORDS + LSR #1,D2 ;HALVE WORDCOUNT FOR LONGCOUNT + BCC.S SETONE ;BR IF EVEN # WORDS LEFT + MOVE D6,(A4)+ ;ELSE MAKE EVEN BY DOING A WORD + SUB #1,D2 ;ADJUST LONGCOUNT + BRA.S SETMORE ;SEE IF ANY LONGS LEFT TO DO +SETTWO MOVE.L D6,(A4)+ ;FILL A LONG WITH BLACK +SETONE MOVE.L D6,(A4)+ ;FILL ANOTHER LONG + SUB #2,D2 ;ANY UNMASKED LONGS LEFT ? +SETMORE BGT SETTWO ;YES, AT LEAST TWO LONGS + BEQ SETONE ;YES, FINISH UP LAST LONG +ENDSET AND D3,D6 ;COMBINE LEFT AND RIGHT MASK + OR D6,(A4) ;DRAW LINE + BRA.S DONE ;RESTORE CURSOR AND QUIT + + +;------------------------------------------------------- +; +; DRAW A VERTICAL LINE. +; +VLINE BSR.S HVSETUP ;GET DSTPTR,ROWBYTES,HGLOBAL + MOVE 64(A0,D0),D0 ;GET BITMASK IN D0 + MOVE MINRECT+BOTTOM(A6),D1 ;GET BOTTOM + SUB MINRECT+TOP(A6),D1 ;CALC HEIGHT + SUB #1,D1 ;INIT HEIGHT COUNT + CMP #1,MODE(A6) ;WHICH MODIFIED MODE ? + BLT.S VSET ;BR IF BLACK + BEQ.S VTOGL ;BR IF XOR + ;ELSE WHITE + NOT D0 ;MAKE NOTMASK +VCLR AND D0,(A4) ;CLEAR ONE DOT + ADD D7,A4 ;BUMP TO NEXT ROW + DBRA D1,VCLR ;LOOP ALL DOTS + BRA.S DONE ;RESTORE CURSOR AND QUIT + +VTOGL EOR D0,(A4) ;TOGGLE ONE DOT + ADD D7,A4 ;BUMP TO NEXT ROW + DBRA D1,VTOGL ;LOOP ALL DOTS + BRA.S DONE ;RESTORE CURSOR AND QUIT + +VSET OR D0,(A4) ;SET ONE DOT + ADD D7,A4 ;BUMP TO NEXT ROW + DBRA D1,VSET ;LOOP ALL DOTS + BRA.S DONE ;RESTORE CURSOR AND QUIT + + + +;------------------------------------------------------------------------ +; +; LOCAL ROUTINE TO SET UP POINTER TO FIRST WORD, BIT INDEX, AND ROWBYTES +; +; INPUTS: MINRECT +; A5: thePort +; +; OUTPUTS: D0: STARTING HORIZ GLOBAL COORDS +; D1: STARTING HORIZ GLOBAL DIV 16 +; D7: ROWBYTES +; A0: MaskTab +; A4: POINTER TO FIRST WORD +; +; CLOBBERS: D0,D1,D7,A0,A4 +; +HVSETUP MOVE.L PORTBITS+BASEADDR(A5),A4 ;GET BITMAP START + MOVE MINRECT+TOP(A6),D0 ;GET STARTING VERT + SUB PORTBITS+BOUNDS+TOP(A5),D0 ;CONVERT TO GLOBAL + MOVE PORTBITS+ROWBYTES(A5),D7 ;GET ROWBYTES + MULU D7,D0 ;MULT TOP BY ROWBYTES + ADD.L D0,A4 ;ADD TO BASEADDR + MOVE MINRECT+LEFT(A6),D0 ;GET STARTING HORIZ + SUB PORTBITS+BOUNDS+LEFT(A5),D0 ;CONVERT TO GLOBAL + MOVE D0,D1 ;MAKE A COPY + LSR #4,D1 ;CONVERT BITS TO WORDS + ADD D1,A4 ;ADD TO RUNNING TOTAL + ADD D1,A4 ;TWICE FOR BYTES + LEA MaskTab,A0 ;return with masktab in A0 + AND #$F,D0 ;TREAT LEFT MOD 16 + ADD D0,D0 ;DOUBLE FOR TABLE + RTS + + + .END diff --git a/DrawText.a b/DrawText.a new file mode 100755 index 0000000..9c9bc8f --- /dev/null +++ b/DrawText.a @@ -0,0 +1,933 @@ + .INCLUDE GRAFTYPES.TEXT +;-------------------------------------------------------------- +; +; --> DRAWTEXT.TEXT +; +; QuickDraw Character Generator +; +; Completely reworked 29 Apr 85 by Bill Atkinson to get 50% speed up. +; Takes advantage of optional height table at end of font. +; + + .PROC DrText,4 + .REF RightMask,MaskTab,RSect,ShieldCursor,ShowCursor + .REF StdTxMeas,RectInRgn,MapRect,StretchBits,TrimRect +;------------------------------------------------------------ +; +; PROCEDURE DrText(count: INTEGER; textAddr: Ptr; numer,denom: Point); +; +; DRAWS CHARACTERS INTO THE CURRENT PORT'S BITMAP. +; THE FONT AND ATTRIBUTES ARE GIVEN IN THE CURRENT PORT'S CHARSTYLE. +; + + +;------------------------------------------- +; +; KERNED STRIKE FONT FORMAT OFFSETS: +; +FORMAT .EQU 0 ;WORD +MINCHAR .EQU 2 ;WORD +MAXCHAR .EQU 4 ;WORD +MAXWD .EQU 6 ;WORD +FBBOX .EQU 8 ;WORD +FBBOY .EQU 10 ;WORD +FBBDX .EQU 12 ;WORD +FBBDY .EQU 14 ;WORD +LENGTH .EQU 16 ;WORD +ASCENT .EQU 18 ;WORD +DESCENT .EQU 20 ;WORD +XOFFSET .EQU 22 ;WORD +RASTER .EQU 24 ;WORD + + +;------------------------------------------------------ +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 14 ;SIZE OF PARAMETERS +COUNT .EQU PARAMSIZE+8-2 ;WORD +TEXTADDR .EQU COUNT-4 ;LONG +NUMER .EQU TEXTADDR-4 ;LONG, POINT +DENOM .EQU NUMER-4 ;LONG, POINT + + +;----------------------------------------------------------- +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +SAVESTK .EQU -4 ;LONG +TEXTRECT .EQU SAVESTK-8 ;RECT +TEXTR2 .EQU TEXTRECT-8 ;RECT +MINRECT .EQU TEXTR2-8 ;RECT +BUFEND .EQU MINRECT-4 ;LONG +BUFSTART .EQU BUFEND-4 ;LONG +BUFSIZE .EQU BUFSTART-2 ;WORD +BUFROW .EQU BUFSIZE-2 ;WORD +BUFLEFT .EQU BUFROW-2 ;WORD +BUF2START .EQU BUFLEFT-4 ;LONG +BUF2END .EQU BUF2START-4 ;LONG +HEIGHT .EQU BUF2END-2 ;WORD +SRCBITS .EQU HEIGHT-14 ;BITMAP +DSTBITS .EQU SRCBITS-14 ;BITMAP +FAKERGN .EQU DSTBITS-10 ;RECTANGULAR REGION +FAKEPTR .EQU FAKERGN-4 ;LONG, FAKE MASTER POINTER +SRCADDR .EQU FAKEPTR-4 ;LONG +SRCROW .EQU SRCADDR-2 ;WORD +FASTFLAG .EQU SRCROW-2 ;BYTE +PENLOC .EQU FASTFLAG-4 ;POINT +SRCPTR .EQU PENLOC-4 ;LONG +DSTPTR .EQU SRCPTR-4 ;LONG +STRETCH .EQU DSTPTR-2 ;BOOLEAN +FROMRECT .EQU STRETCH-8 ;RECT +TORECT .EQU FROMRECT-8 ;RECT +SRCRECT .EQU TORECT-8 ;RECT +DSTRECT .EQU SRCRECT-8 ;RECT +SPWIDTH .EQU DSTRECT-4 ;FIXED POINT +CHARLOC .EQU SPWIDTH-4 ;FIXED POINT +INFO .EQU CHARLOC-8 ;4 WORDS +HEIGHTAB .EQU INFO-4 ;LONG +WIDTAB .EQU HEIGHTAB-4 ;LONG +LOCTAB .EQU WIDTAB-4 ;LONG +TOPHT .EQU LOCTAB-2 ;word +HEIGHTFLAG .EQU TOPHT-2 ;byte +MAXMIN .EQU HEIGHTFLAG-2 ;word +MINCH .EQU MAXMIN-2 ;word +SAVEA5 .EQU MINCH-4 ;LONG +NUMER2 .EQU SAVEA5-4 ;Point +DENOM2 .EQU NUMER2-4 ;Point +VARSIZE .EQU DENOM2 ;SIZE OF VARIABLES + + + + + LINK A6,#VARSIZE ;ALLOCATE TEMP VARS + MOVEM.L D0-D7/A1-A4,-(SP) ;SAVE REGS + MOVE.L SP,SAVESTK(A6) ;REMEMBER WHERE STACK WAS + MOVE.L A5,SAVEA5(A6) ;REMEMBER GLOBAL PTR + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;GET CURRENT GRAFPORT + MOVE.L NUMER(A6),NUMER2(A6) ;SAVE ORIGINAL NUMER + MOVE.L DENOM(A6),DENOM2(A6) ;SAVE ORIGINAL DENOM +; +; Call StdTxMeas to swap font and measure width. +; + CLR -(SP) ;ROOM FOR FCN RESULT + MOVE COUNT(A6),-(SP) ;PUSH COUNT + BLE GOHOME ;QUIT IF COUNT <= 0 + ;STACK CLEANED UP BY SAVESTK + MOVE.L TEXTADDR(A6),-(SP) ;PUSH TEXTADDR + PEA NUMER(A6) ;PUSH VAR NUMER + PEA DENOM(A6) ;PUSH VAR DENOM + PEA INFO(A6) ;PUSH VAR INFO + JSR StdTxMeas ;MEASURE TEXT + MOVE (SP)+,D1 ;POP UNSCALED WIDTH RESULT +; +; StdTxMeas also stashes FMOutPtr in QD global FONTPTR, +; and unscaled fixed point text width inn FixTxWid. +; + MOVE.L FONTPTR(A4),A4 ;POINT TO FMOUTPUT + MOVE.L 2(A4),A2 ;GET FONT HANDLE + MOVE.L (A2),A2 ;DE-REFERENCE IT + MOVE FBBDY(A2),TOPHT(A6) ;INIT TOPHT IN CASE OLD FONT + BTST #0,1(A2) ;DOES FONT HAVE HEIGHT TABLE ? + SNE HEIGHTFLAG(A6) ;REMEMBER FOR LATER +; +; Setup textRect, the rectangle bounding the entire string. +; + MOVE.L PNLOC(A3),D2 ;GET PEN LOCATION + MOVE.L D2,PENLOC(A6) ;SAVE FOR LATER + MOVE.W D2,TEXTRECT+LEFT(A6) ;TEXTRECT.LEFT := PNLOC.H + ADD.W D1,D2 ;right := left + width + MOVEQ #7,D0 ;get mode mask + AND TXMODE(A3),D0 ;is txMode = srcCopy ? + BEQ.S NOSLOP ;yes, don't add slop + CMP #3,D0 ;is textMode > srcBic ? + BGT.S NOSLOP ;yes, don't add slop + ADD.W #32,D2 ;SLOP FOR ITALIC,BOLD,OVERSTRIKE +NOSLOP MOVE.W D2,TEXTRECT+RIGHT(A6) ;STORE IN TEXTRECT.RIGHT + SWAP D2 ;GET PNLOC.V + SUB ASCENT(A2),D2 ;SUBTRACT ASCENT + MOVE D2,TEXTRECT+TOP(A6) ;TEXTRECT.TOP := PNLOC.V - ASCENT + ADD FBBDY(A2),D2 ;ADD HEIGHT + MOVE D2,TEXTRECT+BOTTOM(A6) ;TEXTRECT.BOTTOM := TOP + HEIGHT + MOVE.L TEXTRECT(A6),TEXTR2(A6) ;MAKE AN EXTRA COPY + MOVE.L TEXTRECT+4(A6),TEXTR2+4(A6) ;OF TEXTRECT IN TEXTR2 + +; +; Check for stretching +; + MOVE.L NUMER(A6),D0 ;GET NUMERATOR + CMP.L DENOM(A6),D0 ;ARE WE STRETCHING ? + SNE STRETCH(A6) ;REMEMBER THE ANSWER + BEQ.S NOSTRCH ;CONTINUE IF NOT STRETCHING + +; +; We will be stretching. Setup fromRect and toRect and map textR2. +; + MULU D0,D1 ;MULT WIDTH BY NUMER.H + DIVU DENOM+H(A6),D1 ;DIV BY DENOM.H + + MOVE.L PENLOC(A6),D0 ;GET PENLOC + MOVE.L D0,TORECT+TOPLEFT(A6) ;SET UP TORECT TOPLEFT + ADD.W NUMER+H(A6),D0 ;CALC PENLOC.H + NUMER.H + MOVE D0,TORECT+RIGHT(A6) ;SET UP TORECT RIGHT + SWAP D0 ;GET PENLOC.V + ADD NUMER+V(A6),D0 ;CALC PENLOC.V + NUMER.V + MOVE D0,TORECT+BOTTOM(A6) ;SET UP TORECT BOTTOM + + MOVE.L PENLOC(A6),D0 ;GET PENLOC + MOVE.L D0,FROMRECT+TOPLEFT(A6) ;SET UP FROMRECT TOPLEFT + ADD.W DENOM+H(A6),D0 ;CALC PENLOC.H + DENOM.H + MOVE D0,FROMRECT+RIGHT(A6) ;SET UP FROMRECT RIGHT + SWAP D0 ;GET PENLOC.V + ADD DENOM+V(A6),D0 ;CALC PENLOC.V + DENOM.V + MOVE D0,FROMRECT+BOTTOM(A6) ;SET UP FROMRECT BOTTOM + + PEA TEXTR2(A6) ;PUSH TEXTR2 + PEA FROMRECT(A6) ;PUSH FROMRECT + PEA TORECT(A6) ;PUSH TORECT + JSR MAPRECT ;MAP TEXTR2 (PRESERVES ALL REGS) + +NOSTRCH ADD D1,PNLOC+H(A3) ;BUMP PEN BY (SCALED) TEXT WIDTH +; +; Quit if the pen is hidden +; + TST PNVIS(A3) ;IS PNVIS < 0 ? + BLT GOHOME ;YES, QUIT +; +; Calc minRect: the intersection of textRect, bitMap bounds, +; clipRgn and visRgn bounding boxes. Quit if no intersection. +; + PEA TEXTR2(A6) ;PUSH (MAPPED) TEXTRECT + PEA PORTBOUNDS(A3) ;PUSH BITMAP BOUNDS + MOVE.L CLIPRGN(A3),A0 ;GET CLIPRGN HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + PEA RGNBBOX(A0) ;PUSH CLIPRGN BBOX + MOVE.L VISRGN(A3),A0 ;GET VISRGN HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + PEA RGNBBOX(A0) ;PUSH VISRGN BBOX + MOVE #4,-(SP) ;PUSH NRECTS=4 + PEA MINRECT(A6) ;PUSH DST ADDR + JSR RSECT ;CALC INTERSECTION + BEQ GOHOME ;QUIT IF NO INTERSECTION +; +; Set up srcAddr, srcRow, and height +; + LEA 26(A2),A0 ;GET START OF FONT BITMAP + MOVE.L A0,SRCADDR(A6) ;SAVE FOR LATER + MOVE RASTER(A2),D1 ;GET WORDS PER ROW IN FONT + ADD D1,D1 ;DOUBLE FOR BYTES PER ROW + MOVE D1,SRCROW(A6) ;REMEMBER FOR LATER + MOVE FBBDY(A2),HEIGHT(A6) ;SETUP HEIGHT FOR LATER +; +; Test for fast case: +; not stretched, no color mapping, txMode = srcOr, +; not bold, italic, underlined, outlined or shadowed, +; visRgn and clipRgn both rectangular. +; + TST.W 6(A4) ;TEST BOLD AND ITALIC + BNE NOTFAST ;NOT FAST UNLESS BOTH ZERO + CMP #1,TXMODE(A3) ;IS TEXT MODE SRCOR ? + BNE NOTFAST ;NO, NOT FAST + TST.W 10(A4) ;TEST ULTHICK AND SHADOW + BNE NOTFAST ;NOT FAST UNLESS BOTH ZERO + TST.B STRETCH(A6) ;IS TEXT STRETCHED ? + BNE NOTFAST ;YES, NOT FAST + MOVE COLRBIT(A3),D1 ;ARE WE COLOR MAPPING ? + BEQ.S NOCOLOR ;NO, CONTINUE + MOVE.L BKCOLOR(A3),D0 ;YES GET BACKGROUND COLOR + NOT.L D0 ;INVERT IT + AND.L FGCOLOR(A3),D0 ;AND WITH FOREGROUND COLOR + BTST D1,D0 ;IS THAT PLANE NORMAL ? + BEQ NOTFAST ;NO, NOT FAST +NOCOLOR MOVE.L CLIPRGN(A3),A0 ;GET CLIPRGN HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + MOVEQ #10,D0 + CMP RGNSIZE(A0),D0 ;IS CLIPRGN RECTANGULAR ? + BNE.S NOTFAST ;NO, NOT FAST + MOVE.L VISRGN(A3),A1 ;GET VISRGN HANDLE + MOVE.L (A1),A0 ;DE-REFERENCE IT + CMP RGNSIZE(A0),D0 ;IS VISRGN RECTANGULAR ? + BEQ.S FAST ;YES, TAKE FAST OPTIMIZATION +; +; All systems go except for VisRgn not rectangular. +; Check if visRgn sect minRect is rectangular. +; IF TrimRect(visRgn,minRect) THEN take the fast way. +; + MOVE.L A1,-(SP) ;PUSH VISRGN + PEA MINRECT(A6) ;PUSH MINRECT + JSR TRIMRECT ;CALL TRIMRECT + BLT GOHOME ;quit if intersection empty + BGT.S NOTFAST ;continue if non-rectangular +; +; Fast case, go directly to screen. +; If text is clipped vertically, then clear heightflag and update TOPHT +; +FAST ST FASTFLAG(A6) ;REMEMBER WE'RE GOING FAST + MOVE MINRECT+TOP(A6),D0 ;GET MINRECT.TOP + MOVE MINRECT+BOTTOM(A6),D1 ;GET MINRECT.BOTTOM + SUB TEXTRECT+TOP(A6),D0 ;was top clipped ? + BNE.S VCLIP ;yes, handle clip + CMP TEXTRECT+BOTTOM(A6),D1 ;was bottom clipped ? + BEQ.S VCLIPOK ;no, continue + +VCLIP CLR.B HEIGHTFLAG(A6) ;can't use height table + MOVE.B D0,TOPHT(A6) ;use adjusted top + SUB MINRECT+TOP(A6),D1 ;calc clipped height + MOVE.B D1,TOPHT+1(A6) ;replace TOPHT + +VCLIPOK MOVE TEXTRECT+TOP(A6),D0 ;GET DST TOP + SUB PORTBOUNDS+TOP(A3),D0 ;CONVERT TO GLOBAL COORDINATES + MULU PORTBITS+ROWBYTES(A3),D0 ;MULT BY ROWBYTES + ADD.L PORTBITS+BASEADDR(A3),D0 ;ADD START OF DST BITMAP + MOVE.L D0,BUFSTART(A6) ;SET UP BUFSTART FOR LATER + MOVE PORTBITS+ROWBYTES(A3),BUFROW(A6) ;SET UP BUFROW FOR LATER + MOVE PORTBOUNDS+LEFT(A3),BUFLEFT(A6) ;REMEMBER BUFLEFT + PEA MINRECT(A6) ;PUSH SHIELD RECT + MOVE.L PORTBOUNDS+TOPLEFT(A3),-(SP) ;PUSH DELTA TO CONVERT TO GLOBAL + JSR SHIELDCURSOR ;HIDE CURSOR IF IT INTERSECTS + BRA GETPTRS + +; +; Slow case: Setup for an off-screen buffer. +; +; Calc bufLeft: (word-align to avoid shift) +; +NOTFAST CLR.B FASTFLAG(A6) ;NOT GOING DIRECTLY TO SCREEN + MOVE TEXTRECT+LEFT(A6),D0 ;GET TEXTRECT LEFT + SUB PORTBOUNDS+LEFT(A3),D0 ;CONVERT TO GLOBAL + AND #$FFF0,D0 ;TRUNC TO WORD BOUND + SUB #32,D0 ;32 DOT SLOP FOR SLANT & SHADOW + ADD PORTBOUNDS+LEFT(A3),D0 ;RETURN TO LOCAL COORDS + MOVE D0,BUFLEFT(A6) ;REMEMBER FOR LATER +; +; Calculate buffer size +; + MOVE TEXTRECT+RIGHT(A6),D1 ;BUFRIGHT := TEXTRECT RIGHT + SUB D0,D1 ;WIDTH:=BUFRIGHT-BUFLEFT + LSR #5,D1 ;CONVERT DOTS TO LONGS + ADD #2,D1 ;ROUND UP PLUS EXTRA LONG + MOVE HEIGHT(A6),D3 ;GET HEIGHT + MULU D1,D3 ;BUFSIZE:=HEIGHT*BUFROW LONGS + MOVE D3,BUFSIZE(A6) ;SAVE FOR LATER + LSL #2,D1 ;QUAD BUFROW FOR BYTES + MOVE D1,BUFROW(A6) ;SAVE FOR LATER +; +; Calculate total stack requirements for off-screen buffers. +; + MOVE.L D3,D2 ;GET BUFSIZE LONGS + TST.B 11(A4) ;ARE WE SHADOWING ? + BEQ @1 ;NO, CONTINUE + ADD.L D2,D2 ;YES, CALC 2*BUFSIZE + EXT.L D1 ;SIGN EXTEND BUFROW + ADD.L D1,D2 ;CALC TOTAL LONGS +@1 LSL.L #2,D2 ;CALC TOTAL STACK BYTES NEEDED + ADD.L #1024,D2 ;ADD 1 KBYTE SLOP +; +; If stack is too small to allocate buffer(s), then recursively call +; DrText with the left half and the right half of the text string. +; + _StackAvail ;Get StackAvail IN D0 + CMP.L D0,D2 ;IS stackNeeded > stackAvail ? + BLE.S STACKOK ;NO, CONTINUE + + MOVE.L PENLOC+H(A6),PNLOC+H(A3) ;RESTORE PNLOC TO ORIGINAL + + MOVE COUNT(A6),D7 ;GET CHARACTER COUNT + LSR #1,D7 ;DIVIDE IN HALF + BEQ GOHOME ;GIVE UP IF COUNT WAS ONLY ONE + MOVE D7,-(SP) ;PUSH NEW COUNT + MOVE.L TEXTADDR(A6),-(SP) ;PUSH TEXTADDR + MOVE.L NUMER2(A6),-(SP) ;PUSH ORIGINAL NUMER + MOVE.L DENOM2(A6),-(SP) ;PUSH ORIGINAL DENOM + JSR DrText ;DRAW THE FIRST HALF + + MOVE COUNT(A6),D0 ;GET ORIGINAL CHARACTER COUNT + SUB D7,D0 ;SUBTRACT CHARS ALREADY DONE + MOVE D0,-(SP) ;PUSH NEW COUNT + MOVE.L TEXTADDR(A6),A0 ;GET ORIGINAL TEXTADDR + ADD D7,A0 ;BUMP PAST CHARS ALREADY DONE + MOVE.L A0,-(SP) ;PUSH NEW TEXTADDR + MOVE.L NUMER2(A6),-(SP) ;PUSH ORIGINAL NUMER + MOVE.L DENOM2(A6),-(SP) ;PUSH ORIGINAL DENOM + JSR DrText ;DRAW THE SECOND HALF + BRA GOHOME ;AND QUIT ! + +; +; Allocate and clear an off-screen buffer +; +STACKOK SUB #1,D3 ;INIT DBRA LOOP COUNT + CLR.L -(SP) ;PAD BUFFER WITH AN EXTRA ZERO + MOVE.L SP,BUFEND(A6) ;REMEMBER WHERE BUFFER ENDS +CLRLOOP CLR.L -(SP) + DBRA D3,CLRLOOP ;ALLOCATE AND CLEAR BUFFER + MOVE.L SP,BUFSTART(A6) ;REMEMBER START OF BUFFER + CLR.L -(SP) ;PAD BUFFER WITH AN EXTRA ZERO + +; +; Get pointers to location table, width table, and height table in font +; +GETPTRS LEA 26(A2),A0 ;GET START OF FONT BITMAP + MOVE FBBDY(A2),D0 ;GET HEIGHT OF FONT BITMAP + MULU SRCROW(A6),D0 ;CALC TOTAL SIZE OF STRIKE + ADD.L D0,A0 ;A1 := START OF LOC TABLE + MOVE.L A0,LOCTAB(A6) ;SAVE FOR LATER + + CLR.L D0 ;get ready for unsigned word + MOVE LENGTH(A2),D0 ;HOW MANY WORDS IN STRIKE BODY + ADD.L D0,D0 ;DOUBLE FOR BYTECOUNT + LEA 16(A2,D0.L),A1 ;GET START OF WIDTH TABLE + MOVE.L A1,WIDTAB(A6) ;SAVE FOR LATER + + MOVE MAXCHAR(A2),D0 ;GET MAXCHAR + MOVE MINCHAR(A2),D1 ;GET MINCHAR + MOVE D1,MINCH(A6) ;STASH MINCHAR FOR LATER + SUB D1,D0 ;CALC MAXCHAR-MINCHAR + MOVE D0,MAXMIN(A6) ;SAVE FOR LATER + + ADD #3,D0 ;CALC MAXMIN+3 + ADD D0,D0 ;CALC 2*(MAX-MIN+3) + BTST #1,1(A2) ;DOES FONT HAVE WIDTH TABLE ? + BEQ.S NOWID ;NO, CONTINUE + ADD D0,D0 ;YES, SKIP OVER WIDTH TABLE +NOWID LEA 0(A1,D0),A0 ;POINT TO HEIGHT TABLE + MOVE.L A0,HEIGHTAB(A6) ;SAVE FOR LATER + +; +; Set up space width +; + MOVE.L widthPtr,A0 ;point to width table + MOVE.L 128(A0),SPWIDTH(A6) ;get width of the space char +; +; Setup misc stuff in registers for speed +; + MOVE BUFLEFT(A6),D1 ;GET BUFLEFT + MOVE PENLOC+H(A6),D0 ;GET PEN LOCATION + ADD FBBOX(A2),D0 ;ADJUST FOR KERNING + SUB D1,D0 ;MAKE CHARLOC RELATIVE TO BUFLEFT + MOVE.W D0,CHARLOC(A6) ;INIT INT PART OF CHARLOC + MOVE #$8000,CHARLOC+2(A6) ;SET FRACT PART TO ONE HALF + SUB D1,MINRECT+LEFT(A6) ;MAKE MINRECT.LEFT AND + SUB D1,MINRECT+RIGHT(A6) ;MINRECT.RIGHT BUFFER RELATIVE + MOVE.L TEXTADDR(A6),A1 ;GET TEXTPTR + BRA.S NEXTCH ;GO TO LOOP START + + +;--------------------------------------------------- +; +; Here's the main character drawing loop: +; +SPACECH MOVE.L SPWIDTH(A6),D1 ;GET SPACE WIDTH + ADD.L D1,CHARLOC(A6) ;BUMP CHARLOC +SKIPCH SUB #1,COUNT(A6) ;DECREMENT CHAR COUNT + BLE STRDONE ;QUIT IF CHARCOUNT <= 0 +NEXTCH CLR D0 ;get ready for byte + MOVE.B (A1)+,D0 ;GET NEXT CHAR + CMP.B #32,D0 ;IS IT A SPACE ? + BEQ SPACECH ;YES, HANDLE IT + + MOVE.L WidthPtr,A0 ;POINT TO WIDTH TABLE + MOVE D0,D4 ;COPY CHARACTER + LSL #2,D4 ;QUAD FOR TABLE OFFSET + MOVE.L 0(A0,D4),D4 ;GET FIXED POINT WIDTH + + SUB MINCH(A6),D0 ;SUBTRACT SAVED MINCHAR + CMP MAXMIN(A6),D0 ;IS CH BETWEEN MINCHAR AND MAXCHAR ? + BLS.S OKCHAR ;YES, CONTINUE + +MISSING MOVE MAXMIN(A6),D0 ;NO, USE MISSING SYMBOL + ADD #1,D0 ;WHICH IS ONE PAST MAXCHAR + ADD D0,D0 ;INDEX := 2*(MISSING-MINCHAR) + MOVE.L WIDTAB(A6),A0 ;POINT TO WIDTH TABLE + MOVE 0(A0,D0),D3 ;GET OFFSET AND WIDTH BYTES + BPL.S NOTMISS ;IS MISSING CHAR MISSING ? + BRA NEXTCH ;YES, SKIP THIS CHAR + +OKCHAR ADD D0,D0 ;INDEX := 2*(ASCII-MINCHAR) + MOVE.L WIDTAB(A6),A0 ;POINT TO WIDTH TABLE + MOVE 0(A0,D0),D3 ;GET OFFSET AND WIDTH BYTES + BMI MISSING ;OFFSET NEG = MISSING CHAR + +NOTMISS LSR #8,D3 ;GET OFFSET BYTE + ADD.W CHARLOC(A6),D3 ;DSTLEFT := CHARLOC.INT + OFFSET + ADD.L D4,CHARLOC(A6) ;ADD FIXED POINT WIDTH TO CHARLOC + + MOVE.L LOCTAB(A6),A0 ;POINT TO LOCATION TABLE + MOVE 0(A0,D0),D1 ;GET SRCLEFT + MOVE 2(A0,D0),D2 ;GET SRCRIGHT + SUB D1,D2 ;CALC WIDTH OF BITS + BLE SKIPCH ;SKIP CHARBLT IF WIDTH <= 0 + ADD D3,D2 ;DSTRIGHT := DSTLEFT + WIDTH + + TST.B HEIGHTFLAG(A6) ;does font have height table ? + BEQ.S NOHEIGHT ;no, continue + MOVE.L HEIGHTAB(A6),A0 ;get height table + MOVE 0(A0,D0),TOPHT(A6) ;get this char's top and height +NOHEIGHT + + +;----------------------------------------------------------------------- +; +; Horizontal clip only if FastFlag: (else stretch,outline,shadow,italic die) +; +; skip if hidden on left, string done if hidden on right. +; +; at this point: D1: srcLeft +; D2: dstRight +; D3: dstLeft +; + TST.B FastFlag(A6) ;ARE WE GOING FAST ? + BEQ.S HORIZOK ;NO, DON'T CLIP + CMP MINRECT+LEFT(A6),D3 ;IS DSTLEFT < MINRECT.LEFT ? + BGE.S LEFTOK ;NO, CONTINUE + CMP MINRECT+LEFT(A6),D2 ;IS DSTRIGHT <= MINRECT.LEFT ? + BLE SKIPCH ;YES, SKIP THIS CHAR +TRIMLFT MOVE MINRECT+LEFT(A6),D0 ;NO, GET MINRECT.LEFT + SUB D3,D0 ;DISCARD:=MINRECT.LEFT-DSTLEFT + ADD D0,D1 ;SRCLEFT:=SRCLEFT+DISCARD + ADD D0,D3 ;DSTLEFT:=DSTLEFT+DISCARD + CMP MINRECT+RIGHT(A6),D2 ;IS DSTRIGHT > MINRECT.RIGHT ? + BLE.S HORIZOK ;NO, CONTINUE + BRA.S TRIMRT ;YES, TRIM RIGHT +LEFTOK CMP MINRECT+RIGHT(A6),D2 ;IS DSTRIGHT <= MINRECT.RIGHT ? + BLE.S HORIZOK ;YES, CONTINUE + CMP MINRECT+RIGHT(A6),D3 ;IS DSTLEFT >= MINRECT.RIGHT ? + BGE STRDONE ;YES, IGNORE REST OF STRING +TRIMRT MOVE MINRECT+RIGHT(A6),D2 ;NO, TRIM DSTRIGHT +HORIZOK + + +;-------------------------------------------------------------- +; +; Inputs to local block CharBlt: +; +; srcAddr(A6) +; srcRow(A6) +; bufStart(A6) = dstAddr +; bufRow(A6) = dstRow +; D1 = srcLeft +; D2 = dstRight relative to buffer, > dstLeft +; D3 = dstLeft relative to buffer +; TOPHT(A6) top and height +; +; CLOBBERS: D0,D1,D2,D3,D4,D5,D6,D7,A0,A2,A3,A4,A5 +; PRESERVES: A1,A6,A7 +; +; +; Setup shift count in D5 (relative shift between src and dst) +; + MOVE D3,D5 ;COPY DSTLEFT + SUB D1,D5 ;SUB SRC LEFT + MOVEQ #$F,D0 ;get a 4 bit mask + AND D0,D5 ;SHIFTCNT:=DELTA HORIZ MOD 16 + +; +; Setup srcAddr in A4, address of leftmost word +; + MOVE.L SRCADDR(A6),A4 ;GET START OF SRC BITMAP + ADD D5,D1 ;CALC SRCLEFT+SHIFTCNT + ASR #4,D1 ;CONVERT FROM DOTS TO WORDS + ADD D1,D1 ;DOUBLE FOR BYTES + SUB #2,D1 ;BACK UP 1 WORD SINCE PICKING UP LONG + ADD D1,A4 ;LEAVE SRCPTR IN A4 + +; +; Setup dstPtr in A5, address of leftmost dst word +; + MOVE.L BUFSTART(A6),A5 ;GET START OF DST BITMAP + MOVE D3,D1 ;GET A COPY OF DSTLEFT + ASR #4,D1 ;CONVERT FROM DOTS TO WORDS + ADD D1,A5 ;ADD TO DSTPTR + ADD D1,A5 ;TWICE FOR BYTES + +; +; Setup leftMask in D3 and rightMask in D4 +; + LEA MaskTab,A0 ;point to mask table + AND D0,D3 ;get bottom 4 bits of dstLeft + ADD D3,D3 ;double for table index + MOVE 0(A0,D3),D3 ;get mask word from table + NOT D3 ;invert it for leftMask + MOVE D2,D6 ;copy dstRight + AND D0,D2 ;get bottom 4 bits of dstRight + ADD D2,D2 ;double for table index + MOVE 0(A0,D2),D4 ;get rightMask from table + +; +; Get srcRow, dstRow, and char height into regs +; + MOVE SRCROW(A6),A2 + MOVE BUFROW(A6),A3 + MOVE.W #255,D7 ;GET -1 BYTE, CLEAR HI BYTE + ADD.B TOPHT+1(A6),D7 ;CALC HEIGHT-1 FOR DBRA LOOP + BMI SKIPCH ;OOPS HEIGHT WAS ZERO ! +; +; Adjust srcPtr and dstPtr for charTop +; + CLR.W D0 ;get ready for byte + MOVE.B TOPHT(A6),D0 ;get char top + MOVE A2,D2 ;get srcRow in D-reg + MULU D0,D2 ;calc charTop * srcRow + ADD.L D2,A4 ;add to srcPtr + MOVE A3,D2 ;get dstRow in D-reg + MULU D0,D2 ;calc charTop * dstRow + ADD.L D2,A5 ;add to dstPtr + +; +; Branch based on total number of dst words +; + ASR #4,D6 ;CALC (DSTRIGHT) DIV 16 + SUB D1,D6 ;CALC TOTAL NUMBER OF WORDS-1 + BEQ.S WORD1 ;BR IF DST ALL IN ONE WORD + SUB #1,D6 + BEQ.S LONG1 ;BR IF DST ALL IN ONE LONG + ADD #1,D7 ;COMPENSATE FOR EXTRA DBRA + BRA.S WIDE1 ;DST WIDER THAN ONE LONG + +; +; Slow loop only taken in wierd cases where dst wider than a long. +; +MAIN1 MOVE.L (A4),D0 ;GET SRC FROM BITMAP + ADD #2,A4 ;BUMP SRCPTR RIGHT + LSR.L D5,D0 ;ALIGN TO DST + AND D1,D0 ;MASK EXTRA TO ZEROS + OR D0,(A5)+ ;OR SRC INTO DST + MOVEQ #-1,D1 ;FLUSH MASK + DBRA D2,MAIN1 ;LOOP TILL LAST WORD + MOVE.L (A4),D0 ;GET SRC FROM BITMAP + LSR.L D5,D0 ;ALIGN TO DST + AND D4,D0 ;MASK WITH RIGHTMASK + OR D0,(A5) ;OR SRC INTO DST + MOVE.L SRCPTR(A6),A4 ;RESTORE SRCPTR TO LEFT + ADD A2,A4 ;BUMP TO NEXT ROW + MOVE.L DSTPTR(A6),A5 ;RESTORE DSTPTR TO LEFT + ADD A3,A5 ;BUMP DST TO NEXT ROW +WIDE1 MOVE.L A4,SRCPTR(A6) ;REMEMBER SRCPTR AT LEFT + MOVE.L A5,DSTPTR(A6) ;REMEMBER DSTPTR AT LEFT + MOVE D3,D1 ;MASK:=LEFTMASK + MOVE D6,D2 ;GET WORDCOUNT + DBRA D7,MAIN1 ;LOOP ALL ROWS + SUB #1,COUNT(A6) ;DECREMENT CHAR COUNT + BGT NEXTCH ;LOOP IF MORE CHARS LEFT + BRA STRDONE ;QUIT IF CHARCOUNT <= 0 + +; +; Optimize if dst fits in one long. (30% of normal characters do) +; +LONG1 SUB #2,A3 ;ADJUST DSTEND FOR WORD BUMP +LONG1A MOVE.L (A4),D0 ;GET SRC DATA + LSR.L D5,D0 ;ALIGN TO DST + AND D3,D0 ;MASK EXTRA WITH LEFTMASK + OR D0,(A5)+ ;OR RESULT INTO DST + MOVE.L 2(A4),D0 ;GET SECOND WORD OF SRC + LSR.L D5,D0 ;ALIGN IT + AND D4,D0 ;MASK EXTRA WITH RIGHTMASK + OR D0,(A5) ;OR RESULT INTO DST + ADD A2,A4 ;BUMP SRCPTR TO NEXT ROW + ADD A3,A5 ;BUMP DSTPTR TO NEXT ROW + DBRA D7,LONG1A ;LOOP ALL ROWS + SUB #1,COUNT(A6) ;DECREMENT CHAR COUNT + BGT NEXTCH ;LOOP IF MORE CHARS LEFT + BRA STRDONE ;QUIT IF CHARCOUNT <= 0 + +; +; Optimize if dst fits in one word. (70% of normal characters do) +; +WORD1 AND D4,D3 ;COMBINE LEFT AND RIGHT MASKS +WORD1B MOVE.L (A4),D0 ;GET SRC DATA + LSR.L D5,D0 ;ALIGN TO DST + AND D3,D0 ;MASK EXTRA TO ZEROS + OR D0,(A5) ;OR RESULT INTO DST + ADD A2,A4 ;BUMP SRCPTR TO NEXT ROW + ADD A3,A5 ;BUMP DSTPTR TO NEXT ROW + DBRA D7,WORD1B ;LOOP ALL ROWS + SUB #1,COUNT(A6) ;DECREMENT CHAR COUNT + BGT NEXTCH ;LOOP IF MORE CHARS LEFT + + +STRDONE MOVE.L SAVEA5(A6),A5 ;RESTORE GLOBAL PTR + TST.B FASTFLAG(A6) ;WERE WE GOING DIRECT TO SCREEN ? + BEQ.S @1 ;NO, CONTINUE + JSR SHOWCURSOR ;YES, RESTORE CURSOR + BRA GOHOME ;AND QUIT + +@1 MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A3 ;GET CURRENT GRAFPORT + MOVE.L FONTPTR(A0),A4 ;POINT TO FMOUTPUT + MOVE.L 2(A4),A2 ;GET FONT HANDLE + MOVE.L (A2),A2 ;DE-REFERENCE IT + MOVE CHARLOC(A6),D7 ;GET FINAL CHARLOC INT PART + SUB FBBOX(A2),D7 ;UN-ADJUST FROM KERNING +; +; Make buffer bold if necessary: +; +CKBOLD CLR D2 ;GET READY FOR BYTE + MOVE.B 6(A4),D2 ;GET NUMBER OF OVERSTRIKES + BRA.S NXTBOLD ;BOLD BUFFER IF ANY +BOLDIT MOVE.L BUFSTART(A6),A0 ;POINT TO START OF BUFFER + MOVE BUFSIZE(A6),D1 ;HOW MANY LONGS IN BUF + SUB D0,D0 ;CLEAR X-BIT +BOLDLP MOVE.L (A0),D0 ;GET ONE LONG + ROXR.L #1,D0 ;ROTATE RIGHT WITH EXTEND + OR.L D0,(A0)+ ;OR BACK INTO BUFFER + DBRA D1,BOLDLP ;LOOP ENTIRE BUFFER +NXTBOLD DBRA D2,BOLDIT ;LOOP FOR EACH OVERSTRIKE + + +; +; Slant the buffer if necessary: +; Work from bottom of buffer up, shifting each row right. +; Work right to left to avoid clobbering src. +; + CLR D2 ;GET READY FOR BYTE + MOVE.B 7(A4),D2 ;DO WE NEED ITALIC ? + BEQ.S CHECKUL ;NO, CONTINUE + + MOVE.L BUFEND(A6),A1 ;DSTPTR:=END OF BUFFER + MOVE BUFROW(A6),D3 ;GET BUFFER ROWBYTES + SUB D3,A1 ;BACK UP DSTPTR TO END OF 2ND ROW + LSR #1,D3 ;WORDCNT:=ROWBYTES DIV 2 + SUB #1,D3 ;WORDCOUNT-1 FOR DBRA LOOP + + MOVE HEIGHT(A6),D6 ;INIT ROW COUNTER + CLR D4 ;INIT OFFSET + BRA.S DOSLANT ;GO TO LOOP START +NXTROW ADD D2,D4 ;OFFSET:=OFFSET+ITALIC + MOVE D4,D0 ;COPY OFFSET + LSR #4,D0 ;DELTA := OFFSET SCALED BY 16 + MOVEQ #$F,D5 + AND D0,D5 ;SHIFTCNT:=DELTA MOD 16 + LSR #4,D0 ;DELWORD:=DELTA DIV 16 + MOVE.L A1,A0 ;SRCPTR:=DSTPTR + SUB #4,A0 ;BACK UP ONE LONG + SUB D0,A0 ;SUBTRACT DELWORD + SUB D0,A0 ;TWICE BECAUSE WORDS + + MOVE D3,D1 ;INIT LOOP TO WORDCNT +NXTWORD MOVE.L (A0),D0 ;GET A LONG OF SRC + SUB #2,A0 ;BUMP SRCPTR LEFT ONE WORD + LSR.L D5,D0 ;SHIFT SRC TO ALIGN WITH DST + MOVE D0,-(A1) ;STORE IN DST AND BUMP DSTPTR + DBRA D1,NXTWORD ;LOOP ALL WORDS THIS ROW +DOSLANT DBRA D6,NXTROW ;LOOP FOR ALL ROWS IN BUFFER + + +; +; Underline characters in buffer if necessary. +; +; Use characters in buffer to hide parts of the underline. +; +CHECKUL TST.B 10(A4) ;IS ULTHICK ZERO ? + BEQ NOTUL ;YES, CONTINUE + MOVE.L BUFSTART(A6),A0 ;POINT TO BUFFER START + MOVE BUFROW(A6),D1 ;GET BYTES PER ROW OF BUFFER + MOVE ASCENT(A2),D0 ;GET ASCENT + MOVE DESCENT(A2),D2 ;GET DESCENT + MULU D1,D0 + ADD.L D0,A0 ;POINT TO BASELINE ROW + MOVE.L A0,A1 + MOVE.L A0,A2 + ADD D1,A1 ;POINT TO BASELINE+1 + CMP #2,D2 ;IS DESCENT AT LEAST 2 ? + BLT.S NOTUL ;NO, SKIP UNDERLINE + BEQ.S ONLY2 ;ONLY USE 2 IF DESCENT=2 + ADD D1,A2 + ADD D1,A2 ;POINT TO BASELINE+2 +ONLY2 SUB D1,SP ;ALLOCATE TEMP SCANBUF + MOVE.L A3,-(SP) ;SAVE GRAFPORT + LEA 4(SP),A3 ;POINT TO START OF TEMP + LSR #2,D1 ;CONVERT BYTES TO LONGS + SUB #1,D1 ;INIT DBRA LOOP COUNT + MOVE D1,D2 ;COPY LOOP COUNT + SUB D0,D0 ;CLEAR X-BIT +UL1 MOVE.L (A0)+,D0 ;GET FROM BASELINE + OR.L (A1)+,D0 ;OR WITH BASELINE+1 + OR.L (A2)+,D0 ;OR WITH BASELINE+2 + MOVE.L D0,(A3) ;PUT RESULT TO TEMP + ROXR.L #1,D0 ;SHIFT WITH CARRY + OR.L D0,(A3)+ ;OR INTO TEMP + DBRA D1,UL1 ;LOOP ALL LONGS IN ROW + + MOVE.L A1,A0 ;COPY END PTR + SUB D0,D0 ;CLEAR X-BIT +UL2 MOVE.L -(A3),D0 ;GET FROM TEMP + ROXL.L #1,D0 ;SHIFT LEFT WITH CARRY + OR.L (A3),D0 ;OR WITH TEMP + NOT.L D0 ;INVERT + OR.L D0,-(A1) ;DRAW SOME UNDERLINE + DBRA D2,UL2 ;LOOP ALL LONGS IN ROW + MOVE.L (SP)+,A3 ;RESTORE GRAFPORT +; +; Trim right edge of underline. (left edge trimmed by StretchBits) +; + MOVE BUFROW(A6),D0 ;GET BYTES PER ROW OF BUFFER + LSL #3,D0 ;TIMES 8 FOR DOTS WIDE + SUB D7,D0 ;OVERSHOOT:=BUFRIGHT-LASTRIGHT + SUB #1,D0 ;BACK UP 1 SO MASK COMES OUT RIGHT + LSR #4,D0 ;CONVERT DOTS TO WORDCOUNT + BRA.S UL3 ;GO TO LOOP START +ULTRIM CLR -(A0) ;ERASE SOME UNDERLINE +UL3 DBRA D0,ULTRIM ;LOOP ALL FULL WORDS + ADD BUFLEFT(A6),D7 ;UNDO BUFFER RELATIVE + MOVE D7,D0 ;GET LAST RIGHT COORD + SUB PORTBOUNDS+LEFT(A3),D0 ;CONVERT TO GLOBAL COORDS + JSR RIGHTMASK ;COMPUTE A MASK + AND D0,-(A0) ;ERASE LAST PARTIAL WORD + + +; +; Setup fakeRgn, a dummy rectangular region +; +NOTUL MOVE #10,FAKERGN+RGNSIZE(A6) ;SIZE=10 BYTES FOR RECT RGN + MOVE.L PORTBOUNDS(A3),FAKERGN+RGNBBOX(A6) + MOVE.L PORTBOUNDS+4(A3),FAKERGN+RGNBBOX+4(A6) + LEA FAKERGN(A6),A0 ;GET ADDR OF FAKERGN + MOVE.L A0,FAKEPTR(A6) ;POINT FAKE MASTERPTR TO IT + + +; +; Setup bitMaps to transfer from buffer to screen. +; +; srcBits := buffer +; + LEA SRCBITS(A6),A0 ;POINT TO SRCBITS + MOVE.L BUFSTART(A6),(A0)+ ;SET UP BASEADDR + MOVE BUFROW(A6),(A0)+ ;SET UP ROWBYTES + MOVE TEXTRECT+TOP(A6),(A0)+ ;SET UP BOUNDS TOP + MOVE BUFLEFT(A6),(A0)+ ;SET UP BOUNDS LEFT + MOVE.L TEXTRECT+BOTRIGHT(A6),(A0)+ ;SET UP BOTTOM RIGHT + +; +; dstBits := portBits +; + LEA PORTBITS(A3),A2 ;POINT TO PORTBITS + LEA DSTBITS(A6),A0 ;POINT TO DSTBITS + MOVE.L (A2)+,(A0)+ ;COPY BASEADDR + MOVE (A2)+,(A0)+ ;COPY ROWBYTES + MOVE.L (A2)+,(A0)+ ;COPY BOUNDS.TOPLEFT + MOVE.L (A2)+,(A0)+ ;COPY BOUNDS.BOTRIGHT + +; +; check if any shadowing: +; + CLR D3 ;GET READY FOR BYTE + MOVE.B 11(A4),D3 ;GET SHADOW COUNT + BEQ NOSHAD ;SKIP IF NO SHADOWING +; +; Shadowing will be used. Allocate buf2, 4 scans taller than BUF1. +; Clear out new 4 scanlines, and copy BUF1 into the rest. +; + MOVE BUFROW(A6),D0 ;GET 4 * NUMBER OF LONGS PER ROW + SUB #1,D0 ;INIT LOOP COUNTER + CLR.L -(SP) ;ALLOW ONE LONG OF SLOP + MOVE.L SP,BUF2END(A6) ;REMEMBER END OF BUF2 +CLR2 CLR.L -(SP) ;ALLOCATE AND CLEAR A LONG + DBRA D0,CLR2 ;CLEAR 4 SCANLINES WORTH + MOVE BUFSIZE(A6),D0 ;GET NUMBER OF LONGS IN BUF1 + SUB #1,D0 ;INIT DBRA COUNTER + MOVE.L BUFEND(A6),A0 ;POINT TO END OF BUF1 +COPYLP MOVE.L -(A0),-(SP) ;COPY FROM BUF1 TO NEW BUF2 + DBRA D0,COPYLP ;COPY ALL OF BUF1 + MOVE.L SP,BUF2START(A6) ;REMEMBER START OF BUF2 + CLR.L -(SP) ;ALLOW ONE LONG OF SLOP + +; +; Bold buf2 across to the right enough for shadow. +; + AND #3,D3 ;RESTRICT SHADOW COUNT TO 1..3 + MOVE D3,D2 ;INIT BOLD COUNTER +ACROSS1 MOVE.L BUF2START(A6),A0 ;POINT TO START OF BUFFER2 + MOVE BUFSIZE(A6),D1 ;INIT COUNT OF LONGS + SUB D0,D0 ;CLEAR X-BIT +ACROSS2 MOVE.L (A0),D0 ;GET A LONG FROM BUF2 + ROXR.L #1,D0 ;SHIFT IT RIGHT EXTENDED + OR.L D0,(A0)+ ;OR IT BACK INTO BUFFER + DBRA D1,ACROSS2 ;LOOP FOR ALL LONGS + DBRA D2,ACROSS1 ;BOLD RIGHT 2,3, OR 4 TIMES + +; +; Bold BUF2 down enough for shadow. +; + MOVE.L BUF2START(A6),A2 ;GET LIMIT POINTER +DOWN1 MOVE.L BUF2END(A6),A1 ;DSTPTR:=END OF BUF2 + MOVE.L A1,A0 + SUB SRCBITS+ROWBYTES(A6),A0 ;SRCPTR:=END - 1 SCANLINE +DOWN2 MOVE.L -(A0),D0 ;GET A LONG FROM LINE ABOVE + OR.L D0,-(A1) ;OR INTO THIS LINE + CMP.L A2,A0 ;IS SRCPTR <= BUF2START ? + BGT DOWN2 ;NO, LOOP ALL LONGS + DBRA D3,DOWN1 ;BOLD DOWN 2,3, OR 4 TIMES + + +; +; Alter srcBits to use BUF2 +; + MOVE.L A2,SRCBITS+BASEADDR(A6) ;SRC BASEADDR:=BUF2START + ADD #4,SRCBITS+BOUNDS+BOTTOM(A6) ;4 SCANS TALLER + +; +; Push params and call StretchBits to transfer shadow to screen +; + MOVE.L TEXTRECT(A6),SRCRECT(A6) ;SRCRECT := TEXTRECT + MOVE.L TEXTRECT+4(A6),SRCRECT+4(A6) + ADD #4,SRCRECT+BOTTOM(A6) ;PLUS 4 SCANS TALLER + + MOVE.L SRCRECT(A6),DSTRECT(A6) ;DSTRECT := SRCRECT + MOVE.L SRCRECT+4(A6),DSTRECT+4(A6) + LEA DSTRECT+TOP(A6),A0 ;OFFSET BY (-1,-1) + SUB #1,(A0)+ ;TOP + SUB #1,(A0)+ ;LEFT + SUB #1,(A0)+ ;BOTTOM + SUB #1,(A0)+ ;RIGHT + + TST.B STRETCH(A6) + BEQ.S @1 + PEA DSTRECT(A6) + PEA FROMRECT(A6) + PEA TORECT(A6) + JSR MAPRECT ;THEN MAPPED FOR SCALING +@1 + + PEA SRCBITS(A6) ;PUSH SRCBITS + PEA DSTBITS(A6) ;PUSH DSTBITS + PEA SRCRECT(A6) ;PUSH SRCRECT + PEA DSTRECT(A6) ;PUSH DSTRECT + MOVEQ #7,D0 ;GET A 3-BIT MASK + AND TXMODE(A3),D0 ;GET TEXTMODE MOD 7 + MOVE D0,-(SP) ;PUSH SHADOW MODE + MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN HANDLE + MOVE.L VISRGN(A3),-(SP) ;PUSH VISRGN HANDLE + PEA FAKEPTR(A6) ;PUSH FAKE HANDLE + JSR StretchBits ;TRANSFER BUFFER TO SCREEN + +; +; restore altered srcBits +; + MOVE.L BUFSTART(A6),SRCBITS+BASEADDR(A6) + SUB #4,SRCBITS+BOUNDS+BOTTOM(A6) + +; +; Push params and call StretchBits to transfer buffer to screen +; +NOSHAD PEA SRCBITS(A6) ;PUSH SRCBITS + PEA DSTBITS(A6) ;PUSH DSTBITS + PEA TEXTRECT(A6) ;PUSH SRCRECT = TEXTRECT + PEA TEXTR2(A6) ;PUSH DSTRECT = TEXTR2 + MOVE TXMODE(A3),-(SP) ;PUSH TEXTMODE + TST.B 11(A4) ;ARE WE USING SHADOW ? + BEQ.S MODEOK ;NO, CONTINUE + MOVE #2,(SP) ;YES, USE XOR MODE +MODEOK AND #7,(SP) ;TREAT MODE MOD 8 + MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN HANDLE + MOVE.L VISRGN(A3),-(SP) ;PUSH VISRGN HANDLE + PEA FAKEPTR(A6) ;PUSH FAKE HANDLE + JSR StretchBits ;TRANSFER BUFFER TO SCREEN + + +GOHOME MOVE.L SAVESTK(A6),SP ;STRIP BUFFER + MOVEM.L (SP)+,D0-D7/A1-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'DRTEXT ' + + + + .END diff --git a/FixMove.p b/FixMove.p new file mode 100755 index 0000000..f6e1687 --- /dev/null +++ b/FixMove.p @@ -0,0 +1,45 @@ +PROGRAM FixMove; + +{ Assembler restrictions require procedure Move to assembled as MQVE. } +{ This program back patches the object file replacing 'MQVE' with 'MOVE' } + +VAR f: FILE; + fileName: String[30]; + buffer: PACKED ARRAY[0..1023] OF CHAR; + i,hitCount: INTEGER; + +BEGIN + + REPEAT + WRITE('file to patch:'); + READLN(fileName); + RESET(f,fileName); + UNTIL IORESULT = 0; + + i := BlockRead(f,buffer,2,0); + + hitCount := 0; + FOR i := 0 TO 1020 DO + BEGIN + IF (buffer[i ] = 'M') + AND (buffer[i+1] = 'Q') + AND (buffer[i+2] = 'V') + AND (buffer[i+3] = 'E') + THEN + BEGIN + buffer[i+1] := 'O'; + hitCount := hitCount + 1; + END; + END; + + WRITE(hitCount:1,' matches found.'); + IF hitCount = 0 THEN WRITELN(CHR(7)) + ELSE + BEGIN + i := BlockWrite(f,buffer,2,0); + IF IORESULT <> 0 THEN WRITELN('Oops, trouble writing'); + END; + + CLOSE(f,lock); + +END. diff --git a/Graf3D.p b/Graf3D.p new file mode 100755 index 0000000..b1e9599 --- /dev/null +++ b/Graf3D.p @@ -0,0 +1,477 @@ +{$S Graf } + +UNIT Graf3D; + +{ three-dimensional graphics routines layered on top of QuickDraw } + +INTERFACE + +USES {$U obj:QuickDraw } QuickDraw; + +CONST radConst=57.29578; + +TYPE Point3D=RECORD + x: REAL; + y: REAL; + z: REAL; + END; + + Point2D=RECORD + x: REAL; + y: REAL; + END; + + XfMatrix = ARRAY[0..3,0..3] OF REAL; + Port3DPtr = ^Port3D; + Port3D = RECORD + GPort: GrafPtr; + viewRect: Rect; + xLeft,yTop,xRight,yBottom: REAL; + pen,penPrime,eye: Point3D; + hSize,vSize: REAL; + hCenter,vCenter: REAL; + xCotan,yCotan: REAL; + ident: BOOLEAN; + xForm: XfMatrix; + END; + + +VAR thePort3D: Port3DPtr; + + + PROCEDURE Open3DPort (port: Port3DPtr); + PROCEDURE SetPort3D (port: Port3DPtr); + PROCEDURE GetPort3D (VAR port: Port3DPtr); + + PROCEDURE MoveTo2D(x,y: REAL); PROCEDURE MoveTo3D(x,y,z: REAL); + PROCEDURE LineTo2D(x,y: REAL); PROCEDURE LineTo3D(x,y,z: REAL); + PROCEDURE Move2D(dx,dy: REAL); PROCEDURE Move3D(dx,dy,dz: REAL); + PROCEDURE Line2D(dx,dy: REAL); PROCEDURE Line3D(dx,dy,dz: REAL); + + PROCEDURE ViewPort (r: Rect); + PROCEDURE LookAt (left,top,right,bottom: REAL); + PROCEDURE ViewAngle (angle: REAL); + PROCEDURE Identity; + PROCEDURE Scale (xFactor,yFactor,zFactor: REAL); + PROCEDURE Translate (dx,dy,dz: REAL); + PROCEDURE Pitch (xAngle: REAL); + PROCEDURE Yaw (yAngle: REAL); + PROCEDURE Roll (zAngle: REAL); + PROCEDURE Skew (zAngle: REAL); + PROCEDURE TransForm (src: Point3D; VAR dst: Point3D); + FUNCTION Clip3D (src1,src2: Point3D; VAR dst1,dst2: POINT): BOOLEAN; + + PROCEDURE SetPt3D (VAR pt3D: Point3D; x,y,z: REAL); + PROCEDURE SetPt2D (VAR pt2D: Point2D; x,y: REAL); + + + +IMPLEMENTATION + + + +PROCEDURE Open3DPort(* port: Port3DPtr *); +{ initialize all values in port^ to their defaults } +BEGIN + thePort3D:=port; + port^.GPort:=thePort; + ViewPort(thePort^.portRect); + WITH thePort^.portRect DO LookAt(left,top,right,bottom); + ViewAngle(0); + Identity; + MoveTo3D(0,0,0); +END; + + +PROCEDURE SetPort3D(* port: Port3DPtr *); +{ change to another Port3D } +BEGIN + thePort3D:=port; + SetPort(port^.GPort); +END; + + +PROCEDURE GetPort3D(* VAR port: Port3DPtr *); +{ inquire the current Port3D } +BEGIN + port:=thePort3D; +END; + + +PROCEDURE MoveTo3D(* x,y,z: REAL *); +{ Move from current position to x,y,z without drawing. } +VAR pt1,pt2: POINT; + oldPrime: Point3D; +BEGIN + WITH thePort3D^ DO + BEGIN + oldPrime:=penPrime; + pen.x:=x; + pen.y:=y; + pen.z:=z; + TransForm(pen,penPrime); + IF Clip3D(oldPrime,penPrime,pt1,pt2) THEN MoveTo(pt2.H,pt2.V); + END; +END; + + +PROCEDURE LineTo3D(* x,y,z: REAL *); +{ draw a 3-D line from current position to x,y,z. } +VAR oldPrime: Point3D; + pt1,pt2: POINT; +BEGIN + WITH thePort3D^ DO + BEGIN + oldPrime:=penPrime; + pen.x:=x; + pen.y:=y; + pen.z:=z; + TransForm(pen,penPrime); + IF Clip3D(oldPrime,penPrime,pt1,pt2) THEN + BEGIN + MoveTo(pt1.h,pt1.v); + LineTo(pt2.H,pt2.V); + END; + END; +END; + + +PROCEDURE Move3D(* dx,dy,dz: REAL *); +BEGIN + WITH thePort3D^ DO MoveTo3D(pen.x+dx,pen.y+dy,pen.z+dz); +END; + + +PROCEDURE Line3D(* dx,dy,dz: REAL *); +BEGIN + WITH thePort3D^ DO LineTo3D(pen.x+dx,pen.y+dy,pen.z+dz); +END; + + +PROCEDURE MoveTo2D(* x,y: REAL *); +BEGIN + MoveTo3D(x,y,thePort3D^.pen.z); +END; + + +PROCEDURE Move2D(* dx,dy: REAL *); +BEGIN + Move3D(dx,dy,0.0); +END; + + +PROCEDURE LineTo2D(* x,y: REAL *); +BEGIN + LineTo3D(x,y,thePort3D^.pen.z); +END; + + +PROCEDURE Line2D(* dx,dy: REAL *); +BEGIN + Line3D(dx,dy,0.0); +END; + + +PROCEDURE ViewLook; +{ re-calculate offsets and scales after LookAt or ViewPort } +BEGIN + WITH thePort3D^ DO + WITH viewRect DO + BEGIN + hSize:=(right-left)/2.0; + vSize:=(bottom-top)/(-2.0); { vert pos down, y pos up } + hCenter:=left + hSize; + vCenter:=top - vSize; + END; +END; + + +PROCEDURE ViewPort(* r: Rect *); +{ specify what portion of the folder to map onto } +BEGIN + thePort3D^.viewRect:=r; + ViewLook; { re-calculate scales and offsets } +END; + + +PROCEDURE LookAt(* left,top,right,bottom: REAL *); +{ specify the real number coordinates of the portRect } +BEGIN + WITH thePort3D^ DO + BEGIN + xLeft:=left; + xRight:=right; + yBottom:=bottom; + yTop:=top; + eye.x:=(left+right)/2.0; + eye.y:=(top+bottom)/2.0; + END; + ViewLook; { re-calculate scales and offsets } +END; + + +PROCEDURE ViewAngle(* angle: REAL *); +{ specify the horizontal angle subtended by the viewing pyramid } +BEGIN + WITH thePort3D^ DO + BEGIN + IF angle < 0.1 THEN angle:=0.1; + angle:=angle/(2.0*radConst); { halve angle & convert to rad } + xCotan:=COS(angle)/SIN(angle); { remember for perspective calc } + yCotan:=xCotan * (xRight-xLeft)/(yTop-yBottom); + eye.z:=xCotan * (xRight-xLeft)/2; + END; +END; + + +PROCEDURE TransForm(* src: Point3D; VAR dst: Point3D *); +{ use the current xForm matrix to transform } +{ a 3D source point into a 3D destination point. } +BEGIN + IF thePort3D^.ident THEN dst:=src + ELSE WITH thePort3D^ DO + BEGIN + dst.x:=src.x * xForm[0,0] + src.y * xForm[1,0] + + src.z * xForm[2,0] + xForm[3,0]; + dst.y:=src.x * xForm[0,1] + src.y * xForm[1,1] + + src.z * xForm[2,1] + xForm[3,1]; + dst.z:=src.x * xForm[0,2] + src.y * xForm[1,2] + + src.z * xForm[2,2] + xForm[3,2]; + END; +END; + + +FUNCTION Clip3D(* src1,src2: Point3D; VAR dst1,dst2: POINT *); +{ do full 3D clipping to viewing pyramid and return 2D } +{ screen coords in dst. Function value true if visible. } +LABEL 0; +TYPE Edge=(left,top,right,bottom); + OutCode=SET OF Edge; +VAR c,c1,c2: OutCode; + pt3D: Point3D; + t: REAL; + pt1,pt2: POINT; + + PROCEDURE Code(pt3D: Point3D; VAR c: OutCode); + BEGIN + c:=[]; + IF pt3D.x < -pt3D.z THEN c:=[left] ELSE IF pt3D.x > pt3D.z THEN c:=[right]; + IF pt3D.y < -pt3D.z THEN c:=c+[bottom] ELSE IF pt3D.y > pt3D.z THEN c:=c+[top]; + END; + +BEGIN + Clip3D:=FALSE; + WITH thePort3D^ DO + BEGIN { convert both points into clipping coord system } + src1.x:=(src1.x - eye.x) * xCotan; + src1.y:=(src1.y - eye.y) * yCotan; + src1.z:=eye.z - src1.z; + + src2.x:=(src2.x - eye.x) * xCotan; + src2.y:=(src2.y - eye.y) * yCotan; + src2.z:=eye.z - src2.z; + END; + + + Code(src1,c1); Code(src2,c2); + WHILE c1+c2 <> [] DO + BEGIN + IF c1*c2 <> [] THEN GOTO 0; { both out on same side } + c:=c1; IF c=[] THEN c:=c2; + + IF left IN c THEN { calc intersect with left edge } + BEGIN + t:=(src1.z+src1.x) / ((src1.x-src2.x) - (src2.z-src1.z)); + pt3D.z:=t*(src2.z-src1.z) + src1.z; + pt3D.x:=-pt3D.z; + pt3D.y:=t*(src2.y-src1.y) + src1.y; + END + + ELSE IF right IN c THEN { calc intersect with right edge } + BEGIN + t:=(src1.z-src1.x) / ((src2.x-src1.x) - (src2.z-src1.z)); + pt3D.z:=t*(src2.z-src1.z) + src1.z; + pt3D.x:=pt3D.z; + pt3D.y:=t*(src2.y-src1.y) + src1.y; + END + + ELSE IF bottom IN c THEN { calc intersect with bottom edge } + BEGIN + t:=(src1.z+src1.y) / ((src1.y-src2.y) - (src2.z-src1.z)); + pt3D.z:=t*(src2.z-src1.z) + src1.z; + pt3D.x:=t*(src2.x-src1.x) + src1.x; + pt3D.y:=-pt3D.z; + END + + ELSE IF top IN c THEN { calc intersect with top edge } + BEGIN + t:=(src1.z-src1.y) / ((src2.y-src1.y) - (src2.z-src1.z)); + pt3D.z:=t*(src2.z-src1.z) + src1.z; + pt3D.x:=t*(src2.x-src1.x) + src1.x; + pt3D.y:=pt3D.z; + END; + + IF c=c1 THEN BEGIN src1:=pt3D; Code(src1,c1); END + ELSE BEGIN src2:=pt3D; Code(src2,c2); END; + + END; + + { if we reach here, the line from src1 to src2 is visible } + Clip3D:=TRUE; + WITH thePort3D^ DO + WITH GPort^ DO + BEGIN { convert clip coords to screen coords } + dst1.H:=ROUND(hCenter + hSize * src1.x / src1.z); + dst1.V:=ROUND(vCenter + vSize * src1.y / src1.z); + dst2.H:=ROUND(hCenter + hSize * src2.x / src2.z); + dst2.V:=ROUND(vCenter + vSize * src2.y / src2.z); + END; + +0: END; + + +PROCEDURE Identity; +{ reset the transform matrix to identity } +VAR ROW,COL: INTEGER; +BEGIN; + WITH thePort3D^ DO + BEGIN + FOR ROW:=0 TO 3 DO + FOR COL:=0 TO 3 DO + IF ROW=COL THEN xForm[ROW,COL]:=1.0 + ELSE xForm[ROW,COL]:=0.0; + ident:=TRUE; { SET FLAG SO xForm CAN BE SKIPPED } + END; +END; + + +PROCEDURE Scale(* xFactor,yFactor,zFactor: REAL *); +{ change xForm matrix to provide scaling } +VAR ROW: INTEGER; +BEGIN + WITH thePort3D^ DO + BEGIN + ident:=FALSE; + FOR ROW:=0 TO 3 DO + BEGIN + xForm[ROW,0]:=xForm[ROW,0]*xFactor; + xForm[ROW,1]:=xForm[ROW,1]*yFactor; + xForm[ROW,2]:=xForm[ROW,2]*zFactor; + END; + END; +END; + + +PROCEDURE Translate(* dx,dy,dz: REAL *); +{ change xForm matrix to translate } +BEGIN + WITH thePort3D^ DO + BEGIN + ident:=FALSE; + xForm[3,0]:=xForm[3,0]+dx; + xForm[3,1]:=xForm[3,1]+dy; + xForm[3,2]:=xForm[3,2]+dz; + END; +END; + + +PROCEDURE Pitch(* xAngle: REAL *); +{ change xForm matrix to rotate xAngle degrees around x-Axis } +VAR si,co,TEMP: REAL; +BEGIN + xAngle:=xAngle/radConst; { convert degrees to rads } + si:=SIN(xAngle); co:=COS(xAngle); + WITH thePort3D^ DO + BEGIN + ident:=FALSE; + TEMP:=xForm[0,1]*co+xForm[0,2]*si; + xForm[0,2]:=xForm[0,2]*co-xForm[0,1]*si; xForm[0,1]:=TEMP; + TEMP:=xForm[1,1]*co+xForm[1,2]*si; + xForm[1,2]:=xForm[1,2]*co-xForm[1,1]*si; xForm[1,1]:=TEMP; + TEMP:=xForm[2,1]*co+xForm[2,2]*si; + xForm[2,2]:=xForm[2,2]*co-xForm[2,1]*si; xForm[2,1]:=TEMP; + TEMP:=xForm[3,1]*co+xForm[3,2]*si; + xForm[3,2]:=xForm[3,2]*co-xForm[3,1]*si; xForm[3,1]:=TEMP; + END; +END; + + +PROCEDURE Yaw(* yAngle: REAL *); +{ change xForm matrix to rotate yAngle degrees around y-Axis } +VAR si,co,TEMP: REAL; +BEGIN + yAngle:=yAngle/radConst; { convert degrees to rads } + si:=SIN(yAngle); co:=COS(yAngle); + WITH thePort3D^ DO + BEGIN + ident:=FALSE; + TEMP:=xForm[0,0]*co-xForm[0,2]*si; + xForm[0,2]:=xForm[0,0]*si+xForm[0,2]*co; xForm[0,0]:=TEMP; + TEMP:=xForm[1,0]*co-xForm[1,2]*si; + xForm[1,2]:=xForm[1,0]*si+xForm[1,2]*co; xForm[1,0]:=TEMP; + TEMP:=xForm[2,0]*co-xForm[2,2]*si; + xForm[2,2]:=xForm[2,0]*si+xForm[2,2]*co; xForm[2,0]:=TEMP; + TEMP:=xForm[3,0]*co-xForm[3,2]*si; + xForm[3,2]:=xForm[3,0]*si+xForm[3,2]*co; xForm[3,0]:=TEMP; + END; +END; + + +PROCEDURE Roll(* zAngle: REAL *); +{ change xForm matrix to rotate zAngle degrees around z-Axis } +VAR si,co,TEMP: REAL; +BEGIN + zAngle:=zAngle/radConst; { convert degrees to rads } + si:=SIN(zAngle); co:=COS(zAngle); + WITH thePort3D^ DO + BEGIN + ident:=FALSE; + TEMP:=xForm[0,0]*co+xForm[0,1]*si; + xForm[0,1]:=xForm[0,1]*co-xForm[0,0]*si; xForm[0,0]:=TEMP; + TEMP:=xForm[1,0]*co+xForm[1,1]*si; + xForm[1,1]:=xForm[1,1]*co-xForm[1,0]*si; xForm[1,0]:=TEMP; + TEMP:=xForm[2,0]*co+xForm[2,1]*si; + xForm[2,1]:=xForm[2,1]*co-xForm[2,0]*si; xForm[2,0]:=TEMP; + TEMP:=xForm[3,0]*co+xForm[3,1]*si; + xForm[3,1]:=xForm[3,1]*co-xForm[3,0]*si; xForm[3,0]:=TEMP; + END; +END; + + +PROCEDURE Skew(* zAngle: REAL *); +{ change xForm matrix to skew zAngle degrees around z-Axis } +{ x := (x + y*TAN(zAngle)) zAngle limited to +-90 degrees } +VAR co,TA: REAL; + COL: INTEGER; +BEGIN + zAngle:=zAngle/radConst; { convert degrees to rads } + co:= COS(zAngle); + IF ABS(co) > 1.0E-5 THEN + BEGIN + TA:= SIN(zAngle)/co; + WITH thePort3D^ DO + BEGIN + ident:=FALSE; + FOR COL:=0 TO 2 DO + xForm[1,COL]:=xForm[1,COL]+xForm[0,COL]*TA; + END; + END; +END; + + +PROCEDURE SetPt3D(* VAR pt3D: Point3D; x,y,z: REAL *); +BEGIN + pt3D.x:=x; + pt3D.y:=y; + pt3D.z:=z; +END; + + +PROCEDURE SetPt2D(* VAR pt2D: Point2D; x,y: REAL *); +BEGIN + pt2D.x:=x; + pt2D.y:=y; +END; + + +END. { of Unit } diff --git a/GrafAsm.a b/GrafAsm.a new file mode 100755 index 0000000..1006e71 --- /dev/null +++ b/GrafAsm.a @@ -0,0 +1,507 @@ + .INCLUDE GRAFTYPES.TEXT +;------------------------------------------------------------ +; +; --> GRAFASM.TEXT +; +; Miscellaneous unclassified routines. +; + + + .PROC InitGraf,1 +;-------------------------------------------------- +; +; PROCEDURE InitGraf(globalPtr: Ptr); +; +; +PARAMSIZE .EQU 4 +GLOBALPTR .EQU PARAMSIZE+8-4 ;LONG + + + LINK A6,#0 ;NO LOCALS + MOVE.L A4,-(SP) ;SAVE REG + MOVE.L GLOBALPTR(A6),A4 ;GET POINTER TO QUICKDRAW GLOBALS + MOVE.L A4,GRAFGLOBALS(A5) ;SAVE IN MAGIC LOCATION +; +; new addition 22 Apr 85 +; + CLR.B $8F3 ; set lo-mem flag, QDExist + + LEA lastGrafGlob(A4),A0 ;SET UP START POINTER + LEA thePort+4(A4),A1 ;SET UP LIMIT POINTER +CLRLP CLR.W (A0)+ ;CLEAR A WORD + CMPA.L A1,A0 ;CHECK LIMIT POINTER + BNE CLRLP ;CLEAR ALL GLOBALS + + ;QDSpareD..QDSpare3 = all zeros + ;playIndex := 0 + ;fontPtr = Nil + ;FixTxWid := 0.0 + ;patAlign := (0,0) + ;polyMax := 0 + ;thePoly := Nil + ;QDSpare0 := 0 + ;playPic := Nil + ;rgnMax := 0 + ;rgnIndex := 0 + ;rgnBuf := Nil + LEA wideData(A4),A4 + MOVE.L A4,D0 ;REMEMBER ADDR OF WIDEDATA + MOVE #10,(A4)+ ;wideData.rgnSize := 10 + MOVE.L #$80018001,(A4)+ ;wideData.rgnBBox := + MOVE.L #$7FFF7FFF,(A4)+ ;(-32767,-32767,32767,32767) + MOVE.L A4,D1 ;REMEMBER ADDR OF WIDEMASTER + MOVE.L D0,(A4)+ ;wideMaster := @wideData + MOVE.L D1,(A4)+ ;wideOpen := @wideMaster + MOVEQ #1,D0 + MOVE.L D0,(A4)+ ;randSeed := 1 + MOVE.L A4,-(SP) ;point to screenBits + _GetScrnBits ;fill in screenBits + ADD #14,A4 ;bump past screenBits + MOVEQ #26,D0 ;INIT LOOP COUNT + LEA CURDATA,A0 ;POINT TO CURSOR DATA +CRSRLP MOVE.L (A0)+,(A4)+ ;COPY A LONG INTO GLOBALS + DBRA D0,CRSRLP ;LOOP FOR 27 LONGS + ;thePort := NIL + MOVE.L (SP)+,A4 ;RESTORE REG + UNLINK PARAMSIZE,'INITGRAF' + + +CURDATA .WORD $0000,$4000,$6000,$7000 ;ARROW.DATA + .WORD $7800,$7C00,$7E00,$7F00 + .WORD $7F80,$7C00,$6C00,$4600 + .WORD $0600,$0300,$0300,$0000 + + .WORD $C000,$E000,$F000,$F800 ;ARROW.MASK + .WORD $FC00,$FE00,$FF00,$FF80 + .WORD $FFC0,$FFE0,$FE00,$EF00 + .WORD $CF00,$8780,$0780,$0380 + + .WORD $0001,$0001 ;ARROW.HOTSPOT := (1,1) + + .LONG $77DD77DD,$77DD77DD ;dkGray + .LONG $88228822,$88228822 ;ltGray + .LONG $AA55AA55,$AA55AA55 ;gray + .LONG $FFFFFFFF,$FFFFFFFF ;black + .LONG $00000000,$00000000 ;white + + + + .PROC OpenPort,1 + .REF NewRgn +;------------------------------------------------------------- +; +; PROCEDURE OpenPort(port: GrafPtr); +; { allocate clipRgn and visRgn, then call InitPort. +; + CLR.L -(SP) ;MAKE ROOM FOR FUNCTION RESULT + JSR NEWRGN ;ALLOCATE A NEW REGION + CLR.L -(SP) ;MAKE ROOM FOR FUNCTION RESULT + JSR NEWRGN ;ALLOCATE A SECOND NEW REGION + MOVE.L 12(SP),A0 ;POINT TO PORT + MOVE.L (SP)+,CLIPRGN(A0) ;INSTALL NEW REGION INTO CLIPRGN + MOVE.L (SP)+,VISRGN(A0) ;AND OTHER INTO VISRGN + ;FALL THRU TO InitPort + + + .PROC InitPort,1 + .REF RectRgn,CopyRgn +;------------------------------------------------------------- +; +; PROCEDURE InitPort(port: GrafPtr); +; +; { initialize all fields of an existing GrafPort } +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L 4(SP),A1 ;GET PORT PARAM + MOVE.L A1,THEPORT(A0) ;SetPort(port) + CLR.W (A1)+ ;DEVICE := 0 + LEA SCREENBITS(A0),A0 ;POINT TO SCREENBITS + MOVE.L (A0)+,(A1)+ ;portBits := screenBits + MOVE.W (A0)+,(A1)+ ;COPY ROWBYTES + MOVE.L (A0),(A1)+ ;COPY TOPLEFT + MOVE.L 4(A0),(A1)+ ;COPY BOTRIGHT + MOVE.L (A0),(A1)+ ;portRect := screenBits.bounds + MOVE.L 4(A0),(A1)+ ;all 8 bytes + MOVE.L (A1)+,-(SP) ;visRgn := screenBits.bounds + MOVE.L A0,-(SP) + JSR RECTRGN + MOVE.L 4(SP),A1 ;GET PORT PARAM + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L WIDEOPEN(A0),-(SP) ;PUSH WIDE OPEN RGN + MOVE.L CLIPRGN(A1),-(SP) ;PUSH CLIPRGN + JSR COPYRGN ;SET TO WIDE OPEN + MOVE.L 4(SP),A1 ;GET PORT PARAM + LEA BKPAT(A1),A1 + CLR.L (A1)+ ;bkPat := white + CLR.L (A1)+ + MOVEQ #-1,D0 + MOVE.L D0,(A1)+ ;fillPat := Black + MOVE.L D0,(A1)+ + CLR.L (A1)+ ;pnLoc := (0,0) + MOVE.L #$00010001,(A1)+ ;pnSize := (1,1) + MOVE #8,(A1)+ ;pnMode := patCopy + MOVE.L D0,(A1)+ ;pnPat := black + MOVE.L D0,(A1)+ + CLR.W (A1)+ ;pnVis := 0 + CLR.L (A1)+ ;txFont, txFace := 0 + MOVE #1,(A1)+ ;txMode := srcOr + CLR (A1)+ ;txSize := 0 + CLR.L (A1)+ ;spExtra := 0.0 + MOVE.L #blackColor,(A1)+ ;fgColor := blackColor + MOVE.L #whiteColor,(A1)+ ;bkColor := whiteColor + CLR.L (A1)+ ;colrBit,patStretch := 0 + CLR.L (A1)+ ;picSave := Nil + CLR.L (A1)+ ;rgnSave := Nil + CLR.L (A1)+ ;polySave := Nil + CLR.L (A1)+ ;grafProcs := Nil + MOVE.L (SP)+,(SP) ;STRIP PARAM + RTS ;AND RETURN + + + + .PROC ClosePort,1 +;------------------------------------------------------------- +; +; PROCEDURE ClosePort(port: GrafPtr); +; +; { just disposes of clipRgn and visRgn } +; + MOVE.L 4(SP),A0 ;GET PORT + MOVE.L CLIPRGN(A0),A0 ;GET CLIPRGN HANDLE + _DisposHandle ;DISCARD IT + MOVE.L 4(SP),A0 ;GET PORT + MOVE.L VISRGN(A0),A0 ;GET VISRGN HANDLE + _DisposHandle ;DISCARD IT + MOVE.L (SP)+,(SP) ;STRIP PARAM + RTS ;AND RETURN + + + .PROC SetStdProcs,1 + .REF StdText,StdLine,StdRect,StdRRect,StdOval,StdArc,StdPoly + .REF StdRgn,StdBits,StdComment,StdTxMeas,StdGetPic,StdPutPic +;------------------------------------------------------------- +; +; PROCEDURE SetStdProcs(VAR procs: QDProcs); +; + MOVE.L 4(SP),A1 ;GET ADDRESS OF PROC RECORD + LEA StdText,A0 + MOVE.L A0,(A1)+ + LEA StdLine,A0 + MOVE.L A0,(A1)+ + LEA StdRect,A0 + MOVE.L A0,(A1)+ + LEA StdRRect,A0 + MOVE.L A0,(A1)+ + LEA StdOval,A0 + MOVE.L A0,(A1)+ + LEA StdArc,A0 + MOVE.L A0,(A1)+ + LEA StdPoly,A0 + MOVE.L A0,(A1)+ + LEA StdRgn,A0 + MOVE.L A0,(A1)+ + LEA StdBits,A0 + MOVE.L A0,(A1)+ + LEA StdComment,A0 + MOVE.L A0,(A1)+ + LEA StdTxMeas,A0 + MOVE.L A0,(A1)+ + LEA StdGetPic,A0 + MOVE.L A0,(A1)+ + LEA StdPutPic,A0 + MOVE.L A0,(A1)+ + MOVE.L (SP)+,(SP) ;STRIP PARAM + RTS ;AND RETURN + + + + .PROC LocalToGlobal,1 + .DEF GlobalToLocal,AddPt,SubPt,SetPort,GetPort +;------------------------------------------------------------- +; +; PROCEDURE LocalToGlobal(VAR pt: Point); +; +; restores all registers. +; + MOVEM.L D0-D2/A0/A1,-(SP) ;SAVE REGS + MOVE.L #1,D2 ;INDICATE SUB + BRA.S SHARE + + + +;------------------------------------------------------------- +; +; PROCEDURE GlobalToLocal(VAR pt: Point); +; +; restores all registers. +; +GlobalToLocal + MOVEM.L D0-D2/A0/A1,-(SP) ;SAVE REGS + MOVE.L #0,D2 ;INDICATE ADD +SHARE MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;POINT TO CURRENT GRAFPORT + MOVE.L 24(SP),A1 ;POINT TO VAR PT + MOVE PORTBITS+BOUNDS+TOP(A0),D0 ;GET DV + MOVE PORTBITS+BOUNDS+LEFT(A0),D1 ;GET DH + BSR.S ADDSUB ;CONVERT TO LOCAL + MOVEM.L (SP)+,D0-D2/A0/A1 ;RESTORE REGS + BRA.S SHARE3 ;STRIP 4 BYTES AND RETURN +; +; +; +ADDSUB TST D2 + BEQ.S JUSTADD + NEG D0 + NEG D1 +JUSTADD ADD D0,(A1)+ + ADD D1,(A1)+ + RTS + + + +;------------------------------------------------------------- +; +; PROCEDURE AddPt(src: Point; VAR dst: Point); +; { add two points together, restores all regs } +; +AddPt MOVEM.L D0-D2/A1,-(SP) ;SAVE REGS + MOVE.L #0,D2 ;INDICATE ADD + BRA.S SHARE2 + + + +;------------------------------------------------------------- +; +; PROCEDURE SubPt(src: Point; VAR dst: Point); +; { subtract src Point from dst point, restores all regs } +; +SubPt MOVEM.L D0-D2/A1,-(SP) ;SAVE REGS + MOVE.L #1,D2 ;INDICATE SUB +SHARE2 MOVE.L 20(SP),A1 ;POINT TO DST + MOVE 24+V(SP),D0 ;GET SRC.V + MOVE 24+H(SP),D1 ;GET SRC.H + BSR.S ADDSUB + MOVEM.L (SP)+,D0-D2/A1 ;RESTORE REGS + MOVE.L (SP)+,(SP) +SHARE3 MOVE.L (SP)+,(SP) + RTS ;AND RETURN + + + +;---------------------------------------------------------- +; +; PROCEDURE SetPort(gp: GrafPtr); +; { switch the current port to a different GrafPort } +; +SetPort MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L 4(SP),THEPORT(A0) ;INSTALL INTO THEPORT + BRA.S SHARE3 ;STRIP 4 BYTES AND RETURN + + + +;---------------------------------------------------------- +; +; PROCEDURE GetPort(VAR gp: GrafPtr); +; { inquire the current GrafPort } +; +GetPort MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L 4(SP),A1 ;POINT TO VAR GP + MOVE.L THEPORT(A0),(A1) ;COPY FROM THEPORT + BRA.S SHARE3 ;STRIP 4 BYTES AND RETURN + + + + .PROC GrafDevice,1 + .REF PortWord +;---------------------------------------------------------- +; +; PROCEDURE GrafDevice(device: INTEGER); +; + MOVEQ #DEVICE,D0 ;PUT PORT OFFSET IN D0 + JMP PORTWORD ;INSTALL PARAM INTO THEPORT + + + + .PROC SetPortBits,1 + .DEF BackPat +;---------------------------------------------------------- +; +; PROCEDURE SetPortBits(bm: BitMap); +; { re-direct output to a different BitMap } +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA PORTBITS(A0),A0 ;POINT TO PORTBITS + MOVE.L 4(SP),A1 ;POINT TO BITMAP + MOVE.L (A1)+,(A0)+ ;COPY BASEADDR + MOVE.W (A1)+,(A0)+ ;COPY ROWBYTES +SHARE MOVE.L (A1)+,(A0)+ ;COPY BOUNDS.TOPLEFT + MOVE.L (A1)+,(A0)+ ;COPY BOUNDS.BOTRIGHT + MOVE.L (SP)+,(SP) ;STRIP 4 BYTES + RTS ;AND RETURN + + + +;---------------------------------------------------------- +; +; PROCEDURE BackPat(pat: Pattern); +; { set the background pattern } +; +BackPat MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA BKPAT(A0),A0 ;POINT TO BKPAT + MOVE.L 4(SP),A1 ;GET ADDR OF PATTERN + BRA.S SHARE + + + + .PROC PortSize,2 +;---------------------------------------------------------- +; +; PROCEDURE PortSize(width,height: INTEGER); +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE PORTRECT+LEFT(A0),D0 ;GET PORTRECT.LEFT + ADD 6(SP),D0 ;ADD WIDTH + MOVE D0,PORTRECT+RIGHT(A0) ;UPDATE PORTRECT.RIGHT + MOVE PORTRECT+TOP(A0),D0 ;GET PORTRECT.TOP + ADD 4(SP),D0 ;ADD HEIGHT + MOVE D0,PORTRECT+BOTTOM(A0) ;UPDATE PORTRECT.BOTTOM + MOVE.L (SP)+,(SP) ;STRIP 4 BYTES + RTS ;AND RETURN + + + + .PROC MovePortTo,2 + .DEF SetOrigin,ClipRect + .REF OffsetRgn,RectRgn +;---------------------------------------------------------- +; +; PROCEDURE MovePortTo(leftGlobal,topGlobal: INTEGER); +; { move portRect to a different part of the bitmap } +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE PORTRECT+LEFT(A0),D0 ;GET PORTRECT.LEFT + SUB PORTBITS+BOUNDS+LEFT(A0),D0 ;CONVERT TO GLOBAL + SUB 6(SP),D0 ;SUB LEFTGLOBAL FOR DH + MOVE PORTRECT+TOP(A0),D1 ;GET PORTRECT.TOP + SUB PORTBITS+BOUNDS+TOP(A0),D1 ;CONVERT TO GLOBAL + SUB 4(SP),D1 ;SUB TOPGLOBAL FOR DV + MOVE.L (SP)+,(SP) ;STRIP 4 BYTES +OFSPORT LEA PORTBITS+BOUNDS(A0),A0 ;OFFSET PORTBITS.BOUNDS DH,DV +OFSRECT ADD D1,(A0)+ ;OFFSET TOP + ADD D0,(A0)+ ;OFFSET LEFT + ADD D1,(A0)+ ;OFFSET BOTTOM + ADD D0,(A0)+ ;OFFSET RIGHT + RTS ;AND RETURN + + + +;---------------------------------------------------------- +; +; PROCEDURE SetOrigin(h,v: INTEGER); +; { re-define the local coords by adjusting portBits.bounds, } +; { portRect, and visRgn } +; +SetOrigin + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L 4(SP),D0 ;GET V AND H BOTH + CMP.L PORTRECT+TOPLEFT(A0),D0 ;SAME AS ALREADY IN THEPORT ? + BEQ.S DONE ;YES, QUIT + MOVE 6(SP),D0 ;GET H + SUB PORTRECT+LEFT(A0),D0 ;DH:=H-PORTRECT.LEFT + MOVE 4(SP),D1 ;GET V + SUB PORTRECT+TOP(A0),D1 ;DV:=V-PORTRECT.TOP + MOVE.L VISRGN(A0),-(SP) ;PUSH PARMS FOR LATER + MOVE D0,-(SP) + MOVE D1,-(SP) + BSR.S OFSPORT ;OFFSET PORTBITS.BOUNDS + LEA PORTRECT-PORTBITS-BOUNDS-8(A0),A0 ;POINT A0 AT PORTRECT + BSR.S OFSRECT ;OFFSET PORTRECT + JSR OFFSETRGN +DONE MOVE.L (SP)+,(SP) ;STRIP 4 BYTES + RTS ;AND RETURN + + + +;---------------------------------------------------------- +; +; PROCEDURE ClipRect(r: Rect); +; { Make the current grafport's clipRgn match a given rectangle } +; +ClipRect + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L CLIPRGN(A0),-(SP) ;PUSH CLIPRGN + MOVE.L 8(SP),-(SP) ;PUCH ADDR OF RECT + JSR RECTRGN + BRA.S DONE + + + + .PROC SetClip,1 + .DEF GetClip + .REF CopyRgn +;---------------------------------------------------------- +; +; PROCEDURE SetClip(rgn: RgnHandle); +; +; copy rgn into theport^.clipRgn +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A1 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A1),A1 ;GET CURRENT GRAFPORT + MOVE.L CLIPRGN(A1),-(SP) ;PUSH THEPORT^.CLIPRGN + BRA.S SHARE + + + +;---------------------------------------------------------- +; +; PROCEDURE GetClip(rgn: RgnHandle); +; +; copy from theport^.clipRgn into rgn. +; +GetClip + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D0 ;POP RGN HANDLE + MOVE.L GRAFGLOBALS(A5),A1 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A1),A1 ;GET CURRENT GRAFPORT + MOVE.L CLIPRGN(A1),-(SP) ;PUSH THEPORT^.CLIPRGN + MOVE.L D0,-(SP) ;PUSH RGN +SHARE MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + JMP COPYRGN ;AND GO TO COPYRGN + + + + .PROC SetPt,3 +;------------------------------------------------------------- +; +; PROCEDURE SetPt(VAR pt: Point; h,v: INTEGER); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D0 ;POP H,V + MOVE.L (SP)+,A1 ;POP VAR ADDR OF PT + MOVE.L D0,(A1) ;STORE H,V INTO PT + JMP (A0) ;RETURN + + + .FUNC EqualPt,2 +;---------------------------------------------------------- +; +; FUNCTION EqualPt(pt1,pt2: Point): BOOLEAN; +; +; CLOBBERS D0,A0. +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D0 ;pop point1 + CMP.L (SP)+,D0 ;is point2 = point1 ? + SEQ (SP) ;IF YES, SET TO TRUE + NEG.B (SP) ;CONVERT -1 TO 1 + JMP (A0) ;RETURN + + + .END diff --git a/GrafTypes.a b/GrafTypes.a new file mode 100755 index 0000000..8081d9b --- /dev/null +++ b/GrafTypes.a @@ -0,0 +1,375 @@ +;----------------------------------------------------------------- +; +; --> GRAFTYPES.TEXT +; +; QUICKDRAW TYPE DECLARATIONS, USED BY ALL GRAPHICS ROUTINES +; +NIL .EQU 0 ;IMPLEMENTATION VALUE OF NIL + + +;----------------------------------------------- +; +; QuickDraw VERBS: +; +FRAME .EQU 0 +PAINT .EQU 1 +ERASE .EQU 2 +INVERT .EQU 3 +FILL .EQU 4 + + +;----------------------------------------------- +; +; QuickDraw transfer MODES: +; +srcCopy .EQU 0 +srcOr .EQU 1 +srcXor .EQU 2 +srcBic .EQU 3 +notSrcCopy .EQU 4 +notSrcOr .EQU 5 +notSrcXor .EQU 6 +notSrcBic .EQU 7 +patCopy .EQU 8 +patOr .EQU 9 +patXor .EQU 10 +patBic .EQU 11 +notPatCopy .EQU 12 +notPatOr .EQU 13 +notPatXor .EQU 14 +notPatBic .EQU 15 + + +;----------------------------------------------- +; +; QuickDraw Color Separation: +; +normalBit .EQU 0 ;normal screen mapping +inverseBit .EQU 1 ;inverse screen mapping +redBit .EQU 4 ;RGB additive mapping +greenBit .EQU 3 ;for photos from screen +blueBit .EQU 2 +cyanBit .EQU 8 ;CMYBk subtractive mapping +magentaBit .EQU 7 ;for ink jet printer +yellowBit .EQU 6 +blackBit .EQU 5 + +blackColor .EQU 33 +whiteColor .EQU 30 +redColor .EQU 205 +greenColor .EQU 341 +blueColor .EQU 409 +cyanColor .EQU 273 +magentaColor .EQU 137 +yellowColor .EQU 69 + + + +;----------------------------------------------- +; +; OFFSETS WITHIN A POINT: +; +V .EQU 0 ;WORD +H .EQU 2 ;WORD + + +;----------------------------------------------- +; +; OFFSETS WITHIN A RECT: +; +TOPLEFT .EQU 0 ;POINT +BOTRIGHT .EQU 4 ;POINT + +TOP .EQU 0 ;INTEGER +LEFT .EQU 2 ;INTEGER +BOTTOM .EQU 4 ;INTEGER +RIGHT .EQU 6 ;INTEGER + + +;----------------------------------------------- +; +; OFFSETS WITHIN A BITMAP: +; +BASEADDR .EQU 0 ;LONG +ROWBYTES .EQU 4 ;WORD +BOUNDS .EQU 6 ;RECT + + +;----------------------------------------------- +; +; OFFSETS WITHIN A CURSOR: +; +DATA .EQU 0 ;16 WORDS +MASK .EQU 32 ;16 WORDS +HOTSPOT .EQU 64 ;POINT + + + +;----------------------------------------------- +; +; OFFSETS WITHIN A POLYGON: +; +POLYSIZE .EQU 0 ;WORD, TOTAL BYTES +POLYBBOX .EQU 2 ;RECT +POLYPOINTS .EQU 10 ;ARRAY[0..0] OF Point + + +;----------------------------------------------- +; +; OFFSETS WITHIN A REGION: +; +RGNSIZE .EQU 0 ;WORD, TOTAL BYTES +RGNBBOX .EQU 2 ;RECT +RGNDATA .EQU 10 ;START OF RGN DATA + + +;----------------------------------------------- +; +; OFFSETS WITHIN A PICTURE: +; +PICSIZE .EQU 0 ;WORD, TOTAL BYTES +PICFRAME .EQU 2 ;RECT +PICDATA .EQU 10 ;START OF BYTE CODES + + +;----------------------------------------------- +; +; OFFSETS WITHIN QDProcs RECORD: +; +textProc .EQU 0 ;PROCPTR +lineProc .EQU textProc+4 ;PROCPTR +rectProc .EQU lineProc+4 ;PROCPTR +rRectProc .EQU rectProc+4 ;PROCPTR +ovalProc .EQU rRectProc+4 ;PROCPTR +arcProc .EQU ovalProc+4 ;PROCPTR +polyProc .EQU arcProc+4 ;PROCPTR +rgnProc .EQU polyProc+4 ;PROCPTR +bitsProc .EQU rgnProc+4 ;PROCPTR +commentProc .EQU bitsProc+4 ;PROCPTR +txMeasProc .EQU commentProc+4 ;PROCPTR +getPicProc .EQU txMeasProc+4 ;PROCPTR +putPicProc .EQU getPicProc+4 ;PROCPTR + + + +;----------------------------------------------- +; +; OFFSETS WITHIN A GRAFPORT: +; +device .EQU 0 ;WORD +portBits .EQU device+2 ;BITMAP +portRect .EQU portBits+14 ;RECT +visRgn .EQU portRect+8 ;RGNPTR +clipRgn .EQU visRgn+4 ;RGNPTR +bkPat .EQU clipRgn+4 ;PATTERN +fillPat .EQU bkPat+8 ;PATTERN +pnLoc .EQU fillPat+8 ;POINT +pnSize .EQU pnLoc+4 ;POINT +pnMode .EQU pnSize+4 ;WORD +pnPat .EQU pnMode+2 ;PATTERN +pnVis .EQU pnPat+8 ;WORD +txFont .EQU pnVis+2 ;WORD +txFace .EQU txFont+2 ;WORD +txMode .EQU txFace+2 ;WORD +txSize .EQU txMode+2 ;WORD +spExtra .EQU txSize+2 ;Fixed Point +fgColor .EQU spExtra+4 ;LONG +bkColor .EQU fgColor+4 ;LONG +colrBit .EQU bkColor+4 ;WORD +patStretch .EQU colrBit+2 ;WORD +picSave .EQU patStretch+2 ;handle +rgnSave .EQU picSave+4 ;handle +polySave .EQU rgnSave+4 ;handle +grafProcs .EQU polySave+4 ;Pointer +PORTREC .EQU grafProcs+4 ;SIZE OF A GRAFPORT +PORTBOUNDS .EQU PORTBITS+BOUNDS + + +;----------------------------------------------------- +; +; OFFSETS IN A REGION STATE RECORD: +; +RGNPTR .EQU 0 ;LONG +DATAPTR .EQU RGNPTR+4 ;LONG +SCANBUF .EQU DATAPTR+4 ;LONG +SCANSIZE .EQU SCANBUF+4 ;WORD +THISV .EQU SCANSIZE+2 ;WORD +NEXTV .EQU THISV+2 ;WORD +MINH .EQU NEXTV+2 ;WORD +MAXH .EQU MINH+2 ;WORD +LEFTH .EQU MAXH+2 ;WORD +RGNREC .EQU LEFTH+2 ;SIZE OF A REGION RECORD + + +;----------------------------------------------------- +; +; Offsets in a PicSave record: +; +thePic .EQU 0 ;PICHANDLE +picMax .EQU thePic+4 ;LongInt +picIndex .EQU picMax+4 ;LongInt +picClipRgn .EQU picIndex+4 ;RgnHandle +picBkPat .EQU picClipRgn+4 ;Pattern +picTxFont .EQU picBkPat+8 ;WORD +picTxFace .EQU picTxFont+2 ;Style +picTxMode .EQU picTxFace+2 ;WORD +picTxSize .EQU picTxMode+2 ;WORD +picSpExtra .EQU picTxSize+2 ;Fixed Point +picTxNumer .EQU picSpExtra+4 ;Point +picTxDenom .EQU picTxNumer+4 ;Point +picTxLoc .EQU picTxDenom+4 ;Point +picPnLoc .EQU picTxLoc+4 ;Point +picPnSize .EQU picPnLoc+4 ;Point +picPnMode .EQU picPnSize+4 ;WORD +picPnPat .EQU picPnMode+2 ;Pattern +picFillPat .EQU picPnPat+8 ;Pattern +picTheRect .EQU picFillPat+8 ;Rect +picOvSize .EQU picTheRect+8 ;Point +picOrigin .EQU picOvSize+4 ;Point +picFgColor .EQU picOrigin+4 ;Long +picBkColor .EQU picFgColor+4 ;Long + +picSaveRec .EQU picBkColor+4 ;total size in bytes + + +;----------------------------------------------------- +; +; QuickDraw GLOBAL VARIABLES: +; +; 52(A5) CONTAINS A POINTER TO THEPORT. +; ALL OTHER GLOBAL VARIABLES ARE EXPRESSED RELATIVE TO THEPORT. +; +GRAFGLOBALS .EQU 0 ;A5 OFFSET TO GLOBALPTR + + +;----------------------------------------------------------- +; +; QuickDraw PUBLIC GLOBAL VARIABLES: +; +thePort .EQU 0 ;GrafPtr +white .EQU thePort-8 ;Pattern +black .EQU white-8 ;Pattern +gray .EQU black-8 ;Pattern +ltGray .EQU gray-8 ;Pattern +dkGray .EQU ltGray-8 ;Pattern +arrow .EQU dkGray-68 ;Cursor +screenBits .EQU arrow-14 ;BitMap +randSeed .EQU screenBits-4 ;LONGINT + + +;------------------------------------------------------------ +; +; QuickDraw private global variables: +; +wideOpen .EQU randSeed-4 ;RgnHandle +wideMaster .EQU wideOpen-4 ;RgnPtr +wideData .EQU wideMaster-10 ;Fake Region +rgnBuf .EQU wideData-4 ;PointsHandle +rgnIndex .EQU rgnBuf-2 ;INTEGER +rgnMax .EQU rgnIndex-2 ;INTEGER +playPic .EQU rgnMax-4 ;Long +QDSpare0 .EQU playPic-2 ;unused word +thePoly .EQU QDSpare0-4 ;POLYHANDLE +polyMax .EQU thePoly-2 ;INTEGER +patAlign .EQU polyMax-4 ;Point +fixTxWid .EQU patAlign-4 ;Fixed Point +fontPtr .EQU fixTxWid-4 ;long, ^FMOutput record +playIndex .EQU fontPtr-4 ;long +QDSpare3 .EQU playIndex-2 ;unused word +QDSpare4 .EQU QDSpare3-2 ;unused word +QDSpare5 .EQU QDSpare4-2 ;unused word +QDSpare6 .EQU QDSpare5-2 ;unused word +QDSpare7 .EQU QDSpare6-2 ;unused word +QDSpare8 .EQU QDSpare7-2 ;unused word +QDSpare9 .EQU QDSpare8-2 ;unused word +QDSpareA .EQU QDSpare9-2 ;unused word +QDSpareB .EQU QDSpareA-2 ;unused word +QDSpareC .EQU QDSpareB-2 ;unused word +QDSpareD .EQU QDSpareC-2 ;unused word +lastGrafGlob .EQU QDSpareD +grafSize .EQU 4-lastGrafGlob ;total size in bytes + + + + .MACRO UNLINK +;-------------------------------------------------------------- +; +; UNLINK A6, STRIP PARAMETERS, AND RETURN. +; +; FIRST PARAM IS NUMBER OF BYTES OF STACK BIAS. +; + UNLK A6 ;RELEASE LOCAL VARIABLES + + .IF %1=0 ;NO PARAMETERS ? + RTS ;THEN JUST RTS + + .ELSE + .IF %1=4 ;4 BYTES OF PARAMS ? + MOVE.L (SP)+,(SP) ;YES, STRIP AND ADJUST RET ADDR + RTS + + .ELSE ;NOT 0 OR 4 BYTES OF PARAMS + MOVE.L (SP)+,A0 ;POP RETURN ADDR INTO A0 + ADD #%1,SP ;STRIP PARAMETERS + JMP (A0) ;JUMP THRU A0 TO RETURN + .ENDC + .ENDC + + .ENDM + + + +;---------------------------------------------- +; +; Trap Macros used by QuickDraw: +; + + .MACRO _LongMul + .WORD $A867 + .ENDM + + .MACRO _FixMul + .WORD $A868 + .ENDM + + .MACRO _FixRatio + .WORD $A869 + .ENDM + + .MACRO _NewHandle + .WORD $A122 + .ENDM + + .MACRO _DisposHandle + .WORD $A023 + .ENDM + + .MACRO _SetHandleSize + .WORD $A024 + .ENDM + + .MACRO _GetHandleSize + .WORD $A025 + .ENDM + + .MACRO _HLock + .WORD $A029 + .ENDM + + .MACRO _HUnlock + .WORD $A02A + .ENDM + + .MACRO _GetScrnBits + .WORD $A833 ;new trap number + .ENDM + + .MACRO _StackAvail + MOVE.L SP,D0 ;copy stack pointer + SUB.L $114,D0 ;subtract HeapEnd for stack avail + .ENDM + + .MACRO _SwapFont + MOVE.L $8E0,A0 ;get pointer to FMSwapFont + JSR (A0) ;call font manager + .ENDM diff --git a/GrafUtil.p b/GrafUtil.p new file mode 100755 index 0000000..b9c859a --- /dev/null +++ b/GrafUtil.p @@ -0,0 +1,47 @@ +UNIT GrafUtil; + +INTERFACE + +USES {$U obj:QuickDraw } QuickDraw; + +TYPE Fixed = LongInt; + Int64Bit = RECORD + hiLong: LongInt; + loLong: LongInt; + END; + +FUNCTION BitAnd (long1,long2: LongInt): LongInt; +FUNCTION BitOr (long1,long2: LongInt): LongInt; +FUNCTION BitXor (long1,long2: LongInt): LongInt; +FUNCTION BitNot (long: LongInt): LongInt; +FUNCTION BitShift (long: LongInt; count: INTEGER): LongInt; +FUNCTION BitTst (bytePtr: QDPtr; bitNum: LongInt): BOOLEAN; +PROCEDURE BitSet (bytePtr: QDPtr; bitNum: LongInt); +PROCEDURE BitClr (bytePtr: QDPtr; bitNum: LongInt); +PROCEDURE LongMul (a,b: LongInt; VAR dst: Int64Bit); +FUNCTION FixMul (a,b: Fixed): Fixed; +FUNCTION FixRatio (numer,denom: INTEGER): Fixed; +FUNCTION HiWord (x: Fixed): INTEGER; +FUNCTION LoWord (x: Fixed): INTEGER; +FUNCTION FixRound (x: Fixed): INTEGER; + + +IMPLEMENTATION + +FUNCTION BitAnd; EXTERNAL; +FUNCTION BitOr; EXTERNAL; +FUNCTION BitXor; EXTERNAL; +FUNCTION BitNot; EXTERNAL; +FUNCTION BitShift; EXTERNAL; +FUNCTION BitTst; EXTERNAL; +PROCEDURE BitSet; EXTERNAL; +PROCEDURE BitClr; EXTERNAL; +PROCEDURE LongMul; EXTERNAL; +FUNCTION FixMul; EXTERNAL; +FUNCTION FixRatio; EXTERNAL; +FUNCTION HiWord; EXTERNAL; +FUNCTION LoWord; EXTERNAL; +FUNCTION FixRound; EXTERNAL; + + +END. { of unit } diff --git a/LCursor.a b/LCursor.a new file mode 100755 index 0000000..2067db4 --- /dev/null +++ b/LCursor.a @@ -0,0 +1,122 @@ + .INCLUDE GRAFTYPES.TEXT + +;------------------------------------------------------------------ +; +; --> LCURSOR.TEXT +; +; Links to MacIntosh Cursor routines. +; +; System Graphic Jump Vectors: +; +; Long pointers to system routine entry points. +; +GRAFBEGIN .EQU $800 ;GRAF GLOBAL AREA +JHIDECURSOR .EQU GRAFBEGIN +JSHOWCURSOR .EQU JHIDECURSOR+4 +JSHIELDCURSOR .EQU JSHOWCURSOR+4 +JSCRNADDR .EQU JSHIELDCURSOR+4 ;not used (see _GetScrnBits) +JSCRNSIZE .EQU JSCRNADDR+4 ;not used (see _GetScrnBits) +JINITCRSR .EQU JSCRNSIZE+4 +JSETCRSR .EQU JINITCRSR+4 +JCRSROBSCURE .EQU JSETCRSR+4 + + + + + .PROC InitCursor,0 + .REF SetCursor +;---------------------------------------------------------- +; +; PROCEDURE InitCursor; +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + PEA ARROW(A0) ;PUSH ADDR OF ARROW + JSR SETCURSOR ;INSTALL ARROW CURSOR + MOVE.L JInitCrsr,A0 ;get lo mem pointer + JMP (A0) ;and call it + + + + .PROC SetCursor,1 +;--------------------------------------------------- +; +; PROCEDURE SetCursor(crsr: Cursor); +; + MOVE.L 4(SP),A0 ;Point to Cursor + MOVE.L HOTSPOT+V(A0),-(SP) ;PUSH HOTX & HOTY + MOVE #16,-(SP) ;HEIGHT:=16 + PEA DATA(A0) ;PUSH ADDR OF DATA + PEA MASK(A0) ;PUSH ADDR OF MASK + MOVE.L JSetCrsr,A0 ;get lo mem vector + JSR (A0) ;call vector + MOVE.L (SP)+,(SP) ;strip param + RTS ;and return + + + + .PROC HideCursor,0 +;--------------------------------------------------------- +; +; PROCEDURE HideCursor; +; +; ALL REGS PRESERVED. +; + MOVE.L JHideCursor,-(SP) ;get lo mem vector + RTS ;and call it + + + + .PROC ShowCursor,0 +;--------------------------------------------------------- +; +; PROCEDURE ShowCursor; +; +; ALL REGS PRESERVED. +; + MOVE.L JShowCursor,-(SP) ;get lo mem vector + RTS ;and call it + + + + .PROC ShieldCursor,2 +;--------------------------------------------------------- +; +; PROCEDURE ShieldCursor(shieldRect: Rect; offset: Point); +; +; ALL REGS PRESERVED. +; + MOVEM.L D0-D3/A0-A1,-(SP) ;SAVE REGS + MOVE.L 32(SP),A0 ;POINT TO SHIELDRECT + MOVEM.W (A0)+,D0/D1/D2/D3 ;GET TOP ... RIGHT + LEA 28(SP),A1 + SUB (A1),D0 ;TOP - OFFSET.V + SUB (A1)+,D2 ;BOTTOM - OFFSET.V + SUB (A1),D1 ;LEFT - OFFSET.H + SUB (A1),D3 ;RIGHT - OFFSET.H + MOVE D1,-(SP) ;PUSH GLOBAL LEFT + MOVE D0,-(SP) ;PUSH GLOBAL TOP + MOVE D3,-(SP) ;PUSH GLOBAL RIGHT + MOVE D2,-(SP) ;PUSH GLOBAL BOTTOM + MOVE.L JShieldCursor,A0 ;get lo mem vector + JSR (A0) ;and call it + MOVEM.L (SP)+,D0-D3/A0-A1 ;RESTORE REGS + MOVE.L (SP)+,(SP) + MOVE.L (SP)+,(SP) ;STRIP 8 BYTES + RTS ;AND RETURN + + + + .PROC ObscureCursor,0 +;--------------------------------------------------------- +; +; PROCEDURE ObscureCursor; +; +; Hide the cursor image until the next time the mouse moves. +; + MOVE.L JCrsrObscure,A0 ;get lo mem vector + JMP (A0) ;and call it + + + + + .END diff --git a/Lines.a b/Lines.a new file mode 100755 index 0000000..36d40bf --- /dev/null +++ b/Lines.a @@ -0,0 +1,347 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------------- +; +; +; * *** * * ***** *** +; * * * * * * * +; * * ** * * * +; * * * * * *** *** +; * * * ** * * +; * * * * * * * +; ***** *** * * ***** *** +; +; +; +; Line Drawing Rountines +; + + + .PROC StdLine,1 + .REF CheckPic,PutPicVerb,PutPicByte,PutPicLong,DoLine +;--------------------------------------------------------------- +; +; PROCEDURE StdLine(newPt: Point); +; +PARAMSIZE .EQU 4 +NEWPT .EQU PARAMSIZE+8-4 + + LINK A6,#0 ;NO LOCAL VARS + MOVEM.L D5-D7/A3-A4,-(SP) ;SAVE REGS + JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE.S NOTPIC ;BRANCH IF NOT PICSAVE + + MOVE.B #FRAME,-(SP) ;PUSH VERB + JSR PutPicVerb ;CHECK pnSize, pnMode, pnPat + +;-------------------------------------------------------- +; +; PUT ONE OF FOUR LINE OPCODES BASED ON NEWPT AND DH,DV. +; +; line 20, pnLoc(pt), newPt(pt) +; line from 21, newPt(pt) +; short line 22, pnLoc(pt), dh,dv(-128..127) +; short line from 23, dh,dv(-128..127) +; + + MOVEQ #$20,D7 ;INIT OPCODE TO $20 + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.L PNLOC(A3),D0 ;GET CURRENT PNLOC + CMP.L PICPNLOC(A4),D0 ;IS LINE FROM LAST ENDPOINT ? + BNE.S NOTFROM ;NO, CONTINUE + ADDQ #1,D7 ;YES, SET BIT ZERO +NOTFROM MOVE NEWPT+H(A6),D6 ;GET NEWPT.H + SUB D0,D6 ;CALC DH = NEWPT.H - PNLOC.H + MOVE D6,D0 ;COPY DH + EXT.W D0 + CMP.W D6,D0 ;IS DH -128..127 ? + BNE.S PUTOP ;NO, CONTINUE + + MOVE NEWPT+V(A6),D5 ;GET NEWPT.V + SUB PNLOC+V(A3),D5 ;CALC DV = NEWPT.V - PNLOC.V + MOVE D5,D0 ;COPY DV + EXT.W D0 + CMP.W D5,D0 ;IS DV -128..127 ? + BNE.S PUTOP ;NO, CONTINUE + ADDQ #2,D7 ;YES, SET BIT ONE IN OPCODE + +PUTOP MOVE.B D7,-(SP) + JSR PutPicByte ;PUT ONE OF 4 LINE OPCODES + ROR #1,D7 ;DO WE NEED STARTPT ? (BIT 0) + BCS.S STARTOK ;NO, CONTINUE + MOVE.L PNLOC(A3),-(SP) + JSR PutPicLong ;YES, PUT STARTPT = PNLOC + +STARTOK ROR #1,D7 ;IS LINE SHORT ? (BIT 1) + BCS.S DHDV ;YES, PUT DH,DV + MOVE.L NEWPT(A6),-(SP) ;NO, PUT LONG NEWPT + JSR PutPicLong ;PUT NEWPT TO THEPIC + BRA.S UPDATE + +DHDV MOVE.B D6,-(SP) ;PUSH DH (-128..127) + JSR PutPicByte ;PUT TO THEPIC + MOVE.B D5,-(SP) ;PUSH DV (-128..127) + JSR PutPicByte ;PUT TO THEPIC + +UPDATE MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.L NEWPT(A6),PICPNLOC(A4) ;UPDATE PICTURE SAVING STATE + +NOTPIC MOVE.L NEWPT(A6),-(SP) ;PUSH NEWPT + JSR DoLine ;DoLine(newPt); + MOVEM.L (SP)+,D5-D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDLINE ' + + + + .PROC LineTo,2 + .REF StdLine +;---------------------------------------------------------- +; +; PROCEDURE LineTo(h,v: INTEGER); +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDLINE,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L LINEPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;GO TO IT + + + .PROC Line,2 + .REF LineTo +;---------------------------------------------------------- +; +; PROCEDURE Line(dh,dv: INTEGER); +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE PNLOC+H(A0),D0 ;GET CURRENT PENLOC.H + ADD D0,6(SP) ;ADD TO DH + MOVE PNLOC+V(A0),D0 ;GET CURRENT PENLOC.V + ADD D0,4(SP) ;ADD TO DV + JMP LineTo ;LineTo(pnLoc.h+dh,pnLoc.v+dv); + + + + .PROC MoveTo,2 +;---------------------------------------------------------- +; +; PROCEDURE MoveTo(h,v: INTEGER); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A1 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A1),A1 ;POINT TO CURRENT GRAFPORT + MOVE.L (SP)+,PNLOC(A1) ;COPY POINT INTO PNLOC + JMP (A0) ;RETURN + + + + .PROC MQVE,2 + .DEF Moov +;---------------------------------------------------------- +; +; PROCEDURE Move(dh,dv: INTEGER); +; +MOOV MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE (SP)+,D0 ;POP DV + MOVE (SP)+,D1 ;POP DH + MOVE.L GRAFGLOBALS(A5),A1 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A1),A1 ;GET CURRENT GRAFPORT + ADD D0,PNLOC+V(A1) ;ADD DV TO PNLOC.V + ADD D1,PNLOC+H(A1) ;ADD DH TO PNLOC.H + JMP (A0) ;RETURN + + + + .PROC DoLine,1 + .REF DrawLine,PutLine,SetSize +;---------------------------------------------------------- +; +; PROCEDURE DoLine(newPt: Point); +; +; { called by StdLine and StdPoly frame } +; + MOVEM.L D6-D7/A3-A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;POINT TO CURRENT GRAFPORT + MOVE.L 20(SP),D7 ;GET NEWPT + MOVE.L PNLOC(A3),D6 ;OLDPT := THEPORT^.PNLOC +; +; CHECK IF WE ARE SAVING FOR A POLYGON +; + TST.L POLYSAVE(A3) ;ARE WE SAVING FOR A POLYGON ? + BEQ.S NOTPOLY ;NO, CONTINUE + MOVE.L THEPOLY(A4),A1 ;YES, GET POLYHANDLE + MOVE.L (A1),A0 ;DE-REFERENCE IT + MOVE (A0),D0 ;GET CURRENT POLYSIZE + CMP #10,D0 ;IS THIS THE FIRST POINT ? + BNE.S FIRSTOK ;NO, CONTINUE + MOVE.L D6,0(A0,D0) ;YES, INSTALL FIRST := OLDPT + ADD #4,D0 ;BUMP INDEX +FIRSTOK MOVE.L D7,0(A0,D0) ;INSTALL NEWPT AT END + ADD #4,D0 ;BUMP INDEX + MOVE D0,(A0) ;UPDATE INDEX + CMP POLYMAX(A4),D0 ;TIME TO MAKE BIGGER ? + BLT.S SIZEOK ;NO, CONTINUE + ADD #256,POLYMAX(A4) ;YES, GROW IN CHUNKS + MOVE.L A1,-(SP) ;PUSH POLYHANDLE + MOVE POLYMAX(A4),-(SP) ;PUSH NEW SIZE + JSR SETSIZE ;MAKE THEPOLY BIGGER +SIZEOK BRA.S NOTRGN ;DONT SAVE FOR RGN TOO +; +; IF NOT POLY, THEN CHECK FOR RGNSAVE. +; IF RGNSAVE THEN PutLine(oldPt,newPt,rgnBuf,rgnIndex,rgnMax); +; +NOTPOLY TST.L RGNSAVE(A3) ;ARE WE SAVING FOR A REGION ? + BEQ.S NOTRGN + MOVE.L D6,-(SP) ;PUSH OLDPT + MOVE.L D7,-(SP) ;PUSH NEWPT + MOVE.L RGNBUF(A4),-(SP) ;PUSH RGNBUF + PEA RGNINDEX(A4) ;PUSH VAR RGNINDEX + PEA RGNMAX(A4) ;PUSH VAR RGNMAX + JSR PUTLINE ;ADD INVERSION PTS TO RGNBUF + +NOTRGN MOVE.L D6,-(SP) ;PUSH OLDPT + MOVE.L D7,-(SP) ;PUSH NEWPT + JSR DRAWLINE ;DRAW THE LINE + MOVE.L D7,PNLOC(A3) ;UPDATE THEPORT^.PNLOC + MOVEM.L (SP)+,D6-D7/A3-A4 ;RESTORE REGS + MOVE.L (SP)+,(SP) ;STRIP PARAM + RTS ;AND RETURN + + + + .PROC HidePen,0 + .DEF ShowPen +;---------------------------------------------------------- +; +; PROCEDURE HidePen; +; + MOVEQ #-1,D0 + BRA.S SHARE + + + +;---------------------------------------------------------- +; +; PROCEDURE ShowPen; +; +ShowPen MOVEQ #1,D0 +SHARE MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT PORT + ADD D0,PNVIS(A0) ;INCREMENT/DECREMENT PNVIS + RTS ;AND RETURN + + + + .PROC GetPenState,1 + .DEF SetPenState +;---------------------------------------------------------- +; +; PROCEDURE GetPenState(VAR pnState: PenState); +; PROCEDURE SetPenState(pnState: PenState); +; + MOVEQ #1,D0 ;SET A FLAG + BRA.S SHARE ;AND SHARE CODE + +SetPenState + CLR D0 ;CLEAR FLAG AND SHARE + +SHARE MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA PNLOC(A0),A0 ;POINT TO PNLOC + MOVE.L 4(SP),A1 ;POINT TO VAR PNSTATE + TST D0 ;is this SET penstate ? + BNE.S NOTSET ;NO, CONTINUE + EXG A0,A1 ;YES, SWAP SRC AND DST + +NOTSET MOVE.L (A0)+,(A1)+ ;COPY PNLOC FROM THEPORT + MOVE.L (A0)+,(A1)+ ;COPY PNSIZE FROM THEPORT + MOVE.W (A0)+,(A1)+ ;COPY PNMODE FROM THEPORT + MOVE.L (A0)+,(A1)+ ;COPY PNPAT FROM THEPORT + MOVE.L (A0)+,(A1)+ ;ALL 8 BYTES + MOVE.L (SP)+,(SP) ;STRIP 4 BYTES + RTS ;AND RETURN + + + + .PROC GetPen,1 +;---------------------------------------------------------- +; +; PROCEDURE GetPen(VAR pt: Point); +; { inquire the current pen location } +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L 4(SP),A1 ;POINT TO VAR PT + MOVE.L PNLOC(A0),(A1) ;GET PNLOC FROM THEPORT + MOVE.L (SP)+,(SP) ;STRIP 4 BYTES + RTS ;AND RETURN + + + + .PROC PenSize,2 +;---------------------------------------------------------- +; +; PROCEDURE PenSize(width,height: INTEGER); +; { set the pen width and height } +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L 4(SP),PNSIZE(A0) ;SET PEN WIDTH AND HEIGHT + MOVE.L (SP)+,(SP) ;STRIP 4 BYTES + RTS ;AND RETURN + + + + .PROC PenMode,1 + .REF PortWord +;---------------------------------------------------------- +; +; PROCEDURE PenMode(mode: INTEGER); +; { set the transfer mode for line drawing } +; + MOVEQ #PNMODE,D0 ;PUT PORT OFFSET IN D0 + JMP PORTWORD ;INSTALL PARAM INTO THEPORT + + + + .PROC PenPat,1 +;---------------------------------------------------------- +; +; PROCEDURE PenPat(pat: Pattern); +; { set the pattern for line drawing } +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA PNPAT(A0),A0 ;POINT TO PNPAT + MOVE.L 4(SP),A1 ;POINT TO INPUT PATTERN + MOVE.L (A1)+,(A0)+ ;COPY PATTERN INTO THEPORT + MOVE.L (A1)+,(A0)+ ;ALL 8 BYTES + MOVE.L (SP)+,(SP) ;STRIP 4 BYTES + RTS ;AND RETURN + + + + .PROC PenNormal,0 +;---------------------------------------------------------- +; +; PROCEDURE PenNormal; +; { restore all line drawing parameters to normal } +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L #$00010001,PNSIZE(A0) ;PEN SIZE:=1,1 + MOVE #8,PNMODE(A0) ;PENMODE:=PATTERN COPY + MOVEQ #-1,D0 + MOVE.L D0,PNPAT(A0) ;PNPAT:=BLACK + MOVE.L D0,PNPAT+4(A0) + RTS + + + + + .END diff --git a/Ovals.a b/Ovals.a new file mode 100755 index 0000000..1487933 --- /dev/null +++ b/Ovals.a @@ -0,0 +1,163 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; +; *** * * * * *** +; * * * * * * * * * +; * * * * * * * * +; * * * * * * * *** +; * * * * ***** * * +; * * * * * * * * * +; *** * * * ***** *** +; +; +; + .PROC StdOval,2 + .REF CheckPic,PutPicVerb,PutPicRect + .REF PutOval,PushVerb,DrawArc +;--------------------------------------------------------------- +; +; PROCEDURE StdOval(verb: GrafVerb; r: Rect); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 6 +VERB .EQU PARAMSIZE+8-2 ;GRAFVERB +RECT .EQU VERB-4 ;LONG, ADDR OF RECT + +OVWD .EQU -2 ;WORD +OVHT .EQU OVWD-2 ;WORD +VARSIZE .EQU OVHT ;TOTAL BYTES OF LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D7/A3-A4,-(SP) ;SAVE REGS + MOVE.B VERB(A6),D7 ;GET VERB + JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE.S NOTPIC ;BRANCH IF NOT PICSAVE + + MOVE.B D7,-(SP) + JSR PutPicVerb ;PUT ADDIONAL PARAMS TO THEPIC + MOVEQ #$50,D0 ;PUT OVALNOUN IN HI NIBBLE + ADD D7,D0 ;PUT VERB IN LO NIBBLE + MOVE.B D0,-(SP) ;PUSH OPCODE + MOVE.L RECT(A6),-(SP) ;PUSH ADDR OF RECT + JSR PutPicRect ;PUT OPCODE AND RECTANGLE + +NOTPIC MOVE.L RECT(A6),A0 ;POINT TO RECT + MOVE RIGHT(A0),D0 + SUB LEFT(A0),D0 + MOVE D0,OVWD(A6) ;OVWD := R.RIGHT - R.LEFT + MOVE BOTTOM(A0),D0 + SUB TOP(A0),D0 + MOVE D0,OVHT(A6) ;OVHT := R.BOTTOM - R.TOP + + MOVE.L A0,-(SP) ;PUSH ADDR OF RECT + TST.B D7 ;IS VERB FRAME ? + BNE.S NOTFR ;NO, CONTINUE + TST.L RGNSAVE(A3) ;YES, IS RGNSAVE TRUE ? + BEQ.S NOTRGN ;NO, CONTINUE + + MOVE.L A0,-(SP) ;YES, PUSH ADDR OF RECT + MOVE.L OVHT(A6),-(SP) ;PUSH OVWD, OVHT + MOVE.L RGNBUF(A4),-(SP) ;PUSH RGNBUF + PEA RGNINDEX(A4) ;PUSH VAR RGNINDEX + PEA RGNMAX(A4) ;PUSH VAR RGNMAX + JSR PutOval ;ADD AN OVAL TO THERGN + +NOTRGN MOVE.B #1,-(SP) ;PUSH HOLLOW = TRUE + BRA.S DOIT +NOTFR CLR.B -(SP) ;PUSH HOLLOW = FALSE +DOIT MOVE.L OVHT(A6),-(SP) ;PUSH OVWD,OVHT + JSR PushVerb ;PUSH MODE AND PATTERN + CLR -(SP) ;PUSH STARTANGLE = 0 + MOVE #360,-(SP) ;PUSH ARCANGLE = 360 + +; DrawArc(r,hollow,ovWd,ovHt,mode,pat,startAng,arcAng); + + JSR DrawArc + MOVEM.L (SP)+,D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDOVAL ' + + + + .PROC FrameOval,1 + .DEF CallOval,PaintOval,EraseOval,InvertOval,FillOval + .REF StdOval +;----------------------------------------------------- +; +; PROCEDURE FrameOval(* r: Rect *); +; + MOVEQ #FRAME,D0 ;VERB = FRAME + BRA.S CallOval ;SHARE COMMON CODE + + +;----------------------------------------------------- +; +; PROCEDURE PaintOval(* r: Rect *); +; +PaintOval + MOVEQ #PAINT,D0 ;VERB = PAINT + BRA.S CallOval ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE EraseOval(* r: Rect *); +; +EraseOval + MOVEQ #ERASE,D0 ;VERB = ERASE + BRA.S CallOval ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE InvertOval(* r: Rect *); +; +InvertOval + MOVEQ #INVERT,D0 ;VERB = INVERT + BRA.S CallOval ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE FillOval(* r: Rect; pat: Pattern *); +; +FillOval + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF PATTERN + MOVE.L A0,-(SP) ;PUT RETURN ADDR BACK + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA FILLPAT(A0),A0 ;POINT TO FILLPAT + MOVE.L (A1)+,(A0)+ ;COPY PAT INTO FILLPAT + MOVE.L (A1)+,(A0)+ ;ALL EIGHT BYTES + MOVEQ #FILL,D0 ;VERB = FILL + BRA.S CallOval ;SHARE COMMON CODE + + + +;--------------------------------------------------------------- +; +; PROCEDURE CallOval(r: Rect); +; +; code shared by FrameOval, PaintOval, EraseOval, InvertOval, and FillOval. +; enter with verb in D0. +; +CallOval + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + MOVE.B D0,-(SP) ;PUSH VERB + MOVE.L A1,-(SP) ;PUSH ADDR OF RECT + MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDOVAL,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L OVALPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;GO TO IT + + + .END diff --git a/PackRgn.a b/PackRgn.a new file mode 100755 index 0000000..08fbf53 --- /dev/null +++ b/PackRgn.a @@ -0,0 +1,159 @@ + .INCLUDE GRAFTYPES.TEXT + + + .PROC PACKRGN,3 + .REF SETSIZE +;----------------------------------------------------------------- +; +; PROCEDURE PackRgn(srcHandle: Handle; nPoints: INTEGER; dstRgn: RgnHandle); +; +; Converts a sorted array of inversion points into a region. +; Calls storage allocator to make more room and trim result to minimum size. +; +; OUTPUT IS IN THE FOLLOWING FORM: +; +; RGNSIZE +; RGNBBOX +; V H .. H 32767 +; V H .. H 32767 +; V=32767 +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 10 ;TOTAL BYTES OF PARAMS +SRCHANDLE .EQU PARAMSIZE+8-4 ;LONG +NPOINTS .EQU SRCHANDLE-2 ;INTEGER +DSTRGN .EQU NPOINTS-4 ;LONG, HANDLE + + +;------------------------------------------------------- +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +BBOX .EQU -8 ;RECTANGLE +VARSIZE .EQU BBOX ;SIZE OF LOCAL VARIABLES + + + LINK A6,#VARSIZE ;ALLOCATE LOCAL VARIABLES + MOVEM.L D0-D7/A1-A4,-(SP) ;SAVE REGS + MOVE.L SRCHANDLE(A6),A4 ;GET SRC HANDLE + MOVE.L DSTRGN(A6),A3 ;GET DST RGNHANDLE + MOVE NPOINTS(A6),D6 ;GET NUMBER OF POINTS + MOVE.L (A3),A1 ;DE-REFERENCE DSTRGN + MOVE RGNSIZE(A1),D5 ;GET CURRENT RGNSIZE + MOVE.L (A4),A0 ;DE-REFERENCE SRCHANDLE + + +;------------------------------------------------------------------------ +; +; CHECK NPOINTS TO SPECIAL CASE EMPTY AND RECTANGULAR REGIONS. +; + MOVEQ #10,D7 ;INIT RGNSIZE TO EMPTY RGN SIZE + CLR.L BBOX+TOPLEFT(A6) ;INIT BOUNDING BOX TO EMPTY + CLR.L BBOX+BOTRIGHT(A6) + CMP #4,D6 ;HOW MANY POINTS IN SOURCE ? + BGT.S NOTRECT ;MORE THAN 4, NOT RECTANGULAR + BLT.S DONE ;LESS THAN 4, EMPTY REGION + MOVE.L 0(A0),BBOX+TOPLEFT(A6) ;GET TOPLEFT OF BOUNDING BOX + MOVE.L 12(A0),BBOX+BOTRIGHT(A6) ;GET BOTRIGHT OF BOUNDING BOX + BRA.S DONE ;INSTALL RGNSIZE AND BBOX AND QUIT + + +;------------------------------------------------------------------------ +; +; MORE THAN FOUR POINTS, NON-RECTANGULAR. SCAN FOR BBOX LEFT AND RIGHT. +; +NOTRECT MOVE V(A0),BBOX+TOP(A6) ;BBOX TOP:=FIRST POINT.V + MOVE H(A0),D1 ;INIT MINH TO FIRST HORIZ + MOVE D1,D2 ;INIT MAXH TO FIRST HORIZ ALSO + MOVE D6,D3 ;GET NUMPER OF POINTS IN SRC +SCAN SUB #1,D3 ;ANY POINTS LEFT ? + BLT.S ENDSCAN ;NO, QUIT SCANNING + MOVE.L (A0)+,D0 ;YES, GET NEXT POINT + CMP.W D1,D0 ;IS PT.H < MINH ? + BGE.S LEFTOK ;NO, CONTINUE + MOVE D0,D1 ;YES, MINH:=PT.H + BRA SCAN ;LOOP FOR MORE + +LEFTOK CMP.W D2,D0 ;IS PT.H > MAXH ? + BLE SCAN ;NO, GO FOR NEXT + MOVE D0,D2 ;YES, MAXH:=PT.H + BRA SCAN ;GO FOR NEXT + +ENDSCAN MOVE D1,BBOX+LEFT(A6) ;BBOX LEFT:=MINH + MOVE D2,BBOX+RIGHT(A6) ;BBOX RIGHT:=MAXH + MOVE -4+V(A0),BBOX+BOTTOM(A6) ;BBOX BOTTOM:=LAST POINT.V + + +;---------------------------------------------------------------- +; +; EXPAND DSTRGN TO HOLD WORST CASE = 12 + 4*NPOINTS bytes. +; + MOVEQ #3,D5 + ADD D6,D5 ;GET NPOINTS + 3 + LSL #2,D5 ;TIMES 4 + MOVE.L A3,-(SP) ;PUSH DSTRGN + MOVE D5,-(SP) ;PUSH NEW BYTECOUNT + JSR SetSize ;MAKE IT THAT BIG + + +;---------------------------------------------------- +; +; NEWLY DE-REFERENCE SRC AND DST HANDLES +; + MOVE.L (A4),A0 ;DE-REFERENCE SRC HANDLE + MOVE.L (A3),A1 ;DE-REFERENCE DSTRGN HANDLE + ADD D7,A1 ;SKIP OVER RGNSIZE & BBOX + + SUB #1,D6 ;DBRA COUNT = NPOINTS - 1 + MOVE (A0)+,D0 ;GET FIRST VERT COORD + MOVE #32767,D1 + BRA.S START ;GO TO LOOP START + +NEXTPT CMP (A0)+,D0 ;SAME VERT COORD ? + BEQ.S VSAME ;YES, CONTINUE + MOVE D1,(A1)+ ;PUT END OF ROW MARKER + MOVE -2(A0),D0 ;GET NEW VERT COORD +START MOVE D0,(A1)+ ;PUT VERT COORD +VSAME MOVE (A0)+,(A1)+ ;PUT HORIZ COORD + DBRA D6,NEXTPT ;LOOP FOR ALL POINTS + + MOVE D1,(A1)+ ;PUT END OF ROW MARKER + MOVE D1,(A1)+ ;PUT FINAL VERT = 32767 + MOVE.L (A3),A0 ;DE-REFERENCE DSTRGN HANDLE + SUB.L A0,A1 ;SUBTRACT FROM DSTPTR + MOVE.W A1,D7 ;TO COMPUTE RGNSIZE + + +;-------------------------------------------------------- +; +; INSTALL RGNSIZE AND RGNBBOX. +; +DONE MOVE.L (A3),A0 ;DE-REFERENCE DSTRGN HANDLE + MOVE D7,(A0)+ ;INSTALL RGNSIZE + MOVE.L BBOX+TOPLEFT(A6),(A0)+ ;INSTALL BOUNDING BOX TOPLEFT + MOVE.L BBOX+BOTRIGHT(A6),(A0)+ ;AND BOTRIGHT + + +;-------------------------------------------------------- +; +; TRIM DSTRGN TO EXACT SIZE IF IT ISN'T ALREADY. +; + CMP D7,D5 ;IS IT ALREADY THE RIGHT SIZE ? + BEQ.S SIZEOK ;YES, SKIP + MOVE.L A3,-(SP) ;PUSH DSTRGN HANDLE + MOVE D7,-(SP) ;PUSH NEW SIZE + JSR SETSIZE + + +;------------------------------------------------------ +; +; CLEAN UP THE STACK AND GO HOME. +; +SIZEOK MOVEM.L (SP)+,D0-D7/A1-A4 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'PACKRGN ' + + + + + .END diff --git a/PicFormat.txt b/PicFormat.txt new file mode 100755 index 0000000..c7d326d --- /dev/null +++ b/PicFormat.txt @@ -0,0 +1,120 @@ +QUICKDRAW INTERNAL PICTURE FORMAT: + + +OPCODE NAME ADDITIONAL PARAMS TOTAL BYTES + +00 nop none 1 +01 clipRgn region 1 + region +02 bkPat pattern 9 +03 txFont font(word) 3 +04 txFace face(byte) 2 +05 txMode mode(word) 3 +06 spExtra extra(fixed Point) 5 +07 pnSize pnSize(point) 5 +08 pnMode mode(word) 3 +09 pnPat pattern 9 +0A thePat pattern 9 +0B ovSize point 5 +0C origin dh(word),dv(word) 5 +0D txSize size(word) 3 +0E fgColor color(long) 4 +0F bkColor color(long) 4 + +10 txRatio numer(pt), denom(pt) 9 +11 picVersion version(byte) 2 + +20 line pnLoc(pt), newPt(pt) 9 +21 line from newPt(pt) 5 +22 short line pnLoc(pt), dh, dv(-128..127) 7 +23 short line from dh, dv(-128..127) 3 + +28 long text: txLoc(pt), count(0..255), text 6 + text +29 DH text: dh(0..255), count(0..255), text 3 + text +2A DV text: dv(0..255), count(0..255), text 3 + text +2B DHDV text: dh,dv(0,..255), count(0..255), text 4 + text + +30 frameRect rect 9 +31 paintRect rect 9 +32 eraseRect rect 9 +33 invertRect rect 9 +34 fillRect rect 9 + +38 frameSameRect 1 +39 paintSameRect 1 +3A eraseSameRect 1 +3B invertSameRect 1 +3C fillSameRect 1 + +40 frameRRect rect 9 +41 paintRRect rect 9 +42 eraseRRect rect 9 +43 invertRRect rect 9 +44 fillRRect rect 9 + +48 frameSameRRect 1 +49 paintSameRRect 1 +4A eraseSameRRect 1 +4B invertSameRRect 1 +4C fillSameRRect 1 + +50 frameOval rect 9 +51 paintOval rect 9 +52 eraseOval rect 9 +53 invertOval rect 9 +54 fillOval rect 9 + +58 frameSameOval 1 +59 paintSameOval 1 +5A eraseSameOval 1 +5B invertSameOval 1 +5C fillSameOval 1 + +60 frameArc rect 9 +61 paintArc rect 9 +62 eraseArc rect 9 +63 invertArc rect 9 +64 fillArc rect 9 + +68 frameSameArc 1 +69 paintSameArc 1 +6A eraseSameArc 1 +6B invertSameArc 1 +6C fillSameArc 1 + +70 framePoly poly 1 + poly +71 paintPoly poly 1 + poly +72 erasePoly poly 1 + poly +73 invertPoly poly 1 + poly +74 fillPoly poly 1 + poly + +78 frameSamePoly (not implemented yet) +79 paintSamePoly (not implemented yet) +7A eraseSamePoly (not implemented yet) +7B invertSamePoly (not implemented yet) +7C fillSamePoly (not implemented yet) + +80 frameRgn rgn 1 + region +81 paintRgn rgn 1 + region +82 eraseRgn rgn 1 + region +83 invertRgn rgn 1 + region +84 fillRgn rgn 1 + region + +88 frameSameRgn (not implemented yet) +89 paintSameRgn (not implemented yet) +8A eraseSameRgn (not implemented yet) +8B invertSameRgn (not implemented yet) +8C fillSameRgn (not implemented yet) + +90 BitsRect rowBytes, bounds, srcRect, dstRect, mode, + byteCount, unpacked bitData +91 BitsRgn rowBytes, bounds, srcRect, dstRect, mode, + maskRgn, byteCount, unpacked bitData +98 PackBitsRect rowBytes, bounds, srcRect, dstRect, mode + byteCount, packed bitData +99 PackBitsRgn rowBytes, bounds, srcRect, dstRect, mode + maskRgn, byteCount, packed bitData + +A0 shortComment kind(word) 3 +A1 longComment kind(word) size(word) data 5 + data + +FF endOfPicture diff --git a/Pictures.a b/Pictures.a new file mode 100755 index 0000000..ee4dd66 --- /dev/null +++ b/Pictures.a @@ -0,0 +1,1807 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; +; **** *** *** ***** * * **** ***** *** +; * * * * * * * * * * * * * +; * * * * * * * * * * * +; **** * * * * * **** *** *** +; * * * * * * * * * * +; * * * * * * * * * * * * +; * *** *** * *** * * ***** *** +; +; + + + .PROC StdComment,3 + .REF DPutPicByte,PutPicWord,PutPicData +;------------------------------------------------------------------ +; +; PROCEDURE StdComment(kind,dataSize: INTEGER; dataHandle: Handle); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 8 +KIND .EQU PARAMSIZE+8-2 ;WORD +DATASIZE .EQU KIND-2 ;WORD +DATAHANDLE .EQU DATASIZE-4 ;LONG, HANDLE + + LINK A6,#0 ;NO LOCAL VARS + MOVEM.L D6-D7,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + TST.L PICSAVE(A0) ;ARE WE SAVING FOR THEPIC ? + BEQ.S DONE ;NO, QUIT + + MOVE KIND(A6),D6 ;YES, GET KIND + MOVE DATASIZE(A6),D7 ;IS DATASIZE > 0 ? + BGT.S LONG ;YES, USE LONG FORMAT +; +; DATASIZE 0, USE SHORT FORMAT +; + MOVEQ #$FFFFFFA0,D0 + JSR DPutPicByte ;PUT SHORT COMMENT OPCODE + MOVE D6,-(SP) + JSR PutPicWord ;PUT KIND + BRA.S DONE +; +; DATASIZE > 0, USE LONG FORMAT +; +LONG MOVEQ #$FFFFFFA1,D0 + JSR DPutPicByte ;PUT LONG COMMENT OPCODE + MOVE D6,-(SP) + JSR PutPicWord ;PUT KIND + MOVE D7,-(SP) + JSR PutPicWord ;PUT DATASIZE + MOVE.L DATAHANDLE(A6),A0 ;GET DATA HANDLE + _HLock ;LOCK IT + MOVE.L DATAHANDLE(A6),A0 ;GET DATA HANDLE + MOVE.L (A0),-(SP) ;PUSH DATAPTR + MOVE D7,-(SP) ;PUSH BYTECOUNT + JSR PutPicData ;PUT DATA TO THEPIC + MOVE.L DATAHANDLE(A6),A0 ;GET DATA HANDLE + _HUnlock ;UNLOCK IT + +DONE MOVEM.L (SP)+,D6-D7 ;RESTORE REGS + UNLINK PARAMSIZE,'STDCOMME' + + + + .FUNC StdGetPic,2 +;------------------------------------------------------------------ +; +; PROCEDURE StdGetPic(dataPtr: QDPtr; byteCount: INTEGER); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE (SP)+,D1 ;POP BYTECOUNT + MOVE.L (SP)+,A1 ;POP DATAPTR + MOVE.L A0,-(SP) ;PUSH RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L PLAYINDEX(A0),D0 ;GET PLAYINDEX + EXT.L D1 ;EXTEND BYTECOUNT TO LONG + ADD.L D1,PLAYINDEX(A0) ;BUMP PLAYINDEX + MOVE.L PLAYPIC(A0),A0 ;GET PLAY PICHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + ADD.L D0,A0 ;ADD PLAYINDEX + BRA.S START ;GO TO LOOP START +NXTBYTE MOVE.B (A0)+,(A1)+ ;COPY ONE BYTE +START DBRA D1,NXTBYTE ;LOOP FOR ALL BYTES + RTS ;AND RETURN + + + + .PROC StdPutPic,1 + .REF SetSize +;------------------------------------------------------------------ +; +; PROCEDURE StdPutPic(dataPtr: QDPtr; byteCount: INTEGER); +; +; Append some picture bytes to a growing handle. +; +PARAMSIZE .EQU 6 +SRCPTR .EQU PARAMSIZE+8-4 ;LONG +BYTECOUNT .EQU SRCPTR-2 ;WORD + + LINK A6,#0 ;NO LOCALS + MOVEM.L D7/A3-A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A4 ;GET CURRENT GRAFPORT + TST.L PICSAVE(A4) ;ARE WE SAVING FOR A PICTURE ? + BEQ.S GOHOME ;NO, QUIT + MOVE.L PICSAVE(A4),A4 ;YES, GET PICSAVE HANDLE + MOVE.L (A4),A1 ;DE-REFERENCE PICSAVE HANDLE + MOVE.L PICINDEX(A1),D7 ;GET CURRENT SIZE + BEQ.S GOHOME ;QUIT IF PICTURE IS ALREADY DEAD + MOVE.L THEPIC(A1),A3 ;GET THEPIC HANDLE + + MOVE BYTECOUNT(A6),D0 ;GET BYTES REQUESTED + EXT.L D0 ;MAKE BYTECOUNT LONG + ADD.L D7,D0 ;CALCULATE NEW SIZE + MOVE.L D0,PICINDEX(A1) ;UPDATE PICINDEX + MOVE.L (A3),A0 ;DE-REFERENCE THEPIC + MOVE.W D0,PICSIZE(A0) ;PICSIZE := LO WORD OF PICINDEX + CMP.L PICMAX(A1),D0 ;IS NEW SIZE > PICMAX ? + BLE.S SIZEOK ;NO, CONTINUE +; +; time to grow the picture in chunks of at least 256 bytes +; + ADD.L #256,D0 ;GROW PIC IN CHUNKS + MOVE.L D0,PICMAX(A1) ;UPDATE NEW PICMAX + MOVE.L A3,A0 ;GET THEPIC HANDLE + _SetHandleSize ;MAKE IT BIGGER + MOVE.L (A4),A1 ;RE-DEREFERENCE PICSAVE HANDLE + BEQ.S SIZEOK ;CONTINUE IF NO ERROR +; +; Failed to grow picture, so we will trim handle down to 10 bytes, +; clear PicIndex, and set picSize to -1, PicFrame to (0,0,0,0). +; + CLR.L PICINDEX(A1) ;CLEAR PICINDEX AS DEAD FLAG + MOVE.L #10,D0 ;BYTECOUNT = 10 + MOVE.L A3,A0 ;GET THEPIC HANDLE + _SetHandleSize ;SHRINK PICTURE TO 10 BYTES + MOVE.L (A3),A0 ;DE-REFERENCE PICHANDLE + MOVE #-1,(A0)+ ;STUFF picSize = -1 + CLR.L (A0)+ ;stuff picFrame = (0,0,0,0) + CLR.L (A0)+ ;all 8 bytes of picFrame + BRA.S GOHOME ;AND QUIT +; +; now copy the data bytes into the picture: +; +SIZEOK MOVE.L THEPIC(A1),A1 ;GET THEPIC HANDLE + MOVE.L (A1),A1 ;DE-REFERENCE PICHANDLE + ADD.L D7,A1 ;ADD OLDSIZE FOR DSTPTR + MOVE.L SRCPTR(A6),A0 ;GET SRCPTR + MOVE BYTECOUNT(A6),D0 ;GET BYTECOUNT + BRA.S START ;GO TO LOOP START +NXTBYTE MOVE.B (A0)+,(A1)+ ;COPY A BYTE +START DBRA D0,NXTBYTE ;LOOP ALL BYTES + +GOHOME MOVEM.L (SP)+,D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDPUTPI' + + + + .PROC PicComment,3 + .REF StdComment +;------------------------------------------------------------------ +; +; PROCEDURE PicComment(kind,dataSize: INTEGER; dataHandle: Handle; +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDCOMMENT,A0 + BEQ.S USESTD ;YES, USE STDCOMMENT + MOVE.L D0,A0 + MOVE.L COMMENTPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;AND JUMP TO IT + + + + .FUNC OpenPicture,1 + .REF HidePen,NewRgn,PutPicWord,EqualRgn,ClipRect +;------------------------------------------------------------------ +; +; FUNCTION OpenPicture(picFrame: Rect): PicHandle; +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 4 +RESULT .EQU PARAMSIZE+8 ;LONG, PICHANDLE +RECT .EQU RESULT-4 ;LONG, ADDR OF RECT + + LINK A6,#0 ;NO LOCALS + MOVEM.L A3-A4,-(SP) ;SAVE REGS + CLR.L RESULT(A6) ;INIT FCN RESULT TO NIL + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;GET CURRENT GRAFPORT + TST.L PICSAVE(A3) ;ARE WE ALREADY SAVING ? + BNE DONE ;YES, RETURN NIL AND QUIT + JSR HidePen ;NO, TURN OFF DRAWING +; +; Abort OpenPicture if heap doesn't have at least 500 bytes. +; + MOVE.L #500,D0 ;GET BYTE COUNT + _NewHandle ;AT LEAST 500 BYTES IN THE HEAP ? + BNE DONE ;NO, RETURN NIL AND QUIT + _DisposHandle ;YES, Discard test handle + +; +; If clipRgn = wideOpen, then SetClip(picFrame); +; + CLR.B -(SP) ;ROOM FOR FCN RESULT + MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN + MOVE.L WIDEOPEN(A4),-(SP) ;PUSH WIDEOPEN + JSR EQUALRGN ;COMPARE CLIPRGN AND WIDEOPEN + TST.B (SP)+ ;ARE THEY EQUAL ? + BEQ.S CLIPOK ;NO, CONTINUE + MOVE.L RECT(A6),-(SP) ;YES, PUSH PICFRAME + JSR CLIPRECT ;AND CLIPRECT(PICFRAME) +CLIPOK +; +; ALLOCATE PICSAVE RECORD +; + MOVE.L #PICSAVEREC,D0 ;GET BYTE COUNT + _NewHandle ;ALLOCATE PICSAVE RECORD + MOVE.L A0,A4 ;GET RESULT HANDLE + MOVE.L A4,PICSAVE(A3) ;SAVE RESULT IN THEPORT +; +; ALLOCATE PICCLIPRGN (leave on stack for now) +; + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + JSR NEWRGN ;ALLOCATE A NEW REGION +; +; ALLOCATE THEPIC PICHANDLE +; + MOVE.L #256,D0 ;BYTE COUNT = 256 + _NewHandle ;ALLOCATE NEWHANDLE(256) + MOVE.L A0,A1 ;GET THEPIC HANDLE + MOVE.L A1,RESULT(A6) ;PUT HANDLE IN FCN RESULT +; +; NOW FILL THEPIC'S PICSIZE AND PICFRAME +; + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE HANDLE + MOVE.L A1,(A4)+ ;SAVE PICHANDLE IN THEPIC + MOVE.L (A1),A1 ;DE-REFERENCE PICHANDLE + MOVE #10,(A1)+ ;INSTALL PICSIZE = 10 + MOVE.L RECT(A6),A0 ;POINT TO PICFRAME PARAM + MOVE.L (A0)+,(A1)+ ;COPY RECT INTO PICTURE + MOVE.L (A0)+,(A1)+ +; +; INIT STATE VARIABLES FOR PICTURE CAPTURE +; + MOVE.L #256,(A4)+ ;PICMAX := 256; + MOVE.L #10,(A4)+ ;PICINDEX := 10 + MOVE.L (SP)+,(A4)+ ;INSTALL PICCLIPRGN + CLR.L (A4)+ ;PICBKPAT := WHITE + CLR.L (A4)+ + CLR.L (A4)+ ;PICTXFONT = 0, PICTXFACE = [] + MOVE #1,(A4)+ ;PICTXMODE := SRCCOPY + CLR (A4)+ ;PICTXSIZE := 0 + CLR.L (A4)+ ;PICSPEXTRA := 0.0 + MOVE.L #$00010001,D0 ;GET (1,1) + MOVE.L D0,(A4)+ ;PICTXNUMER := (1,1) + MOVE.L D0,(A4)+ ;PICTXDENOM := (1,1) + CLR.L (A4)+ ;PICTXLOC := (0,0) + CLR.L (A4)+ ;PICPNLOC := (0,0) + MOVE.L D0,(A4)+ ;PICPNSIZE := (1,1) + MOVE #8,(A4)+ ;PICPNMODE := PATCOPY + MOVEQ #-1,D0 ;GET SOME BLACK + MOVE.L D0,(A4)+ ;PICPNPAT := BLACK + MOVE.L D0,(A4)+ + MOVE.L D0,(A4)+ ;PICFILLPAT := BLACK + MOVE.L D0,(A4)+ + CLR.L (A4)+ ;PICTHERECT := (0,0,0,0) + CLR.L (A4)+ + CLR.L (A4)+ ;PICOVSIZE := (0,0) + MOVE.L PORTRECT+TOPLEFT(A3),(A4)+ ;PICORIGIN := CURRENT ORIGIN + MOVE.L #blackColor,(A4)+ ;PICFGCOLOR := blackColor + MOVE.L #whiteColor,(A4)+ ;PICBKCOLOR := whiteColor +; +; put version number opcode +; + MOVE.w #$1101,-(SP) ;VERSION OPCODE + VERSION 1 + JSR PutPicWord ;PUT TO PICTURE + +DONE MOVEM.L (SP)+,A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'OPENPICT' + + + + .PROC ClosePicture,0 + .REF PutPicByte,ShowPen,SetSize +;------------------------------------------------------------------ +; +; PROCEDURE ClosePicture; +; + MOVEM.L D6-D7/A3,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A3 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A3),A3 ;GET CURRENT GRAFPORT + MOVE.L PICSAVE(A3),D7 ;ARE WE SAVING A PICTURE ? + BEQ.S GOHOME ;NO, OOPS, EXIT + ST -(SP) ;YES, PUSH ENDPIC OPCODE, $FF + JSR PutPicByte ;PUT TO THEPIC + MOVE.L D7,A0 ;GET HANDLE TO PICSAVE RECORD + MOVE.L (A0),A0 ;DE-REFERENCE IT + MOVE.L PICCLIPRGN(A0),D6 ;GET picClipRgn + MOVE.L PICINDEX(A0),D0 ;DID PICTURE OVERFLOW ? + BEQ.S OVERFLO ;YES, CONTINUE + MOVE.L THEPIC(A0),A0 ;NO, GET THEPIC HANDLE + _SetHandleSize ;AND TRIM TO FINAL SIZE +OVERFLO MOVE.L D6,A0 ;GET PICCLIPRGN + _DisposHandle ;DISCARD IT + MOVE.L D7,A0 ;GET PICSAVE HANDLE + _DisposHandle ;DISCARD IT + CLR.L PICSAVE(A3) ;RESET PICSAVE TO NIL + JSR SHOWPEN ;RESTORE DRAWING +GOHOME MOVEM.L (SP)+,D6-D7/A3 ;RESTORE REGS + RTS ;AND RETURN + + + + .PROC KillPicture,1 +;--------------------------------------------------- +; +; PROCEDURE KillPicture(myPicture: PicHandle); +; + MOVE.L (SP)+,A1 ;pop return addr + MOVE.L (SP)+,A0 ;pop handle + _DisposHandle ;discard it + JMP (A1) ;and return + + + + .PROC DrawPicture,2 + .REF PicItem,NewRgn +;------------------------------------------------------------------ +; +; PROCEDURE DrawPicture(myPicture: PicHandle; dstRect: Rect); +; + +;-------------------------------------------- +; +; OFFSETS WITHIN A PICTURE PLAY STATE RECORD: +; +THERECT .EQU 0 ;RECT +PENLOC .EQU THERECT+8 ;POINT +TEXTLOC .EQU PENLOC+4 ;POINT +OVALSIZE .EQU TEXTLOC+4 ;POINT +FROMRECT .EQU OVALSIZE+4 ;RECT +TORECT .EQU FROMRECT+8 ;RECT +NUMER .EQU TORECT+8 ;POINT +DENOM .EQU NUMER+4 ;POINT +THECLIP .EQU DENOM+4 ;RGNHANDLE +USERCLIP .EQU THECLIP+4 ;RGNHANDLE +PLAYREC .EQU USERCLIP+4 ;TOTAL SIZE + +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 8 +MYPICTURE .EQU PARAMSIZE+8-4 ;LONG, PICHANDLE +DSTRECT .EQU MYPICTURE-4 ;LONG, ADDR OF RECT + +PLAYSTATE .EQU -PLAYREC ;PICTURE PLAY STATE RECORD +SAVEPORT .EQU PLAYSTATE-PORTREC ;GRAFPORT RECORD +VARSIZE .EQU SAVEPORT ;TOTAL BYTES OF LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE LOCALS + MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGISTERS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;POINT TO CURRENT GRAFPORT + TST.L MYPICTURE(A6) ;IS PICHANDLE NIL ? + BEQ GOHOME ;YES, QUIT + + +;-------------------------------------------------- +; +; SET UP NUMER AND QUIT IF DSTRECT WIDTH OR HEIGHT IS <= 0 +; COPY DSTRECT INTO TORECT +; + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + MOVE RIGHT(A0),D0 + SUB LEFT(A0),D0 ;CALC DST WIDTH + BLE GOHOME ;QUIT IF WIDTH <= 0 + MOVE D0,PLAYSTATE+NUMER+H(A6) ;NUMER.H := DST WIDTH + MOVE BOTTOM(A0),D0 + SUB TOP(A0),D0 ;CALC DST HEIGHT + BLE GOHOME ;QUIT IF HEIGHT <= 0 + MOVE D0,PLAYSTATE+NUMER+V(A6) ;NUMER.V := DST HEIGHT + LEA PLAYSTATE+TORECT(A6),A1 + MOVE.L (A0)+,(A1)+ + MOVE.L (A0)+,(A1)+ ;TORECT := DSTRECT + + +;-------------------------------------------------- +; +; SET UP DENOM AND QUIT IF PICFRAME WIDTH OR HEIGHT IS <= 0 +; COPY PICFRAME INTO FROMRECT. +; + MOVE.L MYPICTURE(A6),A0 ;GET PICHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + LEA PICFRAME(A0),A0 ;POINT TO PICTURE FRAME + MOVE RIGHT(A0),D0 + SUB LEFT(A0),D0 ;CALC SRC WIDTH + BLE GOHOME ;QUIT IF WIDTH <= 0 + MOVE D0,PLAYSTATE+DENOM+H(A6) ;DENOM.H := SRC WIDTH + MOVE BOTTOM(A0),D0 + SUB TOP(A0),D0 ;CALC SRC HEIGHT + BLE GOHOME ;QUIT IF HEIGHT <= 0 + MOVE D0,PLAYSTATE+DENOM+V(A6) ;DENOM.V := SRC HEIGHT + LEA PLAYSTATE+FROMRECT(A6),A1 ;POINT TO FROMRECT + MOVE.L (A0)+,(A1)+ + MOVE.L (A0)+,(A1)+ ;FROMRECT := PICFRAME + + +;--------------------------------------------------- +; +; PRESERVE THE CURRENT GRAFPORT IN SAVEPORT +; + MOVE.L A3,A0 ;SRC = THEPORT + LEA SAVEPORT(A6),A1 ;DST = SAVEPORT + MOVEQ #PORTREC/2-1,D0 ;INIT DBRA COUNT +SAVELP MOVE.W (A0)+,(A1)+ ;COPY A WORD + DBRA D0,SAVELP ;LOOP ENTIRE PORT + + +;---------------------------------------- +; +; INIT GLOBAL VARS: +; + CLR.L PATALIGN(A4) ;PATALIGN := (0,0) + MOVE.L MYPICTURE(A6),PLAYPIC(A4) ;SAVE PICTURE FOR STDGETPIC + MOVE.L #PICDATA,PLAYINDEX(A4) ;INIT INDEX TO FIRST OPCODE + + +;---------------------------------------- +; +; INIT PLAY STATE RECORD: +; + LEA PLAYSTATE(A6),A0 + CLR.L (A0)+ ;THERECT := (0,0,0,0) + CLR.L (A0)+ + CLR.L (A0)+ ;PENLOC := (0,0) + CLR.L (A0)+ ;TEXTLOC := (0,0) + CLR.L (A0)+ ;OVALSIZE := (0,0) + ;FROMRECT SET UP + ;TORECT SET UP + ;NUMER SET UP + ;DENOM SET UP + + + MOVE.L CLIPRGN(A3),PLAYSTATE+USERCLIP(A6) ;SAVE USER CLIPRGN + + CLR.L -(SP) + JSR NEWRGN + MOVE.L (SP)+,PLAYSTATE+THECLIP(A6) ;ALLOCATE THECLIP + + +;-------------------------------------------------------- +; +; INIT MOST FIELDS OF THEPORT +; + CLR.L -(SP) + JSR NEWRGN + MOVE.L (SP)+,CLIPRGN(A3) ;ALLOCATE TEMP CLIPRGN + LEA BKPAT(A3),A0 ;POINT TO BKPAT + CLR.L (A0)+ ;BKPAT := WHITE + CLR.L (A0)+ + MOVEQ #-1,D0 ;GET SOME BLACK + MOVE.L D0,(A0)+ ;fillPat := BLACK + MOVE.L D0,(A0)+ + CLR.L (A0)+ ;PNLOC := (0,0) + MOVE.L #$00010001,D1 + MOVE.L D1,(A0)+ ;pnSize := (1,1) + MOVE #8,(A0)+ ;pnMode := patCopy + MOVE.L D0,(A0)+ ;pnPat := black + MOVE.L D0,(A0)+ + ADD #2,A0 ;skip over pnVis + CLR.L (A0)+ ;txFont, txFace := 0 + MOVE #1,(A0)+ ;txMode := srcOr + CLR (A0)+ ;txSize := 0; + CLR.L (A0)+ ;spExtra := 0.0; + MOVE.L #blackColor,(A0)+ ;FGCOLOR := blackColor + MOVE.L #whiteColor,(A0)+ ;BKCOLOR := whiteColor + ;LEAVE COLRBIT ALONE + ;LEAVE PATSTRETCH ALONE + ;LEAVE PICSAVE ALONE + ;LEAVE RGNSAVE ALONE + ;LEAVE POLYSAVE ALONE + ;LEAVE GRAFPROCS ALONE + +;--------------------------------------------------- +; +; NOW DRAW THE PICTURE: +; REPEAT UNTIL NOT PicItem(playState); +; +MORE CLR.B -(SP) ;MAKE ROOM FOR FCN RESULT + PEA PLAYSTATE(A6) ;PUSH ADDR OF PLAYSTATE + JSR PicItem ;DRAW ONE PICTURE ITEM + MOVE.B (SP)+,D0 ;POP BOOLEAN RESULT + BNE MORE ;LOOP TILL FALSE + + +;----------------------------------------------------- +; +; DISCARD HANDLES, RESTORE GRAFPORT STATE AND QUIT +; +DONE MOVE.L PLAYSTATE+THECLIP(A6),A0 ;GET THECLIP RGNHANDLE + _DisposHandle ;DISCARD IT + MOVE.L CLIPRGN(A3),A0 ;GET TEMPCLIP + _DisposHandle ;DISCARD IT + LEA SAVEPORT(A6),A0 ;SRC = SAVEPORT + MOVEQ #PORTREC/2-1,D0 ;INIT DBRA COUNT +DONELP MOVE.W (A0)+,(A3)+ ;COPY A WORD INTO THEPORT + DBRA D0,DONELP ;LOOP ENTIRE PORT + CLR.L PATALIGN(A4) ;RESTORE PATALIGN TO (0,0) + CLR.L PLAYPIC(A4) ;SET PLAYPIC TO NIL + CLR.L PLAYINDEX(A4) ;AND PLAYINDEX TO 0 + +GOHOME MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'DRAWPICT' + + + + + .FUNC PicItem,1 + .REF GetPicData,ScalePt,MapPt,MapRect,MapRgn,MapPoly + .REF NewRgn,CopyRgn,SectRgn,UnpackBits + .REF StdText,StdLine,StdRect,StdRRect,StdOval + .REF StdArc,StdPoly,StdRgn,StdBits,StdComment +;------------------------------------------------------------------ +; +; FUNCTION PicItem(VAR playState: PicPlayRec): BOOLEAN; +; +; Draws one picture item, updating playState and thePort. +; Returns FALSE when an endPic opCode is encountered. +; The only state modified other than thePort and playState is patAlign. +; + + +;-------------------------------------------- +; +; OFFSETS WITHIN A PICTURE PLAY STATE RECORD: +; +THERECT .EQU 0 ;RECT +PENLOC .EQU THERECT+8 ;POINT +TEXTLOC .EQU PENLOC+4 ;POINT +OVALSIZE .EQU TEXTLOC+4 ;POINT +FROMRECT .EQU OVALSIZE+4 ;RECT +TORECT .EQU FROMRECT+8 ;RECT +NUMER .EQU TORECT+8 ;POINT +DENOM .EQU NUMER+4 ;POINT +THECLIP .EQU DENOM+4 ;RGNHANDLE +USERCLIP .EQU THECLIP+4 ;RGNHANDLE +PLAYREC .EQU USERCLIP+4 ;TOTAL SIZE +; +; params: +; +PARAMSIZE .EQU 4 +RESULT .EQU PARAMSIZE+8 ;BOOLEAN +PLAYSTATE .EQU RESULT-4 ;LONG, PICHANDLE +; +; locals: +; +HANDLE1 .EQU -4 ;HANDLE +HANDLE2 .EQU HANDLE1-4 ;HANDLE +DSTRECT .EQU HANDLE2-8 ;RECT +SRCRECT .EQU DSTRECT-8 ;RECT +SRCBITS .EQU SRCRECT-14 ;BITMAP, MUST BE BELOW SRCRECT +SAMEFLAG .EQU SRCBITS-2 ;BOOLEAN +NEWPT .EQU SAMEFLAG-4 ;LONG +TXDATA .EQU NEWPT-256 ;UP TO 256 CHARACTERS, + ;ALSO USED FOR PACKBUF !!! +SRCPTR .EQU TXDATA-4 ;LONG +DSTPTR .EQU SRCPTR-4 ;LONG +SAVESP .EQU DSTPTR-4 ;LONG +VARSIZE .EQU SAVESP ;TOTAL BYTES OF LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE LOCALS + MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGISTERS + MOVE.L SP,SAVESP(A6) ;REMEMBER STACK FOR ABORT + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;POINT TO CURRENT GRAFPORT + +; +; GET PICTURE OPCODE AND CHECK FOR END OF PICTURE. +; + BSR GetUByte ;GET OPCODE BYTE + MOVE D0,D7 ;PUT IT IN D7 + CMP.B #$FF,D7 ;IS THIS THE PICEND OPCODE ? + BNE.S NOTEND ;NO, CONTINUE + CLR.B RESULT(A6) ;YES, RETURN FALSE + BRA DONE ;AND QUIT +NOTEND MOVE.B #1,RESULT(A6) ;RETURN TRUE + +; +; CHECK FOR PARAM OPCODES $00..$1F +; + CMP #$20,D7 ;IS IT A PARAM OPCODE ? + BLO.S PARAMOP ;YES, GO TO IT + +; +; GET LO AND HI NIBBLES OF OPCODE, AND CASE ON HI NIBBLE (NOUN). +; + MOVE.B D7,D0 ;COPY OPCODE + AND #$F0,D0 ;MASK FOR HI NIBBLE + BTST #3,D7 ;IS OPCODE BIT 3 SET ? + SNE SAMEFLAG(A6) ;REMEMBER IN SAMEFLAG + AND #$7,D7 ;GET VERB FROM LO NIBBLE + LSR #3,D0 ;DOUBLE HI NIBBLE FOR INDEX + MOVE NOUNJMP(D0),D0 ;GET JUMP OFFSET + JMP NOUNJMP(D0) ;TAKE CASE JUMP + +NOUNJMP .WORD DONE-NOUNJMP ;NEVER TAKEN + .WORD DONE-NOUNJMP ;NEVER TAKEN + .WORD TXLNOP-NOUNJMP + .WORD RECTOP-NOUNJMP + .WORD RRECTOP-NOUNJMP + .WORD OVALOP-NOUNJMP + .WORD ARCOP-NOUNJMP + .WORD POLYOP-NOUNJMP + .WORD RGNOP-NOUNJMP + .WORD BITSOP-NOUNJMP + .WORD COMMOP-NOUNJMP + .WORD DONE-NOUNJMP + .WORD DONE-NOUNJMP + .WORD DONE-NOUNJMP + .WORD DONE-NOUNJMP + .WORD DONE-NOUNJMP + .WORD DONE-NOUNJMP + + +;--------------------------------------------------- +; +; OPCODES $00..$1F DO NO DRAWING, THEY JUST SET PARAMETERS. +; +PARAMOP AND #$1F,D7 ;GET LO 5 BITS OF OPCODE + ADD D7,D7 ;DOUBLE PARAM FOR CASE INDEX + MOVE PARMJMP(D7),D0 ;GET CASE JUMP OFFSET + JMP PARMJMP(D0) ;TAKE CASE JUMP +PARMJMP .WORD DONE-PARMJMP ;OPCODE 0 IS PURPOSELY A NOP + .WORD XCLIP-PARMJMP ;OPCODE $01 + .WORD XBKPAT-PARMJMP + .WORD XTXFONT-PARMJMP + .WORD XTXFACE-PARMJMP + .WORD XTXMODE-PARMJMP + .WORD XSPXTRA-PARMJMP + .WORD XPNSIZE-PARMJMP + .WORD XPNMODE-PARMJMP + .WORD XPNPAT-PARMJMP + .WORD XFILLPAT-PARMJMP + .WORD XOVSIZE-PARMJMP + .WORD XORIGIN-PARMJMP + .WORD XTXSIZE-PARMJMP + .WORD XFGCOL-PARMJMP + .WORD XBKCOL-PARMJMP ;OPCODE $0F + .WORD TXRATIO-PARMJMP ;OPCODE $10 + .WORD VERSION-PARMJMP ;OPCODE $11 + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP + .WORD DONE-PARMJMP ;OPCODE $1F + + + +XCLIP BSR GETHNDL ;COPY RGN INTO HANDLE1 + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L HANDLE1(A6),-(SP) ;PUSH HANDLE1 + MOVE.L THECLIP(A2),-(SP) ;PUSH PLAYSTATE THECLIP +XCLIP2 JSR COPYRGN ;COPY HANDLE1 INTO THECLIP + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L HANDLE1(A6),-(SP) ;PUSH HANDLE1 TEMP + PEA FROMRECT(A2) ;PUSH FROMRECT + PEA TORECT(A2) ;PUSH TORECT + JSR MAPRGN ;MAP RGN INTO DST COORDS + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L HANDLE1(A6),-(SP) ;PUSH MAPPED RGN + MOVE.L USERCLIP(A2),-(SP) ;PUSH ORIGINAL CLIP + MOVE.L CLIPRGN(A3),-(SP) ;PUSH DST = THEPORT^.CLIPRGN + JSR SECTRGN ;PUT INTERSECT INTO CLIPRGN + BRA KILL1 ;DISCARD HANDLE1 AND QUIT + + +GET8 MOVEQ #8,D6 ;BYTECOUNT = 8 + BRA GETDONE ;COPY 8 BYTES AND QUIT + +GET4 MOVEQ #4,D6 ;BYTECOUNT = 4 + BRA GETDONE ;COPY 4 BYTES AND QUIT + +GET2 MOVEQ #2,D6 ;BYTECOUNT = 2 + BRA GETDONE ;COPY 2 BYTES AND QUIT + + +XFGCOL LEA FGCOLOR(A3),A3 + BRA GET4 ;GET FOREGROUND COLOR + +XBKCOL LEA BKCOLOR(A3),A3 + BRA GET4 ;GET BACKGROUND COLOR + +XBKPAT LEA BKPAT(A3),A3 + BRA GET8 ;GET BKPAT + +XTXFONT LEA TXFONT(A3),A3 + BRA GET2 ;GET TXFONT + +XTXFACE LEA TXFACE(A3),A3 + MOVEQ #1,D6 + BRA GETDONE ;GET TXFACE + +XTXMODE LEA TXMODE(A3),A3 + BRA GET2 ;GET TXMODE + +XTXSIZE LEA TXSIZE(A3),A3 + BRA GET2 ;GET TXSIZE + +XSPXTRA LEA SPEXTRA(A3),A3 + BRA GET4 ;GET fixed point SPACE EXTRA + +XPNSIZE JSR GETLONG ;GET PNSIZE + MOVE.L D0,PNSIZE(A3) ;INSTALL INTO THEPORT + PEA PNSIZE(A3) + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + PEA FROMRECT(A2) + PEA TORECT(A2) + JSR SCALEPT ;SCALE PNSIZE + BRA DONE + +TXRATIO MOVE.L PLAYSTATE(A6),A3 ;POINT TO PLAYSTATE RECORD + JSR GETLONG ;GET TEXT NUMER + MOVE.L D0,NUMER(A3) ;INSTALL INTO PLAYSTATE + JSR GETLONG ;GET TEXT DENOM + MOVE.L D0,DENOM(A3) ;INSTALL INTO PLAYSTATE + PEA NUMER(A3) + PEA FROMRECT(A3) + PEA TORECT(A3) + JSR SCALEPT ;SCALE NUMER + BRA DONE + +VERSION BSR GETUBYTE ;GET VERSION NUMBER BYTE + BRA DONE ;AND IGNORE IT + +XPNMODE LEA PNMODE(A3),A3 + BRA GET2 ;GET PNMODE + +XPNPAT LEA PNPAT(A3),A3 + BRA GET8 ;GET PNPAT + +XFILLPAT LEA FILLPAT(A3),A3 + BRA GET8 ;GET FILLPAT + +XOVSIZE JSR GETLONG ;GET OVAL SIZE + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L D0,OVALSIZE(A2) + PEA OVALSIZE(A2) + PEA FROMRECT(A2) + PEA TORECT(A2) + JSR SCALEPT ;SCALE OVAL SIZE + BRA DONE + +;----------------------------------------------------- +; +; CHANGE ORIGIN: ADD DH AND DV TO FROMRECT, ADJUST PATALIGN, +; THEN RE-MAP THECLIP +; +XORIGIN JSR GETLONG ;GET DH,DV + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + ADD D0,FROMRECT+TOP(A2) ;ADD DV TO FROMRECT + ADD D0,FROMRECT+BOTTOM(A2) + ADD D0,PATALIGN+V(A4) ;AND TO PATALIGN + SWAP D0 ;GET DH IN LO WORD + ADD D0,FROMRECT+LEFT(A2) ;ADD DH TO FROMRECT + ADD D0,FROMRECT+RIGHT(A2) + ADD D0,PATALIGN+H(A4) ;AND TO PATALIGN +; +; RE-COMPUTE MAPPED CLIPRGN FROM UNMAPPED THECLIP +; + MOVE.L THECLIP(A2),-(SP) ;PUSH THECLIP + CLR.L -(SP) ;ROOM FOR FCN RESULT + JSR NEWRGN ;ALLOCATE A TEMP RGN + MOVE.L (SP),HANDLE1(A6) ;PUT IN HANDLE1 + BRA.S XCLIP2 ;COPY, MAP, SECT, AND DISCARD + + +;--------------------------------------------------- +; +; TEXT OR LINE OPCODES: +; +; LINE: 20, PNLOC(pt), NEWPT(pt) +; LINEFROM: 21, NEWPT(pt) +; SHORT LINE: 22, PNLOC(pt), DH(byte), DV(byte) +; SHORTLNFROM: 23, DH(byte), DV(byte) +; +; TEXT: 28,29,2A,2B +; +TXLNOP TST.B SAMEFLAG(A6) ;IS THIS A TEXT OPCODE ? + BNE TEXTOP ;YES, DO IT + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L PENLOC(A2),D0 ;NO, GET PREVIOUS LINE ENDPOINT + ROR #1,D7 ;IS LO NIBBLE ODD ? (BIT 0) + BCS.S LNFROM ;YES, DRAW LINE FROM PREV + BSR GETLONG ;NO, GET NEW STARTPT +LNFROM MOVE.L D0,PNLOC(A3) ;COPY STARTPT INTO THEPORT + MOVE.L D0,NEWPT(A6) ;SAVE FOR SHORT DH,DV BELOW + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + PEA PNLOC(A3) + PEA FROMRECT(A2) + PEA TORECT(A2) + JSR MAPPT ;MAP STARTPT + + ROR #1,D7 ;IS OPCODE BIT 1 SET ? + BCS.S SHORTLN ;YES, USE SHORT DH,DV FORM + BSR GETLONG ;NO, GET NEWPT + MOVE.L D0,NEWPT(A6) ;PUT IN TEMP + BRA.S LNOK ;AND CONTINUE +SHORTLN BSR GETSBYTE ;GET A SIGNED BYTE + ADD.W D0,NEWPT+H(A6) ;ADD TO STARTPT.H + BSR GETSBYTE ;GET A SIGNED BYTE + ADD.W D0,NEWPT+V(A6) ;ADD TO STARTPT.V + +LNOK MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L NEWPT(A6),PENLOC(A2) ;REMEMBER NEWPT FOR NEXT TIME + PEA NEWPT(A6) ;PUSH ADDRESS OF NEWPT + PEA FROMRECT(A2) + PEA TORECT(A2) + JSR MAPPT ;MAP NEWPT + MOVE.L NEWPT(A6),-(SP) ;PUSH NEWPT PARAM FOR LINEPROC + LEA STDLINE,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L LINEPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL0 ;CALL PROC AND QUIT + + +;--------------------------------------------------- +; +; LONG TEXT: 28, txLoc(pt), count(0..255), text +; DH TEXT: 29, dh(0..255), count(0..255), text +; DV TEXT: 2A, dv(0..255), count(0..255), text +; DHDV TEXT: 2B: dh(0..255), dv(0,..255), count(0..255), text +; +TEXTOP AND #3,D7 ;IS THIS A LONGTEXT OPCODE ? + BEQ.S LONGTXT ;YES, USE LONG FORMAT + ROR #1,D7 ;DO WE NEED DH ? (BIT 0) + BCC.S DHOK ;NO, CONTINUE + BSR GETUBYTE ;GET DH 0..255 + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + ADD D0,TEXTLOC+H(A2) ;BUMP TEXTLOC.H + +DHOK ROR #1,D7 ;DO WE NEED DV ? (BIT 1) + BCC.S TEXTOP2 ;NO, CONTINUE + BSR GETUBYTE ;GET DV 0..255 + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + ADD D0,TEXTLOC+V(A2) ;BUMP TEXTLOC.V + BRA.S TEXTOP2 ;SHARE CODE + +LONGTXT BSR GETLONG ;GET TXLOC, UNMAPPED + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L D0,TEXTLOC(A2) ;SAVE IN TEXTLOC + +TEXTOP2 BSR GETUBYTE ;GET TEXT LENGTH 0..255 + MOVE D0,D6 ;SAVE LENGTH IN D6 + PEA TXDATA(A6) ;PUSH ADDR OF TEXT BUF + MOVE D6,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET THE TEXT + + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L TEXTLOC(A2),PNLOC(A3) ;COPY TEXTLOC INTO PNLOC + PEA PNLOC(A3) + PEA FROMRECT(A2) + PEA TORECT(A2) + JSR MAPPT ;MAP PNLOC + + MOVE D6,-(SP) ;PUSH CHARACTER COUNT + PEA TXDATA(A6) ;PUSH ADDRESS OF TEXT + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L NUMER(A2),-(SP) ;PUSH NUMER + MOVE.L DENOM(A2),-(SP) ;PUSH DENOM + LEA STDTEXT,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L TEXTPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL0 ;CALL PROC AND QUIT + + +;--------------------------------------------------- +; +; Rect: OP, RECT +; +RECTOP MOVE.B D7,-(SP) ;PUSH VERB + BSR GETRECT ;GET AND PUSH DSTRECT + LEA STDRECT,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L RECTPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL0 ;CALL PROC AND QUIT + + +;--------------------------------------------------- +; +; RRect: OP, RECT, OVALPT +; +RRECTOP MOVE.B D7,-(SP) ;PUSH VERB + BSR GETRECT ;GET AND PUSH DSTRECT + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L OVALSIZE(A2),-(SP) ;PUSH OVHT,OVWD + LEA STDRRECT,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L RRECTPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL0 ;CALL PROC AND QUIT + + +;--------------------------------------------------- +; +; Oval: OP, RECT +; +OVALOP MOVE.B D7,-(SP) ;PUSH VERB + BSR GETRECT ;GET AND PUSH DSTRECT + LEA STDOVAL,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L OVALPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL0 ;CALL PROC AND QUIT + + +;--------------------------------------------------- +; +; Arc: OP, RECT, STARTANGLE, ARCANGLE +; +ARCOP MOVE.B D7,-(SP) ;PUSH VERB + BSR GETRECT ;GET AND PUSH DSTRECT + BSR GETWORD ;GET STARTANGLE + MOVE D0,-(SP) ;PUSH STARTANGLE + BSR GETWORD ;GET ARCANGLE + MOVE D0,-(SP) ;PUSH ARCANGLE + LEA STDARC,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L ARCPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL0 ;CALL PROC AND QUIT + + +;--------------------------------------------------- +; +; Poly: OP, POLY +; +POLYOP BSR GETHNDL ;COPY POLY INTO HANDLE1 + MOVE.L HANDLE1(A6),-(SP) ;PUSH POLYHANDLE + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + PEA FROMRECT(A2) ;PUSH FROMRECT + PEA TORECT(A2) ;PUSH TORECT + JSR MAPPOLY ;MAP POLY INTO DST COORDS + MOVE.B D7,-(SP) ;PUSH VERB + MOVE.L HANDLE1(A6),-(SP) ;PUSH POLYHANDLE + LEA STDPOLY,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L POLYPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL1 ;CALL PROC AND QUIT + + +;--------------------------------------------------- +; +; Rgn: OP, RGN +; +RGNOP BSR GETHNDL ;COPY RGN INTO HANDLE1 + MOVE.L HANDLE1(A6),-(SP) ;PUSH RGN + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + PEA FROMRECT(A2) ;PUSH FROMRECT + PEA TORECT(A2) ;PUSH TORECT + JSR MAPRGN ;MAP RGN INTO DSTRECT COORDS + MOVE.B D7,-(SP) ;PUSH VERB + MOVE.L HANDLE1(A6),-(SP) ;PUSH RGN + LEA STDRGN,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L RGNPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL1 ;CALL PROC, DISCARD AND QUIT + + +;-------------------------------------------------------------------------- +; +; BitsRect: 90, ROWBYTES, BOUNDS, SRCRECT, DSTRECT, MODE, +; BYTECOUNT, BITDATA, +; +; BitsRgn: 91, ROWBYTES, BOUNDS, SRCRECT, DSTRECT, MODE, +; MASKRGN, BYTECOUNT, BITDATA, +; +; PackBitsRect: 98, ROWBYTES, BOUNDS, SRCRECT, DSTRECT, MODE, +; BYTECOUNT, BITDATA, +; +; PackBitsRgn: 99, ROWBYTES, BOUNDS, SRCRECT, DSTRECT, MODE, +; MASKRGN, BYTECOUNT, BITDATA, +; +BITSOP PEA SRCBITS+ROWBYTES(A6) ;PUSH ADDR OF SRCBITS.ROWBYTES + MOVE #26,-(SP) ;PUSH BYTECOUNT = 26 + JSR GetPicData ;GET ROWBYTES,BOUNDS,SRC,DST + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + PEA DSTRECT(A6) + PEA FROMRECT(A2) + PEA TORECT(A2) + JSR MAPRECT ;MAP DSTRECT + PEA SRCBITS(A6) ;PUSH SRCBITS + PEA SRCRECT(A6) ;PUSH ADDR OF SRCRECT + PEA DSTRECT(A6) ;PUSH ADDR OF DSTRECT + BSR GETWORD ;GET MODE + MOVE D0,-(SP) ;PUSH MODE + + TST D7 ;IS MASKRGN USED ? + BNE.S USERGN ;YES, CONTINUE + CLR.L -(SP) ;NO, PUSH MASKRGN = NIL + BRA.S NOTRGN ;AND CONTINUE + +USERGN BSR GETHNDL ;GET MASKRGN INTO HANDLE1 + MOVE.L HANDLE1(A6),-(SP) ;PUSH MASKRGN + MOVE.L HANDLE1(A6),HANDLE2(A6) ;REMEMBER MASKRGN IN HANDLE2 + +NOTRGN MOVE SRCBITS+BOUNDS+BOTTOM(A6),D6 ;GET SRCBITS.BOTTOM + SUB SRCBITS+BOUNDS+TOP(A6),D6 ;CALC HEIGHT + MOVE D6,D5 ;COPY HEIGHT + MULU SRCBITS+ROWBYTES(A6),D5 ;CALC BITMAP SIZE + MOVE.L D5,D0 ;GET BYTECOUNT + _NewHandle ;ALLOCATE BITS HANDLE + BEQ MEMOK ;CONTINUE IF NOT MEMFULL + MOVE.L (SP)+,A0 ;POP MASKRGN (MAYBE NIL) + _DisposHandle ;DISCARD IT + BRA ABORT ;AND ABORT +MEMOK _HLock ;LOCK HANDLE1 + MOVE.L A0,HANDLE1(A6) ;REMEMBER IN HANDLE1 +; +; IF OPCODE BIT3 SET, THEN UNPACK COMPRESSED SCANLINES +; + MOVE.L HANDLE1(A6),A0 ;GET HANDLE1 + TST.B SAMEFLAG(A6) ;WAS BIT 3 SET ? + BEQ.S NOPACK ;NO, IT'S NOT PACKED + MOVE.L (A0),DSTPTR(A6) ;YES, INIT DSTPTR + BRA.S START1 ;GO TO LOOP START +MORE1 BSR GetUByte ;GET PACKED BYTECOUNT + PEA TXDATA(A6) ;PUSH ADDR OF BUFFER + MOVE.L (SP),SRCPTR(A6) ;PUT IN SRCPTR TOO + MOVE D0,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET PACKED DATA + PEA SRCPTR(A6) ;PUSH VAR SRCPTR + PEA DSTPTR(A6) ;PUSH VAR DSTPTR + MOVE SRCBITS+ROWBYTES(A6),-(SP) ;PUSH ROWBYTES + JSR UnpackBits ;UNPACK INTO HANDLE1 DATA +START1 DBRA D6,MORE1 ;LOOP HEIGHT ROWS + BRA.S DOBITS ;CONTINUE +; +; BIT3 = 0, DONT USE PACKING +; +NOPACK MOVE.L (A0),-(SP) ;PUSH MASTER + MOVE D5,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;READ BITMAP DATA BITS + +DOBITS MOVE.L HANDLE1(A6),A0 ;GET HANDLE1 + MOVE.L (A0),SRCBITS+BASEADDR(A6) ;FILL IN BASEADDR + LEA STDBITS,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S BITSOK ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L BITSPROC(A0),A0 ;NO, GET PROCPTR +BITSOK JSR (A0) ;CALL BITSPROC + MOVE.L HANDLE1(A6),A0 ;GET HANDLE1 + _HUnlock ;UNLOCK THE DATABITS + TST D7 ;IS MASKRGN USED ? + BEQ KILL1 ;NO, DISCARD ONLY DATABITS + BRA KILL2 ;DISCARD MASKRGN & DATABITS + + +;-------------------------------------------------------------------------- +; +; CommentOp: OP, KIND, { SIZE, DATA } +; +COMMOP BSR GETWORD ;GET COMMENT KIND IN D0 + MOVE D0,-(SP) ;PUSH FOR COMMENTPROC + TST.B D7 ;IS THIS SHORT FORM ? + BNE.S LONGCOM ;NO, GET MORE + CLR -(SP) ;YES, PUSH DATASIZE = 0 + CLR.L -(SP) ;PUSH DATAHANDLE = NIL + LEA STDCOMMENT,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L COMMENTPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL0 ;CALL PROC AND QUIT + +LONGCOM BSR GETWORD ;GET DATASIZE + MOVE D0,-(SP) ;PUSH DATASIZE + CLR D4 ;INIT BYTE INDEX FOR GETHND2 + BSR GETHND2 ;GET DATA INTO HANDLE1 + MOVE.L HANDLE1(A6),-(SP) ;PUSH DATA HANDLE + LEA STDCOMMENT,A0 ;POINT TO STANDARD PROC + MOVE.L GRAFPROCS(A3),D0 ;IS GRAFPROCS NIL ? + BEQ.S @1 ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L COMMENTPROC(A0),A0 ;NO, GET PROCPTR +@1 BRA CALL1 ;CALL PROC, DISCARD AND QUIT + + + MOVE.L GRAFGLOBALS(A5),A0 + MOVE.L SCREENBITS+BASEADDR(A0),A1 + MOVE SCREENBITS+ROWBYTES(A0),D0 + LEA TABLE1,A0 + MOVEQ #24,D1 +LOOP1 MOVE.L (A0)+,(A1) + ADD D0,A1 + DBRA D1,LOOP1 +LOOP2 BRA LOOP2 +TABLE1 .LONG $00000000 + .LONG $7EE9D200 + .LONG $44A91A00 + .LONG $74A99610 + + .LONG $14A91230 + .LONG $74EFD260 + .LONG $00000040 + .LONG $77744358 + + .LONG $4557C7FC + .LONG $77554FFE + .LONG $46544FF8 + .LONG $45744FF0 + + .LONG $00000FF0 + .LONG $7774EFF8 + .LONG $55548FFE + .LONG $7774CFFE + + .LONG $544487BC + .LONG $5447E318 + .LONG $00000000 + .LONG $7745D7FE + + .LONG $456D554A + .LONG $4555D56E + .LONG $4545154C + .LONG $77451D7A + + .LONG $00000000 + +;----------------------------------------------------- +; +; GET SOME BYTES AND QUIT +; +GETDONE MOVE.L A3,-(SP) ;PUSH DATAPTR + MOVE D6,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET DATA FROM THEPIC + BRA DONE + + +;------------------------------------------------------ +; +; LOCAL PROCEDURE TO GET AN UNSIGNED BYTE INTO D0 FROM PICTURE +; +GETUBYTE CLR.B -(SP) ;ALLOCATE TEMP + MOVE.L SP,-(SP) ;PUSH ADDR OF TEMP + MOVE #1,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET DATA FROM THEPIC + CLR D0 ;GET READY FOR BYTE + MOVE.B (SP)+,D0 ;POP RESULT INTO LO BYTE + RTS + + +;------------------------------------------------------ +; +; LOCAL PROCEDURE TO GET A SIGNED BYTE INTO D0 FROM PICTURE +; +GETSBYTE CLR.B -(SP) ;ALLOCATE TEMP + MOVE.L SP,-(SP) ;PUSH ADDR OF TEMP + MOVE #1,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET DATA FROM THEPIC + MOVE.B (SP)+,D0 ;POP RESULT + EXT.W D0 ;SIGN EXTEND TO WORD + RTS + + +;------------------------------------------------------ +; +; LOCAL PROCEDURE TO GET A WORD FROM PICTURE INTO D0 +; +GETWORD CLR.W -(SP) ;ALLOCATE TEMP + MOVE.L SP,-(SP) ;PUSH ADDR OF TEMP + MOVE #2,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET DATA FROM THEPIC + MOVE (SP)+,D0 ;RETURN ANSWER IN D0 + RTS + + +;---------------------------------------------------------- +; +; LOCAL PROCEDURE TO GET A LONG FROM PICTURE INTO D0 +; +GETLONG CLR.L -(SP) ;ALLOCATE TEMP + MOVE.L SP,-(SP) ;PUSH ADDR OF TEMP + MOVE #4,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET DATA FROM THEPIC + MOVE.L (SP)+,D0 ;RETURN ANSWER IN D0 + RTS + + +;---------------------------------------------------------- +; +; LOCAL PROCEDURE TO SET UP AND PUSH DSTRECT AS FOLLOWS: +; IF NOT SAMEFLAG, THEN GET NEXT 8 BYTES INTO THERECT. +; THEN MAP THERECT INTO DSTRECT, AND PUSH ADDR OF DSTRECT. +; CLOBBERS A0,D0 +; +GETRECT TST.B SAMEFLAG(A6) ;SAME RECT ? + BNE.S SAME1 ;YES, CONTINUE + + MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + PEA THERECT(A2) ;PUSH ADDR OF THERECT + MOVE #8,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET DATA FROM THEPIC + +SAME1 MOVE.L PLAYSTATE(A6),A2 ;POINT TO PLAYSTATE RECORD + MOVE.L THERECT(A2),DSTRECT(A6) ;COPY THERECT INTO DSTRECT + MOVE.L THERECT+4(A2),DSTRECT+4(A6) + PEA DSTRECT(A6) + PEA FROMRECT(A2) + PEA TORECT(A2) + JSR MAPRECT ;MAP DSTRECT + MOVE.L (SP)+,A0 ;POP RETURN ADDR + PEA DSTRECT(A6) ;PUSH ADDR OF MAPPED DSTRECT + JMP (A0) ;RETURN + + +;-------------------------------------------------------- +; +; LOCAL ROUTINE TO ALLOCATE, AND COPY HANDLE1 +; +; CLOBBERS D0-D2,A0-A1,D4,D5 +; +; TRICKY ENTRY AT GETHND2 WITH COUNT IN D0, D4 = 0 +; +GETHNDL MOVEQ #2,D4 ;INIT BYTE OFFSET FOR LATER + BSR GETWORD ;GET BYTECOUNT +GETHND2 EXT.L D0 ;MAKE COUNT LONG + MOVE.L D0,D5 ;PUT BYTECOUNT INTO D5 + _NewHandle ;ALLOCATE HANDLE + BNE ABORT ;ABORT IF MEMFULL + MOVE.L A0,HANDLE1(A6) ;SAVE IN HANDLE1 + _HLock ;LOCK HANDLE1 + MOVE.L HANDLE1(A6),A0 ;GET HANDLE1 + MOVE.L (A0),A0 ;DE-REFERENCE IT + MOVE D5,(A0) ;INSTALL SIZE WORD + SUB D4,D5 ;ADJUST COUNT + PEA 0(A0,D4) ;PUSH DATAPTR + MOVE D5,-(SP) ;PUSH BYTECOUNT + JSR GetPicData ;GET DATA FROM THEPIC + MOVE.L HANDLE1(A6),A0 ;GET HANDLE 1 + _HLock ;LOCK IT + RTS ;AND RETURN + + +;----------------------------------------------------------------- +; +; CALL BOTTLENECK PROC, DISPOSE OF ONE OR TWO HANDLES, AND QUIT +; +CALL0 JSR (A0) ;CALL PROC PTR + BRA.S DONE ;AND QUIT + +CALL1 JSR (A0) ;CALL PROC PTR + BRA.S KILL1 ;KILL HANDLE1 AND QUIT +; +; KILL ONE OR TWO HANDLE TEMPS +; +KILL2 MOVE.L HANDLE2(A6),A0 ;GET HANDLE2 + _DisposHandle ;DISCARD IT + +KILL1 MOVE.L HANDLE1(A6),A0 ;GET HANDLE1 + _DisposHandle ;DISCARD IT + BRA.S DONE + +ABORT MOVE.L SAVESP(A6),SP ;RESTORE STACK + CLR.B RESULT(A6) ;RETURN FALSE + +DONE MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'PICITEM ' + + + + + .FUNC GetPicData,2 + .REF StdGetPic +;------------------------------------------------------------------ +; +; FUNCTION GetPicData(dataPtr: QDPtr; byteCount: INTEGER); +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + BNE.S NOTSTD + JMP StdGetPic ;YES, USE STD PROC +NOTSTD MOVE.L D0,A0 + MOVE.L GETPICPROC(A0),A0 ;NO, GET GET PROC PTR + JMP (A0) ;AND CALL IT + + + + .PROC PutPicData,2 + .REF StdPutPic +;------------------------------------------------------ +; +; PROCEDURE PutPicData(dataPtr: QDPtr; byteCount:INTEGER); +; ADD SOME BYTES TO THEPIC. +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + BNE.S NOTSTD + JMP StdPutPic ;YES, USE STD PROC +NOTSTD MOVE.L D0,A0 + MOVE.L PUTPICPROC(A0),A0 ;NO, GET GET PROC PTR + JMP (A0) ;AND CALL IT + + + + .PROC DPutPicByte,1 + .DEF PutPicByte + .REF PutPicData +;------------------------------------------------------ +; +; PROCEDURE PutPicByte(data: Byte); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.B D0,-(SP) ;PUSH DATA BYTE + MOVE.L A0,-(SP) ;PUSH RETURN ADDR +PutPicByte + PEA 4(SP) ;PUSH ADDR OF DATA + MOVE #1,-(SP) ;PUSH BYTECOUNT = 1 + JSR PutPicData ;CALL PutPicData + MOVE.L (SP)+,A0 ;POP RETURN ADDR + TST.B (SP)+ ;STRIP PARAM + JMP (A0) ;AND RETURN + + + + .PROC PutPicWord,1 + .REF PutPicData +;------------------------------------------------------ +; +; PROCEDURE PutPicWord(data: INTEGER); +; + PEA 4(SP) ;PUSH ADDR OF DATA + MOVE #2,-(SP) ;PUSH BYTECOUNT = 2 + JSR PutPicData ;CALL PutPicData + MOVE.L (SP)+,A0 ;POP RETURN ADDR + TST.W (SP)+ ;STRIP PARAM + JMP (A0) ;AND RETURN + + + + .PROC PutPicLong,1 + .REF PutPicData +;------------------------------------------------------ +; +; PROCEDURE PutPicLong(data: LongInt); +; + PEA 4(SP) ;PUSH ADDR OF DATA + MOVE #4,-(SP) ;PUSH BYTECOUNT = 4 + JSR PutPicData ;CALL PutPicData + MOVE.L (SP)+,(SP) ;STRIP PARAM + RTS ;AND RETURN + + + + .PROC PutPicPat,1 + .REF PutPicData +;------------------------------------------------------ +; +; PROCEDURE PutPicPat(pat: Pattern); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE #8,-(SP) ;PUSH BYTECOUNT = 8 + MOVE.L A0,-(SP) ;PUSH RETURN ADDR + JMP PutPicData + + + + .PROC PutPicRect,2 + .REF DPutPicByte,PutPicData +;------------------------------------------------------ +; +; PROCEDURE PutPicRect(opCode: Byte; r: Rect); +; +; Add an opcode and rectangle to thePic and update picTheRect state variable. +; If rect is the same as picTheRect, then just add 8 to the Opcode. +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + MOVE.B (SP)+,D0 ;POP OPCODE + MOVE.L A0,-(SP) ;PUSH RETURN ADDR + + MOVE.L (A1),D2 ;GET TOPLEFT + MOVE.L 4(A1),D1 ;GET BOTRIGHT + + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L PICSAVE(A0),A0 ;GET PICSAVE HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE PICSAVE + CMP.L PICTHERECT(A0),D2 ;IS TOPLEFT THE SAME ? + BNE.S NOTSAME ;NO, CONTINUE + CMP.L PICTHERECT+4(A0),D1 ;IS BOTRIGHT THE SAME ? + BNE.S NOTSAME ;NO, CONTINUE + +SAME ADD #8,D0 ;YES, ADD 8 TO OPCODE + JMP DPutPicByte ;PUT MODIFIED OPCODE AND RETURN + +NOTSAME MOVE.L D2,PICTHERECT(A0) ;UPDATE PICTHERECT + MOVE.L D1,PICTHERECT+4(A0) + MOVE.L A1,-(SP) ;PUSH ADDR OF RECT FOR BELOW + MOVE #8,-(SP) ;PUSH BYTECOUNT FOR BELOW + JSR DPutPicByte ;PUT OPCODE (IN D0) + JSR PutPicData ;PUT 8 BYTES OF RECTANGLE +DONE RTS + + + + .PROC PutPicRgn,1 + .REF PutPicData +;------------------------------------------------------ +; +; PROCEDURE PutPicRgn(rgn: RgnHandle); +; ALSO called to put a polygon. +; + MOVE.L 4(SP),A0 ;PUSH RGNHANDLE + _HLock ;LOCK IT + MOVE.L 4(SP),A0 ;GET HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + MOVE.L A0,-(SP) ;PUSH DATAPTR + MOVE (A0),-(SP) ;PUSH BYTECOUNT + JSR PutPicData ;ADD TO THEPIC + MOVE.L 4(SP),A0 ;GET RGNHANDLE + _HUnlock ;UNLOCK IT + MOVE.L (SP)+,(SP) ;STRIP PARAM + RTS ;AND RETURN + + + + .PROC PutPicVerb,1 + .REF DPutPicByte,PutPicWord,PutPicLong,PutPicPat +;------------------------------------------------------ +; +; PROCEDURE PutPicVerb(verb: GrafVerb); +; +; check additional picture params associated with +; this verb, and add those that have changed to thePic. +; +PARAMSIZE .EQU 2 +VERB .EQU PARAMSIZE+8-2 ;BYTE + + LINK A6,#0 ;NO LOCAL VARS + MOVEM.L D5-D7/A3-A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;POINT TO CURRENT PORT + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.B VERB(A6),D7 ;GET VERB + CMP.B #PAINT,D7 ;CASE JUMP BASSED ON VERB + BLT.S FRAME1 + BEQ PAINT1 ;YES CHECK PNMODE, PNPAT + CMP.B #INVERT,D7 ;IS VERB INVERT ? + BEQ DONE ;YES, NOTHING TO CHECK + BLT.S ERASE1 + +FILL1 MOVE.L FILLPAT(A3),D5 ;GET FILLPAT + MOVE.L FILLPAT+4(A3),D6 + CMP.L PICFILLPAT(A4),D5 ;SAME AS PICFILLPAT ? + BNE.S @1 ;NO, PUT CHANGE TO THEPIC + CMP.L PICFILLPAT+4(A4),D6 + BEQ DONE +@1 MOVE.L D5,PICFILLPAT(A4) ;UPDATE STATE VARIABLE + MOVE.L D6,PICFILLPAT+4(A4) + MOVEQ #$0A,D0 ;PUSH FILLPAT OPCODE + JSR DPutPicByte ;ADD TO THEPIC + PEA FILLPAT(A3) + JSR PutPicPat ;PUT PATTERN DATA + BRA DONE ;AND QUIT + +ERASE1 MOVE.L BKPAT(A3),D5 ;GET BKPAT + MOVE.L BKPAT+4(A3),D6 + CMP.L PICBKPAT(A4),D5 ;SAME AS PICBKPAT ? + BNE.S NEWBK ;NO, PUT CHANGE TO THEPIC + CMP.L PICBKPAT+4(A4),D6 + BEQ DONE +NEWBK MOVE.L D5,PICBKPAT(A4) ;UPDATE STATE VARIABLE + MOVE.L D6,PICBKPAT+4(A4) + MOVEQ #$02,D0 ;BKPAT OPCODE + JSR DPutPicByte ;ADD TO THEPIC + PEA BKPAT(A3) + JSR PutPicPat ;PUT PATTERN DATA + BRA.S DONE ;AND QUIT + +FRAME1 MOVE.L PNSIZE(A3),D6 ;GET PNSIZE + CMP.L PICPNSIZE(A4),D6 ;HAS IT CHANGED ? + BEQ.S PAINT1 ;NO, CONTINUE + MOVEQ #$07,D0 + JSR DPutPicByte ;YES, PUT PNSIZE OPCODE + MOVE.L D6,-(SP) + JSR PutPicLong ;PUT NEW PNSIZE + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.L D6,PICPNSIZE(A4) ;AND UPDATE STATE VARIABLE + +PAINT1 MOVE PNMODE(A3),D6 ;GET PNMODE + CMP PICPNMODE(A4),D6 ;HAS IT CHANGED ? + BEQ.S MODEOK ;NO, CONTINUE + MOVEQ #$08,D0 + JSR DPutPicByte ;YES, PUT PNMODE OPCODE + MOVE D6,-(SP) + JSR PutPicWord ;PUT NEW PNMODE + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE D6,PICPNMODE(A4) ;AND UPDATE STATE VARIABLE + +MODEOK MOVE.L PNPAT(A3),D5 ;GET PNPAT + MOVE.L PNPAT+4(A3),D6 + CMP.L PICPNPAT(A4),D5 ;SAME AS PICPNPAT ? + BNE.S @1 ;NO, PUT CHANGE TO THEPIC + CMP.L PICPNPAT+4(A4),D6 + BEQ.S DONE +@1 MOVE.L D5,PICPNPAT(A4) ;UPDATE STATE VARIABLE + MOVE.L D6,PICPNPAT+4(A4) + MOVEQ #$09,D0 ;PNPAT OPCODE + JSR DPutPicByte ;ADD TO THEPIC + PEA PNPAT(A3) + JSR PutPicPat ;PUT PATTERN DATA + +DONE MOVEM.L (SP)+,D5-D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'PUTPICVERB' + + + + .PROC CheckPic,0 + .REF EqualRgn,CopyRgn + .REF DPutPicByte,PutPicLong,PutPicRgn +;--------------------------------------------------------------- +; +; PROCEDURE CheckPic; +; +; PUT GRAFGLOBALS IN A4, THEPORT IN A3, AND CHECK PICSAVE. +; IF PICSAVE IS NIL, RETURN FLAGS LE. +; +; IF PICSAVE NOT NIL, RETURN FLAGS GT, AND +; CHECK FOR CHANGES IN FGCOLOR, BKCOLOR, ORIGIN, AND CLIPRGN. +; +; + MOVE.L D7,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A3 ;POINT TO CURRENT GRAFPORT + TST.L PICSAVE(A3) ;ARE WE SAVING FOR A PICTURE ? + BEQ DONE ;NO, QUIT + CMP #-1,PNVIS(A3) ;IS PEN HIDDEN MORE THAN ONE ? + BLT DONE ;YES, DON'T ADD TO THEPIC + + MOVE.L PICSAVE(A3),A4 ;YES, GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE +; +; CHECK FOR CHANGES IN FOREGROUND COLOR +; + MOVE.L FGCOLOR(A3),D7 ;GET FORGROUND COLOR + CMP.L PICFGCOLOR(A4),D7 ;HAS IT CHANGED ? + BEQ.S FGCOLOK ;NO, CONTINUE + MOVEQ #$0E,D0 + JSR DPutPicByte ;PUT FGCOLOR OPCODE + MOVE.L D7,-(SP) + JSR PutPicLong ;PUT FGCOLOR + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.L D7,PICFGCOLOR(A4) ;UPDATE CURRENT STATE +FGCOLOK +; +; CHECK FOR CHANGES IN BACKGROUND COLOR +; + MOVE.L BKCOLOR(A3),D7 ;GET BACKGROUND COLOR + CMP.L PICBKCOLOR(A4),D7 ;HAS IT CHANGED ? + BEQ.S BKCOLOK ;NO, CONTINUE + MOVEQ #$0F,D0 + JSR DPutPicByte ;PUT BKCOLOR OPCODE + MOVE.L D7,-(SP) + JSR PutPicLong ;PUT BKCOLOR PARAM + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.L D7,PICBKCOLOR(A4) ;UPDATE CURRENT STATE +BKCOLOK +; +; CHECK FOR ORIGIN CHANGES +; + MOVE.L PORTRECT+TOPLEFT(A3),D0 ;GET PORTRECT.TOPLEFT + CMP.L PICORIGIN(A4),D0 ;SAME AS PIC ORIGIN ? + BEQ.S ORIGNOK ;YES, CONTINUE + + MOVE PORTRECT+LEFT(A3),D7 ;GET PORTRECT LEFT + SUB PICORIGIN+H(A4),D7 ;CALC DH + ADD D7,PICORIGIN+H(A4) ;UPDATE STATE VARIABLE + SWAP D7 ;PUT DH IN HI WORD + + MOVE PORTRECT+TOP(A3),D7 ;GET PORTRECT TOP + SUB PICORIGIN+V(A4),D7 ;CALC DV + ADD D7,PICORIGIN+V(A4) ;UPDATE STATE VARIABLE + + MOVEQ #$0C,D0 + JSR DPutPicByte ;PUT ORIGIN OPCODE TO THEPIC + MOVE.L D7,-(SP) + JSR PutPicLong ;PUT DH,DV TO THEPIC + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE +; +; CHECK FOR CLIPRGN CHANGES +; +ORIGNOK CLR.B -(SP) ;MAKE ROOM FOR FCN VALUE + MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN + MOVE.L PICCLIPRGN(A4),-(SP) ;PUSH STATE VARIABLE + JSR EQUALRGN ;ARE THEY THE SAME ? + TST.B (SP)+ ;TEST RESULT + BNE.S CLIPOK ;QUIT IF SAME + + MOVE.L CLIPRGN(A3),-(SP) ;SET UP FOR COPYRGN BELOW + MOVE.L PICCLIPRGN(A4),-(SP) + + MOVEQ #$01,D0 + JSR DPutPicByte ;PUT CLIPRGN PARAM OPCODE + MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN HANDLE + JSR PutPicRgn ;PUT CLIPRGN TO THEPIC + + JSR COPYRGN ;COPY CLIPRGN INTO PICCLIPRGN + +CLIPOK MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVEQ #1,D0 ;CLEAR ZERO FLAG +DONE MOVEM.L (SP)+,D7 ;MOVEM FOR CC, RESTORE REGS + RTS ;AND RETURN + + + + .PROC ScalePt,3 +;------------------------------------------------------------- +; +; PROCEDURE ScalePt(VAR pt: Point; fromRect,toRect: Rect); +; +; Scale a width and height from one coordinate system to another. +; If fromRect and toRect are the same size, then no change. +; If the input > 0, then enforce 1 pixel minimum on the output. +; +; pt.h := (pt.h * fromWidth) / toWidth +; pt.v := (pt.v * fromHeight) / toHeight +; +; restores ALL registers. +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 12 ;TOTAL BYTES OF PARAMS +PT .EQU PARAMSIZE+8-4 ;LONG, ADDR OF POINT +FROMRECT .EQU PT-4 ;LONG, ADDR OF RECT +TORECT .EQU FROMRECT-4 ;LONG, ADDR OF RECT + + LINK A6,#0 ;NO LOCALS + MOVEM.L D0-D6/A0-A2,-(SP) ;SAVE REGS + MOVE.L PT(A6),A0 ;POINT TO VAR PT + MOVE.L FROMRECT(A6),A1 ;POINT TO FROMRECT + MOVE.L TORECT(A6),A2 ;POINT TO TORECT + BSR.S SCALE1 ;SCALE THE HEIGHT + ADD #2,A0 ;OFFSET TO PT.H + ADD #2,A1 ;OFFSET TO FROMRECT.H + ADD #2,A2 ;OFFSET TO TORECT.H + BSR.S SCALE1 ;SCALE THE WIDTH +DONE MOVEM.L (SP)+,D0-D6/A0-A2 ;RESTORE REGS + UNLINK PARAMSIZE,'SCALEPT ' + + +;------------------------------------------------------- +; +; LOCAL ROUTINE TO SCALE A SINGLE WIDTH OR HEIGHT: +; IF INPUT <= 0, THEN OUTPUT WILL BE 0. +; IF INPUT > 0, THEN OUTPUT WILL BE AT LEAST 1. +; +SCALE1 MOVE BOTTOM(A1),D3 ;GET FROMRECT BOTTOM + SUB TOP(A1),D3 ;CALC FROMHEIGHT + MOVE BOTTOM(A2),D2 ;GET TORECT BOTTOM + SUB.W TOP(A2),D2 ;CALC TORECT HEIGHT + CMP D2,D3 ;ARE BOTH HEIGHTS THE SAME ? + BEQ.S SCDONE ;YES, SKIP + MOVE D3,D1 ;COPY DENOM = FROMHEIGHT + LSR #1,D1 ;CALC DENOM/2 (DENOM IS POS) + EXT.L D1 ;MAKE IT LONG + MOVE (A0),D0 ;GET SIZE COORD + BGT.S POS ;CONTINUE IF POSITIVE + CLR (A0) ;ELSE SET IT TO ZERO + RTS ;AND QUIT + +POS MULU D2,D0 ;MULT BY TORECT HEIGHT + ADD.L D1,D0 ;ADD FROMHEIGHT/2 FOR ROUNDING + DIVU D3,D0 ;DIV BY FROMHEIGHT + BNE.S SIZEOK ;IS RESULT ZERO ? +MINSIZE MOVEQ #1,D0 ;ENFORCE 1 PIXEL MIN SIZE +SIZEOK MOVE D0,(A0) ;UPDATE RESULT +SCDONE RTS + + + + .PROC MapPt,3 +;------------------------------------------------------------- +; +; PROCEDURE MapPt(VAR pt: Point; fromRect,toRect: Rect); +; +; Map a point from one coordinate system to another. +; +; pt.h := ((pt.h-fromLeft) * toWidth) / fromWidth + toLeft +; pt.v := ((pt.v-fromTop) * toHeight) / fromHeight + toTop +; +; restores ALL registers. +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 12 ;TOTAL BYTES OF PARAMS +PT .EQU PARAMSIZE+8-4 ;LONG, ADDR OF POINT +FROMRECT .EQU PT-4 ;LONG, ADDR OF RECT +TORECT .EQU FROMRECT-4 ;LONG, ADDR OF RECT + + LINK A6,#0 ;NO LOCALS + MOVEM.L D0-D6/A0-A2,-(SP) ;SAVE REGS + MOVE.L PT(A6),A0 ;POINT TO VAR PT + MOVE.L FROMRECT(A6),A1 ;POINT TO FROMRECT + MOVE.L TORECT(A6),A2 ;POINT TO TORECT + BSR.S MAP1 ;MAP THE VERTICAL COORD + ADD #2,A0 ;OFFSET TO PT.H + ADD #2,A1 ;OFFSET TO FROMRECT.H + ADD #2,A2 ;OFFSET TO TORECT.H + BSR.S MAP1 ;MAP THE HORIZ COORD +DONE MOVEM.L (SP)+,D0-D6/A0-A2 ;RESTORE REGS + UNLINK PARAMSIZE,'MAPPT ' + + +;----------------------------------------------- +; +; LOCAL ROUTINE TO MAP A SINGLE COORDINATE: +; +MAP1 MOVE TOP(A1),D2 ;GET FROMRECT TOP + MOVE BOTTOM(A1),D3 ;GET FROMRECT BOTTOM + SUB.W D2,D3 ;CALC FROMHEIGHT + MOVE TOP(A2),D4 ;GET TORECT TOP + MOVE BOTTOM(A2),D5 ;GET TORECT BOTTOM + SUB.W D4,D5 ;CALC TORECT HEIGHT + MOVE (A0),D0 ;GET COORD + SUB D2,D0 ;SUBTRACT FROMRECT TOP + CMP D3,D5 ;ARE BOTH HEIGHTS SAME ? + BEQ.S NOSCALE ;YES, SKIP THE SCALING + + MOVE D3,D1 ;DENOM = FROMHEIGHT + LSR #1,D1 ;CALC DENOM/2 (DENOM ALWAYS POS) + EXT.L D1 ;MAKE DENOM/2 LONG + MOVE D0,D2 ;IS COORD NEGATIVE ? + BPL.S NOTNEG ;NO, CONTINUE + NEG D0 ;YES, MAKE IT POSITIVE FOR MULDIV +NOTNEG MULU D5,D0 ;MULT COORD BY TORECT HEIGHT + ADD.L D1,D0 ;ADD FROMHEIGHT/2 FOR ROUNDING + DIVU D3,D0 ;DIV BY FROMHEIGHT + TST D2 ;WAS OLD COORD NEG ? + BPL.S NOSCALE ;NO, CONTINUE + NEG D0 ;YES, RESTORE IT TO NEGATIVE + +NOSCALE ADD D4,D0 ;ADD TORECT TOP + MOVE D0,(A0) ;UPDATE RESULT + RTS + + + + .PROC MapRect,3 + .REF MapPt +;------------------------------------------------------------- +; +; PROCEDURE MapRect(VAR dstRect: Rect; fromRect,toRect: Rect); +; +; Map both points of a rectangle from one coordinate system to another. +; restores ALL registers. +; + MOVE.L 12(SP),-(SP) ;PUSH DSTRECT + MOVE.L 12(SP),-(SP) ;PUSH FROMRECT + MOVE.L 12(SP),-(SP) ;PUSH TORECT + JSR MAPPT ;MAP TOPLEFT POINT + ADD.L #4,12(SP) ;OFFSET RECT TO BOTRIGHT + JMP MAPPT ;MAP BOTRIGHT AND RETURN + + + + .END diff --git a/Polygons.a b/Polygons.a new file mode 100755 index 0000000..3cb4b08 --- /dev/null +++ b/Polygons.a @@ -0,0 +1,417 @@ + .INCLUDE GRAFTYPES.TEXT +;-------------------------------------------------------------- +; +; +; **** *** * * * *** *** * * *** +; * * * * * * * * * * * * * * * +; * * * * * * * * * ** * * +; **** * * * * * ** * * * * * *** +; * * * * * * * * * * ** * +; * * * * * * * * * * * * * +; * *** ***** * *** *** * * *** +; +; + + .PROC StdPoly,2 + .REF CheckPic,PutPicVerb,DPutPicByte,PutPicRgn + .REF PushVerb,FrPoly,RSect,DrawPoly +;--------------------------------------------------------------- +; +; PROCEDURE StdPoly(verb: GrafVerb; poly: PolyHandle); +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 6 +VERB .EQU PARAMSIZE+8-2 ;GRAFVERB +POLY .EQU VERB-4 ;LONG, PolyHandle + +MINRECT .EQU -8 ;RECT +VARSIZE .EQU MINRECT ;TOTAL BYTES OF LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D5-D7/A2-A4,-(SP) ;SAVE REGS + MOVE.B VERB(A6),D7 ;GET VERB + JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE.S NOTPIC ;BRANCH IF NOT PICSAVE + + MOVE.B D7,-(SP) + JSR PutPicVerb ;PUT ADDIONAL PARAMS TO THEPIC + MOVEQ #$70,D0 ;PUT POLYNOUN IN HI NIBBLE + ADD D7,D0 ;PUT VERB IN LO NIBBLE + JSR DPutPicByte ;PUT OPCODE TO THEPIC + MOVE.L POLY(A6),-(SP) ;PUSH POLYHANDLE + JSR PutPicRgn ;TREAT SAME AS A REGION + +NOTPIC MOVE.L POLY(A6),A2 ;GET POLYHANDLE + TST.B D7 ;IS VERB FRAME ? + BNE.S NOTFR ;NO, CONTINUE + MOVE.L A2,-(SP) ;PUSH POLYHANDLE + JSR FrPoly ;FrPoly(poly); + BRA.S GOHOME ;AND QUIT + +NOTFR MOVE.L (A2),A0 ;DE-REFERANCE POLYHANDLE + PEA POLYBBOX(A0) ;PUSH POLYBBOX + MOVE.L VISRGN(A3),A0 ;GET VISRGN HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE HANDLE + PEA RGNBBOX(A0) ;PUSH VISRGN BBOX + MOVE.L CLIPRGN(A3),A0 ;GET CLIPRGN HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE HANDLE + PEA RGNBBOX(A0) ;PUSH CLIPRGN BBOX + MOVE #3,-(SP) ;PUSH NRECTS = 3 + PEA MINRECT(A6) ;PUT RESULT IN MINRECT + JSR RSECT ;CALC INTERSECTION + BEQ.S GOHOME ;QUIT IF NO INTERSECT + + MOVE.L A2,-(SP) ;PUSH POLYHANDLE + JSR PushVerb ;PUSH MODE AND PATTERN + JSR DrawPoly ;DrawPoly(poly,mode,pat); + +GOHOME MOVEM.L (SP)+,D5-D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDPOLY ' + + + + .PROC FramePoly,1 + .DEF CallPoly,PaintPoly,ErasePoly,InvertPoly,FillPoly + .REF StdPoly +;----------------------------------------------------- +; +; PROCEDURE FramePoly(* poly: PolyHandle *); +; + MOVEQ #FRAME,D0 ;VERB = FRAME + BRA.S CallPoly ;SHARE COMMON CODE + + + +;----------------------------------------------------- +; +; PROCEDURE PaintPoly(* poly: PolyHandle *); +; +PaintPoly + MOVEQ #PAINT,D0 ;VERB = PAINT + BRA.S CallPoly ;SHARE COMMON CODE + + + +;-------------------------------------------------------- +; +; PROCEDURE ErasePoly(* poly: PolyHandle *); +; +ErasePoly + MOVEQ #ERASE,D0 ;VERB = ERASE + BRA.S CallPoly ;SHARE COMMON CODE + + + +;-------------------------------------------------------- +; +; PROCEDURE InvertPoly(* poly: PolyHandle *); +; +InvertPoly + MOVEQ #INVERT,D0 ;VERB = INVERT + BRA.S CallPoly ;SHARE COMMON CODE + + + +;-------------------------------------------------------- +; +; PROCEDURE FillPoly(* poly: PolyHandle; pat: Pattern *); +; +FillPoly + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF PATTERN + MOVE.L A0,-(SP) ;PUT RETURN ADDR BACK + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA FILLPAT(A0),A0 ;POINT TO FILLPAT + MOVE.L (A1)+,(A0)+ ;COPY PAT INTO FILLPAT + MOVE.L (A1)+,(A0)+ ;ALL EIGHT BYTES + MOVEQ #FILL,D0 ;VERB = FILL + BRA.S CallPoly ;SHARE COMMON CODE + + + +;--------------------------------------------------------------- +; +; PROCEDURE CallPoly(poly: PolyHandle); +; +; code shared by FramePoly, PaintPoly, ErasePoly, InvertPoly, and FillPoly. +; enter with verb in D0. +; +CallPoly + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP POLY + MOVE.B D0,-(SP) ;PUSH VERB + MOVE.L A1,-(SP) ;PUSH POLY + MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDPOLY,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L POLYPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;GO TO IT + + + + .FUNC OpenPoly,0 + .REF HidePen,NewHandle +;--------------------------------------------------------------- +; +; FUNCTION OpenPoly: PolyHandle; +; +STARTSIZE .EQU 138 ;ENOUGH FOR 32 POINTS + + JSR HidePen ;TURN OFF DRAWING + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE #STARTSIZE,-(SP) ;PUSH BYTE COUNT = STARTSIZE + JSR NEWHANDLE ;ALLOCATE NEWHANDLE + MOVE.L (SP)+,A1 ;POP RESULTING HANDLE + MOVE.L A1,4(SP) ;PUT HANDLE IN FCN RESULT + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L A1,THEPOLY(A0) ;REMEMBER HANDLE IN THEPOLY + MOVE #STARTSIZE,POLYMAX(A0) ;POLYMAX := STARTSIZE; + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVEQ #1,D0 + MOVE.L D0,POLYSAVE(A0) ;POLYSAVE := TRUE + MOVE.L (A1),A1 ;DE-REFERENCE HANDLE + MOVE #10,(A1)+ ;INSTALL POLYSIZE = 10 + CLR.L (A1)+ ;ZERO OUT POLYBBOX + CLR.L (A1)+ + RTS ;RETURN + + + + .PROC ClosePoly,0 + .REF SetSize,ShowPen +;--------------------------------------------------------------- +; +; PROCEDURE ClosePoly; +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; + MOVEM.L D3-D7/A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A0 ;GET CURRENT GRAFPORT + CLR.L POLYSAVE(A0) ;POLYSAVE := FALSE + MOVE.L THEPOLY(A4),A4 ;GET THEPOLY HANDLE + MOVE.L (A4),A0 ;DE-REFERENCE THEPOLY + MOVE (A0)+,D7 ;GET POLYSIZE + CLR.L (A0)+ ;ZERO OUT POLYBBOX + CLR.L (A0)+ + MOVE D7,D6 + SUB #10,D6 + LSR #2,D6 ;NPOINTS = (SIZE-10) DIV 4 + BEQ.S EMPTY ;QUIT IF NO POINTS + + +;----------------------------------------------------- +; +; SCAN FOR BOUNDING BOX OF POLYGON +; + MOVE (A0)+,D1 ;TOP := FIRST POINT VERT + MOVE D1,D2 ;BOTTOM := FIRST POINT VERT + MOVE (A0)+,D3 ;LEFT := FIRST POINT HORIZ + MOVE D3,D4 ;RIGHT := FIRST POINT HORIZ + SUB #1,D6 ;DECREMENT POINT COUNT + BRA.S RIGHTOK ;GO TO LOOP START +NEXTPT MOVE (A0)+,D0 ;GET VERT COORD + CMP D1,D0 ;IS VERT < BBOX TOP ? + BGE.S TOPOK ;NO, CONTINUE + MOVE D0,D1 ;YES, UPDATE BBOX TOP +TOPOK CMP D2,D0 ;IS VERT > BBOX BOTTOM ? + BLE.S BOTOK ;NO, CONTINUE + MOVE D0,D2 ;YES, UPDATE BBOX BOTTOM +BOTOK MOVE (A0)+,D0 ;GET HORIZ COORD + CMP D3,D0 ;IS HORIZ < BBOX LEFT ? + BGE.S LEFTOK ;NO, CONTINUE + MOVE D0,D3 ;YES, UPDATE BBOX LEFT +LEFTOK CMP D4,D0 ;IS HORIZ > BBOX RIGHT ? + BLE.S RIGHTOK ;NO, CONTINUE + MOVE D0,D4 ;YES, UPDATE BBOX RIGHT +RIGHTOK DBRA D6,NEXTPT ;LOOP ALL POINTS + MOVE.L (A4),A0 ;DE-REFERENCE THEPOLY + LEA POLYBBOX(A0),A0 ;POINT TO POLYBBOX + MOVE D1,(A0)+ ;INSTALL BBOX TOP + MOVE D3,(A0)+ ;INSTALL BBOX LEFT + MOVE D2,(A0)+ ;INSTALL BBOX BOTTOM + MOVE D4,(A0)+ ;INSTALL BBOX RIGHT + + +;-------------------------------------------------------- +; +; TRIM THEPOLY TO FINAL SIZE, SHOW PEN AND QUIT +; +EMPTY MOVE.L A4,-(SP) ;PUSH THEPOLY HANDLE + MOVE D7,-(SP) ;PUSH BYTECOUNT = POLYSIZE + JSR SETSIZE ;TRIM TO MINIMUM SIZE + JSR SHOWPEN ;RESTORE PNVIS + MOVEM.L (SP)+,D3-D7/A4 ;RESTORE REGS + RTS ;AND RETURN + + + + .PROC KillPoly,1 +;--------------------------------------------------- +; +; PROCEDURE KillPoly(poly: PolyHandle); +; + MOVE.L (SP)+,A1 ;pop return addr + MOVE.L (SP)+,A0 ;pop handle + _DisposHandle ;discard it + JMP (A1) ;and return + + + + + .PROC OffsetPoly,3 +;--------------------------------------------------- +; +; PROCEDURE OffsetPoly(poly: PolyHandle; dh,dv: INTEGER); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDRESS + MOVE (SP)+,D0 ;POP DV + MOVE (SP)+,D1 ;POP DH + MOVE.L (SP)+,A1 ;POP POLYHANDLE + MOVE.L (A1),A1 ;DE-REFERENCE POLYHANDLE + MOVE (A1)+,D2 ;GET POLYSIZE + SUB #2,D2 ;CALC TOTAL # POINTS, INCL BBOX + LSR #2,D2 ; # POINTS = (SIZE-2) DIV 4 + SUB #1,D2 ;INIT DBRA COUNT +NEXTPT ADD D0,(A1)+ ;OFFSET VERT COORD + ADD D1,(A1)+ ;OFFSET HORIZ COORD + DBRA D2,NEXTPT ;LOOP FOR ALL POINTS + JMP (A0) ;AND RETURN + + + + .PROC MapPoly,3 + .REF MapPt,MapRect +;------------------------------------------------------------- +; +; PROCEDURE MapPoly(poly: PolyHandle; fromRect,toRect: Rect); +; +; A6 OFFSETS OF PARAMETERS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 12 +POLY .EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE +FROMRECT .EQU POLY-4 ;LONG, ADDR OF RECT +TORECT .EQU FROMRECT-4 ;LONG, ADDR OF RECT + + LINK A6,#0 ;ALLOCATE STACK FRAME + MOVEM.L D7/A2-A4,-(SP) ;SAVE REGS +; +; QUIT FAST IF FROMRECT = TORECT +; + MOVE.L FROMRECT(A6),A2 ;POINT TO FROMRECT + MOVE.L TORECT(A6),A3 ;POINT TO TORECT + MOVE.L (A2),D0 + CMP.L (A3),D0 ;IS TOPLEFT SAME ? + BNE.S NOTSAME ;NO, CONTINUE + MOVE.L 4(A2),D0 + CMP.L 4(A3),D0 ;YES, IS BOTRIGHT SAME TOO ? + BEQ.S DONE ;IF SO, JUST QUIT + +NOTSAME MOVE.L POLY(A6),A4 ;GET POLYHANDLE + MOVE.L (A4),A4 ;DE-REFERENCE POLYHANDLE + PEA POLYBBOX(A4) ;PUSH ADDR OF BBOX + MOVE.L A2,-(SP) ;PUSH FROMRECT + MOVE.L A3,-(SP) ;PUSH TORECT + JSR MAPRECT ;MAP POLYBBOX + + MOVEQ #10,D0 + MOVE POLYSIZE(A4),D7 ;GET POLYSIZE + SUB D0,D7 + LSR #2,D7 ;NPOINTS = (POLYSIZE-10) DIV 4 + ADD D0,A4 ;POINT TO FIRST POINT + BRA.S START ;GO TO LOOP START +NEXTPT MOVE.L A4,-(SP) ;PUSH ADDR OF POINT + MOVE.L A2,-(SP) ;PUSH FROMRECT + MOVE.L A3,-(SP) ;PUSH TORECT + JSR MAPPT ;MAP THIS POINT + ADD #4,A4 ;BUMP TO NEXT POINT +START DBRA D7,NEXTPT ;LOOP ALL POINTS IN POLY + +DONE MOVEM.L (SP)+,D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'MAPPOLY ' + + + + .PROC FrPoly,1 + .REF MoveTo,DoLine +;-------------------------------------------------------- +; +; PROCEDURE FrPoly(poly: PolyHandle); +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 4 +POLY .EQU PARAMSIZE+8-4 ;LONG, POLYHANDLE + + LINK A6,#0 ;ALLOCATE STACK FRAME + MOVEM.L D6-D7/A4,-(SP) ;SAVE REGS + MOVE.L POLY(A6),A4 ;GET POLYHANDLE + MOVE.L (A4),A0 ;DE-REFERENCE IT + MOVE (A0),D7 ;GET POLYSIZE + SUB #10,D7 + LSR #2,D7 ;NPOINTS = (SIZE-10) DIV 4 + BEQ.S DONE ;QUIT IF EMPTY POLYGON + MOVE.L 10(A0),-(SP) ;PUSH FIRST POINT + JSR MOVETO ;MOVETO(FIRST POINT) + MOVE.L #14,D6 ;INIT BYTE OFFSET + SUB #1,D7 ;DECREMENT COUNT + BRA.S START ;GOT TO LOOP START +NEXTPT MOVE.L (A4),A0 ;DE-REFERENCE POLYHANDLE + MOVE.L 0(A0,D6),-(SP) ;PUSH NEXT POINT + ADD #4,D6 ;BUMP BYTE OFFSET + JSR DOLINE ;DOLINE(PT) +START DBRA D7,NEXTPT ;LOOP FOR ALL POINTS +DONE MOVEM.L (SP)+,D6-D7/A4 ;RESTORE REGS + UNLINK PARAMSIZE,'FRPOLY ' + + + + .PROC DrawPoly,3 + .REF OpenRgn,FrPoly,DoLine,NewRgn,CloseRgn,DrawRgn +;-------------------------------------------------------- +; +; PROCEDURE DrawPoly(poly: PolyHandle; mode: INTEGER; VAR pat: Pattern); +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 10 +POLY .EQU PARAMSIZE+8-4 ;LONG, POLYHANDLE +MODE .EQU POLY-2 ;WORD +PAT .EQU MODE-4 ;LONG, ADDR OF PATTERN + + LINK A6,#0 ;NO LOCAL VARS + MOVE.L A4,-(SP) ;SAVE REG + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT PORT + TST PNVIS(A0) ;IS PNVIS NEG ? + BMI.S DONE ;YES, QUIT + JSR OPENRGN ;OpenRgn + MOVE.L POLY(A6),-(SP) + JSR FRPOLY ;FrPoly(poly); + MOVE.L POLY(A6),A0 + MOVE.L (A0),A0 + MOVE.L 10(A0),-(SP) ;PUSH FIRST POINT + JSR DOLINE ;MAKE SURE IT CLOSES + CLR.L -(SP) ;ROOM FOR FCN RESULT + JSR NEWRGN ;ALLOCATE TEMPRGN + MOVE.L (SP),A4 ;PUT TEMPRGN IN A4 + JSR CLOSERGN ;CLOSERGN(TEMPRGN) + MOVE.L A4,-(SP) + MOVE MODE(A6),-(SP) + MOVE.L PAT(A6),-(SP) + JSR DRAWRGN ;DrawRgn(tempRgn,mode,pat); + MOVE.L A4,A0 ;get tempRgn + _DisposHandle ;DISCARD IT +DONE MOVEM.L (SP)+,A4 ;RESTORE REG + UNLINK PARAMSIZE,'DRAWPOLY' + + + + .END diff --git a/PutLine.a b/PutLine.a new file mode 100755 index 0000000..e377dda --- /dev/null +++ b/PutLine.a @@ -0,0 +1,205 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; --> PUTLINE.TEXT +; +; Decompose a line segment into a list of inversion points. +; +; + + + .PROC PUTLINE,5 + .REF SETSIZE +;------------------------------------------------------------------ +; +; PROCEDURE PutLine(pt1,pt2: Point; dst: Handle; VAR index,bufMax: INTEGER); +; +; INVERSION POINTS FOR A LINE SEGMENT +; +; SP OFFSETS OF PARAMETERS: +; +PARAMSIZE .EQU 20 ;TOTAL SIZE OF PARAMETERS +PT1 .EQU PARAMSIZE+4-4 ;LONG, POINT (VALUE) +PT2 .EQU PT1-4 ;LONG, POINT (VALUE) +BUF .EQU PT2-4 ;LONG, HANDLE +INDEX .EQU BUF-4 ;LONG, (VAR) +BUFMAX .EQU INDEX-4 ;LONG, (VAR) + + + + MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGS, 8*4 ==> 32 + + +;----------------------------------------------------- +; +; IF LINE IS VERTICAL, IGNORE IT. +; + MOVE PT1+H+32(SP),D2 ;GET 1ST POINT'S HORIZ + MOVE PT2+H+32(SP),D4 ;GET 2ND POINT'S HORIZ + CMP D2,D4 ;IS THIS A VERTICAL LINE ? + BEQ GOHOME ;YES, IGNORE IT + + +;------------------------------------------------------ +; +; CALC BYTESNEEDED = 8 * ( Min(ABS(dh),ABS(dv)) + 1) +; + MOVE D2,D0 ;GET H1 + SUB D4,D0 ;SUBTRACT H2 + BPL.S DHPOS ;BR IF DH POS + NEG D0 ;ELSE TAKE ABSOLUTE VALUE +DHPOS MOVE PT1+V+32(SP),D1 ;GET V1 + SUB PT2+V+32(SP),D1 ;SUBTRACT V2 + BPL.S DVPOS ;BR IF DV POS + NEG D1 ;ELSE TAKE ABSOLUTE VALUE +DVPOS CMP D1,D0 ;IS DH <= DV ? + BLE.S DHLESS ;YES, CONTINUE + MOVE D1,D0 ;NO, PUT MIN(DH,DV) INTO D0 +DHLESS ADD #1,D0 ;CALC MIN(DH,DV)+1 + LSL #3,D0 ;TIMES EIGHT FOR BYTESNEEDED + + + MOVE.L BUF+32(SP),A3 ;GET DSTHANDLE + MOVE.L INDEX+32(SP),A4 ;POINT TO CURRENT INDEX + +;----------------------------------------------------- +; +; GROW POINT BUFFER AS NECESSARY TO HOLD BYTESNEEDED +; + ADD (A4),D0 ;NEWSIZE := INDEX + BYTESNEEDED + MOVE.L BUFMAX+32(SP),A0 ;POINT TO BUFMAX + CMP (A0),D0 ;DO WE HAVE TO GROW DSTBUF ? + BLE.S NOGROW ;NO, CONTINUE + ADD #512,D0 ;GROW IN CHUNKS + MOVE D0,(A0) ;UPDATE NEW BUFMAX + MOVE.L A3,-(SP) ;PUSH DSTBUF HANDLE + MOVE D0,-(SP) ;PUSH NEW BUFMAX + JSR SETSIZE ;MAKE THE BUFFER BIGGER + MOVE PT1+H+32(SP),D2 ;RESTORE CLOBBERED REG + +NOGROW + + + MOVE.L (A3),A3 ;DE-REFERENCE DSTHANDLE + ADD (A4),A3 ;ADD INDEX TO BUFPTR + +;----------------------------------------------------- +; +; IF LINE IS HORIZONTAL, PUT ITS TWO ENDPOINTS +; + MOVE PT1+V+32(SP),D1 ;GET 1ST POINT'S VERT + MOVE PT2+V+32(SP),D3 ;GET 2ND POINT'S VERT + CMP D1,D3 ;IS THIS A HORIZONTAL LINE ? + BNE.S SLANTED ;NO, BRANCH + MOVE D1,(A3)+ ;PUT V1 VERT COORD + MOVE D2,(A3)+ ;PUT H1 HORIZ COORD + MOVE D3,(A3)+ ;PUT V2 VERT COORD + MOVE D4,(A3)+ ;PUT H2 HORIZ COORD + BRA.S DONE ;UPDATE INDEX AND QUIT + + +;------------------------------------------------------ +; +; LINE IS SLANTED. DIVIDE IT INTO HORIZONTAL SLABS +; AND PUT THE TWO ENDPOINTS OF EACH SLAB. +; +; START BY SORTING POINTS VERTICALLY. +; +SLANTED BGT.S NOSWAP ;SKIP IF ALREADY IN ORDER + EXG D1,D3 ;SORT POINTS BY VERTICAL + EXG D2,D4 ;SWAP HORIZ TO MATCH +NOSWAP MOVE D1,D6 ;INIT V TO TOPV + + +;------------------------------------------------------------ +; +; CALCULATE FIXED POINT SLOPE = FixRatio(dh,dv); +; + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE D4,-(SP) ;PUSH BOTTOM HORIZ + SUB D2,(SP) ;CALC DH + MOVE D3,-(SP) ;PUSH BOTTOM VERT + SUB D1,(SP) ;CALC DV + _FixRatio ;CALC FIXED POINT SLOPE + MOVE.L (SP)+,D7 ;POP RESULT + + +;--------------------------------------------------------- +; +; SET UP STARTING HORIZ FIXED POINT. +; + MOVE.W D2,D1 + SWAP D1 ;HORIZ.INT := TOP HORIZ + MOVE.W #$8000,D1 ;HORIZ.FRACT := 1/2 +; +; ADJUST HORIZ DEPENDING ON SIGN AND MAGNITUDE OF SLOPE +; + MOVE.L D7,D0 ;COPY SLOPE + ASR.L #1,D0 ;CALC SLOPE/2 + ADD.L D0,D1 ;HORIZ := HORIZ + SLOPE/2 + + MOVE.L #$00010000,D0 + + TST.L D7 ;IS SLOPE NEG ? + BMI.S NEGSLOPE ;YES, CONTINUE + + CMP.L D0,D7 ;IS SLOPE < ONE ? + BGE.S SLOPEOK ;NO, CONTINUE + ADD.L D7,D1 ;ADD SLOPE TO LEFTEDGE + BRA.S SLOPEOK ;CONTINUE + +NEGSLOPE CMP.L #$FFFF0000,D7 ;IS SLOPE > -ONE ? + BGE.S SLOPEOK ;YES, CONTINUE + ADD.L D0,D1 ;YES, HORIZ := HORIZ + 1 + +SLOPEOK + + + +;------------------------------------------------------ +; +; FOR VERT:=TOPV TO BOTV-1 ADD SLOPE TO HORIZ AND PUT SLABS +; + MOVE D2,D5 ;H:=TOPH +LOOP SWAP D1 ;GET HORIZ.INT INTO D1 LOWER + CMP D1,D5 ;HAS HORIZ.INT CHANGED ? + BEQ.S NOCHNG ;NO, CONTINUE + MOVE D6,(A3)+ ;YES, PUT VERT COORD + MOVE D5,(A3)+ ;PUT OLD HORIZ COORD + MOVE.W D1,D5 ;OLDH := HORIZ.INT + MOVE D6,(A3)+ ;PUT VERT COORD + MOVE D5,(A3)+ ;PUT NEW HORIZ COORD +NOCHNG SWAP D1 ;PUTBACK HORIZ.INT INTO D1 UPPER + ADD #1,D6 ;VERT:=VERT+1 + ADD.L D7,D1 ;ADD SLOPE TO HORIZ + CMP D6,D3 ;IS VERT AT BOTTOM VERT YET ? + BNE LOOP ;NO, GO FOR MORE + + +;------------------------------------------------- +; +; FINISH UP LAST SLAB +; + CMP D4,D5 ;IS OLDH = BOTTOM H ? + BEQ.S DONE ;YES, CONTINUE + MOVE D6,(A3)+ ;NO, PUT VERT COORD + MOVE D5,(A3)+ ;PUT HORIZ COORD + MOVE D6,(A3)+ ;PUT VERT COORD + MOVE D4,(A3)+ ;PUT BOTTOM H COORD + + +;--------------------------------------------------- +; +; UPDATE INDEX TO REFLECT POINTS ADDED. +; +DONE MOVE.L BUF+32(SP),A0 ;GET DSTHANDLE + SUB.L (A0),A3 ;INDEX := BUFPTR-BUFSTART + MOVE A3,(A4) ;UPDATE INDEX + +GOHOME MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE REGS + MOVE.L (SP)+,A0 + ADD.W #PARAMSIZE,A7 + JMP (A0) + + + .END diff --git a/PutOval.a b/PutOval.a new file mode 100755 index 0000000..15b1444 --- /dev/null +++ b/PutOval.a @@ -0,0 +1,249 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; --> PUTOVAL.TEXT +; +; Routine to add the inversion points for an oval to a region. +; + + +;------------------------------------------------------ +; +; OFFSETS IN AN OVAL STATE RECORD: +; +OVALTOP .EQU 0 ;INTEGER +OVALBOT .EQU OVALTOP+2 ;INTEGER +OVALY .EQU OVALBOT+2 ;INTEGER +RSQYSQ .EQU OVALY+2 ;LONGINT +SQUARE .EQU RSQYSQ+4 ;64 BIT LONGFIX +ODDNUM .EQU SQUARE+8 ;64 BIT LONGFIX +ODDBUMP .EQU ODDNUM+8 ;64 BIT LONGFIX +LEFTEDGE .EQU ODDBUMP+8 ;32 BIT FIXED POINT +RIGHTEDGE .EQU LEFTEDGE+4 ;32 BIT FIXED POINT +ONEHALF .EQU RIGHTEDGE+4 ;32 BIT FIXED POINT +OVALSIZE .EQU ONEHALF+4 ;SIZE OF AN OVALREC + + + + .PROC PUTOVAL,6 + .REF INITOVAL,BUMPOVAL,SETSIZE +;---------------------------------------------------------------- +; +; PROCEDURE PutOval(dstRect: Rect; ovalWidth,ovalHeight: INTEGER; +; bufHandle: Handle; VAR index,size: INTEGER); +; +; Create region inversion points for an oval or roundRect. +; + + +;------------------------------------------------ +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 20 ;TOTAL SIZE OF PARAMETERS +DSTRECT .EQU PARAMSIZE+8-4 ;ADDR OF RECT +OVALWIDTH .EQU DSTRECT-2 ;INTEGER +OVALHEIGHT .EQU OVALWIDTH-2 ;INTEGER +BUFHANDLE .EQU OVALHEIGHT-4 ;LONG, HANDLE +INDEX .EQU BUFHANDLE-4 ;LONG, VAR +SIZE .EQU INDEX-4 ;LONG, VAR + + +;------------------------------------------------ +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +OVAL .EQU -OVALSIZE ;OVAL RECORD +SKIPTOP .EQU OVAL-2 ;WORD +SKIPBOT .EQU SKIPTOP-2 ;WORD +OLDLEFT .EQU SKIPBOT-2 ;WORD +OLDRIGHT .EQU OLDLEFT-2 ;WORD +VARSIZE .EQU OLDRIGHT ;SIZE OF LOCAL VARIABLES + + +ENTRY LINK A6,#VARSIZE ;ALLOCATE LOCAL VARS + MOVEM.L D0-D7/A1-A5,-(SP) ;SAVE REGS + + +;--------------------------------------------------------------- +; +; INIT AN OVAL RECORD +; + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + LEA OVAL(A6),A1 ;POINT TO OVAL RECORD + MOVE OVALWIDTH(A6),D2 ;GET OVALWIDTH + MOVE OVALHEIGHT(A6),D1 ;GET OVALHEIGHT + JSR INITOVAL ;INIT OVAL RECORD + MOVE.W OVAL+LEFTEDGE(A6),OLDLEFT(A6) + MOVE.W OVAL+RIGHTEDGE(A6),OLDRIGHT(A6) + + MOVE OVALHEIGHT(A6),D0 ;GET OVALHEIGHT + ASR #1,D0 ;CALC OVAL HEIGHT DIV 2 + ADD OVAL+OVALTOP(A6),D0 ;ADD OVAL TOP + MOVE D0,SKIPTOP(A6) ;SAVE SKIPTOP + + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + ADD BOTTOM(A0),D0 ;ADD BOTTOM + SUB TOP(A0),D0 ;SUBTRACT TOP + SUB OVALHEIGHT(A6),D0 ;SUBTRACT OVALHEIGHT + MOVE D0,SKIPBOT(A6) ;SAVE SKIPBOT + + +;----------------------------------------------------------------- +; +; GET BUF HANDLE, DE-REFERENCE IT, AND ADD INDEX +; + MOVE.L BUFHANDLE(A6),A3 ;GET HANDLE + MOVE.L (A3),A3 ;DE-REFERENCE IT + MOVE.L A3,A2 ;REMEMBER BUFSTART FOR LATER + MOVE.L INDEX(A6),A0 ;GET ADDR OF INDEX + ADD (A0),A3 ;ADD INDEX TO BUFPTR + + +;---------------------------------------------------------- +; +; BUFLIMIT := BUFSTART + BUFSIZE +; + MOVE.L A2,A1 ;GET BUFSTART + MOVE.L SIZE(A6),A0 ;GET ADDR OF SIZE + ADD (A0),A1 ;LEAVE BUFLIMIT IN A1 + + +;------------------------------------------------ +; +; PUT THE TOP EDGE +; + MOVE OVAL+OVALTOP(A6),D6 ;START VERT:= OVAL TOP + MOVE OLDLEFT(A6),D5 + JSR PUTPT ;PUTPOINT (OLDLEFT,VERT) + MOVE OLDRIGHT(A6),D5 + JSR PUTPT ;PUTPOINT (OLDRIGHT,VERT) + + +;----------------------------------------------------- +; +; FOR EACH VERTICAL, BUMP LEFTEDGE AND RIGHTEDGE. +; IF THEY DIFFER FROM OLDLEFT AND OLDRIGHT, PUT INVERSION +; POINTS FOR THE DIFFERENCES +; +NXTVERT CMP SKIPTOP(A6),D6 ;IS VERT < SKIPTOP ? + BLT.S YESBUMP ;YES, BUMP OVAL RECORD + CMP SKIPBOT(A6),D6 ;IS VERT >= SKIPBOT ? + BLT.S RIGHTOK ;NO, SKIP BUMPING + +YESBUMP MOVEM.L D6/A1-A3,-(SP) ;PRESERVE REGS + LEA OVAL(A6),A3 ;POINT TO OVAL RECORD + MOVE D6,D0 ;GET CURRENT VERT + JSR BUMPOVAL ;BUMP IT TO NEXT SCANLINE + MOVEM.L (SP)+,D6/A1-A3 ;RESTORE REGS + + +; CHECK LEFT EDGE AND PUT TWO INVERSION POINTS IF IT HAS CHANGED + + MOVE.W OVAL+LEFTEDGE(A6),D5 ;GET LEFTEDGE.INT + CMP OLDLEFT(A6),D5 ;SAME AS OLDLEFT ? + BEQ.S LEFTOK ;YES, CONTINUE + JSR PUTPT ;PUTPOINT (NEWLEFT,VERT) + MOVE OLDLEFT(A6),D5 + JSR PUTPT ;PUTPOINT(OLDLEFT,VERT) + MOVE OVAL+LEFTEDGE(A6),OLDLEFT(A6) ;UPDATE OLDLEFT + +; CHECK RIGHT EDGE AND PUT TWO INVERSION POINTS IF IT HAS CHANGED + +LEFTOK MOVE.W OVAL+RIGHTEDGE(A6),D5 ;GET RIGHTEDGE.INT + CMP OLDRIGHT(A6),D5 ;SAME AS OLDRIGHT ? + BEQ.S RIGHTOK ;YES, CONTINUE + JSR PUTPT ;PUTPOINT (NEWRIGHT,VERT) + MOVE OLDRIGHT(A6),D5 + JSR PUTPT ;PUTPOINT(OLDRIGHT,VERT) + MOVE OVAL+RIGHTEDGE(A6),OLDRIGHT(A6) ;UPDATE OLDRIGHT + +RIGHTOK ADD #1,D6 ;BUMP CURRENT VERT + CMP OVAL+OVALBOT(A6),D6 ;DONE WITH THE OVAL ? + BLT NXTVERT ;LOOP FOR ALL VERTICALS + + +;------------------------------------------------ +; +; PUT THE BOTTOM EDGE +; + MOVE OLDLEFT(A6),D5 + JSR PUTPT ;PUTPOINT (OLDLEFT,VERT) + MOVE OLDRIGHT(A6),D5 + JSR PUTPT ;PUTPOINT (OLDRIGHT,VERT) + + +;---------------------------------------------------- +; +; UPDATE INDEX TO REFLECT POINTS ADDED, CLEAN UP STACK AND GO HOME. +; + SUB.L A2,A3 ;CALC BUFPTR-BUFSTART + MOVE.L INDEX(A6),A0 ;GET VAR ADDR OF INDEX + MOVE A3,(A0) ;UPDATE INDEX + MOVEM.L (SP)+,D0-D7/A1-A5 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'PUTOVAL ' + + + +;----------------------------------------------------------------------- +; +; Local routine to Append a point to the end of the saved points buffer, +; extending buffer if necessary. If pt is a duplicate of the last pt, +; cancel both instead. +; +; INPUTS: D5: HORIZ COORD +; D6: VERT COORD +; A1: BUFLIMIT GETS EXPANDED AND RELOCATED +; A2: BUFSTART GETS RELOCATED +; A3: BUFPTR GETS BUMPED AND RELOCATED +; +; ALTERS: A1,A2,A3, VAR SIZE +; +PUTPT CMP.L A1,A3 ;IS BUFPTR < BUFLIMIT ? + BLT.S SIZEOK ;YES, CONTINUE + + +;--------------------------------------------------------------------- +; +; BUFFER IS FULL, CALL STORAGE ALLOCATOR TO MAKE ROOM FOR 256 MORE POINTS. +; UPDATE BUFPTR, BUFSTART, BUFLIMIT, AND BUFSIZE AFTER RELOCATION. +; + SUB.L A2,A3 ;MAKE BUFPTR RELATIVE + SUB.L A2,A1 ;MAKE BUFLIMIT RELATIVE + ADD #1024,A1 ;MAKE BUFLIMIT BIGGER + + MOVEM.L D0-D7/A0-A3,-(SP) ;SAVE REGS + MOVE.L SIZE(A6),A0 ;GET ADDR OF SIZE + MOVE A1,(A0) ;UPDATE BUFFER SIZE + MOVE.L BUFHANDLE(A6),-(SP) ;PUSH HANDLE PARAM + MOVE A1,-(SP) ;PUSH NEW SIZE + JSR SETSIZE ;MAKE THE BUFFER BIGGER + MOVEM.L (SP)+,D0-D7/A0-A3 ;RESTORE REGS + + MOVE.L BUFHANDLE(A6),A2 ;GET BUF HANDLE + MOVE.L (A2),A2 ;GET NEW BUFSTART + ADD.L A2,A3 ;MAKE BUFPTR UN-RELATIVE + ADD.L A2,A1 ;MAKE BUFLIMIT UN-RELATIVE + + +;------------------------------------------------------------------- +; +; ADD NEW POINT TO THE SAVE BUFFER UNLESS IT MATCHED THE PREVIOUS PT. +; DELETE DUPLICATE POINTS SINCE THEY WILL CANCEL EACH OTHER ANYWAY. +; +SIZEOK CMP.L A2,A3 ;IS BUFPTR=STARTPTR ? + BEQ.S APPEND ;BR IF FIRST POINT + CMP -4+H(A3),D5 ;IS PREVIOUS HORIZ SAME ? + BNE.S APPEND ;NO, APPEND NEW POINT + CMP -4+V(A3),D6 ;YES, IS PREVIOUS VERT SAME TOO ? + BNE.S APPEND ;NO, APPEND NEW POINT + SUB #4,A3 ;YES, DELETE OLD INSTEAD + RTS + +APPEND MOVE D6,(A3)+ ;PUT VERT COORD + MOVE D5,(A3)+ ;PUT HORIZ COORD + RTS + + + + .END diff --git a/PutRgn.a b/PutRgn.a new file mode 100755 index 0000000..fb7a7c0 --- /dev/null +++ b/PutRgn.a @@ -0,0 +1,79 @@ + .INCLUDE GRAFTYPES.TEXT + + + .PROC PUTRGN,4 + .REF SETSIZE +;---------------------------------------------------------------- +; +; PROCEDURE PutRgn(Rgn: RgnHandle; bufHandle: Handle; VAR index,size: INTEGER); +; +; Expands a region out to an array of inversion points. +; + + +;------------------------------------------------ +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 16 ;TOTAL SIZE OF PARAMETERS +RGNHANDLE .EQU PARAMSIZE+8-4 ;LONG,RGNHANDLE +BUFHANDLE .EQU RGNHANDLE-4 ;LONG, HANDLE +INDEX .EQU BUFHANDLE-4 ;LONG, VAR +SIZE .EQU INDEX-4 ;LONG, VAR + + + LINK A6,#0 ;NO LOCAL VARS + MOVEM.L D7/A2-A4,-(SP) ;SAVE REGS + +;------------------------------------------------------- +; +; EXPAND BUF TO FIT WORST CASE BYTESNEEDED = RGNSIZE * 2 +; + MOVE.L BUFHANDLE(A6),A4 ;GET BUFHANDLE + MOVE.L RGNHANDLE(A6),A3 ;GET RGNHANDLE + MOVE.L INDEX(A6),A2 ;POINT TO CURRENT INDEX + MOVE.L (A3),A0 ;DE-REFERENCE RGN + MOVE (A0),D7 ;GET RGNSIZE + ADD D7,D7 ;TIMES 2 + ADD (A2),D7 ;ADD CURRENT INDEX + MOVE.L SIZE(A6),A1 ;POINT TO SIZE + CMP (A1),D7 ;IS REQUIRED > CURRENT SIZE ? + BLE.S NOGROW ;NO, CONTINUE + + ADD #256,D7 ;GROW IN CHUNKS + MOVE D7,(A1) ;UPDATE CURRENT SIZE + MOVE.L A4,-(SP) ;PUSH BUFHANDLE + MOVE D7,-(SP) ;PUSH NEW SIZE + JSR SETSIZE ;MAKE ROOM IN BUF + MOVE.L (A3),A0 ;RE-DEREFERENCE RGNHANDLE + MOVE.L INDEX(A6),A2 ;GET ADDR OF INDEX AGAIN + +NOGROW MOVE.L (A4),A1 ;DE-REFERENCE BUFHANDLE + ADD (A2),A1 ;ADD INDEX TO BUFPTR + CMP #10,RGNSIZE(A0) ;IS REGION RECTANGULAR ? + BNE.S NOTRECT ;NO, CONTINUE + ADD #2,A0 ;YES, POINT TO BBOX TOPLEFT + MOVE.L (A0)+,(A1)+ ;COPY TOPLEFT + MOVE.L (A0)+,(A1)+ ;COPY BOTRIGHT + BRA.S DONE ;UPDATE INDEX AND QUIT + +NOTRECT LEA RGNDATA(A0),A0 ;POINT TO TOP VERT IN RGN +NXTVERT MOVE.L (A0)+,D7 ;GET VERT AND HORIZ COORDS +NXTHOR MOVE.L D7,(A1)+ ;PUT LEFT POINT TO DST + MOVE (A0)+,D7 ;GET HORIZ COORD + MOVE.L D7,(A1)+ ;PUT RIGHT POINT TO DST + MOVE (A0)+,D7 ;GET NEXT HORIZ COORD + CMP #32767,D7 ;END OF SCAN FLAG ? + BNE NXTHOR ;NO, GO FOR MORE + CMP #32767,(A0) ;END OF REGION ? + BNE NXTVERT ;NO, LOOP FOR MORE + +DONE SUB.L (A4),A1 ;CALC DSTPTR - DSTSTART + MOVE A1,(A2) ;UPDATE VAR INDEX +GOHOME MOVEM.L (SP)+,D7/A2-A4 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'PUTRGN ' + + + + + .END diff --git a/QDPatch.a b/QDPatch.a new file mode 100755 index 0000000..7aacaa0 --- /dev/null +++ b/QDPatch.a @@ -0,0 +1,1028 @@ +; +; QuickDraw patch program +; +;-------------------------------------------------------------------------------- + + .NoList + .Include TLASM:GrafEQU.TEXT ; All definitions + .Include TLASM:SYSEQU.TEXT ; All definitions + .Include TLASM:SYSMACS.TEXT ; All definitions + .Include TLASM:TOOLMACS.TEXT ; All definitions + .List + + + .Main BlockHead + + LEA fastStart,A0 + + MOVE.L #30000,D0 ; copy into system + _NewHandle ,SYS + _HLock + + MOVE.L (A0),A1 + MOVE.L A1,A2 ; save ptr + LEA fastStart,A0 + MOVE.L #30000,D0 ; copy into system + _BlockMove + + JSR (A2) + + _ExitToShell + +fastStart + .REF CopyMask + LEA CopyMask,A0 + MOVE.L A0,$C00+<4*$32> ;Set new trap address kludge + + .REF GetMaskTab + LEA GetMaskTab,A0 + MOVE.L A0,$C00+<4*$36> ;Set new trap address kludge + + .REF MeasureText + LEA MeasureText,A0 + MOVE.L A0,$C00+<4*$37> ;Set new trap address kludge + + .REF CalcMask + LEA CalcMask,A0 + MOVE.L A0,$C00+<4*$38> ;Set new trap address kludge + + .REF SeedFill + LEA SeedFill,A0 + MOVE.L A0,$C00+<4*$39> ;Set new trap address kludge + + .REF InitCurs + LEA InitCurs,A0 + MOVE #$50,D0 + _SetTrapAddress + + .REF SetCurso + LEA SetCurso,A0 + MOVE #$51,D0 + _SetTrapAddress + + .REF HideCurs + LEA HideCurs,A0 + MOVE #$52,D0 + _SetTrapAddress + + .REF ShowCurs + LEA ShowCurs,A0 + MOVE #$53,D0 + _SetTrapAddress + + + .REF ShieldCu + LEA ShieldCu,A0 + MOVE #$55,D0 + _SetTrapAddress + + + .REF ObscureC + LEA ObscureC,A0 + MOVE #$56,D0 + _SetTrapAddress + + + .REF BitAnd + LEA BitAnd ,A0 + MOVE #$58,D0 + _SetTrapAddress + + + .REF BitXOr + LEA BitXOr ,A0 + MOVE #$59,D0 + _SetTrapAddress + + + .REF BitNot + LEA BitNot ,A0 + MOVE #$5A,D0 + _SetTrapAddress + + + .REF BitOr + LEA BitOr ,A0 + MOVE #$5B,D0 + _SetTrapAddress + + + .REF BitShift + LEA BitShift,A0 + MOVE #$5C,D0 + _SetTrapAddress + + + .REF BitTst + LEA BitTst ,A0 + MOVE #$5D,D0 + _SetTrapAddress + + + .REF BitSet + LEA BitSet ,A0 + MOVE #$5E,D0 + _SetTrapAddress + + + .REF BitClr + LEA BitClr ,A0 + MOVE #$5F,D0 + _SetTrapAddress + + + .REF Random + LEA Random ,A0 + MOVE #$61,D0 + _SetTrapAddress + + + .REF ForeColo + LEA ForeColo,A0 + MOVE #$62,D0 + _SetTrapAddress + + + .REF BackColo + LEA BackColo,A0 + MOVE #$63,D0 + _SetTrapAddress + + + .REF ColorBit + LEA ColorBit,A0 + MOVE #$64,D0 + _SetTrapAddress + + + .REF GetPixel + LEA GetPixel,A0 + MOVE #$65,D0 + _SetTrapAddress + + + .REF StuffHex + LEA StuffHex,A0 + MOVE #$66,D0 + _SetTrapAddress + + + .REF InitPort + LEA InitPort,A0 + MOVE #$6D,D0 + _SetTrapAddress + + + .REF InitGraf + LEA InitGraf,A0 + MOVE #$6E,D0 + _SetTrapAddress + + + .REF OpenPort + LEA OpenPort,A0 + MOVE #$6F,D0 + _SetTrapAddress + + + .REF LocalToG + LEA LocalToG,A0 + MOVE #$70,D0 + _SetTrapAddress + + + .REF GlobalTo + LEA GlobalTo,A0 + MOVE #$71,D0 + _SetTrapAddress + + + .REF GrafDevi + LEA GrafDevi,A0 + MOVE #$72,D0 + _SetTrapAddress + + + .REF SetPort + LEA SetPort ,A0 + MOVE #$73,D0 + _SetTrapAddress + + + .REF GetPort + LEA GetPort ,A0 + MOVE #$74,D0 + _SetTrapAddress + + + .REF SetPortB + LEA SetPortB,A0 + MOVE #$75,D0 + _SetTrapAddress + + + .REF PortSize + LEA PortSize,A0 + MOVE #$76,D0 + _SetTrapAddress + + + .REF MovePort + LEA MovePort,A0 + MOVE #$77,D0 + _SetTrapAddress + + + .REF SetOrigi + LEA SetOrigi,A0 + MOVE #$78,D0 + _SetTrapAddress + + + .REF SetClip + LEA SetClip ,A0 + MOVE #$79,D0 + _SetTrapAddress + + + .REF GetClip + LEA GetClip ,A0 + MOVE #$7A,D0 + _SetTrapAddress + + + .REF ClipRect + LEA ClipRect,A0 + MOVE #$7B,D0 + _SetTrapAddress + + + .REF BackPat + LEA BackPat ,A0 + MOVE #$7C,D0 + _SetTrapAddress + + + .REF ClosePor + LEA ClosePor,A0 + MOVE #$7D,D0 + _SetTrapAddress + + + .REF AddPt + LEA AddPt ,A0 + MOVE #$7E,D0 + _SetTrapAddress + + + .REF SubPt + LEA SubPt ,A0 + MOVE #$7F,D0 + _SetTrapAddress + + + .REF SetPt + LEA SetPt ,A0 + MOVE #$80,D0 + _SetTrapAddress + + + .REF EqualPt + LEA EqualPt ,A0 + MOVE #$81,D0 + _SetTrapAddress + + + .REF StdText + LEA StdText ,A0 + MOVE #$82,D0 + _SetTrapAddress + + + .REF DrawChar + LEA DrawChar,A0 + MOVE #$83,D0 + _SetTrapAddress + + + .REF DrawStri + LEA DrawStri,A0 + MOVE #$84,D0 + _SetTrapAddress + + + .REF DrawText + LEA DrawText,A0 + MOVE #$85,D0 + _SetTrapAddress + + + .REF TextWidt + LEA TextWidt,A0 + MOVE #$86,D0 + _SetTrapAddress + + + .REF TextFont + LEA TextFont,A0 + MOVE #$87,D0 + _SetTrapAddress + + + .REF TextFace + LEA TextFace,A0 + MOVE #$88,D0 + _SetTrapAddress + + + .REF TextMode + LEA TextMode,A0 + MOVE #$89,D0 + _SetTrapAddress + + + .REF TextSize + LEA TextSize,A0 + MOVE #$8A,D0 + _SetTrapAddress + + + .REF GetFontI + LEA GetFontI,A0 + MOVE #$8B,D0 + _SetTrapAddress + + + .REF StringWi + LEA StringWi,A0 + MOVE #$8C,D0 + _SetTrapAddress + + + .REF CharWidt + LEA CharWidt,A0 + MOVE #$8D,D0 + _SetTrapAddress + + + .REF SpaceExt + LEA SpaceExt,A0 + MOVE #$8E,D0 + _SetTrapAddress + + + .REF StdLine + LEA StdLine ,A0 + MOVE #$90,D0 + _SetTrapAddress + + + .REF LineTo + LEA LineTo ,A0 + MOVE #$91,D0 + _SetTrapAddress + + + .REF Line + LEA Line ,A0 + MOVE #$92,D0 + _SetTrapAddress + + + .REF MoveTo + LEA MoveTo ,A0 + MOVE #$93,D0 + _SetTrapAddress + + + .REF Moov + LEA Moov ,A0 + MOVE #$94,D0 + _SetTrapAddress + + + .REF HidePen + LEA HidePen ,A0 + MOVE #$96,D0 + _SetTrapAddress + + + .REF ShowPen + LEA ShowPen ,A0 + MOVE #$97,D0 + _SetTrapAddress + + + .REF GetPenSt + LEA GetPenSt,A0 + MOVE #$98,D0 + _SetTrapAddress + + + .REF SetPenSt + LEA SetPenSt,A0 + MOVE #$99,D0 + _SetTrapAddress + + + .REF GetPen + LEA GetPen ,A0 + MOVE #$9A,D0 + _SetTrapAddress + + + .REF PenSize + LEA PenSize ,A0 + MOVE #$9B,D0 + _SetTrapAddress + + + .REF PenMode + LEA PenMode ,A0 + MOVE #$9C,D0 + _SetTrapAddress + + + .REF PenPat + LEA PenPat ,A0 + MOVE #$9D,D0 + _SetTrapAddress + + + .REF PenNorma + LEA PenNorma,A0 + MOVE #$9E,D0 + _SetTrapAddress + + + .REF StdRect + LEA StdRect ,A0 + MOVE #$A0,D0 + _SetTrapAddress + + + .REF FrameRec + LEA FrameRec,A0 + MOVE #$A1,D0 + _SetTrapAddress + + + .REF PaintRec + LEA PaintRec,A0 + MOVE #$A2,D0 + _SetTrapAddress + + + .REF EraseRec + LEA EraseRec,A0 + MOVE #$A3,D0 + _SetTrapAddress + + + .REF InvertRe + LEA InvertRe,A0 + MOVE #$A4,D0 + _SetTrapAddress + + + .REF FillRect + LEA FillRect,A0 + MOVE #$A5,D0 + _SetTrapAddress + + + .REF EqualRec + LEA EqualRec,A0 + MOVE #$A6,D0 + _SetTrapAddress + + + .REF SetRect + LEA SetRect ,A0 + MOVE #$A7,D0 + _SetTrapAddress + + + .REF OffSetRe + LEA OffSetRe,A0 + MOVE #$A8,D0 + _SetTrapAddress + + + .REF InSetRec + LEA InSetRec,A0 + MOVE #$A9,D0 + _SetTrapAddress + + + .REF SectRect + LEA SectRect,A0 + MOVE #$AA,D0 + _SetTrapAddress + + + .REF UnionRec + LEA UnionRec,A0 + MOVE #$AB,D0 + _SetTrapAddress + + + .REF Pt2Rect + LEA Pt2Rect ,A0 + MOVE #$AC,D0 + _SetTrapAddress + + + .REF PtInRect + LEA PtInRect,A0 + MOVE #$AD,D0 + _SetTrapAddress + + + .REF EmptyRec + LEA EmptyRec,A0 + MOVE #$AE,D0 + _SetTrapAddress + + + .REF StdRRect + LEA StdRRect,A0 + MOVE #$AF,D0 + _SetTrapAddress + + + .REF FrameRou + LEA FrameRou,A0 + MOVE #$B0,D0 + _SetTrapAddress + + + .REF PaintRou + LEA PaintRou,A0 + MOVE #$B1,D0 + _SetTrapAddress + + + .REF EraseRou + LEA EraseRou,A0 + MOVE #$B2,D0 + _SetTrapAddress + + + .REF InvertRo + LEA InvertRo,A0 + MOVE #$B3,D0 + _SetTrapAddress + + + .REF FillRoun + LEA FillRoun,A0 + MOVE #$B4,D0 + _SetTrapAddress + + + .REF StdOval + LEA StdOval ,A0 + MOVE #$B6,D0 + _SetTrapAddress + + + .REF FrameOva + LEA FrameOva,A0 + MOVE #$B7,D0 + _SetTrapAddress + + + .REF PaintOva + LEA PaintOva,A0 + MOVE #$B8,D0 + _SetTrapAddress + + + .REF EraseOva + LEA EraseOva,A0 + MOVE #$B9,D0 + _SetTrapAddress + + + .REF InvertOv + LEA InvertOv,A0 + MOVE #$BA,D0 + _SetTrapAddress + + + .REF FillOval + LEA FillOval,A0 + MOVE #$BB,D0 + _SetTrapAddress + + + .REF StdArc + LEA StdArc ,A0 + MOVE #$BD,D0 + _SetTrapAddress + + + .REF FrameArc + LEA FrameArc,A0 + MOVE #$BE,D0 + _SetTrapAddress + + + .REF PaintArc + LEA PaintArc,A0 + MOVE #$BF,D0 + _SetTrapAddress + + + .REF EraseArc + LEA EraseArc,A0 + MOVE #$C0,D0 + _SetTrapAddress + + + .REF InvertAr + LEA InvertAr,A0 + MOVE #$C1,D0 + _SetTrapAddress + + + .REF FillArc + LEA FillArc ,A0 + MOVE #$C2,D0 + _SetTrapAddress + + + .REF PtToAngl + LEA PtToAngl,A0 + MOVE #$C3,D0 + _SetTrapAddress + + + .REF StdPoly + LEA StdPoly ,A0 + MOVE #$C5,D0 + _SetTrapAddress + + + .REF FramePol + LEA FramePol,A0 + MOVE #$C6,D0 + _SetTrapAddress + + + .REF PaintPol + LEA PaintPol,A0 + MOVE #$C7,D0 + _SetTrapAddress + + + .REF ErasePol + LEA ErasePol,A0 + MOVE #$C8,D0 + _SetTrapAddress + + + .REF InvertPo + LEA InvertPo,A0 + MOVE #$C9,D0 + _SetTrapAddress + + + .REF FillPoly + LEA FillPoly,A0 + MOVE #$CA,D0 + _SetTrapAddress + + + .REF OpenPoly + LEA OpenPoly,A0 + MOVE #$CB,D0 + _SetTrapAddress + + + .REF ClosePol + LEA ClosePol,A0 + MOVE #$CC,D0 + _SetTrapAddress + + + .REF KillPoly + LEA KillPoly,A0 + MOVE #$CD,D0 + _SetTrapAddress + + + .REF OffSetPo + LEA OffSetPo,A0 + MOVE #$CE,D0 + _SetTrapAddress + + + .REF PackBits + LEA PackBits,A0 + MOVE #$CF,D0 + _SetTrapAddress + + + .REF UnpackBi + LEA UnpackBi,A0 + MOVE #$D0,D0 + _SetTrapAddress + + + .REF StdRgn + LEA StdRgn ,A0 + MOVE #$D1,D0 + _SetTrapAddress + + + .REF FrameRgn + LEA FrameRgn,A0 + MOVE #$D2,D0 + _SetTrapAddress + + + .REF PaintRgn + LEA PaintRgn,A0 + MOVE #$D3,D0 + _SetTrapAddress + + + .REF EraseRgn + LEA EraseRgn,A0 + MOVE #$D4,D0 + _SetTrapAddress + + + .REF InvertRg + LEA InvertRg,A0 + MOVE #$D5,D0 + _SetTrapAddress + + + .REF FillRgn + LEA FillRgn ,A0 + MOVE #$D6,D0 + _SetTrapAddress + + + .REF NewRgn + LEA NewRgn ,A0 + MOVE #$D8,D0 + _SetTrapAddress + + + .REF DisposeR + LEA DisposeR,A0 + MOVE #$D9,D0 + _SetTrapAddress + + + .REF OpenRgn + LEA OpenRgn ,A0 + MOVE #$DA,D0 + _SetTrapAddress + + + .REF CloseRgn + LEA CloseRgn,A0 + MOVE #$DB,D0 + _SetTrapAddress + + + .REF CopyRgn + LEA CopyRgn ,A0 + MOVE #$DC,D0 + _SetTrapAddress + + + .REF SetEmpty + LEA SetEmpty,A0 + MOVE #$DD,D0 + _SetTrapAddress + + + .REF SetRectR + LEA SetRectR,A0 + MOVE #$DE,D0 + _SetTrapAddress + + + .REF RectRgn + LEA RectRgn ,A0 + MOVE #$DF,D0 + _SetTrapAddress + + + .REF OffSetRg + LEA OffSetRg,A0 + MOVE #$E0,D0 + _SetTrapAddress + + + .REF InSetRgn + LEA InSetRgn,A0 + MOVE #$E1,D0 + _SetTrapAddress + + + .REF EmptyRgn + LEA EmptyRgn,A0 + MOVE #$E2,D0 + _SetTrapAddress + + + .REF EqualRgn + LEA EqualRgn,A0 + MOVE #$E3,D0 + _SetTrapAddress + + + .REF SectRgn + LEA SectRgn ,A0 + MOVE #$E4,D0 + _SetTrapAddress + + + .REF UnionRgn + LEA UnionRgn,A0 + MOVE #$E5,D0 + _SetTrapAddress + + + .REF DiffRgn + LEA DiffRgn ,A0 + MOVE #$E6,D0 + _SetTrapAddress + + + .REF XOrRgn + LEA XOrRgn ,A0 + MOVE #$E7,D0 + _SetTrapAddress + + + .REF PtInRgn + LEA PtInRgn ,A0 + MOVE #$E8,D0 + _SetTrapAddress + + + .REF RectInRg + LEA RectInRg,A0 + MOVE #$E9,D0 + _SetTrapAddress + + + .REF StdBits + LEA StdBits ,A0 + MOVE #$EB,D0 + _SetTrapAddress + + + .REF CopyBits + LEA CopyBits,A0 + MOVE #$EC,D0 + _SetTrapAddress + + + .REF ScrollRe + LEA ScrollRe,A0 + MOVE #$EF,D0 + _SetTrapAddress + + + .REF SetStdPr + LEA SetStdPr,A0 + MOVE #$EA,D0 + _SetTrapAddress + + + .REF StdTxMea + LEA StdTxMea,A0 + MOVE #$ED,D0 + _SetTrapAddress + + + .REF StdGetPi + LEA StdGetPi,A0 + MOVE #$EE,D0 + _SetTrapAddress + + + .REF StdPutPi + LEA StdPutPi,A0 + MOVE #$F0,D0 + _SetTrapAddress + + + .REF StdComme + LEA StdComme,A0 + MOVE #$F1,D0 + _SetTrapAddress + + + .REF PicComme + LEA PicComme,A0 + MOVE #$F2,D0 + _SetTrapAddress + + + .REF OpenPict + LEA OpenPict,A0 + MOVE #$F3,D0 + _SetTrapAddress + + + .REF ClosePic + LEA ClosePic,A0 + MOVE #$F4,D0 + _SetTrapAddress + + + .REF KillPict + LEA KillPict,A0 + MOVE #$F5,D0 + _SetTrapAddress + + .REF DrawPict + LEA DrawPict,A0 + MOVE #$F6,D0 + _SetTrapAddress + + .REF ScalePt + LEA ScalePt,A0 + MOVE #$F8,D0 + _SetTrapAddress + + + .REF MapPt + LEA MapPt,A0 + MOVE #$F9,D0 + _SetTrapAddress + + + .REF MapRect + LEA MapRect,A0 + MOVE #$FA,D0 + _SetTrapAddress + + + .REF MapRgn + LEA MapRgn,A0 + MOVE #$FB,D0 + _SetTrapAddress + + + .REF MapPoly + LEA MapPoly,A0 + MOVE #$FC,D0 + _SetTrapAddress + + +; FONT MANAGER + + .REF InitFont + LEA InitFont,A0 + MOVE #$FE,D0 + _SetTrapAddress + + + .REF GetFontName + LEA GetFontName,A0 + MOVE #$FF,D0 + _SetTrapAddress + + + .REF GetFNum + LEA GetFNum,A0 + MOVE #$100,D0 + _SetTrapAddress + + + .REF FMSwapFont + LEA FMSwapFont,A0 + MOVE #$101,D0 + _SetTrapAddress + + + .REF RealFont + LEA RealFont,A0 + MOVE #$102,D0 + _SetTrapAddress + + + .REF SetFontLo + LEA SetFontLo,A0 + MOVE #$103,D0 + _SetTrapAddress + + LEA FMSwapFont,A0 + MOVE.L A0,JSwapFont + + RTS + + + + .END diff --git a/QuickDraw.p b/QuickDraw.p new file mode 100755 index 0000000..cc7a659 --- /dev/null +++ b/QuickDraw.p @@ -0,0 +1,418 @@ +UNIT QuickDraw; + +{ Copyright 1983 Apple Computer Inc. } +{ Written by Bill Atkinson } + +INTERFACE + +CONST srcCopy = 0; { the 16 transfer modes } + srcOr = 1; + srcXor = 2; + srcBic = 3; + notSrcCopy = 4; + notSrcOr = 5; + notSrcXor = 6; + notSrcBic = 7; + patCopy = 8; + patOr = 9; + patXor = 10; + patBic = 11; + notPatCopy = 12; + notPatOr = 13; + notPatXor = 14; + notPatBic = 15; + +{ QuickDraw color separation constants } + + normalBit = 0; { normal screen mapping } + inverseBit = 1; { inverse screen mapping } + redBit = 4; { RGB additive mapping } + greenBit = 3; + blueBit = 2; + cyanBit = 8; { CMYBk subtractive mapping } + magentaBit = 7; + yellowBit = 6; + blackBit = 5; + + blackColor = 33; { colors expressed in these mappings } + whiteColor = 30; + redColor = 205; + greenColor = 341; + blueColor = 409; + cyanColor = 273; + magentaColor = 137; + yellowColor = 69; + + picLParen = 0; { standard picture comments } + picRParen = 1; + + +TYPE QDByte = -128..127; + QDPtr = ^QDByte; { blind pointer } + QDHandle = ^QDPtr; { blind handle } + Str255 = String[255]; + Pattern = PACKED ARRAY[0..7] OF 0..255; + Bits16 = ARRAY[0..15] OF INTEGER; + VHSelect = (v,h); + GrafVerb = (frame,paint,erase,invert,fill); + StyleItem = (bold,italic,underline,outline,shadow,condense,extend); + Style = SET OF StyleItem; + + FontInfo = RECORD + ascent: INTEGER; + descent: INTEGER; + widMax: INTEGER; + leading: INTEGER; + END; + + Point = RECORD CASE INTEGER OF + + 0: (v: INTEGER; + h: INTEGER); + + 1: (vh: ARRAY[VHSelect] OF INTEGER); + + END; + + + Rect = RECORD CASE INTEGER OF + + 0: (top: INTEGER; + left: INTEGER; + bottom: INTEGER; + right: INTEGER); + + 1: (topLeft: Point; + botRight: Point); + END; + + + BitMap = RECORD + baseAddr: QDPtr; + rowBytes: INTEGER; + bounds: Rect; + END; + + + Cursor = RECORD + data: Bits16; + mask: Bits16; + hotSpot: Point; + END; + + + PenState = RECORD + pnLoc: Point; + pnSize: Point; + pnMode: INTEGER; + pnPat: Pattern; + END; + + + PolyHandle = ^PolyPtr; + PolyPtr = ^Polygon; + Polygon = RECORD + polySize: INTEGER; + polyBBox: Rect; + polyPoints: ARRAY[0..0] OF Point; + END; + + + RgnHandle = ^RgnPtr; + RgnPtr = ^Region; + Region = RECORD + rgnSize: INTEGER; { rgnSize = 10 for rectangular } + rgnBBox: Rect; + { plus more data if not rectangular } + END; + + + PicHandle = ^PicPtr; + PicPtr = ^Picture; + Picture = RECORD + picSize: INTEGER; + picFrame: Rect; + { plus byte codes for picture content } + END; + + + QDProcsPtr = ^QDProcs; + QDProcs = RECORD + textProc: QDPtr; + lineProc: QDPtr; + rectProc: QDPtr; + rRectProc: QDPtr; + ovalProc: QDPtr; + arcProc: QDPtr; + polyProc: QDPtr; + rgnProc: QDPtr; + bitsProc: QDPtr; + commentProc: QDPtr; + txMeasProc: QDPtr; + getPicProc: QDPtr; + putPicProc: QDPtr; + END; + + + GrafPtr = ^GrafPort; + GrafPort = RECORD + device: INTEGER; + portBits: BitMap; + portRect: Rect; + visRgn: RgnHandle; + clipRgn: RgnHandle; + bkPat: Pattern; + fillPat: Pattern; + pnLoc: Point; + pnSize: Point; + pnMode: INTEGER; + pnPat: Pattern; + pnVis: INTEGER; + txFont: INTEGER; + txFace: Style; + txMode: INTEGER; + txSize: INTEGER; + spExtra: LongInt; + fgColor: LongInt; + bkColor: LongInt; + colrBit: INTEGER; + patStretch: INTEGER; + picSave: QDHandle; + rgnSave: QDHandle; + polySave: QDHandle; + grafProcs: QDProcsPtr; + END; + + + +VAR thePort: GrafPtr; + white: Pattern; + black: Pattern; + gray: Pattern; + ltGray: Pattern; + dkGray: Pattern; + arrow: Cursor; + screenBits: BitMap; + randSeed: LongInt; + + +{ GrafPort Routines } + +PROCEDURE InitGraf (globalPtr: QDPtr); +PROCEDURE OpenPort (port: GrafPtr); +PROCEDURE InitPort (port: GrafPtr); +PROCEDURE ClosePort (port: GrafPtr); +PROCEDURE SetPort (port: GrafPtr); +PROCEDURE GetPort (VAR port: GrafPtr); +PROCEDURE GrafDevice (device: INTEGER); +PROCEDURE SetPortBits(bm: BitMap); +PROCEDURE PortSize (width,height: INTEGER); +PROCEDURE MovePortTo (leftGlobal,topGlobal: INTEGER); +PROCEDURE SetOrigin (h,v: INTEGER); +PROCEDURE SetClip (rgn: RgnHandle); +PROCEDURE GetClip (rgn: RgnHandle); +PROCEDURE ClipRect (r: Rect); +PROCEDURE BackPat (pat: Pattern); + + +{ Cursor Routines } + +PROCEDURE InitCursor; +PROCEDURE SetCursor(crsr: Cursor); +PROCEDURE HideCursor; +PROCEDURE ShowCursor; +PROCEDURE ObscureCursor; + + +{ Line Routines } + +PROCEDURE HidePen; +PROCEDURE ShowPen; +PROCEDURE GetPen (VAR pt: Point); +PROCEDURE GetPenState(VAR pnState: PenState); +PROCEDURE SetPenState(pnState: PenState); +PROCEDURE PenSize (width,height: INTEGER); +PROCEDURE PenMode (mode: INTEGER); +PROCEDURE PenPat (pat: Pattern); +PROCEDURE PenNormal; +PROCEDURE MoveTo (h,v: INTEGER); +PROCEDURE Move (dh,dv: INTEGER); +PROCEDURE LineTo (h,v: INTEGER); +PROCEDURE Line (dh,dv: INTEGER); + + +{ Text Routines } + +PROCEDURE TextFont (font: INTEGER); +PROCEDURE TextFace (face: Style); +PROCEDURE TextMode (mode: INTEGER); +PROCEDURE TextSize (size: INTEGER); +PROCEDURE SpaceExtra (extra: LongInt); +PROCEDURE DrawChar (ch: char); +PROCEDURE DrawString (s: Str255); +PROCEDURE DrawText (textBuf: QDPtr; firstByte,byteCount: INTEGER); +FUNCTION CharWidth (ch: CHAR): INTEGER; +FUNCTION StringWidth (s: Str255): INTEGER; +FUNCTION TextWidth (textBuf: QDPtr; firstByte,byteCount: INTEGER): INTEGER; +PROCEDURE GetFontInfo (VAR info: FontInfo); + + +{ Point Calculations } + +PROCEDURE AddPt (src: Point; VAR dst: Point); +PROCEDURE SubPt (src: Point; VAR dst: Point); +PROCEDURE SetPt (VAR pt: Point; h,v: INTEGER); +FUNCTION EqualPt (pt1,pt2: Point): BOOLEAN; +PROCEDURE ScalePt (VAR pt: Point; fromRect,toRect: Rect); +PROCEDURE MapPt (VAR pt: Point; fromRect,toRect: Rect); +PROCEDURE LocalToGlobal (VAR pt: Point); +PROCEDURE GlobalToLocal (VAR pt: Point); + + +{ Rectangle Calculations } + +PROCEDURE SetRect (VAR r: Rect; left,top,right,bottom: INTEGER); +FUNCTION EqualRect (rect1,rect2: Rect): BOOLEAN; +FUNCTION EmptyRect (r: Rect): BOOLEAN; +PROCEDURE OffsetRect (VAR r: Rect; dh,dv: INTEGER); +PROCEDURE MapRect (VAR r: Rect; fromRect,toRect: Rect); +PROCEDURE InsetRect (VAR r: Rect; dh,dv: INTEGER); +FUNCTION SectRect (src1,src2: Rect; VAR dstRect: Rect): BOOLEAN; +PROCEDURE UnionRect (src1,src2: Rect; VAR dstRect: Rect); +FUNCTION PtInRect (pt: Point; r: Rect): BOOLEAN; +PROCEDURE Pt2Rect (pt1,pt2: Point; VAR dstRect: Rect); + + +{ Graphical Operations on Rectangles } + +PROCEDURE FrameRect (r: Rect); +PROCEDURE PaintRect (r: Rect); +PROCEDURE EraseRect (r: Rect); +PROCEDURE InvertRect (r: Rect); +PROCEDURE FillRect (r: Rect; pat: Pattern); + + +{ RoundRect Routines } + +PROCEDURE FrameRoundRect (r: Rect; ovWd,ovHt: INTEGER); +PROCEDURE PaintRoundRect (r: Rect; ovWd,ovHt: INTEGER); +PROCEDURE EraseRoundRect (r: Rect; ovWd,ovHt: INTEGER); +PROCEDURE InvertRoundRect (r: Rect; ovWd,ovHt: INTEGER); +PROCEDURE FillRoundRect (r: Rect; ovWd,ovHt: INTEGER; pat: Pattern); + + +{ Oval Routines } + +PROCEDURE FrameOval (r: Rect); +PROCEDURE PaintOval (r: Rect); +PROCEDURE EraseOval (r: Rect); +PROCEDURE InvertOval (r: Rect); +PROCEDURE FillOval (r: Rect; pat: Pattern); + + +{ Arc Routines } + +PROCEDURE FrameArc (r: Rect; startAngle,arcAngle: INTEGER); +PROCEDURE PaintArc (r: Rect; startAngle,arcAngle: INTEGER); +PROCEDURE EraseArc (r: Rect; startAngle,arcAngle: INTEGER); +PROCEDURE InvertArc (r: Rect; startAngle,arcAngle: INTEGER); +PROCEDURE FillArc (r: Rect; startAngle,arcAngle: INTEGER; pat: Pattern); +PROCEDURE PtToAngle (r: Rect; pt: Point; VAR angle: INTEGER); + + +{ Polygon Routines } + +FUNCTION OpenPoly: PolyHandle; +PROCEDURE ClosePoly; +PROCEDURE KillPoly (poly: PolyHandle); +PROCEDURE OffsetPoly (poly: PolyHandle; dh,dv: INTEGER); +PROCEDURE MapPoly (poly: PolyHandle; fromRect,toRect: Rect); +PROCEDURE FramePoly (poly: PolyHandle); +PROCEDURE PaintPoly (poly: PolyHandle); +PROCEDURE ErasePoly (poly: PolyHandle); +PROCEDURE InvertPoly (poly: PolyHandle); +PROCEDURE FillPoly (poly: PolyHandle; pat: Pattern); + + +{ Region Calculations } + +FUNCTION NewRgn: RgnHandle; +PROCEDURE DisposeRgn(rgn: RgnHandle); +PROCEDURE CopyRgn (srcRgn,dstRgn: RgnHandle); +PROCEDURE SetEmptyRgn(rgn: RgnHandle); +PROCEDURE SetRectRgn(rgn: RgnHandle; left,top,right,bottom: INTEGER); +PROCEDURE RectRgn (rgn: RgnHandle; r: Rect); +PROCEDURE OpenRgn; +PROCEDURE CloseRgn (dstRgn: RgnHandle); +PROCEDURE OffsetRgn (rgn: RgnHandle; dh,dv: INTEGER); +PROCEDURE MapRgn (rgn: RgnHandle; fromRect,toRect: Rect); +PROCEDURE InsetRgn (rgn: RgnHandle; dh,dv: INTEGER); +PROCEDURE SectRgn (srcRgnA,srcRgnB,dstRgn: RgnHandle); +PROCEDURE UnionRgn (srcRgnA,srcRgnB,dstRgn: RgnHandle); +PROCEDURE DiffRgn (srcRgnA,srcRgnB,dstRgn: RgnHandle); +PROCEDURE XorRgn (srcRgnA,srcRgnB,dstRgn: RgnHandle); +FUNCTION EqualRgn (rgnA,rgnB: RgnHandle): BOOLEAN; +FUNCTION EmptyRgn (rgn: RgnHandle): BOOLEAN; +FUNCTION PtInRgn (pt: Point; rgn: RgnHandle): BOOLEAN; +FUNCTION RectInRgn (r: Rect; rgn: RgnHandle): BOOLEAN; + + +{ Graphical Operations on Regions } + +PROCEDURE FrameRgn (rgn: RgnHandle); +PROCEDURE PaintRgn (rgn: RgnHandle); +PROCEDURE EraseRgn (rgn: RgnHandle); +PROCEDURE InvertRgn (rgn: RgnHandle); +PROCEDURE FillRgn (rgn: RgnHandle; pat: Pattern); + + +{ Graphical Operations on BitMaps } + +PROCEDURE ScrollRect(dstRect: Rect; dh,dv: INTEGER; updateRgn: rgnHandle); +PROCEDURE CopyBits (srcBits,dstBits: BitMap; + srcRect,dstRect: Rect; + mode: INTEGER; + maskRgn: RgnHandle); + +{ Picture Routines } + +FUNCTION OpenPicture(picFrame: Rect): PicHandle; +PROCEDURE ClosePicture; +PROCEDURE DrawPicture(myPicture: PicHandle; dstRect: Rect); +PROCEDURE PicComment(kind,dataSize: INTEGER; dataHandle: QDHandle); +PROCEDURE KillPicture(myPicture: PicHandle); + + +{ The Bottleneck Interface: } + +PROCEDURE SetStdProcs(VAR procs: QDProcs); +PROCEDURE StdText (count: INTEGER; textAddr: QDPtr; numer,denom: Point); +PROCEDURE StdLine (newPt: Point); +PROCEDURE StdRect (verb: GrafVerb; r: Rect); +PROCEDURE StdRRect (verb: GrafVerb; r: Rect; ovWd,ovHt: INTEGER); +PROCEDURE StdOval (verb: GrafVerb; r: Rect); +PROCEDURE StdArc (verb: GrafVerb; r: Rect; startAngle,arcAngle: INTEGER); +PROCEDURE StdPoly (verb: GrafVerb; poly: PolyHandle); +PROCEDURE StdRgn (verb: GrafVerb; rgn: RgnHandle); +PROCEDURE StdBits (VAR srcBits: BitMap; VAR srcRect,dstRect: Rect; + mode: INTEGER; maskRgn: RgnHandle); +PROCEDURE StdComment (kind,dataSize: INTEGER; dataHandle: QDHandle); +FUNCTION StdTxMeas (count: INTEGER; textAddr: QDPtr; + VAR numer,denom: Point; VAR info: FontInfo): INTEGER; +PROCEDURE StdGetPic (dataPtr: QDPtr; byteCount: INTEGER); +PROCEDURE StdPutPic (dataPtr: QDPtr; byteCount: INTEGER); + + +{ Misc Utility Routines } + +FUNCTION GetPixel (h,v: INTEGER): BOOLEAN; +FUNCTION Random: INTEGER; +PROCEDURE StuffHex (thingptr: QDPtr; s:Str255); +PROCEDURE ForeColor (color: LongInt); +PROCEDURE BackColor (color: LongInt); +PROCEDURE ColorBit (whichBit: INTEGER); + + +IMPLEMENTATION + +{$I QuickDraw2.text } diff --git a/QuickDraw2.p b/QuickDraw2.p new file mode 100755 index 0000000..35632a7 --- /dev/null +++ b/QuickDraw2.p @@ -0,0 +1,267 @@ +{ QuickDraw2.text: Implementation part of QuickDraw } + +{$S Graf } + +TYPE FMOutPtr = ^FMOutRec; + FMOutrec = PACKED RECORD + errNum: INTEGER; { used only for GrafError } + fontHandle: QDHandle; { handle to font } + bold: 0..255; { how much to smear horiz } + italic: 0..255; { how much to shear } + ulOffset: 0..255; { pixels below baseline } + ulShadow: 0..255; { how big is the halo } + ulThick: 0..255; { how thick is the underline } + shadow: 0..255; { 0,1,2,or 3 only } + extra: -128..127; { extra white dots each char } + ascent: 0..255; { ascent measure for font } + descent: 0..255; { descent measure for font } + widMax: 0..255; { width of widest char } + leading: -128..127; { leading between lines } + unused: 0..255; + numer: Point; { use this modified scale to } + denom: Point; { draw or measure text with } + END; + + + +VAR wideOpen: RgnHandle; { a dummy rectangular region, read-only } + wideMaster: RgnPtr; + wideData: Region; + rgnBuf: QDHandle; { point saving buffer for OpenRgn } + rgnIndex: INTEGER; { current bytes used in rgnBuf } + rgnMax: INTEGER; { max bytes allocated so far to rgnBuf } + playPic: PicHandle; { used by StdGetPic } + QDSpare0: INTEGER; { unused word } + thePoly: PolyHandle; { the current polygon being defined } + polyMax: INTEGER; { max bytes allocated so far to thePoly } + patAlign: Point; { to align pattern during DrawPicture } + fixTxWid: Fixed; { Fixed Point width from StdTxMeas. } + fontPtr: FMOutPtr; { the last font used, used by DrawText } + playIndex: LongInt; { used by StdGetPic during DrawPicture } + QDSpare3: INTEGER; { unused word } + QDSpare4: INTEGER; { unused word } + QDSpare5: INTEGER; { unused word } + QDSpare6: INTEGER; { unused word } + QDSpare7: INTEGER; { unused word } + QDSpare8: INTEGER; { unused word } + QDSpare9: INTEGER; { unused word } + QDSpareA: INTEGER; { unused word } + QDSpareB: INTEGER; { unused word } + QDSpareC: INTEGER; { unused word } + QDSpareD: INTEGER; { unused word } + + + + +{ grafPort routines } + +PROCEDURE InitGraf; EXTERNAL; +PROCEDURE OpenPort; EXTERNAL; +PROCEDURE InitPort; EXTERNAL; +PROCEDURE ClosePort; EXTERNAL; +PROCEDURE GrafDevice; EXTERNAL; +PROCEDURE SetPort; EXTERNAL; +PROCEDURE GetPort; EXTERNAL; +PROCEDURE SetPortBits; EXTERNAL; +PROCEDURE PortSize; EXTERNAL; +PROCEDURE MovePortTo; EXTERNAL; +PROCEDURE SetOrigin; EXTERNAL; +PROCEDURE SetClip; EXTERNAL; +PROCEDURE GetClip; EXTERNAL; +PROCEDURE ClipRect; EXTERNAL; +PROCEDURE BackPat; EXTERNAL; + + +{ cursor routines } + +PROCEDURE InitCursor; EXTERNAL; +PROCEDURE SetCursor; EXTERNAL; +PROCEDURE HideCursor; EXTERNAL; +PROCEDURE ShowCursor; EXTERNAL; +PROCEDURE ObscureCursor; EXTERNAL; + + +{ text routines } + +PROCEDURE TextFont; EXTERNAL; +PROCEDURE TextFace; EXTERNAL; +PROCEDURE TextMode; EXTERNAL; +PROCEDURE TextSize; EXTERNAL; +PROCEDURE SpaceExtra; EXTERNAL; +PROCEDURE DrawChar; EXTERNAL; +PROCEDURE DrawString; EXTERNAL; +PROCEDURE DrawText; EXTERNAL; +FUNCTION CharWidth; EXTERNAL; +FUNCTION StringWidth; EXTERNAL; +FUNCTION TextWidth; EXTERNAL; +PROCEDURE GetFontInfo; EXTERNAL; + + +{ line routines } + +PROCEDURE HidePen; EXTERNAL; +PROCEDURE ShowPen; EXTERNAL; +PROCEDURE GetPen; EXTERNAL; +PROCEDURE GetPenState; EXTERNAL; +PROCEDURE SetPenState; EXTERNAL; +PROCEDURE PenSize; EXTERNAL; +PROCEDURE PenMode; EXTERNAL; +PROCEDURE PenPat; EXTERNAL; +PROCEDURE PenNormal; EXTERNAL; +PROCEDURE MoveTo; EXTERNAL; +PROCEDURE Move; EXTERNAL; +PROCEDURE LineTo; EXTERNAL; +PROCEDURE Line; EXTERNAL; + + +{ rectangle calculations } + +PROCEDURE SetRect; EXTERNAL; +FUNCTION EqualRect; EXTERNAL; +FUNCTION EmptyRect; EXTERNAL; +PROCEDURE OffsetRect; EXTERNAL; +PROCEDURE MapRect; EXTERNAL; +PROCEDURE InsetRect; EXTERNAL; +FUNCTION SectRect; EXTERNAL; +PROCEDURE UnionRect; EXTERNAL; +FUNCTION PtInRect; EXTERNAL; +PROCEDURE Pt2Rect; EXTERNAL; + + +{ graphical operations on rectangles } + +PROCEDURE FrameRect; EXTERNAL; +PROCEDURE PaintRect; EXTERNAL; +PROCEDURE EraseRect; EXTERNAL; +PROCEDURE InvertRect; EXTERNAL; +PROCEDURE FillRect; EXTERNAL; + + +{ graphical operations on RoundRects } + +PROCEDURE FrameRoundRect; EXTERNAL; +PROCEDURE PaintRoundRect; EXTERNAL; +PROCEDURE EraseRoundRect; EXTERNAL; +PROCEDURE InvertRoundRect; EXTERNAL; +PROCEDURE FillRoundRect; EXTERNAL; + + +{ graphical operations on Ovals } + +PROCEDURE FrameOval; EXTERNAL; +PROCEDURE PaintOval; EXTERNAL; +PROCEDURE EraseOval; EXTERNAL; +PROCEDURE InvertOval; EXTERNAL; +PROCEDURE FillOval; EXTERNAL; + + +{ Arc routines } + +PROCEDURE FrameArc; EXTERNAL; +PROCEDURE PaintArc; EXTERNAL; +PROCEDURE EraseArc; EXTERNAL; +PROCEDURE InvertArc; EXTERNAL; +PROCEDURE FillArc; EXTERNAL; +PROCEDURE PtToAngle; EXTERNAL; + + +{ polygon routines } + +FUNCTION OpenPoly; EXTERNAL; +PROCEDURE ClosePoly; EXTERNAL; +PROCEDURE KillPoly; EXTERNAL; +PROCEDURE OffsetPoly; EXTERNAL; +PROCEDURE MapPoly; EXTERNAL; + +PROCEDURE FramePoly; EXTERNAL; +PROCEDURE PaintPoly; EXTERNAL; +PROCEDURE ErasePoly; EXTERNAL; +PROCEDURE InvertPoly; EXTERNAL; +PROCEDURE FillPoly; EXTERNAL; + + +{ region calculations } + +FUNCTION NewRgn; EXTERNAL; +PROCEDURE DisposeRgn; EXTERNAL; +PROCEDURE OpenRgn; EXTERNAL; +PROCEDURE CloseRgn; EXTERNAL; +PROCEDURE OffsetRgn; EXTERNAL; +PROCEDURE MapRgn; EXTERNAL; +PROCEDURE InsetRgn; EXTERNAL; +PROCEDURE SectRgn; EXTERNAL; +PROCEDURE CopyRgn; EXTERNAL; +PROCEDURE SetEmptyRgn; EXTERNAL; +PROCEDURE SetRectRgn; EXTERNAL; +PROCEDURE RectRgn; EXTERNAL; +PROCEDURE UnionRgn; EXTERNAL; +PROCEDURE DiffRgn; EXTERNAL; +PROCEDURE XorRgn; EXTERNAL; +FUNCTION EqualRgn; EXTERNAL; +FUNCTION EmptyRgn; EXTERNAL; +FUNCTION PtInRgn; EXTERNAL; +FUNCTION RectInRgn; EXTERNAL; + + +{ graphical operations on Regions } + +PROCEDURE FrameRgn; EXTERNAL; +PROCEDURE PaintRgn; EXTERNAL; +PROCEDURE EraseRgn; EXTERNAL; +PROCEDURE InvertRgn; EXTERNAL; +PROCEDURE FillRgn; EXTERNAL; + + +{ BitMap routines } + +PROCEDURE CopyBits; EXTERNAL; +PROCEDURE ScrollRect; EXTERNAL; + + +{ Picture routines } + +FUNCTION OpenPicture; EXTERNAL; +PROCEDURE ClosePicture; EXTERNAL; +PROCEDURE KillPicture; EXTERNAL; +PROCEDURE DrawPicture; EXTERNAL; +PROCEDURE PicComment; EXTERNAL; + + +{ BottleNeck routines } + +PROCEDURE StdText; EXTERNAL; +PROCEDURE StdLine; EXTERNAL; +PROCEDURE StdRect; EXTERNAL; +PROCEDURE StdRRect; EXTERNAL; +PROCEDURE StdOval; EXTERNAL; +PROCEDURE StdArc; EXTERNAL; +PROCEDURE StdPoly; EXTERNAL; +PROCEDURE StdRgn; EXTERNAL; +PROCEDURE StdBits; EXTERNAL; +PROCEDURE StdComment; EXTERNAL; +FUNCTION StdTxMeas; EXTERNAL; +PROCEDURE StdGetPic; EXTERNAL; +PROCEDURE StdPutPic; EXTERNAL; + + +{ misc utility routines } + +FUNCTION GetPixel; EXTERNAL; +FUNCTION Random; EXTERNAL; +PROCEDURE AddPt; EXTERNAL; +PROCEDURE SubPt; EXTERNAL; +PROCEDURE SetPt; EXTERNAL; +FUNCTION EqualPt; EXTERNAL; +PROCEDURE StuffHex; EXTERNAL; +PROCEDURE LocalToGlobal; EXTERNAL; +PROCEDURE GlobalToLocal; EXTERNAL; +PROCEDURE ScalePt; EXTERNAL; +PROCEDURE MapPt; EXTERNAL; +PROCEDURE ForeColor; EXTERNAL; +PROCEDURE BackColor; EXTERNAL; +PROCEDURE ColorBit; EXTERNAL; +PROCEDURE SetStdProcs; EXTERNAL; + + + +END. { of UNIT } diff --git a/QuickGlue.a b/QuickGlue.a new file mode 100755 index 0000000..2f8bd3a --- /dev/null +++ b/QuickGlue.a @@ -0,0 +1,145 @@ +; File: QuickGlue.TEXT +;------------------------------------------------------------------ +; +; QuickDraw/Mac OS Interface +; +; written by Andy Hertzfeld 16-Sept-82 +; +; (c) 1982 by Apple Computer, Inc. All rights reserved. +; +; QuickGlue is the QuickDraw/Mac OS interface. It is linked with QuickDraw and +; defines all of the externals required by QuickDraw except those of the +; font manager. All of these are very short and simple (memory manager traps or +; jumps through the graphics jump table). +; +; Modification History +; +; 16-Nov-82 AJH Made font manager interface go through graphics jump table +; 09-Feb-83 AJH Added LockHandle, UnLockHandle +; 17-Aug-83 SC Made all cursor jumps preserve A0 +; 22-Apr-85 LAK Removed RInitGraf (coordinated with Bill clearing +; QDExist flag in InitGraf). +;------------------------------------------------------------------ + + .INCLUDE tlasm-SysTlQk.Sym + +; +; Here is a subset of Unit Storage (the ones needed by +; QuickDraw), implemented by trapping to the Mac OS. +; + + +; +; FUNCTION NewHandle(byteCount: INTEGER): Ptr; +; + .FUNC NewHandle,1 +; + MOVEQ #0,D0 ;clear out high part + MOVE.L (SP)+,A1 ;get return address + MOVE.W (SP)+,D0 ;get the byte count + _NEWHANDLE ;ask OS to do request + BNE.S MemFull ;if memory full, deep shit! + MOVE.L A0,(SP) ;return result handle on stack + JMP (A1) ;return to caller + +; handle the memory full error by deep-shitting + +MemFull + MOVEQ #DSMemFullErr,D0 + _SysError + .WORD $A9FF ;invoke debugger just in case it comes back + +; +; PROCEDURE SetSize(h: Handle; newSize: INTEGER); +; + .DEF SetSize +; +SetSize + MOVEQ #0,D0 ;clear out high part + MOVE.L (SP)+,A1 ;get return address + MOVE.W (SP)+,D0 ;get the new size + MOVE.L (SP)+,A0 ;get the handle + _SETHANDLESIZE ;let OS do it + BNE.S MemFull ;if out of memory, deepShit + JMP (A1) ;return to caller + +; +; PROCEDURE DisposeHandle(h: Handle); +; + .PROC DisposeHandle,2 +; + MOVE.L (SP)+,A1 ;get return address + MOVE.L (SP)+,A0 ;get parameter + _DISPOSHANDLE ;let OS do work + JMP (A1) ;return to caller +; +; PROCEDURE LockHandle(h: Handle); +; + .PROC LockHandle + + MOVE.L 4(SP),A0 + BSET #7,(A0) + MOVE.L (SP)+,(SP) + RTS +; +; PROCEDURE UnLockHandle(h: handle); +; + .PROC UnlockHandle + + MOVE.L 4(SP),A0 + BCLR #7,(A0) + MOVE.L (SP)+,(SP) + RTS + +; +; Following is the QuickDraw cursor interface, implemented by accessing +; system routines through the graphics jump table +; + .PROC CursorDisplay,0 +; + MOVE.L JShowCursor,-(SP) + RTS +; + .PROC CursorHide,0 +; + MOVE.L JHideCursor,-(SP) + RTS +; + .PROC CursorImage,0 +; + MOVE.L JSetCrsr,-(SP) + RTS +; + .PROC CursorInit,0 +; + MOVE.L JInitCrsr,-(SP) + RTS +; + .PROC CursorObscure,0 +; + MOVE.L JCrsrObscure,-(SP) + RTS +; + .PROC CursorShield,0 +; + MOVE.L JShieldCursor,-(SP) + RTS +; + .PROC ScreenAdress,0 +; + MOVE.L JScrnAddr,-(SP) + RTS +; + .PROC ScreenSize,0 +; + MOVE.L JScrnSize,-(SP) + RTS +; + .PROC FMSwapFont,0 + + MOVE.L JSwapFont,-(SP) + RTS + + + + .END diff --git a/RRects.a b/RRects.a new file mode 100755 index 0000000..52d59ab --- /dev/null +++ b/RRects.a @@ -0,0 +1,177 @@ + .INCLUDE GRAFTYPES.TEXT + +;----------------------------------------------------------- +; +; +; **** **** ***** *** ***** *** +; * * * * * * * * * * +; * * * * * * * * +; **** **** *** * * *** +; * * * * * * * * +; * * * * * * * * * * +; * * * * ***** *** * *** +; +; +; procedures for operating on RoundRects. +; +; + + .PROC StdRRect,4 + .REF CheckPic,DPutPicByte,PutPicVerb,PutPicLong,PutPicRect + .REF PutOval,PushVerb,DrawArc +;--------------------------------------------------------------- +; +; PROCEDURE StdRRect(verb: GrafVerb; r: Rect; ovWd,ovHt: INTEGER); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 10 +VERB .EQU PARAMSIZE+8-2 ;GRAFVERB +RECT .EQU VERB-4 ;LONG, ADDR OF RECT +OVWD .EQU RECT-2 ;WORD +OVHT .EQU OVWD-2 ;WORD + + LINK A6,#0 ;NO LOCALS + MOVEM.L D7/A3-A4,-(SP) ;SAVE REGS + MOVE.B VERB(A6),D7 ;GET VERB + JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE.S NOTPIC ;BRANCH IF NOT PICSAVE + + MOVE.B D7,-(SP) ;PUSH VERB + JSR PutPicVerb ;PUT ADDIONAL PARAMS TO THEPIC +; +; CHECK FOR NEW OVAL SIZE +; + MOVE.L PICSAVE(A3),A0 ;GET PICSAVE HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE PICSAVE + MOVE.L OVHT(A6),D0 ;GET OVWD AND OVHT + CMP.L PICOVSIZE(A0),D0 ;SAME AS CURRENT OVAL SIZE ? + BEQ.S OVALOK ;YES, CONTINUE + MOVE.L D0,PICOVSIZE(A0) ;NO, UPDATE STATE VARIABLE + MOVE.L D0,-(SP) ;PUSH OVSIZE FOR PutPicLong CALL + MOVEQ #$0B,D0 + JSR DPutPicByte ;PUT OVSIZE OPCODE + JSR PutPicLong ;PUT NEW OVAL SIZE DATA + +OVALOK MOVEQ #$40,D0 ;PUT RRECT NOUN IN HI NIBBLE + ADD D7,D0 ;PUT VERB IN LO NIBBLE + MOVE.B D0,-(SP) ;PUSH OPCODE + MOVE.L RECT(A6),-(SP) ;PUSH ADDR OF RECT + JSR PutPicRect ;PUT OPCODE AND RECTANGLE + +NOTPIC MOVE.L RECT(A6),-(SP) ;PUSH ADDR OF RECT + CLR.B -(SP) ;PUSH HOLLOW = FALSE + TST.B D7 ;IS VERB FRAME ? + BNE.S DOIT ;NO, CONTINUE + TST.L RGNSAVE(A3) ;YES, IS RGNSAVE TRUE ? + BEQ.S NOTRGN ;NO, CONTINUE + + MOVE.L RECT(A6),-(SP) ;YES, PUSH ADDR OF RECT + MOVE.L OVHT(A6),-(SP) ;PUSH OVWD, OVHT + MOVE.L RGNBUF(A4),-(SP) ;PUSH RGNBUF + PEA RGNINDEX(A4) ;PUSH VAR RGNINDEX + PEA RGNMAX(A4) ;PUSH VAR RGNMAX + JSR PutOval ;ADD AN OVAL TO THERGN + +NOTRGN MOVE.B #1,(SP) ;REPLACE, PUSH HOLLOW = TRUE +DOIT MOVE.L OVHT(A6),-(SP) ;PUSH OVWD,OVHT + JSR PushVerb ;PUSH MODE AND PATTERN + CLR -(SP) ;PUSH STARTANGLE = 0 + MOVE #360,-(SP) ;PUSH ARCANGLE = 360 + +; DrawArc(r,hollow,ovWd,ovHt,mode,pat,startAng,arcAng); + + JSR DrawArc + + MOVEM.L (SP)+,D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDRRECT' + + + + .PROC FrameRoundRect,3 + .DEF CallRRect,PaintRoundRect,EraseRoundRect + .DEF InvertRoundRect,FillRoundRect + .REF StdRRect +;-------------------------------------------------------- +; +; PROCEDURE FrameRoundRect(* r: Rect; ovWd,ovHt: INTEGER *); +; + MOVEQ #FRAME,D0 ;VERB = FRAME + BRA.S CallRRect ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE PaintRoundRect(* r: Rect; ovWd,ovHt: INTEGER *); +; +PaintRoundRect + MOVEQ #PAINT,D0 ;VERB = PAINT + BRA.S CallRRect ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE EraseRoundRect(* r: Rect; ovWd,ovHt: INTEGER *); +; +EraseRoundRect + MOVEQ #ERASE,D0 ;VERB = ERASE + BRA.S CallRRect ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE InvertRoundRect(* r: Rect; ovWd,ovHt: INTEGER *); +; +InvertRoundRect + MOVEQ #INVERT,D0 ;VERB = INVERT + BRA.S CallRRect ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE FillRoundRect(r: Rect; ovWd,ovHt: INTEGER; pat: Pattern); +; +FillRoundRect + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF PATTERN + MOVE.L A0,-(SP) ;PUT RETURN ADDR BACK + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA FILLPAT(A0),A0 ;POINT TO FILLPAT + MOVE.L (A1)+,(A0)+ ;COPY PAT INTO FILLPAT + MOVE.L (A1)+,(A0)+ ;ALL EIGHT BYTES + MOVEQ #FILL,D0 ;VERB = FILL + BRA.S CallRRect ;SHARE COMMON CODE + + + +;--------------------------------------------------------------- +; +; PROCEDURE CallRRect(r: Rect; ovWd,ovHt: INTEGER); +; +; code shared by FrameRoundRect, PaintRoundRect, EraseRoundRect, +; InvertRoundRect, and FillRoundRect. +; enter with verb in D0. +; +CallRRect + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D1 ;POP ovWd and ovHt + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + MOVE.B D0,-(SP) ;PUSH VERB + MOVE.L A1,-(SP) ;PUSH ADDR OF RECT + MOVE.L D1,-(SP) ;PUSH ovWd and ovHt + MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDRRECT,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L RRECTPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;GO TO IT + + + + + + .END diff --git a/Rects.a b/Rects.a new file mode 100755 index 0000000..d06a552 --- /dev/null +++ b/Rects.a @@ -0,0 +1,675 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; +; **** ***** *** ***** *** +; * * * * * * * * +; * * * * * * +; **** *** * * *** +; * * * * * * +; * * * * * * * * +; * * ***** *** * *** +; +; +; +; Procedures for operating on rectangles. +; + + + .PROC StdRect,2 + .REF CheckPic,PutPicVerb,PutPicRect + .REF PutRect,FrRect,PushVerb,DrawRect +;--------------------------------------------------------------- +; +; PROCEDURE StdRect(verb: GrafVerb; r: Rect); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 6 +VERB .EQU PARAMSIZE+8-2 ;GRAFVERB +RECT .EQU VERB-4 ;LONG, ADDR OF RECT + + LINK A6,#0 ;NO LOCALS + MOVEM.L D7/A3-A4,-(SP) ;SAVE REGS + MOVE.B VERB(A6),D7 ;GET VERB + JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE.S NOTPIC ;BRANCH IF NOT PICSAVE + + MOVE.B D7,-(SP) ;PUSH VERB + JSR PutPicVerb ;PUT ADDIONAL PARAMS TO THEPIC + MOVEQ #$30,D0 ;GET RECTNOUN IN HI NIBBLE + ADD D7,D0 ;PUT VERB IN LO NIBBLE + MOVE.B D0,-(SP) ;PUSH OPCODE + MOVE.L RECT(A6),-(SP) ;PUSH ADDR OF RECT + JSR PutPicRect ;PUT OPCODE AND RECTANGLE + +NOTPIC MOVE.L RECT(A6),-(SP) ;PUSH RECT FOR FrRect or DrawRect + TST.B D7 ;IS VERB FRAME ? + BNE.S NOTFR ;NO, CONTINUE + TST.L RGNSAVE(A3) ;YES, IS RGNSAVE TRUE ? + BEQ.S NOTRGN ;NO, CONTINUE + + MOVE.L RECT(A6),-(SP) ;YES, PUSH ADDR OF RECT + MOVE.L RGNBUF(A4),-(SP) ;PUSH RGNBUF + PEA RGNINDEX(A4) ;PUSH VAR RGNINDEX + PEA RGNMAX(A4) ;PUSH VAR RGNMAX + JSR PutRect ;ADD A RECT TO THERGN + +NOTRGN JSR FrRect ;FrRect(rect) + BRA.S GOHOME + +NOTFR JSR PushVerb ;PUSH MODE AND PATTERN + JSR DRAWRECT ;DrawRect(rect,mode,pat); + +GOHOME MOVEM.L (SP)+,D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDRECT ' + + + + .PROC PushVerb +;---------------------------------------------------------- +; +; PUSH A MODE AND A PATTERN, BASED ON VERB +; ENTER WITH VERB IN D7, GRAFGLOBALS IN A4, THEPORT IN A3. +; +; CLOBBERS A0. +; +; frame: pnMode, pnPat +; paint: pnMode, pnPat +; erase: patCopy, bkPat +; invert: patXor, black +; fill: patCopy, fillPat +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE #8,-(SP) ;PUSH MODE = PATCOPY (IE. DEFAULT) + CMP.B #1,D7 ;CASE ON VERB + BLE.S PAINT1 + CMP.B #3,D7 + BLT.S ERASE1 + BEQ.S INVERT1 + +FILL1 PEA FILLPAT(A3) ;PUSH PAT := FILLPAT + BRA.S DONE + +ERASE1 PEA BKPAT(A3) ;PUSH PAT = BKPAT + BRA.S DONE + +INVERT1 ADD.W #2,(SP) ;ADJUST, PUSH MODE = PATXOR + PEA BLACK(A4) ;PUSH PAT = BLACK + BRA.S DONE + +PAINT1 MOVE PNMODE(A3),(SP) ;REPLACE, PUSH MODE = PNMODE + PEA PNPAT(A3) ;PUSH PAT = PNPAT + +DONE JMP (A0) ;RETURN TO CALLER + + + + .PROC FillRect,2 + .DEF CallRect,FrameRect,PaintRect,EraseRect,InvertRect + .REF StdRect +;---------------------------------------------------------- +; +; PROCEDURE FillRect(r: Rect; pat: Pattern); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF PATTERN + MOVE.L A0,-(SP) ;PUT RETURN ADDR BACK + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA FILLPAT(A0),A0 ;POINT TO FILLPAT + MOVE.L (A1)+,(A0)+ ;COPY PAT INTO FILLPAT + MOVE.L (A1)+,(A0)+ ;ALL EIGHT BYTES + MOVEQ #FILL,D0 ;VERB = FILL + BRA.S CallRect ;SHARE COMMON CODE + + + +;---------------------------------------------------------- +; +; PROCEDURE FrameRect(r: Rect); +; +FrameRect + MOVEQ #FRAME,D0 ;VERB = FRAME + BRA.S CallRect ;SHARE COMMON CODE + + +;---------------------------------------------------------- +; +; PROCEDURE PaintRect(r: Rect); +; +PaintRect + MOVEQ #PAINT,D0 ;VERB = PAINT + BRA.S CallRect ;SHARE COMMON CODE + + +;---------------------------------------------------------- +; +; PROCEDURE EraseRect(r: Rect); +; +EraseRect + MOVEQ #ERASE,D0 ;VERB = ERASE + BRA.S CallRect ;SHARE COMMON CODE + + +;---------------------------------------------------------- +; +; PROCEDURE InvertRect(r: Rect); +; +InvertRect + MOVEQ #INVERT,D0 ;VERB = INVERT + BRA.S CallRect ;SHARE COMMON CODE + + +;--------------------------------------------------------------- +; +; PROCEDURE CallRect(r: Rect); +; +; code shared by FrameRect, PaintRect, EraseRect, InvertRect, and FillRect. +; enter with verb in D0. +; +CallRect + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + MOVE.B D0,-(SP) ;PUSH VERB + MOVE.L A1,-(SP) ;PUSH ADDR OF RECT + MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDRECT,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L RECTPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;GO TO IT + + + .PROC DrawRect,3 + .REF RgnBlt +;---------------------------------------------------------- +; +; PROCEDURE DrawRect(r: Rect; mode: INTEGER; pat: Pattern); +; +; Rectangle is given in local coordinates. +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 10 ;TOTAL BYTES OF PARAMS +DSTRECT .EQU PARAMSIZE+8-4 ;LONG, ADDR OF RECT +MODE .EQU DSTRECT-2 ;WORD +PAT .EQU MODE-4 ;LONG, ADDR OF PAT + + LINK A6,#0 ;NO LOCAL VARS + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A1 ;GET CURRENT GRAFPORT + TST PNVIS(A1) ;IS PNVIS >= 0 ? + BLT.S GOHOME ;NO, QUIT + PEA PORTBITS(A1) ;PUSH SRCBITS = DSTBITS + MOVE.L (SP),-(SP) ;PUSH DSTBITS + MOVE.L DSTRECT(A6),-(SP) ;PUSH SRCRECT = DSTRECT + MOVE.L (SP),-(SP) ;PUSH DSTRECT + MOVE MODE(A6),-(SP) ;PUSH MODE + MOVE.L PAT(A6),-(SP) ;PUSH ADDR OF PATTERN + MOVE.L CLIPRGN(A1),-(SP) ;PUSH CLIPRGN + MOVE.L VISRGN(A1),-(SP) ;PUSH VISRGN + MOVE.L WIDEOPEN(A0),-(SP) ;PUSH WIDE OPEN + JSR RGNBLT ;CALL RGNBLT +GOHOME UNLINK PARAMSIZE,'DRAWRECT' + + + + .PROC FrRect,1 + .REF RgnBlt +;---------------------------------------------------------- +; +; PROCEDURE FrRect(r: Rect); +; Draws an outline inside a rect. +; +; A6 OFFSETS OF PARAMETERS AND LOCALS AFTER LINK: +; +DSTRECT .EQU 8 ;LONG, ADDR OF RECT +H1 .EQU -2 ;WORD +H2 .EQU H1-2 ;WORD +H3 .EQU H2-2 ;WORD +H4 .EQU H3-4 ;WORD +V1 .EQU H4-2 ;WORD +V2 .EQU V1-2 ;WORD +V3 .EQU V2-2 ;WORD +V4 .EQU V3-4 ;WORD +TEMPRECT .EQU V4-8 ;RECT +VARSIZE .EQU TEMPRECT ;TOTAL SIZE OF LOCALS + + + LINK A6,#VARSIZE ;SET UP STACK FRAME + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + TST PNVIS(A0) ;IS PNVIS NEGATIVE ? + BLT GOHOME ;YES, DON'T DRAW AT ALL + MOVE.L DSTRECT(A6),A1 ;POINT TO INPUT RECT + MOVE.L (A1)+,TEMPRECT+TOPLEFT(A6) ;COPY INPUT RECT + MOVE.L (A1)+,TEMPRECT+BOTRIGHT(A6) +; +; Now set up h1,h2,h3,h4 and v1,v2,v3,v4 +; + LEA TEMPRECT(A6),A1 ;POINT TO COPIED RECT + MOVE PNSIZE+H(A0),D2 ;GET PEN WIDTH + MOVE LEFT(A1),D0 + MOVE D0,H1(A6) ;H1:=LEFT + ADD D2,D0 + MOVE D0,H2(A6) ;H2:=LEFT+PENWIDTH + MOVE RIGHT(A1),D1 + MOVE D1,H4(A6) ;H4:=RIGHT + SUB D2,D1 + MOVE D1,H3(A6) ;H3:=RIGHT-PENWIDTH + CMP D1,D0 ;IS H2 >= H3 ? + BGE.S @1 ;YES, FILL IT IN SOLID + + MOVE PNSIZE+V(A0),D2 ;GET PEN HEIGHT + MOVE TOP(A1),D0 + MOVE D0,V1(A6) ;V1:=TOP + ADD D2,D0 + MOVE D0,V2(A6) ;V2:=TOP+PENHEIGHT + MOVE BOTTOM(A1),D1 + MOVE D1,V4(A6) ;V4:=BOTTOM + SUB D2,D1 + MOVE D1,V3(A6) ;V3:=BOTTOM-PENHEIGHT + CMP D1,D0 ;IS V2 >= V3 ? + BGE.S @1 ;YES, FILL IT IN SOLID + +; +; PEN IS NOT SO BIG AS TO FILL IN SOLID. BREAK RECT INTO 4 EDGES. +; + MOVE H1(A6),TEMPRECT+LEFT(A6) + MOVE H3(A6),TEMPRECT+RIGHT(A6) + MOVE V1(A6),TEMPRECT+TOP(A6) + MOVE V2(A6),TEMPRECT+BOTTOM(A6) + BSR.S DORECT ;PAINT TOP EDGE + + MOVE H3(A6),TEMPRECT+LEFT(A6) + MOVE H4(A6),TEMPRECT+RIGHT(A6) + MOVE V3(A6),TEMPRECT+BOTTOM(A6) + BSR.S DORECT ;PAINT RIGHT EDGE + + MOVE H2(A6),TEMPRECT+LEFT(A6) + MOVE V3(A6),TEMPRECT+TOP(A6) + MOVE V4(A6),TEMPRECT+BOTTOM(A6) + BSR.S DORECT ;PAINT BOTTOM EDGE + + MOVE H1(A6),TEMPRECT+LEFT(A6) + MOVE H2(A6),TEMPRECT+RIGHT(A6) + MOVE V2(A6),TEMPRECT+TOP(A6) +@1 BRA.S FILLED ;PAINT LEFT EDGE + + +;-------------------------------------------------------- +; +; LOCAL ROUTINE TO PAINT TEMPRECT, GIVEN IN LOCAL COORDS +; +DORECT MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A1 ;POINT TO CURRENT GRAFPORT + PEA PORTBITS(A1) ;PUSH SRCBITS = DSTBITS + MOVE.L (SP),-(SP) ;PUSH DSTBITS + PEA TEMPRECT(A6) ;PUSH SRCRECT = DSTRECT + MOVE.L (SP),-(SP) ;PUSH DSTRECT, LOCAL COORDS + MOVE PNMODE(A1),-(SP) ;PUSH PEN MODE + PEA PNPAT(A1) ;PUSH ADDR OF PEN PATTERN + MOVE.L CLIPRGN(A1),-(SP) ;PUSH CLIPRGN + MOVE.L VISRGN(A1),-(SP) ;PUSH VISRGN + MOVE.L WIDEOPEN(A0),-(SP) ;PUSH WIDE OPEN + JSR RGNBLT ;CALL RGNBLT + RTS + +FILLED BSR DORECT ;FILL TEMPRECT SOLID +GOHOME UNLINK 4,'FRRECT ' + + + + .PROC SetRect,5 +;---------------------------------------------------------- +; +; PROCEDURE SetRect(VAR r: Rect; left,top,right,bottom: INTEGER); +; { assign 4 integers into a rectangle } +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D1 ;POP BOTRIGHT POINT + MOVE.L (SP)+,D0 ;POP TOPLEFT POINT + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + MOVE.L D0,(A1)+ ;INSTALL TOPLEFT + MOVE.L D1,(A1)+ ;INSTALL BOTRIGHT + JMP (A0) ;RETURN + + + + .FUNC EqualRect,2 +;---------------------------------------------------------- +; +; FUNCTION EqualRect(rect1,rect2: Rect): BOOLEAN; +; +; CLOBBERS D0,A0,A1. +; + MOVE.L (SP)+,D0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF RECT2 + MOVE.L (SP)+,A0 ;POP ADDR OF RECT1 + CMPM.L (A0)+,(A1)+ ;IS TOPLEFT SAME ? + BNE.S FALSE ;NO, RETURN FALSE + CMPM.L (A0)+,(A1)+ ;YES, IS BOTRIGHT SAME TOO ? + BNE.S FALSE ;NO, RETURN FALSE + MOVE.B #1,(SP) ;YES, RETURN TRUE + BRA.S DONE ;AND QUIT +FALSE CLR.B (SP) ;RETURN FALSE +DONE MOVE.L D0,-(SP) ;PUSH RETURN ADDR + RTS ;AND RETURN + + + + .FUNC EmptyRect,1 +;---------------------------------------------------------- +; +; FUNCTION EmptyRect(r: Rect): BOOLEAN; +; +; CLOBBERS D0,D1,A0,A1. +; + MOVE.L (SP)+,A1 ;POP RETURN ADDR + MOVE.L (SP)+,A0 ;POP ADDR OF RECT + MOVE (A0)+,D0 ;GET TOP + MOVE (A0)+,D1 ;GET LEFT + CMP (A0)+,D0 ;IS TOP >= BOTTOM ? + BGE.S EMPTY ;YES, RETURN TRUE + CMP (A0)+,D1 ;IS LEFT >= RIGHT ? + BGE.S EMPTY ;YES, RETURN TRUE + CLR.B (SP) ;NOT EMPTY, RETURN FALSE + BRA.S DONE ;AND QUIT +EMPTY MOVE.B #1,(SP) ;RETURN TRUE +DONE JMP (A1) ;RETURN + + + + .PROC OffsetRect,3 +;---------------------------------------------------------- +; +; PROCEDURE OffsetRect(VAR r: Rect; dh,dv: INTEGER); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE (SP)+,D1 ;POP DV + MOVE (SP)+,D0 ;POP DH + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + ADD D1,(A1)+ ;TOP:=TOP+DV + ADD D0,(A1)+ ;LEFT:=LEFT+DH + ADD D1,(A1)+ ;BOTTOM:=BOTTOM+DV + ADD D0,(A1)+ ;RIGHT:=RIGHT+DH + JMP (A0) ;RETURN + + + .PROC InsetRect,3 +;---------------------------------------------------------- +; +; PROCEDURE InsetRect(VAR r: Rect; dh,dv: INTEGER); +; { inset a rectangle on all 4 sides } +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE (SP)+,D1 ;POP DV + MOVE (SP)+,D0 ;POP DH + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + ADD D1,(A1)+ ;ADD DV TO TOP + ADD D0,(A1)+ ;ADD DH TO LEFT + SUB D1,(A1)+ ;SUBTRACT DV FROM BOTTOM + SUB D0,(A1)+ ;SUBTRACT DH FROM RIGHT +DONE JMP (A0) ;RETURN + + + + .FUNC SectRect,3 + .DEF RSect +;--------------------------------------------------------- +; +; FUNCTION SectRect(srcA,srcB: Rect; VAR dstC: Rect): BOOLEAN; +; +; Returns TRUE and intersection in dst, +; else FALSE and dst = 0,0,0,0. +; Dst may also be used as one of the inputs +; +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 12 ;SIZE OF PARAMETERS +RESULT .EQU PARAMSIZE+8 ;BOOLEAN RESULT +SRCA .EQU RESULT-4 ;LONG, ADDR OF RECTANGLE +SRCB .EQU SRCA-4 ;LONG, ADDR OF RECTANGLE +DST .EQU SRCB-4 ;LONG, ADDR OF RECTANGLE + + + LINK A6,#0 ;NO LOCAL VARS + MOVE.L SRCA(A6),-(SP) ;PUSH SRCA POINTER + MOVE.L SRCB(A6),-(SP) ;PUSH SRCB POINTER + MOVE #2,-(SP) ;PUSH NRECTS=2 + MOVE.L DST(A6),-(SP) ;PUSH DST POINTER + BSR.S RSECT ;CALC INTERSECTION + SNE RESULT(A6) ;STORE BOOLEAN RESULT + NEG.B RESULT(A6) ;CONVERT $FF TO $01 +NOTEMPTY UNLINK PARAMSIZE,'SECTRECT' + + +;--------------------------------------------------- +; +; ASSEMBLY CALLABLE ROUTINE TO COMPUTE THE INTERSECTION OF +; ANY NUMBER OF RECTANGLES. +; +; INPUTS: PUSH ADDRESSES OF EACH INPUT RECTANGLE (LONGS) +; PUSH # OF RECTANGLES (WORD) +; PUSH ADDRESS OF OUTPUT RECTANGLE (LONG) +; +; RETURNS DST=(0,0,0,0) AND Z-FLAG SET IF NO INTERSECTION +; +; CLOBBERS: D0,A0 +; +RSECT LINK A6,#0 + MOVEM.L D1-D4/A1,-(SP) ;SAVE REGS + LEA 12(A6),A1 ;POINT TO NRECTS + MOVE (A1)+,D0 ;GET NRECTS COUNT + BLE.S EMPTY ;EMPTY IF NRECTS <= 0 + MOVE.L (A1)+,A0 ;POINT TO FIRST RECT + MOVEM.W (A0)+,D1/D2/D3/D4 ;GET TOP, LEFT, BOT, RIGHT + SUB #1,D0 ;DECREMENT RECT COUNT + BRA.S RTOK ;CHECK THIS RECT AND LOOP + +NEXTRECT MOVE.L (A1)+,A0 ;POINT TO NEXT RECT + CMP (A0)+,D1 ;IS TOP < NEXT TOP ? + BGE.S TOPOK ;NO, CONTINUE + MOVE -2(A0),D1 ;YES, TOP:=NEXT TOP +TOPOK CMP (A0)+,D2 ;IS LEFT < NEXT LEFT ? + BGE.S LEFTOK ;NO, CONTINUE + MOVE -2(A0),D2 ;YES, LEFT:=NEXT LEFT +LEFTOK CMP (A0)+,D3 ;IS BOTTOM > NEXT BOT ? + BLE.S BOTOK ;NO, CONTINUE + MOVE -2(A0),D3 ;YES, BOTTOM:=NEXT BOT +BOTOK CMP (A0)+,D4 ;IS RIGHT > NEXT RIGHT ? + BLE.S RTOK ;NO, CONTINUE + MOVE -2(A0),D4 ;YES, RIGHT:=NEXT RIGHT +RTOK CMP D1,D3 ;IS BOTTOM <= TOP ? + BLE.S EMPTY ;YES, EMPTY + CMP D2,D4 ;IS RIGHT <= LEFT ? + BLE.S EMPTY ;YES, EMPTY + DBRA D0,NEXTRECT ;LOOP FOR ALL RECTANGLES + BRA.S DONE + +EMPTY CLR D1 ;ALL EMPTY RECTS ARE (0,0,0,0) + CLR D2 + CLR D3 + CLR D4 +DONE MOVE.L 8(A6),A0 ;GET DST ADDR + MOVE D1,(A0)+ ;STORE DST TOP + MOVE D2,(A0)+ ;DST LEFT + MOVE D3,(A0)+ ;DST BOT + MOVE D4,(A0)+ ;DST RIGHT + MOVE 12(A6),D0 ;GET NRECTS COUNT AGAIN + LSL #2,D0 ;TIMES 4 BYTES PER RECTANGLE + ADD #6,D0 ;PLUS 6 BYTES FOR NRECTS AND DSTPTR + CMP D1,D3 ;SET Z-FLAG IF EMPTY RECT + MOVEM.L (SP)+,D1-D4/A1 ;RESTORE REGS + UNLK A6 ;RELEASE STATIC FRAME PTR + MOVE.L (SP)+,A0 ;POP RETURN ADDR + ADD D0,SP ;STRIP VARIABLE NUMBER OF PARAMS + JMP (A0) ;RETURN WITH Z-FLAG IF EMPTY + + + .PROC UnionRect,3 + .DEF Pt2Rect +;---------------------------------------------------------- +; +; PROCEDURE UnionRect(* src1,src2: Rect; VAR dst: Rect *); +; +; { compute smallest rectangle containing both input rectangles } +; { works correctly even if one of the sources is the destination } +; + MOVE.L 12(SP),A0 ;GET ADDR OF SRC1 + MOVE.L 8(SP),A1 ;GET ADDR OF SRC2 + + MOVE (A0)+,D0 ;TOP:=TOP1 + CMP (A1)+,D0 ;IS TOP2 < TOP ? + BLE.S TOPOK ;NO, CONTINUE + MOVE -2(A1),D0 ;YES, TOP:=TOP2 +TOPOK SWAP D0 ;PUT TOP IN HI WORD + MOVE (A0)+,D0 ;LEFT:=LEFT1 + CMP (A1)+,D0 ;IS LEFT2 < LEFT ? + BLE.S LEFTOK ;NO, CONTINUE + MOVE -2(A1),D0 ;YES, LEFT:=LEFT2 +LEFTOK MOVE (A0)+,D1 ;BOTTOM:=BOTTOM1 + CMP (A1)+,D1 ;IS BOTTOM2 > BOTTOM ? + BGE.S BOTOK ;NO, CONTINUE + MOVE -2(A1),D1 ;YES, BOTTOM:=BOTTOM2 +BOTOK SWAP D1 ;PUT BOTTOM IN HI WORD + MOVE (A0)+,D1 ;RIGHT:=RIGHT1 + CMP (A1)+,D1 ;IS RIGHT2 > RIGHT1 ? + BGE.S RIGHTOK ;NO, CONTINUE + MOVE -2(A1),D1 ;YES, RIGHT:=RIGHT2 +RIGHTOK MOVE.L 4(SP),A0 ;POINT TO DST RECT + MOVE.L D0,(A0)+ ;INSTALL TOPLEFT + MOVE.L D1,(A0)+ ;INSTALL BOTRIGHT + BRA.S SHARE ;STRIP 3 PARAMETERS AND RETURN + + +;---------------------------------------------------------- +; +; PROCEDURE Pt2Rect(* pt1,pt2: Point; VAR dst: Rect *); +; +; { make a rectangle from two points } +; +Pt2Rect MOVE.L 4(SP),A0 ;POINT TO DST RECT + MOVE 14(SP),D0 ;GET H1 + MOVE 10(SP),D1 ;GET H2 + CMP D0,D1 ;IS H2 < H1 ? + BGE.S HOK ;NO, CONTINUE + EXG D0,D1 ;YES, SWAP THEM +HOK MOVE D0,LEFT(A0) ;INSTALL DST LEFT = MIN(H1,H2) + MOVE D1,RIGHT(A0) ;INSTALL DST RIGHT = MAX(H1,H2) + MOVE 12(SP),D0 ;GET V1 + MOVE 8(SP),D1 ;GET V2 + CMP D0,D1 ;IS V2 < V1 ? + BGE.S VOK ;NO, CONTINUE + EXG D0,D1 ;YES, SWAP THEM +VOK MOVE D0,TOP(A0) ;INSTALL DST TOP = MIN(V1,V2) + MOVE D1,BOTTOM(A0) ;INSTALL DST BOTTOM = MAX(V1,V2) +SHARE MOVE.L (SP)+,A0 ;POP RETURN ADDR + ADD #12,SP ;STRIP 3 PARAMETERS + JMP (A0) ;AND RETURN + + + + .FUNC PtInRect,2 +;------------------------------------------------------------ +; +; FUNCTION PtInRect(pt: Point; r: Rect): BOOLEAN; +; +; Returns TRUE if point is within the rectangle. +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 8 ;SIZE OF PARAMETERS +RESULT .EQU PARAMSIZE+8 ;A6 OFFSETS AFTER LINK +PT .EQU RESULT-4 ;POINT, VALUE +R .EQU PT-4 ;LONG, ADDR OF RECTANGLE + + LINK A6,#0 ;NO LOCAL VARS + MOVE.L R(A6),A0 ;GET RECT PTR + MOVE PT+H(A6),D0 ;GET HORIZ COORD + MOVE PT+V(A6),D1 ;GET VERT COORD + CLR.B RESULT(A6) ;INIT BOOLEAN TO FALSE + CMP (A0)+,D1 ;IS PT.V < TOP ? + BLT.S FALSE ;YES, QUIT + CMP (A0)+,D0 ;IS PT.H < LEFT ? + BLT.S FALSE ;YES, QUIT + CMP (A0)+,D1 ;IS PT.V >= BOTTOM ? + BGE.S FALSE ;YES, QUIT + CMP (A0)+,D0 ;IS PT.H >= RIGHT ? + BGE.S FALSE ;YES, QUIT + ADDQ.B #1,RESULT(A6) ;RETURN BOOLEAN TRUE +FALSE UNLINK PARAMSIZE,'PTINRECT' + + + + .PROC PutRect,4 + .REF SetSize +;---------------------------------------------------------------- +; +; PROCEDURE PutRect(r: Rect; bufHandle: Handle; VAR index,size: INTEGER); +; +; Puts the four inversion points of a rectangle +; +; Clobbers D0,A0,A1 +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 16 ;TOTAL SIZE OF PARAMETERS +RECT .EQU PARAMSIZE+8-4 ;LONG, ADDR OF RECT +BUFHANDLE .EQU RECT-4 ;LONG, HANDLE +INDEX .EQU BUFHANDLE-4 ;LONG, ADDR OF INTEGER +SIZE .EQU INDEX-4 ;LONG, ADDR OF INTEGER + + + LINK A6,#0 ;NO LOCAL VARIABLES + +;------------------------------------------------------------ +; +; IS THERE ROOM FOR FOUR NEW POINTS IN THE POINT BUFFER ? +; + MOVE.L INDEX(A6),A0 ;POINT TO INDEX + MOVE.L SIZE(A6),A1 ;POINT TO SIZE + MOVEQ #16,D0 + ADD (A0),D0 ;GET CURRENT INDEX + 16 + CMP (A1),D0 ;IS NEW INDEX > SIZE ? + BLE.S SIZEOK ;NO, CONTINUE + + +;------------------------------------------------------------- +; +; NO, GROW THE POINT BUFFER ENOUGH FOR 256 MORE POINTS +; + ADD #1024,(A1) ;ADD 1024 TO SIZE + MOVEM.L D3/A2,-(SP) ;SAVE REGS + MOVE.L BUFHANDLE(A6),-(SP) ;PUSH HANDLE PARAM + MOVE (A1),-(SP) ;PUSH NEW SIZE + JSR SETSIZE ;MAKE THE BUFFER BIGGER + MOVEM.L (SP)+,D3/A2 ;RESTORE REGS + MOVE.L INDEX(A6),A0 ;POINT TO INDEX AGAIN + + +;------------------------------------------------------------ +; +; NOW INSTALL THE 4 NEW INVERSION POINTS +; +SIZEOK MOVE.L BUFHANDLE(A6),A1 ;GET BUFHANDLE + MOVE.L (A1),A1 ;DE-REFERENCE HANDLE + ADD (A0),A1 ;ADD INDEX FOR POINTER + ADD #16,(A0) ;BUMP INDEX + MOVE.L RECT(A6),A0 ;POINT TO RECTANGLE + MOVE.L TOPLEFT(A0),(A1)+ ;PUT TOPLEFT POINT + MOVE TOP(A0),(A1)+ ;PUT TOP-RIGHT POINT + MOVE RIGHT(A0),(A1)+ + MOVE BOTTOM(A0),(A1)+ ;PUT BOTTOM-LEFT POINT + MOVE LEFT(A0),(A1)+ + MOVE.L BOTRIGHT(A0),(A1)+ ;PUT BOTRIGHT POINT + UNLINK PARAMSIZE,'PUTRECT ' + + + + .END diff --git a/Regions.a b/Regions.a new file mode 100755 index 0000000..8d6c909 --- /dev/null +++ b/Regions.a @@ -0,0 +1,1170 @@ + .INCLUDE GRAFTYPES.TEXT +;----------------------------------------------------------- +; +; +; **** ***** *** *** *** * * *** +; * * * * * * * * * * * * +; * * * * * * * ** * * +; **** *** * ** * * * * * * *** +; * * * * * * * * * ** * +; * * * * * * * * * * * * +; * * ***** *** *** *** * * *** +; +; +; +; QuickDraw Routines to operate on Regions. +; + + .PROC StdRgn,2 + .REF CheckPic,PutPicVerb,DPutPicByte,PutPicRgn + .REF PutRgn,FrRgn,PushVerb,DrawRgn +;--------------------------------------------------------------- +; +; PROCEDURE StdRgn(verb: GrafVerb; rgn: RgnHandle); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 6 +VERB .EQU PARAMSIZE+8-2 ;GRAFVERB +RGN .EQU VERB-4 ;LONG, RGNHANDLE + + LINK A6,#0 ;NO LOCALS + MOVEM.L D6-D7/A2-A4,-(SP) ;SAVE REGS + MOVE.B VERB(A6),D7 ;GET VERB + JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE.S NOTPIC ;BRANCH IF NOT PICSAVE + + MOVE.B D7,-(SP) ;PUSH VERB + JSR PutPicVerb ;PUT ADDIONAL PARAMS TO THEPIC + MOVE #$80,D0 ;PUT RGNNOUN IN HI NIBBLE + ADD D7,D0 ;PUT VERB IN LO NIBBLE + JSR DPutPicByte ;PUT OPCODE TO THEPIC + MOVE.L RGN(A6),-(SP) ;PUSH RGNHANDLE + JSR PutPicRgn ;PUT REGION TO THEPIC + +NOTPIC MOVE.L RGN(A6),-(SP) ;PUSH RGNHANDLE + JSR PushVerb ;PUSH MODE AND PATTERN + TST.B D7 ;IS VERB FRAME ? + BNE.S NOTFR ;NO, CONTINUE + TST.L RGNSAVE(A3) ;YES, IS RGNSAVE TRUE ? + BEQ.S NOTRGN ;NO, CONTINUE + MOVE.L RGN(A6),-(SP) ;YES, PUSH RGNHANDLE + MOVE.L RGNBUF(A4),-(SP) ;PUSH RGNBUF + PEA RGNINDEX(A4) ;PUSH VAR RGNINDEX + PEA RGNMAX(A4) ;PUSH VAR RGNMAX + JSR PutRgn ;ADD INVERSION PTS TO THERGN + +NOTRGN JSR FrRgn ;FrRgn(rgn,pnMode,pnPat) + BRA.S GOHOME + +NOTFR JSR DrawRgn ;DrawRgn(rgn,mode,pat); + +GOHOME MOVEM.L (SP)+,D6-D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDRGN ' + + + + .PROC FrameRgn,1 + .DEF CallRgn,PaintRgn,EraseRgn,InvertRgn,FillRgn + .REF StdRgn +;----------------------------------------------------- +; +; PROCEDURE FrameRgn(* rgn: RgnHandle *); +; + MOVEQ #FRAME,D0 ;VERB = FRAME + BRA.S CallRgn ;SHARE COMMON CODE + + +;----------------------------------------------------- +; +; PROCEDURE PaintRgn(* rgn: RgnHandle *); +; +PaintRgn + MOVEQ #PAINT,D0 ;VERB = PAINT + BRA.S CallRgn ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE EraseRgn(* rgn: RgnHandle *); +; +EraseRgn + MOVEQ #ERASE,D0 ;VERB = ERASE + BRA.S CallRgn ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE InvertRgn(* rgn: RgnHandle *); +; +InvertRgn + MOVEQ #INVERT,D0 ;VERB = INVERT + BRA.S CallRgn ;SHARE COMMON CODE + + +;-------------------------------------------------------- +; +; PROCEDURE FillRgn(* rgn: RgnHandle; pat: Pattern *); +; +FillRgn + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF PATTERN + MOVE.L A0,-(SP) ;PUT RETURN ADDR BACK + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + LEA FILLPAT(A0),A0 ;POINT TO FILLPAT + MOVE.L (A1)+,(A0)+ ;COPY PAT INTO FILLPAT + MOVE.L (A1)+,(A0)+ ;ALL EIGHT BYTES + MOVEQ #FILL,D0 ;VERB = FILL + BRA.S CallRgn ;SHARE COMMON CODE + + + +;--------------------------------------------------------------- +; +; PROCEDURE CallRgn(rgn: RgnHandle); +; +; code shared by FrameRgn, PaintRgn, EraseRgn, InvertRgn, and FillRgn. +; enter with verb in D0. +; +CallRgn + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP RGN + MOVE.B D0,-(SP) ;PUSH VERB + MOVE.L A1,-(SP) ;PUSH RGN + MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDRGN,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L RGNPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;GO TO IT + + + .PROC DrawRgn,3 + .REF RgnBlt +;-------------------------------------------------------- +; +; PROCEDURE DrawRgn(rgn: RgnHandle; mode: INTEGER; pat: Pattern); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 10 +RGN .EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE +MODE .EQU RGN-2 ;WORD +PAT .EQU MODE-4 ;LONG, ADDR OF PATTERN + + LINK A6,#0 + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT PORT + TST PNVIS(A0) ;IS PNVIS NEG ? + BMI.S DONE ;YES, QUIT + PEA PORTBITS(A0) ;PUSH SRCBITS + MOVE.L (SP),-(SP) ;PUSH DSTBITS + PEA PORTBITS+BOUNDS(A0) ;PUSH SRCRECT + MOVE.L (SP),-(SP) ;PUSH DSTRECT + MOVE MODE(A6),-(SP) ;PUSH MODE + MOVE.L PAT(A6),-(SP) ;PUSH PAT + MOVE.L CLIPRGN(A0),-(SP) ;PUSH CLIPRGN + MOVE.L VISRGN(A0),-(SP) ;PUSH VISRGN + MOVE.L RGN(A6),-(SP) ;PUSH RGN + JSR RGNBLT ;CALL RGNBLT +DONE UNLINK PARAMSIZE,'DRAWRGN ' + + + + .PROC FrRgn,3 + .REF FrRect,NewRgn,CopyRgn,InsetRgn,DiffRgn,DrawRgn +;-------------------------------------------------------- +; +; PROCEDURE FrRgn(rgn: RgnHandle; mode: INTEGER; pat: Pattern); +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 10 +RGN .EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE +MODE .EQU RGN-2 ;WORD +PAT .EQU MODE-4 ;LONG, ADDR OF PATTERN + + LINK A6,#0 + MOVEM.L D7/A3-A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO LISAGRAF GLOBALS + MOVE.L THEPORT(A4),A3 ;GET CURRENT PORT + TST PNVIS(A3) ;IS PNVIS NEG ? + BMI.S DONE ;YES, QUIT +; +; special case rectangular region for speed. +; + MOVE.L RGN(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + CMP #10,RGNSIZE(A0) ;IS IT RECTANGULAR ? + BNE.S NOTRECT ;NO, CONTINUE + PEA RGNBBOX(A0) ;YES, PUSH ADDR OF BBOX + JSR FRRECT ;FRAME IT + BRA.S DONE ;AND QUIT + +NOTRECT CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + JSR NEWRGN ;ALLOCATE TEMPRGN + MOVE.L (A7)+,D7 ;PUT TEMPRGN IN D7 + MOVE.L RGN(A6),-(SP) ;PUSH RGN + MOVE.L D7,-(SP) ;PUSH TEMPRGN + JSR COPYRGN ;COPY RGN INTO TEMPRGN + MOVE.L D7,-(SP) ;PUSH TEMPRGN + MOVE.L PNSIZE(A3),-(SP) ;PUSH PNSIZE + JSR INSETRGN ;InsetRgn(tempRgn,pnSize); + MOVE.L RGN(A6),-(SP) ;PUSH RGN + MOVE.L D7,-(SP) ;PUSH TEMPRGN + MOVE.L D7,-(SP) ;PUSH TEMPRGN + JSR DIFFRGN ;DiffRgn(rgn,tempRgn,tempRgn); + MOVE.L D7,-(SP) ;PUSH TEMPRGN + MOVE MODE(A6),-(SP) ;PUSH MODE + MOVE.L PAT(A6),-(SP) ;PUSH PAT + JSR DRAWRGN ;DrawRgn(tempRgn,mode,pat); + MOVE.L D7,A0 ;GET TEMPRGN + _DisposHandle ;DISCARD IT +DONE MOVEM.L (SP)+,D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'FRRGN ' + + + + .FUNC NewRgn,0 + .REF NewHandle +;--------------------------------------------------- +; +; FUNCTION NewRgn; +; Allocate a new region and set it to the empty region. +; + MOVEM.L D3/A2,-(SP) ;SAVE REGS + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE #10,-(SP) ;PUSH BYTECOUNT=10 + JSR NEWHANDLE ;ALLOCATE A RELOCATABLE OBJECT + MOVE.L (SP)+,A0 ;POP RESULTING HANDLE + MOVEM.L (SP)+,D3/A2 ;RESTORE REGS + MOVE.L A0,4(SP) ;STORE INTO NEWRGN RESULT + MOVE.L (A0),A0 ;DE-REFERENCE HANDLE + MOVE #10,(A0)+ ;INSTALL RGNSIZE=10 + CLR.L (A0)+ ;INSTALL RGNBBOX=(0,0,0,0) + CLR.L (A0)+ + RTS ;RETURN TO CALLER + + + + .PROC DisposeRgn,1 +;--------------------------------------------------- +; +; PROCEDURE DisposeRgn(rgn: RgnHandle); +; + MOVE.L (SP)+,A1 ;pop return addr + MOVE.L (SP)+,A0 ;pop handle + _DisposHandle ;discard it + JMP (A1) ;and return + + + + .PROC OpenRgn,0 + .REF NewHandle,HidePen +;--------------------------------------------------- +; +; PROCEDURE OpenRgn; +; + MOVEM.L D3/A2-A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A0 ;GET CURRENT GRAFPORT + MOVE.L #1,D0 + MOVE.L D0,RGNSAVE(A0) ;RGNSAVE := TRUE + CLR RGNINDEX(A4) ;RGNINDEX := 0 + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE #256,-(SP) ;PUSH BYTE COUNT = 256 + MOVE (SP),RGNMAX(A4) ;RGNMAX := 256 TOO; + JSR NEWHANDLE + MOVE.L (SP)+,RGNBUF(A4) ;RGNBUF := NEWHANDLE(RGNMAX) + JSR HidePen + MOVEM.L (SP)+,D3/A2-A4 ;RESTORE REGS + RTS ;AND RETURN + + + + .PROC CloseRgn,1 + .REF ShowPen,SortPoints,CullPoints,PackRgn +;--------------------------------------------------- +; +; PROCEDURE CloseRgn(* dstRgn: RgnHandle *); +; Sort array of inversion points and pack into region. +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 4 ;TOTAL BYTES OF PARAMETERS +DSTRGN .EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE +PTCOUNT .EQU -2 ;WORD +VARSIZE .EQU PTCOUNT ;SIZE OF LOCAL VARS + + + LINK A6,#VARSIZE + MOVEM.L D3/A2-A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A0 ;GET CURRENT GRAFPORT + TST.L RGNSAVE(A0) ;IS RGNSAVE TRUE ? + BEQ.S DONE ;NO, ABORT + CLR.L RGNSAVE(A0) ;YES, RGNSAVE := FALSE + JSR SHOWPEN ;UNDO THE HIDEPEN FROM OPENRGN + MOVE RGNINDEX(A4),D0 ;GET CURRENT RGNINDEX + LSR #2,D0 ;DIV BY 4 + MOVE D0,PTCOUNT(A6) ;FOR PTCOUNT + MOVE.L RGNBUF(A4),A3 ;GET RGNBUF HANDLE + MOVE.L (A3),-(SP) ;PUSH BUF POINTER + MOVE D0,-(SP) ;PUSH PTCOUNT + JSR SORTPOINTS ;QUICKSORT IN VH ORDER + MOVE.L (A3),-(SP) ;PUSH BUF POINTER + PEA PTCOUNT(A6) ;PUSH VAR PTCOUNT + JSR CULLPOINTS ;CANCEL DUPLICATE PAIRS + MOVE.L A3,-(SP) ;PUSH RGNBUF HANDLE + MOVE PTCOUNT(A6),-(SP) ;PUSH (UPDATED) PTCOUNT + MOVE.L DSTRGN(A6),-(SP) ;PUSH DSTRGN + JSR PACKRGN ;PACK POINTS INTO DSTRGN + MOVE.L A3,A0 ;GET RGNBUF HANDLE + _DisposHandle ;DISCARD IT +DONE MOVEM.L (SP)+,D3/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE, 'CLOSERGN' + + + + .PROC CopyRgn,1 + .REF SetSize +;--------------------------------------------------- +; +; PROCEDURE CopyRgn(* srcRgn,dstRgn: RgnHandle *); +; +PARAMSIZE .EQU 8 +SRCRGN .EQU PARAMSIZE+8-4 ;RGNHANDLE +DSTRGN .EQU SRCRGN-4 ;RGNHANDLE + + LINK A6,#0 ;ESTABLISH STACK FRAME + MOVE.L SRCRGN(A6),A0 ;GET SRCRGN HANDLE + MOVE.L DSTRGN(A6),A1 ;GET DSTRGN HANDLE + CMP.L A0,A1 ;ARE THEY THE SAME? + BEQ.S DONE ;YES, QUIT + + MOVE.L (A0),A0 ;DE-REFERENCE SRCRGN HANDLE + MOVE.L (A1),A1 ;DE-REFERENCE DSTRGN HANDLE + MOVE RGNSIZE(A0),D0 ;GET SRC SIZE + CMP RGNSIZE(A1),D0 ;IS DST SIZE SAME AS SRC ? + BEQ.S COPY ;YES, CONTINUE + + MOVEM.L D0/D3/A2,-(SP) ;SAVE REGS AND BYTECOUNT + MOVE.L DSTRGN(A6),-(SP) ;PUSH DSTRGN HANDLE + MOVE D0,-(SP) ;PUSH NEWSIZE=SRC SIZE + JSR SETSIZE ;CHANGE SIZE OF DST + MOVEM.L (SP)+,D0/D3/A2 ;RESTORE REGS AND BYTECOUNT + MOVE.L SRCRGN(A6),A0 ;GET SRCRGN HANDLE + MOVE.L DSTRGN(A6),A1 ;GET DSTRGN HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE SRCRGN HANDLE + MOVE.L (A1),A1 ;DE-REFERENCE DSTRGN HANDLE + +COPY LSR #2,D0 ;LONGCOUNT := BYTECOUNT DIV 4 + BCC.S EVEN ;WAS THERE AN ODD WORD ? + MOVE (A0)+,(A1)+ ;YES, DO IT TO MAKE EVEN + BRA.S EVEN ;AND CONTINUE +COPYLP MOVE.L (A0)+,(A1)+ ;COPY A LONG OF SRC TO DST +EVEN DBRA D0,COPYLP ;LOOP FOR ALL LONGS + +DONE UNLINK PARAMSIZE,'COPYRGN ' + + + + .PROC SetEmptyRgn,1 + .REF SetRectRgn +;--------------------------------------------------- +; +; PROCEDURE SetEmptyRgn(rgn: RgnHandle); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + CLR.L -(SP) ;PUSH LEFT, TOP + CLR.L -(SP) ;PUSH RIGHT,BOTTOM + MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + JMP SETRECTRGN ;DOUBLE UP ON CODE + + + + .PROC SetRectRgn,5 + .REF SetSize +;--------------------------------------------------- +; +; PROCEDURE SetRectRgn(rgn: RgnHandle; left,top,right,bottom: INTEGER); +; make a rectangular region from 4 integers. +; + LINK A6,#0 ;ESTABLISH STACK FRAME + MOVEM.L D3/A2,-(SP) ;SAVE REGS + MOVE.L 16(A6),A0 ;GET RGN HANDLE + MOVE.L (A0),A1 ;DE-REFERENCE HANDLE + MOVEQ #10,D0 + CMP RGNSIZE(A1),D0 ;IS RGNSIZE ALREADY 10 ? + BEQ.S SIZEOK ;YES, CONTINUE + MOVE.L A0,-(SP) ;PUSH RGNHANDLE + MOVE D0,-(SP) ;PUSH SIZE = 10 BYTES + JSR SETSIZE ;CHANGE SIZE OF REGION + MOVE.L 16(A6),A0 ;GET RGN HANDLE + MOVE.L (A0),A1 ;DE-REFERENCE HANDLE + MOVE #10,RGNSIZE(A1) ;INSTALL SIZE = 10 +SIZEOK MOVE.L 12(A6),RGNBBOX+TOPLEFT(A1) ;INSTALL RGNBBOX TOPLEFT + MOVE.L 8(A6),RGNBBOX+BOTRIGHT(A1) ;INSTALL RGNBBOX BOTRIGHT + MOVE RGNBBOX+LEFT(A1),D0 + CMP RGNBBOX+RIGHT(A1),D0 ;IS LEFT >= RIGHT ? + BGE.S EMPTY ;YES, SET TO EMPTY + + MOVE RGNBBOX+TOP(A1),D0 + CMP RGNBBOX+BOTTOM(A1),D0 ;IS TOP < BOTTOM ? + BLT.S DONE ;YES, CONTINUE + +EMPTY CLR.L RGNBBOX+TOPLEFT(A1) + CLR.L RGNBBOX+BOTRIGHT(A1) +DONE MOVEM.L (SP)+,D3/A2 ;RESTORE REGS + UNLINK 12,'SETRECTR' + + + + .PROC RectRgn,2 + .REF SetRectRgn +;--------------------------------------------------- +; +; PROCEDURE RectRgn(rgn: RgnHandle; r: Rect); +; make a rectangular region from a rectangle +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP ADDR OF RECT + MOVE.L (A1)+,-(SP) ;PUSH LEFT,TOP + MOVE.L (A1)+,-(SP) ;PUSH RIGHT,BOTTOM + MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + JMP SETRECTRGN ;DOUBLE UP ON CODE + + + + .PROC OffsetRgn,3 +;--------------------------------------------------------- +; +; PROCEDURE OffsetRgn(rgn: RgnHandle; dh,dv: INTEGER); +; + MOVE.L (SP)+,A1 ;POP RETURN ADDR + MOVE (SP)+,D1 ;POP DV + MOVE (SP)+,D0 ;POP DH + MOVE.L (SP)+,A0 ;POP RGN HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + ADD #2,A0 ;POINT TO RGNBBOX + +;------------------------------------------------------ +; +; OFFSET THE BOUNDING BOX +; + ADD D1,(A0)+ ;ADD DV TO TOP + ADD D0,(A0)+ ;ADD DH TO LEFT + ADD D1,(A0)+ ;ADD DV TO BOTTOM + ADD D0,(A0)+ ;ADD DH TO RIGHT + + +;--------------------------------------------------------------------- +; +; IF NON-RECTANGULAR REGION, OFFSET THE COORDINATES TOO. +; + CMP #10,-10(A0) ;IS REGION RECTANGULAR ? + BEQ.S DONE ;IF SO, WE'RE ALL DONE +NXTVERT ADD D1,(A0)+ ;OFFSET VERTICAL COORD DV +NXTHOR ADD D0,(A0)+ ;OFFSET LEFT COORD DH + ADD D0,(A0)+ ;OFFSET RIGHT COORD DH + CMP #32767,(A0) ;HORIZ TERMINATOR ? + BNE NXTHOR ;NO, LOOP + ADD #2,A0 ;YES, SKIP OVER TERMINATOR + CMP #32767,(A0) ;IS NEXT VERT = 32767 ? + BNE NXTVERT ;NO, LOOP FOR MORE +DONE JMP (A1) ;RETURN + + + + .PROC InsetRgn,3 + .REF InsetRect,SortPoints + .REF NewHandle,RgnOp,PackRgn +;--------------------------------------------------------- +; +; PROCEDURE InsetRgn(rgn: RgnHandle; dh,dv: INTEGER); +; +; Inset a region by (dh,dv). Outset if dh or dv neg +; +; A6 OFFSETS OF PARAMS AFTER LINK: +; +PARAMSIZE .EQU 8 +RGN .EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE +DH .EQU RGN-2 ;WORD +DV .EQU DH-2 ;WORD + + + LINK A6,#0 ;NO LOCAL VARS + MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGS + MOVE.L DV(A6),D6 ;GET DV AND DH BOTH + BEQ.S JGOHOME ;QUIT IF BOTH ARE ZERO + MOVE.L RGN(A6),A4 ;GET RGNHANDLE + MOVE.L (A4),A3 ;DE-REFERENCE IT + MOVE (A3)+,D7 ;GET RGNSIZE + + +;-------------------------------------------------------------- +; +; IF RECTANGULAR REGION, CALL INSETRECT AND CHECK FOR EMPTY. +; + CMP #10,D7 ;IS RGN RECTANGULAR ? + BNE.S NOTRECT ;NO, CONTINUE + MOVE.L A3,-(SP) ;PUSH ADDR OF RGNBBOX + MOVE.L D6,-(SP) ;PUSH DH AND DV + JSR INSETRECT ;InsetRect(rgn^^.rgnbbox,dh,dv); + MOVE LEFT(A3),D0 ;GET BBOX LEFT + CMP RIGHT(A3),D0 ;IS LEFT >= RIGHT ? + BGE.S EMPTY ;YES, RETURN EMPTY RGN + MOVE TOP(A3),D0 ;GET BBOX TOP + CMP BOTTOM(A3),D0 ;IS TOP >= BOTTOM ? + BLT.S JGOHOME ;NO, CONTINUE +EMPTY CLR.L (A3)+ ;SET RGNBBOX TO (0,0,0,0) TO + CLR.L (A3)+ ;RETURN EMPTY REGION +JGOHOME BRA.S GOHOME ;ALL DONE + + +;----------------------------------------------------- +; +; THE REGION IS NOT RECTANGULAR. ALLOCATE A POINT BUFFER IN THE HEAP. +; +NOTRECT ADD D7,D7 ;TRY BYTES NEEDED = RGNSIZE*2 + CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE D7,-(SP) ;PUSH BYTESNEEDED + JSR NEWHANDLE ;ALLOCATE PTBUF + MOVE.L (SP)+,A3 ;PUT PTBUF HANDLE IN A3 + BSR.S HINSET ;INSET HORIZ AND FLIP + SWAP D6 ;GET DV INSTEAD OF DH + BSR.S HINSET ;INSET VERTICAL AND FLIP BACK + BRA.S DONE ;ALL DONE + + +;-------------------------------------------------------------------------- +; +; LOCAL ROUTINE TO INSET HORIZONTALLY, SWAP H AND V COORDS, AND RE-SORT +; +; RgnOp(rgn,rgn,bufHandle,maxBytes,op,dh,TRUE); +; +HINSET CLR.W -(SP) ;ROOM FOR FCN RESULT + MOVE.L A4,-(SP) ;PUSH RGNA = USER RGN + MOVE.L A4,-(SP) ;PUSG RGNB = USER RGN ALSO + MOVE.L A3,-(SP) ;PUSH BUFHANDLE + MOVE D7,-(SP) ;PUSH MAXBYTES + MOVE #8,-(SP) ;PUSH OP = INSET + MOVE D6,-(SP) ;PUSH DH + ST -(SP) ;PUSH OKGROW = TRUE + JSR RGNOP + MOVE.W (SP)+,D5 ;GET PTCOUNT IN D5 +; +; SWAP VERT AND HORIZ COORDS OF ALL INVERSION POINTS +; + MOVE.L (A3),A0 ;DE-REFERENCE PTBUF HANDLE + MOVE D5,D1 ;COPY PTCOUNT + BRA.S SWAP2 ;GO TO LOOP START +SWAPLP MOVE.L (A0),D0 ;GET A POINT + SWAP D0 ;SWAP ITS COORDINATES + MOVE.L D0,(A0)+ ;PUT IT BACK INTO ARRAY +SWAP2 DBRA D1,SWAPLP ;LOOP FOR ALL POINTS +; +; RE-SORT THE POINTS IN V.H ORDER +; + MOVE.L (A3),-(SP) ;PUSH PTBUF PTR + MOVE D5,-(SP) ;PUSH PTCOUNT + JSR SORTPOINTS ;RE-SORT INTO VH ORDER +; +; PACK THE RESULTING POINTS +; + MOVE.L A3,-(SP) ;PUSH PTBUF HANDLE + MOVE D5,-(SP) ;PUSH PTCOUNT + MOVE.L A4,-(SP) ;PUSH RGN HANDLE + JSR PACKRGN ;PackRgn(ptBuf,ptCount,rgn); + RTS ;RETURN TO LOCAL CALLER + + +;---------------------------------------------- +; +; DISCARD POINT BUFFER AND QUIT. +; +DONE MOVE.L A3,A0 ;GET PTBUF HANDLE + _DisposHandle ;DISCARD IT + +GOHOME MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'INSETRGN' + + + + .FUNC EmptyRgn,1 + .REF EmptyRect +;--------------------------------------------------- +; +; FUNCTION EmptyRgn(rgn: RgnHandle): BOOLEAN; +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,A1 ;POP RGNHANDLE + MOVE.L (A1),A1 ;DE-REFERENCE HANDLE + PEA RGNBBOX(A1) ;PUSH RGNBBOX + MOVE.L A0,-(SP) ;PUSH RETURN ADDR + JMP EMPTYRECT ;USE EMPTYRECT CODE + + + + .FUNC EqualRgn,2 +;------------------------------------------------------- +; +; FUNCTION EqualRgn(rgnA,rgnB: RgnHandle): BOOLEAN; +; +; RETURNS TRUE IF RGNA AND RGNB DESCRIBE THE SAME AREA +; + MOVE.L 4(SP),A0 ;GET RGNA HANDLE + MOVE.L 8(SP),A1 ;GET RGNB HANDLE + CMP.L A0,A1 ;ARE THEY THE SAME ? + BEQ.S TRUE ;YES, THE REGIONS ARE THE SAME + MOVE.L (A0),A0 ;DE-REFERENCE RGN A + MOVE.L (A1),A1 ;DE-REFERENCE RGN B + MOVE (A0),D0 ;GET RGNSIZE A + MOVE D0,D1 ;MAKE AN EXTRA COPY + LSR #2,D1 ;DIV BY 4 FOR LONG COUNT + SUB #1,D1 ;INIT DBRA LOOP COUNT +LOOP CMPM.L (A0)+,(A1)+ ;COMPARE A LONG + DBNE D1,LOOP ;LOOK TILL DIFFERENT OR COUNT + BNE.S FALSE ;DIFFERENT --> FALSE + AND #3,D0 ;GET 0..3 FINISH UP BYTES + BEQ.S TRUE ;IF NO MORE, WE MADE IT +LOOP2 CMPM.B (A0)+,(A1)+ ;COMPARE A BYTE + BNE.S FALSE ;BR IF DIFFERENT + SUB #1,D0 + BNE.S LOOP2 ;LOOP LAST 1..3 BYTES +TRUE MOVE.L #1,D0 ;TRUE + BRA.S DONE +FALSE MOVE.L #0,D0 ;FALSE +DONE MOVE.B D0,12(SP) ;SET RESULT + MOVE.L (SP)+,A0 ;POP RETURN ADDR + ADD #8,SP ;STRIP PARAMETERS + JMP (A0) ;RETURN + + + + .PROC SectRgn,3 + .DEF DoRgnOp,UnionRgn,DiffRgn,XorRgn + .REF EqualRgn,CopyRgn,RSect,RectRgn,SetEmptyRgn + .REF NewHandle,RgnOp,PackRgn +;--------------------------------------------------------- +; +; PROCEDURE SectRgn(srcRgnA,srcRgnB,dstRgn: RgnHandle); +; calculate the intersection of two regions. +; + MOVEQ #0,D0 ;OP = SECT + BRA.S DoRgnOp ;SHARE COMMON CODE + + + +;--------------------------------------------------------- +; +; PROCEDURE UnionRgn(srcRgnA,srcRgnB,dstRgn: RgnHandle); +; calculate the union of two regions. +; +UnionRgn + MOVEQ #4,D0 ;OP = UNION + BRA.S DoRgnOp ;SHARE COMMON CODE + + + +;--------------------------------------------------------- +; +; PROCEDURE DiffRgn(srcRgnA,srcRgnB,dstRgn: RgnHandle); +; calculate the difference A-B of two regions +; +DiffRgn MOVEQ #2,D0 ;OP = DIFF + BRA.S DoRgnOp ;SHARE COMMON CODE + + + +;--------------------------------------------------------- +; +; PROCEDURE XorRgn(srcRgnA,srcRgnB,dstRgn: RgnHandle); +; calculate the exclusive or of two regions +; +XorRgn MOVEQ #6,D0 ;OP = DIFF + BRA.S DoRgnOp ;SHARE COMMON CODE + + + +;--------------------------------------------------------- +; +; PROCEDURE DoRgnOp(srcRgnA,srcRgnB,dstRgn: RgnHandle); +; +; Computes the Intersection, Difference, Union, or Xor of two regions. +; +; enter with op in D0. +; op = 0: SECT +; 2: DIFF A-B +; 4: UNION +; 6: XOR +; +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 12 +RGNA .EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE +RGNB .EQU RGNA-4 ;LONG, RGNHANDLE +DSTRGN .EQU RGNB-4 ;LONG, RGNHANDLE +; +TEMPRECT .EQU -8 ;RECT +VARSIZE .EQU TEMPRECT ;TOTAL LOCALS +; +DoRgnOp + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGS + MOVE D0,D5 ;COPY OP INTO D5 + MOVE.L RGNA(A6),A2 ;GET RGNA + MOVE.L RGNB(A6),A3 ;GET RGNB + MOVE.L DSTRGN(A6),A4 ;GET DSTRGN + MOVE.L #2,D7 +; +; ARE THE TWO INPUT REGIONS THE SAME ? +; + CLR.B -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE.L A2,-(SP) ;PUSH RGNA + MOVE.L A3,-(SP) ;PUSH RGNB + JSR EQUALRGN ;CALL EQUALRGN + TST.B (SP)+ ;ARE THEY THE SAME ? + BEQ.S NOTSAME ;NO, CONTINUE +; +; THE TWO REGIONS ARE THE SAME. IF SECT OR UNION +; THEN COPY RGNA INTO DSTRGN, ELSE ZERO OUT DSTRGN. +; + AND D7,D5 ;WAS OP SECT OR UNION ? + BNE.S ZERO ;NO, ZERO OUT DSTRGN +COPY MOVE.L A2,-(SP) ;PUSH RGNA + MOVE.L A4,-(SP) ;PUSH DSTRGN + JSR COPYRGN ;COPY RGNA INTO DSTRGN + BRA.S JDONE ;AND QUIT +ZERO MOVE.L A4,-(SP) ;PUSH DSTRGN + JSR SetEmptyRgn ;SET IT TO EMPTY + BRA.S JDONE ;AND QUIT + +; +; IF OP = DIFF AND RGNB = EMPTY, COPY RGNA INTO DST +; +NOTSAME MOVE.L (A2),A0 ;DE-REFERENCE RGNA + MOVE.L (A3),A1 ;DE-REFERENCE RGNB + CMP D7,D5 ;IS OP = DIFF ? + BGT.S UNIXOR ;NO, ITS UNION OR XOR + BLT.S BBOXES ;NO, IT'S SECT + MOVE RGNBBOX+LEFT(A1),D0 ;GET BBOX LEFT + CMP RGNBBOX+RIGHT(A1),D0 ;IS BBOX LEFT >= RIGHT ? + BGE COPY ;YES, COPY RGNA INTO DST + +; +; IF op = SECT OR DIFF, THEN INTERSECT THE BOUNDING BOXES. +; +BBOXES PEA RGNBBOX(A0) ;PUSH RGNA^^.RGNBBOX + PEA RGNBBOX(A1) ;PUSH RGNB^^.RGNBBOX + MOVE D7,-(SP) ;PUSH NRECTS = 2 + PEA TEMPRECT(A6) ;PUSH DST = TEMPRECT + JSR RSECT ;CALC INTERSECTION + BNE.S NOTEMPTY ;BR IF RESULT NOT EMPTY +; +; THE BOUNDING BOXES DON'T INTERSECT. +; IF OP = SECT, THEN RETURN EMPTY. +; IF OP = DIFF, THEN COPY RGNA INTO DSTRGN. +; + TST D5 ;IS OP = SECT ? + BEQ ZERO ;YES, RETURN EMPTY + BRA COPY ;NO, COPY SRCA INTO DSTRGN + +; +; IF OP = SECT, THEN CHECK FOR BOTH INPUTS RECTANGULAR +; +NOTEMPTY MOVE.L (A2),A0 ;DE-REFERENCE RGNA + MOVE.L (A3),A1 ;DE-REFERENCE RGNB + TST D5 ;IS OP = SECT ? + BNE.S NOTEASY ;NO, CONTINUE + MOVEQ #10,D0 + CMP RGNSIZE(A0),D0 ;IS RGNA RECTANGULAR ? + BNE.S NOTEASY ;NO, CONTINUE + CMP RGNSIZE(A1),D0 ;IS RGNB RECTANGULAR ? + BNE.S NOTEASY ;NO, CONTINUE + MOVE.L A4,-(SP) ;PUSH DSTRGN + PEA TEMPRECT(A6) ;PUSH TEMPRECT + JSR RECTRGN ;RectRgn(dstRgn,tempRect); +JDONE BRA.S DONE + +; +; OP = UNION OR XOR: IF EITHER REGION IS EMPTY, COPY THE OTHER. +; +UNIXOR MOVE RGNBBOX+LEFT(A1),D0 ;GET RGNB BBOX LEFT + CMP RGNBBOX+RIGHT(A1),D0 ;IS RGNB BBOX LEFT >= RIGHT ? + BGE COPY ;YES, COPY RGNA INTO DST + + MOVE RGNBBOX+LEFT(A0),D0 ;GET RGNA BBOX LEFT + CMP RGNBBOX+RIGHT(A0),D0 ;IS RGNA BBOX LEFT >= RIGHT ? + BLT.S NOTEASY ;NO, CONTINUE + MOVE.L A3,A2 ;YES, GET RGNB INSTEAD + BRA COPY ;COPY RGNB INTO DST + + +NOTEASY MOVE RGNSIZE(A0),D4 ;GET RGNA RGNSIZE + ADD RGNSIZE(A1),D4 ;ADD RGNB RGNSIZE + ADD D4,D4 ;TRY DOUBLE FOR BYTECOUNT + CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE D4,-(SP) ;PUSH BYTECOUNT + JSR NEWHANDLE ;ALLOCATE PTBUF + MOVE.L (SP)+,A3 ;GET PTBUF HANDLE IN A3 +; +; PtCount := RgnOp(srcA,srcB,bufHandle,maxBytes,op,0,TRUE); +; + CLR.W -(SP) ;MAKE ROOM FOR FCN RESULT + MOVE.L RGNA(A6),-(SP) ;PUSH RGNA + MOVE.L RGNB(A6),-(SP) ;PUSH RGNB + MOVE.L A3,-(SP) ;PUSH BUFHANDLE + MOVE D4,-(SP) ;PUSH MAXBYTES + MOVE D5,-(SP) ;PUSH OP + CLR.W -(SP) ;PUSH DH=0 + ST -(SP) ;PUSH OKGROW = TRUE + JSR RGNOP + MOVE (SP)+,D6 ;GET PTCOUNT + + MOVE.L A3,-(SP) ;PUSH PTBUF HANDLE + MOVE D6,-(SP) ;PUSH PTCOUNT + MOVE.L A4,-(SP) ;PUSH DSTRGN + JSR PACKRGN ;PackRgn(ptBuf,ptCount,dstRgn); + + MOVE.L A3,A0 ;GET PTBUF HANDLE + _DisposHandle ;DISCARD IT + +DONE MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'DORGNOP ' + + + + .FUNC PtInRgn,2 +;------------------------------------------------------------ +; +; FUNCTION PtInRgn(pt: Point; rgn: RgnHandle): BOOLEAN; +; +; TESTS IF A GIVEN POINT IS INSIDE A REGION. +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 8 ;SIZE OF PARAMETERS +RESULT .EQU PARAMSIZE+8 ;BOOLEAN +PT .EQU RESULT-4 ;POINT, VALUE +RGN .EQU PT-4 ;LONG, HANDLE + + +ENTRY LINK A6,#0 ;NO LOCAL VARS + MOVE.L D3,-(SP) ;SAVE REG + MOVE PT+H(A6),D1 ;GET TEST HORIZ + MOVE PT+V(A6),D2 ;GET TEST VERT + CLR D3 ;INIT INSIDE:=FALSE + + +;----------------------------------------------------------- +; +; FIRST CHECK BOUNDING BOX +; + MOVE.L RGN(A6),A0 ;GET RGN HANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + CMP RGNBBOX+LEFT(A0),D1 ;IS PT.H < BBOX LEFT ? + BLT.S DONE ;YES, RETURN FALSE + CMP RGNBBOX+RIGHT(A0),D1 ;IS PT.H >= BBOX RIGHT ? + BGE.S DONE ;YES, RETURN FALSE + CMP RGNBBOX+TOP(A0),D2 ;IS PT.V < BBOX TOP ? + BLT.S DONE ;YES, RETURN FALSE + CMP RGNBBOX+BOTTOM(A0),D2 ;IS PT.V >= BBOX BOT ? + BGE.S DONE ;YES, RETURN FALSE + CMP #10,RGNSIZE(A0) ;IS REGION RECTANGULAR ? + BNE.S NOTRECT ;NO, CONTINUE + NOT D3 ;YES, RETURN TRUE + BRA.S DONE + + +;------------------------------------------------------------------ +; +; PT IS INSIDE BOUNDING BOX AND REGION IS NOT RECTANGULAR. +; LOOK AT THE INVERSION POINTS TO DETERMINE IF PT IN REGION. +; +NOTRECT LEA RGNDATA(A0),A0 ;POINT TO FIRST VERT COORD +NXTVERT CMP (A0)+,D2 ;IS NEXT VERT > PT.V ? + BLT.S DONE ;YES, QUIT +NEXTHOR MOVE (A0)+,D0 ;GET HORIZ COORD + CMP #32767,D0 ;IS IT THE TERMINATOR ? + BEQ NXTVERT ;YES, GET NEXT VERT COORD + CMP D1,D0 ;IS HORIZ <= PT.H ? + BGT NEXTHOR ;NO, IGNORE THIS POINT + NOT D3 ;YES, TOGGLE INSIDE + BRA NEXTHOR ;AND GO FOR MORE POINTS +DONE NEG.B D3 ;BOOLEAN RESULT IS 0 OR 1 + MOVE.B D3,RESULT(A6) ;RETURN BOOLEAN FCN RESULT + MOVE.L (SP)+,D3 ;RESTORE REG + UNLINK PARAMSIZE,'PTINRGN ' + + + + + .FUNC RectInRgn,2 + .REF RSect,InitRgn,SeekRgn +;-------------------------------------------------- +; +; FUNCTION RectInRgn(r: Rect; rgn: RgnHandle): BOOLEAN; +; +; Returns TRUE if any part of the rectangle intersects the region. +; +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 8 ;TOTAL SIZE OF PARAMETERS +RESULT .EQU PARAMSIZE+8 ;BYTE, BOOLEAN +RECT .EQU RESULT-4 ;LONG, VAR ADDR +RGN .EQU RECT-4 ;LONG, RGNHANDLE + + +;------------------------------------------------------ +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +MINRECT .EQU -8 ;RECTANGLE +SAVESTACK .EQU MINRECT-4 ;LONG +STATE .EQU SAVESTACK-RGNREC ;REGION STATE RECORD +VARSIZE .EQU STATE ;TOTAL SIZE OF VARIABLES + + + LINK A6,#VARSIZE ;ALLOCATE LOCAL VARIABLES + MOVEM.L D0-D7/A1-A5,-(SP) ;SAVE REGISTERS + MOVE.L SP,SAVESTACK(A6) ;REMEMBER STACK START + CLR.B RESULT(A6) ;INIT BOOLEAN RESULT TO FALSE + MOVE.L RGN(A6),A1 ;GET REGION HANDLE + MOVE.L (A1),A1 ;DE-REFERENCE IT + + +;-------------------------------------------------------------- +; +; FIRST CHECK IF RECTANGLE INTERSECTS BOUNDING BOX OF REGION +; + MOVE.L RECT(A6),-(SP) ;PUSH POINTER TO RECT + PEA RGNBBOX(A1) ;PUSH POINTER TO RGN BBOX + MOVE #2,-(SP) ;PUSH NRECTS=2 + PEA MINRECT(A6) ;PUSH ADDR WHERE TO PUT RESULT + JSR RSECT ;CALC INTERSECTION + BEQ.S GOHOME ;QUIT IF NO INTERSECTION + CMP #10,RGNSIZE(A1) ;IS REGION RECTANGULAR ? + BEQ.S TRUE ;YES, RETURN TRUE + + +;------------------------------------------------------------ +; +; THE REGION IS NON-RECTANGULAR AND THE RECTANGLE INTERSECTS +; THE REGION'S BOUNDING BOX. WE WILL PLAY BACK THE PORTION OF +; THE REGION WITHIN MINRECT AND SEE IF ANY PART OF THE REGION +; IS ACTUALLY INSIDE THE RECTANGLE. +; + + +;------------------------------------------------- +; +; INITIALIZE RGN STATE RECORD AT TOP. +; + MOVE.L A1,A0 ;GET RGNPTR IN A0 + LEA STATE(A6),A1 ;GET STATE RECORD IN A1 + MOVE MINRECT+LEFT(A6),D0 ;MINH IN D0 + MOVE MINRECT+RIGHT(A6),D1 ;MAXH IN D1 + MOVE D0,D2 ;BUFLEFT:=MINH + JSR INITRGN ;INIT RECORD, ALLOCATE BUFFER + + +;------------------------------------------------------------ +; +; PLAY THE REGION BACK INTO SCAN BUFFER UNTIL IT GETS DOWN TO +; MINRECT, THEN CHECK EACH SCANLINE FOR NON-ZERO PLAYBACK. +; QUIT AND RETURN TRUE IF NON-ZERO FOUND BEFORE RGN GOES BEYOND MINRECT. +; + MOVE SCANSIZE(A1),D5 ;GET BUFSIZE= # LONGS -1 + MOVE MINRECT+TOP(A6),D0 + JSR SEEKRGN ;SEEK THE REGION TO MINRECT TOP + MOVE MINRECT+BOTTOM(A6),D6 +TESTBUF MOVE.L SCANBUF(A1),A0 ;POINT TO BUFFER START + MOVE D5,D0 ;INIT LOOP COUNT TO BUFSIZE +NXTLONG TST.L (A0)+ ;IS SCAN BUF NON-ZERO ? + DBNE D0,NXTLONG ;TEST LONGS TILL NON ZERO OR END + BNE.S TRUE ;WE FOUND A NON-ZERO, RETURN TRUE + MOVE NEXTV(A1),D0 ;GET NEXT VERTICAL IN RGN + CMP D0,D6 ;IS NEXT RGN VERT BEYOND BOTTOM ? + BLE.S GOHOME ;YES, RETURN FALSE + JSR SEEKRGN ;NO, SEEK TO NEXT VERT CHANGE + BRA.S TESTBUF ;AND SEE IF IT IS NON-ZERO + +TRUE ADDQ.B #1,RESULT(A6) ;SET BOOLEAN RESULT TO TRUE +GOHOME MOVE.L SAVESTACK(A6),SP ;STRIP SCAN BUFFER IF ANY + MOVEM.L (SP)+,D0-D7/A1-A5 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'RECTINRG' + + + + .FUNC TrimRect,2 + .REF RgnOp +;------------------------------------------------------ +; +; FUNCTION TrimRect(rgn: RgnHandle; VAR dstRect: Rect): CCR TRISTATE; +; +; RESULT IN CONDITION CODES: +; +; = RESULT RECTANGULAR, DSTRECT TRIMMED +; < RESULT EMPTY, DSTRECT NOT MODIFIED +; > RESULT NON-RECT, DSTRECT NOT MODIFIED +; +; If the intersection of rgn and dstRect is rectangular, +; then return EQUAL and put the intersection into dstRect. +; If the intersection is empty or not rectangular, then +; return FALSE and don't modify dstRect. +; +; Does not call the storage allocator. +; +; 1. Fake up a rect rgn on the stack from dstRect +; 2. Call RgnOp with max bytes = 24, OKGROW = FALSE +; 3a. If ptCount = 4 THEN result rect, return TRUE and update dstRect. +; 3b. If ptCount < 4 THEN result empty, return TRUE and clear dstRect. +; 3c. If ptCount > 4 THEN result not rect, return FALSE +; +PARAMSIZE .EQU 8 +RGN .EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE +DSTRECT .EQU RGN-4 ;LONG, ADDR OF DSTRECT + +PTDATA .EQU -24 ;ROOM FOR 6 POINTS +PTMASTER .EQU PTDATA-4 ;LONG, FAKE MASTER +REGION .EQU PTMASTER-10 ;ROOM FOR RECT RGN DATA +RGNMASTER .EQU REGION-4 ;LONG +VARSIZE .EQU RGNMASTER + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D0-D2/A1,-(SP) ;SAVE ALL REGS USED + LEA PTDATA(A6),A0 ;POINT TO BUFFER + MOVE.L A0,PTMASTER(A6) ;INSTALL INTO FAKE MASTER + LEA REGION(A6),A1 ;POINT TO REGION DATA + MOVE.L A1,RGNMASTER(A6) ;INSTALL INTO FAKE MASTER + MOVE #10,(A1)+ ;INSTALL RGNSIZE = 10 + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + MOVE.L (A0)+,(A1)+ ;COPY DSTRECT TOPLEFT + MOVE.L (A0)+,(A1)+ ;COPY DSTRECT BOTRIGHT +; +; RgnOp(rgn,rectRgn,BufHandle,24,sect,0,FALSE) +; + CLR.W -(SP) ;ROOM FOR FCN RESULT + MOVE.L RGN(A6),-(SP) ;PUSH RGN + PEA RGNMASTER(A6) ;PUSH FAKE RGNHANDLE + PEA PTMASTER(A6) ;PUSH BUFHANDLE + MOVE #24,-(SP) ;PUSH MAXBYTES = 24 + CLR.L -(SP) ;PUSH OP = SECT, DH = 0 + CLR.B -(SP) ;PUSH OKGROW = FALSE + JSR RGNOP ;RgnOp(rgn,rectRgn,buf,64,op,dh,FALSE); + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + CMP #4,(SP)+ ;IS PT COUNT = 4 ? + BNE.S DONE ;NO, RETURN < OR > IN CCR + MOVE.L PTDATA(A6),(A0)+ ;UPDATE DSTRECT.TOPLEFT + MOVE.L PTDATA+12(A6),(A0)+ ;UPDATE DSTRECT.BOTRIGHT + SUB D0,D0 ;SET EQUAL FLAG +DONE MOVEM.L (SP)+,D0-D2/A1 ;RESTORE ALL REGS + UNLK A6 ;RELEASE STACK FRAME + MOVE.L (SP)+,A0 ;POP RETURN ADDR INTO A0 + ADD #PARAMSIZE,SP ;STRIP PARAMETERS + JMP (A0) ;JUMP THRU A0 TO RETURN + + + + .PROC MapRgn,3 + .REF MapRect,NewHandle,PutRgn,MapPt + .REF SortPoints,CullPoints,PackRgn +;------------------------------------------------------------- +; +; PROCEDURE MapRgn(rgn: RgnHandle; fromRect,toRect: Rect); +; +; A6 OFFSETS OF PARAMETERS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 12 +RGN .EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE +FROMRECT .EQU RGN-4 ;LONG, ADDR OF RECT +TORECT .EQU FROMRECT-4 ;LONG, ADDR OF RECT + +INDEX .EQU -2 ;INTEGER +SIZE .EQU INDEX-2 ;WORD +PTCOUNT .EQU SIZE-2 ;WORD +VARSIZE .EQU PTCOUNT ;TOTAL BYTES + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D3/D6-D7/A2-A4,-(SP) ;SAVE REGS +; +; QUIT FAST IF FROMRECT = TORECT +; + MOVE.L FROMRECT(A6),A0 ;POINT TO FROMRECT + MOVE.L TORECT(A6),A1 ;POINT TO TORECT + CMPM.L (A0)+,(A1)+ ;IS TOPLEFT SAME ? + BNE.S NOTSAME ;NO, CONTINUE + CMPM.L (A0)+,(A1)+ ;YES, IS BOTRIGHT SAME TOO ? + BEQ.S JDONE ;IF SO, JUST QUIT +; +; SPECIAL CASE RECTANGULAR RGN +; +NOTSAME MOVE.L RGN(A6),A4 ;GET RGNHANDLE + MOVE.L (A4),A0 ;DE-REFERENCE RGN + CMP #10,RGNSIZE(A0) ;IS RGN RECTANGULAR ? + BNE.S NOTRECT ;NO, CONTINUE + PEA RGNBBOX(A0) ;YES, PUSH RGNBBOX + MOVE.L FROMRECT(A6),-(SP) ;PUSH FROMRECT + MOVE.L TORECT(A6),-(SP) ;PUSH TO RECT + JSR MAPRECT ;MapRect(rgn^^.rgnBBox,from,to); +JDONE BRA.S DONE + +NOTRECT CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE #256,-(SP) ;PUSH BYTECOUNT = 256 + MOVE (SP),SIZE(A6) ;SIZE := 256 BYTES + JSR NEWHANDLE ;ALLOCATE PTBUF + MOVE.L (SP)+,A3 ;GET PTBUF HANDLE IN A3 + + CLR INDEX(A6) ;INDEX := 0 + MOVE.L A4,-(SP) ;PUSH RGN + MOVE.L A3,-(SP) ;PUSH PTBUF HANDLE + PEA INDEX(A6) ;PUSH VAR INDEX + PEA SIZE(A6) ;PUSH VAR SIZE + JSR PUTRGN ;UNPACK RGN INTO INVERSION PTS + MOVE INDEX(A6),D7 ;GET INDEX + LSR #2,D7 ;PTCOUNT := INDEX DIV 4 +; +; MAP ALL INVERSION POINTS +; + MOVE D7,D6 ;COPY PTCOUNT FOR LOOP COUNT + MOVE.L (A3),A2 ;DE-REFERENCE PTBUF HANDLE + BRA.S MORE ;GO TO LOOP START +LOOP MOVE.L A2,-(SP) ;PUSH ADDR OF AN INV PT + MOVE.L FROMRECT(A6),-(SP) ;PUSH FROMRECT + MOVE.L TORECT(A6),-(SP) ;PUSH TORECT + JSR MAPPT ;MAP THIS POINT + ADD.L #4,A2 ;BUMP TO NEXT POINT +MORE DBRA D6,LOOP ;LOOP ALL INVERSION POINTS + + MOVE.L (A3),-(SP) ;PUSH PTBUF PTR + MOVE D7,-(SP) ;PUSH PTCOUNT + JSR SORTPOINTS ;SortPoints(ptBuf^,ptCount) + + MOVE.L (A3),-(SP) ;PUSH PTBUF PTR + MOVE D7,PTCOUNT(A6) ;PUT PTCOUNT IN MEMORY + PEA PTCOUNT(A6) ;PUSH VAR PTCOUNT + JSR CULLPOINTS ;CullPoints(ptBuf^,ptCount) + + MOVE.L A3,-(SP) ;PUSH PTBUF HANDLE + MOVE PTCOUNT(A6),-(SP) ;PUSH PTCOUNT + MOVE.L A4,-(SP) ;PUSH RGN + JSR PACKRGN ;PackRgn(ptBuf,ptCount,rgn); + + MOVE.L A3,A0 ;PUSH PTBUF HANDLE + _DisposHandle ;DISCARD IT + +DONE MOVEM.L (SP)+,D3/D6-D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'MAPRGN ' + + + + + .END diff --git a/RgnBlt.a b/RgnBlt.a new file mode 100755 index 0000000..4b236f2 --- /dev/null +++ b/RgnBlt.a @@ -0,0 +1,825 @@ + .INCLUDE GRAFTYPES.TEXT +;------------------------------------------------------------------ +; +; --> RGNBLT.TEXT +; +; Low level block transfer clipped to an arbitrary region. +; + + + .PROC RgnBlt,9 + .REF BitBlt,RSect,ShieldCursor,ShowCursor + .REF SeekRgn,PatExpand,ColorMap,InitRgn,TrimRect +;-------------------------------------------------------------- +; +; PROCEDURE RgnBlt(srcBits,dstBits: BitMap; +; srcRect,dstRect: Rect; +; mode: INTEGER; pat: Pattern; +; rgnA,rgnB,rgnC: RgnHandle); +; +; TRANSFERS A RECTANGULAR BLOCK OF BITS CLIPPED TO THE DESTINATION +; BITMAP'S BOUNDS AND TO THE INTERSECTION OF THREE REGIONS. +; MODE SPECIFIES THE TRANSFER MODE AND WHETHER THE SOURCE SHOULD COME +; FROM THE SOURCE BITMAP OR FROM A REPEATING PATTERN. +; +; COPYRIGHT APPLE COMPUTER INC. +; DESIGNED AND WRITTEN BY BILL ATKINSON +; +; THIS CODE IS POSITION INDEPENDENT, RE-ENTRANT, AND READ-ONLY. +; CLOBBERS ONLY A0. +; +; MODES: 0 SRC --> DST +; 1 SRC OR DST --> DST +; 2 SRC XOR DST --> DST +; 3 SRC BIC DST --> DST +; +; 4 (NOT SRC) --> DST +; 5 (NOT SRC) OR DST --> DST +; 6 (NOT SRC) XOR DST --> DST +; 7 (NOT SRC) BIC DST --> DST +; +; 8 PATTERN --> DST +; 9 PATTERN OR DST --> DST +; 10 PATTERN XOR DST --> DST +; 11 PATTERN BIC DST --> DST +; +; 12 (NOT PATTERN) --> DST +; 13 (NOT PATTERN) OR DST --> DST +; 14 (NOT PATTERN) XOR DST --> DST +; 15 (NOT PATTERN) BIC DST --> DST +; +; + + +;---------------------------------------------------- +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 34 ;SIZE OF PARAMETERS +SRCBITS .EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP +DSTBITS .EQU SRCBITS-4 ;LONG, ADDR OF BITMAP +SRCRECT .EQU DSTBITS-4 ;LONG, ADDR OF RECT +DSTRECT .EQU SRCRECT-4 ;LONG, ADDR OF RECT +MODE .EQU DSTRECT-2 ;WORD +PAT .EQU MODE-4 ;LONG, ADDR OF PATTERN +RGNA .EQU PAT-4 ;LONG, RGNHANDLE +RGNB .EQU RGNA-4 ;LONG, RGNHANDLE +RGNC .EQU RGNB-4 ;LONG, RGNHANDLE + + +;------------------------------------------------- +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +EXPAT .EQU -64 ;16 LONGS +MINRECT .EQU EXPAT-8 ;RECT +STATEA .EQU MINRECT-RGNREC ;RGN STATE RECORD +STATEB .EQU STATEA-RGNREC ;RGN STATE RECORD +STATEC .EQU STATEB-RGNREC ;RGN STATE RECORD +SAVESTK .EQU STATEC-4 ;LONG +RECTFLAG .EQU SAVESTK-2 ;WORD +MASKBUF .EQU RECTFLAG-4 ;LONG +BUFLEFT .EQU MASKBUF-2 ;WORD +BUFSIZE .EQU BUFLEFT-2 ;WORD +SRCADDR .EQU BUFSIZE-4 ;LONG +DSTADDR .EQU SRCADDR-4 ;LONG +SRCROW .EQU DSTADDR-4 ;LONG +DSTROW .EQU SRCROW-4 ;LONG +VERT .EQU DSTROW-2 ;WORD +MODECASE .EQU VERT-4 ;LONG +SAVEA5 .EQU MODECASE-4 ;LONG +FIRSTV .EQU SAVEA5-2 ;WORD +LASTV .EQU FIRSTV-2 ;WORD +VBUMP .EQU LASTV-2 ;WORD, MUST BE ABOVE HBUMP +HBUMP .EQU VBUMP-2 ;WORD +SRCRECT2 .EQU HBUMP-8 ;RECT +MASKADDR .EQU SRCRECT2-4 ;LONG +VARSIZE .EQU MASKADDR ;SIZE OF LOCAL VARIABLES + + + + LINK A6,#VARSIZE ;ALLOCATE LOCAL VARIABLES + MOVEM.L D3-D7/A2-A5,-(SP) ;SAVE REGS + MOVE.L SP,SAVESTK(A6) ;REMEMBER STACK FOR LATER + MOVE.L A5,SAVEA5(A6) ;REMEMBER GLOBAL PTR + + +;---------------------------------------------------------------- +; +; ADJUST MODE AND PATTERN IF COLOR FILTERING. +; + MOVE MODE(A6),-(SP) ;YES, PUSH INPUT MODE + MOVE.L PAT(A6),-(SP) ;PUSH ADDR OF INPUT PATTERN + JSR COLORMAP ;ALTER BY THECOLOR, THEFILTER + MOVE.L (SP)+,PAT(A6) ;GET (ALTERED) PATTERN + MOVE (SP)+,MODE(A6) ;GET (ALTERED) MODE + + +;------------------------------------------------------ +; +; GET THREE REGION HANDLES AND DE-REFERENCE THEM. +; + MOVE.L RGNA(A6),A1 ;GET RGNHANDLE + MOVE.L (A1),A1 ;DE-REFERENCE IT + MOVE.L RGNB(A6),A2 ;GET RGNHANDLE + MOVE.L (A2),A2 ;DE-REFERENCE IT + MOVE.L RGNC(A6),A3 ;GET RGNHANDLE + MOVE.L (A3),A3 ;DE-REFERENCE IT + + +;------------------------------------------------------------------- +; +; CALC MINRECT, THE INTERSECTION OF DSTRECT, DSTBITS.BOUNDS, +; AND 3 REGION BOUNDING BOXES. QUIT IF THE INTERSECTION IS EMPTY. +; + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + MOVE.L DSTBITS(A6),A4 ;A4 POINTS TO DSTBITS + PEA BOUNDS(A4) ;PUSH DSTBITS.BOUNDS + PEA RGNBBOX(A1) ;PUSH RGNA BBOX + PEA RGNBBOX(A2) ;PUSH RGNB BBOX + PEA RGNBBOX(A3) ;PUSH RGNC BBOX + MOVE #5,-(SP) ;PUSH NRECTS=5 + PEA MINRECT(A6) ;PUSH WHERE TO PUT RESULT + JSR RSECT ;CALC INTERSECTION + BEQ GOHOME ;QUIT IF EMPTY + + +;---------------------------------------------------- +; +; HIDE THE CURSOR IF IT INTERSECTS MINRECT +; + PEA MINRECT(A6) ;PUSH SHIELD RECT + MOVE.L BOUNDS+TOPLEFT(A4),-(SP) ;PUSH DELTA TO CONVERT TO GLOBAL + JSR SHIELDCURSOR ;REMOVE CURSOR IF INTERSECT + + +;---------------------------------------------------- +; +; ARE ALL THREE REGIONS RECTANGULAR ? +; + CMP #10,RGNSIZE(A1) ;IS RGNA RECTANGULAR ? + BNE.S NOTRECT ;NO, CONTINUE + CMP #10,RGNSIZE(A3) ;IS RGN3 RECTANGULAR ? + BNE.S NOTRECT ;NO, CONTINUE + CMP #10,RGNSIZE(A2) ;IS RGN2 RECTANGULAR ? + BEQ.S OKRECT ;NO, CONTINUE +; +; If only rgnB (visRgn) is non-rectangular, then check if +; its intersection with minrect would be rectangular. +; IF TrimRect(rgnB,minRect) then take the fast way. +; + MOVE.L RGNB(A6),-(SP) ;push rgnHandle + PEA minRect(A6) ;push addr of minRect + JSR TrimRect ;call trimRect + BLT DONE ;quit if intersection empty + BGT.S NOTRECT ;continue if non-rectangular + +;-------------------------------------------------------------- +; +; SINCE ALL THREE REGIONS ARE RECTANGULAR, WE WILL USE BITBLT. +; FIRST CLIP SRCRECT TO MATCH MINRECT. (COPY SRCRECT SINCE IT'S NOT VAR) +; +OKRECT MOVE.L SRCRECT(A6),A2 ;POINT TO SRC RECT + LEA SRCRECT2(A6),A0 ;POINT TO LOCAL COPY OF SRCRECT + MOVE.L DSTRECT(A6),A3 ;POINT TO DSTRECT + + MOVE MINRECT+TOP(A6),D0 ;GET MINRECT TOP + SUB TOP(A3),D0 ;CONVERT FROM DST COORDS + ADD TOP(A2),D0 ;TO SRC COORDS + MOVE D0,TOP(A0) ;PUT CLIPPED SRC TOP INTO COPY + + MOVE MINRECT+LEFT(A6),D0 ;GET MINRECT LEFT + SUB LEFT(A3),D0 ;CONVERT FROM DST COORDS + ADD LEFT(A2),D0 ;TO SRC COORDS + MOVE D0,LEFT(A0) ;PUT CLIPPED SRC LEFT INTO COPY + + +;---------------------------------------------------- +; +; PUSH PARAMETERS AND CALL BITBLT +; + MOVE.L SRCBITS(A6),-(SP) ;PUSH SRCBITS + MOVE.L A4,-(SP) ;PUSH DSTBITS + MOVE.L A0,-(SP) ;PUSH SRCRECT COPY + PEA MINRECT(A6) ;PUSH DST = MINRECT + MOVE MODE(A6),-(SP) ;PUSH MODE + MOVE.L PAT(A6),-(SP) ;PUSH PATTERN + JSR BITBLT ;CALL BITBLT + BRA DONE ;RESTORE CURSOR AND QUIT + + +;----------------------------------- +; +; CALC BUFLEFT AND BUFSIZE +; +NOTRECT MOVE MINRECT+LEFT(A6),D1 ;GET MINRECT LEFT + SUB BOUNDS+LEFT(A4),D1 ;CONVERT TO GLOBAL COORDS + AND #$FFF0,D1 ;TRUNC TO MULT OF 16 + ADD BOUNDS+LEFT(A4),D1 ;CONVERT BACK TO LOCAL + MOVE D1,BUFLEFT(A6) ;SAVE AS BUFLEFT + MOVE MINRECT+RIGHT(A6),D0 ;GET MINRECT RIGHT + SUB D1,D0 ;CALC WIDTH IN DOTS + LSR #5,D0 ;DIV BY 32 FOR LONGS + MOVE D0,BUFSIZE(A6) ;BUFSIZE = # LONGS -1 + + +;----------------------------------------------------------------------- +; +; ALLOCATE AND CLEAR A SCANLINE BUFFER FOR THE COMPOSITE MASK. +; +CLRMASK CLR.L -(SP) ;ALLOCATE AND CLEAR + DBRA D0,CLRMASK ;LOOP TILL DONE + MOVE.L SP,MASKBUF(A6); ;REMEMBER WHERE MASKBUF IS + + +;------------------------------------------------------------------- +; +; INIT STATE RECORDS VERT0 AND VERT1 IN CASE RECTANGULAR +; + MOVE #32767,D0 + MOVE D0,STATEA+NEXTV(A6) + MOVE D0,STATEB+NEXTV(A6) + MOVE D0,STATEC+NEXTV(A6) + NEG D0 + MOVE D0,STATEA+THISV(A6) + MOVE D0,STATEB+THISV(A6) + MOVE D0,STATEC+THISV(A6) + + +;---------------------------------------------------------------------- +; +; ALLOCATE BUFFERS AND INIT STATE RECORDS FOR EACH NON-RECT REGION +; + CLR D5 ;INIT ALL RGNS RECT + MOVE.L RGNA(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + CMP #10,RGNSIZE(A0) ;IS RGNA RECTANGULAR ? + BEQ.S ARECT ;YES, SKIP IT + ADD #2,D5 ;NO, SET UP FLAG + LEA STATEA(A6),A1 ;POINT TO STATE RECORD A + BSR.S INITONE ;INIT STATE, ALLOC BUFFER +ARECT + MOVE.L RGNB(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + CMP #10,RGNSIZE(A0) ;IS RGNB RECTANGULAR ? + BEQ.S BRECT ;YES, SKIP IT + ADD #4,D5 ;NO, BUMP FLAG + LEA STATEB(A6),A1 ;POINT TO STATE RECORD B + BSR.S INITONE ;INIT STATE, ALLOC BUFFER +BRECT + MOVE.L RGNC(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + CMP #10,RGNSIZE(A0) ;IS RGNC RECTANGULAR ? + BEQ.S CRECT ;YES, SKIP IT + ADD #8,D5 ;NO, BUMP FLAG + LEA STATEC(A6),A1 ;POINT TO STATE RECORD C + PEA CRECT ;PUSH FAKE RETURN ADDR +INITONE MOVE MINRECT+LEFT(A6),D0 ;GET MINH + MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH + MOVE BUFLEFT(A6),D2 ;GET BUFLEFT + JMP INITRGN ;INIT STATE, ALLOC BUFFER +CRECT + + +;--------------------------------------------------------------------- +; +; IF ONLY ONE REGION IS NON-RECTANGULAR, PLAY IT BACK DIRECTLY +; INTO THE MASK BUFFER. +; + MOVE.L MASKBUF(A6),D7 + MOVE D5,RECTFLAG(A6) + CMP #2,D5 ;IS RGNA THE ONLY NON-RECT ? + BNE.S AOK ;NO, CONTINUE + MOVE.L D7,STATEA+SCANBUF(A6) ;YES, PLAY DIRECTLY INTO MASK + BRA.S COK +AOK CMP #4,D5 ;IS RGNB THE ONLY NON-RECT ? + BNE.S BOK + MOVE.L D7,STATEB+SCANBUF(A6) + BRA.S COK +BOK CMP #8,D5 ;IS RGNC THE ONLY NON-RECT ? + BNE.S COK + MOVE.L D7,STATEC+SCANBUF(A6) +COK + + +;---------------------------------------------------------- +; +; ASSUME WE WILL BE DRAWING DOWNWARD AND TO RIGHT. +; + MOVE MINRECT+TOP(A6),FIRSTV(A6) ;FIRSTV:=MINRECT TOP + MOVE MINRECT+BOTTOM(A6),LASTV(A6) ;LASTV:=MINRECT BOTTOM + MOVE.L #$00040001,HBUMP(A6) ;HBUMP:=4 BYTES, VBUMP:=1 SCAN + MOVE ROWBYTES(A4),D0 + EXT.L D0 + MOVE.L D0,DSTROW(A6) ;DSTROW:=+ROWBYTES + MOVE.L D7,MASKADDR(A6) ;MASKADDR:=MASKBUF + + +;--------------------------------------- +; +; SET UP INVERT FLAG IN D7 TO REFLECT MODE BIT 2 +; + CLR.L D7 ;SAY NOT INVERTED + MOVE MODE(A6),D2 ;GET TRANSFER MODE + BMI DONE ;QUIT IF MODE NEGATIVE + BCLR #2,D2 ;TEST AND CLR INVERT BIT + BEQ.S SETMODE ;SKIP IF NOT INVERTED + NOT.L D7 ;INVERTED; D7 GETS ALL 1'S + + +;-------------------------------------------------- +; +; CALCULATE CASE JUMP FOR DIFFERENT TRANSFER MODES +; +SETMODE AND #$F,D2 ;TREAT MODE MOD 16 + MOVEQ #3,D0 + AND D2,D0 ;GET BOTTOM 2 BITS OF MODE + ADD D0,D2 ;MODIFY MODE FOR INDEX + LEA MODETAB,A0 ;POINT TO MODE TABLE + ADD 0(A0,D2),A0 ;GET CASE JUMP ADDRESS + MOVE.L A0,MODECASE(A6) ;SAVE FOR LATER + + BTST #3,D2 ;WILL PATTERN BE USED ? + BEQ.S USESRC ;NO, USE SOURCE INSTEAD + + +;------------------------------------------------------------------ +; +; PATTERN WILL BE USED. EXPAND 8 BYTE PATTERN TO 16 LONGS +; + MOVE BOUNDS+LEFT(A4),D2 ;GET GLOBAL-LOCAL OFFSET + MOVE.L PAT(A6),A0 ;POINT TO BYTE WIDE PATTERN + LEA EXPAT(A6),A1 ;POINT TO EXPANDED PATTERN + JSR PATEXPAND ;EXPAND 8 BYTES TO 16 LONGS + + +;------------------------------------------------- +; +; SET UP (VERT * 4) MOD 64 AS PATTERN SELECTOR +; + MOVEQ #$F,D7 ;TREAT COORD MOD 16 + AND MINRECT+TOP(A6),D7 ;GET TOP VERT COORD + LSL #2,D7 ;QUAD FOR 4 BYTE PATTERNS + MOVE.L EXPAT(A6,D7),D6 ;GET FIRST PATTERN DATA + BRA GETDST ;SKIP OVER SRC STUFF + + +;-------------------------------------------------------------- +; +; SRC WILL BE USED. CHECK FOR OVERLAP AND CHOOSE DIRECTION SO +; THAT SRC WONT GET CLOBBERED BEFORE IT IS USED. +; +USESRC MOVE.L DSTRECT(A6),A1 ;POINT TO DSTRECT + MOVE.L SRCRECT(A6),A2 ;POINT TO SRCRECT + MOVE.L SRCBITS(A6),A3 ;POINT TO SRCBITS + MOVE ROWBYTES(A3),D0 + EXT.L D0 + MOVE.L D0,SRCROW(A6) ;SRCROW:=+ROWBYTES + MOVE.L BASEADDR(A3),D0 ;GET SRC BASEADDR + CMP.L BASEADDR(A4),D0 ;ARE SRC AND DST SAME BITMAP ? + BNE.S SRCOK ;NO, DON'T WORRY ABOUT OVERLAP + + MOVE TOP(A1),D0 ;GET DST TOP + SUB BOUNDS+TOP(A4),D0 ;CONVERT TO GLOBAL + MOVE TOP(A2),D1 ;GET SRC TOP + SUB BOUNDS+TOP(A3),D1 ;CONVERT TO GLOBAL + SUB D1,D0 ;CALC DV:=DSTTOP-SRCTOP + BLT.S SRCOK ;EVERYTHING FINE IF SCROLLING UP + BGT.S UPSIDE ;UPSIDE DOWN IF SCROLLING DOWN + + +;------------------------------------------------------------ +; +; DV=0. IF DH > 0 THEN WE MUST TRANSFER BACKWARDS FROM RIGHT. +; + MOVE LEFT(A1),D0 ;GET DST LEFT + SUB BOUNDS+LEFT(A4),D0 ;CONVERT TO GLOBAL + MOVE LEFT(A2),D1 ;GET SRC LEFT + SUB BOUNDS+LEFT(A3),D1 ;CONVERT TO GLOBAL + SUB D1,D0 ;DH := DSTLEFT-SRCLEFT + BLE.S SRCOK ;IF DH <= 0, WE'RE FINE + NEG HBUMP(A6) ;ELSE BUMP TOWARD LEFT + BRA.S SRCOK ;CONTINUE + + +;------------------------------------------------------------ +; +; DV IS POSITIVE, WE MUST TRANSFER UPSIDE-DOWN FROM BOTTOM. +; +UPSIDE NEG VBUMP(A6) ;VBUMP:=-1, BUMP UPWARD + NEG.L SRCROW(A6) ;SRCROW:=-SRC ROWBYTES + NEG.L DSTROW(A6) ;DSTROW:=-DST ROWBYTES + MOVE MINRECT+BOTTOM(A6),FIRSTV(A6) + SUB #1,FIRSTV(A6) ;FIRSTV:=BOTTOM-1 + MOVE MINRECT+TOP(A6),LASTV(A6) + SUB #1,LASTV(A6) ;LASTV:=TOP-1 + + +;---------------------------------------------- +; +; CALC SHIFTCNT +; +SRCOK MOVE LEFT(A1),D6 ;GET DST LEFT LOCAL COORDS + SUB BOUNDS+LEFT(A4),D6 ;CONVERT TO GLOBAL + MOVE LEFT(A2),D1 ;GET SRC LEFT LOCAL COORDS + SUB BOUNDS+LEFT(A3),D1 ;CONVERT TO GLOBAL + SUB D1,D6 ;CALC DELTA HORIZ GLOBAL + AND #$F,D6 ;MOD 16 FOR SHIFTCNT + + +;------------------------------------ +; +; CALC STARTING SRCADDR +; + MOVE FIRSTV(A6),D0 ;GET FIRST DST VERTICAL + SUB TOP(A1),D0 ;SUBTRACT DSTRECT TOP + ADD TOP(A2),D0 ;ADD SRCRECT TOP + SUB BOUNDS+TOP(A3),D0 ;CONVERT SRCV TO GLOBAL + MULU ROWBYTES(A3),D0 ;MULT BY SRC ROWBYTES + MOVE.L BASEADDR(A3),A0 ;GET START OF BITMAP + ADD.L D0,A0 ;ADD OFFSET TO BASEADDR + + MOVE MINRECT+LEFT(A6),D0 ;GET DST LEFT + SUB LEFT(A1),D0 ;CONVERT FROM DST COORDS + ADD LEFT(A2),D0 ;TO SRC COORDS + SUB BOUNDS+LEFT(A3),D0 ;CONVERT TO GLOBAL SRC + ADD D6,D0 ;ADD SHIFTCNT + LSR #4,D0 ;CONVERT DOTS TO WORDS + ADD D0,D0 ;DOUBLE FOR BYTES + ADD D0,A0 ;ADD HORIZ OFFSET + MOVE.L A0,SRCADDR(A6) ;SAVE AS SRCADDR + + +;------------------------------------ +; +; CALC STARTING DSTADDR +; +GETDST MOVE FIRSTV(A6),D0 ;GET FIRST DST VERT + SUB BOUNDS+TOP(A4),D0 ;CONVERT TO GLOBAL + MULU ROWBYTES(A4),D0 ;MULT BY ROWBYTES + MOVE.L BASEADDR(A4),A0 ;GET START OF BITMAP + ADD.L D0,A0 ;ADD VERTICAL OFFSET + + MOVE MINRECT+LEFT(A6),D0 ;GET DST LEFT + SUB BOUNDS+LEFT(A4),D0 ;CONVERT TO GLOBAL + LSR #4,D0 ;CONVERT DOTS TO WORDS + ADD D0,D0 ;DOUBLE FOR BYTES + ADD D0,A0 ;ADD HORIZ OFFSET + MOVE.L A0,DSTADDR(A6) ;SAVE AS DSTADDR + + + +;------------------------------------------------------------------------ +; +; ADJUST SRCADDR,DSTADDR,MASKADDR IF WE ARE BUMPING BACKWARDS FROM RIGHT +; + TST HBUMP(A6) ;BUMPING BACKWARD ? + BPL.S HBUMPOK ;NO, CONTINUE + MOVE BUFSIZE(A6),D0 ;GET BUFFER SIZE + ASL #2,D0 ;QUAD FOR # BYTES + EXT.L D0 ;CLEAR HI WORD + ADD.L D0,DSTADDR(A6) ;ADJUST DSTADDR + ADD.L D0,SRCADDR(A6) ;ADJUST SRCADDR + ADD.L D0,MASKADDR(A6) ;ADJUST MASKADDR +HBUMPOK + + + MOVE FIRSTV(A6),VERT(A6) ;INIT CURRENT VERTICAL +;------------------------------------------------------- +; +; MAKE MASK BUFFER CURRENT FOR THIS VERTICAL. +; THEN SET UP AND DRAW CURRENT SCANLINE. +; +NXTMASK JSR SEEKMASK ;MAKE MASK BUFFER CURRENT + MOVE.L SRCADDR(A6),A3 ;INIT SRCPTR + MOVE.L DSTADDR(A6),A5 ;INIT DSTPTR FOR ROW + MOVE.L MASKADDR(A6),A4 ;INIT MASKPTR FOR ROW + MOVE BUFSIZE(A6),D2 ;INIT COUNT OF LONGS + MOVE.L MODECASE(A6),A2 ;GET MODE CASE JUMP + JMP (A2) ;TAKE MODE JUMP + +NEXTSRC MOVE.L SRCROW(A6),D0 ;GET SRC ROWBYTES + ADD.L D0,SRCADDR(A6) ;BUMP SRC TO NEXT ROW + BRA.S BUMPV ;CONTINUE WITH NEXT ROW + +NEXTPAT ADD #4,D7 ;BUMP PATTERN SELECTOR + AND #$3F,D7 ;MOD 64 FOR 16 LONG REPEAT + MOVE.L EXPAT(A6,D7),D6 ;GET PATTERN FOR NEXT ROW + + +;----------------------------------------------------- +; +; BUMP DESTINATION VERTICALLY AND LOOP FOR ALL ROWS +; +BUMPV MOVE.L DSTROW(A6),D0 ;GET DST ROWBYTES + ADD.L D0,DSTADDR(A6) ;BUMP DST TO NEXT ROW +NODRAW MOVE VERT(A6),D0 ;GET CURRENT VERT + ADD VBUMP(A6),D0 ;BUMP UP OR DOWN A SCAN LINE + MOVE D0,VERT(A6) ;UPDATE CURRENT VERT + CMP LASTV(A6),D0 ;ARE WE AT THE LAST SCAN LINE ? + BNE NXTMASK ;NO, LOOP FOR ALL SCAN LINES + + +;----------------------------------------------------------------- +; +; ENTIRE RGNBLT COMPLETE. RESTORE REGS AND STACK AND GO HOME. +; +DONE MOVE.L SAVEA5(A6),A5 ;GET GLOBAL POINTER + JSR SHOWCURSOR ;RESTORE CURSOR +GOHOME MOVE.L SAVESTK(A6),SP ;STRIP VARIABLE SIZED BUFFER + MOVEM.L (SP)+,D3-D7/A2-A5 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'RGNBLT ' + + + +;----------------------------------------------------------------- +; +; LOCAL ROUTINE TO UPDATE MASK BUFFER TO CURRENT VERTICAL COORD. +; +SEEKMASK MOVE VERT(A6),D0 ;GET CURRENT VERT COORD + MOVE RECTFLAG(A6),D1 ;GET RECTFLAG = 0,2,4 + MOVE RECTJMP(D1),D1 ;GET OFFSET FROM TABLE + JMP RECTJMP(D1) ;TAKE CASE JUMP + +RECTJMP .WORD SEEKOK-RECTJMP + .WORD A-RECTJMP + .WORD B-RECTJMP + .WORD AB-RECTJMP + .WORD C-RECTJMP + .WORD AC-RECTJMP + .WORD BC-RECTJMP + .WORD ABC-RECTJMP + + +;-------------------------------------------------------------------- +; +; ONLY REGION A IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +A LEA STATEA(A6),A1 + BRA.S JMPSEEK + + +;-------------------------------------------------------------------- +; +; ONLY REGION B IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +B LEA STATEB(A6),A1 + BRA.S JMPSEEK + + +;-------------------------------------------------------------------- +; +; ONLY REGION C IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +C LEA STATEC(A6),A1 +JMPSEEK MOVE.L MASKBUF(A6),SCANBUF(A1) ;PLAY DIRECTLY INTO MASKBUF + JMP SEEKRGN + + +;------------------------------------------------------------------- +; +; REGIONS A AND B ARE NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +AB LEA STATEA(A6),A1 + JSR SEEKRGN + MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED + LEA STATEB(A6),A1 + JSR SEEKRGN + OR (SP)+,D1 ;HAS EITHER RGN CHANGED ? + BEQ.S SEEKOK ;NO, WE'RE DONE + MOVE.L STATEA+SCANBUF(A6),A0 + MOVE.L STATEB+SCANBUF(A6),A1 + BRA.S CPY2BUF + + +;------------------------------------------------------------------- +; +; REGIONS A AND C ARE NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +AC LEA STATEA(A6),A1 + JSR SEEKRGN + MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED + LEA STATEC(A6),A1 + JSR SEEKRGN + OR (SP)+,D1 ;HAS EITHER RGN CHANGED ? + BEQ.S SEEKOK ;NO, WE'RE DONE + MOVE.L STATEA+SCANBUF(A6),A0 + MOVE.L STATEC+SCANBUF(A6),A1 + BRA.S CPY2BUF + + +;------------------------------------------------------------------- +; +; REGIONS B AND C ARE NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +BC LEA STATEB(A6),A1 + JSR SEEKRGN + MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED + LEA STATEC(A6),A1 + JSR SEEKRGN + OR (SP)+,D1 ;HAS EITHER RGN CHANGED ? + BEQ.S SEEKOK ;NO, WE'RE DONE + MOVE.L STATEB+SCANBUF(A6),A0 + MOVE.L STATEC+SCANBUF(A6),A1 +CPY2BUF MOVE.L MASKBUF(A6),A2 + MOVE BUFSIZE(A6),D1 +BCLOOP MOVE.L (A0)+,D0 + AND.L (A1)+,D0 + MOVE.L D0,(A2)+ + DBRA D1,BCLOOP +SEEKOK RTS ;ALL 3 ARE RECT, DO NOTHING + + +;------------------------------------------------------------------- +; +; REGIONS A, B AND C ARE ALL NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +ABC LEA STATEA(A6),A1 + JSR SEEKRGN + MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED + LEA STATEB(A6),A1 + JSR SEEKRGN + OR D1,(SP) ;REMEMBER IF RGN CHANGED + LEA STATEC(A6),A1 + JSR SEEKRGN + OR (SP)+,D1 ;HAS EITHER RGN CHANGED ? + BEQ.S ABCDONE ;NO, WE'RE DONE + MOVE.L STATEA+SCANBUF(A6),A0 + MOVE.L STATEB+SCANBUF(A6),A1 + MOVE.L STATEC+SCANBUF(A6),A2 + MOVE.L MASKBUF(A6),A3 + MOVE BUFSIZE(A6),D1 +ABCLOOP MOVE.L (A0)+,D0 + AND.L (A1)+,D0 + AND.L (A2)+,D0 + MOVE.L D0,(A3)+ + DBRA D1,ABCLOOP +ABCDONE RTS + + +;---------------------------------------------------------------; +; ; +; INTERFACE TO EACH OF THE RGNBLT SCANLINE LOOPS: ; +; ; +; REGISTERS: A0: D0: ; +; A1: D1: ; +; A2: D2: LONGCNT ; +; A3: SRCPTR D3: ; +; A4: MASKPTR D4: ; +; A5: DSTPTR D5: ; +; A6: D6: SHIFTCNT OR PATTERN ; +; A7: D7: INVERT OR PAT-SEL ; +; ; +;---------------------------------------------------------------; + +MODETAB .WORD MASK0-MODETAB + .WORD MASK1-MODETAB + .WORD MASK2-MODETAB + .WORD MASK3-MODETAB + .WORD MASK8-MODETAB + .WORD MASK9-MODETAB + .WORD MASK10-MODETAB + .WORD MASK11-MODETAB + + +;------------------------------------------------------- +; +; MODE 0 OR 4: SRC --> DST +; +MASK0 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP + LSR.L D6,D0 ;ALIGN TO DST + SWAP D0 ;PUT INTO HI HALF OF D0 + MOVE.L (A3),D1 ;GET SRC FROM BITMAP + ADD HBUMP(A6),A3 ;BUMP 4 BYTES RIGHT OR LEFT + LSR.L D6,D1 ;ALIGN TO DST + MOVE D1,D0 ;ASSEMBLE ONE LONG + EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET + MOVE.L (A4),D1 ;GET MASK + ADD HBUMP(A6),A4 ;BUMP 4 BYTES RIGHT OR LEFT + AND.L D1,D0 ;MASK SRC + NOT.L D1 ;FORM NOTMASK + AND.L (A5),D1 ;GET DST DATA + OR.L D1,D0 ;MERGE WITH SRC DATA + MOVE.L D0,(A5) ;PUT RESULT IN DST + ADD HBUMP(A6),A5 ;BUMP 4 BYTES RIGHT OR LEFT + DBRA D2,MASK0 ;LOOP ALL LONGS THIS ROW + BRA NEXTSRC ;GO FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 1 OR 5: SRC OR DST --> DST +; +MASK1 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP + LSR.L D6,D0 ;ALIGN TO DST + SWAP D0 ;PUT INTO HI HALF OF D0 + MOVE.L (A3),D1 ;GET SRC FROM BITMAP + ADD HBUMP(A6),A3 ;BUMP 4 BYTES RIGHT OR LEFT + LSR.L D6,D1 ;ALIGN TO DST + MOVE D1,D0 ;ASSEMBLE ONE LONG + EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND.L (A4),D0 ;AND WITH MASK + ADD HBUMP(A6),A4 ;BUMP 4 BYTES RIGHT OR LEFT + OR.L D0,(A5) ;OR RESULT INTO DST + ADD HBUMP(A6),A5 ;BUMP 4 BYTES RIGHT OR LEFT + DBRA D2,MASK1 ;LOOP ALL LONGS THIS ROW + BRA NEXTSRC ;LOOP FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 2 OR 6: SRC XOR DST --> DST +; +MASK2 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP + LSR.L D6,D0 ;ALIGN TO DST + SWAP D0 ;PUT INTO HI HALF OF D0 + MOVE.L (A3),D1 ;GET SRC FROM BITMAP + ADD HBUMP(A6),A3 ;BUMP 4 BYTES RIGHT OR LEFT + LSR.L D6,D1 ;ALIGN TO DST + MOVE D1,D0 ;ASSEMBLE ONE LONG + EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND.L (A4),D0 ;AND WITH MASK + ADD HBUMP(A6),A4 ;BUMP 4 BYTES RIGHT OR LEFT + EOR.L D0,(A5) ;XOR RESULT INTO DST + ADD HBUMP(A6),A5 ;BUMP 4 BYTES RIGHT OR LEFT + DBRA D2,MASK2 ;LOOP ALL LONGS THIS ROW + BRA NEXTSRC ;LOOP FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 3 OR 7: SRC BIC DST --> DST +; +MASK3 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP + LSR.L D6,D0 ;ALIGN TO DST + SWAP D0 ;PUT INTO HI HALF OF D0 + MOVE.L (A3),D1 ;GET SRC FROM BITMAP + ADD HBUMP(A6),A3 ;BUMP 4 BYTES RIGHT OR LEFT + LSR.L D6,D1 ;ALIGN TO DST + MOVE D1,D0 ;ASSEMBLE ONE LONG + EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND.L (A4),D0 ;AND WITH MASK + ADD HBUMP(A6),A4 ;BUMP 4 BYTES RIGHT OR LEFT + NOT.L D0 ;INVERT FOR BIC + AND.L D0,(A5) ;BIC RESULT INTO DST + ADD HBUMP(A6),A5 ;BUMP 4 BYTES RIGHT OR LEFT + DBRA D2,MASK3 ;LOOP ALL LONGS THIS ROW + BRA NEXTSRC ;LOOP FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 8 OR 12: PATTERN --> DST (FILLING AREAS, DRAWING LINES) +; +MASK8 MOVE.L D6,D0 ;GET PATTERN DATA + MOVE.L (A4)+,D1 ;GET MASK + AND.L D1,D0 ;MASK PATTERN DATA + NOT.L D1 ;MAKE NOTMASK + AND.L (A5),D1 ;GET DST DATA + OR.L D1,D0 ;MERGE WITH PAT DATA + MOVE.L D0,(A5)+ ;PUT RESULT TO DST + DBRA D2,MASK8 ;LOOP ALL LONGS THIS ROW + BRA NEXTPAT ;LOOP BACK FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 9 OR 13: PATTERN OR DST --> DST +; +MASK9 MOVE.L D6,D0 ;GET PATTERN DATA + AND.L (A4)+,D0 ;MASK PATTERN DATA + OR.L D0,(A5)+ ;OR RESULT INTO DST + DBRA D2,MASK9 ;LOOP ALL LONGS THIS ROW + BRA NEXTPAT ;LOOP BACK FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 10 OR 14: PATTERN XOR DST --> DST (INVERTING AREAS, XOR LINES) +; +MASK10 MOVE.L D6,D0 ;GET PATTERN DATA + AND.L (A4)+,D0 ;MASK PATTERN DATA + EOR.L D0,(A5)+ ;XOR RESULT INTO DST + DBRA D2,MASK10 ;LOOP ALL LONGS THIS ROW + BRA NEXTPAT ;LOOP BACK FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 11 OR 15: PATTERN BIC DST --> DST +; +MASK11 MOVE.L D6,D0 ;GET PATTERN DATA + AND.L (A4)+,D0 ;MASK PATTERN DATA + NOT.L D0 ;INVERT FOR BIC + AND.L D0,(A5)+ ;BIC RESULT INTO DST + DBRA D2,MASK11 ;LOOP ALL LONGS THIS ROW + BRA NEXTPAT ;LOOP BACK FOR NEXT ROW + + + + + .END diff --git a/RgnOp.a b/RgnOp.a new file mode 100755 index 0000000..499bef6 --- /dev/null +++ b/RgnOp.a @@ -0,0 +1,444 @@ + .INCLUDE GRAFTYPES.TEXT + + .FUNC RgnOp,7 + .REF SectScan,DiffScan,UnionScan,XorScan,InsetScan,SetSize +;------------------------------------------------------------------- +; +; FUNCTION RgnOp(rgnA,rgnB: RgnHandle; +; bufHandle: Handle; +; maxBytes: INTEGER; +; op,dh: INTEGER; +; okGrow: BOOLEAN): INTEGER; +; +; Computes the intersection, difference, union, or XOR of two regions, +; or the horizontal inset of one region, and stores the result as an +; unpacked array of sorted inversion points in bufHandle. Returns the +; number of points as the function value. BufHandle will be grown only +; if more space is needed needed and okGrow is true. +; +; OP = 0: SECT +; 2: DIFF A-B +; 4: UNION +; 6: XOR +; 8: HORIZ INSET +; +; +; A6 OFFSETS OF PARAMETERS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 20 ;TOTAL # BYTES +RESULT .EQU PARAMSIZE+8 ;INTEGER, FUNCTION RESULT +RGNA .EQU RESULT-4 ;LONG, RGNHANDLE +RGNB .EQU RGNA-4 ;LONG, RGNHANDLE +BUFHANDLE .EQU RGNB-4 ;LONG, HANDLE TO POINT BUFFER +MAXBYTES .EQU BUFHANDLE-2 ;WORD +OP .EQU MAXBYTES-2 ;WORD +DH .EQU OP-2 ;WORD +OKGROW .EQU DH-2 ;BOOLEAN + +SCAN1 .EQU -4 ;long +SCAN2 .EQU SCAN1-4 ;long +SCAN3 .EQU SCAN2-4 ;long +SCAN4 .EQU SCAN3-4 ;long +SCAN5 .EQU SCAN4-4 ;long +NEXTA .EQU SCAN5-2 ;WORD +NEXTB .EQU NEXTA-2 ;WORD +VERT .EQU NEXTB-2 ;WORD +BUFPTR .EQU VERT-4 ;LONG, ^POINT +BUFLIMIT .EQU BUFPTR-4 ;LONG +FAKEB .EQU BUFLIMIT-18 ;18 BYTE FAKE RGN DATA +MASTERB .EQU FAKEB-4 ;LONG +FAKEA .EQU MASTERB-18 ;18 BYTE FAKE RGN DATA +MASTERA .EQU FAKEA-4 ;LONG +CASEJMP .EQU MASTERA-4 ;LONG +SAVESTK .EQU CASEJMP-4 ;LONG +VARSIZE .EQU SAVESTK ;TOTAL BYTES OF LOCALS + + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE REGS + MOVE.L SP,SAVESTK(A6) ;REMEMBER STACK PTR + + +;------------------------------------------------------------ +; +; DE-REFERENCE RGNA AND RGNB AND OFFSET TO FIRST RGNDATA. +; IF EITHER IS RECTANGULAR, REPLACE IT WITH AN EXPANDED ONE. +; + LEA MASTERA(A6),A2 ;POINT TO FAKE AREA + LEA RGNA(A6),A0 ;POINT TO RGNA HANDLE + BSR EXPAND ;DE-REFERENCE AND EXPAND + MOVE.L A0,A3 ;SAVE RGNA DATA PTR IN A3 + LEA RGNB(A6),A0 ;POINT TO RGNB HANDLE + BSR EXPAND ;DE-REFERENCE AND EXPAND + MOVE.L A0,A4 ;SAVE RGNB DATA PTR IN A4 + + +;----------------------------------------------------------- +; +; SET UP A CASE JUMP BASED ON OP +; + LEA SECTSCAN,A0 + MOVE OP(A6),D0 + BEQ.S CASEOK ;BR IF OP = SECT + LEA DIFFSCAN,A0 + SUB #2,D0 + BEQ.S CASEOK ;BR IF OP = DIFF + LEA UNIONSCAN,A0 + SUB #2,D0 + BEQ.S CASEOK ;BR IF OP = UNION + LEA XORSCAN,A0 + SUB #2,D0 + BEQ.S CASEOK ;BR IF OP = XOR + LEA INSETSCAN,A0 ;ELSE OP = INSET +CASEOK MOVE.L A0,CASEJMP(A6) ;SAVE FOR LATER + + + +;----------------------------------------------------------------- +; +; Calc bufSize based on StackAvail and allocate 5 scan buffers +; + _StackAvail ;get stack avail in D0.L + SUB.L #1024,D0 ;subtract slop factor + CMP.L #200,D0 ;is result < 200 bytes ? + BGE.S STKOK1 ;no, continue + MOVE #40,D0 ;yes, make bufSize = 40 bytes + BRA.S ALLOC ;and continue +STKOK1 DIVS #5,D0 ;no, divide for 5 buffers + BVC.S STKOK2 ;overflow ? + MOVE #30000,D0 ;yes, use 30K bytes +STKOK2 BCLR #0,D0 ;make bufSize even +ALLOC SUB D0,SP ;allocate one buffer + MOVE.L SP,SCAN1(A6) ;remember buffer pointer + SUB D0,SP ;allocate one buffer + MOVE.L SP,SCAN2(A6) ;remember buffer pointer + SUB D0,SP ;allocate one buffer + MOVE.L SP,SCAN3(A6) ;remember buffer pointer + SUB D0,SP ;allocate one buffer + MOVE.L SP,SCAN4(A6) ;remember buffer pointer + SUB D0,SP ;allocate one buffer + MOVE.L SP,SCAN5(A6) ;remember buffer pointer + + + +;----------------------------------------------------------- +; +; INIT ASSORTED POINTERS +; + MOVE.L BUFHANDLE(A6),A0 ;GET BUFHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + MOVE.L A0,BUFPTR(A6) ;BUFPTR := BUFSTART + AND #$FFF8,MAXBYTES(A6) ;TRUNCATE TO A MULT OF 8 BYTES + ADD MAXBYTES(A6),A0 + MOVE.L A0,BUFLIMIT(A6) ;BUFLIMIT:=BUFSTART+MAXBYTES + MOVE.L SCAN1(A6),A0 + MOVE.L A0,D4 ;SCANA := @SCAN1 + MOVE #32767,D0 + MOVE D0,(A0) ;INIT SCANA TO EMPTY + MOVE.L SCAN2(A6),A0 + MOVE.L A0,D5 ;SCANB := @SCAN2 + MOVE D0,(A0) ;INIT SCANB TO EMPTY + MOVE.L SCAN3(A6),A0 + MOVE.L A0,D6 ;SCANC := @SCAN3 + MOVE D0,(A0) ;INIT SCANC TO EMPTY + MOVE.L SCAN4(A6),A0 + MOVE.L A0,D7 ;TEMPSCAN := @SCAN4 + MOVE (A3)+,NEXTA(A6) ;NEXTA := FIRST VERT IN A + MOVE (A4)+,NEXTB(A6) ;NEXTB := FIRST VERT IN B + CMP #8,OP(A6) ;IS OP = INSET ? + BNE.S NXTVERT ;NO, CONTINUE + MOVE D0,NEXTB(A6) ;YES, NEXTB := 32767 +NXTVERT MOVE NEXTA(A6),D0 ;GET NEXT VERT IN A + CMP NEXTB(A6),D0 ;WHICH COMES FIRST ? + BEQ.S BOTH ;SAME, UPDATE BOTH RGNS + BGT.S UPDATEB ;B, UPDATE RGNB ONLY + BSR.S UPDATEA ;A, UPDATE RGNA ONLY + BRA.S CALC ;CALC NEW C-SCAN + + +UPDATEA MOVE NEXTA(A6),VERT(A6) ;VERT := NEXTA + MOVE.L A3,A0 ;SRCA := PTRA + MOVE.L D4,A1 ;SRCB := SCANA + MOVE.L D7,A2 ;DSTC := TEMPSCAN + JSR XORSCAN ;XORSCAN(PTRA,SCANA,TEMPSCAN) + MOVE.L A0,A3 ;BUMP PTRA TO END OF SCAN + MOVE (A3)+,NEXTA(A6) ;NEXTA := NEXT VERT + EXG D4,D7 ;SWAP SCANA AND TEMPSCAN + RTS ;RETURN TO LOCAL CALLER + + +BOTH CMP #32767,D0 ;ARE BOTH VERTICALS 32767 ? + BEQ DONE ;YES, WE'RE ALL FINISHED + BSR.S UPDATEA ;UPDATE RGNA +UPDATEB MOVE NEXTB(A6),VERT(A6) ;VERT := NEXTB + MOVE.L A4,A0 ;SRCA := PTRB + MOVE.L D5,A1 ;SRCB := SCANB + MOVE.L D7,A2 ;DSTC := TEMPSCAN + JSR XORSCAN ;XORSCAN(PTRB,SCANB,TEMPSCAN) + MOVE.L A0,A4 ;BUMP PTRB TO END OF SCAN + MOVE (A4)+,NEXTB(A6) ;NEXTB := NEXT VERT + EXG D7,D5 ;SWAP SCANB AND TEMPSCAN + +;--------------------------------------------------------- +; +; CALCULATE SECT, DIFF, UNION, XOR, OR INSET INTO SCANC +; +CALC MOVE.L D4,A0 ;POINT TO SCANA + MOVE.L D5,A1 ;POINT TO SCANB + MOVE.L D7,A2 ;POINT TO TEMPSCAN + MOVE DH(A6),D2 ;GET DH IN CASE INSET + PEA CHANGES ;PUSH RETURN ADDR + MOVE.L CASEJMP(A6),-(SP) ;PUSH CASE JUMP + RTS ;DO CASE JSR + + +;------------------------------------------------------------- +; +; FIND ANY CHANGES NOT IN PREVIOUS SCANC, THEN UPDATE SCANC +; +CHANGES MOVE.L D7,A0 ;GET TEMPSCAN + MOVE.L D6,A1 ;GET SCANC + MOVE.L SCAN5(A6),A2 ;GET OUTPUT SCAN + JSR XORSCAN ;XorScan(tempScan,scanC,@SCAN5); + EXG D7,D6 ;SWAP TEMPSCAN AND SCANC + + MOVE.L SCAN5(A6),A0 ;POINT TO OUTPUT SCAN + MOVE.L BUFPTR(A6),A1 ;POINT TO DST POINT BUFFER + MOVE.L BUFLIMIT(A6),A2 ;GET BUFLIMIT + MOVE.L VERT(A6),D0 ;GET VERT COORD IN HI WORD + BRA.S OUTTEST ;GO TO LOOP START +OUTLOOP MOVE.W (A0)+,D0 ;GET LEFT HORIZ COORD + MOVE.L D0,(A1)+ ;PUT LEFT POINT + MOVE.W (A0)+,D0 ;GET RIGHT HORIZ COORD + MOVE.L D0,(A1)+ ;PUT RIGHT POINT +OUTTEST CMP.L A2,A1 ;IS BUFPTR >= BUFLIMIT ? + BLO.S SIZEOK ;NO, CONTINUE + + +;----------------------------------------------------------- +; +; THE POINT BUFFER IS FULL, GROW IT IF OKGROW IS TRUE +; + TST.B OKGROW(A6) ;ARE WE ALLOWED TO GROW ? + BEQ ABORT ;NO, ABORT RGNOP + MOVE.L A0,D1 ;YES, SAVE OUTPUT SCAN PTR + MOVE.L RGNA(A6),A0 ;GET RGNA MASTER + SUB.L (A0),A3 ;MAKE RGNA PTR RELATIVE + MOVE.L RGNB(A6),A0 ;GET RGNB MASTER + SUB.L (A0),A4 ;MAKE RGNB PTR RELATIVE + MOVE.L BUFHANDLE(A6),A0 ;GET BUFHANDLE + SUB.L (A0),A1 ;MAKE BUFPTR RELATIVE + SUB.L (A0),A2 ;MAKE BUFLIMIT RELATIVE, = SIZE + ADD #256,A2 ;BUMP BUFLIMIT 256 BYTES + MOVEM.L D0-D2/A0-A2,-(SP) ;SAVE REGS + MOVE.L A0,-(SP) ;PUSH BUFHANDLE + MOVE.W A2,-(SP) ;PUSH NEW BYTECOUNT + JSR SETSIZE ;GROW POINT BUFFER + MOVEM.L (SP)+,D0-D2/A0-A2 ;RESTORE REGS + MOVE.L RGNA(A6),A0 ;GET RGNA MASTER + ADD.L (A0),A3 ;MAKE RGNA UN-RELATIVE + MOVE.L RGNB(A6),A0 ;GET RGNB MASTER + ADD.L (A0),A4 ;MAKE RGNB UN-RELATIVE + MOVE.L BUFHANDLE(A6),A0 ;GET BUFHANDLE + ADD.L (A0),A1 ;MAKE BUFPTR UN-RELATIVE + ADD.L (A0),A2 ;MAKE BUFLIMIT UN-RELATIVE + MOVE.L A2,BUFLIMIT(A6) ;UPDATE BUFLIMIT + MOVE.L D1,A0 ;RESTORE OUTPUT SCAN PTR + + +SIZEOK CMP #32767,(A0) ;END OF SCAN MARKER ? + BNE OUTLOOP ;NO, GO FOR MORE + MOVE.L A1,BUFPTR(A6) ;UPDATE BUFPTR + BRA NXTVERT ;LOOP FOR NEXT VERT + + +;------------------------------------------------------------------------ +; +; LOCAL ROUTINE TO EXPAND A RECTANGULAR REGION TO ITS INVERSION POINTS. +; ENTER WITH ADDR OF RGNHANDLE IN A0, ADDR OF FAKE MASTER IN A2. +; RETURNS IN A0 DE-REFERENCED POINTER BUMPED TO FIRST RGNDATA, +; AND A2 BUMPED TO NEXT AVAILABLE FAKE MASTER. +; +EXPAND MOVE.L (A0),A1 ;GET RGNHANDLE + MOVE.L (A1),A1 ;DE-REFERENCE HANDLE + CMP #10,RGNSIZE(A1) ;IS REGION RECTANGULAR ? + BNE.S NOTRECT ;NO, DON'T EXPAND IT + MOVE.L A2,(A0) ;POINT HANDLE TO FAKE MASTER + LEA -6(A2),A0 ;POINT 10 BYTES BEFORE DATA + MOVE.L A0,(A2)+ ;FILL IN FAKE MASTER + MOVE.L RGNBBOX+TOPLEFT(A1),(A2)+ ;PUT TOP V AND LEFT H + MOVE RGNBBOX+RIGHT(A1),(A2)+ ;PUT RIGHT HORIZ + MOVE #32767,D0 + MOVE D0,(A2)+ ;PUT HORIZ TERMINATOR + MOVE RGNBBOX+BOTTOM(A1),(A2)+ ;PUT BOTTOM VERT + MOVE RGNBBOX+LEFT(A1),(A2)+ ;PUT LEFT HORIZ + MOVE RGNBBOX+RIGHT(A1),(A2)+ ;PUT RIGHT HORIZ + MOVE D0,(A2)+ ;PUT HORIZ TERMINATOR + MOVE D0,(A2)+ ;PUT VERT TERMINATOR + MOVE.L A0,A1 ;PUT FAKE RGNPTR IN A1 +NOTRECT LEA RGNDATA(A1),A0 ;OFFSET TO FIRST REGION DATA + RTS ;AND RETURN + + +ABORT MOVE.L A1,BUFPTR(A6) ;UPDATE BUFPTR +DONE MOVE.L BUFPTR(A6),D0 ;GET BUFPTR + MOVE.L BUFHANDLE(A6),A0 ;GET BUFHANDLE + SUB.L (A0),D0 ;BYTES USED = BUFPTR - BUFSTART + LSR #2,D0 ;DIV BY 4 FOR NPOINTS + MOVE D0,RESULT(A6) ;RETURN NPOINTS + MOVE.L SAVESTK(A6),SP ;STRIP SCAN BUFFERS + MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'RGNOP ' + + + + .PROC SectScan,3 + .DEF DiffScan,UnionScan +;--------------------------------------------------------- +; +; PROCEDURE SectScan(srcA,srcB,dstC: ScanPtr); +; +; Calculate the intersection, difference, or union of two inversion scans. +; +; Each input scan is a sorted array of integers terminated by 32767. +; The output scan contains the inversion coordinates for the result. +; +; INPUTS: A0 SRCA +; A1 SRCB +; A2 DSTC +; +; CLOBBERS D0-D3, A0-A2 +; +SECT CLR D2 ;RESET ASTATE OFF + CLR D3 ;RESET BSTATE OFF + BRA.S SHARE ;SHARE CODE +DIFFSCAN CLR D2 ;RESET ASTATE OFF + BRA.S UNION2 ;SHARE CODE +UNIONSCAN MOVEQ #-1,D2 ;SET ASTATE ON +UNION2 MOVEQ #-1,D3 ;SET BSTATE ON + +SHARE MOVE (A0)+,D0 ;GET NEXTA + MOVE (A1)+,D1 ;GET NEXTB +NEXT CMP D1,D0 ;IS NEXTA < NEXT B ? + BLT.S ALESS ;YES, BRANCH + BGT.S BLESS ;BR IF NEXTB IS LESS +EQUAL CMP #32767,D0 ;ARE WE AT THE END ? + BEQ.S DONE ;YES, QUIT + CMP D3,D2 ;ARE ASTATE AND BSTATE SAME ? + BNE.S SKIP0 ;NO, SKIP + MOVE D0,(A2)+ ;YES, PUT CHANGE +SKIP0 MOVE (A0)+,D0 ;GET NEW NEXTA + NOT D2 ;TOGGLE ASTATE + MOVE (A1)+,D1 ;GET NEW NEXTB + NOT D3 ;TOGGLE BSTATE + BRA NEXT ;LOOP FOR MORE +ALESS TST D3 ;TEST BSTATE + BEQ.S SKIP1 ;SKIP IF NOT TRUE + MOVE D0,(A2)+ ;PUT NEXTA +SKIP1 MOVE (A0)+,D0 ;GET NEW NEXTA + NOT D2 ;AND TOGGLE ASTATE + BRA NEXT ;LOOP FOR MORE +BLESS TST D2 ;TEST ASTATE + BEQ.S SKIP2 ;SKIP IF NOT TRUE + MOVE D1,(A2)+ ;PUT NEXTB +SKIP2 MOVE (A1)+,D1 ;GET NEW NEXTB + NOT D3 ;AND TOGGLE BSTATE + BRA NEXT ;LOOP FOR MORE +DONE MOVE #32767,(A2)+ ;PUT END MARKER INTO DST + RTS + + + .PROC InsetScan,3 + .DEF XorScan +;--------------------------------------------------------- +; +; PROCEDURE InsetScan(src,dst: ScanPtr; dh: INTEGER); +; +; Horizontally inset an inversion scan by dh; +; +; The input scan is a sorted array of integers terminated by 32767. +; The output scan contains the inversion coordinates for the inset. +; +; INPUTS: A0 SRC +; A2 DST +; D2 DH +; +; CLOBBERS D0-D1/A0-A2 +; + TST D2 ;IS DH NEG ? + BLT.S OUTSET ;YES, OUTSET + +;--------------------------------------------------------------- +; +; GET EACH PAIR OF COORDS, INSET THEM, AND CANCEL IF THEY CROSS. +; +INSET CMP #32767,(A0) ;CHECK FOR TERMINATOR + BEQ.S DONE ;QUIT WHEN FOUND + MOVE (A0)+,D0 ;GET LEFT COORD + MOVE (A0)+,D1 ;GET RIGHT COORD + ADD.W D2,D0 ;ADD DH TO LEFT + SUB.W D2,D1 ;SUB DH FROM RIGHT + CMP D1,D0 ;IS LEFT >= RIGHT ? + BGE.S INSET ;YES, SKIP BOTH + MOVE D0,(A2)+ ;PUT LEFT COORD TO DST + MOVE D1,(A2)+ ;PUT RIGHT COORD TO DST + BRA.S INSET ;LOOP ENTIRE SCAN + + +;------------------------------------------------------------------ +; +; GET EACH PAIR OF COORDS, OUTSET THEM, AND CANCEL IF THEY CROSS. +; +OUTSET MOVE #-32767,A1 ;OLDRIGHT := -32767 + BRA.S START ;GO TO LOOP START +OUTLOOP MOVE (A0)+,D0 ;GET LEFT COORD + MOVE (A0)+,D1 ;GET RIGHT COORD + ADD D2,D0 ;ADD DH TO LEFT + SUB D2,D1 ;SUB DH FROM RIGHT + CMP A1,D0 ;IS LEFT <= OLDRIGHT ? + BGT.S OUTOK ;NO, CONTINUE + SUB #2,A2 ;YES, OVER-WRITE PREVIOUS RIGHT + BRA.S OUTOK2 ;AND CONTINUE +OUTOK MOVE D0,(A2)+ ;PUT LEFT COORD +OUTOK2 MOVE D1,(A2)+ ;PUT RIGHT COORD + MOVE D1,A1 ;OLDRIGHT := RIGHT +START CMP #32767,(A0) ;CHECK FOR TERMINATOR + BNE OUTLOOP ;AND LOOP ENTIRE SCAN + +DONE MOVE #32767,(A2)+ ;PUT TERMINATOR + RTS + + +;-------------------------------------------------------------- +; +; LOCAL PROCEDURE XorScan(srcA,srcB,dstC: ScanPtr); +; +; Form the exclusive-or of two inversion scans. +; +; Each input scan is a sorted array of integers terminated by 32767. +; The output scan conatins all input coordinates from each, but +; with duplicate pairs cancelled. It also is terminated by 32767. +; +; INPUTS: A0 SRCA +; A1 SRCB +; A2 DSTC +; +; CLOBBERS D0-D1, A0-A2 +; +EQUAL CMP #32767,D0 ;ALL DONE ? + BEQ.S DONE ;YES, QUIT +XorScan MOVE (A0)+,D0 ;GET NEXT A + MOVE (A1)+,D1 ;GET NEXT B +NEXT CMP D1,D0 ;WHICH IS LESS, A OR B ? + BEQ.S EQUAL ;THE SAME, SO CANCEL + BLT.S ALESS ;A IS LESS +BLESS MOVE D1,(A2)+ ;PUT B TO DST + MOVE (A1)+,D1 ;GET NEXT B + BRA.S NEXT ;LOOP FOR MORE +ALESS MOVE D0,(A2)+ ;PUT A TO DST + MOVE (A0)+,D0 ;GET NEXT A + BRA.S NEXT ;LOOP FOR MORE + + + .END diff --git a/SeekRgn.a b/SeekRgn.a new file mode 100755 index 0000000..ff546c2 --- /dev/null +++ b/SeekRgn.a @@ -0,0 +1,192 @@ + .INCLUDE GRAFTYPES.TEXT +;------------------------------------------------------------------ +; +; --> SEEKRGN.TEXT +; +; Routines to play back a region into a scanline buffer. +; +; + + + .PROC INITRGN,0 +;------------------------------------------------------ +; +; INPUTS: A0: RGNPTR +; A1: STATE RECORD +; D0: MINH +; D1: MAXH +; D2: BUFLEFT +; +; OUTPUTS: ALL FIELDS OF STATE RECORD, +; SCANBUF ALLOCATED ON STACK +; +; CLOBBERS: D0,D1,A0 +; + MOVE D0,MINH(A1) ;INSTALL MINH + MOVE D1,MAXH(A1) ;INSTALL MAXH + MOVE D2,LEFTH(A1) ;INSTALL LEFTH + MOVE.L A0,RGNPTR(A1) ;INSTALL RGNPTR + MOVE #-32767,THISV(A1) ;THISV := -32767 + MOVE RGNBBOX+TOP(A0),NEXTV(A1) ;NEXTV := RGN BBOX TOP + LEA RGNDATA(A0),A0 ;POINT TO FIRST DATA + MOVE.L A0,DATAPTR(A1) ;INIT DATAPTR + MOVE.L (SP)+,A0 ;POP RETURN ADDR + SUB D2,D1 ;CALC BUFFER WIDTH IN DOTS + LSR #5,D1 ;DIV BY 32 FOR #LONGS-1 + MOVE D1,SCANSIZE(A1) ;SAVE SCANSIZE FOR LATER + +CLRLOOP CLR.L -(SP) ;ALLOCATE AND CLEAR BUFFER + DBRA D1,CLRLOOP + MOVE.L SP,SCANBUF(A1) ;REMEMBER BUFFER START + JMP (A0) ;RETURN + + + + .PROC SEEKRGN,0 + .REF MaskTab +;------------------------------------------------------------------ +; +; SeekRgn(rgnState,vert); +; +; ROUTINE TO PLAY BACK A REGION FORWARD OR BACKWARD UNTIL ITS SCAN +; BUFFER CONTAINS THE BITMAP FOR THE GIVEN VERTICAL COORDINATE. +; +; INPUTS: A1 POINTS TO A REGION STATE RECORD +; DO CONTAINS THE DESIRED VERTICAL COORD +; +; OUTPUTS: UPDATES THISV, NEXTV, DATAPTR, AND SCANBUF^ OF STATE RECORD +; D1-->1 IF CHANGE, 0 IF NO CHANGE. (Z-FLAG SET IF NO CHANGE) +; +; CLOBBERS: A0,D1. +; + +;---------------------------------------------------- +; +; RETURN QUICKLY IF SCANBUF IS ALREADY CURRENT. +; + CMP NEXTV(A1),D0 ;IS DESIRED VERT >= NEXTV ? + BGE.S DOWN ;YES, BUMP DOWNWARD + CMP THISV(A1),D0 ;IS DESIRED VERT < CURRENT VERT ? + BLT.S UP ;YES, BUMP UPWARD + CLR D1 ;ELSE REPORT NO CHANGES + RTS ;AND RETURN + + +;----------------------------------------------------- +; +; TO MOVE UPWARDS, JUST RESET TO START AND MOVE DOWN. +; +UP MOVE.L SCANBUF(A1),A0 ;POINT TO SCANBUF + MOVE SCANSIZE(A1),D1 ;GET BUFFER SIZE +CLRLP CLR.L (A0)+ ;CLEAR A LONG + DBRA D1,CLRLP ;LOOP ENTIRE SCANBUF + MOVE.L RGNPTR(A1),A0 ;GET RGNPTR + MOVE RGNBBOX+TOP(A0),NEXTV(A1) ;NEXTV := TOP VERT + MOVE #-32767,THISV(A1) ;RESET THISV TO -32767 + LEA RGNDATA(A0),A0 ;POINT TO START OF REGION DATA + MOVE.L A0,DATAPTR(A1) ;RESET DATAPTR + CMP NEXTV(A1),D0 ;IS DESIRED VERT >= NEXTV ? + BLT DONE ;NO, QUIT + + +;------------------------------------------------------ +; +; WHILE DESIRED VERT >= NEXTV DO BUMP DOWN. +; +DOWN MOVEM.L D0-D6/A2-A3,-(SP) ;SAVE REGS + MOVE D0,D2 ;SAVE VERT + MOVE.L DATAPTR(A1),A2 ;POINT TO VERT COORD +DOWN1 MOVE (A2)+,THISV(A1) ;UPDATE CURRENT VERT + + +;------------------------------------------------- +; +; GET LEFT AND RIGHT HORIZ COORDS +; AND TRIM AGAINST MINH AND MAXH +; +NEXTHOR MOVE (A2)+,D3 ;GET LEFT COORD + CMP #32767,D3 ;IS IT A TERMINATOR ? + BEQ.S DONE1 ;YES, QUIT + MOVE (A2)+,D4 ;GET RIGHT COORD + CMP MINH(A1),D4 ;IS RIGHT <= MINH ? + BLE NEXTHOR ;YES, IGNORE ON LEFT + CMP MAXH(A1),D3 ;IS LEFT >= MAXH ? + BGE NEXTHOR ;YES, IGNORE ON RIGHT + CMP MINH(A1),D3 ;IS LEFT < MINH ? + BGE.S LOK ;NO, CONTINUE + MOVE MINH(A1),D3 ;YES, TRIM LEFT +LOK CMP MAXH(A1),D4 ;IS RIGHT > MAXH ? + BLE.S ROK ;NO, CONTINUE + MOVE MAXH(A1),D4 ;YES, TRIM RIGHT + +ROK SUB LEFTH(A1),D3 ;MAKE COORDS REL TO BUFFER + SUB LEFTH(A1),D4 + + +;------------------------------------------ +; +; GET LEFTMASK AND RIGHTMASK +; + LEA MASKTAB,A0 ;POINT TO MASK TABLE + MOVEQ #$F,D0 ;GET MASK FOR LO 4 BITS + + MOVE D3,D5 ;COPY LEFT COORD + AND D0,D5 ;CALC LEFT MOD 16 + ADD D5,D5 ;DOUBLE FOR INDEX + MOVE 0(A0,D5),D5 ;GET MASK FROM TABLE + NOT D5 ;INVERT FOR LEFTMASK + + MOVE D4,D6 ;COPY RIGHT COORD + AND D0,D6 ;CALC RIGHT MOD 16 + ADD D6,D6 ;DOUBLE FOR INDEX + MOVE 0(A0,D6),D6 ;GET RIGHTMASK IN D6 + + +;------------------------------------------ +; +; CALC LEFTWORD, BUFPTR, WORDCOUNT +; + LSR #4,D3 ;CONVERT DOTS TO WORDS + MOVE.L SCANBUF(A1),A3 ;COPY BUFSTART + ADD D3,A3 + ADD D3,A3 ;INIT BUFPTR TO LEFTWORD + LSR #4,D4 ;CALC RIGHT DIV 16 + SUB D3,D4 ;WORDCOUNT:=RIGHTWORD-LEFTWORD + BGT.S NOTIN1 ;BR IF NOT ALL IN ONE + + +;------------------------------------------ +; +; LEFT AND RIGHT ARE ALL IN ONE WORD +; + AND D5,D6 ;COMBINE LEFT AND RIGHT MASKS + EOR D6,(A3) ;XOR COMBINATION INTO BUFFER + BRA NEXTHOR ;GO FOR MORE DH'S THIS SCAN + + +;------------------------------------------ +; +; NOT ALL IN ONE WORD. DO LEFT, MIDDLE IF ANY, THEN RIGHT +; +NOTIN1 EOR D5,(A3)+ ;XOR LEFTMASK INTO BUFFER + BRA.S TEST ;SEE IF ANY FULL WORDS +INVLONG NOT.L (A3)+ ;INVERT 2 WHOLE WORDS +TEST SUBQ #2,D4 ;ANY FULL WORDS LEFT ? + BGT INVLONG ;YES, AT LEAST 2 + BLT.S ENDWORD ;NO, FINISH UP LAST WITH MASK + NOT (A3)+ ;YES, DO LAST FULL WORD +ENDWORD EOR D6,(A3) ;XOR RIGHTMASK INTO BUFFER + BRA NEXTHOR ;GO FOR MORE DH'S THIS SCAN + + +DONE1 MOVE.L A2,DATAPTR(A1) ;UPDATE DATAPTR + MOVE (A2),NEXTV(A1) ;UPDATE NEXT VERT + CMP NEXTV(A1),D2 ;IS DESIRED VERT >= NEXTV ? + BGE DOWN1 ;YES, BUMP DOWN SOME MORE + MOVEM.L (SP)+,D0-D6/A2-A3 ;RESTORE REGS +DONE MOVEQ #1,D1 ;REPORT SCANLINE CHANGED + RTS ;AND RETURN + + + + .END diff --git a/SortPoints.a b/SortPoints.a new file mode 100755 index 0000000..0beabbe --- /dev/null +++ b/SortPoints.a @@ -0,0 +1,180 @@ + .INCLUDE GRAFTYPES.TEXT +;------------------------------------------------------------------ +; +; --> SORTPOINTS.TEXT +; +; Routines to sort inversion points and cull duplicates. +; + + + .PROC SortPoints +;------------------------------------------------------------- +; +; PROCEDURE SortPoints(ptBuf: PointsPtr; ptCount: INTEGER); +; +; PERFORMS A NON-RECURSIVE QUICKSORT ON AN ARRAY OF POINTS +; TO PUT THEM IN INCREASING VERT.HORIZ ORDER. +; +; RE-WROTE 5 SEPT 83 TO CUT DOWN WORST CASE STACK USAGE +; +; See Algorithms + Data Structures = Programs, p.80 +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 6 +PTBUF .EQU PARAMSIZE+8-4 ;LONG +PTCOUNT .EQU PTBUF-2 ;WORD + + + + LINK A6,#0 ;NO LOCAL VARIABLES + MOVEM.L D3-D4/A2-A4,-(SP) ;SAVE REGS + MOVE.L PTBUF(A6),A3 ;LEFTPTR:=START OF PT ARRAY + MOVE A3,D3 + AND #3,D3 ;SET UP LOBITS FOR SORT + CLR.L D0 + MOVE PTCOUNT(A6),D0 ;GET PTCOUNT + BLE.S GOHOME ;DO NOTHING IF NO POINTS + LSL.L #2,D0 ;QUAD PTCOUNT FOR BYTES + MOVE.L A3,A4 + ADD.L D0,A4 ;ADD TO DSTSTART + SUB #4,A4 ;RIGHTPTR:=DSTEND-4 + + MOVE.L SP,D4 ;REMEMBER STACK MARKER + MOVEM.L A3/A4,-(SP) ;PUSH LEFTPTR AND RIGHTPTR + + +POPNXT MOVEM.L (SP)+,A3/A4 ;POP LEFTPTR AND RIGHTPTR + + +SPLIT MOVE.L A3,A1 ;IPTR := LEFTPTR + MOVE.L A4,A2 ;JPTR := RIGHTPTR +; +; CALC MIDPTR AND MIDPT +; + MOVE.L A3,D0 ;ADD LEFTPTR + ADD.L A4,D0 ;AND RIGHTPTR + ROXR.L #1,D0 ;THEN DIVIDE BY 2 FOR MIDPTR + AND #$FFFC,D0 ;TRUNC TO MULTIPLE OF 4 BYTES + OR D3,D0 ;OR IN LOBITS FOR POINT BOUNDARY + MOVE.L D0,A0 ;GET MIDPTR INTO A-REG + MOVE H(A0),D1 ;GET MIDPT.H + MOVE V(A0),D2 ;AND MIDPT.V + +SCAN +; +; WHILE IPTR^ < MIDPT DO BUMP IPTR TO RIGHT +; + BRA.S TWO ;GO TO LOOP START +ONE ADD #4,A1 ;BUMP IPTR TO RIGHT +TWO CMP V(A1),D2 ;IS MIDPT.V > IPTR^.V ? + BGT ONE ;YES, BUMP SOME MORE + BLT.S THREE ;BR IF DONE WITH IPTR. + CMP H(A1),D1 ;IF SAME VERT, LOOK AT HORIZ + BGT ONE ;KEEP BUMPING IF MIDPT.H > IPTR^.H +THREE + + +; +; WHILE JPTR^ > MIDPT DO BUMP JPTR TO LEFT +; + BRA.S FIVE ;GO TO LOOP START +FOUR SUB #4,A2 ;BUMP JPTR TO LEFT +FIVE CMP V(A2),D2 ;IS MIDPT.V < JPTR^.V ? + BLT FOUR ;YES, BUMP SOME MORE + BGT.S SIX ;BR IF DONE BUMPING JPTR + CMP H(A2),D1 ;IF SAME VERT, LOOK AT HORIZ + BLT FOUR ;KEEP BUMPING IF MIDPT.H < JPTR^.H +SIX + +; +; if IPtr <= JPtr then swap IPtr^ and JPtr^, and bump both pointers +; + CMP.L A2,A1 ;IS IPTR > JPTR ? + BGT.S NOSWAP ;YES, ALL DONE + MOVE.L (A1),D0 + MOVE.L (A2),(A1) + MOVE.L D0,(A2) ;SWAP POINTS + ADD #4,A1 ;BUMP IPTR TO RIGHT + SUB #4,A2 ;BUMP JPTR TO LEFT + +; +; repeat until this partitioning is complete, IPtr > JPtr +; +NOSWAP CMPA.L A2,A1 ;IS IPTR > JPTR ? + BLS SCAN ;NO, LOOP AGAIN + +; +; IF i < right then stack request to sort right partition +; + CMPA.L A4,A1 ;IS IPTR < RIGHTPTR ? + BHS.S RIGHTOK ;YES, CONTINUE + MOVEM.L A1/A4,-(SP) ;NO, PUSH IPTR,RIGHTPTR + +RIGHTOK MOVE.L A2,A4 ;RIGHTPTR := JPTR + + CMPA.L A4,A3 ;IS LEFTPTR >= RIGHTPTR ? + BLO SPLIT ;NO, PARTITION AGAIN + + CMPA.L D4,SP ;IS STACK EMPTY YET ? + BNE POPNXT ;NO, LOOP FOR MORE + +GOHOME MOVEM.L (SP)+,D3-D4/A2-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'SORTPOIN' + + + + + + .PROC CullPoints,2 +;------------------------------------------------------------- +; +; PROCEDURE CullPoints(ptBuf: PointsPtr; VAR ptCount: INTEGER); +; +; CANCEL ANY DUPLICATE PAIRS OF POINTS IN AN ARRAY OF POINTS. +; +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 8 +PTBUF .EQU PARAMSIZE+8-4 ;LONG +PTCOUNT .EQU PTBUF-4 ;LONG, VAR + + LINK A6,#0 ;NO LOCAL VARIABLES + MOVEM.L D0-D7/A1-A5,-(SP) ;SAVE REGS + MOVE.L PTCOUNT(A6),A0 ;GET VAR ADDR OF PTCOUNT + MOVE (A0),D0 ;GET PTCOUNT + BLE GOHOME ;DO NOTHING IF NO POINTS + MOVE.L PTBUF(A6),A1 ;SRCPTR:=START PTR + MOVE.L A1,A3 ;COPY START + EXT.L D0 ;CLEAR HI WORD + LSL.L #2,D0 ;QUAD PTCOUNT FOR BYTES + ADD.L D0,A3 ;ADD TO START + SUB #4,A3 ;LAST POINT IS AT END-4 + MOVE.L A1,D5 ;SAVE START FOR LATER + MOVE.L A1,A2 ;DSTPTR:=START + BRA.S WHILE1 ;GO TO LOOP START + +DELETE ADD #4,A1 ;SKIP OVER BOTH SRC POINTS + BRA.S WHILE1 ;GO TO LOOP START +MORE1 MOVE.L (A1)+,D0 ;GET CURRENT SRC POINT + CMP.L (A1),D0 ;IS IT SAME AS NEXT ? + BEQ DELETE ;YES, DELETE BOTH + MOVE.L D0,(A2)+ ;NO, COPY TO DST +WHILE1 CMP.L A3,A1 ;IS SRCPTR < LASTPTR ? + BLT.S MORE1 ;YES, GO FOR MORE + BGT.S DONE + MOVE.L (A1)+,(A2)+ ;FINISH UP LAST POINT +DONE MOVE.L A2,D0 ;GET DST PTR + SUB.L D5,D0 ;SUBTRACT START PTR + LSR #2,D0 ;DIV BY 4 FOR PTCOUNT + MOVE.L PTCOUNT(A6),A0 ;GET VAR ADDR + MOVE D0,(A0) ;UPDATE PTCOUNT TO REFLECT DELETIONS +GOHOME MOVEM.L (SP)+,D0-D7/A1-A5 ;RESTORE REGS + UNLINK PARAMSIZE,'CULLPOIN' + + + + + + .END diff --git a/Stretch.a b/Stretch.a new file mode 100755 index 0000000..73c3394 --- /dev/null +++ b/Stretch.a @@ -0,0 +1,1164 @@ +;------------------------------------------------------------------ +; +; --> STRETCH.TEXT +; + + .PROC StretchBits,8 + .REF RgnBlt,RSect,ShieldCursor,ShowCursor + .REF InitRgn,SeekRgn,SetupStretch,ColorMap,XorSlab +;-------------------------------------------------------------- +; +; PROCEDURE StretchBits(srcBits,dstBits: BitMap; +; srcRect,dstRect: Rect; +; mode: INTEGER +; rgnA,rgnB,rgnC: RgnHandle); +; +; Transfer a rectangle of bits from srcBits to dstBits, +; stretching or compressing according to srcRect and dstRect. +; The transfer is clipped to the intersection of rgnA, rgnB, and rgnC. +; +; +; Restrictions: +; +; transfer mode 0..7 only. +; if numer <> denom, then src and dst bitmaps do not overlap. +; +; +; COPYRIGHT APPLE COMPUTER INC. +; DESIGNED AND WRITTEN BY BILL ATKINSON +; + + +;---------------------------------------------------- +; +; A6 OFFSETS OF PARAMETERS AFTER LINK: +; +PARAMSIZE .EQU 30 ;TOTAL BYTES OF PARAMETERS +SRCBITS .EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP +DSTBITS .EQU SRCBITS-4 ;LONG, ADDR OF BITMAP +SRCRECT .EQU DSTBITS-4 ;LONG, ADDR OF RECT +DSTRECT .EQU SRCRECT-4 ;LONG, ADDR OF RECT +MODE .EQU DSTRECT-2 ;WORD +RGNA .EQU MODE-4 ;RGNHANDLE +RGNB .EQU RGNA-4 ;RGNHANDLE +RGNC .EQU RGNB-4 ;RGNHANDLE + + +;------------------------------------------------- +; +; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: +; +NUMER .EQU -4 ;POINT +DENOM .EQU NUMER-4 ;POINT +VERROR .EQU DENOM-4 ;INTEGER +MINRECT .EQU VERROR-8 ;RECT +SRCBUF .EQU MINRECT-4 ;LONG +DSTBUF .EQU SRCBUF-4 ;LONG +SRCLONGS .EQU DSTBUF-2 ;WORD +DSTLONGS .EQU SRCLONGS-2 ;WORD +STATEA .EQU DSTLONGS-RGNREC ;RGN STATE RECORD +STATEB .EQU STATEA-RGNREC ;RGN STATE RECORD +STATEC .EQU STATEB-RGNREC ;RGN STATE RECORD +SAVESTK .EQU STATEC-4 ;LONG +RECTFLAG .EQU SAVESTK-2 ;WORD +MASKBUF .EQU RECTFLAG-4 ;LONG +BUFLEFT .EQU MASKBUF-2 ;WORD +BUFSIZE .EQU BUFLEFT-2 ;WORD +SRCADDR .EQU BUFSIZE-4 ;LONG +DSTADDR .EQU SRCADDR-4 ;LONG +SRCROW .EQU DSTADDR-4 ;LONG +DSTROW .EQU SRCROW-4 ;LONG +SRCLIMIT .EQU DSTROW-4 ;LONG +VERT .EQU SRCLIMIT-2 ;WORD +MODECASE .EQU VERT-4 ;LONG +PAT .EQU MODECASE-4 ;LONG, ADDR OF PAT +RATIOCASE .EQU PAT-4 ;LONG +FRACTION .EQU RATIOCASE-2 ;WORD +VARSIZE .EQU FRACTION ;SIZE OF LOCAL VARIABLES + + + LINK A6,#VARSIZE ;ALLOCATE LOCAL VARIABLES + MOVEM.L D0-D7/A1-A4,-(SP) ;SAVE REGS + MOVE.L SP,SAVESTK(A6) ;REMEMBER STACK FOR LATER + +;---------------------------------------------------------------- +; +; CALC NUMER AND DENOM BASED ON DSTRECT AND SRCRECT. +; IF NUMER = DENOM THEN JUST CALL RGNBLT. +; + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + MOVE BOTTOM(A0),D0 + SUB TOP(A0),D0 ;CALC DST HEIGHT + SWAP D0 ;PUT IN HI WORD + MOVE RIGHT(A0),D0 + SUB LEFT(A0),D0 ;CALC DST WIDTH + + MOVE.L SRCRECT(A6),A0 ;POINT TO SRCRECT + MOVE BOTTOM(A0),D1 + SUB TOP(A0),D1 ;CALC SRC HEIGHT + SWAP D1 ;PUT IN HI WORD + MOVE RIGHT(A0),D1 + SUB LEFT(A0),D1 ;CALC SRC WIDTH + CMP.L D0,D1 ;ARE BOTH RECTS SAME SIZE + BNE.S STRETCH ;NO, CAN'T USE RGNBLT + +XRGNBLT MOVE.L SRCBITS(A6),-(SP) ;PUSH SRCBITS + MOVE.L DSTBITS(A6),-(SP) ;PUSH DSTBITS + MOVE.L SRCRECT(A6),-(SP) ;PUSH SRCRECT + MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT + MOVE MODE(A6),-(SP) ;PUSH MODE + MOVE.L PAT(A6),-(SP) ;PAT ONLY USED FROM BELOW + MOVE.L RGNA(A6),-(SP) ;PUSH RGNA + MOVE.L RGNB(A6),-(SP) ;PUSH RGNB + MOVE.L RGNC(A6),-(SP) ;PUSH RGNC + JSR RGNBLT ;CALL RGNBLT + BRA GOHOME ;AND QUIT + + +STRETCH MOVE.L D0,NUMER(A6) ;NUMER := DST SIZE + MOVE.L D1,DENOM(A6) ;DENOM := SRC SIZE + JSR SetupStretch ;CALC CASEJUMP AND HORIZ FRACT + MOVE.L A0,RATIOCASE(A6) ;SAVE CASE JUMP FOR LATER + MOVE D0,FRACTION(A6) ;SAVE FRACTION FOR LATER + + +;---------------------------------------------------------------- +; +; ADJUST MODE AND PATTERN FOR COLOR SEPARATION. +; + MOVE MODE(A6),-(SP) ;PUSH INPUT MODE + MOVE.L PAT(A6),-(SP) ;PUSH ADDR OF DUMMY PATTERN + JSR COLORMAP ;ALTER FOR COLOR SEPARATION + MOVE.L (SP)+,PAT(A6) ;GET (ALTERED) PATTERN + MOVE (SP)+,D2 ;GET (ALTERED) MODE + MOVE D2,D3 ;COPY MODE + ROR #4,D3 ;IS PATTERN BIT SET ? + BCS.S XRGNBLT ;YES, USE RGNBLT TO DO PAT + MOVE D2,MODE(A6) ;NO, UPDATE (ALTERED) MODE + + +;------------------------------------------------------------------- +; +; CALC MINRECT = INTERSECTION OF DSTRECT, DSTBITS.BOUNDS, AND THREE +; REGION BOUNDING BOXES. QUIT IF THE INTERSECTION IS EMPTY. +; + MOVE.L DSTBITS(A6),A3 ;POINT TO DST BITMAP + MOVE.L DSTRECT(A6),-(SP) ;PUSH ADDR OF DSTRECT + PEA BOUNDS(A3) ;PUSH ADDR OF DSTBITS.BOUNDS + MOVE.L RGNA(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + PEA RGNBBOX(A0) ;PUSH RGN BBOX + MOVE.L RGNB(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + PEA RGNBBOX(A0) ;PUSH RGN BBOX + MOVE.L RGNC(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + PEA RGNBBOX(A0) ;PUSH RGN BBOX + MOVE #5,-(SP) ;PUSH NRECTS + PEA MINRECT(A6) ;PUSH WHERE TO PUT RESULT + JSR RSECT ;INTERSECT ALL RECTS + BEQ GOHOME ;QUIT IF RESULT IS EMPTY + + +;---------------------------------------------------- +; +; HIDE THE CURSOR IF IT INTERSECTS MINRECT +; + PEA MINRECT(A6) ;PUSH SHIELD RECT + MOVE.L BOUNDS+TOPLEFT(A3),-(SP) ;PUSH DELTA TO CONVERT TO GLOBAL + JSR SHIELDCURSOR ;REMOVE CURSOR IF INTERSECT + + +;----------------------------------------------------------------------- +; +; ALLOCATE AND CLEAR SRCBUF TO HOLD SRCWIDTH. +; + MOVE DENOM+H(A6),D0 ;GET SRC WIDTH + SUB #1,D0 ;SUBTRACT 1 PIXEL + LSR #5,D0 ;AND DIV BY 32 FOR LONGS + MOVE D0,SRCLONGS(A6) ;SAVE FOR LATER + + CLR.L -(SP) ;CLEAR A LONG OF SLOP AT RIGHT +CLRSRC CLR.L -(SP) ;ALLOCATE AND CLEAR A LONG + DBRA D0,CLRSRC ;LOOP ENTIRE BUFFER + MOVE.L SP,SRCBUF(A6); ;REMEMBER WHERE SRCBUF IS + + +;----------------------------------------------------------------------- +; +; ALLOCATE AND CLEAR DSTBUF TO HOLD DSTWIDTH. +; + MOVE NUMER+H(A6),D0 ;GET DST WIDTH + SUB #1,D0 ;SUBTRACT 1 PIXEL + LSR #5,D0 ;AND DIV BY 32 FOR LONGS + MOVE D0,DSTLONGS(A6) ;SAVE FOR LATER + + CLR.L -(SP) ;CLEAR A LONG OF SLOP AT RIGHT + CLR.L -(SP) ;CLEAR ANOTHER LONG OF SLOP +CLRDST CLR.L -(SP) ;ALLOCATE AND CLEAR A LONG + DBRA D0,CLRDST ;LOOP ENTIRE BUFFER + MOVE.L SP,DSTBUF(A6); ;REMEMBER WHERE DSTBUF IS + + +;-------------------------------------------------------- +; +; CALC BUFLEFT AND BUFSIZE FOR RGN SCANLINE BUFFERS +; + MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT + MOVE LEFT(A0),D1 ;GET DSTRECT LEFT + SUB BOUNDS+LEFT(A3),D1 ;CONVERT TO GLOBAL COORDS + AND #$FFF0,D1 ;TRUNC TO MULT OF 16 + ADD BOUNDS+LEFT(A3),D1 ;CONVERT BACK TO LOCAL + MOVE D1,BUFLEFT(A6) ;SAVE AS BUFLEFT + MOVE MINRECT+RIGHT(A6),D0 ;GET MINRECT RIGHT + SUB D1,D0 ;CALC WIDTH IN DOTS + LSR #5,D0 ;DIV BY 32 FOR LONGS + MOVE D0,BUFSIZE(A6) ;BUFSIZE = # LONGS -1 + + +;----------------------------------------------------------------------- +; +; ALLOCATE AND CLEAR A SCANLINE BUFFER FOR THE COMPOSITE MASK. +; +CLRMASK CLR.L -(SP) ;ALLOCATE AND CLEAR + DBRA D0,CLRMASK ;LOOP TILL DONE + MOVE.L SP,MASKBUF(A6); ;REMEMBER WHERE MASKBUF IS + + +;------------------------------------------------------------------- +; +; INIT STATE RECORDS VERT0 AND VERT1 IN CASE RECTANGULAR +; + MOVE #32767,D0 + MOVE D0,STATEA+NEXTV(A6) + MOVE D0,STATEB+NEXTV(A6) + MOVE D0,STATEC+NEXTV(A6) + NEG D0 + MOVE D0,STATEA+THISV(A6) + MOVE D0,STATEB+THISV(A6) + MOVE D0,STATEC+THISV(A6) + + +;---------------------------------------------------------------------- +; +; ALLOCATE BUFFERS AND INIT STATE RECORDS FOR EACH NON-RECT REGION +; + MOVEQ #10,D7 + CLR D5 ;INIT ALL RGNS RECT + MOVE.L RGNA(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + CMP RGNSIZE(A0),D7 ;IS RGNA RECTANGULAR ? + BEQ.S ARECT ;YES, SKIP IT + ADD #2,D5 ;NO, SET UP FLAG + LEA STATEA(A6),A1 ;POINT TO STATE RECORD A + BSR.S INITONE ;INIT STATE, ALLOC BUFFER +ARECT + MOVE.L RGNB(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + CMP RGNSIZE(A0),D7 ;IS RGNB RECTANGULAR ? + BEQ.S BRECT ;YES, SKIP IT + ADD #4,D5 ;NO, BUMP FLAG + LEA STATEB(A6),A1 ;POINT TO STATE RECORD B + BSR.S INITONE ;INIT STATE, ALLOC BUFFER +BRECT + MOVE.L RGNC(A6),A0 ;GET RGNHANDLE + MOVE.L (A0),A0 ;DE-REFERENCE IT + CMP RGNSIZE(A0),D7 ;IS RGNC RECTANGULAR ? + BEQ.S CRECT ;YES, SKIP IT + ADD #8,D5 ;NO, BUMP FLAG + LEA STATEC(A6),A1 ;POINT TO STATE RECORD C + PEA CRECT ;PUSH FAKE RETURN ADDR +INITONE MOVE MINRECT+LEFT(A6),D0 ;GET MINH + MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH + MOVE BUFLEFT(A6),D2 ;GET BUFLEFT + JMP INITRGN ;INIT STATE, ALLOC BUFFER +CRECT + + +;-------------------------------------------------------------------- +; +; IF ALL REGIONS ARE RECTANGULAR, THEN DRAW MINRECT INTO MASK BUFFER +; + MOVE.W D5,RECTFLAG(A6) ;ARE ALL RGNS RECT ? + BNE.S NOTRECT ;NO, CONTNUE + MOVE.L MASKBUF(A6),A0 ;YES, POINT TO MASK BUFFER + MOVE MINRECT+LEFT(A6),D3 ;SET UP LEFT + SUB BUFLEFT(A6),D3 ;MAKE IT BUFFER RELATIVE + MOVE MINRECT+RIGHT(A6),D4 ;SET UP RIGHT + SUB BUFLEFT(A6),D4 ;MAKE IT BUFFER RELATIVE + JSR XorSlab ;AND XOR BETWEEN THEM +NOTRECT + + +;------------------------------------------------------ +; +; SET UP INVERT FLAG IN D7 TO REFLECT MODE BIT 2 +; + CLR.L D7 ;SAY NOT INVERTED + MOVE MODE(A6),D2 ;GET TRANSFER MODE + BMI DONE ;QUIT IF MODE NEGATIVE + BCLR #2,D2 ;TEST AND CLR INVERT BIT + BEQ.S SETMODE ;SKIP IF NOT INVERTED + NOT.L D7 ;INVERTED; D7 GETS ALL 1'S + + +;-------------------------------------------------- +; +; CALCULATE CASE JUMP FOR DIFFERENT TRANSFER MODES +; +SETMODE CMP #7,D2 ;IS MODE > 7 ? + BGT DONE ;YES, QUIT + LEA MODETAB,A0 ;POINT TO MODE TABLE + MOVE.B 0(A0,D2),D2 ;GET OFFSET + SUB D2,A0 ;COMPUTE ADDRESS + MOVE.L A0,MODECASE(A6) ;SAVE FOR LATER + + +;------------------------------------------------ +; +; SET UP SRCROW, SRCLIMIT, SRCSHIFT, AND SRCADDR +; + MOVE.L SRCBITS(A6),A2 ;POINT TO SRCBITS + MOVE ROWBYTES(A2),D0 ;GET SRC ROWBYTES + EXT.L D0 ;AND EXTEND TO LONG + MOVE.L D0,SRCROW(A6) ;SRCROW := SRC ROWBYTES + + MOVE BOUNDS+BOTTOM(A2),D1 ;GET SRCBITS.BOUNDS.BOTTOM + SUB BOUNDS+TOP(A2),D1 ;MAKE IT GLOBAL + MULU D0,D1 ;MULT BY SRC ROWBYTES + ADD.L BASEADDR(A2),D1 ;ADD BASEADDR + ADD.L #2,D1 ;ADJUST FOR -2(A0) SRC PICKUP + MOVE.L D1,SRCLIMIT(A6) ;SAVE RESULT AS SRCLIMIT + + MOVE.L SRCRECT(A6),A0 ;POINT TO SRCRECT + MOVE LEFT(A0),D1 ;GET SRCRECT LEFT + SUB BOUNDS+LEFT(A2),D1 ;CONVERT TO SRC GLOBAL + MOVE D1,D5 ;MAKE A COPY + NEG D5 ;NEGATE IT AND + AND #$F,D5 ;TREAT MOD 16 FOR SRCSHIFT + + MOVE TOP(A0),D0 ;GET SRCRECT TOP + SUB BOUNDS+TOP(A2),D0 ;CONVERT TO SRC GLOBAL + MULU ROWBYTES(A2),D0 ;MULT BY SRC ROWBYTES + MOVE.L BASEADDR(A2),A0 ;GET START OF SRC BITMAP + ADD.L D0,A0 ;ADD VERTICAL OFFSET + + ADD D5,D1 ;ADJUST SRCLEFT FOR SRCSHIFT + ASR #4,D1 ;CONVERT DOTS TO WORDS + ADD D1,A0 ;ADD HORIZONTAL OFFSET + ADD D1,A0 ;TWICE FOR BYTES + MOVE.L A0,SRCADDR(A6) ;SAVE AS SRCADDR + + +;---------------------------------------------------- +; +; CALC STARTING DSTROW, DSTSHIFT, AND DSTADDR +; + MOVE ROWBYTES(A3),D0 ;GET DST ROWBYTES + EXT.L D0 ;EXTEND TO LONG + MOVE.L D0,DSTROW(A6) ;DSTROW := DST ROWBYTES + + MOVE.L DSTRECT(A6),A0 + MOVE TOP(A0),VERT(A6) ;INIT CURRENT VERTICAL + MOVE LEFT(A0),D1 ;GET DSTRECT LEFT + SUB BOUNDS+LEFT(A3),D1 ;CONVERT TO GLOBAL COORDS + MOVEQ #$F,D6 + AND D1,D6 ;TREAT MOD 16 FOR SHIFTCNT + + MOVE MINRECT+TOP(A6),D0 ;GET MINRECT TOP + SUB BOUNDS+TOP(A3),D0 ;CONVERT TO GLOBAL COORDS + MULU ROWBYTES(A3),D0 ;MULT BY DST ROWBYTES + MOVE.L BASEADDR(A3),A0 ;GET START OF DST BITMAP + ADD.L D0,A0 ;ADD VERTICAL OFFSET + + ASR #4,D1 ;CONVERT DOTS TO WORDS + ADD D1,A0 ;ADD HORIZ OFFSET + ADD D1,A0 ;TWICE FOR BYTES + MOVE.L A0,DSTADDR(A6) ;SAVE AS DSTADDR + + +;----------------------------------------------------- +; +; INIT ERROR TERM FOR DDA +; + MOVE DENOM+V(A6),D0 + LSR #1,D0 + NEG D0 + MOVE D0,VERROR(A6) ;VERROR := -DENOM.V/2 + + +;----------------------------------------------------- +; +; GET FIRST SCANLINE OF SRC INTO SRCBUF +; +NEXTSRC MOVE.L SRCADDR(A6),A0 ;POINT TO SRC BITMAP + CMP.L SRCLIMIT(A6),A0 ;IS IT EXHAUSTED ? + BHS DONE ;YES, QUIT + MOVE.L SRCBUF(A6),A1 ;POINT TO SRCBUF + MOVE SRCLONGS(A6),D1 ;GET COUNT OF LONGS +NXTSRC2 MOVE.L -2(A0),D0 ;GET A LONG OF SRC + LSR.L D5,D0 ;ALIGN TO SRCBUF + MOVE D0,(A1)+ ;PUT A WORD TO SRCBUF + MOVE.L (A0)+,D0 ;GET A SECOND LONG + LSR.L D5,D0 ;ALIGN TO SRCBUF + MOVE D0,(A1)+ ;PUT A WORD TO SRCBUF + DBRA D1,NXTSRC2 ;LOOP FOR ALL LONGS + MOVE.L SRCROW(A6),D2 ;GET SRC ROWBYTES + ADD.L D2,SRCADDR(A6) ;BUMP SRC TO NEXT ROW + MOVE NUMER+V(A6),D0 ;GET NUMER.V + ADD D0,VERROR(A6) ;VERROR := VERROR + NUMER.V + BGT.S SRCOK ;SKIP IF VERROR > 0 + + +;----------------------------------------------------- +; +; WHILE (VERROR < 0) DO MERGE OTHER SCANLINES INTO SRCBUF. +; +SRCLOOP MOVE.L SRCADDR(A6),A0 ;POINT TO SRC BITMAP + CMP.L SRCLIMIT(A6),A0 ;IS IT EXHAUSTED ? + BHS.S SRCOK ;YES, DONT GET ANY MORE + MOVE.L SRCBUF(A6),A1 ;POINT TO SRCBUF + MOVE SRCLONGS(A6),D1 ;GET COUNT OF LONGS +NXTSRC3 MOVE.L -2(A0),D0 ;GET A LONG OF SRC + LSR.L D5,D0 ;ALIGN TO SRCBUF + OR D0,(A1)+ ;OR A WORD TO SRCBUF + MOVE.L (A0)+,D0 ;GET A SECOND LONG + LSR.L D5,D0 ;ALIGN TO SRCBUF + OR D0,(A1)+ ;OR A WORD TO SRCBUF + DBRA D1,NXTSRC3 ;LOOP FOR ALL LONGS + ADD.L D2,SRCADDR(A6) ;BUMP SRC TO NEXT ROW + MOVE NUMER+V(A6),D0 ;GET NUMER.V + ADD D0,VERROR(A6) ;VERROR := VERROR + NUMER.V +MORESRC BLE.S SRCLOOP ;LOOP WHILE VERROR <= 0 +SRCOK + + +;---------------------------------------------------------- +; +; HORIZONTALLY STRETCH SRCBUF INTO DSTBUF +; + MOVE.L SRCBUF(A6),A0 ;POINT TO SRCBUF + MOVE.L DSTBUF(A6),A1 ;POINT TO DSTBUF + MOVE DSTLONGS(A6),D0 ;GET DSTLONGS + LSL #2,D0 ;QUAD FOR BYTE OFFSET + LEA 4(A1,D0),A2 ;SET UP DSTLIMIT + MOVE FRACTION(A6),D4 ;GET HORIZONTAL FRACTION + MOVE.L RATIOCASE(A6),A3 ;GET CASE JUMP + JSR (A3) ;AND CALL STRETCHROW + + + +;------------------------------------------------------- +; +; TRANSFER ONE OR MORE COPIES OF DSTBUF INTO DSTBITS +; +NXTMASK MOVE VERT(A6),D0 ;GET CURRENT VERT COORD + CMP MINRECT+TOP(A6),D0 ;IS VERT < MINV ? + BLT.S NODRAW ;YES, DON'T DRAW + + BSR SEEKMASK ;MAKE MASK BUFFER CURRENT + MOVE.L DSTBUF(A6),A3 ;INIT SRCPTR + MOVE.L DSTADDR(A6),A4 ;INIT DSTPTR FOR ROW + MOVE.L MASKBUF(A6),A2 ;INIT MASKPTR FOR ROW + MOVE BUFSIZE(A6),D2 ;INIT COUNT OF LONGS + MOVE.L MODECASE(A6),A0 ;GET MODE CASE JUMP + JMP (A0) ;TAKE MODE JUMP +NEXTDST MOVE.L DSTROW(A6),D0 ;GET DST ROWBYTES + ADD.L D0,DSTADDR(A6) ;BUMP DST TO NEXT ROW + +NODRAW ADD #1,VERT(A6) ;BUMP TO NEXT VERT + MOVE VERT(A6),D0 ;GET VERT + CMP MINRECT+BOTTOM(A6),D0 ;ARE WE AT THE LAST SCAN LINE ? + BEQ.S DONE ;YES, QUIT + MOVE DENOM+V(A6),D0 + SUB D0,VERROR(A6) ;VERROR := VERROR - DENOM.V + BGE NXTMASK ;IF VERROR >= 0 THEN DRAW MORE + BRA NEXTSRC ;ELSE GET NEXT SRC + + +;----------------------------------------------------------------- +; +; ENTIRE STRETCHBITS COMPLETE. RESTORE REGS AND STACK AND GO HOME. +; +DONE JSR SHOWCURSOR ;RESTORE CURSOR +GOHOME MOVE.L SAVESTK(A6),SP ;STRIP VARIABLE SIZED BUFFER + MOVEM.L (SP)+,D0-D7/A1-A4 ;RESTORE REGISTERS + UNLINK PARAMSIZE,'STRETCHB' + + + +;----------------------------------------------------------------- +; +; LOCAL ROUTINE TO UPDATE MASK BUFFER TO CURRENT VERTICAL COORD. +; +SEEKMASK MOVE VERT(A6),D0 ;GET CURRENT VERT COORD + MOVE RECTFLAG(A6),D1 ;GET RECTFLAG = 0,2,4 + MOVE RECTJMP(D1),D1 ;GET OFFSET FROM TABLE + JMP RECTJMP(D1) ;TAKE CASE JUMP + +RECTJMP .WORD SEEKOK-RECTJMP + .WORD A-RECTJMP + .WORD B-RECTJMP + .WORD AB-RECTJMP + .WORD C-RECTJMP + .WORD AC-RECTJMP + .WORD BC-RECTJMP + .WORD ABC-RECTJMP + + +;-------------------------------------------------------------------- +; +; ONLY REGION A IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +A LEA STATEA(A6),A1 + BRA.S JMPSEEK + + +;-------------------------------------------------------------------- +; +; ONLY REGION B IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +B LEA STATEB(A6),A1 + BRA.S JMPSEEK + + +;-------------------------------------------------------------------- +; +; ONLY REGION C IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK +; +C LEA STATEC(A6),A1 +JMPSEEK MOVE.L MASKBUF(A6),SCANBUF(A1) ;PLAY DIRECTLY INTO MASKBUF + JMP SEEKRGN + + +;------------------------------------------------------------------- +; +; REGIONS A AND B ARE NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +AB LEA STATEA(A6),A1 + JSR SEEKRGN + MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED + LEA STATEB(A6),A1 + JSR SEEKRGN + OR (SP)+,D1 ;HAS EITHER RGN CHANGED ? + BEQ.S SEEKOK ;NO, WE'RE DONE + MOVE.L STATEA+SCANBUF(A6),A0 + MOVE.L STATEB+SCANBUF(A6),A1 + BRA.S CPY2BUF + + +;------------------------------------------------------------------- +; +; REGIONS A AND C ARE NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +AC LEA STATEA(A6),A1 + JSR SEEKRGN + MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED + LEA STATEC(A6),A1 + JSR SEEKRGN + OR (SP)+,D1 ;HAS EITHER RGN CHANGED ? + BEQ.S SEEKOK ;NO, WE'RE DONE + MOVE.L STATEA+SCANBUF(A6),A0 + MOVE.L STATEC+SCANBUF(A6),A1 + BRA.S CPY2BUF + + +;------------------------------------------------------------------- +; +; REGIONS B AND C ARE NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +BC LEA STATEB(A6),A1 + JSR SEEKRGN + MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED + LEA STATEC(A6),A1 + JSR SEEKRGN + OR (SP)+,D1 ;HAS EITHER RGN CHANGED ? + BEQ.S SEEKOK ;NO, WE'RE DONE + MOVE.L STATEB+SCANBUF(A6),A0 + MOVE.L STATEC+SCANBUF(A6),A1 +CPY2BUF MOVE.L MASKBUF(A6),A2 + MOVE BUFSIZE(A6),D1 +BCLOOP MOVE.L (A0)+,D0 + AND.L (A1)+,D0 + MOVE.L D0,(A2)+ + DBRA D1,BCLOOP +SEEKOK RTS ;ALL 3 ARE RECT, DO NOTHING + + +;------------------------------------------------------------------- +; +; REGIONS A, B AND C ARE ALL NON-RECTANGULAR. UPDATE EACH, +; THEN FORM INTERSECTION IN THE MASK BUFFER. +; +ABC LEA STATEA(A6),A1 + JSR SEEKRGN + MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED + LEA STATEB(A6),A1 + JSR SEEKRGN + OR D1,(SP) ;REMEMBER IF RGN CHANGED + LEA STATEC(A6),A1 + JSR SEEKRGN + OR (SP)+,D1 ;HAS EITHER RGN CHANGED ? + BEQ.S ABCDONE ;NO, WE'RE DONE + MOVE.L STATEA+SCANBUF(A6),A0 + MOVE.L STATEB+SCANBUF(A6),A1 + MOVE.L STATEC+SCANBUF(A6),A2 + MOVE.L MASKBUF(A6),A3 + MOVE BUFSIZE(A6),D1 +ABCLOOP MOVE.L (A0)+,D0 + AND.L (A1)+,D0 + AND.L (A2)+,D0 + MOVE.L D0,(A3)+ + DBRA D1,ABCLOOP +ABCDONE RTS + + + + +;---------------------------------------------------------------; +; ; +; INTERFACE TO EACH OF THE STRETCHBITS SCANLINE LOOPS: ; +; ; +; REGISTERS: A0: D0: ; +; A1: D1: ; +; A2: MASKPTR D2: LONGCNT ; +; A3: SRCPTR D3: ; +; A2: DSTPTR D4: ; +; A4: D5: SRCSHIFT ; +; A6: D6: DSTSHIFT ; +; A7: D7: INVERT ; +; ; +;---------------------------------------------------------------; + +;------------------------------------------------------- +; +; MODE 0 OR 4: SRC --> DST +; +MASK0 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP + LSR.L D6,D0 ;ALIGN TO DST + SWAP D0 ;PUT INTO HI HALF OF D0 + MOVE.L (A3)+,D1 ;GET SRC FROM BITMAP AND BUMP RIGHT + LSR.L D6,D1 ;ALIGN TO DST + MOVE D1,D0 ;ASSEMBLE ONE LONG + EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET + MOVE.L (A2)+,D1 ;GET MASK + AND.L D1,D0 ;MASK SRC + NOT.L D1 ;FORM NOTMASK + AND.L (A4),D1 ;GET DST DATA + OR.L D1,D0 ;MERGE WITH SRC DATA + MOVE.L D0,(A4)+ ;PUT RESULT IN DST + DBRA D2,MASK0 ;LOOP ALL LONGS THIS ROW + BRA NEXTDST ;GO FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 1 OR 5: SRC OR DST --> DST +; +MASK1 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP + LSR.L D6,D0 ;ALIGN TO DST + SWAP D0 ;PUT INTO HI HALF OF D0 + MOVE.L (A3)+,D1 ;GET SRC FROM BITMAP + LSR.L D6,D1 ;ALIGN TO DST + MOVE D1,D0 ;ASSEMBLE ONE LONG + EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND.L (A2)+,D0 ;AND WITH MASK + OR.L D0,(A4)+ ;OR RESULT INTO DST + DBRA D2,MASK1 ;LOOP ALL LONGS THIS ROW + BRA NEXTDST ;LOOP FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 2 OR 6: SRC XOR DST --> DST +; +MASK2 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP + LSR.L D6,D0 ;ALIGN TO DST + SWAP D0 ;PUT INTO HI HALF OF D0 + MOVE.L (A3)+,D1 ;GET SRC FROM BITMAP + LSR.L D6,D1 ;ALIGN TO DST + MOVE D1,D0 ;ASSEMBLE ONE LONG + EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND.L (A2)+,D0 ;AND WITH MASK + EOR.L D0,(A4)+ ;XOR RESULT INTO DST + DBRA D2,MASK2 ;LOOP ALL LONGS THIS ROW + BRA NEXTDST ;LOOP FOR NEXT ROW + + +;------------------------------------------------------- +; +; MODE 3 OR 7: SRC BIC DST --> DST +; +MASK3 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP + LSR.L D6,D0 ;ALIGN TO DST + SWAP D0 ;PUT INTO HI HALF OF D0 + MOVE.L (A3)+,D1 ;GET SRC FROM BITMAP + LSR.L D6,D1 ;ALIGN TO DST + MOVE D1,D0 ;ASSEMBLE ONE LONG + EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET + AND.L (A2)+,D0 ;AND WITH MASK + NOT.L D0 ;INVERT FOR BIC + AND.L D0,(A4)+ ;BIC RESULT INTO DST + DBRA D2,MASK3 ;LOOP ALL LONGS THIS ROW + BRA NEXTDST ;LOOP FOR NEXT ROW + + + +MODETAB .BYTE MODETAB-MASK0 + .BYTE MODETAB-MASK1 + .BYTE MODETAB-MASK2 + .BYTE MODETAB-MASK3 + + + + .PROC SetupStretch +;-------------------------------------------------------------- +; +; Routine to setup case jump for StretchRow, +; based on horiz numer and denom. +; +; Call SetupStretch with numer in D0, denom in D1. +; Returns case jump in A0, fraction in D0. +; +; Call resulting case jump with: +; +; A0: srcPtr +; A1: dstPtr +; A2: dstLimit +; D4: fraction +; +; clobbers D0-D3,A0-A1 +; + LEA DONE,A0 ;POINT TO ABORT + TST D0 ;IS NUMER <= 0 ? + BLE FOUND ;YES, POINT TO ABORT + TST D1 ;IS DENOM <= 0 ? + BLE FOUND ;YES, POINT TO ABORT + LEA ONE,A0 ;POINT TO FAST COPY + CMP D1,D0 ;IS NUMER = DENOM ? + BEQ FOUND ;YES, USE FAST COPY + BLT.S SHRNKING ;NO, BRANCH IF SHRINKING +; +; We will be stretching. Calc fract = denom/numer and check for fast. +; +STRCHING MOVE D0,D3 ;MAKE A COPY OF NUMER + MOVE D1,D4 ;MAKE A COPY OF DENOM + CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE D1,-(SP) ;PUSH DENOM + MOVE D0,-(SP) ;PUSH NUMER + _FixRatio ;CALL FIXRATIO, < 1.0 + MOVE.L (SP)+,D0 ;POP RESULT + LEA DOUBLE,A0 ;CHECK FOR FAST RATIOS + CMP #$8000,D0 + BEQ.S FOUND + LEA QUAD,A0 + CMP #$4000,D0 + BEQ.S FOUND + LEA EIGHT,A0 + CMP #$2000,D0 + BEQ.S FOUND + LEA SIXTEEN,A0 + CMP #$1000,D0 + BEQ.S FOUND + LEA ONE.5,A0 + CMP #$AAAA,D0 + BEQ.S FOUND + LEA TRIPLE,A0 + CMP #$5555,D0 + BEQ.S FOUND + LEA SIX,A0 + CMP #$2AAA,D0 + BEQ.S FOUND +; +; check for any multiple of 8: +; + EXT.L D3 ;CLEAR HI WORD OF NUMER + DIVU D4,D3 ;CALC NUMER DIV DENOM + MOVE D3,D1 ;SAVE QUOTIENT + AND.L #$FFFF0007,D3 ;IS SCALE AN EVEN MULT OF 8 ? + BNE.S NOMATCH ;NO, USE GENERAL STRETCH + MOVE D1,D0 ;YES RETURN QUOTIENT IN D0 + LEA EIGHTS,A0 ;POINT TO FAST ROUTINE + RTS ;AND RETURN +NOMATCH LEA STRETCH,A0 ;POINT TO SLOW GENERAL CODE +FOUND RTS ;RETURN WITH CASE JUMP IN A0 + + +; +; We will be shrinking. Calc fract = numer/denom and check for fast. +; +SHRNKING CLR.L -(SP) ;ROOM FOR FCN RESULT + MOVE D0,-(SP) ;PUSH NUMER + MOVE D1,-(SP) ;PUSH DENOM + _FixRatio ;CALL FIXRATIO, < 1.0 + MOVE.L (SP)+,D0 ;POP RESULT + LEA HALF,A0 ;CHECK FOR FAST RATIOS + CMP #$8000,D0 + BEQ.S FOUND + LEA QRTR,A0 + CMP #$4000,D0 + BEQ.S FOUND + LEA THREE4,A0 + CMP #$C000,D0 + BEQ.S FOUND + LEA SHRINK,A0 + BRA FOUND + + + +;----------------------------------------------- +; +; NUMERATOR = DENOMINATOR, JUST COPY LONGS +; +ONE MOVE.L (A0)+,(A1)+ ;COPY ONE LONG + MOVE.L (A0)+,(A1)+ ;COPY ANOTHER LONG + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO ONE ;NO, LOOP FOR MORE + RTS ;ALL DONE + + +;--------------------------------------------------- +; +; SHRINK TO THREE QUARTERS. +; +THREE4 MOVEQ #3,D3 ;MASK FOR HI 2 BITS + ROR.L #2,D3 ;IE. $C0000000 + CLR.L -(SP) ;ALLOCATE A LONG OF TEMP +THREE4A MOVE.L (A0)+,D0 ;GET A LONG OF SRC + MOVEQ #7,D2 ;INIT COUNT OF 24 DST BITS +THREE4B ADD.L D0,D0 ;GET 1 BIT OF SRC + ADDX.L D1,D1 ;PUT 1 BIT TO DST + ADD.L D3,D0 ;PUT HI 2 BITS INTO CARRY + ADDX.L D1,D1 ;SHIFT INTO DST + LSL.L #3,D0 ;SHIFT LEFT 3 BITS + ADDX.L D1,D1 ;PUT CARRY BIT INTO DST + DBRA D2,THREE4B ;LOOP 8 TIMES + MOVE.L D1,(SP) ;STASH 3 DST BYTES IN TEMP + MOVE.B 1(SP),(A1)+ ;PUT FIRST BYTE TO DST + MOVE.B 2(SP),(A1)+ ;PUT SECOND BYTE TO DST + MOVE.B 3(SP),(A1)+ ;PUT THIRD BYTE TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO THREE4A ;NO, CONTINUE + ADD #4,SP ;YES, STRIP TEMP + RTS ;AND QUIT + + +;--------------------------------------------------- +; +; SHRINK TO ONE HALF. +; +HALF MOVEQ #3,D3 ;MASK FOR HI 2 BITS + ROR.L #2,D3 ;IE. $C0000000 +HALF1 MOVE.L (A0)+,D0 ;GET A LONG OF SRC + MOVEQ #7,D2 ;INIT COUNT OF 16 DST BITS +HALF2 ADD.L D3,D0 ;PUT OR OF HI BITS INTO CARRY + ADDX D1,D1 ;SHIFT BIT INTO DST + LSL.L #2,D0 ;SHIFT LEFT 2 BITS + ADD.L D3,D0 ;PUT OR OF HI BITS INTO CARRY + ADDX.L D1,D1 ;SHIFT BIT INTO DST + LSL.L #2,D0 ;SHIFT LEFT 2 BITS + DBRA D2,HALF2 ;LOOP 8 TIMES + MOVE D1,(A1)+ ;THEN PUT A WORD TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO HALF1 ;NO, CONTINUE + RTS ;YES, QUIT + + +;--------------------------------------------------- +; +; SHRINK TO ONE QUARTER. +; +QRTR MOVE.L #$F0000000,D3 ;MASK FOR HI 4 BITS +QRTR1 MOVE.L (A0)+,D0 ;GET A LONG OF SRC + MOVEQ #7,D2 ;INIT COUNT OF 8 DST BITS +QRTR2 ADD.L D3,D0 ;PUT OR OF HI BITS INTO CARRY + ADDX.L D1,D1 ;SHIFT BIT INTO DST + LSL.L #4,D0 ;SHIFT LEFT 4 BITS + DBRA D2,QRTR2 ;LOOP 8 TIMES + MOVE.B D1,(A1)+ ;THEN PUT A BYTE TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO QRTR1 ;NO, CONTINUE + RTS ;YES, QUIT + + +;----------------------------------------------- +; +; STRETCH TO 1.5 TIMES AS WIDE +; +ONE.5 MOVE.B (A0)+,D0 ;GET FIRST BYTE FROM SRC + MOVE D0,D1 ;MAKE AN EXTRA COPY + LSR.B #4,D1 ;GET HI NIBBLE + MOVE.B TABLE15(D1),D2 ;EXPAND TO 6 BITS + LSL.L #6,D2 ;SHIFT OVER 6 + AND #$F,D0 ;GET LO NIBBLE + MOVE.B TABLE15(D0),D2 ;EXPAND TO 6 BITS + LSL.L #6,D2 ;SHIFT OVER 6 + MOVE.B (A0)+,D0 ;GET SECOND BYTE FROM SRC + MOVE D0,D1 ;MAKE AN EXTRA COPY + LSR.B #4,D1 ;GET HI NIBBLE + MOVE.B TABLE15(D1),D2 ;EXPAND TO 6 BITS + LSL.L #6,D2 ;SHIFT OVER 6 + AND #$F,D0 ;GET LO NIBBLE + MOVE.B TABLE15(D0),D2 ;EXPAND TO 6 BITS + LSR.L #2,D2 ;RIGHT JUSTIFY + SWAP D2 ;FLIP WORDS + MOVE.B D2,(A1)+ ;PUT FIRST BYTE TO DST + SWAP D2 ;FLIP BACK AGAIN + MOVE D2,D1 + ROR #8,D1 + MOVE.B D1,(A1)+ ;PUT SECOND BYTE TO DST + MOVE.B D2,(A1)+ ;PUT THIRD BYTE TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO ONE.5 ;NO, LOOP FOR MORE + RTS ;ALL DONE + +TABLE15 .BYTE $00,$0C,$10,$1C ;1.5 TIMES TABLE + .BYTE $60,$6C,$70,$7C + .BYTE $80,$8C,$90,$9C + .BYTE $E0,$EC,$F0,$FC + + +;----------------------------------------------- +; +; DOUBLE USING TABLE LOOKUP +; +DOUBLE MOVE.B (A0)+,D0 ;GET A BYTE FROM SRC + MOVE D0,D1 ;MAKE AN EXTRA COPY + LSR.B #4,D1 ;GET HI NIBBLE + MOVE.B TABLE2(D1),(A1)+ ;DOUBLE FOR A BYTE + AND #$F,D0 ;GET LO NIBBLE + MOVE.B TABLE2(D0),(A1)+ ;DOUBLE FOR A BYTE + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO DOUBLE ;NO, LOOP FOR MORE + RTS ;ALL DONE + +TABLE2 .BYTE $00,$03,$0C,$0F ;DOUBLING TABLE + .BYTE $30,$33,$3C,$3F + .BYTE $C0,$C3,$CC,$CF + .BYTE $F0,$F3,$FC,$FF + + +;----------------------------------------------- +; +; TRIPLE USING TABLE LOOKUP +; +TRIPLE MOVE.B (A0)+,D0 ;GET A BYTE FROM SRC + MOVE D0,D1 ;MAKE AN EXTRA COPY + MOVE D0,D2 ;MAKE A THIRD COPY + LSR.B #5,D2 ;GET 3 HI BITS + MOVE.B TABLE3A(D2),(A1)+ ;PUT FIRST BYTE TO DST + LSR.B #2,D1 + AND #$F,D1 ;GET MIDDLE 4 BITS + MOVE.B TABLE3B(D1),(A1)+ ;PUT SECOND BYTE TO DST + AND #$7,D0 ;GET 3 LO BITS + MOVE.B TABLE3C(D0),(A1)+ ;PUT THIRD BYTE TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO TRIPLE ;NO, LOOP FOR MORE + RTS ;ALL DONE + +TABLE3A .BYTE $00,$03,$1C,$1F ;TRIPLING TABLE + .BYTE $E0,$E3,$FC,$FF +TABLE3B .BYTE $00,$01,$0E,$0F + .BYTE $70,$71,$7E,$7F + .BYTE $80,$81,$8E,$8F + .BYTE $F0,$F1,$FE,$FF +TABLE3C .BYTE $00,$07,$38,$3F + .BYTE $C0,$C7,$F8,$FF + + + +;----------------------------------------------- +; +; QUADRUPLE USING TABLE LOOKUP +; +QUAD MOVE.B (A0)+,D0 ;GET A BYTE FROM SRC + MOVE D0,D1 ;MAKE AN EXTRA COPY + AND #$F0,D1 ;MASK FOR HI NIBBLE + LSR #3,D1 ;SHIFT FOR TABLE INDEX + MOVE.W TABLE4(D1),(A1)+ ;PUT FIRST WORD TO DST + AND #$F,D0 ;MASK FOR LO NIBBLE + ADD D0,D0 ;DOUBLE FOR TABLE INDEX + MOVE.W TABLE4(D0),(A1)+ ;PUT SECOND WORD TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO QUAD ;NO, LOOP FOR MORE + RTS ;ALL DONE + +TABLE4 .WORD $0000,$000F,$00F0,$00FF ;QUADRUPLING TABLE + .WORD $0F00,$0F0F,$0FF0,$0FFF + .WORD $F000,$F00F,$F0F0,$F0FF + .WORD $FF00,$FF0F,$FFF0,$FFFF + +;----------------------------------------------- +; +; STRETCH BY SIX USING TABLE LOOKUP +; +SIX MOVE.B (A0)+,D0 ;GET A BYTE FROM SRC + MOVE D0,D1 ;MAKE AN EXTRA COPY + AND #$E0,D1 ;MASK FOR HI 3 BITS + LSR.B #4,D1 ;SHIFT FOR TABLE INDEX + MOVE.W TABLE6A(D1),(A1)+ ;PUT A WORD TO DST + MOVE D0,D1 ;GET SRC BYTE AGAIN + AND #$3C,D1 ;MASK FOR MIDDLE 4 BITS + LSR.B #1,D1 ;SHIFT FOR TABLE INDEX + MOVE.W TABLE6B(D1),(A1)+ ;PUT A WORD TO DST + MOVE D0,D1 ;GET SRC BYTE AGAIN + AND #7,D1 ;MASK FOR LO 3 BITS + ADD D1,D1 ;DOUBLE FOR TABLE INDEX + MOVE.W TABLE6C(D1),(A1)+ ;PUT A WORD TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO SIX ;NO, LOOP FOR MORE + RTS ;ALL DONE + +TABLE6A .WORD $0000,$000F,$03F0,$03FF ;SIX TIMES TABLE + .WORD $FC00,$FC0F,$FFF0,$FFFF +TABLE6B .WORD $0000,$0003,$00FC,$00FF + .WORD $3F00,$3F03,$3FFC,$3FFF + .WORD $C000,$C003,$C0FC,$C0FF + .WORD $FF00,$FF03,$FFFC,$FFFF +TABLE6C .WORD $0000,$003F,$0FC0,$0FFF + .WORD $F000,$F03F,$FFC0,$FFFF + + + +;----------------------------------------------- +; +; SCALE UP BY EIGHT USING TABLE LOOKUP +; +EIGHT MOVE.B (A0)+,D0 ;GET A BYTE OF SRC + MOVE D0,D1 ;MAKE AN EXTRA COPY + AND #$F0,D1 ;MASK FOR HI NIBBLE + LSR #2,D1 ;SHIFT FOR TABLE INDEX + MOVE.L TABLE8(D1),(A1)+ ;PUT FIRST LONG TO DST + AND #$0F,D0 ;MASK FOR LO NIBBLE + LSL #2,D0 ;SHIFT FOR TABLE INDEX + MOVE.L TABLE8(D0),(A1)+ ;PUT SECOND LONG TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO EIGHT ;NO, GO FOR MORE + RTS ;ALL DONE + +TABLE8 .LONG $00000000,$000000FF,$0000FF00,$0000FFFF + .LONG $00FF0000,$00FF00FF,$00FFFF00,$00FFFFFF + .LONG $FF000000,$FF0000FF,$FF00FF00,$FF00FFFF + .LONG $FFFF0000,$FFFF00FF,$FFFFFF00,$FFFFFFFF + + +;------------------------------------------------- +; +; SCALE UP BY 16 +; +SIXTEEN MOVEQ #-1,D1 ;GET SOME BLACK + MOVE #$8000,D0 ;INIT SRC DATA +SIXTENA ADD D0,D0 ;GET ONE BIT OF SRC + BCC.S WHITE16 ;BR IF WHITE + BNE.S BLACK16 ;BR IF BLACK + MOVE (A0)+,D0 ;ELSE GET NEXT SRC WORD + ADDX D0,D0 ;SHIFT SRC BIT OUT, 1 BIT IN + BCS.S BLACK16 ;BR IF BLACK +WHITE16 CLR.W (A1)+ ;PUT A WORD OF WHITE TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO SIXTENA ;NO, GO FOR MORE + RTS ;ALL DONE +BLACK16 MOVE D1,(A1)+ ;PUT A WORD OF BLACK TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + BLO SIXTENA ;NO, GO FOR MORE + RTS ;ALL DONE + + +;----------------------------------------------- +; +; SCALE UP BY ANY MULTIPLE OF 8 GREATER THAN 2 +; +EIGHTS LSR #3,D4 ;DIVIDE SCALE FACTOR BY 8 + SUB #1,D4 ;SUB 1 FOR LOOP COUNT + MOVE #$8000,D0 ;INIT SRC DATA +EIGHTS1 ADD D0,D0 ;GET ONE SRC BIT IN CARRY + BNE.S EIGHTS2 ;TIME FOR NEW SRC ? + MOVE (A0)+,D0 ;YES, GET NEXT SRC LONG + ADDX D0,D0 ;SHIFT SRC BIT OUT, 1 BIT IN +EIGHTS2 SCS D1 ;SET OR CLR A BYTE + MOVE D4,D2 ;INIT LOOP COUNT +EIGHTS3 MOVE.B D1,(A1)+ ;PUT ONE BYTE TO DST + CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ? + DBHI D2,EIGHTS3 ;LOOP TILL SCALE OR DST FULL + BLS EIGHTS1 ;MORE SRC IF DST NOT FULL + BRA.S DONE ;THEN QUIT + + + +;------------------------------------------------------------------ +; +; DO FULL RATIO SCALING, SHRINKING ONE BIT AT A TIME +; +SHRINK CLR D1 ;INIT DST WORD + MOVE #$8000,D0 ;INIT SRC WORD + MOVE D0,D2 ;INIT MASK + MOVE D4,D3 ;COPY RATIO + LSR #1,D3 ;INIT ERR TO RATIO/2 + +NXTSRC1 ADD D0,D0 ;GET SRC BIT + BCC.S WHITE1 ;BRANCH IF WHITE + BNE.S BLACK1 ;BRANCH IF BLACK + MOVE (A0)+,D0 ;ELSE GET NEW SRC WORD + ADDX D0,D0 ;GET SRC BIT + BCC.S WHITE1 ;AND CONTINUE + +BLACK1 OR D2,D1 ;SET A BIT IN DST +WHITE1 ADD D4,D3 ;TIME FOR NEXT DSTBIT ? + BCC NXTSRC1 ;NO, LOOP MORE SRC + ROR #1,D2 ;YES, ROTATE MASK + BCC NXTSRC1 ;LOOP IF DST WORD OK + MOVE D1,(A1)+ ;ELSE WRITE WORD TO DST + CLR D1 ;RESET DST WORD + CMP.L A2,A1 ;DSTPTR >= DSTLIMIT ? + BLO NXTSRC1 ;NO, LOOP + RTS ;YES, QUIT + + + +;------------------------------------------------------------------ +; +; DO FULL RATIO SCALING, STRETCHING ONE BIT AT A TIME +; +STRETCH CLR D1 ;INIT DST WORD + MOVE #$8000,D0 ;INIT SRC WORD + MOVE D0,D2 ;INIT MASK + MOVE D4,D3 ;COPY RATIO + LSR #1,D3 ;INIT ERR TO RATIO/2 + +NXTSRC2 ADD D0,D0 ;GET SRC BIT + BCC.S WHITE2 ;BRANCH IF WHITE + BNE.S BLACK2 ;BRANCH IF BLACK + MOVE (A0)+,D0 ;ELSE GET NEW SRC WORD + ADDX D0,D0 ;GET SRC BIT + BCC.S WHITE2 ;CONTINUE WITH WHITE + BRA.S BLACK2 ;CONTINUE WITH BLACK + +BLACKOK ADD D4,D3 ;TIME FOR NEXT SRC BIT ? + BCS NXTSRC2 ;YES, LOOP FOR SRC +BLACK2 OR D2,D1 ;SET A BIT OF DST + ROR #1,D2 ;ROTATE MASK + BCC BLACKOK ;LOOP IF DST WORD OK + MOVE D1,(A1)+ ;ELSE WRITE WORD TO DST + CLR D1 ;RESET DST WORD + CMP.L A2,A1 ;DSTPTR >= DSTLIMIT ? + BLO BLACKOK ;NO, LOOP + RTS ;YES, QUIT + +WHITEOK ADD D4,D3 ;TIME FOR NEXT SRC BIT ? + BCS NXTSRC2 ;YES, LOOP FOR SRC +WHITE2 ROR #1,D2 ;ROTATE MASK + BCC WHITEOK ;LOOP IF DST WORD OK + MOVE D1,(A1)+ ;ELSE WRITE WORD TO DST + CLR D1 ;RESET DST WORD + CMP.L A2,A1 ;DSTPTR >= DSTLIMIT ? + BLO WHITEOK ;NO, LOOP + +DONE RTS + + + + + .END diff --git a/TestGraf.p b/TestGraf.p new file mode 100755 index 0000000..9a125fd --- /dev/null +++ b/TestGraf.p @@ -0,0 +1,971 @@ +PROGRAM TestGraf; + +{ Quick Checkout for QuickDraw } + +USES {$U obj:QuickDraw } QuickDraw, + {$U obj:QDSupport } QDSupport, + {$U obj:GrafUtil } GrafUtil; + +LABEL 1; + +CONST heapSize = $10000; { 64k bytes } + +TYPE IconData = ARRAY[0..95] OF INTEGER; + +VAR heapStart: QDPtr; + heapLimit: QDPtr; + port1: GrafPtr; + tempRect: Rect; + myPoly: PolyHandle; + myRgn: RgnHandle; + myPattern: Pattern; + myPicture: PicHandle; + bigPicture: PicHandle; + icons: ARRAY[0..5] OF IconData; + i,errNum: INTEGER; + numerArray: ARRAY[0..30] OF INTEGER; + denomArray: ARRAY[0..30] OF INTEGER; + srcRect: Rect; + dstRect: Rect; + ch: CHAR; + + + +FUNCTION HeapError(hz: QDPtr; bytesNeeded: INTEGER): INTEGER; +{ this function will be called if the heapZone runs out of space } +BEGIN + WRITELN('The heap is full. User Croak !! '); + Halt; +END; + + +PROCEDURE InitIcons; +{ Manually stuff some icons. Normally we would read them from a file } +BEGIN + { Lisa } + StuffHex(@icons[0, 0],'000000000000000000000000000000000000001FFFFFFFFC'); + StuffHex(@icons[0,12],'00600000000601800000000B0600000000130FFFFFFFFFA3'); + StuffHex(@icons[0,24],'18000000004311FFFFF00023120000080F231200000BF923'); + StuffHex(@icons[0,36],'120000080F23120000080023120000080023120000080F23'); + StuffHex(@icons[0,48],'1200000BF923120000080F2312000008002311FFFFF00023'); + StuffHex(@icons[0,60],'08000000004307FFFFFFFFA30100000000260FFFFFFFFE2C'); + StuffHex(@icons[0,72],'18000000013832AAAAA8A9F0655555515380C2AAAA82A580'); + StuffHex(@icons[0,84],'800000000980FFFFFFFFF300800000001600FFFFFFFFFC00'); + + { Printer } + StuffHex(@icons[1, 0],'000000000000000000000000000000000000000000000000'); + StuffHex(@icons[1,12],'00000000000000007FFFFF00000080000280000111514440'); + StuffHex(@icons[1,24],'0002000008400004454510400004000017C00004A5151000'); + StuffHex(@icons[1,36],'0004000010000004A54510000004000017FE00F4A5151003'); + StuffHex(@icons[1,48],'0184000013870327FFFFF10F06400000021B0CFFFFFFFC37'); + StuffHex(@icons[1,60],'18000000006B3000000000D77FFFFFFFFFABC00000000356'); + StuffHex(@icons[1,72],'8000000001AC87F000000158841000CCC1B087F000CCC160'); + StuffHex(@icons[1,84],'8000000001C0C000000003807FFFFFFFFF0007800001E000'); + + { Trash Can } + StuffHex(@icons[2, 0],'000001FC000000000E0600000000300300000000C0918000'); + StuffHex(@icons[2,12],'00013849800000026C4980000004C0930000000861260000'); + StuffHex(@icons[2,24],'0010064FE0000031199830000020E6301800002418E00800'); + StuffHex(@icons[2,36],'0033E3801C0000180E002C00000FF801CC0000047FFE0C00'); + StuffHex(@icons[2,48],'000500004C000005259A4C000005250A4C00000525FA4C00'); + StuffHex(@icons[2,60],'000524024C00000524924C00600524924C0090E524924C7C'); + StuffHex(@icons[2,72],'932524924C82A44524924D01C88524924CF10C4524924C09'); + StuffHex(@icons[2,84],'0784249258E70003049233100000E000E40800001FFFC3F0'); + + { tray } + StuffHex(@icons[3, 0],'000000000000000000000000000000000000000000000000'); + StuffHex(@icons[3,12],'0000000000000000000000000000000000000007FFFFFFF0'); + StuffHex(@icons[3,24],'000E00000018001A00000038003600000078006A000000D8'); + StuffHex(@icons[3,36],'00D7FFFFFFB801AC000003580358000006B807FC000FFD58'); + StuffHex(@icons[3,48],'040600180AB80403FFF00D58040000000AB8040000000D58'); + StuffHex(@icons[3,60],'040000000AB807FFFFFFFD5806AC00000AB8055800000D58'); + StuffHex(@icons[3,72],'06B000000AB807FC000FFD70040600180AE00403FFF00DC0'); + StuffHex(@icons[3,84],'040000000B80040000000F00040000000E0007FFFFFFFC00'); + + { File Cabinet } + StuffHex(@icons[4, 0],'0007FFFFFC00000800000C00001000001C00002000003400'); + StuffHex(@icons[4,12],'004000006C0000FFFFFFD40000800000AC0000BFFFFED400'); + StuffHex(@icons[4,24],'00A00002AC0000A07F02D40000A04102AC0000A07F02D400'); + StuffHex(@icons[4,36],'00A00002AC0000A08082D40000A0FF82AC0000A00002D400'); + StuffHex(@icons[4,48],'00A00002AC0000BFFFFED40000800000AC0000BFFFFED400'); + StuffHex(@icons[4,60],'00A00002AC0000A07F02D40000A04102AC0000A07F02D400'); + StuffHex(@icons[4,72],'00A00002AC0000A08082D40000A0FF82AC0000A00002D800'); + StuffHex(@icons[4,84],'00A00002B00000BFFFFEE00000800000C00000FFFFFF8000'); + + { drawer } + StuffHex(@icons[5, 0],'000000000000000000000000000000000000000000000000'); + StuffHex(@icons[5,12],'000000000000000000000000000000000000000000000000'); + StuffHex(@icons[5,24],'000000000000000000000000000000000000000000000000'); + StuffHex(@icons[5,36],'00000000000000000000000000000000000000001FFFFFF0'); + StuffHex(@icons[5,48],'0000380000300000680000700000D80000D0003FFFFFF1B0'); + StuffHex(@icons[5,60],'0020000013500020000016B000201FE01D50002010201AB0'); + StuffHex(@icons[5,72],'00201FE01560002000001AC0002000001580002020101B00'); + StuffHex(@icons[5,84],'00203FF01600002000001C00002000001800003FFFFFF000'); + +END; + + +PROCEDURE DrawIcon(whichIcon,h,v: INTEGER); +VAR srcBits: BitMap; + srcRect,dstRect: Rect; +BEGIN + srcBits.baseAddr:=@icons[whichIcon]; + srcBits.rowBytes:=6; + SetRect(srcBits.bounds,0,0,48,32); + srcRect:=srcBits.bounds; + + dstRect:=srcRect; + OffsetRect(dstRect,h,v); + CopyBits(srcBits,thePort^.portBits,srcRect,dstRect,srcOr,Nil); +END; + + +PROCEDURE DrawStuff; +VAR i: INTEGER; + tempRect: Rect; + srcRect: Rect; + dstRect: Rect; + + dataPtr: QDPtr; + tempStr: Str255; + +BEGIN + BackColor(whiteColor); + ForeColor(blackColor); + + { test comments } + PicComment(100,0,Nil); + tempStr := 'Hello Test'; + dataPtr := @tempStr; + PicComment(200,11,@dataPtr); + + + tempRect := thePort^.portRect; + ClipRect(tempRect); + EraseRoundRect(tempRect,30,20); + FrameRoundRect(tempRect,30,20); + + { draw two horizontal lines across the top } + MoveTo(0,18); + LineTo(719,18); + MoveTo(0,20); + LineTo(719,20); + + { draw divider lines } + MoveTo(0,134); + LineTo(719,134); + MoveTo(0,248); + LineTo(719,248); + MoveTo(240,21); + LineTo(240,363); + MoveTo(480,21); + LineTo(480,363); + + { draw title } + TextFont(0); + MoveTo(210,14); + DrawString('Look what you can draw with QuickDraw'); + + + + {--------- draw text samples --------- } + + ForeColor(redColor); + MoveTo(80,34); DrawString('Red'); + + ForeColor(greenColor); + TextFace([bold]); + MoveTo(70,55); DrawString('Green'); + + ForeColor(blueColor); + TextFace([italic]); + MoveTo(70,70); DrawString('Blue'); + + ForeColor(cyanColor); + TextFace([underline]); + MoveTo(70,85); DrawString('Cyan'); + + ForeColor(magentaColor); + TextFace([outline]); + MoveTo(70,100); DrawString('Magenta'); + + ForeColor(yellowColor); + TextFace([shadow]); + MoveTo(70,115); DrawString('Yellow'); + + TextFace([]); { restore to normal } + + + + { --------- draw line samples --------- } + + ForeColor(blackColor); + MoveTo(330,34); DrawString('Lines'); + + ForeColor(redColor); + MoveTo(280,25); Line(160,40); + + ForeColor(greenColor); + PenSize(3,2); + MoveTo(280,35); Line(160,40); + + ForeColor(blueColor); + PenSize(6,4); + MoveTo(280,46); Line(160,40); + + ForeColor(cyanColor); + PenSize(12,8); + PenPat(gray); + MoveTo(280,61); Line(160,40); + + ForeColor(magentaColor); + PenSize(15,10); + PenPat(myPattern); + MoveTo(280,80); Line(160,40); + PenNormal; + + + + { --------- draw rectangle samples --------- } + + ForeColor(blackColor); + MoveTo(560,34); DrawString('Rectangles'); + + ForeColor(redColor); + SetRect(tempRect,510,40,570,70); + FrameRect(tempRect); + + ForeColor(greenColor); + OffsetRect(tempRect,25,15); + PenSize(3,2); + EraseRect(tempRect); + FrameRect(tempRect); + + ForeColor(blueColor); + OffsetRect(tempRect,25,15); + PaintRect(tempRect); + + ForeColor(cyanColor); + OffsetRect(tempRect,25,15); + PenNormal; + FillRect(tempRect,gray); + FrameRect(tempRect); + + ForeColor(magentaColor); + OffsetRect(tempRect,25,15); + FillRect(tempRect,myPattern); + FrameRect(tempRect); + + + { --------- draw roundRect samples --------- } + + ForeColor(blackColor); + MoveTo(70,148); DrawString('RoundRects'); + + ForeColor(redColor); + SetRect(tempRect,30,150,90,180); + FrameRoundRect(tempRect,30,20); + + ForeColor(greenColor); + OffsetRect(tempRect,25,15); + PenSize(3,2); + EraseRoundRect(tempRect,30,20); + FrameRoundRect(tempRect,30,20); + + ForeColor(blueColor); + OffsetRect(tempRect,25,15); + PaintRoundRect(tempRect,30,20); + + ForeColor(cyanColor); + OffsetRect(tempRect,25,15); + PenNormal; + FillRoundRect(tempRect,30,20,gray); + FrameRoundRect(tempRect,30,20); + + ForeColor(magentaColor); + OffsetRect(tempRect,25,15); + FillRoundRect(tempRect,30,20,myPattern); + FrameRoundRect(tempRect,30,20); + + + { --------- draw bitmap samples --------- } + + ForeColor(blackColor); + MoveTo(320,148); DrawString('BitMaps'); + + ForeColor(redColor); + DrawIcon(0,266,156); + ForeColor(greenColor); + DrawIcon(1,336,156); + ForeColor(blueColor); + DrawIcon(2,406,156); + ForeColor(cyanColor); + DrawIcon(3,266,196); + ForeColor(magentaColor); + DrawIcon(4,336,196); + ForeColor(yellowColor); + DrawIcon(5,406,196); + + + { --------- draw ARC samples --------- } + + ForeColor(blackColor); + MoveTo(570,148); DrawString('Arcs'); + + SetRect(tempRect,520,153,655,243); + ForeColor(redColor); + FillArc(tempRect,135,65,dkGray); + ForeColor(greenColor); + FillArc(tempRect,200,130,myPattern); + ForeColor(blueColor); + FillArc(tempRect,330,75,gray); + ForeColor(cyanColor); + FrameArc(tempRect,135,270); + OffsetRect(tempRect,20,0); + ForeColor(magentaColor); + PaintArc(tempRect,45,90); + + + { --------- draw polygon samples --------- } + + ForeColor(blackColor); + MoveTo(80,262); DrawString('Polygons'); + + myPoly:=OpenPoly; + MoveTo(30,290); + LineTo(30,280); + LineTo(50,265); + LineTo(90,265); + LineTo(80,280); + LineTo(95,290); + LineTo(30,290); + ClosePoly; { end of definition } + + ForeColor(redColor); + FramePoly(myPoly); + + ForeColor(greenColor); + OffsetPoly(myPoly,25,15); + PenSize(3,2); + ErasePoly(myPoly); + FramePoly(myPoly); + + ForeColor(blueColor); + OffsetPoly(myPoly,25,15); + PaintPoly(myPoly); + + ForeColor(cyanColor); + OffsetPoly(myPoly,25,15); + PenNormal; + FillPoly(myPoly,gray); + FramePoly(myPoly); + + ForeColor(magentaColor); + OffsetPoly(myPoly,25,15); + FillPoly(myPoly,myPattern); + FramePoly(myPoly); + + KillPoly(myPoly); + +(* + + { --------- draw region samples --------- } + + ForeColor(blackColor); + MoveTo(80,262); DrawString('Regions'); + + myRgn := NewRgn; + OpenRgn; + MoveTo(30,290); + LineTo(30,280); + LineTo(50,265); + LineTo(90,265); + LineTo(80,280); + LineTo(95,290); + LineTo(30,290); + CloseRgn(myRgn); { end of definition } + + ForeColor(redColor); + FrameRgn(myRgn); + + ForeColor(greenColor); + OffsetRgn(myRgn,25,15); + PenSize(3,2); + EraseRgn(myRgn); + FrameRgn(myRgn); + + ForeColor(blueColor); + OffsetRgn(myRgn,25,15); + PaintRgn(myRgn); + + ForeColor(cyanColor); + OffsetRgn(myRgn,25,15); + PenNormal; + FillRgn(myRgn,gray); + FrameRgn(myRgn); + + ForeColor(magentaColor); + OffsetRgn(myRgn,25,15); + FillRgn(myRgn,myPattern); + FrameRgn(myRgn); + + DisposeRgn(myRgn); + +*) + + { --------- demonstrate region clipping --------- } + + ForeColor(blackColor); + MoveTo(320,262); DrawString('Regions'); + + myRgn:=NewRgn; + OpenRgn; + ShowPen; + + ForeColor(yellowColor); + SetRect(tempRect,260,270,460,350); + FrameRoundRect(tempRect,24,16); + + MoveTo(275,335); { define triangular hole } + LineTo(325,285); + LineTo(375,335); + LineTo(275,335); + + SetRect(tempRect,365,277,445,325); { oval hole } + FrameOval(tempRect); + + HidePen; + CloseRgn(myRgn); { end of definition } + + SetClip(myRgn); + + BackColor(blueColor); + ForeColor(greenColor); + FOR i:=0 TO 6 DO { draw stuff inside the clip region } + BEGIN + MoveTo(260,280+12*i); + DrawString('Arbitrary Clipping Regions'); + END; + BackColor(whiteColor); + + ClipRect(thePort^.portRect); + DisposeRgn(myRgn); + + + { --------- draw oval samples --------- } + + ForeColor(blackColor); + MoveTo(580,262); DrawString('Ovals'); + + ForeColor(redColor); + SetRect(tempRect,510,264,570,294); + FrameOval(tempRect); + + ForeColor(greenColor); + OffsetRect(tempRect,25,15); + PenSize(3,2); + EraseOval(tempRect); + FrameOval(tempRect); + + ForeColor(blueColor); + OffsetRect(tempRect,25,15); + PaintOval(tempRect); + + ForeColor(cyanColor); + OffsetRect(tempRect,25,15); + PenNormal; + FillOval(tempRect,gray); + FrameOval(tempRect); + + ForeColor(magentaColor); + OffsetRect(tempRect,25,15); + FillOval(tempRect,myPattern); + FrameOval(tempRect); + + BackColor(whiteColor); + ForeColor(blackColor); + + { test large CopyBits } + SetRect(srcRect,0,0,200,100); + SetRect(dstRect,50,50,250,150); + CopyBits(thePort^.portBits,thePort^.portBits,srcRect,dstRect,0,Nil); + +END; { DrawStuff } + + +PROCEDURE InitScales; +{ initialize an array of common scale factors } +BEGIN + numerArray[ 0] := 1; denomArray[ 0] := 8; + numerArray[ 1] := 1; denomArray[ 1] := 4; + numerArray[ 2] := 1; denomArray[ 2] := 3; + numerArray[ 3] := 3; denomArray[ 3] := 8; + numerArray[ 4] := 1; denomArray[ 4] := 2; + numerArray[ 5] := 2; denomArray[ 5] := 3; + numerArray[ 6] := 3; denomArray[ 6] := 4; + numerArray[ 7] := 1; denomArray[ 7] := 1; + numerArray[ 8] := 4; denomArray[ 8] := 3; + numerArray[ 9] := 3; denomArray[ 9] := 2; + numerArray[10] := 2; denomArray[10] := 1; + numerArray[11] := 3; denomArray[11] := 1; + numerArray[12] := 4; denomArray[12] := 1; + numerArray[13] := 6; denomArray[13] := 1; + numerArray[14] := 8; denomArray[14] := 1; + numerArray[15] := 16; denomArray[15] := 1; + numerArray[16] := 24; denomArray[16] := 1; + numerArray[17] := 32; denomArray[17] := 1; + numerArray[18] := 40; denomArray[18] := 1; + numerArray[19] := 48; denomArray[19] := 1; + numerArray[20] := 56; denomArray[20] := 1; + numerArray[21] := 64; denomArray[21] := 1; +END; + + +PROCEDURE SetScale(numer,denom: LongInt); +BEGIN + WITH dstRect DO + BEGIN + left := 360 - (360 * numer) DIV denom; + right := 360 + (360 * numer) DIV denom; + top := 182 - (182 * numer) DIV denom; + bottom:= 182 + (182 * numer) DIV denom; + END; +END; + + +PROCEDURE DumpPicture(myPicture: PicHandle); +LABEL 1; +VAR ch: CHAR; + i,byteCount: INTEGER; + count,total: INTEGER; + picPtr: QDPtr; + opCode,hiNibble,loNibble: INTEGER; + sameFlag: BOOLEAN; + srcBits: BitMap; + + FUNCTION GetWord: INTEGER; + VAR word: INTEGER; + BEGIN + word := BitAnd(picPtr^,$FF); + picPtr := Pointer(ORD(picPtr)+1); + word := BitShift(word,+8) + BitAnd(picPtr^,$FF); + picPtr := Pointer(ORD(picPtr)+1); + GetWord := word; + END; + + FUNCTION GetSByte: INTEGER; + BEGIN + GetSByte := picPtr^; + picPtr := Pointer(ORD(picPtr)+1); + END; + + FUNCTION GetUByte: INTEGER; + BEGIN + GetUByte := BitAnd(picPtr^,$FF); + picPtr := Pointer(ORD(picPtr)+1); + END; + + FUNCTION GetLong: LongInt; + VAR long: LongInt; + BEGIN + long := BitAnd(picPtr^,$FF); + picPtr := Pointer(ORD(picPtr)+1); + long := BitShift(long,+8) + BitAnd(picPtr^,$FF); + picPtr := Pointer(ORD(picPtr)+1); + long := BitShift(long,+8) + BitAnd(picPtr^,$FF); + picPtr := Pointer(ORD(picPtr)+1); + long := BitShift(long,+8) + BitAnd(picPtr^,$FF); + picPtr := Pointer(ORD(picPtr)+1); + GetLong := long; + END; + +BEGIN + WRITELN; + WRITELN('picSize = ',myPicture^^.picSize,' bytes'); + WITH myPicture^^.picFrame DO + WRITELN('picFrame = (',left:1,',',top:1,',',right:1,',',bottom:1,')'); + + picPtr := Pointer(ORD(myPicture^) + 10); + +1: opCode := GetSByte; + WRITELN; + IF opCode = -1 THEN EXIT(DumpPicture); + + loNibble := BitAnd(opCode,$F); + hiNibble := BitShift(BitAnd(opCode,$F0),-4); + + IF hiNibble = 0 THEN + BEGIN + CASE loNibble OF + + 1: BEGIN + WRITE('Set clipRgn '); + byteCount := GetWord; + WRITE('rgnSize = ',byteCount); + picPtr := Pointer(ORD(picPtr) + byteCount - 2); + END; + + 2: BEGIN + WRITE('Set bkPat'); + picPtr := Pointer(ORD(picPtr) + 8); + END; + + 3: BEGIN + WRITE('Set txFont ',GetWord); + END; + + 4: BEGIN + WRITE('Set txFace ',GetUByte); + END; + + 5: BEGIN + WRITE('Set txMode ',GetWord); + END; + + 6: BEGIN + WRITE('Set spExtra ',GetWord); + END; + + 7: BEGIN + WRITE('Set pnSize ',GetWord,GetWord); + END; + + 8: BEGIN + WRITE('Set pnMode ',GetWord); + END; + + 9: BEGIN + WRITE('Set pnPat'); + picPtr := Pointer(ORD(picPtr) + 8); + END; + + 10: BEGIN + WRITE('Set thePat'); + picPtr := Pointer(ORD(picPtr) + 8); + END; + + 11: BEGIN + WRITE('Set ovalSize ',GetWord,GetWord); + END; + + 12: BEGIN + WRITE('Set Origin ',GetWord,GetWord); + END; + + 13: BEGIN + WRITE('Set txSize ',GetWord); + END; + + 14: BEGIN + WRITE('Set ForeColor ',GetLong); + END; + + 15: BEGIN + WRITE('Set BackColor ',GetLong); + END; + + END; { case } + GOTO 1; + END; { if hiNibble = 0 } + + + IF hiNibble = 1 THEN + BEGIN + CASE loNibble OF + + 0: BEGIN + WRITE('txNumer,txDenom = ',GetWord,GetWord,GetWord,GetWord); + END; + + 1: BEGIN + WRITE('picVersion = ',GetUByte); + END; + + OTHERWISE WRITE('OOPS ! OPCODE WAS ',opCode); + END; { case } + GOTO 1; + END; { if hiNibble = 1 } + + + IF hiNibble = 2 THEN + BEGIN { text or line } + CASE loNibble OF + 0: WRITE('Line from ',GetWord,GetWord,' to ',GetWord,GetWord); + 1: WRITE('Line to ',GetWord,GetWord); + 2: WRITE('Line from ',GetWord,GetWord, ' dh,dv = ',GetSByte,GetSByte); + 3: WRITE('Line dh,dv = ',GetSByte,GetSByte); + 8,9,10,11: + BEGIN { text } + CASE loNibble OF + 8: WRITE('LongText at ',GetWord,GetWord,' '); + 9: WRITE('DH Text, dh = ',GetUByte,' '); + 10: WRITE('DV Text, dv = ',GetUByte,' '); + 11: WRITE('DHDV Text, dh,dv = ',GetUByte,GetUByte,' '); + END; + byteCount := GetUByte; + FOR i:= 1 to byteCount DO WRITE(CHR(GetUByte)); + END; + END; { case loNibble } + GOTO 1; + END; + + + IF hiNibble = 9 THEN WITH srcBits, bounds DO + BEGIN + sameFlag := FALSE; { not packed } + IF BitAnd(loNibble,$8) <> 0 THEN + BEGIN + sameFlag := TRUE; { packed } + loNibble := BitAnd(loNibble,$7); + WRITE('Pack'); + END; + + IF loNibble = 0 + THEN WRITELN('BitsRect: ') ELSE WRITELN('BitsRgn: '); + rowBytes := GetWord; + top := GetWord; + left := GetWord; + bottom := GetWord; + right := GetWord; + + WRITELN(' rowBytes = ',rowBytes); + WRITELN(' bounds = ',top,left,bottom,right); + WRITELN(' srcRect = ',GetWord,GetWord,GetWord,GetWord); + WRITELN(' dstRect = ',GetWord,GetWord,GetWord,GetWord); + WRITELN(' mode = ',GetWord); + IF loNibble <> 0 THEN + BEGIN + byteCount := GetWord; + WRITELN(' maskRgn rgnSize = ',byteCount); + picPtr := Pointer(ORD(picPtr) + byteCount-2); + END; + byteCount := rowBytes*(bottom-top); + IF sameFlag THEN + BEGIN + total := 0; + FOR i := top TO bottom - 1 DO + BEGIN + count := GetUByte; + total := total + count; + picPtr := Pointer(ORD(picPtr) + count); + END; + WRITELN(' ',byteCount:1,' bytes compressed to ',total); + END + ELSE + BEGIN + WRITELN(' Uncompressed bytes = ',byteCount); + picPtr := Pointer(ORD(picPtr) + byteCount); + END; + GOTO 1; + END; + + IF hiNibble = 10 THEN + BEGIN + IF loNibble = 0 THEN + BEGIN + WRITE('Short Comment ',GetWord); + GOTO 1; + END; + + WRITE('Long Comment ',GetWord); + byteCount := GetWord; + picPtr := Pointer(ORD(picPtr) + byteCount); + GOTO 1; + END; + + IF hiNibble > 10 THEN + BEGIN + WRITE('OOPS, hiNibble > 10 ! opcode was ',opCode); + READLN; + GOTO 1; + END; + + + { hi nibble is 3..8 } + + sameFlag := FALSE; + IF BitAnd(loNibble,$8) <> 0 THEN + BEGIN + sameFlag := TRUE; + loNibble := BitAnd(loNibble,$7); + END; + + CASE loNibble OF + 0: WRITE('Frame'); + 1: WRITE('Paint'); + 2: WRITE('Erase'); + 3: WRITE('Invert'); + 4: WRITE('Fill'); + END; + + IF sameFlag THEN WRITE('Same'); + + CASE hiNibble OF + 3: BEGIN + WRITE('Rect'); + IF NOT sameFlag THEN WRITE(GetWord,GetWord,GetWord,GetWord); + END; + + 4: BEGIN + WRITE('RRect'); + IF NOT sameFlag THEN WRITE(GetWord,GetWord,GetWord,GetWord); + END; + + 5: BEGIN + WRITE('Oval'); + IF NOT sameFlag THEN WRITE(GetWord,GetWord,GetWord,GetWord); + END; + + 6: BEGIN + WRITE('Arc'); + IF NOT sameFlag THEN WRITE(GetWord,GetWord,GetWord,GetWord); + WRITE(GetWord,GetWord); + END; + + 7: BEGIN + WRITE('Poly'); + byteCount := GetWord; + WRITE(' polySize = ',byteCount); + picPtr := Pointer(ORD(picPtr) + byteCount-2); + END; + + 8: BEGIN + WRITE('Rgn'); + byteCount := GetWord; + WRITE(' rgnSize = ',byteCount); + picPtr := Pointer(ORD(picPtr) + byteCount-2); + END; + + END; + + GOTO 1; + +END; + + +BEGIN { main program } + WRITE('Press return '); READLN; + NEW(heapStart); + heapLimit:=Pointer(ORD(heapStart)+heapSize); + RELEASE(heapLimit); { forward release to allocate } + InitHeap(heapStart,heapLimit,@heapError); + InitGraf(@thePort); + + InitCursor; + HideCursor; + FMInit(errNum); + IF errNum <> 0 THEN + BEGIN + WRITELN('FMInit says errNum=',errNum); + HALT; + END; + + StuffHex(@myPattern,'8040200002040800'); + + InitIcons; + InitScales; + + NEW(port1); + OpenPort(port1); + PaintRect(thePort^.portRect); + DrawStuff; + READLN; + + myPicture := OpenPicture(thePort^.portRect); + DrawStuff; + ClosePicture; + WRITELN('picSize = ',myPicture^^.picSize:1); + READLN; + DrawPicture(myPicture,thePort^.portRect); + + WRITE('Dump ?'); READ(ch); WRITELN; + IF ch IN ['Y','y'] THEN + BEGIN + DumpPicture(myPicture); + READLN; + END; + + WRITE('ABOUT TO make bigPicture '); READLN; + bigPicture := OpenPicture(thePort^.portRect); + DrawPicture(myPicture,thePort^.portRect); + tempRect := thePort^.portRect; + InsetRect(tempRect,100,50); + DrawPicture(myPicture,tempRect); + InsetRect(tempRect,100,50); + DrawPicture(myPicture,tempRect); + ClosePicture; + WRITELN('big picSize = ',bigPicture^^.picSize:1); + READLN; + DrawPicture(bigPicture,thePort^.portRect); + + WRITE('Dump Big ?'); READ(ch); WRITELN; + IF ch IN ['Y','y'] THEN + BEGIN + DumpPicture(bigPicture); + READLN; + END; + + KillPicture(bigPicture); + + WRITE('ABOUT TO DO NORMAL from picture '); READLN; + ColorBit(normalBit); + DrawPicture(myPicture,thePort^.portRect); + + WRITE('ABOUT TO DO INVERSE from picture '); READLN; + ColorBit(inverseBit); + DrawPicture(myPicture,thePort^.portRect); + + WRITE('ABOUT TO DO CYAN from picture '); READLN; + ColorBit(cyanBit); + DrawPicture(myPicture,thePort^.portRect); + + WRITE('ABOUT TO DO MAGENTA from picture '); READLN; + ColorBit(magentaBit); + DrawPicture(myPicture,thePort^.portRect); + + WRITE('ABOUT TO DO YELLOW from picture '); READLN; + ColorBit(yellowBit); + DrawPicture(myPicture,thePort^.portRect); + + WRITE('ABOUT TO DO BLACK from picture'); READLN; + ColorBit(blackBit); + DrawPicture(myPicture,thePort^.portRect); + + ColorBit(normalBit); + READLN; + + PaintRect(thePort^.portRect); + REPEAT + FOR i:=0 to 15 DO + BEGIN + SetScale(numerArray[i],denomArray[i]); + DrawPicture(myPicture,dstRect); + IF MouseButton THEN GOTO 1; + END; + + FOR i:=14 DOWNTO 1 DO + BEGIN + SetScale(numerArray[i],denomArray[i]); + DrawPicture(myPicture,dstRect); + IF MouseButton THEN GOTO 1; + END; + UNTIL FALSE; + +1: ShowCursor; + + SetRect(myPicture^^.picFrame,0,0,200,100); + + REPEAT UNTIL NOT MouseButton; + REPEAT + REPEAT UNTIL MouseButton; + GetMouse(dstRect.topLeft); + REPEAT UNTIL NOT MouseButton; + GetMouse(dstRect.botRight); + ClipRect(thePort^.portRect); + PaintRect(thePort^.portRect); + DrawPicture(myPicture,dstRect); + IF MouseButton THEN EXIT(TestGraf); + UNTIL FALSE; + + KillPicture(myPicture); +END. diff --git a/Text.a b/Text.a new file mode 100755 index 0000000..b976451 --- /dev/null +++ b/Text.a @@ -0,0 +1,740 @@ + .INCLUDE GRAFTYPES.TEXT +;--------------------------------------------------------- +; +; +; ***** ***** * * ***** +; * * * * * +; * * * * * +; * *** * * +; * * * * * +; * * * * * +; * ***** * * * +; +; +; Routines for measuring and drawing Text. +; + + +;------------------------------------------- +; +; KERNED STRIKE FONT FORMAT OFFSETS: +; +FORMAT .EQU 0 ;WORD +MINCHAR .EQU 2 ;WORD +MAXCHAR .EQU 4 ;WORD +MAXWD .EQU 6 ;WORD +FBBOX .EQU 8 ;WORD +FBBOY .EQU 10 ;WORD +FBBDX .EQU 12 ;WORD +FBBDY .EQU 14 ;WORD +LENGTH .EQU 16 ;WORD +ASCENT .EQU 18 ;WORD +DESCENT .EQU 20 ;WORD +XOFFSET .EQU 22 ;WORD +RASTER .EQU 24 ;WORD + + + + + .PROC StdText,4 + .REF CheckPic,DPutPicByte,PutPicData,PutPicWord,PutPicLong + .REF DrText +;-------------------------------------------------------------------------- +; +; PROCEDURE StdText(count: INTEGER; textAddr: Ptr; numer,denom: Point); +; +; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: +; +PARAMSIZE .EQU 14 +COUNT .EQU PARAMSIZE+8-2 ;WORD +TEXTADDR .EQU COUNT-4 ;LONG +NUMER .EQU TEXTADDR-4 ;POINT +DENOM .EQU NUMER-4 ;POINT + +TXLOC .EQU -4 ;POINT +VARSIZE .EQU TXLOC ;TOTAL LOCALS + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVEM.L D5-D7/A3-A4,-(SP) ;SAVE REGS +TXTLOOP MOVE COUNT(A6),D6 ;GET CHARACTER COUNT + BLE GOHOME ;QUIT IF COUNT <= 0 + CMP #255,D6 ;is count > 255 ? + BLE.S COUNTOK ;no, continue + MOVE #255,D6 ;yes, pin at 255 + +COUNTOK JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE + BLE NOTPIC + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE +; +; CHECK TXFONT +; + MOVE TXFONT(A3),D7 ;GET THEPORT^.TXFONT + CMP PICTXFONT(A4),D7 ;HAS IT CHANGED ? + BEQ.S FONTOK ;NO, CONTINUE + MOVEQ #3,D0 ;YES, PUSH TXFONT PARAM OPCODE + JSR DPutPicByte ;PUT OPCODE + MOVE D7,-(SP) + JSR PutPicWord ;PUT TXFONT PARAM + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE D7,PICTXFONT(A4) ;UPDATE CURRENT STATE +; +; CHECK TXFACE +; +FONTOK MOVE.B TXFACE(A3),D7 ;GET THEPORT^.TXFACE + CMP.B PICTXFACE(A4),D7 ;HAS IT CHANGED ? + BEQ.S FACEOK ;NO, CONTINUE + MOVEQ #4,D0 ;YES, PUSH TXFACE PARAM OPCODE + JSR DPutPicByte ;PUT OPCODE + MOVE.B D7,D0 + JSR DPutPicByte ;PUT TXFACE PARAM + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.B D7,PICTXFACE(A4) ;UPDATE CURRENT STATE +; +; CHECK TXMODE +; +FACEOK MOVE TXMODE(A3),D7 ;GET THEPORT^.TXMODE + CMP PICTXMODE(A4),D7 ;HAS IT CHANGED ? + BEQ.S MODEOK ;NO, CONTINUE + MOVEQ #5,D0 ;YES, PUSH TXMODE PARAM OPCODE + JSR DPutPicByte ;PUT OPCODE + MOVE D7,-(SP) + JSR PutPicWord ;PUT TXMODE PARAM + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE D7,PICTXMODE(A4) ;UPDATE CURRENT STATE +; +; CHECK TXSIZE +; +MODEOK MOVE TXSIZE(A3),D7 ;GET THEPORT^.TXSIZE + CMP PICTXSIZE(A4),D7 ;HAS IT CHANGED ? + BEQ.S SIZEOK ;NO, CONTINUE + MOVEQ #$0D,D0 ;YES, PUSH TXSIZE PARAM OPCODE + BSR.S JDPutPicByte ;PUT OPCODE + MOVE D7,-(SP) + JSR PutPicWord ;PUT TXSIZE PARAM + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE D7,PICTXSIZE(A4) ;UPDATE CURRENT STATE +; +; CHECK SPEXTRA +; +SIZEOK MOVE.L SPEXTRA(A3),D7 ;GET THEPORT^.SPEXTRA + CMP.L PICSPEXTRA(A4),D7 ;HAS IT CHANGED ? + BEQ.S SPOK ;NO, CONTINUE + MOVEQ #6,D0 ;YES, PUSH SPEXTRA PARAM OPCODE + BSR.S JDPutPicByte ;PUT OPCODE + MOVE.L D7,-(SP) + BSR.S JPutPicLong ;PUT SPEXTRA PARAM + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.L D7,PICSPEXTRA(A4) ;UPDATE CURRENT STATE +; +; CHECK NUMER, DENOM +; +SPOK MOVE.L NUMER(A6),D7 ;GET NUMER + MOVE.L DENOM(A6),D5 ;GET DENOM + CMP.L PICTXNUMER(A4),D7 ;HAS IT CHANGED ? + BNE.S NOTSAME ;YES, RECORD CHANGE + CMP.L PICTXDENOM(A4),D5 ;HAS IT CHANGED ? + BEQ.S NUMEROK ;NO, CONTINUE +NOTSAME MOVEQ #$10,D0 ;YES, PUSH TXRATIO OPCODE + BSR.S JDPutPicByte ;PUT OPCODE + MOVE.L D7,-(SP) + BSR.S JPutPicLong ;PUT NUMER + MOVE.L D5,-(SP) + BSR.S JPutPicLong ;PUT DENOM + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.L D7,PICTXNUMER(A4) ;UPDATE CURRENT STATE + MOVE.L D5,PICTXDENOM(A4) ;UPDATE CURRENT STATE +NUMEROK + + +;------------------------------------------------------------- +; +; USE DH AND DV TO CHOOSE ONE OF FOUR TEXT OPCODES. +; + MOVE.L PNLOC(A3),D5 ;GET CURRENT PNLOC + SUB.L PICTXLOC(A4),D5 ;CALC DV.DH + MOVE.L D5,D0 ;COPY DV.DH + AND.L #$FF00FF00,D0 ;ARE DH AND DV BOTH 0..255 ? + BEQ.S SHORT ;YES, USE SHORT FORM + MOVEQ #$28,D0 + BSR.S JDPutPicByte ;NO, PUT LONGTEXT OPCODE + MOVE.L PNLOC(A3),-(SP) + BSR.S JPutPicLong ;PUT PNLOC 4 BYTES + BRA.S TEXT2 ;AND CONTINUE +JDPutPicByte + JMP DPutPicByte +JPutPicLong + JMP PutPicLong + +SHORT MOVE.L D5,D0 ;YES, COPY DV.DH + AND.L #$00FF0000,D0 ;IS DV = 0 ? + BNE.S DV ;NO, CONTINUE + MOVEQ #$29,D0 + BSR.S JDPutPicByte ;YES, PUT DHTEXT OPCODE + BRA.S SHARE2 ;SHARE COMMON CODE + +DV TST.B D5 ;IS DH = 0 ? + BNE.S DHDV ;NO, CONTINUE + MOVEQ #$2A,D0 + BSR.S JDPutPicByte ;YES, PUT DVTEXT OPCODE + BRA.S SHARE1 ;SHARE COMMON CODE + +DHDV MOVEQ #$2B,D0 + BSR.S JDPutPicByte ;PUT DHDVTEXT OPCODE + MOVE.B D5,D0 + BSR.S JDPutPicByte ;PUT DH 0..255 TO PIC + +SHARE1 SWAP D5 ;PUT DV IN LO WORD +SHARE2 MOVE.B D5,D0 + BSR.S JDPutPicByte ;PUT DH OR DV 0..255 TO PIC + +TEXT2 MOVE.B D6,D0 + BSR.S JDPutPicByte ;PUT COUNT BYTE TO PIC + MOVE.L TEXTADDR(A6),-(SP) ;PUSH ADDR OF TEXT + MOVE D6,-(SP) ;PUSH COUNT + JSR PutPicData ;PUT TEXT DATA + MOVE.L PICSAVE(A3),A4 ;GET PICSAVE HANDLE + MOVE.L (A4),A4 ;DE-REFERENCE PICSAVE + MOVE.L PNLOC(A3),PICTXLOC(A4) ;UPDATE PICTXLOC STATE + +; +; DrText(count,textAddr,numer,denom); +; +NOTPIC MOVE D6,-(SP) ;PUSH COUNT + MOVE.L TEXTADDR(A6),-(SP) ;PUSH TEXTADDR + MOVE.L NUMER(A6),-(SP) ;PUSH NUMER + MOVE.L DENOM(A6),-(SP) ;PUSH DENOM + JSR DrText ;DRAW THE TEXT + + SUB D6,COUNT(A6) ;was count > 255 ? + BLE.S GOHOME ;no, quit + MOVE.L TEXTADDR(A6),A0 ;yes, get old textaddr + ADD D6,A0 ;offset for characters done + MOVE.L A0,TEXTADDR(A6) ;update textAddr + BRA TXTLOOP ;and loop for more + +GOHOME MOVEM.L (SP)+,D5-D7/A3-A4 ;RESTORE REGS + UNLINK PARAMSIZE,'STDTEXT ' + + + + .PROC CallText,2 + .REF STDTEXT +;--------------------------------------------------------------- +; +; PROCEDURE CallText(count: INTEGER; textAddr: Ptr); +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L #$00010001,-(SP) ;PUSH NUMER = (1,1) + MOVE.L (SP),-(SP) ;PUSH DENOM = (1,1) + MOVE.L A0,-(SP) ;RESTORE RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QuickDraw GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDTEXT,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L TEXTPROC(A0),A0 ;NO, GET PROC PTR +USESTD JMP (A0) ;GO TO IT + + + + .PROC TextFace,1 + .DEF DrawChar,CharWidth + .REF CallText,TextWidth +;------------------------------------------------------- +; +; PROCEDURE TextFace(face: Style); +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QuickDraw GLOBALS + MOVE.L THEPORT(A0),A0 ;POINT TO THEPORT + MOVE.B 5(SP),TXFACE(A0) ;INSTALL TXFACE + BRA.S SHARE ;STRIP PARAM AND RETURN + + +;---------------------------------------------------- +; +; PROCEDURE DrawChar(ch: CHAR); +; +DrawChar + MOVE #1,-(SP) ;PUSH COUNT=1 + PEA 7(SP) ;PUSH TEXTADDR + JSR CallText ;CALL TEXT ROUTINE + BRA.S SHARE ;STRIP PARAM AND RETURN + + +;--------------------------------------------- +; +; FUNCTION CharWidth(ch: CHAR): INTEGER; +; +CharWidth + CLR -(SP) ;ROOM FOR FCN RESULT + MOVE.L SP,-(SP) ;PUSH TEXTBUF + MOVE.L #$00010007,-(SP) ;PUSH OFFSET = 7 & COUNT = 1 + JSR TEXTWIDTH + MOVE (SP)+,6(SP) ;MOVE UP RESULT +SHARE MOVE.L (SP)+,A0 ;POP RETURN ADDR + ADD #2,SP ;STRIP CHAR PARAM + JMP (A0) ;AND RETURN + + + + .PROC TextFont,1 + .DEF TextSize + .DEF TextMode + .REF PortWord +;------------------------------------------------------- +; +; PROCEDURE TextFont(font: INTEGER); +; + MOVEQ #TXFONT,D0 ;PUT PORT OFFSET IN D0 + BRA.S SHARE + + +;------------------------------------------------------- +; +; PROCEDURE TextMode(mode: INTEGER); +; +TextMode + MOVEQ #TXMODE,D0 ;PUT PORT OFFSET IN D0 + BRA.S SHARE + + +;------------------------------------------------------- +; +; PROCEDURE TextSize(mode: INTEGER); +; +TextSize + MOVEQ #TXSIZE,D0 ;PUT PORT OFFSET IN D0 +SHARE JMP PORTWORD ;INSTALL PARAM INTO THEPORT + + + .PROC SpaceExtra,1 + .DEF DrawString,DrawText + .REF CallText +;------------------------------------------------------- +; +; PROCEDURE SpaceExtra(extra: LongInt); +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QuickDraw GLOBALS + MOVE.L THEPORT(A0),A0 ;POINT TO THEPORT + MOVE.L 4(SP),SPEXTRA(A0) ;INSTALL FIXED POINT SPEXTRA + BRA.S SHARE + + +;---------------------------------------------------- +; +; PROCEDURE DrawString(s: Str255); +; +DrawString + MOVE.L 4(SP),A0 ;POINT TO STRING + CLR D0 ;GET READY FOR BYTE + MOVE.B (A0)+,D0 ;GET STRING LENGTH + MOVE D0,-(SP) ;PUSH COUNT + MOVE.L A0,-(SP) ;PUSH TEXTADDR + JSR CallText ;CALL TEXT ROUTINE + BRA.S SHARE + + +;---------------------------------------------------- +; +; PROCEDURE DrawText(textBuf: WordPtr; start,count: INTEGER); +; +DrawText + MOVE.L 8(SP),A0 ;POINT TO TEXTBUF + ADD 6(SP),A0 ;ADD STARTING OFFSET + MOVE 4(SP),-(SP) ;PUSH COUNT + MOVE.L A0,-(SP) ;PUSH TEXTADDR + JSR CallText ;CALL TEXT ROUTINE + MOVE.L (SP)+,(SP) +SHARE MOVE.L (SP)+,(SP) ;STRIP PARAMS + RTS ;AND RETURN + + + .FUNC StringWidth,1 + .REF TextWidth +;--------------------------------------------- +; +; FUNCTION StringWidth(s: Str255): INTEGER; +; + MOVE.L (SP)+,A1 ;POP RETURN ADDR + MOVE.L (SP)+,A0 ;POP ADDR OF STRING + CLR D0 + MOVE.B (A0)+,D0 ;GET UNSIGNED BYTE + MOVE.L A0,-(SP) ;PUSH TEXTADDR + CLR -(SP) ;FIRSTBYTE := 0 + MOVE D0,-(SP) ;PUSH BYTECOUNT + MOVE.L A1,-(SP) ;PUT BACK RETURN ADDR +; +; FALL THRU INTO TEXTWIDTH +; + .FUNC TextWidth,3 + .REF StdTxMeas +;------------------------------------------ +; +; FUNCTION TEXTWIDTH(TEXTBUF: WordPtr; firstbyte,byteCount: INTEGER): INTEGER; +; +PARAMSIZE .EQU 8 +RESULT .EQU PARAMSIZE+8 +TEXTBUF .EQU RESULT-4 ;LONG +FIRSTBYTE .EQU TEXTBUF-2 ;WORD +BYTECOUNT .EQU FIRSTBYTE-2 ;WORD + +INFO .EQU -8 ;4 WORDS +NUMER .EQU INFO-4 ;POINT +DENOM .EQU NUMER-4 ;POINT +VARSIZE .EQU DENOM ;TOTAL BYTES OF LOCALS + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + CLR RESULT(A6) ;INIT RESULT TO 0 + CLR -(SP) ;MAKE ROOM FOR FCN CALL BELOW + MOVE BYTECOUNT(A6),-(SP) ;PUSH BYTE COUNT + BLE.S GOHOME ;QUIT IF COUNT <= 0 + ;UNLK TAKES CARE OF SP + MOVE.L TEXTBUF(A6),A0 ;GET ADDR OF BUFFER + ADD FIRSTBYTE(A6),A0 ;ADD STARTING INDEX + MOVE.L A0,-(SP) ;PUSH TEXTADDR + MOVE.L #$00010001,D0 + MOVE.L D0,NUMER(A6) ;NUMER := (1,1) + MOVE.L D0,DENOM(A6) ;DENOM := (1,1) + PEA NUMER(A6) ;PUSH VAR NUMER + PEA DENOM(A6) ;PUSH VAR DENOM + PEA INFO(A6) ;PUSH VAR INFO + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + BEQ.S STD ;YES, USE STDTXMEAS + MOVE.L D0,A0 ;NO, GET GRAFPROCS + MOVE.L TXMEASPROC(A0),A0 ;GET TXMEAS CAPTURE PROC + JSR (A0) ;CALL IT + BRA.S NOTSTD ;AND CONTINUE +STD JSR STDTXMEAS +NOTSTD MOVE (SP)+,D1 ;POP UNSCALED WIDTH + MOVE NUMER+H(A6),D0 ;get numer + MOVE DENOM+H(A6),D2 ;get denom + CMP D2,D0 ;is numer same as denom ? + BEQ.S DONE ;yes, skip muldiv + MULU D0,D1 ;MUL BY NUMER + MOVE D2,D0 ;COPY DENOM + LSR #1,D0 ;CALC DENOM DIV 2 + ADD D0,D1 ;ADD DENOM DIV 2 + DIVU D2,D1 ;DIV BY DENOM +DONE MOVE D1,RESULT(A6) ;RETURN SCALED WIDTH +GOHOME UNLINK PARAMSIZE,'TEXTWIDT' + + + + + .FUNC StdTxMeas,5 +;------------------------------------------ +; +; FUNCTION StdTxMeas(count: INTEGER; textAddr: Ptr; +; VAR numer,denom: Point; +; VAR info: FontInfo): INTEGER; +; +; Measure some text, returning unscaled values plus updated scale factor. +; Fills info record with unscaled ascent, descent, widMax, and leading, +; and returns unscaled integer width as the function value. +; +; Also leaves unscaled fixed point width in QD global 'fixTxWid' +; and stashes FMOutPtr in QD global 'fontPtr' for DrawText. +; +PARAMSIZE .EQU 18 +RESULT .EQU PARAMSIZE+8 ;FCN RESULT IS A WORD +COUNT .EQU RESULT-2 ;WORD +TEXTADDR .EQU COUNT-4 ;LONG +NUMER .EQU TEXTADDR-4 ;LONG, VAR ADDR +DENOM .EQU NUMER-4 ;LONG, VAR ADDR +INFO .EQU DENOM-4 ;LONG, ADDR OF FONTINFO + +INREC .EQU -16 ;FMInput record +VARSIZE .EQU INREC + + + LINK A6,#VARSIZE ;ALLOCATE LOCALS + MOVE.L A4,-(SP) ;SAVE REG + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A4),A0 ;GET CURRENT GRAFPORT + LEA INREC(A6),A1 ;POINT TO FMINPUT RECORD + MOVE TXFONT(A0),(A1)+ ;GET TXFONT FROM THEPORT + MOVE TXSIZE(A0),(A1)+ ;GET TXSIZE FROM THEPORT + MOVE.B TXFACE(A0),(A1)+ ;GET TXFACE FROM THEPORT + ST (A1)+ ;ALWAYS SET NEEDBITS TRUE + MOVE DEVICE(A0),(A1)+ ;GET DEVICE FROM THEPORT + MOVE.L NUMER(A6),A0 ;POINT TO NUMER + MOVE.L (A0),(A1)+ ;INSTALL INPUT NUMER + MOVE.L DENOM(A6),A0 ;POINT TO DENOM + MOVE.L (A0),(A1)+ ;INSTALL INPUT DENOM + CLR.L -(SP) ;ROOM FOR FCN RESULT + PEA INREC(A6) ;PUSH INPUT RECORD + _SwapFont ;CALL FMSWAPFONT + MOVE.L (SP)+,A1 ;POP FMOUTPUT POINTER + MOVE.L A1,FONTPTR(A4) ;STASH FMOUTPTR FOR LATER + + MOVE.L INFO(A6),A0 ;POINT TO VAR INFO RECORD + CLR.L (A0) ;INIT TO (0,0,0,0) + CLR.L 4(A0) ;ALL 4 WORDS + MOVE.B 13(A1),1(A0) ;FILL IN UNSIGNED ASCENT + MOVE.B 14(A1),3(A0) ;FILL IN UNSIGNED DESCENT + MOVE.B 15(A1),5(A0) ;FILL IN UNSIGNED WIDMAX + MOVE.B 16(A1),D0 ;GET SIGNED LEADING + EXT.W D0 ;SIGN EXTEND TO WORD + MOVE.W D0,6(A0) ;FILL IN LEADING +; +; UPDATE NUMER AND DENOM +; + MOVE.L NUMER(A6),A0 ;GET VAR ADDR + MOVE.L 18(A1),(A0) ;UPDATE NUMER + MOVE.L DENOM(A6),A0 ;GET VAR ADDR + MOVE.L 22(A1),(A0) ;UPDATE DENOM + + MOVE.L TEXTADDR(A6),A0 ;POINT TO CHARACTERS + MOVE.L WidthPtr,A1 ;POINT TO WIDTH TABLE + CLR.L D1 ;INIT WIDTH TO 0.0 + MOVE COUNT(A6),D2 ;GET CHARACTER COUNT + BRA.S MORE ;GO TO LOOP START +NEXTCH CLR D0 ;GET READY FOR BYTE + MOVE.B (A0)+,D0 ;GET A CHARACTER + LSL #2,D0 ;QUAD FOR TABLE OFFSET + ADD.L 0(A1,D0),D1 ;ADD FIXED POINT WIDTH +MORE DBRA D2,NEXTCH ;LOOP FOR ALL CHARS + MOVE.L D1,fixTxWid(A4) ;STASH FIXED POINT WIDTH + SWAP D1 ;GET HI WORD = INTEGER PORTION + MOVE D1,RESULT(A6) ;UPDATE FUNCTION RESULT + MOVE.L (SP)+,A4 ;RESTORE REG + UNLINK PARAMSIZE,'STDTXMEA' + + + + + .PROC MeasureText +;-------------------------------------------------------------------- +; +; PROCEDURE MeasureText(count: INTEGER; textAddr,charLocs: Ptr); +; +; Measure some text, returning (scaled) screen widths in charlocs. +; +; Charlocs points to an array of count+1 integers. +; +PARAMSIZE .EQU 10 +COUNT .EQU PARAMSIZE+8-2 ;WORD +TEXTADDR .EQU COUNT-4 ;LONG, Ptr to ASCII +CHARLOCS .EQU TEXTADDR-4 ;LONG, Ptr to output array + +INREC .EQU -16 ;FMInput record +VARSIZE .EQU INREC + + + LINK A6,#VARSIZE ;ALLOCATE LOCALS + MOVEM.L D3-D4/A2,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT +; +; Call swapfont to set up width table and return numer,denom: +; + LEA INREC(A6),A1 ;POINT TO FMINPUT RECORD + MOVE TXFONT(A0),(A1)+ ;GET TXFONT FROM THEPORT + MOVE TXSIZE(A0),(A1)+ ;GET TXSIZE FROM THEPORT + MOVE.B TXFACE(A0),(A1)+ ;GET TXFACE FROM THEPORT + ST (A1)+ ;ALWAYS SET NEEDBITS TRUE + MOVE DEVICE(A0),(A1)+ ;GET DEVICE FROM THEPORT + MOVE.L #$00010001,(A1)+ ;INSTALL INPUT NUMER = 1,1 + MOVE.L #$00010001,(A1)+ ;INSTALL INPUT DENOM = 1,1 + CLR.L -(SP) ;ROOM FOR FCN RESULT + PEA INREC(A6) ;PUSH INPUT RECORD + _SwapFont ;CALL FMSWAPFONT + MOVE.L (SP)+,A0 ;POP FMOUTPUT POINTER + MOVE.W 18+H(A0),D3 ;GET NUMER.H + MOVE.W 22+H(A0),D4 ;GET DENOM.H + +; +; Step thru characters, adding up unscaled widths and storing in charLocs: +; + MOVE.L TEXTADDR(A6),A0 ;POINT TO CHARACTERS + MOVE.L WidthPtr,A1 ;POINT TO WIDTH TABLE + MOVE.L CHARLOCS(A6),A2 ;POINT TO CHARLOCS + CLR.L D1 ;INIT WIDTH TO 0.0 + MOVE COUNT(A6),D2 ;GET CHARACTER COUNT +NEXTCH SWAP D1 ;GET HI WORD OF WIDTH + MOVE.W D1,(A2)+ ;STORE IN CHARLOCS + SWAP D1 ;RETURN WIDTH TO FIXED POINT + CLR D0 ;GET READY FOR BYTE + MOVE.B (A0)+,D0 ;GET A CHARACTER + LSL #2,D0 ;QUAD FOR TABLE OFFSET + ADD.L 0(A1,D0),D1 ;ADD FIXED POINT WIDTH +MORE DBRA D2,NEXTCH ;LOOP FOR COUNT+1 CHARLOCS + +; +; if font is horizontally stretched, scale all widths accordingly +; + CMP D3,D4 ;IS NUMER.H = DENOM.H ? + BEQ.S NOSCALE ;YES, SKIP SCALING + MOVE D4,D1 ;COPY DENOM + LSR #1,D1 ;CALC DENOM DIV 2 + MOVE.L CHARLOCS(A6),A2 ;NO, POINT TO CHARLOCS + MOVE COUNT(A6),D2 ;GET CHARACTER COUNT +NEXTCH2 MOVE (A2),D0 ;GET CHARLOC + MULU D3,D0 ;MUL BY NUMER + ADD D1,D0 ;ADD DENOM DIV 2 + DIVU D4,D0 ;DIV BY DENOM + MOVE D0,(A2)+ ;UPDATE CHARLOC + DBRA D2,NEXTCH2 ;LOOP FOR COUNT+1 CHARLOCS +NOSCALE + + MOVEM.L(SP)+,D3-D4/A2 ;RESTORE REGS + UNLINK PARAMSIZE,'MEASURET' + + + + +;-------------------------------------------------------------------- +; +; FUNCTION FMSwapFont(inRec: FMInput): FMOutPtr; +; +; FMSwapFont is the only contact between QuickDraw and the Font Manager. +; It swaps in the requested font and returns a pointer to an output record +; telling how to use the font. FMSwapFont is called from StdTxMeas +; in response to DrawChar, DrawString, DrawText, CharWidth, StringWidth, +; TextWidth, and GetFontInfo. +; +; IF fontHandle returns as Nil (can't find the font), then: +; 1. The output record will be undefined except for errNum and fontHandle. +; 2. DrawString will neither draw the text nor bump the pen. +; 3. StringWidth will return 0. +; 4. GetFontInfo will return 0,0,0,0. +; +; +; FMInput = PACKED RECORD +; family: INTEGER; { i.e. Century } +; size: INTEGER; { i.e. 12 point } +; face: Style; { i.e. [bold,underlined] } +; needBits: BOOLEAN; { do we need the bitmaps ? } +; device: INTEGER; { i.e. 0 for screen } +; numer: Point; { current drawing scale } +; denom: Point; { current drawing scale } +; END; +; +; +; FMOutPtr = ^FMOutPut; +; FMOutput = PACKED RECORD +; errNum: INTEGER; { not used } +; fontHandle: Handle; { handle to font } +; bold: Byte; { how much to smear horiz } +; italic: Byte; { how much to shear } +; ulOffset: Byte; { pixels below baseline } +; ulShadow: Byte; { how big is the halo } +; ulThick: Byte; { how thick is the underline } +; shadow: Byte; { 0,1,2,or 3 only } +; extra: SignedByte; { extra white dots each char } +; ascent: Byte; { ascent measure for font } +; descent: Byte; { descent measure for font } +; widMax: Byte; { width of widest char } +; leading: SignedByte; { leading between lines } +; unused: Byte; +; numer: Point; { use this modified scale to } +; denom: Point; { draw or measure text with } +; END; +; +; +; +;-------------------------------------------------------------------------- + + + .PROC GetFontInfo,1 + .REF StdTxMeas +;------------------------------------------ +; +; PROCEDURE GetFontInfo(VAR info: FontInfo); +; +; Calls StdTxMeas thru capture proc, then adjusts and scales the result. +; +; 13 MAY 85, changed so that all 4 values round UP in the case of scaling. +; +PARAMSIZE .EQU 4 +INFO .EQU PARAMSIZE+8-4 ;LONG, ADDR OF INFO + +NUMER .EQU -4 ;POINT +DENOM .EQU NUMER-4 ;POINT +VARSIZE .EQU DENOM ;TOTAL LOCALS + + LINK A6,#VARSIZE ;ALLOCATE LOCALS + MOVE.L #$00010001,NUMER(A6) ;NUMER := (1,1) + MOVE.L #$00010001,DENOM(A6) ;DENOM := (1,1) + CLR.L -(SP) ;ROOM FOR FCN, COUNT = 0 + CLR.L -(SP) ;TEXTADDR := NIL + PEA NUMER(A6) ;PUSH VAR NUMER + PEA DENOM(A6) ;PUSH VAR DENOM + MOVE.L INFO(A6),-(SP) ;PUSH VAR INFO + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ? + LEA STDTXMEAS,A0 + BEQ.S USESTD ;YES, USE STD PROC + MOVE.L D0,A0 + MOVE.L TXMEASPROC(A0),A0 ;NO, GET TXMEAS CAPTURE PROC +USESTD JSR (A0) ;CALL IT + TST (SP)+ ;DISCARD WIDTH FCN RSLT + +; +; ADJUST WIDMAX FOR EXTRA +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS + MOVE.L FONTPTR(A0),A0 ;GET FMOUTPUT RECORD + MOVE.L INFO(A6),A1 ;POINT TO RESULT INFO + MOVE.B 12(A0),D0 ;GET SIGNED EXTRA + EXT.W D0 ;EXTEND TO WORD + ADD D0,4(A1) ;ADD TO WIDMAX +; +; ADJUST ASCENT & DESCENT FOR SHADOW +; + CLR D0 ;GET READY FOR BYTE + MOVE.B 11(A0),D0 ;GET SHADOW COUNT + BEQ.S NOTSHAD ;SKIP IF ZERO + ADD #1,0(A1) ;ADJUST ASCENT + ADD D0,2(A1) ;ADJUST DESCENT +NOTSHAD + +; +; SCALE RESULT IF NUMER <> DENOM +; + MOVE.L NUMER(A6),D0 + CMP.L DENOM(A6),D0 ;IS NUMER SAME AS DENOM ? + BEQ.S NOSCALE ;YES, SKIP SCALING + + BSR.S SCALE ;SCALE ASCENT + + BSR.S SCALE ;SCALE DESCENT + + MOVE (A1),D0 ;GET MAXWID + MULU NUMER+H(A6),D0 ;SCALE MAXWID + MOVE DENOM+H(A6),D1 ;get denom + SUB #1,D1 ;calc denom-1 + EXT.L D1 ;extend to long + ADD.L D1,D0 ;add denom-1 to round up + DIVU DENOM+H(A6),D0 ;divide by denom + MOVE D0,(A1)+ ;UPDATE MAXWID + + BSR.S SCALE ;SCALE LEADING + +NOSCALE UNLINK PARAMSIZE,'GETFONTI' + + +SCALE MOVE (A1),D0 ;GET IT + MULU NUMER+V(A6),D0 ;SCALE IT + MOVE DENOM+V(A6),D1 ;get denom + SUB #1,D1 ;calc denom-1 + EXT.L D1 ;extend to long + ADD.L D1,D0 ;add denom-1 to round up + DIVU DENOM+V(A6),D0 ;divide by denom + MOVE D0,(A1)+ ;UPDATE IT + RTS + + + .END diff --git a/Util.a b/Util.a new file mode 100755 index 0000000..f25d081 --- /dev/null +++ b/Util.a @@ -0,0 +1,837 @@ + .INCLUDE GRAFTYPES.TEXT +;------------------------------------------------------------- +; +; --> UTIL.TEXT +; +; SMALL UTILITY ROUTINES USED BY QuickDraw. +; + + + .FUNC BitNot,1 +;----------------------------------------------------------- +; +; Function BitNot(long: LongInt): LongInt; +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + NOT.L (SP) ;INVERT LONG + MOVE.L (SP)+,(SP) ;STORE INTO RESULT + JMP (A0) ;AND RETURN + + + .FUNC BitAnd,2 + .DEF BitXor,BitOr,BitShift +;----------------------------------------------------------- +; +; Function BitAnd(long1,long2: LongInt): LongInt; +; + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D0 ;GET ONE LONG + AND.L (SP)+,D0 ;AND IT WITH THE OTHER + BRA.S DONE ;AND STORE RESULT + + +;----------------------------------------------------------- +; +; Function BitXor(long1,long2: LongInt): LongInt; +; +BitXor MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D0 ;GET ONE LONG + MOVE.L (SP)+,D1 ;GET THE SECOND + EOR.L D1,D0 ;XOR BOTH + BRA.S DONE ;AND STORE RESULT + + +;----------------------------------------------------------- +; +; Function BitOr(long1,long2: LongInt): LongInt; +; +BitOr MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D0 ;GET ONE LONG + OR.L (SP)+,D0 ;OR IT WITH THE OTHER + BRA.S DONE ;AND STORE RESULT + + +;----------------------------------------------------------- +; +; Function BitShift(long: LongInt; count: INTEGER): LongInt; +; +; positive count --> shift left. +; negative count --> shift right. +; +BitShift MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE (SP)+,D1 ;GET COUNT + BPL.S SHLEFT ;SHIFT LEFT IF POSITIVE + NEG D1 ;MAKE COUNT POSITIVE + MOVE.L (SP)+,D0 ;GET LONG + LSR.L D1,D0 ;SHIFT IT RIGHT + BRA.S DONE ;AND STORE RESULT +SHLEFT MOVE.L (SP)+,D0 ;GET LONG + LSL.L D1,D0 ;SHIFT IT LEFT +DONE MOVE.L D0,(SP) ;STORE THE RESULT + JMP (A0) ;AND RETURN + + + .FUNC BitTst,2 + .DEF BitSet,BitClr +;--------------------------------------------------------- +; +; FUNCTION BitTst(bytePtr: Ptr; bitNum: LongInt): BOOLEAN; +; + BSR.S SHARE + MOVE.L (SP)+,A1 ;GET PTR + BTST D0,0(A1,D1.L) ;TEST THE BIT + SNE (SP) ;SET OR CLEAR RESULT + NEG.B (SP) ;CONVERT -1 TO 1 + JMP (A0) ;RETURN + + +;--------------------------------------------------------- +; +; PROCEDURE BitSet(bytePtr: Ptr; bitNum: LongInt); +; +BitSet BSR.S SHARE + MOVE.L (SP)+,A1 ;GET PTR + BSET D0,0(A1,D1.L) ;SET THE BIT + JMP (A0) + + +;--------------------------------------------------------- +; +; PROCEDURE BitClr(bytePtr: Ptr; bitNum: LongInt); +; +BitClr BSR.S SHARE + MOVE.L (SP)+,A1 ;GET PTR + BCLR D0,0(A1,D1.L) ;SET THE BIT + JMP (A0) +; +; +; +SHARE MOVE.L (A7)+,A1 + MOVE.L (SP)+,A0 ;POP RETURN ADDR + MOVE.L (SP)+,D1 ;GET BITNUM + MOVE D1,D0 ;COPY IT + ASR.L #3,D1 ;CONVERT BITS TO BYTES + NOT D0 ;REVERSE BIT SENSE + JMP (A1) + + + + .FUNC Random,0 +;-------------------------------------------------------------- +; +; FUNCTION Random: INTEGER; +; +; returns a signed 16 bit number, and updates unsigned 32 bit randSeed. +; +; recursion is randSeed := (randSeed * 16807) MOD 2147483647. +; +; See paper by Linus Schrage, A More Portable Fortran Random Number Generator +; ACM Trans Math Software Vol 5, No. 2, June 1979, Pages 132-138. +; +; Clobbers D0-D2, A0 +; +; +; GET LO 16 BITS OF SEED AND FORM LO PRODUCT +; xalo := A * LoWord(seed) +; + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QuickDraw GLOBALS + MOVE #16807,D0 ;GET A = 7^5 + MOVE D0,D2 ;GET A = 7^5 + MULU RANDSEED+2(A0),D0 ;CALC LO PRODUCT = XALO +; +; FORM 31 HIGHEST BITS OF LO PRODUCT +; fhi:=HiWord(seed) * ORD4(a) + HiWord(xalo); +; + MOVE.L D0,D1 ;COPY xalo + CLR.W D1 + SWAP D1 ;GET HiWord(xalo) as a long + MULU RANDSEED(A0),D2 ;MULT BY HiWord(seed) + ADD.L D1,D2 ;ADD LEFTLO = FHI +; +; GET OVERFLOW PAST 31ST BIT OF FULL PRODUCT +; k:=fhi DIV 32768; +; + MOVE.L D2,D1 ;COPY FHI + ADD.L D1,D1 ;CALC 2 TIMES FHI + CLR.W D1 + SWAP D1 ;CALC FHI SHIFTED RIGHT 15 FOR K +; +; ASSEMBLE ALL THE PARTS AND PRE-SUBTRACT P +; seed:=((BitAnd(XALO,$0000FFFF) - P) + BitAnd(fhi,$00007FFF) * b16) + K; +; + AND.L #$0000FFFF,D0 ;GET LO WORD XALO + SUB.L #$7FFFFFFF,D0 ;SUBTRACT P = 2^31-1 + AND.L #$00007FFF,D2 ;BitAnd(fhi,$00007FFF) + SWAP D2 ;TIMES 64K + ADD.L D1,D2 ;PLUS K + ADD.L D2,D0 ;CALC TOTAL +; +; IF seed < 0 THEN seed:=seed+p; +; + BPL.S UPDATE + ADD.L #$7FFFFFFF,D0 +UPDATE MOVE.L D0,RANDSEED(A0) ;UPDATE SEED + CMP.W #$8000,D0 ;IS NUMBER -32768 ? + BNE.S NUMOK ;NO, CONTINUE + CLR D0 ;YES, RETURN ZERO INSTEAD +NUMOK MOVE.W D0,4(SP) ;RETURN LO WORD AS RESULT + RTS + + + + .PROC ForeColor,1 + .DEF BackColor,PortLong,ColorBit,PortWord +;-------------------------------------------------------------- +; +; PROCEDURE ForeColor(color: LongInt); +; + MOVEQ #FGCOLOR,D0 ;GET OFFSET TO FGCOLOR + BRA.S PortLong ;INSTALL A LONG + + + +;-------------------------------------------------------------- +; +; PROCEDURE BackColor(color: LongInt); +; +BackColor + MOVEQ #BKCOLOR,D0 ;GET OFFSET TO FGCOLOR +; +; FALL THRU INTO PORTLONG +; +;------------------------------------------------------- +; +; PROCEDURE PortLong(long: LongInt); +; INSTALL A LONG INTO CURRENT GRAFPORT. ENTER WITH OFFSET IN D0 +; +PortLong + MOVE.L (SP)+,A1 ;POP RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QuickDraw GLOBALS + MOVE.L THEPORT(A0),A0 ;POINT TO THEPORT + MOVE.L (SP)+,0(A0,D0) ;INSTALL WORD INTO THEPORT + JMP (A1) ;AND RETURN + + +;-------------------------------------------------------------- +; +; PROCEDURE ColorBit(whichBit: INTEGER); +; +ColorBit + MOVEQ #COLRBIT,D0 ;GET OFFSET TO COLRBIT + ;FALL THRU INTO PORTWORD + +;------------------------------------------------------- +; +; PROCEDURE PortWord(word: INTEGER); +; INSTALL A WORD INTO CURRENT GRAFPORT. ENTER WITH OFFSET IN D0 +; +PortWord + MOVE.L (SP)+,A1 ;POP RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QuickDraw GLOBALS + MOVE.L THEPORT(A0),A0 ;POINT TO THEPORT + MOVE.W (SP)+,0(A0,D0) ;INSTALL WORD INTO THEPORT + JMP (A1) ;AND RETURN + + + + .PROC GetMaskTab,0 + .DEF LeftMask,RightMask,BitMask,MaskTab +;---------------------------------------------------------- +; +; ASSEMBLY LANGUAGE CALLABLE PROCEDURES LEFTMASK, RIGHTMASK, AND BITMASK: +; +; ENTER WITH COORDINATE IN D0, RETURNS WITH 16 BIT MASK IN D0 +; NO OTHER REGISTERS ALTERED. +; + LEA MaskTab,A0 ;POINT TO MASK TABLE + RTS ;AND RETURN + +LeftMask + AND #$F,D0 ;TREAT MOD 16 + ADD D0,D0 ;DOUBLE FOR TABLE + MOVE MASKTAB+32(D0),D0 ;GET LEFTMASK + RTS + +RIGHTMASK + AND #$F,D0 ;TREAT MOD 16 + ADD D0,D0 ;DOUBLE FOR TABLE + MOVE MASKTAB(D0),D0 ;GET RIGHT MASK + RTS + +BITMASK AND #$F,D0 ;TREAT MOD 16 + ADD D0,D0 ;DOUBLE FOR TABLE + MOVE MASKTAB+64(D0),D0 ;GET BITMASK + RTS + +MASKTAB .WORD $0000,$8000,$C000,$E000 ;TABLE OF 16 RIGHT MASKS + .WORD $F000,$F800,$FC00,$FE00 + .WORD $FF00,$FF80,$FFC0,$FFE0 + .WORD $FFF0,$FFF8,$FFFC,$FFFE + + .WORD $FFFF,$7FFF,$3FFF,$1FFF ;TABLE OF 16 LEFT MASKS + .WORD $0FFF,$07FF,$03FF,$01FF + .WORD $00FF,$007F,$003F,$001F + .WORD $000F,$0007,$0003,$0001 + + .WORD $8000,$4000,$2000,$1000 ;TABLE OF 16 BIT MASKS + .WORD $0800,$0400,$0200,$0100 + .WORD $0080,$0040,$0020,$0010 + .WORD $0008,$0004,$0002,$0001 + + + + + .PROC PatExpand,0 +;---------------------------------------------------------- +; +; EXPAND AN 8 BYTE PATTERN OUT TO 16 LONGS. +; +; CALLED ONLY FROM BITBLT,RGNBLT,DRAWLINE,DRAWARC. +; +; INPUTS: A0: POINTS TO 8 BYTE PATTERN +; A1: POINTS TO 16 LONGS OF DESTINATION +; A5: PASCAL GLOBAL PTR +; D2: HORIZONTAL GLOBAL-LOCAL OFFSET USED FOR PRE-ROTATE +; D7: -1 TO INVERT, ELSE 0 +; patStretch AND PATALIGN +; +; OUTPUTS: 16 LONGS OF EXPANDED PATTERN +; +; CLOBBERS: D0,D1,D2,A0,A1 +; +PARAMSIZE .EQU 0 +TWOPAT .EQU -16 ;ROOM FOR TWO COPIES OF PAT +VARSIZE .EQU TWOPAT ;TOTAL BYTES OF LOCAL VARS + + + LINK A6,#VARSIZE ;ALLOCATE STACK FRAME + MOVE.L A4,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS +; +; IF PATALIGN VERT NON-ZERO, COPY PAT TWICE AND REPLACE A0 +; + MOVEQ #7,D0 + AND PATALIGN(A4),D0 ;GET PATALIGN MOD 8 + BEQ.S VERTOK ;SKIP IF ZERO + MOVE.L (A0),TWOPAT(A6) ;MAKE TWO COPIES OF PATTERN + MOVE.L (A0)+,TWOPAT+8(A6) + MOVE.L (A0),TWOPAT+4(A6) + MOVE.L (A0),TWOPAT+12(A6) + LEA TWOPAT(A6),A0 + ADD D0,A0 +VERTOK + ADD PATALIGN+H(A4),D2 ;ADJUST FOR PATALIGN HORIZ + MOVEQ #7,D1 ;INIT COUNT OF 8 BYTES + AND D1,D2 ;TREAT SHIFTCOUNT MOD 8 + MOVE.L THEPORT(A4),A4 ;GET CURRENT GRAFPORT + MOVE patStretch(A4),D0 ;GET patStretch + CMP #2,D0 ;IS patStretch = 2 ? + BEQ.S DOUBLE ;YES, DOUBLE + CMP #-2,D0 ;IS PAT STRETCH = -2 ? + BEQ.S THIN ;YES, STRETCH THIN + ;ANY OTHER, USE NORMAL + +;--------------------------------------------------------- +; +; NORMAL PATTERN. SIMPLY REPLICATE THE 8 BY 8 PATTERN. +; +NORMAL MOVE.B (A0)+,D0 ;GET A BYTE OF PATTERN + EOR.B D7,D0 ;INVERT IT IF MODE BIT 2 + 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 8 SCANS LATER + DBRA D1,NORMAL ;LOOP ALL 8 INPUT BYTES + BRA.S DONE + + +;----------------------------------------------------------- +; +; STRETCHED BY TWO: DOUBLE EACH BIT HORIZONTALLY AND VERTICALLY +; +DOUBLE CLR D0 ;CLEAR OUT HI BYTE +DLOOP MOVE.B (A0)+,D0 ;GET A BYTE OF PATTERN + EOR.B D7,D0 ;INVERT IT IF MODE BIT 2 + ROL.B D2,D0 ;ALIGN TO LOCAL COORDS + MOVE.B D0,-(SP) ;STASH FOR A WHILE + LSR.B #4,D0 ;GET HI NIBBLE + MOVE.B STRETCH(D0),(A1)+ ;PUT ONE BYTE + MOVEQ #$F,D0 ;MASK FOR LO NIBBLE + AND.B (SP)+,D0 ;GET THE LO NIBBLE + MOVE.B STRETCH(D0),(A1)+ ;PUT ANOTHER TO MAKE A WORD + MOVE.W -2(A1),(A1)+ ;STRETCH WORD OUT TO LONG + MOVE.L -4(A1),(A1)+ ;STRETCH LONG TO TWO LONGS + DBRA D1,DLOOP ;LOOP ALL 8 INPUT BYTES + BRA.S DONE + + +;----------------------------------------------------------- +; +; STRETCH BY TWO AND THIN OUT THE BITS. ADD EXTRA WHITE DOTS. +; +THIN CLR D0 ;CLEAR OUT HI BYTE +THINLP MOVE.B (A0)+,D0 ;GET A BYTE OF PATTERN + EOR.B D7,D0 ;INVERT IT IF MODE BIT 2 + ROL.B D2,D0 ;ALIGN TO LOCAL COORDS + MOVE.B D0,-(SP) ;STASH FOR A WHILE + LSR.B #4,D0 ;GET HI NIBBLE + MOVE.B THINSTR(D0),(A1)+ ;PUT ONE BYTE + MOVEQ #$F,D0 ;MASK FOR LO NIBBLE + AND.B (SP)+,D0 ;GET THE LO NIBBLE + MOVE.B THINSTR(D0),(A1)+ ;PUT ANOTHER TO MAKE A WORD + MOVE.W -2(A1),(A1)+ ;STRETCH WORD OUT TO LONG + CLR.L (A1)+ ;STRETCH LONG TO TWO LONGS + DBRA D1,THINLP ;LOOP ALL 8 INPUT BYTES + +DONE MOVE.L (SP)+,A4 ;RESTORE REG + UNLINK PARAMSIZE,'PATEXPAN' + + +;---------------------------------------------------------------- +; +; BIT DOUBLING TABLE FOR 0..15 INPUT --> BYTE OUTPUT +; +STRETCH .BYTE $00,$03,$0C,$0F,$30,$33,$3C,$3F + .BYTE $C0,$C3,$CC,$CF,$F0,$F3,$FC,$FF +; +; TABLE FOR THIN DOUBLING. +; +THINSTR .BYTE $00,$01,$04,$05,$10,$11,$14,$15 + .BYTE $40,$41,$44,$45,$50,$51,$54,$55 + + + + + .PROC ColorMap,2 +;---------------------------------------------------------------- +; +; PROCEDURE ColorMap(mode: INTEGER, pat: Pattern); +; +; ADJUST INPUT MODE AND PATTERN TO ACCOMPLISH COLOR SEPARATION. +; Returns (altered) mode and pat on the stack where they were. +; PRESERVES ALL REGISTERS. +; + MOVEM.L D0-D3/A0,-(SP) ;SAVE REGS + MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QuickDraw GLOBALS + MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT + MOVE.L A0,D0 ;IS THEPORT NIL ? + BEQ.S COLOROK ;YES, LEAVE COLOR ALONE + BTST #0,D0 ;IS THEPORT ODD ? + BNE.S COLOROK ;YES, LEAVE COLOR ALONE + MOVE COLRBIT(A0),D2 ;GET COLOR BIT SELECT + BEQ.S COLOROK ;COLORBIT = 0 MEANS NO COLOR + MOVE 28(SP),D3 ;GET INPUT MODE + MOVEQ #3,D0 ;MASK FOR BOTTOM 2 BITS + AND D3,D0 ;GET 2 BITS OF MODE + BEQ.S COPY ;BR IF COPY MODE +; +; THE XOR MODES DEPEND ON NEITHER FOREGROUND OR BACKGROUND COLOR +; + CMP #2,D0 ;IS IT SOME KIND OF XOR ? + BEQ.S COLOROK ;YES, THEY DON'T CHANGE + BGT.S BICMODE ;BRANCH IF BIC + ;ELSE MUST BE OR +; +; THE OR MODES DEPEND ONLY ON THE FOREGROUND COLOR +; +ORMODE MOVE.L FGCOLOR(A0),D1 ;GET FOREGROUND COLOR +SHARE BTST D2,D1 ;TEST FOREGROUND COLOR BIT + BNE.S COLOROK ;NO CHANGE IF FG TRUE + EOR #2,D3 ;ELSE INVERT MODE BIT 2 + BRA.S NEWMODE ;UPDATE MODE AND QUIT + +; +; THE BIC MODES DEPEND ONLY ON THE BACKGROUND COLOR +; +BICMODE MOVE.L BKCOLOR(A0),D1 ;GET BACKGROUND COLOR + NOT.L D1 ;INVERT IT + BRA SHARE ;AND SHARE CODE + +; +; THE COPY MODES DEPEND ON BOTH FOREGOUND AND BACKGROUND +; +COPY MOVE.L FGCOLOR(A0),D0 ;GET FOREGROUND COLOR + MOVE.L BKCOLOR(A0),D1 ;GET BACKGROUND COLOR + BTST D2,D0 ;TEST FOREGROUND COLOR BIT + BEQ.S FORE0 ;BRANCH IF IT'S ZERO + +FORE1 BTST D2,D1 ;TEST BACKGROUND COLOR BIT + BEQ.S COLOROK ;NO CHANGE IF BKGND FALSE + MOVEQ #8,D3 ;ELSE REPLACE MODE = PAT COPY +USEPAT MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QuickDraw GLOBALS + LEA BLACK(A0),A0 ;POINT TO BLACK PATTERN + MOVE.L A0,24(SP) ;REPLACE PATTERN WITH BLACK + BRA.S NEWMODE ;UPDATE MODE AND QUIT + +FORE0 BTST D2,D1 ;TEST BACKGROUND COLOR BIT + BNE.S INVMODE ;IF BK TRUE, INVERT MODE + MOVEQ #12,D3 ;ELSE REPLACE MODE = NOTPAT COPY + BRA.S USEPAT ;AND PATTERN WITH BLACK + +INVMODE EOR #4,D3 ;USE INVERSE OF MODE +NEWMODE MOVE D3,28(SP) ;CHANGE INPUT MODE +COLOROK MOVEM.L (SP)+,D0-D3/A0 ;RESTORE REGS + RTS ;AND RETURN + + + .FUNC GetPixel,2 + .REF HideCursor,ShowCursor +;--------------------------------------------------------- +; +; FUNCTION GetPixel(h,v: INTEGER): BOOLEAN; +; +; Returns TRUE if the pixel at (h,v) is set to black. +; h and v are in local coords of the current grafport. +; +; CLOBBERS A0,A1,D0,D1,D2 +; + JSR HIDECURSOR ;GET RID OF CURSOR + MOVE.L (SP)+,D2 ;POP RETURN ADDR + MOVE.L GRAFGLOBALS(A5),A1 ;POINT TO QuickDraw GLOBALS + MOVE.L THEPORT(A1),A1 ;GET THEPORT + MOVE (SP)+,D0 ;GET VERT COORD + SUB PORTBITS+BOUNDS+TOP(A1),D0 ;CONVERT TO GLOBAL COORDS + MOVE (SP)+,D1 ;GET HORIZ COORD + SUB PORTBITS+BOUNDS+LEFT(A1),D1 ;CONVERT TO GLOBAL + MULU PORTBITS+ROWBYTES(A1),D0 ;CALC VERT * ROWBYTES + MOVE.L PORTBITS+BASEADDR(A1),A1 ;GET BASEADDR + ADD.L D0,A1 ;ADD VERTICAL OFFSET + MOVE D1,D0 ;COPY HORIZ + NOT D0 ;INVERT FOR BIT INDEX + LSR #3,D1 ;CONVERT DOTS TO BYTES + BTST D0,0(A1,D1) ;TEST ONE SCREEN BIT + SNE (SP) ;SET BOOLEAN RESULT + NEG.B (SP) ;MAKE $FF --> $01 + MOVE.L D2,-(SP) ;PUSH RETURN ADDR + JMP SHOWCURSOR ;RESTORE CURSOR AND RETURN + + + + .PROC StuffHex,2 +;------------------------------------------------------- +; +; PROCEDURE STUFFHEX(THINGPTR: WORDPTR; S: STR255); +; +; CONVENIENCE ROUTINE TO STUFF HEX INTO ANY VARIABLE. +; BEWARE, NO RANGE-CHECKING. +; + MOVE.L 4(SP),A0 ;A0:=ADDR OF STRING + MOVE.L 8(SP),A1 ;A1:=THINGPTR + MOVE.L (SP),8(SP) ;CLEAN OFF STACK + ADD #8,SP ;POINT TO RETURN ADDR + MOVE.B (A0)+,D2 ;GET STRING LENGTH + AND #$00FE,D2 ;TRUNCATE LENGTH TO EVEN + BEQ.S ENDHEX ;QUIT IF LENGTH = 0 +HEXLOOP BSR.S NEXTHEX ;GET HEX DIGIT AND CONVERT TO BINARY + MOVE.B D0,D1 ;SAVE MOST SIG DIGIT + BSR.S NEXTHEX ;GET HEX DIGIT AND CONVERT TO BINARY + LSL.B #4,D1 ;SHIFT MOST SIG INTO PLACE + ADD.B D0,D1 ;FILL IN LS NIBBLE + MOVE.B D1,(A1)+ ;STUFF BYTE INTO THING + SUB #2,D2 ;2 LESS CHARS TO GO + BNE.S HEXLOOP ;LOOP FOR STRING LENGTH +ENDHEX RTS ;RETURN TO PASCAL +; +; LOCAL ROUTINE TO GET NEXT HEX DIGIT AND CONVERT ASCII TO BINARY +; +NEXTHEX MOVE.B (A0)+,D0 ;GET HEX DIGIT FROM STRING + CMP.B #$39,D0 ;IS IT GTR THAN '9' ? + BLE.S SMALL ;NO, DO IT + ADD.B #9,D0 ;YES, ADD CORRECTION +SMALL AND.B #$F,D0 ;TREAT MOD 16, EVEN LOWER CASE OK + RTS + + + + .PROC XorSlab + .REF MaskTab +;----------------------------------------------------------- +; +; LOCAL PROCEDURE XorSlab(bufAddr: Ptr; left,right: INTEGER); +; +; Enter with: +; +; A0: bufAddr +; D3: left coord +; D4: right coord +; +; Clobbers: A0,D0,D1,D3,D4,D5,D6 +; +; +; GET LEFTMASK AND RIGHTMASK +; + MOVE.L A0,D1 ;save bufAddr + LEA MASKTAB,A0 ;point to mask table + MOVEQ #$F,D0 ;get mask for 4 lo bits + + MOVE D3,D5 ;COPY LEFT COORD + AND D0,D5 ;CALC LEFT MOD 16 + ADD D5,D5 ;DOUBLE FOR TABLE INDEX + MOVE 0(A0,D5),D5 ;GET MASK FROM TABLE + NOT D5 ;INVERT FOR LEFTMASK + + MOVE D4,D6 ;COPY RIGHT COORD + AND D0,D6 ;TREAT RIGHT MOD 16 + ADD D6,D6 ;DOUBLE FOR TABLE INDEX + MOVE 0(A0,D6),D6 ;GET RIGHTMASK IN D6 + MOVE.L D1,A0 ;RESTORE SAVED bufAddr + +; +; CALC LEFTWORD, BUFPTR, WORDCOUNT +; + ASR #4,D3 ;CONVERT DOTS TO WORDS + ADD D3,A0 ;ADD TO bufAddr + ADD D3,A0 ;TWICE FOR BYTE OFFSET + ASR #4,D4 ;CALC RIGHT DIV 16 + SUB D3,D4 ;WORDCOUNT:=RIGHTWORD-LEFTWORD + BGT.S NOTIN1 ;BR IF NOT ALL IN ONE +; +; LEFT AND RIGHT ARE ALL IN ONE WORD +; + AND D5,D6 ;COMBINE LEFT AND RIGHT MASKS + EOR D6,(A0) ;XOR RIGHTMASK INTO BUFFER + RTS ;AND RETURN +; +; NOT ALL IN ONE WORD. DO LEFT, MIDDLE IF ANY, THEN RIGHT +; +NOTIN1 EOR D5,(A0)+ ;XOR LEFTMASK INTO BUFFER + BRA.S TEST ;SEE IF ANY FULL WORDS +INVLONG NOT.L (A0)+ ;INVERT 2 WHOLE WORDS +TEST SUBQ #2,D4 ;ANY FULL WORDS LEFT ? + BGT INVLONG ;YES, AT LEAST 2 + BLT.S ENDWORD ;NO, FINISH UP LAST WITH MASK + NOT (A0)+ ;YES, DO LAST FULL WORD +ENDWORD EOR D6,(A0) ;XOR RIGHTMASK INTO BUFFER + RTS + + + .PROC DrawSlab,0 + .DEF SlabMode,FastSlabMode + .REF MaskTab +;-------------------------------------------------------------- +; +; LOCAL PROCEDURE DRAWSLAB +; +; INPUTS: +; +; D0: scratch A0: MASKTAB +; D1: left A1: DSTLEFT, clobbered +; D2: right A2: MASKBUF, clobbered +; D3: A3: MINRECT +; D4: A4: MODECASE +; D5: A5: +; D6: pattern A6: +; D7: A7: stack +; +; CLOBBERS: D0-D3,A1,A2 +; +; +; +; CLIP LEFT AND RIGHT TO MINRECT: +; + CMP LEFT(A3),D1 ;IS LEFT < MINRECT.LEFT ? + BGE.S LEFTOK ;NO, CONTINUE + MOVE LEFT(A3),D1 ;YES, LEFT := MINRECT.LEFT +LEFTOK CMP RIGHT(A3),D2 ;IS RIGHT > MINRECT.RIGHT ? + BLE.S RIGHTOK ;NO, CONTINUE + MOVE RIGHT(A3),D2 ;YES, RIGHT := MINRECT.RIGHT +RIGHTOK CMP D2,D1 ;IS LEFT >= RIGHT ? + BGE.S DONESLAB ;YES, QUIT + +; +; SET UP LEFTMASK AND RIGHTMASK: (A0 already points to MaskTab) +; + MOVEQ #$F,D3 ;get mask for 4 lo bits + MOVE D1,D0 ;COPY LEFT + AND D3,D1 ;TREAT LEFT MOD 16 + ADD D1,D1 ;DOUBLE FOR TABLE + MOVE 32(A0,D1),D1 ;GET LEFTMASK IN D1 + AND D2,D3 ;GET RIGHT MOD 16 + ADD D3,D3 ;DOUBLE FOR TABLE + MOVE 0(A0,D3),D3 ;GET RIGHTMASK IN D3 + +; +; CALC WORDCOUNT, DSTPTR, MASKPTR, AND TAKE CASE JUMP +; + ASR #4,D2 ;CONVERT RIGHT TO WORDS + ASR #4,D0 ;CONVERT LEFT TO WORDS + SUB D0,D2 ;CALC WORD COUNT + ADD D0,D0 ;DOUBLE FOR BYTES + ADD D0,A1 ;OFFSET DSTPTR + ADD D0,A2 ;OFFSET MASKPTR + TST D2 ;SET Z-FLAG BASED ON WORDCOUNT + JMP (A4) ;TAKE MODECASE TO DRAW SLAB +DONESLAB RTS + + + + +;--------------------------------------------------------- +; +; INTERFACE TO EACH SCAN LINE ROUTINE: +; +; ENTER WITH Z-FLAG SET IF ALL IN ONE WORD +; +; INPUTS: A1: DSTPTR +; A2: MASKPTR +; D1: LEFTMASK +; D2: WORDCNT +; D3: RIGHTMASK +; D6: PATTERN +; +; CLOBBERS: D0,D1,D2,A1,A2 +; + +;------------------------------------------------------- +; +; MODE 8 OR 12: PATTERN --> DST +; +END8 AND D3,D1 ;COMBINE RIGHT AND LEFT MASK +NEXT8 MOVE D6,D0 ;GET PATTERN DATA + AND (A2)+,D1 ;MERGE MASK AND CLIPRGN MASK + AND D1,D0 ;MASK PATTERN DATA + NOT D1 ;MAKE NOTMASK + AND (A1),D1 ;AND NOTMASK WITH OLD DST + OR D0,D1 ;FILL HOLE WITH PATTERN + MOVE D1,(A1)+ ;UPDATE DST + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT +MASK8 BGT NEXT8 ;LOOP FOR ALL WORDS IN ROW + BEQ END8 ;DO LAST WORD WITH MASK + RTS + + +;------------------------------------------------------- +; +; MODE 9 OR 13: PATTERN OR DST --> DST +; +END9 AND D3,D1 ;COMBINE RIGHT AND LEFT MASK +NEXT9 AND D6,D1 ;GET PATTERN DATA + AND (A2)+,D1 ;MERGE MASK AND CLIPRGN MASK + OR D1,(A1)+ ;OR RESULT INTO DST + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT +MASK9 BGT NEXT9 ;LOOP FOR ALL WORDS IN ROW + BEQ END9 ;DO LAST WORD WITH MASK + RTS + + +;------------------------------------------------------- +; +; MODE 10 OR 14: PATTERN XOR DST --> DST +; +END10 AND D3,D1 ;COMBINE RIGHT AND LEFT MASK +NEXT10 AND D6,D1 ;GET PATTERN DATA + AND (A2)+,D1 ;MERGE MASK AND CLIPRGN MASK + EOR D1,(A1)+ ;XOR RESULT INTO DST + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT +MASK10 BGT NEXT10 ;LOOP FOR ALL WORDS IN ROW + BEQ END10 ;DO LAST WORD WITH MASK + RTS + + +;------------------------------------------------------- +; +; MODE 11 OR 15: PATTERN BIC DST --> DST +; +END11 AND D3,D1 ;COMBINE RIGHT AND LEFT MASK +NEXT11 AND D6,D1 ;GET PATTERN DATA + AND (A2)+,D1 ;MERGE MASK AND CLIPRGN MASK + NOT D1 ;INVERT FOR BIC + AND D1,(A1)+ ;BIC RESULT INTO DST + MOVEQ #-1,D1 ;FLUSH MASK + SUB #1,D2 ;DEC WORD COUNT +MASK11 BGT NEXT11 ;LOOP FOR ALL WORDS IN ROW + BEQ END11 ;DO LAST WORD WITH MASK + RTS + +;-------------------------------------------- +; +; PROCEDURE SlabMode +; +; INPUT: D2: MODE, CLOBBERED +; OUTPUT: A4: MODECASE +; +SlabMode + AND #$3,D2 ;GET LO 2 BITS OF MODE + LEA MODETAB,A4 ;POINT TO MODE TABLE + MOVE.B 0(A4,D2),D2 ;GET OFFSET FROM MODETAB + SUB D2,A4 ;GET CASE JUMP ADDRESS + RTS + +MODETAB .BYTE MODETAB-MASK8 + .BYTE MODETAB-MASK9 + .BYTE MODETAB-MASK10 + .BYTE MODETAB-MASK11 + + +;--------------------------------------------------------------- +; +; FAST LOOPS, OPTIMIZED FOR BLACK PATTERN AND RECTANGLE CLIPPED +; +; FAST BLACK SLAB: +; +FAST8 BEQ.S MERGE8 ;BR IF ALL IN ONE WORD + OR D1,(A1)+ ;OR LEFTMASK INTO DST + SUB #2,D2 ;ADJUST WORDCOUNT FOR DBRA + BLT.S LAST8 ;BR IF NO UNMASKED WORDS + MOVEQ #-1,D1 ;GET SOME BLACK +LOOP8 MOVE D1,(A1)+ ;WRITE A WORD OF BLACK + DBRA D2,LOOP8 ;LOOP ALL UNMASKED WORDS +MERGE8 AND D1,D3 ;COMBINE LEFTMASK AND RIGHTMASK +LAST8 OR D3,(A1)+ ;OR RIGHTMASK INTO DST + RTS ;AND RETURN + +; +; FAST XOR SLAB: +; +FAST10 BEQ.S MERGE10 ;BR IF ALL IN ONE WORD + EOR D1,(A1)+ ;XOR LEFTMASK INTO DST + SUB #2,D2 ;ADJUST WORDCOUNT FOR DBRA + BLT.S LAST10 ;BR IF NO UNMASKED WORDS +LOOP10 NOT (A1)+ ;INVERT A WORD OF DST + DBRA D2,LOOP10 ;LOOP ALL UNMASKED WORDS + BRA.S LAST10 ;THEN FINISH UP LAST WITH MASK +MERGE10 AND D1,D3 ;COMBINE LEFTMASK AND RIGHTMASK +LAST10 EOR D3,(A1)+ ;XOR RIGHTMASK INTO DST + RTS ;AND RETURN + +; +; FAST WHITE SLAB: +; +FAST11 BEQ.S MERGE11 ;BR IF ALL IN ONE WORD + NOT D1 ;FORM NOT LEFTMASK + AND D1,(A1)+ ;AND NOT LEFTMASK INTO DST + SUB #2,D2 ;ADJUST WORDCOUNT FOR DBRA + BLT.S LAST11 ;BR IF NO UNMASKED WORDS +LOOP11 CLR (A1)+ ;CLEAR A WORD OF DST + DBRA D2,LOOP11 ;LOOP ALL UNMASKED WORDS + BRA.S LAST11 ;THEN FINISH UP LAST WITH MASK +MERGE11 AND D1,D3 ;COMBINE LEFTMASK AND RIGHTMASK +LAST11 NOT D3 ;FORM NOT RIGHTMASK + AND D3,(A1)+ ;AND NOT RIGHTMASK INTO DST + RTS ;AND RETURN + + +;-------------------------------------------------------------------- +; +; PROCEDURE FastSlabMode, Call when rect clipped and pattern black. +; +; INPUT: D2: MODE, CLOBBERED mode 0=black, 1=xor, 2=white +; OUTPUT: A4: MODECASE +; +FastSlabMode + AND #$3,D2 ;GET LO 2 BITS OF MODE + LEA FASTTAB,A4 ;POINT TO MODE TABLE + MOVE.B 0(A4,D2),D2 ;GET OFFSET FROM FASTTAB + SUB D2,A4 ;GET CASE JUMP ADDRESS + RTS + +FASTTAB .BYTE FASTTAB-FAST8 ;BLACK + .BYTE FASTTAB-FAST10 ;XOR + .BYTE FASTTAB-FAST11 ;WHITE + + + .END