I am trying to create a game in C++ using SDL2, and of course I want to check for window resize events... since I have everything SDL-related handled by a Game
class:
bool Game::SetupSDL()
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
std::cout << "SDL initialization failed: " << SDL_GetError() << std::endl;
return false;
}
window = SDL_CreateWindow(
"SDL",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if (window == NULL)
{
std::cout << "SDL window creation failed: " << SDL_GetError() << std::endl;
return false;
}
if (TTF_Init() < 0)
{
return false;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_AddEventWatch(OnResize, window);
return true;
}
Here is how OnResize
is initialized:
int Game::OnResize(void *data, SDL_Event *event)
{
if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED)
{
SetScale();
states[state]->OnResize(*this);
}
return 0;
}
However, when I attempt to compile it I get the following:
error: cannot convert 'Game::OnResize' from type 'int (Game::)(void*, SDL_Event*)' to type 'SDL_EventFilter {aka int (*)(void*, SDL_Event*)}'
SDL_AddEventWatch(this->OnResize, window);
So it appears I´m having complications passing an instance method as an SDL_FilterEvent
... attempts to recast it have resulted in compile or runtime erros, how can I resolve this?
The problem:
In order to register an event callback with SDL_AddEventWatch
,
you need to supply a callback in the form of a function with the type SDL_EventFilter
:
int (*SDL_EventFilter)(void *userdata, SDL_Event *event);
This should be either a free function, or a static method of a class. It cannot be a non-static method because such method requires a Game
instance (the this
pointer) in order to be invoked.
A solution:
In order to use a non-static method as a callback, you can utilize the userdata
parameter to serve as your context.
When you register the event handler, pass this
(i.e. a Game*
) as userdata
together with a static method:
static int Game::OnResizeEventCallback(void *userdata, SDL_Event *event); // see implementation below
// ...
//---------------------------------------vvvvv-
SDL_AddEventWatch(OnResizeEventCallback, this);
Then when you get the callback convert userdata
back to Game*
, and call the non-static method:
static int Game::OnResizeEventCallback(void *userdata, SDL_Event *event)
{
// Retrieve your instance:
Game* pThis = reinterpret_cast<Game*>(userdata);
// Call your non-static method with it:
pThis->OnResize(event);
}