Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Blacking out the display while resizing

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Blacking out the display while resizing
xsquid
Member #16,498
July 2016

Is there a way to control what the display shows when it's being resized on Windows?

Currently, it stretches the contents of the display. I'd prefer to be able to detect that the display is being resized (through an event?) so I can control what it displays (e.g., plain black during the resize).

I found a similar question here ([AL5] Knowing when a resize event is starting?), and it didn't seem there was a resolution, but that was back in 2011.

Is there any way to do this now?

Update: Switching to OpenGL made it so the ALLEGRO_EVENT_DISPLAY_RESIZE event is emitted repeatedly which allowed me to detect a resize in-progress. The follow-up problem is now finding a way to fix this: https://my.mixtape.moe/rdxqwg.webm (What I've got right now, vs what I'm trying to achieve)

GullRaDriel
Member #3,861
September 2003
avatar

ALLEGRO_EVENT_DISPLAY_RESIZE is an event fired when resizing.
For the control of the window content itself, I don't know.

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

xsquid
Member #16,498
July 2016

As far as I know, that event is only fired when the user has finished resizing, right? What I'm looking for is something that indicates that the display has started being resized, or is currently being resized, so I can hide its contents while this is occurring instead of having them awkwardly stretch.

It looks bad when you're trying to respect the aspect ratio, because it doesn't respect it while the resize is occurring and I have no way of dealing with that because I can't detect it.

Elias
Member #358
May 2000

In Linux you get the resize event as soon as the resizing starts. But the Windows port is a bit strange for some reason. It should not be hard to fix it though. This is where the resize starts:

https://github.com/liballeg/allegro5/blob/master/src/win/wwindow.c#L915

--
"Either help out or stop whining" - Evert

Edgar Reynaldo
Member #8,592
May 2007
avatar

Blacking out the display is not preferable for everyone. I want the window to display its contents during a resize, not black out. This is typical of most major desktop applications. The contents are redrawn as necessary, not ignored, or blacked out.

One issue comes from the number of resize events that are emitted during a resize. The question is whether to collect them or deal with them individually. What I do personally is wait a short period of time and then take all the resize events off of the queue at once. There are usually between 3 and 10 resize events in a short period of time because you get one for every mouse move when the window controls are being dragged.

A further question comes whether you are using Direct3D or OpenGL, as they handle resize events differently.

Elias
Member #358
May 2000

I think how it should work is send a resize event immediately when resizing starts. But then ignore all resize events until the user calls al_acknowledge_resize.

So that way it is completely up to the user how many resize events they want to handle. They can acknowledge 1000 resize events per second (and for example smoothly redraw the game scene during the resize that way). Or they can only handle one event per second or whatever. If reloading of fonts or similar things are necessary then this way only at most one resize event would be pending if it takes too long.

I think that's how it already works in Linux (but not sure, would have to double check).

--
"Either help out or stop whining" - Evert

Edgar Reynaldo
Member #8,592
May 2007
avatar

xsquid
Member #16,498
July 2016

Blacking out the display is not preferable for everyone. I want the window to display its contents during a resize, not black out. This is typical of most major desktop applications. The contents are redrawn as necessary, not ignored, or blacked out.

It goes without saying that you're not going to find a default behavior that satisfies literally everyone. I don't want to change the default behavior, but instead have more control over what happens. All I'm looking for is a way to detect that a resize has either (1) started or (2) is in progress so I can alter drawing accordingly. As it is, I can only detect when the resize has ended. How can I "redraw as necessary" if I can't detect that the size of the window is changing? The current behavior (just stretching the contents) isn't exactly typical of the Windows experience.

One issue comes from the number of resize events that are emitted during a resize. The question is whether to collect them or deal with them individually. What I do personally is wait a short period of time and then take all the resize events off of the queue at once. There are usually between 3 and 10 resize events in a short period of time because you get one for every mouse move when the window controls are being dragged.

A further question comes whether you are using Direct3D or OpenGL, as they handle resize events differently.

I'm using whichever is the default for the latest version of Allegro 5. I'm detecting the resize via the display's event source, which only emits a resize event once the resize has completed (ALLEGRO_EVENT_DISPLAY_RESIZE). I can't find anything in the documentation for detecting that a resize has started or is in progress. At least, not through the typical events.

According to Elias' responses, it seems this is only possible on Linux, not Windows... Is the final verdict that this cannot be done without modifying Allegro?

Edgar Reynaldo
Member #8,592
May 2007
avatar

You might be able to accomplish what you want by setting the Background Brush using the HWND Window handle that Allegro gives you. See al_get_win_window_handle for details.

   HBRUSH brush = CreateSolidBrush(RGB(0, 0, 0));
   SetClassLongPtr(hwnd, GCLP_HBRBACKGROUND, (LONG)brush);

But yes, Allegro probably needs to be patched to accomplish what you want.

xsquid
Member #16,498
July 2016

That certainly blacks out the display, but the problem is detecting the resize in the first place. Am I supposed to detect it somehow through the handle, or am I out of luck?

(Blacking out the display was never the problem, it was just an example to illustrate why I want to be able to detect this.)

bamccaig
Member #7,536
July 2006
avatar

I suppose the question is what kind of drawing control each framework gives you during a resize. If you're free to run whatever program and respond to the process dynamically then I think it makes sense for Allegro to offer up as much data as is feasible. That said, I think that resizing games is kind of black magic. It seems to rarely work, and generally I stick to full-screen to avoid problems. Am I just old or is it truly black magic to have windowed games?

Elias
Member #358
May 2000

