• Advertisement
Sign in to follow this  

How do I keep my DirectX window from turning white when I move it.

This topic is 2998 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I will admit this is a problem I have had for a while and never fixed. I figure its about time I learn what is going on. When I create a window and setup a directX device all is well. The window shows up and is rendered how I want it. The problem occures when I move the window around with my mouse. As I drag the window and part of it goes off of screen it turns white when I pull back into view. This happens until I let go of the mouse. When the mouse is let go the window redraws itself. Looking through the DirectX sample this is not a problem. So, what am I missing? Regards Chad

Share this post


Link to post
Share on other sites
Advertisement
When your window is being dragged, your message pump will go into a modal loop and none of your code will get a chance to execute unless you respond to WM_MOVING notifications or WM_PAINT notifications. I believe the samples will render upon receiving WM_PAINT, which causes them to re-draw when the off-screen portion of the window gets invalidated.

Share this post


Link to post
Share on other sites
I think I get what your saying but I am not sure the best way to do it. So i have a few question...

1) Lets say this is a snippet of my game loop where I deal with messages
if(PeekMessage(&msg,NULL,0,0, PM_REMOVE)) 
{
// ?
m_graphics.Update(msg);

// translate messages into the right format
TranslateMessage(&msg);

// send the message to the WindowProc function
DispatchMessage(&msg);
}
Should I send the message to a custom funtion that will check it for WM_PAINT. And then do something along the lines of..
void Graphics::Update(MSG &msg )
{
switch(msg.message)
{
case WM_PAINT:
Render();
break;
}
}


Does this wound about correct? If not do you have any suggetions? One thing that I am thinking of is that it might not be the most efficent way. Considering my WindowProc is already checking the messages I feel weird about making another check outside of it. Truth be told I don't know if this is a warrented thought. As far as I know this is the only way to do it.

Regards

ChaD

Share this post


Link to post
Share on other sites
What exactly are you after, do you just want the rendered window content to be visible when you move the window (but a static image), or do you want the game to keep going and updating (animations etc)?
Is it just when you move the window, or do you want it when you resize?
If so, is it enough that the current image is scaled, or do you want to re-render at the new resolution as the user is resizing?

The easiest might be to use copying instead of swapping to Present the back-buffer. Then you can just call Present again in WM_PAINT. I guess that the samples do something like this, as with resizing nothing is re-rendered at the new resolution until you are done resizing, it's just a scaled static image. I'm not sure exactly the method they use, there are multiple ways to do it. I would look through the code the SDK samples use.

Share this post


Link to post
Share on other sites
Quote:
Original post by Erik Rufelt
What exactly are you after, do you just want the rendered window content to be visible when you move the window (but a static image), or do you want the game to keep going and updating (animations etc)?
Is it just when you move the window, or do you want it when you resize?
If so, is it enough that the current image is scaled, or do you want to re-render at the new resolution as the user is resizing?

The easiest might be to use copying instead of swapping to Present the back-buffer. Then you can just call Present again in WM_PAINT. I guess that the samples do something like this, as with resizing nothing is re-rendered at the new resolution until you are done resizing, it's just a scaled static image. I'm not sure exactly the method they use, there are multiple ways to do it. I would look through the code the SDK samples use.


1) I am not giving the user an option to resize.
2) Because the user does not have the option then scalling or rendering is not an issue at this point.
3) As the window is moving I just want a static image.
4) When the user release the window it should start its normal render cycle.

Looking at the simplest of DirectX samples they simply make a call to there "Render" function when WM_PAINT is recived. My issue is that my "Render" function is a part of a class object. Which leads me to another question that I just posted in the beginners section.

Question

How do you acceess "Render" in side the message handeler when render is a part of a class object?

Regards

Chad

Share this post


Link to post
Share on other sites
Was a thread like this a while back.. The solution they came up with was to stop repainting the window.
So that it doesnt get black edges etc if temporarily overlapped.

A search could probably reveal it :)

Share this post


