Skip to content

Commit 2c995a8

Browse files
committed
create immediate mode animation for tsoding
1 parent 85e0d37 commit 2c995a8

4 files changed

Lines changed: 311 additions & 0 deletions

File tree

nob.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ int main(int argc, char **argv)
122122
if (!build_plug_c(force, PLUGS_DIR"template/plug.c", BUILD_DIR"libtemplate.so")) return 1;
123123
if (!build_plug_c(force, PLUGS_DIR"squares/plug.c", BUILD_DIR"libsquare.so")) return 1;
124124
if (!build_plug_c(force, PLUGS_DIR"tsoding/plug.c", BUILD_DIR"libtsoding.so")) return 1;
125+
if (!build_plug_c(force, PLUGS_DIR"imtsoding/plug.c", BUILD_DIR"libimtsoding.so")) return 1;
125126
if (!build_plug_c(force, PLUGS_DIR"bezier/plug.c", BUILD_DIR"libbezier.so")) return 1;
126127
if (!build_plug_cxx(force, PLUGS_DIR"cpp/plug.cpp", BUILD_DIR"libcpp.so")) return 1;
127128

plugs/imtsoding/imanim.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
3+
float clipTime(AnimState *a, float duration) {
4+
float timeSinceStart = a->currentTime - a->clipStartTime;
5+
float animT = timeSinceStart / duration;
6+
if(animT < 0) //before the clip requested
7+
animT = 0.f;
8+
if(animT > 1) //after the clip requested
9+
animT = 1.f;
10+
11+
if(a->globEnd < (a->clipStartTime + duration))
12+
a->globEnd = a->clipStartTime + duration;
13+
14+
return animT;
15+
}
16+
float prevClipTime(AnimState *a, float duration) {
17+
float timeSinceStart = a->currentTime - a->deltaTime - a->clipStartTime;
18+
float animT = timeSinceStart / duration;
19+
if(animT < 0) //before the clip requested
20+
animT = 0.f;
21+
if(animT > 1) //after the clip requested
22+
animT = 1.f;
23+
24+
if(a->globEnd < (a->clipStartTime + duration))
25+
a->globEnd = a->clipStartTime + duration;
26+
27+
return animT;
28+
}
29+
30+
void anim_wait(AnimState *a, float duration) {
31+
if(a->globEnd < (a->clipStartTime + duration))
32+
a->globEnd = a->clipStartTime + duration;
33+
a->clipStartTime = a->globEnd;
34+
}
35+
36+
void wait_for_end(AnimState *a){
37+
a->clipStartTime = a->globEnd;
38+
}
39+
40+
void anim_move_scalar(AnimState *anim, float *src, float dst, float duration)
41+
{
42+
float t = clipTime(anim, duration);
43+
if(t<=0.0f) return;
44+
if(t>=1.0f) {
45+
*src = dst; return;
46+
}
47+
*src = Lerp(*src, dst, t);
48+
}
49+
50+
void anim_move_vec2(AnimState *anim, Vector2 *src, Vector2 dst, float duration)
51+
{
52+
float t = clipTime(anim, duration);
53+
if(t<=0.0f) return;
54+
if(t>=1.0f) {
55+
*src = dst; return;
56+
}
57+
*src = Vector2Lerp(*src, dst, t);
58+
}
59+
60+
void anim_move_vec4(AnimState *anim, Vector4 *src, Vector4 dst, float duration)
61+
{
62+
float t = clipTime(anim, duration);
63+
if(t<=0.0f) return;
64+
if(t>=1.0f) {
65+
*src = dst; return;
66+
}
67+
*src = Vector4Lerp(*src, dst, t);
68+
}

