From ce9a9c3c0d85f97a0281c6d4368fa844eb893d8f Mon Sep 17 00:00:00 2001 From: klemek Date: Sat, 8 Nov 2025 12:10:21 +0100 Subject: [PATCH] feat: iBeats --- default/forge_project.cfg | 3 +++ default/frag0.glsl | 21 +++++++++++---------- src/forge.c | 1 + src/shaders.c | 8 +++++++- src/tempo.c | 10 ++++++---- src/tempo.h | 2 ++ src/types.h | 2 ++ 7 files changed, 32 insertions(+), 15 deletions(-) diff --git a/default/forge_project.cfg b/default/forge_project.cfg index 981f630..c8ee1bf 100644 --- a/default/forge_project.cfg +++ b/default/forge_project.cfg @@ -24,6 +24,8 @@ UNIFORM_TIME=iTime # Current tempo UNIFORM_TEMPO=iTempo +# Current total beats +UNIFORM_BEATS=iBeats # --- uniform int --- @@ -103,6 +105,7 @@ IN_2_OUT=2 # Fragment shaders will be read from the CLI directory as "fragX.glsl" # Special shader "frag0.glsl" will be prepend to each one +# Prefix of fragment shaders to detect FRAG_FILE_PREFIX=frag # Total number of fragment shaders (excluding frag0.glsl) diff --git a/default/frag0.glsl b/default/frag0.glsl index 9c127f2..a8be55e 100644 --- a/default/frag0.glsl +++ b/default/frag0.glsl @@ -8,6 +8,7 @@ uniform float iTime; uniform float iTempo; +uniform float iBeats; uniform int iFPS; uniform vec2 iResolution; uniform vec2 iTexResolution; @@ -150,7 +151,7 @@ float mean(vec4 v) // TIME float randTime(float seed){ - return rand(seed + mod(floor(iTime * iTempo / 240), 1000)); + return rand(seed + floor(iBeats / 4)); } float divider(float x) @@ -166,7 +167,7 @@ float divider(float x) float modTime(float k, float k2) { - return mod(divider(k) * iTime * iTempo * k2 / 240, 1); + return mod(divider(k) * iBeats * k2 / 4, 1); } float modTime(float k) @@ -309,8 +310,8 @@ float v_index(vec2 uv) { } vec2 v_pos(float i) { - int iTimeId = int(iTime * iTempo / 60); - float iTimeV = iTime * iTempo / 60 - iTimeId; + int iTimeId = int(iBeats); + float iTimeV = iBeats - iTimeId; float x0 = rand(i + 823 + iTimeId); float y0 = rand(i + 328 + iTimeId); @@ -942,7 +943,7 @@ subroutine(src_stage_sub) vec4 src_2(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 vec2 uv2 = uv1; uv2.y *= cos(uv2.x * 5 * distort); - uv2 *= rot(rotation + iTime * iTempo / 960); + uv2 *= rot(rotation + iBeats / 16); float k = thickness * 2; uv2.y = cmod(uv2.y, k * 2 + 0.1); float f = step(uv2.y, k * 0.125 + 0.05) * step(-uv2.y, k * 0.125 + 0.01); @@ -971,7 +972,7 @@ subroutine(src_stage_sub) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 float k1 = lens_v * 5; uv2 = lens(uv2, -k1, k1); uv2 = kal(uv2, 5); - uv2 *= rot(rotation + iTime * iTempo / 960); + uv2 *= rot(rotation + iBeats / 16); float k = zoom * 0.1 + 0.05; uv2 = cmod(uv2, k * 2); float f = step(length(uv2), k / (1 + length(uv1) * 2)); @@ -1002,7 +1003,7 @@ subroutine(src_stage_sub) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 uv2 = vec2((uv2.x + 1) * 0.5, -uv2.y); float m1 = spacing * 4.5 + 0.5; float y = log(-uv2.y) * m1; - y = mod(y + scroll * 5.0 - iTime * iTempo / 960, 5.); + y = mod(y + scroll * 5.0 - iBeats / 16, 5.); float id = floor(y) * 32; float s = cos(uv2.x * rand(id + 837) * 100 + rand(id + 281) * PI) + cos(uv2.x * rand(id + 231) * 100 + rand(id + 526) * PI) @@ -1042,7 +1043,7 @@ subroutine(src_stage_sub) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 vec2 uv2 = uv1; uv2 *= zoom * 20 + 3; - uv2.x += iTime * iTempo / 60; + uv2.x += iBeats; vec4 data = voronoi(uv2, voronoi_distort); float f = data.x / (data.x + data.y); f = sin(f * PI * (details * 20)) * 0.5 + 1; @@ -1078,7 +1079,7 @@ subroutine(src_stage_sub) vec4 src_7(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 vec2 uv2 = uv1; uv2 *= zoom * 20 + 3; - uv2 += iTime * iTempo / 60; + uv2 += iBeats; uv2 = mod(uv2, 100) + 100; int start_char = charset_ctrl.x > 0 ? charsets[int(charset.x * CHARSETS) * 2] : 0x01; int char_span = int((charset_ctrl.x > 0 ? charsets[int(charset.x * CHARSETS) * 2 + 1] : 255)); @@ -1372,7 +1373,7 @@ subroutine(src_stage_sub) vec4 src_15(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 x = 0; f += write_5(uv3, vec2(x,13), texts[1]); f += write_int(uv3, vec2(x - 3.5,13), int(iTempo), 3); - v = modTime(1); + v = fract(iBeats); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); diff --git a/src/forge.c b/src/forge.c index 4ee14a5..160a574 100644 --- a/src/forge.c +++ b/src/forge.c @@ -214,6 +214,7 @@ static void loop(bool hr, bool trace_fps) { compute_fps(trace_fps); context->time = window_get_time(); + context->tempo_total = (float)tempo_total(context->tempo); if (window_output != NULL) { window_use(window_output, context); diff --git a/src/shaders.c b/src/shaders.c index f0283a9..de60551 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -3,12 +3,14 @@ #include #include +#include "types.h" + #include "arr.h" #include "config.h" #include "config_file.h" #include "constants.h" #include "shaders.h" -#include "types.h" +#include "tempo.h" #define GLAD_GL_IMPLEMENTATION #include @@ -252,6 +254,9 @@ static void init_single_program(ShaderProgram *program, unsigned int i, program->itempo_locations[i] = glGetUniformLocation( program->programs[i], config_file_get_str(config, "UNIFORM_TEMPO", "iTempo")); + program->ibeats_locations[i] = glGetUniformLocation( + program->programs[i], + config_file_get_str(config, "UNIFORM_BEATS", "iBeats")); program->ifps_locations[i] = glGetUniformLocation( program->programs[i], config_file_get_str(config, "UNIFORM_FPS", "iFPS")); program->ires_locations[i] = glGetUniformLocation( @@ -507,6 +512,7 @@ static void use_program(ShaderProgram program, int i, bool output, // set fragment uniforms write_uniform_1f(program.itime_locations[i], context->time); write_uniform_1f(program.itempo_locations[i], context->tempo.tempo); + write_uniform_1f(program.ibeats_locations[i], context->tempo_total); write_uniform_1i(program.ifps_locations[i], context->fps); write_uniform_1i(program.idemo_locations[i], context->demo ? 1 : 0); write_uniform_1i(program.ipage_locations[i], context->page); diff --git a/src/tempo.c b/src/tempo.c index 64af55d..dcbbd18 100644 --- a/src/tempo.c +++ b/src/tempo.c @@ -3,7 +3,6 @@ #include #include "config.h" -#include "log.h" #include "tempo.h" static long now() { @@ -112,11 +111,14 @@ void tempo_tap(Tempo *tempo) { add_tap_to_chain(tempo, t); } -double tempo_progress(Tempo tempo, double modulo) { +double tempo_total(Tempo tempo) { long t; t = now(); - return fmod((double)(t - tempo.last_reset) / (double)tempo.beat_length, - modulo); + return (double)(t - tempo.last_reset) / (double)tempo.beat_length; +} + +double tempo_progress(Tempo tempo, double modulo) { + return fmod(tempo_total(tempo), modulo); } \ No newline at end of file diff --git a/src/tempo.h b/src/tempo.h index cc73551..3482cf8 100644 --- a/src/tempo.h +++ b/src/tempo.h @@ -9,6 +9,8 @@ void tempo_tap(Tempo *tempo); void tempo_set(Tempo *tempo, float value); +double tempo_total(Tempo tempo); + double tempo_progress(Tempo tempo, double modulo); #endif /* TEMPO_H */ \ No newline at end of file diff --git a/src/types.h b/src/types.h index 985247d..c7b3e94 100644 --- a/src/types.h +++ b/src/types.h @@ -88,6 +88,7 @@ typedef struct ShaderProgram { GLuint itime_locations[ARRAY_SIZE]; GLuint itempo_locations[ARRAY_SIZE]; + GLuint ibeats_locations[ARRAY_SIZE]; GLuint ifps_locations[ARRAY_SIZE]; GLuint ires_locations[ARRAY_SIZE]; GLuint itexres_locations[ARRAY_SIZE]; @@ -157,6 +158,7 @@ typedef struct SharedContext { double time; unsigned int fps; Tempo tempo; + double tempo_total; UintArray state; unsigned int page; unsigned int selected;