467 lines
10 KiB
Odin
467 lines
10 KiB
Odin
package main
|
|
|
|
import "core:fmt"
|
|
import "core:math"
|
|
import "core:math/ease"
|
|
import rl "vendor:raylib"
|
|
|
|
SFX: []u8 : #load("sfx.mp3")
|
|
OTF: []u8 : #load("a.otf")
|
|
|
|
color_mul_rgb :: proc(a, b: rl.Color) -> rl.Color {
|
|
return {
|
|
u8((f32(a.r) * f32(b.r)) / 255),
|
|
u8((f32(a.g) * f32(b.g)) / 255),
|
|
u8((f32(a.b) * f32(b.b)) / 255),
|
|
255,
|
|
}
|
|
}
|
|
|
|
with_alpha :: proc(c: rl.Color, alpha: f32) -> rl.Color {
|
|
out := c
|
|
out.a = u8(clamp(alpha, 0, 1) * 255)
|
|
return out
|
|
}
|
|
|
|
ease_out_back :: proc(t: f32, s: f32 = 1.70158) -> f32 {
|
|
t1 := clamp(t, 0, 1)
|
|
return 1 + s * math.pow(t1 - 1, 3) + s * (t1 - 1) * math.pow(t1 - 1, 2)
|
|
}
|
|
|
|
adsr :: proc(t, attack, decay, sustain: f32, r_start: f32, r_dur: f32) -> f32 {
|
|
if t <= 0 {return 0}
|
|
if t < attack {
|
|
return ease.cubic_out(t / attack)
|
|
}
|
|
if t < attack + decay {
|
|
return f32(math.lerp(f32(1), sustain, ease.cubic_in_out((t - attack) / decay)))
|
|
}
|
|
if t < r_start {
|
|
return sustain
|
|
}
|
|
return sustain * (1 - ease.cubic_out((t - r_start) / math.max(r_dur, 0.0001)))
|
|
}
|
|
|
|
draw_noun_verbed_sheen :: proc(
|
|
font: rl.Font,
|
|
text: string,
|
|
center: rl.Vector2,
|
|
base_font_size: f32,
|
|
spacing: f32,
|
|
text_color: rl.Color,
|
|
text_opacity: f32,
|
|
sheen_tint: rl.Color,
|
|
blur_size_: f32,
|
|
blur_opacity: f32,
|
|
) {
|
|
blur_size := blur_size_
|
|
screen_h := rl.GetScreenHeight()
|
|
s := f32(screen_h) / 1080.0
|
|
|
|
if blur_size <= 1.0001 {
|
|
blur_size = 1.0001
|
|
}
|
|
|
|
steps_f := 20.0 * blur_size * math.pow(s, 0.25)
|
|
zoomSteps := i32(math.floor(steps_f))
|
|
if zoomSteps < 6 {
|
|
zoomSteps = 6
|
|
}
|
|
|
|
voff := s / (blur_size - 1.0)
|
|
|
|
base_size := rl.MeasureTextEx(font, fmt.ctprintf("{}", text), base_font_size, spacing)
|
|
base_origin := rl.Vector2{base_size.x * 0.5, base_size.y * 0.5}
|
|
|
|
glow_base := color_mul_rgb(text_color, sheen_tint)
|
|
|
|
rl.BeginBlendMode(.ADDITIVE)
|
|
for i := zoomSteps; i >= 0; i -= 1 {
|
|
t := f32(i) / f32(zoomSteps)
|
|
scale_factor := f32(math.pow(blur_size, t))
|
|
|
|
denom := f32(math.log2_f32(blur_size) / math.log2_f32(2))
|
|
if denom == 0 {
|
|
denom = 0.000001
|
|
}
|
|
fat_product := f32(math.pow(scale_factor, 1.0 / denom))
|
|
|
|
alpha := blur_opacity / fat_product
|
|
if alpha <= 0.001 {
|
|
continue
|
|
}
|
|
|
|
fs := base_font_size * scale_factor
|
|
sp := spacing * scale_factor
|
|
|
|
size := rl.MeasureTextEx(font, fmt.ctprintf("{}", text), fs, sp)
|
|
origin := rl.Vector2{size.x * 0.5, size.y * 0.5}
|
|
|
|
y_offset := voff * (scale_factor - 1.0)
|
|
|
|
rl.DrawTextPro(
|
|
font,
|
|
fmt.ctprintf("{}", text),
|
|
rl.Vector2{center.x, center.y + y_offset},
|
|
origin,
|
|
0.0,
|
|
fs,
|
|
sp,
|
|
with_alpha(glow_base, alpha),
|
|
)
|
|
}
|
|
rl.EndBlendMode()
|
|
|
|
rl.DrawTextPro(
|
|
font,
|
|
fmt.ctprintf("{}", text),
|
|
center,
|
|
base_origin,
|
|
0.0,
|
|
base_font_size,
|
|
spacing,
|
|
with_alpha(text_color, text_opacity),
|
|
)
|
|
}
|
|
|
|
draw_shadow_bar :: proc(
|
|
center_y: f32,
|
|
rel_size: f32,
|
|
opacity: f32,
|
|
offset: f32,
|
|
softness: f32,
|
|
tint: rl.Color,
|
|
) {
|
|
if rel_size <= 0.0 || opacity <= 0.0 {
|
|
return
|
|
}
|
|
|
|
w := rl.GetScreenWidth()
|
|
hf := f32(rl.GetScreenHeight())
|
|
|
|
shadow_h := rel_size * 0.25 * hf
|
|
center := center_y + offset * hf
|
|
top := center - shadow_h * 0.5
|
|
|
|
c_tint := rl.Color{tint.r, tint.g, tint.b, u8(clamp(opacity, 0, 1) * 255)}
|
|
c_clear := rl.Color{tint.r, tint.g, tint.b, 0}
|
|
|
|
y0 := i32(math.round(top))
|
|
total_h := i32(math.round(shadow_h))
|
|
if total_h <= 0 {
|
|
return
|
|
}
|
|
y3 := y0 + total_h
|
|
|
|
fade_h := shadow_h * clamp(softness, 0, 1) * 0.5
|
|
fade_i := i32(math.round(fade_h))
|
|
if fade_i * 2 > total_h {
|
|
fade_i = total_h / 2
|
|
}
|
|
|
|
y1 := y0 + fade_i
|
|
y2 := y3 - fade_i
|
|
mid_h := y2 - y1
|
|
|
|
rl.BeginBlendMode(.ALPHA)
|
|
|
|
if fade_i > 0 {
|
|
rl.DrawRectangleGradientV(0, y0, w, y1 - y0, c_clear, c_tint)
|
|
}
|
|
|
|
if mid_h > 0 {
|
|
rl.DrawRectangle(0, y1, w, mid_h, c_tint)
|
|
}
|
|
|
|
if fade_i > 0 {
|
|
rl.DrawRectangleGradientV(0, y2, w, y3 - y2, c_tint, c_clear)
|
|
}
|
|
|
|
rl.EndBlendMode()
|
|
}
|
|
|
|
draw_sheen_sweep :: proc(
|
|
font: rl.Font,
|
|
text: string,
|
|
center: rl.Vector2,
|
|
font_size: f32,
|
|
spacing: f32,
|
|
tint: rl.Color,
|
|
progress: f32,
|
|
core_frac: f32,
|
|
soft_frac: f32,
|
|
core_alpha: f32,
|
|
soft_alpha: f32,
|
|
) {
|
|
size := rl.MeasureTextEx(font, fmt.ctprintf("{}", text), font_size, spacing)
|
|
origin := rl.Vector2{size.x * 0.5, size.y * 0.5}
|
|
|
|
left := center.x - origin.x
|
|
top := center.y - origin.y
|
|
width := size.x
|
|
height := size.y
|
|
|
|
p := clamp(progress, 0, 1)
|
|
|
|
x_center := left + width * p
|
|
core_w := width * core_frac
|
|
soft_w := width * soft_frac
|
|
|
|
bright := rl.Color{255, 235, 210, 255}
|
|
|
|
rl.BeginBlendMode(.ADDITIVE)
|
|
|
|
rl.BeginScissorMode(i32(x_center - soft_w * 0.5), i32(top), i32(soft_w), i32(height))
|
|
rl.DrawTextPro(
|
|
font,
|
|
fmt.ctprintf("{}", text),
|
|
center,
|
|
origin,
|
|
0,
|
|
font_size,
|
|
spacing,
|
|
with_alpha(bright, soft_alpha),
|
|
)
|
|
rl.EndScissorMode()
|
|
|
|
rl.BeginScissorMode(i32(x_center - core_w * 0.5), i32(top), i32(core_w), i32(height))
|
|
rl.DrawTextPro(
|
|
font,
|
|
fmt.ctprintf("{}", text),
|
|
center,
|
|
origin,
|
|
0,
|
|
font_size,
|
|
spacing,
|
|
with_alpha(bright, core_alpha),
|
|
)
|
|
rl.EndScissorMode()
|
|
|
|
rl.EndBlendMode()
|
|
}
|
|
|
|
main :: proc() {
|
|
mon := rl.GetCurrentMonitor()
|
|
w, h := rl.GetMonitorWidth(mon), rl.GetMonitorHeight(mon)
|
|
|
|
rl.SetConfigFlags(
|
|
{
|
|
.WINDOW_TRANSPARENT,
|
|
.WINDOW_RESIZABLE,
|
|
.WINDOW_MOUSE_PASSTHROUGH,
|
|
.WINDOW_HIGHDPI,
|
|
.WINDOW_TOPMOST,
|
|
.WINDOW_UNFOCUSED,
|
|
.WINDOW_UNDECORATED,
|
|
.FULLSCREEN_MODE,
|
|
},
|
|
)
|
|
rl.InitWindow(w, h, "amongus")
|
|
|
|
rl.InitAudioDevice()
|
|
music := rl.LoadMusicStreamFromMemory(".mp3", raw_data(SFX), i32(len(SFX)))
|
|
rl.PlayMusicStream(music)
|
|
|
|
rt := rl.LoadRenderTexture(rl.GetScreenWidth(), rl.GetScreenHeight())
|
|
rl.SetTextureFilter(rt.texture, .BILINEAR)
|
|
|
|
font := rl.LoadFontFromMemory(".otf", raw_data(OTF), i32(len(OTF)), 256, nil, 0)
|
|
|
|
text := "NIXOS REBUILT"
|
|
//base_font_size0 := f32(128)
|
|
spacing := f32(2)
|
|
text_color := rl.Color{235, 200, 120, 255}
|
|
sheen_tint := rl.Color{255, 178, 153, 255}
|
|
|
|
// base durations
|
|
fade_in_dur := f32(0.55)
|
|
scale_dur := f32(1.10)
|
|
sweep_delay := f32(0.20)
|
|
sweep_dur := f32(1.20)
|
|
glow_rise_dur := f32(0.70)
|
|
|
|
post_fade_in_dur := f32(0.25)
|
|
post_hold_after_sweep := f32(0.35)
|
|
post_fade_out_dur := f32(0.60)
|
|
|
|
DUR_SCALE :: f32(2.0)
|
|
|
|
blur_base := f32(1.0)
|
|
blur_opacity_base := f32(0.08)
|
|
|
|
// overlay appears 7s into the mp3
|
|
OVERLAY_DELAY :: f32(5.0)
|
|
|
|
SHEEN_GAIN :: 0.3 // overall intensity (0..1)
|
|
SHEEN_W_SCALE :: 0.5 // width scaler (<1 = thinner)
|
|
SHEEN_SOFT_ALPHA_CAP :: 0.10 // upper cap for soft halo
|
|
SHEEN_CORE_ALPHA_CAP :: 0.28 // upper cap for core
|
|
|
|
prev_mt := f32(0)
|
|
ended := false
|
|
len_s := f32(rl.GetMusicTimeLength(music))
|
|
|
|
running := true
|
|
for !rl.WindowShouldClose() && running {
|
|
free_all(context.temp_allocator)
|
|
|
|
if rl.IsWindowResized() {
|
|
rl.UnloadRenderTexture(rt)
|
|
rt = rl.LoadRenderTexture(rl.GetScreenWidth(), rl.GetScreenHeight())
|
|
rl.SetTextureFilter(rt.texture, .BILINEAR)
|
|
}
|
|
|
|
rl.UpdateMusicStream(music)
|
|
mt_raw := f32(rl.GetMusicTimePlayed(music))
|
|
if !ended {
|
|
if mt_raw < prev_mt - 0.02 ||
|
|
mt_raw >= len_s - 0.01 ||
|
|
(!rl.IsMusicStreamPlaying(music) && mt_raw > 0) {
|
|
ended = true
|
|
rl.StopMusicStream(music)
|
|
}
|
|
}
|
|
mt := mt_raw
|
|
if ended {
|
|
mt = len_s
|
|
running = false
|
|
}
|
|
prev_mt = mt_raw
|
|
|
|
visible := mt >= OVERLAY_DELAY
|
|
t := mt - OVERLAY_DELAY
|
|
if t < 0 {t = 0}
|
|
|
|
fade_in := fade_in_dur * DUR_SCALE
|
|
scale_len := scale_dur * DUR_SCALE
|
|
sweep_dly := sweep_delay * DUR_SCALE
|
|
sweep_len := sweep_dur * DUR_SCALE
|
|
glow_len := glow_rise_dur * DUR_SCALE
|
|
post_in := post_fade_in_dur * DUR_SCALE
|
|
post_hold := post_hold_after_sweep * DUR_SCALE
|
|
post_out := post_fade_out_dur * DUR_SCALE
|
|
|
|
alpha := ease.cubic_out(t / fade_in)
|
|
scale_bump := 0.06 * ease_out_back(t / scale_len, 1.3)
|
|
|
|
base_font_size0 := 0.6 * 0.25 * f32(rl.GetScreenHeight())
|
|
font_size := base_font_size0 * (1.0 + scale_bump)
|
|
|
|
glow_in := ease.cubic_out(t / glow_len)
|
|
glow_pulse := 0.5 + 0.5 * f32(math.sin(t * 2.0))
|
|
|
|
sweep_end_time := sweep_dly + sweep_len
|
|
fade_out_start := sweep_end_time + post_hold
|
|
|
|
blur_env := adsr(
|
|
t,
|
|
0.18 * DUR_SCALE, // attack
|
|
0.35 * DUR_SCALE, // decay
|
|
0.70, // sustain level
|
|
fade_out_start, // release start
|
|
post_out, // release dur
|
|
)
|
|
blur_size := blur_base * f32(math.lerp(f32(1.00), 1.30, ease.cubic_in_out(blur_env)))
|
|
blur_opacity := blur_opacity_base
|
|
blur_opacity *= (0.60 + 0.40 * blur_env) // grow with env
|
|
blur_opacity *= clamp(glow_in * (0.8 + 0.2 * glow_pulse), 0.0, 1.0)
|
|
|
|
sheen_t := t - sweep_dly
|
|
|
|
raw_env := adsr(
|
|
sheen_t,
|
|
0.10 * DUR_SCALE,
|
|
0.22 * DUR_SCALE,
|
|
0.65,
|
|
sweep_len,
|
|
0.28 * DUR_SCALE,
|
|
)
|
|
sheen_env := f32(math.pow(clamp(raw_env, 0, 1), 0.75) * SHEEN_GAIN)
|
|
|
|
core_frac := f32(math.lerp(f32(0.12), 0.18, sheen_env) * SHEEN_W_SCALE)
|
|
soft_frac := f32(math.lerp(f32(0.24), 0.34, sheen_env) * SHEEN_W_SCALE)
|
|
|
|
core_alpha_dyn := f32(
|
|
math.min(math.lerp(f32(0.10), 0.26, sheen_env), SHEEN_CORE_ALPHA_CAP),
|
|
)
|
|
soft_alpha_dyn := f32(
|
|
math.min(math.lerp(f32(0.03), 0.09, sheen_env), SHEEN_SOFT_ALPHA_CAP),
|
|
)
|
|
|
|
center := rl.Vector2{f32(rl.GetScreenWidth()) * 0.5, f32(rl.GetScreenHeight()) * 0.5}
|
|
|
|
rl.BeginTextureMode(rt)
|
|
rl.ClearBackground(rl.BLANK)
|
|
|
|
if visible {
|
|
draw_shadow_bar(center.y, 1.4, 0.95, -0.002, 0.5, rl.BLACK)
|
|
|
|
draw_noun_verbed_sheen(
|
|
font,
|
|
text,
|
|
center,
|
|
font_size,
|
|
spacing,
|
|
text_color,
|
|
alpha,
|
|
sheen_tint,
|
|
blur_size,
|
|
blur_opacity,
|
|
)
|
|
|
|
sweep_p := clamp((t - sweep_dly) / sweep_len, 0, 1)
|
|
if sweep_p > 0 && sweep_p <= 1 {
|
|
draw_sheen_sweep(
|
|
font,
|
|
text,
|
|
center,
|
|
font_size,
|
|
spacing,
|
|
sheen_tint,
|
|
sweep_p,
|
|
core_frac,
|
|
soft_frac,
|
|
core_alpha_dyn,
|
|
soft_alpha_dyn,
|
|
)
|
|
}
|
|
}
|
|
|
|
rl.EndTextureMode()
|
|
|
|
post_alpha := f32(1.0)
|
|
if !visible {
|
|
post_alpha = 0
|
|
} else {
|
|
if t < post_in {
|
|
post_alpha = ease.cubic_out(t / post_in)
|
|
} else if t >= fade_out_start {
|
|
post_alpha = 1.0 - ease.cubic_out((t - fade_out_start) / post_out)
|
|
}
|
|
post_alpha = clamp(post_alpha, 0, 1)
|
|
}
|
|
|
|
rl.BeginDrawing()
|
|
rl.ClearBackground(rl.BLANK)
|
|
|
|
src := rl.Rectangle{0, 0, f32(rt.texture.width), -f32(rt.texture.height)}
|
|
dst := rl.Rectangle{0, 0, f32(rl.GetScreenWidth()), f32(rl.GetScreenHeight())}
|
|
rl.DrawTexturePro(
|
|
rt.texture,
|
|
src,
|
|
dst,
|
|
rl.Vector2{0, 0},
|
|
0,
|
|
with_alpha(rl.WHITE, post_alpha),
|
|
)
|
|
|
|
rl.EndDrawing()
|
|
}
|
|
|
|
rl.UnloadRenderTexture(rt)
|
|
rl.UnloadFont(font)
|
|
rl.UnloadMusicStream(music)
|
|
rl.CloseAudioDevice()
|
|
rl.CloseWindow()
|
|
}
|