7.4 フェードアウト

HSPの標準命令であるpalfade命令でもフェードアウトをする事はできますが、パレットモードでしかpalfade命令は使用できません。 そこで、フルカラーモードでフェードアウトをするfadeout命令を作ってみましょう。 画面上の画像をフェードアウトするには、全てのドットの濃度値から一定の値を引きます。 いくつ引くかは、p2で指定する事にしたいと思います。 (p1はBMSCR構造体へのポインタです。)

一つ一つのドットのR, G, Bの濃度は、0〜255の範囲内でなければなりません。 しかし、仮に元々の濃度が10でp2の値が20だったとすると、10から20を引いたら-10になってしまいますね。 このように、そのまま引き算をすると負の数になってしまう場合は、引き算をせずに0にしなければなりません。 そうしないと、意図した通りにはフェードアウトされなくなってしまいます。

さて、ecxにセットする繰り返しの回数を考えてみましょう。 まず、1行あたりのバイト数を7.3と同様に計算します。 sxの値を3倍し、4の倍数になるようにダミーのバイト数を加えればいいんでしたね。 1行あたりのバイト数が求まったら、それにsyの値を掛ければ、全体のバイト数が求まります。

あとは、esiにpBitを代入してecx回引き算を繰り返せばOKです。 ダミーからもp2の値を引いているため若干無駄があるような気がしますが、まぁよしとしましょう。(^^;

FADEOUT.ASM
.486
.model          flat,stdcall
.code
option          casemap :none

include         \masm32\include\windows.inc
include         \masm32\include\gdi32.inc
include         \masm32\include\user32.inc
include         hspdll.inc
includelib      \masm32\lib\gdi32.lib
includelib      \masm32\lib\user32.lib

bm              equ     [esi].BMSCR

DLLMain         proc    p1,p2,p3
                mov     eax,1
                ret
DLLMain         endp

bmspnt          proc    uses ebx esi hdc,bmscr:ptr
                mov     esi,bmscr
                cmp     bm.hpal,NULL
                jz      @f
                invoke  SelectPalette,hdc,bm.hpal,0
                mov     ebx,eax
                invoke  RealizePalette,hdc
        @@:     cmp     bm._type,2
                jz      @f
                invoke  BitBlt,hdc,0,0,bm.wx,bm.wy,bm.hdc,bm.xx,bm.yy,SRCCOPY
        @@:     cmp     bm.hpal,NULL
                jz      @f
                invoke  SelectPalette,hdc,ebx,0
        @@:     ret
bmspnt          endp

bms_update      proc    uses ebx esi bmscr:ptr
                mov     esi,bmscr
                cmp     bm.fl_udraw,0
                jz      @f
                invoke  GetDC,bm.hwnd
                mov     ebx,eax
                invoke  bmspnt,ebx,esi
                invoke  ReleaseDC,bm.hwnd,ebx
        @@:     ret
bms_update      endp

fadeout         proc    export uses ebx ecx edx esi edi bmscr:ptr,p2,dummy1,dummy2
                mov     esi,bmscr
                cmp     bm.palmode,1
                jz      err1            ;パレットモードならerr1へ
                cmp     p2,255
                ja      err2            ;p2>255ならerr2へ

                mov     eax,3
                mul     bm.sx
                test    eax,3
                jz      @f
                and     eax,0fffffffch
                add     eax,4
        @@:     mul     bm.sy
                mov     ecx,eax

                pushf
                cld
                mov     ebx,p2
                mov     edi,bm.pBit
        next:   mov     al,[edi]
                cmp     al,bl
                jbe     zero
                sub     al,bl
                jmp     @f
        zero:   mov     al,0
        @@:     stosb
                loop    next
                popf

                invoke  bms_update,esi
                mov     eax,0
                ret
        err1:   mov     eax,-1
                ret
        err2:   mov     eax,-2
                ret
fadeout         endp

end             DLLMain
FADEOUT.AS
#uselib "fadeout.dll"
#func fadeout fadeout 2

screen 0,640,480,0,0,0,640,480
color   0,  0,255 : boxf 100,100,200,200
color   0,255,  0 : boxf 300,100,400,200
color   0,255,255 : boxf 500,100,600,200
color 255,  0,  0 : boxf 100,300,200,400
color 255,  0,255 : boxf 300,300,400,400
color 255,255,  0 : boxf 500,300,600,400
repeat 128,0
        fadeout 2
loop

7.5 フェードイン

フェードアウトとは逆に、フェードインをするfadein命令も作ってみましょう。 フェードアウトでは全てのドットの濃度値から一定の値を引きましたが、フェードインでは全てのドットの濃度値に一定の値を加えます。ただし、p2の値を加えると255を超えてしまう場合は255にしなければなりません。

FADEIN.ASM
.486
.model          flat,stdcall
.code
option          casemap :none

include         \masm32\include\windows.inc
include         \masm32\include\gdi32.inc
include         \masm32\include\user32.inc
include         hspdll.inc
includelib      \masm32\lib\gdi32.lib
includelib      \masm32\lib\user32.lib

bm              equ     [esi].BMSCR

DLLMain         proc    p1,p2,p3
                mov     eax,1
                ret
DLLMain         endp

bmspnt          proc    uses ebx esi hdc,bmscr:ptr
                mov     esi,bmscr
                cmp     bm.hpal,NULL
                jz      @f
                invoke  SelectPalette,hdc,bm.hpal,0
                mov     ebx,eax
                invoke  RealizePalette,hdc
        @@:     cmp     bm._type,2
                jz      @f
                invoke  BitBlt,hdc,0,0,bm.wx,bm.wy,bm.hdc,bm.xx,bm.yy,SRCCOPY
        @@:     cmp     bm.hpal,NULL
                jz      @f
                invoke  SelectPalette,hdc,ebx,0
        @@:     ret
bmspnt          endp

bms_update      proc    uses ebx esi bmscr:ptr
                mov     esi,bmscr
                cmp     bm.fl_udraw,0
                jz      @f
                invoke  GetDC,bm.hwnd
                mov     ebx,eax
                invoke  bmspnt,ebx,esi
                invoke  ReleaseDC,bm.hwnd,ebx
        @@:     ret
bms_update      endp

fadein          proc    export uses ebx ecx edx esi edi bmscr:ptr,p2,dummy1,dummy2
                mov     esi,bmscr
                cmp     bm.palmode,1
                jz      err1            ;パレットモードならerr1へ
                cmp     p2,255
                ja      err2            ;p2>255ならerr2へ

                mov     eax,3
                mul     bm.sx
                test    eax,3
                jz      @f
                and     eax,0fffffffch
                add     eax,4
        @@:     mul     bm.sy
                mov     ecx,eax

                pushf
                cld
                mov     ebx,p2          ;bl=p2
                mov     bh,bl
                not     bh              ;bh=255-p2
                mov     edi,bm.pBit
        next:   mov     al,[edi]
                cmp     al,bh
                jae     max
                add     al,bl
                jmp     @f
        max:    mov     al,255
        @@:     stosb
                loop    next
                popf

                invoke  bms_update,esi
                mov     eax,0
                ret
        err1:   mov     eax,-1
                ret
        err2:   mov     eax,-2
                ret
fadein          endp

end             DLLMain
FADEIN.AS
#uselib "fadein.dll"
#func fadein fadein 2

screen 0,640,480,0,0,0,640,480
color   0,  0,255 : boxf 100,100,200,200
color   0,255,  0 : boxf 300,100,400,200
color   0,255,255 : boxf 500,100,600,200
color 255,  0,  0 : boxf 100,300,200,400
color 255,  0,255 : boxf 300,300,400,400
color 255,255,  0 : boxf 500,300,600,400
repeat 128,0
        fadein 2
loop

7.6 おわりに

いわゆるフォトレタッチソフトには、必ずと言っていいほど明るさを調整する機能が付いているかと思いますが、一体どのような処理を行っているのでしょうか? 実は、ここで説明したフェードイン、フェードアウトと同様に、全てのドットの濃度値に一定の値を足したり引いたりしているだけです。

明るさの調整以外にもフォトレタッチソフトには様々な機能がありますが、それらを全て紹介していてはきりがありません。 そこで、比較的簡単に実現でき、かつ比較的簡単にMMX命令で高速化できそうな明るさの調整を取り上げてみました。 次の章では、fadeinとfadeoutをMMX命令を利用して高速化したいと思います。 次の章へ進む前に両方とも理解しておいてください。