Files
JPEGView/Source/68020/CopyScaledFrom32.a
Aaron Giles 92bdb55672 JPEGView 3.3 for Macintosh
These are the sources for the final official release of JPEGView for the
Mac, back in 1994.
2015-02-05 00:18:10 -08:00

1 line
18 KiB
Plaintext

;*********************************************************/
;* This source code copyright (c) 1991-2001, Aaron Giles */
;* See the Read Me file for licensing information. */
;* Contact email: mac@aarongiles.com */
;*********************************************************/
;
; On entry here we expect the following values:
;
; srcBase = (long) pointer to the first source pixel
; srcRow = (long) rowBytes for the source pixmap
; dstBase = (long) pointer to the first destination pixel
; dstRow = (long) rowBytes for the destination pixmap
; itAddr = (long) pointer to the inverse color table
; ctAddr = (long) pointer to the color table
; theRgn = (long) handle to the destination region
; boxRect = (Rect) the bounding rectangle of this region
; height = (word) height of the region bounding box
; width = (word) width of the region bounding box
; srcWidth = (word) width of the source rectangle
; srcHeight = (word) height of the source rectangle
; dstWidth = (word) width of the destination rectangle
; dstHeight = (word) height of the destination rectangle
; xRemainder = (word) starting X remainder for the source counter
; yRemainder = (word) starting Y remainder for the source counter
;
; The following registers will be modified:
;
; d0,d1,d2
; a0,a1
;
; Internally, the register usage is as follows:
;
; d0 = accumulator
; d1 = scratch register for expanding 24-bit pixels
; d2 = scratch [save for d6.l/d7.l]
; d3 = scratch [multiplier for xy-scale]
; d4 = (low word) remaining source Y pixels needed for current dest. Y
; d4 = (high word) dstHeight/srcHeight
; d5 = (low word) remaining Y fraction of current source pixel
; d5 = (high word) 1.00
; d6 = (low word) remaining source Y pixels needed for current dest. X
; d6 = (high word) dstWidth/srcWidth
; d7 = (low word) remaining Y fraction of current source pixel
; d7 = (high word) scratch [save for d5.l]
;
; a0 = pointer to 24-bit source row
; a1 = pointer to 8-bit destination row
; a2 = sum of the red contributions
; a3 = sum of the green contributions
; a4 = sum of the blue contributions
; a5 = temporary save area for a0
;
movem.l d3-d7/a2-a6,-(sp) ;save registers on the stack
move.l 48(sp),a6 ;get the address of the CopyData structure in a6
;(based off stack: 10 registers + 1 a6 link + 1 return addr.
; = 12 * 4 bytes = 48 bytes)
;
; Create some room in the stack for our buffers
;
clr.l d0 ;zero out d0
move.w width(a6),d0 ;get width of destination in d0.l
addq.l #2,d0 ;plus two for overflows
lsl.l #4,d0 ;times 16 (2 * 6 + 4)
addq.l #4,d0 ;add 4 for alignment
sub.l d0,sp ;get it from the stack space
move.l d0,-(sp) ;and save the amount
lsr.l #3,d0 ;return to times 2
move.l d0,d1 ;save that in d1
lsl.l #1,d0 ;d0 = width * 4
add.l d1,d0 ; = width * 6
moveq.l #13,d1 ;offset by 10, plus 3 for rounding up
add.l sp,d1 ;add in the stack pointer
andi.l #-4,d1 ;make it longword-aligned (-4 == $fffffffc)
move.l d1,evenAddr(a6) ;that's the even buffer
add.l d0,d1 ;point to the odd buffer
move.l d1,oddAddr(a6) ;save that pointer
add.l d0,d1 ;point to the scale buffer
move.l d1,outputAddr(a6) ;now we've got them all
;
; Clear the dithering buffers to zeros
;
move.l evenAddr(a6),a0 ;point to the evenBuffer
subq.l #4,d1 ;decrement d1 for the dbra, plus the extras
@ClearLoop:
clr.w (a0)+ ;clear this word
dbra.w d0,@ClearLoop ;loop for all dithering
;
; Initialize the region data
;
move.l theRgn(a6),a0 ;get theRgn in a0
lea.l rgnBuffer(a6),a1 ;point a1 to the region buffer
move.w boxRect+0(a6),d2 ;get box top in d2
move.w boxRect+2(a6),d3 ;box left in d3
move.w height(a6),d4 ;height in d4
move.w width(a6),d5 ;width in d5
jsr InitRegion ;initialize the region
move.l a0,-(sp) ;store our pointer to the rgn on the stack
;
; Set up the source/destination quantities in the high words of d4-d7
;
move.w #1024,d5 ;get 1.00 into d5 (1024 == $0400)
swap d5 ;swap it high
clr.l d4 ;clear out d4
move.w dstHeight(a6),d4 ;get dest height there
moveq.l #10,d0 ;get shift value in d0
lsl.l d0,d4 ;shift it up by 10 bits
move.w srcHeight(a6),d0 ;get source height in d0
divu.w d0,d4 ;divide by full source height
addq.w #1,d4 ;plus one to prevent overflows
swap d4 ;swap it high
clr.l d6 ;clear out d6
move.w dstWidth(a6),d6 ;get destination width in d6
moveq.l #10,d0 ;get shift value in d0
lsl.l d0,d6 ;shift d6 up by 10 bits
move.w srcWidth(a6),d0 ;get source width in d0
divu.w d0,d6 ;divide by full source width
addq.w #1,d4 ;plus one to prevent overflows
swap d6 ;into high word of d6
;
; Set up the counter "rows" & reset the source Y remainder
;
move.w height(a6),rows(a6) ;set up the row counter
move.w yRemainder(a6),d5 ;restore yRemainder
;
; The outermost (row) loop begins here; set up our pointers into the data
;
@ScaleRowLoop:
move.l srcBase(a6),a0 ;get pointer to source in a0
move.l outputAddr(a6),a1 ;put to destination with a1
;
; Reset the "columns" counter and reset the source X remainder
;
move.w width(a6),columns(a6);reset the column counter
move.w xRemainder(a6),d7 ;restore xRemainder
;
; The inner (column) loop begins here; set up our counters in the destination system
;
@ScaleColLoop:
swap d5 ;reset remaining destination to 1.00
move.w d5,d4 ;first in X
move.w d5,d6 ;and then in Y
swap d5 ;restore d5
clr.l d0 ;clear out d0
move.l d0,a2 ;zero out the colors: red
move.l d0,a3 ;green
move.l d0,a4 ;blue
;
; Determine what sort of scaling is best for us
;
cmp.w d4,d5 ;can we avoid Y scaling?
bge.s @NoYScale ;if so, check X as well
cmp.w d6,d7 ;can we at least avoid X scaling?
bge.w @ScaleY ;if so, scale in Y only
bra.w @ScaleXY ;otherwise, scale in both
@NoYScale:
cmp.w d6,d7 ;do we have to scale in X?
bge.w @NoScale ;if not, do it quick
bra.w @ScaleX ;otherwise, just scale X
;
; End of the columns loop here; decrement counters and loop until done
;
@ScaleColEnd:
move.l a2,d1 ;get red in d1
lsl.l #6,d1 ;shift it up six bits here
move.l a3,d0 ;get green in d0
lsr.l #2,d0 ;shift it down two bits
move.w d0,d1 ;copy the resulting word in
move.l a4,d0 ;get blue in d0
moveq.l #10,d2 ;get shift amount in d2
lsr.l d2,d0 ;shift it down ten bits
move.b d0,d1 ;copy the last byte in
move.l d1,(a1)+ ;store that to the output
@ScaleColSkip:
subq.w #1,columns(a6) ;decrement columns
bne.s @ScaleColLoop ;loop if not done
;
; We now have a row; save our registers and set up to do a dithered copy
;
movem.l d4-d7,-(sp) ;save registers
move.l outputAddr(a6),a0 ;source here
move.l dstBase(a6),a1 ;get destination address
move.l itAddr(a6),a2 ;inverse color table
move.l ctAddr(a6),a3 ;color table
lea.l rgnBuffer+4(a6),a4 ;get rgnBuffer address in a4
move.l a4,d2 ;point d2 (a6) to the region buffer
move.l evenAddr(a6),d0 ;even address
move.l oddAddr(a6),d1 ;odd address
move.l errTable(a6),d6 ;point d6 to the error table
move.w width(a6),d7 ;column count
bchg.b #0,evodd+1(a6) ;check the even/odd flag
beq.s @ScaleEven ;if zero, do an even row
move.l odd(a6),a4 ;get address of routine
jsr (a4) ;otherwise, dither as an odd row
bra.s @ScaleRowEnd ;skip ahead
@ScaleEven:
move.l even(a6),a4 ;get address of routine
jsr (a4) ;dither as an even row
@ScaleRowEnd:
movem.l (sp)+,d4-d7 ;restore registers
;
; Adjust ourselves for the next row
;
subq.w #1,rows(a6) ;decrement rows
beq.w @ScaleExit ;exit if done
move.l dstRow(a6),d0 ;get destination row increment in d0
add.l d0,dstBase(a6) ;point to next destination row
move.l srcRow(a6),d0 ;get source row increment in d0
swap d5 ;swap d5 low
move.w d5,d4 ;get 1.00 count in d4
swap d5 ;restore d5
@ScaleIncRow:
cmp.w d4,d5 ;did we upgrade 1 row?
bgt.s @ScaleRowNext ;if not, loop
add.l d0,srcBase(a6) ;point to next source row
sub.w d5,d4 ;adjust Y for remainder
swap d4 ;get destination height in d4
move.w d4,d5 ;reset Y count for the new pixel
swap d4 ;restore Y count
bra.s @ScaleIncRow ;handle any further adjustments
@ScaleRowNext:
sub.w d4,d5 ;get the new Y multiplier
;
; Update the region counters
;
subq.w #1,rgnBuffer(a6) ;decrement the Y region count
bne.w @ScaleRowLoop ;skip if we're not done
move.l (sp)+,a0 ;restore region pointer
lea.l rgnBuffer+4(a6),a1 ;point a1 into the region buffer
move.w boxRect+2(a6),d0 ;get left end of the box in d0
jsr UpdateRegion ;update our region
move.l a0,-(sp) ;push new position again
bra.w @ScaleRowLoop ;loop for more
;------------------------- NoScale ---------------------------
@NoScale:
move.l (a0),(a1)+ ;just copy src->dest
sub.w d6,d7 ;adjust for remainder
bne.s @NSR ;skip this if not done in X here
swap d6 ;get source fraction in d6
move.w d6,d7 ;reset d7 to a new value
swap d6 ;restore d6
addq.l #4,a0 ;point to next pixel
@NSR:
bra.w @ScaleColSkip ;loop for another
;------------------------- ScaleX ----------------------------
@ScaleX:
move.l (a0)+,d1 ;get the next pixel
clr.l d0 ;clear out d0
move.b d1,d0 ;get the blue into d0
mulu.w d7,d0 ;times remainder of the source
add.l d0,a4 ;add to the blue total
move.w d1,d0 ;get pixel again
lsr.w #8,d0 ;shift to get the green
mulu.w d7,d0 ;times remainder of the source
add.l d0,a3 ;add to the green total
swap d1 ;swap the red into the low byte
clr.l d0 ;clear out d0
move.b d1,d0 ;get the red in d0
mulu.w d7,d0 ;times remainder of the source
add.l d0,a2 ;add to the red total
sub.w d7,d6 ;adjust X for remainder
swap d6 ;get dest width in d6
move.w d6,d7 ;reset X count for the new pixel
swap d6 ;restore X count
cmp.w d6,d7 ;still another whole pixel to go?
blt.s @ScaleX ;if so, loop again
move.l (a0),d1 ;get the next pixel
clr.l d0 ;clear out d0
move.b d1,d0 ;get the blue into d0
mulu.w d6,d0 ;times remainder of the source
add.l d0,a4 ;add to the blue total
move.w d1,d0 ;get pixel again
lsr.w #8,d0 ;shift to get the green
mulu.w d6,d0 ;times remainder of the source
add.l d0,a3 ;add to the green total
swap d1 ;swap the red into the low byte
clr.l d0 ;clear out d0
move.b d1,d0 ;get the red in d0
mulu.w d6,d0 ;times remainder of the source
add.l d0,a2 ;add to the red total
sub.w d6,d7 ;adjust X for remainder
bne.w @ScaleColEnd ;if we don't need next pixel, skip
swap d6 ;get dest. width in d6
move.w d6,d7 ;reset X counter for new pixel
swap d6 ;restore X counter
addq.l #4,a0 ;point to it in memory
bra.w @ScaleColEnd ;loop for the next pixel
;------------------------- ScaleY ----------------------------
@ScaleY:
move.l a0,a5 ;copy a0 into a5 for storage
move.l srcRow(a6),d2 ;get source row into d2 for speed
move.w d5,d3 ;save d5 into d3
@ScaleYLoop:
move.l (a0),d1 ;get the next pixel
clr.l d0 ;clear out d0
move.b d1,d0 ;get the blue into d0
mulu.w d5,d0 ;times remainder of the source
add.l d0,a4 ;add to the blue total
move.w d1,d0 ;get pixel again
lsr.w #8,d0 ;shift to get the green
mulu.w d5,d0 ;times remainder of the source
add.l d0,a3 ;add to the green total
swap d1 ;swap the red into the low byte
clr.l d0 ;clear out d0
move.b d1,d0 ;get the red in d0
mulu.w d5,d0 ;times remainder of the source
add.l d0,a2 ;add to the red total
add.l d2,a0 ;point to the next row
sub.w d5,d4 ;adjust Y for remainder
swap d4 ;get destination height in d4
move.w d4,d5 ;reset Y count for the new pixel
swap d4 ;restore Y count
cmp.w d4,d5 ;still another whole pixel to go?
blt.s @ScaleYLoop ;if so, loop again
move.l (a0),d1 ;get the next pixel
clr.l d0 ;clear out d0
move.b d1,d0 ;get the blue into d0
mulu.w d4,d0 ;times remainder of the source
add.l d0,a4 ;add to the blue total
move.w d1,d0 ;get pixel again
lsr.w #8,d0 ;shift to get the green
mulu.w d4,d0 ;times remainder of the source
add.l d0,a3 ;add to the green total
swap d1 ;swap the red into the low byte
clr.l d0 ;clear out d0
move.b d1,d0 ;get the red in d0
mulu.w d4,d0 ;times remainder of the source
add.l d0,a2 ;add to the red total
move.w d3,d5 ;restore original d5 here
move.l a5,a0 ;restore original a0 here
sub.w d6,d7 ;adjust X for remainder
bne.w @ScaleColEnd ;if we don't need next pixel, skip
swap d6 ;get dstWidth in d6
move.w d6,d7 ;reset X counter for new pixel
swap d6 ;restore X counter
addq.l #4,a0 ;point to it in memory
bra.w @ScaleColEnd ;loop for the next pixel
;------------------------- ScaleXY ----------------------------
@ScaleXY:
move.l a0,-(sp) ;save a0 on the stack
swap d7 ;swap d7
move.w d5,d7 ;save d5.l there
swap d7 ;safely in the high word
move.w d7,d2 ;save d7 in d2
swap d2 ;(high word)
move.w d6,d2 ;and save d6 in the low
@ScaleXYLoopY:
move.l a0,a5 ;copy a0 to a5 for now
@ScaleXYLoopX:
move.w d7,d3 ;get X multiplier in d3
mulu.w d5,d3 ;times Y multiplier
; moveq.l #10,d0 ;get divisor in d0
lsr.l #4,d3 ;shift off extra bits
move.l (a0)+,d1 ;get the next pixel
clr.w d0
move.b d1,d0 ;get the blue into d0
mulu.w d3,d0 ;times remainder of the source
add.l d0,a4 ;add to the blue total
move.w d1,d0 ;get pixel again
lsr.w #8,d0 ;shift to get the green
mulu.w d3,d0 ;times remainder of the source
add.l d0,a3 ;add to the green total
swap d1 ;swap the red into the low byte
clr.l d0 ;clear out d0
move.b d1,d0 ;get the red in d0
mulu.w d3,d0 ;times remainder of the source
add.l d0,a2 ;add to the red total
sub.w d7,d6 ;adjust X for remainder
swap d6 ;get dest width in d6
move.w d6,d7 ;reset X count for the new pixel
swap d6 ;restore X count
cmp.w d6,d7 ;still another whole pixel to go?
blt.s @ScaleXYLoopX ;if so, loop again
move.w d6,d3 ;get X multiplier in d3
mulu.w d5,d3 ;times Y multiplier
; moveq.l #10,d0 ;get divisor in d0
lsr.l #4,d3 ;shift off 8 bits
move.l (a0),d1 ;get the next pixel
clr.w d0
move.b d1,d0 ;get the blue into d0
mulu.w d3,d0 ;times remainder of the source
add.l d0,a4 ;add to the blue total
move.w d1,d0 ;get pixel again
lsr.w #8,d0 ;shift to get the green
mulu.w d3,d0 ;times remainder of the source
add.l d0,a3 ;add to the green total
swap d1 ;swap the red into the low byte
clr.l d0 ;clear out d0
move.b d1,d0 ;get the red in d0
mulu.w d3,d0 ;times remainder of the source
add.l d0,a2 ;add to the red total
move.w d2,d6 ;restore source counter in d6
swap d2 ;swap to get the low word
move.w d2,d7 ;restore source remainder in d7
swap d2 ;swap things back for the future
movea.l a5,a0 ;restore a0
add.l srcRow(a6),a0 ;point to the next row
sub.w d5,d4 ;adjust Y for remainder
swap d4 ;get destination height in d4
move.w d4,d5 ;reset Y count for the new pixel
swap d4 ;restore Y count
cmp.w d4,d5 ;still another whole pixel to go?
blt.s @ScaleXYLoopY ;if so, loop again
move.l a0,d0 ;copy current a0 into d0
sub.l d0,(sp) ;subtract it from old a0
@ScaleXYLoopX2:
move.w d7,d3 ;get X multiplier in d3
mulu.w d4,d3 ;times Y multiplier
; moveq.l #10,d0 ;get divisor in d0
lsr.l #4,d3 ;shift off extra bits
move.l (a0)+,d1 ;get the next pixel
clr.w d0
move.b d1,d0 ;get the blue into d0
mulu.w d3,d0 ;times remainder of the source
add.l d0,a4 ;add to the blue total
move.w d1,d0 ;get pixel again
lsr.w #8,d0 ;shift to get the green
mulu.w d3,d0 ;times remainder of the source
add.l d0,a3 ;add to the green total
swap d1 ;swap the red into the low byte
clr.l d0 ;clear out d0
move.b d1,d0 ;get the red in d0
mulu.w d3,d0 ;times remainder of the source
add.l d0,a2 ;add to the red total
sub.w d7,d6 ;adjust X for remainder
swap d6 ;get dest width in d6
move.w d6,d7 ;reset X count for the new pixel
swap d6 ;restore X count
cmp.w d6,d7 ;still another whole pixel to go?
blt.s @ScaleXYLoopX2 ;if so, loop again
move.w d6,d3 ;get X multiplier in d3
mulu.w d4,d3 ;times Y multiplier
; moveq.l #10,d0 ;get divisor in d0
lsr.l #4,d3 ;shift off extra bits
move.l (a0),d1 ;get the next pixel
clr.w d0
move.b d1,d0 ;get the blue into d0
mulu.w d3,d0 ;times remainder of the source
add.l d0,a4 ;add to the blue total
move.w d1,d0 ;get pixel again
lsr.w #8,d0 ;shift to get the green
mulu.w d3,d0 ;times remainder of the source
add.l d0,a3 ;add to the green total
swap d1 ;swap the red into the low byte
clr.l d0 ;clear out d0
move.b d1,d0 ;get the red in d0
mulu.w d3,d0 ;times remainder of the source
add.l d0,a2 ;add to the red total
sub.w d6,d7 ;adjust X for remainder
bne.s @SXYSave ;if we don't need next pixel, skip
swap d6 ;get dest. width in d6
move.w d6,d7 ;reset X counter for new pixel
swap d6 ;restore X counter
addq.l #4,a0 ;point to it in memory
@SXYSave:
swap d7 ;swap d7's words
move.w d7,d5 ;restore d5.l
swap d7 ;put things back
adda.l (sp)+,a0 ;point back to original row
move.l a2,d1 ;get red in d1
move.l a3,d0 ;get green in d0
lsr.l #8,d0 ;shift it down 8 bits
move.w d0,d1 ;copy the resulting word in
move.l a4,d0 ;get blue in d0
swap d0 ;swap it low
move.b d0,d1 ;copy the last byte in
move.l d1,(a1)+ ;store that to the output
bra.w @ScaleColSkip ;continue the loop
@ScaleExit:
add.l #4,sp ;pop off region position
move.l (sp)+,d0 ;get length of buffer
add.l d0,sp ;get it off the stack
movem.l (sp)+,d3-d7/a2-a6 ;get registers from the stack