sys7.1-doc-wip/QuickDraw/Patches/QuickerDraw.a
2019-07-27 22:37:48 +08:00

6891 lines
150 KiB
Plaintext

;EASE$$$ READ ONLY COPY of file “QuickerDraw.a”
; 1.2 CCH 01/16/1989 Merged 6.0.3 final sources into 7.0.
;•1.1 CCH 11/16/1988 Updated to newest version.
PRINT ON
; File QuickLoops.a
;-----------------------------------------------------------------------------
;
; High performance Mac II Color QuickDraw Inner Loops (for 8-bit mode)
;
; written by Andy Hertzfeld December 22, 1987
;
; This INIT patches out some of the Color QuickDraw inner loop traps
; to improve 8-bit performance by a factor of 2 to 3 (or even more!)
;
; Modification History:
;
; AJH 11-Jan-88 1st Beta release, version .9
; AJH 13-Jan-88 made fills work in modes other than 8-bit (.91)
; AJH 14-Jan-88 fixed bug in unclipped pattern fill (.92)
; AJH 16-Jan-88 fixed seek region bug in mapped copyBits (.93)
; AJH 17-Jan-88 fixed scaling rejection bug in mapped copyBits
; AJH 18-Jan-88 implemented fast 8 to 1 copyBits; fixed 1-8 seekRgn bug (.94)
; AJH 20-Jan-88 region counting for clipped blit
; AJH 22-Jan-88 fixed OR mode fill, added $335 for MacDraw Plus
; AJH 23-Jan-88 fixed bug when region is a mask (CB1to8 from CopyMask)
; AJH 24-Jan-88 broke LogoPict into separate resource; separate 1-bit logo (.95)
; AJH 25-Jan-88 region counting for InvertClip
; AJH 26-Jan-88 significantly improved oval/rrects when unclipped
; AJH 26-Jan-88 added oval/rrects in OR mode
; AJH 27-Jan-88 OR mode fills (simple and complex patterns) (.96)
; AJH 28-Jan-88 INIT wasn't locked bug (.97)
; AJH 28-Jan-88 check if already installed; if so, display logo
; AJH 29-Jan-88 removed OR mode complex fills; fixed OR mode simple fills
; AJH 29-Jan-88 reject patterns > 8 pixels wide
; AJH 29-Jan-88 added oval/rrects with complex patterns
; AJH 30-Jan-88 added arithmetic transfer mode fills for rrects/ovals
; AJH 31-Jan-88 added arithmetic transfer mode fills for unclipped rects
; AJH 01-Feb-88 added arithmetic transfer mode fills for clipped rects (.98)
; AJH 02-Feb-88 added blend mode; fixed arithmetic copyBits bug
; AJH 03-Feb-88 removed hilite by invert hack (.985)
; AJH 03-Feb-88 further optimized hilite, 1 to 8 copybits
; AJH 04-Feb-88 added transparent modes
; AJH 04-Feb-88 fixed arithmetic mode bug with type 0 patterns (-$68, not -68!) (.987)
; AJH 05-Feb-88 converted to cdev
; AJH 07-Feb-88 added configuration code at startup time (.99)
; AJH 18-Feb-88 fixed bug in transparent mode fill (LSR instead of ASR)
; AJH 18-Feb-88 fixed bug in unclipped, less than 5 wide arithmetic modes
; AJH 21-Feb-88 fixed bug in arithmetic mode cache initialization
; AJH 21-Feb-88 fixed wrong reg (A4 -> A2) bump bug in oval handler (MacDraw crash) (1.0)
; AJH 22-Feb-88 fixed bug in 8-1 copybits (can't assume map is 0 or 1 only)
; AJH 23-Feb-88 fixed arithmetic mode cache initialization (add and sub modes) (1.1)
;
;---- A New Life at Apple --------------------
;
; PB415 DAF/BAL 01Mar88 QuickerDraw integrated into system patch files
; PB427 BAL 17Mar88 Corrected some edge masking bugs in arithmetic modes.
; Return to ROM if arithmetic mode copybits from left to right.
; PB428 DAF 18Mar88 Fixed QuickerDraw to be A/UX friendly.
; PB433 DAF 22Mar88 Improved dispatches to ROM (saved a couple of bytes and cycles)
; BAL 25Mar88 Converted to use symbolic stack frame references
; PB446 DBG 29Mar88 Fixed up missed JMPs into ROM in QuickerDraw.a, which cause certain
; CopyBits cases to crash.
; PB448 DBG 30Mar88 Fixed erroneous references to HBUMP to be to SRCBUMP
; PB452 BAL 01Apr88 Fixed bug in DrawSlab OR mode handler ($381) to preserve fgColor
; PB471 BAL 18Apr88 Fixed 1 to 8 bit expansion to first insure CLUT is B/W.
; PB473 DAF 19Apr88 Modified PB471 to allow more cases to be accelerated.
; PB471 BAL/DVB 13Jun88 Fixed 1 to 8 bit expansion to first insure src = scalebuf
; (i.e. dest not before pixmap's baseAddr).
; PBnnn d√b 12Jul88 Fixed error in 8 to 1 when white doesn't map to white.
;
;--------------------------------------------------------------------------------------------------
MACHINE MC68020
; for reference, here are the patched traps
IF 0 THEN
InstToolTp CopyScanLine1,$330
InstToolTp PatClipScanLine,$362
InstToolTp PatFillScanLine,$338
InstToolTp CBClipLine,$35A
InstToolTp InvertClip,$360
InstToolTp InvertHiliteClip,$372
InstToolTp CB1To8Clip,$373
InstToolTp FillClipScanLine,$380
InstToolTp FillClipOrLine,$381 ; Removed typo ` <PB446 DBG>
InstToolTp PatClipVar2,$35E
InstToolTp FillClipXLine,$384
InstToolTp AddOverFillO,$38A
InstToolTp SubOverFillO,$38E
InstToolTp AddPinFillO,$389
InstToolTp SubPinFillO,$38B
InstToolTp AddMaxFillO,$38D
InstToolTp AddMinFillO,$38F
InstToolTp BlendFillO,$388
InstToolTp TransFillO,$38C
InstToolTp AddOverFillR,$368
InstToolTp SubOverFillR,$36C
InstToolTp AddPinFillR,$367
InstToolTp SubPinFillR,$369
InstToolTp AddMaxFillR,$36B
InstToolTp AddMinFillR,$36D
InstToolTp BlendFillR,$366
InstToolTp TransFillR,$36A
InstToolTp AddOverUnClip,$352
InstToolTp SubOverUnClip,$356
InstToolTp AddPinUnClip,$351
InstToolTp SubPinUnClip,$353
InstToolTp AddMaxUnClip,$355
InstToolTp AddMinUnClip,$357
InstToolTp BlendUnClip,$350
InstToolTp TransUnClip,$354
ENDIF
;******************************************************************************************
;
; to make scoping for upcoming equates happier, we force the end of the previous procedure here
;
QuickerDraw PROC EXPORT
EXPORT CopyScanLine1
EXPORT PatClipScanLine
EXPORT PatClipVar2
EXPORT PatFillScanLine
EXPORT CBClipLine
EXPORT InvertClip
EXPORT InvertHiliteClip
EXPORT CB1To8Clip
EXPORT FillClipScanLine
EXPORT FillClipOrLine
EXPORT FillClipXLine
EXPORT AddOverFillO
EXPORT SubOverFillO
EXPORT AddPinFillO
EXPORT SubPinFillO
EXPORT AddMaxFillO
EXPORT AddMinFillO
EXPORT BlendFillO
EXPORT AddOverFillR
EXPORT SubOverFillR
EXPORT AddPinFillR
EXPORT SubPinFillR
EXPORT AddMaxFillR
EXPORT AddMinFillR
EXPORT BlendFillR
EXPORT AddOverUnClip
EXPORT SubOverUnclip
EXPORT AddPinUnclip
EXPORT SubPinUnclip
EXPORT AddMaxUnclip
EXPORT AddMinUnclip
EXPORT BlendUnclip
EXPORT TransFillO
EXPORT TransFillR
EXPORT TransUnClip
; now patch the inner loop traps; so far we handle:
Old330 EQU $1B8F8 ; bMain0-- copyBits, no clip, copy mode
Old338 EQU $1BB7A ; bXMain8-- pattern fill, complex pattern, copy mode, no clipping
Old350 EQU $1BF24 ; bAvg-- blend fill, unclipped rects
Old351 EQU $1BC6A ; bAddPin-- addPin fill, unclipped rects
Old352 EQU $1BBF4 ; bAddOver-- addOver fill, unclipped rects (and bitmaps)
Old353 EQU $1BD7C ; bSubPin-- subPin fill, unclipped rects
Old354 EQU $1C0B0 ; bTransparent-- transparent fill, unclipped rects
Old355 EQU $1BE18 ; bMax-- addMax fill, unclipped rects
Old356 EQU $1BD06 ; bSubOver-- subOver fill, unclipped rects
Old357 EQU $1BE9E ; bMin-- addMin fill, unclipped rects
Old35A EQU $1CBF8 ; rMASK0-- copyBits, copy mode, region clipped
Old35E EQU $1CCCC ; rMASK8-- one-reg region clipped fill
Old360 EQU $1CCFA ; rMASK10-- invert, region clipped, pattern black
Old362 EQU $1CD20 ; rXMASK8-- pattern fill, region clipped
Old366 EQU $1CF94 ; rAvg-- blend fill, clipped rects
Old367 EQU $1CDE8 ; rAddPin-- addPin fill, clipped rects
Old368 EQU $1CD9C ; rAddOver-- addOver fill, clipped rects (and bitmaps)
Old369 EQU $1CE88 ; rSubPin-- subPin fill, clipped rects
Old36A EQU $1D094 ; rTransparent-- transparent fill, clipped rects
Old36B EQU $1CEDC ; rMax-- addMax fill, clipped rects
Old36C EQU $1CE3C ; rSubOver-- subOver fill, clipped rects
Old36D EQU $1CF38 ; rMin-- addMin fill, clipped rects
Old372 EQU $1D000 ; rHilite-- clipped hilite invert
Old373 EQU $227EC ; stMASK0-- 1 to 8 clipped copyBits
Old380 EQU $1DD7E ; slMASK8-- oval/rrect copy mode scan line handler
Old381 EQU $1DD9A ; slMASK9-- oval/rrect OR mode scan line handler
Old384 EQU $1DDCE ; slXMask8-- oval/rrect complex fill, copy mode
Old388 EQU $1E1BE ; slAvg-- blend fill, ovals
Old389 EQU $1DF50 ; slAddPin-- addPin fill, ovals
Old38A EQU $1DEBA ; slAddOver-- addOver fill, ovals
Old38B EQU $1E042 ; slSubPin-- subPin fill, ovals
Old38C EQU $1E2CE ; slTransparent-- transparent fill, ovals
Old38D EQU $1E0CE ; slMax-- AddMax fill, ovals
Old38E EQU $1DFDA ; slSubOver-- subOver fill, ovals
Old38F EQU $1E146 ; slMin-- AddMin fill, ovals
;******************************************************************************************
;--------------------------------------------------------------
;
; PROCEDURE StretchBits(srcBits,maskBits,dstBits: BitMap;
; srcRect,maskRect,dstRect: Rect;
; mode: INTEGER; pat: Pattern;
; rgnA,rgnB,rgnC: RgnHandle);
;
; Transfer a rectangle of bits from srcBits to dstBits,
; stretching or compressing according to srcRect and dstRect.
; The transfer is clipped to the intersection of rgnA, rgnB, and rgnC.
; It is also clipped to the specified mask. If MaskBits is NIL, then
; no masking is done.
;
; Restrictions:
;
; transfer mode 0..7 only.
; if numer <> denom, then src and dst bitmaps do not overlap.
;
;
; COPYRIGHT APPLE COMPUTER INC.
; DESIGNED AND WRITTEN BY BILL ATKINSON
;
;----------------------------------------------------
;
; A6 OFFSETS OF PARAMETERS AFTER LINK:
;
PARAMSIZE EQU 44 ;SIZE OF PARAMETERS
SRCBITS EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP
MASKBITS EQU SRCBITS-4 ;LONG, ADDR OF BITMAP
DSTBITS EQU MASKBITS-4 ;LONG, ADDR OF BITMAP
SRCRECT EQU DSTBITS-4 ;LONG, ADDR OF RECT
MASKRECT EQU SRCRECT-4 ;LONG, ADDR OF RECT
DSTRECT EQU MASKRECT-4 ;LONG, ADDR OF RECT
MODE EQU DSTRECT-2 ;WORD
PAT EQU MODE-4 ;LONG, ADDR OF PATTERN
RGNA EQU PAT-4 ;LONG, RGNHANDLE
RGNB EQU RGNA-4 ;LONG, RGNHANDLE
RGNC EQU RGNB-4 ;LONG, RGNHANDLE
multColor EQU RGNC-2 ;byte, set if source contains nonblack/white colors
;-------------------------------------------------
;
; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK:
;
; STACK FRAME VARS USED BY SEEKMASK (CALLED BY STRETCHBITS, RGNBLT, DRAWARC, DRAWLINE)
;
RECTFLAG EQU -2 ;WORD
VERT EQU RECTFLAG-2 ;WORD
RGNBUF EQU VERT-4 ;LONG
BUFLEFT EQU RGNBUF-2 ;WORD
BUFSIZE EQU BUFLEFT-2 ;WORD
EXRTN EQU BUFSIZE-4 ;LONG
SEEKMASK EQU EXRTN-4 ;LONG
DSTMASKBUF EQU SEEKMASK-4 ;LONG
DSTMASKALIGN EQU DSTMASKBUF-4 ;LONG
STATEA EQU DSTMASKALIGN-RGNREC ;RGN STATE RECORD
STATEB EQU STATEA-RGNREC ;RGN STATE RECORD
STATEC EQU STATEB-RGNREC ;RGN STATE RECORD
; STACK FRAME VARS USED BY PATEXPAND, COLORMAP, DRAWSLAB
; CALLED BY STRETCHBITS, RGNBLT, BITBLT, DRAWARC, DRAWLINE
; SET UP FOR BITBLT AND RGNBLT
EXPAT EQU STATEC-4 ;LONG YES
PATVMASK EQU EXPAT-2 ;WORD (must follow expat)
PATHMASK EQU PATVMASK-2 ;WORD (must follow PATVMASK)
PATROW EQU PATHMASK-2 ;WORD (must follow PATHMASK)
PATHPOS EQU PATROW-2 ;WORD YES
PATVPOS EQU PATHPOS-2 ;WORD YES
LOCMODE EQU PATVPOS-2 ;WORD YES
PIXSRC EQU LOCMODE-1 ;BYTE YES
NEWPAT EQU LOCMODE-2 ;BYTE YES
LOCPAT EQU NEWPAT-4 ;LONG YES
FCOLOR EQU LOCPAT-4 ;LONG YES
BCOLOR EQU FCOLOR-4 ;LONG YES
DSTPIX EQU BCOLOR-(PMREC+CTREC+20) ;PIXMAP+COLOR TABLE YES
DSTSHIFT EQU DSTPIX-2 ;WORD YES
; these shared stack frame vars are set up and used by the arithmetic drawing modes
weight EQU DSTSHIFT-6 ;RGB weight for averaging
pin EQU weight ;RGB used by max, min
notWeight EQU weight-6 ;RGB complement of weight (for average)
multiColor EQU notWeight-2 ;byte set if source contains nonblack/white colors
colorTable EQU multiColor-4 ;long pointer to color table
invColor EQU colorTable-4 ;long pointer to inverse color table
invSize EQU invColor-2 ;word resolution of inverse color table
rtShift EQU invSize-2 ;Word used by average how far to shift
transColor EQU rtShift-4 ;long copy of backcolor for transparent
hilitColor EQU transColor-4 ;long hilite color pixels
; MORE SHARED STACK FRAME VARS (STRETCHBITS, RGNBLT, BITBLT)
SRCPIX EQU hilitColor-(PMREC+CTREC+20) ;PIXMAP YES
MASKPIX EQU SRCPIX-(PMREC+CTREC+20) ;PIXMAP YES
SRCROW EQU MASKPIX-4 ;LONG YES
MASKROW EQU SRCROW-4 ;LONG YES
DSTROW EQU MASKROW-4 ;LONG YES
SRCSHIFT EQU DSTROW-2 ;WORD YES
MASKSHIFT EQU SRCSHIFT-2 ;WORD YES
MINRECT EQU MASKSHIFT-8 ;RECT YES
INVERT EQU MINRECT-4 ;LONG YES
SAVESTK EQU INVERT-4 ;LONG YES
SAVEA5 EQU SAVESTK-4 ;LONG YES
SRCBUF EQU SAVEA5-4 ;LONG
DSTBUF EQU SRCBUF-4 ;LONG
SCALEBUF EQU DSTBUF-4 ;LONG
SRCMASKBUF EQU SCALEBUF-4 ;LONG
SRCLONGS EQU SRCMASKBUF-2 ;WORD
SRCMASKLONGS EQU SRCLONGS-2 ;WORD
DSTMASKLONGS EQU SRCMASKLONGS-2 ;WORD
DSTLONGS EQU DSTMASKLONGS-2 ;WORD
SCALELONGS EQU DSTLONGS-2 ;WORD
SRCADDR EQU SCALELONGS-4 ;LONG
MASKADDR EQU SRCADDR-4 ;LONG
DSTADDR EQU MASKADDR-4 ;LONG
SRCLIMIT EQU DSTADDR-4 ;LONG
NUMER EQU SRCLIMIT-4 ;POINT
DENOM EQU NUMER-4 ;POINT
MASKNUMER EQU DENOM-4 ;POINT
MASKDENOM EQU MASKNUMER-4 ;POINT
MODECASE EQU MASKDENOM-4 ;LONG
; STACK FRAME VARS USED BY STRETCHBITS ONLY
STACKFREE EQU MODECASE-4 ;LONG
VERROR EQU STACKFREE-2 ;INTEGER
RATIOCASE EQU VERROR-4 ;LONG
MASKCASE EQU RATIOCASE-4 ;LONG
FRACTION EQU MASKCASE-2 ;WORD
MASKFRACT EQU FRACTION-2 ;WORD
SCALECASE EQU MASKFRACT-4 ;LONG
SRCSCANS EQU SCALECASE-2 ;WORD
SRCPIXCNT EQU SRCSCANS-2 ;WORD
SRCALIGN EQU SRCPIXCNT-4 ;LONG
DSTALIGN EQU SRCALIGN-4 ;LONG
MASKALIGN EQU DSTALIGN-4 ;LONG
ScaleTbl EQU MASKALIGN-4 ;LONG
CRSRFLAG EQU ScaleTbl-2 ;WORD
REALBOUNDS EQU CRSRFLAG-4 ;LONG
; STACK FRAME VARS USED BY RGNBLT ONLY
FIRSTV EQU REALBOUNDS-2 ;WORD
LASTV EQU FIRSTV-2 ;WORD
VBUMP EQU LASTV-2 ;WORD, MUST BE ABOVE HBUMP
HBUMP EQU VBUMP-2 ;WORD
RGNADDR EQU HBUMP-4 ;LONG
SRCSIZE EQU RGNADDR-2 ;WORD
SAVESTK2 EQU SRCSIZE-4 ;LONG
; STACK FRAME VARS USED BY BITBLT ONLY
SRCV EQU SAVESTK2-2 ;WORD
DSTV EQU SRCV-2 ;WORD
SRCBUMP EQU DSTV-2 ;WORD
HEIGHT EQU SRCBUMP-2 ;WORD
LONGCNT EQU HEIGHT-2 ;WORD
SRCRECT2 EQU LONGCNT-8 ;RECT
FIRSTMASK EQU SRCRECT2-4 ;LONG
doneMid EQU FIRSTMASK-1 ;Byte two flags used to control loop
endSwitch EQU doneMid-1 ;Byte three-way switch chooses from src, pat, bigpat
lastMask EQU endSwitch-4 ;Long mask for last long blitted on line
midCount EQU lastMask-2 ;Word # of pixels on line less mask longs - 1
pixInLong EQU midCount-2 ;Word > # of pixels in a long - 1
patPos EQU pixInLong-2 ;Word pattern vertical offset
patOffset EQU patPos-4 ;Long pattern horizontal initial offset
destPixOffset EQU patOffset-2 ;Word destination pixel offset
pixInLong1 EQU destPixOffset-2 ;Word same as pixInLong, 1 based (for transparent)
VARSIZE EQU pixInLong1 ;SIZE OF LOCAL VARIABLES
;-----------------------------------------------------
; Here's where we handle the case of copyBits copy mode without region clipping ($330)
UseOld330
LEARom Old330,A1 ;must use A1 to avoid re-entry
JMP (A1)
CopyScanLine1
CMP.W #8,SRCPIX+PIXELSIZE(A6) ;8 bits/pixel?
BNE.S UseOld330 ;if not, don't handle
TST.L D7 ;toggling source?
BNE.S UseOld330 ;if so, don't handle
; it's 8 bit mode, so handle it. Calculate the address adjustments in D7 from the
; bit offset in D6 and mask in D1. First decode the mask, casing out on the direction
; in A0
MOVE.L D1,D3 ;get mask
MOVEQ #0,D1 ;assume minimum
MOVE.W D6,D0
ASR #3,D0 ;turn into byte number
MOVE.W A0,D5 ;remember direction
BPL.S @0 ;if positive, we're cool
NOT.L D3 ;invert the mask for other direction
@0
TST.L D3
BMI.S Got1stOffset ;if on, we're done
ADDQ #1,D1
LSL.L #8,D3
BMI.S Got1stOffset ;if on, we're done
ADDQ #1,D1
LSL.L #8,D3
BMI.S Got1stOffset ;if on, we're done
ADDQ #1,D1
; we got the mask offset in D1 and the byte offset in D0, so compute the bump factors
Got1stOffset
ADD.W D1,D0 ;compute byte offset
MOVE.W D0,D7 ;remember offset
SWAP D7
MOVE.W D1,D7 ;use mask offset for dest
; here's the top of the outer loop where we adjust the addresses by the offsets in D7
SL1Loop
ADD.W D7,A5
SWAP D7
ADD.W D7,A4
; get the byte count and blast the scan line
SL1Blast
MOVE.W MINRECT+RIGHT(A6),D0
SUB.W MINRECT+LEFT(A6),D0 ;compute pixel count
EXT.L D0
MOVE.L A4,A0
MOVE.L A5,A1
BSR BlockMove ;blast those bytes!
; done with this scan line, so bump to the next scan line and loop until done
SUB.W D7,A4 ;undo source offset
SWAP D7
SUB.W D7,A5 ;undo dest offset
MOVEQ #0,D0
MOVE.W LONGCNT(A6),D0 ;get long count
ADDQ #1,D0
ASL #2,D0 ;turn into byte count
TST.W D5
BPL.S @0 ;if positive, skip
NEG.L D0 ;negate it
@0
ADD.L D0,A4
ADD.L D0,A5
ADD.W SRCBUMP(A6),A4 ;bump source ; <PB448 DBG>
ADD.W A3,A5 ;bump destination
SUBQ.W #1,HEIGHT(A6) ;decrement scan line count
BNE.S SL1Loop ;if more, go do it
RTS
;******************************************************************************************
; Here's where we handle the case of 8-bit pattern fill with region clipping (trap $362)
; this is used for the more complex patterns that require 2 registers per scan line
; this routine uses "region counting" to keep track of the last scan line's region runs
; for ultra-fast plotting when the region mask hasn't changed. This requires a few different
; loops to keep track of measuring state implicitly, without performance degradation.
UseOld362
LEARom Old362,A1 ;must use A1 to avoid re-entry
JMP (A1)
PatClipScanLine
CMP.W #4,D7 ;is pattern too complex?
BGT.S UseOld362 ;if so, can't handle
LEA PatClipOuter,A0
MOVE.L A0,MODECASE(A6) ;skip initial testing on return
MOVEQ #0,D7 ;no runs yet
SUB.L A2,A2 ;runs not valid
; Handle pattern fill with region clipping. Fetch the pattern raster into D3 and D4.
PatClipOuter
ADD.W D6,A3
SWAP D6 ;bump to next raster
MOVE.L 0(A3,D6),D3 ;get 1st 4 pixels
EOR.W #4,D6
MOVE.L 0(A3,D6),D4 ;get next 4 pixels
MOVEQ #-1,D5 ;mask for comparing
; first handle the left edge outside of the inner loop so we don't count it in the runs
MOVE.L (A4)+,D1 ;fetch region mask
MOVE.L D3,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
EXG.L D3,D4
SUBQ #1,D2
BMI.S DonePCV1Line
; if the region runs in D4 are still valid, we can use special code to really plot super
; fast.
MOVE.L A2,D0 ;is it valid?
BNE V1PlotRgnRuns ;if so, go super fast
ADDQ #1,A2 ;validate it for next time
MOVEQ #0,D7 ;zero the run count
; see what the next region longword is. Go to three different loops depending on whether
; the region is all ones, zeros or both
MOVE.L (A4)+,D1 ;fetch next word of region mask
BEQ V1FirstZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE V1StartSecondRun ;if not, skip
BRA.S V1FirstOnes1
; here's the loop that counts and plots the first run of all ones
V1FirstOnes
MOVE.L (A4)+,D1
CMP.L D5,D1 ;is it still all ones?
BNE V1StartSecondRun ;if not, end the run
V1FirstOnes1
ADDQ.W #1,D7 ;bump the run count
MOVE.L D3,(A5)+
EXG.L D3,D4
DBRA D2,V1FirstOnes ;loop until we're done
; done with this scan line, so bump to the next
DonePCV1Line
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6) ;bump to next line of destination
; bump pattern index
MOVE.W PATHPOS(A6),D6
SWAP D6
ADD.W PATROW(A6),D6
AND.W PATVMASK(A6),D6 ;wrap around
; bump line count and see if we're done
MOVE.W VERT(A6),D0
ADDQ #1,D0
MOVE.W D0,VERT(A6)
CMP.W MINRECT+BOTTOM(A6),D0 ;all done?
BEQ DonePatClip ;if so, use common exit
; create the region mask for the new scan line, and maintain the all one's flag
CMP.W STATEB+NEXTV(A6),D0 ;rebuild the region?
BGE.S V1NewRgn ;if so, go do it
CMP.W STATEB+THISV(A6),D0 ;need to rebuild?
BLT.S V1NewRgn ;if so, go do it
CMP.W STATEC+NEXTV(A6),D0 ;rebuild the region?
BGE.S V1NewRgn ;if so, go do it
CMP.W STATEC+THISV(A6),D0 ;need to rebuild?
BLT.S V1NewRgn ;if so, go do it
CMP.W STATEA+NEXTV(A6),D0 ;rebuild the region?
BGE.S V1NewRgn ;if so, go do it
CMP.W STATEA+THISV(A6),D0 ;need to rebuild?
BLT.S V1NewRgn ;if so, go do it
TST.L DSTMASKBUF(A6) ;can we skip it?
BEQ.S V1SkipRgn ;if so, skip
V1NewRgn
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;make new region mask
SUB.L A2,A2 ;invalidate region counts
; set up registers and go handle the next line
V1SkipRgn
MOVE.L SRCADDR(A6),A3
MOVE.L RGNBUF(A6),A4
MOVE.L DSTADDR(A6),A5
MOVE.W BUFSIZE(A6),D2
BRA PatClipOuter
; here's the loop that counts and plots the first run of all zeros
V1FirstZero
MOVE.L (A4)+,D1
BNE.S V1StartSecondRun
V1FirstZero0
SUBQ.W #1,D7 ;decrement run count for zeros
ADDQ #4,A5
EXG.L D3,D4
DBRA D2,V1FirstZero
BRA.S DonePCV1Line
; the region mask is heterogenous, so plot the word and start the second run.
V1StartSecondRun
SWAP D7
MOVE.L D3,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
EXG.L D3,D4
SUBQ #1,D2
BMI.S DoneV1SecondRun
; sample the region and case out for the 2nd time
MOVE.L (A4)+,D1 ;fetch next word of region mask
BEQ.S V1stZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE.S V1StartLastRun ;if not, skip
BRA.S V1stOnes1
; here's the loop that counts and plots the second run of all ones
V1stOnes
MOVE.L (A4)+,D1
CMP.L D5,D1 ;is it still all ones?
BNE.S V1StartLastRun ;if not, end the run
V1stOnes1
ADDQ.W #1,D7 ;bump the run count
MOVE.L D3,(A5)+
EXG.L D3,D4
DBRA D2,V1stOnes ;loop until we're done
DoneV1SecondRun
SWAP D7
BRA DonePCV1Line ;all done
; here's the loop that counts the 2nd run of zeros
V1stZero
MOVE.L (A4)+,D1
BNE.S V1StartLastRun
V1stZero0
SUBQ.W #1,D7
ADDQ #4,A5 ;bump dest reg
EXG.L D3,D4
DBRA D2,V1stZero ;loop until it changes
BRA.S DoneV1SecondRun
; OK, we've accumulated two runs, so finish up the line without counting
V1StartLastRun
SWAP D7
TST.L D1
BEQ.S V1LastZero
BRA.S V1LastLoopA
V1LastLoop
MOVE.L (A4)+,D1 ;get region
BEQ.S V1LastZero
V1LastLoopA
CMP.L D5,D1
BNE.S V1LastHard
MOVE.L D3,(A5)+ ;plot it
EXG.L D3,D4
DBRA D2,V1LastLoop
BRA DonePCV1Line
V1LastZero
ADDQ #4,A5
EXG.L D3,D4
DBRA D2,V1LastLoop
BRA DonePCV1Line
V1LastHard
MOVE.L D3,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
EXG.L D3,D4
DBRA D2,V1LastLoop
BRA DonePCV1Line
; Here's where we have the ultra fast plotting by interpreting the 2 region runs in D7.
V1PlotRgnRuns
TST.W D7 ;which type of run?
BPL.S V1BlastPat1 ;if ones, go blast it
BEQ V1PlotRHard1 ;if zero, plot one slowly, then plot 2nd run
; it's negative, so just skip over 4 times the count
MOVE.W D7,D0
NEG.W D0 ;turn into longword count
BTST #0,D0 ;is the run odd?
BEQ.S @0 ;if not, skip
EXG.L D3,D4
@0
LSL.W #2,D0 ;times 4
ADD.W D0,A4 ;skip over region
ADD.W D0,A5 ;skip over destination
ADD.W D7,D2 ;decrement count
BMI DonePCV1Line ;if done, skip
; now handle the second run
V1PRRun2
LEA @0,A0 ;plot the break longword
BRA V1PlotHardCommon
@0
MOVE.L D7,D0 ;which type of run?
BPL.S V1BlastPat2 ;if ones, go blast it
BEQ V1PlotRHard2
; it's negative, so we can skip over like above
SWAP D0
NEG.W D0 ;turn into longword count
BTST #0,D0 ;is the run odd?
BEQ.S @1 ;if not, skip
EXG.L D3,D4
@1
SUB.W D0,D2 ;decrement count
LSL.W #2,D0 ;times 4
ADD.W D0,A4 ;skip over region
ADD.W D0,A5 ;skip over destination
TST.W D2
BMI DonePCV1Line ;if done, skip
; we've interpreted both runs, so finish up using common code
BRA V1LastLoop
; Handle blasting out the first run
V1BlastPat1
MOVE.W D7,D0 ;get the size
LEA V1PRRun2,A0
BRA.S V1BlastPat
; Blast out the second run
V1BlastPat2
SWAP D0 ;use high word for 2nd run
LEA V1LastLoop,A0
; Here's the unwound loop to blast the # of longwords in D0 out.
V1BlastPat
CMP.W #8,D0 ;8 left to do?
BLT.S V1BlastFinishUp
MOVE.W D0,D1
LSR #3,D1
SUBQ #1,D1
V1BlastLoop
MOVE.L D3,(A5)+
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+
MOVE.L D4,(A5)+
DBRA D1,V1BlastLoop
V1BlastFinishUp
MOVE.W D0,D1
AND #7,D1
EOR #7,D1
BTST #0,D1
BEQ.S @0
EXG.L D3,D4
@0
JMP V1FinishTable(D1.W*2)
V1FinishTable
MOVE.L D3,(A5)+
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+ ;15 total to finish up
EXG.L D3,D4
; all done with plotting so adjust the region pointer and count, then return
@0
MOVE.W D0,D1
LSL #2,D1 ;times 4
ADD.W D1,A4 ;bump region ptr
SUB.W D0,D2
BMI DonePCV1Line
V1BlastDone
JMP (A0)
; handle the heterogenous plots between runs
V1PlotRHard1
LEA V1PRRun2,A0
BRA.S V1PlotHardCommon
V1PlotRHard2
LEA V1LastLoop,A0
V1PlotHardCommon
MOVE.L (A4)+,D1
MOVE.L D3,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
EXG.L D3,D4
SUBQ #1,D2 ;count it
BMI DonePCV1Line
JMP (A0)
;******************************************************************************************
; Here's where we handle a case of 8-bit pattern fill with region clipping (trap $35E)
; where there's only 4 pixel repeating pattern so it fits in a single register.
; this routine uses "region counting" to keep track of the last scan line's region runs
; for ultra-fast plotting when the region mask hasn't changed. This requires 5 different
; loops to keep track of measuring state implicitly, without performance degradation.
; D3 has 2 runs in its two words; negative numbers are runs of zeros, positive numbers ones
; D4 has the "scan line valid" flag; if it's non-zero, it's valid.
; this routine works for any bits/pixel
UseOld35E
LEARom Old35E,A1 ;must use A1 to avoid re-entry <PB446 DBG>
JMP (A1)
PatClipVar2
LEA PatClipV2Outer,A0
MOVE.L A0,MODECASE(A6) ;skip initial testing on return
MOVEQ #0,D3 ;zero run counts
MOVEQ #0,D4 ;runs are currently invalid
; Handle pattern fill with region clipping. Fetch the pattern raster into D3 and D4.
PatClipV2Outer
MOVEQ #-1,D5 ;mask for comparing
; first handle the left edge outside of the inner loop so we don't count it in the runs
MOVE.L (A4)+,D1 ;fetch region mask
MOVE.L D6,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
SUBQ #1,D2
BMI.S DonePCV2Line
; if the region runs in D4 are still valid, we can use special code to really plot super
; fast.
TST.W D4 ;is it valid?
BNE V2PlotRgnRuns ;if so, go super fast
MOVEQ #-1,D4 ;validate it for next time
MOVEQ #0,D3 ;zero the run count
; see what the next region longword is. Go to three different loops depending on whether
; the region is all ones, zeros or both
MOVE.L (A4)+,D1 ;fetch next word of region mask
BEQ V2FirstZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE V2StartSecondRun ;if not, skip
BRA.S V2FirstOnes1
; here's the loop that counts and plots the first run of all ones
V2FirstOnes
MOVE.L (A4)+,D1
CMP.L D5,D1 ;is it still all ones?
BNE V2StartSecondRun ;if not, end the run
V2FirstOnes1
ADDQ.W #1,D3 ;bump the run count
MOVE.L D6,(A5)+
DBRA D2,V2FirstOnes ;loop until we're done
; done with this scan line, so bump to the next
DonePCV2Line
ADDQ #1,D7
AND.W #15,D7
MOVE.L ([EXPAT,A6],D7.W*4),D6 ;bump the pattern
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6) ;bump to next line of destination
; bump line count and see if we're done
MOVE.W VERT(A6),D0
ADDQ #1,D0
MOVE.W D0,VERT(A6)
CMP.W MINRECT+BOTTOM(A6),D0 ;all done?
BEQ DonePatClip ;if so, use common exit
; create the region mask for the new scan line, and maintain the all one's flag
CMP.W STATEB+NEXTV(A6),D0 ;rebuild the region?
BGE.S V2NewRgn ;if so, go do it
CMP.W STATEB+THISV(A6),D0 ;need to rebuild?
BLT.S V2NewRgn ;if so, go do it
CMP.W STATEC+NEXTV(A6),D0 ;rebuild the region?
BGE.S V2NewRgn ;if so, go do it
CMP.W STATEC+THISV(A6),D0 ;need to rebuild?
BLT.S V2NewRgn ;if so, go do it
CMP.W STATEA+NEXTV(A6),D0 ;rebuild the region?
BGE.S V2NewRgn ;if so, go do it
CMP.W STATEA+THISV(A6),D0 ;need to rebuild?
BLT.S V2NewRgn ;if so, go do it
TST.L DSTMASKBUF(A6) ;can we skip it?
BEQ.S V2SkipRgn ;if so, skip
V2NewRgn
MOVEQ #0,D4 ;invalidate region counts
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;make new region mask
; set up registers and go handle the next line
V2SkipRgn
MOVE.L RGNBUF(A6),A4
MOVE.L DSTADDR(A6),A5
MOVE.W BUFSIZE(A6),D2
BRA PatClipV2Outer
; here's the loop that counts and plots the first run of all zeros
V2FirstZero
MOVE.L (A4)+,D1
BNE.S V2StartSecondRun
V2FirstZero0
SUBQ.W #1,D3 ;decrement run count for zeros
ADDQ #4,A5
DBRA D2,V2FirstZero
BRA.S DonePCV2Line
; the region mask is heterogenous, so plot the word and start the second run.
V2StartSecondRun
SWAP D3
MOVE.L D6,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
SUBQ #1,D2
BMI.S DoneSecondRun
; sample the region and case out for the 2nd time
MOVE.L (A4)+,D1 ;fetch next word of region mask
BEQ.S V2ndZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE.S V2StartLastRun ;if not, skip
BRA.S V2ndOnes1
; here's the loop that counts and plots the second run of all ones
V2ndOnes
MOVE.L (A4)+,D1
CMP.L D5,D1 ;is it still all ones?
BNE.S V2StartLastRun ;if not, end the run
V2ndOnes1
ADDQ.W #1,D3 ;bump the run count
MOVE.L D6,(A5)+
DBRA D2,V2ndOnes ;loop until we're done
DoneSecondRun
SWAP D3
BRA DonePCV2Line ;all done
; here's the loop that counts the 2nd run of zeros
V2ndZero
MOVE.L (A4)+,D1
BNE.S V2StartLastRun
V2ndZero0
SUBQ.W #1,D3
ADDQ #4,A5 ;bump dest reg
DBRA D2,V2ndZero ;loop until it changes
BRA.S DoneSecondRun
; OK, we've accumulated two runs, so finish up the line without counting
V2StartLastRun
SWAP D3
TST.L D1
BEQ.S V2LastZero
BRA.S V2LastLoopA
V2LastLoop
MOVE.L (A4)+,D1 ;get region
BEQ.S V2LastZero
V2LastLoopA
CMP.L D5,D1
BNE.S V2LastHard
MOVE.L D6,(A5)+ ;plot it
DBRA D2,V2LastLoop
BRA DonePCV2Line
V2LastZero
ADDQ #4,A5
DBRA D2,V2LastLoop
BRA DonePCV2Line
V2LastHard
MOVE.L D6,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
DBRA D2,V2LastLoop
BRA DonePCV2Line
; Here's where we have the ultra fast plotting by interpreting the 2 region runs in D3.
V2PlotRgnRuns
TST.W D3 ;which type of run?
BPL.S V2BlastPat1 ;if ones, go blast it
BEQ V2PlotRHard1 ;if zero, plot one slowly, then plot 2nd run
; it's negative, so just skip over 4 times the count
MOVE.W D3,D0
NEG.W D0 ;turn into longword count
LSL.W #2,D0 ;times 4
ADD.W D0,A4 ;skip over region
ADD.W D0,A5 ;skip over destination
ADD.W D3,D2 ;decrement count
BMI DonePCV2Line ;if done, skip
; now handle the second run
V2PRRun2
LEA @0,A0 ;plot the break longword
BRA V2PlotHardCommon
@0
MOVE.L D3,D0 ;which type of run?
BPL.S V2BlastPat2 ;if ones, go blast it
BEQ.S V2PlotRHard2
; it's negative, so we can skip over like above
SWAP D0
NEG.W D0 ;turn into longword count
SUB.W D0,D2 ;decrement count
LSL.W #2,D0 ;times 4
ADD.W D0,A4 ;skip over region
ADD.W D0,A5 ;skip over destination
TST.W D2
BMI DonePCV2Line ;if done, skip
; we've interpreted both runs, so finish up using common code
BRA.S V2LastLoop
; Handle blasting out the first run
V2BlastPat1
MOVE.W D3,D0 ;get the size
LEA V2PRRun2,A0
BRA.S V2BlastPat
; Blast out the second run
V2BlastPat2
SWAP D0 ;use high word for 2nd run
LEA V2LastLoop,A0
; Here's the unwound loop to blast the # of longwords in D0 out.
V2BlastPat
CMP.W #8,D0 ;8 left to do?
BLT.S V2BlastFinishUp
MOVE.W D0,D1
LSR #3,D1
SUBQ #1,D1
V2BlastLoop
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
DBRA D1,V2BlastLoop
V2BlastFinishUp
MOVE.W D0,D1
AND #7,D1
EOR #7,D1
JMP V2FinishTable(D1.W*2)
V2FinishTable
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+
MOVE.L D6,(A5)+ ;15 total to finish up
; all done with plotting so adjust the region pointer and count, then return
MOVE.W D0,D1
LSL #2,D1 ;times 4
ADD.W D1,A4 ;bump region ptr
SUB.W D0,D2
BMI DonePCV2Line
JMP (A0)
; handle the heterogenous plots between runs
V2PlotRHard1
LEA V2PRRun2,A0
BRA.S V2PlotHardCommon
V2PlotRHard2
LEA V2LastLoop,A0
V2PlotHardCommon
MOVE.L (A4)+,D1
MOVE.L D6,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
SUBQ #1,D2 ;count it
BMI DonePCV2Line
JMP (A0)
;******************************************************************************************
; Here's where we handle the case of 8-bit pattern fill with no clipping (trap $338)
; (with complex pattern, copy mode)
UseOld338
LEARom Old338,A1 ;must use A1 to avoid re-entry
JMP (A1)
PatFillScanLine
CMP.W #4,D7 ;is pattern too complex?
BGT.S UseOld338 ;if so, can't handle
; Handle pattern fill with no clipping. Fetch the pattern raster into D3 and D4. The
; basic strategy is to do the edge in the general (masking) way, then blast away for
; the middle, finally handling the right edge generally.
PatFillOuter
MOVE.L 0(A4,D6),D3 ;get left pattern
EOR.W #4,D6
MOVE.L 0(A4,D6),D4 ;get right pattern
; first special case the left edge before falling into the loop
MOVE.L D1,D0 ;get left mask
AND.L D3,D0 ;use left pattern
NOT.L D1 ;flip mask
AND.L (A5),D1 ;get dest
OR.L D1,D0 ;combine with source
MOVE.L D0,(A5)+ ;stuff it
; now blast away for the bulk of it
MOVE.W D2,D0
BEQ.S NextPFillLine
CMP.W #4,D2 ;near the end?
BLE.S PatFillFinish ;if so, go handle
SUBQ #1,D0 ;do last one with mask
LSR #2,D0 ;divide by 4 for unwound loop
SUBQ #1,D0 ;bias for DBRA
PatFillInner
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+ ;store 32 pixels worth real fast
DBRA D0,PatFillInner
; finish up the last few pixels
PatFillFinish
MOVE.L D4,D0
MOVE.W D2,D1
AND #3,D1
JMP PatFinTable(D1.W*2)
Finish4
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+
Finish2
MOVE.L D4,(A5)+
MOVE.L D3,D0
BRA.S Finish1
PatFinTable
BRA.S Finish4
BRA.S Finish1
BRA.S Finish2
BRA.S Finish3
Finish3
MOVE.L D4,(A5)+
MOVE.L D3,(A5)+
Finish1
MOVE.L D5,D1 ;get mask
AND.L D1,D0 ;mask pattern in D0
NOT.L D1 ;flip mask
AND.L (A5),D1 ;get dest
OR.L D1,D0 ;combine with source
MOVE.L D0,(A5)+ ;stuff it
NextPFillLine
SWAP D6
SUB.W D6,A4
ADD.W PATROW(A6),D6
AND.W PATVMASK(A6),D6 ;wrap around
ADD.W D6,A4
SWAP D6
MOVE.W PATHPOS(A6),D6
ADD.W A3,A5
MOVE.L FIRSTMASK(A6),D1
MOVE.W LONGCNT(A6),D2
SUBQ.W #1,HEIGHT(A6) ;decrement scan line count
BNE PatFillOuter
RTS
;******************************************************************************************
; Handle copyBits, copy mode, with region clipping. Use the region clipping technique
; for fast plotting
UseOld35A
LEARom Old35A,A1 ; <PB446 DBG>
JMP (A1)
CBClipLine
CMP.W #8,SRCPIX+PIXELSIZE(A6) ;8 bits/pixel?
BNE.S UseOld35A ;if not, don't handle
TST.L D7 ;toggling source?
BNE.S UseOld35A ;if so, don't handle
LEA CBClipCommon,A0
MOVE.L A0,MODECASE(A6) ;skip initial testing on return
MOVEQ #0,D4 ;count invalid 1st time through
CBClipCommon
MOVEQ #-1,D5 ;get all ones for comparing
CBClipOuter
MOVE.W D6,D0 ;get bit index
ASR.W #3,D0 ;convert to byte index
ADD.W D0,A3 ;factor in the byte offset
TST.W D3 ;forwards or backwards?
BMI CBClipNeg ;if backwards, handle specially
; the first set of loops is for the plotting forward case (moving towards the left)
; first handle the left edge outside of the inner loop so we don't count it in the runs
CBClipLoop
MOVE.L (A4)+,D1 ;fetch region mask
MOVE.L (A3)+,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
SUBQ #1,D2
BMI.S DoneCBCLine
; if the region runs in D4 are still valid, we can use special code to really plot super
; fast.
TST.W D4 ;is it valid?
BNE CBCPlotRgnRuns ;if so, go super fast
MOVEQ #-1,D4 ;validate it for next time
MOVEQ #0,D7 ;zero the run count
; see what the next region longword is. Go to three different loops depending on whether
; the region is all ones, zeros or both
MOVE.L (A4)+,D1 ;fetch next word of region mask
BEQ CBCFirstZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE CBCStartSecondRun ;if not, skip
BRA.S CBCFirstOnes1
; here's the loop that counts and plots the first run of all ones
CBCFirstOnes
MOVE.L (A4)+,D1
CMP.L D5,D1 ;is it still all ones?
BNE CBCStartSecondRun ;if not, end the run
CBCFirstOnes1
ADDQ.W #1,D7 ;bump the run count
MOVE.L (A3)+,(A5)+
DBRA D2,CBCFirstOnes ;loop until we're done
; all done with the scan line so bump the pointers, generate a new region mask if
; necessary, and loop until we're done
DoneCBCLine
MOVE.L SRCROW(A6),D0
ADD.L D0,SRCADDR(A6)
; now bump the output scan line pointer
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6) ;bump to next line
; bump line count and see if we're done
MOVE.W VERT(A6),D0
ADD.W VBUMP(A6),D0
MOVE.W D0,VERT(A6)
CMP.W LASTV(A6),D0 ;all done?
BEQ.S DonePatClip ;if not, skip
; create the region mask for the new scan line, and maintain the all one's flag
CMP.W STATEB+NEXTV(A6),D0 ;rebuild the region?
BGE.S CBCNewRgn ;if so, go do it
CMP.W STATEB+THISV(A6),D0 ;need to rebuild?
BLT.S CBCNewRgn ;if so, go do it
CMP.W STATEC+NEXTV(A6),D0 ;rebuild the region?
BGE.S CBCNewRgn ;if so, go do it
CMP.W STATEC+THISV(A6),D0 ;need to rebuild?
BLT.S CBCNewRgn ;if so, go do it
CMP.W STATEA+NEXTV(A6),D0 ;rebuild the region?
BGE.S CBCNewRgn ;if so, go do it
CMP.W STATEA+THISV(A6),D0 ;need to rebuild?
BLT.S CBCNewRgn ;if so, go do it
TST.L DSTMASKBUF(A6) ;can we skip it?
BEQ.S CBCSkipRgn ;if so, skip
CBCNewRgn
MOVEQ #0,D4 ;invalidate region counts
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;make new region mask
; set up registers and go handle the next line
CBCSkipRgn
MOVE.L SRCADDR(A6),A3
MOVE.L RGNADDR(A6),A4
MOVE.L DSTADDR(A6),A5
MOVE.W BUFSIZE(A6),D2
MOVE.L MODECASE(A6),A2
JMP (A2)
; all done so strip stack and return
DonePatClip
MOVE.L SAVESTK2(A6),A7
DonePClipRTS
RTS
; here's the loop that counts and plots the first run of all zeros
CBCFirstZero
MOVE.L (A4)+,D1
BNE.S CBCStartSecondRun
CBCFirstZero0
SUBQ.W #1,D7 ;decrement run count for zeros
ADDQ #4,A3
ADDQ #4,A5
DBRA D2,CBCFirstZero
BRA.S DoneCBCLine
; the region mask is heterogenous, so plot the word and start the second run.
CBCStartSecondRun
SWAP D7
MOVE.L (A3)+,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
SUBQ #1,D2
BMI.S DoneCBCSecondRun
; sample the region and case out for the 2nd time
MOVE.L (A4)+,D1 ;fetch next word of region mask
BEQ.S CBCndZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE.S CBCStartLastRun ;if not, skip
BRA.S CBCndOnes1
; here's the loop that counts and plots the second run of all ones
CBCndOnes
MOVE.L (A4)+,D1
CMP.L D5,D1 ;is it still all ones?
BNE.S CBCStartLastRun ;if not, end the run
CBCndOnes1
ADDQ.W #1,D7 ;bump the run count
MOVE.L (A3)+,(A5)+
DBRA D2,CBCndOnes ;loop until we're done
DoneCBCSecondRun
SWAP D7
BRA DoneCBCLine ;all done
; here's the loop that counts the 2nd run of zeros
CBCndZero
MOVE.L (A4)+,D1
BNE.S CBCStartLastRun
CBCndZero0
SUBQ.W #1,D7
ADDQ #4,A3
ADDQ #4,A5 ;bump dest reg
DBRA D2,CBCndZero ;loop until it changes
BRA.S DoneCBCSecondRun
; OK, we've accumulated two runs, so finish up the line without counting
CBCStartLastRun
SWAP D7
TST.L D1
BEQ.S CBCLastZero
BRA.S CBCLastLoopA
CBCLastLoop
MOVE.L (A4)+,D1 ;get region
BEQ.S CBCLastZero
CBCLastLoopA
CMP.L D5,D1
BNE.S CBCLastHard
MOVE.L (A3)+,(A5)+ ;plot it
DBRA D2,CBCLastLoop
BRA DoneCBCLine
CBCLastZero
ADDQ #4,A3
ADDQ #4,A5
DBRA D2,CBCLastLoop
BRA DoneCBCLine
CBCLastHard
MOVE.L (A3)+,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
DBRA D2,CBCLastLoop
BRA DoneCBCLine
; Here's where we have the ultra fast plotting by interpreting the 2 region runs in D7.
CBCPlotRgnRuns
TST.W D7 ;which type of run?
BPL.S CBCBlastPat1 ;if ones, go blast it
BEQ CBCPlotRHard1 ;if zero, plot one slowly, then plot 2nd run
; it's negative, so just skip over 4 times the count
MOVE.W D7,D0
NEG.W D0 ;turn into longword count
LSL.W #2,D0 ;times 4
ADD.W D0,A3
ADD.W D0,A4 ;skip over region
ADD.W D0,A5 ;skip over destination
ADD.W D7,D2 ;decrement count
BMI DoneCBCLine ;if done, skip
; now handle the second run
CBCPRRun2
LEA @0,A0 ;plot the break longword
BRA CBCPlotHardCommon
@0
MOVE.L D7,D0 ;which type of run?
BPL.S CBCBlastPat2 ;if ones, go blast it
BEQ.S CBCPlotRHard2
; it's negative, so we can skip over like above
SWAP D0
NEG.W D0 ;turn into longword count
SUB.W D0,D2 ;decrement count
LSL.W #2,D0 ;times 4
ADD.W D0,A3
ADD.W D0,A4 ;skip over region
ADD.W D0,A5 ;skip over destination
TST.W D2
BMI DoneCBCLine ;if done, skip
; we've interpreted both runs, so finish up using common code
BRA.S CBCLastLoop
; Handle blasting out the first run
CBCBlastPat1
MOVE.W D7,D0 ;get the size
LEA CBCPRRun2,A0
BRA.S CBCBlastPat
; Blast out the second run
CBCBlastPat2
SWAP D0 ;use high word for 2nd run
LEA CBCLastLoop,A0
; Here's the unwound loop to blast the # of longwords in D0 out.
CBCBlastPat
CMP.W #8,D0 ;8 left to do?
BLT.S CBCBlastFinishUp
MOVE.W D0,D1
LSR #3,D1
SUBQ #1,D1
CBCBlastLoop
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
DBRA D1,CBCBlastLoop
CBCBlastFinishUp
MOVE.W D0,D1
AND #7,D1
EOR #7,D1
JMP CBCFinishTable(D1.W*2)
CBCFinishTable
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+
MOVE.L (A3)+,(A5)+ ;15 total to finish up
; all done with plotting so adjust the region pointer and count, then return
MOVE.W D0,D1
LSL #2,D1 ;times 4
ADD.W D1,A4 ;bump region ptr
SUB.W D0,D2
BMI DoneCBCLine
JMP (A0)
; handle the heterogenous plots between runs
CBCPlotRHard1
LEA CBCPRRun2,A0
BRA.S CBCPlotHardCommon
CBCPlotRHard2
LEA CBCLastLoop,A0
CBCPlotHardCommon
MOVE.L (A4)+,D1
MOVE.L (A3)+,D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5)+ ;deposit it
SUBQ #1,D2 ;count it
BMI DoneCBCLine
JMP (A0)
; here's a whole different set of loops for the backwards case
CBClipNeg
ADDQ #4,A3 ;ditto for source
ADDQ #4,A4 ;bias region ptr
ADDQ #4,A5 ;and dest
CBClipNegLoop
MOVE.L -(A4),D1 ;fetch region mask
MOVE.L -(A3),D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L -(A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5) ;deposit it
SUBQ #1,D2
BMI DoneCBCLine
; if the region runs in D4 are still valid, we can use special code to really plot super
; fast.
TST.W D4 ;is it valid?
BNE CBCNegPlotRgnRuns ;if so, go super fast
MOVEQ #-1,D4 ;validate it for next time
MOVEQ #0,D7 ;zero the run count
; see what the next region longword is. Go to three different loops depending on whether
; the region is all ones, zeros or both
MOVE.L -(A4),D1 ;fetch next word of region mask
BEQ.S CBCNegFirstZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE.S CBCNegStartSecondRun ;if not, skip
BRA.S CBCNegFirstOnes1
; here's the loop that counts and plots the first run of all ones
CBCNegFirstOnes
MOVE.L -(A4),D1
CMP.L D5,D1 ;is it still all ones?
BNE.S CBCNegStartSecondRun ;if not, end the run
CBCNegFirstOnes1
ADDQ.W #1,D7 ;bump the run count
MOVE.L -(A3),-(A5)
DBRA D2,CBCNegFirstOnes ;loop until we're done
BRA DoneCBCLine
; here's the loop that counts and plots the first run of all zeros
CBCNegFirstZero
MOVE.L -(A4),D1
BNE.S CBCNegStartSecondRun
CBCNegFirstZero0
SUBQ.W #1,D7 ;decrement run count for zeros
SUBQ #4,A3
SUBQ #4,A5
DBRA D2,CBCNegFirstZero
BRA DoneCBCLine
; the region mask is heterogenous, so plot the word and start the second run.
CBCNegStartSecondRun
SWAP D7
MOVE.L -(A3),D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L -(A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5) ;deposit it
SUBQ #1,D2
BMI.S DoneCBCNegSecondRun
; sample the region and case out for the 2nd time
MOVE.L -(A4),D1 ;fetch next word of region mask
BEQ.S CBCNegndZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE.S CBCNegStartLastRun ;if not, skip
BRA.S CBCNegndOnes1
; here's the loop that counts and plots the second run of all ones
CBCNegndOnes
MOVE.L -(A4),D1
CMP.L D5,D1 ;is it still all ones?
BNE.S CBCNegStartLastRun ;if not, end the run
CBCNegndOnes1
ADDQ.W #1,D7 ;bump the run count
MOVE.L -(A3),-(A5)
DBRA D2,CBCNegndOnes ;loop until we're done
DoneCBCNegSecondRun
SWAP D7
BRA DoneCBCLine ;all done
; here's the loop that counts the 2nd run of zeros
CBCNegndZero
MOVE.L -(A4),D1
BNE.S CBCNegStartLastRun
CBCNegndZero0
SUBQ.W #1,D7
SUBQ #4,A3
SUBQ #4,A5 ;bump dest reg
DBRA D2,CBCNegndZero ;loop until it changes
BRA.S DoneCBCNegSecondRun
; OK, we've accumulated two runs, so finish up the line without counting
CBCNegStartLastRun
SWAP D7
TST.L D1
BEQ.S CBCNegLastZero
BRA.S CBCNegLastLoopA
CBCNegLastLoop
MOVE.L -(A4),D1 ;get region
BEQ.S CBCNegLastZero
CBCNegLastLoopA
CMP.L D5,D1
BNE.S CBCNegLastHard
MOVE.L -(A3),-(A5) ;plot it
DBRA D2,CBCNegLastLoop
BRA DoneCBCLine
CBCNegLastZero
SUBQ #4,A3
SUBQ #4,A5
DBRA D2,CBCNegLastLoop
BRA DoneCBCLine
CBCNegLastHard
MOVE.L -(A3),D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L -(A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5) ;deposit it
DBRA D2,CBCNegLastLoop
BRA DoneCBCLine
; Here's where we have the ultra fast plotting by interpreting the 2 region runs in D7.
CBCNegPlotRgnRuns
TST.W D7 ;which type of run?
BPL.S CBCNegBlastPat1 ;if ones, go blast it
BEQ CBCNegPlotRHard1 ;if zero, plot one slowly, then plot 2nd run
; it's negative, so just skip over 4 times the count
MOVE.W D7,D0
NEG.W D0 ;turn into longword count
LSL.W #2,D0 ;times 4
SUB.W D0,A3
SUB.W D0,A4 ;skip over region
SUB.W D0,A5 ;skip over destination
ADD.W D7,D2 ;decrement count
BMI DoneCBCLine ;if done, skip
; now handle the second run
CBCNegPRRun2
LEA @0,A0 ;plot the break longword
BRA CBCNegPlotHardCommon
@0
MOVE.L D7,D0 ;which type of run?
BPL.S CBCNegBlastPat2 ;if ones, go blast it
BEQ.S CBCNegPlotRHard2
; it's negative, so we can skip over like above
SWAP D0
NEG.W D0 ;turn into longword count
SUB.W D0,D2 ;decrement count
LSL.W #2,D0 ;times 4
SUB.W D0,A3
SUB.W D0,A4 ;skip over region
SUB.W D0,A5 ;skip over destination
TST.W D2
BMI DoneCBCLine ;if done, skip
; we've interpreted both runs, so finish up using common code
BRA.S CBCNegLastLoop
; Handle blasting out the first run
CBCNegBlastPat1
MOVE.W D7,D0 ;get the size
LEA CBCNegPRRun2,A0
BRA.S CBCNegBlastPat
; Blast out the second run
CBCNegBlastPat2
SWAP D0 ;use high word for 2nd run
LEA CBCNegLastLoop,A0
; Here's the unwound loop to blast the # of longwords in D0 out.
CBCNegBlastPat
CMP.W #8,D0 ;8 left to do?
BLT.S CBCNegBlastFinishUp
MOVE.W D0,D1
LSR #3,D1
SUBQ #1,D1
CBCNegBlastLoop
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
DBRA D1,CBCNegBlastLoop
CBCNegBlastFinishUp
MOVE.W D0,D1
AND #7,D1
EOR #7,D1
JMP CBCNegFinishTable(D1.W*2)
CBCNegFinishTable
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5)
MOVE.L -(A3),-(A5) ;15 total to finish up
; all done with plotting so adjust the region pointer and count, then return
MOVE.W D0,D1
LSL #2,D1 ;times 4
SUB.W D1,A4 ;bump region ptr
SUB.W D0,D2
BMI DoneCBCLine
JMP (A0)
; handle the heterogenous plots between runs
CBCNegPlotRHard1
LEA CBCNegPRRun2,A0
BRA.S CBCNegPlotHardCommon
CBCNegPlotRHard2
LEA CBCNegLastLoop,A0
CBCNegPlotHardCommon
MOVE.L -(A4),D1
MOVE.L -(A3),D0 ;get pattern
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L -(A5),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A5) ;deposit it
SUBQ #1,D2 ;count it
BMI DoneCBCLine
JMP (A0)
;******************************************************************************************
; InvertRgn case ($360) -- ie, invert clipped to region. Use the standard region
; counting stuff
UseOld360
LEARom Old360,A1
JMP (A1)
InvertClip
GoInvertClip
LEA Inv1ClipOuter,A0
MOVE.L A0,MODECASE(A6) ;skip initial testing on return
MOVEQ #0,D4 ;no runs yet
SUB.L A2,A2 ;runs not valid
MOVEQ #-1,D5 ;mask for comparing
Inv1ClipOuter
; first handle the left edge outside of the inner loop so we don't count it in the runs
MOVE.L D6,D0
AND.L (A4)+,D0
EOR.L D0,(A5)+
SUBQ #1,D2
BMI.S DoneInv1Line
; if the region runs in D4 are still valid, we can use special code to really plot super
; fast.
MOVE.L A2,D0 ;is it valid?
BNE Inv1PlotRgnRuns ;if so, go super fast
ADDQ #1,A2 ;validate it for next time
MOVEQ #0,D4 ;zero the run count
; see what the next region longword is. Go to three different loops depending on whether
; the region is all ones, zeros or both
MOVE.L (A4)+,D1 ;fetch next word of region mask
BEQ Inv1FirstZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE Inv1StartSecondRun ;if not, skip
BRA.S Inv1FirstOnes1
; here's the loop that counts and plots the first run of all ones
Inv1FirstOnes
MOVE.L (A4)+,D1
CMP.L D5,D1 ;is it still all ones?
BNE Inv1StartSecondRun ;if not, end the run
Inv1FirstOnes1
ADDQ.W #1,D4 ;bump the run count
EOR.L D6,(A5)+
DBRA D2,Inv1FirstOnes ;loop until we're done
; done with this scan line, so bump to the next
DoneInv1Line
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6) ;bump to next line of destination
; bump pattern index
ADDQ #1,D7
AND.W #15,D7
MOVE.L ([EXPAT,A6],D7.W*4),D6 ;bump the pattern
; bump line count and see if we're done
MOVE.W VERT(A6),D0
ADD.W VBUMP(A6),D0
MOVE.W D0,VERT(A6)
CMP.W LASTV(A6),D0 ;all done?
BEQ DonePatClip ;if so, use common exit
; create the region mask for the new scan line, and maintain the all one's flag
CMP.W STATEB+NEXTV(A6),D0 ;rebuild the region?
BGE.S Inv1NewRgn ;if so, go do it
CMP.W STATEB+THISV(A6),D0 ;need to rebuild?
BLT.S Inv1NewRgn ;if so, go do it
CMP.W STATEC+NEXTV(A6),D0 ;rebuild the region?
BGE.S Inv1NewRgn ;if so, go do it
CMP.W STATEC+THISV(A6),D0 ;need to rebuild?
BLT.S Inv1NewRgn ;if so, go do it
CMP.W STATEA+NEXTV(A6),D0 ;rebuild the region?
BGE.S Inv1NewRgn ;if so, go do it
CMP.W STATEA+THISV(A6),D0 ;need to rebuild?
BLT.S Inv1NewRgn ;if so, go do it
TST.L DSTMASKBUF(A6) ;can we skip it?
BEQ.S Inv1SkipRgn ;if so, skip
Inv1NewRgn
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;make new region mask
SUB.L A2,A2 ;invalidate region counts
; set up registers and go handle the next line
Inv1SkipRgn
MOVE.L RGNBUF(A6),A4
MOVE.L DSTADDR(A6),A5
MOVE.W BUFSIZE(A6),D2
BRA Inv1ClipOuter
; here's the loop that counts and plots the first run of all zeros
Inv1FirstZero
MOVE.L (A4)+,D1
BNE.S Inv1StartSecondRun
Inv1FirstZero0
SUBQ.W #1,D4 ;decrement run count for zeros
ADDQ #4,A5
DBRA D2,Inv1FirstZero
BRA.S DoneInv1Line
; the region mask is heterogenous, so plot the word and start the second run.
Inv1StartSecondRun
SWAP D4
AND.L D6,D1 ;mask it
EOR.L D1,(A5)+ ;deposit it
SUBQ #1,D2
BMI.S DoneInv1SecondRun
; sample the region and case out for the 2nd time
MOVE.L (A4)+,D1 ;fetch next word of region mask
BEQ.S Inv1stZero0 ;if zero, go handle
CMP.L D5,D1 ;all one's?
BNE.S Inv1StartLastRun ;if not, skip
BRA.S Inv1stOnes1
; here's the loop that counts and plots the second run of all ones
Inv1stOnes
MOVE.L (A4)+,D1
CMP.L D5,D1 ;is it still all ones?
BNE.S Inv1StartLastRun ;if not, end the run
Inv1stOnes1
ADDQ.W #1,D4 ;bump the run count
EOR.L D6,(A5)+
DBRA D2,Inv1stOnes ;loop until we're done
DoneInv1SecondRun
SWAP D4
BRA DoneInv1Line ;all done
; here's the loop that counts the 2nd run of zeros
Inv1stZero
MOVE.L (A4)+,D1
BNE.S Inv1StartLastRun
Inv1stZero0
SUBQ.W #1,D4
ADDQ #4,A5 ;bump dest reg
DBRA D2,Inv1stZero ;loop until it changes
BRA.S DoneInv1SecondRun
; OK, we've accumulated two runs, so finish up the line without counting
Inv1StartLastRun
SWAP D4
TST.L D1
BEQ.S Inv1LastZero
BRA.S Inv1LastLoopA
Inv1LastLoop
MOVE.L (A4)+,D1 ;get region
BEQ.S Inv1LastZero
Inv1LastLoopA
CMP.L D5,D1
BNE.S Inv1LastHard
EOR.L D6,(A5)+ ;plot it
DBRA D2,Inv1LastLoop
BRA DoneInv1Line
Inv1LastZero
ADDQ #4,A5
DBRA D2,Inv1LastLoop
BRA DoneInv1Line
Inv1LastHard
AND.L D6,D1
EOR.L D1,(A5)+ ;deposit it
DBRA D2,Inv1LastLoop
BRA DoneInv1Line
; Here's where we have the ultra fast plotting by interpreting the 2 region runs in D4.
Inv1PlotRgnRuns
TST.W D4 ;which type of run?
BPL.S Inv1BlastPat1 ;if ones, go blast it
BEQ Inv1PlotRHard1 ;if zero, plot one slowly, then plot 2nd run
; it's negative, so just skip over 4 times the count
MOVE.W D4,D0
NEG.W D0 ;turn into longword count
LSL.W #2,D0 ;times 4
ADD.W D0,A4 ;skip over region
ADD.W D0,A5 ;skip over destination
ADD.W D4,D2 ;decrement count
BMI DoneInv1Line ;if done, skip
; now handle the second run
Inv1PRRun2
LEA @0,A0 ;plot the break longword
BRA Inv1PlotHardCommon
@0
MOVE.L D4,D0 ;which type of run?
BPL.S Inv1BlastPat2 ;if ones, go blast it
BEQ.S Inv1PlotRHard2
; it's negative, so we can skip over like above
SWAP D0
NEG.W D0 ;turn into longword count
SUB.W D0,D2 ;decrement count
LSL.W #2,D0 ;times 4
ADD.W D0,A4 ;skip over region
ADD.W D0,A5 ;skip over destination
TST.W D2
BMI DoneInv1Line ;if done, skip
; we've interpreted both runs, so finish up using common code
BRA.S Inv1LastLoop
; Handle blasting out the first run
Inv1BlastPat1
MOVE.W D4,D0 ;get the size
LEA Inv1PRRun2,A0
BRA.S Inv1BlastPat
; Blast out the second run
Inv1BlastPat2
SWAP D0 ;use high word for 2nd run
LEA Inv1LastLoop,A0
; Here's the unwound loop to blast the # of longwords in D0 out.
Inv1BlastPat
CMP.W #8,D0 ;8 left to do?
BLT.S Inv1BlastFinishUp
MOVE.W D0,D1
LSR #3,D1
SUBQ #1,D1
Inv1BlastLoop
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
DBRA D1,Inv1BlastLoop
Inv1BlastFinishUp
MOVE.W D0,D1
AND #7,D1
EOR #7,D1
JMP Inv1FinishTable(D1.W*2)
Inv1FinishTable
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
EOR.L D6,(A5)+
; all done with plotting so adjust the region pointer and count, then return
@0
MOVE.W D0,D1
LSL #2,D1 ;times 4
ADD.W D1,A4 ;bump region ptr
SUB.W D0,D2
BMI DoneInv1Line
Inv1BlastDone
JMP (A0)
; handle the heterogenous plots between runs
Inv1PlotRHard1
LEA Inv1PRRun2,A0
BRA.S Inv1PlotHardCommon
Inv1PlotRHard2
LEA Inv1LastLoop,A0
Inv1PlotHardCommon
MOVE.L D6,D1
AND.L (A4)+,D1
EOR.L D1,(A5)+ ;deposit it
SUBQ #1,D2 ;count it
BMI DoneInv1Line
JMP (A0)
;******************************************************************************************
; InvertHiliteClip ($372) speeds up region clipped hiliting; no more invert hack
UseOld372
LEARom Old372,A1
JMP (A1)
InvertHiliteClip
CMP.W #8,SRCPIX+PIXELSIZE(A6) ;8 bits/pixel?
BNE.S UseOld372 ;if not, don't handle
LEA InvertHiOuter,A0
MOVE.L A0,MODECASE(A6) ;come back here
; if the background/hilite colors are black and white, we can expedite matters significantly
InvertHiOuter
MOVE.L D4,D7 ;get hilite
EOR.L D5,D7 ;compute toggle mask
; OK, here's the inner loop. If the whole longword at the destination is background or
; hilite color, toggle it with the hilite mask. Otherwise, we have to process it a
; byte at a time
InvertHInner
MOVE.L (A4)+,D1 ;get the region mask
BEQ.S InvertEmpty ;if empty, skip
MOVE.L (A5),D0 ;get the current destination
CMP.L D0,D4 ;all hilite?
BEQ.S @0 ;if so, it's easy
CMP.L D0,D5 ;all background?
BNE.S InvertHPixels ;if not, it's harder
@0
AND.L D7,D1 ;mask toggle with region
EOR.L D1,D0 ;toggle dest
MOVE.L D0,(A5)+ ;stuff it
NextInvertH
DBRA D2,InvertHInner ;loop till done
; all done with the scan line, so bump the appropriate pointers, and loop until done
BumpNextScanLine
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6) ;bump to next line
; bump line count and see if we're done
MOVE.W VERT(A6),D0
ADD.W VBUMP(A6),D0
MOVE.W D0,VERT(A6)
CMP.W LASTV(A6),D0 ;all done?
BEQ.S DoneInvertSL ;if not, skip
; create the region mask for the new scan line
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;make new region mask
; set up registers and go handle the next line
MOVE.L SRCADDR(A6),A3
MOVE.L RGNADDR(A6),A4
MOVE.L DSTADDR(A6),A5
MOVE.W BUFSIZE(A6),D2
MOVE.L MODECASE(A6),A2
JMP (A2)
; all done so strip stack and return
DoneInvertSL
MOVE.L SAVESTK2(A6),A7
RTS
; handle the case of the empty region by simply bumping the output pointer
InvertEmpty
ADDQ #4,A5 ;bump ptr
DBRA D2,InvertHInner
BRA.S BumpNextScanLine
; handle the more difficult case of a non-homogenous line, which we must process a pixel
; at a time. Destination value is in D0, region mask in D1. Repeat in-line for 4 pixels
; try to do a word at a time, if we can
InvertHPixels
CMP.W D4,D0
BEQ.S IHBumpWord1
CMP.W D5,D0
BEQ.S IHBumpWord1
CMP.B D4,D0 ;same as hilite?
BEQ.S IHBump1 ;if so, let it through
CMP.B D5,D0 ;same as background
BEQ.S IHBump1 ;if so, let it through
CLR.B D1 ;don't use this one
IHBump1
ROR.L #8,D0
ROR.L #8,D1
CMP.B D4,D0 ;same as hilite?
BEQ.S IHBump2 ;if so, let it through
CMP.B D5,D0 ;same as background
BEQ.S IHBump2 ;if so, let it through
CLR.B D1 ;don't use this one
IHBump2
ROR.L #8,D0
ROR.L #8,D1
IHWord2
CMP.W D4,D0
BEQ.S IHBumpWord2
CMP.W D5,D0
BEQ.S IHBumpWord2
CMP.B D4,D0 ;same as hilite?
BEQ.S IHBump3 ;if so, let it through
CMP.B D5,D0 ;same as background
BEQ.S IHBump3 ;if so, let it through
CLR.B D1 ;don't use this one
IHBump3
ROR.L #8,D0
ROR.L #8,D1
CMP.B D4,D0 ;same as hilite?
BEQ.S IHBump4 ;if so, let it through
CMP.B D5,D0 ;same as background?
BEQ.S IHBump4 ;if so, let it through
CLR.B D1 ;don't use this one
IHBump4
ROR.L #8,D0
ROR.L #8,D1
; OK, now we can plot it
IHPlotIt
AND.L D7,D1 ;mask toggle with region
EOR.L D1,D0 ;toggle dest
MOVE.L D0,(A5)+ ;stuff it
DBRA D2,InvertHInner ;loop till done
BRA BumpNextScanLine
; handle word hits
IHBumpWord1
SWAP D0
SWAP D1
BRA.S IHWord2
IHBumpWord2
SWAP D0
SWAP D1
BRA.S IHPlotIt
;******************************************************************************************
; CB1To8Clip ($373) is the clipped copyBits loop used in the 1 to 8 expansion blits,
; common in programs like HyperCard and Servant. If it's the typical case we can handle
; (black and white, source 1 bit,dest 8 bits), expand on the fly, right onto the screen,
; for a pretty big gain.
; it really shouldn't be named CB1to8, as it's the routine used for any scaling or lookup
; blit. We also optimize the 8-bit to 8-bit blits that require table lookup, and also
; handle the 8 to 1 case
UseOld373
LEARom Old373,A1
JMP (A1)
CB1To8Clip
TST.L D7 ;toggle mode?
BNE.S UseOld373 ;if so, don't handle
MOVE.L NUMER(A6),D0
CMP.L DENOM(A6),D0 ;botRights the same?
BNE.S UseOld373 ;if so, don't handle
MOVE.L MASKNUMER(A6),D0
CMP.L MASKDENOM(A6),D0 ;how about topLefts?
BNE.S UseOld373 ;if so, don't handle
TST.L DSTMASKBUF(A6) ;is mask a bitmap?
BNE.S UseOld373 ;if so, don't handle!
MOVE.W SRCPIX+PIXELSIZE(A6),D0 ;get source bits/pixel
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;destination 1 bits/pixel?
BNE ChkDst1Bit ;if not, skip
SUBQ #8,D0
BEQ CB8to8Clip ;if source is 8 bits, go handle
ADDQ #7,D0 ;is it one bit?
BNE.S UseOld373 ;if not, don't handle
Eight EQU $23344 ; offset to the expand by eight, non-colormap routine
CmpRA Eight,ScaleCase(A6) ; is this doing a 1-8bit stretch? <PB473 DAF 19Apr88>
bne.s UseOld373 ; no, can't handle this one. <PB471 BAL 18Apr88>
CMP.L #-1,FCOLOR(A6) ;foreground = black?
BNE.S UseOld373
TST.L BCOLOR(A6) ;background = white?
BNE.S UseOld373
cmp.l scalebuf(a6),a3 ;has src been advanced (i.e. dest < baseAddr) <PB501 BAL/DVB 13Jun88>
bne.s UseOld373 ;if so, don't handle <PB501 BAL/DVB 13Jun88>
MOVE.L SRCROW(A6),D0
SUB.L D0,SRCADDR(A6) ;back up one line
SUBQ #1,BUFSIZE(A6) ;one less than they say
; its our case, so handle it. Pick up the shifted source with a bit-field instruction,
; then use it to plot 8 longwords, indirecting a nibble at a time through an expansion
; table. Special case the edges, so we can really zoom if the middle's region is all ones.
; A2 has the region mask, A4 has the destination; use A3 to hold the source.
; D7 holds the "OK to zoom" (region all ones) flag
CB1to8Outer
MOVE.L DSTALIGN(A6),D0
ASR.L #3,D0
MOVEQ #15,D3 ;D3 has 4 bit mask
MOVEQ #-1,D6 ;D6 has -1 for region compare
LEA Expand1to8,A1
MOVE.L SRCADDR(A6),A3 ;get source pointer
MOVE.L SRCALIGN(A6),D5 ;get shift count
ADD.L D0,D5
; OK, first do the left edge (one nybble worth)
BFEXTU (A3){D5:16},D4 ;pick up next word of source
ADDQ.L #4,D5 ;bump to next nibble
ROL.W #4,D4 ;get next nibble
MOVE.L (A2)+,D1 ;get region mask
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),D0 ;get source longword
AND.L D1,D0
NOT.L D1 ;flip mask
AND.L (A4),D1
OR.L D1,D0 ;combine source and dest
MOVE.L D0,(A4)+ ;stuff it
; OK, here's the loop that handles the middle, which is where all the action is
MOVE.W BUFSIZE(A6),D2 ;get destination count
CMP.W #4,D2 ;four or less we can't optimize
BLE FinishLastFew
; if we have a multiple of 4 left to do, don't do last 4
MOVE.W D2,D0
AND #3,D0
BNE.S @1
SUBQ #1,D2
@1
LSR #2,D2 ;do 4 longwords each iteration
SUBQ #1,D2
TST.B D7 ;is region all ones?
BNE CB1to8SpLoop0 ;if so, we can go super-fast
ST D7 ;assume next like is special
CB1to8Loop
BFEXTU (A3){D5:16},D4 ;pick up next word of source
ADDQ #2,A3 ;bump it
BEQ CB1to8AllZeros ;special case all zeros
CB1to8AltEntry
ROL.W #4,D4 ;get high nibble first
; OK, expand the low 4 bits in D4 into a longword, then plot it. Fetch the region mask
; first, since it may not even be necessary
CB1to8Inner
LEA CB1to8Nib2,A5
MOVE.L (A2)+,D1 ;get region mask
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),D0 ;get source longword
CMP.L D6,D1 ;mask all ones?
BNE CB1to8HardPlot ;if not, plot it the hard way
MOVE.L D0,(A4)+ ;plot the longword
; now plot the 2nd nibble
CB1to8Nib2
LEA CB1to8Nib3,A5
ROL.W #4,D4 ;get next nybble
MOVE.L (A2)+,D1 ;get region mask
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),D0 ;get source longword
CMP.L D6,D1 ;mask all ones?
BNE.S CB1to8HardPlot ;if not, plot it the hard way
MOVE.L D0,(A4)+ ;plot the longword
; now plot the 3rd nibble
CB1to8Nib3
LEA CB1to8Nib4,A5
ROL.W #4,D4 ;get next nybble
MOVE.L (A2)+,D1 ;get region mask
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),D0 ;get source longword
CMP.L D6,D1 ;mask all ones?
BNE.S CB1to8HardPlot ;if not, plot it the hard way
MOVE.L D0,(A4)+ ;plot the longword
; now plot the last nibble
CB1to8Nib4
LEA CB1to8NibBot,A5
ROL.W #4,D4 ;get next nybble
MOVE.L (A2)+,D1 ;get region mask
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),D0 ;get source longword
CMP.L D6,D1 ;mask all ones?
BNE.S CB1to8HardPlot ;if not, plot it the hard way
MOVE.L D0,(A4)+ ;plot the longword
CB1to8NibBot
DBRA D2,CB1to8Loop ;loop until done
; clean up the last 0 to 3 nibbles; 4 remaining handled specially
FinishLastFew
BFEXTU (A3){D5:16},D4 ;pick up last word of source
LEA BotFin1to8Loop,A5
MOVE.W BUFSIZE(A6),D2 ;get the number left to do
BEQ CB1to8NextLine ;if zero, we're done
AND.W #3,D2 ;0 to 3 only
BNE.S BotFin1to8Loop
MOVEQ #3,D2 ;4 to do
TopFin1to8Loop
ROL.W #4,D4
MOVE.L (A2)+,D1 ;get region mask
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),D0 ;get source longword
CMP.L D6,D1 ;mask all ones?
BNE.S CB1to8HPNoInval ;if not, plot it the hard way (no edge)
MOVE.L D0,(A4)+ ;plot the longword
BotFin1to8Loop
DBRA D2,TopFin1to8Loop
BRA.S CB1to8NextLine
; handle the case where the region mask is all zeros
CB1to8NoPlot
ADDQ.L #4,A4 ;bump dest ptr
JMP (A5) ;advance to next one
; handle the more difficult case of a heterogenous region mask
CB1to8HardPlot
MOVEQ #0,D7 ;not all ones
CB1to8HPNoInval
TST.L D1
BEQ.S CB1to8NoPlot
AND.L D1,D0
NOT.L D1 ;flip mask
AND.L (A4),D1
OR.L D1,D0 ;combine source and dest
MOVE.L D0,(A4)+ ;stuff it
JMP (A5)
; to speed things up, we special case words of all zero and blast 4 long words of zero out as
; fast as we can, without having to do any lookups.
CB1to8AllZeros
MOVE.L (A2)+,D1 ;get region mask
BEQ.S CBZEmpty1 ;if all zeros, skip
CMP.L D6,D1 ;all ones?
BNE.S CBZBIC1 ;if not, skip
CLR.L (A4)+ ;plot the zeros
CBZLong2
MOVE.L (A2)+,D1 ;get region mask
BEQ.S CBZEmpty2 ;if all zeros, skip
CMP.L D6,D1 ;all ones?
BNE.S CBZBIC2 ;if not, skip
CLR.L (A4)+ ;plot the zeros
CBZLong3
MOVE.L (A2)+,D1 ;get region mask
BEQ.S CBZEmpty3 ;if all zeros, skip
CMP.L D6,D1 ;all ones?
BNE.S CBZBIC3 ;if not, skip
CLR.L (A4)+ ;plot the zeros
CBZLong4
MOVE.L (A2)+,D1 ;get region mask
BEQ.S CBZEmpty4 ;if all zeros, skip
CMP.L D6,D1 ;all ones?
BNE.S CBZBIC4 ;if not, skip
CLR.L (A4)+ ;plot the zeros
BRA.S CB1to8NibBot ;dive back in
CBZEmpty1
MOVEQ #0,D7
ADDQ #4,A4
BRA.S CBZLong2
CBZEmpty2
MOVEQ #0,D7
ADDQ #4,A4
BRA.S CBZLong3
CBZEmpty3
MOVEQ #0,D7
ADDQ #4,A4
BRA.S CBZLong4
CBZEmpty4
MOVEQ #0,D7
ADDQ #4,A4
BRA CB1to8NibBot
CBZBIC1
MOVEQ #0,D7
NOT.L D1
AND.L D1,(A4)+
BRA.S CBZLong2
CBZBIC2
MOVEQ #0,D7
NOT.L D1
AND.L D1,(A4)+
BRA.S CBZLong3
CBZBIC3
MOVEQ #0,D7
NOT.L D1
AND.L D1,(A4)+
BRA.S CBZLong4
CBZBIC4
MOVEQ #0,D7
NOT.L D1
AND.L D1,(A4)+
BRA CB1to8NibBot
; all done with this line, so bump the pointers and loop until done
CB1to8NextLine
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6) ;bump to next line of destination
MOVE.L SRCROW(A6),D0
ADD.L D0,SRCADDR(A6) ;bump to next line of source
; bump line count and see if we're done
MOVE.W VERT(A6),D0
ADDQ #1,D0
MOVE.W D0,VERT(A6)
CMP.W MINRECT+BOTTOM(A6),D0 ;all done?
BEQ.S Done1To8Clip ;if so, skip
; create the region mask for the new scan line, and maintain the all one's flag
CMP.W STATEB+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB1to8NewRgn ;if so, go do it
CMP.W STATEB+THISV(A6),D0 ;need to rebuild?
BLT.S CB1to8NewRgn ;if so, go do it
CMP.W STATEC+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB1to8NewRgn ;if so, go do it
CMP.W STATEC+THISV(A6),D0 ;need to rebuild?
BLT.S CB1to8NewRgn ;if so, go do it
CMP.W STATEA+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB1to8NewRgn ;if so, go do it
CMP.W STATEA+THISV(A6),D0 ;need to rebuild?
BGE.S Skip1to8Rgn ;if not, skip
CB1to8NewRgn
MOVEQ #0,D7 ;invalidate region all ones flag
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;make new region mask
; set up registers and go handle the next line
Skip1to8Rgn
MOVE.L RGNBUF(A6),A2
MOVE.L DSTADDR(A6),A4
BRA CB1to8Outer ;go process next line
; all done so strip stack and return
Done1To8Clip
MOVE.L SAVEA5(A6),A5
TST.B CRSRFLAG(A6)
BEQ.S @0
JSR ([$0F4C]) ;SHOWCURSOR
@0
BSET #7,HILITEMODE ;$938
MOVE.L SAVESTK(A6),A7
MOVEM.L (SP)+,D0-D7/A1-A5
UNLK A6
RTD #44
; here's where we go when we've detected that region masking isn't necessary, so we can really
; blast things 4 longwords at a time
CB1to8SpLoop0
MOVE.W D2,D7 ;remember the count
CB1to8SpLoop
BFEXTU (A3){D5:16},D4 ;pick up next word of source
ADDQ #2,A3 ;bump it
BEQ.S CB1to8SpAllZeros ;special case all zeros
CMP.W D4,D6 ;all ones?
BEQ.S CB1to8SpAllOnes
ROL.W #4,D4 ;get first nibble
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),(A4)+ ;plot expanded longword
ROL.W #4,D4 ;get next nibble
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),(A4)+ ;plot expanded longword
ROL.W #4,D4 ;get next nibble
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),(A4)+ ;plot expanded longword
ROL.W #4,D4 ;get next nibble
MOVE.W D4,D0 ;get low 4 bits
AND.W D3,D0
MOVE.L 0(A1,D0.W*4),(A4)+ ;plot expanded longword
BotCB1to8SpLoop
DBRA D2,CB1to8SpLoop
; finish up the special case by adjusting A2 and diving back into common code
Finish1to8Sp
ADDQ #1,D7 ;add one for real count
LSL.W #4,D7 ;4 longs (16 bytes) per iteration
ADD.W D7,A2 ;bump region pointer
BRA FinishLastFew ;finish the last few
; handle the case when the source word is all zero and there's no region clipping -- we
; can go as fast as we can.
CB1to8SpAllZeros
CLR.L (A4)+
CLR.L (A4)+
CLR.L (A4)+
CLR.L (A4)+
BRA.S BotCB1to8SpLoop
CB1to8SpAllOnes
MOVE.L D6,(A4)+
MOVE.L D6,(A4)+
MOVE.L D6,(A4)+
MOVE.L D6,(A4)+
BRA.S BotCB1to8SpLoop
; here is the nybble to longword expansion table
ALIGN 4
Expand1To8
DC.L $00000000,$000000FF,$0000FF00,$0000FFFF
DC.L $00FF0000,$00FF00FF,$00FFFF00,$00FFFFFF
DC.L $FF000000,$FF0000FF,$FF00FF00,$FF00FFFF
DC.L $FFFF0000,$FFFF00FF,$FFFFFF00,$FFFFFFFF
;******************************************************************************************
CB8to81st0
ADDQ #4,A3 ;bump source ptr
ADDQ #4,A4 ;bump dest ptr
BRA CB8to8Middle
; Handler for the 8 to 8 copyBits case (with mapping). The basic strategy is the usual
; region counting, with the added twist of a single element cache for the longword mapping,
; using A1 to hold the pre-map and D7 to hold the post-mapped values.
CB8to8Clip
TST.L MASKBITS(A6) ;should we handle it?
BNE UseOld373 ;if not, skip
MOVE.L SRCROW(A6),D0
SUB.L D0,SRCADDR(A6) ;back up one line
SUBQ #1,BUFSIZE(A6) ;one less than they say
MOVEQ #-1,D6 ;D6 has -1 for region compare
MOVEQ #0,D4
MOVEQ #0,D3 ;init region counting regs
SUB.L A1,A1
SUBQ.L #1,A1 ;all ones for initial
MOVEQ #-1,D7 ;map cache values
CB8to8Outer
MOVE.L RGNBUF(A6),A2
MOVE.L SRCADDR(A6),A3 ;get source pointer
MOVE.L DSTADDR(A6),A4 ;get destptr
MOVE.L SCALETBL(A6),A5 ;get mapping table
; offset source pointer according to bit offsets
MOVE.L DSTALIGN(A6),D0 ;get shift count
ASR.L #3,D0
MOVE.L SRCALIGN(A6),D1
ASR.L #3,D1
ADD.L D1,D0
ADD.L D0,A3 ;offset source ptr
; OK, first do the left edge
MOVE.W BUFSIZE(A6),D2 ;get the count
MOVEQ #0,D5
MOVE.L (A2)+,D1 ;get region mask
BEQ.S CB8to81st0 ;if zero, handle it
; fetch the 1st source longword and map it through the table pointed to by A5
MOVE.L (A3)+,D0 ;get source longword
MOVE.L D0,A1 ;remember it
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 1st byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 2nd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 3rd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 4th byte
ROL.L #8,D0
MOVE.L D0,D7 ;remember result of mapping
; plot it using the region mask
AND.L D1,D0
NOT.L D1 ;flip mask
AND.L (A4),D1
OR.L D1,D0 ;combine source and dest
MOVE.L D0,(A4)+ ;stuff it
SUBQ #1,D2
BMI.S CB8to8NextLine
; if the region runs in D4 are still valid, we can use special code to really plot super
; fast.
CB8to8Middle
TST.W D4 ;is it valid?
BNE V8to8PlotRgnRuns ;if so, go super fast
MOVEQ #-1,D4 ;validate it for next time
MOVEQ #0,D3 ;zero the run count
; see what the next region longword is. Go to three different loops depending on whether
; the region is all ones, zeros or both
MOVE.L (A2)+,D1 ;fetch next word of region mask
BEQ V8to8FirstZero0 ;if zero, go handle
CMP.L D6,D1 ;all one's?
BNE V8to8StartSecondRun ;if not, skip
BRA.S V8to8FirstOnes1
; here's the loop that counts and plots the first run of all ones
V8to8FirstOnes
MOVE.L (A2)+,D1
CMP.L D6,D1 ;is it still all ones?
BNE V8to8StartSecondRun ;if not, end the run
V8to8FirstOnes1
ADDQ.W #1,D3 ;bump the run count
MOVE.L (A3)+,D0 ;fetch from source
CMP.L D0,A1 ;same as before?
BNE.S @0
MOVE.L D7,D0
BRA.S @1
@0
MOVE.L D0,A1
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 1st byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 2nd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 3rd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 4th byte
ROL.L #8,D0
MOVE.L D0,D7
@1
MOVE.L D0,(A4)+ ;store at destination
DBRA D2,V8to8FirstOnes ;loop until we're done
; OK, all done with this line, so bump the pointers and loop until done
CB8to8NextLine
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6) ;bump to next line of destination
MOVE.L SRCROW(A6),D0
ADD.L D0,SRCADDR(A6) ;bump to next line of source
; bump line count and see if we're done
MOVE.W VERT(A6),D0
ADDQ #1,D0
MOVE.W D0,VERT(A6)
CMP.W MINRECT+BOTTOM(A6),D0 ;all done?
BEQ Done1To8Clip ;if so, use common exit
; create the region mask for the new scan line, and maintain the all ones flag
CMP.W STATEB+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB8to8NewRgn ;if so, go do it
CMP.W STATEB+THISV(A6),D0 ;need to rebuild?
BLT.S CB8to8NewRgn ;if so, go do it
CMP.W STATEC+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB8to8NewRgn ;if so, go do it
CMP.W STATEC+THISV(A6),D0 ;need to rebuild?
BLT.S CB8to8NewRgn ;if so, go do it
CMP.W STATEA+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB8to8NewRgn ;if so, go do it
CMP.W STATEA+THISV(A6),D0 ;need to rebuild?
BGE CB8to8Outer ;if not, skip
CB8to8NewRgn
MOVEQ #0,D4 ;invalidate region all ones flag
MOVE.L A1,-(SP)
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;make new region mask
MOVE.L (SP)+,A1
; go handle the next line
BRA CB8to8Outer ;go process next line
Fin8to8Zeros
ADDQ #4,A4
BRA.S CB8to8NextLine
; here's the loop that counts and plots the first run of all zeros
V8to8FirstZero
MOVE.L (A2)+,D1
BNE.S V8to8StartSecondRun
V8to8FirstZero0
SUBQ.W #1,D3 ;decrement run count for zeros
ADDQ #4,A3
ADDQ #4,A4
DBRA D2,V8to8FirstZero
BRA.S CB8to8NextLine
; the region mask is heterogenous, so plot the word and start the second run.
V8to8StartSecondRun
SWAP D3
MOVE.L (A3)+,D0 ;fetch from source
CMP.L D0,A1 ;same as before?
BNE.S @0
MOVE.L D7,D0
BRA.S @1
@0
MOVE.L D0,A1
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 1st byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 2nd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 3rd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 4th byte
ROL.L #8,D0
MOVE.L D0,D7
@1
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A4),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A4)+ ;deposit it
SUBQ #1,D2
BMI.S Done8to8SecondRun
; sample the region and case out for the 2nd time
MOVE.L (A2)+,D1 ;fetch next word of region mask
BEQ.S V8to8Zero0 ;if zero, go handle
CMP.L D6,D1 ;all one's?
BNE.S V8to8StartLastRun ;if not, skip
BRA.S V8to8Ones1
; here's the loop that counts and plots the second run of all ones
V8to8Ones
MOVE.L (A2)+,D1
CMP.L D6,D1 ;is it still all ones?
BNE.S V8to8StartLastRun ;if not, end the run
V8to8Ones1
ADDQ.W #1,D3 ;bump the run count
MOVE.L (A3)+,D0 ;fetch from source
CMP.L D0,A1 ;same as before?
BNE.S @0
MOVE.L D7,D0
BRA.S @1
@0
MOVE.L D0,A1
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 1st byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 2nd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 3rd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 4th byte
ROL.L #8,D0
MOVE.L D0,D7
@1
MOVE.L D0,(A4)+ ;store at destination
DBRA D2,V8to8Ones ;loop until we're done
Done8to8SecondRun
SWAP D3
BRA CB8to8NextLine ;all done
; here's the loop that counts the 2nd run of zeros
V8to8Zero
MOVE.L (A2)+,D1
BNE.S V8to8StartLastRun
V8to8Zero0
SUBQ.W #1,D3
ADDQ #4,A3
ADDQ #4,A4 ;bump dest reg
DBRA D2,V8to8Zero ;loop until it changes
BRA.S Done8to8SecondRun
; OK, we've accumulated two runs, so finish up the line without counting
V8to8StartLastRun
SWAP D3
TST.L D1
BEQ.S V8to8LastZero
BRA.S V8to8LastLoopA
V8to8LastLoop
MOVE.L (A2)+,D1 ;get region
BEQ.S V8to8LastZero
V8to8LastLoopA
CMP.L D6,D1
BNE.S V8to8LastHard
MOVE.L (A3)+,D0 ;fetch from source
CMP.L D0,A1 ;same as before?
BNE.S @0
MOVE.L D7,D0
BRA.S @1
@0
MOVE.L D0,A1
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 1st byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 2nd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 3rd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 4th byte
ROL.L #8,D0
MOVE.L D0,D7
@1
MOVE.L D0,(A4)+ ;store at destination
DBRA D2,V8to8LastLoop
BRA CB8to8NextLine
V8to8LastZero
ADDQ #4,A4
ADDQ #4,A3
DBRA D2,V8to8LastLoop
BRA CB8to8NextLine
V8to8LastHard
MOVE.L (A3)+,D0 ;fetch from source
CMP.L D0,A1 ;same as before?
BNE.S @0
MOVE.L D7,D0
BRA.S @1
@0
MOVE.L D0,A1
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 1st byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 2nd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 3rd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 4th byte
ROL.L #8,D0
MOVE.L D0,D7
@1
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A4),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A4)+ ;deposit it
DBRA D2,V8to8LastLoop
BRA CB8to8NextLine
; Here's where we have the ultra fast plotting by interpreting the 2 region runs in D3.
V8to8PlotRgnRuns
TST.W D3 ;which type of run?
BPL.S V8to8BlastPat1 ;if ones, go blast it
BEQ V8to8PlotRHard1 ;if zero, plot one slowly, then plot 2nd run
; it's negative, so just skip over 4 times the count
MOVE.W D3,D0
NEG.W D0 ;turn into longword count
LSL.W #2,D0 ;times 4
ADD.W D0,A2 ;skip over region
ADD.W D0,A3 ;skip over source
ADD.W D0,A4 ;skip over destination
ADD.W D3,D2 ;decrement count
BMI CB8to8NextLine ;if done, skip
; now handle the second run
V8to8PRRun2
LEA @0,A0 ;plot the break longword
BRA V8to8PlotHardCommon
@0
MOVE.L D3,D0 ;which type of run?
BPL.S V8to8BlastPat2 ;if ones, go blast it
BEQ.S V8to8PlotRHard2
; it's negative, so we can skip over like above
SWAP D0
NEG.W D0 ;turn into longword count
SUB.W D0,D2 ;decrement count
LSL.W #2,D0 ;times 4
ADD.W D0,A2 ;skip over region
ADD.W D0,A3 ;skip over source
ADD.W D0,A4 ;skip over destination
TST.W D2
BMI CB8to8NextLine ;if done, skip
; we've interpreted both runs, so finish up using common code
BRA V8to8LastLoop
; Handle blasting out the first run
V8to8BlastPat1
MOVE.W D3,D0 ;get the size
MOVE.W D0,D1
LSL #2,D1 ;times 4
ADD.W D1,A2 ;bump region ptr
SUB.W D0,D2
LEA V8to8PRRun2,A0
BRA.S V8to8BlastPatBot
; Blast out the second run
V8to8BlastPat2
SWAP D0 ;use high word for 2nd run
MOVE.W D0,D1
LSL #2,D1 ;times 4
ADD.W D1,A2 ;bump region ptr
SUB.W D0,D2
LEA V8to8LastLoop,A0
BRA.S V8to8BlastPatBot
V8to8BlastPat
MOVE.L (A3)+,D1 ;fetch from source
CMP.L D1,A1 ;same as before?
BNE.S @0
MOVE.L D7,D1
BRA.S @1
@0
MOVE.L D1,A1
MOVE.B D1,D5
MOVE.B 1(A5,D5.W*2),D1 ;map 1st byte
ROL.L #8,D1
MOVE.B D1,D5
MOVE.B 1(A5,D5.W*2),D1 ;map 2nd byte
ROL.L #8,D1
MOVE.B D1,D5
MOVE.B 1(A5,D5.W*2),D1 ;map 3rd byte
ROL.L #8,D1
MOVE.B D1,D5
MOVE.B 1(A5,D5.W*2),D1 ;map 4th byte
ROL.L #8,D1
MOVE.L D1,D7
@1
MOVE.L D1,(A4)+ ;store at destination
V8to8BlastPatBot
DBRA D0,V8to8BlastPat
; all done with plotting run of ones
TST.W D2
BMI CB8to8NextLine
JMP (A0)
; handle the heterogenous plots between runs
V8to8PlotRHard1
LEA V8to8PRRun2,A0
BRA.S V8to8PlotHardCommon
V8to8PlotRHard2
LEA V8to8LastLoop,A0
V8to8PlotHardCommon
MOVE.L (A2)+,D1 ;get region mask
MOVE.L (A3)+,D0 ;fetch from source
CMP.L D0,A1 ;same as before?
BNE.S @0
MOVE.L D7,D0
BRA.S @1
@0
MOVE.L D0,A1
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 1st byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 2nd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 3rd byte
ROL.L #8,D0
MOVE.B D0,D5
MOVE.B 1(A5,D5.W*2),D0 ;map 4th byte
ROL.L #8,D0
MOVE.L D0,D7
@1
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A4),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A4)+ ;deposit it
SUBQ #1,D2 ;count it
BMI CB8to8NextLine
JMP (A0)
;******************************************************************************************
; Handler for the 8 to 1 copyBits case (mapped ). The basic strategy is the usual
; region counting, with the added twist of a single element cache for the longword mapping,
; using A1 to hold the pre-map and D7 to hold the post-mapped values.
CB8to11st0
ADD.W #32,A3 ;bump source ptr
ADDQ #4,A4 ;bump dest ptr
BRA.S CB8to1Middle
ChkDst1Bit
CMP.W #1,DSTPIX+PIXELSIZE(A6) ;destination 8 bits/pixel?
BNE UseOld373 ;if not, can't handle
SUBQ #8,D0 ;source 8 bits/pixel?
BNE UseOld373 ;if not, can't handle
CB8to1Clip
TST.L MASKBITS(A6) ;should we handle it?
BNE UseOld373 ;if not, skip
MOVE.L SRCROW(A6),D0
SUB.L D0,SRCADDR(A6) ;back up one line
SUBQ #1,BUFSIZE(A6) ;one less than they say
MOVEQ #-1,D6 ;D6 has -1 for region compare
MOVEQ #0,D4
MOVEQ #0,D3 ;init region counting regs
SUB.L A1,A1
SUBQ.L #1,A1 ;all ones for initial
MOVEQ #-1,D7 ;map cache values
CB8to1Outer
MOVE.L RGNBUF(A6),A2
MOVE.L SRCADDR(A6),A3 ;get source pointer
MOVE.L DSTADDR(A6),A4 ;get destptr
MOVE.L SCALETBL(A6),A5 ;get mapping table
; offset source pointer according to bit offsets
MOVE.L DSTALIGN(A6),D0 ;get shift count
MOVE.L SRCALIGN(A6),D1
ASR.L #3,D1
ADD.L D1,D0
ADD.L D0,A3 ;offset source ptr
; OK, first do the left edge
MOVE.W BUFSIZE(A6),D2 ;get the count
MOVEQ #0,D5
MOVE.L (A2)+,D1 ;get region mask
BEQ.S CB8to11st0 ;if zero, handle it
; fetch the 1st source longword and map it through the table pointed to by A5
BSR Map8to1
; plot it using the region mask
AND.L D1,D0
NOT.L D1 ;flip mask
AND.L (A4),D1
OR.L D1,D0 ;combine source and dest
MOVE.L D0,(A4)+ ;stuff it
SUBQ #1,D2
BMI.S CB8to1NextLine
; if the region runs in D4 are still valid, we can use special code to really plot super
; fast.
CB8to1Middle
TST.W D4 ;is it valid?
BNE V8to1PlotRgnRuns ;if so, go super fast
MOVEQ #-1,D4 ;validate it for next time
MOVEQ #0,D3 ;zero the run count
; see what the next region longword is. Go to three different loops depending on whether
; the region is all ones, zeros or both
MOVE.L (A2)+,D1 ;fetch next word of region mask
BEQ.S V8to1FirstZero0 ;if zero, go handle
CMP.L D6,D1 ;all one's?
BNE V8to1StartSecondRun ;if not, skip
BRA.S V8to1FirstOnes1
; here's the loop that counts and plots the first run of all ones
V8to1FirstOnes
MOVE.L (A2)+,D1
CMP.L D6,D1 ;is it still all ones?
BNE.S V8to1StartSecondRun ;if not, end the run
V8to1FirstOnes1
ADDQ.W #1,D3 ;bump the run count
BSR Map8to1
MOVE.L D0,(A4)+ ;store at destination
DBRA D2,V8to1FirstOnes ;loop until we're done
; OK, all done with this line, so bump the pointers and loop until done
CB8to1NextLine
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6) ;bump to next line of destination
MOVE.L SRCROW(A6),D0
ADD.L D0,SRCADDR(A6) ;bump to next line of source
; bump line count and see if we're done
MOVE.W VERT(A6),D0
ADDQ #1,D0
MOVE.W D0,VERT(A6)
CMP.W MINRECT+BOTTOM(A6),D0 ;all done?
BEQ Done1To8Clip ;if so, use common exit
; create the region mask for the new scan line, and maintain the all ones flag
CMP.W STATEB+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB8to1NewRgn ;if so, go do it
CMP.W STATEB+THISV(A6),D0 ;need to rebuild?
BLT.S CB8to1NewRgn ;if so, go do it
CMP.W STATEC+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB8to1NewRgn ;if so, go do it
CMP.W STATEC+THISV(A6),D0 ;need to rebuild?
BLT.S CB8to1NewRgn ;if so, go do it
CMP.W STATEA+NEXTV(A6),D0 ;rebuild the region?
BGE.S CB8to1NewRgn ;if so, go do it
CMP.W STATEA+THISV(A6),D0 ;need to rebuild?
BGE CB8to1Outer ;if so, go do it
CB8to1NewRgn
MOVEQ #0,D4 ;invalidate region all ones flag
MOVE.L A1,-(SP)
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;make new region mask
MOVE.L (SP)+,A1
; go handle the next line
BRA CB8to1Outer ;go process next line
Fin8to1Zeros
ADDQ #4,A4
BRA.S CB8to1NextLine
; here's the loop that counts and plots the first run of all zeros
V8to1FirstZero
MOVE.L (A2)+,D1
BNE.S V8to1StartSecondRun
V8to1FirstZero0
SUBQ.W #1,D3 ;decrement run count for zeros
ADD.W #32,A3
ADDQ #4,A4
DBRA D2,V8to1FirstZero
BRA.S CB8to1NextLine
; the region mask is heterogenous, so plot the word and start the second run.
V8to1StartSecondRun
SWAP D3
BSR Map8to1
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A4),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A4)+ ;deposit it
SUBQ #1,D2
BMI.S Done8to1SecondRun
; sample the region and case out for the 2nd time
MOVE.L (A2)+,D1 ;fetch next word of region mask
BEQ.S V8to1Zero0 ;if zero, go handle
CMP.L D6,D1 ;all one's?
BNE.S V8to1StartLastRun ;if not, skip
BRA.S V8to1Ones1
; here's the loop that counts and plots the second run of all ones
V8to1Ones
MOVE.L (A2)+,D1
CMP.L D6,D1 ;is it still all ones?
BNE.S V8to1StartLastRun ;if not, end the run
V8to1Ones1
ADDQ.W #1,D3 ;bump the run count
BSR Map8to1 ;fetch and map it
MOVE.L D0,(A4)+ ;store at destination
DBRA D2,V8to1Ones ;loop until we're done
Done8to1SecondRun
SWAP D3
BRA CB8to1NextLine ;all done
; here's the loop that counts the 2nd run of zeros
V8to1Zero
MOVE.L (A2)+,D1
BNE.S V8to1StartLastRun
V8to1Zero0
SUBQ.W #1,D3
ADD.W #32,A3
ADDQ #4,A4 ;bump dest reg
DBRA D2,V8to1Zero ;loop until it changes
BRA.S Done8to1SecondRun
; OK, we've accumulated two runs, so finish up the line without counting
V8to1StartLastRun
SWAP D3
TST.L D1
BEQ.S V8to1LastZero
BRA.S V8to1LastLoopA
V8to1LastLoop
MOVE.L (A2)+,D1 ;get region
BEQ.S V8to1LastZero
V8to1LastLoopA
CMP.L D6,D1
BNE.S V8to1LastHard
BSR Map8to1
MOVE.L D0,(A4)+ ;store at destination
DBRA D2,V8to1LastLoop
BRA CB8to1NextLine
V8to1LastZero
ADDQ #4,A4
ADD.W #32,A3
DBRA D2,V8to1LastLoop
BRA CB8to1NextLine
V8to1LastHard
BSR Map8to1
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A4),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A4)+ ;deposit it
DBRA D2,V8to1LastLoop
BRA CB8to1NextLine
; Here's where we have the ultra fast plotting by interpreting the 2 region runs in D3.
V8to1PlotRgnRuns
TST.W D3 ;which type of run?
BPL.S V8to1BlastPat1 ;if ones, go blast it
BEQ.S V8to1PlotRHard1 ;if zero, plot one slowly, then plot 2nd run
; it's negative, so just skip over 4 times the count
MOVE.W D3,D0
NEG.W D0 ;turn into longword count
LSL.W #2,D0 ;times 4
ADD.W D0,A2 ;skip over region
ADD.W D0,A4 ;skip over destination
LSL #3,D0 ;times 8 for source
ADD.W D0,A3 ;skip over source
ADD.W D3,D2 ;decrement count
BMI CB8to1NextLine ;if done, skip
; now handle the second run
V8to1PRRun2
LEA @0,A0 ;plot the break longword
BRA.S V8to1PlotHardCommon
@0
MOVE.L D3,D0 ;which type of run?
BPL.S V8to1BlastPat2 ;if ones, go blast it
BEQ.S V8to1PlotRHard2
; it's negative, so we can skip over like above
SWAP D0
NEG.W D0 ;turn into longword count
SUB.W D0,D2 ;decrement count
LSL.W #2,D0 ;times 4
ADD.W D0,A2 ;skip over region
ADD.W D0,A4 ;skip over destination
LSL #3,D0 ;times 8 for source
ADD.W D0,A3 ;skip over source
TST.W D2
BMI CB8to1NextLine ;if done, skip
; we've interpreted both runs, so finish up using common code
BRA.S V8to1LastLoop
; Handle blasting out the first run
V8to1BlastPat1
MOVE.W D3,D0 ;get the size
MOVE.W D0,D1
LSL #2,D1 ;times 4
ADD.W D1,A2 ;bump region ptr
SUB.W D0,D2
MOVE.W D0,D1
LEA V8to1PRRun2,A0
BRA.S V8to1BlastPatBot
; Blast out the second run
V8to1BlastPat2
SWAP D0 ;use high word for 2nd run
MOVE.W D0,D1
LSL #2,D1 ;times 4
ADD.W D1,A2 ;bump region ptr
SUB.W D0,D2
MOVE.W D0,D1
LEA V8to1LastLoop,A0
BRA.S V8to1BlastPatBot
V8to1BlastPat
BSR.S Map8to1
MOVE.L D0,(A4)+ ;store at destination
V8to1BlastPatBot
DBRA D1,V8to1BlastPat
; all done with plotting run of ones
TST.W D2
BMI CB8to1NextLine
JMP (A0)
; handle the heterogenous plots between runs
V8to1PlotRHard1
LEA V8to1PRRun2,A0
BRA.S V8to1PlotHardCommon
V8to1PlotRHard2
LEA V8to1LastLoop,A0
V8to1PlotHardCommon
MOVE.L (A2)+,D1 ;get region mask
BSR.S Map8to1
AND.L D1,D0 ;mask it
NOT.L D1 ;flip mask
AND.L (A4),D1 ;combine with source
OR.L D1,D0 ;form dest longword
MOVE.L D0,(A4)+ ;deposit it
SUBQ #1,D2 ;count it
BMI CB8to1NextLine
JMP (A0)
; Map8to1 is the routine that takes 8 longwords from the source (pointed to by A3)
; and returns the single longword result in D0.
Map8to1
MOVEQ #0,D0 ;start dest at 0
TST.W (A5) ;check mapping for color 0 <d√b> 12Jul88
BEQ.s @a ;if white->white, ok <d√b> 12Jul88
MOVEQ #$F,D0 ;else, its black <d√b> 12Jul88
@a ; <d√b> 12Jul88
MOVEQ #7,D7 ;8 longs to process
SUB.L A1,A1 ;set last source to 0
Map8to1Loop
MOVE.L (A3)+,D6 ;fetch from source
CMP.L A1,D6 ;same as last time?
BEQ.S Map8to1Fast ;if so, we've got the
MOVE.L D6,A1 ;remember for next time
ROL.L #8,D6 ;get next pixel
MOVE.B D6,D5 ;get current pixel
MOVE.B 1(A5,D5.W*2),D5 ;get mapped bit
LSR.W #1,D5 ;get bit into carry
ROXL.L #1,D0 ;shift it in
ROL.L #8,D6 ;get next pixel
MOVE.B D6,D5 ;get current pixel
MOVE.B 1(A5,D5.W*2),D5 ;get mapped bit
LSR.W #1,D5 ;get bit into carry
ROXL.L #1,D0 ;shift it in
ROL.L #8,D6 ;get next pixel
MOVE.B D6,D5 ;get current pixel
MOVE.B 1(A5,D5.W*2),D5 ;get mapped bit
LSR.W #1,D5 ;get bit into carry
ROXL.L #1,D0 ;shift it in
ROL.L #8,D6 ;get next pixel
MOVE.B D6,D5 ;get current pixel
MOVE.B 1(A5,D5.W*2),D5 ;get mapped bit
LSR.W #1,D5 ;get bit into carry
ROXL.L #1,D0 ;shift it in
DBRA D7,Map8to1Loop
MOVEQ #-1,D6 ;restore comparison mask
RTS
; handle the case where it was the same as the last one, so we can repeat the
; high 4 bits
Map8to1Fast
MOVE.B D0,D5
AND.W #15,D5
LSL.L #4,D0
OR.B D5,D0
DBRA D7,Map8to1Loop
MOVEQ #-1,D6
RTS
;******************************************************************************************
; Scan line handler for clipped pattern fill copy mode (called by oval, rrect) -- trap $380
UseOld380
TST.W D2
LEARom Old380,A0
JMP (A0)
FillClipScanLine
FCSL1 ; << PB452 BAL>>
FCSL2
AND.L (A2)+,D3 ;use left mask to start with
SUBQ #1,D2
BMI.S DoFCLast0
; special case the left edge
MOVE.L D6,D0 ;get pattern
AND.L D3,D0 ;mask it
NOT.L D3 ;flip mask
AND.L (A1),D3 ;combine with source
OR.L D3,D0 ;form dest longword
MOVE.L D0,(A1)+ ;deposit it
MOVE.L (A2)+,D3
SUBQ #1,D2
BMI.S DoFCLast0
; see if we're in the unclipped case; if so, use a faster loop
MOVE.L SEEKMASK(A6),A0 ;get seekRgn address
CMP.W #$4E75,(A0) ;is it a RTS?
BEQ.S DoFCUnclipped ;if so, handle specially
BRA.S FCNotOn1
; here's the loop -- use standard technique of special casing region masks
FCLineLoop
MOVE.L (A2)+,D3 ;fetch region mask
BEQ.S FCOff ;if all zero, can optimize
FCNotOff1
CMP.L MINUSONE,D3 ;all ones? << PB452 BAL>>
BEQ.S FCOn ;if so, optimize
FCNotOn1
MOVE.L D6,D0 ;get pattern
AND.L D3,D0 ;mask it
NOT.L D3 ;flip mask
AND.L (A1),D3 ;combine with source
OR.L D3,D0 ;form dest longword
MOVE.L D0,(A1)+ ;deposit it
DBRA D2,FCLineLoop
; handle the last one, using the mask in D1
DoFCLast
MOVE.L (A2)+,D3
DoFCLast0
AND.L D1,D3 ;use right mask
MOVE.L D6,D0 ;get pattern
AND.L D3,D0 ;mask it
NOT.L D3 ;flip mask
AND.L (A1),D3 ;combine with source
OR.L D3,D0 ;form dest longword
MOVE.L D0,(A1)+ ;deposit it
RTS
; handle the case of an all zero region mask
FCOff
ADDQ #4,A1 ;skip over it
SUBQ #1,D2
BMI.S DoFCLast
FCOffLoop
MOVE.L (A2)+,D3
BNE.S FCNotOff1
ADDQ #4,A1 ;skip it
DBRA D2,FCOffLoop
BRA.S DoFCLast
; handle the case of an all one's region mask
FCOn
MOVE.L D6,(A1)+
SUBQ #1,D2
BMI.S DoFCLast
FCOnLoop
MOVE.L (A2)+,D3
CMP.L MINUSONE,D3 ; << PB452 BAL>>
BNE.S FCNotOn1
MOVE.L D6,(A1)+
DBRA D2,FCOnLoop
BRA.S DoFCLast
; handle the unclipped case with faster unwound code
DoFCUnclipped
LEA 0(A2,D2.W*4),A2 ;bump region ptr
ADDQ #1,D2 ;compute count to do
CMP.W #8,D2
BLT.S FinishFCUnClip
MOVE.W D2,D0
LSR #3,D0 ;divide by 8
SUBQ #1,D0 ;bias for DBRA
FCUnClipLoop
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
DBRA D0,FCUnClipLoop
; now finish up the last 7 or less
FinishFCUnClip
AND #7,D2
EOR #7,D2
JMP FinishFCUCTab(D2.W*2)
FinishFCUCTab
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
MOVE.L D6,(A1)+
BRA.S DoFCLast
;******************************************************************************************
; Scan line handler for clipped pattern fill OR mode (called by oval, rrect) -- trap $381
; similar to above, but in OR mode. We can only handle if the foreground pattern
; is all ones; if so, use the copy mode routine to fill.
UseOld381
TST.W D2
LEARom Old381,A0
JMP (A0)
FillClipOrLine
CMP.L #-1,D6 ;all foreground?
BNE.S UseOld381 ;if not, we can't handle
MOVE.L D4,D6 ;set up fill pattern
BRA FCSL1 ;use common code
;******************************************************************************************
; Scan line handler for clipped pattern fill copy mode (called by oval, rrect)
; for complex patterns-- trap $384
UseOld384
TST.W D2
LEARom Old384,A0
JMP (A0)
FillClipXLine
CMP.W #4,PATHMASK(A6) ;pattern too complex?
BGT.S UseOld384 ;if so, don't handle
MOVE.L D7,-(SP) ;save work register
; keep the pattern in D6 and D7
ADD.W PATHPOS(A6),D0
AND #4,D0
MOVE.L EXPAT(A6),A0
ADD.W PATVPOS(A6),A0
MOVE.L 0(A0,D0),D6 ;get left pattern
EOR.W #4,D0
MOVE.L 0(A0,D0),D7 ;get right pattern
; fetch the leftmost region mask
MOVEQ #-1,D4 ;all ones for comparing
AND.L (A2)+,D3 ;use left mask to start with
SUBQ #1,D2
BMI.S DoFCXLast0
; special case the left edge
MOVE.L D6,D0 ;get pattern
AND.L D3,D0 ;mask it
NOT.L D3 ;flip mask
AND.L (A1),D3 ;combine with source
OR.L D3,D0 ;form dest longword
MOVE.L D0,(A1)+ ;deposit it
EXG.L D6,D7
MOVE.L (A2)+,D3
SUBQ #1,D2
BMI.S DoFCXLast0
; see if we're in the unclipped case; if so, use a faster loop
MOVE.L SEEKMASK(A6),A0 ;get seekRgn address
CMP.W #$4E75,(A0) ;is it a RTS?
BEQ.S DoFCXUnclipped ;if so, handle specially
BRA.S FCXNotOn1
; here's the loop -- use standard technique of special casing region masks
FCXLineLoop
MOVE.L (A2)+,D3 ;fetch region mask
BEQ.S FCXOff ;if all zero, can optimize
FCXNotOff1
CMP.L D4,D3 ;all ones?
BEQ.S FCXOn ;if so, optimize
FCXNotOn1
MOVE.L D6,D0 ;get pattern
AND.L D3,D0 ;mask it
NOT.L D3 ;flip mask
AND.L (A1),D3 ;combine with source
OR.L D3,D0 ;form dest longword
MOVE.L D0,(A1)+ ;deposit it
EXG.L D6,D7
DBRA D2,FCXLineLoop
; handle the last one, using the mask in D1
DoFCXLast
MOVE.L (A2)+,D3
DoFCXLast0
AND.L D1,D3 ;use right mask
MOVE.L D6,D0 ;get pattern
AND.L D3,D0 ;mask it
NOT.L D3 ;flip mask
AND.L (A1),D3 ;combine with source
OR.L D3,D0 ;form dest longword
MOVE.L D0,(A1)+ ;deposit it
MOVE.L (SP)+,D7 ;restore work reg
RTS
; handle the case of an all zero region mask
FCXOff
ADDQ #4,A1 ;skip over it
SUBQ #1,D2
BMI.S DoFCXLast
FCXOffLoop
MOVE.L (A2)+,D3
BNE.S FCXNotOff1
ADDQ #4,A1 ;skip it
DBRA D2,FCXOffLoop
BRA.S DoFCXLast
; handle the case of an all one's region mask
FCXOn
MOVE.L D6,(A1)+
EXG.L D6,D7
SUBQ #1,D2
BMI.S DoFCXLast
FCXOnLoop
MOVE.L (A2)+,D3
CMP.L D4,D3
BNE.S FCXNotOn1
MOVE.L D6,(A1)+
EXG.L D6,D7
DBRA D2,FCXOnLoop
BRA.S DoFCXLast
; handle the unclipped case with faster unwound code
DoFCXUnclipped
LEA 0(A2,D2.W*4),A2 ;bump region ptr
ADDQ #1,D2 ;compute count to do
CMP.W #8,D2
BLT.S FinishFCXUnClip
MOVE.W D2,D0
LSR #3,D0 ;divide by 8
SUBQ #1,D0 ;bias for DBRA
FCXUnClipLoop
MOVE.L D6,(A1)+
MOVE.L D7,(A1)+
MOVE.L D6,(A1)+
MOVE.L D7,(A1)+
MOVE.L D6,(A1)+
MOVE.L D7,(A1)+
MOVE.L D6,(A1)+
MOVE.L D7,(A1)+
DBRA D0,FCXUnClipLoop
; now finish up the last 7 or less
FinishFCXUnClip
AND #7,D2
EOR #7,D2
BTST #0,D2
BEQ.S @0
EXG.L D6,D7
@0
JMP FinishFCXUCTab(D2.W*2)
FinishFCXUCTab
MOVE.L D6,(A1)+
MOVE.L D7,(A1)+
MOVE.L D6,(A1)+
MOVE.L D7,(A1)+
MOVE.L D6,(A1)+
MOVE.L D7,(A1)+
MOVE.L D6,(A1)+
EXG.L D6,D7
BRA DoFCXLast
;******************************************************************************************
; Arithmetic transfer modes start here...
;******************************************************************************************
; Here's where we implement the arithmetic transfer mode fills for ovals/rrects
; Use a common loop for all the transfer modes, with specialized handlers to do the
; pixel arithmetic.
; the first receiver is for AddOver mode for ovals and roundRects
AddOverFillO
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BEQ.S @0 ;if not, skip
JMPRom Old38A ; continue in ROM <S433>
; OK, first do the pattern setup
@0
MOVE.L A0,A3 ;set up pattern base
LEA AddOverHandler,A0 ;use addOver
DoArithMode
MOVEM.L D7/A4-A5,-(SP) ;save work regs
BSR.S ArithModeHandler ;invoke the handler
MOVEM.L (SP)+,D7/A4-A5 ;restore regs
RTS
; here is the general handler for a scan line of arithmetic fills
ArithModeHandler
MOVEQ #0,D6 ;init pattern index
MOVE.W PATROW(A6),D4 ;get pattern size in bytes
SUBQ #4,D4 ;is it a simple one?
BLE ArithSimplePat ;if so, handle faster
; sometimes simple patterns come in as 8 byte ones, so check for that
MOVE.W D0,D6
ADD.W PATHPOS(A6),D6
SUBQ #4,D4 ;is it 8 long?
BNE.S ArithComplexPat ;if not, skip
; fetch both halves of the pattern and see if they match
MOVE.W PATHMASK(A6),D4 ;get pattern mask
ASR #3,D4 ;turn bit index to byte index
AND.W D4,D6 ;mask it
MOVE.L EXPAT(A6),A4
ADD.W PATVPOS(A6),A4 ;compute pattern address
MOVE.L 0(A4,D6),D4 ;get source longword
EOR #4,D6
CMP.L 0(A4,D6),D4 ;is it really simple?
BEQ ArithSimplePat ;if so, go handle
EOR #4,D6 ;restore D6
; set up the pattern variables, since it's a complex pattern
ArithComplexPat
MOVE.L EXPAT(A6),A3
ADD.W PATVPOS(A6),A3 ;compute pattern address
ArithComplex1
MOVE.L D1,-(SP) ;remember right edge mask
MOVEQ #0,D1
MOVEQ #0,D7 ;clear for pixCache
; set up A0 to point to the proper handler, depending on the width of the inverse table
MOVE.L A0,A4 ;remember handler base
MOVE.W INVSIZE(A6),D4 ;get shift count (3,4,5)
SUBQ #3,D4
ADD.W 0(A0,D4.W*2),A0 ;point to proper handler
; init the single pixel cache, where D1 is last source, D7 is last dest, and D0 is last result
MOVEQ #0,D5
MOVE.L COLORTABLE(A6),A5 ;get color table ptr
MOVE.B D1,D5
LEA 0(A5,D5.W*8),A4 ;point to source color
MOVE.B D7,D5
LEA 0(A5,D5.W*8),A5 ;point to dest color
JSR (A0) ;map it
MOVE.B ([INVCOLOR,A6],D0.W,6),D0 ;look up in inverse table
; test for the single long case
TST.W D2
BRA ArithBot0
; here's the main loop for complex patterns, where we process a longword at a time
; use a single pixel cache for speed using D0, D1 and D7
ArithRight0
AND.L (SP)+,D3
ArithLoop0
MOVE.W PATHMASK(A6),D4 ;get pattern mask
ASR #3,D4 ;turn bit index to byte index
AND.W D4,D6 ;mask it
MOVE.L 0(A3,D6),D4 ;get source longword
ADDQ #4,D6
MOVE.L A2,D5 ;no clipping?
BEQ.S @0 ;if none, skip
AND.L (A2)+,D3 ;get region/edge mask in D3
BEQ ArithMask0
@0
MOVE.L (A1),D5 ;get dest longword
; map 1st byte
TST.B D3
BEQ.S @8 ;if mask zero, we can skip
; if same as previous, we can short-circuit the mapping
CMP.B D4,D1 ;source the same?
BNE.S @9 ;if not, skip
CMP.B D5,D7 ;dest the same?
BNE.S @9 ;if not, skip
; it's the same, so use it
MOVE.B D0,D5 ;use last result
BRA.S @8 ;skip the mapping
; it's different than the last one, so map it
@9
MOVE.B D4,D1
MOVE.L COLORTABLE(A6),A5
LEA 0(A5,D1.W*8),A4 ;point to source color
MOVE.B D5,D7
LEA 0(A5,D7.W*8),A5 ;point to dest color
JSR (A0) ;map according to Xfer mode
MOVE.B ([INVCOLOR,A6],D0.W,6),D5 ;look up in inverse table
MOVE.B D5,D0
@8
LSR.L #8,D3
LSR.L #8,D4
ROR.L #8,D5
; map 2nd byte
TST.B D3
BEQ.S @2 ;if mask zero, we can skip
; if same as previous, we can short-circuit the mapping
CMP.B D4,D1 ;source the same?
BNE.S @1 ;if not, skip
CMP.B D5,D7 ;dest the same?
BNE.S @1 ;if not, skip
; it's the same, so use it
MOVE.B D0,D5 ;use last result
BRA.S @2 ;skip the mapping
; it's different than the last one, so map it
@1
MOVE.B D4,D1
MOVE.L COLORTABLE(A6),A5
LEA 0(A5,D1.W*8),A4 ;point to source color
MOVE.B D5,D7
LEA 0(A5,D7.W*8),A5 ;point to dest color
JSR (A0) ;map according to Xfer mode
MOVE.B ([INVCOLOR,A6],D0.W,6),D5 ;look up in inverse table
MOVE.B D5,D0
@2
LSR.L #8,D3
LSR.L #8,D4
ROR.L #8,D5
; map 3rd byte
TST.B D3
BEQ.S @4 ;if mask zero, we can skip
; if same as previous, we can short-circuit the mapping
CMP.B D4,D1 ;source the same?
BNE.S @3 ;if not, skip
CMP.B D5,D7 ;dest the same?
BNE.S @3 ;if not, skip
; it's the same, so use it
MOVE.B D0,D5 ;use last result
BRA.S @4 ;skip the mapping
; it's different than the last one, so map it
@3
MOVE.B D4,D1
MOVE.L COLORTABLE(A6),A5
LEA 0(A5,D1.W*8),A4 ;point to source color
MOVE.B D5,D7
LEA 0(A5,D7.W*8),A5 ;point to dest color
JSR (A0) ;map according to Xfer mode
MOVE.B ([INVCOLOR,A6],D0.W,6),D5 ;look up in inverse table
MOVE.B D5,D0
@4
LSR.L #8,D3
LSR.L #8,D4
ROR.L #8,D5
; map final byte
TST.B D3
BEQ.S @6 ;if mask zero, we can skip
; if same as previous, we can short-circuit the mapping
CMP.B D4,D1 ;source the same?
BNE.S @5 ;if not, skip
CMP.B D5,D7 ;dest the same?
BNE.S @5 ;if not, skip
; it's the same, so use it
MOVE.B D0,D5 ;use last result
BRA.S @6 ;skip the mapping
; it's different than the last one, so map it
@5
MOVE.B D4,D1
MOVE.L COLORTABLE(A6),A5
LEA 0(A5,D1.W*8),A4 ;point to source color
MOVE.B D5,D7
LEA 0(A5,D7.W*8),A5 ;point to dest color
JSR (A0) ;map according to Xfer mode
MOVE.B ([INVCOLOR,A6],D0.W,6),D5 ;look up in inverse table
MOVE.B D5,D0
@6
ROR.L #8,D5
; it's all mapped, so store the result
MOVE.L D5,(A1)+ ;store the destination
ArithBotCommon
MOVEQ #-1,D3 ;set up the mask for the middle
SUBQ #1,D2
ArithBot0
BGT ArithLoop0
BEQ ArithRight0
; all done with this scan line
RTS
; handle a region of all zeros
ArithMask0
ADDQ #4,A1 ;skip over destination
BRA.S ArithBotCommon
; the pattern is simpler (it fits in a register), so use a separate loop to make things
;faster. Use a longword cache instead of the single pixel caches.
ArithSimplePat
MOVE.L D1,-(SP) ;save right edge mask
MOVEQ #0,D7 ;clear for pixIndexing
MOVE.L (A3),D4 ;keep pattern in D4
MOVE.L COLORTABLE(A6),A3 ;use A3 for color table ptr
; set up A0 to point to the proper handler, depending on the width of the inverse table
MOVE.L A0,A4 ;remember handler base
MOVE.W INVSIZE(A6),D0 ;get shift count (3,4,5)
SUBQ #3,D0
ADD.W 0(A0,D0.W*2),A0 ;point to proper handler
; init the longword pattern cache by mapping the four pixels in D4
MOVEQ #3,D5
MOVE.L D4,D6 ;init lastDest
BRA.S CacheILoop0 ;skip cache check 1st time
; if the next pixel in D4 is the same as the previous (in D7), take a shortcut
CacheInitLoop
CMP.B D4,D7 ;does it match?
BNE.S CacheILoop0 ;if not, must do the hard way
MOVE.B D0,D1 ;use last result
ROL.L #8,D1
ROL.L #8,D4
DBRA D5,CacheInitLoop
BRA.S CacheIDone
; it's not the same, so do it the hard way
CacheILoop0
MOVE.B D4,D7
LEA 0(A3,D7.W*8),A4 ;point to source color
MOVE.L A4,A5 ;source and dest are same
JSR (A0) ;map next pixel
MOVE.B ([INVCOLOR,A6],D0.W,6),D1 ;look up in inverse table
MOVE.L D1,D0 ;remember last result
ROL.L #8,D1
ROL.L #8,D4
DBRA D5,CacheInitLoop
; OK, here's the start of the main loop; first, see if there's only one long to do
CacheIDone
TST.W D2
BNE.S ArithLoop1
; here's the main loop for simple patterns, where we process a longword at a time
; We use a longword cache in D6
ArithRight1
AND.L (SP)+,D3
ArithLoop1
MOVE.L A2,D5 ;no clipping?
BEQ.S @0 ;if none, skip
AND.L (A2)+,D3 ;get mask in D4
BEQ ArithMask1
@0
MOVE.L (A1),D5 ;get dest longword
CMP.L #-1,D3 ;mask all ones?
BNE.S ArithMapIt1A ;if not, can't use cache
CMP.L D5,D6 ;same as last time?
BNE.S ArithMapIt1 ;if not, skip
; the long was the same as last time, so we can skip the mapping. Better make sure
; the mask was the same, too
MOVE.L D1,D5 ;use last result
BRA ArithStoreIt ;skip the mapping
; it was different, so we have to map it the hard way
ArithMapIt1
MOVE.L D5,D6 ;remember for next time
ArithMapIt1A
TST.B D3
BEQ.S @0 ;if mask zero, we can skip
MOVE.B D4,D7
LEA 0(A3,D7.W*8),A4 ;point to source color
MOVE.B D5,D7
LEA 0(A3,D7.W*8),A5 ;point to dest color
JSR (A0) ;map according to Xfer mode
MOVE.B ([INVCOLOR,A6],D0.W,6),D5 ;look up in inverse table
@0
ROR.L #8,D3
ROR.L #8,D4
ROR.L #8,D5
; map 2nd byte
TST.B D3
BEQ.S @2 ;if mask zero, we can skip
MOVE.B D4,D7
LEA 0(A3,D7.W*8),A4 ;point to source color
MOVE.B D5,D7
LEA 0(A3,D7.W*8),A5 ;point to dest color
JSR (A0) ;map according to Xfer mode
MOVE.B ([INVCOLOR,A6],D0.W,6),D5 ;look up in inverse table
@2
ROR.L #8,D3
ROR.L #8,D4
ROR.L #8,D5
; map 3rd byte
TST.B D3
BEQ.S @4 ;if mask zero, we can skip
; map it
MOVE.B D4,D7
LEA 0(A3,D7.W*8),A4 ;point to source color
MOVE.B D5,D7
LEA 0(A3,D7.W*8),A5 ;point to dest color
JSR (A0) ;map according to Xfer mode
MOVE.B ([INVCOLOR,A6],D0.W,6),D5 ;look up in inverse table
@4
ROR.L #8,D3
ROR.L #8,D4
ROR.L #8,D5
; map final byte
TST.B D3
BEQ.S @6 ;if mask zero, we can skip
; it's different than the last one, so map it
MOVE.B D4,D7
LEA 0(A3,D7.W*8),A4 ;point to source color
MOVE.B D5,D7
LEA 0(A3,D7.W*8),A5 ;point to dest color
JSR (A0) ;map according to Xfer mode
MOVE.B ([INVCOLOR,A6],D0.W,6),D5 ;look up in inverse table
@6
ROR.L #8,D4
ROR.L #8,D5
; it's all mapped, so store the result
ArithStoreIt
MOVE.L D5,(A1)+ ;store the destination
ADDQ.L #1,D3 ;was mask all ones?
BNE.S ArithCom1 ;if not, skip
MOVE.L D5,D1 ;remember last result
ArithCom1
MOVEQ #-1,D3 ;set up the mask for the middle
SUBQ #1,D2
ArithBot1
BGT ArithLoop1
BEQ ArithRight1
; all done with this scan line
RTS
; handle a region of all zeros
ArithMask1
ADDQ #4,A1 ;skip over destination
BRA.S ArithCom1
; Here is the handler for the AddOver mode. A4 points to the source RGBColor, while
; A5 points to the destination. Return the index in D0 (to be looked up in the
; inverse table). First there is a case table for using a static shift count
AddOverHandler
DC.W AddOver3-AddOverHandler
DC.W AddOver4-AddOverHandler
DC.W AddOver5-AddOverHandler
AddOver3
MOVEQ #0,D0
MOVE.W (A4)+,D0 ;red
ADD.W (A5)+,D0
LSL.L #3,D0
MOVE.W (A4)+,D0 ;green
ADD.W (A5)+,D0
LSL.L #3,D0
MOVE.W (A4),D0 ;blue
ADD.W (A5),D0
LSL.L #3,D0
SWAP D0 ;return inverse table index
RTS
AddOver4
MOVEQ #0,D0
MOVE.W (A4)+,D0 ;red
ADD.W (A5)+,D0
LSL.L #4,D0
MOVE.W (A4)+,D0 ;green
ADD.W (A5)+,D0
LSL.L #4,D0
MOVE.W (A4),D0 ;blue
ADD.W (A5),D0
LSL.L #4,D0
SWAP D0 ;return inverse table index
RTS
AddOver5
MOVEQ #0,D0
MOVE.W (A4)+,D0 ;red
ADD.W (A5)+,D0
LSL.L #5,D0
MOVE.W (A4)+,D0 ;green
ADD.W (A5)+,D0
LSL.L #5,D0
MOVE.W (A4),D0 ;blue
ADD.W (A5),D0
LSL.L #5,D0
SWAP D0 ;return inverse table index
RTS
;*************************************************************************************
; Here is the receiver for the SubOver arithmetic fill mode, for ovals and roundRects.
; It uses mainly common code with the other oval handlers
SubOverFillO
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BEQ.S @0 ;if not, skip <S433>
JMPRom Old38E ; <S433>
; OK, first do the pattern setup
@0 MOVE.L A0,A3 ;set up pattern base
LEA SubOverHandler,A0 ;use subOver
BRA DoArithMode
; Here is the handler for the SubOver mode. A4 points to the source RGBColor, while
; A5 points to the destination. Return the index in D0 (to be looked up in the
; inverse table). First there is a case table for using a static shift count
SubOverHandler
DC.W SubOver3-SubOverHandler
DC.W SubOver4-SubOverHandler
DC.W SubOver5-SubOverHandler
SubOver3
MOVEQ #0,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #3,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #3,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #3,D0
SWAP D0 ;return inverse table index
RTS
SubOver4
MOVEQ #0,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #4,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #4,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #4,D0
SWAP D0 ;return inverse table index
RTS
SubOver5
MOVEQ #0,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #5,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #5,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
LSL.L #5,D0
SWAP D0 ;return inverse table index
RTS
;*************************************************************************************
; Here is the receiver for the AddPin arithmetic fill mode, for ovals and roundRects.
; It uses mainly common code with the other oval handlers
AddPinFillO
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BEQ.S @0 ;if not, skip <S433>
JMPRom Old389 ; <S433>
; set up handlers and use common code
@0 MOVE.L A0,A3 ;set up pattern base
LEA AddPinHandler,A0 ;use addPin
BRA DoArithMode
; Here is the handler for the AddPin mode. A4 points to the source RGBColor, while
; A5 points to the destination. Return the index in D0 (to be looked up in the
; inverse table). First there is a case table for using a static shift count
AddPinHandler
DC.W AddPin3-AddPinHandler
DC.W AddPin4-AddPinHandler
DC.W AddPin5-AddPinHandler
AddPin3
MOVEQ #0,D0
MOVE.W (A4)+,D0 ;red
ADD.W (A5)+,D0
BCS.S @0
CMP.W WEIGHT+BLUE(A6),D0
BLS.S @1
@0
MOVE.W WEIGHT+BLUE(A6),D0
@1
LSL.L #3,D0
MOVE.W (A4)+,D0 ;green
ADD.W (A5)+,D0
BCS.S @2
CMP.W WEIGHT+GREEN(A6),D0
BLS.S @3
@2
MOVE.W WEIGHT+GREEN(A6),D0
@3
LSL.L #3,D0
MOVE.W (A4),D0 ;blue
ADD.W (A5),D0
BCS.S @4
CMP.W WEIGHT+RED(A6),D0
BLS.S @5
@4
MOVE.W WEIGHT+RED(A6),D0
@5
LSL.L #3,D0
SWAP D0 ;return inverse table index
RTS
AddPin4
MOVEQ #0,D0
MOVE.W (A4)+,D0 ;red
ADD.W (A5)+,D0
BCS.S @0
CMP.W WEIGHT+BLUE(A6),D0
BLS.S @1
@0
MOVE.W WEIGHT+BLUE(A6),D0
@1
LSL.L #4,D0
MOVE.W (A4)+,D0 ;green
ADD.W (A5)+,D0
BCS.S @2
CMP.W WEIGHT+GREEN(A6),D0
BLS.S @3
@2
MOVE.W WEIGHT+GREEN(A6),D0
@3
LSL.L #4,D0
MOVE.W (A4),D0 ;blue
ADD.W (A5),D0
BCS.S @4
CMP.W WEIGHT+RED(A6),D0
BLS.S @5
@4
MOVE.W WEIGHT+RED(A6),D0
@5
LSL.L #4,D0
SWAP D0 ;return inverse table index
RTS
AddPin5
MOVEQ #0,D0
MOVE.W (A4)+,D0 ;red
ADD.W (A5)+,D0
BCS.S @0
CMP.W WEIGHT+BLUE(A6),D0
BLS.S @1
@0
MOVE.W WEIGHT+BLUE(A6),D0
@1
LSL.L #5,D0
MOVE.W (A4)+,D0 ;green
ADD.W (A5)+,D0
BCS.S @2
CMP.W WEIGHT+GREEN(A6),D0
BLS.S @3
@2
MOVE.W WEIGHT+GREEN(A6),D0
@3
LSL.L #5,D0
MOVE.W (A4),D0 ;blue
ADD.W (A5),D0
BCS.S @4
CMP.W WEIGHT+RED(A6),D0
BLS.S @5
@4
MOVE.W WEIGHT+RED(A6),D0
@5
LSL.L #5,D0
SWAP D0 ;return inverse table index
RTS
;*************************************************************************************
; Here is the receiver for the SubPin arithmetic fill mode, for ovals and roundRects.
; It uses mainly common code with the other oval handlers
SubPinFillO
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BEQ.S @0 ;if not, skip <S433>
JMPRom Old38B ; <S433>
; set up handlers and use common code
@0 MOVE.L A0,A3 ;set up pattern base
LEA SubPinHandler,A0 ;use SubPin
BRA DoArithMode
; Here is the handler for the SubPin mode. A4 points to the source RGBColor, while
; A5 points to the destination. Return the index in D0 (to be looked up in the
; inverse table). First there is a case table for using a static shift count
SubPinHandler
DC.W SubPin3-SubPinHandler
DC.W SubPin4-SubPinHandler
DC.W SubPin5-SubPinHandler
SubPin3
MOVEQ #0,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @0
CMP.W WEIGHT+BLUE(A6),D0
BCC.S @1
@0
MOVE.W WEIGHT+BLUE(A6),D0
@1
LSL.L #3,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @2
CMP.W WEIGHT+GREEN(A6),D0
BCC.S @3
@2
MOVE.W WEIGHT+GREEN(A6),D0
@3
LSL.L #3,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @4
CMP.W WEIGHT+RED(A6),D0
BCC.S @5
@4
MOVE.W WEIGHT+RED(A6),D0
@5
LSL.L #3,D0
SWAP D0 ;return inverse table index
RTS
SubPin4
MOVEQ #0,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @0
CMP.W WEIGHT+BLUE(A6),D0
BCC.S @1
@0
MOVE.W WEIGHT+BLUE(A6),D0
@1
LSL.L #4,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @2
CMP.W WEIGHT+GREEN(A6),D0
BCC.S @3
@2
MOVE.W WEIGHT+GREEN(A6),D0
@3
LSL.L #4,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @4
CMP.W WEIGHT+RED(A6),D0
BCC.S @5
@4
MOVE.W WEIGHT+RED(A6),D0
@5
LSL.L #4,D0
SWAP D0 ;return inverse table index
RTS
SubPin5
MOVEQ #0,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @0
CMP.W WEIGHT+BLUE(A6),D0
BCC.S @1
@0
MOVE.W WEIGHT+BLUE(A6),D0
@1
LSL.L #5,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @2
CMP.W WEIGHT+GREEN(A6),D0
BCC.S @3
@2
MOVE.W WEIGHT+GREEN(A6),D0
@3
LSL.L #5,D0
MOVE.W (A5)+,D0 ;red
SUB.W (A4)+,D0
BCS.S @4
CMP.W WEIGHT+RED(A6),D0
BCC.S @5
@4
MOVE.W WEIGHT+RED(A6),D0
@5
LSL.L #5,D0
SWAP D0 ;return inverse table index
RTS
;*************************************************************************************
; Here is the receiver for the AddMax arithmetic fill mode, for ovals and roundRects.
; It uses mainly common code with the other oval handlers
AddMaxFillO
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BEQ.S @0 ;if not, skip <S433>
JMPRom Old38D ; <S433>
; OK, first do the pattern setup
@0 MOVE.L A0,A3 ;set up pattern base
LEA AddMaxHandler,A0 ;use AddMax
BRA DoArithMode
; Here is the handler for the AddMax mode. A4 points to the source RGBColor, while
; A5 points to the destination. Return the index in D0 (to be looked up in the
; inverse table). First there is a case table for using a static shift count
AddMaxHandler
DC.W AddMax3-AddMaxHandler
DC.W AddMax4-AddMaxHandler
DC.W AddMax5-AddMaxHandler
AddMax3
MOVEQ #0,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @0
MOVE.W (A5),D0
@0
ADDQ #2,A5
LSL.L #3,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @1
MOVE.W (A5),D0
@1
ADDQ #2,A5
LSL.L #3,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @2
MOVE.W (A5),D0
@2
ADDQ #2,A5
LSL.L #3,D0
SWAP D0 ;return inverse table index
RTS
AddMax4
MOVEQ #0,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @0
MOVE.W (A5),D0
@0
ADDQ #2,A5
LSL.L #4,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @1
MOVE.W (A5),D0
@1
ADDQ #2,A5
LSL.L #4,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @2
MOVE.W (A5),D0
@2
ADDQ #2,A5
LSL.L #4,D0
SWAP D0 ;return inverse table index
RTS
AddMax5
MOVEQ #0,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @0
MOVE.W (A5),D0
@0
ADDQ #2,A5
LSL.L #5,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @1
MOVE.W (A5),D0
@1
ADDQ #2,A5
LSL.L #5,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BCC.S @2
MOVE.W (A5),D0
@2
ADDQ #2,A5
LSL.L #5,D0
SWAP D0 ;return inverse table index
RTS
;*************************************************************************************
; Here is the receiver for the AddMin arithmetic fill mode, for ovals and roundRects.
; It uses mainly common code with the other oval handlers
AddMinFillO
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BEQ.S @0 ;if not, skip <S433>
JMPRom Old38F ; <S433>
; OK, first do the pattern setup
@0 MOVE.L A0,A3 ;set up pattern base
LEA AddMinHandler,A0 ;use addMin
BRA DoArithMode
; Here is the handler for the AddMin mode. A4 points to the source RGBColor, while
; A5 points to the destination. Return the index in D0 (to be looked up in the
; inverse table). First there is a case table for using a static shift count
AddMinHandler
DC.W AddMin3-AddMinHandler
DC.W AddMin4-AddMinHandler
DC.W AddMin5-AddMinHandler
AddMin3
MOVEQ #0,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @0
MOVE.W (A5),D0
@0
ADDQ #2,A5
LSL.L #3,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @1
MOVE.W (A5),D0
@1
ADDQ #2,A5
LSL.L #3,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @2
MOVE.W (A5),D0
@2
ADDQ #2,A5
LSL.L #3,D0
SWAP D0 ;return inverse table index
RTS
AddMin4
MOVEQ #0,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @0
MOVE.W (A5),D0
@0
ADDQ #2,A5
LSL.L #4,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @1
MOVE.W (A5),D0
@1
ADDQ #2,A5
LSL.L #4,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @2
MOVE.W (A5),D0
@2
ADDQ #2,A5
LSL.L #4,D0
SWAP D0 ;return inverse table index
RTS
AddMin5
MOVEQ #0,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @0
MOVE.W (A5),D0
@0
ADDQ #2,A5
LSL.L #5,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @1
MOVE.W (A5),D0
@1
ADDQ #2,A5
LSL.L #5,D0
MOVE.W (A4)+,D0
CMP.W (A5),D0
BLS.S @2
MOVE.W (A5),D0
@2
ADDQ #2,A5
LSL.L #5,D0
SWAP D0 ;return inverse table index
RTS
;*************************************************************************************
; Here is the receiver for the blend arithmetic fill mode, for ovals and roundRects.
; It uses mainly common code with the other oval handlers
BlendFillO
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BEQ.S @0 ;if not, skip <S433>
JMPRom Old388 ; <S433>
; OK, first do the pattern setup
@0 MOVE.L A0,A3 ;set up pattern base
LEA BlendHandler,A0 ;use blend
BRA DoArithMode
; Here is the handler for the Blend mode. A4 points to the source RGBColor, while
; A5 points to the destination. Return the index in D0 (to be looked up in the
; inverse table). First there is a case table for using a static shift count
BlendHandler
DC.W Blend3-BlendHandler
DC.W Blend4-BlendHandler
DC.W Blend5-BlendHandler
Blend3
MOVEM.L D1-D3,-(SP)
MOVEQ #3,D2 ;set up shift count
BRA.S BlendCommon
Blend4
MOVEM.L D1-D3,-(SP)
MOVEQ #4,D2
BlendCommon
MOVEQ #0,D0 ;clear accum reg
; do red
MOVE.W (A4)+,D1
MULU WEIGHT+BLUE(A6),D1
MOVE.W (A5)+,D3
MULU NOTWEIGHT+BLUE(A6),D3
ADD.L D1,D3
SWAP D3
MOVE.W D3,D0
ASL.L D2,D0
; do green
MOVE.W (A4)+,D1
MULU WEIGHT+GREEN(A6),D1
MOVE.W (A5)+,D3
MULU NOTWEIGHT+GREEN(A6),D3
ADD.L D1,D3
SWAP D3
MOVE.W D3,D0
ASL.L D2,D0
; do blue
MOVE.W (A4)+,D1
MULU WEIGHT+RED(A6),D1
MOVE.W (A5)+,D3
MULU NOTWEIGHT+RED(A6),D3
ADD.L D1,D3
SWAP D3
MOVE.W D3,D0
ASL.L D2,D0
SWAP D0
MOVEM.L (SP)+,D1-D3
RTS
Blend5
MOVEM.L D1-D3,-(SP)
MOVEQ #5,D2
BRA.S BlendCommon
;******************************************************************************************
; Now we start on the arithmetic fills for clipped rectangles. Use the common
; scan line handler for ovals/rrects to save code.
; First we handle AddOver mode
UseOld368
JMPROM Old368 ; <S433>
AddOverFillR
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld368 ;if not, skip
tst.l d3 ;right to left? <PB427 BAL>
bmi.s UseOld368 ;if so, skip <PB427 BAL>
LEA AddOverHandler,A0 ;set up the handler
ArithFillCommon
MOVE.L A0,-(SP) ;remember handler address
; set up the registers and invoke the common scan-line handler
MOVE.L A4,A2 ;set up region pointer
ASR #3,D6 ;bit index to byte index
MOVE.L A5,A1 ;set up destination
ArithFillLoop
MOVEQ #-1,D1
MOVEQ #-1,D3 ;edge masks all ones (edges in region)
MOVE.W BUFSIZE(A6),D2 ;set up the count
ADDQ #4,D2 ;make one based <PB427 BAL>
LSR.W #2,D2
SUBQ #1,D2 ;make zero based <PB427 BAL>
MOVE.L (SP),A0 ;get handler address
; call the appropriate handle, depending on whether the pattern is simple or complex
CMP.W #8,PATROW(A6) ;is pattern real complex?
BGT.S @0 ;if so, go handle it
TST.B SRCV(A6) ;test pattern mode
BMI.S @0 ;treat bitmap as complex
MOVE.L 0(A3,D6),D0 ;get left pattern
EOR #4,D6
CMP.L 0(A3,D6),D0 ;left same as right?
BEQ.S @1 ;if so, it's simple
EOR #4,D6 ;restore D6
@0
BSR ArithComplex1 ;invoke scan-line handler for complex pats
BRA.S @2
@1
EOR #4,D6
BSR ArithSimplePat
; bump pointers to next time, and loop until done
@2
MOVE.L HEIGHT(A6),D6 ;get pattern index
ASR.L #3,D6 ;bit index to byte index
MOVE.W DSTV(A6),D0
TST.B SRCV(A6) ;test pattern mode
BEQ.S AFPat1 ;if zero, handle
BMI.S AFBitMap1 ;if <0, go handle bitmap
; handle bumping the pattern pointers
MOVE.L SRCADDR(A6),A3 ;set up pattern pointer
SUB.W D0,A3
ADD.W PATROW(A6),D0
AND.W PATVMASK(A6),D0
MOVE.W D0,DSTV(A6)
ADD.W D0,A3
BRA.S AFSetPatPtr
; handle second type of pattern
AFPat1
ADDQ #1,D0
AND #15,D0
LEA ([EXPAT,A6],D0.W*4),A3
MOVE.W D0,HEIGHT(A6)
AFSetPatPtr
MOVE.L A3,SRCADDR(A6)
; bump to the next scan line
ArithFillNextLine
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6)
MOVE.W VERT(A6),D0
ADD.W VBUMP(A6),D0
MOVE.W D0,VERT(A6)
CMP.W LASTV(A6),D0
BNE.S @0
; all done, so strip stack and return
MOVE.L SAVESTK2(A6),A7
RTS
; set up registers and loop for the next line
@0
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;seek new region
MOVE.L SRCADDR(A6),A3 ;set up pattern pointer
MOVE.L DSTADDR(A6),A1 ;set up dest ptr
MOVE.L RGNADDR(A6),A2 ;set up region ptr
BRA ArithFillLoop
; handle bumping the source if it's a bitmap
AFBitMap1
MOVE.L SRCROW(A6),D0
ADD.L D0,SRCADDR(A6)
BRA.S ArithFillNextLine
;******************************************************************************************
; Handle SubOver clipped rectangle fill
UseOld36C
JMPRom Old36C ; <PB433>
SubOverFillR
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld36C ;if not, skip
tst.l d3 ;right to left? <PB427 BAL>
bmi.s UseOld36c ;if so, skip <PB427 BAL>
LEA SubOverHandler,A0 ;set up the handler
BRA ArithFillCommon ;use comon code
;******************************************************************************************
; Handle AddPin clipped rectangle fill
UseOld367
JMPRom Old367 ; <PB433>
AddPinFillR
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld367 ;if not, skip
tst.l d3 ;right to left? <PB427 BAL>
bmi.s UseOld367 ;if so, skip <PB427 BAL>
LEA AddPinHandler,A0 ;set up the handler
BRA ArithFillCommon ;use comon code
;******************************************************************************************
; Handle SubPin clipped rectangle fill
UseOld369
JMPRom Old369 ; <PB433>
SubPinFillR
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld369 ;if not, skip
tst.l d3 ;right to left? <PB427 BAL>
bmi.s UseOld369 ;if so, skip <PB427 BAL>
LEA SubPinHandler,A0 ;set up the handler
BRA ArithFillCommon ;use comon code
;******************************************************************************************
; Handle AddMax clipped rectangle fill
UseOld36B
JMPRom Old36B ; <PB433>
AddMaxFillR
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld36B ;if not, skip
tst.l d3 ;right to left? <PB427 BAL>
bmi.s UseOld36B ;if so, skip <PB427 BAL>
LEA AddMaxHandler,A0 ;set up the handler
BRA ArithFillCommon ;use comon code
;******************************************************************************************
; Handle AddMin clipped rectangle fill
UseOld36D
JMPRom Old36D ; <PB433>
AddMinFillR
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld36D ;if not, skip
tst.l d3 ;right to left? <PB427 BAL>
bmi.s UseOld36D ;if so, skip <PB427 BAL>
LEA AddMinHandler,A0 ;set up the handler
BRA ArithFillCommon ;use comon code
;******************************************************************************************
; Handle Blend clipped rectangle fill
UseOld366
JMPRom Old366 ; <PB433>
BlendFillR
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld366 ;if not, skip
tst.l d3 ;right to left? <PB427 BAL>
bmi.s UseOld366 ;if s0, skip <PB427 BAL>
LEA BlendHandler,A0 ;set up the handler
BRA ArithFillCommon ;use comon code
;******************************************************************************************
; Now we start on the arithmetic fills for unclipped rectangles. Use the common
; scan line handler for ovals/rrects to save code.
; First we handle AddOver mode, unclipped
UseOld352
JMPRom Old352 ; <PB433>
AddOverUnClip
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld352 ;if not, skip
tst.l (sp) ;right to left? <PB427 BAL>
bmi.s UseOld352 ;if so, skip <PB427 BAL>
LEA AddOverHandler,A0 ;set up the handler
ArithUCCommon
MOVE.L A0,-(SP) ;remember handler address
; set up the registers and invoke the common scan-line handler
SUB.L A2,A2 ;no region pointer
ASR #3,D6 ;bit index to byte index
MOVE.L A4,A3 ;set up pattern pointer
MOVE.L A5,A1 ;set up destination
ArithUCLoop
MOVE.L FIRSTMASK(A6),D3 ;set up left edge
MOVE.L LASTMASK(A6),D1 ;set up right edge
; compute the count from the three pieces: left, mid and right
MOVE.W LONGCNT(A6),D2 ;get left count
BPL.S @3 ;if positive, we're cool
MOVEQ #0,D2 ;only one word
BRA.S @4
@3
ADD.W MIDCOUNT(A6),D2 ;add in the middle
ADD.W PIXINLONG(A6),D2 ;add in the right
ADDQ.W #2,D2 ;add for count bias
LSR.W #2,D2 ;bytes -> longs
@4
MOVE.L (SP),A0 ;get handler address
; call the appropriate handle, depending on whether the pattern is simple or complex
CMP.W #8,PATROW(A6) ;is pattern real complex?
BGT.S @0 ;if so, go handle it
TST.B ENDSWITCH(A6) ;test pattern mode
BMI.S @0 ;if bitmap, it's complex
MOVE.L 0(A3,D6),D0 ;get left pattern
EOR #4,D6
CMP.L 0(A3,D6),D0 ;left same as right?
BEQ.S @1 ;if so, it's simple
EOR #4,D6 ;restore D6
@0
MOVE.L A1,-(SP)
BSR ArithComplex1 ;invoke scan-line handler for complex pats
MOVE.L (SP)+,A1
BRA.S @2
@1
EOR #4,D6
MOVEM.L A1/A3,-(SP)
BSR ArithSimplePat
MOVEM.L (SP)+,A1/A3
; bump pointers to next time, and loop until done
@2
TST.B ENDSWITCH(A6) ;test pattern mode
BEQ.S AFUCPat1 ;if zero, handle
BMI.S AFUCBitMap1 ;if <0, go handle bitmap
; handle bumping the pattern pointers
MOVE.W PATPOS(A6),D0
SUB.W D0,A3
ADD.W PATROW(A6),D0
AND.W PATVMASK(A6),D0
MOVE.W D0,PATPOS(A6)
ADD.W D0,A3
BRA.S ArithUCNextLine
; handle second type of pattern
AFUCPat1
MOVE.W PATPOS(A6),D0
ADDQ #1,D0
AND #15,D0
LEA ([EXPAT,A6],D0.W*4),A3
MOVE.W D0,PATPOS(A6)
; bump to the next scan line
ArithUCNextLine
MOVE.L PATOFFSET(A6),D6
ASR.L #3,D6 ;bits to bytes
ArithUCNL2
ADD.W DSTROW+2(A6),A1 ;bump destination
SUBQ.W #1,HEIGHT(A6)
BNE ArithUCLoop
ADDQ #8,SP
RTS
; handle unclipped blits source setup
AFUCBitMap1
ADD.W D6,A3
ADD.W SRCBUMP(A6),A3 ;bump to next line <PB448 DBG>
MOVEQ #0,D6
BRA.S ArithUCNL2
;******************************************************************************************
; Handle SubOver unclipped rectangle fill
UseOld356
JMPRom Old356 ; <PB433>
SubOverUnclip
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld356 ;if not, skip
tst.l (sp) ;right to left? <PB427 BAL>
bmi.s UseOld356 ;if so, skip <PB427 BAL>
LEA SubOverHandler,A0 ;set up the handler
BRA ArithUCCommon ;use comon code
;******************************************************************************************
; Handle AddPin unclipped rectangle fill
UseOld351
JMPRom Old351 ; <PB433>
AddPinUnclip
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld351 ;if not, skip
tst.l (sp) ;right to left? <PB427 BAL>
bmi.s UseOld351 ;if so, skip <PB427 BAL>
LEA AddPinHandler,A0 ;set up the handler
BRA ArithUCCommon ;use comon code
;******************************************************************************************
; Handle SubPin unclipped rectangle fill
UseOld353
JMPRom Old353 ; <PB433>
SubPinUnclip
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld353 ;if not, skip
tst.l (sp) ;right to left? <PB427 BAL>
bmi.s UseOld353 ;if so, skip <PB427 BAL>
LEA SubPinHandler,A0 ;set up the handler
BRA ArithUCCommon ;use comon code
;******************************************************************************************
; Handle AddMax unclipped rectangle fill
UseOld355
JMPRom Old355 ; <PB433>
AddMaxUnclip
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld355 ;if not, skip
tst.l (sp) ;right to left? <PB427 BAL>
bmi.s UseOld355 ;if so, skip <PB427 BAL>
LEA AddMaxHandler,A0 ;set up the handler
BRA ArithUCCommon ;use comon code
;******************************************************************************************
; Handle AddMin unclipped rectangle fill
UseOld357
JMPRom Old357 ; <PB433>
AddMinUnclip
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld357 ;if not, skip
tst.l (sp) ;right to left? <PB427 BAL>
bmi.s UseOld357 ;if so, skip <PB427 BAL>
LEA AddMinHandler,A0 ;set up the handler
BRA ArithUCCommon ;use comon code
;******************************************************************************************
; Handle Blend unclipped rectangle fill
UseOld350
JMPRom Old350 ; <PB433>
BlendUnclip
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld350 ;if not, skip
tst.l (sp) ;right to left? <PB427 BAL>
bmi.s UseOld350 ;if so, skip <PB427 BAL>
LEA BlendHandler,A0 ;set up the handler
BRA ArithUCCommon ;use comon code
;******************************************************************************************
; Here's where we handle transparent mode. The basic strategy is to create a mask from
; the pattern (for one and two long patterns) so we don't have to keep examining it
; pixel by pixel. (If the mask is all ones, fall into the standard fills).
; the first one is for transparent mode for ovals and roundRects
TransFillO
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BEQ.S @0 ;if not, skip
JMPRom Old38C ;
@0 CMP.W #4,PATROW(A6) ;is it a simple pattern?
BGT.S TransComplexPat ;if not, inspect it closer
; it's a simple pattern, so make a mask according to the see-through color
TransSimple1
MOVE.L (A0),D6 ;fetch the pattern
MOVEQ #-1,D4 ;mask is initially all ones
MOVE.B TRANSCOLOR(A6),D5 ;get color to compare with
CMP.B D6,D5
BNE.S @0
CLR.B D4
@0
ROR.L #8,D4
ROR.L #8,D6
CMP.B D6,D5
BNE.S @1
CLR.B D4
@1
ROR.L #8,D4
ROR.L #8,D6
CMP.B D6,D5
BNE.S @2
CLR.B D4
@2
ROR.L #8,D4
ROR.L #8,D6
CMP.B D6,D5
BNE.S @3
CLR.B D4
@3
ROR.L #8,D4
ROR.L #8,D6
; if the mask is all ones, plot it quickly using the standard fill routine
MOVE.L A2,D0 ;if no clipping
BEQ.S @4 ;skip optimization (things not set up)
CMP.L #-1,D4 ;is mask all ones?
BEQ FCSL2 ;use standard pattern fill
; OK, mask is in D4, A2 points to the region, pattern in D6 and A1 is the destination.
; use the straightforward loop, since region optimizations aren't worth it since we
; always have to read the destination.
@4
TST.W D2 ;only one long?
BNE.S TransSimpleLoop ;if not, skip
TSL0
AND.L D1,D3 ;combine edges for last one
TransSimpleLoop
MOVE.L A2,D0
BEQ.S @0
AND.L (A2)+,D3 ;pick up the region mask
@0
AND.L D4,D3 ;punch out transparent part
MOVE.L D6,D0
AND.L D3,D0
NOT.L D3
AND.L (A1),D3
OR.L D0,D3
MOVE.L D3,(A1)+
MOVEQ #-1,D3
SUBQ.W #1,D2 ;decrement counter
BGT.S TransSimpleLoop ;loop until done
BEQ.S TSL0
RTS
; see if the complex pattern is really a simple one, if so, we can speed things up
TransComplexPat
MOVE.W D0,D6
ADD.W PATHPOS(A6),D6
MOVE.W PATHMASK(A6),D4 ;get pattern mask
ASR #3,D4 ;turn bit index to byte index
AND.W D4,D6 ;mask it
MOVE.L EXPAT(A6),A3
ADD.W PATVPOS(A6),A3 ;compute pattern address
CMP.W #8,PATROW(A6) ;is it a double pattern?
BGT.S TransComplex1 ;if not, must be complex
MOVE.L 0(A3,D6),D4 ;get source longword
EOR #4,D6
CMP.L 0(A3,D6),D4 ;is it really simple?
BEQ TransSimple1 ;if so, go handle
EOR #4,D6 ;restore D6
TransComplex1
MOVE.L D7,-(SP)
MOVE.L TRANSCOLOR(A6),D5 ;get color to compare with
TST.W D2
BNE.S TCPatLoop
; it's complex, so plot it ourselves. First fetch the pattern.
TCPLoop0
AND.L D1,D3
TCPatLoop
MOVE.W PATHMASK(A6),D4 ;get pattern mask
ASR #3,D4 ;turn bit index to byte index
AND.W D4,D6 ;mask it
MOVE.L 0(A3,D6),D7 ;get source longword
ADDQ #4,D6
CMP.L D7,D5 ;all transparent?
BEQ.S TCPSkip
; now create a mask for it
MOVEQ #-1,D4 ;mask is initially all ones
CMP.B D7,D5
BNE.S @0
CLR.B D4
@0
ROR.L #8,D4
ROR.L #8,D7
CMP.B D7,D5
BNE.S @1
CLR.B D4
@1
ROR.L #8,D4
ROR.L #8,D7
CMP.B D7,D5
BNE.S @2
CLR.B D4
@2
ROR.L #8,D4
ROR.L #8,D7
CMP.B D7,D5
BNE.S @3
CLR.B D4
@3
ROR.L #8,D4
ROR.L #8,D7
; now we can finally plot it
MOVE.L A2,D0
BEQ.S @8
AND.L (A2)+,D3 ;pick up the region mask
@8
AND.L D4,D3 ;punch out transparent part
MOVE.L D7,D0
AND.L D3,D0
NOT.L D3
AND.L (A1),D3
OR.L D0,D3
MOVE.L D3,(A1)+
; loop until done
NextTCP
MOVEQ #-1,D3
SUBQ.W #1,D2 ;decrement counter
BGT.S TCPatLoop ;loop until done
BEQ.S TCPLoop0
MOVE.L (SP)+,D7
RTS
TCPSkip
MOVE.L A2,D0
BEQ.S @0
ADDQ.L #4,A2
@0
ADDQ #4,A1
BRA.S NextTCP
;******************************************************************************************
; Here's where we handle the clipped transparent mode rectangle fill
UseOld36A
JMPRom Old36A ; <PB433>
TransFillR
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld36A ;if not, skip
tst.l d3 ;right to left? <PB427 BAL>
bmi.s UseOld36A ;if s0, skip <PB427 BAL>
; set up the registers and invoke the common scan-line handler
MOVE.L A4,A2 ;set up region pointer
ASR #3,D6 ;bit index to byte index
MOVE.L A5,A1 ;set up destination
TransFillLoop
MOVEQ #-1,D1
MOVEQ #-1,D3 ;edge masks all ones (edges in region)
MOVE.W BUFSIZE(A6),D2 ;set up the count
ADDQ #4,D2 ;make one based <PB427 BAL>
LSR.W #2,D2
SUBQ #1,D2 ;make zero based <PB427 BAL>
; call the appropriate handle, depending on whether the pattern is simple or complex
CMP.W #8,PATROW(A6) ;is pattern real complex?
BGT.S @0 ;if so, go handle it
TST.B SRCV(A6) ;test pattern mode
BMI.S @0 ;treat bitmap as complex
MOVE.L 0(A3,D6),D0 ;get left pattern
EOR #4,D6
CMP.L 0(A3,D6),D0 ;left same as right?
BEQ.S @1 ;if so, it's simple
EOR #4,D6 ;restore D6
@0
BSR TransComplex1 ;invoke scan-line handler for complex pats
BRA.S @2
@1
EOR #4,D6
MOVE.L A3,A0
BSR TransSimple1
; bump pointers to next time, and loop until done
@2
MOVE.W DSTV(A6),D0
TST.B SRCV(A6) ;test pattern mode
BEQ.S TransPat1 ;if zero, handle
BMI.S TransBitMap1 ;if <0, go handle bitmap
MOVE.L HEIGHT(A6),D6 ;get pattern index
ASR.L #3,D6 ;bit index to byte index
; handle bumping the pattern pointers
MOVE.L SRCADDR(A6),A3 ;set up pattern pointer
SUB.W D0,A3
ADD.W PATROW(A6),D0
AND.W PATVMASK(A6),D0
MOVE.W D0,DSTV(A6)
ADD.W D0,A3
BRA.S TransSetPatPtr
; handle second type of pattern
TransPat1
MOVE.L HEIGHT(A6),D6 ;get pattern index
ASR.L #3,D6 ;bit index to byte index
ADDQ #1,D0
AND #15,D0
LEA ([EXPAT,A6],D0.W*4),A3
MOVE.W D0,HEIGHT(A6)
TransSetPatPtr
MOVE.L A3,SRCADDR(A6)
; bump to the next scan line
TransFillNextLine
MOVE.L DSTROW(A6),D0
ADD.L D0,DSTADDR(A6)
MOVE.W VERT(A6),D0
ADD.W VBUMP(A6),D0
MOVE.W D0,VERT(A6)
CMP.W LASTV(A6),D0
BNE.S @0
; all done, so strip stack and return
MOVE.L SAVESTK2(A6),A7
RTS
; set up registers and loop for the next line
@0
MOVE.L SEEKMASK(A6),A0
JSR (A0) ;seek new region
MOVE.L SRCADDR(A6),A3 ;set up pattern pointer
MOVE.L DSTADDR(A6),A1 ;set up dest ptr
MOVE.L RGNADDR(A6),A2 ;set up region ptr
BRA TransFillLoop
; handle bumping the source if it's a bitmap
TransBitMap1
MOVE.L SRCROW(A6),D0
;<PB427 BAL>
ADD.L D0,SRCADDR(A6)
MOVE.l HEIGHT(A6),D6
asr.l #3,d6 ;make byte offset <PB427 BAL>
BRA.S TransFillNextLine
;******************************************************************************************
UseOld354
JMPRom Old354 ; <PB433>
TransUnClip
CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode?
BNE.S UseOld354 ;if not, skip
tst.l (sp) ;right to left? <PB427 BAL>
bmi.s UseOld354 ;if so, skip <PB427 BAL>
; set up the registers and invoke the common scan-line handler
SUB.L A2,A2 ;no region pointer
ASR #3,D6 ;bit index to byte index
MOVE.L A4,A3 ;set up pattern pointer
MOVE.L A5,A1 ;set up destination
TransUCLoop
MOVE.L FIRSTMASK(A6),D3 ;set up left edge
MOVE.L LASTMASK(A6),D1 ;set up right edge
; compute the count from the three pieces: left, mid and right
MOVE.W LONGCNT(A6),D2 ;get left count
BPL.S @3 ;if positive, we're cool
MOVEQ #0,D2 ;only one word
BRA.S @4
@3
ADD.W MIDCOUNT(A6),D2 ;add in the middle
ADD.W PIXINLONG(A6),D2 ;add in the right
ADDQ.W #2,D2 ;add for count bias
LSR.W #2,D2 ;bytes -> longs
; call the appropriate handle, depending on whether the pattern is simple or complex
@4
CMP.W #8,PATROW(A6) ;is pattern real complex?
BGT.S @0 ;if so, go handle it
TST.B ENDSWITCH(A6) ;test pattern mode
BMI.S @0 ;if bitmap, handle as complex
MOVE.L 0(A3,D6),D0 ;get left pattern
EOR #4,D6
CMP.L 0(A3,D6),D0 ;left same as right?
BEQ.S @1 ;if so, it's simple
EOR #4,D6 ;restore D6
@0
MOVE.L A1,-(SP)
BSR TransComplex1 ;invoke scan-line handler for complex pats
MOVE.L (SP)+,A1
BRA.S @2
@1
EOR #4,D6
MOVEM.L A1/A3,-(SP)
MOVE.L A3,A0
BSR TransSimple1
MOVEM.L (SP)+,A1/A3
; bump pointers to next time, and loop until done
@2
TST.B ENDSWITCH(A6) ;test pattern mode
BEQ.S TransUCPat1 ;if zero, handle
BMI.S TransUCBitMap1 ;if <0, go handle bitmap
; handle bumping the pattern pointers
MOVE.W PATPOS(A6),D0
SUB.W D0,A3
ADD.W PATROW(A6),D0
AND.W PATVMASK(A6),D0
MOVE.W D0,PATPOS(A6)
ADD.W D0,A3
BRA.S TransUCNextLine
; handle second type of pattern
TransUCPat1
MOVE.W PATPOS(A6),D0
ADDQ #1,D0
AND #15,D0
LEA ([EXPAT,A6],D0.W*4),A3
MOVE.W D0,PATPOS(A6)
; bump to the next scan line
TransUCNextLine
MOVE.L PATOFFSET(A6),D6
ASR.L #3,D6 ;bits to bytes
TransUCNL2
ADD.W DSTROW+2(A6),A1 ;bump destination
SUBQ.W #1,HEIGHT(A6)
BNE TransUCLoop
ADDQ #4,SP
RTS
; handle unclipped blits source setup
TransUCBitMap1
ADD.W D6,A3
ADD.W SRCBUMP(A6),A3 ;bump to next line <PB448 DBG>
MOVEQ #0,D6
BRA.S TransUCNL2
;******************************************************************************************
; End of arithmetic transfer modes!
;******************************************************************************************
; Special BlockMove subroutine optimized for this situation. The source is in A0
; and dest in A1, with byte count in D0. Note things are already pre-bumped for
; the MoveRight case. Note that we assume that no move is bigger than 32KBytes,
; to save a little speed (no scanline is that big!)
BlockMove
TST.W D5 ;test direction
BMI MoveRight ;if right, skip
; for small moves, all this casing out is a losing battle, so dive in quickly
CMP.W #32,D0 ;is it really small?
BLT.S FinishUpLeft ;if so, finish up last few
; make sure the destination is always longword aligned by moving up to 3 bytes
MOVE.W A1,D1 ;get destination
AND.W #3,D1 ;low two bits only
BEQ.S MediumLeft ;if 0, skip
JMP LeftAlign(D1.W*4)
LeftAlign
NOP
NOP
MOVE.B (A0)+,(A1)+
SUBQ #1,D0
MOVE.B (A0)+,(A1)+
SUBQ #1,D0
MOVE.B (A0)+,(A1)+
SUBQ #1,D0
; we've got a medium-sized block to move (at least 32), so handle it with an unwound MOVE.L loop
MediumLeft
MOVE.W D0,D1
LSR.W #5,D1 ;divide by 32
BRA.S @2
@1
MOVE.L (A0)+,(A1)+ ;move 32 bytes
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+
@2
DBRA D1,@1 ;move it
; now we have 31 or less bytes left to move
AND #31,D0
FinishUpLeft
MOVE.W LOffsetTable(D0.W*2),D0
JMP LastLeft(D0)
LastLeft
Left1F
MOVE.L (A0)+,(A1)+
Left1B
MOVE.L (A0)+,(A1)+
Left17
MOVE.L (A0)+,(A1)+
Left13
MOVE.L (A0)+,(A1)+
LeftF
MOVE.L (A0)+,(A1)+ ;move next 32 (64 total)
LeftB
MOVE.L (A0)+,(A1)+
Left7
MOVE.L (A0)+,(A1)+
Left3
MOVE.W (A0)+,(A1)+
Left1
MOVE.B (A0)+,(A1)+
Left0
DoneBlockMove
RTS
Left1E
MOVE.L (A0)+,(A1)+
Left1A
MOVE.L (A0)+,(A1)+
Left16
MOVE.L (A0)+,(A1)+
Left12
MOVE.L (A0)+,(A1)+
LeftE
MOVE.L (A0)+,(A1)+
LeftA
MOVE.L (A0)+,(A1)+
Left6
MOVE.L (A0)+,(A1)+
Left2
MOVE.W (A0)+,(A1)+
RTS
Left1C
MOVE.L (A0)+,(A1)+
Left18
MOVE.L (A0)+,(A1)+
Left14
MOVE.L (A0)+,(A1)+
Left10
MOVE.L (A0)+,(A1)+
LeftC
MOVE.L (A0)+,(A1)+
Left8
MOVE.L (A0)+,(A1)+
Left4
MOVE.L (A0)+,(A1)+
RTS
Left1D
MOVE.L (A0)+,(A1)+
Left19
MOVE.L (A0)+,(A1)+
Left15
MOVE.L (A0)+,(A1)+
Left11
MOVE.L (A0)+,(A1)+
LeftD
MOVE.L (A0)+,(A1)+
Left9
MOVE.L (A0)+,(A1)+
Left5
MOVE.L (A0)+,(A1)+
MOVE.B (A0)+,(A1)+
RTS
LOffsetTable
DC.W Left0-LastLeft
DC.W Left1-LastLeft
DC.W Left2-LastLeft
DC.W Left3-LastLeft
DC.W Left4-LastLeft
DC.W Left5-LastLeft
DC.W Left6-LastLeft
DC.W Left7-LastLeft
DC.W Left8-LastLeft
DC.W Left9-LastLeft
DC.W LeftA-LastLeft
DC.W LeftB-LastLeft
DC.W LeftC-LastLeft
DC.W LeftD-LastLeft
DC.W LeftE-LastLeft
DC.W LeftF-LastLeft
DC.W Left10-LastLeft
DC.W Left11-LastLeft
DC.W Left12-LastLeft
DC.W Left13-LastLeft
DC.W Left14-LastLeft
DC.W Left15-LastLeft
DC.W Left16-LastLeft
DC.W Left17-LastLeft
DC.W Left18-LastLeft
DC.W Left19-LastLeft
DC.W Left1A-LastLeft
DC.W Left1B-LastLeft
DC.W Left1C-LastLeft
DC.W Left1D-LastLeft
DC.W Left1E-LastLeft
DC.W Left1F-LastLeft
; Handle the case of moving to the right
MoveRight
CMP.W #32,D0 ;is it really small?
BLT.S FinishUpRight ;if so, finish up last few
; make sure the destination is always longword aligned by moving up to 3 bytes
MOVE.W A1,D1 ;get destination
AND.W #3,D1 ;low two bits only
EOR.W #3,D1 ;flip sense
JMP RightAlign(D1.W*4)
RightAlign
MOVE.B -(A0),-(A1)
SUBQ #1,D0
MOVE.B -(A0),-(A1)
SUBQ #1,D0
MOVE.B -(A0),-(A1)
SUBQ #1,D0
; we've got a medium-sized block to move (at least 32), so handle it with an unwound MOVE.L loop
MediumRight
MOVE.W D0,D1
LSR.W #5,D1 ;divide by 32
BRA.S @2
@1
MOVE.L -(A0),-(A1) ;move 32 bytes
MOVE.L -(A0),-(A1)
MOVE.L -(A0),-(A1)
MOVE.L -(A0),-(A1)
MOVE.L -(A0),-(A1)
MOVE.L -(A0),-(A1)
MOVE.L -(A0),-(A1)
MOVE.L -(A0),-(A1)
@2
DBRA D1,@1 ;move the bulk of it
; now we have 31 or less bytes left to move
AND #31,D0
FinishUpRight
MOVE.W ROffsetTable(D0.W*2),D0
;+++ JMP LastRight(D0)
JMP (QGLastRight,PC,D0) ; this is a hack - this JMP must be immediately before the table
QGLastRight
Right1F
MOVE.L -(A0),-(A1)
Right1B
MOVE.L -(A0),-(A1)
Right17
MOVE.L -(A0),-(A1)
Right13
MOVE.L -(A0),-(A1)
RightF
MOVE.L -(A0),-(A1) ;move next 32 (64 total)
RightB
MOVE.L -(A0),-(A1)
Right7
MOVE.L -(A0),-(A1)
Right3
MOVE.W -(A0),-(A1)
Right1
MOVE.B -(A0),-(A1)
Right0
RTS
Right1E
MOVE.L -(A0),-(A1)
Right1A
MOVE.L -(A0),-(A1)
Right16
MOVE.L -(A0),-(A1)
Right12
MOVE.L -(A0),-(A1)
RightE
MOVE.L -(A0),-(A1)
RightA
MOVE.L -(A0),-(A1)
Right6
MOVE.L -(A0),-(A1)
Right2
MOVE.W -(A0),-(A1)
RTS
Right1C
MOVE.L -(A0),-(A1)
Right18
MOVE.L -(A0),-(A1)
Right14
MOVE.L -(A0),-(A1)
Right10
MOVE.L -(A0),-(A1)
RightC
MOVE.L -(A0),-(A1)
Right8
MOVE.L -(A0),-(A1)
Right4
MOVE.L -(A0),-(A1)
RTS
Right1D
MOVE.L -(A0),-(A1)
Right19
MOVE.L -(A0),-(A1)
Right15
MOVE.L -(A0),-(A1)
Right11
MOVE.L -(A0),-(A1)
RightD
MOVE.L -(A0),-(A1)
Right9
MOVE.L -(A0),-(A1)
Right5
MOVE.L -(A0),-(A1)
MOVE.B -(A0),-(A1)
RTS
ROffsetTable
DC.W Right0-QGLastRight
DC.W Right1-QGLastRight
DC.W Right2-QGLastRight
DC.W Right3-QGLastRight
DC.W Right4-QGLastRight
DC.W Right5-QGLastRight
DC.W Right6-QGLastRight
DC.W Right7-QGLastRight
DC.W Right8-QGLastRight
DC.W Right9-QGLastRight
DC.W RightA-QGLastRight
DC.W RightB-QGLastRight
DC.W RightC-QGLastRight
DC.W RightD-QGLastRight
DC.W RightE-QGLastRight
DC.W RightF-QGLastRight
DC.W Right10-QGLastRight
DC.W Right11-QGLastRight
DC.W Right12-QGLastRight
DC.W Right13-QGLastRight
DC.W Right14-QGLastRight
DC.W Right15-QGLastRight
DC.W Right16-QGLastRight
DC.W Right17-QGLastRight
DC.W Right18-QGLastRight
DC.W Right19-QGLastRight
DC.W Right1A-QGLastRight
DC.W Right1B-QGLastRight
DC.W Right1C-QGLastRight
DC.W Right1D-QGLastRight
DC.W Right1E-QGLastRight
DC.W Right1F-QGLastRight
EndQPatches
PRINT OFF