mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 07:50:45 +00:00
Always render player name when under the cursor
This commit is contained in:
@@ -919,6 +919,7 @@ export class GPURenderer {
|
||||
setHighlightOwner(ownerID: number): void {
|
||||
this.borderPass.setHighlightOwner(ownerID);
|
||||
this.territoryPass.setHighlightOwner(ownerID);
|
||||
this.namePass.setHighlightOwner(ownerID);
|
||||
}
|
||||
setHighlightStructureTypes(unitTypes: string[] | null): void {
|
||||
this.structurePass.setHighlightTypes(unitTypes);
|
||||
|
||||
@@ -41,6 +41,7 @@ export class TextProgram {
|
||||
private uNameScaleFactor: WebGLUniformLocation;
|
||||
private uNameScaleCap: WebGLUniformLocation;
|
||||
private uTroopSizeMultiplier: WebGLUniformLocation;
|
||||
private uHighlightOwnerID: WebGLUniformLocation;
|
||||
private uOutlineWidth: WebGLUniformLocation;
|
||||
private uNightAmbient: WebGLUniformLocation;
|
||||
private uOutlineColor: WebGLUniformLocation;
|
||||
@@ -105,6 +106,10 @@ export class TextProgram {
|
||||
this.program,
|
||||
"uTroopSizeMultiplier",
|
||||
)!;
|
||||
this.uHighlightOwnerID = gl.getUniformLocation(
|
||||
this.program,
|
||||
"uHighlightOwnerID",
|
||||
)!;
|
||||
this.uOutlineWidth = gl.getUniformLocation(this.program, "uOutlineWidth")!;
|
||||
this.uNightAmbient = gl.getUniformLocation(this.program, "uNightAmbient")!;
|
||||
this.uOutlineColor = gl.getUniformLocation(this.program, "uOutlineColor")!;
|
||||
@@ -148,6 +153,7 @@ export class TextProgram {
|
||||
vao: WebGLVertexArrayObject,
|
||||
maxPlayers: number,
|
||||
ambient: number,
|
||||
highlightOwnerID: number,
|
||||
): void {
|
||||
if (!this.atlasReady) return;
|
||||
|
||||
@@ -163,6 +169,7 @@ export class TextProgram {
|
||||
gl.uniform1f(this.uNameScaleFactor, ns.nameScaleFactor);
|
||||
gl.uniform1f(this.uNameScaleCap, ns.nameScaleCap);
|
||||
gl.uniform1f(this.uTroopSizeMultiplier, ns.troopSizeMultiplier);
|
||||
gl.uniform1f(this.uHighlightOwnerID, highlightOwnerID);
|
||||
gl.uniform1f(this.uOutlineWidth, ns.outlineWidth);
|
||||
gl.uniform1f(this.uNightAmbient, ambient);
|
||||
gl.uniform3f(this.uOutlineColor, ns.outlineR, ns.outlineG, ns.outlineB);
|
||||
|
||||
@@ -98,6 +98,9 @@ export class NamePass {
|
||||
// Reusable per-tick lookup maps (avoid allocation + GC)
|
||||
private alivePlayerIDs = new Set<string>();
|
||||
private troopsByPlayerID = new Map<string, number>();
|
||||
|
||||
// Hovered player's small ID (0 = no highlight, matches TerritoryPass).
|
||||
private highlightOwnerID = 0;
|
||||
private playerStateByID = new Map<string, PlayerState>();
|
||||
|
||||
constructor(
|
||||
@@ -498,7 +501,7 @@ export class NamePass {
|
||||
// Column 4: flagLayerIdx, emojiAtlasIdx, [free], [free]
|
||||
d[off + 16] = slot.flagLayerIdx;
|
||||
d[off + 17] = slot.emojiAtlasIdx;
|
||||
d[off + 18] = 0;
|
||||
d[off + 18] = slot.static.smallID;
|
||||
d[off + 19] = 0;
|
||||
|
||||
// Column 5: crown, traitor, disconnected, alliance
|
||||
@@ -526,6 +529,10 @@ export class NamePass {
|
||||
// Render
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
setHighlightOwner(ownerID: number): void {
|
||||
this.highlightOwnerID = ownerID;
|
||||
}
|
||||
|
||||
draw(cameraMatrix: Float32Array, ambient: number): void {
|
||||
if (!this.textProgram.ready) return;
|
||||
if (this.slots.size === 0) return;
|
||||
@@ -583,6 +590,7 @@ export class NamePass {
|
||||
this.vao,
|
||||
this.maxPlayers,
|
||||
ambient,
|
||||
this.highlightOwnerID,
|
||||
);
|
||||
this.statusIconProgram.draw(cameraMatrix, this.settings, this.vao);
|
||||
this.iconProgram.draw(cameraMatrix, this.settings, this.vao);
|
||||
|
||||
@@ -27,6 +27,7 @@ uniform float uCullThreshold;
|
||||
uniform float uNameScaleFactor;
|
||||
uniform float uNameScaleCap;
|
||||
uniform float uTroopSizeMultiplier;
|
||||
uniform float uHighlightOwnerID;
|
||||
|
||||
out vec2 vUV;
|
||||
out vec4 vPlayerColor; // player territory color (rgb) + alpha
|
||||
@@ -45,6 +46,8 @@ void main() {
|
||||
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 pd4 = texelFetch(uPlayerData, ivec2(4, playerIdx), 0); // flagLayerIdx, emojiAtlasIdx, smallID, 0
|
||||
float smallID = pd4.z;
|
||||
|
||||
// Early out: dead player
|
||||
if (pd1.w <= 0.0) {
|
||||
@@ -90,16 +93,19 @@ void main() {
|
||||
float nameWorldScale = (nameSize * nameScale) / uFontSize;
|
||||
float worldScale = nameWorldScale;
|
||||
|
||||
bool isHighlighted = uHighlightOwnerID > 0.0 && smallID == uHighlightOwnerID;
|
||||
|
||||
// Troop count is smaller
|
||||
if (lineIdx == 1) {
|
||||
worldScale *= uTroopSizeMultiplier;
|
||||
}
|
||||
|
||||
// Zoom-based culling: compute screen-space size and skip if too small
|
||||
// Zoom-based culling: compute screen-space size and skip if too small.
|
||||
// Highlighted (hovered) names bypass the cull so they're always visible.
|
||||
// uCamera[0][0] is the x-scale component of the camera matrix
|
||||
float cameraScale = length(vec2(uCamera[0][0], uCamera[1][0]));
|
||||
float screenSize = nameWorldScale * uBase * cameraScale;
|
||||
if (screenSize < uCullThreshold) {
|
||||
if (screenSize < uCullThreshold && !isHighlighted) {
|
||||
gl_Position = vec4(0.0);
|
||||
vUV = vec2(0.0);
|
||||
vPlayerColor = vec4(0.0);
|
||||
|
||||
Reference in New Issue
Block a user