再掲・クライアント領域に残像が残ってしまいます

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
めんつゆ

再掲・クライアント領域に残像が残ってしまいます

#1

投稿記事 by めんつゆ » 6年前

あけましておめでとうございます。
以前投稿させていただいたのですが、いまだに解決に至らないため再掲載させていただきました。

ダイレクトx、ビジュアルC++2010エクスプレスを使用してプログラムを書いています。

ウインドウのサイズを変更した際、画像が表示される領域を一定の比率で保つようにしたのですが、
残像が残ってしまいます。
このような状態になってしまいます。(Imgurというサイトです)
中心の画像が本来描画したい画像になります。
http://imgur.com/S6YL5he.jpg

仕組みとしては、クライアント領域内のフロントバッファ表示領域をウインドウサイズの変更に応じて変化させているのですがうまくいきません。
フロントバッファ表示領域外の画像をクリアするにはどうすればいいのでしょうか。

テストチェック用の画像はこちらに用意させていただきました。(Imgurというサイトです)


宜しくお願いします。

コード:

#define NAME "DirectX勉強中"
#define INITGUID
 
#include <Windows.h>
#include <d3dx9.h>
#include <dsound.h>
#include <MMSystem.h>
#include <stdio.h>
 
// ライブラリのリンク
#pragma once
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"dsound.lib")
#pragma comment(lib,"winmm.lib")
 
 
 
HWND g_hWnd = NULL;      // Window Handle
LPDIRECT3D9             g_pD3D = NULL;     
LPDIRECT3DDEVICE9       g_pDEV = NULL;    
 
D3DXVECTOR3 Position;//位置(x座標,y座標)キャラクタ
D3DXVECTOR3 haikeiPosition;//背景の座標
 
BYTE diKeyState[256];
 
LPD3DXSPRITE pSprite = NULL; 
LPDIRECT3DTEXTURE9 pTexture = NULL; 
LPDIRECT3DTEXTURE9 phaikeiTexture;
LPDIRECT3DTEXTURE9 MapchipTexture;
 
 
D3DXMATRIX m_Matrix;//キャラクタの行列
D3DXVECTOR2 m_vec2;//マトリックス自体の座標
 
RECT B_B_Area = {0,0,0,0}; //バックバッファのサイズ
RECT PaintArea ={0,0,0,0}; //フロントバッファの描画領域
 
 
D3DDISPLAYMODE          d3ddm;
D3DPRESENT_PARAMETERS   d3dpp;
 
//***********************
 
 
D3DVIEWPORT9 vp;    
 
#define wwx 1280
#define wwy 960
 
//開放のための関数
#define SAFE_RELEASE(x) if(x)  { x->Release(); x=NULL; }
#define DIDEVICE_BUFFERSIZE 100                     
 
RECT W_Size;//ウインドウサイズ
RECT C_Size;//クライアントサイズ
int W_BarX,W_BarY; //ウインドウバー
 
//初期化処理(デバイスの設定)
HRESULT Init3DDev()
{
    //インターフェイスの取得
    if (NULL==(g_pD3D=Direct3DCreate9(D3D_SDK_VERSION)))    return E_FAIL;
 
    //アダプタのデータを得る(数、幅、高さ、リフレッシュレート)
    if (FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm)))   return E_FAIL;
 
    //D3DPRESENT_PARAMETERS構造体の設定
    ZeroMemory(&d3dpp,sizeof(d3dpp));
    d3dpp.BackBufferWidth = wwx;
    d3dpp.BackBufferHeight =wwy;
    d3dpp.Windowed                  = TRUE;      
    d3dpp.SwapEffect =  D3DSWAPEFFECT_COPY;
    d3dpp.BackBufferFormat          = d3ddm.Format;
    d3dpp.EnableAutoDepthStencil    = TRUE;       
    d3dpp.AutoDepthStencilFormat    = D3DFMT_D16; 
 
    //デバイスの作成:CreateDeviceの実行//復元用
    if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,g_hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&g_pDEV)))
    return E_FAIL;
    return S_OK;
}
 
///メモリ開放処理
// DirectX Graphics の終了処理:未開放有り
void Cleanup(void)
{
    SAFE_RELEASE(g_pDEV);   //デバイスの開放
    SAFE_RELEASE(g_pD3D);   //ダイレクトxの開放
}
 
 
 
