mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-22 17:49:43 +01:00
Add deferred callbacks to game loop
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.
This commit is contained in:
parent
c8958de537
commit
c8537beac1
4 changed files with 120 additions and 0 deletions
|
@ -125,6 +125,7 @@ SET(VVV_SRC
|
|||
src/WarpClass.cpp
|
||||
src/XMLUtils.cpp
|
||||
src/main.cpp
|
||||
src/DeferCallbacks.c
|
||||
src/Network.c
|
||||
src/ThirdPartyDeps.c
|
||||
)
|
||||
|
|
84
desktop_version/src/DeferCallbacks.c
Normal file
84
desktop_version/src/DeferCallbacks.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
#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;
|
||||
}
|
||||
}
|
31
desktop_version/src/DeferCallbacks.h
Normal file
31
desktop_version/src/DeferCallbacks.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef DEFERCALLBACKS_H
|
||||
#define DEFERCALLBACKS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct DEFER_Callback
|
||||
{
|
||||
void (*func)(void);
|
||||
struct DEFER_Callback* next;
|
||||
};
|
||||
|
||||
void DEFER_add_callback(struct DEFER_Callback* callback);
|
||||
|
||||
void DEFER_execute_callbacks(void);
|
||||
|
||||
#define DEFER_CALLBACK(FUNC) \
|
||||
do \
|
||||
{ \
|
||||
static struct DEFER_Callback callback = {FUNC, NULL}; \
|
||||
\
|
||||
DEFER_add_callback(&callback); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* DEFERCALLBACKS_H */
|
|
@ -1,6 +1,7 @@
|
|||
#include <SDL.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "DeferCallbacks.h"
|
||||
#include "editor.h"
|
||||
#include "Enums.h"
|
||||
#include "Entity.h"
|
||||
|
@ -226,6 +227,9 @@ static enum IndexCode increment_gamestate_func_index(void)
|
|||
&num_gamestate_funcs
|
||||
);
|
||||
|
||||
/* Also run callbacks that were deferred to end of func sequence. */
|
||||
DEFER_execute_callbacks();
|
||||
|
||||
gamestate_func_index = 0;
|
||||
|
||||
return Index_end;
|
||||
|
|
Loading…
Reference in a new issue