I have started to work with SDL2 and am not experienced with it. I am working on a Mac system. Almost everything has been good, but I have a problem that when a resizeable window is resized, while the handle is being dragged, the window turns black, and I can only repaint it after releasing. And I have checked that while the window is being resized, no event is being produced and I have no means to interfere or detect this, as the event loop is just paused. Is there any possible solutions?
Here is the code (Almost replica of a tutorial on handling resize event):
SDL_Event event;
SDL_Rect nativeSize;
SDL_Rect newWindowSize;
float scaleRatioW;//This is to change anything that might rely on something like mouse coords
float scaleRatioH; //(such as a button on screen) over to the new coordinate system scaling would create
SDL_Window * window; //Our beautiful window
SDL_Renderer * renderer; //The renderer for our window
SDL_Texture * backBuffer; //The back buffer that we will be rendering everything to before scaling up
SDL_Texture * ballImage; //A nice picture to demonstrate the scaling;
bool resize;
void InitValues(); //Initialize all the variables needed
void InitSDL(); //Initialize the window, renderer, backBuffer, and image;
bool HandleEvents(); //Handle the window changed size event
void Render(); //Switches the render target back to the window and renders the back buffer, then switches back.
void Resize(); //The important part for stretching. Changes the viewPort, changes the scale ratios
void InitValues()
{
nativeSize.x = 0;
nativeSize.y = 0;
nativeSize.w = 256;
nativeSize.h = 224; //A GameBoy size window width and height
scaleRatioW = 1.0f;
scaleRatioH = 1.0f;
newWindowSize.x = 0;
newWindowSize.y = 0;
newWindowSize.w = nativeSize.w;
newWindowSize.h = nativeSize.h;
window = NULL;
renderer = NULL;
backBuffer = NULL;
ballImage = NULL;
resize = false;
}
void InitSDL()
{
if(SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
//cout << "Failed to initialize SDL" << endl;
printf("%d\r\n", __LINE__);
}
//Set the scaling quality to nearest-pixel
if(SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0") < 0)
{
//cout << "Failed to set Render Scale Quality" << endl;
printf("%d\r\n", __LINE__);
}
//Window needs to be resizable
window = SDL_CreateWindow("Rescaling Windows!",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
256,
224,
SDL_WINDOW_RESIZABLE);
//You must use the SDL_RENDERER_TARGETTEXTURE flag in order to target the backbuffer
renderer = SDL_CreateRenderer(window,
-1,
SDL_RENDERER_ACCELERATED |
SDL_RENDERER_TARGETTEXTURE);
//Set to blue so it's noticeable if it doesn't do right.
SDL_SetRenderDrawColor(renderer, 0, 0, 200, 255);
//Similarly, you must use SDL_TEXTUREACCESS_TARGET when you create the texture
backBuffer = SDL_CreateTexture(renderer,
SDL_GetWindowPixelFormat(window),
SDL_TEXTUREACCESS_TARGET,
nativeSize.w,
nativeSize.h);
//IMPORTANT Set the back buffer as the target
SDL_SetRenderTarget(renderer, backBuffer);
//Load an image yay
SDL_Surface * image = SDL_LoadBMP("Ball.bmp");
ballImage = SDL_CreateTextureFromSurface(renderer, image);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
SDL_FreeSurface(image);
}
bool HandleEvents()
{
while(SDL_PollEvent(&event) )
{
printf("%d\r\n", __LINE__);
if(event.type == SDL_QUIT)
{
printf("%d\r\n", __LINE__);
return true;
}
else if(event.type == SDL_WINDOWEVENT)
{
if(event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
resize = true;
printf("%d\r\n", __LINE__);
}
}
return false;
}
return false;
}
void Render()
{
SDL_RenderCopy(renderer, ballImage, NULL, NULL); //Render the entire ballImage to the backBuffer at (0, 0)
printf("%d\r\n", __LINE__);
SDL_SetRenderTarget(renderer, NULL); //Set the target back to the window
if(resize)
{
Resize();
resize = false;
}
printf("%d\r\n", __LINE__);
SDL_RenderCopy(renderer, backBuffer, &nativeSize, &newWindowSize); //Render the backBuffer onto the screen at (0,0)
SDL_RenderPresent(renderer);
SDL_RenderClear(renderer); //Clear the window buffer
SDL_SetRenderTarget(renderer, backBuffer); //Set the target back to the back buffer
SDL_RenderClear(renderer); //Clear the back buffer
printf("%d\r\n", __LINE__);
}
void Resize()
{
int w, h;
printf("%d\r\n", __LINE__);
SDL_GetWindowSize(window, &w, &h);
scaleRatioW = w / nativeSize.w;
scaleRatioH = h / nativeSize.h; //The ratio from the native size to the new size
newWindowSize.w = w;
newWindowSize.h = h;
//In order to do a resize, you must destroy the back buffer. Try without it, it doesn't work
SDL_DestroyTexture(backBuffer);
backBuffer = SDL_CreateTexture(renderer,
SDL_GetWindowPixelFormat(window),
SDL_TEXTUREACCESS_TARGET, //Again, must be created using this
nativeSize.w,
nativeSize.h);
SDL_Rect viewPort;
SDL_RenderGetViewport(renderer, &viewPort);
if(viewPort.w != newWindowSize.w || viewPort.h != newWindowSize.h)
{
//VERY IMPORTANT - Change the viewport over to the new size. It doesn't do this for you.
SDL_RenderSetViewport(renderer, &newWindowSize);
}
}
int main(int argc, char * argv[])
{
InitValues();
InitSDL();
bool quit = false;
printf("%d\r\n", __LINE__);
while(!quit)
{
printf("%d\r\n", __LINE__);
quit = HandleEvents();
Render();
}
return 0;
}
Ok, after fighting a bit with SDL2, I got it working with macOS 10.12.
Here is the problem:
SDL_PollEvent(&event)
for example.SDL_PollEvent
is blocking.Here is the workaround:
Luckily, you can hook into the event handler using SDL_SetEventFilter
. This will fire every time a event is being received. So for all resize events as they occur.
So what you can do is to register your own event filter callback that basically allows every event (by returning 1
), listens on resize events, and sends them to your draw loop.
Example:
//register this somewhere
int filterEvent(void *userdata, SDL_Event * event) {
if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED) {
//convert userdata pointer to yours and trigger your own draw function
//this is called very often now
//IMPORTANT: Might be called from a different thread, see SDL_SetEventFilter docs
((MyApplicationClass *)userdata)->myDrawFunction();
//return 0 if you don't want to handle this event twice
return 0;
}
//important to allow all events, or your SDL_PollEvent doesn't get any event
return 1;
}
///after SDL_Init
SDL_SetEventFilter(filterEvent, this) //this is instance of MyApplicationClass for example
Important: Do not call SDL_PollEvent
within your filterEvent
callback, as this will result in weird behaviour of stuck events. (resize will not stop sometimes for example)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With