//ウインドウのサイズ関連の調整
void AdjustmentWindow()
{
    //描画領域の指定
    B_B_Area.top = 0;
    B_B_Area.bottom = wwy;
    B_B_Area.left = 0;
    B_B_Area.right = wwx;
 
    //描画領域の指定
    PaintArea.top = 0;
    PaintArea.bottom = wwy;
    PaintArea.left = 0;
    PaintArea.right = wwx;
 
 
    //クライアント領域からウインドウサイズの調整
    GetWindowRect(g_hWnd,&W_Size);//ウインドウのサイズを取得
    GetClientRect(g_hWnd,&C_Size);//クライアント領域のサイズを取得
 
    int WindowsX,WindowsY,W_X,W_Y;
    //ウインドウのサイズを計算
    W_X = W_Size.right - W_Size.left;
    W_Y = W_Size.bottom - W_Size.top;
 
    //ウインドウバーのサイズを計算
    W_BarX = W_X - C_Size.right;
    W_BarY = W_Y - C_Size.bottom;
 
    //正しいウインドウのサイズを計算
    WindowsX = W_X + W_BarX;
    WindowsY = W_Y + W_BarY;
 
    //ウインドウのサイズを代入
    SetWindowPos(g_hWnd,HWND_TOP,600,300,WindowsX,WindowsY,SWP_SHOWWINDOW);
}
 
//バックバッファの内容を描画する領域の計算
void WindowDraw(int a,int b,int c)//WX,WY,FBArea;
{
 
//フロントバッファの表示領域の算出
        if(a>b)
        {
            //領域の高さ開始位置をリセット
            PaintArea.top = 0;      
 
            //領域の高さを決定
            PaintArea.bottom = b;
 
            //領域の幅を決定
            c = (b/3)*4;
 
            if(c < a)//算出されたX軸の描画範囲がウインドウよりも小さい場合
            {
                //領域の横開始位置を決定
                PaintArea.left = (a - c)/2;
 
                //領域の幅の開始から終点を決定
                PaintArea.right = PaintArea.left + c;
            }
            else if(c > b)//算出されたX軸の描画範囲がウインドウよりも大きい場合
            {
                PaintArea.left = 0;
                PaintArea.right = a;
                c = (a/4)*3;
                PaintArea.top = (b - c)/2;
                PaintArea.bottom = PaintArea.top + c;
            }
        }
        else if(a<b || a == b)
        {
            //領域の高さ開始位置をリセット
            PaintArea.left = 0;
 
            //領域の幅を決定
            PaintArea.right = a;
 
            //領域の高さを決定
            c = (a/4)*3;
 
            if(c < b)//算出されたY軸の描画範囲がウインドウよりも小さい場合
            {
                //領域の高さ開始位置を決定
                PaintArea.top = (b - c)/2;
 
                //領域の高さの開始から終点を決定
                PaintArea.bottom = PaintArea.top + c;
            }
            else if(c > b)//算出されたY軸の描画範囲がウインドウよりも大きい場合
            {
                PaintArea.top = 0;
                PaintArea.bottom = b;
                c = (b/3)*4;
                PaintArea.left = (a - c)/2;
                PaintArea.bottom = PaintArea.right + c;
            }
        }
}
 
//ビューポートの作成
HRESULT Viewport()
{
    HRESULT hr;//ハンドル
 
    //ビューポートの作成
    vp.X = 0;
    vp.Y = 0;
    vp.Width = wwx;
    vp.Height =wwy;
    vp.MinZ = 0.0f;
    vp.MaxZ = 1.0f;
    hr = g_pDEV -> SetViewport(&vp);
    if(FAILED(hr))
    return false;
    return S_OK;
}
 
//テクスチャの作成
HRESULT textureCreate()
{
     HRESULT hr;//ハンドル
    //背景3.png
    hr =  D3DXCreateTextureFromFileEx(g_pDEV,"mtkfbxI.png",
                                      wwx,wwy,1,0,
                                      D3DFMT_UNKNOWN,D3DPOOL_MANAGED,
                                      D3DX_DEFAULT,D3DX_DEFAULT,
                                      D3DCOLOR_XRGB(0,0,0),
                                      NULL,NULL,&phaikeiTexture);
 
    if(FAILED(hr))
        return false;   
        return S_OK;
}
 
//スプライトの作成
HRESULT spriteCreate()
{
    HRESULT hr;//ハンドル
    hr = D3DXCreateSprite(g_pDEV,&pSprite);//1.使用するデバイス、2.受け取る変数
    if(FAILED(hr))
    return false;
    return S_OK;
}
 
