Merge commit 'e691f07' into lang/foundations
This commit is contained in:
commit
614f030407
3 changed files with 93 additions and 2 deletions
|
|
@ -411,7 +411,7 @@ function actor_draw_casters(render3d_st: mut Render3dState, light_vp: floats) ->
|
||||||
var ap = render3d_st.ac_sh
|
var ap = render3d_st.ac_sh
|
||||||
if a.cutout { ap = render3d_st.ac_sh_cut }
|
if a.cutout { ap = render3d_st.ac_sh_cut }
|
||||||
if render3d_st.ac_census_at > 0 and render3d_st.ac_frame == render3d_st.ac_census_at { ac_caster_count(render3d_st, a) }
|
if render3d_st.ac_census_at > 0 and render3d_st.ac_frame == render3d_st.ac_census_at { ac_caster_count(render3d_st, a) }
|
||||||
actor_draw_one(render3d_st, a, ap, true)
|
if ac_proxy_figure(render3d_st, a) { actor_draw_proxy(render3d_st, a) } else { actor_draw_one(render3d_st, a, ap, true) }
|
||||||
}
|
}
|
||||||
if render3d_st.ac_census_at > 0 and render3d_st.ac_frame == render3d_st.ac_census_at {
|
if render3d_st.ac_census_at > 0 and render3d_st.ac_frame == render3d_st.ac_census_at {
|
||||||
print(`actor census, cascade {render3d_st.sh_cascade}: {render3d_st.ac_cc_actors} actors cast {render3d_st.ac_cc_draws} draws ({render3d_st.ac_cc_skinned} of them skinned, {render3d_st.ac_cc_cut} cutout)`)
|
print(`actor census, cascade {render3d_st.sh_cascade}: {render3d_st.ac_cc_actors} actors cast {render3d_st.ac_cc_draws} draws ({render3d_st.ac_cc_skinned} of them skinned, {render3d_st.ac_cc_cut} cutout)`)
|
||||||
|
|
@ -492,3 +492,87 @@ function actor_room(l: []Actor, n: int) -> void {
|
||||||
for i in 0 .. n { push(l, null) }
|
for i in 0 .. n { push(l, null) }
|
||||||
while len(l) > have { List.pop(l) }
|
while len(l) > have { List.pop(l) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---- a figure's shadow past 60 m: one capsule ---------------------------------------------------
|
||||||
|
# A dressed figure is up to 86 skinned pieces, and the far cascades (2 and out: receivers from 60 m)
|
||||||
|
# drew each piece of every walker in them - most of a forest frame's shadow pass. Nobody can tell a
|
||||||
|
# garment's shadow from the body's there, so a figure casts one capsule its own height instead.
|
||||||
|
# Animals (a piece or two) and anything rigid keep their own shape.
|
||||||
|
const AC_PROXY_CASCADE: int = 2
|
||||||
|
const AC_PROXY_SIDES: int = 8
|
||||||
|
const AC_PROXY_R: float = 0.13 # the capsule's radius, as a fraction of the figure's height
|
||||||
|
function ac_proxy_figure(render3d_st: Render3dState, a: Actor) -> bool {
|
||||||
|
if render3d_st.sh_cascade < AC_PROXY_CASCADE { return false }
|
||||||
|
if a.skin == null and a.model.skin == null { return false }
|
||||||
|
return len(a.model.prims) > 8
|
||||||
|
}
|
||||||
|
function actor_draw_proxy(render3d_st: mut Render3dState, a: Actor) -> void {
|
||||||
|
let m = ac_proxy_mesh(render3d_st)
|
||||||
|
let ap = render3d_st.ac_sh
|
||||||
|
gpu_use_program(render3d_st, ap.prog)
|
||||||
|
let h = a.model.height
|
||||||
|
m4_scaling(render3d_st.ac_proxy_s, h * AC_PROXY_R, h, h * AC_PROXY_R)
|
||||||
|
m4_mul(render3d_st.ac_proxy_m, a.mat, render3d_st.ac_proxy_s)
|
||||||
|
u_mat4(render3d_st, ap.l_model, render3d_st.ac_proxy_m)
|
||||||
|
u_f(render3d_st, ap.l_skin, 0.0)
|
||||||
|
gpu_cull(render3d_st, false)
|
||||||
|
mesh_draw(render3d_st, m)
|
||||||
|
}
|
||||||
|
# a unit capsule (radius 1, height 1, feet at the origin): a ring of AC_PROXY_SIDES at each end of the
|
||||||
|
# body and a cone to a point below and above them
|
||||||
|
@alloc_ok("made once: the capsule every far figure casts, and its two matrices")
|
||||||
|
function ac_proxy_mesh(render3d_st: mut Render3dState) -> Mesh {
|
||||||
|
if render3d_st.ac_proxy != null { return render3d_st.ac_proxy }
|
||||||
|
render3d_st.ac_proxy_s = m4_new()
|
||||||
|
render3d_st.ac_proxy_m = m4_new()
|
||||||
|
let n = AC_PROXY_SIDES
|
||||||
|
let nv = 2 + 2 * n
|
||||||
|
let pos = gl_floats(nv * 3)
|
||||||
|
let nrm = gl_floats(nv * 3)
|
||||||
|
let uv = gl_floats(nv * 2)
|
||||||
|
ac_proxy_vert(pos, nrm, 0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0)
|
||||||
|
ac_proxy_vert(pos, nrm, 1, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0)
|
||||||
|
for i in 0 .. n {
|
||||||
|
let t = float(i) * 6.2831853 / float(n)
|
||||||
|
let cx = Math.cos(t)
|
||||||
|
let sz = Math.sin(t)
|
||||||
|
ac_proxy_vert(pos, nrm, 2 + i, cx, AC_PROXY_R, sz, cx, 0.0, sz)
|
||||||
|
ac_proxy_vert(pos, nrm, 2 + n + i, cx, 1.0 - AC_PROXY_R, sz, cx, 0.0, sz)
|
||||||
|
}
|
||||||
|
for i in 0 .. nv * 2 { gl_put_bits(uv, i, float_bits(0.0)) }
|
||||||
|
let m = gpu_mesh_new(render3d_st)
|
||||||
|
gpu_mesh_vertices(render3d_st, m, pos, gl_bytes_of(nv * 3), GPU_STATIC)
|
||||||
|
gpu_mesh_attr(render3d_st, m, 0, 3, GPU_F32, 0, 0, false)
|
||||||
|
gpu_mesh_vertices(render3d_st, m, nrm, gl_bytes_of(nv * 3), GPU_STATIC)
|
||||||
|
gpu_mesh_attr(render3d_st, m, 1, 3, GPU_F32, 0, 0, false)
|
||||||
|
gpu_mesh_vertices(render3d_st, m, uv, gl_bytes_of(nv * 2), GPU_STATIC)
|
||||||
|
gpu_mesh_attr(render3d_st, m, 2, 2, GPU_F32, 0, 0, false)
|
||||||
|
free(pos)
|
||||||
|
free(nrm)
|
||||||
|
free(uv)
|
||||||
|
let ni = n * 12
|
||||||
|
let idx = words(ni)
|
||||||
|
var k = 0
|
||||||
|
for i in 0 .. n {
|
||||||
|
let j = (i + 1) % n
|
||||||
|
let b0 = 2 + i
|
||||||
|
let b1 = 2 + j
|
||||||
|
let t0 = 2 + n + i
|
||||||
|
let t1 = 2 + n + j
|
||||||
|
idx[k] = 0; idx[k + 1] = b0; idx[k + 2] = b1
|
||||||
|
idx[k + 3] = b0; idx[k + 4] = t0; idx[k + 5] = t1
|
||||||
|
idx[k + 6] = b0; idx[k + 7] = t1; idx[k + 8] = b1
|
||||||
|
idx[k + 9] = 1; idx[k + 10] = t1; idx[k + 11] = t0
|
||||||
|
k += 12
|
||||||
|
}
|
||||||
|
gpu_mesh_indices(render3d_st, m, data_of(idx), ni * 4, 4)
|
||||||
|
free(idx)
|
||||||
|
m.count = ni
|
||||||
|
gpu_mesh_done(render3d_st, m)
|
||||||
|
render3d_st.ac_proxy = m
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
function ac_proxy_vert(pos: pointer, nrm: pointer, v: int, x: float, y: float, z: float, nx: float, ny: float, nz: float) -> void {
|
||||||
|
gl_put_bits(pos, v * 3, float_bits(x)); gl_put_bits(pos, v * 3 + 1, float_bits(y)); gl_put_bits(pos, v * 3 + 2, float_bits(z))
|
||||||
|
gl_put_bits(nrm, v * 3, float_bits(nx)); gl_put_bits(nrm, v * 3 + 1, float_bits(ny)); gl_put_bits(nrm, v * 3 + 2, float_bits(nz))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ export state Render3dState {
|
||||||
ac_oq_n: int = 0 # live entries; the array is kept and reused
|
ac_oq_n: int = 0 # live entries; the array is kept and reused
|
||||||
ac_oq_closed: bool = true
|
ac_oq_closed: bool = true
|
||||||
ac_census_at: int = -2
|
ac_census_at: int = -2
|
||||||
|
ac_proxy: Mesh = null # the capsule a figure casts in the far cascades (actor.ludic)
|
||||||
|
ac_proxy_s: floats = null # its scale and its world matrix, made with it
|
||||||
|
ac_proxy_m: floats = null
|
||||||
ac_lp0: floats = floats(3)
|
ac_lp0: floats = floats(3)
|
||||||
ac_lpx: floats = floats(3)
|
ac_lpx: floats = floats(3)
|
||||||
ac_lpy: floats = floats(3)
|
ac_lpy: floats = floats(3)
|
||||||
|
|
|
||||||
|
|
@ -1058,6 +1058,7 @@ function scatter_draw(render3d_st: mut Render3dState) -> void {
|
||||||
# whole class of caster vanish at a fixed distance, which is exactly the popping. A layer
|
# whole class of caster vanish at a fixed distance, which is exactly the popping. A layer
|
||||||
# with an impostor now casts its entire instance list from the card in every cascade;
|
# with an impostor now casts its entire instance list from the card in every cascade;
|
||||||
# only layers that have no impostor at all fall back to the mesh.
|
# only layers that have no impostor at all fall back to the mesh.
|
||||||
|
const SC_IMP_CAST_CASCADE: int = 2
|
||||||
function scatter_draw_casters(render3d_st: mut Render3dState, light_vp: floats) -> void {
|
function scatter_draw_casters(render3d_st: mut Render3dState, light_vp: floats) -> void {
|
||||||
for i in 0 .. len(render3d_st.sc_layers) {
|
for i in 0 .. len(render3d_st.sc_layers) {
|
||||||
let l = render3d_st.sc_layers[i]
|
let l = render3d_st.sc_layers[i]
|
||||||
|
|
@ -1067,7 +1068,10 @@ function scatter_draw_casters(render3d_st: mut Render3dState, light_vp: floats)
|
||||||
if render3d_st.r3d_no_trees and l.imp != null and not l.card { continue }
|
if render3d_st.r3d_no_trees and l.imp != null and not l.card { continue }
|
||||||
layer_update(render3d_st, l)
|
layer_update(render3d_st, l)
|
||||||
if l.imp != null {
|
if l.imp != null {
|
||||||
layer_draw_shadow(render3d_st, l, light_vp)
|
# the impostor casts only into the far cascades: every tree on the map was drawn as a card
|
||||||
|
# into the near two as well, whose receivers (within 60 m) are shaded by the near trees'
|
||||||
|
# own LOD2 meshes, cast just below
|
||||||
|
if render3d_st.sh_cascade >= SC_IMP_CAST_CASCADE { layer_draw_shadow(render3d_st, l, light_vp) }
|
||||||
# Shadow LOD (the practice in every production engine: a caster uses a low mesh LOD,
|
# Shadow LOD (the practice in every production engine: a caster uses a low mesh LOD,
|
||||||
# the billboard only far away). The card alone is a side-view silhouette and a
|
# the billboard only far away). The card alone is a side-view silhouette and a
|
||||||
# crown of drooping needle cards is mostly slivers from the side, so the sun, which
|
# crown of drooping needle cards is mostly slivers from the side, so the sun, which
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue