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

1928 lines
60 KiB
Plaintext

;
; File: DrawPicture32Patch.a
;
; Contains: This patch gets loaded on Classic QD machines
;
; Written by: Konstantin Othmer
;
; Copyright: © 1987-1990 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <12> 3/23/91 KON csd, WRKSHT#SAH-QD-58: ReduceD3D4 would hang because MapRatio
; would return a zero result. I removed calls to MapRatio (since
; ReduceD3D4 does the same work) and changed ReduceD3D4 so it
; won't hang.
; <11> 1/14/91 KON Reduce Numer and Denom by GCD when drawing a picture. These
; overflow on higher DPI devices. [CEL]
; <10> 11/7/90 KON Fix display of 16-bit pixmaps (were drawn as all black). [smc]
; <9> 9/21/90 KON Added check for PICT2 header so we use the resolution adjusted
; rectangle for the header if the picture was created by
; openCPicture.
; <8> 9/17/90 dba Fix loop case for unpacking bits when the rectangle has a 0
; height. This was crashing while printing in Claris applications.
; <7> 9/11/90 KON Remove benign redefinition of pixmapTooDeepErr.
; <6> 8/2/90 gbm fix more warnings
; <5> 7/20/90 gbm get rid of excess equates
; <4> 4/4/90 KON Make into a linked patch
; <3> 3/29/90 KON Broke traps which load on all B&W machines to a new file
; AllB&WQDPatch.a. This makes the disk footprint much smaller.
; <2> 3/16/90 KON Add gWorld calls to PLUS, SE, and portable.
; <1.5> 12/4/89 KON Uses GrafTypes.m.a for include rather than ColorEqu.a.
; <1.4> 11/15/89 KON Now includes common file GetPMData.a and installs GetPMData as
; Trap $ABC4.
; <1.3> 11/9/89 KON Patch BitMapRgn only on Plus and SE
; <1.2> 11/7/89 KON Fixed font name/ID binding, added ptch for open picture and
; close picture
; <1.1> 11/7/89 BAL Added Font Name/ID binding, draw picture now works in low memory
; situations
; <1.0> 10/16/89 CCH Adding to EASE.
; 8/25/89 KON Added support for 16 & 32 bit picts for plus and SE
; PMAB270> 9/13/87 FJL Patch DrawPicture to first check for valid picture handle and
; pointer, then do GetState, make it non-purgeable, and SetState
; on return. At the request of Sheila, Phil and Scott.
; <PMA207> 7/16/87 EHB If device color table found, fill in pixel values
; <PMA157> 3/30/87 DBG Fixed bug where color table was freed even if there wasn't one.
; <S072> 2/27/87 DBG Added support for interpolated colors
; <S051> 2/19/87 DBG Fixed bug in interpretation of color table
;
;INITFILE EQU 0 ;set to 1 for standalone install, 0 for ptchInstall
;withFonts EQU 1 ;set to 1 to build with font name/ID binding
;wholeErrors EQU 1
;; INCLUDE 'SysErr.a'
; INCLUDE 'Traps.a'
; INCLUDE 'QuickEqu.a'
; INCLUDE 'SysEqu.a'
; INCLUDE 'GrafTypes.m.a'
; INCLUDE 'LinkedPatchMacros.a'
; RomBinds were here
PStdBits_SE_Portable EQU $0E00+(4*$EB)
PStdBits_Plus EQU $0C00+(4*$EB)
PStdGetPic_SE_Portable EQU $0E00+(4*$EE)
PStdGetPic_Plus EQU $0C00+(4*$EE)
IF (&TYPE('onMac') = 'UNDEFINED') THEN
onMac EQU 0
ENDIF
IF (&TYPE('onMacPP') = 'UNDEFINED') THEN
onMacPP EQU 0
ENDIF
noROM EQU 0
StdOpcodeProc PROC EXPORT
IMPORT GETWORD, GetLong,GetPicdata
;------------------------------------------------------------------
;
; PROCEDURE StdOpcode(fromRect,toRect: Rect; opcode,version: INTEGER);
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch DrawPicturePatch.a 01Jan1904 #??? (StdOpcode) (StdOpcode)
;
; GETS CALLED FOR OPCODE VALUES $0100-$FFFF
;
; OPCODE: $0100-$01FF 2 BYTES DATA
; $0200-$02FF 4 BYTES DATA
; ...
; $7F00-$7FFF 254 BYTES DATA
; $8000-$80FF 0 BYTES DATA
; $8100-$FFFF 4 BYTES SIZE + SIZE BYTES DATA
;
; THIS PROCEDURE READS THE OPCODE'S DATA AND IGNORES IT unless it's the header
; from a PICT 2 created by OpenCPicture. <20Sept90 KON>
;
;--------------------------------------------
;
; OFFSETS WITHIN A PICTURE PLAY STATE RECORD:
;
THERECT EQU 0 ;RECT
PENLOC EQU THERECT+8 ;POINT
TEXTLOC EQU PENLOC+4 ;POINT
OVALSIZES EQU TEXTLOC+4 ;POINT
FROMRECT EQU OVALSIZES+4 ;RECT
TORECT EQU FROMRECT+8 ;RECT
NUMER EQU TORECT+8 ;POINT
DENOM EQU NUMER+4 ;POINT
THECLIP EQU DENOM+4 ;RGNHANDLE
USERCLIP EQU THECLIP+4 ;RGNHANDLE
PLAYVERSION EQU USERCLIP+4 ;PICTURE VERSION
TXHFRAC EQU PLAYVERSION+2 ;FRACTIONAL TEXT POSITION
NEWHFRAC EQU TXHFRAC+2 ;UPDATED FRACTION RECIEVED
TEMPPIXPAT EQU NEWHFRAC+2 ;PIXPAT FOR PLAYING NEW PICS IN OLD PORTS
FontMappingTbl EQU TEMPPIXPAT+4 ;Handle to array of old,new font id pairs
PSreserve1 EQU FontMappingTbl+4 ;reserved
PSreserve2 EQU PSreserve1+4 ;reserved
PLAYREC EQU PSreserve2+4 ;TOTAL SIZE
;------------------------------------------------------
;
; New offsets in a PICT2 header record:
;
hdrVersion EQU 0 ;Word (=-2)
hdrReserved EQU hdrVersion+2 ;Word
hdrHRes EQU hdrReserved+2 ;Fixed
hdrVRes EQU hdrHRes+4 ;Fixed
hdrSrcRect EQU hdrVRes+4 ;Rect
hdrReserved2 EQU hdrSrcRect+8 ;Long
picHdrSize EQU hdrReserved2+4 ;size of a PICT2 header record
;------------------------------------------------------------------
;
; PROCEDURE StdOpcode(fromRect,toRect: Rect; opcode,version: INTEGER);
;
; GETS CALLED FOR OPCODE VALUES $0100-$FFFF
;
; OPCODE: $0100-$01FF 2 BYTES DATA
; $0200-$02FF 4 BYTES DATA
; ...
; $7F00-$7FFF 254 BYTES DATA
; $8000-$80FF 0 BYTES DATA
; $8100-$FFFF 4 BYTES SIZE + SIZE BYTES DATA
;
; THIS PROCEDURE READS THE OPCODE'S DATA AND IGNORES IT
;
; A6 OFFSETS OF PARAMS AFTER LINK:
;
PARAMSIZE EQU 12
pFROMRECT EQU PARAMSIZE+8-4 ;LONG
pTORECT EQU pFROMRECT-4 ;LONG
OPCODE EQU pTORECT-2 ;WORD
VERSION EQU OPCODE-2 ;WORD
LINK A6,#0 ;NO LOCAL VARS
MOVEM.L D6/D7,-(SP) ;SAVE WORK REGISTERS
MOVE.L #256,D6 ;GET USEFUL NUMBER
SUB.L D6,SP ;ALLOCATE STACK BUFFER
MOVE OPCODE(A6),D0 ;GET THE OPCODE
BMI.S GETSIZE ;=>OP CONTAINS SIZE
LSR #8,D0 ;GET SIZE/2 IN LOW NIBBLE
ADD D0,D0 ;CALC SIZE
EXT.L D0 ;MAKE IT LONG
BRA.S SHARE ;=>USE COMMON CODE
GETSIZE AND #$7F00,D0 ;MASK THE OPCODE
BEQ.S DONE ;=>NO DATA BYTES
JSR GETLONG ;READ IN SIZE
SHARE MOVE.L D0,D7 ;SAVE WHOLE SIZE
NXTCHNK MOVE D6,D0 ;ASSUME SIZE >= 256
CMP.L D6,D7 ;IS SIZE >= 256?
BGE.S SIZEOK ;=>YES, SKIP 256 BYTES
MOVE D7,D0 ;ELSE SKIP REMAINING BYTES
SIZEOK MOVE.L SP,-(SP) ;PUSH BUFFER POINTER
MOVE D0,-(SP) ;PUSH BYTECOUNT
JSR GETPICDATA ;READ DATA INTO BUFFER
SUB.L D6,D7 ;SUBTRACT BUFSIZE FROM COUNT
BGT.S NXTCHNK ;=>GO SKIP NEXT CHUNK
;
; This stuff is taken from Pictures.a <20Sept90 KON>
;
cmp.w #ngHeaderOp,OPCODE(a6) ;pict2 header opcode? <18Jan90 KON>
bne.s done ;not a pict2 header opcode <18Jan90 KON>
cmp.w #$fffe,(sp) ;is it version -2 header? <18Jan90 KON>
bne.s done ;<27nov89 KON> <18Jan90 KON>
move.l pFromRect(a6),a1 ;point to playstate's FromRect
lea hdrSrcRect(sp),a0 ;point to sourceRect stored in header record
MOVE RIGHT(A0),D0
SUB LEFT(A0),D0 ;CALC SRC WIDTH
MOVE D0,DENOM+H-FromRect(A1) ;DENOM.H := SRC WIDTH
MOVE BOTTOM(A0),D0
SUB TOP(A0),D0 ;CALC SRC HEIGHT
MOVE D0,DENOM+V-FromRect(A1) ;DENOM.V := SRC HEIGHT
MOVE.L (A0)+,(A1)+
MOVE.L (A0)+,(A1)+ ;FROMRECT := PICFRAME
;
; end <20Sept90 KON>
;
DONE ADD.L D6,SP ;STRIP BUFFER
MOVEM.L (SP)+,D6/D7 ;RESTORE WORK REGISTERS
UNLINK PARAMSIZE,'STDPICPR' ;destroys condition codes
ENDPROC
;=========================================================================================
;=========================================================================================
;
; Add routines to calculate to reduce numer and denom by GCD
;
; These are called by DrawPicture and PicItem1
;
;=========================================================================================
;=========================================================================================
CalcGCD PROC EXPORT
; Routine returns GCD( d0, d1 ) using Euclidean method
; On Entry: D0 and D1 contain word size values to reduce
; On Exit: D0 and D1 both contain GCD
;
cmp.l d0,d1 ;while d0 != d1 (unsigned word compare)
beq.s @FoundGCD
bgt.s @D1isBigger ; if( d1 < d0 )
exg d0,d1 ; swap( d1, d0 )
@D1isBigger
sub d0,d1 ; d1 = d1 - d0
bra.s CalcGCD ;end while
@FoundGCD
rts ;d0 and d1 contain GCD
ENDPROC
ReduceD3D4 PROC EXPORT
IMPORT CalcGCD
; Routine returns ReduceD3D4( d3, d4 ) reduces d3.w and d4.w by GCD for
; both the low and high words
;
; On Entry: D3 and D4 contain two word size values to reduce
; On Exit: D3 and D4 contain reduced values
;
;
; Divide Numer and Denom for width and height by GCD to prevent overflow.
;
moveq #0,d0 ;make sure high word is zero for next 2 divides
move.l d0,d1 ;CalcGCD exchanges regs, so both need to be cleared
move.w d3,d0 ;D0 has denom.v, d1 has numer.v
beq.s @Done ;abort if zero.
move.w d4,d1 ;D0 has denom.v, d1 has numer.v
beq.s @Done ;abort if zero.
jsr CalcGCD ;returns GCD in d0
move.w d3,d1 ;D0 has denom.v, d1 has numer.v
divu.w d0,d1 ;dividing by GCD should never leave remainder
move.w d1,d3 ;save reduced numer.v
move.w d4,d1 ;D0 has denom.v, d1 has numer.v
divu.w d0,d1
move.w d1,d4 ;save reduced denom.v
;
; Now do width: Could have different scale factor than height did
;
swap d3 ;operate on high word
swap d4
move.w d3,d0 ;D0 has denom.h, d1 has numer.h
beq.s @DoneSwap ;abort if zero.
move.w d4,d1 ;D0 has denom.h, d1 has numer.h
beq.s @DoneSwap ;abort if zero.
jsr CalcGCD ;returns GCD in d0
move.w d3,d1 ;D0 has denom.h, d1 has numer.h
divu.w d0,d1 ;dividing by GCD should never leave remainder
move.w d1,d3 ;save reduced numer.h
move.w d4,d1 ;D0 has denom.h, d1 has numer.h
divu.w d0,d1
move.w d1,d4 ;save reduced denom.h
@DoneSwap
swap d3 ;put things back
swap d4
@Done
rts ;all done
;
; End <KON 7/1/91>
;
ENDPROC
INCLUDE 'DrawPicturePlusSE.a'
INCLUDE 'DrawPicturePortable.a'
;---------- broke out local procs from picItem1 for code sharing ------------
GETSBYTE FUNC EXPORT
IMPORT GetPicData
;------------------------------------------------------
;
; LOCAL PROCEDURE TO GET A SIGNED BYTE INTO D0 FROM PICTURE
;
CLR.B -(SP) ;ALLOCATE TEMP
MOVE.L SP,-(SP) ;PUSH ADDR OF TEMP
MOVE #1,-(SP) ;PUSH BYTECOUNT
JSR GetPicData ;GET DATA FROM THEPIC
MOVE.B (SP)+,D0 ;POP RESULT
EXT.W D0 ;SIGN EXTEND TO WORD
RTS
;-----------------End of breaking out local procs-----------------------------
GETLONG FUNC EXPORT
IMPORT GetPicData
;----------------------------------------------------------
;
; LOCAL PROCEDURE TO GET A LONG FROM PICTURE INTO D0
;
CLR.L -(SP) ;ALLOCATE TEMP
MOVE.L SP,-(SP) ;PUSH ADDR OF TEMP
MOVE #4,-(SP) ;PUSH BYTECOUNT
JSR GetPicData ;GET DATA FROM THEPIC
MOVE.L (SP)+,D0 ;RETURN ANSWER IN D0
RTS
MAPMODE FUNC EXPORT
;----------------------------------------------------------
;
; LOCAL PROCEDURE TO MAP COLOR QUICKDRAW MODES TO OLD MODES
;
CMP.W #$1F,D0 ;OLD MODE, OR UNKNOWN?
BLS.S DONEMODE ;SKIP OUT
CMP.W #$2F,D0 ;WITHIN CORRECT RANGE?
BLS.S @MAPIT ;SKIP IF SO
CMP.W #$32,D0 ;HILITE?
BEQ.S @MAPIT ;SKIP IF SO
CMP.W #$3A,D0 ;HILITE?
BNE.S DONEMODE ;NO, PASS THROUGH
@MAPIT
AND.W #7,D0 ;EXTRACT LOW 3 BITS
MOVE.B arithMode(D0.W),D0 ;GET EQUIVALENT MODE
DONEMODE
RTS ;QUIT
; [This table extracted from utils.a]
arithMode
; hilite
;avg addPin addOver subPin trans max subOver min
DC.B srcCopy, srcBic, srcXor, srcOr, srcOr, srcBic, srcXor, srcOr
SkipPicData PROC EXPORT
IMPORT GETPICDATA
;----------------------------------------------------------
;
; LOCAL PROCEDURE TO SKIP D0.L BYTES IN THE PICTURE
;
MOVEM.L D6/D7,-(SP) ;SAVE WORK REGISTERS
MOVE.L #256,D6 ;GET USEFUL NUMBER
SUB.L D6,SP ;ALLOCATE STACK BUFFER
MOVE.L D0,D7 ;SAVE WHOLE SIZE
BEQ.S IGDONE ;=>NO DATA, JUST RETURN
NXTCHNK MOVE D6,D0 ;ASSUME SIZE >= 256
CMP.L D6,D7 ;IS SIZE >= 256?
BGE.S IGSIZEOK ;=>YES, SKIP 256 BYTES
MOVE D7,D0 ;ELSE SKIP REMAINING BYTES
IGSIZEOK MOVE.L SP,-(SP) ;PUSH BUFFER POINTER
MOVE D0,-(SP) ;PUSH BYTECOUNT
JSR GETPICDATA ;READ DATA INTO BUFFER
SUB.L D6,D7 ;SUBTRACT BUFSIZE FROM COUNT
BGT.S NXTCHNK ;=>GO SKIP NEXT CHUNK
IGDONE ADD.L D6,SP ;STRIP BUFFER
MOVEM.L (SP)+,D6/D7 ;RESTORE WORK REGISTERS
RTS
GetPicTable PROC EXPORT
IMPORT GetPicData,GETLONG
;------------------------------------------------------
;
; PROCEDURE GetPicTable(CTabHandle);
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch DrawPicturePatch.a 01Jan1904 #??? (GetPicTable) (GetPicTable)
;
;
JSR GETLONG ;GET SEED INTO D0
MOVE.L D0,-(SP) ;SAVE SEED
JSR GETLONG ;GET TRANSINDEX, SIZE INTO D0
MOVE.L D0,-(SP) ;SAVE TRANSINDEX,SIZE
MOVE D0,D2 ;GET SIZE INTO D2
ADDQ #1,D2 ;MAKE IT ONE BASED
MULU #CTENTRYSIZE,D2 ;GET SIZE OF TABLE
MOVE.L D2,D0 ;SAVE SIZE OF TABLE
ADD #CTREC,D0 ;ADD SIZE OF HEADER
MOVE.L 12(SP),A0 ;GET HANDLE
_SETHANDLESIZE ;RESIZE IT
BEQ.S @1 ;Skip if OK
MOVEQ #25, D0 ;Sayonara, sweetheart
_SysError
; ??? Should really be able to do better than this. Maybe if this fails,
; we should do an _EmptyHandle as a signal to the caller that we flopped???
@1
_HLock ;LOCK IT
MOVE.L (A0),A0 ;POINT TO CTAB
MOVE.L (SP)+,D0 ;GET TRANSINDEX,SIZE
MOVE.L (SP)+,(A0)+ ;COPY SEED TO CTAB
MOVE.L D0,(A0)+ ;COPY TRANSINDEX,SIZE
MOVE.L A0,-(SP) ;PUSH DST POINTER
MOVE D2,-(SP) ;PUSH BYTECOUNT
JSR GETPICDATA ;READ DATA FROM PICTURE
MOVE.L 4(SP),A0 ;GET HANDLE
_HUnlock ;UNLOCK IT
MOVE.L (A0),A0 ;point to table <PMA207>
TST transIndex(A0) ;device color table? <PMA207>
BPL.S @done ;=>no, just return <PMA207>
MOVE ctSize(A0),D0 ;get size of table <PMA207>
MOVEQ #0,D1 ;get first pixel value <PMA207>
ADDQ #ctRec,A0 ;point to first entry <PMA207>
@2 MOVE D1,(A0) ;stuff a pixel <PMA207>
ADDQ #ctEntrySize,A0 ;bump to next entry <PMA207>
ADDQ #1,D1 ;bump to next pixel value <PMA207>
DBRA D0,@2 ;repeat for all entries <PMA207>
@done MOVE.L (SP)+,(SP) ;STRIP PARAM
RTS ;AND RETURN
;
; GetPicData, getubyte, getword also appear in DrawPicture32Patch.a. They should
; only appear in one place xxxxx
;
GetPicData PROC EXPORT
;------------------------------------------------------------------
;
; PROCEDURE GetPicData(dataPtr: QDPtr; byteCount: INTEGER);
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch DrawPicturePatch.a 01Jan1904 #??? (GetPicData) (GetPicData)
;
;
MOVE.L 6(SP),-(SP) ;COPY DATAPTR
MOVE.W 8(SP),-(SP) ;COPY BYTECOUNT
MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS
MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT
MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ?
MOVE.L PStdGetPic_SE_Portable,A0 ;get piece of trap table (SE or Portable)
ENTRY GetPicDataStdGetPic
GetPicDataStdGetPic equ * - 2 ;fix the word in the above instruction on Plus
BEQ.S USESTD ;yes, use std proc
MOVE.L D0,A0
MOVE.L GETPICPROC(A0),A0 ;NO, GET GET PROC PTR
USESTD JSR (A0) ;AND CALL IT
MOVEQ #0,D0 ;CLEAR HIGH WORD
MOVE.W 4(SP),D0 ;GET BYTECOUNT
MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS
ADD.L D0,PLAYINDEX(A0) ;BUMP PLAYINDEX
MOVE.L (SP)+,A0 ;RETURN ADDRESS
ADDQ #6,SP ;STRIP PARAMS
JMP (A0) ;RETURN
ENDPROC
FixStdGetPicInGetPicData INSTALLPROC (Plus)
IMPORT GetPicDataStdGetPic
lea GetPicDataStdGetPic,a0 ;point at above code
move.w #PStdGetPic_Plus,(a0) ;jam in the correct vector for the Mac. Plus
rts
ENDPROC
GETUBYTE FUNC EXPORT
IMPORT GetPicData
;------------------------------------------------------
;
; LOCAL PROCEDURE TO GET AN UNSIGNED BYTE INTO D0 FROM PICTURE
;
CLR.B -(SP) ;ALLOCATE TEMP
MOVE.L SP,-(SP) ;PUSH ADDR OF TEMP
MOVE #1,-(SP) ;PUSH BYTECOUNT
JSR GetPicData ;GET DATA FROM THEPIC
CLR D0 ;GET READY FOR BYTE
MOVE.B (SP)+,D0 ;POP RESULT INTO LO BYTE
RTS
GETWORD FUNC EXPORT
IMPORT GetPicData
;------------------------------------------------------
;
; LOCAL PROCEDURE TO GET A WORD FROM PICTURE INTO D0
;
CLR.W -(SP) ;ALLOCATE TEMP
MOVE.L SP,-(SP) ;PUSH ADDR OF TEMP
MOVE #2,-(SP) ;PUSH BYTECOUNT
JSR GetPicData ;GET DATA FROM THEPIC
MOVE (SP)+,D0 ;RETURN ANSWER IN D0
RTS
GetPicPixPat PROC EXPORT
IMPORT GetWord,GETPICDATA
IMPORT RGB2Pat,GETLONG,GetUByte
;------------------------------------------------------
;
; PROCEDURE GetPicPixPat(PatPtr);
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch DrawPicturePatch.a 01Jan1904 #??? (GetPicPixPat) (GetPicPixPat)
;
;
; GET TYPE AND ONE BIT PATTERN FROM THE PICTURE
MOVEQ #10,D0 ;GET NUMBER OF BYTES
SUB D0,SP ;MAKE ROOM FOR TYPE, PATTERN
MOVE.L SP,-(SP) ;PUSH POINTER
MOVE D0,-(SP) ;PUSH BYTE COUNT
JSR GETPICDATA ;READ IN 10 BYTES
MOVE.L 14(SP),A0 ;GET PTR TO PATTERN
MOVE (SP)+,D1 ;GET TYPE
MOVE.L (SP)+,(A0)+ ;SAVE 1ST HALF PATTERN
MOVE.L (SP)+,(A0) ;SAVE 2ND HALF PATTERN
CMP.W #ditherPat,D1 ;IS IT A DITHER PATTERN?
BNE.S @1 ;No, just use pattern data
MOVEQ #6,D0 ;Size of RGB buffer
SUB.L D0,SP ;MAKE ROOM FOR RGB ON STACK
MOVE.L SP,-(SP) ;BUFFER ADDRESS
MOVE D0,-(SP) ;LENGTH
jsr GetPicData ;GET R, G, B
MOVE.L SP,A1 ;Point at RGB
JSR RGB2Pat ;Get pattern
ADDQ #6,SP ;Blow off RGB
MOVE.L 4(SP),A1 ;GET PAT PTR
MOVE.L D0,(A1)+ ;Copy gray pattern
MOVE.L D0,(A1)
BRA.S PATDONE ;No pixmap to skip
@1
; GET PIXMAP FROM THE PICTURE
MOVEQ #PMREC-4,D0 ;Size of record
SUB.W D0,SP ;Make handy buffer
MOVE.L SP,-(SP) ;Push PIXMAP pointer
MOVE.W D0,-(SP) ;Push length
JSR GetPicData ;Get the information
; SKIP THE COLOR TABLE.
JSR GETLONG ;Skip the seed
JSR GETLONG ;Get TRANSINDEX, SIZE
ADDQ #1,D0 ;Make size 1-based
MULU #CTENTRYSIZE,D0 ;Get size of table
JSR SkipPicData ;Skip the rest of the table
; SKIP PIXMAP DATA FROM PICTURE
LEA -4(SP),A1 ;GET PIXMAP POINTER
MOVE BOUNDS+BOTTOM(A1),D1 ;GET TOP OF PIXMAP
SUB BOUNDS+TOP(A1),D1 ;CALC HEIGHT OF PIXMAP
MOVE ROWBYTES(A1),D0 ;GET WIDTH OF PIXMAP
AND #RBMASK,D0 ;MASK OFF FLAG BITS
CMP #8,D0 ;IS ROWBYTES < 8
BLT.S @NOPACK ;=>YES, DON'T UNPACK
MOVEM.L D3-D4,-(SP) ;SAVE WORK REGS
MOVE D0,D3 ;SAVE ROWBYTES
MOVE D1,D4 ;SAVE HEIGHT
BRA.S @START1 ;GO TO LOOP START
@MORE1
CMP #250,D3 ;IS ROWBYTES > 250
BGT.S @3 ;=>YES, GET WORD
JSR GetUByte ;ELSE GET A BYTE INTO D0
BRA.S @2 ;=>AND GO GET DATA
@3 JSR GETWORD ;GET A WORD INTO D0
@2
SWAP D0 ;HIGH WORD
CLR.W D0 ;MAKE SURE IT'S 0
SWAP D0 ;GET BACK IN RIGHT ORDER
JSR SkipPicData ;Skip that much
@START1
DBRA D4,@MORE1 ;LOOP HEIGHT ROWS
MOVEM.L (SP)+,D3-D4 ;RESTORE WORK REGS
BRA.S @PIXDONE ;CONTINUE
;
; ROWBYTES < 8, DON'T USE PACKING
;
@NOPACK
MULU D1,D0 ;GET DATA SIZE
JSR SkipPicData ;Skip that much
@PIXDONE
ADD #PMREC-4,SP ;POP PIXMAP
PATDONE
MOVE.L (SP)+,(SP) ;STRIP PARAM
RTS ;AND RETURN
GetPM1Deep PROC EXPORT
IMPORT GetUByte,GetWord,GetPicData, patTBL
;------------------------------------------------------
;
; PROCEDURE GetPM1Deep(myDst: Ptr; xTab: Ptr; myData: Handle; targetRB: SHORT; mode SHORT); <19Feb87 DBG>
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch DrawPicturePatch.a 01Jan1904 #??? (GetPM1Deep) (GetPM1Deep)
;
; HANDLE SIZE IS SET TO ROWBYTES*(BOUNDS.BOTTOM-BOUNDS.TOP) EXTERNALLY
;
PARAMSIZE EQU 16
MYDST EQU PARAMSIZE+8-4 ;DST PIXMAP POINTER
XTAB EQU MYDST-4 ;TRANSLATE TABLE POINTER <19Feb87 DBG>
MYDATA EQU XTAB-4 ;DST DATA HANDLE <19Feb87 DBG>
TARGETRB EQU MYDATA-2 ;TARGET ROWBYTES
MODE EQU TARGETRB-2 ;copybits copy mode (64 means dither)
SrcHndl EQU -4 ;VAR POINTER TO SOURCE
DSTPTR EQU SrcHndl-4 ;VAR POINTER TO DST
PACKBUF EQU DSTPTR-4 ;POINTER TO PACKING BUFFER
SAVEDSP EQU PACKBUF-4 ;PRESERVE STACK POINTER
BITSDST EQU SAVEDSP-4 ;CURRENT OUTPUT POINTER
MUSTMAP EQU BITSDST-2 ;NEED TO MAP?
LastError EQU MustMap-2 ;luminance error value
Direction EQU LastError-2 ;alternate directions for dither
VARSIZE EQU Direction
LINK A6,#VARSIZE ;MAKE A STACK FRAME
MOVEM.L D3-D7/A2-A4,-(SP) ;SAVE WORK REGISTERS
MOVE.L SP,SAVEDSP(A6) ;PRESERVE STACK POINTER
MOVE.L MYDST(A6),A2 ;POINT TO PIXMAP
MOVE.L MYDATA(A6),A0 ;GET DATA HANDLE
; _HLOCK ;LOCK IT DOWN
MOVE.L (A0),BITSDST(A6) ;GET DATA POINTER IN BITSDST
MOVE BOUNDS+BOTTOM(A2),D7
SUB BOUNDS+TOP(A2),D7 ;HEIGHT := BOUNDS BOT - TOP
MOVE ROWBYTES(A2),D5 ;GET ROWBYTES
SMI MUSTMAP(A6) ;SET FLAG IFF PIXMAP
AND #RBMASK,D5 ;CLEAR OFF FLAG BITS
;
; Here we calculate ROWBYTES + ROWBYTES/64, rounded up to an even number.
; The worst-case expansion from _PackBits is one extra byte for every
; 127 bytes of data. Rather than divide by 127, we divide by 64, the next
; lowest power of 2.
;
MOVE D5,D6 ;COPY ROWBYTES
ADD #63,D6 ;MAKE SURE TO ROUND UP!
LSR.W #6,D6 ;GET CEIL(ROWBYTES/64)
ADDQ.W #1,D6 ;ROUND UP...
BCLR #0,D6 ;...TO EVEN NUMBER
ADD D5,D6 ;SIZE OF PACKED BUFFER
CMP #8,D5 ;ROWBYTES < 8?
BGE.S @DOUNPACK ;=>NO, GO DO UNPACK
TST ROWBYTES(A2) ;BITMAP, NOT PIXMAP?
BPL NOPACK ;GO READ IT STRAIGHT IN
@DOUNPACK
TST.B MUSTMAP(A6) ;PIXMAP?
BEQ.S @GetRow ;=>NO, BITMAP
MOVE PIXELSIZE(A2),D4 ;=>YES, PIXMAP: GET BITS/PIXEL
cmp #32,d4 ;32 bit/pixel?
beq @getrow ;if so, skip get mask stuff
MOVE D4,D0 ;COPY IT
LSL.W #1,D0 ;DOUBLE IT
NEG.W D0 ;NEGATE IT
; ??? 64K ROM problem. Need to do LEA on 64K ROM. ???
_GetMaskTable ;GET MASK TABLE ADDRESS
MOVE (16*2*2)(A0,D0.W),D3 ;GET MASK FOR PIXEL
MOVE.L XTAB(A6),A4 ;XLATE TABLE POINTER <19Feb87 DBG>
CMP.W #1,D4 ;TEST BITS/PIXEL
BNE.S @GetRow ;IF <>1, MUST MAP
CMP.W #$0001,(A4) ;MAPPING NEEDED? <19Feb87 DBG>
SNE MUSTMAP(A6) ;IF NOT $0001, MUST MAP
;----------------------------------------------------------------
;
; Get unpacked data one row at a time
;
@GetRow
;
; Allocate handle for one row of source information
; and initialize various dither parameters
;
move.w #-127, LastError(a6) ;init luminance error (8-bit)
cmp.w #16,d4
bne @1
move.w #-15, LastError(a6) ;5-bit luminance error init
@1
move.w #0, direction(a6)
move RowBytes(A2),d0
and #RBMASK,d0
_NewHandle ;allocate handle for row of source info
bne.s ExitGetPM1Deep ;Exit with not equal set <Halloween89 KON>
move.l a0, SrcHndl(a6)
_HLock
;
; Do one row at a time
;
move Bounds+bottom(a2), d5 ;Save old bounds.bottom
move Bounds+top(a2), Bounds+bottom(a2) ;make bit/pix map ...
addq #1, Bounds+bottom(a2) ;...one row high
bra.s START1 ;start off the loop <8 dba>
GetRow1
move.l a2,-(sp) ;push source pixmap data
MOVE.L SrcHndl(A6),-(SP) ;put row of data here
IF INITFILE THEN
dc.w $A8F3 ;Test with open picture trap num
ELSE
dc.w $ABC4 ;_GetPMData
ENDIF
; JSR GETPMDATA ;AND READ IN PIXMAP DATA
move.l SrcHndl(a6),a0
move.l (a0),a0
JSR MapRow ;Map the row and place 1 bit/pixel in dst
START1 DBRA D7,GetRow1 ;LOOP HEIGHT ROWS
;----------------------------------------------------------------
;
; Dispose row handle and set bounds back
;
move d5, Bounds+bottom(a2) ;bounds.top was unchanged
move.l SrcHndl(a6),a0
_DisposHandle
BRA.S DONE ;CONTINUE
;----------------------------------------------------------------
; ROWBYTES < 8 and it's a bitmap, DON'T USE PACKING
; OR it's already 1 bit/pixel
;
NOPACK MULU D7,D5 ;BYTECOUNT := HEIGHT * WIDTH
MOVE.L BITSDST(A6),-(SP) ;PUSH DATA POINTER
MOVE D5,-(SP) ;PUSH BYTECOUNT
JSR GetPicData ;READ BITMAP DATA BITS
Done
move #0, d0 ;successfully created 1-bit bitmap <Halloween89 KON>
bra.s PMDone
ExitGetPM1Deep ;Error exit branches here <Halloween89 KON>
move #1, d0 ;d0 != 0 indicates error
PMDone MOVE.L SAVEDSP(A6),SP ;RESTORE STACK POINTER
MOVEM.L (SP)+,D3-D7/A2-A4 ;RESTORE WORK REGISTERS
UNLINK PARAMSIZE,'GETPMDAT' ;destroys condition codes
;-----------------------------------------------
;
; MapRow - internal utility to map a row to a one-bit-deep row
; and copy it into the target bitmap.
; Uses up-level stack frame. Source ptr passed in a0, destination in bitsdst
; d4.w has bits/pixel
MapRow
;
; Now it's time to actually shrink the bits.
; We build up a word of output at a time (since rowbytes is even, it doesn't
; matter if we convert a slop byte), then write it out. We have two loops:
; An outer one over words of output, and an inner one over words of input.
; In the interests of patch compactness, the only special case we make is
; if the number of colors is <= 32, in which case we keep the color mapping
; bitmap in D6 for speed.
;
MOVEM.W D4-D7/a3,-(SP) ;SAVE REGISTERS
MOVE BOUNDS+RIGHT(A2),D7 ;GET BOUNDS.RIGHT
SUB BOUNDS+LEFT(A2),D7 ;CALC WIDTH
MOVE.L BITSDST(A6),A1 ;Destination pointer
tst.b MustMap(a6)
bne.s MapRow1 ;need to map the row
;
; No mapping needed: copy bits to destination buffer
;
move.w rowbytes(a2),d7
and #RBMask, d7
sub #1, d7 ;zero base loop
@LOOP
move.b (a0)+,(a1)+
dbra d7,@loop
MOVE TARGETRB(A6),D0 ;GET TARGET ROWBYTES (HIWRD CLR)
and.l #$FFFF,d0
ADD.l D0,BITSDST(A6) ;NEXT SCAN LINE
bra Shrunk
MapRow1
CMP.W #8,D4 ;8 BITS/PIXEL?
BEQ.S EIGHTLOOP ;=>YES, USE CUSTOM LOOP
cmp.w #32,d4
beq ThirtyTwoLOOP ;Use custom loop for 32bits/pixel <28AUG89 KON>
cmp.w #16,d4
beq SixteenBitLOOP ;Use custom loop for 16bits/pixel <28AUG89 KON>
;
; Start of the shrinking loop. A0 is source, A1 is destination, a4 points to translation table.
; We assume an even number of pixels per 16-bit word. They are isolated,
; one by one, and a one or zero or'd in to the output word we're building up.
;
@NEXTOUTWORD
MOVEQ #16,D6 ;BITS/OUTPUT WORD
MOVEQ #0,D2 ;OUTPUT WORD
@NEXTINWORD
MOVEQ #16,D1 ;BITS IN INPUT WORD
MOVE (A0)+,D5 ;GET NEXT INPUT WORD
@NEXTPIX
ROL.W D4,D5 ;ISOLATE NEXT PIXEL
MOVE D5,D0 ;GET COPY
AND D3,D0 ;GET PIXEL
LSL.W #1,D2 ;MAKE ROOM FOR NEW PIXEL
OR.B (A4,D0.W),D2 ;GET NEW PIXEL <19Feb87 DBG>
SUBQ #1,D7 ;ONE LESS PIXEL
SUBQ #1,D6 ;ONE LESS OUTPUT PIXEL
SUB D4,D1 ;BITS LEFT IN INPUT WORD
BGT.S @NEXTPIX ;IF SOME LEFT, GET NEXT PIX
TST D7 ;ANY INPUT LEFT?
BLE.S @1 ;NO, DONE WITH LINE
TST D6 ;ANY OUTPUT ROOM LEFT?
BGT.S @NEXTINWORD ;YES, GET NEXT INPUT WORD
MOVE D2,(A1)+ ;WRITE AN OUTPUT WORD
BRA.S @NEXTOUTWORD
@1
LSL.W D6,D2 ;LEFT JUSTIFY LAST WORD
MOVE D2,(A1)+ ;WRITE AN OUTPUT WORD
MOVEQ #0,D0 ;CLEAR OUT LONG
MOVE TARGETRB(A6),D0 ;GET TARGET ROWBYTES
and.l #$ffff,d0 ;clear hi word
ADD.L D0,BITSDST(A6) ;NEXT SCAN LINE
BRA SHRUNK ;EXIT
;
; Here is the custom loop for eight bit pixels. Principle is
; the same as the previous loop.
;
EIGHTLOOP
MOVEQ #0,D0 ;CLEAR PIXEL BUFFER/ROWBYTES
@NEXTOUTWORD
MOVEQ #15,D6 ;BITS/OUTPUT WORD (-1)
MOVEQ #0,D2 ;OUTPUT WORD
@NEXTPIX
MOVE.B (A0)+,D0 ;GET NEXT INPUT BYTE
LSL.W #1,D2 ;MAKE ROOM FOR NEW PIXEL
OR.B (A4,D0.W),D2 ;GET IT <19Feb87 DBG>
SUBQ #1,D7 ;ONE LESS PIXEL
BLE.S @1 ;IF NONE LEFT, DONE WITH ROW
DBRA D6,@NEXTPIX ;LOOP FOR NEXT PIXEL
MOVE D2,(A1)+ ;WRITE AN OUTPUT WORD
BRA.S @NEXTOUTWORD
@1
LSL.W D6,D2 ;LEFT JUSTIFY LAST WORD
MOVE D2,(A1)+ ;WRITE LAST OUTPUT WORD
MOVE TARGETRB(A6),D0 ;GET TARGET ROWBYTES
and.l #$ffff,d0 ;clear hi word
ADD.L D0,BITSDST(A6) ;NEXT SCAN LINE
bra SHRUNK ;exit <28AUG89 KON>
;------------------------------------------------------------------
;
; SCALES A SCANLINE OF PIXELS FROM 32 BIT DIRECT TO A B/W BitMap
; ASSUMES SRC IS COMPOSED OF FOUR BYTES OF THE FORM 'XRGB'
;
; D7: Number of pixels to convert
; A0: SRC BUFFER
; A1: DST BUFFER
ThirtyTwoLOOP
move.l #$80000000,d5 ;init offset into dst
moveq #0,d0 ; d0-d2 hold r,g,b values...
moveq #0,d1 ;...when calculating luminance...
moveq #0,d2 ;...and only low byte is used.
move.w LastError(a6),d3 ;get luminance error from last line
btst #6, mode+1(a6) ;do dithering?
beq.s NewOutputLong ;no
eori.w #1, direction(a6) ;if we dither, we scan ...
beq.s DoReverseThirtyTwoLoop ;... backwards every other time
NewOutputLong
moveq #0, d6 ;assume output value will be white
move.l #$80000000,d5 ; rotating mask
NextInputLong
move.l (a0)+,d4 ;get next long of src
move.b d4,d2 ; get the blue component
lsr.l #8,d4 ; get red,green in low word
move.b d4,d1 ; get the green component
lsr.w #8,d4 ; get red in low byte
move.b d4,d0 ; get the red component
; Compute Luminance = ((((((r+g)/2)+b)/2+r)/2)+g)/2
add.w d1,d4
add.w d2,d4
add.w d2,d4
lsr.w #2,d4
add.w d0,d4
add.w d1,d4
add.w d1,d4
lsr.w #2,d4
btst #6, mode+1(a6)
beq.s NoDither
;
; add luminance to current error and compare to threshold
; if lum + err <= 0 then pixel is set.
;
add.w d4,d3 ;add luminance to error (slop)
ble.s SetBit
sub.w #255,d3
bra.s SetBitDone
;
; No Dithering: Use 50% theshold
NoDither
tst.b d4 ; check high bit of luminance
bmi.s SetBitDone ; if set, pixel is white (0), so skip
SetBit
or.l d5,D6 ; set pixel value
SetBitDone
sub #1, d7 ;done enough pixels?
beq.s @rowdone ;
lsr.l #1,d5 ;BUMP TO NEXT DST PIXEL
bne.s NextInputLong
move.l d6,(a1)+ ;save destination pixel values
bra.s NewOutputLong
@rowdone
MOVE.L D6,(A1)+ ;done: save current output value
MOVE TARGETRB(A6),D0 ;GET TARGET ROWBYTES
and.l #$ffff,d0 ;clear hi word
ADD.L D0,BITSDST(A6) ;NEXT SCAN LINE
move.w d3, LastError(a6) ;save luminance error for next line
bra shrunk
;
; Scan line in reverse direction
;
DoReverseThirtyTwoLoop
moveq #0,d4 ;clear high word of temp pixel count
move.w d7, d4 ;pixel count to temp register
lsl.l #2, d4 ;convert to long
add.l d4, a0 ;move to end of source
add.l #31<<2,d4 ;31<<2
lsr.l #5, d4 ;/4 to convert XRGB to pixels...
;... and /32 because 32 pixels/long...
;... and *4 because we 4 bytes/long
and.w #$fffc,d4 ;must end on word boundry
add.l d4, a1 ;move to end of destination
move d7, d4 ;find starting pixel position
sub.w #1, d4
and.w #$1f, d4 ;get pixel count mod 32
move.l #$80000000,d5
lsr.l d4, d5 ;move to starting pixel position
moveq #0, d6
bra.s ReverseNextInputLong
ReverseNewOutputLong
moveq #0,d6 ;assume output value will be white
moveq #$00000001,d5 ; rotating mask: start on right...
;...and move left
ReverseNextInputLong
move.l -(a0),d4 ;get long of src
move.b d4,d2 ; get the blue component
lsr.l #8,d4 ; get red,green in low word
move.b d4,d1 ; get the green component
lsr.w #8,d4 ; get red in low byte
move.b d4,d0 ; get the red component
; Compute Luminance = ((((((r+g)/2)+b)/2+r)/2)+g)/2
add.w d1,d4
add.w d2,d4
add.w d2,d4
lsr.w #2,d4
add.w d0,d4
add.w d1,d4
add.w d1,d4
lsr.w #2,d4
add.w d4,d3 ;add luminance to error (slop)
bpl.s ReverseDitherSetBitDone
or.l d5,D6 ; set pixel value
bra.s ReverseSetBitDone
ReverseDitherSetBitDone
sub.w #255,d3
ReverseSetBitDone
sub #1, d7 ;done enough pixels?
beq.s @rowdone ;
lsl.l #1, d5 ;BUMP TO NEXT DST PIXEL
bne.s ReverseNextInputLong
move.l d6,-(a1) ;save destination pixel values
bra.s ReverseNewOutputLong
@rowdone
MOVE.L D6,-(A1) ;done: save current output value
MOVE TARGETRB(A6),D0 ;GET TARGET ROWBYTES
and.l #$ffff,d0 ;clear hi word
ADD.L D0,BITSDST(A6) ;NEXT SCAN LINE
move.w d3, LastError(a6) ;save luminance error for next line
bra shrunk
;------------------------------------------------------------------
;
; SCALES A SCANLINE OF PIXELS FROM 16 BIT DIRECT TO A B/W BitMap
; ASSUMES SRC IS COMPOSED OF one word OF THE FORM 'XRRRRRGGGGGBBBBB'
;
; D7: Number of pixels to convert
; A0: SRC BUFFER
; A1: DST BUFFER
SixteenBitLOOP
move.l #$80000000,d5 ;init offset into dst
moveq #0,d0 ; zero luninance rgb values
moveq #0,d1 ;
moveq #0,d2 ;
move.w LastError(a6),d3 ;get luminance error from last line
btst #6, mode+1(a6) ;do dithering?
beq.s NewOutputLong16 ;no
eori.w #1, direction(a6) ;if we dither, we scan ...
beq.s DoReverse16Loop ;... backwards every other time
NewOutputLong16
move.l #0, d6 ;assume output value will be white
move.l #$80000000,d5 ; rotating mask
NextInputWord16
move.w (a0)+,d4 ;get first word of src
move.b d4,d2 ; get the blue component
and.b #$1F,d2 ;save only bottom 5 bits
lsr.l #5,d4 ; get red,green in low word
move.b d4,d1 ; get the green component
and.b #$1F,d1 ;save only bottom 5 bits
lsr.w #5,d4 ; get red in low byte
move.b d4,d0 ; get the red component
and.b #$1F,d0 ;save only bottom 5 bits
; Compute Luminance = ((((((r+g)/2)+b)/2+r)/2)+g)/2
add.w d1,d4
add.w d2,d4
add.w d2,d4
lsr.w #2,d4
add.w d0,d4
add.w d1,d4
add.w d1,d4
lsr.w #2,d4
btst #6, mode+1(a6)
beq.s NoDither16
;
; Do dithering
;
add.w d4,d3 ;add luminance to error (slop)
ble.s SetBit16
sub.w #$1F,d3 ;reset error (max luminance for five bits)
bra.s SetBitDone16
;
; No Dithering: Use 50% theshold
;
NoDither16
btst #4,d4 ; check bit 4 (high bit of luminance for 16 bit) <KON 2NOV90>
bne.s SetBitDone16 ; if set, pixel is white (0), so skip
SetBit16
or.l d5,D6 ; set pixel value
SetBitDone16
sub #1, d7 ;done enough pixels?
beq.s @rowdone ;
lsr.l #1,d5 ;BUMP TO NEXT DST PIXEL
bne.s NextInputWord16
move.l d6,(a1)+ ;save destination pixel values
bra.s NewOutputLong16
@rowdone
MOVE.L D6,(A1)+ ;done: save current output value
MOVE TARGETRB(A6),D0 ;GET TARGET ROWBYTES
and.l #$ffff,d0 ;clear hi word
ADD.L D0,BITSDST(A6) ;NEXT SCAN LINE
move.w d3, LastError(a6) ;save luminance error for next line
bra shrunk
;
; Scan line in reverse direction
;
DoReverse16Loop
moveq #0,d4 ;clear high word of temp pixel count
move.w d7, d4 ;pixel count to temp register
lsl.l #1, d4 ;convert to number of words
add.l d4, a0 ;move to end of source
add.l #15<<2,d4 ;adjust to round up
lsr.l #4, d4 ;/2 to convert 16 bit to number of pixels...
;... and /32 because 32 pixels/long...
;... and *2 because 2 bytes/word
and.w #$fffc,d4 ;must end on word boundry
add.l d4, a1 ;move to end of destination
move d7, d4 ;find starting pixel position
sub.w #1, d4
and.w #$1f, d4 ;get pixel count mod 32
move.l #$80000000,d5
lsr.l d4, d5 ;move to starting pixel position
moveq #0, d6
bra.s ReverseNextInputLong16
ReverseNewOutputLong16
moveq #0, d6 ;assume output value will be white
moveq #$00000001,d5 ; rotating mask: start on right...
;...and move left
ReverseNextInputLong16
move.w -(a0),d4 ;get word of src
move.b d4,d2 ; get the blue component
and.b #$1F,d2 ;save only bottom 5 bits
lsr.l #5,d4 ; get red,green in low word
move.b d4,d1 ; get the green component
and.b #$1F,d1 ;save only bottom 5 bits
lsr.w #5,d4 ; get red in low byte
move.b d4,d0 ; get the red component
and.b #$1F,d0 ;save only bottom 5 bits
; Compute Luminance = ((((((r+g)/2)+b)/2+r)/2)+g)/2
add.w d1,d4
add.w d2,d4
add.w d2,d4
lsr.w #2,d4
add.w d0,d4
add.w d1,d4
add.w d1,d4
lsr.w #2,d4
add.w d4,d3 ;add luminance to error (slop)
bpl.s ReverseDitherSetBitDone16
or.l d5,D6 ; set pixel value
bra.s ReverseSetBitDone16
ReverseDitherSetBitDone16
sub.w #$1F,d3
ReverseSetBitDone16
sub #1, d7 ;done enough pixels?
beq.s @rowdone ;
lsl.l #1, d5 ;BUMP TO NEXT DST PIXEL
bne ReverseNextInputLong16
move.l d6,-(a1) ;save destination pixel values
bra.s ReverseNewOutputLong16
@rowdone
MOVE.L D6,-(A1) ;done: save current output value
MOVE TARGETRB(A6),D0 ;GET TARGET ROWBYTES
and.l #$ffff,d0 ;clear hi word
ADD.L D0,BITSDST(A6) ;NEXT SCAN LINE
move.w d3, LastError(a6) ;save luminance error for next line
SHRUNK
MOVEM.W (SP)+,D4-D7/a3 ;Restore registers
RTS ;EXIT
ENDPROC
RGB2OLD PROC EXPORT
;-----------------------------------------------
;
; UTILITY TO CONVERT AN RGB (POINTED TO BY A1) VALUE
; TO AN OLD STYLE COLOR VALUE. RETURNS VALUE IN D0. CLOBBERS D0,D1
;
; USES HIGH BIT OF EACH COMPONENT TO SELECT RGB OFF (0) OR ON (1)
MOVEQ #0,D1 ; clear out D1
MOVE (A1)+,D1 ; get red
LSL.L #1,D1 ; get high bit
MOVE (A1)+,D1 ; get green
LSL.L #1,D1 ; get high bit
MOVE (A1)+,D1 ; get blue
LSL.L #1,D1 ; get high bit
SWAP D1 ; get RGB index
LSL.W #1,D1 ; Make a word index
MOVEQ #0,D0 ; clear out target
MOVE.W MapTBL(D1.W),D0 ; convert to planar value
RTS ; => all done
; TABLE TO MAP FROM 3 BIT RGB TO OLD-STYLE COLOR INDICES
MapTBL DC.W blackColor ; RBG = 0,0,0 -> black
DC.W blueColor ; RBG = 0,0,1 -> blue
DC.W greenColor ; RBG = 0,1,0 -> green
DC.W cyanColor ; RBG = 0,1,1 -> cyan
DC.W redColor ; RBG = 1,0,0 -> red
DC.W magentaColor ; RBG = 1,0,1 -> magenta
DC.W yellowColor ; RBG = 1,1,0 -> yellow
DC.W whiteColor ; RBG = 1,1,1 -> white
RGB2Pat PROC EXPORT
ENTRY RGB2Pixel
EXPORT PatTBL
;-----------------------------------------------
;
; UTILITY TO CONVERT AN RGB (POINTED TO BY A1) VALUE
; TO AN OLD STYLE GRAY PATTERN. RETURNS HALF-PATTERN IN D0. CLOBBERS D1.
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch DrawPicturePatch.a 01Jan1904 #??? (RGB2Pat) (RGB2Pat)
;
; USES COMPUTED GRAY LEVEL TO SELECT A PATTERN
MOVE (A1)+,D1 ; Get Red
MULU #$4CCC,D1 ; Weight for Red
MOVE (A1)+,D0 ; Get Green
MULU #$970A,D0 ; Weight for Green
ADD.L D0,D1 ; Add in
MOVE (A1)+,D0 ; Get Blue
MULU #$1C28,D0 ; Weight for Blue
ADD.L D0,D1 ; Get sum: luminance of RGB
CLR D1 ; Clear low word
ROL.L #3,D1 ; Get high three bits (0-7)
LSL.W #2,D1 ; Get long offset
MOVE.L PatTBL(D1.W),D0 ; Get half-pattern
RTS
PatTBL
DC.L $FFFFFFFF ; Gray = 0 -> black
DC.L $DDFF77FF ; Gray = 1 -> 7/8 gray
DC.L $FF55FF55 ; Gray = 2 -> 3/4 gray
DC.L $EE55BB55 ; Gray = 3 -> 5/8 gray
DC.L $AA55AA55 ; Gray = 4 -> 1/2 gray
DC.L $88552255 ; Gray = 5 -> 3/8 gray
DC.L $88002200 ; Gray = 6 -> 1/8 gray
DC.L $00000000 ; Gray = 7 -> white
;-----------------------------------------------
;
; UTILITY TO CONVERT AN RGB (POINTED TO BY A0) VALUE <19Feb87 DBG>
; TO A SINGLE PIXEL. RETURNS VALUE IN D0.B. CLOBBERS D1.
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch DrawPicturePatch.a 01Jan1904 #??? (RGB2Pixel) (RGB2Pixel)
;
; USES COMPUTED GRAY LEVEL TO SELECT A PATTERN
RGB2Pixel
MOVEQ #0,D1 ; Clear out
MOVE (A0)+,D1 ; Get Red <19Feb87 DBG>
MOVEQ #0,D0 ; Clear out
MOVE (A0)+,D0 ; Get Green <19Feb87 DBG>
ADD.L D0,D1 ; Add in
MOVE (A0)+,D0 ; Get Blue <19Feb87 DBG>
ADD.L D0,D1 ; Get sum
DIVU #3,D1 ; Compute unweighted Gray value
SGE D0 ; Should be 1 (black) if <$8000
NEG.B D0 ; Make single bit
RTS
MapRatio PROC EXPORT
;-------------------------------------------------------------
;
; PROCEDURE MapRatio(VAR numer, denom: Point; fromRect: Rect);
;
; Fix File Date Patch# Fix Routine(s) Routine(s) Fixed
;AppleSystemPatch DrawPicturePatch.a 01Jan1904 #??? (MapRatio) (MapRatio)
;
; Map ratio so that denom.h/.v = height/width of fromRect.
; This is so that later scaling of the numerator will have some
; range to work within.
;
; NOTE: Only necessary because fractional numer, denom not used
;
; numer.h := numer.h * fromWidth / denom.h
; denom.h := fromWidth
; numer.v := numer.v * fromHeight / denom.v
; denom.v := fromHeight
PARAMSIZE EQU 12 ; TOTAL BYTES OF PARAMS
NUMER EQU PARAMSIZE+8-4 ; LONG, ADDR OF POINT
DENOM EQU NUMER-4 ; LONG, ADDR OF POINT
FROMRECT EQU DENOM-4 ; LONG, ADDR OF RECT
LINK A6,#0 ; NO LOCALS
MOVEM.L D0-D1/A0-A2,-(SP) ; SAVE REGS
MOVE.L NUMER(A6),A0 ; point to numer
MOVE.L DENOM(A6),A1 ; point to denom
MOVE.L FROMRECT(A6),A2 ; point to fromRect
MOVE.W right(A2),D0 ; get fromRect right
SUB.W left(A2),D0 ; get fromWidth
MOVE.W h(A0),D1 ; get numer.h
MULU D0,D1 ; multiply by fromWidth
DIVU h(A1),D1 ; divide by denom.h
MOVE.W D1,h(A0) ; update numer.h
MOVE.W D0,h(A1) ; update denom.h
MOVE.W bottom(A2),D0 ; get fromRect bottom
SUB.W top(A2),D0 ; get fromHeight
MOVE.W v(A0),D1 ; get numer.v
MULU D0,D1 ; multiply by fromHeight
DIVU v(A1),D1 ; divide by denom.v
MOVE.W D1,v(A0) ; update numer.v
MOVE.W D0,v(A1) ; update denom.v
DONE MOVEM.L (SP)+,D0-D1/A0-A2 ; RESTORE REGS
UNLINK PARAMSIZE,'MAPRATIO' ;destroys condition codes
ENDPROC
;--------- BitMap to Region Added by KON 11/6/89 for Plus and SE only -----------
;________________________________________________________________________________
;
; FUNCTION BitMapRgn(region:RgnHandle; bMap:BitMap): OSErr; INLINE $A8D7;
; (BHogToRegion is debugging memory hog version)
;
; 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
; 5/18/89 BAL made classic QD friendly
;
;________________________________________________________________________________
;
;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)
;
;________________________________________________________________________________
BitMapRgnptch PROC EXPORT
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.W 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
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
;get boundary rectangle so we can tell how to process the bitmap
MOVE.L bMapPtr(A6),A1 ;get bitmap pointer
MOVE.W rowBytes(A1), D0 ;rowbytes
if hasCQD then
BPL.S @1 ;it's a bitmap so go ahead
BTST #isCPort, D0 ;is this a ptr to portBits?
BEQ.S @2 ;nope; it's a ptr to a pixmap
MOVE.L baseAddr(A1), A0 ;get the PixMapHandle
MOVE.L (A0), A1 ;and get the real ptr to pixmap
@2
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
else
MOVE.W rowBytes(A1), rowNumBytes(A6) ;get the rowbytes from the bit/pixmap
endif ;hasCQD
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)
BMRHScramLine
MOVE.L regionH(A6),A2
MOVE.L (A2),A2 ;point to start of region
BMRLineLoop
LEA (A2,D7.W),A5 ;point to new region start + size
MOVE.L handSize(A6),D1 ;get handle size
SUB.W 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
MOVE.L regionH(A6),A0 ;region handle
_SetHandleSize
BNE BMRBadEmpty ;if we failed then return a NIL handle
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.W 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.W A5,D7 ;current region pointer
SUB.W A2,D7 ;figga region size
CMP.W startSize(A6),D7 ;did we add inv. pts to this line?
BEQ.S BMRNoLine ;br = no, so back up
BLT BMR32KErr ;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.W #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.L rowLongs(A6),D0
ASL.L #2,D0 ;longs => bytes
_NewHandle clear ;get a full line of zero bits
BNE.S BMRBadEmpty ;if we failed then return a NIL handle
MOVE.L A0,lastLineH(A6) ;save handle
MOVE.L (A0),A4 ;start of current line
BRA BMRHScramLine ;do this last one (and rederef handle)
BMRNoLine
SUBQ.L #2,A5 ;back up pointer
SUBQ.W #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.W D7 (which contains the length)
OutputRgnWord
MOVE.W D0,(A5)+ ;put a word to the region
ADDQ.W #2,D7 ;ink the size
RTS
; all done so clean up, output the final $7FFF
BMRFinis
MOVE.L lastLineH(A6),A0
_DisposHandle ;get rid of that last line of zeroes
CMP.W #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
BMI.S BMR32KErr ;if we went negative, 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.W #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 32K, so we have to error out, man
BMR32KErr
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
;-------------End of BitMap to Region Code Addition 11/6/89 --------------