合計 昨日 今日

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

[このトピックは解決済みです]

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: めんつゆ
[URL]
Date: 2018年1月04日(木) 21:05
No: 1
(OFFLINE)

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

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

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

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

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

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

宜しくお願いします。

コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#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;
}

Name: めんつゆ
[URL]
Date: 2018年1月06日(土) 14:39
No: 2
(OFFLINE)

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

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

Name: ISLe
[URL]
ハッカー(266,335 ポイント)
Date: 2018年1月06日(土) 18:00
No: 3
(OFFLINE)

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

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

Name: めんつゆ
[URL]
Date: 2018年1月06日(土) 20:12
No: 4
(OFFLINE)

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

ISLe様

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

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

Name: ISLe
[URL]
ハッカー(266,335 ポイント)
Date: 2018年1月07日(日) 16:36
No: 5
(OFFLINE)

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

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

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

Name: ISLe
[URL]
ハッカー(266,335 ポイント)
Date: 2018年1月08日(月) 15:50
No: 6
(OFFLINE)

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

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

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

Name: めんつゆ
[URL]
Date: 2018年1月09日(火) 11:30
No: 7
(OFFLINE)

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

[解決!]

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


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[10人]