plugs/imtsoding/imanim.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <raymath.h>
2+
3+
typedef struct {
4+
float currentTime; // time since start of the animation, increment with deltaTime every frame
5+
float clipStartTime; // where the code is in the animation, only updated by a "wait" operation, reset every frame.
6+
float globEnd; // when the animation ends, updated by clipTime, reset every frame.
7+
float deltaTime;
8+
9+
} AnimState;
10+
11+
/*
12+
* returns a value between [0.0, 1.0] representing at which point
13+
* the current time the animation is in.
14+
* a 0.0 return value represents that the current clip hasn't started yet
15+
* a 1.0 return value represents that the current clip is fully finished
16+
*
17+
* updates the globEnd value used in wait_for_end
18+
*/
19+
float clipTime(AnimState *a, float duration);
20+
21+
/*
22+
* returns a value between [0.0, 1.0] representing at which point
23+
* the time the animation was in last frame.
24+
*
25+
* updates the globEnd value used in wait_for_end
26+
*
27+
* this is useful for sound triggers
28+
*
29+
* if(clipTime(anim, 0.1f) > 0 && prevClipTime(anim, 0.1f) == 0.0)
30+
* p->env.play_sound(p->kick_sound, p->kick_wave);
31+
*/
32+
float prevClipTime(AnimState *a, float duration);
33+
34+
/*
35+
* advances the clipStartTime
36+
*/
37+
void anim_wait(AnimState *a, float duration) ;
38+
void wait_for_end(AnimState *a);
39+
40+
/*
41+
* utilities for interpolating floats using clipTime(anim, duration)
42+
*
43+
* if clipTime would return 0.0f it is a noop
44+
* if clipTime(anim, duration) would return 1.0f does `*src = dst;`
45+
*/
46+
void anim_move_scalar(AnimState *anim, float *src, float dst, float duration);
47+
void anim_move_vec2(AnimState *anim, Vector2 *src, Vector2 dst, float duration);
48+
void anim_move_vec4(AnimState *anim, Vector4 *src, Vector4 dst, float duration);