//スプライトの描画(キャラクタ)//描画は全てこの中で行う(画像、文字)
HRESULT drawsprite()
{
    HRESULT hr;//ハンドル
    D3DXMatrixTransformation2D(&m_Matrix,0,0,0,NULL,0,&m_vec2);
 
    //塗りつぶし
    g_pDEV->Clear(0,NULL,(D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER),
                       D3DCOLOR_RGBA(100,150,255,0),1.0f,0);
 
    g_pDEV->BeginScene();//スプライトシーンの開始---------------------
        pSprite->Begin(D3DXSPRITE_ALPHABLEND|D3DXSPRITE_DONOTSAVESTATE);
        hr = pSprite->SetTransform(&m_Matrix);  
 
            //背景
            hr = pSprite->Draw(phaikeiTexture,NULL,NULL,&haikeiPosition,0xffffffff);
 
            if(FAILED(hr))
            return false;
 
        pSprite->End();//スプライトを描画して終了
 
    g_pDEV->EndScene();//シーンを終了----------------------------------
    //デバイスの情報を返す
    //ここでバック、フロントバッファの範囲、描画対象のウインドウなどを指定する
    return g_pDEV->Present(&B_B_Area, &PaintArea, g_hWnd, NULL);
    
    return S_OK;
}
 
 
 
 
 
 
////////////////////////////////////////////////////////////////////
 
/* コールバック関数関連 */
 
////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, UINT wParam, LONG lParam)
{
    switch(msg)
    {   
        case WM_DESTROY://ウインドウの破棄
                Cleanup();
              PostQuitMessage(0);
                    break;
        
        case WM_SIZING://ウインドウサイズの変更中
                    drawsprite();
                    InvalidateRgn(hWnd, NULL,TRUE);     
                    return TRUE;
 
        case WM_SIZE://ウインドウサイズの変更後
    
                if(!g_pDEV || wParam == SIZE_MINIMIZED)
                {
                    break;
                }
                if(wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)
                {
                    //フロントバッファの描画位置と領域を算出
                    int WX,WY,FBArea;
 
                    FBArea = 0;             //初期化
                    WX = LOWORD(lParam);    //横の取得
                    WY = HIWORD(lParam);    //縦の取得
 
                    WindowDraw(WX,WY,FBArea);//描画領域の計算
 
                    pSprite->OnLostDevice();//スプライトのロスト
                    g_pDEV->Reset(&d3dpp);
                    InvalidateRgn(hWnd, NULL,TRUE);
 
                }
                break;
 
 
        case WM_KEYDOWN://キーを押す
            switch(wParam)
            {   case VK_ESCAPE:
                    DestroyWindow(hWnd);
                    break;
                    default:
                    diKeyState[wParam] = 1;
            }
            break;
 
        case WM_KEYUP://キーを放す
            diKeyState[wParam] = 0;
            break;
            
       default:
            return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    return 0;
}
 
////////////////////////////////////////////////////////////////////
 
/* メインコード */
 
////////////////////////////////////////////////////////////////////
//★ WinMain()
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR lpCmdLine, int nCmdShow)
{   
    MSG msg;
 
    //ウインドウクラスの登録
    WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,WndProc,0,0,hInst,NULL,NULL,NULL,NULL,NAME,NULL };
    if (!RegisterClassEx(&wc))  return FALSE;
 
    //メインウインドウ
    g_hWnd= CreateWindowEx(0,NAME,NAME,WS_OVERLAPPEDWINDOW,600,300,640,480,NULL,NULL,hInst,NULL);
    if (!g_hWnd)  return FALSE;
 
    // DirectX Graphics の初期化
    if (FAILED(Init3DDev()))    return FALSE;
 
    // ウインドウ表示
    ShowWindow(g_hWnd, SW_SHOWNORMAL);
    UpdateWindow(g_hWnd);
 
    //ウインドウサイズ等の調整
    AdjustmentWindow();
    ZeroMemory(&msg,sizeof(msg));
 
    //背景の位置のセット
    haikeiPosition.x = 0.0f;
    haikeiPosition.y = 0.0f;
 
    //描画関連
    textureCreate();//テクスチャの作成
    spriteCreate();//スプライトの作成
    Viewport();//ビューポートの作成
 
    //ループ
    while(msg.message!=WM_QUIT)
    {  
        //プロシージャ
        if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
        {   
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {    
            drawsprite();
        }
    }
    UnregisterClass(NAME, hInst);
    return  TRUE;
}

