灵符lingfu

lingdev

↓ 0 downloads

LingDev: a Godot / Unity-style game editor written in Ling. 2-D and 3-D scenes, Flash-style timeline and cutscenes, HUDs over 3-D, Ling scripting, audio / music / MIDI, builds for Windows, Linux, macOS, web, Raspberry Pi and LingOS. Ships with Ling Agent (an N64-style spy FPS), Ling Breaker (a 3-D breakout) and Moko's Picture Book (a kawaii storybook platformer).

Windows · x86-64Linux · x86-64LingOS · x86-64LingOS · Pi 5 ARM64Web · WASM
Keywords game-engine, editor, 3d, 2d, cutscene, timeline, ling, lingos, raspberry-pi
lingfu install lingdev
LicenseApache-2.0 OR MIT
Authorsling-lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (136)

ling/buildpanel.ling
# buildpanel.ling - project settings and the export targets (ling build), run / generate buttons.

fn build_targets() { return ["win", "lin", "mac", "web", "rpi", "lingos"] }
fn build_target_title(t) {
    if t == "win" { return "Windows x86-64" }
    if t == "lin" { return "Linux x86-64" }
    if t == "mac" { return "macOS" }
    if t == "web" { return "Web (WASM)" }
    if t == "rpi" { return "Raspberry Pi kernel" }
    return "LingOS app"
}
fn build_target_blurb(t) {
    if t == "win" { return "dist/windows/<name>.exe with assets packed in (--pack)" }
    if t == "lin" { return "dist/linux/<name> (cross-builds with `cross` + Docker)" }
    if t == "mac" { return "dist/macos/<name> (build on a Mac, or cross)" }
    if t == "web" { return "dist/web/ - WASM + WebGL2, served by `ling run --wasm`" }
    if t == "rpi" { return "dist/rpi/kernel8.img - bare metal aarch64 (Pi 3/4 map today; Pi 5 needs the BCM2712 HAL)" }
    return "dist/apps/<name>.elf - a LingOS userspace app; lingos/Ling.toml makes it a Pi desktop built-in" }
fn build_target_icon(t) {
    if t == "win" { return "window" }
    if t == "lin" { return "terminal" }
    if t == "mac" { return "window" }
    if t == "web" { return "globe" }
    return "chip"
}

