Commit graph

150 commits

Author SHA1 Message Date
b055fc2496 chore(release): v0.18.0
Some checks failed
bootstrap / cfree-fixpoint (push) Successful in 35s
ci / build-and-test (push) Failing after 3m22s
commit-lint / conventional-commits (push) Successful in 4s
docs / build-and-deploy (push) Successful in 42s
release / publish (push) Failing after 3m22s
2026-09-16 16:18:28 +03:00
1900f9ca80 fix(compiler): == / != on references is identity; only text compares by content
emit_bin_vals lowered every pointer-typed ==/!= to @lp_str_eq, so two
distinct records compared their bytes up to the first zero byte. Content
compare now needs both sides to be text (string, or the untyped
pointer/ptr runtime code carries text in); other references use
icmp eq ptr, and string vs a non-text reference is a compile error.
Adds selfhost/tests/identity.ludic; both seeds regenerated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 16:13:31 +03:00
e010c2cecc feat(lang): float and double types with ordinary operators
`float` (32-bit) and `double` (64-bit) with + - * / %, comparisons and unary minus.
Decimal literals take their type from context and stay `fixed` elsewhere; int and long
promote implicitly (LUDIC_WARN_FLOAT_PROMOTE=1 lists every promotion). float(), double(),
int(), long() and fixed() convert; floats(n)/doubles(n) buffers; float fields, globals,
constants and parameters; Math.* computes in float for float arguments; string/print
write the shortest round-tripping decimal; float_bits/float_from_bits expose the bits.
@deterministic code may not use floats. The f_* runtime helpers stay as they are.

Editors know the new type words; the JetBrains plugin is 1.5.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 16:13:31 +03:00
f92d7f89c6 feat(tooling): JetBrains IDE support, LSP navigation, barrel imports, package scripts and hooks
- JetBrains plugin 1.4.0: semantic colours (builtin / vendor / own), template strings,
  brace handling, run configurations and a test console, package.ludic and
  package.lock.ludic editing (completion, docs, app preview, colour previews, asset
  navigation), External Libraries for the runtime and packages, doc pages for built-ins
- ludic-lsp: go to definition for imports, document links, hover with inferred types,
  type definition, signature help with parameters, docs from docs/language
- `import "dir"` resolves a barrel `dir/index.ludic`
- package.ludic `entry`, `script` and `hook before|after <command>`; `ludic <script>`,
  `ludic script`, `ludic scripts`
- `ludic test --verbose` and `--test NAME`; the test runner filters by name

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 16:13:31 +03:00
da57b20156 chore(release): v0.17.0
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 44s
ci / build-and-test (push) Successful in 3m32s
commit-lint / conventional-commits (push) Successful in 5s
docs / build-and-deploy (push) Successful in 41s
release / publish (push) Successful in 3m22s
2026-09-16 16:13:00 +03:00
1a2259bdca Merge the R3D_DEV gate: render3d's debug switches only in headless or R3D_DEV builds 2026-09-16 15:31:54 +03:00
fa6c422f9b feat(render3d): terrain_lake_carve - a height map may carry its own lake bed
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 15:27:21 +03:00
6dfdee75e2 fix(render3d): a lake can be the mirrored water, with its own wet shore
A reflecting body is clipped to its ellipse like every other unless it is an
unbounded sea, so a map whose reflection belongs to its lake (Maroon Lake, once
its sea sits below it) does not draw that lake's level over every hollow in the
survey. The terrain's wet shore and its forest and scree gates read the carved
lake's line inside its outline (u_lake), the rule grass already used. SPIR-V
regenerated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 15:15:28 +03:00
2980f050ed feat(render3d): gate R3D_* switches behind R3D_DEV in windowed builds
Every R3D_* read goes through r3d_env_has / r3d_env (env.ludic): a headless
build honours them as before, a windowed build only when R3D_DEV is set to
anything but "0", so a shipped game never reaches a debug view, feature kill,
file writer or hardware fake. Documented in docs/SHIPPING.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 13:21:51 +03:00
132deac5bc chore(release): v0.16.2
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 33s
ci / build-and-test (push) Successful in 3m32s
commit-lint / conventional-commits (push) Successful in 5s
docs / build-and-deploy (push) Successful in 41s
release / publish (push) Successful in 3m22s
2026-09-15 23:27:04 +03:00
619476ffed fix(input): keys are physical positions on every layout; Input.key_label names them
The Windows runtime keyed the held set by the character MapVirtualKeyA gave a
virtual key, so a game's WASD belonged to whatever the active layout put there,
and with an input method on every letter arrived as VK_PROCESSKEY. The typing
block is now read from the scancode (the arrows, numpad and F-keys still by
virtual key); macOS reads keyCode the same way. Input.key_label(key) names a key
in the player's own layout (Windows) or as its US character elsewhere.