Whoever implemented resizing in the Windows port just did it in a way to not allow updates to the window during the resize. And it should get fixed (but not by me, I don't even have Windows).

--
"Either help out or stop whining" - Evert

Edgar Reynaldo
Member #8,592
May 2007
avatar

You can try messing with al_win_add_window_callback

bool al_win_add_window_callback(ALLEGRO_DISPLAY *display,
   bool (*callback)(ALLEGRO_DISPLAY *display, UINT message, WPARAM wparam,
   LPARAM lparam, LRESULT *result, void *userdata), void *userdata)

Try intercepting WM_SIZING messages and repainting if you get one.

Eric Johnson
Member #14,841
January 2013
avatar

If all you want is to "black out" the display while resizing, surely something like the following would work:

#SelectExpand
1#include <iostream> 2 3#include <allegro5/allegro.h> 4#include <allegro5/allegro_image.h> 5#include <allegro5/allegro_primitives.h> 6 7using std::cout; 8 9int main(void) { 10 11 if (!al_init()) { 12 13 cout << "Error: failed to initialize Allegro 5\n"; 14 15 return - 1; 16 } 17 18 if (!al_init_image_addon()) { 19 20 cout << "Error: failed to initialize image addon\n"; 21 22 return - 1; 23 } 24 25 if (!al_init_primitives_addon()) { 26 27 cout << "Error: failed to initialize primitives addon\n"; 28 29 return - 1; 30 } 31 32 // Allow the display window the be resizable. 33 al_set_new_display_flags(ALLEGRO_RESIZABLE); 34 35 // Create events. 36 ALLEGRO_TIMER *timer = al_create_timer(1.0 / 60.0); 37 ALLEGRO_DISPLAY *display = al_create_display(400, 300); 38 ALLEGRO_EVENT_QUEUE *event_queue = al_create_event_queue(); 39 40 // Register events with the event queue. 41 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 42 al_register_event_source(event_queue, al_get_display_event_source(display)); 43 44 al_start_timer(timer); 45 46 bool render = true; 47 bool running = true; 48 49 // This will be used to "black out" the display. 50 bool display_black = false; 51 52 // Do main game loop. 53 while (running) { 54 55 ALLEGRO_EVENT event; 56 57 al_wait_for_event(event_queue, &event); 58 59 if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { 60 61 // The window was closed; end the game. 62 running = false; 63 } 64 else if (event.type == ALLEGRO_EVENT_DISPLAY_RESIZE) { 65 66 al_acknowledge_resize(display); 67 68 // Change the display to black. 69 display_black = true; 70 } 71 else if (event.type == ALLEGRO_EVENT_TIMER) { 72 73 // Update stuff here. 74 render = true; 75 } 76 77 if (render && al_is_event_queue_empty(event_queue)) { 78 79 // Render stuff here. 80 81 render = false; 82 83 if (display_black) { 84 85 // Clear display to black color. 86 al_clear_to_color(al_map_rgb(0, 0, 0)); 87 88 static unsigned ticks = 0; 89 90 ++ticks; 91 92 if (ticks > 30) { 93 94 // Keep the display black for half a second as a "cool down" period. 95 96 display_black = false; 97 98 ticks = 0; 99 } 100 } 101 else { 102 103 // Clear display to red color. 104 al_clear_to_color(al_map_rgb(255, 0, 0)); 105 } 106 107 // Update display. 108 al_flip_display(); 109 } 110 } 111 112 // Destroy events. 113 al_destroy_timer(timer); 114 al_destroy_display(display); 115 al_destroy_event_queue(event_queue); 116}

Here is a video of it in action.

[EDIT]
Not sure how this behaves on Windows.

Edgar Reynaldo
Member #8,592
May 2007
avatar

That doesn't work on Windows with Direct3D. D3D stretches the contents of the context onto the screen during a resize, which means it depends on whatever you were displaying when the resize started. You don't get a resize event until WM_EXITSIZEMOVE is triggered, so you can't acknowledge it and redraw in the interim. That's why I suggested the background brush, or monitoring WM_ENTERSIZEMOVE and WM_SIZING yourself.

EDIT

bool al_win_add_window_callback(ALLEGRO_DISPLAY *display,
   bool (*callback)(ALLEGRO_DISPLAY *display, UINT message, WPARAM wparam,
   LPARAM lparam, LRESULT *result, void *userdata), void *userdata)

bool WinProcCallback(ALLEGRO_DISPLAY* d , UINT msg , WPARAM wparam , LPARAM lparam ,
                     LRESULT* result , void* userdata) {
   if (msg == WM_SIZING) {
      RECT r = *lparam;
      int w = r.right - r.left;
      int h = r.bottom - r.top;
      al_resize_display(d , w , h);
      return true;
   }
   return false;
}

HWND hwnd = al_get_win_window_handle(display);
al_win_add_window_callback(display , WinProcCallback , 0);

You still have to acknowledge resize events, but this way the window should resize each time it gets a WM_SIZING event. Untested. It might enter an endless loop.

Eric Johnson
Member #14,841
January 2013
avatar

That doesn't work on Windows with Direct3D.

Ah, gotcha. Is it possible to tell Allegro 5 to use OpenGL on Windows though?

Edgar Reynaldo
Member #8,592
May 2007
avatar

Eric Johnson
Member #14,841
January 2013
avatar

Fantastic, thanks.

Why not force the use of OpenGL then on Windows and use code similar to what I posted to achieve xsquid's desired outcome? That would work, wouldn't it?

[EDIT]
Seems to work on Windows 10.

Edgar Reynaldo
Member #8,592
May 2007
avatar

xsquid
Member #16,498
July 2016

Why not force the use of OpenGL then on Windows and use code similar to what I posted to achieve xsquid's desired outcome? That would work, wouldn't it?

Yes! As you mentioned, it does seem to work if the ALLEGRO_OPENGL flag is set, because a nice stream of ALLEGRO_EVENT_DISPLAY_RESIZE events is generated. But then you encounter the problem that (I think) Edgar Reynaldo is describing. If you resize the display quickly, it looks jittery (look at the bottom; the main grey rectangle should be filling the display vertically):

{"name":"jOt7ysWqT.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/3\/a31cdfe9b949195cd1f18c186bbdb426.png","w":813,"h":490,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/3\/a31cdfe9b949195cd1f18c186bbdb426"}jOt7ysWqT.png

Here's the code used in the program in the screenshot:

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_image.h> 3#include <allegro5/allegro_primitives.h> 4#include <algorithm> 5 6void draw_rect(ALLEGRO_DISPLAY* disp) { 7 8 float w = (std::min)(al_get_display_width(disp), al_get_display_height(disp)); 9 float x = al_get_display_width(disp) / 2.0f - w / 2.0f; 10 float y = al_get_display_height(disp) / 2.0f - w / 2.0f; 11 al_draw_filled_rectangle(x, y, x + w, y + w, al_map_rgb(192, 192, 192)); 12 13} 14 15int main() { 16 17 al_init(); 18 al_init_primitives_addon(); 19 al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_RESIZABLE); 20 ALLEGRO_DISPLAY *display = al_create_display(640, 480); 21 22 while (1) { 23 al_acknowledge_resize(display); 24 al_clear_to_color(al_map_rgb(0, 0, 0)); 25 draw_rect(display); 26 al_flip_display(); 27 } 28 29}

I haven't tested it, but I think Edgar's brush method would solve this for simply filling the display with black. But, since that was an example situation, I'm looking for something a bit more versatile as well. There are many programs/games that can resize without the ugly jitter-- Is there something I did wrong with my code above that causes it? I tried the same concept using an event queue, but it didn't fix it.

Edgar Reynaldo
Member #8,592
May 2007
avatar

xsquid
Member #16,498
July 2016

That should be y + h there where it says y + w.

It's supposed to be a square, where "w", while perhaps misleadingly named, is the smaller of the width/height. I'm trying to keep the aspect ratio. It should fill the display vertically, and it does, the issue now is simply that when you resize quickly there's some lag/jitter and some ugly lines before it's finally drawn properly. In other words, it's not smooth.

The screenshot is one of the "between frames" which I'm trying to find a way to avoid as much as possible. A lot of applications resize smoothly, but Allegro displays on Windows don't seem to. I'd like for it to be redrawn immediately after the resize occurs, but it's as if it's lagging behind a little bit.

For comparison, when using Direct3D, while I didn't want the stretching, the stretching itself was very smooth. I'm trying to accomplish that degree of smooth redrawing but with control over what exactly is drawn...

Edgar Reynaldo
Member #8,592
May 2007
avatar

Try acknowledging WM_SIZING messages in a window callback process. If the w or h is different, call al_resize_display. If they are the same, stop.

Use

int oldh = al_get_display_height(display);
int oldw = al_get_display_width(display);
if (msg == WM_SIZING) {
   Rect r = *lparam;
   if (oldh != r.bottom - r.top || oldw != r.right - r.left) {
      al_resize_display(display , r.right - r.left , r.bottom - r.top);
   }
}

xsquid
Member #16,498
July 2016

Okay, I have this now:

#SelectExpand
1 2void draw_rect(ALLEGRO_DISPLAY* disp) { 3 4 float w = (std::min)(al_get_display_width(disp), al_get_display_height(disp)); 5 float x = al_get_display_width(disp) / 2.0f - w / 2.0f; 6 float y = al_get_display_height(disp) / 2.0f - w / 2.0f; 7 al_draw_filled_rectangle(x, y, x + w, y + w, al_map_rgb(192, 192, 192)); 8 9} 10 11bool WinProcCallback(ALLEGRO_DISPLAY* d, UINT msg, WPARAM wparam, LPARAM lparam, LRESULT* result, void* userdata) { 12 13 int oldh = al_get_display_height(d); 14 int oldw = al_get_display_width(d); 15 if (msg == WM_SIZING) { 16 RECT r = *(RECT*)lparam; 17 if (oldh != r.bottom - r.top || oldw != r.right - r.left) { 18 al_resize_display(d, r.right - r.left, r.bottom - r.top); 19 return true; 20 } 21 } 22 23 return false; 24 25} 26 27int main() { 28 29 al_init(); 30 al_init_primitives_addon(); 31 32 al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_RESIZABLE); 33 ALLEGRO_DISPLAY *display = al_create_display(640, 480); 34 35 HWND hwnd = al_get_win_window_handle(display); 36 al_win_add_window_callback(display, WinProcCallback, 0); 37 38 while (1) { 39 al_acknowledge_resize(display); 40 al_clear_to_color(al_map_rgb(0, 0, 0)); 41 draw_rect(display); 42 al_flip_display(); 43 } 44 45 return 0; 46 47}

... But it crashes on resize with a read access violation. The crash occurs when al_resize_display is called; it doesn't occur when it's commented out.

Edit: For the record, here's a comparison video of what it looks like (the last example, since this example throws an error) vs what I'd like to achieve: https://my.mixtape.moe/rdxqwg.webm

Edgar Reynaldo
Member #8,592
May 2007
avatar

 1   2 


Go to: