mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 07:50:45 +00:00
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:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user