Verified on Windows with SendInput into a live window: VK_Z carrying W's scancode
holds 'w', VK_PROCESSKEY carrying A's holds 'a', Caps Lock changes nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 23:26:53 +03:00
2a2f463d5b chore(release): v0.16.1
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 33s
ci / build-and-test (push) Successful in 3m30s
commit-lint / conventional-commits (push) Successful in 4s
release / publish (push) Successful in 3m21s
2026-09-15 23:01:01 +03:00
ce94944c2d Merge feat/gpu-driven: HDR calibration and the HDR toggle crash fix
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 22:57:42 +03:00
65c1b9ca5c feat(render3d): HDR calibration; fix the HDR toggle crash and yellow reading as red
r3d_hdr_calibrate(peak, paper, black) feeds the tonemap's and the overlay's HDR10 variants and
the display's HDR metadata; ov_hdr_nits draws a calibration patch at a number of nits.

gpu_caps_probe asks the running Vulkan renderer's instance instead of making and destroying a
second one under Streamline's interposer, which left the next swapchain rebuild calling address 0.
The overlay gets an HDR10 variant, and the tonemap brightens HDR highlights by one factor rather
than per channel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 22:57:18 +03:00
95a65b05ca chore(release): v0.16.0
Some checks failed
bootstrap / cfree-fixpoint (push) Successful in 33s
ci / build-and-test (push) Successful in 3m29s
commit-lint / conventional-commits (push) Failing after 5s
docs / build-and-deploy (push) Successful in 41s
release / publish (push) Successful in 3m19s
2026-09-15 20:43:08 +03:00
d80786e99a perf(render3d): mesh-shader grass dispatches each tile with its own count; not yet counted as implemented
A chunk's dispatch was sized for its largest tile, so the far tiles beside a
near one ran thousands of empty invocations: 9.8 ms of grass at 4K on an RTX
3070 Ti. One dispatch per tile, sized to that tile, brings it to 5.0 ms - still
three times the chunked path's 1.7 (36 fps against 41), so GF_MESH_GRASS is not
implemented yet and the Advanced row says a coming update.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 20:40:47 +03:00
00ebd6df77 docs(changes): changesets for DLSS and Reflex, HDR output, mesh-shader grass, the Vulkan grass fix and app native
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 20:21:18 +03:00
00df8839e6 perf(render3d): the sky light baked once at start, the terrain load in four steps, actor cull bounds by height
- sky_start_yaw: a game that turns the sky at boot sets it before r3d_init and the image-based light
  is baked once at that yaw; sky_set_yaw to a yaw already baked bakes nothing.
- terrain_init_step: the height field and normals, the sun shadow, the materials, the patches and
  programs as separate steps; r3d_load_count is 8, so a loading bar moves through the terrain (half
  the start-up) instead of jumping over it. terrain_init runs the four in a row as before.
- The per-cascade actor cull centres its sphere at half the model's height and sizes it by the
  larger of height and radius: centred at the radius, it dropped a head at a cascade's edge (11 px
  in town, found by the drawstats comparison). Lake was byte-identical before and after.

OpenGL frames at the five viewpoints unchanged; the game's 59 self-tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 15:03:06 +03:00
f2b976c976 feat(render3d): load steps for a loading screen, four quality switches, and the ring's uniform usage
- r3d_open opens the window with nothing baked; r3d_load_count / r3d_load_step run the rest (sky
  and light, terrain, shadow and screen targets, cover and actors, grass) so a game can present a
  loading frame between them. r3d_init is the same calls in a row.
- sky_set_quality(width): the prefiltered sky light at 256 / 512 / 1024, baked again.
- post_set_msaa(samples): multisampling on OpenGL, remade in place (post_msaa_live is false on
  Vulkan); post_free frees the multisampled framebuffer too.
- STREAM_BUDGET_US is a variable; r3d_fog_scale multiplies the fog the day sets.
- Vulkan buffers carry UNIFORM_BUFFER usage: the frame's ring is bound as uniform buffers and was
  created without it (VUID-VkWriteDescriptorSet-descriptorType-00330, found on MoltenVK).

OpenGL frames at the five viewpoints unchanged; the game's 59 self-tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 14:46:55 +03:00
5b28063b52 feat(render3d): texture filtering and shadow resolution a game can change while it runs
- r3d_set_anisotropy(level) updates every mipmapped texture already loaded (OpenGL parameter,
  Vulkan sampler record), not only later uploads; the game's setting never reached the scanned
  materials, which load before the settings are read.
- shadow_set_res(size) remakes the cascades at 1024 / 2048 / 4096 (shadow_res replaces the
  SHADOW_RES constant); lighting.glsl reads the texel size from the map, so OpenGL frames at
  2048 are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 14:25:55 +03:00
c10abd9f9f feat(jobs): real OS threads - Job.parallel_for, fn name, thread-safe Sync
- `fn name` names a top-level function as a value (E_FNREF, lowers to @fn_<name>); the worker
  entry point for Job.parallel_for, which checks it takes (int, pointer-like) and returns void.
- runtime/native/threads.ll (pthreads) and threads_win.ll (Win32 SRWLOCK/CONDITION_VARIABLE): a
  pool of one worker per core but one, parked between batches; every thread claims chunks by
  compare-and-swap. Linked only into programs that use Job/Promise/Sync, by `ludicc -o`,
  `ludic build` and the test suite's build helper.
- Sync.* is real: native mutexes, atomics as cmpxchg retry loops (neither clang takes atomicrw,
  the PC's rejects seq_consistent), mutex-guarded channels, Sync.cpu_count from the OS.
- spawn/despawn on a pool thread stop the program with a located panic.
- examples/library/threads.ludic and its test; docs for fn, Job.parallel_for, Job.is_worker.
- Reseeded (bootstrap-cfree: out.ll == seed.ll). 141/141 on macOS; jobs, threads and the guard
  pass on Windows from the reseeded Windows seed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:52:22 +03:00
81d4344bdc chore(release): v0.15.0
Some checks failed
commit-lint / conventional-commits (push) Waiting to run
docs / build-and-deploy (push) Waiting to run
bootstrap / cfree-fixpoint (push) Successful in 41s
ci / build-and-test (push) Has been cancelled
release / publish (push) Successful in 3m16s
2026-09-15 09:55:37 +03:00
54eeef5f8d feat(render3d): gpu.ludic - the seam for a second graphics API, and what the GPU can do
Render state (depth, blending, culling, colour writes, alpha-to-coverage, depth bias,
scissor) and uniforms go through gpu_* / u_* and nowhere else; OpenGL state is cached and
only changes reach the driver. Frames are bit-identical to before at the fixed viewpoints.
R3D_GFX=gl|vk or gpu_request chooses a backend, falling back to OpenGL with a reason.

gpu_caps_probe() asks Vulkan, on Windows, for the 1.3 floor, ray tracing, mesh shaders, the
NVIDIA RTX generation, Reflex and HDR colour spaces, for a game's settings to grey out what
a machine cannot use; R3D_CAPS pretends to be a given card for tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 09:52:12 +03:00
043d8d81a2 chore(release): v0.14.2
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 39s
ci / build-and-test (push) Successful in 3m23s
commit-lint / conventional-commits (push) Successful in 4s
docs / build-and-deploy (push) Successful in 37s
release / publish (push) Successful in 3m11s
2026-09-14 15:35:40 +03:00
28e8769a8b fix(input): mouse_dx/dy report no motion on the first frame or across a cursor-mode change
The delta was this frame's position minus the last, and the last started at 0,0, so the
first frame reported the cursor's whole distance from the corner as motion. A cursor-mode
change did the same, switching between a locked cursor's virtual reticle and the real
cursor. Maroon Lake's camera adds mouse_dy to its pitch and came up pointing at the ground.

examples/library/input_mouse_rebase.ludic covers both cases, plus ordinary motion and
re-setting the mode already in force.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 15:35:26 +03:00
dc9138846f chore(release): v0.14.1
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 29s
ci / build-and-test (push) Successful in 3m22s
commit-lint / conventional-commits (push) Successful in 4s
release / publish (push) Successful in 3m12s
2026-09-13 12:46:46 +03:00
bfec11926f fix(render3d): a rim from outline_model goes out when the caller stops asking
The queue was only emptied by the next outline_model call, so the last highlighted tree kept
its rim after the player looked away. r3d_frame now calls outline_frame, which drops a batch
the previous frame closed and nobody reopened.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 12:46:46 +03:00
751532831a chore(release): v0.14.0
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 30s
ci / build-and-test (push) Successful in 3m21s
commit-lint / conventional-commits (push) Successful in 4s
release / publish (push) Successful in 3m11s
2026-09-13 05:03:41 +03:00
e58e8ae263 feat(render3d): UTF-8 overlay text and fonts that list their code points
ov_text, ov_text_w and ov_text_wrap decode UTF-8 instead of drawing bytes 32-126. font.json
may list the atlas's code points in "codes"; an atlas without it reads as before (ASCII
from "first"). A missing code point draws as '?', a cut-off sequence as one '?'.
overlay_font(dir) loads or swaps the atlas at run time, for a language with its own script.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 05:03:41 +03:00
a90c58eb09 chore(release): v0.13.3
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 30s
ci / build-and-test (push) Successful in 3m21s
commit-lint / conventional-commits (push) Successful in 4s
release / publish (push) Successful in 3m12s
2026-09-13 04:18:38 +03:00
d6ffdfa638 perf(render3d): a depth prepass for the near tree foliage
Needle-card crowns are many cut-out quads deep and a discarding shader turns early depth
rejection off, so every card behind the front one ran the full lighting shader. The near
tree LODs now write depth first (depth.frag, the same alpha coverage test), terrain under
them is rejected before shading, and the lit pass draws them with no discard and an equal
depth test (invariant gl_Position). R3D_NOPREPASS=1 restores the old path.

Dense forest on a Windows PC: 61 -> 78 fps at 3840x2160, 116 -> 164 fps at 1920x1080.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 04:18:38 +03:00
21bc611455 chore(release): v0.13.2
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 30s
ci / build-and-test (push) Successful in 3m22s
commit-lint / conventional-commits (push) Successful in 4s
docs / build-and-deploy (push) Successful in 38s
release / publish (push) Successful in 3m12s
2026-09-13 03:48:57 +03:00
39a7593521 fix(cli): link http.ll only for a program that calls hs_send
http_link_flags grepped the IR for "@hs_", which every program's header
declares, so `ludic build` linked the HTTP transport and Foundation into
everything - invisible on macOS, a failed link on Linux, where it broke four CI
cases (ludic run, the installed layout, ludic new, the seed build through
`ludic build`). It now looks for a call to hs_send: examples/library/http.ludic
has one, snake.ludic (which still declares ten @hs_ names) has none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 03:45:04 +03:00
096f851408 chore(release): v0.13.1
Some checks failed
bootstrap / cfree-fixpoint (push) Successful in 30s
ci / build-and-test (push) Failing after 3m2s
commit-lint / conventional-commits (push) Successful in 4s
release / publish (push) Failing after 3m2s
2026-09-13 03:32:18 +03:00
7586c3ad25 fix(ci): supply _NSGetExecutablePath on Linux, so the seed links and CI publishes
The asset-pack boot calls _NSGetExecutablePath, which glibc does not have, so
the Linux link of the compiler seed failed in every CI job - build-and-test,
cfree-fixpoint and every publish run - since packs landed. The last release CI
created was v0.7.0. The Linux shim now defines it over /proc/self/exe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 03:32:18 +03:00
762d39bdff chore(release): v0.13.0
Some checks failed
bootstrap / cfree-fixpoint (push) Failing after 21s
ci / build-and-test (push) Failing after 11s
commit-lint / conventional-commits (push) Successful in 4s
docs / build-and-deploy (push) Failing after 8s
release / publish (push) Failing after 11s
2026-09-13 03:29:55 +03:00
fb4d904ab6 Merge branch 'fix/arrows-http-backspace': held arrow keys, ludic build Http.* link, macOS Backspace
# Conflicts:
#	tools/ludic-cli/build.ludic
2026-09-13 03:28:29 +03:00
40d78cbd92 feat(windows): Http.* over WinHTTP, and the splash and window icon through WIC
http_win.ll implements http.ll's hs_* contract over WinHTTP: the request is a
record built on the game thread, the whole exchange runs on a worker thread,
TLS uses the system's certificate checks, and headers are answered from the
kept request handle. ludicc links it with winhttp instead of refusing Http.* on
Windows.

