mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-23 10:09:43 +01:00
c8537beac1
Sometimes, there needs to be code that gets ran at the end of the game loop, otherwise rendering issues might occur. Currently, we do this by special-casing each deferred routine (e.g. shouldreturntoeditor), but it would be better if we could generalize this deference instead. Deferred callbacks can be added using the DEFER_CALLBACK macro. It takes in one argument, which is the name of a function, and that function must be a void function that takes in no arguments. Also, due to annoying C++ quirks, void functions taking no arguments cannot be attributes of objects (because they have an implicit `this` parameter), so it's recommended to create each callback separately before using the DEFER_CALLBACK macro.
84 lines
1.9 KiB
C
84 lines
1.9 KiB
C
#include "DeferCallbacks.h"
|
|
|
|
#include <SDL.h>
|
|
|
|
/* Callbacks to be deferred to the end of each sequence of gamestate functions
|
|
* in main. Useful for fixing frame-flicker glitches when doing a state
|
|
* transition in a function that gets executed before the render function.
|
|
*
|
|
* We store a linked list of callbacks, to allow for the possibility of having
|
|
* more than one callback active at a time (otherwise we could easily just
|
|
* have a single pointer here and the header would only be 1 line and an
|
|
* include guard) and to do it without having to allocate memory at runtime.
|
|
*/
|
|
|
|
static struct DEFER_Callback* head = NULL;
|
|
|
|
/* Add a callback. Don't call this directly; use the DEFER_CALLBACK macro. */
|
|
void DEFER_add_callback(struct DEFER_Callback* callback)
|
|
{
|
|
struct DEFER_Callback* node;
|
|
|
|
/* Are we adding the first node? */
|
|
if (head == NULL)
|
|
{
|
|
head = callback;
|
|
return;
|
|
}
|
|
|
|
/* Time to walk the linked list */
|
|
node = head;
|
|
|
|
if (node == callback)
|
|
{
|
|
goto fail;
|
|
}
|
|
|
|
while (node->next != NULL)
|
|
{
|
|
node = node->next;
|
|
|
|
if (node == callback)
|
|
{
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
/* We're at the end */
|
|
node->next = callback;
|
|
|
|
/* Success! */
|
|
return;
|
|
|
|
fail:
|
|
/* Having multiple instances of a callback isn't well-defined
|
|
* and is a bit complicated to reason about */
|
|
SDL_assert(0 && "Duplicate callback added!");
|
|
}
|
|
|
|
/* Call each callback in the list, along with deleting the entire list. */
|
|
void DEFER_execute_callbacks(void)
|
|
{
|
|
struct DEFER_Callback* node = head;
|
|
struct DEFER_Callback* next;
|
|
|
|
head = NULL;
|
|
|
|
if (node == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
next = node->next;
|
|
node->func();
|
|
node->next = NULL;
|
|
|
|
while (next != NULL)
|
|
{
|
|
node = next;
|
|
next = node->next;
|
|
|
|
node->func();
|
|
node->next = NULL;
|
|
}
|
|
}
|