resize display handling
shadyvillian

Hey guys I have a question for you. I've got some code that scales my ui when I resize my display. In my program I've noticed the following behaviors: While dragging the window to resize my graphics change size(display not acknowledged yet) then once I let it go, display is acknowledged(it returns to the correct size), then my scaling code kicks in and you can see it change. I'm wondering if there's a way to make this whole process more "smooth". Is there anything I could do in my end or is this all allegro backend stuff? ALLEGRO_EVENT_DISPLAY_RESIZE should be called ALLEGRO_EVENT_DISPLAY_RESIZED because it doesn't seem to call as I'm resizing. Is there a way to automatically acknowledge resize while I'm dragging that window? Or some kind of ALLEGRO_EVENT_DISPLAY_RESIZING kind of event I could use? Here's a snippet of my code for reference:

#SelectExpand
1 while(app.currentEvent.display.type != ALLEGRO_EVENT_DISPLAY_CLOSE) 2 { 3 al_wait_for_event(app.eventQueue, &app.currentEvent); 4 5 if(app.currentEvent.timer.type == ALLEGRO_EVENT_TIMER) 6 { 7 if(app.currentEvent.timer.source == app.bufferTimer) 8 { 9 app.redraw = true; 10 } 11 } 12 13 if(app.currentEvent.display.type == ALLEGRO_EVENT_DISPLAY_RESIZE) 14 { 15 al_acknowledge_resize(app.mainDisplay); 16 app.ScaleUi(); 17 } 18 19 if(app.redraw && al_is_event_queue_empty(app.eventQueue)) 20 { 21 app.Draw(); 22 } 23 }

Elias

It's supposed to work continuously... but whoever implemented it in windows messed up. You could file a bug report.

shadyvillian

I mean the display does resize but I want the event to keep firing as I drag not just once the mouse button is let off. I'll probably end up poking in the source files tonight and see if I can figure it out I suppose(just for fun)

Thomas Fjellstrom

I don't think you really want that. Every single resize would cause DX and Allegro to have to reinitialize your entire context, including textures. I can't imagine that would perform well at all.

Edgar Reynaldo

Other applications seem to be able to handle window resizing with no problem (non-allegro apps). I just tried CodeBlocks in a window and it resizes smoothly as butter, with no black or uninitialized areas. So it is possible. I don't know what it would take to do so though.

Thomas, are you sure there's no way to resize a window without reinitializing the entire context?

Thomas Fjellstrom

Other applications seem to be able to handle window resizing with no problem (non-allegro apps). I just tried CodeBlocks in a window and it resizes smoothly as butter, with no black or uninitialized areas. So it is possible. I don't know what it would take to do so though.

Windows GDI apps are not equivalent to 3d apps.

Quote:

Thomas, are you sure there's no way to resize a window without reinitializing the entire context?

If they use a 3D surface, you tend to have to reinitialize everything. I could be wrong on that, but D3D at least seems like it'd impose that limitation.

Edgar Reynaldo

Windows GDI apps are not equivalent to 3d apps.

Okay, this is something I'm not familiar with. Is it possible to make a GDI app with allegro? Would that require another driver for windows?

Quote:

If they use a 3D surface, you tend to have to reinitialize everything. I could be wrong on that, but D3D at least seems like it'd impose that limitation.

What exactly is a 3D surface? Just a D3D context? Or is it substantially different from a GDI context (if there is such a thing)...?

You can tell I know very little about this sort of thing....

Arthur Kalliokoski

Is it possible to make a GDI app with allegro?

A4 can stretch a 2D image with ease.

Edgar Reynaldo

A4 doesn't and probably never will have resizable windows, so that's kind of moot in this case...

Thomas Fjellstrom

Okay, this is something I'm not familiar with. Is it possible to make a GDI app with allegro? Would that require another driver for windows?

A4 has a GDI driver. It's pretty slow, but it works. A5 pretty much wants an accelerated driver, but it isn't required. Someone could implement a GDI driver, but I don't know why you'd want such a thing.

Quote:

What exactly is a 3D surface? Just a D3D context?

Yeah, for the most part. a 3D surface can also be a texture or FBO (Frame Buffer Object. in GL terms).

Quote:

Or is it substantially different from a GDI context (if there is such a thing)...?

Very different. A "GDI Context" i assume is just a regular windows window. I don't think classic GDI has a "context" as such, other than some hidden state associated with a given program.

A4 doesn't and probably never will have resizable windows, so that's kind of moot in this case...

There's a patch for it. That no-one bothered to apply.

Edgar Reynaldo

There's a patch for it. That no-one bothered to apply.

Lost in the mailing list somewhere? Or is it still floating around?

GDI on Windows with A4 never worked reliably for me.

Allegro 5.1.GIT said:

wwindow.c#SelectExpand
871 case WM_SIZE: 872 if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || wParam == SIZE_MINIMIZED) { 873 /* 874 * Delay the resize event so we don't get bogged down with them 875 */ 876 if (!resize_postponed) { 877 resize_postponed = true; 878 _beginthread(postpone_thread_proc, 0, (void *)d); 879 } 880 } 881 return 0; 882 case WM_ENTERSIZEMOVE: 883 /* DefWindowProc for WM_ENTERSIZEMOVE enters a modal loop, which also 884 * ends up blocking the loop in d3d_display_thread_proc (which is 885 * where we are called from, if using D3D). Rather than batching up 886 * intermediate resize events which the user cannot acknowledge in the 887 * meantime anyway, make it so only a single resize event is generated 888 * at WM_EXITSIZEMOVE. 889 */ 890 if (d->flags & ALLEGRO_DIRECT3D_INTERNAL) { 891 resize_postponed = true; 892 } 893 break; 894 case WM_EXITSIZEMOVE: 895 if (resize_postponed) { 896 win_generate_resize_event(win_display); 897 win_display->ignore_resize = false; 898 resize_postponed = false; 899 win_display->can_acknowledge = true; 900 } 901 break; 902 } 903 904 return DefWindowProc(hWnd,message,wParam,lParam); 905}

It looks like everything happens in WM_EXITSIZEMOVE. WM_SIZE messages are mostly ignored, and WM_ENTERSIZEMOVE can't respond if using d3d (according to the comments).

Arthur Kalliokoski

My point was that it's much easier to stretch a 2D image rather than resizing an entire 3D context.

Edgar Reynaldo

Yeah, that's fine. I just want to know if we can get a smooth resize and use D3D at the same time....

EDIT
This looks promising :
http://blogs.msdn.com/b/oldnewthing/archive/2008/01/16/7123299.aspx

Seems you can intercept the resize before it actually occurs, using WM_WINDOWPOSCHANGING or WM_SIZING.

Edit
This is the current state of affairs on D3D with Windows :
{"name":"608726","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/f\/9fccccc67c7e58de521fd1dbb9563d89.png","w":877,"h":600,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/f\/9fccccc67c7e58de521fd1dbb9563d89"}608726

The current screen is frozen in place, with black or white filling in the excess area of the window until it is resized. Not very pretty.

shadyvillian

Yeah Edgar is on the same page as to what I mean, but as to a fix I know it can be done I guess implementing it in the correct way is the issue. My program is more of an app than a game(though I understand allegro is for games) I'm sure it would benefit allegro to have it implemented even if its just an optional flag.

Edgar Reynaldo

WM_ERASEBKGND might be useful to at least clear the background to a single color when resizing. If you specify a default background brush when creating the window WM_ERASEBKGND should handle it for us.

What would be ideal is to detect WM_SIZING messages and then have the window background be repainted by the user or a default function if not specified.

I will have to hack on Allegro for a while and see what I can come up with.

EDIT

Here are some of the events that are being fired during a window resize :

It starts out with WM_PAINT when the window is opened.
Then WM_WINDOWPOSCHANGING and WM_ENTERSIZEMOVE and WM_SIZING when you grab the handle on the window to resize it. Then a bunch of groups of these :

WM_SIZING
WM_WINDOWPOSCHANGING
WM_ERASEBKGND
WM_WINDOWPOSCHANGED
WM_SIZE
WM_PAINT

and then closes with a group of

WM_SIZING
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGING
WM_EXITSIZEMOVE
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGED

when you let go of the window handle.

So something we could do is provide a default background brush when creating the window handle. Also, we should be able to set a default clear color for the window when resized.

EDIT 2 :
Changing it to window_class.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); clears the screen to black during each resize, blanking out what was showing. That's not quite what we want, but it is a start.

Elias