Link to post
Share on other sites
Quote:
Original post by marius1930
Was a thread like this a while back.. The solution they came up with was to stop repainting the window.
So that it doesnt get black edges etc if temporarily overlapped.

A search could probably reveal it :)


Do you have any suggestion for keywords to search for. I have been searching for the past few hours and have not found anything.

REgards

Chad

Share this post


Link to post
Share on other sites
Quote:
Original post by eFoDay
you could stop using WM_PAINT


Care to expalin some more? I was not using WM_PAINT until it was suggested to me by the first responder. At this point if I don't check WM_PAINT how will I know if the window is being invalidated?

Regards

Chad

Share this post


Link to post
Share on other sites
Last time I used WM_PAINT was with GDI because it was so slow you had to make "dirty" regions and only update that area or there would be tearing.

Direct3D is fast and you can redraw the entire screen as fast as possible so your render function can just go in the main loop.

Oh and I see its only going white when you take it off screen. I thought it was going all white when you just moved it.

When I move my window off screen then back on it shows like the edge of the window or something until you let go of the mouse. So I guess you would have to do something else.

Share this post


Link to post
Share on other sites
Quote:
Original post by eFoDay
Last time I used WM_PAINT was with GDI because it was so slow you had to make "dirty" regions and only update that area or there would be tearing.

Direct3D is fast and you can redraw the entire screen as fast as possible so your render function can just go in the main loop.

Oh and I see its only going white when you take it off screen. I thought it was going all white when you just moved it.

When I move my window off screen then back on it shows like the edge of the window or something until you let go of the mouse. So I guess you would have to do something else.


Yeah...when you move the window it does not continue through the loop until you let the window go. And when the window is moved of screen logic of the program says "Don't draw what is not on screen". Then you bring the window back into the screen it has not had a chance redraw.

Ugh...every example I am seeing says to check for WM_PAINT. Once the message is recived you know you need to rerender. Problem is all the examples are using Global Render functions. My render function is inside of a class object. And I have no clue how to access that inside of the WindowProc. I messed around with accessing the Message from within side the game loop like I posted above but for some reason I am never reciving the WM_PAINT message.

Regards

Chad

Share this post


Link to post
Share on other sites
There's a response in your other thread telling you how to do it with SetWindowLongPtr, which is the correct way. Each window often gets a window-handler class attached to it with SetWindowLongPtr, which is then used to actually handle the message.

Example: (not compiled so there might be some syntax errors)

class RenderWindowHandler {
public:
RenderWindowHandler(Model *model) : model(model) {
}

LRESULT wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_PAINT:
model->render();
return 0;
}

return DefWindowProc(hWnd, msg, wParam, lParam);
}

private:
Model *model;
};


void init() {
RenderWindowHandler *handler = new RenderWindowHandler(my3DModel);

CreateWindow(..., (LPVOID)handler);
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if(msg == WM_CREATE) {
LPCREATESTRUCT lpCreateStruct = (LPCREATESTRUCT)lParam;
RenderWindowHandler *handler = (RenderWindowHandler*)lpCreateStruct->lpCreateParams;

SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)handler);

return 0;
}
else {
RenderWindowHandler *handler = (RenderWindowHandler*)GetWindowLongPtr(hWnd, GWLP_USERDATA);

if(handler)
return handler->wndProc(hWnd, msg, wParam, lParam);
else
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}



And if you want the handler class to automatically be deleted with the window, add an if(msg == WM_NCDESTROY) delete handler;.

Share this post


Link to post
Share on other sites
Quote:
Original post by chadsxe
Quote:
Original post by eFoDay
Last time I used WM_PAINT was with GDI because it was so slow you had to make "dirty" regions and only update that area or there would be tearing.

Direct3D is fast and you can redraw the entire screen as fast as possible so your render function can just go in the main loop.

Oh and I see its only going white when you take it off screen. I thought it was going all white when you just moved it.

When I move my window off screen then back on it shows like the edge of the window or something until you let go of the mouse. So I guess you would have to do something else.


Yeah...when you move the window it does not continue through the loop until you let the window go. And when the window is moved of screen logic of the program says "Don't draw what is not on screen". Then you bring the window back into the screen it has not had a chance redraw.

Ugh...every example I am seeing says to check for WM_PAINT. Once the message is recived you know you need to rerender. Problem is all the examples are using Global Render functions. My render function is inside of a class object. And I have no clue how to access that inside of the WindowProc. I messed around with accessing the Message from within side the game loop like I posted above but for some reason I am never reciving the WM_PAINT message.

Regards

Chad


The easy solution is to either make your renderer class a global or static object. The better solution is to encapsulate all of your window code in its own class, and give it a renderer as a member variable.

Share this post


Link to post
Share on other sites
ok heres a basic version of what I do


#include <d3dx9.h>

namespace Game
{
// Windows
HWND hWnd = NULL;

HWND openWindow(int width, int height);
void closeWindow();

// Graphics
IDirect3D9* d3d9 = NULL;
IDirect3DDevice9* d3dDevice = NULL;

HRESULT setupD3D(int width, int height, int bpp);
void shutdownD3D();

int update();
void render();

void loadScene();
void unloadScene();
};

LRESULT __stdcall WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

//
LRESULT result = 0;

switch(msg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;

default:
result = DefWindowProc(hWnd, msg, wParam, lParam);
}

return result;
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nCmd)
{

using namespace Game;

int w=1024, h=768;

bool gameIsRunning = true;

// Create a render window and setup Direct3D
openWindow(w, h);
if (FAILED(setupD3D(w, h, 32))) { gameIsRunning = false; }

// Load the scene
loadScene();

// Enter the game loop
MSG uMsg;
while (gameIsRunning)
{
// Process window messages
if (PeekMessage(&uMsg, hWnd, 0, 0, PM_REMOVE))
{
if (uMsg.message != WM_QUIT)
{
TranslateMessage(&uMsg);
DispatchMessage(&uMsg);
}
else break;
}

// Update game
update();

// Draw
render();
}

// Unload the scene
unloadScene();

// Shutdown D3D and close the window
shutdownD3D();
closeWindow();

return 0;
}



The window doesn't turn white but it doesn't redraw while your moving it either so if you move it off the screen it looks crazy but I create my window so it can't be moved anyway.
DWORD dwstyle = WS_POPUP | WS_BORDER | WS_VISIBLE;

Share this post


Link to post
Share on other sites
Ok so what I gather is that I have a few options.

1) Global or Static Object. This I don't want to do for obvious reasons.

2) What Erik Rufelt is suggesting (and poster from other thread). I will admit I have never seen some of the stuff and I will need to investigate further.

3) What eFoDay is suggesting. This won't work in my case do to the level of abstraction and encapsulation I am using.

From the little info I am gathering I am guessing number 2) is the way I need to go. I just need to figure out what is exactly going on before I commit. None the less I am sure I will be back tonight or tomorrow with more question.

Until then

Regards

Chad

Share this post


Link to post
Share on other sites
For the class of your main window you can try setting the style flags to 0.
I haven't tried it, worth a shot.

Share this post


Link to post
Share on other sites
I figured out by adding my render function to the WM_MOVE message it does not affect the drawing at all when you bring the window off the screen and then back on again


LRESULT __stdcall WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

//
LRESULT result = 0;

switch(msg)
{
case WM_MOVE:
{
if (Game::gameIsRunning)
{
Game::render();
result = DefWindowProc(hWnd, msg, wParam, lParam);
break;
}
}
case WM_CLOSE:
PostQuitMessage(0);
break;

default:
result = DefWindowProc(hWnd, msg, wParam, lParam);
}

return result;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by chadsxe
3) What eFoDay is suggesting. This won't work in my case do to the level of abstraction and encapsulation I am using.


So where do you declare your graphics class? in WinMain()?

wherever it is, at the highest level, just make a namespace and declare all the stuff inside

then you can access it from inside WindowProc().