win32.ll decodes the splash and App.set_icon images with WIC (ole32): the
splash is a topmost borderless window at the artwork's size in points times the
display scale, composited over its background colour; the icon becomes an
HICON set on the window now or when win_open makes one.

Verified on the PC: examples/library/http.ludic prints its expected output, a
real GET to https://git.workshopsoft.io/ returns 200 with its body and
Content-Type, and the bundled Maroon Lake shows its splash centred at launch and
its icon in the title bar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 03:24:50 +03:00
55b0e2ebf6 feat(windows): the ludic CLI and ludic bundle on Windows
The CLI's shell commands go through shell(), which is run() on POSIX and a
scratch script handed to Git for Windows' bash on Windows (exit codes read
directly there). compile_app links through `ludicc -o` on Windows, ludic run
starts the .exe, and ludic-dev build and ensure_ludicc assemble
selfhost/ludicc.win.seed.ll, which ludic-dev reseed now writes beside the
macOS seed. ludic bundle makes build/<name>/ with a GUI-subsystem exe carrying
the .ico beside `app icon` as an llvm-rc resource, game.lpak and packs.index;
ludicc gains --gui and --link, and quotes its whole link line for cmd.exe.

Verified: ludic-dev test 135/135, selfhost-test 32/32; on the PC a checkout
bootstraps from the Windows seed, ludic-dev build makes the toolchain, and
`ludic bundle` makes build/Maroon Lake/, which runs from its own folder.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 03:01:33 +03:00
885943e73f fix(cocoa): the Delete key reports Key.Backspace (8)
AppKit gives kVK_Delete (51) the character NSDeleteCharacter, 127, which is
what both ev_keyval (the held-key set) and win_poll (the per-frame key)
received, so Key.Backspace, which folds to 8, never matched. Both now map key
code 51 to 8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 03:00:29 +03:00
09247c57cf fix(cli): ludic build links http.ll for a program that uses Http.*
compile_app linked gl.ll when the IR named @lgl_* but never http.ll and
Foundation for @hs_*, so examples/library/http.ludic failed to link under
`ludic build` on every hs_* symbol while `ludicc -o` built it. http_link_flags
greps for @hs_ and links them in both modes; ludic-dev test now builds the
example through `ludic build` as well.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 03:00:29 +03:00
6117f73602 fix(input): Key.Up/Down/Left/Right are the held set's 128-131
The arrow Key constants folded to the codes of w/s/a/d, which is what the
per-frame key reports for an arrow, but cocoa.ll has always stored an arrow in
the held-key set under 128-131. So Input.key_down(Key.Up) read the W bit and
Input.move_i's arrow half never moved anything. Input.key keeps its WASD alias,
so games comparing it with 'w' (snake, chronorift) still take the arrows.

New example input_arrows.ludic, checked by ludic-dev test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 03:00:29 +03:00
3300fb3957 feat(windows): sound, through XAudio2
audio_win.ll implements audio.ll's snd_* contract over XAudio2 from IR: a
source voice per clip, restart on play, LoopCount for loops, SetVolume,
SetFrequencyRatio and a balance pan through SetOutputMatrix, with the COM
slots taken from the SDK's xaudio2.h. Clips are RIFF WAVE read through
lp_pak_open (weakly referenced), so a packed sound loads directly. ludicc links
it with xaudio2 and ole32, and silences xinput.lib's importeddllmain warning.

Verified: ludic-dev test 135/135, selfhost-test 32/32; on the PC a harness
loads, plays, pans, loops and stops clips, and Maroon Lake windowed reports
"sound: 31 of 31 clips loaded".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 02:42:48 +03:00
00d25dcc3e feat(windows): a window - win32.ll, WGL on it, and a windowed Windows build
win32.ll implements cocoa.ll's contracts over user32 and xinput: the message
pump, the held-key set and frame key in Ludic codes, the mouse with raw input
for cursor mode 2, clip-based cursor modes released on focus loss, XInput pads,
and the software framebuffer present. win32_gl.ll puts the WGL 4.1 core context
on that window (vsync, borderless full screen); gl_win.ll's context code is now
lgl_wgl_core, shared with the headless hidden window, whose win_gl_* stubs move
to gl_win_nowin.ll. audio_win.ll links Audio.* silently for now.

Verified: macOS fixpoint, ludic-dev test 135/135, selfhost-test 32/32; on the
PC gl_triangle renders identically headless and in a real window, and Maroon
Lake builds windowed and runs a playtest to frame 240 in the desktop session.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 02:33:53 +03:00
cb05721a89 feat(windows): Gl.* on Windows, through WGL and a driver-filled thunk table
gl_win.ll creates a hidden-window WGL 4.1 core context and carries gl.ll's
float/memory helpers, with ldexp and QueryPerformanceCounter in place of the
libSystem calls. glgen now also writes gl_thunks_win.ll: the same 478 thunks,
calling through pointers that @lgl_win_load fills from wglGetProcAddress (and
opengl32.dll for GL 1.1). ludicc links the pair against opengl32/gdi32/user32
on a Windows target.

Verified: gl_api.ludic and gl_thunks.ll regenerate byte-identically, ludic-dev
test 135/135, selfhost-test 32/32, and headless gl_triangle on an RTX 3070 Ti
matches the macOS frame to within one level per channel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 02:10:36 +03:00
5801005fca feat(windows): a Windows target for ludicc, and the compiler builds itself there
--target <triple> (default: the host, from OS=Windows_NT) selects the Windows
runtime. emit_win.ludic defines the POSIX names the backend already calls over
the UCRT and Win32 in IR, so rename replaces an existing file, ftell is 64-bit,
and fopen is binary. Known folders follow %APPDATA% / %LOCALAPPDATA% / %TEMP%,
and the driver speaks cmd.exe, writes .exe outputs and finds LLVM's clang.

Verified: macOS three-stage fixpoint, ludic-dev test 135/135, and on Windows
the Mac-emitted Windows IR and the Windows-built compiler's IR are identical
through two generations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 01:59:41 +03:00
572e09b2b1 chore(release): v0.12.1
Some checks failed
bootstrap / cfree-fixpoint (push) Failing after 10s
ci / build-and-test (push) Failing after 9s
commit-lint / conventional-commits (push) Successful in 2s
release / publish (push) Failing after 10s
2026-09-13 00:29:37 +03:00
3e76785b40 fix(render3d): lakes clipped to their ellipse; r3d_fog_base
A water body other than the reflecting one drew its whole bounding rectangle,
so the corners outside the lake's carved ellipse showed water over dry ground;
those bodies now discard outside the ellipse. r3d_fog_base (default 0) is the
height the height fog is measured from, so maps sharing one datum at different
heights get the same air.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 00:29:37 +03:00
7a0c03dd21 chore(release): v0.12.0
Some checks failed
release / publish (push) Failing after 10s
2026-09-13 00:03:56 +03:00
a4a3d75cd9 feat(render3d): replace the world at run time, water bodies, terrain_sea
terrain_reload/terrain_unload release one map's height field, survey, photograph
and patch bounds and generate another at any TERRAIN_HALF; scatter_clear_all
(with streams), actor_clear_all, col_reset and mesh_free empty the scene;
water_body_add/water_bodies_clear draw several still-water planes with one
reflecting; terrain_sea separates the coast's sea level from the carved lake's,
and grass keeps off both. Fixes CDLOD patch bounds for TERRAIN_HALF != 4096 and
water_init leaking a mesh and program per call. examples/rendering/reload.ludic.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 00:03:40 +03:00