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