Color player name labels by player type

Name text fill now darkens based on player type so human players stand
out from AI: human = black, nation = a bit gray, bot = greyer. Shades are
tunable in render-settings.json (nameShadeNation, nameShadeBot; human is
always 0).

Repurpose the previously-unused pd3.z slot (was isHuman, dead in the
fragment shader) to carry a per-player grayscale shade, and use it as the
name fill color directly so it applies in both day and night.
This commit is contained in:
evanpelle
2026-06-09 19:58:46 -07:00
parent b5840d7887
commit 3552b08f7a
5 changed files with 29 additions and 17 deletions
+3
View File
@@ -194,6 +194,9 @@ export interface RenderSettings {
outlineB: number;
outlineUsePlayerColor: boolean;
fillUsePlayerColor: boolean;
/** Name fill grayscale shade by player type (0 = black). Human is always 0. */
nameShadeNation: number;
nameShadeBot: number;
emojiRowOffset: number;
statusRowOffset: number;
};
+10 -2
View File
@@ -499,10 +499,18 @@ export class NamePass {
d[off + 10] = color[2];
d[off + 11] = 1.0;
// Column 3: nameLen, troopLen, isHuman, nameHalfWidth
// Column 3: nameLen, troopLen, nameShade, nameHalfWidth
// Name fill darkens by type: human black, nation a bit gray, bot greyer.
const ns = this.settings.name;
let nameShade = 0.0;
if (slot.static.playerType === PlayerTypeEnum.Nation) {
nameShade = ns.nameShadeNation;
} else if (slot.static.playerType === PlayerTypeEnum.Bot) {
nameShade = ns.nameShadeBot;
}
d[off + 12] = slot.nameLen;
d[off + 13] = slot.troopLen;
d[off + 14] = slot.static.playerType === PlayerTypeEnum.Human ? 1.0 : 0.0;
d[off + 14] = nameShade;
d[off + 15] = slot.nameHalfWidth;
// Column 4: flagLayerIdx, emojiAtlasIdx, [free], [free]
@@ -202,6 +202,8 @@
"outlineB": 0.0,
"outlineUsePlayerColor": true,
"fillUsePlayerColor": false,
"nameShadeNation": 0.3,
"nameShadeBot": 0.4,
"emojiRowOffset": 1.4,
"statusRowOffset": 1.4
},
@@ -11,7 +11,7 @@ uniform float uFillUsePlayerColor;
in vec2 vUV;
in vec4 vPlayerColor; // player territory color (rgb) + alpha
in float vIsHuman; // 1.0 = human, 0.0 = bot/nation
in float vNameShade; // name fill grayscale shade (0.0 = black)
out vec4 fragColor;
float median(float r, float g, float b) {
@@ -22,15 +22,14 @@ void main() {
// Degenerate fragment — skip
if (vPlayerColor.a <= 0.0) discard;
// Stagger fill/border curves so they never share the same gray.
// t² for border (stays dark longer, snaps white late) and √t for fill (inverse).
// At midpoint t=0.5: border=0.25 (dark), fill=0.71 (light) — always distinct.
// Border darkens with night: t² stays dark longer, snaps toward the
// outline color late in the day cycle.
float t = 1.0 - uNightAmbient;
float borderT = t * t;
float fillT = sqrt(t);
// Compute fill color: player color, or cycle-aware white↔black (inverse of border)
vec3 defaultFill = mix(uOutlineColor, vec3(0.0), fillT);
// Compute fill color: player color, or per-type grayscale shade
// (black for human, grayer for nation/bot). Applies in day and night.
vec3 defaultFill = vec3(vNameShade);
vec3 fillColor = mix(defaultFill, vPlayerColor.rgb, uFillUsePlayerColor);
vec3 msd = texture(uAtlas, vUV).rgb;
@@ -31,7 +31,7 @@ uniform float uHighlightOwnerID;
out vec2 vUV;
out vec4 vPlayerColor; // player territory color (rgb) + alpha
out float vIsHuman; // 1.0 for human, 0.0 for bot/nation
out float vNameShade; // name fill grayscale shade (0.0 = black)
void main() {
// 1. Decode instance ID → playerIdx, lineIdx, charPos
@@ -45,7 +45,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 pd2 = texelFetch(uPlayerData, ivec2(2, playerIdx), 0); // r, g, b, a
vec4 pd3 = texelFetch(uPlayerData, ivec2(3, playerIdx), 0); // nameLen, troopLen, isHuman, 0
vec4 pd3 = texelFetch(uPlayerData, ivec2(3, playerIdx), 0); // nameLen, troopLen, nameShade, nameHalfWidth
vec4 pd4 = texelFetch(uPlayerData, ivec2(4, playerIdx), 0); // flagLayerIdx, emojiAtlasIdx, smallID, 0
float smallID = pd4.z;
@@ -54,7 +54,7 @@ void main() {
gl_Position = vec4(0.0);
vUV = vec2(0.0);
vPlayerColor = vec4(0.0);
vIsHuman = 0.0;
vNameShade = 0.0;
return;
}
@@ -64,7 +64,7 @@ void main() {
gl_Position = vec4(0.0);
vUV = vec2(0.0);
vPlayerColor = vec4(0.0);
vIsHuman = 0.0;
vNameShade = 0.0;
return;
}
@@ -75,7 +75,7 @@ void main() {
gl_Position = vec4(0.0);
vUV = vec2(0.0);
vPlayerColor = vec4(0.0);
vIsHuman = 0.0;
vNameShade = 0.0;
return;
}
@@ -109,7 +109,7 @@ void main() {
gl_Position = vec4(0.0);
vUV = vec2(0.0);
vPlayerColor = vec4(0.0);
vIsHuman = 0.0;
vNameShade = 0.0;
return;
}
@@ -133,7 +133,7 @@ void main() {
gl_Position = vec4(0.0);
vUV = vec2(0.0);
vPlayerColor = vec4(0.0);
vIsHuman = 0.0;
vNameShade = 0.0;
return;
}
@@ -158,5 +158,5 @@ void main() {
// 10. UV interpolation across quad
vUV = vec2(mix(u0, u1, aPos.x), mix(v0, v1, aPos.y));
vPlayerColor = pd2; // player territory color (rgb) + alpha
vIsHuman = pd3.z; // 1.0 = human, 0.0 = bot/nation
vNameShade = pd3.z; // name fill grayscale shade (0.0 = black)
}