;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 ` 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 ; 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 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 ; 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? bne.s UseOld373 ; no, can't handle this one. 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) bne.s UseOld373 ;if so, don't handle 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 12Jul88 BEQ.s @a ;if white->white, ok 12Jul88 MOVEQ #$F,D0 ;else, its black 12Jul88 @a ; 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 ; 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 JMPRom Old38E ; ; 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 JMPRom Old389 ; ; 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 JMPRom Old38B ; ; 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 JMPRom Old38D ; ; 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 JMPRom Old38F ; ; 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 JMPRom Old388 ; ; 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 ; AddOverFillR CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld368 ;if not, skip tst.l d3 ;right to left? bmi.s UseOld368 ;if so, skip 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 LSR.W #2,D2 SUBQ #1,D2 ;make zero based 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 ; SubOverFillR CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld36C ;if not, skip tst.l d3 ;right to left? bmi.s UseOld36c ;if so, skip LEA SubOverHandler,A0 ;set up the handler BRA ArithFillCommon ;use comon code ;****************************************************************************************** ; Handle AddPin clipped rectangle fill UseOld367 JMPRom Old367 ; AddPinFillR CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld367 ;if not, skip tst.l d3 ;right to left? bmi.s UseOld367 ;if so, skip LEA AddPinHandler,A0 ;set up the handler BRA ArithFillCommon ;use comon code ;****************************************************************************************** ; Handle SubPin clipped rectangle fill UseOld369 JMPRom Old369 ; SubPinFillR CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld369 ;if not, skip tst.l d3 ;right to left? bmi.s UseOld369 ;if so, skip LEA SubPinHandler,A0 ;set up the handler BRA ArithFillCommon ;use comon code ;****************************************************************************************** ; Handle AddMax clipped rectangle fill UseOld36B JMPRom Old36B ; AddMaxFillR CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld36B ;if not, skip tst.l d3 ;right to left? bmi.s UseOld36B ;if so, skip LEA AddMaxHandler,A0 ;set up the handler BRA ArithFillCommon ;use comon code ;****************************************************************************************** ; Handle AddMin clipped rectangle fill UseOld36D JMPRom Old36D ; AddMinFillR CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld36D ;if not, skip tst.l d3 ;right to left? bmi.s UseOld36D ;if so, skip LEA AddMinHandler,A0 ;set up the handler BRA ArithFillCommon ;use comon code ;****************************************************************************************** ; Handle Blend clipped rectangle fill UseOld366 JMPRom Old366 ; BlendFillR CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld366 ;if not, skip tst.l d3 ;right to left? bmi.s UseOld366 ;if s0, skip 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 ; AddOverUnClip CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld352 ;if not, skip tst.l (sp) ;right to left? bmi.s UseOld352 ;if so, skip 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 MOVEQ #0,D6 BRA.S ArithUCNL2 ;****************************************************************************************** ; Handle SubOver unclipped rectangle fill UseOld356 JMPRom Old356 ; SubOverUnclip CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld356 ;if not, skip tst.l (sp) ;right to left? bmi.s UseOld356 ;if so, skip LEA SubOverHandler,A0 ;set up the handler BRA ArithUCCommon ;use comon code ;****************************************************************************************** ; Handle AddPin unclipped rectangle fill UseOld351 JMPRom Old351 ; AddPinUnclip CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld351 ;if not, skip tst.l (sp) ;right to left? bmi.s UseOld351 ;if so, skip LEA AddPinHandler,A0 ;set up the handler BRA ArithUCCommon ;use comon code ;****************************************************************************************** ; Handle SubPin unclipped rectangle fill UseOld353 JMPRom Old353 ; SubPinUnclip CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld353 ;if not, skip tst.l (sp) ;right to left? bmi.s UseOld353 ;if so, skip LEA SubPinHandler,A0 ;set up the handler BRA ArithUCCommon ;use comon code ;****************************************************************************************** ; Handle AddMax unclipped rectangle fill UseOld355 JMPRom Old355 ; AddMaxUnclip CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld355 ;if not, skip tst.l (sp) ;right to left? bmi.s UseOld355 ;if so, skip LEA AddMaxHandler,A0 ;set up the handler BRA ArithUCCommon ;use comon code ;****************************************************************************************** ; Handle AddMin unclipped rectangle fill UseOld357 JMPRom Old357 ; AddMinUnclip CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld357 ;if not, skip tst.l (sp) ;right to left? bmi.s UseOld357 ;if so, skip LEA AddMinHandler,A0 ;set up the handler BRA ArithUCCommon ;use comon code ;****************************************************************************************** ; Handle Blend unclipped rectangle fill UseOld350 JMPRom Old350 ; BlendUnclip CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld350 ;if not, skip tst.l (sp) ;right to left? bmi.s UseOld350 ;if so, skip 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 ; TransFillR CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld36A ;if not, skip tst.l d3 ;right to left? bmi.s UseOld36A ;if s0, skip ; 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 LSR.W #2,D2 SUBQ #1,D2 ;make zero based ; 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 ; ADD.L D0,SRCADDR(A6) MOVE.l HEIGHT(A6),D6 asr.l #3,d6 ;make byte offset BRA.S TransFillNextLine ;****************************************************************************************** UseOld354 JMPRom Old354 ; TransUnClip CMP.W #8,DSTPIX+PIXELSIZE(A6) ;is it 8 bit mode? BNE.S UseOld354 ;if not, skip tst.l (sp) ;right to left? bmi.s UseOld354 ;if so, skip ; 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 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