.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