Last active
October 30, 2024 23:23
-
-
Save thacuber2a03/0e9868c2f520064e2b56c9f513d8026b to your computer and use it in GitHub Desktop.
a header-only tweening library for C compatible with C89
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef EASEL_H | |
#define EASEL_H | |
/* | |
** easel.h -- a tweening library compatible with ANSI/C89 | |
** by @thacuber2a03, public domain, or CC0 where unapplicable | |
** release 30-10-2024 (dd-mm-yyyy) | |
*/ | |
#include <string.h> | |
#define EASEL_VERSION "0.1.0" | |
#ifdef EASEL_STATIC | |
#define EASEL_IMPLEMENTATION | |
#endif | |
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L | |
#define ESL_INLINE__ inline | |
#else | |
#define ESL_INLINE__ | |
#endif | |
#ifdef EASEL_STATIC | |
#define ESLAPI static ESL_INLINE__ | |
#else | |
#define ESLAPI extern ESL_INLINE__ | |
#endif | |
/*********************************************************************************/ | |
#define esl_util_lerp(a, b, t) ((a) + ((b) - (a)) * (t)) | |
#define esl_util_min(a, b) ((a) < (b) ? (a) : (b)) | |
#define esl_util_max(a, b) ((a) > (b) ? (a) : (b)) | |
#define esl_util_clamp(v, a, b) (esl_util_max(a, esl_util_min(v, b))) | |
/*********************************************************************************/ | |
typedef float esl_real; | |
typedef esl_real (*esl_ease_func)(esl_real t); | |
typedef struct { | |
esl_real progress; | |
esl_ease_func ease; | |
int finished; | |
} esl_tween_base; | |
#define esl_tween_t(T) \ | |
struct { \ | |
esl_tween_base base; \ | |
T start, end, *value; \ | |
void (*tween)(T *v, T *a, T *b, esl_real t); \ | |
} | |
typedef void (*esl_typeerased_tween__)(void* v, void* a, void* b, esl_real t); | |
#define esl_unpack_tween__(t) \ | |
&(t)->base, &(t)->start, &(t)->end, (t)->value, (esl_typeerased_tween__)((t)->tween) | |
#define esl_supported_prims__(X) \ | |
X(double) X(float) X(long long) X(long) X(int) X(short) X(char) | |
#define esl_init(t) (memset(t, 0, sizeof *(t))) | |
#define esl_ease(t) ((t)->base.ease) | |
#define esl_progress(t) ((t)->base.progress) | |
#define esl_finished(t) ((t)->base.finished) | |
/*********************************************************************************/ | |
#define esl_register_prim__(T) \ | |
typedef esl_tween_t(T) esl_##T##_tween_t; \ | |
ESLAPI void esl_##T##_tween_func(T *v, T* a, T* b, esl_real t); \ | |
ESLAPI esl_##T##_tween_t esl_##T##_tween(T *value); | |
esl_supported_prims__(esl_register_prim__) | |
#undef esl_register_prim__ | |
/*********************************************************************************/ | |
#define esl_register_simple_ease__(n, e) ESLAPI esl_real esl_ease_##n(esl_real t) { return e; } | |
esl_register_simple_ease__(linear, t ) | |
esl_register_simple_ease__(inQuad, t*t ) | |
esl_register_simple_ease__(outQuad, 2*t - t*t ) | |
esl_register_simple_ease__(inOutQuad, t*t*(3-2*t) ) | |
#define esl_ease_smoothstep esl_ease_inOutQuad | |
esl_register_simple_ease__(inCubic, t*t*t ) | |
esl_register_simple_ease__(outCubic, t*(t*(t-3)+3)) | |
#undef esl_register_simple_ease__ | |
/*********************************************************************************/ | |
#define esl_func_params__ esl_tween_base* t, void *start, void *end, void *value, esl_typeerased_tween__ tween | |
#define esl_update(t, dt) (esl_set_(esl_unpack_tween__(t), (t)->base.progress + (dt))) | |
#define esl_set(t, time) (esl_set_(esl_unpack_tween__(t), time)) | |
ESLAPI void esl_set_(esl_func_params__, esl_real time); | |
#endif | |
#ifdef EASEL_IMPLEMENTATION | |
#define esl_define_prim__(T) \ | |
ESLAPI void esl_##T##_tween_func(T *v, T* a, T* b, esl_real t) { \ | |
*v = esl_util_lerp(*a, *b, t); \ | |
} \ | |
\ | |
ESLAPI esl_##T##_tween_t esl_##T##_tween(T *value) { \ | |
esl_##T##_tween_t t; \ | |
esl_init(&t); \ | |
t.value = value; \ | |
t.tween = esl_##T##_tween_func; \ | |
return t; \ | |
} | |
esl_supported_prims__(esl_define_prim__) | |
#undef esl_define_prim__ | |
ESLAPI void esl_set_(esl_func_params__, esl_real time) | |
{ | |
t->progress = esl_util_clamp(time, 0, 1); | |
if (t->progress == 1) t->finished = 1; | |
tween(value, start, end, t->ease(t->progress)); | |
} | |
#endif | |
#undef esl_supported_prims__ | |
#undef esl_func_params__ | |
#undef ESL_INLINE__ | |
#undef ESLAPI |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
usage
include this file somewhere in your project.
define
EASEL_IMPLEMENTATION
before including it to place the function implementations in that file.define
EASEL_STATIC
to implement all the functions statically in the current file.api
esl_tween_t(T)
the macro for tween types.
there are 5 predefined versions of this macro, for
double
,float
,long long
,long
,int
,short
andchar
, respectively.each definition also comes with a function,
esl_T_tween
, and an easing typedef,esl_T_tween_func
,where
T
stands for one of the types listed above.esl_update(t, dt)
step tween
t
bydt
.esl_set(t, progress)
set the
progress
of a tweent
.progress
must be a number from 0 to 1.esl_real
the value standing for a real number type in the library.
esl_ease_func
the typedef for an easing function.
esl_tween_base
the base struct all tweening structs extend.
esl_ease
,esl_progress
andesl_finished
are shorthands for accessing each of the properties in this struct for individual tweens.esl_ease_F(esl_real t)
predefined easing formulas for some common eases.
F can be one of:
linear
inQuad
outQuad
inOutQuad
smoothstep
(alias forinOutQuad
)inCubic
outCubic
EASEL_VERSION
the current version of the library, as a semver string.
utility macros
esl_util_lerp(a, b, t)
esl_util_min(a, b)
esl_util_max(a, b)
esl_util_clamp(v, a, b)