fn build_panel(x, y, w, h) {
    g_rect(x, y, w, h, C_BG_PANEL)
    if proj_root() == "" {
        ds_word(x + 12.0, y + 10.0, 10.0, "BUILD & EXPORT", ds_col("func"), true)
        g_text(x + 12.0, y + 40.0, 12.0, C_TEXT_DIM, "Open or create a project to build it.")
        if u_button("bp_np", x + 12.0, y + 64.0, 120.0, 26.0, "New Project", C_BLUE) { do_action("project.new") }
        return 0.0
    }
    bind lw = min(380.0, w * 0.42)
    # project column
    ds_word(x + 12.0, y + 10.0, 10.0, "PROJECT", ds_col("bind"), true)
    bind yy = y + 32.0
    g_text(x + 12.0, yy + 6.0, 11.0, C_TEXT_DIM, "Title")
    bind tv = u_textfield("bp_title", x + 70.0, yy, lw - 90.0, 24.0, st_get("proj_title", ""))
    if tv != st_get("proj_title", "") { st_set("proj_title", tv)  st_set("proj_dirty", 1.0) }
    bind yy = yy + 30.0
    g_text(x + 12.0, yy + 6.0, 11.0, C_TEXT_DIM, "Window")
    bind nv = u_dragval("bp_w", x + 70.0, yy, 80.0, 24.0, st_get("proj_w", 1280.0), 320.0, 3840.0, 2.0, num_str(st_get("proj_w", 1280.0)))
    if u_has(nv) { st_set("proj_w", floor(nv))  st_set("proj_dirty", 1.0) }
    bind nv = u_dragval("bp_h", x + 154.0, yy, 80.0, 24.0, st_get("proj_h", 720.0), 200.0, 2160.0, 2.0, num_str(st_get("proj_h", 720.0)))
    if u_has(nv) { st_set("proj_h", floor(nv))  st_set("proj_dirty", 1.0) }
    bind nv = u_dragval("bp_fps", x + 238.0, yy, 70.0, 24.0, st_get("proj_fps", 60.0), 10.0, 240.0, 0.5, num_str(st_get("proj_fps", 60.0)) + " fps")
    if u_has(nv) { st_set("proj_fps", floor(nv))  st_set("proj_dirty", 1.0) }
    bind yy = yy + 30.0
    g_text(x + 12.0, yy + 6.0, 11.0, C_TEXT_DIM, "Start")
    bind scenes = sl_to_list("proj_scenes")
    bind names = []
    bind cur = 0.0
    bind s = 0.0
    while s < len(scenes) {
        bind names = list_push(names, list_get(scenes, s))
        if list_get(scenes, s) == st_get("proj_start", "") { bind cur = s }
        bind s = s + 1.0
    }
    if len(names) < 0.5 { bind names = ["(save a scene first)"] }
    bind pi = u_combo("bp_start", x + 70.0, yy, lw - 90.0, 24.0, names, cur)
    if pi >= 0.0 && len(scenes) > 0.5 { st_set("proj_start", list_get(scenes, pi))  st_set("proj_dirty", 1.0) }
    bind yy = yy + 30.0
    g_text(x + 12.0, yy + 6.0, 11.0, C_TEXT_DIM, "Version")
    bind vv = u_textfield("bp_ver", x + 70.0, yy, 90.0, 24.0, st_get("proj_version", "0.1.0"))
    if vv != st_get("proj_version", "0.1.0") { st_set("proj_version", vv)  st_set("proj_dirty", 1.0) }
    g_text(x + 170.0, yy + 6.0, 11.0, C_TEXT_DIM, "Author")
    bind av = u_textfield("bp_author", x + 214.0, yy, lw - 234.0, 24.0, st_get("proj_author", ""))
    if av != st_get("proj_author", "") { st_set("proj_author", av)  st_set("proj_dirty", 1.0) }
    bind yy = yy + 30.0
    g_text(x + 12.0, yy + 6.0, 11.0, C_TEXT_DIM, "Icon")
    bind iv = u_textfield("bp_icon", x + 70.0, yy, lw - 150.0, 24.0, st_get("proj_icon", ""))
    if iv != st_get("proj_icon", "") { st_set("proj_icon", iv)  st_set("proj_dirty", 1.0) }
    if u_button("bp_icon_pick", x + lw - 74.0, yy, 54.0, 24.0, "Pick", 0.0) { picker_open("open", "App icon (svg / png / ico)", "svg,png,ico", "project.set_icon", proj_root(), "") }
    bind yy = yy + 34.0
    if u_button("bp_save", x + 12.0, yy, 110.0, 26.0, "Save project", sel(st_get("proj_dirty", 0.0) > 0.5, C_BLUE, 0.0)) { proj_save()  st_set("proj_dirty", 0.0)  status("Project saved") }
    if u_button("bp_gen", x + 128.0, yy, 150.0, 26.0, "Generate sources", 0.0) { do_action("build.gen") }
    bind yy = yy + 32.0
    if u_button("bp_run", x + 12.0, yy, 110.0, 26.0, "Run (ling run)", C_GREEN) { gen_write_all()  build_run() }
    if u_button("bp_open", x + 128.0, yy, 110.0, 26.0, "Open folder", 0.0) { plat_reveal(proj_root()) }
    if u_button("bp_dist", x + 244.0, yy, 90.0, 26.0, "Open dist", 0.0) { plat_reveal(p_join(proj_root(), "dist")) }
    bind yy = yy + 36.0
    g_text_wrap(x + 12.0, yy, lw - 24.0, 10.0, C_TEXT_DIM, "Generate writes main.ling (the player + your scenes and scripts), main_os.ling (LingOS), Ling.toml, run.bat/.sh and BUILD.md. Run opens run.bat, which starts `ling run --interp main.ling`.")
    # targets column
    bind tx = x + lw + 16.0
    bind tw = w - lw - 28.0
    ds_word(tx, y + 10.0, 10.0, "TARGETS", ds_col("func"), true)
    bind targets = build_targets()
    bind cols = sel(tw > 620.0, 2.0, 1.0)
    bind cw = floor((tw - (cols - 1.0) * 10.0) / cols)
    bind ch = 58.0
    bind i = 0.0
    while i < len(targets) {
        bind t = list_get(targets, i)
        bind cx = tx + (i % cols) * (cw + 10.0)
        bind cy = y + 32.0 + floor(i / cols) * (ch + 8.0)
        bind col = sel(t == "rpi" || t == "lingos", C_INDIGO, sel(t == "web", C_GREEN, C_BLUE))
        bind hot = u_hot(cx, cy, cw, ch)
        px_rect(cx, cy, cw, ch, c_mix(C_BG_PANEL, col, sel(hot, 0.10, 0.04)))
        px_outline(cx, cy, cw, ch, sel(hot, col, c_mix(C_BG_PANEL, col, 0.5)), 0.8)
        ds_brackets(cx, cy, cw, ch, sel(hot, 10.0, 6.0), col)
        icon_draw(build_target_icon(t), cx + 24.0, cy + ch * 0.5, 22.0, col)
        g_text(cx + 48.0, cy + 9.0, 13.0, C_TEXT_STRONG, build_target_title(t))
        g_text_fit(cx + 48.0, cy + 30.0, cw - 150.0, 10.0, C_TEXT_DIM, build_target_blurb(t))
        if u_button("bp_t_" + t, cx + cw - 92.0, cy + 16.0, 80.0, 26.0, "Build", col) { build_target(t) }
        if u_hot(cx + cw - 92.0, cy + 16.0, 80.0, 26.0) { u_tip(build_command(t)) }
        bind i = i + 1.0
    }
    bind by = y + 32.0 + ceil(len(targets) / cols) * (ch + 8.0) + 6.0
    if by + 40.0 < y + h {
        bind last = st_get("build_last", "")
        g_text_wrap(tx, by, tw, 10.0, C_TEXT_DIM, sel(last == "", "Build writes build_<target>.bat / .sh next to main.ling and opens it (Windows runs the script). The ling toolchain must be installed: cargo install ling-lang, or set ling.exe in Settings.", "Last: " + build_command(last) + "  ->  " + p_join(proj_root(), "build_" + last + ".bat")))
        if by + 70.0 < y + h { g_text_wrap(tx, by + 28.0, tw, 10.0, C_TEXT_DIM, "Pi / LingOS: these targets compile main_os.ling against the in-kernel runtime (software renderer, no audio yet). lingos/Ling.toml shows how to bundle the game into the LingOS Pi desktop like LingStationX.") }
    }
    return 0.0
}

← Back to index