お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
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