Skip to content

Commit aef6390

Browse files
committed
Add the tsoding animation
1 parent a6aba8b commit aef6390

File tree

8 files changed

+378
-6
lines changed

8 files changed

+378
-6
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
build/
22
nob
33
nob.old
4-
*.mp4
5-
*.wav
4+
output.mp4
5+
output.wav
66
*~
77

88
# LaTeX

assets/sounds/kick.wav

28.5 KB
Binary file not shown.

nob.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Procs procs = {0};
1414

1515
void cflags(void)
1616
{
17-
cmd_append(&cmd, "-Wall", "-Wextra", "-ggdb");
17+
cmd_append(&cmd, "-Wall", "-Wextra", "-Wno-missing-field-initializers", "-ggdb");
1818
cmd_append(&cmd, "-I"RAYLIB_DIR"include");
1919
cmd_append(&cmd, "-I"PANIM_DIR);
2020
cmd_append(&cmd, "-I.");
@@ -117,6 +117,7 @@ int main(int argc, char **argv)
117117
if (!build_plug_c(force, PLUGS_DIR"tm/plug.c", BUILD_DIR"libtm.so")) return 1;
118118
if (!build_plug_c(force, PLUGS_DIR"template/plug.c", BUILD_DIR"libtemplate.so")) return 1;
119119
if (!build_plug_c(force, PLUGS_DIR"squares/plug.c", BUILD_DIR"libsquare.so")) return 1;
120+
if (!build_plug_c(force, PLUGS_DIR"tsoding/plug.c", BUILD_DIR"libtsoding.so")) return 1;
120121
if (!build_plug_c(force, PLUGS_DIR"bezier/plug.c", BUILD_DIR"libbezier.so")) return 1;
121122
if (!build_plug_cxx(force, PLUGS_DIR"cpp/plug.cpp", BUILD_DIR"libcpp.so")) return 1;
122123

panim/ffmpeg_linux.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ FFMPEG *ffmpeg_start_rendering_audio(const char *output_path)
118118

119119
"-f", "s16le",
120120
"-sample_rate", "44100",
121-
"-channels", "2",
121+
"-channels", "1",
122122
"-i", "-",
123123

124124
"-c:a", "pcm_s16le",

panim/panim.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#define FFMPEG_VIDEO_FPS 60
2121
#define FFMPEG_VIDEO_DELTA_TIME (1.0f/FFMPEG_VIDEO_FPS)
2222
#define FFMPEG_SOUND_SAMPLE_RATE 44100
23-
#define FFMPEG_SOUND_CHANNELS 2
23+
#define FFMPEG_SOUND_CHANNELS 1
2424
#define FFMPEG_SOUND_SAMPLE_SIZE_BITS 16
2525
#define FFMPEG_SOUND_SAMPLE_SIZE_BYTES (FFMPEG_SOUND_SAMPLE_SIZE_BITS/8)
2626
// SPF - Samples Per Frame
@@ -106,7 +106,8 @@ void ffmpeg_play_sound(Sound _sound, Wave wave)
106106
TraceLog(LOG_ERROR,
107107
"Animation tried to play sound with rate: %dhz, sample size: %d bits, channels: %d. "
108108
"But we only support rate: %dhz, sample size: %d bits, channels: %d for now",
109-
wave.sampleRate, wave.sampleSize, wave.channels);
109+
wave.sampleRate, wave.sampleSize, wave.channels,
110+
FFMPEG_SOUND_SAMPLE_RATE, FFMPEG_SOUND_SAMPLE_SIZE_BITS, FFMPEG_SOUND_CHANNELS);
110111
return;
111112
}
112113

plugs/tsoding/coroutine.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#include <assert.h>
2+
#include <stdio.h>
3+
#include <string.h>
4+
5+
#include <unistd.h>
6+
#include <sys/mman.h>
7+
8+
#include "coroutine.h"
9+
10+
#define COROUTINE_DA_INIT_CAP 256
11+
// Append an item to a dynamic array
12+
#define coroutine_da_append(da, item) \
13+
do { \
14+
if ((da)->count >= (da)->capacity) { \
15+
(da)->capacity = (da)->capacity == 0 ? COROUTINE_DA_INIT_CAP : (da)->capacity*2; \
16+
(da)->items = realloc((da)->items, (da)->capacity*sizeof(*(da)->items)); \
17+
assert((da)->items != NULL && "Buy more RAM lol"); \
18+
} \
19+
\
20+
(da)->items[(da)->count++] = (item); \
21+
} while (0)
22+
#define COROUTINE_UNREACHABLE(message) do { fprintf(stderr, "%s:%d: UNREACHABLE: %s\n", __FILE__, __LINE__, message); abort(); } while(0)
23+
24+
Stack *coroutine_init(void)
25+
{
26+
Stack *stack = malloc(sizeof(*stack));
27+
memset(stack, 0, sizeof(*stack));
28+
29+
Coroutine *c = malloc(sizeof(*c));
30+
memset(c, 0, sizeof(*c));
31+
coroutine_da_append(stack, c);
32+
33+
return stack;
34+
}
35+
36+
void coroutine_deinit(Stack *stack)
37+
{
38+
assert(stack->count == 1);
39+
free(stack->items[0]);
40+
free(stack->items);
41+
free(stack);
42+
}
43+
44+
void __attribute__((naked)) coroutine_restore_context(void *rsp)
45+
{
46+
// @arch
47+
(void)rsp;
48+
asm(
49+
" movq %rdi, %rsp\n"
50+
" popq %r15\n"
51+
" popq %r14\n"
52+
" popq %r13\n"
53+
" popq %r12\n"
54+
" popq %rbx\n"
55+
" popq %rbp\n"
56+
" popq %rsi\n"
57+
" popq %rdi\n"
58+
" ret\n");
59+
}
60+
61+
void coroutine_pop_frame(Stack *stack, void *rsp)
62+
{
63+
assert(stack->count > 0);
64+
stack->items[stack->count - 1]->rsp = rsp;
65+
stack->count -= 1;
66+
assert(stack->count > 0);
67+
coroutine_restore_context(stack->items[stack->count - 1]->rsp);
68+
}
69+
70+
void __attribute__((naked)) coroutine__finish_current(void)
71+
{
72+
register Stack *stack = NULL;
73+
asm("popq %0" : "=r" (stack));
74+
assert(stack->count > 0);
75+
stack->items[stack->count-1]->finished = true;
76+
coroutine_yield(stack);
77+
COROUTINE_UNREACHABLE("Finished coroutine was resumed!!!");
78+
}
79+
80+
Coroutine *coroutine_create(Stack *stack, void (*f)(Stack*, void*), void *arg)
81+
{
82+
Coroutine *c = malloc(sizeof(*c));
83+
memset(c, 0, sizeof(*c));
84+
c->stack_base = mmap(NULL, STACK_CAPACITY, PROT_WRITE|PROT_READ, MAP_PRIVATE|MAP_STACK|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
85+
assert(c->stack_base != MAP_FAILED);
86+
void **rsp = (void**)((char*)c->stack_base + STACK_CAPACITY);
87+
// @arch
88+
*(--rsp) = 0; // pad
89+
*(--rsp) = stack;
90+
*(--rsp) = coroutine__finish_current;
91+
*(--rsp) = f;
92+
*(--rsp) = stack; // push rdi
93+
*(--rsp) = arg; // push rsi
94+
*(--rsp) = 0; // push rbx
95+
*(--rsp) = 0; // push rbp
96+
*(--rsp) = 0; // push r12
97+
*(--rsp) = 0; // push r13
98+
*(--rsp) = 0; // push r14
99+
*(--rsp) = 0; // push r15
100+
c->rsp = rsp;
101+
102+
return c;
103+
}
104+
105+
void coroutine_destroy(Coroutine *c)
106+
{
107+
munmap(c->stack_base, STACK_CAPACITY);
108+
free(c);
109+
}
110+
111+
void __attribute__((naked)) coroutine_resume(Stack *stack, Coroutine *c)
112+
{
113+
(void) stack;
114+
(void) c;
115+
// @arch
116+
asm(
117+
" pushq %rdi\n"
118+
" pushq %rsi\n"
119+
" pushq %rbp\n"
120+
" pushq %rbx\n"
121+
" pushq %r12\n"
122+
" pushq %r13\n"
123+
" pushq %r14\n"
124+
" pushq %r15\n"
125+
" movq %rsp, %rdx\n"
126+
" jmp coroutine_push_frame\n");
127+
}
128+
129+
void coroutine_push_frame(Stack *stack, Coroutine *c, void *rsp)
130+
{
131+
assert(stack->count > 0);
132+
stack->items[stack->count - 1]->rsp = rsp;
133+
134+
coroutine_da_append(stack, c);
135+
coroutine_restore_context(c->rsp);
136+
}
137+
138+
void __attribute__((naked)) coroutine_yield(Stack *stack)
139+
{
140+
(void) stack;
141+
// @arch
142+
asm(
143+
" pushq %rdi\n"
144+
" pushq %rsi\n"
145+
" pushq %rbp\n"
146+
" pushq %rbx\n"
147+
" pushq %r12\n"
148+
" pushq %r13\n"
149+
" pushq %r14\n"
150+
" pushq %r15\n"
151+
" movq %rsp, %rsi\n" // rsp
152+
" jmp coroutine_pop_frame\n");
153+
}

plugs/tsoding/coroutine.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef COROUTINE_PANIM_H_
2+
#define COROUTINE_PANIM_H_
3+
4+
#include <stdlib.h>
5+
#include <stdbool.h>
6+
7+
typedef struct {
8+
void *rsp;
9+
void *stack_base;
10+
bool finished;
11+
} Coroutine;
12+
13+
// TODO: make the STACK_CAPACITY customizable by the user
14+
//#define STACK_CAPACITY (4*1024)
15+
#define STACK_CAPACITY (1024*getpagesize())
16+
17+
typedef struct {
18+
Coroutine **items;
19+
size_t count;
20+
size_t capacity;
21+
} Stack;
22+
23+
Stack *coroutine_init(void);
24+
void coroutine_deinit(Stack *stack);
25+
Coroutine *coroutine_create(Stack *stack, void (*f)(Stack*, void*), void *arg);
26+
void coroutine_destroy(Coroutine *c);
27+
void coroutine_resume(Stack *stack, Coroutine *c);
28+
void coroutine_yield(Stack *stack);
29+
30+
#endif // COROUTINE_PANIM_H_

0 commit comments

Comments
 (0)