Fade player names under the cursor, with a graphics setting to tune it (#4221)

## Description:

Player name plates can block the view of what's underneath them
(structures, units, terrain). This PR fades the entire name plate —
name, troop count, flag, and emoji/status row — to 25% opacity while the
cursor is over it, so you can see and click what's behind it.

**How it works:**

- `HoverHighlightController` pushes the cursor's world position into the
renderer on mouse move.
- `NamePass` hit-tests the cursor against each player's name plate
bounds on the CPU (mirroring the lerp/sizing math in `name.vert.glsl`)
and passes the matched player's ID to the text, icon, and status-icon
programs, which apply the alpha multiplier in their shaders.

**Graphics setting:**

- New "Name opacity under cursor" slider in the Graphics Settings modal
(Name Labels section), range 0–1, default 0.25. Setting it to 1 disables
the fade entirely.
- Wired through the existing `GraphicsOverrides` pipeline: changes apply
live and are cleared by "Reset to defaults".
- Tuning knob exposed as `name.hoverFadeAlpha` in `render-settings.json`
and the debug GUI.

## Please complete the following:

- [ ] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] I have added relevant tests to the test directory

## Please put your Discord username so you can be contacted if a bug or
regression is found:

evan
This commit is contained in:
Evan
2026-06-11 09:25:13 -07:00
committed by GitHub
parent af2849a2d7
commit 7137347b7d
19 changed files with 210 additions and 9 deletions
+2
View File
@@ -939,6 +939,8 @@
"name_scale_label": "Name Scale",
"name_cull_label": "Minimum name size",
"name_cull_desc": "Hide names smaller than this size",
"hover_fade_label": "Name opacity under cursor",
"hover_fade_desc": "How visible names are while your cursor is over them (1 to disable fading)",
"colored_names_label": "Name color",
"colored_names_desc": "Show player names in their player color or in black",
"colored": "Colored",
@@ -31,6 +31,9 @@ export class HoverHighlightController implements Controller {
}
private onMouseMove(e: MouseMoveEvent): void {
const world = this.transformHandler.screenToWorldCoordinatesFloat(e.x, e.y);
this.view.setMouseWorldPos(world.x, world.y);
const cell = this.transformHandler.screenToWorldCoordinates(e.x, e.y);
let ownerID = 0;
if (this.game.isValidCoord(cell.x, cell.y)) {
@@ -20,6 +20,10 @@ const NAME_CULL_MIN = 0;
const NAME_CULL_MAX = 0.05;
const NAME_CULL_STEP = 0.001;
const HOVER_FADE_MIN = 0;
const HOVER_FADE_MAX = 1;
const HOVER_FADE_STEP = 0.05;
const HIGHLIGHT_FILL_MIN = 0;
const HIGHLIGHT_FILL_MAX = 1;
const HIGHLIGHT_FILL_STEP = 0.01;
@@ -148,6 +152,13 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
);
}
private currentHoverFade(): number {
return (
this.userSettings.graphicsOverrides().name?.hoverFadeAlpha ??
renderDefaults.name.hoverFadeAlpha
);
}
private patchName(patch: Partial<GraphicsOverrides["name"]>) {
const current = this.userSettings.graphicsOverrides();
this.userSettings.setGraphicsOverrides({
@@ -309,6 +320,11 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
this.patchName({ cullThreshold: value });
}
private onHoverFadeChange(event: Event) {
const value = parseFloat((event.target as HTMLInputElement).value);
this.patchName({ hoverFadeAlpha: value });
}
private currentDarkNames(): boolean {
return (
this.userSettings.graphicsOverrides().name?.darkNames ??
@@ -330,6 +346,7 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
const nameScale = this.currentNameScale();
const nameCull = this.currentNameCull();
const hoverFade = this.currentHoverFade();
const namesColored = !this.currentDarkNames();
const classicIcons = this.currentClassicIcons();
const highlightFill = this.currentHighlightFill();
@@ -425,6 +442,31 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
</div>
</div>
<div
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded-sm text-white transition-colors"
>
<div class="flex-1">
<div class="font-medium">
${translateText("graphics_setting.hover_fade_label")}
</div>
<div class="text-sm text-slate-400">
${translateText("graphics_setting.hover_fade_desc")}
</div>
<input
type="range"
min=${HOVER_FADE_MIN}
max=${HOVER_FADE_MAX}
step=${HOVER_FADE_STEP}
.value=${String(hoverFade)}
@input=${this.onHoverFadeChange}
class="w-full border border-slate-500 rounded-lg"
/>
</div>
<div class="text-sm text-slate-400 w-12 text-right">
${hoverFade.toFixed(2)}
</div>
</div>
<button
class="flex gap-3 items-center w-full text-left p-3 hover:bg-slate-700 rounded-sm text-white transition-colors"
@click=${this.onToggleNamesColored}
+3
View File
@@ -400,6 +400,9 @@ export class GameView {
setHighlightOwner(ownerID: number): void {
this.renderer?.setHighlightOwner(ownerID);
}
setMouseWorldPos(x: number, y: number): void {
this.renderer?.setMouseWorldPos(x, y);
}
setHighlightStructureTypes(unitTypes: string[] | null): void {
this.renderer?.setHighlightStructureTypes(unitTypes);
}
@@ -7,6 +7,7 @@ export const GraphicsOverridesSchema = z
nameScaleFactor: z.number(),
cullThreshold: z.number(),
darkNames: z.boolean(),
hoverFadeAlpha: z.number(),
})
.partial(),
structure: z
+3
View File
@@ -13,6 +13,9 @@ export function applyGraphicsOverrides(
if (overrides.name?.cullThreshold !== undefined) {
settings.name.cullThreshold = overrides.name.cullThreshold;
}
if (overrides.name?.hoverFadeAlpha !== undefined) {
settings.name.hoverFadeAlpha = overrides.name.hoverFadeAlpha;
}
if (overrides.structure?.classicIcons === true) {
// Classic look: lighter player-colored shape behind a dark icon glyph,
// with a touch of translucency.
+2
View File
@@ -201,6 +201,8 @@ export interface RenderSettings {
nameShadeBot: number;
emojiRowOffset: number;
statusRowOffset: number;
/** Alpha multiplier applied to a name while the cursor is over it. */
hoverFadeAlpha: number;
};
fx: {
shockwaveRingWidth: number;
+3
View File
@@ -951,6 +951,9 @@ export class GPURenderer {
this.territoryPass.setHighlightOwner(ownerID);
this.namePass.setHighlightOwner(ownerID);
}
setMouseWorldPos(x: number, y: number): void {
this.namePass.setMouseWorldPos(x, y);
}
setHighlightStructureTypes(unitTypes: string[] | null): void {
this.structurePass.setHighlightTypes(unitTypes);
this.structureLevelPass.setHighlightTypes(unitTypes);
+1
View File
@@ -325,6 +325,7 @@ export function buildTree(s: RenderSettings, d: RenderSettings): DebugNode[] {
toggle(s.name, "fillUsePlayerColor", d.name, "Fill = Player Color"),
slider(s.name, "emojiRowOffset", d.name, 0, 5, 0.1, "Emoji Row Offset"),
slider(s.name, "statusRowOffset", d.name, 0, 5, 0.1, "Status Row Offset"),
slider(s.name, "hoverFadeAlpha", d.name, 0, 1, 0.05, "Hover Fade Alpha"),
]),
folder("FX", [
@@ -40,6 +40,8 @@ export class IconProgram {
private uNameScaleFactor: WebGLUniformLocation;
private uNameScaleCap: WebGLUniformLocation;
private uEmojiRowOffset: WebGLUniformLocation;
private uFadeOwnerID: WebGLUniformLocation;
private uHoverFadeAlpha: WebGLUniformLocation;
constructor(
gl: WebGL2RenderingContext,
@@ -107,6 +109,11 @@ export class IconProgram {
this.program,
"uEmojiRowOffset",
)!;
this.uFadeOwnerID = gl.getUniformLocation(this.program, "uFadeOwnerID")!;
this.uHoverFadeAlpha = gl.getUniformLocation(
this.program,
"uHoverFadeAlpha",
)!;
this.loadEmojiAtlas();
}
@@ -142,6 +149,7 @@ export class IconProgram {
cameraMatrix: Float32Array,
settings: RenderSettings,
vao: WebGLVertexArrayObject,
fadeOwnerID: number,
): void {
if (!this.emojiReady) return;
@@ -156,6 +164,8 @@ export class IconProgram {
gl.uniform1f(this.uNameScaleFactor, ns.nameScaleFactor);
gl.uniform1f(this.uNameScaleCap, ns.nameScaleCap);
gl.uniform1f(this.uEmojiRowOffset, ns.emojiRowOffset);
gl.uniform1f(this.uFadeOwnerID, fadeOwnerID);
gl.uniform1f(this.uHoverFadeAlpha, ns.hoverFadeAlpha);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, this.playerDataTex);
@@ -38,6 +38,8 @@ export class StatusIconProgram {
private uNameScaleFactor: WebGLUniformLocation;
private uNameScaleCap: WebGLUniformLocation;
private uStatusRowOffset: WebGLUniformLocation;
private uFadeOwnerID: WebGLUniformLocation;
private uHoverFadeAlpha: WebGLUniformLocation;
constructor(
gl: WebGL2RenderingContext,
@@ -98,6 +100,11 @@ export class StatusIconProgram {
this.program,
"uStatusRowOffset",
)!;
this.uFadeOwnerID = gl.getUniformLocation(this.program, "uFadeOwnerID")!;
this.uHoverFadeAlpha = gl.getUniformLocation(
this.program,
"uHoverFadeAlpha",
)!;
this.loadAtlas();
}
@@ -129,6 +136,7 @@ export class StatusIconProgram {
cameraMatrix: Float32Array,
settings: RenderSettings,
vao: WebGLVertexArrayObject,
fadeOwnerID: number,
): void {
if (!this.atlasReady) return;
@@ -143,6 +151,8 @@ export class StatusIconProgram {
gl.uniform1f(this.uNameScaleFactor, ns.nameScaleFactor);
gl.uniform1f(this.uNameScaleCap, ns.nameScaleCap);
gl.uniform1f(this.uStatusRowOffset, ns.statusRowOffset);
gl.uniform1f(this.uFadeOwnerID, fadeOwnerID);
gl.uniform1f(this.uHoverFadeAlpha, ns.hoverFadeAlpha);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, this.playerDataTex);
@@ -42,6 +42,8 @@ export class TextProgram {
private uNameScaleCap: WebGLUniformLocation;
private uTroopSizeMultiplier: WebGLUniformLocation;
private uHighlightOwnerID: WebGLUniformLocation;
private uFadeOwnerID: WebGLUniformLocation;
private uHoverFadeAlpha: WebGLUniformLocation;
private uOutlineWidth: WebGLUniformLocation;
private uNightAmbient: WebGLUniformLocation;
private uOutlineColor: WebGLUniformLocation;
@@ -110,6 +112,11 @@ export class TextProgram {
this.program,
"uHighlightOwnerID",
)!;
this.uFadeOwnerID = gl.getUniformLocation(this.program, "uFadeOwnerID")!;
this.uHoverFadeAlpha = gl.getUniformLocation(
this.program,
"uHoverFadeAlpha",
)!;
this.uOutlineWidth = gl.getUniformLocation(this.program, "uOutlineWidth")!;
this.uNightAmbient = gl.getUniformLocation(this.program, "uNightAmbient")!;
this.uOutlineColor = gl.getUniformLocation(this.program, "uOutlineColor")!;
@@ -154,6 +161,7 @@ export class TextProgram {
maxPlayers: number,
ambient: number,
highlightOwnerID: number,
fadeOwnerID: number,
): void {
if (!this.atlasReady) return;
@@ -170,6 +178,8 @@ export class TextProgram {
gl.uniform1f(this.uNameScaleCap, ns.nameScaleCap);
gl.uniform1f(this.uTroopSizeMultiplier, ns.troopSizeMultiplier);
gl.uniform1f(this.uHighlightOwnerID, highlightOwnerID);
gl.uniform1f(this.uFadeOwnerID, fadeOwnerID);
gl.uniform1f(this.uHoverFadeAlpha, ns.hoverFadeAlpha);
gl.uniform1f(this.uOutlineWidth, ns.outlineWidth);
gl.uniform1f(this.uNightAmbient, ambient);
gl.uniform3f(this.uOutlineColor, ns.outlineR, ns.outlineG, ns.outlineB);
+79 -2
View File
@@ -50,6 +50,9 @@ import { TextProgram } from "./TextProgram";
import type { PlayerSlot } from "./Types";
import { LINES_PER_PLAYER, MAX_CHARS } from "./Types";
// Flag quad aspect ratio — must match FLAG_CELL_W / FLAG_CELL_H in FlagAtlasArray.ts.
const FLAG_ASPECT = 128 / 85;
export class NamePass {
private gl: WebGL2RenderingContext;
private settings: RenderSettings;
@@ -72,6 +75,8 @@ export class NamePass {
// Atlas + glyph data
private glyph: GlyphTables;
private kernTable: Int8Array;
private fontSize: number;
private fontBase: number;
// Player management
private playerByID: Map<string, PlayerStatic>;
@@ -102,6 +107,9 @@ export class NamePass {
// Hovered player's small ID (0 = no highlight, matches TerritoryPass).
private highlightOwnerID = 0;
// Cursor in world coords — fades names under it (far off-map = no fade).
private mouseWorldX = -1e9;
private mouseWorldY = -1e9;
private playerStateByID = new Map<string, PlayerState>();
constructor(
@@ -116,6 +124,8 @@ export class NamePass {
// Parse atlas + build CPU lookup tables
const atlas = parseAtlasData();
this.fontSize = atlas.fontSize;
this.fontBase = atlas.base;
this.glyph = buildGlyphTables(atlas.chars);
this.kernTable = buildKernTable(atlas.kernings);
this.emojiCharToIndex = buildEmojiLookup();
@@ -548,6 +558,65 @@ export class NamePass {
this.highlightOwnerID = ownerID;
}
setMouseWorldPos(x: number, y: number): void {
this.mouseWorldX = x;
this.mouseWorldY = y;
}
/**
* Find the player whose name plate (name + troops + flag + emoji/status row)
* is under the cursor, so the whole plate can fade as a unit. Mirrors the
* lerp + sizing math in name.vert.glsl. Returns the smallID, or 0 for none.
*/
private hitTestNamePlate(now: number): number {
const mx = this.mouseWorldX;
const my = this.mouseWorldY;
const ns = this.settings.name;
for (const slot of this.slots.values()) {
if (!slot.alive) continue;
const t = Math.min(
1 - Math.exp(-ns.lerpSpeed * (now - slot.startTime)),
1,
);
const wx = slot.srcX + (slot.tgtX - slot.srcX) * t;
const wy = slot.srcY + (slot.tgtY - slot.srcY) * t;
const ws = slot.srcScale + (slot.tgtScale - slot.srcScale) * t;
const baseSize = Math.max(1, Math.floor(ws));
const nameSize = Math.max(4, Math.floor(baseSize * ns.nameScaleFactor));
const nameScale = Math.min(baseSize * 0.25, ns.nameScaleCap);
const lineH = this.fontBase * ((nameSize * nameScale) / this.fontSize);
const halfW =
slot.nameHalfWidth * ((nameSize * nameScale) / this.fontSize);
let left = wx - halfW;
const right = wx + halfW;
if (slot.flagLayerIdx >= 0) left -= lineH * 1.2 * FLAG_ASPECT;
// Name line (flag is slightly taller); emoji/status rows sit above it.
let top = wy - lineH * 0.6;
const hasStatus =
slot.crown ||
slot.traitor ||
slot.disconnected ||
slot.alliance ||
slot.allianceReq ||
slot.target ||
slot.embargo ||
slot.nukeActive;
if (slot.emojiAtlasIdx >= 0) {
top = wy - lineH * ns.emojiRowOffset;
} else if (hasStatus) {
top = wy - lineH * ns.statusRowOffset;
}
const bottom = wy + lineH * (1.1 + 0.5 * ns.troopSizeMultiplier);
if (mx >= left && mx <= right && my >= top && my <= bottom) {
return slot.static.smallID;
}
}
return 0;
}
draw(cameraMatrix: Float32Array, ambient: number): void {
if (!this.textProgram.ready) return;
if (this.slots.size === 0) return;
@@ -599,6 +668,8 @@ export class NamePass {
this.playerDataDirty = false;
}
const fadeOwnerID = this.hitTestNamePlate(performance.now() / 1000);
this.textProgram.draw(
cameraMatrix,
this.settings,
@@ -606,9 +677,15 @@ export class NamePass {
this.maxPlayers,
ambient,
this.highlightOwnerID,
fadeOwnerID,
);
this.statusIconProgram.draw(cameraMatrix, this.settings, this.vao);
this.iconProgram.draw(cameraMatrix, this.settings, this.vao);
this.statusIconProgram.draw(
cameraMatrix,
this.settings,
this.vao,
fadeOwnerID,
);
this.iconProgram.draw(cameraMatrix, this.settings, this.vao, fadeOwnerID);
if (this.settings.passEnabled.nameDebug) {
this.debugProgram.draw(cameraMatrix, this.settings, this.vao);
+2 -1
View File
@@ -206,7 +206,8 @@
"nameShadeNation": 0.3,
"nameShadeBot": 0.4,
"emojiRowOffset": 1.4,
"statusRowOffset": 1.4
"statusRowOffset": 1.4,
"hoverFadeAlpha": 0.25
},
"fx": {
"shockwaveRingWidth": 0.04,
@@ -8,6 +8,7 @@ uniform sampler2D uEmojiAtlas;
in vec2 vUV;
flat in int vIconType; // 0 = flag, 1 = emoji, -1 = discard
flat in int vFlagLayer;
in float vHoverAlpha;
out vec4 fragColor;
@@ -22,5 +23,5 @@ void main() {
}
if (texel.a < 0.01) discard;
fragColor = texel;
fragColor = vec4(texel.rgb, texel.a * vHoverAlpha);
}
@@ -31,9 +31,13 @@ uniform float uEmojiAtlasH; // emoji atlas texture height
// Row offset (multiples of uFontBase * nameWorldScale)
uniform float uEmojiRowOffset;
uniform float uFadeOwnerID; // smallID of player whose name plate the cursor is over (0 = none)
uniform float uHoverFadeAlpha; // alpha multiplier applied to that player's name plate
out vec2 vUV;
flat out int vIconType; // 0 = flag, 1 = emoji, -1 = discard
flat out int vFlagLayer; // valid when vIconType == 0
out float vHoverAlpha;
void main() {
// Decode instance ID → playerIdx + iconType (0=flag, 1=emoji)
@@ -44,7 +48,7 @@ void main() {
vec4 pd0 = texelFetch(uPlayerData, ivec2(0, playerIdx), 0); // srcX, srcY, srcScale, startTime
vec4 pd1 = texelFetch(uPlayerData, ivec2(1, playerIdx), 0); // tgtX, tgtY, tgtScale, alive
vec4 pd3 = texelFetch(uPlayerData, ivec2(3, playerIdx), 0); // nameLen, troopLen, isHuman, nameHalfWidth
vec4 pd4 = texelFetch(uPlayerData, ivec2(4, playerIdx), 0); // flagLayer, emojiIdx, [free], [free]
vec4 pd4 = texelFetch(uPlayerData, ivec2(4, playerIdx), 0); // flagLayer, emojiIdx, smallID, [free]
// Early out: dead player
if (pd1.w <= 0.0) {
@@ -52,6 +56,7 @@ void main() {
vUV = vec2(0.0);
vIconType = -1;
vFlagLayer = 0;
vHoverAlpha = 1.0;
return;
}
@@ -62,6 +67,7 @@ void main() {
vUV = vec2(0.0);
vIconType = -1;
vFlagLayer = 0;
vHoverAlpha = 1.0;
return;
}
@@ -86,6 +92,7 @@ void main() {
vUV = vec2(0.0);
vIconType = -1;
vFlagLayer = 0;
vHoverAlpha = 1.0;
return;
}
@@ -138,6 +145,11 @@ void main() {
vFlagLayer = 0;
}
// Fade the icon along with the rest of the name plate when the cursor is
// over any part of it. Hit test runs on the CPU (NamePass).
vHoverAlpha = (uFadeOwnerID > 0.0 && pd4.z == uFadeOwnerID)
? uHoverFadeAlpha : 1.0;
// Quad world position
vec2 worldPos = iconOrigin + aPos * vec2(iconW, iconH);
@@ -28,6 +28,8 @@ uniform float uNameScaleFactor;
uniform float uNameScaleCap;
uniform float uTroopSizeMultiplier;
uniform float uHighlightOwnerID;
uniform float uFadeOwnerID; // smallID of player whose name plate the cursor is over (0 = none)
uniform float uHoverFadeAlpha; // alpha multiplier applied to that player's name plate
out vec2 vUV;
out vec4 vPlayerColor; // player territory color (rgb) + alpha
@@ -155,8 +157,13 @@ void main() {
vec3 clip = uCamera * vec3(worldPos, 1.0);
gl_Position = vec4(clip.xy, 0.0, 1.0);
// 10. UV interpolation across quad
// 10. Fade the whole name plate when the cursor is on top of any part of it
// so units underneath stay visible. Hit test runs on the CPU (NamePass).
float hoverAlpha = (uFadeOwnerID > 0.0 && smallID == uFadeOwnerID)
? uHoverFadeAlpha : 1.0;
// 11. UV interpolation across quad
vUV = vec2(mix(u0, u1, aPos.x), mix(v0, v1, aPos.y));
vPlayerColor = pd2; // player territory color (rgb) + alpha
vPlayerColor = vec4(pd2.rgb, pd2.a * hoverAlpha); // player territory color + alpha
vNameShade = pd3.z; // name fill grayscale shade (0.0 = black)
}
@@ -10,6 +10,7 @@ flat in float vAllianceFraction;
flat in vec2 vFadedUV0;
flat in vec2 vFadedUV1;
flat in float vFlashAlpha;
in float vHoverAlpha;
out vec4 fragColor;
@@ -33,7 +34,7 @@ void main() {
}
// Traitor flash: modulate alpha for urgency pulse
texel.a *= vFlashAlpha;
texel.a *= vFlashAlpha * vHoverAlpha;
if (texel.a < 0.01) discard;
fragColor = texel;
@@ -28,6 +28,9 @@ uniform float uStatusPad; // transparent padding in texels per side
// Configurable layout
uniform float uStatusRowOffset; // row Y offset (multiples of uFontBase * nameWorldScale)
uniform float uFadeOwnerID; // smallID of player whose name plate the cursor is over (0 = none)
uniform float uHoverFadeAlpha; // alpha multiplier applied to that player's name plate
out vec2 vUV;
out vec2 vLocalUV; // 0..1 within the icon cell
flat out int vDiscard;
@@ -35,6 +38,7 @@ flat out float vAllianceFraction; // 0 = no drain effect, >0 = active drain
flat out vec2 vFadedUV0; // top-left UV of faded alliance cell
flat out vec2 vFadedUV1; // bottom-right UV of faded alliance cell
flat out float vFlashAlpha; // traitor flash opacity (1.0 = fully visible)
out float vHoverAlpha;
// Status flag float array — indexed by icon slot.
// Slot mapping: 0=crown, 1=traitor, 2=disconnected, 3=alliance,
@@ -85,7 +89,7 @@ void main() {
// Read player data
vec4 pd0 = texelFetch(uPlayerData, ivec2(0, playerIdx), 0); // srcX, srcY, srcScale, startTime
vec4 pd1 = texelFetch(uPlayerData, ivec2(1, playerIdx), 0); // tgtX, tgtY, tgtScale, alive
vec4 pd4 = texelFetch(uPlayerData, ivec2(4, playerIdx), 0); // flagIdx, emojiIdx, [free], [free]
vec4 pd4 = texelFetch(uPlayerData, ivec2(4, playerIdx), 0); // flagIdx, emojiIdx, smallID, [free]
vec4 pd7 = texelFetch(uPlayerData, ivec2(7, playerIdx), 0); // nukeTargetsMe, traitorRemainingTicks, allianceFraction, [free]
// Early out: dead player OR emoji is active
@@ -98,6 +102,7 @@ void main() {
vFadedUV0 = vec2(0.0);
vFadedUV1 = vec2(0.0);
vFlashAlpha = 1.0;
vHoverAlpha = 1.0;
return;
}
@@ -114,6 +119,7 @@ void main() {
vFadedUV0 = vec2(0.0);
vFadedUV1 = vec2(0.0);
vFlashAlpha = 1.0;
vHoverAlpha = 1.0;
return;
}
@@ -142,6 +148,7 @@ void main() {
vFadedUV0 = vec2(0.0);
vFadedUV1 = vec2(0.0);
vFlashAlpha = 1.0;
vHoverAlpha = 1.0;
return;
}
@@ -172,6 +179,11 @@ void main() {
atlasIdx = (pd7.x > 0.5) ? 7 : 8;
}
// Fade the status row along with the rest of the name plate when the cursor
// is over any part of it. Hit test runs on the CPU (NamePass).
vHoverAlpha = (uFadeOwnerID > 0.0 && pd4.z == uFadeOwnerID)
? uHoverFadeAlpha : 1.0;
// Quad world position
vec2 iconOrigin = vec2(iconX, iconY);
vec2 worldPos = iconOrigin + aPos * vec2(iconWorldSize, iconWorldSize);