JPEGView/Source/68020/DitherCopyTo16Even.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
7.0 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:
;
; a0 = pointer to the 24-bit source pixmap row
; a1 = pointer to the 8-bit destination pixmap row
; a2 = pointer to the inverse color table
; a3 = pointer to the color table
; d0 = pointer to the even row dithering buffer
; d1 = pointer to the odd row dithering buffer
; d2 = pointer to the region buffer
; d7 = (low word) column count
;
; The following registers will be modified:
;
; d0,d1,d2,d3,d4,d5,d6,d7
; a0,a1,a3
;
; Internally, the register usage is as follows:
;
; d0 = accumulator
; d1 = accumulator
; d2 = current sum of red components (<< 4)
; d3 = current sum of green components (<< 4)
; d4 = current sum of blue components (<< 4)
; d5 = (low word) ANDing mask = 0x0ff0
; d5 = (high word) temporary storage for red error
; d6 = (low word) region column counter
; d6 = (high word) temporary storage for green error
; d7 = (low word) column counter
; d7 = (high word) temporary storage for blue error
;
; a0 = pointer to 24-bit source row
; a1 = pointer to 8-bit destination row
; a2 = pointer to inverse color table
; a3 = pointer to color table
; a4 = pointer to even dithering buffer
; a5 = pointer to odd dithering buffer
; a6 = pointer to region buffer
;
movem.l a5/a6,-(a7) ;save a5/a6 on the stack
move.l d0,a4 ;get the real a4 from d0
move.l d1,a5 ;and the real a5 from d1
move.l d2,a6 ;and the real a6 from d2
;
; Initialize our counters and clear out next row
;
subq.w #1,d7 ;subtract 1 from the width for dbra
move.w #4080,d5 ;use d5 as a useful anding mask
clr.w d2 ;clear the leftover dithering: red
clr.w 0(a5) ;clear the odd row dithering: red
clr.w d3 ;green
clr.w 2(a5) ;green
clr.w d4 ;blue
clr.w 4(a5) ;blue
;
; Set up the region column counter in d6
;
move.w (a6)+,d6 ;get region start in d6
bne.s @EvenLoop ;if not zero, skip over this business
sub.w (a6)+,d6 ;otherwise, subtract the next word
bra.s @EvenLoop ;start by updating the region
;
; Clamp over/underflows to 255/0
;
@FixRed:
spl.b d2 ;if negative, set to 0, else set to ff
lsl.w #4,d2 ;shift up 4 bits
and.w d5,d2 ;and with d5
bra.s @RedRet ;return
@FixGreen:
spl.b d3 ;if negative, set to 0, else set to ff
lsl.w #4,d3 ;shift up 4 bits
and.w d5,d3 ;and with d5
bra.s @GreenRet ;return
@FixBlue:
spl.b d4 ;if negative, set to 0, else set to ff
lsl.w #4,d4 ;shift up 4 bits
and.w d5,d4 ;and with d5
bra.s @BlueRet ;return
@EvenLoop:
swap d7 ;save the column counter
;
; Combine the various parts of the dithered pixel
;
move.l (a0)+,d1 ;get source pixel
move.l d1,d0 ;copy to d0
add.w (a4)+,d2 ;get dithering from previous row: red
lsl.l #4,d0 ;shift pixel value up by 4
and.w d5,d0 ;isolate the blue
add.w d0,d4 ;add to the blue total
add.w (a4)+,d3 ;get dithering from previous row: green
swap d0 ;get red part in lower 8 bits
and.w d5,d0 ;keep only the good bits
add.w d0,d2 ;add it to the leftover red
add.w (a4)+,d4 ;get dithering from previous row: blue
lsr.w #4,d1 ;shift pixel down by 4 (upper 8 bits << 4)
and.w d5,d1 ;keep only the good bits
add.w d1,d3 ;add it to the leftover green
;
; Round, check for overflows, and handle them
;
addq.w #8,d2 ;add 1/2 a pixel to the total
bftst d2{16:4} ;check bits 12-15 for red overflow
bne.s @FixRed ;if it's set, fix up the red
@RedRet:
addq.w #8,d3 ;add 1/2 a pixel to the total
bftst d3{16:4} ;check bits 12-15 for green overflow
bne.s @FixGreen ;if it's set, fix up the green
@GreenRet:
addq.w #8,d4 ;add 1/2 a pixel to the total
bftst d4{16:4} ;check bits 12-15 for blue overflow
bne.s @FixBlue ;if it's set, fix up the blue
@BlueRet:
;
; Calculate the 16-bit pixel value
;
move.w d4,d0 ;get the blue bits in d0
ror.l #8,d0 ;rotate them off the right side
ror.l #4,d0 ;(12 bits -- we do it in two steps)
move.w d3,d0 ;get the green bits in d0
lsr.w #7,d0 ;shift off the low three bits
ror.l #5,d0 ;rotate them off the right side
move.w d2,d0 ;get the red bits in d0
lsr.w #7,d0 ;shift off the low three bits
ror.l #6,d0 ;rotate off the right side
swap d0 ;swap the result into the low word
;
; Determine whether or not to draw this pixel, and handle switches
;
tst.w d6 ;is d6 negative?
bmi.s @EvenStore ;if so, store this value
addq.w #2,a1 ;skip past the current pixel
subq.w #1,d6 ;decrement this counter
bne.s @EvenCont ;if non-zero continue
sub.w (a6)+,d6 ;get the negative of the next value
add.w -4(a6),d6 ;and add the previous one
bra.s @EvenCont ;continue
@EvenStore:
move.w d0,(a1)+ ;store the value to the output
addq.w #1,d6 ;increment the counter
bne.s @EvenCont ;if non-zero, continue
move.w (a6)+,d6 ;get the next value
sub.w -4(a6),d6 ;minus the previous
;
; Get the real color for this entry
;
@EvenCont:
move.w d2,d0 ;get red value in d0
lsr.w #7,d0 ;shift down 7 bits
move.w d0,d1 ;copy to d1
lsl.w #5,d0 ;shift back 5 bits
add.w d0,d1 ;add together
lsl.w #2,d1 ;shift up two more
sub.w d1,d2 ;subtract from desired red
move.w d3,d0 ;get green value in d0
lsr.w #7,d0 ;shift down 7 bits
move.w d0,d1 ;copy to d1
lsl.w #5,d0 ;shift back 5 bits
add.w d0,d1 ;add together
lsl.w #2,d1 ;shift up two more
sub.w d1,d3 ;subtract from desired green
move.w d4,d0 ;get blue value in d0
lsr.w #7,d0 ;shift down 7 bits
move.w d0,d1 ;copy to d1
lsl.w #5,d0 ;shift back 5 bits
add.w d0,d1 ;add together
lsl.w #2,d1 ;shift up two more
sub.w d1,d4 ;subtract from desired blue
;
; Divide the real color by 16 and set up to calculate odd multiples
;
swap d5 ;save the 0x0ff0 mask
swap d6 ;save our region info
asr.w #4,d2 ;divide the error by 16: red
asr.w #4,d3 ;green
asr.w #4,d4 ;blue
move.w d2,d5 ;copy this value to d5-d7: red
move.w d3,d6 ;green
move.w d4,d7 ;blue
add.w d5,d5 ;double it in d5-d7: red
add.w d6,d6 ;green
add.w d7,d7 ;blue
;
; Store 1/16, 3/16, and 5/16 into next row; leave 7/16 for neighbor
;
movem.w d2-d4,6(a5) ;store 1/16 at (+1,+1): red/green/blue
add.w d5,d2 ;add 2 * error = 3/16: red
add.w d6,d3 ;green
add.w d7,d4 ;blue
add.w d2,-6(a5) ;add 3/16 to (-1,+1): red
add.w d5,d2 ;add 2 * error = 5/16: red
add.w d3,-4(a5) ;green
add.w d6,d3 ;green
add.w d4,-2(a5) ;blue
add.w d7,d4 ;blue
add.w d2,(a5)+ ;add 5/16 to (0,+1): red
add.w d5,d2 ;add 2 * error = 7/16: red
add.w d3,(a5)+ ;green
add.w d6,d3 ;green
add.w d4,(a5)+ ;blue
add.w d7,d4 ;blue
swap d6 ;restore our region info
swap d5 ;restore 0x0ff0 mask
;
; End of loop: go until done
;
swap d7 ;restore column counter
dbra.w d7,@EvenLoop ;loop until done
movem.l (sp)+,a5/a6 ;restore a5/a6 from the stack