feat: generate demo gifs for all languages
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
**/raylib_*
|
**/raylib_*
|
||||||
|
demo_gen
|
||||||
|
|||||||
12
Makefile
Normal file
12
Makefile
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# used to generate the demos for all languages
|
||||||
|
|
||||||
|
demo_gen: _tools/demo_gen.c
|
||||||
|
gcc -Wall -Wextra -pedantic -I./_raylib-5.5_linux_amd64/include $^ -o $@ -L./_raylib-5.5_linux_amd64/lib -l:libraylib.a -lm
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run: demo_gen
|
||||||
|
./demo_gen
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f ./**/raylib* ./demo_gen
|
||||||
149
_tools/demo_gen.c
Normal file
149
_tools/demo_gen.c
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#include <raylib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <glob.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#define WINDOW_WIDTH 800
|
||||||
|
#define WINDOW_HEIGHT 600
|
||||||
|
#define LOGO_HEIGHT 64
|
||||||
|
#define LOGO_SPEED 300.0f
|
||||||
|
#define GIF_FPS 20
|
||||||
|
|
||||||
|
static unsigned int hash_str(const char *s) {
|
||||||
|
unsigned int h = 5381;
|
||||||
|
while (*s) h = h * 33 ^ (unsigned char)*s++;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generate_gif(const char *output_gif, const char **logo_paths, int logo_count, float switch_secs, int duration_secs) {
|
||||||
|
if (FileExists(output_gif)) {
|
||||||
|
TraceLog(LOG_INFO, "Skipping %s (already exists)", output_gif);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceLog(LOG_INFO, "Generating %s...", output_gif);
|
||||||
|
|
||||||
|
char tmpdir[] = "/tmp/demo_gen_XXXXXX";
|
||||||
|
if (!mkdtemp(tmpdir)) {
|
||||||
|
perror("mkdtemp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D *textures = (Texture2D *)malloc(logo_count * sizeof(Texture2D));
|
||||||
|
for (int i = 0; i < logo_count; i++) {
|
||||||
|
Image img = LoadImage(logo_paths[i]);
|
||||||
|
ImageResize(&img, img.width * LOGO_HEIGHT / img.height, LOGO_HEIGHT);
|
||||||
|
textures[i] = LoadTextureFromImage(img);
|
||||||
|
UnloadImage(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTexture2D target = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||||
|
|
||||||
|
SetRandomSeed(hash_str(output_gif));
|
||||||
|
|
||||||
|
int cur_logo = 0;
|
||||||
|
float x = GetRandomValue(0, WINDOW_WIDTH - textures[cur_logo].width);
|
||||||
|
float y = GetRandomValue(0, WINDOW_HEIGHT - textures[cur_logo].height);
|
||||||
|
float vx = LOGO_SPEED * (GetRandomValue(0, 1) ? 1.0f : -1.0f);
|
||||||
|
float vy = LOGO_SPEED * (GetRandomValue(0, 1) ? 1.0f : -1.0f);
|
||||||
|
|
||||||
|
int total_frames = duration_secs * GIF_FPS;
|
||||||
|
float frame_dt = 1.0f / GIF_FPS;
|
||||||
|
float logo_timer = 0.0f;
|
||||||
|
|
||||||
|
for (int f = 0; f < total_frames; f++) {
|
||||||
|
Texture2D tex = textures[cur_logo];
|
||||||
|
|
||||||
|
x += vx * frame_dt;
|
||||||
|
y += vy * frame_dt;
|
||||||
|
|
||||||
|
if (x < 0 || x + tex.width >= WINDOW_WIDTH) {
|
||||||
|
vx *= -1.0f;
|
||||||
|
x += vx * frame_dt;
|
||||||
|
}
|
||||||
|
if (y < 0 || y + tex.height >= WINDOW_HEIGHT) {
|
||||||
|
vy *= -1.0f;
|
||||||
|
y += vy * frame_dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo_timer += frame_dt;
|
||||||
|
if (logo_timer >= switch_secs) {
|
||||||
|
logo_timer = 0.0f;
|
||||||
|
cur_logo = (cur_logo + 1) % logo_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
BeginTextureMode(target);
|
||||||
|
ClearBackground(BLACK);
|
||||||
|
DrawTextureV(tex, (Vector2){x, y}, WHITE);
|
||||||
|
EndTextureMode();
|
||||||
|
|
||||||
|
Image frame_img = LoadImageFromTexture(target.texture);
|
||||||
|
ImageFlipVertical(&frame_img);
|
||||||
|
|
||||||
|
ExportImage(frame_img, TextFormat("%s/frame_%04d.png", tmpdir, f));
|
||||||
|
UnloadImage(frame_img);
|
||||||
|
|
||||||
|
TraceLog(LOG_INFO, " frame %d/%d", f + 1, total_frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnloadRenderTexture(target);
|
||||||
|
for (int i = 0; i < logo_count; i++) UnloadTexture(textures[i]);
|
||||||
|
free(textures);
|
||||||
|
|
||||||
|
if (system(TextFormat(
|
||||||
|
"ffmpeg -y -framerate %d -i '%s/frame_%%04d.png' "
|
||||||
|
"-vf 'fps=%d,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse' "
|
||||||
|
"'%s' 2>/dev/null",
|
||||||
|
GIF_FPS, tmpdir, GIF_FPS, output_gif)) != 0)
|
||||||
|
TraceLog(LOG_ERROR, "ffmpeg failed for %s", output_gif);
|
||||||
|
|
||||||
|
system(TextFormat("rm -rf '%s'", tmpdir));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void extract_dir(const char *logo_path, char *out, int maxlen) {
|
||||||
|
const char *slash = strchr(logo_path, '/');
|
||||||
|
if (slash) {
|
||||||
|
int len = (int)(slash - logo_path);
|
||||||
|
if (len >= maxlen) len = maxlen - 1;
|
||||||
|
strncpy(out, logo_path, len);
|
||||||
|
out[len] = '\0';
|
||||||
|
} else {
|
||||||
|
strncpy(out, logo_path, maxlen - 1);
|
||||||
|
out[maxlen - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
SetConfigFlags(FLAG_WINDOW_HIDDEN);
|
||||||
|
InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "demo_gen");
|
||||||
|
|
||||||
|
glob_t gl;
|
||||||
|
if (glob("*/*_logo.png", 0, NULL, &gl) != 0) {
|
||||||
|
TraceLog(LOG_ERROR, "No logos found. Run from project root.");
|
||||||
|
CloseWindow();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir("docs", 0755);
|
||||||
|
|
||||||
|
// generate docs/demo.gif (cycles all logos)
|
||||||
|
generate_gif("docs/demo.gif", (const char **)gl.gl_pathv, (int)gl.gl_pathc, 1.0f, (int)gl.gl_pathc);
|
||||||
|
|
||||||
|
// generate languages/**/demo.gif
|
||||||
|
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
char dir[256];
|
||||||
|
extract_dir(gl.gl_pathv[i], dir, sizeof(dir));
|
||||||
|
|
||||||
|
const char *path = gl.gl_pathv[i];
|
||||||
|
char* output_path = strdup(TextFormat("%s/demo.gif", dir));
|
||||||
|
generate_gif(output_path, &path, 1, 9999.0f, 4);
|
||||||
|
|
||||||
|
free(output_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseWindow();
|
||||||
|
globfree(&gl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user