shader_type canvas_item; // Shader per l'insegna centrale UPENDI CIRCUS: // Lucine colorate lungo la cornice del pannello che si accendono in modo rado e casuale // solo dopo che l'insegna ha finito di atterrare e rimbalzare (sign_lights_active = 1.0). uniform float sign_lights_active : hint_range(0.0, 1.0) = 0.0; uniform float blink_speed : hint_range(0.5, 8.0) = 2.2; // 37 posizioni lampadina distribuite lungo il contorno in legno dell'insegna (UV su canvas 880x561) const vec2 sign_bulbs[37] = vec2[37]( // Arco superiore vec2(0.2107, 0.3839), vec2(0.2590, 0.3851), vec2(0.3223, 0.3828), vec2(0.3725, 0.3774), vec2(0.4209, 0.3707), vec2(0.4946, 0.3551), vec2(0.5700, 0.3261), vec2(0.6281, 0.3031), vec2(0.6769, 0.2784), vec2(0.7503, 0.2651), vec2(0.7999, 0.2504), vec2(0.8620, 0.2458), // Bordo destro vec2(0.8565, 0.3564), vec2(0.8585, 0.4328), vec2(0.8579, 0.5043), vec2(0.8628, 0.5807), vec2(0.8640, 0.6594), vec2(0.8703, 0.7179), vec2(0.8680, 0.7879), // Arco inferiore vec2(0.8264, 0.8164), vec2(0.7829, 0.8452), vec2(0.7112, 0.8651), vec2(0.6513, 0.8823), vec2(0.5675, 0.8988), vec2(0.5082, 0.9059), vec2(0.4341, 0.9007), vec2(0.3600, 0.8980), vec2(0.3098, 0.8763), vec2(0.2447, 0.8536), vec2(0.1897, 0.8309), vec2(0.1363, 0.7941), // Bordo sinistro vec2(0.1328, 0.6995), vec2(0.1297, 0.6286), vec2(0.1256, 0.5398), vec2(0.1239, 0.4893), vec2(0.1221, 0.4318), vec2(0.1208, 0.3685) ); // Palette di colori circensi vivaci vec3 get_bulb_color(int idx) { int c = idx % 6; if (c == 0) return vec3(1.0, 0.25, 0.25); // Rosso rubino if (c == 1) return vec3(1.0, 0.84, 0.15); // Giallo oro if (c == 2) return vec3(0.25, 0.88, 0.40); // Verde smeraldo if (c == 3) return vec3(0.25, 0.70, 1.00); // Blu ciano if (c == 4) return vec3(0.95, 0.38, 0.90); // Magenta fucsia return vec3(1.0, 0.55, 0.15); // Arancio caldo } // Generatore pseudo-casuale deterministico per lampadina e tempo float pseudo_rand(float n) { return fract(sin(n) * 43758.5453123); } void fragment() { vec4 color = texture(TEXTURE, UV); if (sign_lights_active > 0.001) { vec2 px = UV * vec2(880.0, 561.0); // Calcolo delle 5 lampadine attive nei 5 settori della cornice // Durate leggermente sfalsate per evitare che si sincronizzino const float durations[5] = float[5](1.3, 1.6, 1.9, 1.5, 2.1); const int ranges_start[5] = int[5](0, 7, 15, 22, 30); const int ranges_count[5] = int[5](7, 8, 7, 8, 7); for (int c = 0; c < 5; c++) { float dur = durations[c] / (blink_speed / 2.2); float step = floor(TIME / dur); float sub_t = fract(TIME / dur); // Campana morbida di accensione (fade-in -> picco -> fade-out) float lit = sin(sub_t * 3.14159265); if (lit <= 0.15) { continue; } // Indice lampadina estratta pseudo-casualmente per questo settore e questo ciclo float r_val = pseudo_rand(step * 17.13 + float(c) * 31.7); int chosen_bulb = ranges_start[c] + int(floor(r_val * float(ranges_count[c]))); chosen_bulb = clamp(chosen_bulb, 0, 36); vec2 delta = px - sign_bulbs[chosen_bulb] * vec2(880.0, 561.0); float r = length(delta); // Nucleo piccolo e brillante ~5px + alone diffuso ~12px float core = 1.0 - smoothstep(2.0, 6.0, r); float halo = exp(-r / 7.5); float intensity = lit * sign_lights_active; vec3 bulb_col = get_bulb_color(chosen_bulb); // Colorazione del nucleo e alone additivo color.rgb = mix(color.rgb, bulb_col, core * intensity); color.rgb += bulb_col * (halo * 0.75 * intensity * (1.0 - core)); color.a = max(color.a, halo * 0.5 * intensity); } } color.rgb = min(color.rgb, vec3(1.0)); COLOR = color; }