fix(selection): port SmartBox click lighting pulse

Port the retail high/low material-lighting cadence for successful world clicks, keep it instance-scoped in the modern renderer, and restore authored lighting after 0.8 seconds. Correct the selection oracle and pin timing plus per-frame buffer lifecycle with tests.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-17 23:00:04 +02:00
parent 146a963aeb
commit ea4f52ec51
11 changed files with 338 additions and 16 deletions

View file

@ -7,10 +7,6 @@ layout(location = 2) in vec2 aTexCoord;
struct InstanceData {
mat4 transform;
// Reserved for Phase B.4 follow-up (selection-blink retail-faithful
// highlight): vec4 highlightColor; — extend stride here, increase the
// _instanceSsbo upload size in WbDrawDispatcher, add a flat varying out,
// and consume in mesh_modern.frag.
};
struct BatchData {
@ -115,6 +111,15 @@ layout(std430, binding = 7) readonly buffer InstanceAlphaBuf {
float instanceAlpha[];
};
// Retail SmartBox click confirmation. One vec2 per OBJECT instance, parallel
// to binding=0: x = CMaterial luminosity, y = CMaterial diffuse. Normal
// rendering is (0,1); SmartBox alternates LOW=(0,.35) and HIGH=(.99,1).
// EnvCellRenderer uses uLightingMode=1 and deliberately never reads this
// object-only binding.
layout(std430, binding = 8) readonly buffer InstanceSelectionLightingBuf {
vec2 instanceSelectionLighting[];
};
// Core profile: redeclare gl_PerVertex so writing gl_ClipDistance[] is legal
// alongside gl_Position. The array is sized 8 to match the CellClip plane budget
// and the GL guarantee (GL_MAX_CLIP_DISTANCES >= 8). The host enables
@ -277,11 +282,15 @@ out vec3 vLit; // A7: per-vertex Gouraud lighting (ambient + capped l
out flat uvec2 vTextureHandle;
out flat uint vTextureLayer;
out flat float vOpacityMultiplier; // #188
out flat vec2 vSelectionLighting;
void main() {
int instanceIndex = gl_BaseInstanceARB + gl_InstanceID;
mat4 model = Instances[instanceIndex].transform;
vOpacityMultiplier = instanceAlpha[instanceIndex]; // #188
vSelectionLighting = (uLightingMode == 0)
? instanceSelectionLighting[instanceIndex]
: vec2(0.0, 1.0);
vec4 worldPos = model * vec4(aPosition, 1.0);
gl_Position = uViewProjection * worldPos;