commit 646aa270df7eddc1928f82c3f4e2fc87b02167c9 Author: Jonathan Ragan-Kelley Date: Tue Jul 20 21:37:29 2010 -0700 initial import 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