; ; File: QuickDrawPatches.a ; ; Contains: Linked patches for QuickDraw ; ; Written by: Jeff Miller and Darin Adler ; ; Copyright: © 1990-1993 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 9/12/93 SAM Changed all instances of _Translate24to32 to _rTranslate24to32 ; so they can coditionalized out of the build. ; 8/14/92 CSS Integrate from Reality: ; <22> 8/13/92 SAH #1039892: Fixed a bug in the ScaleBlt 1->16 non-colorizing loop ; (scIndexedTo16) where the bit offset into the source would be ; trashed in certain cases. ; 7/17/92 CSS Integrate from Reality: ; <21> 6/8/92 SAH #1031825: Added new indexed to 16 and indexed to 32 blit loops ; for ScaleBlt. ; 5/21/92 CSS Integrate from Reality: ; <20> 4/10/92 SAH Moved in the working fast bSetup0 patch for 68040 machines from ; QDIIciPatchROM.a. ; 4/15/92 RB All patches in this file up to this point have been rolled in ; except for the ones designated for 'TheFuture' which are not ; tested : DrawPictureForPurgedPictures in Pictures.a, ; newGetCTable in ColorMgr.a, ciNewFixRatio in DrawArc.a, ; DisposeOffscreenBufferFix in GWorld.a, FixPatExpand (TheFuture) ; not set yet, CheckForAbortPicPlayBackFix (TheFuture) not set ; yet, PatchSeedFill (TheFuture) not set yet, ciPatchGetCPixel ; (TheFuture) not set yet, PatchClosePictureCI (TheFuture) not set ; yet, AfterOpenCPortInNewGWorld in GWorld.a, PutPMDataPackBits 2 ; patches in Pictures.a, CopyBitsGetScreenBase in BitMaps.a, ; CopyBitsDitherWhileFlattening, GWorldGetMaxDevice in GWorld.a, ; ciClosePortPatch in CoorAsm.A, NewPixMap in ColorAsm.a, ; BitMapRgn in Regions.a ; <19> 10/17/91 DTY Avoid duplicate NewPatExpand label, and use trap number for ; PatExpand instead of macro because the linked patch macros don’t ; seem to know about it. ; <18> 10/16/91 KON Move some routines from QDciPatchROM over and make them linked ; patches. ; <17> 10/15/91 KON Clear pmVersion in NewPixMap so that pixmaps created while an ; offscreen gWorld is active don't have non-nil pmVersions. ; <16> 10/2/91 DTY Conditionalise last change for TheFuture. ; <15> 10/1/91 KON ComeFrom inside getPMData patch on UnpackBits to abort picture ; if an error is detected (QDError = AbortPicPlayBackErr). ; <14> 7/23/91 KON Fix 32-bit clean problems in BitMapRgn. ; <13> 6/12/91 LN changed #include 'HardwareEqu.a' to 'HardwarePrivateEqu.a' ; <12> 4/3/91 KON dba, BRC#86188: Make DrawPicture re-entrant by saving and ; restoring global variables playpic, playindex, and patAlign ; across calls. This fixes bugs in balloon help while printing, ; and a bug in ResEdit while printing in the background. ; <11> 3/31/91 dba gbm: DrawPicture cannot handle purged handles, so lets make sure ; it never gets any ; <10> 3/22/91 KON CSD, BRC#B6-C4-HitTeam: DelPortList cannot assume that the port ; is in the list. Also, clear the high word of D0 before calling ; SetHandleSize. ; <9> 3/19/91 KON DTY: When fixing PortList Munger bug, QDciROMPatch was getting ; too big, so we moved some patches (ClosePort, CloseCPort, ; NewPixMap, & BitMapRgn) into this file and made then linked ; patches. ; <8> 1/14/91 KON Remove comefrom UpdateGWorld patch since it is now completely ; patched out in QDciPatch. [SMC] ; <7> 12/14/90 bbm (djw) roll in linked comefrompatch from patchIIrom.a. ; <6> 11/26/90 JSM Move come-from patch on _StackSpace inside RgnOp here from ; PatchIIROM.a. Note that this patch was also on the Plus and SE, ; but never worked on those machines since the ROM doesn't call ; _StackSpace! We may want to revisit this in the future. ; <5> 11/15/90 JSM Add _OpenCPort patch from AllB&WQDPatch.a and come-from ; patch on _OpenCPort inside NewGWorld from PatchIIciROM.a. ; <4> 11/13/90 JSM Move the following patches here from QDciPatchROM.a: ; come-from patch on _PackBits inside PutPMData, come-from patch ; on _CopyBits inside CopyBits, come-from patch on _GetMaxDevice ; inside NewGWorld and NewTempScreenBuffer, come-from patch on ; _DisposeGWorld inside UpdateGWorld. Split the _CopyBits patch ; into a come-from and a regular patch to avoid future problems. ; <3> 8/22/90 DTY OK, so I botched it. Forget I ever did anything. ; <2> 8/22/90 DTY Install the GetPMData trap here since it’s used by both ; QuickDrawPatchII and AllB&WQDPatch. ; <1> 6/11/90 JSM First checked in. ; load 'StandardEqu.d' include 'LinkedPatchMacros.a' ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; DrawPicture — purged and purgeable pictures <11> ; ; do nothing for purged handles and mark handles non-purgeable before doing DrawPicture ; this could be rolled into the main DrawPicture patches, but it would probably be trickier there ; we’re doing it here because we are working on the final candidate for 7.0 ; ; Save and restore global info so DrawPicture is reentrant. This should be rolled into DrawPicture ; someday soon, but we're ready to ship and this was the lowest risk way since the patch is the same ; across machines. <12> ; DrawPictureForPurgedPictures PatchProc _DrawPicture,(Plus,SE,II,Portable,IIci) ; ; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: ; ParamSize EQU 8 MyPicture EQU ParamSize+8-4 ;LONG, PICHANDLE DstRect EQU MyPicture-4 ;LONG, ADDR OF RECT ; Locals SavePatAlign EQU -4 SavePlayPic EQU SavePatAlign-4 SavePlayIndex equ SavePlayPic-4 SaveHandleState equ SavePlayIndex-2 VarSize EQU SaveHandleState ;TOTAL BYTES OF LOCALS move.l 8(sp),d0 ; get the picture handle beq.s Done ; if NIL, do nothing move.l d0,a0 ; dereference the picture handle move.l (a0),d0 beq.s Done ; if purged, do nothing link a6, #VarSize _HGetState ; get the handle’s state ; DO NOT CHECK ERRORS HERE ; that would mess up people who do DrawPicture on fake handles move.b d0,SaveHandleState(a6) ; save the state _HNoPurge ; mark the handle non-purgeable ; ; save global variables so DrawPicture is re-entrant ; move.l a4,-(sp) ;need register a4 move.l GrafGlobals(A5),a4 ;point to QuickDraw globals move.l PATALIGN(A4),SavePatAlign(a6) ;save patalign move.l PLAYPIC(A4),SavePlayPic(a6) ;save playpic move.l PLAYINDEX(A4),SavePlayIndex(a6) ;save playindex move.l a0,-(sp) ; pass the picture through move.l DstRect(a6),-(sp) ; pass a pointer to the rectangle to draw in also jsrOld ; ; Restore global variables ; move.l SavePlayIndex(a6),PLAYINDEX(A4) ;restore 'em all move.l SavePlayPic(a6),PLAYPIC(A4) move.l SavePatAlign(a6),PATALIGN(A4) move.l (sp)+,a4 ;done with a4 move.b SaveHandleState(a6),d0 ; get back the handle state move.l MyPicture(a6),a0 ; get back the picture handle _HSetState ; set the picture back like before unlk a6 Done move.l (sp)+,a0 ; get the return address addq #8,sp ; get rid of the parameters jmp (a0) ; return EndProc ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Code below this point is for Color QuickDraw only! ;———————————————————————————————————————————————————————————————————————————————————————————————————— INCLUDE 'paletteEqu.a' INCLUDE 'palettePriv.a' include 'colorequ.a' INCLUDE 'qdHooks.a' INCLUDE 'VideoEqu.a' include 'HardwarePrivateEqu.a' INCLUDE 'fontPrivate.a' GBLC &CurFile ;current file name used by DrawingVars MACHINE MC68020 ; assumes this is for ColorQD only ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; CharExtraFixDiv ; Replace 0 sized font with system font if family is system, or fmDefault otherwise. AfterFixDivInCharExtra ROMBIND (II,$19B88) IF (&TYPE('_FixDiv') = 'UNDEFINED') THEN _FixDiv OPWORD $A84D ENDIF CharExtraFixDiv ComeFromPatchProc _FixDiv,AfterFixDivInCharExtra,(II) TST.L 4(SP) ; passed zero font size? bneOld TST txFont(A0) ; system font? BNE.S @apFont ; if not, use default MOVE SysFontSize,D0 ; if family is zero, use system font size BNE.S @notZero @apFont MOVEQ #0,D0 ; clear high byte of low word MOVE.B FMDefaultSize,D0 ; if family nonzero or system font size zero, BNE.S @notZero ; use the default size MOVEQ #12,D0 ; if the default is zero, hardcode to 12 @notZero MOVE D0,4(SP) ; stuff it in the high word jmpOld ENDPROC ;========================================================================================= ;========================================================================================= ; ; Patch to GetCTable to make sure it always returns NIL when the call fails ; ;========================================================================================= ;========================================================================================= newGetCTable PatchProc _GetCTable,(IIci) clr.l 6(sp) ; NIL return if call fails. jmpOld ENDPROC ;========================================================================================= ;========================================================================================= ; ; ComeFrom patch on FixRatio to see if from arc drawing ; ;========================================================================================= ;========================================================================================= ciNewFixRatio ComeFromPatchProc _FixRatio,,(IIci) FromDrawArc ROMBIND (IIci,$34856) &CurFile SETC 'DRAWARC' INCLUDE 'DrawingVars.a' cmpROM FromDrawArc,(SP) ;coming from right place? BNE.S BackToROM ; MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT MOVE TOP(A0),A1 ADD BOTTOM(A0),A1 MOVE.L A1,D0 ASR.L #1,D0 MOVE D0,MIDVERT(A6) ;MID VERT := (DSTBOT+DSTTOP)/2 MOVE LEFT(A0),A1 ADD RIGHT(A0),A1 MOVE.L A1,D0 ASR.L #1,D0 MOVE D0,MIDHORIZ(A6) ;MID HORIZ := (DSTLEFT+DSTRIGHT)/2 BackToROM jmpold ENDPROC ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Come-from patch on _StackSpace inside RgnOp <6> ; ; When calculating buffer sizes in the initialization section of RgnOp, the buffer size is ; incorrectly calculated (signed add instead of unsigned). By correcting this problem, ; operations on 2 16K regions should be OK. Many thanks to Darren Adler and Chris DeRossi ; of Tech Support for locating this problem. ; ; Note that since QuickDraw calls _StackSpace directly, bypassing the OS trap dispatcher, ; we can't use the ComeFromPatchProc macro to compare the come-from address, as it ; assumes the return address is farther down the stack (since the OS trap dispatcher ; saves registers before dispatching). ; ; ***This bug needs to be fixed on the Plus and SE as well, but the Plus and SE ROM RgnOp ; procedures don't call _StackSpace to calculate the stack size, so we can't fix it here. ; AfterStackSpaceInRgnOp ROMBIND (Plus,$0C424),(SE,$16B94),(II,$261CC) ; AfterBufferSizeCalcInRgnOp ROMBIND (Plus,$0C47E),(SE,$16BEE),(II,$26220) AfterStackSpaceInRgnOp ROMBIND (II,$261CC) AfterBufferSizeCalcInRgnOp ROMBIND (II,$26220) RgnOpStackSpace ComeFromPatchProc _StackSpace,,(II) ; ; Here is the stack frame for RgnOp copied from ROM source ; PARAMSIZE EQU 20 ;TOTAL # BYTES RESULT EQU PARAMSIZE+8 ;INTEGER, FUNCTION RESULT RGNA EQU RESULT-4 ;LONG, RGNHANDLE RGNB EQU RGNA-4 ;LONG, RGNHANDLE BUFHANDLE EQU RGNB-4 ;LONG, HANDLE TO POINT BUFFER MAXBYTES EQU BUFHANDLE-2 ;WORD OP EQU MAXBYTES-2 ;WORD DH EQU OP-2 ;WORD OKGROW EQU DH-2 ;BOOLEAN SCAN1 EQU -4 ;long SCAN2 EQU SCAN1-4 ;long SCAN3 EQU SCAN2-4 ;long SCAN4 EQU SCAN3-4 ;long SCAN5 EQU SCAN4-4 ;long NEXTA EQU SCAN5-2 ;WORD NEXTB EQU NEXTA-2 ;WORD VERT EQU NEXTB-2 ;WORD BUFPTRX EQU VERT-4 ;LONG, ^POINT BUFLIMIT EQU BUFPTRX-4 ;LONG FAKEB EQU BUFLIMIT-18 ;18 BYTE FAKE RGN DATA MASTERB EQU FAKEB-4 ;LONG FAKEA EQU MASTERB-18 ;18 BYTE FAKE RGN DATA MASTERA EQU FAKEA-4 ;LONG CASEJMP EQU MASTERA-4 ;LONG SAVESTK EQU CASEJMP-4 ;LONG VARSIZE EQU SAVESTK ;TOTAL BYTES OF LOCALS cmpROM AfterStackSpaceInRgnOp,(SP) ;coming from right place? bneOld ;no, let StackSpace do its stuff jsrOld ;call stackSpace SUB.L #qdStackXtra,D0 ;subtract slop factor CMP.L #200,D0 ;is result < 200 bytes ? BGE.S STKOK1 ;no, continue MOVE #40,D0 ;yes, make bufSize = 40 bytes BRA.S ALLOC ;and continue STKOK1 DIVS #5,D0 ;no, divide for 5 buffers BVC.S STKOK2 ;overflow ? MOVE #30000,D0 ;yes, use 30K bytes STKOK2 BCLR #0,D0 ;make bufSize even ALLOC SUB D0,SP ;allocate one buffer MOVE.L SP,SCAN1(A6) ;remember buffer pointer SUB D0,SP ;allocate one buffer MOVE.L SP,SCAN2(A6) ;remember buffer pointer SUB D0,SP ;allocate one buffer MOVE.L SP,SCAN3(A6) ;remember buffer pointer SUB D0,SP ;allocate one buffer MOVE.L SP,SCAN4(A6) ;remember buffer pointer SUB D0,SP ;allocate one buffer MOVE.L SP,SCAN5(A6) ;remember buffer pointer MOVE.L BUFHANDLE(A6),A0 ;GET BUFHANDLE MOVE.L (A0),A0 ;DE-REFERENCE IT MOVE.L A0,BUFPTRX(A6) ;BUFPTR := BUFSTART AND #$FFF8,MAXBYTES(A6) ;TRUNCATE TO A MULT OF 8 BYTES CLR.L D4 ;zero hi-word of register DAF MOVE.W MAXBYTES(A6),D4 ;get long version of MaxBytes DAF ADD.L D4,A0 ;add MaxBytes to BufStart DAF jmpROM AfterBufferSizeCalcInRgnOp ENDPROC ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Fix to NewScreenBuffer and NewTempScreenBuffer in _QDExtensions ; ROM code loads D0 with offscreen buffer and offscreen pixmap handles to dispose, ; we put them in A0 where they belong AfterFirstDisposeD0 ROMBIND (IIci,$40EA4) ; disposing offscreen buffer AfterSecondDisposeD0 ROMBIND (IIci,$40EAA) ; disposing offscreen pixmap DisposeOffscreenBufferFix ComeFromPatchProc _DisposHandle,,(IIci) CMPROM AfterFirstDisposeD0,ReturnAddressDepth(SP) ; disposing offscreen buffer? BEQ.S @doIt ; yes CMPROM AfterSecondDisposeD0,ReturnAddressDepth(SP) ; disposing offscreen pixmap? BNEOLD ; no @doIt MOVE.L D0,A0 ; move handle into A0 BRAOLD ; and continue ENDPROC ; DisposeOffscreenBufferFix ; ; <16> Build these patches when the future arrives. ; if TheFuture then ; <16> ; ; Begin <18> ; ;Patches from Patterns.a FixPatExpand PatchProc $AB15,(IIci) ciRSetHSize ROMBIND (IIci,$31450) ciGotCopy ROMBIND (IIci,$30972) ciNEWDONE ROMBIND (IIci,$30A96) ciNOTOLD ROMBIND (IIci,$30A9E) &CurFile SETC 'PATEXPAND' INCLUDE 'DrawingVars.a' ;------------------------------------------------------------- PARAMSIZE EQU 0 TWOPAT EQU -16 ;ROOM FOR TWO COPIES OF PAT SAVESTK EQU TWOPAT-4 ;ROOM TO SAVE STACK POINTER ROTSIZE EQU SAVESTK-2 ;SCANLINE SIZE FOR ROTATION ROTSHIFT EQU ROTSIZE-2 ;ROTATE AMOUNT GGLOBALS EQU ROTSHIFT-4 ;POINTER TO GRAFGLOBALS SAVEA5 EQU GGLOBALS-4 ;PLACE TO SAVE A5 VARSIZE EQU SAVEA5 ;TOTAL BYTES OF LOCAL VARS ;------------------------------------------------------------------ ; ; IF OLD PATTERN, ALLOCATE A BUFFER ON THE STACK AND POINT TO IT. ; IF NEW PATTERN, GO EXPAND IF NECESSARY. ; TST.B NEWPATTERN(A6) ;IS IT A NEW PATTERN? BNE NEWPATEXPAND ;=>YES, EXPAND PIXELPAT ; ALLOCATE AN EXPAND BUFFER ON THE STACK FOR USE BY CALLER DOOLD MOVE.L (SP)+,A0 ;GET RETURN ADDRESS MOVEQ #64,D0 ;MINIMUM BUFFER IS 64 BYTES MOVE DSTSHIFT(A6),D1 ;GET DEPTH SHIFT subq #3,D1 ;DEPTHS 1-8 OK @@@@ BAL 10Apr88 ble.S GETBUF ;=>SO GET THE PATTERN BUFFER @@@@ BAL 10Apr88 LSL D1,D0 ;ELSE DOUBLE FOR 16, QUAD FOR 32 GETBUF SUB D0,SP ;MAKE THE BUFFER (LONG ALIGNED) MOVE.L SP,EXPAT(A6) ;POINT TO PATTERN BUFFER MOVE.L A0,-(SP) ;REPLACE RETURN ADDRESS PSHARE LINK A4,#VARSIZE ;ALLOCATE STACK FRAME MOVEM.L D3-D6/A2-A3/A5,-(SP) ;SAVE REGS MOVE LOCMODE(A6),D0 ;GET MODE MOVE DSTPIX+BOUNDS+LEFT(A6),D2 ;GET GLOBAL-LOCAL OFFSET (PIXELS) MOVE.L FCOLOR(A6),D3 ;GET CURRENT FG COLOR MOVE.L BCOLOR(A6),D4 ;GET CURRENT BK COLOR MOVE DSTSHIFT(A6),D5 ;GET SHIFT FOR PIXEL DEPTH MOVE.L LOCPAT(A6),A0 ;GET PATTERN LEA PATROW(A6),A1 ;AND DATA DST AND #$F3,D0 ;TURN OFF PAT, INVERT BITS BEQ.S GOTCOPY ;=>IT'S COPY MODE BTST #5,D0 ;is it a new mode? BNE.S GotCopy ; MOVEQ #-1,D3 ;ELSE FGCOLOR = BLACK MOVE.L alphaMask(A6),D3 MOVEQ #0,D4 ;AND BKCOLOR = WHITE GotCopy jmpROM ciGotCopy NEWPATEXPAND ;---------------------------------------------------------------- ; ; NEWPATEXPAND -- EXPAND A PIXELPAT, IF NECESSARY ; ; NOTE: STACK FRAME LINKED USING A4 SO NORMAL FRAME STILL IN A6 ; LINK A4,#VARSIZE ;ALLOCATE STACK FRAME MOVEM.L D3-D6/A2-A3/A5,-(SP) ;SAVE REGS MOVE.L SP,SAVESTK(A4) ;SAVE STACK POINTER MOVE.L GRAFGLOBALS(A5),A3 ;POINT TO QUICKDRAW GLOBALS MOVE.L A3,GGLOBALS(A4) ;SAVE IN STACK FRAME MOVE.L A5,SAVEA5(A4) ;AND SAVE GLOBAL POINTER MOVE.L LOCPAT(A6),A0 ;GET THE PIXPAT HANDLE POINTER MOVE.L (A0),A0 ;GET THE PIXPAT HANDLE MOVE.L (A0),A0 ;GET THE PIXPAT POINTER TST PATTYPE(A0) ;IS IT AN OLD PATTERN? BNE.S NOTOLD ;=>NO, CHECK FOR EXPANSION OF NEW PAT ;--------------------------------------------------------- ; ; IF OLD PATTERN, USE SHARED CODE TO EXPAND IT ; MOVE.L PATXDATA(A0),A0 ;GET THE EXPANDED DATA HANDLE MOVEQ #64,D0 ;MINIMUM BUFFER IS 64 BYTES MOVE DSTSHIFT(A6),D1 ;GET DEPTH SHIFT subq #3,D1 ;DEPTHS 1-8 OK @@@@ BAL 10Apr88 ble.S BUFOK ;=>SO GET THE PATTERN BUFFER @@@@ BAL 10Apr88 LSL.L D1,D0 ;ELSE DOUBLE FOR 16, QUAD FOR 32 BUFOK jsrROM ciRSetHSize MOVE.L (A0),d0 ;get master pointer @@@@ BAL 10Apr88 _rTranslate24To32 ;mask off high byte @@@@ BAL 10Apr88 move.l d0,EXPAT(A6) ;SAVE POINTER TO EXPAND DATA AREA ;*** LEAVE IT UNLOCKED MOVE.L LOCPAT(A6),A0 ;GET PIXPAT HANDLE POINTER MOVE.L A0,-(SP) ;SAVE PIXPAT HANDLE POINTER MOVE.L (A0),A0 ;GET HANDLE TO PIXPAT MOVE.L (A0),A0 ;GET POINTER TO PIXPAT MOVE.L PATDATA(A0),A0 ;GET HANDLE TO DATA MOVE.L (A0),A0 ;GET POINTER TO DATA MOVE.L A0,LOCPAT(A6) ;SET UP POINTER TO SRC DATA JSR PSHARE ;AND CALL COMMON CODE MOVE.L (SP)+,LOCPAT(A6) ;RESTORE PATTERN HANDLE NEWDONE jmpROM ciNEWDONE NOTOLD jmpROM ciNOTOLD ENDPROC ; ; end <18> ; ; ; Begin <15> ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Abort GetDirectPMData if an error is encountered. This is done via a comefrom on Unpackbits. ; if QDError = AbortPicPlayBackErr, return immediately. Put 0 in d3, d6, and d7 which are loop ; counters so the routine is also aborted immediately. ; ; In the unPack loop, D4 is used as the loop counter so we zero this also. Zeroing all these reg. ; should be ok for both places. AfterUnPackBitsInGetDirectPMData ROMBIND (IIci,$3332E) AfterUnPackBitsInGetPMData ROMBIND (IIci,$336A0) CheckForAbortPicPlayBackFix ComeFromPatchProc _UnpackBits,,(IIci) CMPROM AfterUnPackBitsInGetDirectPMData,ReturnAddressDepth(SP) ; disposing offscreen buffer? BEQ.S @doIt ; yes CMPROM AfterUnPackBitsInGetPMData,ReturnAddressDepth(SP) ; disposing offscreen pixmap? BNEOLD ; no @doIt cmp.w #AbortPicPlayBackErr,qdErr ;abort if our special error bneold moveq #0,d3 move.l d3,d4 move.l d4,d6 move.l d6,d7 move.l (sp)+,a0 ;get return address add #$a,sp ;clear two ptrs and a count 4+4+2 = a jmp (a0) ; and abort ENDPROC ; DisposeOffscreenBufferFix ; ; Stuff from QDciPatch because that file is too big ; ;========================================================================================= ;========================================================================================= ; ; Patch SeedFill and CalcMask to check both up and down on the first pass of filling ; ;========================================================================================= ;========================================================================================= PatchSeedFill PatchProc _SeedFill,(IIci) EXPORT ciPatchCalcMask ciSeedFill ROMBIND (IIci,$35A4C) ciGoHome ROMBIND (IIci,$35B0A) ;------------------------------------------------------------------------- ; ; PROCEDURE SeedFill(srcPtr,dstPtr: Ptr; ; srcRow,dstRow,height,words: INTEGER; ; seedH,seedV: INTEGER) ; MOVE.L (SP)+,A0 ;pop return addr MOVEQ #-1,D0 ;get a long of -1 MOVE.L D0,-(SP) ;push edge = all ones BRA.S SHARE ;share common code ;------------------------------------------------------------------------- ; ; PROCEDURE CalcMask(srcPtr,dstPtr: Ptr; ; srcRow,dstRow,height,words: INTEGER); ; ciPatchCalcMask MOVE.L (SP)+,A0 ;pop return addr MOVEQ #-1,D0 ;get a long of -1 MOVE.L D0,-(SP) ;push seed = (-1,-1) CLR.L -(SP) ;push edge = zeros SHARE MOVE.L A0,-(SP) ;restore return addr ;------------------------------------------------------------------------- ; ; LOCAL PROCEDURE MakeMask(srcPtr,dstPtr: Ptr; ; srcRow,dstRow,height,words: INTEGER; ; seedH,seedV: INTEGER; ; edge: LongInt); ; ; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK: ; PARAMSIZE EQU 24 srcPtr EQU PARAMSIZE+8-4 ;long dstPtr EQU srcPtr-4 ;long srcRow EQU dstPtr-2 ;word dstRow EQU srcRow-2 ;word height EQU dstRow-2 ;word words EQU height-2 ;word seedH EQU words-2 ;word seedV EQU seedH-2 ;word edge EQU seedV-4 ;long dstBump EQU -2 ;word saveStk EQU dstBump-4 ;long varSize EQU saveStk ;total locals LINK A6,#varSize ;allocate stack frame MOVEM.L D3-D7/A2-A4,-(SP) ;save regs MOVE.L SP,saveStk(A6) ;save stack pointer ; ; prepare height and words for DBRA count. Quit if either <= 0. ; MOVE words(A6),D5 ;get count of words BLE GOHOME ;quit if words <= 0 SUB #1,D5 ;subtract 1 for DBRA count SUB #1,height(A6) ;convert height to DBRA BLT GOHOME ;quit if height <= 0 ; ; init dst to all ones: ; MOVE words(A6),D0 ;get # of words ADD D0,D0 ;double for bytes MOVE dstRow(A6),D1 ;get dstRow SUB D0,D1 ;subtract bytes for dstBump MOVE D1,dstBump(A6) ;save dstBump for later MOVE.L dstPtr(A6),A2 ;point to dst MOVEQ #-1,D0 ;get some black MOVE height(A6),D3 ;init DBRA rowCount BLACK1 MOVE D5,D2 ;init DBRA wordCount BLACK2 MOVE D0,(A2)+ ;put a word of black DBRA D2,BLACK2 ;loop all words in row ADD D1,A2 ;bump to next row DBRA D3,BLACK1 ;loop height rows ; ; clear one dst pixel at seedH,seedV ; MOVE seedV(A6),D0 ;get seed vert coord BLT.S NOSEED ;skip if neg (no seed) MULU dstRow(A6),D0 ;mul times dst row MOVE.L dstPtr(A6),A0 ;point to dst ADD.L D0,A0 ;add vertical offset MOVE seedH(A6),D0 ;get seed horiz coord MOVE D0,D1 ;copy seedH ASR #3,D0 ;div by 8 for byte NOT D1 ;invert bit number BCLR D1,0(A0,D0) ;clear seed pixel NOSEED ; ; allocate a scanline buffer of ones or zeros on the stack: ; MOVE.L edge(A6),D6 ;get zero or all ones MOVE D5,D1 ;get longCount NEXTBUF MOVE D6,-(SP) ;write a word of ones or zeros DBRA D1,NEXTBUF ;loop all words MOVE.L srcPtr(A6),A0 ;point to top of src MOVE.L dstPtr(A6),A2 ;point to top of dst st d7 ;set dirty flag to force ; bra.s FirstPass ;search up and down ;NXTPASS SF D7 ;clear dirty flag FirstPass jmpROM ciSeedFill GoHome jmpROM ciGoHome ENDPROC ;========================================================================================= ;========================================================================================= ; ; Patch to getPixel and getCPixel so that SwapMMUMode is called if pixmap needs 32-bit ; addressing (pmVersion = 4). These calls are in QDUtil.a. ; ;========================================================================================= ;========================================================================================= ciPatchGetCPixel PatchProc _GetCPixel, (IIci) EXPORT ciPatchGetPixel ciMMUModeOK ROMBIND (IIci,$2F018) ciGetPixelDone ROMBIND (IIci,$2F070) PARAMSIZE EQU 4 RETURN EQU PARAMSIZE+8 ;ADDRESS OF BOOLEAN/RGBCOLOR HLOC EQU PARAMSIZE+8-2 ;HORIZONTAL POSITION VLOC EQU HLOC-2 ;VERTICAL POSITION VARSIZE EQU 0 ;TOTAL SIZE OF LOCALS ;--------------------------------------------------------- ; ; FUNCTION GetPixel(h,v: INTEGER): BOOLEAN; ; PROCEDURE GetCPixel(h,v: INTEGER; myColor: RGBColor); ; ; Returns TRUE if the pixel at (h,v) is set to black. ; h and v are in local coords of the current grafport. ; ; WATCH OUT FOR STACK TRICKERY WHEN GETCPIXEL CALLS GETPIXEL!! ; ; CLOBBERS A0,A1,D0,D1,D2 ; ciPatchGetPixel MOVE.L 8(SP),-(SP) ;PUSH H,V MOVEQ #1,D2 ;ROUTINE = GETCPIXEL BSR.S SHARE ;USE COMMON CODE RTD #8 ;STRIP PARAMS AND RETURN MOVEQ #0,D2 ;ROUTINE = GETPIXEL SHARE LINK A6,#VARSIZE ;ALLOCATE STACKFRAME MOVEM.L D4-D5/A2-A3,-(SP) ;SAVE WORK REGISTERS MOVE.L THEGDEVICE,-(SP) ;SAVE CURRENT GRAFDEVICE MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS MOVE.L THEPORT(A0),A0 ;GET THEPORT _PORTTOMAP ;GET BIT/PIXMAP IN A0 ; GET GLOBAL COORDINATES OF VLOC INTO D4 AND HLOC INTO D5 OLDRB MOVE VLOC(A6),D4 ;GET VERTICAL SUB BOUNDS+TOP(A0),D4 ;CONVERT TO GLOBAL COORDS MOVE HLOC(A6),D5 ;GET HORIZ COORD SUB BOUNDS+LEFT(A0),D5 ;CONVERT TO GLOBAL ; IS IT FROM THE SCREEN? MOVE.L MAINDEVICE,A2 ;GET MAIN DEVICE MOVE.L (A2),A2 ;POINT TO IT MOVE.L GDPMAP(A2),A2 ;GET PIXMAP HANDLE MOVE.L (A2),A2 ;POINT TO PIXMAP MOVE.L BASEADDR(A0),D1 ;GET PORT'S BASEADDR CMP.L BASEADDR(A2),D1 ;SAME AS SCREEN'S? seq.b -(sp) ;push crsrFlag @@@@ BAL 14Apr88 move.l a0,a3 ;save pixmap in a3 BNE.S NOTSCRN ;=>NO, NOT SCREEN ; IT IS FROM THE SCREEN! Shield the Cursor. @@@@ BAL 14Apr88 MOVE D5,-(SP) ;PUSH GLOBAL LEFT MOVE D4,-(SP) ;PUSH GLOBAL TOP MOVE D5,-(SP) ;PUSH GLOBAL RIGHT MOVE D4,-(SP) ;PUSH GLOBAL BOTTOM MOVE.L JShieldCursor,A1 ;get lo mem vector JSR (A1) ;and call it MOVE.L DEVICELIST,A3 ;GET FIRST IN DEVICE LIST DONXT MOVE.L (A3),A2 ;POINT TO DEVICE TST GDFLAGS(A2) ;IS DEVICE ACTIVE? BPL.S NXTDEV ;=>NO, NOT ACTIVE LEA GDRECT(A2),A1 ;POINT TO DEVICE'S RECT CMP (A1)+,D4 ;IS VERTICAL < GDRECT.TOP ? BLT.S NXTDEV ;=>YES, CHECK NEXT DEVICE CMP (A1)+,D5 ;IS HORIZONTAL < GDRECT.LEFT ? BLT.S NXTDEV ;=>YES, CHECK NEXT DEVICE CMP (A1)+,D4 ;IS VERTICAL >= GDRECT.BOTTOM ? BGE.S NXTDEV ;=>YES, CHECK NEXT DEVICE CMP (A1)+,D5 ;IS HORIZONTAL >= GDRECT.RIGHT ? BLT.S GOTDEV ;=>NO, FOUND DEVICE NXTDEV MOVE.L GDNEXTGD(A2),D0 ;GET HANDLE TO NEXT DEVICE MOVE.L D0,A3 ;KEEP IN A3 BNE.S DONXT ;=>THERE IS A DEVICE BRA DONE ;=>DEVICE NOT FOUND, JUST RETURN ; FOUND THE DEVICE! SET DEVICE AND OFFSET POINT TO DEVICE LOCAL COORDINATES GOTDEV MOVE.L A3,THEGDEVICE ;MAKE DEVICE CURRENT LEA GDRECT(A2),A1 ;POINT TO DEVICE'S RECT SUB (A1)+,D4 ;OFFSET VERTICAL SUB (A1)+,D5 ;OFFSET HORIZONTAL MOVE.L GDPMAP(A2),A3 ;GET PIXMAP HANDLE MOVE.L (A3),d0 ;POINT TO PIXMAP _rTranslate24To32 ;strip off high byte @@@@ BAL 14Apr88 move.l d0,a3 ;----------------------------------------------------------- ; ; Switch to 32 bit addressing mode ; Needs32BitMode move.b #$ff,(sp) ;flag the fact that MMU mode must be swapped moveq #true32b,d0 ;switch to 32 bit addressing move.w d2,-(sp) ;save color/ bw flag across call _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a2, d0/d2) move.w (sp)+,d2 ;restore flag in d2 ;save previous state in d0 for later bra.s MMUModeOK NOTSCRN ; ; Check if pixmap needs 32-bit addressing ; baseAddr32Bit EQU 2 tst.w rowbytes(a3) ; bpl.s MMUModeOK ;it's a bitmap btst #baseAddr32Bit,pmVersion+1(a3) ; bne.s Needs32BitMode ;pixmap needs 32-bit addressing MMUModeOK jmpROM ciMMUModeOK DONE jmpROM ciGetPixelDone ENDPROC PatchClosePictureCI patchProc _ClosePicture,(IIci) ciClosePictureEntry ROMBIND (IIci,$31D4C) ciClosePictureGoHome ROMBIND (IIci,$31D82) cinopp ROMBIND (IIci,$31D74) DPutPicOp ROMBIND (IIci,$32C90) ;------------------------------------------------------------------ ; ; PROCEDURE ClosePicture; ; MOVEM.L D6-D7/A3,-(SP) ;SAVE REGS MOVE.L GRAFGLOBALS(A5),A3 ;POINT TO QUICKDRAW GLOBALS MOVE.L THEPORT(A3),A3 ;GET CURRENT GRAFPORT MOVE.L PICSAVE(A3),D7 ;ARE WE SAVING A PICTURE ? BEQ.S GOHOME ;NO, OOPS, EXIT MOVE #opEndPic,D0 ;PUSH ENDPIC OPCODE jsrROM DPutPicOp ;PUT TO THEPIC MOVE.L D7,A0 ;GET PICSAVE HANDLE MOVE.L (A0),A0 ;POINT TO PICSAVE RECORD move.l picFontList(a0),a0 ;get fontList handle _DisposHandle MOVE.L D7,A0 ;GET HANDLE TO PICSAVE RECORD MOVE.L (A0),A0 ;DE-REFERENCE IT MOVE.L PICCLIPRGN(A0),D6 ;GET picClipRgn MOVE.L PICINDEX(A0),D0 ;DID PICTURE OVERFLOW ? BEQ.S OVERFLO ;YES, CONTINUE MOVE.L THEPIC(A0),A0 ;NO, GET THEPIC HANDLE _SetHandleSize ;AND TRIM TO FINAL SIZE OVERFLO MOVE.L D6,A0 ;GET PICCLIPRGN _DisposHandle ;DISCARD IT tst portBits+rowBytes(a3) ;is it in an old grafport? <20Sept90 KON> bpl.s nopp ;=>yes, skip new stuff <20Sept90 KON> jmpROM ciClosePictureEntry nopp jmpROM cinopp GOHOME jmpROM ciClosePictureGoHome ;AND RETURN ENDPROC ; ; End <15> ; endif ; <16> of TheFuture ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Patch to _OpenCPort to reset the horizontal pen fraction <5> PatchOpenCPort PatchProc _OpenCPort,(II,IIci) move.l grafGlobals(a5),a0 ; load QuickDraw globals. move.w #$8000,pnLocFixed(a0) ; reset pen fraction. jmpOld ; join the original code. ENDPROC ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Come-from patch on _OpenCPort inside NewGWorld <5> ; ; NewGWorld trashes the current port when it calls OpenCPort to create ; the offscreen port. This patch prevents the GWorld OpenCPort from changing the ; current port. AfterOpenCPortInNewGWorld ROMBIND (IIci,$3FE3E) NewGWorldOpenCPort ComeFromPatchProc _OpenCPort,AfterOpenCPortInNewGWorld,(IIci) move.l 4(sp),-(sp) ; get parameter to OpenCPort on stack move.l grafGlobals(a5),a0 ; get QD globals move.l thePort(a0),4+4(sp) ; save thePort jsrOld ; open the port move.l grafGlobals(a5),a0 ; get QD globals move.l 4(sp),thePort(a0) ; restore thePort rtd #4 ; deallocate thePort while returning ENDPROC ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; The following come-from patches are from QDciPatchROM.a for the IIci ROM ;———————————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Come-from patch on _PackBits inside PutPMData FromPutPMData ROMBIND (IIci,$3372C) FromPutPicPixPat ROMBIND (IIci,$33224) PutPMDataPackBits ComeFromPatchProc _PackBits,FromPutPMData,(IIci) ; ; clean up PixMap address if we came from PutPicPixPat <16Sept90 KON> ; cmpROM FromPutPicPixPat, 4(a6) ;and making a PixPat <2Oct90 KON> bne.s @1 move.l -4(a6),d0 _rTranslate24To32 ;fix up the high bytes <16Sept90 KON> move.l d0,-4(a6) ;srcptr in putPMData stackframe <16Sept90 KON> ; move.l d0,$a(a6) ;myData in putPMData stackframe <16Sept90 KON> @1 moveq #true32b,d0 ;switch to 32 bit addressing for source access _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) addq #4,sp ;strip extra return address jsrOld ;PACK ROW INTO PACKBUF moveq #false32b,d0 ;switch back before calling PutPicProc _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) jmpROM FromPutPmData ;return to PutPmData ENDPROC ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Patch _CopyBits to get base address of screen from ScrnBase instead of screenBits. AfterGetScreenBaseInCopyBits ROMBIND (IIci,$356DC) CopyBitsGetScreenBase PatchProc _CopyBits,(IIci) ; ; Here is the stack frame for CopyBits copied from ROM source ; PARAMSIZE EQU 22 ;TOTAL BYTES OF PARAMS SRCBITS EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP DSTBITS EQU SRCBITS-4 ;LONG, ADDR OF BITMAP SRCRECT EQU DSTBITS-4 ;LONG, ADDR OF RECT DSTRECT EQU SRCRECT-4 ;LONG, ADDR OF RECT MODE EQU DSTRECT-2 ;WORD MASKRGN EQU MODE-4 ;LONG, RGNHANDLE SRCRECT1 EQU -8 ;LOCAL SRC RECT DSTRECT1 EQU SRCRECT1-8 ;LOCAL DST RECT (MUST FOLLOW SRCRECT1) VARSIZE EQU DSTRECT1 ;SIZE OF LOCAL VARS ; ; Get base address of main screen from ScrnBase instead of Baseaddr ; LINK A6,#VARSIZE ;NO LOCAL VARS MOVEM.L d2/D6-D7/A2-A4,-(SP) ;SAVE REGS (save d2 for MS Works) <01Apr89 BAL> MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS MOVE.L THEPORT(A4),A3 ;POINT TO CURRENT GRAFPORT MOVE.L SRCBITS(A6),A0 ;POINT TO SRCBITS _BITSTOMAP ;GET POINTER TO BIT/PIXMAP IN A0 MOVE.L A0,A2 ;AND SAVE IN A2 ; MOVE.L SCREENBITS+BASEADDR(A4),D6 ;GET BASE ADDRESS OF SCREEN MOVE.L ScrnBase,D6 ;GET BASE ADDRESS OF main SCREEN jmpROM AfterGetScreenBaseInCopyBits ENDPROC ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Come-from patch on _CopyBits inside _CopyBits ; ; When doing CopyBits to an old port and the image is being flattened (as when ; printing a 32-bit bitmap to a laser-writer), set the dither mode if dither was ; requested when copybits was called. AfterCopyBitsCallsItselfToFlatten ROMBIND (IIci,$3586A) CopyBitsDitherWhileFlattening ComeFromPatchProc _CopyBits,AfterCopyBitsCallsItselfToFlatten,(IIci) ; ; Here is the stack frame for CopyBits copied from ROM source ; PARAMSIZE EQU 22 ;TOTAL BYTES OF PARAMS SRCBITS EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP DSTBITS EQU SRCBITS-4 ;LONG, ADDR OF BITMAP SRCRECT EQU DSTBITS-4 ;LONG, ADDR OF RECT DSTRECT EQU SRCRECT-4 ;LONG, ADDR OF RECT MODE EQU DSTRECT-2 ;WORD MASKRGN EQU MODE-4 ;LONG, RGNHANDLE SRCRECT1 EQU -8 ;LOCAL SRC RECT DSTRECT1 EQU SRCRECT1-8 ;LOCAL DST RECT (MUST FOLLOW SRCRECT1) VARSIZE EQU DSTRECT1 ;SIZE OF LOCAL VARS btst #6,mode+1(a6) ;is the ditherCopy bit set beqOld ;no, just pass through to ROM move.w #$40,8(sp) ;yes, use ditherCopy instead jmpOld ENDPROC ;———————————————————————————————————————————————————————————————————————————————————————————————————— ; Come-from patch on _GetMaxDevice inside NewGWorld and NewTempScreenBuffer to check for NIL devices. FromNewGWorld ROMBIND (IIci,$3FB88) FromNewTempScreenBuffer ROMBIND (IIci,$40D0E) newGWorldParamError ROMBIND (IIci,$3FEE6) newTempScreenBufferParamError ROMBIND (IIci,$40E88) GWorldGetMaxDevice ComeFromPatchProc _GetMaxDevice,,(IIci) cmpROM FromNewGWorld,(sp) ; from NewGWorld? beq.s @itsForMe ; yes cmpROM FromNewTempScreenBuffer,(sp) ; from NewTempScreenBuffer? bneOld ; no ; ; Call through, then check for NIL result ; @itsForMe move.l (sp),d0 ;get return address move.l 4(sp),(sp) ;move rect down move.l d0,8(sp) ;put old return address on top of old result jsrOld ;call original GetMaxDevice move.l (sp)+,d0 ;get handle to max device bnz.s @returnToCaller ;if it isn't NIL, we're ok cmpROM FromNewGWorld, (sp)+ ;was this from NewGWorld? (nuke return address also) bneROM newTempScreenBufferParamError ;if not, goto parameter error jmpROM newGWorldParamError @returnToCaller move.l d0,a0 addq.l #2,(sp) ;skip over the move.l (sp)+,a0 instruction rts ENDPROC ;———————————————————————————————————————————————————————————————————————————————————————————————————— ;========================================================================================= ;========================================================================================= ; ; Patch ClosePort and CloseCPort so that they jsr to the RAM version of DelPortList ; (which doesn't call Munger). ; ;========================================================================================= ;========================================================================================= ciClosePortEntry RomBind (IIci,$301E8) ciOpenPixMap ROMBind (IIci,$302D0) ciInitPixMap ROMBind (IIci,$30330) ROMs IIci PatchIIciCloseCPort MakePatch ciClosePortPatch,$AA02 PatchIIciClosePort MakePatch ciClosePortPatch,$A87D if TheFuture then ; <16> Patch only for future builds PatchIIciGetPixel MakePatch ciPatchGetPixel,$A865 PatchIIciCalcMask MakePatch ciPatchCalcMask,$A838 endif ; <16> ciClosePortPatch Proc Export Import DelPortList ;------------------------------------------------------------- ; ; PROCEDURE ClosePort(port: GrafPtr); ; ; Disposes of clipRgn and visRgn. ; ; If color grafPort, dispose of additional fields ; MOVE.L 4(SP),-(SP) ;PUSH GRAFPTR JSR DelPortList ;DELETE PORT FROM PORTLIST jmpROM ciClosePortEntry ENDPROC DelPortList PROC EXPORT ;---------------------------------------------------------- ; ; PROCEDURE DelPortList(grafPtr); ; ; Delete the specified grafPtr from the portList ; MOVE.L portList,A0 ;get the portList MOVE.L (A0),A0 ;point to it TST (A0) ;any elements? BEQ.S DONE ;=> no ; SUBQ #1,(A0) ;else decrement count ; ; Find the port and delete it from the list. NOTE: The item is assumed to be in the list. ; ; a0 points to the beginning of the list ; move.w (a0)+,d0 ;get length >= 1 subq #1,d0 ;get length >= 0 move.l 4(sp),d1 ;grafPtr to match @loop cmp.l (a0)+,d1 dbeq.w d0,@loop ;fall through if found ; ; found it: delete the item and shrink the handle by 4 bytes ; ; a0 points 4 bytes past the item to delete ; bne.s Done ;port was not found bra.s @MoveLoopEntry ;yes, move the others up @moveLoop move.l (a0),-4(a0) ;move the next item over this one addq.l #4,a0 @MoveLoopEntry dbra.w d0,@moveLoop @DoSetHandleSize move.l portList,a0 ;handle to portList move.l (a0),a1 ;point to it subq #1,(a1) ;decrement count to remove 1 item moveq #0,d0 move.w (a1),d0 ;get size lsl.w #2,d0 ;*4 addq.w #2,d0 _SetHandleSize ;set the new size ; ;size word in portlist was decremented above ; DONE MOVE.L (SP)+,(SP) ;strip param RTS ;and return ENDPROC ;========================================================================================= ;========================================================================================= ; ; Patch NewPixMap to always return 72 dpi pixmaps ; ;========================================================================================= ;========================================================================================= NewPixMap PatchProc _NewPixMap,(IIci) ;------------------------------------------------------------- ; ; FUNCTION NewPixMap : PixMapHandle; ; ; Create a new, initialized pixel map and return a handle to it ; CLR.L -(SP) ;make room for a handle jsrROM ciOpenPixMap ;open the pixMap MOVE.L (SP),8(SP) ;return result jsrROM ciInitPixMap ;initialize it move.l #$480000,hRes(a1) ;don't try this at home: a1 still points move.l hRes(a1),vRes(a1) ;to pixmap. Make resolution 72dpi if TheFuture then if ADDRMODEFLAG then ; <17> clr.w pmVersion(A1) ; assume 24 bit addressing <17> endif ; endif RTS ;and return ENDPROC ;========================================================================================= ;========================================================================================= ;= ;= Patch to BitMapRgn to allow 32-bit addressed pixmaps and to create ;= 64K regions. ;========================================================================================= ;========================================================================================= ;________________________________________________________________________________ ; ; FUNCTION BitMapRgn(region:RgnHandle; bMap:BitMap): OSErr; INLINE $A8D7; ; ; Given a region and bitmap, BitMapRgn makes the region a bounding ; region for the 'map. If it can't get memory it will return a ; Memory Manager-type error and an empty region gibbley. Note that ; the region might also be empty with no error (if the bounds is an ; empty rectangle or there are no 1 bits in the bitmap). Lastly, ; if the region would have to exceed 32K it returns a result of ; -500 (rgnTooBigErr). ; ; The bMap parameter may be a pointer to a bitmap, a pointer to a ; pixmap, or a pointer to a portBits field in a color grafport. ; In the latter two cases, if the pixmap is not 1-bit deep, an error ; result of -148 (pixmapTooDeepErr) is returned. ; ; (the nibble state machine idea is from the Finder MaskToRgn routine) ; ; History ; 2/19/88 RBB changed to take in washing and handle rect. & empties properly ; also now finds minimum rectangle to enclose region ; *** version of 2/22/88 *** ; 2/23/88 RBB putting in numerous optimizations recommended by Darin ; 4/4/88 RBB trying to re-do lost work from March ; DBA ; 3/28/89 CSD adjusted setup to know about pixmaps and portBits ; ;________________________________________________________________________________ ; ;Theory ; We scan each line of the bitmap and pump inversion points (ip's) into the region ; to put the areas with ones in the bitmap into the region and the areas ; with zeroes outside the region. ; ; In order to keep track of where we are in "inversion land" we use two ; techniques: ; The first is a scanline buffer which records the changes ; (zeroes to ones and vice versa) as we go. Wherever a change occurs (a ; 1 next to a 0 in the buffer) we need to put out an inversion point. ; The second is a togglin' flag which tells us whether we are "inverted" or not. ; Since we use a state machine in the innermost (nibble) loop to churn out ; ip's, the input to the state machine must be complemented if the flag is set. ; The loop stuff looks like this: ; outer line loop (grows handle in anticipation of worst case for next line) ; longword loop for current line (puts out inter-long ip's as needed) ; loop for 4 nibbles in current long (calls state maching for each nibble) ; ;________________________________________________________________________________ BitMapRgn PatchProc _BitMapRgn,(II,IIci) BMFrame RECORD {A6Link},DECR result DS.W 1 paramTop EQU * regionH DS.L 1 bMapPtr DS.L 1 paramSize EQU paramTop-* return DS.L 1 A6Link DS.L 1 rowLongs DS.L 1 ;number of longwords per line rightMask DS.L 1 ;mask for rightmost long of each line slHandle DS.L 1 ;handle to scanline buffer numLines DS.W 1 ;number of lines in bitmap rowNumBytes DS.W 1 ;rowbytes from the bitmap startSize DS.L 1 ;size of region at start of line lastLineH DS.L 1 ;last line (zeroes) handle handSize DS.L 1 ;size of handle (avoid calls to GetHandleSize) max2Add DS.L 1 ;worst case for bytes we could add for next line MMUSave ds.b 2 ;keep it even! SrcPixMap ds.b PMREC+CTREC+20 ;room for pixmap and color table localSize EQU * ENDR WITH BMFrame LINK A6,#localSize MOVEM.L A2-A5/D3-D7,-(SP) ;save work registers CLR.L slHandle(A6) ;no scanline handle, yet CLR.W result(A6) ;function result presumed zero at start MOVE.L regionH(A6),A0 MOVE.L (A0),A2 MOVEQ #0,D0 MOVE.W (A2),D0 ;get size of region MOVE.L D0,handSize(A6) ;save it long ; ; Convert bitmap/pixmap to a pixmap ; move.l bMapPtr(a6),a1 lea SrcPixMap(a6),a2 _BitsToPix ;get boundary rectangle so we can tell how to process the bitmap lea SrcPixMap(A6),A1 ;get bitmap pointer CMP.W #1, pmPixelSize(A1) ;is it 1 bit per pixel deep? BEQ.S @1 ;if yes, we're fine MOVE.W #pixmapTooDeepErr, D0 ;return an error otherwise BRA BMRBadEmpty ;clean up and bail out @1 MOVE.W rowBytes(A1), rowNumBytes(A6) ;get the rowbytes from the bit/pixmap ANDI.W #$7FFF, rowNumBytes(A6) ;mask off pixmap flag MOVE.L bounds+topLeft(A1),D2 ;get topLeft MOVE.W bounds+right(A1),D0 ;get right ;figure the number of longs per row (according to width, not rowbytes) ;so we can get a scanline buffer SUB.W D2,D0 ;right - left BLE BMREmptyOut ;if empty rect. then empty region EXT.L D0 MOVE.L D0,D4 ADD.L D4,D4 ;double width for 2 bytes/ip ADDQ.L #4+2,D4 ;add 4 bytes for y value and $7FFF word ;add 2 more for the $7FFF if the last line ADD.L D4,D4 ;double, just 'cause I feel like it! MOVE.L D4,max2Add(A6) ;save max. bytes for a given line MOVEQ #32,D7 ;(side effect: clear high word of D7) DIVU D7,D0 ;number of longs = width/32 ;get a mask for the rightmost long into rightMask MOVE.L D0,D3 ;save remainder(hi word) SWAP D3 ;get remainder from width/32 MOVEQ #-1,D1 ;default rightmost long mask TST.W D3 ;zero remainder? BEQ.S @0 ;yes, $FFFF is a good mask ADDQ.W #1,D0 ;we need one more long SUB.W D3,D7 ;32 - remainder = zero bits to shift in ASL.L D7,D1 ;get proper mask @0 MOVE.L D1,rightMask(A6) EXT.L D0 MOVE.L D0,rowLongs(A6) ;save # of longs ASL.L #2,D0 ;longs => bytes ;get the scanline buffer (D0 = number of bytes per line) _NewHandle clear ;get a scanline buffer (of zeroes) BNE BMRBadEmpty ;if we failed then return a NIL handle MOVE.L A0,slHandle(A6) ;save buffer handle ;figure the number of lines MOVE.L D2,D3 SWAP D3 ;get top MOVE.W bounds+bottom(A1),D0 ;get bottom SUB.W D3,D0 ;bottom - top BLE BMREmptyOut ;if empty rect. then empty region MOVE.W D0,numLines(A6) ;number of lines MOVE.L baseAddr(A1),a4 ;point to start of map MOVE.W #rgnData,D7 ;initial region size ;OK, now we start the loops. ; A1 will point to the bitmap long, ; A2 to the region. ; A3 points to the current scanline buffer long. ; A4 will point to the row in the map. ; A5 points to the current word (= size + A2) ; D1 holds the current long (modified). ; D2 holds the leftmost coordinate of bitmap.bounds. ; D3 has the y coordinate, and ; D4 the x coordinate (high word stays clear!). ; D5 has number of longs remaining for current line. ; D6 holds the (on or off) value of the "beam" (for the line). ; D7 holds the size outside the longword loop (used as scratch while nibbling). ; (we assume at the very end that D7's high word has remained clear) ; ; goto 32-bit mode ; moveq #true32b,d0 ;switch to 32 bit addressing _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) move.b d0,MMUsave(a6) ;save previous state for later BMRHScramLine MOVE.L regionH(A6),A2 MOVE.L (A2),d0 _StripAddress ;clean it up <14> move.l d0,a2 ;point to start of region BMRLineLoop LEA (A2,D7.L),A5 ;point to new region start + size MOVE.L handSize(A6),D1 ;get handle size SUB.l D7,D1 ;handle size - region size CMP.L max2Add(A6),D1 ;is there enough for worst case on next line? BGE.S @1 ;skippy if so MOVE.L handSize(A6),D0 ;get handle size ADD.L max2Add(A6),D0 ;add more than enough for worst case on next line MOVE.L D0,handSize(A6) ;save new size ; ; go back to previous mode ; move.b MMUsave(a6),d0 ;get previous MMU state in d0 _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) MOVE.L handSize(A6),d0 ;save new size MOVE.L regionH(A6),A0 ;region handle _SetHandleSize BNE BMRBadEmpty ;if we failed then return a NIL handle ; ; goto 32-bit mode ; moveq #true32b,d0 ;switch to 32 bit addressing _rSwapMMUMode BRA.S BMRHScramLine ;rederef. handle and recompute current pointer @1 MOVE.W D2,D4 ;get current x coordinate from left MOVEQ #0,D6 ;beam initially off MOVE.L A4,A1 ;start of current line into map pointer MOVE.L rowLongs(A6),D5 ;longs remaining for current line MOVE.L slHandle(A6),A3 ;A3 points to the current "differences" long MOVE.L (A3),A3 ; Note: within this loop we assume that nothing will be done to move the heap MOVE.W D3,D0 ;get y position BSR OutputRgnWord ;output y pos to region MOVE.l D7,startSize(A6) ;save size at line start (a la Derwood) BRA NextBMRLong ;enter the long loop BMRLongLoop MOVE.L (A1)+,D0 ;fetch the next long for this line BMRLastLEntry MOVE.L (A3),D1 ;get differences long EOR.L D0,D1 ;compute the differences BNE BMRDiff ;if not the same, skip ahead BMRSame ;since we want to skip this long (it matches the previous line) we need to ;put out an ip if the beam is on TST.B D6 ;beam on? BEQ.S @1 ;skip if not MOVE.W D4,(A5)+ ;pump it out MOVEQ #0,D6 ;beam off @1 ADD.W #32,D4 ;slip to next long's x coordinate @2 ADDQ.W #4,A3 ;to next changes buffer long BRA NextBMRLong ;---------------------------------------------------------------------------------------- ; Start of State Machine ; Handle state 0001 BMRState1 ADDQ.W #3,D4 ;bump x by 3 State1Common MOVE.W D4,(A5)+ ;generate one ;Tog1StateDone ADDQ.W #1,D4 ;bump x by one more TogStateDone NOT.B D6 ;toggle state RTS ; Handle state 0010 BMRState2 ADDQ.W #2,D4 ;bump x by 2 MOVE.W D4,(A5)+ ;generate one Gen1BumpBy1 BSR.S Gen1InvPoint ;and another one BumpBy1 ADDQ.W #1,D4 ;bump once more RTS ;state doesn't change ; Handle state 0011 BMRState3 ADDQ.W #2,D4 ;bump x by 2 MOVE.W D4,(A5)+ ;generate one ADDQ.W #2,D4 ;bump BRA.S TogStateDone ;toggle the state ; Handle state 0100 BMRState4 BSR.S Gen1InvPoint BSR.S Gen1InvPoint BumpBy2 ADDQ.W #2,D4 RTS ; Handle state 0101 BMRState5 BSR.S BMRState4 ;start out as state 4 SUBQ #1,D4 BRA.S State1Common ;use common code ; Handle state 0110 BMRState6 BSR.S Gen1InvPoint ADDQ.W #1,D4 BRA.S Gen1BumpBy1 ; Handle state 0111 BMRState7 BSR.S Gen1InvPoint ADDQ.W #3,D4 BRA.S TogStateDone ; Gen1InvPoint bumps x by one and then generates a horizontal inversion point Gen1InvPoint ADDQ.W #1,D4 ;bump by 1, first MOVE.W D4,(A5)+ ;add x value (ip) to region RTS ; Handle State 1000 BMRState8 MOVE.W D4,(A5)+ BSR.S Gen1InvPoint ADDQ.W #3,D4 RTS ; Handle State 1001 BMRState9 MOVE.W D4,(A5)+ BSR.S Gen1InvPoint ADDQ.W #2,D4 BRA.S State1Common ; Handle State 1010 (most complicated case) BMRState10 MOVE.W D4,(A5)+ BSR.S Gen1InvPoint BSR.S Gen1InvPoint BRA.S Gen1BumpBy1 ; Handle State 1011 BMRState11 MOVE.W D4,(A5)+ BSR.S Gen1InvPoint BSR.S Gen1InvPoint ADDQ.W #2,D4 BRA.S TogStateDone ; Handle State 1100 BMRState12 MOVE.W D4,(A5)+ ADDQ.W #2,D4 MOVE.W D4,(A5)+ BRA.S BumpBy2 ; Handle State 1101 BMRState13 BSR.S BMRState12 SUBQ #1,D4 BRA.S State1Common ; Handle State 1110 BMRState14 MOVE.W D4,(A5)+ ADDQ.W #3,D4 MOVE.W D4,(A5)+ BRA.S BumpBy1 ; State table BMRHandler BRA.S BMRState0 BRA.S BMRState1 BRA.S BMRState2 BRA.S BMRState3 BRA.S BMRState4 BRA.S BMRState5 BRA.S BMRState6 BRA.S BMRState7 BRA.S BMRState8 BRA.S BMRState9 BRA.S BMRState10 BRA.S BMRState11 BRA.S BMRState12 BRA.S BMRState13 BRA.S BMRState14 ; Handle State 15 or 1111 BMRState15 MOVE.W D4,(A5)+ ;generate one now NOT.B D6 ;toggle the state ; Handle State 0 or 0000 BMRState0 ADDQ.W #4,D4 RTS ; End of the State Guys ;---------------------------------------------------------------------------------------- BMRDiff MOVE.L D0,(A3)+ ;fix up scanline buffer for next time ; this long is different from the last one, so output a bunch ; of inversion points by pumping it through the state machine, a nibble ; at a time. MOVEQ #3,D7 ;4 bytes to process (D7 high word clear) MOVEQ #0,D0 ;prevent need to mask for first nibble ; here is the loop where we feed it through a nibble at a time. ; it's worth it to special case a whole byte of 0 BMRByteLoop ROL.L #8,D1 ;get next (topmost) byte TST.B D1 ;is it zero? BNE.S BMRNibble ;if not, 4 bits at a time TST.B D6 BNE.S BMRNibble ;if beam on, must pass through ;the top 8 are zero, so we can save some time ADDQ.W #8,D4 ;bump x BRA.S BMRNextByte ;take care of the rightmost long for a line BMRLastLong MOVE.L (A1),D0 ;fetch the long from the bitmap AND.L rightMask(A6),D0 ;mask off right bits that aren't in map BRA BMRLastLEntry ;go process this long ; handle the first nibble BMRNibble MOVE.B D1,D0 ;get byte EOR.B D6,D0 ;invert nibble when beam is on LSR.B #4,D0 ;get 1st nibble ADD.W D0,D0 ;double for word index JSR BMRHandler(D0.W) ;invoke the handler ; handle the second nibble MOVE.B D1,D0 ;get byte again EOR.B D6,D0 ;invert nibble when beam is on AND.W #%1111,D0 ;mask to it ADD.W D0,D0 ;double for word index JSR BMRHandler(D0.W) ;invoke the handler BMRNextByte DBRA D7,BMRByteLoop ;loop for all 8 nibbles ; bump to the next long NextBMRLong SUBQ.W #1,D5 ;decrement longword index BGT BMRLongLoop ;not at end, loop for whole line BEQ.S BMRLastLong ;process last long for this line ; we've reached the end of the (this) line BMREOL MOVE.l A5,D7 ;current region pointer SUB.l A2,D7 ;figga region size CMP.l startSize(A6),D7 ;did we add inv. pts to this line? BEQ.S BMRNoLine ;br = no, so back up BLT BMR64KErr ;if the size decreased, we overflowed ; if the state is on, generate one last inversion point TST.B D6 BEQ.S @1 MOVE.W D4,(A5)+ ;generate a last one ADDQ.l #2,D7 ;keep sizable advantage @1 ; end the scan line with the traditional $7FFF BSR.S OutputLastRgnWord BMREOL2 ADDQ.W #1,D3 ;bump y position MOVE.W D2,D4 ;start x at left again ADD.W rowNumBytes(A6),A4 ;bump to next row in map SUBQ.W #1,numLines(A6) BGT BMRLineLoop ;if we're not done then do next line BLT.S BMRFinis ;br if really done ; as the last line process an imaginary line of zeroes to end the region… move.b MMUsave(a6),d0 ;get previous MMU state in d0 <14> _rSwapMMUMode ;(can trash a0/a1/a2, d0/d1/d2) <14> MOVE.L rowLongs(A6),D0 ASL.L #2,D0 ;longs => bytes _NewHandle clear ;get a full line of zero bits BNE BMRBadEmpty ;if we failed then return a NIL handle MOVE.L A0,lastLineH(A6) ;save handle MOVE.L (A0),A4 ;start of current line ; ; Since we just allocated this handle, there is no need to strip it since the flags are guaranteed ; to be zero. ; moveq #true32b,d0 ;switch to 32 bit addressing <14> _rSwapMMUMode ; <14> BRA BMRHScramLine ;do this last one (and rederef handle) BMRNoLine SUBQ.L #2,A5 ;back up pointer SUBQ.l #2,D7 ;back down size BRA.S BMREOL2 ;go for next line ; Append the "end of line" token to the region OutputLastRgnWord MOVE.W #$7FFF,D0 ; OutputRgnWord takes the word in D0, appends it to the region, ; and leaves the condition codes set for ADDQ.l D7 (which contains the length) OutputRgnWord MOVE.W D0,(A5)+ ;put a word to the region ADDQ.l #2,D7 ;ink the size RTS ; all done: Restore MMU Mode, clean up, and output the final $7FFF ; BMRFinis move.b MMUsave(a6),d0 ;get previous MMU state in d0 _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) MOVE.L lastLineH(A6),A0 _DisposHandle ;get rid of that last line of zeroes CMP.l #10,D7 ;is region empty of inversion points? BEQ.S BMREmptyOut ;skip if so (it's an empty region) BSR.S OutputLastRgnWord ;put End-O-Region ($7FFF) word ; ; check if rgn > 64K ; cmp.l #$0000FFFF,d7 BGT.S BMR64KErr ;if larger than $FFFF, we overflowed! ; find the smallest rectangle that encompasses all the inversion points ; A0 will point to the current region word, A1 to the start of the line ; D1 will have the smallest x, D2 the largest x, D4 will contain $7FFF ; D3 gets the smallest y value (which we know at the start) LEA rgnData(A2),A0 ;point A0 past the rgnBBox MOVE.W #$7FFF,D4 MOVE.W D4,D1 ;smallest x so far = $7FFF MOVE.W #$8000,D2 ;largest x so far = -32768 MOVE.W (A0),D3 ;smallest y there is BRA.S BMRPackStart ;enter loop BMRPackY MOVE.L A0,A1 ;remember where the y value is (sort of) CMP.W (A0)+,D1 ;less than smallest x so far? BLE.S @1 ;skip if not MOVE.W -2(A0),D1 ;new smallest x @1 CMP.W (A0)+,D4 ;end of line? BNE.S @1 ;if not then keep looking CMP.W -4(A0),D2 ;last x greater than largest x so far? BGE.S BMRPackStart ;skip if not MOVE.W -4(A0),D2 ;new largest x BMRPackStart MOVE.W (A0)+,D0 ;get next word (y value or $7FFF) CMP.W D4,D0 ;if $7FFF then we're done BNE.S BMRPackY ;otherwise loop SWAP D3 ;top into top word MOVE.W D1,D3 ;left into bottom word MOVE.W -2(A1),D4 ;bottom (from last y at start of line) SWAP D4 ;move bottom to high word MOVE.W D2,D4 ;get right CMP.l #28,D7 ;size = 28? (do we have a rect. region?) BEQ.S BMRRect ;skip if so BRA.S BMROut ;return complex region ;the region would exceed 64K, so we have to error out, man BMR64KErr move.b MMUsave(a6),d0 ;get previous MMU state in d0 _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) MOVE.W #rgnTooBigErr,D0 ;if >32K needed return error ;we come here after failing a SetHandleSize (or NewHandle) BMRBadEmpty MOVE.W D0,result(A6) ;OSErr function result ; emptify the region on errors (or when it should be empty with no error) BMREmptyOut MOVE.L regionH(A6),A0 ;handle to region MOVE.L (A0),A2 ;point to it CLR.L D3 ;(0, 0) to topLeft CLR.L D4 ;(0, 0) to botRight BMRRect MOVEQ #10,D7 ;the size of the region = 10 ;output the region with size (longword, high word clear) in D7 ;D3 comes in with topLeft, D4 with botRight BMROut MOVE.W D7,(A2)+ ;the size of the region MOVE.L D3,(A2)+ ;topLeft to rgnBBox MOVE.L D4,(A2) ;botRight to rgnBBox MOVE.L D7,D0 ;size MOVE.L regionH(A6),A0 ;handle to region _SetHandleSize BMRDspSL MOVE.L slHandle(A6),A0 _DisposHandle ;get rid of the scanline buffer (even if NIL) BMRDone MOVEM.L (SP)+,A2-A5/D3-D7 ;restore work registers UNLK A6 MOVE.L (SP)+,A0 ;pop return address ADD #paramSize,SP ;pop params JMP (A0) ENDWITH ENDPROC ;========================================================================================= ;========================================================================================= ; ; Patch to bSetup0 on 040 machines with VM off to use Move16's to speed up scrolling ; radically. Moved from QDIIciPatchROM.a ; ;========================================================================================= ;========================================================================================= installPatchBSetup0 InstallProc (IIci,hasTERROR) IMPORT bSETUP0 INCLUDE 'GestaltEqu.a' ;call gestalt to see if we have an 040 or greater. If not, bail move.l #gestaltProcessorType,d0 _Gestalt tst.w d0 ;did gestalt return an error? bne.s @skipme ;if so, bail moveq.l #gestalt68040,d0 ;get the 040 flag cmp.l a0,d0 ;compare result to 040 flag bgt.s @skipme ;if less than 040, bail ;call gestalt to see if VM is on. If so, bail move.l #gestaltVMAttr,d0 _Gestalt tst.w d0 ;did gestalt return an error? bne.s @skipme ;if so, bail move.l a0,d0 ;get the result btst #gestaltVMPresent,d0 ;check the VM on bit bne.s @skipme ;if on, quit ;we're ok, so install the patch leaResident bSETUP0,a0 move.w #$AB58,d0 _SetTrapAddress ,NewTool @skipme rts ENDPROC ;------------------------------------------------------------ ; ; All new fast scrolling routine that takes advantage of the ; MOVE16 instruction on the 68040 when possible. ; Added NOP's to appropriate places to make Move16's work. ; ;------------------------------------------------------- ; a0 = JUMPA d0 = SCRATCH ; a1 = JUMPB d1 = ,SCRATCH ; a2 = JUMPC d2 = LEFTLONGS,SCRATCH ; a3 = JUMPD d3 = RIGHTLONGS,QUADBLOCKS ; a4 = d4 = ; a5 = d5 = ; a6 = locals d6 = SRCWID ; a7 = sp d7 = DSTWID ;------------------------------------------------------- bSETUP0 PROC EXPORT SRCBUMP EQU -606 HEIGHT EQU -608 OFFSET EQU 38 MOVE SRCBUMP(A6),D6 ;get srcwid into a register MOVE A3,D7 ;put dstwid into a more useful register MOVEQ #$F,D1 ;get useful mask ADDQ #1,D2 ;make longs width one based CMP #8,D2 ;are at least 8 longs being moved? BLT.S @normal ;no, use normal case MOVE D2,D3 ;are srcwid and dstwid both quadlong multiples? LSL #2,D3 ; ((srcwid + (longs*4)) | (dstwid + (longs*4))) & 0x000F == 0) MOVE D6,D0 ADD D3,D0 ADD D7,D3 OR D0,D3 AND D1,D3 BNE.S @normal ;no, use normal case MOVE.L A4,D3 ;do srcptr and dstptr have same quadlong phase? SUB.L A5,D3 ; (srcptr - dstptr) & 0x000F == 0) AND D1,D3 BEQ.S @fast ;yes, use fast case @normal MOVE D2,D3 ;count = longs MOVEQ #0,D0 ADDQ.L #1,D4 ;count += (leftmask++ == -1) ADDX D0,D3 ADDQ.L #1,D5 ;count += (rightmask++ == -1) ADDX D0,D3 MOVE.L D5,D0 ;JUMPD = &@right + (rightmask ? (@right - @rmask) : 0) BEQ.S @0 MOVEQ #-OFFSET,D0 @0: LEA (@right,D0.W),A3 MOVE.L A3,A1 ;JUMPB = JUMPD SUBQ #3,D3 ;if ((count -= 3) < 0) BMI.S @5 ; goto @5 AND D3,D1 ;JUMPB = &@mv4 - (count % 16) * 2 NEG D1 LEA (@mv4,D1.W*2),A1 LSR #4,D3 ;count /= 16; BRA.S @5 @fast MOVEQ #-1,D0 MOVE.W A4,D3 ;leftlongs = (-srcptr % 16) / 4 NEG D3 AND.W D3,D1 LSR.W #2,D1 SUB D1,D2 ;longs -= leftlongs ADDQ.L #1,D4 ;leftlongs -= (leftmask++ != -1) ADDX D0,D1 BGE.S @1 ;if (leftlongs < 0) MOVEQ #3,D1 ; leftlongs = 3 SUBQ #4,D2 ; longs -= 4 @1: MOVEQ #3,D3 ;rightlongs = longs & 0x03 AND D2,D3 SUB D3,D2 ;longs -= rightlongs ADDQ.L #1,D5 ;rightlongs -= (rightmask++ != -1) ADDX D0,D3 BGE.S @2 ;if (rightlongs < 0) MOVEQ #3,D3 ; rightlongs = 3 SUBQ #4,D2 ; longs -= 4 @2: NEG D3 ;JUMPD = &@right + (-rightlongs * 2) LEA (@right,D3.W*2),A3 TST.L D5 ;if (rightmask - 1 != -1) BEQ.S @3 SUB #OFFSET,A3 ; JUMPD -= @right - @rmask; @3: MOVE.L A3,A2 ;JUMPC = JUMPD LSR #2,D2 ;longs /= 4 BEQ.S @4 ;if (longs) SUBQ #1,D2 ; longs-- MOVE D2,D3 ; quadblocks = longs / 8 LSR #3,D3 AND #$07,D2 ; JUMPC = &@mv16 + (-(longs & 0x7) * 4) NEG D2 LEA (@mv16,D2.W*4),A2 @4: MOVE.L A2,A1 ;JUMPB = JUMPC MOVE D1,D2 ;if (leftlongs != 0) BEQ.S @5 NEG D2 ; JUMPB = &@left - (leftlongs * 2) LEA (@left,D2.W*2),A1 @5: MOVE.L A1,A0 ;JUMPA = JUMPB TST.L D4 ;if (leftmask - 1 != -1) BEQ.S @6 LEA @lmask,A0 ; JUMPA = &@lmask @6: SUBQ.L #1,D4 ;++leftmask SUBQ.L #1,D5 ;++rightmask MOVE.L HEIGHT(A6),D1 ;(put height into high word) MOVE D3,D1 ;(set up initial quadblocks count) nop ;finish any write in pipeline (may not need this one) JMP (A0) MACRO ;*** REMOVE WHEN ASSEMBLER KNOWS ABOUT MOVE16 myMOVE16 ;*** REMOVE WHEN ASSEMBLER KNOWS ABOUT MOVE16 DC.L $F624D000 ;*** REMOVE WHEN ASSEMBLER KNOWS ABOUT MOVE16 ENDM ;*** REMOVE WHEN ASSEMBLER KNOWS ABOUT MOVE16 ALIGN Alignment @lmask MOVE.L (A4)+,D0 ;get long of src MOVE.L (A5),D2 ;get long of dst EOR.L D2,D0 ; AND.L D4,D0 ;splice src and dst together through leftmask EOR.L D2,D0 ; MOVE.L D0,(A5)+ ;save result to dst nop ;finish any write in pipeline JMP (A1) ;go copy partial or full quadlong blocks MOVE.L (A4)+,(A5)+ ;copy partial left quadlong block MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ @left nop ;finish any write in pipeline JMP (A2) ;go copy quadlong blocks @mv256 myMOVE16 ;MOVE16 (A4)+,(A5)+ ;copy 32 longs myMOVE16 ;MOVE16 (A4)+,(A5)+ myMOVE16 ;MOVE16 (A4)+,(A5)+ myMOVE16 ;MOVE16 (A4)+,(A5)+ myMOVE16 ;MOVE16 (A4)+,(A5)+ ;copy 16 longs myMOVE16 ;MOVE16 (A4)+,(A5)+ myMOVE16 ;MOVE16 (A4)+,(A5)+ @mv16 myMOVE16 ;MOVE16 (A4)+,(A5)+ ;copy 4 longs DBRA D1,@mv256 ;dec counter and go do another 32 longs JMP (A3) ;go finish right edge of scanline @mv64 MOVE.L (A4)+,(A5)+ ;copy 16 longs MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ ;copy 8 longs MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ @mv4 MOVE.L (A4)+,(A5)+ ;copy 1 long DBRA D1,@mv64 ;dec count and go do another 16 longs JMP (A3) ;go finish right edge of scanline MOVE.L (A4)+,(A5)+ ;copy partial right quadlong block MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ @rmask MOVE.L (A4)+,D0 ;get long of src MOVE.L (A5),D2 ;get long of dst EOR.L D2,D0 AND.L D5,D0 ;splice src and dst together through rightmask EOR.L D2,D0 MOVE.L D0,(A5)+ ;save result to dst ADD D6,A4 ;bump srcptr by (srcbump - (longcnt * 4)) ADD D7,A5 ;bump dstptr by (dstbump - (longcnt * 4)) MOVE D3,D1 ;restore quadblock count SWAP D1 ;swap linecount into low word SUBQ #1,D1 ;decrement linecount BEQ GoHome ;leave if zero SWAP D1 ;swap linecount out of low word nop ;finish any write in pipeline JMP (A0) ;go do another line MOVE.L (A4)+,(A5)+ ;copy partial right quadlong block MOVE.L (A4)+,(A5)+ MOVE.L (A4)+,(A5)+ @right ADD D6,A4 ;bump srcptr by (srcbump - (longcnt * 4)) ADD D7,A5 ;bump dstptr by (dstbump - (longcnt * 4)) MOVE D3,D1 ;restore quadblock count SWAP D1 ;swap linecount into low word SUBQ #1,D1 ;decrement linecount BEQ.S GoHome ;leave if zero SWAP D1 ;swap linecount out of low word nop ;finish any write in pipeline JMP (A0) ;go do another line IF @right - @rmask - OFFSET THEN AERROR '••• Offset assumption is bad •••' ENDIF GOHOME RTS ;THEN QUIT ENDPROC ;========================================================================================= ;========================================================================================= ; ; Patch to bring in new indexed to 16 bit scaleblt routine. <5JUNE92 SAH> ; ;========================================================================================= ;========================================================================================= scIndTab16 PatchProc $ABB0,(IIci) &CurFile SETC 'STRETCH' INCLUDE 'DrawingVars.a' DC.L scIndexedto16-scIndTab16 ;0 1 to 16 DC.L scIndexedto16-scIndTab16 ;1 2 to 16 DC.L scIndexedto16-scIndTab16 ;2 4 to 16 DC.L scIndexedto16-scIndTab16 ;3 8 to 16 runMaskBit equ 30 ;bit number for run MASK instruction ;------------------------------------------------------- ; ; ; scale and clip indexed source to 16-bit dst ; ; put in special case for 1->16 using Sean Callahan's ; code from 1->32 ; ;------------------------------------------------------- ; a0 = tmpsrc d0 = vert/scratch ; a1 = tmpmask d1 = scanCount ; a2 = tmpdst d2 = scratch ; a3 = scaleTbl d3 = run cnt ; a4 = srcPtr/patPtr d4 = src pixel size ; a5 = dstPtr d5 = scratch ; a6 = locals d6 = bit offset in src ; a7 = d7 = src shift ;------------------------------------------------------- scNonBWto16 move srcShift(a6),d7 ;set this up once move.l scaleTbl(a6),a3 ;set this up once lea first16,a0 ;go here from now on move.l A3,scaleBltA3(a6) ;save for reload after seekMask move.l a0,ScaleCase(a6) ;remember for later bra.s first16 ;go to it nxtScan16 add.l dstRow(a6),a5 ;BUMP DST TO NEXT ROW add.l srcRow(a6),a4 ;BUMP src TO NEXT ROW addq.w #1,vert(a6) ;BUMP DOWN A SCAN LINE subq #1,d1 ble NXTMASK16 first16 move.l dstAlign(a6),d2 ;get initial dst offset asr.l #4,d2 ;convert it to pixels asl.l d7,d2 ;and convert it to src bits move.l srcAlign(a6),d6 ;start with initial src offset move.l a4,a0 ;init tmp src ptr ;now make sure the source is long aligned move.w a0,d5 and.w #3,d5 ;get the non-long address beq.s @srcAligned ;branch if aligned sub.w d5,a0 ;align the source lsl.w #3,d5 ;turn it into a bit offset add.w d5,d6 ;add it to the src index @srcAligned add.w d2,d6 ;back up the number of dst pixels bge.s @srcOK ;make sure we didn't go negative add.w #$20,d6 ;figure out where to start in the new src long subq.l #4,a0 ;back up the src @srcOK cmp.w #$1f,d6 ;make sure we didn't overshoot this long ble.s @srcAligned2 addq.l #4,a0 ;bump src ptr to next long and.w #$1f,d6 ;and find where we are inside it @srcAligned2 move.l a5,a2 ;init tmp dst ptr move.l runBuf(a6),a1 ;point to run encoded mask buffer inst16 move.l (a1)+,d3 ;pick up next instruction long bmi.s nxtScan16 ;if high bit set then done with scan add.w d3,a2 ;bump destptr by skip amount lsr.w #1,d3 ;make byte skip into pixel skip lsl.w d7,d3 ;make into bit skip add.w d3,d6 ;bump src offset move d6,d3 ;make a copy lsr.w #5,d3 ;make into long cnt lea (a0,d3.w*4),a0 ;bump src ptr swap d3 ;get mask/blit cnt and check done flag BCLR #runMaskBit-16,D3 ;check and clear mask flag BNE MASKRUN16 @blit MOVE.L (A0)+,D5 ;GET FIRST LONG OF SRC @NXPXL BFEXTU D5{D6:D4},D0 ;GET A PIXEL OF SRC ADD D4,D6 ;ADVANCE TO NEXT SRC PIXEL MOVE.L 0(A3,D0*4),D2 ;TRANSLATE IT and.w #$1f,D6 ;TIME FOR NEXT SRC LONG? bne.s @srcOK MOVE.L (A0)+,D5 ;GET NEXT LONG OF SRC @srcOK SWAP D2 ;MOVE LAST PIXEL INTO HIGH WORD BFEXTU D5{D6:D4},D0 ;GET A PIXEL OF SRC MOVE.W 2(A3,D0*4),D2 ;TRANSLATE IT ADD D4,D6 ;ADVANCE TO NEXT SRC PIXEL ext.l d6 ;bfext uses all of it MOVE.L D2,(A2)+ ;WRITE OUT LONG TO DST AND #$1f,D6 ;TIME FOR NEXT SRC LONG? DBEQ D3,@NXPXL ;LOOP ALL PIXELS THIS LONG DBNE D3,@blit ;LOOP ALL PIXELS THIS RUN beq.s inst16 ;LOOP BACK FOR more runs subq.w #4,a0 ;point back to remaining pixels BRA.s inst16 ;LOOP BACK FOR more runs NXTMASK16 move.w MinRect+bottom(a6),d2 ;get bottom vertical position sub.w vert(a6),d2 ;compute scans remaining, prime d2 ble Done move d2,d3 ;save scans remaining JSR ([SEEKMASK,A6]) ;MAKE MASK BUFFER CURRENT move.w d2,d1 ;get scan count in d1 cmp.w d3,d1 ;scan count > scans remaining? ble.s @go ;no, call the blit loop move.w d3,d1 ;yes, pin to scans remaining @go JSR ([RUNRTN,A6]) ;MAKE RUN BUFFER CURRENT move.l scaleBltA3(a6),A3 ;reload A3 for scan loops MOVE.L ScaleCase(A6),A2 ;GET MODE CASE JUMP JMP (A2) ;TAKE MODE JUMP MASKRUN16 @BLIT MOVE.L (A0)+,D5 ;GET FIRST LONG OF SRC @NXPXL2 BFEXTU D5{D6:D4},D0 ;GET A PIXEL OF SRC ADD D4,D6 ;ADVANCE TO NEXT SRC PIXEL MOVE.l 0(A3,D0*4),D2 ;TRANSLATE IT AND #$1f,D6 ;TIME FOR NEXT SRC LONG? BNE.S @srcOK MOVE.L (A0)+,D5 ;GET NEXT LONG OF SRC @srcOK SWAP D2 ;MOVE LAST PIXEL INTO HIGH WORD BFEXTU D5{D6:D4},D0 ;GET A PIXEL OF SRC ADD D4,D6 ;ADVANCE TO NEXT SRC PIXEL MOVE.W 2(A3,D0*4),D2 ;TRANSLATE IT MOVE.L (A2),D0 ;GET LONG OF DST EOR.L D0,D2 AND.L (A1)+,D2 EOR.L D0,D2 MOVE.L D2,(A2)+ AND #$1f,D6 ;TIME FOR NEXT SRC LONG? DBEQ D3,@NXPXL2 ;LOOP ALL PIXELS THIS LONG DBNE D3,@blit ;LOOP ALL PIXELS THIS RUN beq.s inst16 ;LOOP BACK FOR more runs subq.w #4,a0 ;point back to remaining pixels BRA.s inst16 ;LOOP BACK FOR more runs scIndexedto16 MOVE.L scaleTbl(A6),A3 ;set this up once CMP.W #1,D4 ;is src one bit? BNE.S scNonBWto16 TST.L 4(A3) ;is second color black? BNE.S scNonBWto16 MOVE.L #$7FFF,D0 CMP.L (A3),D0 ;is first color white? BNE.S scNonBWto16 MOVE.W D0,D4 ;move white mask to better register SWAP D4 MOVE.W D0,D4 LEA @first,A0 ;go here from now on MOVE.L A0,ScaleCase(A6) ;remember for later BRA.S @first ;go to it @next ADD.L dstRow(A6),A5 ;BUMP DST TO NEXT ROW ADD.L srcRow(A6),A4 ;BUMP src TO NEXT ROW ADDQ.W #1,vert(A6) ;BUMP DOWN A SCAN LINE SUBQ #1,D1 BLE.S NXTMASK16 @first MOVE.L dstAlign(a6),D6 ;get dest alignment ASR.L #4,D6 ;and convert to dst pixels ADD.L srcAlign(A6),D6 ;add src alignment MOVE.L A4,A0 ;init tmp src ptr MOVE.L A5,A2 ;init tmp dst ptr MOVE.L runBuf(A6),A1 ;point to run encoded mask buffer @inst MOVE.L (A1)+,D3 ;pick up next instruction long BMI.S @next ;if high bit set then done with scan ADD.W D3,A2 ;bump destptr by skip amount LSR.W #1,D3 ;byte skip to pixel skip MOVEQ #0,D2 ;clear out d2 MOVE.W D3,D2 ;get a LONG bit skip ADD.L D2,D6 ;add to current skip SWAP D3 ;get mask/blit cnt and check done flag BCLR #runMaskBit-16,D3 ;check and clear mask flag BNE @doMaskedRun @blit MOVEQ #$07,D2 ADDQ.W #1,D3 AND.W D3,D2 LSR.W #3,D3 SUBQ.W #1,D3 BMI.S @no16 @reblit BFEXTS (A0){D6:16},D0 ADDQ.W #2,A0 BEQ.S @white NOT.L D0 BEQ.S @black MOVEQ #1,D5 @pixel ADD.W D0,D0 SUBX.L D7,D7 ADD.W D0,D0 SUBX.W D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ ADD.W D0,D0 SUBX.L D7,D7 ADD.W D0,D0 SUBX.W D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ ADD.W D0,D0 SUBX.L D7,D7 ADD.W D0,D0 SUBX.W D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ ADD.W D0,D0 SUBX.L D7,D7 ADD.W D0,D0 SUBX.W D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ DBRA D5,@pixel DBRA D3,@reblit BRA.S @no16 @white MOVE.L D4,D0 @black MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ DBRA D3,@reblit @no16 SUBQ.W #1,D2 BMI.S @inst @last15 BFEXTS (A0){D6:16},D0 NOT.L D0 EXT.L D2 ADD.L D2,D6 ADD.L D2,D6 ;2 pixels per long ADDQ.L #2,D6 ;the 1 we subtracted above @sloop ADD.W D0,D0 SUBX.L D7,D7 ADD.W D0,D0 SUBX.W D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ DBRA D2,@sloop BRA.S @inst @doMaskedRun MOVE.W D3,D2 AND.W #$7,D2 SUB.W D2,D3 BFEXTS (A0){D6:16},D0 NOT.L D0 EXT.L D2 ADD.L D2,D6 ADD.L D2,D6 ;2 pixels per long ADDQ.L #2,D6 ;we're about to do 2 pixels @maskPixels ADD.W D0,D0 SUBX.L D7,D7 ADD.W D0,D0 SUBX.W D7,D7 AND.L D4,D7 MOVE.L (A2),D5 ;get a long of dest EOR.L D5,D7 AND.L (A1)+,D7 ;splice them together using mask EOR.L D5,D7 MOVE.L D7,(A2)+ DBRA D2,@maskPixels DBRA D3,@doMaskedRun BRA.S @inst ;----------------------------------------------------------------- ; ; ENTIRE STRETCHBITS COMPLETE. RESTORE REGS AND STACK AND GO HOME. ; Done MoveQ #1,d0 ;return success GoBack MOVE.L SAVESTK2(A6),SP ;RESTORE STACK POINTER RTS ;AND RETURN TO STRETCHBITS ENDPROC ;========================================================================================= ;========================================================================================= ; ; Patch to bring in new indexed to 32 bit scaleblt routine. <5JUNE92 SAH> ; ;========================================================================================= ;========================================================================================= scIndTab32 PatchProc $ABB1,(IIci) &CurFile SETC 'STRETCH' INCLUDE 'DrawingVars.a' runMaskBit equ 30 ;bit number for run MASK instruction DC.L scIndexedto32-scIndTab32 ;0 1 to 32 DC.L scIndexedto32-scIndTab32 ;1 2 to 32 DC.L scIndexedto32-scIndTab32 ;2 4 to 32 DC.L scIndexedto32-scIndTab32 ;3 8 to 32 ;------------------------------------------------------- ; ; scale and clip indexed source to 32-bit dst ; ; brought in Sean Callahan's new fast loop for 1 ; to 32 ; ;------------------------------------------------------- ; a0 = tmpsrc d0 = vert/scratch ; a1 = tmpmask d1 = scanCount ; a2 = tmpdst d2 = scratch ; a3 = scaleTbl d3 = run cnt ; a4 = srcPtr/patPtr d4 = src pixel size ; a5 = dstPtr d5 = scratch ; a6 = locals d6 = bit offset in src ; a7 = d7 = src shift ;------------------------------------------------------- scNonBWto32 move srcShift(a6),d7 ;set this up once move.l scaleTbl(a6),a3 ;set this up once lea @first,a0 ;go here from now on move.l A3,scaleBltA3(a6) ;save for reload after seekMask move.l a0,ScaleCase(a6) ;remember for later bra.s @first ;go to it @nxtScan add.l dstRow(a6),a5 ;BUMP DST TO NEXT ROW add.l srcRow(a6),a4 ;BUMP src TO NEXT ROW addq.w #1,vert(a6) ;BUMP DOWN A SCAN LINE subq #1,d1 ble.s NXTMASK2 @first move.l srcAlign(a6),d6 ;start with initial src offset move.l a4,a0 ;init tmp src ptr move.l a5,a2 ;init tmp dst ptr move.l runBuf(a6),a1 ;point to run encoded mask buffer @inst move.l (a1)+,d3 ;pick up next instruction long bmi.s @nxtScan ;if high bit set then done with scan add.w d3,a2 ;bump destptr by skip amount lsr.w #2,d3 ;make byte skip into pixel skip lsl.w d7,d3 ;make into bit skip add.w d3,d6 ;bump src offset move d6,d3 ;make a copy lsr.w #5,d3 ;make into long cnt lea (a0,d3.w*4),a0 ;bump src ptr swap d3 ;get mask/blit cnt and check done flag @blit MOVE.L (A0)+,D5 ;GET FIRST LONG OF SRC @NXPXL BFEXTU D5{D6:D4},D0 ;GET A PIXEL OF SRC move.l 0(A3,D0*4),(a2)+ ;TRANSLATE IT ADD D4,D6 ;ADVANCE TO NEXT SRC PIXEL AND #$1f,D6 ;TIME FOR NEXT SRC LONG? DBEQ D3,@NXPXL ;LOOP ALL PIXELS THIS LONG DBNE D3,@blit ;LOOP ALL PIXELS THIS RUN beq.s @inst ;LOOP BACK FOR more runs subq.w #4,a0 ;point back to remaining pixels BRA.s @inst ;LOOP BACK FOR more runs NXTMASK2 move.w MinRect+bottom(a6),d2 ;get bottom vertical position sub.w vert(a6),d2 ;compute scans remaining, prime d2 ble Done move d2,d3 ;save scans remaining JSR ([SEEKMASK,A6]) ;MAKE MASK BUFFER CURRENT move.w d2,d1 ;get scan count in d1 cmp.w d3,d1 ;scan count > scans remaining? ble.s @go ;no, call the blit loop move.w d3,d1 ;yes, pin to scans remaining @go JSR ([RUNRTN,A6]) ;MAKE RUN BUFFER CURRENT move.l scaleBltA3(a6),A3 ;reload A3 for scan loops MOVE.L ScaleCase(A6),A2 ;GET MODE CASE JUMP JMP (A2) ;TAKE MODE JUMP scIndexedto32 MOVE.L scaleTbl(A6),A3 ;set this up once ; btst #1,$17b ; bne.s scNonBWto32 CMP.W #1,D4 ;is src one bit? BNE.S scNonBWto32 TST.L 4(A3) ;is second color black? BNE.S scNonBWto32 MOVE.L #$00FFFFFF,D0 CMP.L (A3),D0 ;is first color white? BNE.S scNonBWto32 MOVE.L D0,D4 ;move white mask to better register LEA @first,A0 ;go here from now on MOVE.L A0,ScaleCase(A6) ;remember for later BRA.S @first ;go to it @next ADD.L dstRow(A6),A5 ;BUMP DST TO NEXT ROW ADD.L srcRow(A6),A4 ;BUMP src TO NEXT ROW ADDQ.W #1,vert(A6) ;BUMP DOWN A SCAN LINE SUBQ #1,D1 BLE.S NXTMASK2 @first MOVE.L srcAlign(A6),D6 ;start with initial src offset MOVE.L A4,A0 ;init tmp src ptr MOVE.L A5,A2 ;init tmp dst ptr MOVE.L runBuf(A6),A1 ;point to run encoded mask buffer @inst MOVE.L (A1)+,D3 ;pick up next instruction long BMI.S @next ;if high bit set then done with scan ADD.W D3,A2 ;bump destptr by skip amount LSR.W #2,D3 ;byte skip to pixel skip ADD.W D6,D3 ;add current skip to bit skip MOVEQ #$0F,D6 ;get mod 16 mask AND.W D3,D6 ;get shift mod 16 LSR.W #4,D3 ;get short skip ADD.W D3,A0 ;bump src ADD.W D3,A0 SWAP D3 ;get mask/blit cnt and check done flag @blit MOVEQ #$0F,D2 ADDQ.W #1,D3 AND.W D3,D2 LSR.W #4,D3 SUBQ.W #1,D3 BMI.S @no16 @reblit BFEXTS (A0){D6:16},D0 ADDQ.W #2,A0 BEQ.S @white NOT.L D0 BEQ.S @black MOVEQ #3,D5 @pixel ADD.W D0,D0 SUBX.L D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ ADD.W D0,D0 SUBX.L D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ ADD.W D0,D0 SUBX.L D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ ADD.W D0,D0 SUBX.L D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ DBRA D5,@pixel DBRA D3,@reblit SUBQ.W #1,D2 BMI.S @inst BRA.S @last15 @white MOVE.L D4,D0 @black MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ MOVE.L D0,(A2)+ DBRA D3,@reblit @no16 SUBQ.W #1,D2 BMI.S @inst @last15 BFEXTS (A0){D6:16},D0 NOT.W D0 ADD.W D2,D6 ADDQ.W #1,D6 @sloop ADD.W D0,D0 SUBX.L D7,D7 AND.L D4,D7 MOVE.L D7,(A2)+ DBRA D2,@sloop BRA.S @inst ;----------------------------------------------------------------- ; ; ENTIRE STRETCHBITS COMPLETE. RESTORE REGS AND STACK AND GO HOME. ; Done MoveQ #1,d0 ;return success GoBack MOVE.L SAVESTK2(A6),SP ;RESTORE STACK POINTER RTS ;AND RETURN TO STRETCHBITS ENDPROC END