QuickDraw/Regions.a

1171 lines
50 KiB
Plaintext
Executable File

.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