mac-rom/QuickDraw/SeekMask.a

1665 lines
50 KiB
Plaintext
Raw Permalink Normal View History

;
; File: SeekMask.a
;
; Contains: xxx put contents here (or delete the whole line) xxx
;
; Written by: xxx put name of writer here (or delete the whole line) xxx
;
; Copyright: <09> 1981-1990 by Apple Computer, Inc., all rights reserved.
;
; This file is used in these builds: Mac32 Bigbang Sys606
;
; Change History (most recent first):
;
; <4> 9/18/90 BG Removed <2>. 040s are behaving more reliably now.
; <3> 7/20/90 gbm Change some identifiers to avoid conflicts with interfaces
; <2> 6/28/90 BG Added EclipseNOPs to deal with flakey 040s.
; <<3C>1.6> 7/14/89 BAL For Aurora: Final CQD
; <1.5> 6/30/89 BAL Now looks at runBuf(a6) to determine whether to use run clipping
; <<3C>1.4> 5/29/89 BAL Blasting in 32-Bit QuickDraw version 1.0 Final
; <<3C>1.3> 4/12/89 BAL Blasting in 32-Bit QuickDraw 1.0B1
; 11/5/88 BAL Added transfer direction (RUNBUMP) to SeekMask interface so
; appropriate run mask could be generated.
; 10/1/88 BAL Added RUNRTN, rtn to form n-bit run mask from 1-bit scan mask.
; 9/22/88 BAL Consolidated initialization of region state records. Moved code
; here from Drawline, drawarc, rgnblt, and stretch. Obviated the
; need for combinations other than A, AB, and ABC.
; 9/18/88 BAL Altered to use common stack frame file 'Drawing Vars.a'
; 12/1/86 EHB Redid SeekMask routines to avoid JSR's to SeekRgn (at the
; expense of a bunch of extra code)
; 10/9/86 EHB Added support for masks
; 7/5/86 EHB Added routine GETSEEK to set up all seekRgn information
; 6/15/86 EHB Removed scanbuf := RGNBUFFER (done externally, not in loop)
; 6/13/86 EHB New today Broken out from Drawline, drawarc, rgnblt, stretch
; Modified to expand result according to depth
BLANKS ON
STRING ASIS
MACHINE MC68020
;------------------------------------------------------------------
;
; --> SEEKMASK.a
;
;------------------------------------------------------------------
;------------------------------------------------------------------
;
; REGION CLIPPING
;
; When region clipping is being done, the drawing routine calls a routine
; that seeks to the current scanline in all necessary regions, ANDs all the
; regions together (with a mask too, if necessary), and then expands that
; one-bit scanline to the current screen depth so that it can be used as a
; pixel mask.
;
; The drawing routine first calls GETSEEK which places the routine that will
; do all this into SEEKMASK(A6). (All drawing routines which call this routine
; must have the same stack frame as defined in StretchBits.)
;
; GETSEEK sets up two routines: SEEKMASK(A6) which is the routine that combines
; the appropriate number of regions together, and EXRTN(A6), which expands a
; scanline to the proper depth and is called by the routine in SEEKMASK(A6).
;
;
; APPLYING A MASK TO THE REGION
;
; If a mask is to be combined with the regions, then DSTMASKBUF(A6) is non-zero
; and points to the mask for the current scanline. The mask is one bit deep
; and has been stretched, if necessary to the same size as the destination.
; Note that although SeekRgn seeks to the proper scanline of the regions within
; this routine, the proper scanline of the mask must be maintained externally
; to this routine.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RgnBlt and everyone else (stretch,drawline,drawarc) compute bufSize as: <C954> 08Nov87 BAL
;
; [ (minRect.right-minRect.left) div 32 + 1 ] * pixelsize - 1
;
; This will result in an excess of upto (pixelsize-1) longs to be accessed during the
; region masked drawing. Since region masks are created as long aligned 1-bit deep masks
; which are then expanded to the proper depth the RGNBUFFER on the stack must be the bulky
; size computed above (until seekMask is changed to be more intelligent) but the stackFrame
; variable bufSize which determines the width of the scanline actually written to can more
; accurately be computed as:
;
; [ (minRect.right-minRect.left) * pixelsize - 1 ] div 32
;
xGETSEEK PROC EXPORT
EXPORT GETSEEK,AllocRunBuf,gsRunTbl,gsExpTbl,gsSeekTbl
IMPORT SEEKRGN,SEEKUP,SEEKDOWN
IMPORT Table2,Table4
;-----------------------------------------------------------------------
;
&CurFile SETC 'SEEKMASK'
INCLUDE 'DrawingVars.a'
; Low stack space error exit routine
GetOutofTown
clr.l StackFree(a6) ;guarantee stretch won't come back
GetMoreStk
jmp ([goShow,a6]) ;go show the cursor and return
;-----------------------------------------------------------------------
;
; ALLOCATE A RUN BUFFER FOR RUN-MASK CLIPPING. <BAL 21Sep88>
; Requires DrawingVars stack frame for inputs
; Returns ptr to stack buffer in a0
; Called by GetSeek, ScaleBlt
;
; trashes: d0,d1,d2,a0
;
AllocRunBuf
move.l (sp)+,d2 ;get return address
moveq #0,d1 ;clear out high word
move.w BufSize(a6),d1 ;get longs in ScanBuf-1
addq.l #2,d1 ;get longs in ScanBuf+1
cmp.w #5,DstShift(a6) ;is dest 32 bits/pixel ?
beq.s @1 ;yes, size <= N/2 + 1
move.l d1,d0 ;no, compute size <= 3(N+1)/2
add.l d1,d1
add.l d0,d1
@1 lsr.l #1,d1
addq.l #3,d1 ;got long cnt, 2 for slop
SUB.L D1,STACKFREE(A6) ;IS THERE ENOUGH STACK?
bpl.s @stkOK
bsr.s GetMoreStk ;no, go look for more stack!
@stkOK
lsl.l #2,d1 ;convert to a byte count
sub.l d1,sp ;allocate the buffer
move.l sp,a0 ;return where RunBuf is
addq #4,a0 ;leave a long in front for hacking
jmp (za0,d2.l) ;go back
ALIGN Alignment
;-------------------------------------------------
;
; GetSeek(RgnHandle1, RgnHandle2, ..., HandleCount.L);
;
; SET UP ADDRESS OF SEEK ROUTINE IN SEEKMASK(A6)
; SET UP ADDRESS OF EXPAND ROUTINE IN EXRTN(A6)
;
; CLOBBERS: A0-A3,D0-D4
;
; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK:
;
; LINK DONE BY CALLER (STRETCHBITS, RGNBLT, ScaleBlt, DRAWLINE, DRAWARC, QuickPolys)
;
;
GETSEEK
MOVE.L 4(SP),D3 ;GET COUNT OF RGN HANDLES
LEA 12(SP,D3*4),A3 ;POINT TO FIRST RGN PARAM
LEA STATEA(A6),A1 ;POINT AT FIRST STATE RECORD
CLR D4 ;INIT ALL RGNS RECT
;-----------------------------------------------------------------------
;
; ALLOCATE A RUN BUFFER FOR RUN-MASK CLIPPING. <BAL 21Sep88>
;
tst.l runBuf(a6) ;are we run clipping? <1.5> BAL
beq.s NxtRgn ;no, don't allocate run buffer <1.5> BAL
_AllocRunBuf ;go do it
move.l a0,RunBuf(A6) ;remember where RunBuf is
;----------------------------------------------------------------------
;
; ALLOCATE BUFFERS AND INIT STATE RECORDS FOR EACH NON-RECT REGION
;
NXTRGN
MOVEQ #10,D0
MOVE.L -(A3),A0 ;GET RGNHANDLE
MOVE.L (A0),A0 ;DE-REFERENCE IT
CMP RGNSIZE(A0),D0 ;IS RGN RECTANGULAR ?
BEQ.S ARECT ;YES, SKIP IT
CMP #2,D3 ;IS THIS THE USER RGN?
BEQ.S NOTRECT ;YES, DON'T TRIM
MOVE.L (A3),-(SP) ;PUSH REGION HANDLE
PEA MINRECT(A6) ;PUSH ADDR OF MINRECT
CLR.W -(SP) ;pass Trim = False
_TRIMRECT ;CALL TRIMRECT (trashes a0)
blt.s GetOutofTown ;=>INTERSECTION EMPTY, QUIT & SHOW CURSOR
BEQ.S ARECT ;YES, SKIP IT
MOVE.L (A3),A0 ;GET RGNHANDLE
MOVE.L (A0),A0 ;DE-REFERENCE IT FOR INITRGN
NOTRECT
ADDQ.W #1,D4 ;NO, SET UP FLAG
ADD.W D4,D4 ;SAVE FLAGS
MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH
MOVE BUFLEFT(A6),D2 ;GET BUFLEFT
MOVEQ #0,D0 ;CLEAR HIGH WORD OF D3
MOVE D1,D0 ;GET RIGHT
SUB D2,D0 ;GET WIDTH IN DOTS
LSR #5,D0 ;CONVERT TO LONGS
SUB.L D0,STACKFREE(A6) ;IS THERE ENOUGH STACK?
bpl.s @stkOK
bsr.s GetMoreStk ;no, go look for more stack!
@stkOK
MOVE MINRECT+LEFT(A6),D0 ;GET MINH
_INITRGN ;INIT STATE, ALLOC BUFFER
SUB #RGNREC,A1 ;BUMP TO NEXT RGN STATE RECORD
ARECT
DBRA D3,NXTRGN ;LOOP FOR ALL ACTIVE REGIONS
;--------------------------------------------------------------------
;
; IF ALL REGIONS ARE RECTANGULAR, AND THERE IS NO MASK,
; THEN DRAW MINRECT INTO MASK BUFFER. IF THERE IS A MASK, THEN INIT
; STATE RECORD FOR REGION A, AND DRAW MINRECT THERE INSTEAD.
;
TST.L DSTMASKBUF(A6) ;IS THERE A MASK?
BEQ.S NOMASK
ADDQ #1,D4 ;ALTER RECTFLAG TO REFLECT MASK
MOVE.W D4,RECTFLAG(A6) ;SAVE FOR GETRTNS
CMP.W #1,D4 ;ARE ALL RGNS RECT?
BGT.S GETRTNS ;NO, ATLEAST ONE ACTIVE STATE REC
;A1 POINTS TO STATE RECORD A
;A0 POINTS TO A VALID RGN
MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH
MOVE BUFLEFT(A6),D2 ;GET BUFLEFT
MOVEQ #0,D0 ;CLEAR HIGH WORD OF D3
MOVE D1,D0 ;GET RIGHT
SUB D2,D0 ;GET WIDTH IN DOTS
LSR #5,D0 ;CONVERT TO LONGS
SUB.L D0,STACKFREE(A6) ;IS THERE ENOUGH STACK?
bpl.s @stkOK
bsr.s GetMoreStk ;no, go look for more stack!
@stkOK
MOVE MINRECT+LEFT(A6),D0 ;GET MINH
_INITRGN ;INIT STATE, ALLOC BUFFER
MOVEQ #0,D0 ;PIXEL SHIFT FOR MASK = 0
MOVE.L STATEA+SCANBUF(A6),A0 ;POINT TO RECT BUFFER
BRA.S DORECT
NOMASK
MOVE DSTSHIFT(A6),D0 ;GET THE DST DEPTH
tst.l runBuf(a6) ;are we run clipping? <1.5> BAL
beq.s @shiftOK ;no, use dstShift <1.5> BAL
moveq #0,d0 ;yes, RGNBUFFER is 1 bit/pixel <1.5> BAL
@shiftOK
MOVE.W D4,RECTFLAG(A6) ;ARE ALL RGNS RECT ?
BNE.S NOTRRGN ;NO, CONTINUE
MOVE.L RGNBUFFER(A6),A0 ;POINT TO REGION BUFFER
DORECT MOVE MINRECT+LEFT(A6),D3 ;SET UP LEFT
SUB BUFLEFT(A6),D3 ;MAKE IT BUFFER RELATIVE
MOVE MINRECT+RIGHT(A6),D4 ;SET UP RIGHT
SUB BUFLEFT(A6),D4 ;MAKE IT BUFFER RELATIVE
_XorSlab ;AND XOR BETWEEN THEM
BRA.S GETRTNS ;=>SKIP NEXT TEST
;---------------------------------------------------------------------
;
; IF ONLY ONE REGION IS NON-RECTANGULAR, AND THE DEPTH = 1, PLAY THE
; REGION DIRECTLY INTO THE MASK BUFFER (NO EXPANSION OR COMPOSITION).
;
NOTRRGN TST D0 ;IS DST PIXELSIZE ONE? <1.5> BAL
BNE.S USEEXP ;=>NO, DON'T PLAY INTO MASK BUFFER
CMP #2,D4 ;ONLY 1 NON-RECT RGN?
BNE.S GETRTNS ;NO, CONTINUE
MOVE.L RGNBUFFER(A6),STATEA+SCANBUF(A6) ;YES, PLAY DIRECTLY INTO MASK
BRA.S GETRTNS
;---------------------------------------------------------------------
;
; ATLEAST ONE NON-RECT REGION AND DEPTH > 1 SO MUST USE EXPAND ROUTINE
;
USEEXP OR #1,RECTFLAG(A6) ;FORCE USE OF EXRTN
;--------------------------------------------------------------------
;
; GET SEEK ROUTINE INTO SEEKMASK(A6)
; GET EXPAND ROUTINE INTO EXRTN(A6) FOR SEEK ROUTINE
;
GETRTNS
MOVE DSTSHIFT(A6),D0 ;GET SHIFT AMOUNT
move.l gsRunTblPtr,A0 ;GET ADDRESS OF ROUTINE TBL
add.l (a0,d0*4),A0 ;CALC ROUTINE BASED ON DEPTH
MOVE.L A0,RUNRTN(A6) ;RETURN RUN ROUTINE
tst.l runBuf(a6) ;are we run clipping? <1.5> BAL
beq.s @shiftOK ;no, use dstShift <1.5> BAL
moveq #0,d0 ;yes, RGNBUFFER is 1 bit/pixel <1.5> BAL
@shiftOK
SUB.L A0,A0 ;ASSUME NO EXPAND ROUTINE
SUB.L #8,A3 ;SKIP OVER LAST RGNHANDLE, COUNT
MOVE.L (A3),A1 ;GET RETURN ADDRESS
MOVE RECTFLAG(A6),D1 ;GET OFFSET TO SEEK ROUTINE
MOVE D0,D2 ;MAKE A COPY OF DSTSHIFT
OR D1,D2 ;ARE ALL RGNS RECT AND NO MASK AND 1 BIT DEEP?
BEQ.S GOTXRTN ;YES, NO EXRTN
move.l gsExpTblPtr,A0 ;GET ADDRESS OF ROUTINE TBL
add.l (a0,d0*4),A0 ;PASS BACK OFFSET TO THE ROUTINE
GOTXRTN MOVE.L A0,EXRTN(A6) ;RETURN ADDRESS OF EXPAND ROUTINE
move.l gsSeekTblPtr,A0 ;GET TBL FOR SEEK ROUTINES
cmp.w #7,d1
ble.s @modeOK
sub.w #10,d1 ;fold the entries for a smaller tbl
@modeOK add.l (a0,D1*4),A0 ;ADD OFFSET TO ROUTINE
MOVE.L A0,SEEKMASK(A6) ;RETURN SEEK ROUTINE
JMP (A1) ;AND RETURN
ALIGN 4
;-------------------------------------------------
;
; ROUTINES TO CONVERT A 1-BIT SCANLINE MASK TO
; A RUN MASK FOR THE CURRENT DEPTH
; Runs are computed for either forward or reverse blitting
;
gsRunTbl DC.L RUN1-gsRunTbl,RUN2-gsRunTbl,RUN4-gsRunTbl
DC.L RUN8-gsRunTbl,RUN16-gsRunTbl,RUN32-gsRunTbl
;-------------------------------------------------
;
; ROUTINES TO EXPAND A SCANLINE TO THE CURRENT DEPTH
;
gsExpTbl DC.L SINGLE-gsExpTbl,DOUBLE-gsExpTbl,QUAD-gsExpTbl
DC.L EIGHT-gsExpTbl,SIXTEEN-gsExpTbl,THRTWO-gsExpTbl
;-------------------------------------------------
;
; ROUTINES TO SEEK TO THE CURRENT SCANLINE OF ONE, TWO, OR THREE REGIONS,
; APPLY A MASK TO THAT SCANLINE, IF NECESSARY, AND THEN CALL THE ROUTINE
; IN EXRTN(A6) TO EXPAND TO THE CURRENT DEPTH.
;
gsSeekTbl DC.L SEEKOK-gsSeekTbl ; IF RECT RGN, NO MASK
DC.L RECTMASK-gsSeekTbl ; IF RECT RGN, MASK
DC.L A-gsSeekTbl
DC.L AX-gsSeekTbl
DC.L ABC-gsSeekTbl; B-gsSeekTbl
DC.L ABC-gsSeekTbl; BX-gsSeekTbl
DC.L AB-gsSeekTbl
DC.L AB-gsSeekTbl
; DC.L 0; C-gsSeekTbl
; DC.L 0; CX-gsSeekTbl
; DC.L 0; AC-gsSeekTbl
; DC.L 0; AC-gsSeekTbl
; DC.L 0; BC-gsSeekTbl
; DC.L 0; BC-gsSeekTbl
; DC.L ABC-gsSeekTbl
; DC.L ABC-gsSeekTbl
;--------------------------------------------------------------------
;
; REGION IS RECTANGULAR (ALREADY DRAWN INTO STATEA+SCANBUF)
; Return a large scancount in d2 so that seekmask is not called again.
;
SEEKOK move.w #$7fff,d2 ;return scan count = <20> <1.5> BAL
RTS
ALIGN Alignment
;--------------------------------------------------------------------
;
; REGION IS RECTANGULAR (ALREADY DRAWN INTO STATEA+SCANBUF) BUT THERE IS A MASK
; SO WE MUST COMBINE REGION WITH MASK AND EXPAND INTO RGNBUFFER.
;
RECTMASK MOVEM.L D3-D5/A4-A6,-(SP) ;SAVE WORK REGISTERS
MOVE.L STATEA+SCANBUF(A6),A1 ;POINT AT THE BUFFER
MOVE.L DSTMASKBUF(A6),D0 ;POINT AT THE MASK
MOVE STATEA+SCANSIZE(A6),D1 ;GET SIZE OF MASK IN LONGS
MOVE.L DSTMASKALIGN(A6),D5 ;GET ALIGNMENT
MOVE.L RGNBUFFER(A6),A0 ;EXPAND INTO RGNBUFFER
MOVE.L EXRTN(A6),A4 ;GET EXPAND ROUTINE
LEA RETRECTM,A5 ;GET RETURN ADDRESS FOR LOOP
MOVE.L D0,A6 ;GET MASK BUFFER
MOVEQ #0,D2 ;SCANLOOPS WANT D2=0
RECTMLOOP BFEXTU (A6){D5:0},D0 ;EXTRACT A LONG OF MASK
ADDQ #4,A6 ;BUMP TO NEXT MASK LONG
AND.L (A1)+,D0 ;GET RECTANGULAR REGION
JMP (A4) ;EXPAND DO INTO RGNBUFFER
RETRECTM DBRA D1,RECTMLOOP ;LOOP FOR ALL LONGS IN SRC
MOVEM.L (SP)+,D3-D5/A4-A6 ;RESTORE WORK REGISTERS
RDONE moveq #1,d2 ;return scan count = 1
RTS
ALIGN Alignment
;--------------------------------------------------------------------
;
; ONLY REGION A IS NON-RECTANGULAR. UPDATE IT AND USE IT AS THE MASK
;
; IF DEPTH = 1 THEN PLAY DIRECTLY INTO RGNBUFFER, ELSE PLAY INTO SCANBUF
; AND EXPAND INTO RGNBUFFER.
;
A LEA STATEA(A6),A1 ;POINT TO OUR STATE RECORD
MOVE VERT(A6),D0 ;GET VERT COORD
JMP SEEKRGN ;=>PLAY DIRECTLY INTO RGNBUFFER
;AND RETURN
AX MOVE VERT(A6),D0 ;GET VERT COORD
CMP STATEA+NEXTV(A6),D0 ;IS DESIRED VERT >= NEXTV ?
BGE.S AXDOWN ;YES, BUMP DOWNWARD
CMP STATEA+THISV(A6),D0 ;IS DESIRED VERT < CURRENT VERT ?
BLT.S AXUP ;YES, BUMP UPWARD
TST.L DSTMASKBUF(A6) ;IS THERE A MASK?
BEQ.S RDONE ;=>NO, NO CHANGE IN REGION
AXCHG MOVE.L STATEA+SCANBUF(A6),A1 ;ELSE GET THE BUFFER
MOVE STATEA+SCANSIZE(A6),D1 ;GET THE BUFFER SIZE
BRA.S CPY1BUF ;AND EXPAND INTO RGNBUFFER
AXDOWN LEA STATEA(A6),A1 ;POINT TO PROPER STATE RECORD
JSR SEEKDOWN ;SEEK DOWNWARD
BRA.S AXCHG ;=>GO EXPAND THE BUFFER
AXUP LEA STATEA(A6),A1 ;POINT TO PROPER STATE RECORD
JSR SEEKUP ;SEEK UPWARD
BRA.S AXCHG ;AND CONTINUE
CPY1BUF MOVE.L DSTMASKBUF(A6),D0 ;IS THERE A MASK?
BNE.S CPY1MASK ;=>YES, APPLY MASK TO REGIONS
; EXPAND 1 REGION INTO REGION BUFFER
MOVEM.L D2-D4/A4-A5,-(SP) ;SAVE WORK REGISTERS
MOVE.L RGNBUFFER(A6),A0 ;EXPAND INTO RGNBUFFER
MOVE.L EXRTN(A6),A4 ;GET EXPAND ROUTINE
LEA RETAX,A5 ;GET RETURN ADDRESS FOR LOOP
MOVEQ #0,D2 ;SCANLOOPS WANT D2=0
AXLOOP MOVE.L (A1)+,D0
JMP (A4) ;EXPAND DO INTO RGNBUFFER
RETAX DBRA D1,AXLOOP ;LOOP FOR ALL LONGS IN SRC
MOVEM.L (SP)+,D2-D4/A4-A5 ;RESTORE WORK REGISTERS
RTS
; COMBINE 1 REGION AND MASK AND EXPAND INTO REGION BUFFER
CPY1MASK MOVEM.L D3-D5/A4-A6,-(SP) ;SAVE WORK REGISTERS
MOVE.L RGNBUFFER(A6),A0 ;EXPAND INTO RGNBUFFER
MOVE.L EXRTN(A6),A4 ;GET EXPAND ROUTINE
LEA RETAXM,A5 ;GET RETURN ADDRESS FOR LOOP
MOVE.L DSTMASKALIGN(A6),D5 ;ALIGN MASK TO DST
MOVE.L D0,A6 ;GET MASK BUFFER
MOVEQ #0,D2 ;SCANLOOPS WANT D2=0
AXMLOOP BFEXTU (A6){D5:0},D0 ;EXTRACT A LONG OF MASK
ADDQ #4,A6 ;BUMP TO NEXT MASK LONG
AND.L (A1)+,D0 ;GET RECTANGULAR REGION
JMP (A4) ;EXPAND DO INTO RGNBUFFER
RETAXM DBRA D1,AXMLOOP ;LOOP FOR ALL LONGS IN SRC
MOVEM.L (SP)+,D3-D5/A4-A6 ;RESTORE WORK REGISTERS
moveq #1,d2 ;mask->force scan count = 1
RTS
ALIGN Alignment
;-------------------------------------------------------------------
;
; REGIONS A AND B ARE NON-RECTANGULAR. UPDATE EACH,
; THEN FORM INTERSECTION IN THE MASK BUFFER.
;
AB MOVE VERT(A6),D0 ;GET VERT COORD
LEA STATEA(A6),A1 ;POINT TO PROPER STATE RECORD
bsr.s SeekAny ;make scanBuf current
MOVE D2,-(SP) ;REMEMBER IF RGN CHANGED
LEA STATEB(A6),A1 ;POINT TO PROPER STATE RECORD
bsr.s SeekAny ;make scanBuf current
move (sp)+,d1 ;get previous result
cmp d2,d1 ;get d2=min(d1,d2)
bgt.s @min1
move d1,d2
@min1
ABCHG MOVE.L STATEA+SCANBUF(A6),A2
MOVE.L STATEB+SCANBUF(A6),A1
MOVE STATEA+SCANSIZE(A6),D1 ;GET THE BUFFER SIZE
CPY2BUF MOVE.L RGNBUFFER(A6),A0 ;FORM INTERSECTION IN RGNBUFFER
MOVE.L EXRTN(A6),D0 ;GET EXPAND ROUTINE
BNE.S ABX ;=>NEED TO EXPAND
ABLOOP MOVE.L DSTMASKBUF(A6),D0 ;IS THERE A MASK?
BNE.S ABM ;=>YES, APPLY MASK TO REGIONS
; COMBINE TWO REGIONS WITHOUT EXPANDING
MOVE.L (A2)+,D0
AND.L (A1)+,D0
MOVE.L D0,(A0)+
DBRA D1,ABLOOP
ABDONE RTS
; COMBINE TWO REGIONS AND A MASK WITHOUT EXPANDING
ABM MOVEM.L D5/A6,-(SP) ;SAVE WORK REGISTERS
MOVE.L DSTMASKALIGN(A6),D5 ;ALIGN MASK TO DST
MOVE.L D0,A6 ;GET MASK POINTER
ABMLOOP BFEXTU (A6){D5:0},D0 ;EXTRACT A LONG OF MASK
ADDQ #4,A6 ;BUMP TO NEXT MASK LONG
AND.L (A2)+,D0 ;GET FIRST REGION
AND.L (A1)+,D0 ;COMBINE WITH SECOND REGION
MOVE.L D0,(A0)+ ;AND PUT TO DST BUFFER
DBRA D1,ABMLOOP ;REPEAT FOR ALL LONGS
MOVEM.L (SP)+,D5/A6 ;RESTORE WORK REGISTERS
moveq #1,d2 ;mask->force scan count = 1
RTS
;-------------------------------------------------------------------
;
; Make scanBuf current for given vert (d0) and region state record (a1)
; May seek either up or down and returns count of valid scans for
; current direction in D2.
;
SeekAny CMP NEXTV(A1),D0 ;IS DESIRED VERT >= NEXTV ?
BGE SEEKDOWN ;YES, BUMP DOWNWARD
CMP THISV(A1),D0 ;IS DESIRED VERT < CURRENT VERT ?
BLT SEEKUP ;YES, BUMP UPWARD
move.w NEXTV(A1),D2 ;assume top to bottom
sub.w d0,d2 ;compute scan down count
tst.l DstRow(a6) ;seeking up or down?
bpl.s @ok ;d2 is OK
move.w d0,d2 ;
sub.w THISV(A1),D2 ;compute scan up count
addq.w #1,d2 ;
@ok rts
;-------------------------------------------------------------------
ABX MOVEM.L D2-D5/A4-A6,-(SP) ;SAVE WORK REGISTERS
MOVE.L DSTMASKBUF(A6),D2 ;IS THERE A MASK?
BNE.S ABXM ;=>YES, APPLY MASK TO REGIONS
; COMBINE TWO REGIONS AND EXPAND TO PROPER DEPTH
MOVE.L D0,A4 ;GET EXPAND ROUTINE
LEA RETABX,A5 ;GET RETURN ADDRESS FOR LOOP
MOVEQ #0,D2 ;SCANLOOPS WANT D2=0
ABXLOOP MOVE.L (A2)+,D0
AND.L (A1)+,D0
JMP (A4) ;EXPAND DO INTO RGNBUFFER
RETABX DBRA D1,ABXLOOP ;LOOP FOR ALL LONGS IN SRC
MOVEM.L (SP)+,D2-D5/A4-A6 ;RESTORE WORK REGISTERS
RTS
; COMBINE TWO REGIONS AND A MASK AND EXPAND TO PROPER DEPTH
ABXM MOVE.L D0,A4 ;GET EXPAND ROUTINE
LEA RETABXM,A5 ;GET RETURN ADDRESS FOR LOOP
MOVE.L DSTMASKALIGN(A6),D5 ;ALIGN MASK TO DST
MOVE.L D2,A6 ;GET ADDRESS OF MASK
MOVEQ #0,D2 ;SCANLOOPS WANT D2=0
ABXMLOOP BFEXTU (A6){D5:0},D0 ;EXTRACT A LONG OF MASK
ADDQ #4,A6 ;BUMP TO NEXT MASK LONG
AND.L (A2)+,D0
AND.L (A1)+,D0
JMP (A4) ;EXPAND DO INTO RGNBUFFER
RETABXM DBRA D1,ABXMLOOP ;LOOP FOR ALL LONGS IN SRC
MOVEM.L (SP)+,D2-D5/A4-A6 ;RESTORE WORK REGISTERS
moveq #1,d2 ;mask->force scan count = 1
RTS
ALIGN Alignment
;-------------------------------------------------------------------
;
; REGIONS A, B AND C ARE ALL NON-RECTANGULAR. UPDATE EACH,
; THEN FORM INTERSECTION IN THE MASK BUFFER.
;
ABC MOVE VERT(A6),D0 ;GET VERT COORD
LEA STATEA(A6),A1 ;POINT TO PROPER STATE RECORD
bsr.s SeekAny ;make scanBuf current
MOVE D2,-(SP) ;REMEMBER IF RGN CHANGED
LEA STATEB(A6),A1 ;POINT TO PROPER STATE RECORD
bsr.s SeekAny ;make scanBuf current
MOVE D2,-(SP) ;REMEMBER IF RGN CHANGED
LEA STATEC(A6),A1 ;POINT TO PROPER STATE RECORD
bsr.s SeekAny ;make scanBuf current
move (sp)+,d1 ;get previous result
cmp d2,d1 ;get d2=min(d1,d2)
bgt.s @min1
move d1,d2
@min1 move (sp)+,d1 ;get previous result
cmp d2,d1 ;get d2=min(d1,d2)
bgt.s @min2
move d1,d2
@min2
ABCCHG MOVE.L STATEA+SCANBUF(A6),A3
MOVE.L STATEB+SCANBUF(A6),A2
MOVE.L STATEC+SCANBUF(A6),A1
MOVE.L RGNBUFFER(A6),A0
MOVE STATEC+SCANSIZE(A6),D1 ;GET THE BUFFER SIZE (ALL SAME SIZE)
MOVE.L EXRTN(A6),D0 ;GET EXPAND ROUTINE
BNE ABCX ;=>NEED TO EXPAND
MOVE.L DSTMASKBUF(A6),D0 ;IS THERE A MASK?
BNE.S ABCM ;=>YES, APPLY MASK
; COMBINE 3 REGIONS INTO REGION BUFFER WITHOUT EXPANDING
ABCLOOP MOVE.L (A3)+,D0
AND.L (A2)+,D0
AND.L (A1)+,D0
MOVE.L D0,(A0)+
DBRA D1,ABCLOOP
RTS
; COMBINE 3 REGIONS AND MASK INTO REGION BUFFER WITHOUT EXPANDING
ABCM MOVEM.L D5/A6,-(SP) ;SAVE WORK REGISTERS
MOVE.L DSTMASKALIGN(A6),D5 ;ALIGN MASK TO DST
MOVE.L D0,A6 ;GET ADDRESS OF MASK
ABCMLOOP BFEXTU (A6){D5:0},D0 ;EXTRACT A LONG OF MASK
ADDQ #4,A6 ;BUMP TO NEXT MASK LONG
AND.L (A3)+,D0
AND.L (A2)+,D0
AND.L (A1)+,D0
MOVE.L D0,(A0)+ ;AND PUT TO REGION BUFFER
DBRA D1,ABCMLOOP
MOVEM.L (SP)+,D5/A6 ;RESTORE WORK REGISTERS
moveq #1,d2 ;mask->force scan count = 1
RTS ;AND RETURN
ABCX MOVEM.L D2-D5/A4-A6,-(SP) ;SAVE WORK REGISTERS
MOVE.L DSTMASKBUF(A6),D2 ;IS THERE A MASK?
BNE.S ABCXM ;=>YES, APPLY MASK
; COMBINE 3 REGIONS AND EXPAND
MOVE.L D0,A4 ;GET EXPAND ROUTINE
LEA RETABCX,A5 ;GET RETURN ADDRESS FOR LOOP
MOVEQ #0,D2 ;SCANLOOPS WANT D2=0
ABCXLOOP MOVE.L (A3)+,D0
AND.L (A2)+,D0
AND.L (A1)+,D0
JMP (A4) ;EXPAND DO INTO RGNBUFFER
RETABCX DBRA D1,ABCXLOOP ;LOOP FOR ALL LONGS IN SRC
MOVEM.L (SP)+,D2-D5/A4-A6 ;RESTORE WORK REGISTERS
RTS
; COMBINE 3 REGIONS AND MASK AND EXPAND
ABCXM MOVE.L D0,A4 ;GET EXPAND ROUTINE
LEA RETABCXM,A5 ;GET RETURN ADDRESS FOR LOOP
MOVE.L DSTMASKALIGN(A6),D5 ;ALIGN MASK TO DST
MOVE.L D2,A6 ;GET ADDRESS OF MASK
MOVEQ #0,D2 ;SCANLOOPS WANT D2=0
ABCXMLOOP BFEXTU (A6){D5:0},D0 ;EXTRACT A LONG OF MASK
ADDQ #4,A6 ;BUMP TO NEXT MASK LONG
AND.L (A3)+,D0
AND.L (A2)+,D0
AND.L (A1)+,D0
JMP (A4) ;EXPAND DO INTO RGNBUFFER
RETABCXM DBRA D1,ABCXMLOOP ;LOOP FOR ALL LONGS IN SRC
MOVEM.L (SP)+,D2-D5/A4-A6 ;RESTORE WORK REGISTERS
moveq #1,d2 ;mask->force scan count = 1
RTS
;-----------------------------------------------
;
; SCALING ROUTINES CALLED TO EXPAND A MASK BUFFER
; FROM ONE BIT TO N-BITS DEEP. THESE ROUTINES
; EXPAND A SINGLE LONG AT A TIME.
;
; D0: SRC DATA A0: DSTPTR
; D1: LONGCOUNT A1: SRC1
; D2: SCRATCH A2: SRC2
; D3: BYTECNT/BITCNT A3: SRC3
; D4: SCRATCH A4: RTN ADDRESS
; D5: A5: RETURN ADDRESS
;
;-----------------------------------------------
ALIGN Alignment
;-----------------------------------------------
;
; SCALE UP BY ONE USING INSCRUTABLE LOGIC
;
SINGLE MOVE.L D0,(A0)+ ;WRITE OUT WORD
JMP (A5) ;AND RETURN
ALIGN Alignment
DOUBLE
;-----------------------------------------------
;
; SCALE UP BY TWO USING TABLE LOOKUP
;
; D2 SHOULD BE 0 ON ENTRY
;
MOVE.L A5,-(SP) ; Save A5
LEA Table2,A5 ; A5->byte to word double table
CLR D2 ; clear upper bits of D2
MOVE.B D0,D2 ; D2 = 4th byte src
MOVE (A5,D2*2),D4 ; D4.lo = 4th word result
SWAP D0 ; 3412
MOVE.B D0,D2 ; D2 = 2nd byte src
MOVE (A5,D2*2),D3 ; D3.lo = 2nd word result
LSR.L #8,D0 ; x341
MOVE.B D0,D2 ; D2 = 1st byte src
SWAP D3
MOVE (A5,D2*2),D3
SWAP D3 ; D3 = 1st,2nd word results
SWAP D0 ; 41x3
MOVE.B D0,D2 ; D2 = 3rd byte of src
SWAP D4
MOVE (A5,D2*2),D4
SWAP D4 ; D4 = 3rd,4th word results
MOVE.L D3,(A0)+
MOVE.L D4,(A0)+
MOVE.L (SP)+,A5
JMP (A5)
ALIGN Alignment
QUAD
;-----------------------------------------------
;
; SCALE UP BY FOUR USING TABLE LOOKUP
;
; D2 SHOULD BE 0 ON ENTRY
;
MOVEQ #3,D3 ;DO 4 BYTES OF SRC
@DOQUAD ROL.L #8,D0 ;GET NEXT BYTE OF SRC
MOVE.B D0,D2 ;MAKE AN EXTRA COPY
MOVE.L (TABLE4,PC,D2*4),(A0)+
DBRA D3,@DOQUAD ;=>QUAD NEXT BYTE
JMP (A5) ;AND RETURN
ALIGN Alignment
EIGHT
;-----------------------------------------------
;
; SCALE UP BY EIGHT USING TABLE LOOKUP
;
; D2 SHOULD BE 0 ON ENTRY
;
MOVEQ #3,D3 ;DO 4 BYTES OF SRC
@DOEIGHT ROL.L #8,D0 ;GET A BYTE OF SRC
MOVE.B D0,D2 ;MAKE AN EXTRA COPY
LSR #4,D2 ;CLEAR HI NIBBLE
MOVE.L (TABLE8,PC,D2*4),(A0)+ ;PUT FIRST LONG TO DST
MOVEQ #$F,D2 ;MASK FOR LO NIBBLE
AND D0,D2 ;CLEAR HI NIBBLE
MOVE.L (TABLE8,PC,D2*4),(A0)+ ;PUT SECOND LONG TO DST
DBRA D3,@DOEIGHT ;=>EIGHT NEXT BYTE
JMP (A5) ;AND RETURN
ALIGN Alignment
SIXTEEN
;-------------------------------------------------
;
; SCALE UP BY 16
;
MOVEQ #15,D3 ;16 OUTPUT LONGS
@SIXTENA ADD.L D0,D0 ;GET ONE BIT OF SRC
SUBX.L D2,D2 ;EXTEND THRU HI WORD
ADD.L D0,D0 ;GET ONE BIT OF SRC
SUBX.W D2,D2 ;EXTEND THRU SET LO WORD
MOVE.L D2,(A0)+ ;OUTPUT 1 RESULT
DBRA D3,@SIXTENA ;
JMP (A5) ;AND RETURN
ALIGN Alignment
THRTWO
;-----------------------------------------------
;
; SCALE UP BY 32
;
MOVEQ #31,D3 ;32 OUTPUT LONGS
@THRTY2 ADD.L D0,D0 ;GET ONE BIT OF SRC
SUBX.L D2,D2 ;EXTEND THRU LONG
MOVE.L D2,(A0)+ ;OUTPUT 1 RESULT
DBRA D3,@THRTY2 ;
JMP (A5) ;AND RETURN
;-----------------------------------------------
;
; RUN MASK ROUTINES CALLED TO ENCODE A 1-BIT SCANLINE MASK
; INTO A RUN MASK APPROPRIATE FOR THE DESTINATION DEPTH.
; THESE ROUTINES ARE CALLED ON A SCANLINE BASIS.
;
; D0: scratch A0: scratch
; D1: scratch A1: scratch
; D2: preserved A2: scratch
; D3: preserved A3: preserved
; D4: preserved A4: preserved
; D5: A5: preserved
;
; Clobbers: D0-D1/A0-A2
;
;-----------------------------------------------
ALIGN Alignment
;-----------------------------------------------
;
;
RUN1
move.l RGNBUFFER(a6),a0
MOVEM.L D1/D3-D6,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
moveq #-1,d1 ;get blit mask
moveq #1,d4 ;get bump size for blit
swap d4
MOVE.L (a0)+,d0 ;prefetch first region data long
move.w RUNBUMP(a6),d6 ;are we blitting forwards?
bpl.s @nxtRun ;yes, go ahead
moveq #0,d0
move.w d5,d0 ;copy bufSize
asl.l #2,d0 ;get mask byte width
add.l d0,a0 ;point at last long in RGNBUFFER
move.l d0,d3 ;force skip to right edge
MOVE.L -(a0),d0 ;re-fetch first region data long
add.w d6,a0 ;predecrement
bra.s @first1
@nxtRun moveq #0,d3 ;init blit/mask, skip cnt
@first1 tst.l d0
beq.s @cntSkip ;mask is all zeros
@chkBlt cmp.l d1,d0 ;is the mask all ones?
beq.s @cntBlit ;yes, go cnt repeats
move.l a2,a1 ;save ptr to blit/skip long
addq.w #4,a2 ;bump past instruction long
bra.s @cntMask
@mask1 MOVE.L (a0),d0 ;all 0's?
add.w d6,a0 ;bump forward/backward in region
beq.s @dumpMask ;yes, done with mask run
cmp.l d1,d0 ;all 1's?
beq.s @dumpMask ;yes, done with mask run
add.l d4,d3
@cntMask move.l d0,(a2)+ ;write out mask
dbra d5,@mask1
bset #runMaskBit,d3
move.l d3,(a1)
bra.s @endRun
@dumpMask bset #runMaskBit,d3
move.l d3,(a1) ;write out blit/skip
bra.s @nxtRun
@dumpBlit move.l d3,(a2)+ ;write out blit/skip
bra.s @nxtRun
@skip1 MOVE.L (a0),d0 ;get region data
add.w d6,a0 ;bump forward/backward in region
bne.s @chkBlt
@cntSkip add.w d6,d3 ;accumulate skip (<28>4)
dbra d5,@skip1
bra.s @endRun
@blit1 MOVE.L (a0),d0 ;get region data
add.w d6,a0 ;bump forward/backward in region
cmp.l d1,d0
bne.s @dumpBlit
add.l d4,d3
@cntBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
@endRun move.l d1,(a2) ;flag end of run data (-1L)
MOVEM.L (SP)+,D1/D3-D6 ;RESTORE WORK REGISTERS
RTS
ALIGN Alignment
;-----------------------------------------------
;
; Build a 2 bit run mask from a 1 bit scan mask
; for use when blitting Left to Right or Right to Left
;
;
RUN2
move.l RGNBUFFER(a6),a0
MOVEM.L D1-D7/A3-A5,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
lea TABLE2,a4 ;point at doubling table
moveq #-1,d1 ;get blit mask
moveq #1,d4 ;get bump size for blit
swap d4
move.l d4,a5 ;put blit bump size in a5
moveq #$F,d4 ;put nibble mask in d4
moveq #0,d6 ;clear out high end
MOVE.w (a0)+,d0 ;prefetch first region data word
move.w RUNBUMP(a6),d2 ;are we blitting forwards?
move.w d2,a3 ;make a copy for skip bump
asr.w #1,d2 ;make into word bump
bpl.s @nxtRun ;yes, go ahead
@backwards
addq.w #2,d5 ;make BufSize 1 based
and.w #~1,d5 ;round up to mult of pixelsize
moveq #0,d0
move.w d5,d0 ;copy bufSize
add.l d0,d0 ;get mask byte width
add.l d0,a0 ;point at last long in RGNBUFFER
add.l d0,d0 ;scale for dst bump
move.l d0,d3 ;force bump to far right
MOVE.w -(a0),d0 ;fetch last region data word
subq.w #2,a0 ;predecrement
bra.s @first
@nxtRun moveq #0,d3 ;init blit/mask, skip cnt
tst.w d0
@first beq.s @cntSkip ;mask is all zeros
@chkBlt cmp.w d1,d0 ;is the mask all ones?
beq.s @cntBlit ;yes, go cnt repeats
move.l a2,a1 ;save ptr to blit/skip long
addq.l #4,a2 ;bump past instruction long
bra.s @cntMask
@mask1 MOVE.w (a0),d0 ;all 0's?
add.w d2,a0 ;bump for/backward in region
beq.s @dumpMask ;yes, done with mask run
cmp.w d1,d0 ;all 1's?
beq.s @dumpMask ;yes, done with mask run
add.l a5,d3
@cntMask
MOVE.B D0,D6
MOVE (A4,D6*2),D7
SWAP D7
ROL.W #8,D0
MOVE.B D0,D6
MOVE (A4,D6*2),D7
SWAP D7
MOVE.L D7,(A2)+ ;WRITE OUT MASK
dbra d5,@mask1
bset #runMaskBit,d3
move.l d3,(a1)
bra.s @endRun
@dumpMask bset #runMaskBit,d3
move.l d3,(a1) ;write out blit/skip
bra.s @nxtRun
@dumpBlit move.l d3,(a2)+ ;write out blit/skip
bra.s @nxtRun
@skip1 MOVE.w (a0),d0 ;get region data
add.w d2,a0 ;bump for/backward in region
bne.s @chkBlt
@cntSkip add.w a3,d3 ;accumulate skip <20>4
dbra d5,@skip1
bra.s @endRun
@blit1 MOVE.w (a0),d0 ;get region data
add.w d2,a0 ;bump for/backward in region
cmp.w d1,d0
bne.s @dumpBlit
add.l a5,d3
@cntBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
@endRun move.l d1,(a2) ;flag end of run data (-1L)
MOVEM.L (SP)+,D1-D7/A3-A5 ;RESTORE WORK REGISTERS
RTS
;-----------------------------------------------
ALIGN Alignment
RUN4
;-----------------------------------------------
;
; SCALE UP BY FOUR USING TABLE LOOKUP
;
;
move.l RGNBUFFER(a6),a0
MOVEM.L D1-D7/A3/A4,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
LEA TABLE4,A4 ;point to quad table
moveq #-1,d1 ;get blit mask
moveq #1,d4 ;get bump size for blit
swap d4
moveq #0,d6 ;clear out high end
MOVE.b (a0)+,d0 ;get region data
move.w RUNBUMP(a6),d2 ;are we blitting forwards?
move.w d2,a3 ;save for skip bump
asr.w #2,d2 ;make into byte bump
bpl.s @nxtRun ;yes, go ahead
@backwards
addq.w #4,d5 ;make BufSize 1 based
and.w #~3,d5 ;round up to mult of pixelsize
moveq #0,d0
move.w d5,d0 ;copy bufSize
add.l d0,a0 ;point at last long in RGNBUFFER
lsl.l #2,d0 ;scale for dst bump
move.l d0,d3 ;force bump to far right
MOVE.b -(a0),d0 ;fetch last region data word
subq.w #1,a0 ;predecrement
bra.s @first
@nxtRun moveq #0,d3 ;init blit/mask, skip cnt
tst.b d0
@first beq.s @cntSkip ;mask is all zeros
@chkBlt cmp.b d1,d0 ;is the mask all ones?
beq.s @cntBlit ;yes, go cnt repeats
move.l a2,a1 ;save ptr to blit/skip long
addq.l #4,a2 ;bump past instruction long
bra.s @cntMask
@mask1 MOVE.b (a0),d0 ;all 0's?
add.w d2,a0 ;bump for/back-wards 1 byte
beq.s @dumpMask ;yes, done with mask run
cmp.b d1,d0 ;all 1's?
beq.s @dumpMask ;yes, done with mask run
add.l d4,d3
@cntMask
MOVE.B D0,D6 ;MAKE AN EXTRA COPY
MOVE.L (A4,D6*4),(A2)+
dbra d5,@mask1
bset #runMaskBit,d3
move.l d3,(a1)
bra.s @endRun
@dumpMask bset #runMaskBit,d3
move.l d3,(a1) ;write out blit/skip
bra.s @nxtRun
@dumpBlit move.l d3,(a2)+ ;write out blit/skip
bra.s @nxtRun
@skip1 MOVE.b (a0),d0 ;get region data
add.w d2,a0 ;bump for/back-wards 1 byte
bne.s @chkBlt
@cntSkip add.w a3,d3 ;accumulate skip bump (<28>4)
dbra d5,@skip1
bra.s @endRun
@blit1 MOVE.b (a0),d0 ;get region data
add.w d2,a0 ;bump for/back-wards 1 byte
cmp.b d1,d0
bne.s @dumpBlit
add.l d4,d3
@cntBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
@endRun move.l d1,(a2) ;flag end of run data (-1L)
MOVEM.L (SP)+,D1-D7/A3/A4 ;RESTORE WORK REGISTERS
RTS
;
;-----------------------------------------------
ALIGN Alignment
RUN8
tst.w RunBump(a6) ;forward?
bmi BackWards8 ;yes, go there
;fall thru
Forwards8
;-----------------------------------------------
;
; Build a 8 bit run mask from a 1 bit scan mask
; for use when blitting Left to Right
; -Consumes bytes and produces double longs
;
move.l RGNBUFFER(a6),a0
MOVEM.L D1-D6/A4,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
LEA TABLE8,A4 ;point to scale table
lsr.w #1,d5 ;get cnt of double longs-1
moveq #-1,d1 ;get blit mask
moveq #1*2,d4 ;get bump size for blit
swap d4
moveq #0,d6 ;clear out high end
move.l #$10000,d2 ;init blit/mask to 2-1
MOVE.b (a0)+,d0 ;get region data
@nxtRun move.l d2,d3 ;init blit/mask, skip cnt
tst.b d0
beq.s @cntSkip ;mask is all zeros
@chkBlt cmp.b d1,d0 ;is the mask all ones?
beq.s @cntBlit ;yes, go cnt repeats
move.l a2,a1 ;save ptr to blit/skip long
addq.l #4,a2 ;bump past instruction long
bra.s @cntMask
@mask1 MOVE.b (a0)+,d0 ;all 0's?
beq.s @dumpMask ;yes, done with mask run
cmp.b d1,d0 ;all 1's?
beq.s @dumpMask ;yes, done with mask run
add.l d4,d3
@cntMask
MOVE.B D0,D6 ;MAKE AN EXTRA COPY
LSR #4,D6 ;SHIFT FOR TABLE INDEX
; MOVE.L (TABLE8,PC,D6*4),(A2)+ ;bigger and slower than below
MOVE.L (A4,D6*4),(A2)+ ;PUT FIRST LONG TO DST
MOVEQ #$0F,D6 ;MASK FOR LO NIBBLE
AND D0,D6 ;MAKE AN EXTRA COPY
MOVE.L (A4,D6*4),(A2)+ ;PUT SECOND LONG TO DST
dbra d5,@mask1
bset #runMaskBit,d3
move.l d3,(a1)
bra.s @endRun
@dumpMask bset #runMaskBit,d3
move.l d3,(a1) ;write out mask/skip
bra.s @nxtRun
@dumpBlit move.l d3,(a2)+ ;write out blit/skip
bra.s @nxtRun
@skip1 MOVE.b (a0)+,d0 ;get region data
bne.s @chkBlt
@cntSkip addq.w #8,d3 ;skip bump size is +8
dbra d5,@skip1
bra.s @endRun
@blit1 MOVE.b (a0)+,d0 ;get region data
cmp.b d1,d0
bne.s @dumpBlit
add.l d4,d3
@cntBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
@endRun move.l d1,(a2) ;flag end of run data (-1L)
MOVEM.L (SP)+,D1-D6/A4 ;RESTORE WORK REGISTERS
RTS
;-----------------------------------------------
ALIGN Alignment
BackWards8
;-----------------------------------------------
;
; Build a 8 bit run mask from a 1 bit scan mask
; for use when blitting RIGHT to LEFT
; -Consumes bytes and produces double longs
;
move.l RGNBUFFER(a6),a0
MOVEM.L D1-D6/A4,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
LEA TABLE8,A4 ;point to scale table
moveq #-1,d1 ;get blit mask
moveq #1*2,d4 ;get bump size for blit
swap d4
moveq #0,d6 ;clear out high end
move.l #$10000,d2 ;init blit/mask to 2-1
move.l d2,d3 ;init high word of instruction
add.w #8,d5
and.w #~7,d5 ;round up to mult of pixelsize
move.w d5,d3 ;copy bufSize
asr.w #1,d3 ;get mask byte width /8*4
add.w d3,a0 ;point at last long in RGNBUFFER
lsl.w #3,d3 ;force skip to right edge
subq.w #1,d5 ;make zero based
subq.w #4,d3 ;make zero based
lsr.w #1,d5 ;get cnt of double longs-1
MOVE.b -(a0),d0 ;get region data
bra.s @first
@nxtRun move.l d2,d3 ;init blit/mask, skip cnt
@first tst.b d0
beq.s @cntSkip ;mask is all zeros
@chkBlt cmp.b d1,d0 ;is the mask all ones?
beq.s @cntBlit ;yes, go cnt repeats
move.l a2,a1 ;save ptr to blit/skip long
addq.l #4,a2 ;bump past instruction long
bra.s @cntMask
@mask1 MOVE.b -(a0),d0 ;all 0's?
beq.s @dumpMask ;yes, done with mask run
cmp.b d1,d0 ;all 1's?
beq.s @dumpMask ;yes, done with mask run
add.l d4,d3
@cntMask
MOVEQ #$0F,D6 ;MASK FOR LO NIBBLE
AND D0,D6 ;GET LO NIBBLE
MOVE.L (A4,D6*4),(A2)+ ;PUT SECOND LONG TO DST
MOVE.B D0,D6 ;MAKE AN EXTRA COPY
LSR #4,D6 ;SHIFT FOR TABLE INDEX
; MOVE.L (TABLE8,PC,D6*4),(A2)+ ;bigger and slower than below
MOVE.L (A4,D6*4),(A2)+ ;PUT FIRST LONG TO DST
dbra d5,@mask1
bset #runMaskBit,d3
move.l d3,(a1)
bra.s @endRun
@dumpMask bset #runMaskBit,d3
move.l d3,(a1) ;write out mask/skip
bra.s @nxtRun
@dumpBlit move.l d3,(a2)+ ;write out blit/skip
bra.s @nxtRun
@skip1 MOVE.b -(a0),d0 ;get region data
bne.s @chkBlt
@cntSkip subq.w #8,d3 ;skip bump size is -8
dbra d5,@skip1
bra.s @endRun
@blit1 MOVE.b -(a0),d0 ;get region data
cmp.b d1,d0
bne.s @dumpBlit
add.l d4,d3
@cntBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
@endRun move.l d1,(a2) ;flag end of run data (-1L)
MOVEM.L (SP)+,D1-D6/A4 ;RESTORE WORK REGISTERS
RTS
ALIGN 4
TABLE8 DC.L $00000000,$000000FF,$0000FF00,$0000FFFF
DC.L $00FF0000,$00FF00FF,$00FFFF00,$00FFFFFF
DC.L $FF000000,$FF0000FF,$FF00FF00,$FF00FFFF
DC.L $FFFF0000,$FFFF00FF,$FFFFFF00,$FFFFFFFF
ALIGN Alignment
Forwards16
;-----------------------------------------------
;
; Build a 16 bit run mask from a 1 bit scan mask
; for use when blitting Left to Right
;
;
move.l RGNBUFFER(a6),a0
MOVEM.L D3-D5,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
moveq #1,d4 ;get bump size for blit
swap d4
moveq #1,d0 ;get 1 into high bit
ror.l #1,d0 ;to init data stream
moveq #0,d3 ;init blit/mask, skip cnt
@skip1 add.l d0,d0 ;get one bit of src
bcc.s @chkSkip ;br if 0
bne.s @BlitOrMask ;br if 1
move.l (a0)+,d0 ;else get next long of region data
addx.l d0,d0 ;shift src bit out, 1 bit in
bcs.s @BlitOrMask ;br if 1
@chkSkip add.l d0,d0 ;another 0?
bcc.s @cntSkip ;yes, its a skip
@first01 move.l a2,a1 ;save ptr to mask/skip long
addq.l #4,a2 ;bump past instruction long
bra.s @dump01
@cntSkip addq.w #4,d3 ;bump skip by +4
dbra d5,@skip1
bra.s endRun16
@BlitOrMask add.l d0,d0 ;another 1?
bcs.s @goBlit ;yes, begin a blit run
@first10 move.l a2,a1 ;save ptr to mask/skip long
addq.l #4,a2 ;bump past instruction long
bra.s @dump10
@dumpMaskS bset #runMaskBit,d3
move.l d3,(a1) ;write out mask/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @cntSkip
@dumpMaskB bset #runMaskBit,d3
move.l d3,(a1) ;write out mask/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @goBlit
@chkMask0 add.l d0,d0 ;another 0?
bcc.s @dumpMaskS ;yes, its a skip
add.l d4,d3
@dump01 move.l #$ffff,(a2)+ ;write out 01 mask
bra.s @nextMask
@mask1 add.l d0,d0 ;get one bit of src
bcc.s @chkMask0 ;br if 0
bne.s @chkMask1 ;br if 1
move.l (a0)+,d0 ;else get next long of region data
addx.l d0,d0 ;shift src bit out, 1 bit in
bcc.s @chkMask0 ;br if 0
@chkMask1 add.l d0,d0 ;another 1?
bcs.s @dumpMaskB ;yes, its a blit
add.l d4,d3
@dump10 move.l #$ffff0000,(a2)+ ;write out 10 mask
@nextMask dbra d5,@mask1
bset #runMaskBit,d3
move.l d3,(a1) ;write out mask/skip
bra.s endRun16
@dumpBlitS move.l d3,(a2)+ ;write out blit/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @chkSkip
@dumpBlitM move.l d3,(a2)+ ;write out blit/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @first10
@blit1 add.l d0,d0 ;get one bit of src
bcc.s @dumpBlitS ;br if 0
bne.s @chkBlit ;br if 1
move.l (a0)+,d0 ;else get next long of region data
addx.l d0,d0 ;shift src bit out, 1 bit in
bcc.s @dumpBlitS ;br if 0
@chkBlit add.l d0,d0 ;another 1?
bcc.s @dumpBlitM ;no, its a mask
add.l d4,d3
@goBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
endRun16 moveq #-1,d3 ;get a long -1
move.l d3,(a2) ;flag end of run data (-1L)
MOVEM.L (SP)+,D3-D5 ;RESTORE WORK REGISTERS
RTS
;-----------------------------------------------
ALIGN Alignment
RUN16
lea Forwards16,a0 ;assume blitting left to right
move.l a0,RunRtn(a6) ;go there from now on
tst.w RunBump(a6) ;forward?
bpl.s Forwards16 ;yes, go there
lea BackWards16,a0 ;blitting right to left
move.l a0,RunRtn(a6) ;go there from now on
;fall thru
BackWards16
;-----------------------------------------------
;
; Build a 16 bit run mask from a 1 bit scan mask
; for use when blitting RIGHT to LEFT
;
move.l RGNBUFFER(a6),a0
MOVEM.L D3-D5,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
add.w #16,d5
and.w #~15,d5 ;round up to mult of pixelsize
moveq #1,d4 ;get bump size for blit
swap d4
move.w d5,d3 ;copy bufSize
ext.l d3 ;clear out high end
asr.w #2,d3 ;get mask byte width /16*4
add.w d3,a0 ;point at last long in RGNBUFFER
lsl.w #4,d3 ;force skip to right edge
subq.w #1,d5 ;make zero based
subq.w #4,d3 ;make zero based
moveq #1,d0 ;get 1 to init data stream
@skip1 lsr.l #1,d0 ;get one bit of src
bcc.s @chkSkip ;br if 0
bne.s @BlitOrMask ;br if 1
move.l -(a0),d0 ;else get next long of region data
roxr.l #1,d0 ;shift src bit out, 1 bit in
bcs.s @BlitOrMask ;br if 1
@chkSkip lsr.l #1,d0 ;another 0?
bcc.s @cntSkip ;yes, its a skip
@first01 move.l a2,a1 ;save ptr to mask/skip long
addq.l #4,a2 ;bump past instruction long
bra.s @dump01
@cntSkip subq.w #4,d3 ;bump skip by -4
dbra d5,@skip1
bra.s endRun16 ;use common exit
@BlitOrMask lsr.l #1,d0 ;another 1?
bcs.s @goBlit ;yes, begin a blit run
@first10 move.l a2,a1 ;save ptr to mask/skip long
addq.l #4,a2 ;bump past instruction long
bra.s @dump10
@dumpMaskS bset #runMaskBit,d3
move.l d3,(a1) ;write out mask/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @cntSkip
@dumpMaskB bset #runMaskBit,d3
move.l d3,(a1) ;write out mask/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @goBlit
@chkMask0 lsr.l #1,d0 ;another 0?
bcc.s @dumpMaskS ;yes, its a skip
add.l d4,d3
@dump01 move.l #$ffff0000,(a2)+ ;write out 01 mask
bra.s @nextMask
@mask1 lsr.l #1,d0 ;get one bit of src
bcc.s @chkMask0 ;br if 0
bne.s @chkMask1 ;br if 1
move.l -(a0),d0 ;else get next long of region data
roxr.l #1,d0 ;shift src bit out, 1 bit in
bcc.s @chkMask0 ;br if 0
@chkMask1 lsr.l #1,d0 ;another 1?
bcs.s @dumpMaskB ;yes, its a blit
add.l d4,d3
@dump10 move.l #$0000ffff,(a2)+ ;write out 10 mask
@nextMask dbra d5,@mask1
bset #runMaskBit,d3
move.l d3,(a1) ;write out mask/skip
bra.s endRun16 ;use common exit
@dumpBlitS move.l d3,(a2)+ ;write out blit/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @chkSkip
@dumpBlitM move.l d3,(a2)+ ;write out blit/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @first10
@blit1 lsr.l #1,d0 ;get one bit of src
bcc.s @dumpBlitS ;br if 0
bne.s @chkBlit ;br if 1
move.l -(a0),d0 ;else get next long of region data
roxr.l #1,d0 ;shift src bit out, 1 bit in
bcc.s @dumpBlitS ;br if 0
@chkBlit lsr.l #1,d0 ;another 1?
bcc.s @dumpBlitM ;no, its a mask
add.l d4,d3
@goBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
bra.s endRun16 ;use common exit
ALIGN Alignment
Forwards32
;-----------------------------------------------
;
; Build a 32 bit run mask from a 1 bit scan mask
; for use when blitting Left to Right
;
move.l RGNBUFFER(a6),a0
MOVEM.L D3-D5,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
moveq #1,d4 ;get bump size for blit
swap d4
moveq #1,d0 ;get 1 into high bit
ror.l #1,d0 ;to init data stream
moveq #0,d3 ;init blit/mask, skip cnt
@skip1 add.l d0,d0 ;get one bit of src
bcc.s @cntSkip ;br if 0
bne.s @cntBlit ;br if 1
move.l (a0)+,d0 ;else get next long of region data
addx.l d0,d0 ;shift src bit out, 1 bit in
bcs.s @cntBlit ;br if 1
@cntSkip addq.w #4,d3 ;bump skip by +4
dbra d5,@skip1
bra.s endRun32
@goSkip move.l d3,(a2)+ ;write out blit/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @cntSkip
@blit1 add.l d0,d0 ;get one bit of src
bcc.s @goSkip ;br if 0
bne.s @goBlit ;br if 1
move.l (a0)+,d0 ;else get next long of region data
addx.l d0,d0 ;shift src bit out, 1 bit in
bcc.s @goSkip ;br if 1
@goBlit add.l d4,d3 ;bump blit count
@cntBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
endRun32 moveq #-1,d3 ;get a long -1
move.l d3,(a2) ;flag end of run data (-1L)
MOVEM.L (SP)+,D3-D5 ;RESTORE WORK REGISTERS
RTS
;-----------------------------------------------
ALIGN Alignment
RUN32
lea Forwards32,a0 ;assume blitting left to right
move.l a0,RunRtn(a6) ;go there from now on
tst.w RunBump(a6) ;forward?
bpl.s Forwards32 ;yes, go there
lea BackWards32,a0 ;blitting right to left
move.l a0,RunRtn(a6) ;go there from now on
;fall thru
BackWards32
;-----------------------------------------------
;
; Build a 32 bit run mask from a 1 bit scan mask
; for use when blitting RIGHT to LEFT
;
; This should be optimized to look at longs as fast case
;
move.l RGNBUFFER(a6),a0
MOVEM.L D3-D5,-(SP) ;SAVE WORK REGISTERS
MOVE.L RUNBUF(A6),A2 ;point to run encoded mask buffer
MOVE.W BUFSIZE(A6),D5 ;get dest longs-1
add.w #32,d5
and.w #~31,d5 ;round up to mult of pixelsize
moveq #1,d4 ;get bump size for blit
swap d4
move.w d5,d3 ;copy bufSize
ext.l d3 ;clear out high end
asr.w #3,d3 ;get mask byte width /32*4
add.w d3,a0 ;point at last long in RGNBUFFER
lsl.w #5,d3 ;force skip to right edge
subq.w #1,d5 ;make zero based
subq.w #4,d3 ;make zero based
moveq #1,d0 ;get 1 to init data stream
@skip1 lsr.l #1,d0 ;get one bit of src
bcc.s @cntSkip ;br if 0
bne.s @cntBlit ;br if 1
move.l -(a0),d0 ;else get next long of region data
roxr.l #1,d0 ;shift src bit out, 1 bit in
bcs.s @cntBlit ;br if 1
@cntSkip subq.w #4,d3 ;bump skip by -4
dbra d5,@skip1
bra.s endRun32
@goSkip move.l d3,(a2)+ ;write out blit/skip
moveq #0,d3 ;init blit/mask, skip cnt
bra.s @cntSkip
@blit1 lsr.l #1,d0 ;get one bit of src
bcc.s @goSkip ;br if 0
bne.s @goBlit ;br if 1
move.l -(a0),d0 ;else get next long of region data
roxr.l #1,d0 ;shift src bit out, 1 bit in
bcc.s @goSkip ;br if 1
@goBlit add.l d4,d3 ;bump blit cnt
@cntBlit dbra d5,@blit1
move.l d3,(a2)+ ;write out blit/skip
bra.s endRun32 ;use common exit
ENDPROC