feat: per-voice audio, outlines for what is not an actor, and a coast
Three things a game could not say, each of which had been worked around. Audio.play_at(id, gain:, pitch:, pan:) fires a one-shot with its own gain, pitch and stereo position. Audio.volume and Audio.pitch are global - they are the options screen - so a game placing a sound in the world was fighting them, and distance attenuation was simply not expressible. The backend already took volume and rate per call; this adds setPan: alongside them and stops routing through the master state. ludic.render3d gains outline_model(model, mat, width, r, g, b): a rim around something that is not an Actor. The outline pass walked the actor list and stopped, so instanced scatter - a forest - could not be highlighted at all. It is a queue flushed by the same pass, which is what gets the depth test right when the caller does not control pass order. And terrain_coast(cx, cz, margin, fall), the other way to make an island: the sea around the survey's own edge rather than cut out of the middle of it. terrain_island measures a radius from a centre, which drowns two thirds of a real survey to make an island of the rest; this measures inward from the boundary, so everything the data covers stays land and the coast is where the data runs out. Both modes gained a strand - the last few metres of height either side of the water line compressed, which stretches a cliff plunge out into beach and shallows. 132 regression tests and the self-host fixpoints pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
39ad8e85d9
commit
3c27606747
15 changed files with 30113 additions and 29690 deletions
|
|
@ -15,7 +15,7 @@ function is_intrinsic2(name: pointer) -> bool {
|
|||
if (name == "win_pad") or (name == "win_touch") { return true } # #51 gamepad / touch
|
||||
if (name == "win_cursor_mode") { return true } # #89 cursor capture
|
||||
if (name == "snd_load") or (name == "snd_play") or (name == "snd_stop") { return true } # #22 audio
|
||||
if (name == "snd_playing") or (name == "snd_set_volume") or (name == "snd_set_rate") { return true }
|
||||
if (name == "snd_playing") or (name == "snd_set_volume") or (name == "snd_set_rate") or (name == "snd_set_pan") { return true }
|
||||
if (name == "hs_req_new") or (name == "hs_req_header") or (name == "hs_req_body") { return true } # #6 HTTP
|
||||
if (name == "hs_send") or (name == "hs_done") or (name == "hs_status") or (name == "hs_body") { return true }
|
||||
if (name == "hs_blen") or (name == "hs_header") or (name == "hs_free") { return true }
|
||||
|
|
@ -78,6 +78,7 @@ function emit_intrinsic2(name: pointer, e: Node) -> Val {
|
|||
if (name == "snd_playing") { let a = arg_code(e, 0); return val(emit_bind(`call i32 @snd_playing(ptr {a})`), "int") }
|
||||
if (name == "snd_set_volume") { let a = arg_code(e, 0); let b = arg_code(e, 1); emit(" call void @snd_set_volume(ptr "); emit(a); emit(", i32 "); emit(b); emit(")\n"); return val("0", "void") }
|
||||
if (name == "snd_set_rate") { let a = arg_code(e, 0); let b = arg_code(e, 1); emit(" call void @snd_set_rate(ptr "); emit(a); emit(", i32 "); emit(b); emit(")\n"); return val("0", "void") }
|
||||
if (name == "snd_set_pan") { let a = arg_code(e, 0); let b = arg_code(e, 1); emit(" call void @snd_set_pan(ptr "); emit(a); emit(", i32 "); emit(b); emit(")\n"); return val("0", "void") }
|
||||
# #6 HTTP transport — NSURLConnection on a background thread (http.ll).
|
||||
if (name == "hs_req_new") { let a = arg_code(e, 0); let b = arg_code(e, 1); return val(emit_bind(`call ptr @hs_req_new(ptr {a}, ptr {b})`), "pointer") }
|
||||
if (name == "hs_req_header") { let a = arg_code(e, 0); let b = arg_code(e, 1); let c = arg_code(e, 2); emit(" call void @hs_req_header(ptr "); emit(a); emit(", ptr "); emit(b); emit(", ptr "); emit(c); emit(")\n"); return val("0", "void") }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue