mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 01:49:19 +00:00
2187 lines
66 KiB
Plaintext
2187 lines
66 KiB
Plaintext
;
|
||
; File: Regions.a
|
||
;
|
||
; Contains: QuickDraw routines to operate on regions.
|
||
;
|
||
; Copyright: © 1981-1992 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM4> 1/25/93 kc Roll in Shannon Holland's alpha channel fix to DrawRgn.
|
||
; <SM3> 6/11/92 stb <sm 6/9/92>stb Synch with QDciPatchROM.a; comments added to
|
||
; StdRgn, MapRgn
|
||
; <SM2> 5/21/92 kc Change the name of QuickDraws wrapper for NewHandle to
|
||
; NewHandleWrapper to avoid name conflict with the glue.
|
||
; <10> 8/22/91 JSM Don’t use TRUE and FALSE as labels.
|
||
; <9> 7/23/91 KON Fix 32-bit clean crimes in BitMapRgn.
|
||
; <8> 10/30/90 KON Forgot to make all the changes before checking in; This updates
|
||
; to the current version on the ci in QDciPatch. [SMC]
|
||
; <7> 10/30/90 KON Make pmVersion=4 pixmaps work and create rgns as large as 64K
|
||
; (not 32K).
|
||
; <6> 9/7/90 KON Fix misleading comment and enter Comment of the Week contest.
|
||
; <5> 9/7/90 KON Don't remap wideopen rectangular regions since maprect will blow
|
||
; up.
|
||
; <4> 8/28/90 KON Remove benign redefinition of pixmapTooDeepErr (-148) which is
|
||
; now defined in SysErr.a.
|
||
; <3> 8/2/90 gbm change TEMPRECT to TEMPRECTANGLE to avoid global conflict
|
||
; <2> 7/24/90 gbm axe duplicate defs
|
||
; <•1.6> 7/14/89 BAL For Aurora: Final CQD
|
||
; <1.5> 6/30/89 BAL Now uses equate for qdStackXtra
|
||
; <•1.4> 5/29/89 BAL Blasting in 32-Bit QuickDraw version 1.0 Final
|
||
; 9/26/88 BAL Provided RectWithinRgn, a variant of TrimRect
|
||
; 9/25/88 BAL Rewrote TrimRect for a better than 5X performance improvement
|
||
; 11/8/87 DAF Fixed pict opcode recorded by StdRgn
|
||
; 6/4/87 CRC set patMode even if user forgets to
|
||
; 1/3/87 CRC pass color param to stretch
|
||
; 10/9/86 EHB Added mask parameters to stretchbits calls
|
||
; 9/5/86 EHB Added FillCRgn
|
||
; 8/16/86 EHB In FillRgn added support for color grafports
|
||
; 6/18/86 EHB Fixed up references to PortBits in DrawRgn for color ports Call
|
||
; StretchBits instead of RgnBlt
|
||
;
|
||
|
||
BLANKS ON
|
||
STRING ASIS
|
||
|
||
;-----------------------------------------------------------
|
||
;
|
||
;
|
||
; **** ***** *** *** *** * * ***
|
||
; * * * * * * * * * * * *
|
||
; * * * * * * * ** * *
|
||
; **** *** * ** * * * * * * ***
|
||
; * * * * * * * * * ** *
|
||
; * * * * * * * * * * * *
|
||
; * * ***** *** *** *** * * ***
|
||
;
|
||
;-----------------------------------------------------------
|
||
|
||
StdRgn PROC EXPORT
|
||
IMPORT PutPicVerb,DPutPicOp,PutPicRgn
|
||
IMPORT PutRgn,FrRgn,PushVerb,DrawRgn,StdDevLoop
|
||
;---------------------------------------------------------------
|
||
;
|
||
; PROCEDURE StdRgn(verb: GrafVerb; rgn: RgnHandle);
|
||
;
|
||
; A6 OFFSETS OF PARAMS AFTER LINK:
|
||
;
|
||
; has fix from QDciPatchROM.a <sm 6/9/92>stb
|
||
|
||
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
|
||
MOVEQ #0,D7 ;CLEAR LOWORD OF PICT OPCODE <C952/08Nov87> DAF
|
||
MOVE.B VERB(A6),D7 ;GET VERB
|
||
_CheckPic ;SET UP A4,A3 AND CHECK PICSAVE
|
||
BLE.S NOTPIC ;BRANCH IF NOT PICSAVE
|
||
|
||
MOVE.B D7,-(SP) ;PUSH VERB
|
||
JSR PutPicVerb ;PUT ADDITONAL PARAMS TO THEPIC
|
||
MOVE #$80,D0 ;PUT RGNNOUN IN HI NIBBLE
|
||
ADD D7,D0 ;PUT VERB IN LO NIBBLE
|
||
JSR DPutPicOp ;PUT OPCODE TO THEPIC
|
||
MOVE.L RGN(A6),-(SP) ;PUSH RGNHANDLE
|
||
JSR PutPicRgn ;PUT REGION TO THEPIC
|
||
|
||
; CALL STANDARD LOOP TO DRAW TO ALL DEVICES
|
||
|
||
NOTPIC PEA StdDraw ;PUSH ADDRESS OF DRAW ROUTINE
|
||
PEA GetRect ;PUSH ADDRESS OF RECT ROUTINE
|
||
_StdDevLoop ;DRAW TO ALL DEVICES
|
||
|
||
GOHOME MOVEM.L (SP)+,D6-D7/A2-A4 ;RESTORE REGS
|
||
UNLINK PARAMSIZE,'STDRGN '
|
||
|
||
|
||
;---------------------------------------------------------------
|
||
;
|
||
; PROCEDURE GetRect(VAR theRect: rect);
|
||
;
|
||
; RETURN THE OBJECT'S RECTANGLE
|
||
;
|
||
GetRect MOVE.L (SP)+,D0 ;GET RETURN ADDRESS
|
||
MOVE.L (SP)+,A1 ;GET DST RECT
|
||
MOVE.L RGN(A6),A0 ;GET REGION
|
||
MOVE.L (A0),A0 ;POINT AT IT
|
||
LEA RGNBBOX(A0),A0 ;POINT TO BOUNDING BOX
|
||
MOVE.L (A0)+,(A1)+ ;SET TOPLEFT
|
||
MOVE.L (A0),(A1) ;SET BOTRIGHT
|
||
MOVE.L D0,A0 ;GET RETURN ADDRESS
|
||
JMP (A0) ;AND RETURN
|
||
|
||
|
||
;---------------------------------------------------------------
|
||
;
|
||
; PROCEDURE StdDraw;
|
||
;
|
||
; DRAW THE OBJECT
|
||
;
|
||
StdDraw MOVE.L RGN(A6),-(SP) ;PUSH RGNHANDLE
|
||
_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
|
||
_PutRgn ;ADD INVERSION PTS TO THERGN
|
||
|
||
NOTRGN JSR FrRgn ;FrRgn(rgn,pnMode,pnPat)
|
||
BRA.S drawDone
|
||
|
||
NOTFR JSR DrawRgn ;DrawRgn(rgn,mode,pat);
|
||
drawDone
|
||
DONE RTS
|
||
|
||
|
||
|
||
FrameRgn PROC EXPORT
|
||
EXPORT CallRgn,PaintRgn,EraseRgn,InvertRgn,FillRgn,FillCRgn
|
||
IMPORT SetFillPat
|
||
;-----------------------------------------------------
|
||
;
|
||
; 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 MOVEQ #0,D0 ;FLAG = FillRgn
|
||
BRA.S SHARE ; => USE COMMON CODE
|
||
|
||
|
||
;----------------------------------------------------------
|
||
;
|
||
; PROCEDURE FillCRgn(rgn: RgnHandle; PPH: PixPatHandle);
|
||
;
|
||
FillCRgn MOVEQ #1,D0 ;FLAG = FillCRgn
|
||
|
||
SHARE 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 A1,-(SP) ;PUSH ADDR OF PATTERN
|
||
_SETFILLPAT ;FILLPAT := PAT
|
||
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 STRETCHBITS
|
||
IMPORT PortToMap
|
||
;--------------------------------------------------------
|
||
;
|
||
; 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
|
||
|
||
BBOX EQU -8 ;LOCAL COPY OF RGNBBOX
|
||
VARSIZE EQU BBOX ;SIZE OF LOCALS
|
||
|
||
LINK A6,#VARSIZE ;ALLOCATE STACK FRAME
|
||
MOVE.L RGN(A6),A0 ;GET THE REGION HANDLE
|
||
MOVE.L (A0),A0 ;POINT TO THE RGN
|
||
MOVE.L RGNBBOX(A0),BBOX(A6) ;COPY RGNBBOX.TOPLEFT
|
||
MOVE.L RGNBBOX+4(A0),BBOX+4(A6) ;COPY RGNBBOX.BOTRIGHT
|
||
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
|
||
MOVE.L A0,A1 ;SAVE A COPY
|
||
_PORTTOMAP ;GET BIT/PIXMAP IN A0
|
||
MOVE.L A0,-(SP) ;PUSH SRCBITS
|
||
CLR.L -(SP) ;NO MASKBITS
|
||
MOVE.L A0,-(SP) ;PUSH DSTBITS
|
||
PEA BBOX(A6) ;PUSH SRCRECT
|
||
CLR.L -(SP) ;NO MASKRECT
|
||
PEA BBOX(A6) ;PUSH DSTRECT
|
||
MOVE MODE(A6),D1 ;PUSH MODE ; <SM4>
|
||
OR #$8,D1 ;set the pattern bit in case the user forgot to ; <SM4>
|
||
_GetStreamMode ;strip mode ; <SM4>
|
||
MOVE.W D1,-(SP) ;save stripped mode ; <SM4>
|
||
MOVE.L PAT(A6),-(SP) ;PUSH PAT
|
||
MOVE.L CLIPRGN(A1),-(SP) ;PUSH CLIPRGN
|
||
MOVE.L VISRGN(A1),-(SP) ;PUSH VISRGN
|
||
MOVE.L RGN(A6),-(SP) ;PUSH RGN
|
||
CLR -(SP) ;pass multicolor flag false
|
||
_STRETCHBITS ;CALL STRETCHBITS
|
||
DONE UNLINK PARAMSIZE,'DRAWRGN '
|
||
|
||
|
||
|
||
FrRgn PROC EXPORT
|
||
IMPORT FrmRect,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
|
||
bsr.l FRMRECT ;FRAME IT
|
||
BRA.S DONE ;AND QUIT
|
||
|
||
NOTRECT CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT
|
||
_NEWRGN ;ALLOCATE TEMPRGN
|
||
MOVE.L (A7)+,D7 ;PUT TEMPRGN IN D7
|
||
MOVE.L RGN(A6),-(SP) ;PUSH RGN
|
||
MOVE.L D7,-(SP) ;PUSH TEMPRGN
|
||
_COPYRGN ;COPY RGN INTO TEMPRGN
|
||
MOVE.L D7,-(SP) ;PUSH TEMPRGN
|
||
MOVE.L PNSIZE(A3),-(SP) ;PUSH PNSIZE
|
||
_INSETRGN ;InsetRgn(tempRgn,pnSize);
|
||
MOVE.L RGN(A6),-(SP) ;PUSH RGN
|
||
MOVE.L D7,-(SP) ;PUSH TEMPRGN
|
||
MOVE.L D7,-(SP) ;PUSH TEMPRGN
|
||
_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 NewHandleWrapper
|
||
;---------------------------------------------------
|
||
;
|
||
; FUNCTION NewRgn;
|
||
; Allocate a new region and set it to the empty region.
|
||
; Altered not to SysErr; if memerr then return nil. <BAL/dvb/RAJ 03Mar89>
|
||
;
|
||
moveq #10,d0 ;pass BYTECOUNT=10
|
||
_NewHandle ;ALLOCATE A RELOCATABLE OBJECT
|
||
MOVE.L A0,4(SP) ;STORE INTO NEWRGN RESULT
|
||
tst.w d0
|
||
bne.s @retNil ;if couldn't get it, return nil
|
||
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)+
|
||
@retNil 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 NewHandleWrapper,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 NewHandleWrapper
|
||
MOVE.L (SP)+,RGNBUF(A4) ;RGNBUF := NEWHANDLE(RGNMAX)
|
||
_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
|
||
_SHOWPEN ;UNDO THE HIDEPEN FROM OPENRGN
|
||
MOVE RGNINDEX(A4),D0 ;GET CURRENT RGNINDEX
|
||
|
||
cmp.w #-147,qderr ;rgnTooBigErr? <BAL 28Apr89>
|
||
bne.s @rgnOK ;no, return the region <BAL 28Apr89>
|
||
moveq #0,d0 ;yes, return an empty region <BAL 28Apr89>
|
||
move d0,qdErr ;clear error so it doesn't bite us. <BAL 28Apr89>
|
||
|
||
@rgnOK 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
|
||
_SORTPOINTS ;QUICKSORT IN VH ORDER
|
||
MOVE.L (A3),-(SP) ;PUSH BUF POINTER
|
||
PEA PTCOUNT(A6) ;PUSH VAR PTCOUNT
|
||
_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
|
||
_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 NewHandleWrapper,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
|
||
_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 NewHandleWrapper ;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
|
||
_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
|
||
_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
|
||
_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 ([4*$ae+$e00]) ;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 RETTRUE ;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 RETFALSE ;DIFFERENT --> FALSE
|
||
AND #3,D0 ;GET 0..3 FINISH UP BYTES
|
||
BEQ.S RETTRUE ;IF NO MORE, WE MADE IT
|
||
LOOP2 CMPM.B (A0)+,(A1)+ ;COMPARE A BYTE
|
||
BNE.S RETFALSE ;BR IF DIFFERENT
|
||
SUB #1,D0
|
||
BNE.S LOOP2 ;LOOP LAST 1..3 BYTES
|
||
RETTRUE MOVE.L #1,D0 ;TRUE
|
||
BRA.S DONE
|
||
RETFALSE 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 NewHandleWrapper,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
|
||
;FALL INTO DORGNOP
|
||
|
||
|
||
;---------------------------------------------------------
|
||
;
|
||
; 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
|
||
;
|
||
TEMPRECTANGLE EQU -8 ;RECT
|
||
VARSIZE EQU TEMPRECTANGLE ;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
|
||
_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
|
||
_COPYRGN ;COPY RGNA INTO DSTRGN
|
||
BRA.S JDONE ;AND QUIT
|
||
ZERO MOVE.L A4,-(SP) ;PUSH DSTRGN
|
||
_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 TEMPRECTANGLE(A6) ;PUSH DST = TEMPRECTANGLE
|
||
_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 TEMPRECTANGLE(A6) ;PUSH TEMPRECTANGLE
|
||
_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 NewHandleWrapper ;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
|
||
_RGNOP
|
||
MOVE (SP)+,D6 ;GET PTCOUNT
|
||
|
||
MOVE.L A3,-(SP) ;PUSH PTBUF HANDLE
|
||
MOVE D6,-(SP) ;PUSH PTCOUNT
|
||
MOVE.L A4,-(SP) ;PUSH DSTRGN
|
||
_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
|
||
;--------------------------------------------------
|
||
;
|
||
; 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
|
||
_RSECT ;CALC INTERSECTION
|
||
BEQ.S GOHOME ;QUIT IF NO INTERSECTION
|
||
CMP #10,RGNSIZE(A1) ;IS REGION RECTANGULAR ?
|
||
BEQ.S RETTRUE ;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
|
||
_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
|
||
_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 RETTRUE ;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
|
||
_SEEKRGN ;NO, SEEK TO NEXT VERT CHANGE
|
||
BRA.S TESTBUF ;AND SEE IF IT IS NON-ZERO
|
||
|
||
RETTRUE 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'
|
||
|
||
|
||
IF 0 THEN
|
||
|
||
OldTrimRect FUNC EXPORT
|
||
|
||
IMPORT RgnOp,TrimRgn
|
||
;------------------------------------------------------
|
||
;
|
||
; 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
|
||
|
||
bra TrimRgn
|
||
|
||
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
|
||
_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
|
||
RTD #PARAMSIZE ;STRIP PARAMETERS AND RETURN
|
||
|
||
ENDIF
|
||
|
||
|
||
|
||
TrimRect FUNC EXPORT
|
||
;------------------------------------------------------
|
||
;
|
||
; FUNCTION TrimRgn(rgn: RgnHandle; VAR dstRect: Rect; Trim: integer): CCR TRISTATE;
|
||
;
|
||
; Quickly determine the complexity of the interection of a
|
||
; rectangle and a region. If the intersection is rectangular,
|
||
; return the intersection in dstRect.
|
||
;
|
||
; If Trim is false, dstRect will not be altered:
|
||
; NON-RECT will be returned if intersection ≠ dstRect
|
||
;
|
||
; RESULT IN CONDITION CODES:
|
||
;
|
||
; = RESULT RECTANGULAR
|
||
; < RESULT EMPTY
|
||
; > RESULT NON-RECT
|
||
;
|
||
; CLOBBERS: A0
|
||
;
|
||
; Does not call the storage allocator.
|
||
;
|
||
; 1. Allocate 2 inversion pair buffers on stack
|
||
; 2. Play rgn (trimmed to rect.left, right) into buffers until rect.top reached
|
||
; if more than 2 points in buffer -> NON-RECT result
|
||
; 3. Play rgn until rect.bottom,
|
||
; if pair in buffer changes -> NON-RECT result
|
||
; else if buffer empty then -> EMPTY/FULL result
|
||
; else Trimmed RECT result
|
||
;
|
||
; ASSUMES: RgnBBox completely encloses Rect
|
||
;
|
||
; NOTE: Only the sides of the dstRect are actually trimmed,
|
||
; no top/bottom trimming is performed
|
||
;
|
||
;
|
||
PARAMSIZE EQU 10
|
||
RGN EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE
|
||
DSTRECT EQU RGN-4 ;LONG, ADDR OF DSTRECT
|
||
TRIM EQU DSTRECT-2 ;WORD, SHOULD DST BE TRIMMED?
|
||
|
||
VARSIZE EQU 0
|
||
|
||
LINK A6,#VARSIZE ;ALLOCATE STACK FRAME
|
||
MOVEM.L D0-D7/A1-A5,-(SP) ;SAVE ALL REGS USED
|
||
MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT
|
||
MOVEM.L (A0),D4/D5 ;D4 = MinRect.Top, Left
|
||
;D5 = MinRect.Bottom, Right
|
||
MOVE.L D4,D6
|
||
SWAP D6 ;D6 = MinRect.Top
|
||
MOVE.L RGN(A6),A3 ;get RgnHandle
|
||
MOVE.L (A3),A3
|
||
MOVE.W RGNSIZE(A3),D2 ;get rgnSize in D2
|
||
CMP #10,D2 ;Rect Rgn?
|
||
BEQ DONE1 ;return with RECT intersect true
|
||
ADD #RGNDATA,A3 ;point at rgnData
|
||
|
||
_StackAvail ;get stack avail in D0.L
|
||
SUB.L #qdStackXtra,D0 ;subtract slop factor <1.5> BAL
|
||
EXT.L D2 ;make it long
|
||
CMP.L D2,D0 ;enough space?
|
||
BGE.S STKOK ;yes, go allocate
|
||
|
||
MOVE.W D5,D2
|
||
SUB.W D4,D2 ;get Right - Left
|
||
EXT.L D2 ;make it long
|
||
LSL.L #2,D2 ;2 max buffers = 2 (width * 2)
|
||
CMP.L D0,D2 ;enough space?
|
||
BLE.S STKOK ;yes, go allocate
|
||
|
||
; _debugger ;I wish I had a better solution here...
|
||
BRA DONE1 ;return with cc = GT => NON-RECT
|
||
|
||
STKOK LSR.L #1,D2 ;
|
||
BCLR #0,D2 ;make bufSize even
|
||
MOVE.L SP,A0 ;Save stack base in A0
|
||
SUB.L D2,SP ;allocate one buffer
|
||
MOVE.L SP,A4 ;remember buffer pointer
|
||
SUB.L D2,SP ;allocate one buffer
|
||
MOVE.L SP,A5 ;remember buffer pointer
|
||
|
||
;-------------------------------------------------------------
|
||
;
|
||
; Seek into region until ThisV >= minRect.Top
|
||
;;
|
||
|
||
MOVEQ #0,D2 ;init parity to out=even
|
||
MOVE.W #32767,D7 ;get a MAXINT for comparisons
|
||
MOVE.L A4,A1 ;set up src1 ptr
|
||
bra.s NXTV
|
||
|
||
EQUAL CMP D7,D0 ;ALL DONE ?
|
||
BNE.S XorScam ;no, go back for more
|
||
|
||
NXTV MOVE.W D7,(A1) ;flag end of buffer
|
||
|
||
CMP.W (A3)+,D6 ;is minRect.Top < thisV?
|
||
BLT.S INRECT ;yes, go check result
|
||
|
||
MOVE.L A4,A2 ;set up src1 ptr
|
||
MOVE.L A5,A1 ;set up dest ptr
|
||
EXG A4,A5 ;swap the point buffers
|
||
|
||
|
||
;-------------------------------------------------------------
|
||
;
|
||
; Each input scan is a sorted array of integers terminated by 32767.
|
||
;
|
||
; Combine region inversion point data (A3) with that in current
|
||
; buffer (A2) and place result in (A1). Discard inversion points not
|
||
; between Left = D4 and Right = D5. Eliminate duplicate points.
|
||
; Maintain count of inversion points to the left of D4 in D2.
|
||
;
|
||
; NOTE: This routine is similar to XorScan except that
|
||
; it trims the inversion pairs to minRect.Left, Right
|
||
;
|
||
|
||
XorScam MOVE (A2)+,D1 ;get next B
|
||
NEXTA MOVE (A3)+,D0 ;get next A
|
||
NEXT CMP D1,D0 ;find the leftmost
|
||
BEQ.S EQUAL ;equal points cancel
|
||
BLT.S ALESS ;A is less
|
||
BLESS MOVE D1,(A1)+ ;B is pre-clipped so put to dst
|
||
MOVE (A2)+,D1 ;get next B
|
||
BRA.S NEXT ;loop for more
|
||
ALESS CMP.W D4,D0 ;is A less than or equal to minRect.Left?
|
||
BLE.S FLIP ;yes, flip parity
|
||
CMP.W D0,D5 ;is A greater than or equal to minRect.Right?
|
||
BLE.S NEXTA ;yes, discard
|
||
MOVE D0,(A1)+ ;PUT A TO DST
|
||
;move.l a0,d0
|
||
;move.l a1,d3
|
||
;chk.l d0,d3 ;have we gone to far?
|
||
BRA.S NEXTA ;loop for more
|
||
FLIP ADDQ #1,D2 ;toggle even/odd state
|
||
BRA.S NEXTA ;loop for more
|
||
|
||
;-------------------------------------------------------------
|
||
;
|
||
; Scan through region pointed to by A3 until
|
||
; 1) Find an odd number of points to the left of D4 -or-
|
||
; 2) Find a point between D4 and D5 -or-
|
||
; 3) Find a MAXINT (D7)
|
||
;
|
||
|
||
Scam MOVE (A3)+,D0 ;get next A
|
||
CMP.W D4,D0 ;is A less than or equal to minRect.Left?
|
||
BLE.S FLIP2 ;yes, flip parity
|
||
CMP.W D0,D7 ;is A MAXINT?
|
||
BEQ.S NXTV2 ;go get next vert
|
||
CMP.W D0,D5 ;is A greater than or equal to minRect.Right?
|
||
BLE.S Scam ;yes, discard
|
||
BRA.S BAIL ;this would alter the result so bail
|
||
FLIP2 MOVE (A3)+,D0 ;get another A
|
||
CMP.W D4,D0 ;is it also less than or equal to minRect.Left?
|
||
BLE.S Scam ;yes, parity preserved
|
||
|
||
BAIL CMP.W #0,D7 ;NON-RECT, set CC GT and return
|
||
BRA.S DONE
|
||
|
||
|
||
;-------------------------------------------------------------
|
||
;
|
||
; If the initial scanline of intersection is rectangular then
|
||
; 'Scam' through the region until ThisV >= minRect.Bottom.
|
||
; Else abort and return a NON-RECT result
|
||
;;
|
||
|
||
INRECT
|
||
SUB.L A4,A1 ;Get pnt count * 2
|
||
MOVE A1,D3 ;make a copy
|
||
CMP #4,D3 ;is pnt count > 2?
|
||
BGT.S DONE ;NON-RECT so bail out
|
||
BLT.S RECT ;less than 2 pnts => rectangular so far
|
||
AND #1,D2 ;2 pnts => must check parity, is parity even?
|
||
BNE.S BAIL ;no, return NON-RECT
|
||
|
||
RECT MOVE.L D5,D6
|
||
SWAP D6 ;D6 = MinRect.Bottom
|
||
SUB #2,A3 ;back up to thisV
|
||
NXTV2 CMP.W (A3)+,D6 ;is thisV < minRect.Bottom?
|
||
BGT.S SCAM ;yes, go scan more of region
|
||
|
||
TST TRIM(A6) ;is trimming allowed?
|
||
BNE.S TRIMOK ;yes, go to it
|
||
TST D3 ;no, there must be zero points
|
||
BEQ.S NOTRIM ;check for empty/full result
|
||
BRA.S BAIL ;return failure
|
||
|
||
;-------------------------------------------------------------
|
||
;
|
||
; The entire intersection is complete and the result is still
|
||
; rectangular. First check for the trivial FULL/EMPTY intersections then
|
||
; process any partial rectangular intersections.
|
||
;
|
||
|
||
TRIMOK MOVE.L DSTRECT(A6),A1 ;point to dstRect
|
||
MOVE D2,D0 ;prepare for DONE2 fall thru
|
||
CMP #2,D3 ;How many words in scan buffer?
|
||
BLT.S NOTRIM ;none, go decide between full/empty
|
||
BGT.S TRIM2 ;two, must trim both left and right
|
||
;one, could be left or right
|
||
BTST #0,D0 ;check parity
|
||
BNE.S TRIMR ;odd, must trim right
|
||
|
||
MOVE (A4),Left(A1) ;even, trim left and return RECT
|
||
BRA.S DONE2
|
||
|
||
TRIM2 MOVE (A4)+,Left(A1) ;trim Left and then Right
|
||
TRIMR MOVE (A4),Right(A1) ;trim right and return RECT
|
||
BRA.S DONE2
|
||
|
||
NOTRIM MOVEQ #1,D0
|
||
AND D0,D2 ;make even/odd count 0/1
|
||
DONE2 CMP D0,D2 ;set cc LT if even, EQ if odd
|
||
DONE MOVE.L A0,SP ;strip buffers, restore stack ptr
|
||
DONE1 MOVEM.L (SP)+,D0-D7/A1-A5 ;RESTORE ALL REGS
|
||
UNLK A6 ;RELEASE STACK FRAME
|
||
RTD #PARAMSIZE ;STRIP PARAMETERS AND RETURN
|
||
|
||
|
||
|
||
|
||
|
||
|
||
MapRgn PROC EXPORT
|
||
IMPORT MapRect,NewHandleWrapper,PutRgn,MapPt
|
||
IMPORT SortPoints,CullPoints,PackRgn
|
||
;-------------------------------------------------------------
|
||
;
|
||
; PROCEDURE MapRgn(rgn: RgnHandle; fromRect,toRect: Rect);
|
||
;
|
||
; A6 OFFSETS OF PARAMETERS AND LOCALS AFTER LINK:
|
||
;
|
||
; fix from QDciPatchROM.a is in as <7Sept90 KON> <sm 6/9/92>stb
|
||
|
||
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 <7Sept90 KON>
|
||
;
|
||
NOTSAME MOVE.L RGN(A6),A4 ;GET RGNHANDLE <7Sept90 KON>
|
||
MOVE.L (A4),A0 ;DE-REFERENCE RGN <7Sept90 KON>
|
||
CMP #10,RGNSIZE(A0) ;IS RGN RECTANGULAR ? <7Sept90 KON>
|
||
BNE.S NOTRECT ;NO, CONTINUE <7Sept90 KON>
|
||
;
|
||
; Don't do anything if region is rectangular and wide open since MapRect will choke <7Sept90 KON>
|
||
; a0 points to rgn
|
||
;
|
||
cmp.l #$80018001,2(a0) ; <7Sept90 KON>
|
||
bne.s @notWide ; <7Sept90 KON>
|
||
cmp.l #$7fff7fff,6(a0) ;wide open?; <7Sept90 KON>
|
||
beq.s JDone ;Yes, Don't remap <7Sept90 KON>
|
||
@notWide
|
||
PEA RGNBBOX(A0) ;YES, PUSH RGNBBOX
|
||
MOVE.L FROMRECT(A6),-(SP) ;PUSH FROMRECT
|
||
MOVE.L TORECT(A6),-(SP) ;PUSH TO RECT
|
||
_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 NewHandleWrapper ;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
|
||
_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
|
||
_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
|
||
_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
|
||
_CULLPOINTS ;CullPoints(ptBuf^,ptCount)
|
||
|
||
MOVE.L A3,-(SP) ;PUSH PTBUF HANDLE
|
||
MOVE PTCOUNT(A6),-(SP) ;PUSH PTCOUNT
|
||
MOVE.L A4,-(SP) ;PUSH RGN
|
||
_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
|
||
|
||
|
||
;________________________________________________________________________________
|
||
;
|
||
|
||
; version of Tuesday, March 28, 1989
|
||
|
||
; Purpose:
|
||
; To convert bitmaps to regions.
|
||
;
|
||
; PRINT PUSH,OFF
|
||
; INCLUDE 'Traps.a'
|
||
; INCLUDE 'ToolEqu.a'
|
||
; INCLUDE 'QuickEqu.a'
|
||
; INCLUDE 'SysEqu.a'
|
||
; PRINT POP
|
||
; LOAD 'AIncludes.d'
|
||
|
||
|
||
;________________________________________________________________________________
|
||
;
|
||
; FUNCTION BitMapRgn(region:RgnHandle; bMap:BitMap): OSErr; INLINE $A8D7;
|
||
;
|
||
; 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
|
||
;
|
||
;________________________________________________________________________________
|
||
;
|
||
;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)
|
||
;
|
||
;________________________________________________________________________________
|
||
|
||
|
||
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.L 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
|
||
MMUSave ds.b 2 ;keep it even!
|
||
SrcPixMap ds.b PMREC+CTREC+20 ;room for pixmap and color table
|
||
|
||
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
|
||
;
|
||
; Convert bitmap/pixmap to a pixmap
|
||
;
|
||
move.l bMapPtr(a6),a1
|
||
lea SrcPixMap(a6),a2
|
||
_BitsToPix
|
||
|
||
;get boundary rectangle so we can tell how to process the bitmap
|
||
|
||
lea SrcPixMap(A6),A1 ;get bitmap pointer
|
||
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
|
||
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)
|
||
|
||
;
|
||
; goto 32-bit mode
|
||
;
|
||
moveq #true32b,d0 ;switch to 32 bit addressing
|
||
_rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2)
|
||
move.b d0,MMUsave(a6) ;save previous state for later
|
||
|
||
BMRHScramLine
|
||
MOVE.L regionH(A6),A2
|
||
MOVE.L (A2),d0
|
||
_StripAddress ;clean it up <9>
|
||
move.l d0,a2 ;point to start of region
|
||
|
||
BMRLineLoop
|
||
LEA (A2,D7.L),A5 ;point to new region start + size
|
||
|
||
MOVE.L handSize(A6),D1 ;get handle size
|
||
SUB.l 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
|
||
;
|
||
; go back to previous mode
|
||
;
|
||
move.b MMUsave(a6),d0 ;get previous MMU state in d0
|
||
_rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2)
|
||
|
||
MOVE.L handSize(A6),d0 ;save new size
|
||
MOVE.L regionH(A6),A0 ;region handle
|
||
_SetHandleSize
|
||
BNE BMRBadEmpty ;if we failed then return a NIL handle
|
||
;
|
||
; goto 32-bit mode
|
||
;
|
||
moveq #true32b,d0 ;switch to 32 bit addressing
|
||
_rSwapMMUMode
|
||
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.l 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.l A5,D7 ;current region pointer
|
||
SUB.l A2,D7 ;figga region size
|
||
CMP.l startSize(A6),D7 ;did we add inv. pts to this line?
|
||
BEQ.S BMRNoLine ;br = no, so back up
|
||
BLT BMR64KErr ;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.l #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.b MMUsave(a6),d0 ;get previous MMU state in d0 <9>
|
||
_rSwapMMUMode ;(can trash a0/a1/a2, d0/d1/d2) <9>
|
||
|
||
MOVE.L rowLongs(A6),D0
|
||
ASL.L #2,D0 ;longs => bytes
|
||
_NewHandle clear ;get a full line of zero bits
|
||
BNE BMRBadEmpty ;if we failed then return a NIL handle
|
||
MOVE.L A0,lastLineH(A6) ;save handle
|
||
MOVE.L (A0),A4 ;start of current line
|
||
;
|
||
; Since we just allocated this handle, there is no need to strip it since the flags are guaranteed
|
||
; to be zero.
|
||
;
|
||
moveq #true32b,d0 ;switch to 32 bit addressing <9>
|
||
_rSwapMMUMode ; <9>
|
||
BRA BMRHScramLine ;do this last one (and rederef handle)
|
||
|
||
BMRNoLine
|
||
SUBQ.L #2,A5 ;back up pointer
|
||
SUBQ.l #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.l D7 (which contains the length)
|
||
|
||
OutputRgnWord
|
||
MOVE.W D0,(A5)+ ;put a word to the region
|
||
ADDQ.l #2,D7 ;ink the size
|
||
RTS
|
||
|
||
|
||
; all done: Restore MMU Mode, clean up, and output the final $7FFF
|
||
;
|
||
BMRFinis
|
||
move.b MMUsave(a6),d0 ;get previous MMU state in d0
|
||
_rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2)
|
||
|
||
MOVE.L lastLineH(A6),A0
|
||
_DisposHandle ;get rid of that last line of zeroes
|
||
|
||
CMP.l #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
|
||
;
|
||
; check if rgn > 64K
|
||
;
|
||
cmp.l #$0000FFFF,d7
|
||
BGT.S BMR64KErr ;if larger than $FFFF, 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.l #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 64K, so we have to error out, man
|
||
BMR64KErr
|
||
move.b MMUsave(a6),d0 ;get previous MMU state in d0
|
||
_rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2)
|
||
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
|
||
|
||
ENDPROC
|