like for example I have inside WindowProc() Game::render();
you could have Game::engine.m_graphics.render(); if you wanted to

Share this post


Link to post
Share on other sites
Quote:
Original post by chadsxe
I think I get what your saying but I am not sure the best way to do it. So i have a few question...

1) Lets say this is a snippet of my game loop where I deal with messages



you should pump your messages as long as there are some and not call render routine at it.
while(1==1)
{
if(PeekMessage(&msg,NULL,0,0, PM_REMOVE))
{
// translate messages into the right format
TranslateMessage(&msg);

// send the message to the WindowProc function
DispatchMessage(&msg);
}
else
m_graphics.Update(msg);
}



and handle the message in the window procedure.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
See "A Bit of Polish".


@ Evil Steve

I actually used your tutorial

Evil Steve's tutorial

to figure out what was suggested to me and it is working nicely so far. In regards to "A Bit of Polish" why are using

WM_ENTERSIZEMOVE

instead of

WM_PAINT

One of the directX samples has a "Render" call when WM_PAINT is dispatched. I currently have things set up like that sample...

		case WM_PAINT:
Application()->GetStateManager().Render();
ValidateRect( hWnd, NULL );
return 0;
It appears to be working so far but I am testing with static text. Will things be different once I start moving things?

Regards

Chad

Share this post


Link to post
Share on other sites
@Evil Steve

I actually just figured out that WM_ENTERSIZEMOVE sends the message only once. Which also allows me to understand your example.

Regards

Chad

Share this post


Link to post
Share on other sites
Quote:
Original post by Erik Rufelt
There's a response in your other thread telling you how to do it with SetWindowLongPtr, which is the correct way. Each window often gets a window-handler class attached to it with SetWindowLongPtr, which is then used to actually handle the message.

Example: (not compiled so there might be some syntax errors)
*** Source Snippet Removed ***

And if you want the handler class to automatically be deleted with the window, add an if(msg == WM_NCDESTROY) delete handler;.


Actually.... SetWindowLongPtr is NOT the correct way to do it. It's pretty good and works 99.999% of the time, but it fails if someone were to spy on your application with an external program, open the HWND and call SetWindowLongPtr() on it. Granted that's not high on the list of priorities of things to worry about, but windows supports hooking as one if its features anyway (see, for example, SetWindowsHookEx). it would be better to just not rely on something that had any chance of being threatened by external code, and there is actually a way.

You can use the lpParam member when calling CreateWindow or CreateWindowEx. then respond to the WM_CREATE message in your message loop and get the parameter out and set it to a static variable inside the WindowProc function.

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
Actually.... SetWindowLongPtr is NOT the correct way to do it. It's pretty good and works 99.999% of the time, but it fails if someone were to spy on your application with an external program, open the HWND and call SetWindowLongPtr() on it. Granted that's not high on the list of priorities of things to worry about, but windows supports hooking as one if its features anyway (see, for example, SetWindowsHookEx). it would be better to just not rely on something that had any chance of being threatened by external code, and there is actually a way.

You can use the lpParam member when calling CreateWindow or CreateWindowEx. then respond to the WM_CREATE message in your message loop and get the parameter out and set it to a static variable inside the WindowProc function.
If someone is going to modify the data in your window, there's nothing you can do about it. If you were developing this as some sort of library then it'd be fair enough, but not using a perfectly acceptable way to store the window handle is like not using the heap alloc functions because someone could inject a DLL into your process and modify the heap.

If you use a static variable as an HWND, you can't reinitialise the window without restarting the process (Or some horrible code to "reset" your static variable), and you can only have one window using that window proc.
Also, it still doesn't work if someone sends your window a WM_CREATE message when it's running.

Quote:
Original post by chadsxe
@Evil Steve

I actually just figured out that WM_ENTERSIZEMOVE sends the message only once. Which also allows me to understand your example.
Ah sorry, I should perhaps have made that clearer. The WM_ENTERSIZEMOVE message is sent when Windows is entering the size/move modal loop for your window, not repeatedly.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement