diff --git a/CHANGELOG.md b/CHANGELOG.md index 8332cf22..6fcee44a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,77 @@ change type. Preview the next one with `ludic dev release --dry-run`. A released section may carry a hand-written summary paragraph above its groups (v0.2.0 has one); the generated bullets below it are not edited by hand. +## v0.13.0 — 2026-09-13 + +### Features + +- **Windows target** — `ludicc` builds and runs headless programs on Windows, and builds itself there. + + - **`--target `** — a triple naming `windows` selects the Windows runtime; without + the flag the target is the host, read at run time from `OS=Windows_NT`. The IR still + carries no triple, so clang assembles it for the machine it runs on. + - **The libc surface, in IR** — on Windows the header emits `emit_win.ludic`, which defines + the POSIX names the backend calls (`fopen`, `ftell`, `rename`, `opendir`, `mmap`, + `fmemopen`, `uname`, …) over the UCRT and Win32. Three of them fixed silent breakage + rather than link errors: `rename` onto an existing file (every `Fs.write_text` after the + first), a 32-bit `ftell`, and text-mode `fopen` rewriting `\n` as `\r\n`. + - **Known folders** — `Os.save_dir` / `config_dir` are `%APPDATA%\`, `cache_dir` is + `%LOCALAPPDATA%\`, `temp_dir` is `%TEMP%`, all with forward slashes; a bundle's + `home` line points at `%APPDATA%\`. + - **The driver** — finds `C:\Program Files\LLVM\bin\clang.exe` when clang is not on + `%PATH%`, writes `.exe` outputs, speaks cmd.exe for its directory and cleanup commands, + and reads `argv[0]`, `%PATH%` and `$LUDIC_HOME` with either separator. + - **A window** — `win32.ll` is `cocoa.ll`'s contract over user32: the held-key set and frame + key in Ludic codes, the mouse in framebuffer pixels with raw input for cursor mode 2, + cursor hide/lock/confine that lets go when the window loses the foreground, XInput pads + in SDL order with rescaled deadzones, and the software `win_present`. `win32_gl.ll` puts + the WGL context on that window with vsync and borderless full screen; a headless build + links `gl_win_nowin.ll` instead. The process is per-monitor DPI aware. + - **Sound** — `audio_win.ll` is `audio.ll`'s contract over XAudio2: one source voice per + clip, loops, volume, rate and a balance pan through the output matrix, RIFF WAVE in PCM or + float. It reads a clip through the asset pack, so a bundled game's first `Audio.load` + succeeds - AVAudioPlayer takes a filesystem path, which is why macOS cannot. + - **The CLI on Windows** — `ludic build`, `ludic run` and `ludic-dev build` work from a Windows + checkout. Every shell command the CLI issues runs through Git for Windows' bash + (`$LUDIC_BASH` names another), `compile_app` links through `ludicc -o`, and a checkout + bootstraps from the new `selfhost/ludicc.win.seed.ll`, which `ludic-dev reseed` now + writes beside the macOS seed. + - **`ludic bundle` on Windows** — `build//` holding a GUI-subsystem `.exe`, the + `game.lpak` and `packs.index`; an `.ico` beside `app icon` is compiled with `llvm-rc` and + linked in. `ludicc` gains `--gui` (no console behind the window) and `--link `. + - **`Http.*` on Windows** — `http_win.ll` is `http.ll`'s contract over WinHTTP: a request + built on the game thread, the exchange on a worker thread, TLS with the system's + certificate checks, and response headers answered from the kept request handle. + - **The splash and the window icon** — decoded by WIC from the bytes in the pack. The splash + is a topmost borderless window at the artwork's own size in points times the display's + scale; `App.set_icon` sets the title bar and taskbar icon of a build with no icon resource. + - **`Gl.*` on Windows** — `gl_win.ll` makes a WGL 4.1 core context on a hidden window's DC, + and `gl_thunks_win.ll` (generated by `ludic-dev glgen` beside `gl_thunks.ll`) calls + every entry point through a table `@lgl_win_load` fills from `wglGetProcAddress`, falling + back to `opengl32.dll` for the 1.1 functions it will not return. A headless GL program + renders on the GPU there: `gl_triangle` matches the macOS frame to within one level per + channel. + +### Fixes + +- **Backspace fires on macOS** — the Delete key reports `Key.Backspace` (8). + + AppKit gives the key marked delete (kVK_Delete, 51) the character `NSDeleteCharacter`, 127, + which is what both the held-key set and the per-frame key received, so `Key.Backspace` never + matched. `cocoa.ll` maps key code 51 to 8 in both. +- **Held arrow keys register** — `Key.Up`, `Key.Down`, `Key.Left` and `Key.Right` are 128-131. + + They folded to the codes of w, s, a and d, which is what the single per-frame key + (`Input.key`) reports for an arrow. The held-key set has always stored an arrow under + 128-131, so `Input.key_down(Key.Up)` tested the W bit and `Input.move_i`'s arrow half never + moved anything. `Input.key` keeps its WASD alias: a game comparing it with `'w'` still + takes the arrows. +- **`ludic build` links `Http.*`** — a program that uses the HTTP client builds through the CLI. + + `compile_app` linked the OpenGL backend when a program named `@lgl_*` but never + `runtime/native/http.ll` and Foundation for `@hs_*`, so a `Http.*` program failed to link + under `ludic build` / `ludic run` while `ludicc -o` built it. It now links them the same way, + windowed and headless. ## v0.12.1 — 2026-09-13 ### Features diff --git a/VERSION b/VERSION index 34a83616..54d1a4f2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.12.1 +0.13.0 diff --git a/changes/arrow-keys.md b/changes/arrow-keys.md deleted file mode 100644 index 70a2e589..00000000 --- a/changes/arrow-keys.md +++ /dev/null @@ -1,9 +0,0 @@ -bump: patch -type: fix -**Held arrow keys register** — `Key.Up`, `Key.Down`, `Key.Left` and `Key.Right` are 128-131. - -They folded to the codes of w, s, a and d, which is what the single per-frame key -(`Input.key`) reports for an arrow. The held-key set has always stored an arrow under -128-131, so `Input.key_down(Key.Up)` tested the W bit and `Input.move_i`'s arrow half never -moved anything. `Input.key` keeps its WASD alias: a game comparing it with `'w'` still -takes the arrows. diff --git a/changes/backspace-key.md b/changes/backspace-key.md deleted file mode 100644 index 85cd81b9..00000000 --- a/changes/backspace-key.md +++ /dev/null @@ -1,7 +0,0 @@ -bump: patch -type: fix -**Backspace fires on macOS** — the Delete key reports `Key.Backspace` (8). - -AppKit gives the key marked delete (kVK_Delete, 51) the character `NSDeleteCharacter`, 127, -which is what both the held-key set and the per-frame key received, so `Key.Backspace` never -matched. `cocoa.ll` maps key code 51 to 8 in both. diff --git a/changes/ludic-build-http.md b/changes/ludic-build-http.md deleted file mode 100644 index da86e5ad..00000000 --- a/changes/ludic-build-http.md +++ /dev/null @@ -1,8 +0,0 @@ -bump: patch -type: fix -**`ludic build` links `Http.*`** — a program that uses the HTTP client builds through the CLI. - -`compile_app` linked the OpenGL backend when a program named `@lgl_*` but never -`runtime/native/http.ll` and Foundation for `@hs_*`, so a `Http.*` program failed to link -under `ludic build` / `ludic run` while `ludicc -o` built it. It now links them the same way, -windowed and headless. diff --git a/changes/windows-target.md b/changes/windows-target.md deleted file mode 100644 index cad489eb..00000000 --- a/changes/windows-target.md +++ /dev/null @@ -1,48 +0,0 @@ -bump: minor -type: feat -**Windows target** — `ludicc` builds and runs headless programs on Windows, and builds itself there. - -- **`--target `** — a triple naming `windows` selects the Windows runtime; without - the flag the target is the host, read at run time from `OS=Windows_NT`. The IR still - carries no triple, so clang assembles it for the machine it runs on. -- **The libc surface, in IR** — on Windows the header emits `emit_win.ludic`, which defines - the POSIX names the backend calls (`fopen`, `ftell`, `rename`, `opendir`, `mmap`, - `fmemopen`, `uname`, …) over the UCRT and Win32. Three of them fixed silent breakage - rather than link errors: `rename` onto an existing file (every `Fs.write_text` after the - first), a 32-bit `ftell`, and text-mode `fopen` rewriting `\n` as `\r\n`. -- **Known folders** — `Os.save_dir` / `config_dir` are `%APPDATA%\`, `cache_dir` is - `%LOCALAPPDATA%\`, `temp_dir` is `%TEMP%`, all with forward slashes; a bundle's - `home` line points at `%APPDATA%\`. -- **The driver** — finds `C:\Program Files\LLVM\bin\clang.exe` when clang is not on - `%PATH%`, writes `.exe` outputs, speaks cmd.exe for its directory and cleanup commands, - and reads `argv[0]`, `%PATH%` and `$LUDIC_HOME` with either separator. -- **A window** — `win32.ll` is `cocoa.ll`'s contract over user32: the held-key set and frame - key in Ludic codes, the mouse in framebuffer pixels with raw input for cursor mode 2, - cursor hide/lock/confine that lets go when the window loses the foreground, XInput pads - in SDL order with rescaled deadzones, and the software `win_present`. `win32_gl.ll` puts - the WGL context on that window with vsync and borderless full screen; a headless build - links `gl_win_nowin.ll` instead. The process is per-monitor DPI aware. -- **Sound** — `audio_win.ll` is `audio.ll`'s contract over XAudio2: one source voice per - clip, loops, volume, rate and a balance pan through the output matrix, RIFF WAVE in PCM or - float. It reads a clip through the asset pack, so a bundled game's first `Audio.load` - succeeds - AVAudioPlayer takes a filesystem path, which is why macOS cannot. -- **The CLI on Windows** — `ludic build`, `ludic run` and `ludic-dev build` work from a Windows - checkout. Every shell command the CLI issues runs through Git for Windows' bash - (`$LUDIC_BASH` names another), `compile_app` links through `ludicc -o`, and a checkout - bootstraps from the new `selfhost/ludicc.win.seed.ll`, which `ludic-dev reseed` now - writes beside the macOS seed. -- **`ludic bundle` on Windows** — `build//` holding a GUI-subsystem `.exe`, the - `game.lpak` and `packs.index`; an `.ico` beside `app icon` is compiled with `llvm-rc` and - linked in. `ludicc` gains `--gui` (no console behind the window) and `--link `. -- **`Http.*` on Windows** — `http_win.ll` is `http.ll`'s contract over WinHTTP: a request - built on the game thread, the exchange on a worker thread, TLS with the system's - certificate checks, and response headers answered from the kept request handle. -- **The splash and the window icon** — decoded by WIC from the bytes in the pack. The splash - is a topmost borderless window at the artwork's own size in points times the display's - scale; `App.set_icon` sets the title bar and taskbar icon of a build with no icon resource. -- **`Gl.*` on Windows** — `gl_win.ll` makes a WGL 4.1 core context on a hidden window's DC, - and `gl_thunks_win.ll` (generated by `ludic-dev glgen` beside `gl_thunks.ll`) calls - every entry point through a table `@lgl_win_load` fills from `wglGetProcAddress`, falling - back to `opengl32.dll` for the 1.1 functions it will not return. A headless GL program - renders on the GPU there: `gl_triangle` matches the macOS frame to within one level per - channel.