mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-30 14:34:35 +00:00
4325cdcc78
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.
1821 lines
53 KiB
Plaintext
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
|
|
|
|
|
|
|
|
|