Removed legacy border color texture and all related plumbing

In src/client/graphics/layers/TerritoryWebGLRenderer.ts:
- Deleted borderColorTexture, borderColorData, borderDirtyRows, borderNeedsFullUpload.
- Removed setBorderColor, clearBorderColor, markBorderDirty, and uploadBorderTexture, plus the extra profiling calls.
- Dropped the u_borderColor uniform from both the uniform map and the fragment shader.
- Removed all texture creation/binding/uniform setup for the old border color texture; only u_state, u_palette, and u_relations remain.

The WebGL renderer now relies solely on the palette + relations + state buffers for borders.
This commit is contained in:
scamiv
2025-12-04 03:20:10 +01:00
parent 84bcf6fb55
commit 84bb2e0e65
@@ -32,13 +32,11 @@ export class TerritoryWebGLRenderer {
private readonly stateTexture: WebGLTexture | null;
private readonly paletteTexture: WebGLTexture | null;
private readonly relationTexture: WebGLTexture | null;
private readonly borderColorTexture: WebGLTexture | null;
private readonly uniforms: {
resolution: WebGLUniformLocation | null;
state: WebGLUniformLocation | null;
palette: WebGLUniformLocation | null;
relations: WebGLUniformLocation | null;
borderColor: WebGLUniformLocation | null;
fallout: WebGLUniformLocation | null;
altSelf: WebGLUniformLocation | null;
altAlly: WebGLUniformLocation | null;
@@ -67,9 +65,7 @@ export class TerritoryWebGLRenderer {
private readonly state: Uint16Array;
private readonly dirtyRows: Map<number, DirtySpan> = new Map();
private readonly borderDirtyRows: Map<number, DirtySpan> = new Map();
private needsFullUpload = true;
private borderNeedsFullUpload = true;
private alternativeView = false;
private paletteWidth = 0;
private hoverHighlightStrength = 0.7;
@@ -78,7 +74,6 @@ export class TerritoryWebGLRenderer {
private hoverPulseSpeed = Math.PI * 2;
private hoveredPlayerId = -1;
private animationStartTime = Date.now();
private borderColorData: Uint8Array;
private constructor(
private readonly game: GameView,
@@ -90,9 +85,6 @@ export class TerritoryWebGLRenderer {
this.canvas.height = game.height();
this.state = new Uint16Array(sharedState);
this.borderColorData = new Uint8Array(
this.canvas.width * this.canvas.height * 4,
);
this.gl = this.canvas.getContext("webgl2", {
premultipliedAlpha: true,
@@ -107,13 +99,11 @@ export class TerritoryWebGLRenderer {
this.stateTexture = null;
this.paletteTexture = null;
this.relationTexture = null;
this.borderColorTexture = null;
this.uniforms = {
resolution: null,
state: null,
palette: null,
relations: null,
borderColor: null,
fallout: null,
altSelf: null,
altAlly: null,
@@ -149,13 +139,11 @@ export class TerritoryWebGLRenderer {
this.stateTexture = null;
this.paletteTexture = null;
this.relationTexture = null;
this.borderColorTexture = null;
this.uniforms = {
resolution: null,
state: null,
palette: null,
relations: null,
borderColor: null,
fallout: null,
altSelf: null,
altAlly: null,
@@ -188,7 +176,6 @@ export class TerritoryWebGLRenderer {
state: gl.getUniformLocation(this.program, "u_state"),
palette: gl.getUniformLocation(this.program, "u_palette"),
relations: gl.getUniformLocation(this.program, "u_relations"),
borderColor: gl.getUniformLocation(this.program, "u_borderColor"),
fallout: gl.getUniformLocation(this.program, "u_fallout"),
altSelf: gl.getUniformLocation(this.program, "u_altSelf"),
altAlly: gl.getUniformLocation(this.program, "u_altAlly"),
@@ -291,33 +278,12 @@ export class TerritoryWebGLRenderer {
this.state,
);
this.borderColorTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE3);
gl.bindTexture(gl.TEXTURE_2D, this.borderColorTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA8,
this.canvas.width,
this.canvas.height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
this.borderColorData,
);
this.uploadPalette();
gl.useProgram(this.program);
gl.uniform1i(this.uniforms.state, 0);
gl.uniform1i(this.uniforms.palette, 1);
gl.uniform1i(this.uniforms.relations, 2);
gl.uniform1i(this.uniforms.borderColor, 3);
if (this.uniforms.resolution) {
gl.uniform2f(
@@ -448,27 +414,6 @@ export class TerritoryWebGLRenderer {
this.alternativeView = enabled;
}
setBorderColor(
tile: TileRef,
rgba: { r: number; g: number; b: number; a: number },
) {
const offset = tile * 4;
this.borderColorData[offset] = rgba.r;
this.borderColorData[offset + 1] = rgba.g;
this.borderColorData[offset + 2] = rgba.b;
this.borderColorData[offset + 3] = rgba.a;
this.markBorderDirty(tile);
}
clearBorderColor(tile: TileRef) {
const offset = tile * 4;
this.borderColorData[offset] = 0;
this.borderColorData[offset + 1] = 0;
this.borderColorData[offset + 2] = 0;
this.borderColorData[offset + 3] = 0;
this.markBorderDirty(tile);
}
setHoveredPlayerId(playerSmallId: number | null) {
const encoded = playerSmallId ?? -1;
this.hoveredPlayerId = encoded;
@@ -508,26 +453,9 @@ export class TerritoryWebGLRenderer {
}
}
private markBorderDirty(tile: TileRef) {
if (this.borderNeedsFullUpload) {
return;
}
const x = tile % this.canvas.width;
const y = Math.floor(tile / this.canvas.width);
const span = this.borderDirtyRows.get(y);
if (span === undefined) {
this.borderDirtyRows.set(y, { minX: x, maxX: x });
} else {
span.minX = Math.min(span.minX, x);
span.maxX = Math.max(span.maxX, x);
}
}
markAllDirty() {
this.needsFullUpload = true;
this.dirtyRows.clear();
this.borderNeedsFullUpload = true;
this.borderDirtyRows.clear();
}
refreshPalette() {
@@ -547,10 +475,6 @@ export class TerritoryWebGLRenderer {
this.uploadStateTexture();
FrameProfiler.end("TerritoryWebGLRenderer:uploadState", uploadStateSpan);
const uploadBorderSpan = FrameProfiler.start();
this.uploadBorderTexture();
FrameProfiler.end("TerritoryWebGLRenderer:uploadBorder", uploadBorderSpan);
const renderSpan = FrameProfiler.start();
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
gl.useProgram(this.program);
@@ -648,64 +572,6 @@ export class TerritoryWebGLRenderer {
return { rows: rowsUploaded, bytes: bytesUploaded };
}
private uploadBorderTexture(): { rows: number; bytes: number } {
if (!this.gl || !this.borderColorTexture) return { rows: 0, bytes: 0 };
const gl = this.gl;
gl.activeTexture(gl.TEXTURE3);
gl.bindTexture(gl.TEXTURE_2D, this.borderColorTexture);
const bytesPerPixel = Uint8Array.BYTES_PER_ELEMENT * 4; // RGBA8
let rowsUploaded = 0;
let bytesUploaded = 0;
if (this.borderNeedsFullUpload) {
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA8,
this.canvas.width,
this.canvas.height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
this.borderColorData,
);
this.borderNeedsFullUpload = false;
this.borderDirtyRows.clear();
rowsUploaded = this.canvas.height;
bytesUploaded = this.canvas.width * this.canvas.height * bytesPerPixel;
return { rows: rowsUploaded, bytes: bytesUploaded };
}
if (this.borderDirtyRows.size === 0) {
return { rows: 0, bytes: 0 };
}
for (const [y, span] of this.borderDirtyRows) {
const width = span.maxX - span.minX + 1;
const offset = (y * this.canvas.width + span.minX) * 4;
const rowSlice = this.borderColorData.subarray(
offset,
offset + width * 4,
);
gl.texSubImage2D(
gl.TEXTURE_2D,
0,
span.minX,
y,
width,
1,
gl.RGBA,
gl.UNSIGNED_BYTE,
rowSlice,
);
rowsUploaded++;
bytesUploaded += width * bytesPerPixel;
}
this.borderDirtyRows.clear();
return { rows: rowsUploaded, bytes: bytesUploaded };
}
private labelUpload(
base: string,
metrics: { rows: number; bytes: number },
@@ -847,7 +713,6 @@ export class TerritoryWebGLRenderer {
uniform usampler2D u_state;
uniform sampler2D u_palette;
uniform usampler2D u_relations;
uniform sampler2D u_borderColor;
uniform int u_viewerId;
uniform vec2 u_resolution;
uniform vec4 u_fallout;