|
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"画像表示を左右方向にフェード更新する"
【タイトル】画像表示を左右方向にフェード更新する
#827 で「ビットマップを半透明描画する」という題でコードを出させてい
ただきましたが、これをちょっと応用して、画像の上下左右方向へのフェード
更新するサンプルコードです。
上下方向と、左右方向は内部コードの共有が難しかったのでそれぞれ別の関
数にしました。また、発言の 300行制限のため、上下方向にフェード更新する
サンプルコードと、左右方向に更新するサンプルコードを別々の発言に分けま
した。
動作確認は Delphi4 で行いました。
この発言は左右方向にフェード更新するサンプルコードです。
type
TForm1 = class(TForm)
{ 省略 }
procedure FormCreate(Sender: TObject); // Bitmap を作成する
procedure FormDestroy(Sender: TObject);// Bitmap を破棄する
procedure FormPaint(Sender: TObject); // Bitmap を描画する
private
// 同じ大きさで PixelFormat = pf24bitにしておく
FBitmap, FNextBitmap: TBitmap;
procedure HorzFade(FrameCount: Integer; Leftward: Boolean);
end;
{ ここから implementation }
// Form1.OnPaintイベントハンドラでビットマップを表示
procedure TForm1.FormPaint(Sender: TObject);
begin
Canvas.Draw(0, 0, FBitmap);
end;
procedure TForm1.HorzFade(FrameCount: Integer; Leftward: Boolean);
const
NumSteps = 8;
// BlockSize = sizeof(DWORD) * 20;
// BlockSize = sizeof(DWORD) * 10;
BlockSize = sizeof(DWORD) * 8; // VGAサイズではこの位が良い?
// BlockSize = sizeof(DWORD) * 5;
// FBitmap.Width が BlockSize の整数倍になるようにします、要注意!
var
bmpBlock: TBitmap;
rectStart, rectBlock: TRect;
NextLine, PrevLine: TList;
pdwBlock, pdwNext, pdwPrev: PDWORD;
w, h, x, y, StepCount: Integer;
StepIndex: Integer;
var
SaveIndex: Integer;
rgnTmp: HRGN;
var
Count, CountStep: DWORD;
begin
if(FBitmap.Width <> FNextBitmap.Width) or
(FBitmap.Height <> FNextBitmap.Height) or
(FBitmap.PixelFormat <> pf24bit) or
(FNextBitmap.PixelFormat <> pf24bit) then
begin
ShowMessage('フォーマットが一致しません');
Exit;
end;
w := FBitmap.Width;
h := FBitmap.Height;
PrevLine := TList.Create;
NextLine := TList.Create;
PrevLine.Count := h;
NextLine.Count := h;
for y := 0 to h - 1 do
begin
PrevLine[y] := FBitmap.ScanLine[y];
NextLine[y] := FNextBitmap.ScanLine[y];
end;
SaveIndex := SaveDC(Canvas.Handle);
rgnTmp := CreateRectRgn(0, 0, w, h);
SelectClipRgn(Canvas.Handle, rgnTmp);
bmpBlock := TBitmap.Create;
bmpBlock.Width := BlockSize * NumSteps;
bmpBlock.Height := h;
bmpBlock.PixelFormat := pf24bit;
CountStep := FrameCount div (w div BlockSize + NumSteps - 1);
Count := timeGetTime; // 表示速度の調整
if Leftward then
begin
rectStart := Rect(w - BlockSize, 0, w, h);
OffsetRect(rectStart, BlockSize * (NumSteps - 1), 0);
end
else
begin
rectStart := Rect(0, 0, BlockSize, h);
OffsetRect(rectStart, -BlockSize * (NumSteps - 1), 0);
end;
// while rectStart.Left < w do
while TRUE do
begin
if Leftward then
begin
if rectStart.Right <= 0 then break;
end
else
if rectStart.Left >= w then break;
rectBlock := rectStart;
for StepCount := 0 to NumSteps - 1 do
begin
if Leftward then
StepIndex := 7 - StepCount
else
StepIndex := StepCount;
if(rectBlock.Left >= 0)and(rectBlock.Right <= w)then
case(StepCount)of
0:for y := 0 to h - 1 do
begin
pdwNext := Pointer(Integer(NextLine[y]) + rectBlock.Left * 3);
pdwBlock := Pointer(Integer(bmpBlock.ScanLine[y])
+ StepIndex * BlockSize * 3);
CopyMemory(pdwBlock, pdwNext, BlockSize * 3);
end;
7:for y := 0 to h - 1 do
begin
pdwPrev := Pointer(Integer(PrevLine[y]) + rectBlock.Left * 3);
pdwNext := Pointer(Integer(NextLine[y]) + rectBlock.Left * 3);
pdwBlock := Pointer(Integer(bmpBlock.ScanLine[y])
+ StepIndex * BlockSize * 3);
for x := 0 to BlockSize * 3 div 4 - 1 do
begin
pdwBlock^ := pdwPrev^ - pdwPrev^ shr 3 and $1f1f1f1f
+ pdwNext^ shr 3 and $1f1f1f1f;
Inc(pdwPrev);
Inc(pdwNext);
Inc(pdwBlock);
end;
end;
6:for y := 0 to h - 1 do
begin
pdwPrev := Pointer(Integer(PrevLine[y]) + rectBlock.Left * 3);
pdwNext := Pointer(Integer(NextLine[y]) + rectBlock.Left * 3);
pdwBlock := Pointer(Integer(bmpBlock.ScanLine[y])
+ StepIndex * BlockSize * 3);
for x := 0 to BlockSize * 3 div 4 - 1 do
begin
pdwBlock^ := pdwPrev^ - pdwPrev^ shr 2 and $3f3f3f3f
+ pdwNext^ shr 2 and $3f3f3f3f;
Inc(pdwPrev);
Inc(pdwNext);
Inc(pdwBlock);
end;
end;
5:for y := 0 to h - 1 do
begin
pdwPrev := Pointer(Integer(PrevLine[y]) + rectBlock.Left * 3);
pdwNext := Pointer(Integer(NextLine[y]) + rectBlock.Left * 3);
pdwBlock := Pointer(Integer(bmpBlock.ScanLine[y])
+ StepIndex * BlockSize * 3);
for x := 0 to BlockSize * 3 div 4 - 1 do
begin
pdwBlock^ := pdwPrev^ - pdwPrev^ shr 3 and $1f1f1f1f
+ pdwNext^ shr 3 and $1f1f1f1f
- pdwPrev^ shr 2 and $3f3f3f3f
+ pdwNext^ shr 2 and $3f3f3f3f;
Inc(pdwPrev);
Inc(pdwNext);
Inc(pdwBlock);
end;
end;
4:for y := 0 to h - 1 do
begin
pdwPrev := Pointer(Integer(PrevLine[y]) + rectBlock.Left * 3);
pdwNext := Pointer(Integer(NextLine[y]) + rectBlock.Left * 3);
pdwBlock := Pointer(Integer(bmpBlock.ScanLine[y])
+ StepIndex * BlockSize * 3);
for x := 0 to BlockSize * 3 div 4 - 1 do
begin
pdwBlock^ := pdwPrev^ - pdwPrev^ shr 1 and $7f7f7f7f
+ pdwNext^ shr 1 and $7f7f7f7f;
Inc(pdwPrev);
Inc(pdwNext);
Inc(pdwBlock);
end;
end;
3:for y := 0 to h - 1 do
begin
pdwPrev := Pointer(Integer(PrevLine[y]) + rectBlock.Left * 3);
pdwNext := Pointer(Integer(NextLine[y]) + rectBlock.Left * 3);
pdwBlock := Pointer(Integer(bmpBlock.ScanLine[y])
+ StepIndex * BlockSize * 3);
for x := 0 to BlockSize * 3 div 4 - 1 do
begin
pdwBlock^ := pdwNext^ + pdwPrev^ shr 3 and $1f1f1f1f
- pdwNext^ shr 3 and $1f1f1f1f
+ pdwPrev^ shr 2 and $3f3f3f3f
- pdwNext^ shr 2 and $3f3f3f3f;
Inc(pdwPrev);
Inc(pdwNext);
Inc(pdwBlock);
end;
end;
2:for y := 0 to h - 1 do
begin
pdwPrev := Pointer(Integer(PrevLine[y]) + rectBlock.Left * 3);
pdwNext := Pointer(Integer(NextLine[y]) + rectBlock.Left * 3);
pdwBlock := Pointer(Integer(bmpBlock.ScanLine[y])
+ StepIndex * BlockSize * 3);
for x := 0 to BlockSize * 3 div 4 - 1 do
begin
pdwBlock^ := pdwNext^ + pdwPrev^ shr 2 and $3f3f3f3f
- pdwNext^ shr 2 and $3f3f3f3f;
Inc(pdwPrev);
Inc(pdwNext);
Inc(pdwBlock);
end;
end;
1:for y := 0 to h - 1 do
begin
pdwPrev := Pointer(Integer(PrevLine[y]) + rectBlock.Left * 3);
pdwNext := Pointer(Integer(NextLine[y]) + rectBlock.Left * 3);
pdwBlock := Pointer(Integer(bmpBlock.ScanLine[y])
+ StepIndex * BlockSize * 3);
for x := 0 to BlockSize * 3 div 4 - 1 do
begin
pdwBlock^ := pdwNext^ + pdwPrev^ shr 3 and $1f1f1f1f
- pdwNext^ shr 3 and $1f1f1f1f;
Inc(pdwPrev);
Inc(pdwNext);
Inc(pdwBlock);
end;
end;
end;
if Leftward then
OffsetRect(rectBlock, -BlockSize, 0)
else
OffsetRect(rectBlock, BlockSize, 0);
end; // for StepCount := 0 to NumSteps - 1 do
if CheckBox2.Checked then // 表示速度の調整
while timeGetTime < Count do Sleep(1); Inc(Count, CountStep);
if Leftward then
begin
Canvas.Draw(rectStart.Left - BlockSize * (NumSteps - 1),
rectStart.Top, bmpBlock);
OffsetRect(rectStart, -BlockSize, 0);
end
else
begin
Canvas.Draw(rectStart.Left, rectStart.Top, bmpBlock);
OffsetRect(rectStart, BlockSize, 0);
end;
end; // while rectStart.Left < w do
FBitmap.Canvas.Draw(0, 0, FNextBitmap);
RestoreDC(Canvas.Handle, SaveIndex);
DeleteObject(rgnTmp);
NextLine.Free;
PrevLine.Free;
end;
【速度テスト】
ビットマップサイズ: 640 * 480 pixels(VGAサイズ)
CPU: Pentium120MHz
ビデオカード:Sthealth64
上の条件+表示速度調整を解除して(Wait無し)実行すると 1.3〜1.5秒
くらいかかりました。
このくらいでちょうど良いと感じたので FrameCount = 1500〜2000 の引
数で実行するのが目に優しいと思います。
1999/03/25、河邦 正(GCC02240@nifty.ne.jp)
Original document by 河邦 正 氏 ID:(GCC02240)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|