Init
This commit is contained in:
		
							
								
								
									
										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;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user