5.1 KiB · text History e74691a
# neiam boot splash.
#
# The background is picked from the renders below rather than scaled
# from one master, so each resolution can be art-directed in Blender.
# Keep this table in step with RESOLUTIONS in tools/standins.py.

bg_w[0] = 1280; bg_h[0] = 800;
bg_w[1] = 1366; bg_h[1] = 768;
bg_w[2] = 1920; bg_h[2] = 1080;
bg_w[3] = 1920; bg_h[3] = 1200;
bg_w[4] = 2560; bg_h[4] = 1440;
bg_w[5] = 2560; bg_h[5] = 1600;
bg_w[6] = 3840; bg_h[6] = 2160;
bg_count = 7;

# #651d1d, shown until the image is up and wherever it can't reach.
Window.SetBackgroundTopColor(0.396, 0.114, 0.114);
Window.SetBackgroundBottomColor(0.396, 0.114, 0.114);

screen_w = Window.GetWidth();
screen_h = Window.GetHeight();
screen_x = Window.GetX();
screen_y = Window.GetY();

# #fef3c7
fg_r = 0.996; fg_g = 0.953; fg_b = 0.780;

# Prefer the render whose aspect ratio matches the screen, then the
# one needing the least scaling -- and downscaling over upscaling,
# since a render shrunk slightly still looks like the render.
fun pick_background() {
    best = 0;
    best_score = 1000000;
    for (i = 0; i < global.bg_count; i++) {
        aspect_err = Math.Abs(global.bg_w[i] / global.bg_h[i] - global.screen_w / global.screen_h);
        scale = Math.Max(global.screen_w / global.bg_w[i], global.screen_h / global.bg_h[i]);
        if (scale > 1)
            fit = (scale - 1) * 4;
        else
            fit = 1 / scale - 1;
        score = aspect_err * 100 + fit;
        if (score < best_score) {
            best = i;
            best_score = score;
        }
    }
    return best;
}

i = pick_background();
bg_image = Image("background-" + bg_w[i] + "x" + bg_h[i] + ".png");

# Cover the screen, cropping the overhang evenly off both sides.
cover = Math.Max(screen_w / bg_image.GetWidth(), screen_h / bg_image.GetHeight());
bg_scaled = bg_image.Scale(Math.Int(bg_image.GetWidth() * cover + 0.5),
                           Math.Int(bg_image.GetHeight() * cover + 0.5));
bg_sprite = Sprite(bg_scaled);
bg_sprite.SetX(screen_x + (screen_w - bg_scaled.GetWidth()) / 2);
bg_sprite.SetY(screen_y + (screen_h - bg_scaled.GetHeight()) / 2);
bg_sprite.SetZ(-100);

swatch = Image("swatch.png");

# ---------------------------------------------------------------- progress

bar_w = Math.Int(screen_w * 0.18);
bar_h = Math.Max(2, Math.Int(screen_h / 360));
bar_x = screen_x + (screen_w - bar_w) / 2;
bar_y = screen_y + Math.Int(screen_h * 0.82);

track_sprite = Sprite(swatch.Scale(bar_w, bar_h));
track_sprite.SetPosition(bar_x, bar_y, 10);
track_sprite.SetOpacity(0.2);

progress_sprite = Sprite();
progress_sprite.SetPosition(bar_x, bar_y, 11);

fun boot_progress_callback(duration, progress) {
    w = Math.Int(global.bar_w * Math.Clamp(progress, 0, 1));
    if (w > 0)
        global.progress_sprite.SetImage(global.swatch.Scale(w, global.bar_h));
}
Plymouth.SetBootProgressFunction(boot_progress_callback);

# ---------------------------------------------------------------- prompts

prompt_sprite = Sprite();
entry_sprite = Sprite();
underline_sprite = Sprite();
prompt_y = screen_y + Math.Int(screen_h * 0.66);

fun centre_x(image) {
    return global.screen_x + (global.screen_w - image.GetWidth()) / 2;
}

fun show_entry(prompt, entry) {
    p = Image.Text(prompt, global.fg_r, global.fg_g, global.fg_b);
    global.prompt_sprite.SetImage(p);
    global.prompt_sprite.SetPosition(centre_x(p), global.prompt_y, 20);
    global.prompt_sprite.SetOpacity(1);

    # An empty string renders no image; keep the line height anyway.
    if (entry == "")
        entry = " ";
    e = Image.Text(entry, global.fg_r, global.fg_g, global.fg_b);
    entry_y = global.prompt_y + p.GetHeight() * 2;
    global.entry_sprite.SetImage(e);
    global.entry_sprite.SetPosition(centre_x(e), entry_y, 20);
    global.entry_sprite.SetOpacity(1);

    u = global.swatch.Scale(global.bar_w, 1);
    global.underline_sprite.SetImage(u);
    global.underline_sprite.SetPosition(centre_x(u), entry_y + e.GetHeight() + 4, 20);
    global.underline_sprite.SetOpacity(0.6);
}

fun password_callback(prompt, bullets) {
    stars = "";
    for (i = 0; i < bullets; i++)
        stars += "•";
    if (prompt == "")
        prompt = "Password";
    show_entry(prompt, stars);
}
Plymouth.SetDisplayPasswordFunction(password_callback);

fun question_callback(prompt, entry) {
    show_entry(prompt, entry);
}
Plymouth.SetDisplayQuestionFunction(question_callback);

fun normal_callback() {
    global.prompt_sprite.SetOpacity(0);
    global.entry_sprite.SetOpacity(0);
    global.underline_sprite.SetOpacity(0);
}
Plymouth.SetDisplayNormalFunction(normal_callback);

# ---------------------------------------------------------------- messages

message_sprite = Sprite();
message_y = screen_y + Math.Int(screen_h * 0.88);

fun message_callback(text) {
    m = Image.Text(text, global.fg_r, global.fg_g, global.fg_b);
    global.message_sprite.SetImage(m);
    global.message_sprite.SetPosition(centre_x(m), global.message_y, 20);
    global.message_sprite.SetOpacity(0.8);
}
Plymouth.SetMessageFunction(message_callback);

fun hide_message_callback(text) {
    global.message_sprite.SetOpacity(0);
}
Plymouth.SetHideMessageFunction(hide_message_callback);