画面更新

解決


Haru  2004-02-05 04:40:40  No: 53114

BitBltを使って画像を表示して、タイマーを使用して約100ms後に再度画像を表示しています。
時々画面更新の時、処理がしきれないのか、数ラインが一瞬白くなったりします。
これを無くす方法はないのでしょうか?

簡単な流れとしまして

BitBlt  で画像を表示
InvalidateRect  で更新領域の設定      
UpdateWindow   で画面表示の様な感じです。

アドバイス御願いします。


SELNA  URL  2004-02-05 13:32:43  No: 53115

処理がしきれないのではなくちらつきが発生しているんだと思います。

InvalidateRect、UpdateWindowで画面更新したときWM_PAINTで
BitBltをウィンドウDCに対して複数回描画していないでしょうか?
もししているようでしたら、バックバッファ(裏画面)用にメモリDCを作成し、そこに全ての描画をして画面更新の時はバックバッファを転送してあげればよいです。


Haru  2004-02-05 23:25:11  No: 53116

アドバスありがとうございます。

バックバッファを利用するとの事ですが、DirectDrawを使用するのでしょうか?
DirectDrawを調査した所、フルスクリーンモードでは、プライマリサーフェイスと
バックバッファをフリップしてちらつきのない描画をしていると書いてありました。
今回は、フルスクリーンでは、使用しないのでフリップは出来ないと思うのですが、そのへんについて、実際どうすれば良いか、もう少し詳しく教えて頂けると
助かります。


SELNA  URL  2004-02-06 00:54:52  No: 53117

えーとDirectDrawは使いません。
基本的に考え方は同じなんですけどね。

WindowsAPIだけで描画する場合は初期化時(WM_CREATE)に、

1.ビットマップハンドルを作成。
2.メモリDC作成。
3.2で作成したメモリDCにビットマップハンドルを関連づける。

としてバックバッファ用のメモリDCを作成し、全てここに描画します。

(例)
初期化で、
hBackBitmap = CreateCompatibleBitmap(hdc, 640, 480);
hBackMemDC = CreateCompatibleDC(hdc);
SelectObject(hBackMemDC, hBackBitmap);

実際の描画は、
BitBlt(hBackMemDC, 0, 0, 幅、高さ、描画するメモリDC, ...);
BitBlt(hBackMemDC, 0, 0, 幅、高さ、描画するメモリDC2, ...);
BitBlt(hBackMemDC, 0, 0, 幅、高さ、描画するメモリDC3, ...);

 .
 .
 .
と、全てバックバッファに描画してWM_PAINTでは、

BeginPaint( hWnd, &ps );
BitBlt(ps.hdc, 0, 0, 640, 480, hBackMemDC, 0, 0, SRCCOPY );
EndPaint( hWnd, &ps );

このような感じになります。

ちなみにDirectDrawでウィンドウの場合フリップではなくセカンダリ(バックバッファ)>プライマリにBltします。

また何か分らなかったら質問して下さい。
それでは。


Haru  2004-02-06 04:08:49  No: 53118

SELNAさんのアドバイスを受けて、試してみましたが、うまく動作しないのです。
352×288ピクセルに青を連続でちらつきが無く表示しないのですが、
青い画面がでません。。。

下に、ソースを記載しますので、どこが悪いか見て頂けませんでしょうか?

よろしくおねがいします。

**********************
#include "stdafx.h"

HINSTANCE hInst;                // 現在のインスタンス
HWND hWnd;    //   Main Window Handle
HDC hdcMem;    //  Memory DC
LPBYTE lpBMP;  // BITMAP表示用 Bit値  

DWORD tm=0;          // Wait用変数

HDC hBackMemDC;
HBITMAP hBackBitmap;

ATOM      MyRegisterClass( HINSTANCE hInstance );
BOOL      InitInstance( HINSTANCE, int );
LRESULT CALLBACK  WndProc( HWND, UINT, WPARAM, LPARAM );
LRESULT CALLBACK  About( HWND, UINT, WPARAM, LPARAM );

static BitMapConfig(void);        //BITMAP表示用の定義
static MainLoop(void);          //MainLoop  

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow )
{
  MSG msg;
  MyRegisterClass( hInstance );
  if( !InitInstance( hInstance, nCmdShow ) ) 
  {
    return FALSE;
  }

  BitMapConfig();      //BITMAP表示用の定義

  while (1) { // MainLoop
    if (PeekMessage (&msg,NULL,0,0,PM_NOREMOVE))
    {
      if (!GetMessage (&msg,NULL,0,0))  // Message処理
      {
        return msg.wParam ;
      }
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    else
    {  
      MainLoop();    
    }
  }

  return msg.wParam;
}

//////////////////////////
// BITMAP表示用の定義   //
 //////////////////////////
BitMapConfig(void)
{

  LPBITMAPINFO lpDIB;
  
  HDC hdc;    // DC
  HBITMAP hBMP;  // DIB Handle

  lpDIB=(LPBITMAPINFO)GlobalAlloc(GPTR,352*288*3);// DIBヘッダ用メモリ確保

  lpDIB->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); 
  lpDIB->bmiHeader.biWidth=352;            
  lpDIB->bmiHeader.biHeight=288;    
  lpDIB->bmiHeader.biPlanes=1;    
  lpDIB->bmiHeader.biBitCount=24;    
  lpDIB->bmiHeader.biCompression=BI_RGB;
  lpDIB->bmiHeader.biSizeImage=0;      
  lpDIB->bmiHeader.biXPelsPerMeter=0;    
  lpDIB->bmiHeader.biYPelsPerMeter=0;  
  lpDIB->bmiHeader.biClrUsed=0;      
  lpDIB->bmiHeader.biClrImportant=0;    

  hdc=GetDC(hWnd); // WindowのDC(Deviceコンテキスト)を取得 

  // DIB とウインドウのDC からDIBSection を作成 
  hBMP=CreateDIBSection(hdc,lpDIB,DIB_RGB_COLORS,(void **)&lpBMP,NULL,0);  

  hdcMem=CreateCompatibleDC(hdc); // Memory DC を作成 

  SelectObject(hdcMem,hBMP);    /* メモリDC にビットマップを選択 */

  hBackBitmap = CreateCompatibleBitmap(hdc, 352, 288);
  hBackMemDC = CreateCompatibleDC(hdc);
  SelectObject(hBackMemDC, hBackBitmap);

  ReleaseDC(hWnd,hdc);

  return 0;
}

