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

2605 lines
85 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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):
;
; <SM6> 9/12/93 SAM Changed all instances of _Translate24to32 to _rTranslate24to32
; so they can coditionalized out of the build.
; <SM5> 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.
; <SM4> 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.
; <SM3> 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.
; <SM2> 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 dont
; 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 <bbm> 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 <bbm> Add _OpenCPort patch from AllB&WQDPatch.a and come-from
; patch on _OpenCPort inside NewGWorld from PatchIIciROM.a.
; <4> 11/13/90 JSM <dba> 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 its 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
; were 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 handles 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. <KON 22OCT90>
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 <C970/22Nov87> DAF
MOVE.W MAXBYTES(A6),D4 ;get long version of MaxBytes <C970/22Nov87> DAF
ADD.L D4,A0 ;add MaxBytes to BufStart <C970/22Nov87> 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 <EHB 28-Oct-85>
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 <KON 24JAN91>
; bra.s FirstPass ;search up and down <KON 24JAN91>
;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 ? <SMC 18SEP90>
BLT.S NXTDEV ;=>YES, CHECK NEXT DEVICE <SMC 18SEP90>
CMP (A1)+,D5 ;IS HORIZONTAL < GDRECT.LEFT ? <SMC 18SEP90>
BLT.S NXTDEV ;=>YES, CHECK NEXT DEVICE <SMC 18SEP90>
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 <KON 20JUN90>
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 <KON 20JUN90>
;
baseAddr32Bit EQU 2
tst.w rowbytes(a3) ; <KON 20JUN90>
bpl.s MMUModeOK ;it's a bitmap <KON 20JUN90>
btst #baseAddr32Bit,pmVersion+1(a3) ; <KON 20JUN90>
bne.s Needs32BitMode ;pixmap needs 32-bit addressing <KON 20JUN90>
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 <BAL 02Feb90>
_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 <BAL 02Feb90>
_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 <KON 22OCT90>
move.l hRes(a1),vRes(a1) ;to pixmap. Make resolution 72dpi <KON 22OCT90>
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
;------------------------------------------------------------
;
; <SMC> All new fast scrolling routine that takes advantage of the
; MOVE16 instruction on the 68040 when possible.
; <SAH> Added NOP's to appropriate places to make Move16's work.
;
;-------------------------------------------------------
; a0 = JUMPA d0 = SCRATCH
; a1 = JUMPB d1 = <LONGS>,SCRATCH
; a2 = JUMPC d2 = LEFTLONGS,SCRATCH
; a3 = JUMPD d3 = RIGHTLONGS,QUADBLOCKS
; a4 = <SRCPTR> d4 = <LEFTMASK>
; a5 = <DSTPTR> d5 = <RIGHTMASK>
; 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
;-------------------------------------------------------
;
; <SAH 060292>
; scale and clip indexed source to 16-bit dst
; <SAH 060492>
; 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
; <SAH 060292>
; 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