#version 430 core #extension GL_ARB_bindless_texture : require in vec2 vUv; in vec4 vColor; out vec4 FragColor; // Campaign V slice V6d: the retained UI samples the device's global texture // table instead of whatever happened to be bound to texture unit 0. The old // `uniform sampler2D uTex` plus `uniform int uUseTexture` pair could not exist // under Vulkan — there is no default uniform block, and an opaque sampler // cannot be a push constant — so both are expressed with the pinned block's two // texture-table slots. There is no third field and none was needed: which slots // are ASSIGNED is itself the mode. // // uTextureIndexB assigned -> single-channel coverage source (a font atlas): // red is the glyph's alpha, and the colour's RGB // is NOT multiplied by it. // uTextureIndexA assigned -> RGBA colour source (dat chrome, icons, sprites), // modulated by the vertex colour/tint. // neither assigned -> a flat quad in the vertex colour. Untextured // rects and DrawFill take this path; the old // shader's uUseTexture==0 branch is unchanged. // // Exactly one of the two is ever assigned at a time, so the branch is uniform // across a draw. uniform uint uTextureIndexA; uniform uint uTextureIndexB; // GpuTextureSlot.Unassigned. It is a loud sentinel precisely so it can be // tested for rather than silently resolving to slot 0 — the failure mode that // produced the magenta 1x1 UI placeholder. Both branches below are guarded, so // it never reaches a sampler. const uint kUnassignedTextureSlot = 0xFFFFFFFFu; void main() { if (uTextureIndexB != kUnassignedTextureSlot) { // Font atlas is a single-channel R8 texture; red = coverage alpha. float coverage = ACDREAM_SAMPLE_2D(uTextureIndexB, vUv).r; FragColor = vec4(vColor.rgb, vColor.a * coverage); } else if (uTextureIndexA != kUnassignedTextureSlot) { // RGBA dat sprite (decoded to RGBA8); modulate by tint/alpha. FragColor = ACDREAM_SAMPLE_2D(uTextureIndexA, vUv) * vColor; } else { FragColor = vColor; } if (FragColor.a < 0.005) discard; }