fix(render3d): outline_model's batch survives the whole frame
A frame is drawn by more than one pass - a shadow map, a water reflection, the scene - and actor_draw runs in each. An Actor's rim survives that because it is a field on the actor; the queue did not, because the first pass to run emptied it. A queued outline was drawn into whichever target came first and was gone by the time the scene was drawn, so nothing appeared with every uniform, matrix and mesh correct - which took a while to find. A flush now closes the batch rather than clearing it, and the next outline_model opens a new one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ee2595e139
commit
3137df4fe6
2 changed files with 21 additions and 2 deletions
12
changes/outline-queue-lifetime.md
Normal file
12
changes/outline-queue-lifetime.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
bump: patch
|
||||||
|
type: fix
|
||||||
|
**`outline_model`'s batch survives the whole frame.** A frame is drawn by more than one
|
||||||
|
pass — a shadow map, a water reflection, the scene — and `actor_draw` runs in each of
|
||||||
|
them. An Actor's rim survives that because it is a field on the actor; the queue did not,
|
||||||
|
because the first pass to run emptied it, so a queued outline was drawn into whichever
|
||||||
|
target happened to come first and was gone by the time the scene was drawn. Nothing
|
||||||
|
appeared, with every uniform, matrix and mesh correct.
|
||||||
|
|
||||||
|
A flush now *closes* the batch rather than clearing it, and the next `outline_model`
|
||||||
|
opens a new one: every pass in a frame sees the same requests, and a caller still needs
|
||||||
|
no frame hook.
|
||||||
|
|
@ -213,8 +213,15 @@ property OutlineReq {
|
||||||
}
|
}
|
||||||
var ac_oq: []OutlineReq = null
|
var ac_oq: []OutlineReq = null
|
||||||
var ac_oq_n: int = 0 # live entries; the array is kept and reused
|
var ac_oq_n: int = 0 # live entries; the array is kept and reused
|
||||||
|
# A frame is drawn by more than one pass - a shadow map, a water reflection, the scene -
|
||||||
|
# and actor_draw runs in each of them. An Actor survives that because its rim is a field
|
||||||
|
# on the actor; a queue does not, if the first pass empties it. So a flush CLOSES the
|
||||||
|
# batch rather than clearing it, and the next add opens a new one: every pass in a frame
|
||||||
|
# sees the same requests, and the caller needs no frame hook.
|
||||||
|
var ac_oq_closed: bool = true
|
||||||
function outline_model(m: Model, mat: words, width: int, r: int, g: int, b: int) -> void {
|
function outline_model(m: Model, mat: words, width: int, r: int, g: int, b: int) -> void {
|
||||||
if m == null or mat == null or width == 0 { return }
|
if m == null or mat == null or width == 0 { return }
|
||||||
|
if ac_oq_closed { ac_oq_n = 0; ac_oq_closed = false }
|
||||||
if ac_oq == null { ac_oq = new []OutlineReq }
|
if ac_oq == null { ac_oq = new []OutlineReq }
|
||||||
var q: OutlineReq = null
|
var q: OutlineReq = null
|
||||||
if ac_oq_n < len(ac_oq) { q = ac_oq[ac_oq_n] } else { q = new OutlineReq; q.mat = m4_new(); push(ac_oq, q) }
|
if ac_oq_n < len(ac_oq) { q = ac_oq[ac_oq_n] } else { q = new OutlineReq; q.mat = m4_new(); push(ac_oq, q) }
|
||||||
|
|
@ -222,7 +229,7 @@ function outline_model(m: Model, mat: words, width: int, r: int, g: int, b: int)
|
||||||
m4_copy(q.mat, mat)
|
m4_copy(q.mat, mat)
|
||||||
ac_oq_n += 1
|
ac_oq_n += 1
|
||||||
}
|
}
|
||||||
function outline_clear() -> void { ac_oq_n = 0 }
|
function outline_clear() -> void { ac_oq_n = 0; ac_oq_closed = true }
|
||||||
|
|
||||||
function actor_draw() -> void {
|
function actor_draw() -> void {
|
||||||
if ac_actors == null { return }
|
if ac_actors == null { return }
|
||||||
|
|
@ -271,7 +278,7 @@ function actor_draw_outlines() -> void {
|
||||||
u_f(ap.l_skin, F_ZERO)
|
u_f(ap.l_skin, F_ZERO)
|
||||||
for k in 0 .. len(q.model.prims) { mesh_draw(q.model.prims[k].mesh) }
|
for k in 0 .. len(q.model.prims) { mesh_draw(q.model.prims[k].mesh) }
|
||||||
}
|
}
|
||||||
ac_oq_n = 0
|
ac_oq_closed = true
|
||||||
gl_cull_face(GL_BACK)
|
gl_cull_face(GL_BACK)
|
||||||
}
|
}
|
||||||
function actor_draw_outline_one(a: Actor, ap: AcProg) -> void {
|
function actor_draw_outline_one(a: Actor, ap: AcProg) -> void {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue