QuickDraw/Stretch.a

1165 lines
50 KiB
Plaintext
Executable File

;------------------------------------------------------------------
;
; --> STRETCH.TEXT
;
.PROC StretchBits,8
.REF RgnBlt,RSect,ShieldCursor,ShowCursor
.REF InitRgn,SeekRgn,SetupStretch,ColorMap,XorSlab
;--------------------------------------------------------------
;
; PROCEDURE StretchBits(srcBits,dstBits: BitMap;
; srcRect,dstRect: Rect;
; mode: INTEGER
; rgnA,rgnB,rgnC: RgnHandle);
;
; Transfer a rectangle of bits from srcBits to dstBits,
; stretching or compressing according to srcRect and dstRect.
; The transfer is clipped to the intersection of rgnA, rgnB, and rgnC.
;
;
; Restrictions:
;
; transfer mode 0..7 only.
; if numer <> denom, then src and dst bitmaps do not overlap.
;
;
; COPYRIGHT APPLE COMPUTER INC.
; DESIGNED AND WRITTEN BY BILL ATKINSON
;
;----------------------------------------------------
;
; A6 OFFSETS OF PARAMETERS AFTER LINK:
;
PARAMSIZE .EQU 30 ;TOTAL BYTES OF PARAMETERS
SRCBITS .EQU PARAMSIZE+8-4 ;LONG, ADDR OF BITMAP
DSTBITS .EQU SRCBITS-4 ;LONG, ADDR OF BITMAP
SRCRECT .EQU DSTBITS-4 ;LONG, ADDR OF RECT
DSTRECT .EQU SRCRECT-4 ;LONG, ADDR OF RECT
MODE .EQU DSTRECT-2 ;WORD
RGNA .EQU MODE-4 ;RGNHANDLE
RGNB .EQU RGNA-4 ;RGNHANDLE
RGNC .EQU RGNB-4 ;RGNHANDLE
;-------------------------------------------------
;
; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK:
;
NUMER .EQU -4 ;POINT
DENOM .EQU NUMER-4 ;POINT
VERROR .EQU DENOM-4 ;INTEGER
MINRECT .EQU VERROR-8 ;RECT
SRCBUF .EQU MINRECT-4 ;LONG
DSTBUF .EQU SRCBUF-4 ;LONG
SRCLONGS .EQU DSTBUF-2 ;WORD
DSTLONGS .EQU SRCLONGS-2 ;WORD
STATEA .EQU DSTLONGS-RGNREC ;RGN STATE RECORD
STATEB .EQU STATEA-RGNREC ;RGN STATE RECORD
STATEC .EQU STATEB-RGNREC ;RGN STATE RECORD
SAVESTK .EQU STATEC-4 ;LONG
RECTFLAG .EQU SAVESTK-2 ;WORD
MASKBUF .EQU RECTFLAG-4 ;LONG
BUFLEFT .EQU MASKBUF-2 ;WORD
BUFSIZE .EQU BUFLEFT-2 ;WORD
SRCADDR .EQU BUFSIZE-4 ;LONG
DSTADDR .EQU SRCADDR-4 ;LONG
SRCROW .EQU DSTADDR-4 ;LONG
DSTROW .EQU SRCROW-4 ;LONG
SRCLIMIT .EQU DSTROW-4 ;LONG
VERT .EQU SRCLIMIT-2 ;WORD
MODECASE .EQU VERT-4 ;LONG
PAT .EQU MODECASE-4 ;LONG, ADDR OF PAT
RATIOCASE .EQU PAT-4 ;LONG
FRACTION .EQU RATIOCASE-2 ;WORD
VARSIZE .EQU FRACTION ;SIZE OF LOCAL VARIABLES
LINK A6,#VARSIZE ;ALLOCATE LOCAL VARIABLES
MOVEM.L D0-D7/A1-A4,-(SP) ;SAVE REGS
MOVE.L SP,SAVESTK(A6) ;REMEMBER STACK FOR LATER
;----------------------------------------------------------------
;
; CALC NUMER AND DENOM BASED ON DSTRECT AND SRCRECT.
; IF NUMER = DENOM THEN JUST CALL RGNBLT.
;
MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT
MOVE BOTTOM(A0),D0
SUB TOP(A0),D0 ;CALC DST HEIGHT
SWAP D0 ;PUT IN HI WORD
MOVE RIGHT(A0),D0
SUB LEFT(A0),D0 ;CALC DST WIDTH
MOVE.L SRCRECT(A6),A0 ;POINT TO SRCRECT
MOVE BOTTOM(A0),D1
SUB TOP(A0),D1 ;CALC SRC HEIGHT
SWAP D1 ;PUT IN HI WORD
MOVE RIGHT(A0),D1
SUB LEFT(A0),D1 ;CALC SRC WIDTH
CMP.L D0,D1 ;ARE BOTH RECTS SAME SIZE
BNE.S STRETCH ;NO, CAN'T USE RGNBLT
XRGNBLT MOVE.L SRCBITS(A6),-(SP) ;PUSH SRCBITS
MOVE.L DSTBITS(A6),-(SP) ;PUSH DSTBITS
MOVE.L SRCRECT(A6),-(SP) ;PUSH SRCRECT
MOVE.L DSTRECT(A6),-(SP) ;PUSH DSTRECT
MOVE MODE(A6),-(SP) ;PUSH MODE
MOVE.L PAT(A6),-(SP) ;PAT ONLY USED FROM BELOW
MOVE.L RGNA(A6),-(SP) ;PUSH RGNA
MOVE.L RGNB(A6),-(SP) ;PUSH RGNB
MOVE.L RGNC(A6),-(SP) ;PUSH RGNC
JSR RGNBLT ;CALL RGNBLT
BRA GOHOME ;AND QUIT
STRETCH MOVE.L D0,NUMER(A6) ;NUMER := DST SIZE
MOVE.L D1,DENOM(A6) ;DENOM := SRC SIZE
JSR SetupStretch ;CALC CASEJUMP AND HORIZ FRACT
MOVE.L A0,RATIOCASE(A6) ;SAVE CASE JUMP FOR LATER
MOVE D0,FRACTION(A6) ;SAVE FRACTION FOR LATER
;----------------------------------------------------------------
;
; ADJUST MODE AND PATTERN FOR COLOR SEPARATION.
;
MOVE MODE(A6),-(SP) ;PUSH INPUT MODE
MOVE.L PAT(A6),-(SP) ;PUSH ADDR OF DUMMY PATTERN
JSR COLORMAP ;ALTER FOR COLOR SEPARATION
MOVE.L (SP)+,PAT(A6) ;GET (ALTERED) PATTERN
MOVE (SP)+,D2 ;GET (ALTERED) MODE
MOVE D2,D3 ;COPY MODE
ROR #4,D3 ;IS PATTERN BIT SET ?
BCS.S XRGNBLT ;YES, USE RGNBLT TO DO PAT
MOVE D2,MODE(A6) ;NO, UPDATE (ALTERED) MODE
;-------------------------------------------------------------------
;
; CALC MINRECT = INTERSECTION OF DSTRECT, DSTBITS.BOUNDS, AND THREE
; REGION BOUNDING BOXES. QUIT IF THE INTERSECTION IS EMPTY.
;
MOVE.L DSTBITS(A6),A3 ;POINT TO DST BITMAP
MOVE.L DSTRECT(A6),-(SP) ;PUSH ADDR OF DSTRECT
PEA BOUNDS(A3) ;PUSH ADDR OF DSTBITS.BOUNDS
MOVE.L RGNA(A6),A0 ;GET RGNHANDLE
MOVE.L (A0),A0 ;DE-REFERENCE IT
PEA RGNBBOX(A0) ;PUSH RGN BBOX
MOVE.L RGNB(A6),A0 ;GET RGNHANDLE
MOVE.L (A0),A0 ;DE-REFERENCE IT
PEA RGNBBOX(A0) ;PUSH RGN BBOX
MOVE.L RGNC(A6),A0 ;GET RGNHANDLE
MOVE.L (A0),A0 ;DE-REFERENCE IT
PEA RGNBBOX(A0) ;PUSH RGN BBOX
MOVE #5,-(SP) ;PUSH NRECTS
PEA MINRECT(A6) ;PUSH WHERE TO PUT RESULT
JSR RSECT ;INTERSECT ALL RECTS
BEQ GOHOME ;QUIT IF RESULT IS EMPTY
;----------------------------------------------------
;
; HIDE THE CURSOR IF IT INTERSECTS MINRECT
;
PEA MINRECT(A6) ;PUSH SHIELD RECT
MOVE.L BOUNDS+TOPLEFT(A3),-(SP) ;PUSH DELTA TO CONVERT TO GLOBAL
JSR SHIELDCURSOR ;REMOVE CURSOR IF INTERSECT
;-----------------------------------------------------------------------
;
; ALLOCATE AND CLEAR SRCBUF TO HOLD SRCWIDTH.
;
MOVE DENOM+H(A6),D0 ;GET SRC WIDTH
SUB #1,D0 ;SUBTRACT 1 PIXEL
LSR #5,D0 ;AND DIV BY 32 FOR LONGS
MOVE D0,SRCLONGS(A6) ;SAVE FOR LATER
CLR.L -(SP) ;CLEAR A LONG OF SLOP AT RIGHT
CLRSRC CLR.L -(SP) ;ALLOCATE AND CLEAR A LONG
DBRA D0,CLRSRC ;LOOP ENTIRE BUFFER
MOVE.L SP,SRCBUF(A6); ;REMEMBER WHERE SRCBUF IS
;-----------------------------------------------------------------------
;
; ALLOCATE AND CLEAR DSTBUF TO HOLD DSTWIDTH.
;
MOVE NUMER+H(A6),D0 ;GET DST WIDTH
SUB #1,D0 ;SUBTRACT 1 PIXEL
LSR #5,D0 ;AND DIV BY 32 FOR LONGS
MOVE D0,DSTLONGS(A6) ;SAVE FOR LATER
CLR.L -(SP) ;CLEAR A LONG OF SLOP AT RIGHT
CLR.L -(SP) ;CLEAR ANOTHER LONG OF SLOP
CLRDST CLR.L -(SP) ;ALLOCATE AND CLEAR A LONG
DBRA D0,CLRDST ;LOOP ENTIRE BUFFER
MOVE.L SP,DSTBUF(A6); ;REMEMBER WHERE DSTBUF IS
;--------------------------------------------------------
;
; CALC BUFLEFT AND BUFSIZE FOR RGN SCANLINE BUFFERS
;
MOVE.L DSTRECT(A6),A0 ;POINT TO DSTRECT
MOVE LEFT(A0),D1 ;GET DSTRECT LEFT
SUB BOUNDS+LEFT(A3),D1 ;CONVERT TO GLOBAL COORDS
AND #$FFF0,D1 ;TRUNC TO MULT OF 16
ADD BOUNDS+LEFT(A3),D1 ;CONVERT BACK TO LOCAL
MOVE D1,BUFLEFT(A6) ;SAVE AS BUFLEFT
MOVE MINRECT+RIGHT(A6),D0 ;GET MINRECT RIGHT
SUB D1,D0 ;CALC WIDTH IN DOTS
LSR #5,D0 ;DIV BY 32 FOR LONGS
MOVE D0,BUFSIZE(A6) ;BUFSIZE = # LONGS -1
;-----------------------------------------------------------------------
;
; ALLOCATE AND CLEAR A SCANLINE BUFFER FOR THE COMPOSITE MASK.
;
CLRMASK CLR.L -(SP) ;ALLOCATE AND CLEAR
DBRA D0,CLRMASK ;LOOP TILL DONE
MOVE.L SP,MASKBUF(A6); ;REMEMBER WHERE MASKBUF IS
;-------------------------------------------------------------------
;
; INIT STATE RECORDS VERT0 AND VERT1 IN CASE RECTANGULAR
;
MOVE #32767,D0
MOVE D0,STATEA+NEXTV(A6)
MOVE D0,STATEB+NEXTV(A6)
MOVE D0,STATEC+NEXTV(A6)
NEG D0
MOVE D0,STATEA+THISV(A6)
MOVE D0,STATEB+THISV(A6)
MOVE D0,STATEC+THISV(A6)
;----------------------------------------------------------------------
;
; ALLOCATE BUFFERS AND INIT STATE RECORDS FOR EACH NON-RECT REGION
;
MOVEQ #10,D7
CLR D5 ;INIT ALL RGNS RECT
MOVE.L RGNA(A6),A0 ;GET RGNHANDLE
MOVE.L (A0),A0 ;DE-REFERENCE IT
CMP RGNSIZE(A0),D7 ;IS RGNA RECTANGULAR ?
BEQ.S ARECT ;YES, SKIP IT
ADD #2,D5 ;NO, SET UP FLAG
LEA STATEA(A6),A1 ;POINT TO STATE RECORD A
BSR.S INITONE ;INIT STATE, ALLOC BUFFER
ARECT
MOVE.L RGNB(A6),A0 ;GET RGNHANDLE
MOVE.L (A0),A0 ;DE-REFERENCE IT
CMP RGNSIZE(A0),D7 ;IS RGNB RECTANGULAR ?
BEQ.S BRECT ;YES, SKIP IT
ADD #4,D5 ;NO, BUMP FLAG
LEA STATEB(A6),A1 ;POINT TO STATE RECORD B
BSR.S INITONE ;INIT STATE, ALLOC BUFFER
BRECT
MOVE.L RGNC(A6),A0 ;GET RGNHANDLE
MOVE.L (A0),A0 ;DE-REFERENCE IT
CMP RGNSIZE(A0),D7 ;IS RGNC RECTANGULAR ?
BEQ.S CRECT ;YES, SKIP IT
ADD #8,D5 ;NO, BUMP FLAG
LEA STATEC(A6),A1 ;POINT TO STATE RECORD C
PEA CRECT ;PUSH FAKE RETURN ADDR
INITONE MOVE MINRECT+LEFT(A6),D0 ;GET MINH
MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH
MOVE BUFLEFT(A6),D2 ;GET BUFLEFT
JMP INITRGN ;INIT STATE, ALLOC BUFFER
CRECT
;--------------------------------------------------------------------
;
; IF ALL REGIONS ARE RECTANGULAR, THEN DRAW MINRECT INTO MASK BUFFER
;
MOVE.W D5,RECTFLAG(A6) ;ARE ALL RGNS RECT ?
BNE.S NOTRECT ;NO, CONTNUE
MOVE.L MASKBUF(A6),A0 ;YES, POINT TO MASK BUFFER
MOVE MINRECT+LEFT(A6),D3 ;SET UP LEFT
SUB BUFLEFT(A6),D3 ;MAKE IT BUFFER RELATIVE
MOVE MINRECT+RIGHT(A6),D4 ;SET UP RIGHT
SUB BUFLEFT(A6),D4 ;MAKE IT BUFFER RELATIVE
JSR XorSlab ;AND XOR BETWEEN THEM
NOTRECT
;------------------------------------------------------
;
; SET UP INVERT FLAG IN D7 TO REFLECT MODE BIT 2
;
CLR.L D7 ;SAY NOT INVERTED
MOVE MODE(A6),D2 ;GET TRANSFER MODE
BMI DONE ;QUIT IF MODE NEGATIVE
BCLR #2,D2 ;TEST AND CLR INVERT BIT
BEQ.S SETMODE ;SKIP IF NOT INVERTED
NOT.L D7 ;INVERTED; D7 GETS ALL 1'S
;--------------------------------------------------
;
; CALCULATE CASE JUMP FOR DIFFERENT TRANSFER MODES
;
SETMODE CMP #7,D2 ;IS MODE > 7 ?
BGT DONE ;YES, QUIT
LEA MODETAB,A0 ;POINT TO MODE TABLE
MOVE.B 0(A0,D2),D2 ;GET OFFSET
SUB D2,A0 ;COMPUTE ADDRESS
MOVE.L A0,MODECASE(A6) ;SAVE FOR LATER
;------------------------------------------------
;
; SET UP SRCROW, SRCLIMIT, SRCSHIFT, AND SRCADDR
;
MOVE.L SRCBITS(A6),A2 ;POINT TO SRCBITS
MOVE ROWBYTES(A2),D0 ;GET SRC ROWBYTES
EXT.L D0 ;AND EXTEND TO LONG
MOVE.L D0,SRCROW(A6) ;SRCROW := SRC ROWBYTES
MOVE BOUNDS+BOTTOM(A2),D1 ;GET SRCBITS.BOUNDS.BOTTOM
SUB BOUNDS+TOP(A2),D1 ;MAKE IT GLOBAL
MULU D0,D1 ;MULT BY SRC ROWBYTES
ADD.L BASEADDR(A2),D1 ;ADD BASEADDR
ADD.L #2,D1 ;ADJUST FOR -2(A0) SRC PICKUP
MOVE.L D1,SRCLIMIT(A6) ;SAVE RESULT AS SRCLIMIT
MOVE.L SRCRECT(A6),A0 ;POINT TO SRCRECT
MOVE LEFT(A0),D1 ;GET SRCRECT LEFT
SUB BOUNDS+LEFT(A2),D1 ;CONVERT TO SRC GLOBAL
MOVE D1,D5 ;MAKE A COPY
NEG D5 ;NEGATE IT AND
AND #$F,D5 ;TREAT MOD 16 FOR SRCSHIFT
MOVE TOP(A0),D0 ;GET SRCRECT TOP
SUB BOUNDS+TOP(A2),D0 ;CONVERT TO SRC GLOBAL
MULU ROWBYTES(A2),D0 ;MULT BY SRC ROWBYTES
MOVE.L BASEADDR(A2),A0 ;GET START OF SRC BITMAP
ADD.L D0,A0 ;ADD VERTICAL OFFSET
ADD D5,D1 ;ADJUST SRCLEFT FOR SRCSHIFT
ASR #4,D1 ;CONVERT DOTS TO WORDS
ADD D1,A0 ;ADD HORIZONTAL OFFSET
ADD D1,A0 ;TWICE FOR BYTES
MOVE.L A0,SRCADDR(A6) ;SAVE AS SRCADDR
;----------------------------------------------------
;
; CALC STARTING DSTROW, DSTSHIFT, AND DSTADDR
;
MOVE ROWBYTES(A3),D0 ;GET DST ROWBYTES
EXT.L D0 ;EXTEND TO LONG
MOVE.L D0,DSTROW(A6) ;DSTROW := DST ROWBYTES
MOVE.L DSTRECT(A6),A0
MOVE TOP(A0),VERT(A6) ;INIT CURRENT VERTICAL
MOVE LEFT(A0),D1 ;GET DSTRECT LEFT
SUB BOUNDS+LEFT(A3),D1 ;CONVERT TO GLOBAL COORDS
MOVEQ #$F,D6
AND D1,D6 ;TREAT MOD 16 FOR SHIFTCNT
MOVE MINRECT+TOP(A6),D0 ;GET MINRECT TOP
SUB BOUNDS+TOP(A3),D0 ;CONVERT TO GLOBAL COORDS
MULU ROWBYTES(A3),D0 ;MULT BY DST ROWBYTES
MOVE.L BASEADDR(A3),A0 ;GET START OF DST BITMAP
ADD.L D0,A0 ;ADD VERTICAL OFFSET
ASR #4,D1 ;CONVERT DOTS TO WORDS
ADD D1,A0 ;ADD HORIZ OFFSET
ADD D1,A0 ;TWICE FOR BYTES
MOVE.L A0,DSTADDR(A6) ;SAVE AS DSTADDR
;-----------------------------------------------------
;
; INIT ERROR TERM FOR DDA
;
MOVE DENOM+V(A6),D0
LSR #1,D0
NEG D0
MOVE D0,VERROR(A6) ;VERROR := -DENOM.V/2
;-----------------------------------------------------
;
; GET FIRST SCANLINE OF SRC INTO SRCBUF
;
NEXTSRC MOVE.L SRCADDR(A6),A0 ;POINT TO SRC BITMAP
CMP.L SRCLIMIT(A6),A0 ;IS IT EXHAUSTED ?
BHS DONE ;YES, QUIT
MOVE.L SRCBUF(A6),A1 ;POINT TO SRCBUF
MOVE SRCLONGS(A6),D1 ;GET COUNT OF LONGS
NXTSRC2 MOVE.L -2(A0),D0 ;GET A LONG OF SRC
LSR.L D5,D0 ;ALIGN TO SRCBUF
MOVE D0,(A1)+ ;PUT A WORD TO SRCBUF
MOVE.L (A0)+,D0 ;GET A SECOND LONG
LSR.L D5,D0 ;ALIGN TO SRCBUF
MOVE D0,(A1)+ ;PUT A WORD TO SRCBUF
DBRA D1,NXTSRC2 ;LOOP FOR ALL LONGS
MOVE.L SRCROW(A6),D2 ;GET SRC ROWBYTES
ADD.L D2,SRCADDR(A6) ;BUMP SRC TO NEXT ROW
MOVE NUMER+V(A6),D0 ;GET NUMER.V
ADD D0,VERROR(A6) ;VERROR := VERROR + NUMER.V
BGT.S SRCOK ;SKIP IF VERROR > 0
;-----------------------------------------------------
;
; WHILE (VERROR < 0) DO MERGE OTHER SCANLINES INTO SRCBUF.
;
SRCLOOP MOVE.L SRCADDR(A6),A0 ;POINT TO SRC BITMAP
CMP.L SRCLIMIT(A6),A0 ;IS IT EXHAUSTED ?
BHS.S SRCOK ;YES, DONT GET ANY MORE
MOVE.L SRCBUF(A6),A1 ;POINT TO SRCBUF
MOVE SRCLONGS(A6),D1 ;GET COUNT OF LONGS
NXTSRC3 MOVE.L -2(A0),D0 ;GET A LONG OF SRC
LSR.L D5,D0 ;ALIGN TO SRCBUF
OR D0,(A1)+ ;OR A WORD TO SRCBUF
MOVE.L (A0)+,D0 ;GET A SECOND LONG
LSR.L D5,D0 ;ALIGN TO SRCBUF
OR D0,(A1)+ ;OR A WORD TO SRCBUF
DBRA D1,NXTSRC3 ;LOOP FOR ALL LONGS
ADD.L D2,SRCADDR(A6) ;BUMP SRC TO NEXT ROW
MOVE NUMER+V(A6),D0 ;GET NUMER.V
ADD D0,VERROR(A6) ;VERROR := VERROR + NUMER.V
MORESRC BLE.S SRCLOOP ;LOOP WHILE VERROR <= 0
SRCOK
;----------------------------------------------------------
;
; HORIZONTALLY STRETCH SRCBUF INTO DSTBUF
;
MOVE.L SRCBUF(A6),A0 ;POINT TO SRCBUF
MOVE.L DSTBUF(A6),A1 ;POINT TO DSTBUF
MOVE DSTLONGS(A6),D0 ;GET DSTLONGS
LSL #2,D0 ;QUAD FOR BYTE OFFSET
LEA 4(A1,D0),A2 ;SET UP DSTLIMIT
MOVE FRACTION(A6),D4 ;GET HORIZONTAL FRACTION
MOVE.L RATIOCASE(A6),A3 ;GET CASE JUMP
JSR (A3) ;AND CALL STRETCHROW
;-------------------------------------------------------
;
; TRANSFER ONE OR MORE COPIES OF DSTBUF INTO DSTBITS
;
NXTMASK MOVE VERT(A6),D0 ;GET CURRENT VERT COORD
CMP MINRECT+TOP(A6),D0 ;IS VERT < MINV ?
BLT.S NODRAW ;YES, DON'T DRAW
BSR SEEKMASK ;MAKE MASK BUFFER CURRENT
MOVE.L DSTBUF(A6),A3 ;INIT SRCPTR
MOVE.L DSTADDR(A6),A4 ;INIT DSTPTR FOR ROW
MOVE.L MASKBUF(A6),A2 ;INIT MASKPTR FOR ROW
MOVE BUFSIZE(A6),D2 ;INIT COUNT OF LONGS
MOVE.L MODECASE(A6),A0 ;GET MODE CASE JUMP
JMP (A0) ;TAKE MODE JUMP
NEXTDST MOVE.L DSTROW(A6),D0 ;GET DST ROWBYTES
ADD.L D0,DSTADDR(A6) ;BUMP DST TO NEXT ROW
NODRAW ADD #1,VERT(A6) ;BUMP TO NEXT VERT
MOVE VERT(A6),D0 ;GET VERT
CMP MINRECT+BOTTOM(A6),D0 ;ARE WE AT THE LAST SCAN LINE ?
BEQ.S DONE ;YES, QUIT
MOVE DENOM+V(A6),D0
SUB D0,VERROR(A6) ;VERROR := VERROR - DENOM.V
BGE NXTMASK ;IF VERROR >= 0 THEN DRAW MORE
BRA NEXTSRC ;ELSE GET NEXT SRC
;-----------------------------------------------------------------
;
; ENTIRE STRETCHBITS COMPLETE. RESTORE REGS AND STACK AND GO HOME.
;
DONE JSR SHOWCURSOR ;RESTORE CURSOR
GOHOME MOVE.L SAVESTK(A6),SP ;STRIP VARIABLE SIZED BUFFER
MOVEM.L (SP)+,D0-D7/A1-A4 ;RESTORE REGISTERS
UNLINK PARAMSIZE,'STRETCHB'
;-----------------------------------------------------------------
;
; LOCAL ROUTINE TO UPDATE MASK BUFFER TO CURRENT VERTICAL COORD.
;
SEEKMASK MOVE VERT(A6),D0 ;GET CURRENT VERT COORD
MOVE RECTFLAG(A6),D1 ;GET RECTFLAG = 0,2,4
MOVE RECTJMP(D1),D1 ;GET OFFSET FROM TABLE
JMP RECTJMP(D1) ;TAKE CASE JUMP
RECTJMP .WORD SEEKOK-RECTJMP
.WORD A-RECTJMP
.WORD B-RECTJMP
.WORD AB-RECTJMP
.WORD C-RECTJMP
.WORD AC-RECTJMP
.WORD BC-RECTJMP
.WORD ABC-RECTJMP
;--------------------------------------------------------------------
;
; ONLY REGION A IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK
;
A LEA STATEA(A6),A1
BRA.S JMPSEEK
;--------------------------------------------------------------------
;
; ONLY REGION B IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK
;
B LEA STATEB(A6),A1
BRA.S JMPSEEK
;--------------------------------------------------------------------
;
; ONLY REGION C IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK
;
C LEA STATEC(A6),A1
JMPSEEK MOVE.L MASKBUF(A6),SCANBUF(A1) ;PLAY DIRECTLY INTO MASKBUF
JMP SEEKRGN
;-------------------------------------------------------------------
;
; REGIONS A AND B ARE NON-RECTANGULAR. UPDATE EACH,
; THEN FORM INTERSECTION IN THE MASK BUFFER.
;
AB LEA STATEA(A6),A1
JSR SEEKRGN
MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED
LEA STATEB(A6),A1
JSR SEEKRGN
OR (SP)+,D1 ;HAS EITHER RGN CHANGED ?
BEQ.S SEEKOK ;NO, WE'RE DONE
MOVE.L STATEA+SCANBUF(A6),A0
MOVE.L STATEB+SCANBUF(A6),A1
BRA.S CPY2BUF
;-------------------------------------------------------------------
;
; REGIONS A AND C ARE NON-RECTANGULAR. UPDATE EACH,
; THEN FORM INTERSECTION IN THE MASK BUFFER.
;
AC LEA STATEA(A6),A1
JSR SEEKRGN
MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED
LEA STATEC(A6),A1
JSR SEEKRGN
OR (SP)+,D1 ;HAS EITHER RGN CHANGED ?
BEQ.S SEEKOK ;NO, WE'RE DONE
MOVE.L STATEA+SCANBUF(A6),A0
MOVE.L STATEC+SCANBUF(A6),A1
BRA.S CPY2BUF
;-------------------------------------------------------------------
;
; REGIONS B AND C ARE NON-RECTANGULAR. UPDATE EACH,
; THEN FORM INTERSECTION IN THE MASK BUFFER.
;
BC LEA STATEB(A6),A1
JSR SEEKRGN
MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED
LEA STATEC(A6),A1
JSR SEEKRGN
OR (SP)+,D1 ;HAS EITHER RGN CHANGED ?
BEQ.S SEEKOK ;NO, WE'RE DONE
MOVE.L STATEB+SCANBUF(A6),A0
MOVE.L STATEC+SCANBUF(A6),A1
CPY2BUF MOVE.L MASKBUF(A6),A2
MOVE BUFSIZE(A6),D1
BCLOOP MOVE.L (A0)+,D0
AND.L (A1)+,D0
MOVE.L D0,(A2)+
DBRA D1,BCLOOP
SEEKOK RTS ;ALL 3 ARE RECT, DO NOTHING
;-------------------------------------------------------------------
;
; REGIONS A, B AND C ARE ALL NON-RECTANGULAR. UPDATE EACH,
; THEN FORM INTERSECTION IN THE MASK BUFFER.
;
ABC LEA STATEA(A6),A1
JSR SEEKRGN
MOVE D1,-(SP) ;REMEMBER IF RGN CHANGED
LEA STATEB(A6),A1
JSR SEEKRGN
OR D1,(SP) ;REMEMBER IF RGN CHANGED
LEA STATEC(A6),A1
JSR SEEKRGN
OR (SP)+,D1 ;HAS EITHER RGN CHANGED ?
BEQ.S ABCDONE ;NO, WE'RE DONE
MOVE.L STATEA+SCANBUF(A6),A0
MOVE.L STATEB+SCANBUF(A6),A1
MOVE.L STATEC+SCANBUF(A6),A2
MOVE.L MASKBUF(A6),A3
MOVE BUFSIZE(A6),D1
ABCLOOP MOVE.L (A0)+,D0
AND.L (A1)+,D0
AND.L (A2)+,D0
MOVE.L D0,(A3)+
DBRA D1,ABCLOOP
ABCDONE RTS
;---------------------------------------------------------------;
; ;
; INTERFACE TO EACH OF THE STRETCHBITS SCANLINE LOOPS: ;
; ;
; REGISTERS: A0: D0: ;
; A1: D1: ;
; A2: MASKPTR D2: LONGCNT ;
; A3: SRCPTR D3: ;
; A2: DSTPTR D4: ;
; A4: D5: SRCSHIFT ;
; A6: D6: DSTSHIFT ;
; A7: D7: INVERT ;
; ;
;---------------------------------------------------------------;
;-------------------------------------------------------
;
; MODE 0 OR 4: SRC --> DST
;
MASK0 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP
LSR.L D6,D0 ;ALIGN TO DST
SWAP D0 ;PUT INTO HI HALF OF D0
MOVE.L (A3)+,D1 ;GET SRC FROM BITMAP AND BUMP RIGHT
LSR.L D6,D1 ;ALIGN TO DST
MOVE D1,D0 ;ASSEMBLE ONE LONG
EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET
MOVE.L (A2)+,D1 ;GET MASK
AND.L D1,D0 ;MASK SRC
NOT.L D1 ;FORM NOTMASK
AND.L (A4),D1 ;GET DST DATA
OR.L D1,D0 ;MERGE WITH SRC DATA
MOVE.L D0,(A4)+ ;PUT RESULT IN DST
DBRA D2,MASK0 ;LOOP ALL LONGS THIS ROW
BRA NEXTDST ;GO FOR NEXT ROW
;-------------------------------------------------------
;
; MODE 1 OR 5: SRC OR DST --> DST
;
MASK1 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP
LSR.L D6,D0 ;ALIGN TO DST
SWAP D0 ;PUT INTO HI HALF OF D0
MOVE.L (A3)+,D1 ;GET SRC FROM BITMAP
LSR.L D6,D1 ;ALIGN TO DST
MOVE D1,D0 ;ASSEMBLE ONE LONG
EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET
AND.L (A2)+,D0 ;AND WITH MASK
OR.L D0,(A4)+ ;OR RESULT INTO DST
DBRA D2,MASK1 ;LOOP ALL LONGS THIS ROW
BRA NEXTDST ;LOOP FOR NEXT ROW
;-------------------------------------------------------
;
; MODE 2 OR 6: SRC XOR DST --> DST
;
MASK2 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP
LSR.L D6,D0 ;ALIGN TO DST
SWAP D0 ;PUT INTO HI HALF OF D0
MOVE.L (A3)+,D1 ;GET SRC FROM BITMAP
LSR.L D6,D1 ;ALIGN TO DST
MOVE D1,D0 ;ASSEMBLE ONE LONG
EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET
AND.L (A2)+,D0 ;AND WITH MASK
EOR.L D0,(A4)+ ;XOR RESULT INTO DST
DBRA D2,MASK2 ;LOOP ALL LONGS THIS ROW
BRA NEXTDST ;LOOP FOR NEXT ROW
;-------------------------------------------------------
;
; MODE 3 OR 7: SRC BIC DST --> DST
;
MASK3 MOVE.L -2(A3),D0 ;GET SRC FROM BITMAP
LSR.L D6,D0 ;ALIGN TO DST
SWAP D0 ;PUT INTO HI HALF OF D0
MOVE.L (A3)+,D1 ;GET SRC FROM BITMAP
LSR.L D6,D1 ;ALIGN TO DST
MOVE D1,D0 ;ASSEMBLE ONE LONG
EOR.L D7,D0 ;INVERT SRC IF MODE BIT 2 SET
AND.L (A2)+,D0 ;AND WITH MASK
NOT.L D0 ;INVERT FOR BIC
AND.L D0,(A4)+ ;BIC RESULT INTO DST
DBRA D2,MASK3 ;LOOP ALL LONGS THIS ROW
BRA NEXTDST ;LOOP FOR NEXT ROW
MODETAB .BYTE MODETAB-MASK0
.BYTE MODETAB-MASK1
.BYTE MODETAB-MASK2
.BYTE MODETAB-MASK3
.PROC SetupStretch
;--------------------------------------------------------------
;
; Routine to setup case jump for StretchRow,
; based on horiz numer and denom.
;
; Call SetupStretch with numer in D0, denom in D1.
; Returns case jump in A0, fraction in D0.
;
; Call resulting case jump with:
;
; A0: srcPtr
; A1: dstPtr
; A2: dstLimit
; D4: fraction
;
; clobbers D0-D3,A0-A1
;
LEA DONE,A0 ;POINT TO ABORT
TST D0 ;IS NUMER <= 0 ?
BLE FOUND ;YES, POINT TO ABORT
TST D1 ;IS DENOM <= 0 ?
BLE FOUND ;YES, POINT TO ABORT
LEA ONE,A0 ;POINT TO FAST COPY
CMP D1,D0 ;IS NUMER = DENOM ?
BEQ FOUND ;YES, USE FAST COPY
BLT.S SHRNKING ;NO, BRANCH IF SHRINKING
;
; We will be stretching. Calc fract = denom/numer and check for fast.
;
STRCHING MOVE D0,D3 ;MAKE A COPY OF NUMER
MOVE D1,D4 ;MAKE A COPY OF DENOM
CLR.L -(SP) ;ROOM FOR FCN RESULT
MOVE D1,-(SP) ;PUSH DENOM
MOVE D0,-(SP) ;PUSH NUMER
_FixRatio ;CALL FIXRATIO, < 1.0
MOVE.L (SP)+,D0 ;POP RESULT
LEA DOUBLE,A0 ;CHECK FOR FAST RATIOS
CMP #$8000,D0
BEQ.S FOUND
LEA QUAD,A0
CMP #$4000,D0
BEQ.S FOUND
LEA EIGHT,A0
CMP #$2000,D0
BEQ.S FOUND
LEA SIXTEEN,A0
CMP #$1000,D0
BEQ.S FOUND
LEA ONE.5,A0
CMP #$AAAA,D0
BEQ.S FOUND
LEA TRIPLE,A0
CMP #$5555,D0
BEQ.S FOUND
LEA SIX,A0
CMP #$2AAA,D0
BEQ.S FOUND
;
; check for any multiple of 8:
;
EXT.L D3 ;CLEAR HI WORD OF NUMER
DIVU D4,D3 ;CALC NUMER DIV DENOM
MOVE D3,D1 ;SAVE QUOTIENT
AND.L #$FFFF0007,D3 ;IS SCALE AN EVEN MULT OF 8 ?
BNE.S NOMATCH ;NO, USE GENERAL STRETCH
MOVE D1,D0 ;YES RETURN QUOTIENT IN D0
LEA EIGHTS,A0 ;POINT TO FAST ROUTINE
RTS ;AND RETURN
NOMATCH LEA STRETCH,A0 ;POINT TO SLOW GENERAL CODE
FOUND RTS ;RETURN WITH CASE JUMP IN A0
;
; We will be shrinking. Calc fract = numer/denom and check for fast.
;
SHRNKING CLR.L -(SP) ;ROOM FOR FCN RESULT
MOVE D0,-(SP) ;PUSH NUMER
MOVE D1,-(SP) ;PUSH DENOM
_FixRatio ;CALL FIXRATIO, < 1.0
MOVE.L (SP)+,D0 ;POP RESULT
LEA HALF,A0 ;CHECK FOR FAST RATIOS
CMP #$8000,D0
BEQ.S FOUND
LEA QRTR,A0
CMP #$4000,D0
BEQ.S FOUND
LEA THREE4,A0
CMP #$C000,D0
BEQ.S FOUND
LEA SHRINK,A0
BRA FOUND
;-----------------------------------------------
;
; NUMERATOR = DENOMINATOR, JUST COPY LONGS
;
ONE MOVE.L (A0)+,(A1)+ ;COPY ONE LONG
MOVE.L (A0)+,(A1)+ ;COPY ANOTHER LONG
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO ONE ;NO, LOOP FOR MORE
RTS ;ALL DONE
;---------------------------------------------------
;
; SHRINK TO THREE QUARTERS.
;
THREE4 MOVEQ #3,D3 ;MASK FOR HI 2 BITS
ROR.L #2,D3 ;IE. $C0000000
CLR.L -(SP) ;ALLOCATE A LONG OF TEMP
THREE4A MOVE.L (A0)+,D0 ;GET A LONG OF SRC
MOVEQ #7,D2 ;INIT COUNT OF 24 DST BITS
THREE4B ADD.L D0,D0 ;GET 1 BIT OF SRC
ADDX.L D1,D1 ;PUT 1 BIT TO DST
ADD.L D3,D0 ;PUT HI 2 BITS INTO CARRY
ADDX.L D1,D1 ;SHIFT INTO DST
LSL.L #3,D0 ;SHIFT LEFT 3 BITS
ADDX.L D1,D1 ;PUT CARRY BIT INTO DST
DBRA D2,THREE4B ;LOOP 8 TIMES
MOVE.L D1,(SP) ;STASH 3 DST BYTES IN TEMP
MOVE.B 1(SP),(A1)+ ;PUT FIRST BYTE TO DST
MOVE.B 2(SP),(A1)+ ;PUT SECOND BYTE TO DST
MOVE.B 3(SP),(A1)+ ;PUT THIRD BYTE TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO THREE4A ;NO, CONTINUE
ADD #4,SP ;YES, STRIP TEMP
RTS ;AND QUIT
;---------------------------------------------------
;
; SHRINK TO ONE HALF.
;
HALF MOVEQ #3,D3 ;MASK FOR HI 2 BITS
ROR.L #2,D3 ;IE. $C0000000
HALF1 MOVE.L (A0)+,D0 ;GET A LONG OF SRC
MOVEQ #7,D2 ;INIT COUNT OF 16 DST BITS
HALF2 ADD.L D3,D0 ;PUT OR OF HI BITS INTO CARRY
ADDX D1,D1 ;SHIFT BIT INTO DST
LSL.L #2,D0 ;SHIFT LEFT 2 BITS
ADD.L D3,D0 ;PUT OR OF HI BITS INTO CARRY
ADDX.L D1,D1 ;SHIFT BIT INTO DST
LSL.L #2,D0 ;SHIFT LEFT 2 BITS
DBRA D2,HALF2 ;LOOP 8 TIMES
MOVE D1,(A1)+ ;THEN PUT A WORD TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO HALF1 ;NO, CONTINUE
RTS ;YES, QUIT
;---------------------------------------------------
;
; SHRINK TO ONE QUARTER.
;
QRTR MOVE.L #$F0000000,D3 ;MASK FOR HI 4 BITS
QRTR1 MOVE.L (A0)+,D0 ;GET A LONG OF SRC
MOVEQ #7,D2 ;INIT COUNT OF 8 DST BITS
QRTR2 ADD.L D3,D0 ;PUT OR OF HI BITS INTO CARRY
ADDX.L D1,D1 ;SHIFT BIT INTO DST
LSL.L #4,D0 ;SHIFT LEFT 4 BITS
DBRA D2,QRTR2 ;LOOP 8 TIMES
MOVE.B D1,(A1)+ ;THEN PUT A BYTE TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO QRTR1 ;NO, CONTINUE
RTS ;YES, QUIT
;-----------------------------------------------
;
; STRETCH TO 1.5 TIMES AS WIDE
;
ONE.5 MOVE.B (A0)+,D0 ;GET FIRST BYTE FROM SRC
MOVE D0,D1 ;MAKE AN EXTRA COPY
LSR.B #4,D1 ;GET HI NIBBLE
MOVE.B TABLE15(D1),D2 ;EXPAND TO 6 BITS
LSL.L #6,D2 ;SHIFT OVER 6
AND #$F,D0 ;GET LO NIBBLE
MOVE.B TABLE15(D0),D2 ;EXPAND TO 6 BITS
LSL.L #6,D2 ;SHIFT OVER 6
MOVE.B (A0)+,D0 ;GET SECOND BYTE FROM SRC
MOVE D0,D1 ;MAKE AN EXTRA COPY
LSR.B #4,D1 ;GET HI NIBBLE
MOVE.B TABLE15(D1),D2 ;EXPAND TO 6 BITS
LSL.L #6,D2 ;SHIFT OVER 6
AND #$F,D0 ;GET LO NIBBLE
MOVE.B TABLE15(D0),D2 ;EXPAND TO 6 BITS
LSR.L #2,D2 ;RIGHT JUSTIFY
SWAP D2 ;FLIP WORDS
MOVE.B D2,(A1)+ ;PUT FIRST BYTE TO DST
SWAP D2 ;FLIP BACK AGAIN
MOVE D2,D1
ROR #8,D1
MOVE.B D1,(A1)+ ;PUT SECOND BYTE TO DST
MOVE.B D2,(A1)+ ;PUT THIRD BYTE TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO ONE.5 ;NO, LOOP FOR MORE
RTS ;ALL DONE
TABLE15 .BYTE $00,$0C,$10,$1C ;1.5 TIMES TABLE
.BYTE $60,$6C,$70,$7C
.BYTE $80,$8C,$90,$9C
.BYTE $E0,$EC,$F0,$FC
;-----------------------------------------------
;
; DOUBLE USING TABLE LOOKUP
;
DOUBLE MOVE.B (A0)+,D0 ;GET A BYTE FROM SRC
MOVE D0,D1 ;MAKE AN EXTRA COPY
LSR.B #4,D1 ;GET HI NIBBLE
MOVE.B TABLE2(D1),(A1)+ ;DOUBLE FOR A BYTE
AND #$F,D0 ;GET LO NIBBLE
MOVE.B TABLE2(D0),(A1)+ ;DOUBLE FOR A BYTE
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO DOUBLE ;NO, LOOP FOR MORE
RTS ;ALL DONE
TABLE2 .BYTE $00,$03,$0C,$0F ;DOUBLING TABLE
.BYTE $30,$33,$3C,$3F
.BYTE $C0,$C3,$CC,$CF
.BYTE $F0,$F3,$FC,$FF
;-----------------------------------------------
;
; TRIPLE USING TABLE LOOKUP
;
TRIPLE MOVE.B (A0)+,D0 ;GET A BYTE FROM SRC
MOVE D0,D1 ;MAKE AN EXTRA COPY
MOVE D0,D2 ;MAKE A THIRD COPY
LSR.B #5,D2 ;GET 3 HI BITS
MOVE.B TABLE3A(D2),(A1)+ ;PUT FIRST BYTE TO DST
LSR.B #2,D1
AND #$F,D1 ;GET MIDDLE 4 BITS
MOVE.B TABLE3B(D1),(A1)+ ;PUT SECOND BYTE TO DST
AND #$7,D0 ;GET 3 LO BITS
MOVE.B TABLE3C(D0),(A1)+ ;PUT THIRD BYTE TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO TRIPLE ;NO, LOOP FOR MORE
RTS ;ALL DONE
TABLE3A .BYTE $00,$03,$1C,$1F ;TRIPLING TABLE
.BYTE $E0,$E3,$FC,$FF
TABLE3B .BYTE $00,$01,$0E,$0F
.BYTE $70,$71,$7E,$7F
.BYTE $80,$81,$8E,$8F
.BYTE $F0,$F1,$FE,$FF
TABLE3C .BYTE $00,$07,$38,$3F
.BYTE $C0,$C7,$F8,$FF
;-----------------------------------------------
;
; QUADRUPLE USING TABLE LOOKUP
;
QUAD MOVE.B (A0)+,D0 ;GET A BYTE FROM SRC
MOVE D0,D1 ;MAKE AN EXTRA COPY
AND #$F0,D1 ;MASK FOR HI NIBBLE
LSR #3,D1 ;SHIFT FOR TABLE INDEX
MOVE.W TABLE4(D1),(A1)+ ;PUT FIRST WORD TO DST
AND #$F,D0 ;MASK FOR LO NIBBLE
ADD D0,D0 ;DOUBLE FOR TABLE INDEX
MOVE.W TABLE4(D0),(A1)+ ;PUT SECOND WORD TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO QUAD ;NO, LOOP FOR MORE
RTS ;ALL DONE
TABLE4 .WORD $0000,$000F,$00F0,$00FF ;QUADRUPLING TABLE
.WORD $0F00,$0F0F,$0FF0,$0FFF
.WORD $F000,$F00F,$F0F0,$F0FF
.WORD $FF00,$FF0F,$FFF0,$FFFF
;-----------------------------------------------
;
; STRETCH BY SIX USING TABLE LOOKUP
;
SIX MOVE.B (A0)+,D0 ;GET A BYTE FROM SRC
MOVE D0,D1 ;MAKE AN EXTRA COPY
AND #$E0,D1 ;MASK FOR HI 3 BITS
LSR.B #4,D1 ;SHIFT FOR TABLE INDEX
MOVE.W TABLE6A(D1),(A1)+ ;PUT A WORD TO DST
MOVE D0,D1 ;GET SRC BYTE AGAIN
AND #$3C,D1 ;MASK FOR MIDDLE 4 BITS
LSR.B #1,D1 ;SHIFT FOR TABLE INDEX
MOVE.W TABLE6B(D1),(A1)+ ;PUT A WORD TO DST
MOVE D0,D1 ;GET SRC BYTE AGAIN
AND #7,D1 ;MASK FOR LO 3 BITS
ADD D1,D1 ;DOUBLE FOR TABLE INDEX
MOVE.W TABLE6C(D1),(A1)+ ;PUT A WORD TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO SIX ;NO, LOOP FOR MORE
RTS ;ALL DONE
TABLE6A .WORD $0000,$000F,$03F0,$03FF ;SIX TIMES TABLE
.WORD $FC00,$FC0F,$FFF0,$FFFF
TABLE6B .WORD $0000,$0003,$00FC,$00FF
.WORD $3F00,$3F03,$3FFC,$3FFF
.WORD $C000,$C003,$C0FC,$C0FF
.WORD $FF00,$FF03,$FFFC,$FFFF
TABLE6C .WORD $0000,$003F,$0FC0,$0FFF
.WORD $F000,$F03F,$FFC0,$FFFF
;-----------------------------------------------
;
; SCALE UP BY EIGHT USING TABLE LOOKUP
;
EIGHT MOVE.B (A0)+,D0 ;GET A BYTE OF SRC
MOVE D0,D1 ;MAKE AN EXTRA COPY
AND #$F0,D1 ;MASK FOR HI NIBBLE
LSR #2,D1 ;SHIFT FOR TABLE INDEX
MOVE.L TABLE8(D1),(A1)+ ;PUT FIRST LONG TO DST
AND #$0F,D0 ;MASK FOR LO NIBBLE
LSL #2,D0 ;SHIFT FOR TABLE INDEX
MOVE.L TABLE8(D0),(A1)+ ;PUT SECOND LONG TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO EIGHT ;NO, GO FOR MORE
RTS ;ALL DONE
TABLE8 .LONG $00000000,$000000FF,$0000FF00,$0000FFFF
.LONG $00FF0000,$00FF00FF,$00FFFF00,$00FFFFFF
.LONG $FF000000,$FF0000FF,$FF00FF00,$FF00FFFF
.LONG $FFFF0000,$FFFF00FF,$FFFFFF00,$FFFFFFFF
;-------------------------------------------------
;
; SCALE UP BY 16
;
SIXTEEN MOVEQ #-1,D1 ;GET SOME BLACK
MOVE #$8000,D0 ;INIT SRC DATA
SIXTENA ADD D0,D0 ;GET ONE BIT OF SRC
BCC.S WHITE16 ;BR IF WHITE
BNE.S BLACK16 ;BR IF BLACK
MOVE (A0)+,D0 ;ELSE GET NEXT SRC WORD
ADDX D0,D0 ;SHIFT SRC BIT OUT, 1 BIT IN
BCS.S BLACK16 ;BR IF BLACK
WHITE16 CLR.W (A1)+ ;PUT A WORD OF WHITE TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO SIXTENA ;NO, GO FOR MORE
RTS ;ALL DONE
BLACK16 MOVE D1,(A1)+ ;PUT A WORD OF BLACK TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
BLO SIXTENA ;NO, GO FOR MORE
RTS ;ALL DONE
;-----------------------------------------------
;
; SCALE UP BY ANY MULTIPLE OF 8 GREATER THAN 2
;
EIGHTS LSR #3,D4 ;DIVIDE SCALE FACTOR BY 8
SUB #1,D4 ;SUB 1 FOR LOOP COUNT
MOVE #$8000,D0 ;INIT SRC DATA
EIGHTS1 ADD D0,D0 ;GET ONE SRC BIT IN CARRY
BNE.S EIGHTS2 ;TIME FOR NEW SRC ?
MOVE (A0)+,D0 ;YES, GET NEXT SRC LONG
ADDX D0,D0 ;SHIFT SRC BIT OUT, 1 BIT IN
EIGHTS2 SCS D1 ;SET OR CLR A BYTE
MOVE D4,D2 ;INIT LOOP COUNT
EIGHTS3 MOVE.B D1,(A1)+ ;PUT ONE BYTE TO DST
CMP.L A2,A1 ;IS DSTPTR >= DSTLIMIT ?
DBHI D2,EIGHTS3 ;LOOP TILL SCALE OR DST FULL
BLS EIGHTS1 ;MORE SRC IF DST NOT FULL
BRA.S DONE ;THEN QUIT
;------------------------------------------------------------------
;
; DO FULL RATIO SCALING, SHRINKING ONE BIT AT A TIME
;
SHRINK CLR D1 ;INIT DST WORD
MOVE #$8000,D0 ;INIT SRC WORD
MOVE D0,D2 ;INIT MASK
MOVE D4,D3 ;COPY RATIO
LSR #1,D3 ;INIT ERR TO RATIO/2
NXTSRC1 ADD D0,D0 ;GET SRC BIT
BCC.S WHITE1 ;BRANCH IF WHITE
BNE.S BLACK1 ;BRANCH IF BLACK
MOVE (A0)+,D0 ;ELSE GET NEW SRC WORD
ADDX D0,D0 ;GET SRC BIT
BCC.S WHITE1 ;AND CONTINUE
BLACK1 OR D2,D1 ;SET A BIT IN DST
WHITE1 ADD D4,D3 ;TIME FOR NEXT DSTBIT ?
BCC NXTSRC1 ;NO, LOOP MORE SRC
ROR #1,D2 ;YES, ROTATE MASK
BCC NXTSRC1 ;LOOP IF DST WORD OK
MOVE D1,(A1)+ ;ELSE WRITE WORD TO DST
CLR D1 ;RESET DST WORD
CMP.L A2,A1 ;DSTPTR >= DSTLIMIT ?
BLO NXTSRC1 ;NO, LOOP
RTS ;YES, QUIT
;------------------------------------------------------------------
;
; DO FULL RATIO SCALING, STRETCHING ONE BIT AT A TIME
;
STRETCH CLR D1 ;INIT DST WORD
MOVE #$8000,D0 ;INIT SRC WORD
MOVE D0,D2 ;INIT MASK
MOVE D4,D3 ;COPY RATIO
LSR #1,D3 ;INIT ERR TO RATIO/2
NXTSRC2 ADD D0,D0 ;GET SRC BIT
BCC.S WHITE2 ;BRANCH IF WHITE
BNE.S BLACK2 ;BRANCH IF BLACK
MOVE (A0)+,D0 ;ELSE GET NEW SRC WORD
ADDX D0,D0 ;GET SRC BIT
BCC.S WHITE2 ;CONTINUE WITH WHITE
BRA.S BLACK2 ;CONTINUE WITH BLACK
BLACKOK ADD D4,D3 ;TIME FOR NEXT SRC BIT ?
BCS NXTSRC2 ;YES, LOOP FOR SRC
BLACK2 OR D2,D1 ;SET A BIT OF DST
ROR #1,D2 ;ROTATE MASK
BCC BLACKOK ;LOOP IF DST WORD OK
MOVE D1,(A1)+ ;ELSE WRITE WORD TO DST
CLR D1 ;RESET DST WORD
CMP.L A2,A1 ;DSTPTR >= DSTLIMIT ?
BLO BLACKOK ;NO, LOOP
RTS ;YES, QUIT
WHITEOK ADD D4,D3 ;TIME FOR NEXT SRC BIT ?
BCS NXTSRC2 ;YES, LOOP FOR SRC
WHITE2 ROR #1,D2 ;ROTATE MASK
BCC WHITEOK ;LOOP IF DST WORD OK
MOVE D1,(A1)+ ;ELSE WRITE WORD TO DST
CLR D1 ;RESET DST WORD
CMP.L A2,A1 ;DSTPTR >= DSTLIMIT ?
BLO WHITEOK ;NO, LOOP
DONE RTS
.END