////////////////
// Main-Loop  //
////////////////
MainLoop(void)
{
  int Yline;
  int Xline;
  int i=1;
  RECT rt;
  
  if (GetTickCount()>tm+500)
  {
    tm=GetTickCount();
  }
  else
  {
    return 0;
  }

  for (Yline=1;Yline<=288;Yline++)
  {
    for (Xline=1;Xline<=352;Xline++)
    {    
        lpBMP[(i-1)*3+0]=255;
        lpBMP[(i-1)*3+1]=0;
        lpBMP[(i-1)*3+2]=0;
        i++;
    }
  }

  BitBlt(hBackMemDC,0,0,352,288,hdcMem, 0, 0, SRCCOPY);

  InvalidateRect(hWnd,&rt,TRUE);      
  UpdateWindow (hWnd);             // 再描画      

  return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  int wmId, wmEvent;
  PAINTSTRUCT ps;
  static int x,y;
  HDC hdc;

  switch( message ) 
  {
    case WM_CREATE:
      return 0;
    case WM_COMMAND:
      wmId    = LOWORD(wParam); 
      wmEvent = HIWORD(wParam);   
      return 0;
    case WM_PAINT:
      hdc = BeginPaint (hWnd, &ps);
      BeginPaint( hWnd, &ps );
      BitBlt(ps.hdc, 0, 0, 352, 288, hBackMemDC, 0, 0, SRCCOPY );
      EndPaint( hWnd, &ps );
      break;

    case WM_DESTROY: 
      PostQuitMessage( 0 );
      break;
    default:
      return DefWindowProc( hWnd, message, wParam, lParam );
   }
   return 0;
}

ATOM MyRegisterClass( HINSTANCE hInstance )
{
  WNDCLASSEX wcex;
  wcex.cbSize = sizeof(WNDCLASSEX); 
  wcex.style    = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc  = (WNDPROC)WndProc;
  wcex.cbClsExtra    = 0;
  wcex.cbWndExtra    = 0;
  wcex.hInstance    = hInstance;
  wcex.hIcon    = LoadIcon(hInstance, IDI_WINLOGO);
  wcex.hCursor    = LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground  = (HBRUSH)(COLOR_BTNFACE+5);
  wcex.lpszMenuName  = NULL;
  wcex.lpszClassName  = "Test";
  wcex.hIconSm    = LoadIcon(wcex.hInstance, NULL);
  return RegisterClassEx( &wcex );
}

BOOL InitInstance( HINSTANCE hInstance, int nCmdShow )
{

   hInst = hInstance; // グローバル変数にインスタンス ハンドルを保存します
   hWnd = CreateWindow("Test", "TITLE", WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, // 左のWS_*でWindowSize変更禁止
     CW_USEDEFAULT, 0, 1000, 800, NULL, NULL, hInstance, NULL);
   if( !hWnd ) 
   {
      return FALSE;
   }
   ShowWindow( hWnd, nCmdShow );
   UpdateWindow( hWnd );
   return TRUE;
}


SELNA  URL  2004-02-06 05:42:02  No: 53119

ざっと見た感じ、どうやら

>InvalidateRect(hWnd,&rt,TRUE);

この部分に問題がありますね。
RECT構造体で宣言した、

>RECT rt;

の部分で矩形領域の設定がされていません。
画面全体ならInvalidateRectの第2に引数はNULLでいいと思います。

後ちょっと気になったのが、

>hdc = BeginPaint (hWnd, &ps);
>BeginPaint( hWnd, &ps );
>BitBlt(ps.hdc, 0, 0, 352, 288, hBackMemDC, 0, 0, SRCCOPY );
>EndPaint( hWnd, &ps );

BeginPaintが2回も(笑)
BeginPaintの戻り値とps.hdcは同じです。

それでは。


Haru  2004-02-06 17:47:26  No: 53120

アドバイスのとおり修正し、描画されました。

ありがとうございました。

でも、画面更新の時に、ちらつきが時々見られてしまいます。。。


SELNA  URL  2004-02-07 00:02:44  No: 53121

すみません。重大なところを見落としていました。

>InvalidateRect(hWnd,&rt,TRUE);

第3引数はTRUEだと更新領域の背景が削除されるのでFALSEにしてください。
元々原因はここでした。

後、関係ないですがアプリケーション終了時にメモリが解放されていません。
>HDC hdcMem;        //  Memory DC
>HBITMAP hBMP;    // DIB Handle
>HDC hBackMemDC;
>HBITMAP hBackBitmap;

これを、WM_DESTROYなどで

DeleteDC(hdcMem);
DeleteDC(hBackMemDC);

DeleteObject(hBMP);
DeleteObject(hBackBitmap);

の順番で解放してあげて下さい。

以下のサイトはお薦めですので参考になさって下さい。
http://black.sakura.ne.jp/~third/

それでは。


Haru  2004-02-10 18:45:28  No: 53122

無事解決できました。

SELNAさん。本当にありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加