wip(0.S3): packages and examples migrated again from their pre-0.S sources in one run
ludic migrate state packages <every example program> packages/ludic.lab/example/plate.ludic 1804 vars into 126 states, 64 into lets; 23498 edits in 460 files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5ffe50ed02
commit
19fcf60599
459 changed files with 17862 additions and 17603 deletions
|
|
@ -7,19 +7,21 @@ program GlTriangle {
|
|||
property Marker { on: int = 1 }
|
||||
model Anchor { Marker }
|
||||
|
||||
var prog: int = 0
|
||||
var vao: int = 0
|
||||
var frame: int = 0
|
||||
state GlTriangleState {
|
||||
prog: int = 0
|
||||
vao: int = 0
|
||||
frame: int = 0
|
||||
}
|
||||
|
||||
const VS: string = "#version 410 core\nlayout(location=0) in vec2 p; layout(location=1) in vec3 c; out vec3 vc;\nvoid main(){ vc = c; gl_Position = vec4(p, 0.0, 1.0); }\n"
|
||||
const FS: string = "#version 410 core\nin vec3 vc; out vec4 o;\nvoid main(){ o = vec4(vc, 1.0); }\n"
|
||||
|
||||
handler Boot phase Start {
|
||||
handler Boot(gl_triangle_st: mut GlTriangleState) phase Start {
|
||||
spawn Anchor {}
|
||||
if not Gl.open(width: 640, height: 360, title: "Ludic GL") { print("no GL context"); quit() }
|
||||
print(Gl.get_string(name: GL_VERSION))
|
||||
prog = Gl.program(vs: VS, fs: FS)
|
||||
vao = Gl.vao()
|
||||
gl_triangle_st.prog = Gl.program(vs: VS, fs: FS)
|
||||
gl_triangle_st.vao = Gl.vao()
|
||||
let vbo = Gl.buffer()
|
||||
Gl.bind_buffer(target: GL_ARRAY_BUFFER, buffer: vbo)
|
||||
let v = Gl.floats(15)
|
||||
|
|
@ -34,16 +36,16 @@ program GlTriangle {
|
|||
Gl.check(tag: "boot")
|
||||
}
|
||||
|
||||
handler Draw phase Render {
|
||||
handler Draw(gl_triangle_st: mut GlTriangleState) phase Render {
|
||||
Gl.bind_framebuffer(target: GL_FRAMEBUFFER, framebuffer: Gl.screen_fbo())
|
||||
Gl.viewport(x: 0, y: 0, width: Gl.width(), height: Gl.height())
|
||||
Gl.clear_color(red: 0.1, green: 0.12, blue: 0.18, alpha: 1.0)
|
||||
Gl.clear(mask: GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
|
||||
Gl.use_program(prog: prog)
|
||||
Gl.bind_vertex_array(array: vao)
|
||||
Gl.use_program(prog: gl_triangle_st.prog)
|
||||
Gl.bind_vertex_array(array: gl_triangle_st.vao)
|
||||
Gl.draw_arrays(mode: GL_TRIANGLES, first: 0, count: 3)
|
||||
frame += 1
|
||||
if frame == 1 { Gl.screenshot(path: "build/gl_triangle.ppm") }
|
||||
gl_triangle_st.frame += 1
|
||||
if gl_triangle_st.frame == 1 { Gl.screenshot(path: "build/gl_triangle.ppm") }
|
||||
Gl.swap()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ program Reload {
|
|||
# A program only links the GL runtime render3d stands on when it names Gl.* itself
|
||||
# (the parser's g_uses_gl), so even a check that draws nothing presents its frame.
|
||||
# render3d calls back into the program for what stands on the terrain
|
||||
function scene_draw() -> void { scatter_draw() }
|
||||
function scene_draw_casters(light_vp: floats) -> void { scatter_draw_casters(light_vp) }
|
||||
function scene_draw(render3d_st: mut Render3dState) -> void { scatter_draw(render3d_st) }
|
||||
function scene_draw_casters(render3d_st: mut Render3dState, light_vp: floats) -> void { scatter_draw_casters(render3d_st, light_vp) }
|
||||
# no streamed cover here, but stream.ludic names the generator, so every program supplies one
|
||||
function stream_fill(s: Stream, cx: int, cz: int, band: int) -> void { }
|
||||
|
||||
|
|
@ -27,61 +27,61 @@ program Reload {
|
|||
if not cond { print(`reload: FAILED - {what}`) }
|
||||
return cond
|
||||
}
|
||||
function populate() -> void {
|
||||
let l = layer_cards(model_cross_card(), 1000, F_ZERO, fi(400))
|
||||
function populate(render3d_st: mut Render3dState) -> void {
|
||||
let l = layer_cards(render3d_st, model_cross_card(render3d_st), 1000, F_ZERO, fi(400))
|
||||
for i in 0 .. 400 {
|
||||
let x = fi(i * 2 - 400)
|
||||
layer_add(l, x, terrain_height(x, fi(30)), fi(30), F_ONE, F_ZERO, F_ZERO, F_ZERO)
|
||||
col_add(x, fi(30), F_ONE)
|
||||
layer_add(l, x, terrain_height(render3d_st, x, fi(30)), fi(30), F_ONE, F_ZERO, F_ZERO, F_ZERO)
|
||||
col_add(render3d_st, x, fi(30), F_ONE)
|
||||
}
|
||||
col_build()
|
||||
col_build(render3d_st)
|
||||
}
|
||||
|
||||
handler Boot phase Start {
|
||||
handler Boot(render3d_st: mut Render3dState) phase Start {
|
||||
spawn Anchor {}
|
||||
r3d_on_draw(fn scene_draw)
|
||||
r3d_on_casters(fn scene_draw_casters)
|
||||
r3d_on_stream_fill(fn stream_fill)
|
||||
TERRAIN_HALF = 1000
|
||||
ter_smooth = true
|
||||
if not r3d_init(640, 360, "Reload") {
|
||||
r3d_on_draw(render3d_st, fn scene_draw)
|
||||
r3d_on_casters(render3d_st, fn scene_draw_casters)
|
||||
r3d_on_stream_fill(render3d_st, fn stream_fill)
|
||||
render3d_st.TERRAIN_HALF = 1000
|
||||
render3d_st.ter_smooth = true
|
||||
if not r3d_init(render3d_st, 640, 360, "Reload") {
|
||||
quit()
|
||||
return
|
||||
}
|
||||
cam_set(F_ZERO, fi(80), fi(300), fi(180), f_neg(fi(10)))
|
||||
water_init(fl(4.0), F_ZERO, F_ZERO, fi(200), fi(200))
|
||||
populate()
|
||||
cam_set(render3d_st, F_ZERO, fi(80), fi(300), fi(180), f_neg(fi(10)))
|
||||
water_init(render3d_st, fl(4.0), F_ZERO, F_ZERO, fi(200), fi(200))
|
||||
populate(render3d_st)
|
||||
var ok = true
|
||||
ok = check("the first map has layers and colliders", len(sc_layers) == 1 and col_n == 400) and ok
|
||||
ok = check("the first map has layers and colliders", len(render3d_st.sc_layers) == 1 and render3d_st.col_n == 400) and ok
|
||||
# --- swap to a 3 km map with a sea and a lake above it
|
||||
scatter_clear_all()
|
||||
actor_clear_all()
|
||||
col_reset()
|
||||
water_bodies_clear()
|
||||
terrain_lake(F_ZERO, F_ZERO, F_ZERO, F_ZERO, F_ZERO)
|
||||
terrain_reload("", F_ZERO, F_ZERO, F_ZERO, F_ZERO, F_ZERO, "", 1500)
|
||||
ok = check("everything of the first map released", len(sc_layers) == 0 and col_n == 0 and wb_n == 0 and not water_on) and ok
|
||||
ok = check("the new half", TERRAIN_HALF == 1500 and ter_heights != null and ter_height_tex != 0) and ok
|
||||
ok = check("patch bounds rebuilt", cd_min != null and len(cd_min) == CD_LEVELS) and ok
|
||||
ok = check("patches scale with the map", cd_size(0) == f_mul(fi(32), fr(3000, 8192))) and ok
|
||||
terrain_height(F_ZERO, F_ZERO)
|
||||
ok = check("the cached height scale is the new map's", ter_h_scale == fr(TERRAIN_RES, 3000)) and ok
|
||||
let sea = water_body_add(F_ZERO, F_ZERO, F_ZERO, fi(20000), fi(20000), true)
|
||||
let lake = water_body_add(fl(12.0), fi(600), fi(-400), fi(150), fi(100), false)
|
||||
ok = check("two water bodies, the sea mirrored", sea == 0 and lake == 1 and wb_n == 2 and wb_primary == 0 and water_level == F_ZERO and water_on) and ok
|
||||
populate()
|
||||
ok = check("the new map takes layers and colliders", len(sc_layers) == 1 and col_n == 400 and col_side == 3000 / COL_CELL) and ok
|
||||
scatter_clear_all(render3d_st)
|
||||
actor_clear_all(render3d_st)
|
||||
col_reset(render3d_st)
|
||||
water_bodies_clear(render3d_st)
|
||||
terrain_lake(render3d_st, F_ZERO, F_ZERO, F_ZERO, F_ZERO, F_ZERO)
|
||||
terrain_reload(render3d_st, "", F_ZERO, F_ZERO, F_ZERO, F_ZERO, F_ZERO, "", 1500)
|
||||
ok = check("everything of the first map released", len(render3d_st.sc_layers) == 0 and render3d_st.col_n == 0 and render3d_st.wb_n == 0 and not render3d_st.water_on) and ok
|
||||
ok = check("the new half", render3d_st.TERRAIN_HALF == 1500 and render3d_st.ter_heights != null and render3d_st.ter_height_tex != 0) and ok
|
||||
ok = check("patch bounds rebuilt", render3d_st.cd_min != null and len(render3d_st.cd_min) == CD_LEVELS) and ok
|
||||
ok = check("patches scale with the map", cd_size(render3d_st, 0) == f_mul(fi(32), fr(3000, 8192))) and ok
|
||||
terrain_height(render3d_st, F_ZERO, F_ZERO)
|
||||
ok = check("the cached height scale is the new map's", render3d_st.ter_h_scale == fr(TERRAIN_RES, 3000)) and ok
|
||||
let sea = water_body_add(render3d_st, F_ZERO, F_ZERO, F_ZERO, fi(20000), fi(20000), true)
|
||||
let lake = water_body_add(render3d_st, fl(12.0), fi(600), fi(-400), fi(150), fi(100), false)
|
||||
ok = check("two water bodies, the sea mirrored", sea == 0 and lake == 1 and render3d_st.wb_n == 2 and render3d_st.wb_primary == 0 and render3d_st.water_level == F_ZERO and render3d_st.water_on) and ok
|
||||
populate(render3d_st)
|
||||
ok = check("the new map takes layers and colliders", len(render3d_st.sc_layers) == 1 and render3d_st.col_n == 400 and render3d_st.col_side == 3000 / COL_CELL) and ok
|
||||
# a sea below the carved lake: set once, and not undone by a reload
|
||||
terrain_sea(fl(-2.0))
|
||||
terrain_lake(fl(12.0), fi(600), fi(-400), fi(150), fi(100))
|
||||
ok = check("the sea is its own level", ter_sea_set and ter_sea_gen() == fl(-2.0) and ter_lake_level == fl(12.0)) and ok
|
||||
terrain_sea(render3d_st, fl(-2.0))
|
||||
terrain_lake(render3d_st, fl(12.0), fi(600), fi(-400), fi(150), fi(100))
|
||||
ok = check("the sea is its own level", render3d_st.ter_sea_set and ter_sea_gen(render3d_st) == fl(-2.0) and render3d_st.ter_lake_level == fl(12.0)) and ok
|
||||
# --- and back: the swap is repeatable
|
||||
scatter_clear_all()
|
||||
col_reset()
|
||||
water_init(fl(4.0), F_ZERO, F_ZERO, fi(200), fi(200))
|
||||
terrain_reload("", F_ZERO, F_ZERO, F_ZERO, F_ZERO, F_ZERO, "", 1000)
|
||||
populate()
|
||||
ok = check("back to 2 km", TERRAIN_HALF == 1000 and len(cd_min) == CD_LEVELS and wb_n == 1 and col_side == 2000 / COL_CELL) and ok
|
||||
scatter_clear_all(render3d_st)
|
||||
col_reset(render3d_st)
|
||||
water_init(render3d_st, fl(4.0), F_ZERO, F_ZERO, fi(200), fi(200))
|
||||
terrain_reload(render3d_st, "", F_ZERO, F_ZERO, F_ZERO, F_ZERO, F_ZERO, "", 1000)
|
||||
populate(render3d_st)
|
||||
ok = check("back to 2 km", render3d_st.TERRAIN_HALF == 1000 and len(render3d_st.cd_min) == CD_LEVELS and render3d_st.wb_n == 1 and render3d_st.col_side == 2000 / COL_CELL) and ok
|
||||
if ok { print("RELOAD OK") } else { print("RELOAD FAILED") }
|
||||
quit()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,17 +13,19 @@ program Smooth {
|
|||
property Marker { on: int = 1 }
|
||||
model Anchor { Marker }
|
||||
|
||||
var frame: int = 0
|
||||
var shot_at: int = 40
|
||||
var walk: bool = false
|
||||
var spin: bool = false
|
||||
var l_blades: Layer = null
|
||||
var l_grass_a: Layer = null
|
||||
var l_grass_b: Layer = null
|
||||
var s_blades: Stream = null
|
||||
var s_cards_a: Stream = null
|
||||
var s_cards_b: Stream = null
|
||||
var l_trees: Layer = null
|
||||
state SmoothState {
|
||||
frame: int = 0
|
||||
shot_at: int = 40
|
||||
walk: bool = false
|
||||
spin: bool = false
|
||||
l_blades: Layer = null
|
||||
l_grass_a: Layer = null
|
||||
l_grass_b: Layer = null
|
||||
s_blades: Stream = null
|
||||
s_cards_a: Stream = null
|
||||
s_cards_b: Stream = null
|
||||
l_trees: Layer = null
|
||||
}
|
||||
|
||||
function rnd() -> float { return float(rng_range(0, 9999)) / 10000.0 }
|
||||
function rnd_range(a: float, b: float) -> float { return Math.lerp(a, b, rnd()) }
|
||||
|
|
@ -31,10 +33,10 @@ program Smooth {
|
|||
let t = Math.clamp((x - a) / (b - a), 0.0, 1.0)
|
||||
return t * t * (3.0 - 2.0 * t)
|
||||
}
|
||||
function slope_at(x: float, z: float) -> float {
|
||||
function slope_at(render3d_st: mut Render3dState, x: float, z: float) -> float {
|
||||
let e = 2.0
|
||||
let dx = terrain_height(x + e, z) - terrain_height(x - e, z)
|
||||
let dz = terrain_height(x, z + e) - terrain_height(x, z - e)
|
||||
let dx = terrain_height(render3d_st, x + e, z) - terrain_height(render3d_st, x - e, z)
|
||||
let dz = terrain_height(render3d_st, x, z + e) - terrain_height(render3d_st, x, z - e)
|
||||
let ny = 4.0 / Math.sqrt(dx * dx + dz * dz + 16.0)
|
||||
return 1.0 - ny
|
||||
}
|
||||
|
|
@ -44,7 +46,7 @@ program Smooth {
|
|||
}
|
||||
|
||||
# grass only where the ground is grassy: gentle, above the water, below the mountain
|
||||
function stream_fill(s: Stream, cx: int, cz: int, band: int) -> void {
|
||||
function stream_fill(render3d_st: mut Render3dState, s: Stream, cx: int, cz: int, band: int) -> void {
|
||||
seed((cx * 73856093) ^ (cz * 19349663) ^ (band * 83492791) ^ (s.kind * 2654435761))
|
||||
let size = s.size
|
||||
let x0 = float(cx) * size; let z0 = float(cz) * size
|
||||
|
|
@ -61,19 +63,19 @@ program Smooth {
|
|||
while x < x0 + size {
|
||||
let px = x + rnd() * step
|
||||
let pz = z + rnd() * step
|
||||
let h = terrain_height(px, pz)
|
||||
let h = terrain_height(render3d_st, px, pz)
|
||||
# Grassy ground only: above the water, off the steep parts, below the rim. Every
|
||||
# test is a smooth ramp — a hard height cut carves the cover into contour rings,
|
||||
# because the cut lands on a line of constant elevation.
|
||||
var keep = smooth(0.2, 1.6, h) # out of the water
|
||||
keep = keep * smooth(90.0, 45.0, h) # below the mountain
|
||||
keep = keep * smooth(0.42, 0.16, slope_at(px, pz))
|
||||
keep = keep * smooth(0.42, 0.16, slope_at(render3d_st, px, pz))
|
||||
keep = keep * (0.25 + 0.9 * noise01(px, pz, 0.02))
|
||||
keep = keep * 0.75
|
||||
var sc = rnd_range(0.16, 0.4)
|
||||
if s.kind != 0 { sc = rnd_range(1.5, 2.5) * (1.0 + 0.5 * float(band)) }
|
||||
if rnd() < keep {
|
||||
stream_emit(s, px, h - 0.03, pz, sc, rnd() * (2.0 * PI), rnd(), rnd_range(0.6, 1.0))
|
||||
stream_emit(render3d_st, s, px, h - 0.03, pz, sc, rnd() * (2.0 * PI), rnd(), rnd_range(0.6, 1.0))
|
||||
}
|
||||
x = x + step
|
||||
}
|
||||
|
|
@ -81,24 +83,24 @@ program Smooth {
|
|||
}
|
||||
}
|
||||
|
||||
function scene_draw() -> void { scatter_draw() }
|
||||
function scene_draw_casters(light_vp: floats) -> void { scatter_draw_casters(light_vp) }
|
||||
function scene_draw(render3d_st: mut Render3dState) -> void { scatter_draw(render3d_st) }
|
||||
function scene_draw_casters(render3d_st: mut Render3dState, light_vp: floats) -> void { scatter_draw_casters(render3d_st, light_vp) }
|
||||
|
||||
handler Boot phase Start {
|
||||
handler Boot(render3d_st: mut Render3dState, smooth_st: mut SmoothState) phase Start {
|
||||
spawn Anchor {}
|
||||
r3d_on_draw(fn scene_draw)
|
||||
r3d_on_casters(fn scene_draw_casters)
|
||||
r3d_on_stream_fill(fn stream_fill)
|
||||
r3d_on_draw(render3d_st, fn scene_draw)
|
||||
r3d_on_casters(render3d_st, fn scene_draw_casters)
|
||||
r3d_on_stream_fill(render3d_st, fn stream_fill)
|
||||
# 2 km square, generated analytically
|
||||
TERRAIN_HALF = 1000
|
||||
ter_smooth = true
|
||||
if not r3d_init(1920, 1080, "Smooth") {
|
||||
render3d_st.TERRAIN_HALF = 1000
|
||||
render3d_st.ter_smooth = true
|
||||
if not r3d_init(render3d_st, 1920, 1080, "Smooth") {
|
||||
quit()
|
||||
return
|
||||
}
|
||||
walk = Os.has_env("R3D_WALK")
|
||||
spin = Os.has_env("R3D_SPIN")
|
||||
if Os.has_env("R3D_SHOT") { shot_at = Text.to_int(Os.env("R3D_SHOT")) }
|
||||
smooth_st.walk = Os.has_env("R3D_WALK")
|
||||
smooth_st.spin = Os.has_env("R3D_SPIN")
|
||||
if Os.has_env("R3D_SHOT") { smooth_st.shot_at = Text.to_int(Os.env("R3D_SHOT")) }
|
||||
|
||||
var cx = 0.0; var cz = 260.0
|
||||
if Os.has_env("R3D_CAM_X") { cx = float(Text.to_int(Os.env("R3D_CAM_X"))) }
|
||||
|
|
@ -107,54 +109,54 @@ program Smooth {
|
|||
if Os.has_env("R3D_CAM_H") { ch = float(Text.to_int(Os.env("R3D_CAM_H"))) }
|
||||
if Os.has_env("R3D_CAM_PITCH") { cp = float(Text.to_int(Os.env("R3D_CAM_PITCH"))) }
|
||||
if Os.has_env("R3D_CAM_YAW") { cy = float(Text.to_int(Os.env("R3D_CAM_YAW"))) }
|
||||
cam_set(cx, terrain_height(cx, cz) + ch, cz, cy, cp)
|
||||
cam_set(render3d_st, cx, terrain_height(render3d_st, cx, cz) + ch, cz, cy, cp)
|
||||
|
||||
# a small pond in the middle of the meadow — the plane self-clips to the basin, so
|
||||
# its extent only has to cover the hollow, not the map
|
||||
water_init(4.0, 0.0, 0.0, 200.0, 200.0)
|
||||
sky_set_yaw(Math.deg_to_rad(120.0))
|
||||
water_init(render3d_st, 4.0, 0.0, 0.0, 200.0, 200.0)
|
||||
sky_set_yaw(render3d_st, Math.deg_to_rad(120.0))
|
||||
|
||||
# grass: blades underfoot, cards beyond
|
||||
let dir = r3d_assets + "/models/grass_medium_01"
|
||||
let ga = gltf_load(dir, "grass_medium_01_1k.gltf", "grass_medium_01_tall_a_LOD0")
|
||||
let gb = gltf_load(dir, "grass_medium_01_1k.gltf", "grass_medium_01_mid_a_LOD0")
|
||||
let dir = render3d_st.r3d_assets + "/models/grass_medium_01"
|
||||
let ga = gltf_load(render3d_st, dir, "grass_medium_01_1k.gltf", "grass_medium_01_tall_a_LOD0")
|
||||
let gb = gltf_load(render3d_st, dir, "grass_medium_01_1k.gltf", "grass_medium_01_mid_a_LOD0")
|
||||
if ga == null or gb == null { print("smooth: no grass models"); return }
|
||||
# blades are the expensive layer: keep them near, and cap them low
|
||||
l_blades = layer_new(model_blade(), 400000, true, 3.0, 0.0, 70.0)
|
||||
l_blades.blade = true
|
||||
l_grass_a = layer_cards(ga, 200000, 0.3, 260.0)
|
||||
l_grass_b = layer_cards(gb, 200000, 0.3, 260.0)
|
||||
v3_set(l_grass_a.tint, 0.95, 1.0, 0.85)
|
||||
v3_set(l_grass_b.tint, 0.9, 0.98, 0.8)
|
||||
l_grass_a.rough = 1.6; l_grass_b.rough = 1.6
|
||||
s_blades = stream_new(l_blades, 8.0, 60.0, 12.0, 28.0, 60.0, 60.0)
|
||||
s_cards_a = stream_new(l_grass_a, 32.0, 240.0, 45.0, 110.0, 240.0, 240.0)
|
||||
s_cards_b = stream_new(l_grass_b, 32.0, 240.0, 45.0, 110.0, 240.0, 240.0)
|
||||
s_blades.kind = 0; s_cards_a.kind = 1; s_cards_b.kind = 2
|
||||
place_trees()
|
||||
smooth_st.l_blades = layer_new(render3d_st, model_blade(render3d_st), 400000, true, 3.0, 0.0, 70.0)
|
||||
smooth_st.l_blades.blade = true
|
||||
smooth_st.l_grass_a = layer_cards(render3d_st, ga, 200000, 0.3, 260.0)
|
||||
smooth_st.l_grass_b = layer_cards(render3d_st, gb, 200000, 0.3, 260.0)
|
||||
v3_set(smooth_st.l_grass_a.tint, 0.95, 1.0, 0.85)
|
||||
v3_set(smooth_st.l_grass_b.tint, 0.9, 0.98, 0.8)
|
||||
smooth_st.l_grass_a.rough = 1.6; smooth_st.l_grass_b.rough = 1.6
|
||||
smooth_st.s_blades = stream_new(render3d_st, smooth_st.l_blades, 8.0, 60.0, 12.0, 28.0, 60.0, 60.0)
|
||||
smooth_st.s_cards_a = stream_new(render3d_st, smooth_st.l_grass_a, 32.0, 240.0, 45.0, 110.0, 240.0, 240.0)
|
||||
smooth_st.s_cards_b = stream_new(render3d_st, smooth_st.l_grass_b, 32.0, 240.0, 45.0, 110.0, 240.0, 240.0)
|
||||
smooth_st.s_blades.kind = 0; smooth_st.s_cards_a.kind = 1; smooth_st.s_cards_b.kind = 2
|
||||
place_trees(render3d_st, smooth_st)
|
||||
}
|
||||
|
||||
# scattered firs on the gentle ground, thinning toward the pond and the rim
|
||||
function place_trees() -> void {
|
||||
let model = gltf_load(r3d_assets + "/models/fir_tree_01", "fir_tree_01_1k.gltf", "fir_tree_01_c_LOD0")
|
||||
function place_trees(render3d_st: mut Render3dState, smooth_st: mut SmoothState) -> void {
|
||||
let model = gltf_load(render3d_st, render3d_st.r3d_assets + "/models/fir_tree_01", "fir_tree_01_1k.gltf", "fir_tree_01_c_LOD0")
|
||||
if model == null { print("smooth: no fir model"); return }
|
||||
l_trees = layer_new(model, 20000, false, 0.0, 90.0, 0.0)
|
||||
layer_set_impostor(l_trees, impostor_bake(model, 12, 512, 1024))
|
||||
v3_set(l_trees.tint, 0.9, 1.0, 0.85)
|
||||
smooth_st.l_trees = layer_new(render3d_st, model, 20000, false, 0.0, 90.0, 0.0)
|
||||
layer_set_impostor(render3d_st, smooth_st.l_trees, impostor_bake(render3d_st, model, 12, 512, 1024))
|
||||
v3_set(smooth_st.l_trees.tint, 0.9, 1.0, 0.85)
|
||||
seed(4242)
|
||||
var z = -900.0
|
||||
while z < 900.0 {
|
||||
var x = -900.0
|
||||
while x < 900.0 {
|
||||
let px = x + rnd() * 14.0; let pz = z + rnd() * 14.0
|
||||
let h = terrain_height(px, pz)
|
||||
let h = terrain_height(render3d_st, px, pz)
|
||||
var keep = smooth(7.0, 14.0, h) # above the pond shore
|
||||
keep = keep * smooth(120.0, 60.0, h) # below the rim
|
||||
keep = keep * smooth(0.45, 0.2, slope_at(px, pz))
|
||||
keep = keep * smooth(0.45, 0.2, slope_at(render3d_st, px, pz))
|
||||
keep = keep * smooth(0.45, 0.75, noise01(px, pz, 0.004))
|
||||
if rnd() < keep * 0.5 {
|
||||
let sc = rnd_range(0.7, 1.35)
|
||||
layer_add(l_trees, px, h - 0.2, pz, sc, rnd() * (2.0 * PI), rnd(), 0.0)
|
||||
layer_add(smooth_st.l_trees, px, h - 0.2, pz, sc, rnd() * (2.0 * PI), rnd(), 0.0)
|
||||
}
|
||||
x = x + 14.0
|
||||
}
|
||||
|
|
@ -162,9 +164,9 @@ program Smooth {
|
|||
}
|
||||
}
|
||||
|
||||
handler Fly phase Input {
|
||||
if walk { cam_move(1.0, 0.0, 0.0, 0.003, 0.0); return }
|
||||
if spin { cam_move(0.0, 0.0, 0.0, 0.02, 0.0); return }
|
||||
handler Fly(render3d_st: mut Render3dState, smooth_st: SmoothState) phase Input {
|
||||
if smooth_st.walk { cam_move(render3d_st, 1.0, 0.0, 0.0, 0.003, 0.0); return }
|
||||
if smooth_st.spin { cam_move(render3d_st, 0.0, 0.0, 0.0, 0.02, 0.0); return }
|
||||
if not is_windowed() { return }
|
||||
Input.poll()
|
||||
var fwd = 0.0; var side = 0.0; var up = 0.0
|
||||
|
|
@ -180,17 +182,17 @@ program Smooth {
|
|||
dyaw = float(Input.mouse_dx()) * -0.004
|
||||
dpitch = float(Input.mouse_dy()) * -0.004
|
||||
}
|
||||
if fwd != 0 or side != 0 or up != 0 or dyaw != 0 or dpitch != 0 { cam_move(fwd, side, up, dyaw, dpitch) }
|
||||
if fwd != 0 or side != 0 or up != 0 or dyaw != 0 or dpitch != 0 { cam_move(render3d_st, fwd, side, up, dyaw, dpitch) }
|
||||
if Input.key_pressed(key: 'p') {
|
||||
let gy = terrain_height(cam_pos[0], cam_pos[2])
|
||||
print(`R3D_CAM_X={string(int(cam_pos[0]))} R3D_CAM_Z={string(int(cam_pos[2]))} R3D_CAM_H={string(int(cam_pos[1] - gy))} R3D_CAM_YAW={string(int(cam_yaw * (180.0 / PI)))} R3D_CAM_PITCH={string(int(cam_pitch * (180.0 / PI)))}`)
|
||||
let gy = terrain_height(render3d_st, render3d_st.cam_pos[0], render3d_st.cam_pos[2])
|
||||
print(`R3D_CAM_X={string(int(render3d_st.cam_pos[0]))} R3D_CAM_Z={string(int(render3d_st.cam_pos[2]))} R3D_CAM_H={string(int(render3d_st.cam_pos[1] - gy))} R3D_CAM_YAW={string(int(render3d_st.cam_yaw * (180.0 / PI)))} R3D_CAM_PITCH={string(int(render3d_st.cam_pitch * (180.0 / PI)))}`)
|
||||
}
|
||||
}
|
||||
|
||||
handler Draw phase Render {
|
||||
r3d_frame(float(Time.elapsed()))
|
||||
frame += 1
|
||||
if frame == shot_at { Gl.screenshot(path: "build/smooth.ppm") }
|
||||
handler Draw(render3d_st: mut Render3dState, smooth_st: mut SmoothState) phase Render {
|
||||
r3d_frame(render3d_st, float(Time.elapsed()))
|
||||
smooth_st.frame += 1
|
||||
if smooth_st.frame == smooth_st.shot_at { Gl.screenshot(path: "build/smooth.ppm") }
|
||||
Gl.swap()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ program VkCompute {
|
|||
const W: int = 640
|
||||
const H: int = 360
|
||||
|
||||
var dev: pointer = null
|
||||
state VkComputeState {
|
||||
dev: pointer = null
|
||||
spv_len: int = 0
|
||||
}
|
||||
|
||||
unsafe function fail(what: string, r: int) -> void { print(`vulkan: {what} failed, VkResult {r}`); quit() }
|
||||
unsafe function handle(out: bytes) -> long { return vk_get_i64(out, 0) }
|
||||
|
|
@ -30,7 +33,7 @@ program VkCompute {
|
|||
}
|
||||
return false
|
||||
}
|
||||
unsafe function read_all(path: string) -> bytes {
|
||||
unsafe function read_all(vk_compute_st: mut VkComputeState, path: string) -> bytes {
|
||||
let f = file_open(path, "rb")
|
||||
if f == null { return null }
|
||||
file_seek(f, 0, 2)
|
||||
|
|
@ -39,16 +42,15 @@ program VkCompute {
|
|||
let b = bytes(n + 4)
|
||||
file_read(f, b, n)
|
||||
file_close(f)
|
||||
spv_len = n
|
||||
vk_compute_st.spv_len = n
|
||||
return b
|
||||
}
|
||||
var spv_len: int = 0
|
||||
|
||||
handler Boot phase Start {
|
||||
handler Boot(vk_compute_st: mut VkComputeState) phase Start {
|
||||
spawn Anchor {}
|
||||
var spv_path = "build/vk_compute.spv"
|
||||
if Os.has_env("VKC_SPV") { spv_path = Os.env("VKC_SPV") }
|
||||
let spv = read_all(spv_path)
|
||||
let spv = read_all(vk_compute_st, spv_path)
|
||||
if spv == null { print(`vulkan: no SPIR-V at {spv_path} (compile vk_compute.slang with slangc)`); quit() }
|
||||
if Vk.open() == 0 { print("vulkan: no loader"); quit() }
|
||||
|
||||
|
|
@ -126,8 +128,8 @@ program VkCompute {
|
|||
}
|
||||
r = vk_create_device(pd, dci, null, out)
|
||||
if r != VK_SUCCESS { fail("vkCreateDevice", r) }
|
||||
dev = vk_get_ptr(out, 0)
|
||||
vk_get_device_queue(dev, family, 0, out)
|
||||
vk_compute_st.dev = vk_get_ptr(out, 0)
|
||||
vk_get_device_queue(vk_compute_st.dev, family, 0, out)
|
||||
let queue = vk_get_ptr(out, 0)
|
||||
|
||||
# ---- a host-visible storage buffer for the picture
|
||||
|
|
@ -138,11 +140,11 @@ program VkCompute {
|
|||
vk_put_i64(bci, VkBufferCreateInfo_size, nbytes)
|
||||
vk_put_i32(bci, VkBufferCreateInfo_usage, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
|
||||
vk_put_i32(bci, VkBufferCreateInfo_sharingMode, VK_SHARING_MODE_EXCLUSIVE)
|
||||
r = vk_create_buffer(dev, bci, null, out)
|
||||
r = vk_create_buffer(vk_compute_st.dev, bci, null, out)
|
||||
if r != VK_SUCCESS { fail("vkCreateBuffer", r) }
|
||||
let buf = handle(out)
|
||||
let req = bytes(VkMemoryRequirements_sizeof)
|
||||
vk_get_buffer_memory_requirements(dev, buf, req)
|
||||
vk_get_buffer_memory_requirements(vk_compute_st.dev, buf, req)
|
||||
let mp = bytes(VkPhysicalDeviceMemoryProperties_sizeof)
|
||||
vk_get_physical_device_memory_properties(pd, mp)
|
||||
let want = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
|
|
@ -158,21 +160,21 @@ program VkCompute {
|
|||
vk_put_i32(mai, VkMemoryAllocateInfo_sType, VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO)
|
||||
vk_put_i64(mai, VkMemoryAllocateInfo_allocationSize, vk_get_i64(req, VkMemoryRequirements_size))
|
||||
vk_put_i32(mai, VkMemoryAllocateInfo_memoryTypeIndex, mtype)
|
||||
r = vk_allocate_memory(dev, mai, null, out)
|
||||
r = vk_allocate_memory(vk_compute_st.dev, mai, null, out)
|
||||
if r != VK_SUCCESS { fail("vkAllocateMemory", r) }
|
||||
let mem = handle(out)
|
||||
let zero: long = 0
|
||||
r = vk_bind_buffer_memory(dev, buf, mem, zero)
|
||||
r = vk_bind_buffer_memory(vk_compute_st.dev, buf, mem, zero)
|
||||
if r != VK_SUCCESS { fail("vkBindBufferMemory", r) }
|
||||
|
||||
# ---- the shader, its layout, the pipeline
|
||||
let smci = bytes(VkShaderModuleCreateInfo_sizeof)
|
||||
vk_zero(smci, VkShaderModuleCreateInfo_sizeof)
|
||||
vk_put_i32(smci, VkShaderModuleCreateInfo_sType, VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO)
|
||||
let code_size: long = spv_len
|
||||
let code_size: long = vk_compute_st.spv_len
|
||||
vk_put_i64(smci, VkShaderModuleCreateInfo_codeSize, code_size)
|
||||
vk_put_ptr(smci, VkShaderModuleCreateInfo_pCode, spv)
|
||||
r = vk_create_shader_module(dev, smci, null, out)
|
||||
r = vk_create_shader_module(vk_compute_st.dev, smci, null, out)
|
||||
if r != VK_SUCCESS { fail("vkCreateShaderModule", r) }
|
||||
let module = handle(out)
|
||||
|
||||
|
|
@ -188,7 +190,7 @@ program VkCompute {
|
|||
vk_put_i32(dslci, VkDescriptorSetLayoutCreateInfo_bindingCount, 1)
|
||||
vk_put_ptr(dslci, VkDescriptorSetLayoutCreateInfo_pBindings, binding)
|
||||
let set_layouts = bytes(8)
|
||||
r = vk_create_descriptor_set_layout(dev, dslci, null, set_layouts)
|
||||
r = vk_create_descriptor_set_layout(vk_compute_st.dev, dslci, null, set_layouts)
|
||||
if r != VK_SUCCESS { fail("vkCreateDescriptorSetLayout", r) }
|
||||
|
||||
let pcr = bytes(VkPushConstantRange_sizeof)
|
||||
|
|
@ -202,7 +204,7 @@ program VkCompute {
|
|||
vk_put_ptr(plci, VkPipelineLayoutCreateInfo_pSetLayouts, set_layouts)
|
||||
vk_put_i32(plci, VkPipelineLayoutCreateInfo_pushConstantRangeCount, 1)
|
||||
vk_put_ptr(plci, VkPipelineLayoutCreateInfo_pPushConstantRanges, pcr)
|
||||
r = vk_create_pipeline_layout(dev, plci, null, out)
|
||||
r = vk_create_pipeline_layout(vk_compute_st.dev, plci, null, out)
|
||||
if r != VK_SUCCESS { fail("vkCreatePipelineLayout", r) }
|
||||
let layout = handle(out)
|
||||
|
||||
|
|
@ -215,7 +217,7 @@ program VkCompute {
|
|||
vk_put_i64(cpci, st + VkPipelineShaderStageCreateInfo_module, module)
|
||||
vk_put_ptr(cpci, st + VkPipelineShaderStageCreateInfo_pName, "main")
|
||||
vk_put_i64(cpci, VkComputePipelineCreateInfo_layout, layout)
|
||||
r = vk_create_compute_pipelines(dev, zero, 1, cpci, null, out)
|
||||
r = vk_create_compute_pipelines(vk_compute_st.dev, zero, 1, cpci, null, out)
|
||||
if r != VK_SUCCESS { fail("vkCreateComputePipelines", r) }
|
||||
let pipeline = handle(out)
|
||||
|
||||
|
|
@ -229,7 +231,7 @@ program VkCompute {
|
|||
vk_put_i32(dpci, VkDescriptorPoolCreateInfo_maxSets, 1)
|
||||
vk_put_i32(dpci, VkDescriptorPoolCreateInfo_poolSizeCount, 1)
|
||||
vk_put_ptr(dpci, VkDescriptorPoolCreateInfo_pPoolSizes, psz)
|
||||
r = vk_create_descriptor_pool(dev, dpci, null, out)
|
||||
r = vk_create_descriptor_pool(vk_compute_st.dev, dpci, null, out)
|
||||
if r != VK_SUCCESS { fail("vkCreateDescriptorPool", r) }
|
||||
let pool = handle(out)
|
||||
let dsai = bytes(VkDescriptorSetAllocateInfo_sizeof)
|
||||
|
|
@ -239,7 +241,7 @@ program VkCompute {
|
|||
vk_put_i32(dsai, VkDescriptorSetAllocateInfo_descriptorSetCount, 1)
|
||||
vk_put_ptr(dsai, VkDescriptorSetAllocateInfo_pSetLayouts, set_layouts)
|
||||
let sets = bytes(8)
|
||||
r = vk_allocate_descriptor_sets(dev, dsai, sets)
|
||||
r = vk_allocate_descriptor_sets(vk_compute_st.dev, dsai, sets)
|
||||
if r != VK_SUCCESS { fail("vkAllocateDescriptorSets", r) }
|
||||
let dbi = bytes(VkDescriptorBufferInfo_sizeof)
|
||||
vk_put_i64(dbi, VkDescriptorBufferInfo_buffer, buf)
|
||||
|
|
@ -253,14 +255,14 @@ program VkCompute {
|
|||
vk_put_i32(wds, VkWriteDescriptorSet_descriptorCount, 1)
|
||||
vk_put_i32(wds, VkWriteDescriptorSet_descriptorType, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
|
||||
vk_put_ptr(wds, VkWriteDescriptorSet_pBufferInfo, dbi)
|
||||
vk_update_descriptor_sets(dev, 1, wds, 0, null)
|
||||
vk_update_descriptor_sets(vk_compute_st.dev, 1, wds, 0, null)
|
||||
|
||||
# ---- record, submit, wait
|
||||
let cpi = bytes(VkCommandPoolCreateInfo_sizeof)
|
||||
vk_zero(cpi, VkCommandPoolCreateInfo_sizeof)
|
||||
vk_put_i32(cpi, VkCommandPoolCreateInfo_sType, VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO)
|
||||
vk_put_i32(cpi, VkCommandPoolCreateInfo_queueFamilyIndex, family)
|
||||
r = vk_create_command_pool(dev, cpi, null, out)
|
||||
r = vk_create_command_pool(vk_compute_st.dev, cpi, null, out)
|
||||
if r != VK_SUCCESS { fail("vkCreateCommandPool", r) }
|
||||
let cmd_pool = handle(out)
|
||||
let cbai = bytes(VkCommandBufferAllocateInfo_sizeof)
|
||||
|
|
@ -270,7 +272,7 @@ program VkCompute {
|
|||
vk_put_i32(cbai, VkCommandBufferAllocateInfo_level, VK_COMMAND_BUFFER_LEVEL_PRIMARY)
|
||||
vk_put_i32(cbai, VkCommandBufferAllocateInfo_commandBufferCount, 1)
|
||||
let cbs = bytes(8)
|
||||
r = vk_allocate_command_buffers(dev, cbai, cbs)
|
||||
r = vk_allocate_command_buffers(vk_compute_st.dev, cbai, cbs)
|
||||
if r != VK_SUCCESS { fail("vkAllocateCommandBuffers", r) }
|
||||
let cb = vk_get_ptr(cbs, 0)
|
||||
let cbbi = bytes(VkCommandBufferBeginInfo_sizeof)
|
||||
|
|
@ -294,7 +296,7 @@ program VkCompute {
|
|||
vk_zero(fci, VkFenceCreateInfo_sizeof)
|
||||
vk_put_i32(fci, VkFenceCreateInfo_sType, VK_STRUCTURE_TYPE_FENCE_CREATE_INFO)
|
||||
let fences = bytes(8)
|
||||
r = vk_create_fence(dev, fci, null, fences)
|
||||
r = vk_create_fence(vk_compute_st.dev, fci, null, fences)
|
||||
if r != VK_SUCCESS { fail("vkCreateFence", r) }
|
||||
let si = bytes(VkSubmitInfo_sizeof)
|
||||
vk_zero(si, VkSubmitInfo_sizeof)
|
||||
|
|
@ -304,13 +306,13 @@ program VkCompute {
|
|||
r = vk_queue_submit(queue, 1, si, vk_get_i64(fences, 0))
|
||||
if r != VK_SUCCESS { fail("vkQueueSubmit", r) }
|
||||
let forever: long = -1
|
||||
r = vk_wait_for_fences(dev, 1, fences, 1, forever)
|
||||
r = vk_wait_for_fences(vk_compute_st.dev, 1, fences, 1, forever)
|
||||
if r != VK_SUCCESS { fail("vkWaitForFences", r) }
|
||||
print(`vulkan: dispatched {(W + 15) / 16}x{(H + 15) / 16} groups and waited for the fence`)
|
||||
|
||||
# ---- read the picture back
|
||||
let pp = bytes(8)
|
||||
r = vk_map_memory(dev, mem, zero, nbytes, 0, pp)
|
||||
r = vk_map_memory(vk_compute_st.dev, mem, zero, nbytes, 0, pp)
|
||||
if r != VK_SUCCESS { fail("vkMapMemory", r) }
|
||||
let px = vk_get_ptr(pp, 0)
|
||||
var out_path = "build/vk_compute.ppm"
|
||||
|
|
@ -329,19 +331,19 @@ program VkCompute {
|
|||
file_write(f, row, W * 3)
|
||||
}
|
||||
file_close(f)
|
||||
vk_unmap_memory(dev, mem)
|
||||
vk_unmap_memory(vk_compute_st.dev, mem)
|
||||
print(`vulkan: {lit} of {W * H} pixels written by the shader -> {out_path}`)
|
||||
|
||||
vk_destroy_fence(dev, vk_get_i64(fences, 0), null)
|
||||
vk_destroy_command_pool(dev, cmd_pool, null)
|
||||
vk_destroy_descriptor_pool(dev, pool, null)
|
||||
vk_destroy_pipeline(dev, pipeline, null)
|
||||
vk_destroy_pipeline_layout(dev, layout, null)
|
||||
vk_destroy_descriptor_set_layout(dev, vk_get_i64(set_layouts, 0), null)
|
||||
vk_destroy_shader_module(dev, module, null)
|
||||
vk_destroy_buffer(dev, buf, null)
|
||||
vk_free_memory(dev, mem, null)
|
||||
vk_destroy_device(dev, null)
|
||||
vk_destroy_fence(vk_compute_st.dev, vk_get_i64(fences, 0), null)
|
||||
vk_destroy_command_pool(vk_compute_st.dev, cmd_pool, null)
|
||||
vk_destroy_descriptor_pool(vk_compute_st.dev, pool, null)
|
||||
vk_destroy_pipeline(vk_compute_st.dev, pipeline, null)
|
||||
vk_destroy_pipeline_layout(vk_compute_st.dev, layout, null)
|
||||
vk_destroy_descriptor_set_layout(vk_compute_st.dev, vk_get_i64(set_layouts, 0), null)
|
||||
vk_destroy_shader_module(vk_compute_st.dev, module, null)
|
||||
vk_destroy_buffer(vk_compute_st.dev, buf, null)
|
||||
vk_free_memory(vk_compute_st.dev, mem, null)
|
||||
vk_destroy_device(vk_compute_st.dev, null)
|
||||
vk_destroy_instance(inst, null)
|
||||
if lit == W * H { print("VKCOMPUTE OK") } else { print("VKCOMPUTE INCOMPLETE") }
|
||||
quit()
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ program VkDevice {
|
|||
property Marker { on: int = 1 }
|
||||
model Anchor { Marker }
|
||||
|
||||
handler Boot phase Start {
|
||||
handler Boot(render3d_st: mut Render3dState) phase Start {
|
||||
spawn Anchor {}
|
||||
if not gvk_init() { print(`VKDEVICE NONE: {gvk_why}`); quit() }
|
||||
let cb = gvk_once_begin()
|
||||
let ok = cb != null and gvk_once_end(cb)
|
||||
print(`vulkan: family {gvk_family}, {Vk.get_i32(gvk_mp, VkPhysicalDeviceMemoryProperties_memoryTypeCount)} memory types, one-shot submit {ok}`)
|
||||
gvk_shutdown()
|
||||
if not gvk_init(render3d_st) { print(`VKDEVICE NONE: {render3d_st.gvk_why}`); quit() }
|
||||
let cb = gvk_once_begin(render3d_st)
|
||||
let ok = cb != null and gvk_once_end(render3d_st, cb)
|
||||
print(`vulkan: family {render3d_st.gvk_family}, {Vk.get_i32(render3d_st.gvk_mp, VkPhysicalDeviceMemoryProperties_memoryTypeCount)} memory types, one-shot submit {ok}`)
|
||||
gvk_shutdown(render3d_st)
|
||||
if ok { print("VKDEVICE OK") } else { print("VKDEVICE SUBMIT FAILED") }
|
||||
quit()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ program VkManifest {
|
|||
property Marker { on: int = 1 }
|
||||
model Anchor { Marker }
|
||||
|
||||
handler Boot phase Start {
|
||||
handler Boot(render3d_st: mut Render3dState) phase Start {
|
||||
spawn Anchor {}
|
||||
let n = gpu_manifest_load("packages/ludic.render3d/shaders/spv/manifest.txt")
|
||||
let n = gpu_manifest_load(render3d_st, "packages/ludic.render3d/shaders/spv/manifest.txt")
|
||||
print(`manifest: {n} programs`)
|
||||
var ok = n > 0
|
||||
let list = Fs.read_text("packages/ludic.render3d/shaders/variants.list")
|
||||
|
|
@ -24,13 +24,13 @@ program VkManifest {
|
|||
var defs = ""
|
||||
if len(parts) > 2 { defs = parts[2] }
|
||||
listed += 1
|
||||
let v = gpu_variant_find_key(parts[0], parts[1], defs)
|
||||
let v = gpu_variant_find_key(render3d_st, parts[0], parts[1], defs)
|
||||
if v == null { print(` NOT FOUND: {ln}`); ok = false } else { found += 1 }
|
||||
}
|
||||
print(`variants.list: {listed} listed, {found} resolved`)
|
||||
if found != listed { ok = false }
|
||||
# spot checks against what the tool wrote: the lit foliage program as scatter builds it
|
||||
let fol = gpu_variant_find("model.vert", "model.frag", "#define FOLIAGE\n#define WIND\n#define ALPHA_TEST\n")
|
||||
let fol = gpu_variant_find(render3d_st, "model.vert", "model.frag", "#define FOLIAGE\n#define WIND\n#define ALPHA_TEST\n")
|
||||
if fol == null { print(" the foliage program did not resolve"); ok = false }
|
||||
else {
|
||||
let uv = gpu_variant_uniform(fol, 0, "u_view")
|
||||
|
|
|
|||
|
|
@ -13,98 +13,100 @@ program VkResources {
|
|||
property Marker { on: int = 1 }
|
||||
model Anchor { Marker }
|
||||
|
||||
var failures: int = 0
|
||||
unsafe function check(what: string, ok: bool) -> void {
|
||||
if ok { print(`vulkan: {what} ok`) } else { print(`vulkan: {what} FAILED`); failures += 1 }
|
||||
state VkResourcesState {
|
||||
failures: int = 0
|
||||
}
|
||||
unsafe function check(vk_resources_st: mut VkResourcesState, what: string, ok: bool) -> void {
|
||||
if ok { print(`vulkan: {what} ok`) } else { print(`vulkan: {what} FAILED`); vk_resources_st.failures += 1 }
|
||||
}
|
||||
|
||||
handler Boot phase Start {
|
||||
handler Boot(render3d_st: mut Render3dState, vk_resources_st: mut VkResourcesState) phase Start {
|
||||
spawn Anchor {}
|
||||
print(`vulkan: OpenGL names spliced (pixel scale {Gl.pixel_scale()})`)
|
||||
if not gvk_init() { print(`VKRES NONE: {gvk_why}`); quit() }
|
||||
if not gvk_init(render3d_st) { print(`VKRES NONE: {render3d_st.gvk_why}`); quit() }
|
||||
|
||||
# RGBA8 up and back, byte for byte
|
||||
let w = 64
|
||||
let h = 32
|
||||
let px = bytes(w * h * 4)
|
||||
for i in 0 .. w * h { px[i * 4] = i & 255; px[i * 4 + 1] = (i >> 8) & 255; px[i * 4 + 2] = (i * 7) & 255; px[i * 4 + 3] = 200 }
|
||||
let t1 = gvk_tex_new()
|
||||
check("RGBA8 storage with mips", gvk_tex_storage(t1, false, GL_RGBA8, w, h, 1, true))
|
||||
check("RGBA8 upload", gvk_tex_upload(t1, GL_RGBA8, w, h, 1, GL_RGBA, GL_UNSIGNED_BYTE, px))
|
||||
check("RGBA8 mip chain (7 levels)", gvk_tex_levels[t1] == 7 and gvk_tex_mips(t1, w, h))
|
||||
let t1 = gvk_tex_new(render3d_st)
|
||||
check(vk_resources_st, "RGBA8 storage with mips", gvk_tex_storage(render3d_st, t1, false, GL_RGBA8, w, h, 1, true))
|
||||
check(vk_resources_st, "RGBA8 upload", gvk_tex_upload(render3d_st, t1, GL_RGBA8, w, h, 1, GL_RGBA, GL_UNSIGNED_BYTE, px))
|
||||
check(vk_resources_st, "RGBA8 mip chain (7 levels)", render3d_st.gvk_tex_levels[t1] == 7 and gvk_tex_mips(render3d_st, t1, w, h))
|
||||
let back = bytes(w * h * 4)
|
||||
check("RGBA8 read-back call", gvk_tex_read(t1, GL_RGBA8, w, h, GL_RGBA, GL_UNSIGNED_BYTE, back))
|
||||
check(vk_resources_st, "RGBA8 read-back call", gvk_tex_read(render3d_st, t1, GL_RGBA8, w, h, GL_RGBA, GL_UNSIGNED_BYTE, back))
|
||||
var same = true
|
||||
for i in 0 .. w * h * 4 { if back[i] != px[i] { same = false } }
|
||||
check("RGBA8 read-back matches", same)
|
||||
check(vk_resources_st, "RGBA8 read-back matches", same)
|
||||
|
||||
# R32F, the terrain's height field path
|
||||
let hf = bytes(w * h * 4)
|
||||
for i in 0 .. w * h { Vk.put_i32(hf, i * 4, 0x40000000 + i) }
|
||||
let t2 = gvk_tex_new()
|
||||
check("R32F target", gvk_tex_storage(t2, false, GL_R32F, w, h, 1, false))
|
||||
check("R32F upload", gvk_tex_upload(t2, GL_R32F, w, h, 1, GL_RED, GL_FLOAT, hf))
|
||||
let t2 = gvk_tex_new(render3d_st)
|
||||
check(vk_resources_st, "R32F target", gvk_tex_storage(render3d_st, t2, false, GL_R32F, w, h, 1, false))
|
||||
check(vk_resources_st, "R32F upload", gvk_tex_upload(render3d_st, t2, GL_R32F, w, h, 1, GL_RED, GL_FLOAT, hf))
|
||||
let hb = bytes(w * h * 4)
|
||||
check("R32F read-back call", gvk_tex_read(t2, GL_R32F, w, h, GL_RED, GL_FLOAT, hb))
|
||||
check(vk_resources_st, "R32F read-back call", gvk_tex_read(render3d_st, t2, GL_R32F, w, h, GL_RED, GL_FLOAT, hb))
|
||||
var hsame = true
|
||||
for i in 0 .. w * h * 4 { if hb[i] != hf[i] { hsame = false } }
|
||||
check("R32F read-back matches", hsame)
|
||||
check(vk_resources_st, "R32F read-back matches", hsame)
|
||||
|
||||
# RGB8 stored as RGBA, and an HDR image's float RGB into half floats
|
||||
let rgb = bytes(w * h * 3)
|
||||
for i in 0 .. w * h * 3 { rgb[i] = (i * 3) & 255 }
|
||||
let t3 = gvk_tex_new()
|
||||
check("SRGB8 expanded to RGBA", gvk_tex_storage(t3, false, GL_SRGB8, w, h, 1, true) and gvk_tex_upload(t3, GL_SRGB8, w, h, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb))
|
||||
let t3 = gvk_tex_new(render3d_st)
|
||||
check(vk_resources_st, "SRGB8 expanded to RGBA", gvk_tex_storage(render3d_st, t3, false, GL_SRGB8, w, h, 1, true) and gvk_tex_upload(render3d_st, t3, GL_SRGB8, w, h, 1, GL_RGB, GL_UNSIGNED_BYTE, rgb))
|
||||
let fl = bytes(w * h * 12)
|
||||
for i in 0 .. w * h * 3 { Vk.put_i32(fl, i * 4, 0x3FC00000) }
|
||||
let t4 = gvk_tex_new()
|
||||
check("RGB16F from floats (halved)", gvk_tex_storage(t4, false, GL_RGB16F, w, h, 1, true) and gvk_tex_upload(t4, GL_RGB16F, w, h, 1, GL_RGB, GL_FLOAT, fl))
|
||||
check("half of 1.5 is 0x3E00", gvk_half(0x3FC00000) == 0x3E00)
|
||||
let t4 = gvk_tex_new(render3d_st)
|
||||
check(vk_resources_st, "RGB16F from floats (halved)", gvk_tex_storage(render3d_st, t4, false, GL_RGB16F, w, h, 1, true) and gvk_tex_upload(render3d_st, t4, GL_RGB16F, w, h, 1, GL_RGB, GL_FLOAT, fl))
|
||||
check(vk_resources_st, "half of 1.5 is 0x3E00", gvk_half(0x3FC00000) == 0x3E00)
|
||||
|
||||
# a 16-bit RGB PNG (a normal map): big-endian samples, swapped on upload, alpha filled opaque
|
||||
let n16 = bytes(w * h * 6)
|
||||
for i in 0 .. w * h * 3 { n16[i * 2] = (i >> 8) & 255; n16[i * 2 + 1] = i & 255 }
|
||||
let t7 = gvk_tex_new()
|
||||
gvk_unpack_swap = true
|
||||
check("RGB16 swapped upload", gvk_tex_storage(t7, false, GL_RGB16, w, h, 1, true) and gvk_tex_upload(t7, GL_RGB16, w, h, 1, GL_RGB, GL_UNSIGNED_SHORT, n16))
|
||||
gvk_unpack_swap = false
|
||||
let t7 = gvk_tex_new(render3d_st)
|
||||
render3d_st.gvk_unpack_swap = true
|
||||
check(vk_resources_st, "RGB16 swapped upload", gvk_tex_storage(render3d_st, t7, false, GL_RGB16, w, h, 1, true) and gvk_tex_upload(render3d_st, t7, GL_RGB16, w, h, 1, GL_RGB, GL_UNSIGNED_SHORT, n16))
|
||||
render3d_st.gvk_unpack_swap = false
|
||||
let b16 = bytes(w * h * 6)
|
||||
check("RGB16 read-back call", gvk_tex_read(t7, GL_RGB16, w, h, GL_RGB, GL_UNSIGNED_SHORT, b16))
|
||||
check(vk_resources_st, "RGB16 read-back call", gvk_tex_read(render3d_st, t7, GL_RGB16, w, h, GL_RGB, GL_UNSIGNED_SHORT, b16))
|
||||
var s16 = true
|
||||
for i in 0 .. w * h * 3 { if b16[i * 2] != (i & 255) or b16[i * 2 + 1] != ((i >> 8) & 255) { s16 = false } }
|
||||
check("RGB16 samples arrive little-endian", s16)
|
||||
check(vk_resources_st, "RGB16 samples arrive little-endian", s16)
|
||||
|
||||
# the shadow cascades: a depth array, and a render-sized half-float target with no pixels
|
||||
let t5 = gvk_tex_new()
|
||||
check("D32 array of 4", gvk_tex_storage(t5, true, GL_DEPTH_COMPONENT32F, 256, 256, 4, false))
|
||||
let t6 = gvk_tex_new()
|
||||
check("RGBA16F target", gvk_tex_storage(t6, false, GL_RGBA16F, 320, 180, 1, false))
|
||||
let t5 = gvk_tex_new(render3d_st)
|
||||
check(vk_resources_st, "D32 array of 4", gvk_tex_storage(render3d_st, t5, true, GL_DEPTH_COMPONENT32F, 256, 256, 4, false))
|
||||
let t6 = gvk_tex_new(render3d_st)
|
||||
check(vk_resources_st, "RGBA16F target", gvk_tex_storage(render3d_st, t6, false, GL_RGBA16F, 320, 180, 1, false))
|
||||
|
||||
# the samplers the renderer asks for, and that asking twice returns the same one
|
||||
let s1 = gvk_sampler(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT, 0, 0x41800000)
|
||||
let s2 = gvk_sampler(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, 0)
|
||||
let s3 = gvk_sampler(GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER, GL_LEQUAL, 0)
|
||||
let s4 = gvk_sampler(GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, 0)
|
||||
let again = gvk_sampler(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT, 0, 0x41800000)
|
||||
check("four samplers made", s1 != 0 and s2 != 0 and s3 != 0 and s4 != 0 and len(gvk_smp) == 4)
|
||||
check("a sampler asked for twice is one sampler", again == s1)
|
||||
let s1 = gvk_sampler(render3d_st, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT, 0, 0x41800000)
|
||||
let s2 = gvk_sampler(render3d_st, GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, 0)
|
||||
let s3 = gvk_sampler(render3d_st, GL_LINEAR, GL_LINEAR, GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER, GL_LEQUAL, 0)
|
||||
let s4 = gvk_sampler(render3d_st, GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, 0)
|
||||
let again = gvk_sampler(render3d_st, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT, 0, 0x41800000)
|
||||
check(vk_resources_st, "four samplers made", s1 != 0 and s2 != 0 and s3 != 0 and s4 != 0 and len(render3d_st.gvk_smp) == 4)
|
||||
check(vk_resources_st, "a sampler asked for twice is one sampler", again == s1)
|
||||
|
||||
# a buffer filled, filled again smaller (kept), then larger (grown)
|
||||
let b = gvk_buf_new()
|
||||
let b = gvk_buf_new(render3d_st)
|
||||
let data = bytes(4096)
|
||||
for i in 0 .. 4096 { data[i] = i & 255 }
|
||||
check("buffer upload", gvk_buf_upload(b, 1024, data))
|
||||
let first = gvk_buf[b]
|
||||
check("a smaller upload keeps the buffer", gvk_buf_upload(b, 512, data) and gvk_buf[b] == first)
|
||||
check("a larger upload grows it", gvk_buf_upload(b, 4096, data) and gvk_buf_size[b] >= 4096)
|
||||
check(vk_resources_st, "buffer upload", gvk_buf_upload(render3d_st, b, 1024, data))
|
||||
let first = render3d_st.gvk_buf[b]
|
||||
check(vk_resources_st, "a smaller upload keeps the buffer", gvk_buf_upload(render3d_st, b, 512, data) and render3d_st.gvk_buf[b] == first)
|
||||
check(vk_resources_st, "a larger upload grows it", gvk_buf_upload(render3d_st, b, 4096, data) and render3d_st.gvk_buf_size[b] >= 4096)
|
||||
|
||||
for t in 1 .. 8 { gvk_tex_release(t) }
|
||||
gvk_buf_release(b)
|
||||
for i in 0 .. len(gvk_smp) { Vk.destroy_sampler(gvk_dev, gvk_smp[i], null) }
|
||||
print(`vulkan: {gvk_n_allocs} allocations left after freeing`)
|
||||
check("every allocation freed", gvk_n_allocs == 0)
|
||||
gvk_shutdown()
|
||||
if failures == 0 { print("VKRES OK") } else { print(`VKRES FAILED ({failures})`) }
|
||||
for t in 1 .. 8 { gvk_tex_release(render3d_st, t) }
|
||||
gvk_buf_release(render3d_st, b)
|
||||
for i in 0 .. len(render3d_st.gvk_smp) { Vk.destroy_sampler(render3d_st.gvk_dev, render3d_st.gvk_smp[i], null) }
|
||||
print(`vulkan: {render3d_st.gvk_n_allocs} allocations left after freeing`)
|
||||
check(vk_resources_st, "every allocation freed", render3d_st.gvk_n_allocs == 0)
|
||||
gvk_shutdown(render3d_st)
|
||||
if vk_resources_st.failures == 0 { print("VKRES OK") } else { print(`VKRES FAILED ({vk_resources_st.failures})`) }
|
||||
quit()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@ program VkTriangle {
|
|||
}
|
||||
return false
|
||||
}
|
||||
var spv_len: int = 0
|
||||
unsafe function read_all(path: string) -> bytes {
|
||||
state VkTriangleState {
|
||||
spv_len: int = 0
|
||||
}
|
||||
unsafe function read_all(vk_triangle_st: mut VkTriangleState, path: string) -> bytes {
|
||||
let f = file_open(path, "rb")
|
||||
if f == null { return null }
|
||||
file_seek(f, 0, 2)
|
||||
|
|
@ -39,7 +41,7 @@ program VkTriangle {
|
|||
let b = bytes(n + 4)
|
||||
file_read(f, b, n)
|
||||
file_close(f)
|
||||
spv_len = n
|
||||
vk_triangle_st.spv_len = n
|
||||
return b
|
||||
}
|
||||
# the first memory type the resource allows that has every property wanted
|
||||
|
|
@ -72,13 +74,13 @@ program VkTriangle {
|
|||
color_range(b, VkImageMemoryBarrier_subresourceRange)
|
||||
vk_cmd_pipeline_barrier(cb, src_stage, dst_stage, 0, 0, null, 0, null, 1, b)
|
||||
}
|
||||
unsafe function shader_module(dev: pointer, path: string) -> long {
|
||||
let spv = read_all(path)
|
||||
unsafe function shader_module(vk_triangle_st: mut VkTriangleState, dev: pointer, path: string) -> long {
|
||||
let spv = read_all(vk_triangle_st, path)
|
||||
if spv == null { print(`vulkan: no SPIR-V at {path} (compile vk_triangle.slang with slangc)`); quit() }
|
||||
let smci = bytes(VkShaderModuleCreateInfo_sizeof)
|
||||
vk_zero(smci, VkShaderModuleCreateInfo_sizeof)
|
||||
vk_put_i32(smci, VkShaderModuleCreateInfo_sType, VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO)
|
||||
let code_size: long = spv_len
|
||||
let code_size: long = vk_triangle_st.spv_len
|
||||
vk_put_i64(smci, VkShaderModuleCreateInfo_codeSize, code_size)
|
||||
vk_put_ptr(smci, VkShaderModuleCreateInfo_pCode, spv)
|
||||
let out = bytes(8)
|
||||
|
|
@ -87,7 +89,7 @@ program VkTriangle {
|
|||
return handle(out)
|
||||
}
|
||||
|
||||
handler Boot phase Start {
|
||||
handler Boot(vk_triangle_st: mut VkTriangleState) phase Start {
|
||||
spawn Anchor {}
|
||||
var vs_path = "build/vk_triangle_vs.spv"
|
||||
var fs_path = "build/vk_triangle_fs.spv"
|
||||
|
|
@ -253,8 +255,8 @@ program VkTriangle {
|
|||
if r != VK_SUCCESS { fail("vkBindBufferMemory", r) }
|
||||
|
||||
# ---- the pipeline: two stages, no vertex input, dynamic viewport and scissor, one colour format
|
||||
let vs = shader_module(dev, vs_path)
|
||||
let fs = shader_module(dev, fs_path)
|
||||
let vs = shader_module(vk_triangle_st, dev, vs_path)
|
||||
let fs = shader_module(vk_triangle_st, dev, fs_path)
|
||||
let plci = bytes(VkPipelineLayoutCreateInfo_sizeof)
|
||||
vk_zero(plci, VkPipelineLayoutCreateInfo_sizeof)
|
||||
vk_put_i32(plci, VkPipelineLayoutCreateInfo_sType, VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue