mac-rom/QuickDraw/Classic/Regions.m.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

1821 lines
53 KiB
Plaintext

;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