plugs/imtsoding/plug.c

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#include <raylib.h>
6+
#include <raymath.h>
7+
#include "env.h"
8+
#include "plug.h"
9+
#define NOB_STRIP_PREFIX
10+
#include "nob.h"
11+
#include "imanim.h"
12+
13+
#define PLUG(name, ret, ...) ret name(__VA_ARGS__);
14+
LIST_OF_PLUGS
15+
#undef PLUG
16+
17+
#define FONT_SIZE 68
18+
19+
typedef struct {
20+
size_t size;
21+
Font font;
22+
float radius;
23+
float roundness;
24+
float alpha;
25+
float rotation;
26+
AnimState anim;
27+
Env env;
28+
Sound kick_sound;
29+
Wave kick_wave;
30+
bool finished;
31+
} Plug;
32+
33+
static Plug *p;
34+
35+
static void load_assets(void)
36+
{
37+
p->font = LoadFontEx("./assets/fonts/Vollkorn-Regular.ttf", FONT_SIZE, NULL, 0);
38+
p->kick_wave = LoadWave("./assets/sounds/kick.wav");
39+
p->kick_sound = LoadSoundFromWave(p->kick_wave);
40+
}
41+
42+
static void unload_assets(void)
43+
{
44+
UnloadFont(p->font);
45+
UnloadSound(p->kick_sound);
46+
UnloadWave(p->kick_wave);
47+
}
48+
49+
50+
#define co_tween(anim, duration, ...) co_tween_impl((anim), (duration), __VA_ARGS__, NULL)
51+
52+
53+
void co_tween_impl(AnimState *anim, float duration, ...)
54+
{
55+
va_list args;
56+
va_start(args, duration);
57+
float interp;
58+
float *x = va_arg(args, float*);
59+
while (x != NULL) {
60+
float a = va_arg(args, double);
61+
float b = va_arg(args, double);
62+
anim_move_scalar(anim, x, b, duration);
63+
x = va_arg(args, float*);
64+
}
65+
va_end(args);
66+
wait_for_end(anim);
67+
}
68+
69+
void co_sleep(AnimState *anim, float duration)
70+
{
71+
anim_wait(anim, duration) ;
72+
}
73+
74+
void animation(AnimState *anim, void *data)
75+
{
76+
UNUSED(data);
77+
78+
p->radius = 0;
79+
p->roundness = 0;
80+
p->alpha = 0;
81+
p->rotation = 0;
82+
83+
float duration = 0.15f;
84+
float sleep = 0.25f;
85+
float curr = clipTime(anim, 0.1f);
86+
float prev = prevClipTime(anim, 0.1f);
87+
if(curr > 0 && prev == 0.0)
88+
p->env.play_sound(p->kick_sound, p->kick_wave);
89+
co_tween(anim, duration, &p->radius, 0.f, 1.f);
90+
co_sleep(anim, sleep);
91+
if(clipTime(anim, 0.1f) > 0 && prevClipTime(anim, 0.1f) == 0.0)
92+
p->env.play_sound(p->kick_sound, p->kick_wave);
93+
co_tween(anim, duration, &p->roundness, 0.f, 1.f);
94+
co_sleep(anim, sleep);
95+
if(clipTime(anim, 0.1f) > 0 && prevClipTime(anim, 0.1f) == 0.0)
96+
p->env.play_sound(p->kick_sound, p->kick_wave);
97+
co_tween(anim, duration,
98+
&p->alpha, 0.f, 1.f,
99+
&p->roundness, 1.f, 0.f,
100+
&p->rotation, 0.f, 1.f);
101+
co_sleep(anim, sleep);
102+
if(clipTime(anim, 0.1f) > 0 && prevClipTime(anim, 0.1f) == 0.0)
103+
p->env.play_sound(p->kick_sound, p->kick_wave);
104+
co_tween(anim, duration, &p->radius, 1.f, 0.f);
105+
co_sleep(anim, 2.0);
106+
}
107+
108+
void plug_reset(void)
109+
{
110+
p->anim.currentTime = 0.f;
111+
}
112+
113+
void plug_init(void)
114+
{
115+
p = malloc(sizeof(*p));
116+
assert(p != NULL);
117+
memset(p, 0, sizeof(*p));
118+
p->size = sizeof(*p);
119+
120+
121+
load_assets();
122+
plug_reset();
123+
}
124+
125+
void *plug_pre_reload(void)
126+
{
127+
unload_assets();
128+
return p;
129+
}
130+
131+
void plug_post_reload(void *state)
132+
{
133+
p = state;
134+
if (p->size < sizeof(*p)) {
135+
TraceLog(LOG_INFO, "Migrating plug state schema %zu bytes -> %zu bytes", p->size, sizeof(*p));
136+
p = realloc(p, sizeof(*p));
137+
p->size = sizeof(*p);
138+
}
139+
140+
load_assets();
141+
}
142+
143+
void plug_update(Env env)
144+
{
145+
p->env = env;
146+
147+
p->anim.clipStartTime = 0;
148+
p->anim.globEnd = 0;
149+
p->anim.currentTime += env.delta_time;
150+
p->anim.deltaTime = env.delta_time;
151+
152+
animation(&p->anim, NULL);
153+
154+
p->finished = p->anim.currentTime >= p->anim.clipStartTime;
155+
156+
Color background_color = GetColor(0x181818FF);
157+
Color green_color = GetColor(0x73C936FF);
158+
Color red_color = GetColor(0xF43841FF);
159+
160+
ClearBackground(background_color);
161+
162+
Camera2D camera = {
163+
.zoom = 1.0,
164+
.rotation = 45.*p->rotation,
165+
.offset = {env.screen_width/2, env.screen_height/2},
166+
};
167+
168+
BeginMode2D(camera); {
169+
float size = 300*p->radius;
170+
Rectangle rec = {
171+
.x = -size/2,
172+
.y = -size/2,
173+
.width = size,
174+
.height = size,
175+
};
176+
177+
178+
// // Square
179+
Color color = ColorAlphaBlend(green_color, ColorAlpha(red_color, p->alpha), WHITE);
180+
DrawRectangleRounded(rec, p->roundness, 30, color);
181+
182+
// const char *text = "Tsoding Animation";
183+
// Vector2 text_size = MeasureTextEx(p->font, text, FONT_SIZE, 0);
184+
// Vector2 position = Vector2Scale(text_size, -0.5);
185+
// DrawTextEx(p->font, text, position, FONT_SIZE, 0, foreground_color);
186+
} EndMode2D();
187+
}
188+
189+
bool plug_finished(void)
190+
{
191+
return p->finished;
192+
}
193+
194+
#include "imanim.c"

0 commit comments

Comments
 (0)