wip(0.S3): the packages migrated by ludic migrate state packages - every package test green
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1e8b5b0523
commit
07505e7ef2
294 changed files with 14996 additions and 14675 deletions
|
|
@ -1,56 +1,56 @@
|
|||
# boot.ludic - the window, the renderer on a plate (no terrain, no grass, no water), the plate and
|
||||
# its sky, then the scene named by R3D_SCENE (else the first one added)
|
||||
function lab_draw() -> void {
|
||||
actor_draw()
|
||||
scatter_draw()
|
||||
if lb_draw != null { lb_draw() }
|
||||
function lab_draw(lab_st: LabState, render3d_st: mut Render3dState) -> void {
|
||||
actor_draw(render3d_st)
|
||||
scatter_draw(render3d_st)
|
||||
if lab_st.lb_draw != null { lab_st.lb_draw() }
|
||||
}
|
||||
function lab_casters(light_vp: floats) -> void {
|
||||
actor_draw_casters(light_vp)
|
||||
scatter_draw_casters(light_vp)
|
||||
function lab_casters(render3d_st: mut Render3dState, light_vp: floats) -> void {
|
||||
actor_draw_casters(render3d_st, light_vp)
|
||||
scatter_draw_casters(render3d_st, light_vp)
|
||||
}
|
||||
function lab_pick_scene() -> int {
|
||||
function lab_pick_scene(lab_st: mut LabState) -> int {
|
||||
if LAB_COUNT == 0 { return -1 }
|
||||
lb_scene = LabScenes[0].key
|
||||
if Os.has_env("R3D_SCENE") { lb_scene = Os.env("R3D_SCENE") }
|
||||
return labscenes_find(lb_scene)
|
||||
lab_st.lb_scene = LabScenes[0].key
|
||||
if Os.has_env("R3D_SCENE") { lab_st.lb_scene = Os.env("R3D_SCENE") }
|
||||
return labscenes_find(lab_st.lb_scene)
|
||||
}
|
||||
# once, from the program's Start handler
|
||||
export function lab_boot() -> void {
|
||||
lb_windowed = is_windowed()
|
||||
let k = lab_pick_scene()
|
||||
export function lab_boot(lab_st: mut LabState, render3d_st: mut Render3dState) -> void {
|
||||
lab_st.lb_windowed = is_windowed()
|
||||
let k = lab_pick_scene(lab_st)
|
||||
if k < 0 {
|
||||
print(`lab: no scene called '{lb_scene}' - {lab_scene_names()}`)
|
||||
print(`lab: no scene called '{lab_st.lb_scene}' - {lab_scene_names()}`)
|
||||
quit()
|
||||
return
|
||||
}
|
||||
var ww = 1920
|
||||
var wh = 1080
|
||||
if lb_windowed {
|
||||
if lab_st.lb_windowed {
|
||||
ww = 960
|
||||
wh = 540
|
||||
}
|
||||
r3d_plate_mode(true)
|
||||
r3d_sky_path = `{lab_plate_dir()}/sky.hdr`
|
||||
if not r3d_init(ww, wh, lb_title) {
|
||||
r3d_plate_mode(render3d_st, true)
|
||||
render3d_st.r3d_sky_path = `{lab_plate_dir(lab_st)}/sky.hdr`
|
||||
if not r3d_init(render3d_st, ww, wh, lab_st.lb_title) {
|
||||
quit()
|
||||
return
|
||||
}
|
||||
if lb_font != "" { overlay_init(lb_font) }
|
||||
r3d_on_draw(fn lab_draw)
|
||||
r3d_on_casters(fn lab_casters)
|
||||
lab_plate_load()
|
||||
lab_shots_reset()
|
||||
lb_out = `build/lab/{lb_scene}`
|
||||
if lab_st.lb_font != "" { overlay_init(render3d_st, lab_st.lb_font) }
|
||||
r3d_on_draw(render3d_st, fn lab_draw)
|
||||
r3d_on_casters(render3d_st, fn lab_casters)
|
||||
lab_plate_load(lab_st, render3d_st)
|
||||
lab_shots_reset(lab_st)
|
||||
lab_st.lb_out = `build/lab/{lab_st.lb_scene}`
|
||||
let sc = LabScenes[k]
|
||||
lb_draw = sc.draw
|
||||
lab_st.lb_draw = sc.draw
|
||||
if sc.setup != null { sc.setup() }
|
||||
if lab_shot_count() == 0 { lab_shot_at("plate", 0.0, 1.0, 0.0, 8.0, 0.0, 15.0) }
|
||||
lab_shot_apply(0)
|
||||
if not lb_windowed {
|
||||
if lab_shot_count(lab_st) == 0 { lab_shot_at(lab_st, "plate", 0.0, 1.0, 0.0, 8.0, 0.0, 15.0) }
|
||||
lab_shot_apply(lab_st, render3d_st, 0)
|
||||
if not lab_st.lb_windowed {
|
||||
Fs.mkdir("build")
|
||||
Fs.mkdir("build/lab")
|
||||
Fs.mkdir(lb_out)
|
||||
Fs.mkdir(lab_st.lb_out)
|
||||
}
|
||||
print(`lab: scene {lb_scene}, {lab_shot_count()} shots`)
|
||||
print(`lab: scene {lab_st.lb_scene}, {lab_shot_count(lab_st)} shots`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,50 @@
|
|||
# loop.ludic - each frame: the scene's tick by a fixed step, the shot's camera, its caption, and -
|
||||
# headless - the picture once the shot has settled, then the next shot, then quit. In a window
|
||||
# N and P step through the shots.
|
||||
export function lab_input() -> void {
|
||||
if not lb_windowed { return }
|
||||
export function lab_input(lab_st: mut LabState, render3d_st: mut Render3dState) -> void {
|
||||
if not lab_st.lb_windowed { return }
|
||||
Input.poll()
|
||||
let n = lab_shot_count()
|
||||
let n = lab_shot_count(lab_st)
|
||||
if n > 0 and Input.key_pressed(key: 'n') {
|
||||
lb_shot = (lb_shot + 1) % n
|
||||
lab_shot_apply(lb_shot)
|
||||
lab_st.lb_shot = (lab_st.lb_shot + 1) % n
|
||||
lab_shot_apply(lab_st, render3d_st, lab_st.lb_shot)
|
||||
}
|
||||
if n > 0 and Input.key_pressed(key: 'p') {
|
||||
lb_shot = (lb_shot + n - 1) % n
|
||||
lab_shot_apply(lb_shot)
|
||||
lab_st.lb_shot = (lab_st.lb_shot + n - 1) % n
|
||||
lab_shot_apply(lab_st, render3d_st, lab_st.lb_shot)
|
||||
}
|
||||
}
|
||||
export function lab_render() -> void {
|
||||
lb_frame += 1
|
||||
let k = labscenes_find(lb_scene)
|
||||
export function lab_render(lab_st: mut LabState, render3d_st: mut Render3dState) -> void {
|
||||
lab_st.lb_frame += 1
|
||||
let k = labscenes_find(lab_st.lb_scene)
|
||||
if k >= 0 and LabScenes[k].tick != null { LabScenes[k].tick(1.0 / 60.0) }
|
||||
r3d_frame(lab_time())
|
||||
lab_caption()
|
||||
if not lb_windowed { lab_take() }
|
||||
r3d_present()
|
||||
r3d_frame(render3d_st, lab_time(lab_st))
|
||||
lab_caption(lab_st, render3d_st)
|
||||
if not lab_st.lb_windowed { lab_take(lab_st, render3d_st) }
|
||||
r3d_present(render3d_st)
|
||||
}
|
||||
function lab_caption() -> void {
|
||||
if lb_font == "" { return }
|
||||
ov_begin()
|
||||
function lab_caption(lab_st: LabState, render3d_st: mut Render3dState) -> void {
|
||||
if lab_st.lb_font == "" { return }
|
||||
ov_begin(render3d_st)
|
||||
var name = ""
|
||||
if lb_shot < lab_shot_count() { name = lb_shot_names[lb_shot] }
|
||||
ov_rect(0, 0, 900, 64, 0.0, 0.0, 0.0, 0.55)
|
||||
ov_text(20, 10, 30, `{lb_scene} / {name} ({lb_shot + 1} of {lab_shot_count()})`, 1.0, 1.0, 1.0, 1.0)
|
||||
if len(lb_note) > 0 { ov_text(20, 42, 18, lb_note, 0.8, 0.8, 0.8, 1.0) }
|
||||
ov_end()
|
||||
if lab_st.lb_shot < lab_shot_count(lab_st) { name = lab_st.lb_shot_names[lab_st.lb_shot] }
|
||||
ov_rect(render3d_st, 0, 0, 900, 64, 0.0, 0.0, 0.0, 0.55)
|
||||
ov_text(render3d_st, 20, 10, 30, `{lab_st.lb_scene} / {name} ({lab_st.lb_shot + 1} of {lab_shot_count(lab_st)})`, 1.0, 1.0, 1.0, 1.0)
|
||||
if len(lab_st.lb_note) > 0 { ov_text(render3d_st, 20, 42, 18, lab_st.lb_note, 0.8, 0.8, 0.8, 1.0) }
|
||||
ov_end(render3d_st)
|
||||
}
|
||||
function lab_take() -> void {
|
||||
lb_wait += 1
|
||||
if lb_wait < lb_settle { return }
|
||||
let base = `{lb_out}/{lb_shot_names[lb_shot]}`
|
||||
r3d_screenshot(`{base}.ppm`)
|
||||
if lab_ppm_to_png(`{base}.ppm`, `{base}.png`) { print(`lab: shot {base}.png`) } else { print(`lab: shot {base}.ppm`) }
|
||||
lb_shots_taken += 1
|
||||
lb_wait = 0
|
||||
lb_shot += 1
|
||||
if lb_shot >= lab_shot_count() {
|
||||
function lab_take(lab_st: mut LabState, render3d_st: mut Render3dState) -> void {
|
||||
lab_st.lb_wait += 1
|
||||
if lab_st.lb_wait < lab_st.lb_settle { return }
|
||||
let base = `{lab_st.lb_out}/{lab_st.lb_shot_names[lab_st.lb_shot]}`
|
||||
r3d_screenshot(render3d_st, `{base}.ppm`)
|
||||
if lab_ppm_to_png(lab_st, `{base}.ppm`, `{base}.png`) { print(`lab: shot {base}.png`) } else { print(`lab: shot {base}.ppm`) }
|
||||
lab_st.lb_shots_taken += 1
|
||||
lab_st.lb_wait = 0
|
||||
lab_st.lb_shot += 1
|
||||
if lab_st.lb_shot >= lab_shot_count(lab_st) {
|
||||
quit()
|
||||
return
|
||||
}
|
||||
lab_shot_apply(lb_shot)
|
||||
lab_shot_apply(lab_st, render3d_st, lab_st.lb_shot)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,21 @@
|
|||
# plate.ludic - the stage: a flat disc 40 m across at y = 0 with a line every metre, lit by the
|
||||
# package's own small sky (a sun 40 degrees up), and nothing else. Its files are in plate/.
|
||||
var lb_plate: Actor = null
|
||||
var lb_plate_dir: string = ""
|
||||
|
||||
# the package's plate/ directory: beside the project (a checkout of the toolchain) or installed
|
||||
export function lab_plate_dir() -> string {
|
||||
if lb_plate_dir != "" { return lb_plate_dir }
|
||||
lb_plate_dir = "packages/ludic.lab/plate"
|
||||
if not Fs.exists(`{lb_plate_dir}/plate.gltf`) { lb_plate_dir = `{r3d_home()}/packages/ludic.lab/plate` }
|
||||
return lb_plate_dir
|
||||
export function lab_plate_dir(lab_st: mut LabState) -> string {
|
||||
if lab_st.lb_plate_dir != "" { return lab_st.lb_plate_dir }
|
||||
lab_st.lb_plate_dir = "packages/ludic.lab/plate"
|
||||
if not Fs.exists(`{lab_st.lb_plate_dir}/plate.gltf`) { lab_st.lb_plate_dir = `{r3d_home()}/packages/ludic.lab/plate` }
|
||||
return lab_st.lb_plate_dir
|
||||
}
|
||||
function lab_plate_load() -> void {
|
||||
let m = gltf_load(lab_plate_dir(), "plate.gltf", "plate")
|
||||
function lab_plate_load(lab_st: mut LabState, render3d_st: mut Render3dState) -> void {
|
||||
let m = gltf_load(render3d_st, lab_plate_dir(lab_st), "plate.gltf", "plate")
|
||||
if m == null { return }
|
||||
lb_plate = actor_new(m)
|
||||
lb_plate.casts = false
|
||||
lb_plate.cull = 0.0
|
||||
lb_plate.radius = 0.0
|
||||
actor_place(lb_plate, 0.0, 0.0, 0.0, 0.0)
|
||||
lab_st.lb_plate = actor_new(render3d_st, m)
|
||||
lab_st.lb_plate.casts = false
|
||||
lab_st.lb_plate.cull = 0.0
|
||||
lab_st.lb_plate.radius = 0.0
|
||||
actor_place(lab_st.lb_plate, 0.0, 0.0, 0.0, 0.0)
|
||||
}
|
||||
# the ground under (x, z): the plate is flat at 0
|
||||
export function lab_ground_y(x: float, z: float) -> float { return 0.0 }
|
||||
|
|
@ -27,10 +25,10 @@ export function lab_stand(a: Actor, x: float, z: float, yaw: float) -> void {
|
|||
actor_place(a, x, lab_ground_y(x, z), z, yaw)
|
||||
}
|
||||
# a model from a glTF file stood on the plate: the one call a scene usually needs
|
||||
export function lab_model(dir: string, file: string, node: string, x: float, z: float, yaw: float) -> Actor {
|
||||
let m = gltf_load(dir, file, node)
|
||||
export function lab_model(render3d_st: mut Render3dState, dir: string, file: string, node: string, x: float, z: float, yaw: float) -> Actor {
|
||||
let m = gltf_load(render3d_st, dir, file, node)
|
||||
if m == null { return null }
|
||||
let a = actor_new(m)
|
||||
let a = actor_new(render3d_st, m)
|
||||
lab_stand(a, x, z, yaw)
|
||||
return a
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,27 @@
|
|||
# png.ludic - the renderer writes a frame as a PPM; the lab keeps it as a PNG, stored rather than
|
||||
# compressed (a PNG anything opens, with no zlib here): the shot is the PPM's pixels, filter 0
|
||||
# on every row, in deflate's stored blocks, with its CRCs and its Adler-32.
|
||||
var lp_table: []long = null
|
||||
|
||||
function lp_table_init() -> void {
|
||||
if lp_table != null { return }
|
||||
lp_table = new []long
|
||||
function lp_table_init(lab_st: mut LabState) -> void {
|
||||
if lab_st.lp_table != null { return }
|
||||
lab_st.lp_table = new []long
|
||||
let poly: long = 3988292384 # 0xEDB88320: eight hex digits would be a 32-bit pattern
|
||||
for n in 0 .. 256 {
|
||||
var c = long(n)
|
||||
for k in 0 .. 8 {
|
||||
if (c & long(1)) != long(0) { c = (c >> long(1)) ^ poly } else { c = c >> long(1) }
|
||||
}
|
||||
push(lp_table, c)
|
||||
push(lab_st.lp_table, c)
|
||||
}
|
||||
}
|
||||
# CRC-32 of out[from .. from + n)
|
||||
function lp_crc(out: []byte, from: int, n: int) -> long {
|
||||
lp_table_init()
|
||||
function lp_crc(lab_st: mut LabState, out: []byte, from: int, n: int) -> long {
|
||||
lp_table_init(lab_st)
|
||||
let mask: long = 4294967295
|
||||
var c = mask
|
||||
for i in from .. from + n {
|
||||
let k = int((c ^ long(out[i])) & long(255))
|
||||
c = lp_table[k] ^ (c >> long(8))
|
||||
c = lab_st.lp_table[k] ^ (c >> long(8))
|
||||
}
|
||||
return c ^ mask
|
||||
}
|
||||
|
|
@ -36,9 +35,7 @@ function lp_tag(out: []byte, at: int, tag: string) -> void {
|
|||
for i in 0 .. 4 { out[at + i] = tag[i] }
|
||||
}
|
||||
# a PPM's header: "P6", width, height, maxval, each after white space; returns the pixel offset
|
||||
var lp_w: int = 0
|
||||
var lp_h: int = 0
|
||||
function lp_ppm_header(d: []byte) -> int {
|
||||
function lp_ppm_header(lab_st: mut LabState, d: []byte) -> int {
|
||||
var i = 2
|
||||
var got = 0
|
||||
var vals = new []int
|
||||
|
|
@ -52,17 +49,17 @@ function lp_ppm_header(d: []byte) -> int {
|
|||
push(vals, v)
|
||||
got += 1
|
||||
}
|
||||
lp_w = vals[0]
|
||||
lp_h = vals[1]
|
||||
lab_st.lp_w = vals[0]
|
||||
lab_st.lp_h = vals[1]
|
||||
return i + 1
|
||||
}
|
||||
# the PPM at `ppm` as a PNG at `png`; the PPM is removed
|
||||
export function lab_ppm_to_png(ppm: string, png: string) -> bool {
|
||||
export function lab_ppm_to_png(lab_st: mut LabState, ppm: string, png: string) -> bool {
|
||||
let d = Fs.read_bytes(ppm)
|
||||
if d == null or len(d) < 8 { return false }
|
||||
let px = lp_ppm_header(d)
|
||||
let w = lp_w
|
||||
let h = lp_h
|
||||
let px = lp_ppm_header(lab_st, d)
|
||||
let w = lab_st.lp_w
|
||||
let h = lab_st.lp_h
|
||||
let row = w * 3 + 1
|
||||
let raw = row * h
|
||||
let blocks = (raw + 65534) / 65535
|
||||
|
|
@ -81,7 +78,7 @@ export function lab_ppm_to_png(ppm: string, png: string) -> bool {
|
|||
out[at + 18] = 0
|
||||
out[at + 19] = 0
|
||||
out[at + 20] = 0
|
||||
lp_put32(out, at + 21, lp_crc(out, at + 4, 17))
|
||||
lp_put32(out, at + 21, lp_crc(lab_st, out, at + 4, 17))
|
||||
at += 25
|
||||
lp_put32(out, at, long(idat))
|
||||
lp_tag(out, at + 4, "IDAT")
|
||||
|
|
@ -118,11 +115,11 @@ export function lab_ppm_to_png(ppm: string, png: string) -> bool {
|
|||
}
|
||||
lp_put32(out, o, long(b) * long(65536) + long(a))
|
||||
o += 4
|
||||
lp_put32(out, o, lp_crc(out, at + 4, o - at - 4))
|
||||
lp_put32(out, o, lp_crc(lab_st, out, at + 4, o - at - 4))
|
||||
o += 4
|
||||
lp_put32(out, o, long(0))
|
||||
lp_tag(out, o + 4, "IEND")
|
||||
lp_put32(out, o + 8, lp_crc(out, o + 4, 4))
|
||||
lp_put32(out, o + 8, lp_crc(lab_st, out, o + 4, 4))
|
||||
o += 12
|
||||
if not Fs.write_bytes(png, out, o) { return false }
|
||||
Fs.remove(ppm)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
# shots.ludic - a scene names its cameras; the loop takes them in order
|
||||
function lab_shots_reset() -> void {
|
||||
lb_shot_names = new []string
|
||||
lb_shot_pose = new []float
|
||||
function lab_shots_reset(lab_st: mut LabState) -> void {
|
||||
lab_st.lb_shot_names = new []string
|
||||
lab_st.lb_shot_pose = new []float
|
||||
}
|
||||
# a camera at (x, y, z) looking along yaw / pitch, both in DEGREES (cam_set's units)
|
||||
export function lab_shot(name: string, x: float, y: float, z: float, yaw_deg: float, pitch_deg: float) -> void {
|
||||
push(lb_shot_names, name)
|
||||
push(lb_shot_pose, x)
|
||||
push(lb_shot_pose, y)
|
||||
push(lb_shot_pose, z)
|
||||
push(lb_shot_pose, yaw_deg)
|
||||
push(lb_shot_pose, pitch_deg)
|
||||
export function lab_shot(lab_st: mut LabState, name: string, x: float, y: float, z: float, yaw_deg: float, pitch_deg: float) -> void {
|
||||
push(lab_st.lb_shot_names, name)
|
||||
push(lab_st.lb_shot_pose, x)
|
||||
push(lab_st.lb_shot_pose, y)
|
||||
push(lab_st.lb_shot_pose, z)
|
||||
push(lab_st.lb_shot_pose, yaw_deg)
|
||||
push(lab_st.lb_shot_pose, pitch_deg)
|
||||
}
|
||||
# a camera `dist` metres from the point (tx, ty, tz), from bearing `from_deg` (0 = from +z),
|
||||
# `up_deg` above the horizontal, looking at the point
|
||||
export function lab_shot_at(name: string, tx: float, ty: float, tz: float, dist: float, from_deg: float, up_deg: float) -> void {
|
||||
export function lab_shot_at(lab_st: mut LabState, name: string, tx: float, ty: float, tz: float, dist: float, from_deg: float, up_deg: float) -> void {
|
||||
let b = Math.deg_to_rad(from_deg)
|
||||
let e = Math.deg_to_rad(up_deg)
|
||||
let hd = dist * Math.cos(e)
|
||||
|
|
@ -22,14 +22,14 @@ export function lab_shot_at(name: string, tx: float, ty: float, tz: float, dist:
|
|||
let cz = tz + Math.cos(b) * hd
|
||||
let cy = ty + dist * Math.sin(e)
|
||||
let yaw = Math.atan2(cx - tx, cz - tz) * (180.0 / PI)
|
||||
lab_shot(name, cx, cy, cz, yaw, -up_deg)
|
||||
lab_shot(lab_st, name, cx, cy, cz, yaw, -up_deg)
|
||||
}
|
||||
export function lab_shot_count() -> int {
|
||||
if lb_shot_names == null { return 0 }
|
||||
return len(lb_shot_names)
|
||||
export function lab_shot_count(lab_st: LabState) -> int {
|
||||
if lab_st.lb_shot_names == null { return 0 }
|
||||
return len(lab_st.lb_shot_names)
|
||||
}
|
||||
function lab_shot_apply(i: int) -> void {
|
||||
if i < 0 or i >= lab_shot_count() { return }
|
||||
function lab_shot_apply(lab_st: LabState, render3d_st: mut Render3dState, i: int) -> void {
|
||||
if i < 0 or i >= lab_shot_count(lab_st) { return }
|
||||
let o = i * 5
|
||||
cam_set(lb_shot_pose[o], lb_shot_pose[o + 1], lb_shot_pose[o + 2], lb_shot_pose[o + 3], lb_shot_pose[o + 4])
|
||||
cam_set(render3d_st, lab_st.lb_shot_pose[o], lab_st.lb_shot_pose[o + 1], lab_st.lb_shot_pose[o + 2], lab_st.lb_shot_pose[o + 3], lab_st.lb_shot_pose[o + 4])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,34 @@
|
|||
# state.ludic - which scene, its shots, and where the loop is in them
|
||||
var lb_scene: string = ""
|
||||
var lb_frame: int = 0
|
||||
var lb_shot_names: []string = null
|
||||
var lb_shot_pose: []float = null # 5 per shot: x, y, z, yaw and pitch in degrees
|
||||
var lb_shot: int = 0 # the shot being taken or looked at
|
||||
var lb_wait: int = 0 # frames held on it so far
|
||||
var lb_settle: int = 45 # frames a shot is held before it is taken
|
||||
var lb_out: string = "" # build/lab/<scene>
|
||||
var lb_windowed: bool = false
|
||||
var lb_note: string = "" # one line a scene may show under its title
|
||||
var lb_font: string = "" # an overlay font atlas directory; "" draws no captions
|
||||
var lb_title: string = "Ludic Lab"
|
||||
var lb_draw: fn() = null # the scene's own drawing, beside the actors
|
||||
var lb_shots_taken: int = 0
|
||||
export state LabState {
|
||||
lb_plate: Actor = null
|
||||
lb_plate_dir: string = ""
|
||||
lp_table: []long = null
|
||||
lp_w: int = 0
|
||||
lp_h: int = 0
|
||||
lb_scene: string = ""
|
||||
lb_frame: int = 0
|
||||
lb_shot_names: []string = null
|
||||
lb_shot_pose: []float = null # 5 per shot: x, y, z, yaw and pitch in degrees
|
||||
lb_shot: int = 0 # the shot being taken or looked at
|
||||
lb_wait: int = 0 # frames held on it so far
|
||||
lb_settle: int = 45 # frames a shot is held before it is taken
|
||||
lb_out: string = "" # build/lab/<scene>
|
||||
lb_windowed: bool = false
|
||||
lb_note: string = "" # one line a scene may show under its title
|
||||
lb_font: string = "" # an overlay font atlas directory; "" draws no captions
|
||||
lb_title: string = "Ludic Lab"
|
||||
lb_draw: fn() = null # the scene's own drawing, beside the actors
|
||||
lb_shots_taken: int = 0
|
||||
}
|
||||
|
||||
# frames a shot settles before it is taken (streaming, auto-exposure); 45 by default
|
||||
export function lab_settle(frames: int) -> void { lb_settle = Math.max(1, frames) }
|
||||
export function lab_settle(lab_st: mut LabState, frames: int) -> void { lab_st.lb_settle = Math.max(1, frames) }
|
||||
# the overlay's font atlas (a directory with font.json and font.png) for the captions
|
||||
export function lab_font(dir: string) -> void { lb_font = dir }
|
||||
export function lab_title(title: string) -> void { lb_title = title }
|
||||
export function lab_font(lab_st: mut LabState, dir: string) -> void { lab_st.lb_font = dir }
|
||||
export function lab_title(lab_st: mut LabState, title: string) -> void { lab_st.lb_title = title }
|
||||
# one line under the scene's title in a window
|
||||
export function lab_note(s: string) -> void { lb_note = s }
|
||||
export function lab_note(lab_st: mut LabState, s: string) -> void { lab_st.lb_note = s }
|
||||
# the scene being shown, and the frame the clock is on (60 a second, whatever the machine)
|
||||
export function lab_scene() -> string { return lb_scene }
|
||||
export function lab_frame() -> int { return lb_frame }
|
||||
export function lab_time() -> float { return float(lb_frame) / 60.0 }
|
||||
export function lab_scene(lab_st: LabState) -> string { return lab_st.lb_scene }
|
||||
export function lab_frame(lab_st: LabState) -> int { return lab_st.lb_frame }
|
||||
export function lab_time(lab_st: LabState) -> float { return float(lab_st.lb_frame) / 60.0 }
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ program LabTest {
|
|||
Fs.write_bytes(path, b, len(hdr) + 12)
|
||||
}
|
||||
|
||||
test "a PPM becomes a PNG with its signature, its size and a valid IEND" {
|
||||
test "a PPM becomes a PNG with its signature, its size and a valid IEND" (lab_st: mut LabState) {
|
||||
let dir = Os.temp_dir()
|
||||
ppm(`{dir}/lab_test.ppm`)
|
||||
expect(lab_ppm_to_png(`{dir}/lab_test.ppm`, `{dir}/lab_test.png`))
|
||||
expect(lab_ppm_to_png(lab_st, `{dir}/lab_test.ppm`, `{dir}/lab_test.png`))
|
||||
let p = Fs.read_bytes(`{dir}/lab_test.png`)
|
||||
expect(p != null)
|
||||
expect_eq(p[0], 137)
|
||||
|
|
@ -35,15 +35,15 @@ program LabTest {
|
|||
expect(not Fs.exists(`{dir}/lab_test.ppm`))
|
||||
}
|
||||
|
||||
test "a camera at a point looks back at it" {
|
||||
lab_shots_reset()
|
||||
lab_shot_at("front", 0.0, 1.0, 0.0, 10.0, 0.0, 0.0)
|
||||
lab_shot_at("side", 0.0, 1.0, 0.0, 10.0, 90.0, 30.0)
|
||||
expect_eq(lab_shot_count(), 2)
|
||||
expect_near(lb_shot_pose[2], 10.0, 0.001) # front: 10 m out along +z
|
||||
expect_near(lb_shot_pose[5 + 0], 8.660, 0.01) # side: along +x, 30 degrees up
|
||||
expect_near(lb_shot_pose[5 + 1], 6.0, 0.01)
|
||||
expect_near(lb_shot_pose[5 + 4], -30.0, 0.001)
|
||||
test "a camera at a point looks back at it" (lab_st: mut LabState) {
|
||||
lab_shots_reset(lab_st)
|
||||
lab_shot_at(lab_st, "front", 0.0, 1.0, 0.0, 10.0, 0.0, 0.0)
|
||||
lab_shot_at(lab_st, "side", 0.0, 1.0, 0.0, 10.0, 90.0, 30.0)
|
||||
expect_eq(lab_shot_count(lab_st), 2)
|
||||
expect_near(lab_st.lb_shot_pose[2], 10.0, 0.001) # front: 10 m out along +z
|
||||
expect_near(lab_st.lb_shot_pose[5 + 0], 8.660, 0.01) # side: along +x, 30 degrees up
|
||||
expect_near(lab_st.lb_shot_pose[5 + 1], 6.0, 0.01)
|
||||
expect_near(lab_st.lb_shot_pose[5 + 4], -30.0, 0.001)
|
||||
}
|
||||
|
||||
test "scenes are what the program added, in its order" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue