sys7.1-doc-wip/QuickDraw/Classic/Patterns.m.a
2019-07-27 22:37:48 +08:00

1364 lines
48 KiB
Plaintext

;
; File: Patterns.m.a
;
; Contains: xxx put contents here (or delete the whole line) xxx
;
; Written by: xxx put name of writer here (or delete the whole line) xxx
;
; Copyright: © 1988-1990 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <2> 7/20/90 gbm Change some id's to avoid conflicts
; <1.1> 11/11/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <1.1> 5/18/88 MSH Changed inclides to use m.GRAPHTYPES to work under EASE.
; <1.0> 2/11/88 BBM Adding file for the first time into EASE…
;
; To Do:
;
;EASE$$$ READ ONLY COPY of file “patterns.m.a”
; 1.1 CCH 11/11/1988 Fixed Header.
; 1.0 CCH 11/ 9/1988 Adding to EASE.
; OLD REVISIONS BELOW
; 1.1 MSH 5/18/88 Changed inclides to use m.GRAPHTYPES to work under EASE.
; 1.0 BBM 2/11/88 Adding file for the first time into EASE…
; END EASE MODIFICATION HISTORY
BLANKS ON
STRING ASIS
MACHINE MC68020
LOAD 'systlqk.d'
INCLUDE 'newequ.a'
INCLUDE 'colorequ.a'
;------------------------------------------------------------------
;
; --> PATTERNS.A
;
; Routines for manipulating color Patterns
;
;------------------------------------------------------------------
;
; NOTES: In the old world, patterns were always drawn using the
; foreground and background colors. New patterns can have more
; colors in them, and need to be created with CSubTables that indicate
; the intended colors. When used in old drawing modes, the fg and bk
; colors must be shoved into the tables (or simply used when the pat
; is expanded). In new drawing modes, the new colors can be used.
GETPIXPAT PROC EXPORT
IMPORT NEWPIXPAT,COPYPIXPAT
;-------------------------------------------------------------
;
; FUNCTION GetPixPat(CPatID: INTEGER): PixPatHandle;
;
; GetPixPat gets a resource of type 'PPAT' with the specified ID, places
; all the data fields into handles, installs the handles into the PPAT,
; resizes it, and then returns the data structure as a pixPatHandle.
;
; The resource format consists of a pixPat followed by it's pixMap, the
; pixel data and finally the color table data. The pixPat field contains
; an offset to the pixel data from the beginning of the resource data. The patData
; field contains the offset to the pixel data from the beginning of the res data.
; The pmTable field contains the offset to the color table data from the beginning
; of the resource data. The size of the pixel data is calculated by
; subtracting the offset to the pixel data from the offset to the color table data.
;
PARAMSIZE EQU 4
RESULT EQU PARAMSIZE+8 ; pixPatHandle RESULT
PPatID EQU PARAMSIZE+8-4 ; pattern ID
LINK A6,#0 ; build stack frame
MOVEM.L A2-A3,-(SP) ; preserve a work register
CLR.L RESULT(A6) ; set result to NIL
SUBQ #4,SP ; make space for result
MOVE.L #'PPAT',-(SP) ; push resource class 'CPAT'
MOVE.W PPatID(A6),-(SP) ; push pattern ID
_GetResource ; get the resource
MOVE.L (SP)+,A3 ; keep handle in A3
MOVE.L A3,D0 ; did we get one?
BEQ.S NoGetNew ; if not, don't allocate one
MOVE.L A3,-(SP) ; push CPAT handle
_DetachResource ; disconnect from resource manager
MOVE.L A3,A0 ; else get the handle
_HLock ; and lock it down
; Create the pixMap handle and install it
MOVE.L (A3),A2 ; point to the resource data
MOVE.L A2,A0 ; point to the resource data
ADD.L patMap(A2),A0 ; get pointer to pixMap data
MOVEQ #PMRec,D0 ; get size of pixMap
_PtrToHand ; go get a new handle
MOVE.L A0,patMap(A2) ; install handle
; Create the color table and install it
MOVE.L A2,A0 ; point to the resource data
ADD.L PPRec+pmTable(A2),A0 ; point to the table data
MOVE CTSize(A0),D0 ; get number of entries in table
ADDQ #1,D0 ; make it one based
LSL #3,D0 ; 8 bytes per entry
ADD #CTRec,D0 ; add in size of header
EXT.L D0 ; long for PtrToHand
_PtrToHand ; go get a new handle
MOVE.L patMap(A2),A1 ; get the pixMap handle
MOVE.L (A1),A1 ; point to the pixMap
MOVE.L A0,pmTable(A1) ; install handle
; Create the pixel data handle and install it
MOVE.L A2,A0 ; point to the resource data
MOVE.L PPRec+pmTable(A2),D0 ; get offset to color table data
SUB.L patData(A2),D0 ; subtract offset to pixel data
ADD.L patData(A2),A0 ; get address of pixel data
_PtrToHand ; go get a new handle
MOVE.L A0,patData(A2) ; install handle
; Allocate a dummy handle for expanded data and install it
MOVEQ #2,D0 ; get a dummy size
_NewHandle ; go get a handle
MOVE.L A0,patXData(A2) ; install handle
MOVE.L A3,A0 ; get the pixPat handle
_HUnlock ; and unlock it
MOVEQ #PPRec,D0 ; get size of pixPat
MOVE.L A3,A0 ; get handle to pixPat
_SetHandleSize ; and strip off the old data
MOVE.L A3,RESULT(A6) ; update function result
NoGetNew MOVEM.L (SP)+,A2-A3 ; restore working registers
UNLINK PARAMSIZE,'GETPIXPA' ; strip params and return
NEWPIXPAT PROC EXPORT
IMPORT NEWHANDLE,NEWPIXMAP
;-------------------------------------------------------------
;
; FUNCTION NewPixPat : PixPatHandle;
;
; Create a new, uninitialized pixel pattern and return a handle to it.
; The pixPat's pixMap is initialized to the current depth.
;
CLR.L -(SP) ; make room for function result
MOVE #PPREC,-(SP) ; get size of pixelpat
JSR NEWHANDLE ; allocate pixel pattern,leave on stack
CLR.L -(SP) ; make room for function result
JSR NEWPIXMAP ; get initialized pixMap, leave on stack
MOVE.L (SP),A0 ; get the handle
CLR.L -(SP) ; make room for function result
CLR.W -(SP) ; size = 0
JSR NEWHANDLE ; get handle for pattern data
CLR.L -(SP) ; make room for function result
CLR.W -(SP) ; size = 0
JSR NEWHANDLE ; get handle for expanded data
MOVE.L (SP)+,D2 ; get expanded data handle
MOVE.L (SP)+,D1 ; get pattern data handle
MOVE.L (SP)+,D0 ; get pixMap handle
MOVE.L (SP)+,A1 ; get pixel pat handle
MOVE.L A1,4(SP) ; return result
MOVE.L (A1),A0 ; get pixel pat pointer
MOVE.L D0,patMap(A0) ; install pixMap into pixPat
MOVE.L D1,patData(A0) ; install handle for data
MOVE.L D2,patXData(A0) ; install handle for expanded data
MOVE #1,patType(A0) ; assume it's a color type
MOVEQ #-1,D0 ; get an invalid shift amount
MOVE D0,lastShift(A0) ; make lastshift invalid
RTS ; and return
DisposPixPat PROC EXPORT
IMPORT DisposPixMap
;-------------------------------------------------------------
;
; PROCEDURE DisposPixPat (PPH: PixPatHandle);
;
; Dispose of a pixel pattern
;
MOVE.L 4(SP),A1 ; get pixPat handle
MOVE.L (A1),A1 ; get pixPat pointer
MOVE.L patData(A1),A0 ; get handle to data
_DisposHandle ; and dispose of them
MOVE.L patXData(A1),A0 ; get handle to expanded data
_DisposHandle ; and Close them too
MOVE.L patMap(A1),-(SP) ; get the pixMap
JSR DisposPixMap ; and dispose of it
MOVE.L 4(SP),A0 ; get handle to pixPat
_DisposHandle ; and dispose of it
MOVE.L (SP)+,(SP) ; strip parameter
RTS ; and return
PenPixPat PROC EXPORT
EXPORT BackPixPat
IMPORT DISPOSPIXPAT,PATCONVERT
;-------------------------------------------------------------
;
; PROCEDURE PenPixPat (PPH: PixPatHandle);
;
; SET THE PNPAT TO THE SPECIFIED PIXEL PATTERN
MOVE #PNPIXPAT,D0 ;GET OFFSET TO PATTERN
BRA.S CPATSHARE
BackPixPat
;-------------------------------------------------------------
;
; PROCEDURE BackPixPat (PPH: PixPatHandle);
;
; SET THE BKPAT TO THE SPECIFIED PIXEL PATTERN
MOVE #BKPIXPAT,D0 ;GET OFFSET TO PATTERN
CPATSHARE MOVE.L GRAFGLOBALS(A5),A0 ;GET GLOBAL POINTER
MOVE.L THEPORT(A0),A0 ;GET THE PORT
TST PORTBITS+ROWBYTES(A0) ;IS IT A COLOR PORT?
BPL.S DONE ;=>NO, JUST EXIT
; IF NO PATTERN OR NEW PATTERN, JUST INSTALL SPECIFIED PATTERN
MOVE.L 0(A0,D0),D1 ;GET WHAT IS CURRENTLY THERE
BEQ.S PUTPAT ;=>NOTHING, JUST PUT NEW ONE
MOVE.L D1,A0 ;GET THE PATTERN HANDLE
MOVE.L (A0),A0 ;GET THE PATTERN POINTER
TST PATTYPE(A0) ;OLD OR NEW PATTERN?
BNE.S PUTPAT ;=>NEW ONE, JUST PUT NEW ONE
; IF PREVIOUS PNPAT WAS AN OLD PATTERN, THEN DISPOSE OF IT
MOVE D0,-(SP) ;SAVE PATTERN OFFSET
MOVE.L D1,-(SP) ;PUSH THE HANDLE
JSR DISPOSPIXPAT ;AND DISPOSE OF THE PIXPAT
MOVE (SP)+,D0 ;RESTORE PATTERN OFFSET
; INSTALL SPECIFIED HANDLE AND RETURN
PUTPAT MOVE.L GRAFGLOBALS(A5),A0 ;GET GLOBAL POINTER
MOVE.L THEPORT(A0),A0 ;GET THE PORT
MOVE.L 4(SP),-(SP) ;PUSH HANDLE FOR PATCONVERT
MOVE.L (SP),0(A0,D0) ;INSTALL HANDLE INTO PORT
JSR PATCONVERT ;EXPAND PATTERN/TRANSLATE TABLE
DONE MOVE.L (SP)+,(SP) ;STRIP PARAMETER
RTS ;AND RETURN
COPYPIXPAT PROC EXPORT
IMPORT COPYPIXMAP,COPYHANDLE
;-------------------------------------------------------------
;
; PROCEDURE COPYPIXPAT (SRCPP,DSTPP: PixPatHandle);
;
; COPY THE SRC PIXPAT'S DATA TO THE DST PIXPAT'S HANDLES
;
PARAMSIZE EQU 8
SRCPP EQU PARAMSIZE
DSTPP EQU SRCPP-4
MOVE.L SRCPP(SP),A0 ;GET HANDLE TO SRC PIXPAT
MOVE.L (A0),A0 ;GET POINTER TO SRC PIXPAT
MOVE.L DSTPP(SP),A1 ;GET HANDLE TO DST PIXPAT
MOVE.L (A1),A1 ;GET POINTER TO DST PIXPAT
MOVE (A0)+,(A1)+ ;COPY PATTYPE
MOVE.L (A0)+,-(SP) ;PUSH SRC PATMAP
MOVE.L (A1)+,-(SP) ;PUSH DST PATMAP
MOVE.L (A0)+,-(SP) ;PUSH SRC DATA
MOVE.L (A1)+,-(SP) ;PUSH DST DATA
MOVE.L (A0)+,-(SP) ;PUSH SRC EXPAND DATA
MOVE.L (A1)+,-(SP) ;PUSH DST EXPAND DATA
MOVE.L (A0)+,(A1)+ ;COPY PATXHMASK, PATXVMASK
MOVE.L (A0)+,(A1)+ ;COPY LASTOFST, LASTSHIFT
MOVE.L (A0)+,(A1)+ ;COPY LASTINVERT
MOVE.L (A0)+,(A1)+ ;COPY LASTALIGN
MOVE (A0)+,(A1)+ ;COPY LASTSTRETCH
JSR COPYHANDLE ;COPY EXPAND DATA
JSR COPYHANDLE ;COPY DATA
JSR COPYPIXMAP ;COPY PATMAP
MOVE.L (SP)+,A0 ;GET RETURN ADDRESS
ADDQ #8,SP ;STRIP PARAMS
JMP (A0) ;AND RETURN
OldPatToNew PROC EXPORT
IMPORT OneBitCTable,COPYPMAP,OneBitData
;-------------------------------------------------------------
;
; PROCEDURE OldPatToNew (pat: pattern; PPHP: PixPatHandlePtr);
;
; Copy the specified pattern into a pixPat.
; If the pixPat handle is NIL, then create a new pixPat.
; If the handle contains a new pattern, create a new pixPat and replace it.
; If the handle contains an old-style pattern, then re-use it.
;
; NOTE: This structure is invalid as a pixMap. There is no BaseAddr
; and the rowBytes is set to one (should be multiple of 2).
;
; The data will be tweaked to transform it into a valid pixMap before
; drawing takes place.
;
; NOTE: WE ASSUME THAT THE PAT IS A POINTER THAT WILL NOT MOVE.
;
PARAMSIZE EQU 8 ; total bytes of params
PAT EQU PARAMSIZE+8-4 ; pattern pointer
PPHP EQU PAT-4 ; pixPat handle
LINK A6,#0 ; no local vars
MOVEM.L A2/A3,-(SP) ; save work registers
MOVE.L PPHP(A6),A0 ; get handle pointer
MOVE.L (A0),D0 ; is there a handle?
BEQ.S GetHandle ; => no, go get one
MOVE.L D0,A3 ; get the pixpat handle
MOVE.L (A3),A1 ; point to pixpat
TST PatType(A1) ; is it an old one?
BEQ.S GotHandle ; =>yes, just reuse it
; IF THERE WAS NO PIXPAT HANDLE, CREATE ONE AND INSTALL IT IN PPHP
GetHandle CLR.L -(SP) ; make room for a handle
JSR NewPixPat ; create a new one
MOVE.L PPHP(A6),A0 ; get handle pointer
MOVE.L (SP)+,(A0) ; return new handle
MOVE.L (A0),A3 ; get the pixpat handle
MOVE.L (A3),A1 ; point to pixpat
; CLEAR PATTYPE TO SAY THAT IT IS A FOREGROUND/BACKGROUND PATTERN
; INVALIDATE THE CURRENT PATTERN EXPAND AREA BY SETTING LASTSHIFT TO -1
GotHandle CLR PATTYPE(A1) ; IT'S A FG/BK PATTERN
MOVEQ #-1,D0 ; INVAL ALL SAVE VARS
MOVE D0,LASTSHIFT(A1) ; INVAL LASTSHIFT
MOVE.L patData(A1),A0 ; finally get the data handle
MOVEQ #8,D0 ; get size
_SetHandleSize ; for an 8*8 pattern
MOVE.L (A0),A0 ; get pointer to data
MOVE.L PAT(A6),A1 ; get pattern data
MOVE.L (A1)+,(A0)+ ; put one long
MOVE.L (A1)+,(A0)+ ; and second long of pattern
MOVE.L (A3),A2 ; get PixPat pointer
MOVE.L patMap(A2),A2 ; get pixMap handle
MOVE.L (A2),A2 ; A2 is pixMap pointer
MOVE.L A2,A3 ; A3 is pixMap pointer
MOVE.L pmTable(A3),-(SP) ; save color table
LEA OneBitData,A1 ; point to one bit data
JSR CopyPMap ; and copy into pixMap ptr in A2
; clobbers A1, A2
MOVE.W #1,pRowBytes(A3) ; 1 byte per row (not a valid pixMap)
CLR.L pBounds+topLeft(A3) ; bounds = (0,0,8,8)
MOVE.L #$00080008,pBounds+botRight(A3)
MOVE.L (SP),pmTable(A3) ; restore the color table
; and leave on stack as param
JSR OneBitCTable ; get a color table
MOVEM.L (SP)+,A2/A3 ; restore work registers
UNLINK PARAMSIZE,'OLDPATTO' ; strip params and return
PatExpand PROC EXPORT
IMPORT EXTBL1
;----------------------------------------------------------
;
; EXPAND THE CURRENT PATTERN IF NECESSARY
;
; CALLED ONLY FROM STRETCH,DRAWLINE,DRAWARC.
;
; INPUTS: LOCMODE(A6) ;THE (ALTERED) DRAWING MODE
; DSTPIX+BOUNDS+LEFT(A6) ;THE GLOBAL-LOCAL OFFSET (PIXELS)
; FCOLOR(A6) ;THE CURRENT FG COLOR
; BCOLOR(A6) ;THE CURRENT BK COLOR
; DSTSHIFT(A6) ;THE SHIFT FOR PIXEL DEPTH
; LOCPAT(A6) ;THE (ALTERED) PATTERN
; NEWPATTERN(A6) ;TRUE IF NEW PATTERN
; A5: PASCAL GLOBAL PTR
; D7: -1 TO INVERT, ELSE 0
; patStretch AND PATALIGN
;
; OUTPUTS: POINTER TO EXPANDED PATTERN IN EXPAT(A6)
;
; CLOBBERS: D0,D1,D2,A0,A1
;
; DRAWING WITH COLOR PATTERNS:
;
; IF COPY MODE, COLOR IS ADDED TO THE PATTERN IN THIS ROUTINE AND THEN LATER
; BLITTED DIRECTLY TO THE SCREEN (FOR SPEED). OTHERWISE THE PATTERN IS LEFT AS A
; FOREGROUND/BACKGROUND MASK AND COLOR IS ADDED WITHIN THE BLT ROUTINE IF
; NECESSARY. IF XOR MODE, THE DST IS SIMPLY XOR'D AND THE COLORS ARE IGNORED.
; IF OR MODE, THE FOREGROUND COLOR IS APPLIED TO THE PATTERN AND OR'D INTO THE
; DST. IF BIC MODE, THE BACKGROUND COLOR IS APPLIED TO THE PATTERN AND OR'D INTO
; THE DST.
;
; A6 OFFSETS OF LOCAL VARIABLES OF CALLER:
;
; STACK FRAME VARS USED BY SEEKMASK (CALLED BY STRETCHBITS, RGNBLT, DRAWARC, DRAWLINE)
; NOT USED IN PATEXPAND.
;
RECTFLAG EQU -2 ;WORD
VERT EQU RECTFLAG-2 ;WORD
MASKBUF EQU VERT-4 ;LONG
BUFLEFT EQU MASKBUF-2 ;WORD
BUFSIZE EQU BUFLEFT-2 ;WORD
EXRTN EQU BUFSIZE-4 ;LONG
SEEKMASK EQU EXRTN-4 ;LONG
STATEA EQU SEEKMASK-RGNREC ;RGN STATE RECORD
STATEB EQU STATEA-RGNREC ;RGN STATE RECORD
STATEC EQU STATEB-RGNREC ;RGN STATE RECORD
; STACK FRAME VARS USED BY PATEXPAND
; (CALLED BY STRETCHBITS, RGNBLT, BITBLT, DRAWARC, DRAWLINE)
EXPAT EQU STATEC-4 ;LONG
PATVMASK EQU EXPAT-2 ;WORD
PATHMASK EQU PATVMASK-2 ;WORD
PATROW EQU PATHMASK-2 ;WORD
PATHPOS EQU PATROW-2 ;WORD
PATVPOS EQU PATHPOS-2 ;WORD
LOCMODE EQU PATVPOS-2 ;WORD
NEWPATTERN EQU LOCMODE-2 ;WORD
LOCPAT EQU NEWPATTERN-4 ;LONG
FCOLOR EQU LOCPAT-4 ;LONG
BCOLOR EQU FCOLOR-4 ;LONG
DSTPIX EQU BCOLOR-PMREC ;PIXMAP
DSTSHIFT EQU DSTPIX-2 ;WORD
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
VARSIZE EQU ROTSHIFT ;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
LSR #3,D1 ;DEPTHS 1-8 OK
BEQ.S GETBUF ;=>SO GET THE PATTERN BUFFER
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,-(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
MOVEQ #-1,D3 ;ELSE FGCOLOR = BLACK
MOVEQ #0,D4 ;AND BKCOLOR = WHITE
GOTCOPY MOVE.L GRAFGLOBALS(A5),A3 ;POINT TO QUICKDRAW GLOBALS
;
; IF PATALIGN VERT NON-ZERO, COPY PAT TWICE AND REPLACE A0
;
MOVEQ #7,D0
AND PATALIGN(A3),D0 ;GET PATALIGN MOD 8
BEQ.S VERTOK ;SKIP IF ZERO
MOVE.L (A0),TWOPAT(A4) ;MAKE TWO COPIES OF PATTERN
MOVE.L (A0)+,TWOPAT+8(A4)
MOVE.L (A0),TWOPAT+4(A4)
MOVE.L (A0),TWOPAT+12(A4)
LEA TWOPAT(A4),A0
ADD D0,A0
VERTOK ADD PATALIGN+H(A3),D2 ;ADJUST FOR PATALIGN HORIZ
MOVEQ #7,D6 ;SOURCE PAT IS 8 BYTES LONG
AND D6,D2 ;TREAT SHIFTCOUNT MOD 8
TST D5 ;ONE BIT PER PIXEL?
BNE.S NEWWAY ;=>NO, DO NEW WAY
OLDWAY MOVE.L THEPORT(A3),A3 ;GET CURRENT GRAFPORT
MOVE patStretch(A3),D0 ;GET patStretch
CMP #-2,D0 ;IS PAT STRETCH = -2 ?
BEQ.S THIN ;YES, STRETCH THIN
CMP #2,D0 ;IS patStretch = 2 ?
BEQ.S DOUBLE ;=>YES, DOUBLE THE DATA
; NEW WAY: EXPAND DATA TO MINIMUM NEEDED EXPANDED SIZE.
; DEPTH = 1-4: EXPAND 8*8 PATTERN TO 16 ROWS * 1 LONG (USE OLD BLT ROUTINES)
; DEPTH = 8: EXPAND 8*8 PATTERN TO 8 ROWS * 2 LONGS (USE NEW BLT ROUTINES)
; DEPTH = 16: EXPAND 8*8 PATTERN TO 8 ROWS * 4 LONGS
; DEPTH = 32: EXPAND 8*8 PATTERN TO 8 ROWS * 8 LONGS (64 LONGS MAX SIZE)
; EXPAND ROUTINES IN FILE STRETCH.A TO SHARE COMMON TABLES.
NEWWAY LEA EXTBL1,A2 ;POINT TO ROUTINE TABLE
ADD 0(A2,D5*2),A2 ;USE PIXSHIFT TO SELECT ROUTINE
JSR (A2) ;EXPAND DIRECTLY INTO BUFFER
BRA.S DONE ;=>ALL FINISHED
;-----------------------------------------------------------
;
; STRETCHED BY TWO: DOUBLE EACH BIT HORIZONTALLY AND VERTICALLY
;
DOUBLE CLR D0 ;CLEAR OUT HI BYTE
DLOOP MOVE.B (A0)+,D0 ;GET A BYTE OF PATTERN
EOR.B D7,D0 ;INVERT IT IF MODE BIT 2
ROL.B D2,D0 ;ALIGN TO LOCAL COORDS
MOVE.B D0,-(SP) ;STASH FOR A WHILE
LSR.B #4,D0 ;GET HI NIBBLE
MOVE.B STRETCH(D0),(A1)+ ;PUT ONE BYTE
MOVEQ #$F,D0 ;MASK FOR LO NIBBLE
AND.B (SP)+,D0 ;GET THE LO NIBBLE
MOVE.B STRETCH(D0),(A1)+ ;PUT ANOTHER TO MAKE A WORD
MOVE.W -2(A1),(A1)+ ;STRETCH WORD OUT TO LONG
MOVE.L -4(A1),(A1)+ ;STRETCH LONG TO TWO LONGS
DBRA D1,DLOOP ;LOOP ALL 8 INPUT BYTES
BRA.S DONE
;-----------------------------------------------------------
;
; STRETCH BY TWO AND THIN OUT THE BITS. ADD EXTRA WHITE DOTS.
;
THIN CLR D0 ;CLEAR OUT HI BYTE
THINLP MOVE.B (A0)+,D0 ;GET A BYTE OF PATTERN
EOR.B D7,D0 ;INVERT IT IF MODE BIT 2
ROL.B D2,D0 ;ALIGN TO LOCAL COORDS
MOVE.B D0,-(SP) ;STASH FOR A WHILE
LSR.B #4,D0 ;GET HI NIBBLE
MOVE.B THINSTR(D0),(A1)+ ;PUT ONE BYTE
MOVEQ #$F,D0 ;MASK FOR LO NIBBLE
AND.B (SP)+,D0 ;GET THE LO NIBBLE
MOVE.B THINSTR(D0),(A1)+ ;PUT ANOTHER TO MAKE A WORD
MOVE.W -2(A1),(A1)+ ;STRETCH WORD OUT TO LONG
CLR.L (A1)+ ;STRETCH LONG TO TWO LONGS
DBRA D1,THINLP ;LOOP ALL 8 INPUT BYTES
DONE MOVEM.L (SP)+,D3-D6/A2-A3 ;RESTORE REGS
UNLK A4 ;REMOVE STACK FRAME
RTS ;JUST RETURN
;----------------------------------------------------------------
;
; BIT DOUBLING TABLE FOR 0..15 INPUT --> BYTE OUTPUT
;
STRETCH DC.B $00,$03,$0C,$0F,$30,$33,$3C,$3F
DC.B $C0,$C3,$CC,$CF,$F0,$F3,$FC,$FF
;
; TABLE FOR THIN DOUBLING.
;
THINSTR DC.B $00,$01,$04,$05,$10,$11,$14,$15
DC.B $40,$41,$44,$45,$50,$51,$54,$55
NEWPATEXPAND
;----------------------------------------------------------------
;
; NEWPATEXPAND -- EXPAND A PIXELPAT, IF NECESSARY
;
LINK A4,#VARSIZE ;ALLOCATE STACK FRAME
MOVEM.L D3-D6/A2-A3,-(SP) ;SAVE REGS
MOVE.L SP,SAVESTK(A4) ;SAVE STACK POINTER
MOVE.L GRAFGLOBALS(A5),A3 ;POINT TO QUICKDRAW GLOBALS
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
LSR #3,D1 ;DEPTHS 1-8 OK
BEQ.S BUFOK ;=>SO GET THE PATTERN BUFFER
LSL.L D1,D0 ;ELSE DOUBLE FOR 16, QUAD FOR 32
BUFOK _SETHANDLESIZE
MOVE.L (A0),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 MOVE.L SAVESTK(A4),SP ;RESTORE STACK POINTER
BRA DONE ;AND RETURN
; CALC STATE VARIABLES FOR STACK FRAME
NOTOLD MOVE.L ([PATXDATA,A0]),EXPAT(A6) ;COPY POINTER TO EXPANDED DATA
MOVE PATXROW(A0),PATROW(A6) ;COPY EXPANDED ROWBYTES
MOVE PATXHMASK(A0),PATHMASK(A6) ;COPY HORIZONTAL MASK
MOVE PATXVMASK(A0),PATVMASK(A6) ;COPY VERTICAL MASK
;---------------------------------------------------------
;
; HAS PATTERN CHANGED SINCE LAST TIME?
;
LEA LASTOFST(A0),A2 ;POINT TO SAVED GLOBAL-LOCAL OFFSET
MOVE.L THEPORT(A3),A1 ;GET CURRENT GRAFPORT
MOVE (A2)+,D0 ;GET LASTOFST
CMP DSTPIX+BOUNDS+LEFT(A6),D0 ;HAS IT CHANGED?
BNE.S DOPAT ;=>YES, rotate PATTERN
MOVE (A2)+,D0 ;GET LAST PIXEL SHIFT
CMP DSTSHIFT(A6),D0 ;HAS DEPTH CHANGED?
; BNE.S DOPAT ;=>YES, EXPAND PATTERN
CMP.L (A2)+,D7 ;HAS INVERT CHANGED?
; BNE.S DOPAT ;=>YES, EXPAND PATTERN
MOVE PATALIGN+V(A3),D0 ;GET ALIGN VERTICAL
CMP (A2)+,D0 ;HAS IT CHANGED?
; BNE.S DOPAT ;=>YES, EXPAND PATTERN
MOVE PATALIGN+H(A3),D0 ;GET ALIGN HORIZONTAL
CMP (A2)+,D0 ;HAS IT CHANGED?
BNE.S DOPAT ;=>ROTATE WITH ALIGN
; MOVE PATSTRETCH(A1),D0 ;GET STRETCH
; CMP (A2)+,D0 ;HAS IT CHANGED?
BEQ DONE ;=>NO, JUST RETURN
SAVESTATE
LEA LASTOFST(A0),A2 ;POINT TO START OF SAVE AREA
ADDQ #2,A2 ;LASTOFST ALREADY UPDATED
MOVE DSTSHIFT(A6),(A2)+ ;UPDATE LASTSHIFT
MOVE.L D7,(A2)+ ;SAVE INVERT
MOVE.L PATALIGN(A3),(A2)+ ;SAVE LASTALIGN
MOVE PATSTRETCH(A1),(A2)+ ;SAVE LASTSTRETCH
BRA NEWDONE ;=>STRIP STACK AND RETURN
DOPAT
; GET WIDTH OF PATTERN AND ALLOCATE SCANLINE BUFFER ON STACK
MOVE PATXROW(A0),D0 ;GET ROWBYTES OF EXPANDED PATTERN
BNE.S NOSMALL ;=> NOT AN OLD SIZED PATTERN
MOVEQ #4,D0 ;ELSE ROWBYTES := 4
NOSMALL MOVE.L PATMAP(A0),A1 ;GET THE PATTERN'S PIXMAP HANDLE
MOVE.L (A1),A1 ;POINT TO THE PIXMAP
MOVE DSTSHIFT(A6),D1 ;GET SHIFT FOR PIXEL DEPTH
LSL #3,D0 ;CONVERT BYTES TO BITS
MOVE D0,D3 ;D3 = WIDTH IN BITS
MOVE D0,D4 ;SAVE WIDTH FOR BELOW
LSR D1,D4 ;D4 = WIDTH IN PIXELS
LSR #5,D0 ;CONVERT BITS TO LONGS
NXTLNG0 CLR.L -(SP) ;CLEAR A LONG
DBRA D0,NXTLNG0 ;LOOP UNTIL DONE
; SINCE PATTERN MIGHT ALREADY BE SHIFTED, CALC NEW OFFSET - OLD OFFSET
MOVE DSTPIX+BOUNDS+LEFT(A6),D2 ;GET NEW GLOBAL-LOCAL OFFSET
ADD PATALIGN+H(A3),D2 ;ADD HORIZONTAL ALIGNMENT
MOVE D2,D0 ;SAVE A COPY
SUB LASTOFST(A0),D2 ;SHIFT := NEW OFFSET - OLD OFFSET
MOVE D0,LASTOFST(A0) ;SAVE NEW OFFSET
SUBQ #1,D4 ;GET WIDTH-1 AS MASK
AND D4,D2 ;MASK THE OFFSET
BEQ.S SAVESTATE ;=>SAME ALIGNMENT, RETURN
LSL D1,D2 ;DEPTH*OFFSET = SHIFT AMOUNT
; SET UP ROTATE INFO
MOVE D2,ROTSHIFT(A4) ;SAVE SHIFT AMOUNT
MOVE D3,ROTSIZE(A4) ;SAVE SCANLINE SIZE
MOVE.L PATXDATA(A0),A3 ;GET HANDLE TO EXPANDED DATA
MOVE.L (A3),A3 ;POINT AT EXPANDED DATA
MOVEQ #32,D6 ;GET A USEFUL NUMBER IN D6
MOVEQ #16,D5 ;ASSUME OLD-STYLE PATTERN
TST PATXROW(A0) ;IS IT?
BEQ.S CHKSCAN ;=>YES
MOVE BOUNDS+BOTTOM(A1),D5 ;GET BOTTOM
SUB BOUNDS+TOP(A1),D5 ;GET NUMBER OF SCANS TO DO
BRA.S CHKSCAN ;CHECK FOR INVALID HEIGHTS AND LOOP
; ROTATE NEXT ROW INTO THE SCANLINE BUFFER STARTING AT OFFSET INTO SRC
NXTSCAN MOVE.L SP,A2 ;POINT TO SCANLINE BUFFER
MOVE ROTSIZE(A4),D3 ;GET SIZE OF SCANLINE
MOVE ROTSHIFT(A4),D2 ;GET SHIFT AMOUNT
MOVE D2,D7 ;USE AS START OFFSET INTO SRC
EXT.L D7 ;LONG FOR BFEXTU
SUB D7,D3 ;SCANSIZE-START IS # BITS TO DO
; PART 1: WRITE LONGS UNTIL WE HIT THE END OF THE SRC
NXTLNG1 BFEXTU (A3){D7:0},D0 ;GET 32 BITS OF SRC
ADD.L D6,D7 ;BUMP SRC OFFSET
SUB D6,D3 ;UPDATE NUMBER OF BITS TO DO
BMI.S NOTLONG ;=>IF PAST END, DON'T DO LONG
MOVE.L D0,(A2)+ ;ELSE PUT LONG TO DST
BRA.S NXTLNG1
; PART 2: WRITE THE FRACTIONAL PARTS FROM THE END AND THE START OF THE SRC
NOTLONG MOVE.L D6,D1 ;GET 32
ADD D3,D1 ;GET NUMBER OF LEFTOVER BITS (LONG)
ROL.L D1,D0 ;PUT LEFTOVERS INTO LOW PART OF D0
BFINS D0,(A2){0:D1} ;INSERT BITS FROM END OF SRC
NEG D3 ;GET NUMBER OF BITS TO DO
BFEXTU (A3){0:D3},D0 ;GET THAT MANY BITS
BFINS D0,(A2){D1:D3} ;AND PUT TO DST
ADD.W #4,A2 ;DONE WITH THAT LONG
SUB D3,D2 ;SAY WE'VE DONE THOSE BITS
BLE.S DONESCAN ;=>DONE WITH SCAN (*** NEEDED?)
; PART3: WRITE LONGS UNTIL WE'VE EXHAUSTED ALL SRC BITS.
NXTLNG2 BFEXTU (A3){D3:0},D0 ;GET 32 BITS OF SRC
ADD.L D6,D3 ;GO TO NEXT LONG
SUB D6,D2 ;SAY WE'VE DONE THOSE BITS
BMI.S DONESCAN ;=>COUNT EXHAUSTED, DONE W/SCAN
MOVE.L D0,(A2)+ ;ELSE PUT TO DST
BRA.S NXTLNG2 ;AND LOOP UNTIL DONE
DONESCAN MOVE.L SP,A2 ;POINT TO SCANLINE BUFFER
MOVE ROTSIZE(A4),D0 ;GET NUMBER OF BITS TO DO
SUBQ #1,D0 ;FOR LONG ROUNDING
LSR #5,D0 ;CONVERT TO LONGS
NXTLNG3 MOVE.L (A2)+,(A3)+ ;COPY A LONG
DBRA D0,NXTLNG3 ;LOOP FOR ALL LONGS
CHKSCAN DBRA D5,NXTSCAN ;=>DO NEXT SCANLINE
BRA SAVESTATE ;AND RETURN
PATCONVERT PROC EXPORT
IMPORT GetDevPix,Color2Index,PatDither
;------------------------------------------------------------------
;
; PROCEDURE PATCONVERT (PAT: PixPatHandle);
;
; Convert the specified pattern to the current depth and color table.
;
PARAMSIZE EQU 4
PAT EQU PARAMSIZE+8-4 ; handle to pattern
SAVESTK EQU -4 ; save the stack
WIDCNT EQU SAVESTK-2 ; width of pattern in pixels
HTCNT EQU WIDCNT-2 ; height of pattern in scans
HREPCNT EQU HTCNT-2 ; horizontal repetitions of pattern
VREPCNT EQU HREPCNT-2 ; vertical repetitions of pattern
PATROW EQU VREPCNT-2 ; rowbytes of src pattern
VARSIZE EQU PATROW ; local vars
LINK A6,#VARSIZE ; allocate stack frame
MOVEM.L D3-D7/A0/A2-A4,-(SP) ; save all registers
; A0 saved for SetFillPat
MOVE.L SP,SAVESTK(A6) ; save stack pointer
; get the dst pixel size in D6 and the src pixel size in D7
JSR GetDevPix ; get pointer to GDevice in A0
MOVE PixelSize(A0),D6 ; get dst pixel size
EXT.L D6 ; make long for translate loop
MOVE.L PAT(A6),A4 ; get the PixPat Handle
MOVE.L (A4),A1 ; point to the pixPat
CMP #ditherPat,patType(A1) ; does pat need to be dithered?
BNE.S NoDither ; => no, don't adjust
MOVE.L A4,-(SP) ; push pixPat handle
JSR PatDither ; create best-match dither
MOVE.L (A4),A1 ; point to the pixPat
NoDither CLR lastOfst(A1) ; we're expanding with offset 0
MOVE.L PatMap(A1),A3 ; get the pixmap handle
MOVE.L (A3),A0 ; point to the pixmap
MOVE pixelSize(A0),D7 ; get source pixel size
EXT.L D7 ; make long for translate loop
; set up patXRow, patXHMask, patXVMask
MOVE rowBytes(A0),D0 ; get src rowbytes
AND #RBMask,D0 ; clear flag bits
MOVE D0,patRow(A6) ; save for expand loop
CLR HREPCNT(A6) ; assume no horizontal reps
CLR VREPCNT(A6) ; assume no vertical reps
LEA bounds+right(A0),A2 ; point to end of bounds
MOVE (A2),D4 ; get right
MOVE -(A2),D3 ; get bottom
SUB -(A2),D4 ; get width in pixels in D4
SUB -(A2),D3 ; get height in D3
MOVE D4,D0 ; get src width in pixels
SUBQ #1,D0 ; make it 0 based
MOVE D0,WIDCNT(A6) ; save src width in pixels
MOVE D3,D0 ; get height
SUBQ #1,D0 ; make it 0 based
MOVE D0,HTCNT(A6) ; save src height in pixels
; If the pattern will fit into a long, repeat, if necessary, to fill the whole
; word. Also make the pattern 16 scans high. Set patXRow to 0 to indicate a 32*16 pattern.
MULU D6,D4 ; get dst width in bits
LSR #3,D4 ; convert to bytes
MOVEQ #4,D0 ; we need at least four bytes
DIVU D4,D0 ; get 4 DIV dst rowbytes
CMP #1,D0 ; is it less than one?
BLT.S NOREPS ; => yes, no repetitions
MULU D0,D4 ; multiply rowbytes by rep count
SUBQ #1,D0 ; make HRepCnt 0 based
MOVE D0,HREPCNT(A6) ; and set horizontal rep count
CLR PATXROW(A1) ; flag to use the old blt routines
MOVEQ #16,D0 ; get minimum number of vert lines
DIVU D3,D0 ; get 16 DIV height
CMP #1,D0 ; is it 1 or less?
BLT.S NOREPS ; => yes, no repetitions
MULU D0,D3 ; multiply height by repcount
SUBQ #1,D0 ; make VRepCnt 0 based
MOVE D0,VREPCNT(A6) ; and set vertical rep count
BRA.S REPS ; => patXRow already cleared
NOREPS MOVE D4,patXRow(A1) ; save expanded rowbytes
REPS MOVE D4,D0 ; copy expanded rowBytes
SUBQ #1,D0 ; HMASK := $FFFC AND (rowbytes-1)
AND #$FFFC,D0 ; mask to long boundary
MOVE D0,patXHMask(A1) ; save HMask
MOVE D4,D0 ; get (adjusted) rowbytes
MULU D3,D0 ; VMASK := rowbytes*height - 1
SUBQ #1,D0 ; make it a mask
MOVE D0,patXVMask(A1) ; save VMask
; Calc total size of the dst and set the size of patXData
MOVE D4,D0 ; get (adjusted) width in bytes
MULU D3,D0 ; multiply by (adjusted) height
MOVE.L (A4),A0 ; point to the pixPat
MOVE.L patXData(A0),A0 ; get the handle to expanded bits
_SetHandleSize ; set to proper size
; Allocate pixel translate table
MOVE #127,D0 ; allocate 256 words on stack ***
NXTWORD CLR.L -(SP) ; 0 in case of undefined pixels
DBRA D0,NXTWORD ; repeat until done
CLR.L -(SP) ; allocate VAR colorSpec on stack
CLR.L -(SP)
; Build pixel translate table
MOVE.L (A3),A0 ; get pixMap pointer
MOVE.L PMTable(A0),A3 ; get handle to color table
MOVE.L (A3),A2 ; get pointer to color table
MOVE CTSize(A2),D5 ; get size of table in entries
NXTENTRY MOVE.L (A3),A2 ; get color table pointer
MOVE CTTable+value(A2,D5*8),D4 ; get value of current entry
MOVE.L CTTable+value(A2,D5*8),value(SP) ; copy value, red
MOVE.L CTTable+rgb+green(A2,D5*8),rgb+green(SP) ; copy green,blue
MOVE.L SP,-(SP) ; point to VAR colorSpec
JSR Color2Index ; convert to index
MOVE value(SP),8(SP,D4*2) ; put returned value in table
DBRA D5,NXTENTRY ; => repeat until done
ADDQ #8,SP ; strip VAR colorSpec
; For each pixel, translate and write out
MOVE.L (A4),A1 ; point to the pixPat
MOVE.L patXData(A1),A2 ; get the dst handle
MOVE.L (A2),A2 ; point to the dst
MOVEQ #0,D5 ; position to start of dst
NXTPASS MOVE.L (A4),A1 ; point to the pixPat
MOVE.L patData(A1),A3 ; get the data handle
MOVE.L (A3),A3 ; point to the src data
MOVE HTCNT(A6),D3 ; get number of scans to do
NXTSCAN MOVE HREPCNT(A6),D2 ; get horizontal repeat count
NXTREP MOVEQ #0,D4 ; position to start of src scan
MOVE WIDCNT(A6),D1 ; get width of src
NXTPXL BFEXTU (A3){D4:D7},D0 ; extract a source pixel
MOVE 0(SP,D0*2),D0 ; translate it
BFINS D0,(A2){D5:D6} ; and put to dst
ADD.L D7,D4 ; bump to next src pixel
ADD.L D6,D5 ; bump to next dst pixel
DBRA D1,NXTPXL ; => repeat for each pixel in src
DBRA D2,NXTREP ; => repeat so expanded pat 32 wide
ADD patRow(A6),A3 ; else bump to next scan of src
DBRA D3,NXTSCAN ; => and repeat for each scanline
SUBQ #1,VREPCNT(A6) ; need to repeat vertically?
BPL.S NXTPASS ; => yes, take it from the top
; restore everything and return
MOVE.L SAVESTK(A6),SP ; restore the stack pointer
MOVEM.L (SP)+,D3-D7/A0/A2-A4 ; restore work registers
UNLINK PARAMSIZE,'PATCONVE' ; unlink and return
PatDither PROC EXPORT
IMPORT GetDevPix,Color2Index,Index2Color
;---------------------------------------------------------------
;
; PROCEDURE PatDither (PPH: PixPatHandle);
;
; Called with a pattern of patType = ditherPat (an RGB to be dithered),
; which has the desired RGB as the first entry (entry 0) of its
; color table. This routine finds the best-fit dithered pattern for
; the specified color, and adjusts the pattern data and the second
; entry in the color table so the pattern is ready to be expanded.
; This routine assumes the data and color table are the right size.
PARAMSIZE EQU 4
PPH EQU PARAMSIZE+8-4 ; handle to pattern
MYSPEC EQU -8 ; temporary color spec
BCur EQU MYSPEC-2 ; current delta in blue space
GCur EQU BCur-2 ; current delta in green space
RCur EQU GCur-2 ; current delta in red space
BStep EQU RCur-2 ; step amount in blue space
GStep EQU BStep-2 ; step amount in green space
RStep EQU GStep-2 ; step amount in red space
BestMatch EQU RStep-4 ; quality of best dither found
BestDelta EQU BestMatch-6 ; component deltas for best dither
LastDither EQU BestDelta-6 ; components of last dithered pair
BestDither EQU LastDither-6 ; components of best dithered pair
DesiredRGB EQU BestDither-8 ; RGB desired
compRGB EQU DesiredRGB-8 ; complement of current RGB
curRGB EQU compRGB-8 ; current RGB
saveComp EQU curRGB-8 ; save the best complement
saveCur EQU saveComp-8 ; save the best current
VARSIZE EQU saveCur
LINK A6,#VARSIZE ; allocate stack frame
MOVEM.L D3-D7/A2-A4,-(SP) ; save all registers
; get the color table and lock it down
MOVE.L PPH(A6),A0 ; get the pixPat handle
MOVE.L (A0),A0 ; point at the pixPat
MOVE.L patMap(A0),A3 ; A3 is pixMap handle
MOVE.L (A3),A0 ; point at the pixMap
MOVE.L pmTable(A0),A0 ; get the color table handle
_HLock ; lock while using
MOVE.L (A0),A4 ; A4 is color table pointer
MOVE.L CTTable(A4),DesiredRGB(A6) ; copy desired color
MOVE.L CTTable+4(A4),DesiredRGB+4(A6) ; from color table entry 0
MOVE #$3000,D7 ; get default stepsize
BSR BestTwo ; get best two points describing it
LEA saveCur(A6),A0 ; point to saved curRGB, compRGB
LEA CTTable(A4),A1 ; point to entry 0
MOVEQ #3,D0 ; copy 4 longs
@0 MOVE.L (A0)+,(A1)+ ; copy one long
DBRA D0,@0 ; repeat for curRGB, compRGB
MOVE #0,CTTable(A4) ; set entry number to 0
MOVE #1,CTTable+8(A4) ; set entry number to 1
LEA BestDither+red(A6),A0 ; point to error amounts
LEA DesiredRGB+rgb+red(A6),A1 ; point to desired values
MOVEQ #2,D2 ; repeat for 3 components
GetNext MOVE (A0)+,D0 ; get error for component
EXT.L D0 ; sign extend it
MOVEQ #0,D1 ; get component as positive long
MOVE (A1),D1 ; get desired value
SUB.L D0,D1 ; calc new desired
BMI.S Pin0 ; => it wrapped, pin to 0
BTST #16,D1 ; did it overflow a word?
BEQ.S SetIt ; => no, set desired value
MOVEQ #-1,D1 ; positive overflow, pin to $FFFF
BRA.S SetIt ; => set new desired
Pin0 MOVEQ #0,D1 ; pin to 0
SetIt MOVE D1,(A1)+ ; set new desired
DBRA D2,GetNext ; repeat for each component
MOVE #$2000,D7 ; get default stepsize
BSR BestTwo ; get best two points
LEA saveCur(A6),A0 ; point to saved curRGB, compRGB
LEA CTTable+16(A4),A1 ; start at third entry
MOVEQ #3,D0 ; copy 4 longs
@0 MOVE.L (A0)+,(A1)+ ; copy one long
DBRA D0,@0 ; repeat for curRGB, compRGB
MOVE #2,CTTable+16(A4) ; set entry number to 2
MOVE #3,CTTable+24(A4) ; set entry number to 3
; if entries 0 and 2 are the same, or 1 and 3 are the same, then
; swap entries 2 and 3 to get a better dither pattern
LEA CTTable+rgb(A4),A0 ; point to entry 0
LEA CTTable+16+rgb(A4),A1 ; point to entry 2
CMP.L (A0)+,(A1)+ ; are r,g same?
BNE.S CheckNxt ; =>no, check 1 and 3
CMP (A0)+,(A1)+ ; is b same?
BEQ.S SwapEm ; =>yes, swap 2,3
CheckNxt LEA CTTable+8+rgb(A4),A0 ; point to entry 1
LEA CTTable+24+rgb(A4),A1 ; point to entry 3
CMP.L (A0)+,(A1)+ ; are r,g same?
BNE.S NoSwap ; =>no, check 1 and 3
CMP (A0)+,(A1)+ ; is b same?
BNE.S NoSwap ; =>no, check 1 and 3
SwapEm MOVE #3,CTTable+16(A4) ; set entry number to 3
MOVE #2,CTTable+24(A4) ; set entry number to 2
NoSwap LEA FourPat,A0 ; use 50% pattern
MOVE.L PPH(A6),A4 ; get the pixPat handle
MOVE.L (A4),A1 ; point at the pixPat
MOVE.L patData(A1),A1 ; get the data handle
MOVE.L (A1),A1 ; point at the data
MOVE.L (A0)+,(A1)+ ; copy first quarter of pattern
MOVE.L (A0)+,(A1)+ ; copy second quarter of pattern
MOVE.L (A0)+,(A1)+ ; copy third quarter of pattern
MOVE.L (A0)+,(A1)+ ; copy fourth quarter of pattern
DONE MOVE.L (A3),A0 ; point at the pixMap
MOVE.L pmTable(A0),A0 ; get the color table handle
_HUnlock ; all done with it
MOVEM.L (SP)+,D3-D7/A2-A4 ; restore work registers
UNLINK PARAMSIZE,'DITHERPA' ; unlink and return
FourPat DC.L $1B1BB1B1 ; 8*8 pattern
DC.L $1B1BB1B1 ; two bits per pixel
DC.L $1B1BB1B1 ; pixels 0,1,2,3 repeated
DC.L $1B1BB1B1
BestTwo MOVE.L A3,-(SP) ; save A3
; for each component, determine the points to search. The default is
; desired-$3000, desired, desired+$3000. If the point is near the edge,
; the actual stepsize is adjusted.
LEA RStep(A6),A0 ; and point to steps
MOVE D7,(A0)+ ; init stepsizes
MOVE D7,(A0)+
MOVE D7,(A0)+
LEA DesiredRGB+rgb(A6),A0 ; point to the desired color
LEA RStep(A6),A1 ; point to steps
MOVEQ #2,D2 ; do 3 components
NxtCmp MOVE (A1),D1 ; get default step
MOVE (A0),D0 ; get desired component
ADD D1,D0 ; check cmp in that direction
BCC.S NxtEdge ; =>check next edge
SUB D0,(A1) ; else subtract overflow from delta
SUB #1,(A1) ; pin to $FFFF
BRA.S NotEdge ; =>do next component
NxtEdge MOVE (A0),D0 ; get desired component
SUB D1,D0 ; check cmp in opposite direction
BCC.S NotEdge ; =>not at edge
ADD D0,(A1) ; else add neg overflow to delta
NotEdge ADDQ #2,A0 ; bump desired pointer
ADDQ #2,A1 ; bump step pointer
DBRA D2,NxtCmp ; loop for all 3 components
; the ranges we just set define a cube surrounding the desired RGB in
; color space. What we want to do is to iterate through that cube, and
; determine the quality of dither achieved by pairing each point with its
; complementary point. RStep, GStep, BStep are the search intervals.
MOVEQ #-1,D0 ; get all F's
MOVE.L D0,BestMatch(A6) ; init best match to huge value
MOVE BStep(A6),BCur(A6) ; current blue := starting blue
NxtBlue MOVE GStep(A6),GCur(A6) ; current green := starting green
NxtGreen MOVE RStep(A6),RCur(A6) ; current red := starting red
NxtRed LEA DesiredRGB(A6),A0 ; point to desired color
LEA curRGB(A6),A1 ; point to current color
MOVE.L (A0)+,(A1)+ ; copy red
MOVE.L (A0),(A1)+ ; copy green, blue
SUBQ #4,A0 ; point to desired color
MOVE.L (A0)+,(A1)+ ; copy value, red to comp color
MOVE.L (A0),(A1) ; copy green, blue
LEA RCur(A6),A0 ; point to current delta
LEA curRGB+rgb(A6),A1 ; point to current color
LEA compRGB+rgb(A6),A2 ; point to complementary color
MOVEQ #2,D1 ; do three components
@0 MOVE (A0)+,D0 ; get delta
ADD D0,(A1)+ ; add to current color
SUB D0,(A2)+ ; subtract from complementary color
DBRA D1,@0 ; => repeat for all components
PEA curRGB(A6) ; push current color for Index2Color
MOVE.L (SP),-(SP) ; copy for Color2Index
JSR Color2Index ; get the index for that color
JSR Index2Color ; get the true color
PEA compRGB(A6) ; push complementary color
MOVE.L (SP),-(SP) ; and copy for Color2Index
JSR Color2Index ; get the index for that color
JSR Index2Color ; get the true complementary color
; approximate the quality of the dither based on how close the average of the two colors
; are to the desired color and on how close in color space the two colors are.
LEA curRGB+rgb(A6),A0 ; point to current RGB
LEA compRGB+rgb(A6),A1 ; point to complementary color
LEA DesiredRGB+rgb(A6),A2 ; point to desired color
LEA LastDither(A6),A3 ; place to save last dither
MOVEQ #0,D3 ; dither delta so far
MOVEQ #2,D2 ; do 3 components
NxtDither MOVEQ #0,D0 ; clear high word
MOVE (A0)+,D0 ; get current component
MOVEQ #0,D1 ; clear high word
MOVE (A1)+,D1 ; get current complement
@0 ADD.L D0,D1 ; sum the components
LSR.L #1,D1 ; and divide by 2
MOVEQ #0,D0 ; clear high word
MOVE (A2)+,D0 ; get desired component
SUB.L D0,D1 ; get dither error
MOVE D1,(A3)+ ; save dither error
BPL.S @1 ; => got positive
NEG.L D1 ; get positive error
@1 ADD.L D1,D3 ; add error to dither delta
DBRA D2,NxtDither ; calc dither for each component
; if the dither is the best so far, then record the RGB's
CMP.L BestMatch(A6),D3 ; is it a better match?
BHI.S NotBest ; =>no, keep searching
MOVE.L D3,BestMatch(A6) ; else save new best match
MOVE.L LastDither(A6),BestDither(A6) ; save errors of best dither
MOVE LastDither+4(A6),BestDither+4(A6)
LEA curRGB(A6),A0 ; point to current
LEA saveCur(A6),A1 ; point to save area
MOVEQ #3,D0 ; copy 4 longs
@2 MOVE.L (A0)+,(A1)+ ; copy a long
DBRA D0,@2 ; repeat for curRGB, compRGB
NotBest MOVE RCur(A6),D0 ; get current red
BMI.S AtREnd ; =>done if negative
MOVE RStep(A6),D1 ; get red step
BEQ.S AtREnd ; =>done if step 0
SUB D1,D0 ; step to next position
MOVE D0,RCur(A6) ; else update position
BRA NxtRed ; => go do next red
AtREnd MOVE GCur(A6),D0 ; get current green
BMI.S AtGEnd ; =>done if negative
MOVE GStep(A6),D1 ; get green step
BEQ.S AtGEnd ; =>done if step 0
SUB D1,D0 ; step to next position
MOVE D0,GCur(A6) ; else update position
BRA NxtGreen ; => go do next green
AtGEnd MOVE BCur(A6),D0 ; get current blue
BMI.S AtBEnd ; =>done if negative
MOVE BStep(A6),D1 ; get blue step
BEQ.S AtBEnd ; =>done if step 0
SUB D1,D0 ; step to next position
MOVE D0,BCur(A6) ; else update position
BRA NxtBlue ; => go do next blue
AtBEnd MOVE.L (SP)+,A3 ; restore A3
RTS
MAKERGBPAT PROC EXPORT
IMPORT OneBitData,CopyPMap
;---------------------------------------------------------------
;
; PROCEDURE MakeRGBPat (PPH: PixPatHandle; myRGB: RGBColor);
;
; Alters specified pattern to be type ditherPat (patType = 2).
; Data size is set to 8, and color table made large enough for
; two entries. The first entry is set to the specified RGB.
;
; Note that the dithering is not done here, it is done within
; PatConvert when the pattern is actually set.
;
PARAMSIZE EQU 8
PPH EQU PARAMSIZE+8-4 ; pixPatHandle
myRGB EQU PPH-4 ; RGB
VARSIZE EQU 0 ; no vars
LINK A6,#VARSIZE
MOVEM.L A2-A3,-(SP) ; save work register
MOVE.L PPH(A6),A1 ; get the pix pat handle
MOVE.L (A1),A0 ; point at the pix pat
MOVE #ditherPat,patType(A0) ; set type to ditherPat
MOVE.L patData(A0),A0 ; get the data handle
MOVEQ #16,D0 ; pattern is 16 bytes
_SetHandleSize ; so set the size
MOVE.L (A1),A0 ; point at the pix pat
MOVE.L patMap(A0),A3 ; get the pixMap handle
MOVE.L (A3),A0 ; point at the pix map
MOVE.L pmTable(A0),A0 ; get the color table handle
MOVEQ #CTRec+32,D0 ; size = header + 4 entries
_SetHandleSize ; set color table size
LEA OneBitData,A1 ; point to one bit data
MOVE.L (A3),A2 ; point to the pixMap
JSR CopyPMap ; copy data into pixMap
; clobbers A1, A2 (but not A0)
; also clobbers color table
MOVE.L (A3),A2 ; get back pixMap pointer
MOVE.L A0,pmTable(A2) ; restore color table
MOVE #2,pRowBytes(A2) ; 2 bytes per row
CLR.L pBounds+topLeft(A2) ; bounds = (0,0,8,8)
MOVE.L #$00080008,pBounds+botRight(A2)
MOVE #2,pixelsize(A2) ; two bits per pixel
MOVE.L (A0),A0 ; point at the color table
CLR transIndex(A0) ; clear transIndex
MOVE #3,CTSize(A0) ; say there are 4 entries
ADD #CTRec,A0 ; point at entry 0
MOVE.L myRGB(A6),A1 ; point at the desired color
CLR (A0)+ ; clear value field
MOVE.L (A1)+,(A0)+ ; copy red, green
MOVE (A1),(A0) ; copy blue
MOVEM.L (SP)+,A2-A3 ; restore work register
UNLINK PARAMSIZE,'GETRGBPA' ; unlink and return
SETFILLPAT PROC EXPORT
IMPORT OLDPATTONEW,PatConvert
;---------------------------------------------------------------
;
; PROCEDURE SETFILLPAT (PAT:PATTERN);
;
; Called by: FillRect, FillCRect, FillOval, FillCOval, FillRoundRect, FillCRoundRect
; FillArc, FillCArc, FillRgn, FillCRgn, FillPoly, FillCPoly
;
; On Entry: D0 = 0 Called by old fill routine
; D0 = 1 Called by color fill routine
;
; If called by old routine, install old-style pattern into FillPat (if old port)
; or FillPixPat (if new port). If called by new routine, install new-style pattern
; into FillPixPat (if new port) or just return (if old port).
MOVE.L 4(SP),A1 ;GET PATTERN POINTER
MOVE.L GRAFGLOBALS(A5),A0 ;GET GRAFGLOBALS
MOVE.L THEPORT(A0),A0 ;GET THE PORT
TST PORTBITS+ROWBYTES(A0) ;IS IT A COLOR GRAFPORT?
BPL.S SETOLD ;=>NO, SET OLD PATTERN
TST D0 ;OLD PATTERN OR NEW
BNE.S NEWFILLPAT ;=>NEW, SET NEW PATTERN
MOVE.L A1,-(SP) ;ELSE PUSH PATTERN
PEA FILLPIXPAT(A0) ;AND PIXPAT HANDLE
JSR OLDPATTONEW ;AND CONVERT TO COLOR PATTERN
BRA.S DONE
SETOLD TST D0 ;OLD PATTERN OR NEW?
BNE.S DONE ;=>NEW, JUST EXIT
LEA FILLPAT(A0),A0 ;POINT TO DST
MOVE.L (A1)+,(A0)+ ;COPY PAT INTO FILLPAT
MOVE.L (A1)+,(A0)+ ;ALL EIGHT BYTES
DONE MOVE.L (SP)+,(SP) ;STRIP PARAMETER
RTS ;AND RETURN
NEWFILLPAT
; Install the specified pixPatHandle at the specified position.
; We know the specified place is either NIL or contains a pixPatHandle.
; If it contains an old-style pixPatHandle, then dispose it before replacing.
MOVE.L 4(SP),-(SP) ; push the pixPatHandle
JSR PatConvert ; expand to current depth
MOVE.L (SP)+,A1 ; get the return address
LEA FILLPIXPAT(A0),A0 ; get handle pointer
MOVE.L A0,D2 ; save in D2
MOVE.L (A0),D0 ; is there a handle?
BEQ.S InstallNew ; => no, just install
MOVE.L D0,A0 ; get the pixpat handle
TST ([A0],PatType) ; is it an old one?
BNE.S InstallNew ; =>no, install pattern
_DisposHandle ; and dispose it
InstallNew MOVE.L D2,A0 ; get address of pnFillPat
MOVE.L (SP)+,(A0) ; install the handle
JMP (A1) ; and return
END