Init
This commit is contained in:
commit
33598d2c0a
24
LICENSE
Normal file
24
LICENSE
Normal file
@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
6
Makefile
Normal file
6
Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
example: example.c coro.h
|
||||
$(CC) -o $@ $< `pkg-config --libs --cflags raylib` -lm
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f example
|
106
coro.h
Normal file
106
coro.h
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef _CORO_H_
|
||||
#define _CORO_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// Basic usage example:
|
||||
// Define a specific coroutine struct holding all your variables and return values (variables defined normally within the function will be reset):
|
||||
// typedef struct {
|
||||
// Coro coro;
|
||||
// int x_pos, y_pos;
|
||||
// } ExampleCoro;
|
||||
//
|
||||
// Define a specific coroutine function taking our custom type as a parameter:
|
||||
// void example(ExampleCoro *c)
|
||||
// CORO_BEGIN(&c->coro) // The coroutine initialization simply takes a reference to the core coroutine struct
|
||||
// // Draw the object for a total of 1s
|
||||
// CORO_BEGIN_REPEAT(1.0)
|
||||
// // Rapidly alternate between states A and B displaying each for 0.1s
|
||||
// CORO_BEGIN_REPEAT(0.1)
|
||||
// DrawThingA(c->x_pos, c->y_pos);
|
||||
// CORO_END_REPEAT()
|
||||
// CORO_BEGIN_REPEAT(0.1)
|
||||
// DrawThingB(c->x_pos, c->y_pos);
|
||||
// CORO_END_REPEAT()
|
||||
// CORO_END_REPEAT()
|
||||
// // Print a message
|
||||
// printf("Dying in 1s\n");
|
||||
// CORO_WAIT(1.0)
|
||||
// // Print another message after waiting for 1s
|
||||
// printf("XD\n");
|
||||
// // Done; c->done is now set to true and the coroutine will no longer run any code on subsequent calls
|
||||
// CORO_END()
|
||||
//
|
||||
// Initialization (zero value is ready-to-use):
|
||||
// ExampleCoro coro;
|
||||
// coro = (ExampleCoro){0};
|
||||
//
|
||||
// Each frame:
|
||||
// example(&coro)
|
||||
// coro.time += delta_time;
|
||||
|
||||
#ifndef CORO_MAX_DEPTH
|
||||
#define CORO_MAX_DEPTH 8
|
||||
#endif
|
||||
|
||||
#ifndef CORO_FATAL
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define CORO_FATAL(...) { fprintf(stderr, "[FATAL] Coro: "__VA_ARGS__); abort(); }
|
||||
#endif
|
||||
|
||||
#define CORO_BEGIN(_coro) \
|
||||
{ \
|
||||
Coro *_coro_instance = _coro; \
|
||||
int _coro_goto_line = 0; \
|
||||
if (_coro_instance->done) \
|
||||
return; \
|
||||
if (_coro_instance->stack_size > 0 && !_coro_instance->stack[_coro_instance->stack_size-1].repeat) { \
|
||||
if (_coro_instance->time < _coro_instance->stack[_coro_instance->stack_size-1].timeout) \
|
||||
return; \
|
||||
} \
|
||||
if (_coro_instance->stack_size > 0) \
|
||||
_coro_goto_line = _coro_instance->stack[_coro_instance->stack_size-1].line; \
|
||||
switch (_coro_goto_line) { \
|
||||
case 0:
|
||||
#define CORO_END() \
|
||||
if (_coro_instance->stack_size != 0) { CORO_FATAL("programmer error in %s:%d: CORO_END() called without closing all loops\n", __FILE__, __LINE__); } \
|
||||
_coro_instance->done = true; \
|
||||
}}
|
||||
// Do nothing until the specified amount of time has passed
|
||||
#define CORO_WAIT(_time) \
|
||||
if (_coro_instance->stack_size+1 > CORO_MAX_DEPTH) { CORO_FATAL("programmer error in %s:%d: maximum depth of %d exceeded\n", __FILE__, __LINE__, CORO_MAX_DEPTH); } \
|
||||
_coro_instance->stack_size++; \
|
||||
_coro_instance->stack[_coro_instance->stack_size-1].repeat = false; \
|
||||
_coro_instance->stack[_coro_instance->stack_size-1].timeout = _coro_instance->time + _time; \
|
||||
case __LINE__: _coro_instance->stack[_coro_instance->stack_size-1].line = __LINE__; \
|
||||
if (_coro_instance->time < _coro_instance->stack[_coro_instance->stack_size-1].timeout) \
|
||||
return; \
|
||||
else \
|
||||
_coro_instance->stack_size--;
|
||||
// Repeat a piece of code each frame until the specified amount of time has passed
|
||||
#define CORO_BEGIN_REPEAT(_time) \
|
||||
if (_coro_instance->stack_size+1 > CORO_MAX_DEPTH) { CORO_FATAL("programmer error in %s:%d: maximum depth of %d exceeded\n", __FILE__, __LINE__, CORO_MAX_DEPTH); } \
|
||||
_coro_instance->stack_size++; \
|
||||
_coro_instance->stack[_coro_instance->stack_size-1].repeat = true; \
|
||||
_coro_instance->stack[_coro_instance->stack_size-1].timeout = _coro_instance->time + _time; \
|
||||
case __LINE__: _coro_instance->stack[_coro_instance->stack_size-1].line = __LINE__;
|
||||
#define CORO_END_REPEAT() \
|
||||
if (_coro_instance->stack_size == 0) { CORO_FATAL("programmer error in %s:%d: CORO_END_REPEAT() called without matching CORO_BEGIN_REPEAT()\n", __FILE__, __LINE__); } \
|
||||
if (_coro_instance->time < _coro_instance->stack[_coro_instance->stack_size-1].timeout) \
|
||||
return; \
|
||||
else \
|
||||
_coro_instance->stack_size--;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
unsigned int line; // line to return to for wait/repeat
|
||||
bool repeat; // whether this is a repeat or simply a wait
|
||||
double timeout; // when the repeat/wait is over
|
||||
} stack[CORO_MAX_DEPTH]; // stack for keeping track of waits and repeats
|
||||
unsigned int stack_size;
|
||||
double time; // current time; meaning and unit defined by user
|
||||
bool done; // set to true when coroutine is finished executing
|
||||
} Coro;
|
||||
|
||||
#endif /* !_CORO_H_ */
|
88
example.c
Normal file
88
example.c
Normal file
@ -0,0 +1,88 @@
|
||||
#include <raylib.h>
|
||||
|
||||
#include "coro.h"
|
||||
|
||||
typedef struct {
|
||||
Coro coro;
|
||||
int x_pos, y_pos;
|
||||
bool alive;
|
||||
} DrawCoro;
|
||||
|
||||
static void draw(DrawCoro *c)
|
||||
CORO_BEGIN(&c->coro)
|
||||
CORO_BEGIN_REPEAT(1.0)
|
||||
CORO_BEGIN_REPEAT(0.1)
|
||||
DrawText("Now", c->x_pos, c->y_pos, 20, LIGHTGRAY);
|
||||
CORO_END_REPEAT()
|
||||
CORO_BEGIN_REPEAT(0.1)
|
||||
DrawText("Now", c->x_pos, c->y_pos, 20, BLACK);
|
||||
CORO_END_REPEAT()
|
||||
CORO_END_REPEAT()
|
||||
CORO_BEGIN_REPEAT(1.0)
|
||||
DrawText("1s later", c->x_pos, c->y_pos, 20, LIGHTGRAY);
|
||||
CORO_END_REPEAT()
|
||||
CORO_BEGIN_REPEAT(1.0)
|
||||
DrawText("2s later", c->x_pos, c->y_pos, 20, LIGHTGRAY);
|
||||
CORO_END_REPEAT()
|
||||
CORO_BEGIN_REPEAT(0.5)
|
||||
DrawText("Bye", c->x_pos, c->y_pos, 20, LIGHTGRAY);
|
||||
CORO_END_REPEAT()
|
||||
CORO_END()
|
||||
|
||||
int main(void) {
|
||||
size_t n_coros = 0;
|
||||
DrawCoro coros[64];
|
||||
size_t n_free_coros = 0;
|
||||
size_t free_coros[64];
|
||||
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "Simple coroutine example");
|
||||
|
||||
SetTargetFPS(60);
|
||||
|
||||
while (!WindowShouldClose()) {
|
||||
printf("Coros size: %zu, Free list size: %zu \r", n_coros, n_free_coros);
|
||||
|
||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
|
||||
size_t coro;
|
||||
if (n_free_coros > 0) {
|
||||
coro = free_coros[--n_free_coros];
|
||||
} else {
|
||||
if (n_coros+1 > 64) {
|
||||
fprintf(stderr, "All coroutines in use!\n");
|
||||
abort();
|
||||
}
|
||||
coro = n_coros++;
|
||||
}
|
||||
coros[coro] = (DrawCoro){0};
|
||||
coros[coro].alive = true;
|
||||
coros[coro].x_pos = GetMouseX();
|
||||
coros[coro].y_pos = GetMouseY();
|
||||
}
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(RAYWHITE);
|
||||
for (size_t i = 0; i < n_coros; i++) {
|
||||
if (!coros[i].alive)
|
||||
continue;
|
||||
if (coros[i].coro.done) {
|
||||
coros[i].alive = false;
|
||||
if (n_free_coros+1 > 64) {
|
||||
fprintf(stderr, "Coroutine free list overflow!\n");
|
||||
abort();
|
||||
}
|
||||
free_coros[n_free_coros++] = i;
|
||||
} else {
|
||||
draw(&coros[i]);
|
||||
coros[i].coro.time += GetFrameTime();
|
||||
}
|
||||
}
|
||||
EndDrawing();
|
||||
}
|
||||
|
||||
CloseWindow();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user