这不是一道作业题,而是我正在开发的一个游戏。
我有两个16位RGB颜色,并希望根据另外六个4位数量来改变它们的六个通道。虽然算法简单但很繁琐,我正在寻找一种优化方法,以便一次处理更多有用的工作。
这是高级概述:
hl
指向四个颜色字节:[hl] = %gggrrrrr
、[hl+1] = %0bbbbbgg
、[hl+2] = %GGGRRRRR
和[hl+3] = %0BBBBBGG
。(这是两种颜色,即rgb
和RGB
)bc
指向三个增量字节:[bc] = %hhhhaaaa
、[bc+1] = %ddddssss
和[bc+2] = %ppppqqqq
。(这是六个增量值:h
、a
、d
、s
、p
和q
)- 因此有六个5位颜色通道值和六个4位增量值。我想将每个颜色通道C与一个增量值D配对,并按如下方式变化C:C' = C + (D & %11) − ((D & %1100) >> 2),但保持C在其5位范围内[0, 31]。我并不关心它们是如何配对的:任何方便的一对一配对都可以。如果C + ((D & %1100) >> 2) − (D & %11) 可以更优雅地解决问题,那么我也可以接受。
如果我将一个颜色通道C隔离到寄存器d
中,将一个增量值D隔离到寄存器e
中,那么这个例程将为该对执行变化:
VaryColorChannelByDV:
; d = color, e = DV
; a <- d + (e & %11) - (e >> 2), clamped to [0, 31]
ld a, e
and %11 ; a <- (e & %11)
add d ; a <- d + (e & %11)
srl e
srl e ; e <- e >> 2
sub e ; a <- d + (e & %11) - (e >> 2)
jr c, .zero ; a < 0, clamp to 0
cp 32
ret c ; 0 <= a < 32
ld a, 31 ; a >= 32, clamp to 31
ret
.zero
xor a
ret
目前我有一个通用程序,可以将任何DV应用于任何颜色通道;然后有三个程序将红、绿或蓝通道隔离出来,并将给定的DV应用于它们;最后是一个主程序,选出六个DV并调用相应的通道修改程序。这样已经“足够好了”,但我确定还有改进的空间。执行速度似乎不是问题,但我想减少代码大小(当然,删除冗余指令也会稍微提高速度)。是否有任何汇编位运算技巧可以帮助?
以下是完整代码:
GetColorChannelVariedByDV:
; d = color, e = DV
; a <- d + (e & %11) - (e & %1100 >> 2), clamped to [0, 31]
ld a, e
and %11
add d
srl e
srl e
sub e
jr c, .zero
cp 32
ret c
ld a, 31
ret
.zero
xor a
ret
VaryRedByDV:
;;; e = DV
;;; [hl+0] = gggr:rrrr
;;; [hl+1] = 0bbb:bbgg
; store red in d
ld a, [hl]
and %00011111
ld d, a
; vary d according to e
call GetColorChannelVariedByDV
; store a back in red
ld d, a
ld a, [hl]
and %11100000
or d
ld [hl], a
ret
VaryGreenByDV:
;;; e = DV
;;; [hl+0] = gggr:rrrr
;;; [hl+1] = 0bbb:bbgg
; store green in d
ld a, [hli]
and %11100000
srl a
swap a
ld d, a ; d = 00000ggg
ld a, [hld]
and %00000011
swap a
srl a
or d
ld d, a
; vary d according to e
call GetColorChannelVariedByDV
; store a back in green
sla a
swap a
ld d, a
and %11100000
ld e, a
ld a, d
and %00000011
ld d, a
ld a, [hl]
and %00011111
or e
ld [hli], a
ld a, [hl]
and %11111100
or d
ld [hld], a
ret
VaryBlueByDV:
;;; e = DV
;;; [hl+0] = gggr:rrrr
;;; [hl+1] = 0bbb:bbgg
; store blue in d
inc hl
ld a, [hl]
and %01111100
srl a
srl a
ld d, a
; vary d according to e
call GetColorChannelVariedByDV
; store a back in blue
ld d, a
sla d
sla d
ld a, [hl]
and %10000011
or d
ld [hl], a
dec hl
ret
VaryColorsByDVs::
; hl = colors
; [hl+0] = gggr:rrrr
; [hl+1] = 0bbb:bbgg
; [hl+2] = GGGR:RRRR
; [hl+3] = 0BBB:BBGG
; bc = DVs
; [bc+0] = hhhh:aaaa
; [bc+1] = dddd:ssss
; [bc+2] = pppp:qqqq
;;; LiteRed ~ hDV, aka, rrrrr ~ hhhh
; store hDV in e
ld a, [bc]
swap a
and %1111
ld e, a
; vary LiteRed by e
call VaryRedByDV
;;; LiteGrn ~ aDV, aka, ggggg ~ aaaa
; store aDV in e
ld a, [bc]
and %1111
ld e, a
; vary LiteGrn by e
call VaryGreenByDV
;;; move from h/a DV to d/s DV
inc bc
;;; LiteBlu ~ dDV, aka, bbbbb ~ dddd
; store dDV in e
ld a, [bc]
swap a
and %1111
ld e, a
; vary LiteBlu by e
call VaryBlueByDV
;;; Move from Lite color to Dark color
inc hl
inc hl
;;; DarkRed ~ sDV, aka, RRRRR ~ ssss
; store sDV in e
ld a, [bc]
and %1111
ld e, a
; vary DarkRed by e
call VaryRedByDV
;;; move from d/s DV to p/q DV
inc bc
;;; DarkGrn ~ pDV, aka, GGGGG ~ pppp
; store pDV in e
ld a, [bc]
swap a
and %1111
ld e, a
; vary DarkGrn by e
call VaryGreenByDV
;;; DarkBlu ~ qDV, aka, BBBBB ~ qqqq
; store qDV in e
ld a, [bc]
and %1111
ld e, a
; vary DarkBlu by e
call VaryBlueByDV
ret