めんつゆ

Re: 再掲・クライアント領域に残像が残ってしまいます

#2

投稿記事 by めんつゆ » 6年前

補足させていただきますと、最初はウインドウのサイズを変更するとゲーム画面のサイズもそれに合わせて変化してしまいました。
ゲーム画面のサイズは4:3の比率に保ちたかったので、サイズ変更の際にウインドウのサイズを取得し、フロントバッファの座標を算出する事で、画面中央に表示することには成功しました。
しかしフロントバッファ外の領域にサイズ変更前のグラフィックが残り続けてしまうという状況です。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 再掲・クライアント領域に残像が残ってしまいます

#3

投稿記事 by ISLe » 6年前

351行目を
WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,WndProc,0,0,hInst,NULL,NULL,NULL,NULL,NAME,NULL };
から
WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,WndProc,0,0,hInst,NULL,NULL,(HBRUSH)GetStockObject(BLACK_BRUSH),NULL,NAME,NULL };
に変更すると余白が黒で塗り潰されるようになります。

ただし、ウィンドウサイズ変更時に、GDIの背景塗り潰しとDirect3Dの描画が同時発生し、激しく点滅します。

ゲーム目的であるなら特に、
・フロントバッファはクライアント領域のサイズと一致させる
・バックバッファはフロントバッファのサイズと一致させる
・バックバッファをそのままフロントバッファに転送する
・GDIの背景塗り潰しは無効化(背景ブラシはNULLのままに)する
・固定サイズのレンダーターゲットテクスチャを作成しオフスクリーンとする
・固定サイズでの描画はオフスクリーンに対して行い、オフスクリーンをバックバッファに変形して描画する
のがよろしいかと思います。
いまのコードはウィンドウモードに特化しすぎなので。


ちなみに、No.1のコードは、こちらの環境ではコンパイルエラーになりました。
コンパイルエラーを修正して実行ファイルを作成し起動しても、一瞬ウィンドウが表示されて終了してしまいました。
質問に書かれている動作を確認するのにかなりの変更が必要でした。

めんつゆ

Re: 再掲・クライアント領域に残像が残ってしまいます

#4

投稿記事 by めんつゆ » 6年前

ISLe様

返信ありがとうございます。
いただいた指示を実行したところ、ウインドウクラスを変更後に残像が消えました。
また激しい点滅も確認しました。ありがとうございます。

コードの確認に際してとても手間をかけさせてしまい大変申し訳ありませんでした。
こちらでは特に問題がなかったのですが、ひょっとしてコンパイルとはビルドやデバッグの事ではなくソフトとして実行した場合ということでしょうか。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 再掲・クライアント領域に残像が残ってしまいます

#5

投稿記事 by ISLe » 6年前

ビルドの際にコンパイルエラーが発生し、それを修正し、デバッグ実行した際には一瞬ウィンドウが表示されるだけで終了してしまった
ということを申し上げたつもりです。
環境が違うので、めんつゆさんの想像するものとは異なるかもしれませんが。

回答が欲しいのであれば、たくさんのひとに見てもらえるように対処したほうがよろしいのではないでしょうか。
そのための情報提供をしたつもりです。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 再掲・クライアント領域に残像が残ってしまいます

#6

投稿記事 by ISLe » 6年前

オフトピック
こちらの環境でプログラムを動作させるのに最低限必要だった書き換えは
1.ウィンドウプロシージャのシグネチャの変更
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2.コメントにある『DirectX Graphics の初期化』の処理を『ウインドウ表示』および『ウインドウサイズ等の調整』より後に移動
でした。

ウィンドウが非表示の状態でウィンドウサイズを確定し、ウィンドウを表示した後、デバイスを作成するという手順を踏むことで、ウィンドウサイズの変化する様子が映ることもなく、環境に依存した問題を回避できるものと思われます。

めんつゆ

Re: 再掲・クライアント領域に残像が残ってしまいます

#7

投稿記事 by めんつゆ » 6年前

ISLe 様
詳細を教えていただきありがとうございます!
今後こちらで質問する際に気をつけていきたいと思います。
とても時間を割いていただいたようで申し訳ありません。
ありがとうございました。

返信

“C言語何でも質問掲示板” へ戻る