I think we should just continuously fire events. The resizing only happens after the user acknowledges it anyway. Maybe we could also have a different event used during the resize, so the current behavior stays for those who prefer it (I don't see why anyone would though). The Windows behavior is also not what we do on other platforms as far as I know.

Gideon Weems

Here's what I'm getting on Linux. Is this what it looks like in motion on Windows?

{"name":"608730","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/3\/7\/37b1646e7cad640d428a07942ac9fcdf.gif","w":687,"h":333,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/3\/7\/37b1646e7cad640d428a07942ac9fcdf"}608730

Everything goes immediately back to normal after releasing the, err... mouse.

Thomas Fjellstrom

Is your WM set to show contents while resizing? If not, we'll never get a resize event until the resize is done.

Edgar Reynaldo

@Gideon - yeah that is what it looks like on Windows.

Gideon Weems

Is your WM set to show contents while resizing?

Hehe, I'm not that archaic.

As far as I can tell, this sort of resize behavior only occurs with Allegro programs--though to be honest, I never considered it much of a problem.

Thomas Fjellstrom

When resizing a window you can (and will) get hundreds of resize events if you don't batch them. I don't think you want to be trying to resize the GL/D3D backbuffer for every one. But if we can tell the context to maybe stretch the backbuffer when resizing, or at least clear the empty area, that would look better.

We had stretching at one point I think but people complained :D

Edgar Reynaldo

The problem with using a HBRUSH for the hbrBackground is that during WM_ERASEBKGND it covers the entire surface of the window with whatever brush you use. I tried (NULL_BRUSH) and (COLOR_BACKGROUND + 1), which resulted in white and black using D3D. With OpenGL the window resizes the backbuffer each time its size is changed, almost immediately, with only a brief flash of black or white along the border. If we handle WM_WINDOWPOSCHANGED and send an event then we could repaint the border or provide a way for the user to do so. The user probably knows what he wants to draw with a larger window there. So why not let him acknowledge the resize right away if they want to?

Elias

I'm with Edgar. Let the user decide. If they want to redraw 100s of times, let them (I for one want to). If they only want to redraw once, that's also fine. But Allegro shouldn't force to draw only once by hiding the other events.

Gideon Weems

As a user, I'm with Edgar as well. Processing a batch of resize events every tick of the main loop would be easy. Am I correct in thinking it would look like the following?

#SelectExpand
1/* Event handler. */ 2switch (event.type) { 3 case ALLEGRO_EVENT_TIMER: 4 bUpdate = true; 5 break; 6 case ALLEGRO_EVENT_DISPLAY_RESIZE: 7 bHandleResize = true; 8 break; 9} 10 11/* Logic updater. */ 12if (bUpdate) { 13 bUpdate = false; 14 if (bHandleResize == true) { 15 bHandleResize = false; 16 bDraw = true; 17 } 18} 19 20if (bDraw) { 21 bDraw = false; 22 // Draw. 23}

beoran

For backwards compatibility I'd keep the ALLEGRO_EVENT_DISPLAY_RESIZE as it is, and add a ALLEGRO_EVENT_DISPLAY_RESIZING event that is sent while the resize is going on. Like that, people can choose whether to continuously resize or only once.

Edgar Reynaldo

I think the best message to handle would be WM_WINDOWPOSCHANGED. It is sent when a window is shown, hidden, moved, or resized, and contains info about the WINDOWPOS in the lParam.

WINDOWPOSCHANGED
http://blogs.msdn.com/b/oldnewthing/archive/2008/01/15/7113860.aspx

WINDOWPOS
http://msdn.microsoft.com/en-us/library/windows/desktop/ms632612%28v=vs.85%29.aspx

EDIT
Trying to understand the comments on this code :

      case WM_ENTERSIZEMOVE:
         /* DefWindowProc for WM_ENTERSIZEMOVE enters a modal loop, which also
          * ends up blocking the loop in d3d_display_thread_proc (which is
          * where we are called from, if using D3D).  Rather than batching up
          * intermediate resize events which the user cannot acknowledge in the
          * meantime anyway, make it so only a single resize event is generated
          * at WM_EXITSIZEMOVE.
          */
         if (d->flags & ALLEGRO_DIRECT3D_INTERNAL) {
            resize_postponed = true;
         }
         break;

I was thinking of doing away with WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE and replacing them with WM_WINDOWPOSCHANGING, but then that would change the current behaviour.

What I am really worried about is this modal loop that the comment above is talking about.

I tried only generating an event on WM_WINDOWPOSCHANGING but in D3D for some reason all the ALLEGRO_EVENT_DISPLAY_RESIZE events get backed up until you stop resizing the window. That may be the modal loop effect from above.

Not sure where to go from here...

Edit2
Somehow my changes corrupted all the title bars on all my windows. :o Yeah, Aero is corrupted somehow. I'm gonna reboot and hope it gets fixed.

Thomas Fjellstrom

Yeah, I'm betting ENTERSIZEMOVE's default (windows provided) handler just enter's a loop to handle the resizing. Not sure, but we could not call the defwndproc on ENTERSIZEMOVE/EXITSIZEMOVE. That might break something though.

Edgar Reynaldo

Not sure, but we could not call the defwndproc on ENTERSIZEMOVE/EXITSIZEMOVE. That might break something though.

I think that is why the title bars of all my windows got corrupted. I think we have to call DefWndProc, but then it starts that modal loop mentioned above in WM_ENTERSIZEMOVE. Not sure how / if the loop can be broken. I think that is why all of my EVENT_RESIZE's get piled up when using WM_WINDOWPOSCHANGING.

Thread #614370. Printed from Allegro.cc