# lab_test.ludic - what the lab computes without a window: the PNGs it writes (a shot, raw pixels), the cameras # a scene names, and the scenes a program adds import "ludic.lab" program LabTest { numbers float friend module lab_test of ludic_lab function nothing() -> void { } def LabScenes one { setup: fn nothing } def LabScenes two { setup: fn nothing } function ppm(path: string) -> void { let hdr = "P6\n2 2\n255\n" let b = buffer(len(hdr) + 12) for i in 0 .. len(hdr) { b[i] = hdr[i] } for i in 0 .. 12 { b[len(hdr) + i] = i * 20 } Fs.write_bytes(path, b, len(hdr) + 12) } 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(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) expect_eq(p[1], 80) expect_eq(p[19], 2) # IHDR width, low byte expect_eq(p[23], 2) # height let n = len(p) # the IEND chunk's CRC is always AE 42 60 82 expect_eq(p[n - 4], 174) expect_eq(p[n - 3], 66) expect_eq(p[n - 2], 96) expect_eq(p[n - 1], 130) expect(not Fs.exists(`{dir}/lab_test.ppm`)) } test "raw pixels become a PNG of their channel count" (lab_png_st: LabPngState) { let dir = Os.temp_dir() let px = buffer(3 * 2 * 4) for i in 0 .. 24 { px[i] = i * 10 } expect(lab_png_write(lab_png_st, `{dir}/lab_test_rgba.png`, 3, 2, 4, px)) let p = Fs.read_bytes(`{dir}/lab_test_rgba.png`) expect_eq(p[19], 3) # width expect_eq(p[25], 6) # colour type RGBA expect_eq(len(p), lp_png_size(3, 2, 4)) expect(not lab_png_write(lab_png_st, `{dir}/lab_test_short.png`, 9, 9, 4, px)) } test "16-bit samples become a 16-bit PNG, two bytes a sample" (lab_png_st: LabPngState) { let dir = Os.temp_dir() let px = buffer(3 * 2 * 2) for i in 0 .. 12 { px[i] = i * 20 } expect(lab_png_write16_from(lab_png_st, `{dir}/lab_test_r16.png`, 3, 2, 1, px, 0)) let p = Fs.read_bytes(`{dir}/lab_test_r16.png`) expect_eq(p[24], 16) # bit depth expect_eq(p[25], 0) # colour type grey expect_eq(len(p), lp_png_bytes(3 * 2, 2)) expect(not lab_png_write16_from(lab_png_st, `{dir}/lab_test_r16_short.png`, 3, 3, 1, px, 0)) } test "a half float and a float read as the numbers they store" { let b = buffer(8) b[0] = 0; b[1] = 60 # half 1.0 = 0x3C00 b[2] = 0; b[3] = 192 # half -2.0 = 0xC000 b[4] = 0; b[5] = 0; b[6] = 128; b[7] = 63 # float 1.0 = 0x3F800000 expect_near(lab_f16_at(b, 0), 1.0, 0.0001) expect_near(lab_f16_at(b, 2), -2.0, 0.0001) expect_near(lab_f32_at(b, 4), 1.0, 0.0001) let g = lab_px_rgba16f_hdr(b, 0, 1) # 1.0 -> 0.5 -> sRGB 188 expect_eq(g[0] & 255, 188) } 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" { expect_eq(LAB_COUNT, 2) expect(lab_scene_names() == "one, two") expect_eq(labscenes_find("two"), LAB_TWO) } }