;EASE$$$ READ ONLY COPY of file “regions.m.a” ;•1.3 MSH 05/23/1989 New version from EASE with new Bruce Leak trap (sounds ; like plumbing, eh?). ; 1.2 BAL 05/18/1989 Added BitmapToRegion trap. ; 1.1 CCH 11/11/1988 Fixed Header. ; 1.0 CCH 11/ 9/1988 Adding to EASE. ; OLD REVISIONS BELOW ; 1.2 CCH 10/12/1988 Changed “m.GrafType.a” to “GrafType.m.a”. ; 1.1 MSH 5/18/88 Changed inclides to use m.GRAPHTYPES to work under EASE. ; 1.0 BBM 2/11/88 Adding file for the first time into EASE… ; END EASE MODIFICATION HISTORY BLANKS ON STRING ASIS INCLUDE 'GRAFTYPES.m.a' ;----------------------------------------------------------- ; ; ; **** ***** *** *** *** * * *** ; * * * * * * * * * * * * ; * * * * * * * ** * * ; **** *** * ** * * * * * * *** ; * * * * * * * * * ** * ; * * * * * * * * * * * * ; * * ***** *** *** *** * * *** ; ; ; ; QuickDraw Routines to operate on Regions. ; StdRgn PROC EXPORT IMPORT CheckPic,PutPicVerb,DPutPicByte,PutPicRgn IMPORT 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 ' FrameRgn PROC EXPORT EXPORT CallRgn,PaintRgn,EraseRgn,InvertRgn,FillRgn ;----------------------------------------------------- ; ; 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 ? MOVE.L JStdRgn,A0 ;get piece of trap table 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 DrawRgn PROC EXPORT IMPORT 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 ' FrRgn PROC EXPORT IMPORT 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 ' NewRgn FUNC EXPORT IMPORT 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 DisposeRgn PROC EXPORT ;--------------------------------------------------- ; ; PROCEDURE DisposeRgn(rgn: RgnHandle); ; MOVE.L (SP)+,A1 ;pop return addr MOVE.L (SP)+,A0 ;pop handle _DisposHandle ;discard it JMP (A1) ;and return OpenRgn PROC EXPORT IMPORT 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 CloseRgn PROC EXPORT IMPORT 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' CopyRgn PROC EXPORT IMPORT SETHSIZE ;--------------------------------------------------- ; ; 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 SETHSIZE ;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 ' SetEmptyRgn PROC EXPORT IMPORT 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 SetRectRgn PROC EXPORT IMPORT SETHSIZE ;--------------------------------------------------- ; ; 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 SETHSIZE ;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' RectRgn PROC EXPORT IMPORT 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 OffsetRgn PROC EXPORT ;--------------------------------------------------------- ; ; 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 InsetRgn PROC EXPORT IMPORT InsetRect,SortPoints IMPORT 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' EmptyRgn FUNC EXPORT IMPORT 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 EqualRgn FUNC EXPORT ;------------------------------------------------------- ; ; 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 SectRgn PROC EXPORT EXPORT DoRgnOp,UnionRgn,DiffRgn,XorRgn IMPORT EqualRgn,CopyRgn,RSect,RectRgn,SetEmptyRgn IMPORT 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 ' PtInRgn FUNC EXPORT ;------------------------------------------------------------ ; ; 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 ' RectInRgn FUNC EXPORT IMPORT 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' TrimRect FUNC EXPORT IMPORT 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 MapRgn PROC EXPORT IMPORT MapRect,NewHandle,PutRgn,MapPt IMPORT 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 ' ENDPROC ;________________________________________________________________________________ ; ; FUNCTION BitMapRgn(region:RgnHandle; bMap:BitMap): OSErr; INLINE $A8D7; ; (BHogToRegion is debugging memory hog version) ; ; Given a region and bitmap, BitMapRgn makes the region a bounding ; region for the 'map. If it can't get memory it will return a ; Memory Manager-type error and an empty region gibbley. Note that ; the region might also be empty with no error (if the bounds is an ; empty rectangle or there are no 1 bits in the bitmap). Lastly, ; if the region would have to exceed 32K it returns a result of ; -500 (rgnTooBigErr). ; ; The bMap parameter may be a pointer to a bitmap, a pointer to a ; pixmap, or a pointer to a portBits field in a color grafport. ; In the latter two cases, if the pixmap is not 1-bit deep, an error ; result of -148 (pixmapTooDeepErr) is returned. ; ; (the nibble state machine idea is from the Finder MaskToRgn routine) ; ; History ; 2/19/88 RBB changed to take in washing and handle rect. & empties properly ; also now finds minimum rectangle to enclose region ; *** version of 2/22/88 *** ; 2/23/88 RBB putting in numerous optimizations recommended by Darin ; 4/4/88 RBB trying to re-do lost work from March ; DBA ; 3/28/89 CSD adjusted setup to know about pixmaps and portBits ; 5/18/89 BAL made classic QD friendly ; ;________________________________________________________________________________ ; ;Theory ; We scan each line of the bitmap and pump inversion points (ip's) into the region ; to put the areas with ones in the bitmap into the region and the areas ; with zeroes outside the region. ; ; In order to keep track of where we are in "inversion land" we use two ; techniques: ; The first is a scanline buffer which records the changes ; (zeroes to ones and vice versa) as we go. Wherever a change occurs (a ; 1 next to a 0 in the buffer) we need to put out an inversion point. ; The second is a togglin' flag which tells us whether we are "inverted" or not. ; Since we use a state machine in the innermost (nibble) loop to churn out ; ip's, the input to the state machine must be complemented if the flag is set. ; The loop stuff looks like this: ; outer line loop (grows handle in anticipation of worst case for next line) ; longword loop for current line (puts out inter-long ip's as needed) ; loop for 4 nibbles in current long (calls state maching for each nibble) ; ;________________________________________________________________________________ rgnTooBigErr EQU -500 pixmapTooDeepErr EQU -148 isCPort EQU 14 ;bit 14 in rowbytes means portBits in CGrafPort BitMapRgn PROC EXPORT BMFrame RECORD {A6Link},DECR result DS.W 1 paramTop EQU * regionH DS.L 1 bMapPtr DS.L 1 paramSize EQU paramTop-* return DS.L 1 A6Link DS.L 1 rowLongs DS.L 1 ;number of longwords per line rightMask DS.L 1 ;mask for rightmost long of each line slHandle DS.L 1 ;handle to scanline buffer numLines DS.W 1 ;number of lines in bitmap rowNumBytes DS.W 1 ;rowbytes from the bitmap startSize DS.W 1 ;size of region at start of line lastLineH DS.L 1 ;last line (zeroes) handle handSize DS.L 1 ;size of handle (avoid calls to GetHandleSize) max2Add DS.L 1 ;worst case for bytes we could add for next line localSize EQU * ENDR WITH BMFrame LINK A6,#localSize MOVEM.L A2-A5/D3-D7,-(SP) ;save work registers CLR.L slHandle(A6) ;no scanline handle, yet CLR.W result(A6) ;function result presumed zero at start MOVE.L regionH(A6),A0 MOVE.L (A0),A2 MOVEQ #0,D0 MOVE.W (A2),D0 ;get size of region MOVE.L D0,handSize(A6) ;save it long ;get boundary rectangle so we can tell how to process the bitmap MOVE.L bMapPtr(A6),A1 ;get bitmap pointer MOVE.W rowBytes(A1), D0 ;rowbytes if hasCQD then BPL.S @1 ;it's a bitmap so go ahead BTST #isCPort, D0 ;is this a ptr to portBits? BEQ.S @2 ;nope; it's a ptr to a pixmap MOVE.L baseAddr(A1), A0 ;get the PixMapHandle MOVE.L (A0), A1 ;and get the real ptr to pixmap @2 CMP.W #1, pmPixelSize(A1) ;is it 1 bit per pixel deep? BEQ.S @1 ;if yes, we're fine MOVE.W #pixmapTooDeepErr, D0 ;return an error otherwise BRA BMRBadEmpty ;clean up and bail out @1 MOVE.W rowBytes(A1), rowNumBytes(A6) ;get the rowbytes from the bit/pixmap ANDI.W #$7FFF, rowNumBytes(A6) ;mask off pixmap flag else MOVE.W rowBytes(A1), rowNumBytes(A6) ;get the rowbytes from the bit/pixmap endif ;hasCQD MOVE.L bounds+topLeft(A1),D2 ;get topLeft MOVE.W bounds+right(A1),D0 ;get right ;figure the number of longs per row (according to width, not rowbytes) ;so we can get a scanline buffer SUB.W D2,D0 ;right - left BLE BMREmptyOut ;if empty rect. then empty region EXT.L D0 MOVE.L D0,D4 ADD.L D4,D4 ;double width for 2 bytes/ip ADDQ.L #4+2,D4 ;add 4 bytes for y value and $7FFF word ;add 2 more for the $7FFF if the last line ADD.L D4,D4 ;double, just 'cause I feel like it! MOVE.L D4,max2Add(A6) ;save max. bytes for a given line MOVEQ #32,D7 ;(side effect: clear high word of D7) DIVU D7,D0 ;number of longs = width/32 ;get a mask for the rightmost long into rightMask MOVE.L D0,D3 ;save remainder(hi word) SWAP D3 ;get remainder from width/32 MOVEQ #-1,D1 ;default rightmost long mask TST.W D3 ;zero remainder? BEQ.S @0 ;yes, $FFFF is a good mask ADDQ.W #1,D0 ;we need one more long SUB.W D3,D7 ;32 - remainder = zero bits to shift in ASL.L D7,D1 ;get proper mask @0 MOVE.L D1,rightMask(A6) EXT.L D0 MOVE.L D0,rowLongs(A6) ;save # of longs ASL.L #2,D0 ;longs => bytes ;get the scanline buffer (D0 = number of bytes per line) _NewHandle clear ;get a scanline buffer (of zeroes) BNE BMRBadEmpty ;if we failed then return a NIL handle MOVE.L A0,slHandle(A6) ;save buffer handle ;figure the number of lines MOVE.L D2,D3 SWAP D3 ;get top MOVE.W bounds+bottom(A1),D0 ;get bottom SUB.W D3,D0 ;bottom - top BLE BMREmptyOut ;if empty rect. then empty region MOVE.W D0,numLines(A6) ;number of lines MOVE.L baseAddr(A1),A4 ;point to start of map MOVE.W #rgnData,D7 ;initial region size ;OK, now we start the loops. ; A1 will point to the bitmap long, ; A2 to the region. ; A3 points to the current scanline buffer long. ; A4 will point to the row in the map. ; A5 points to the current word (= size + A2) ; D1 holds the current long (modified). ; D2 holds the leftmost coordinate of bitmap.bounds. ; D3 has the y coordinate, and ; D4 the x coordinate (high word stays clear!). ; D5 has number of longs remaining for current line. ; D6 holds the (on or off) value of the "beam" (for the line). ; D7 holds the size outside the longword loop (used as scratch while nibbling). ; (we assume at the very end that D7's high word has remained clear) BMRHScramLine MOVE.L regionH(A6),A2 MOVE.L (A2),A2 ;point to start of region BMRLineLoop LEA (A2,D7.W),A5 ;point to new region start + size MOVE.L handSize(A6),D1 ;get handle size SUB.W D7,D1 ;handle size - region size CMP.L max2Add(A6),D1 ;is there enough for worst case on next line? BGE.S @1 ;skippy if so MOVE.L handSize(A6),D0 ;get handle size ADD.L max2Add(A6),D0 ;add more than enough for worst case on next line MOVE.L D0,handSize(A6) ;save new size MOVE.L regionH(A6),A0 ;region handle _SetHandleSize BNE BMRBadEmpty ;if we failed then return a NIL handle BRA.S BMRHScramLine ;rederef. handle and recompute current pointer @1 MOVE.W D2,D4 ;get current x coordinate from left MOVEQ #0,D6 ;beam initially off MOVE.L A4,A1 ;start of current line into map pointer MOVE.L rowLongs(A6),D5 ;longs remaining for current line MOVE.L slHandle(A6),A3 ;A3 points to the current "differences" long MOVE.L (A3),A3 ; Note: within this loop we assume that nothing will be done to move the heap MOVE.W D3,D0 ;get y position BSR OutputRgnWord ;output y pos to region MOVE.W D7,startSize(A6) ;save size at line start (a la Derwood) BRA NextBMRLong ;enter the long loop BMRLongLoop MOVE.L (A1)+,D0 ;fetch the next long for this line BMRLastLEntry MOVE.L (A3),D1 ;get differences long EOR.L D0,D1 ;compute the differences BNE BMRDiff ;if not the same, skip ahead BMRSame ;since we want to skip this long (it matches the previous line) we need to ;put out an ip if the beam is on TST.B D6 ;beam on? BEQ.S @1 ;skip if not MOVE.W D4,(A5)+ ;pump it out MOVEQ #0,D6 ;beam off @1 ADD.W #32,D4 ;slip to next long's x coordinate @2 ADDQ.W #4,A3 ;to next changes buffer long BRA NextBMRLong ;---------------------------------------------------------------------------------------- ; Start of State Machine ; Handle state 0001 BMRState1 ADDQ.W #3,D4 ;bump x by 3 State1Common MOVE.W D4,(A5)+ ;generate one ;Tog1StateDone ADDQ.W #1,D4 ;bump x by one more TogStateDone NOT.B D6 ;toggle state RTS ; Handle state 0010 BMRState2 ADDQ.W #2,D4 ;bump x by 2 MOVE.W D4,(A5)+ ;generate one Gen1BumpBy1 BSR.S Gen1InvPoint ;and another one BumpBy1 ADDQ.W #1,D4 ;bump once more RTS ;state doesn't change ; Handle state 0011 BMRState3 ADDQ.W #2,D4 ;bump x by 2 MOVE.W D4,(A5)+ ;generate one ADDQ.W #2,D4 ;bump BRA.S TogStateDone ;toggle the state ; Handle state 0100 BMRState4 BSR.S Gen1InvPoint BSR.S Gen1InvPoint BumpBy2 ADDQ.W #2,D4 RTS ; Handle state 0101 BMRState5 BSR.S BMRState4 ;start out as state 4 SUBQ #1,D4 BRA.S State1Common ;use common code ; Handle state 0110 BMRState6 BSR.S Gen1InvPoint ADDQ.W #1,D4 BRA.S Gen1BumpBy1 ; Handle state 0111 BMRState7 BSR.S Gen1InvPoint ADDQ.W #3,D4 BRA.S TogStateDone ; Gen1InvPoint bumps x by one and then generates a horizontal inversion point Gen1InvPoint ADDQ.W #1,D4 ;bump by 1, first MOVE.W D4,(A5)+ ;add x value (ip) to region RTS ; Handle State 1000 BMRState8 MOVE.W D4,(A5)+ BSR.S Gen1InvPoint ADDQ.W #3,D4 RTS ; Handle State 1001 BMRState9 MOVE.W D4,(A5)+ BSR.S Gen1InvPoint ADDQ.W #2,D4 BRA.S State1Common ; Handle State 1010 (most complicated case) BMRState10 MOVE.W D4,(A5)+ BSR.S Gen1InvPoint BSR.S Gen1InvPoint BRA.S Gen1BumpBy1 ; Handle State 1011 BMRState11 MOVE.W D4,(A5)+ BSR.S Gen1InvPoint BSR.S Gen1InvPoint ADDQ.W #2,D4 BRA.S TogStateDone ; Handle State 1100 BMRState12 MOVE.W D4,(A5)+ ADDQ.W #2,D4 MOVE.W D4,(A5)+ BRA.S BumpBy2 ; Handle State 1101 BMRState13 BSR.S BMRState12 SUBQ #1,D4 BRA.S State1Common ; Handle State 1110 BMRState14 MOVE.W D4,(A5)+ ADDQ.W #3,D4 MOVE.W D4,(A5)+ BRA.S BumpBy1 ; State table BMRHandler BRA.S BMRState0 BRA.S BMRState1 BRA.S BMRState2 BRA.S BMRState3 BRA.S BMRState4 BRA.S BMRState5 BRA.S BMRState6 BRA.S BMRState7 BRA.S BMRState8 BRA.S BMRState9 BRA.S BMRState10 BRA.S BMRState11 BRA.S BMRState12 BRA.S BMRState13 BRA.S BMRState14 ; Handle State 15 or 1111 BMRState15 MOVE.W D4,(A5)+ ;generate one now NOT.B D6 ;toggle the state ; Handle State 0 or 0000 BMRState0 ADDQ.W #4,D4 RTS ; End of the State Guys ;---------------------------------------------------------------------------------------- BMRDiff MOVE.L D0,(A3)+ ;fix up scanline buffer for next time ; this long is different from the last one, so output a bunch ; of inversion points by pumping it through the state machine, a nibble ; at a time. MOVEQ #3,D7 ;4 bytes to process (D7 high word clear) MOVEQ #0,D0 ;prevent need to mask for first nibble ; here is the loop where we feed it through a nibble at a time. ; it's worth it to special case a whole byte of 0 BMRByteLoop ROL.L #8,D1 ;get next (topmost) byte TST.B D1 ;is it zero? BNE.S BMRNibble ;if not, 4 bits at a time TST.B D6 BNE.S BMRNibble ;if beam on, must pass through ;the top 8 are zero, so we can save some time ADDQ.W #8,D4 ;bump x BRA.S BMRNextByte ;take care of the rightmost long for a line BMRLastLong MOVE.L (A1),D0 ;fetch the long from the bitmap AND.L rightMask(A6),D0 ;mask off right bits that aren't in map BRA BMRLastLEntry ;go process this long ; handle the first nibble BMRNibble MOVE.B D1,D0 ;get byte EOR.B D6,D0 ;invert nibble when beam is on LSR.B #4,D0 ;get 1st nibble ADD.W D0,D0 ;double for word index JSR BMRHandler(D0.W) ;invoke the handler ; handle the second nibble MOVE.B D1,D0 ;get byte again EOR.B D6,D0 ;invert nibble when beam is on AND.W #%1111,D0 ;mask to it ADD.W D0,D0 ;double for word index JSR BMRHandler(D0.W) ;invoke the handler BMRNextByte DBRA D7,BMRByteLoop ;loop for all 8 nibbles ; bump to the next long NextBMRLong SUBQ.W #1,D5 ;decrement longword index BGT BMRLongLoop ;not at end, loop for whole line BEQ.S BMRLastLong ;process last long for this line ; we've reached the end of the (this) line BMREOL MOVE.W A5,D7 ;current region pointer SUB.W A2,D7 ;figga region size CMP.W startSize(A6),D7 ;did we add inv. pts to this line? BEQ.S BMRNoLine ;br = no, so back up BLT BMR32KErr ;if the size decreased, we overflowed ; if the state is on, generate one last inversion point TST.B D6 BEQ.S @1 MOVE.W D4,(A5)+ ;generate a last one ADDQ.W #2,D7 ;keep sizable advantage @1 ; end the scan line with the traditional $7FFF BSR.S OutputLastRgnWord BMREOL2 ADDQ.W #1,D3 ;bump y position MOVE.W D2,D4 ;start x at left again ADD.W rowNumBytes(A6),A4 ;bump to next row in map SUBQ.W #1,numLines(A6) BGT BMRLineLoop ;if we're not done then do next line BLT.S BMRFinis ;br if really done ; as the last line process an imaginary line of zeroes to end the region… MOVE.L rowLongs(A6),D0 ASL.L #2,D0 ;longs => bytes _NewHandle clear ;get a full line of zero bits BNE.S BMRBadEmpty ;if we failed then return a NIL handle MOVE.L A0,lastLineH(A6) ;save handle MOVE.L (A0),A4 ;start of current line BRA BMRHScramLine ;do this last one (and rederef handle) BMRNoLine SUBQ.L #2,A5 ;back up pointer SUBQ.W #2,D7 ;back down size BRA.S BMREOL2 ;go for next line ; Append the "end of line" token to the region OutputLastRgnWord MOVE.W #$7FFF,D0 ; OutputRgnWord takes the word in D0, appends it to the region, ; and leaves the condition codes set for ADDQ.W D7 (which contains the length) OutputRgnWord MOVE.W D0,(A5)+ ;put a word to the region ADDQ.W #2,D7 ;ink the size RTS ; all done so clean up, output the final $7FFF BMRFinis MOVE.L lastLineH(A6),A0 _DisposHandle ;get rid of that last line of zeroes CMP.W #10,D7 ;is region empty of inversion points? BEQ.S BMREmptyOut ;skip if so (it's an empty region) BSR.S OutputLastRgnWord ;put End-O-Region ($7FFF) word BMI.S BMR32KErr ;if we went negative, we overflowed! ; find the smallest rectangle that encompasses all the inversion points ; A0 will point to the current region word, A1 to the start of the line ; D1 will have the smallest x, D2 the largest x, D4 will contain $7FFF ; D3 gets the smallest y value (which we know at the start) LEA rgnData(A2),A0 ;point A0 past the rgnBBox MOVE.W #$7FFF,D4 MOVE.W D4,D1 ;smallest x so far = $7FFF MOVE.W #$8000,D2 ;largest x so far = -32768 MOVE.W (A0),D3 ;smallest y there is BRA.S BMRPackStart ;enter loop BMRPackY MOVE.L A0,A1 ;remember where the y value is (sort of) CMP.W (A0)+,D1 ;less than smallest x so far? BLE.S @1 ;skip if not MOVE.W -2(A0),D1 ;new smallest x @1 CMP.W (A0)+,D4 ;end of line? BNE.S @1 ;if not then keep looking CMP.W -4(A0),D2 ;last x greater than largest x so far? BGE.S BMRPackStart ;skip if not MOVE.W -4(A0),D2 ;new largest x BMRPackStart MOVE.W (A0)+,D0 ;get next word (y value or $7FFF) CMP.W D4,D0 ;if $7FFF then we're done BNE.S BMRPackY ;otherwise loop SWAP D3 ;top into top word MOVE.W D1,D3 ;left into bottom word MOVE.W -2(A1),D4 ;bottom (from last y at start of line) SWAP D4 ;move bottom to high word MOVE.W D2,D4 ;get right CMP.W #28,D7 ;size = 28? (do we have a rect. region?) BEQ.S BMRRect ;skip if so BRA.S BMROut ;return complex region ;the region would exceed 32K, so we have to error out, man BMR32KErr MOVE.W #rgnTooBigErr,D0 ;if >32K needed return error ;we come here after failing a SetHandleSize (or NewHandle) BMRBadEmpty MOVE.W D0,result(A6) ;OSErr function result ; emptify the region on errors (or when it should be empty with no error) BMREmptyOut MOVE.L regionH(A6),A0 ;handle to region MOVE.L (A0),A2 ;point to it CLR.L D3 ;(0, 0) to topLeft CLR.L D4 ;(0, 0) to botRight BMRRect MOVEQ #10,D7 ;the size of the region = 10 ;output the region with size (longword, high word clear) in D7 ;D3 comes in with topLeft, D4 with botRight BMROut MOVE.W D7,(A2)+ ;the size of the region MOVE.L D3,(A2)+ ;topLeft to rgnBBox MOVE.L D4,(A2) ;botRight to rgnBBox MOVE.L D7,D0 ;size MOVE.L regionH(A6),A0 ;handle to region _SetHandleSize BMRDspSL MOVE.L slHandle(A6),A0 _DisposHandle ;get rid of the scanline buffer (even if NIL) BMRDone MOVEM.L (SP)+,A2-A5/D3-D7 ;restore work registers UNLK A6 MOVE.L (SP)+,A0 ;pop return address ADD #paramSize,SP ;pop params JMP (A0) ENDWITH END