mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:50:43 +00:00
Coordinate grid (#4224)
**Add approved & assigned issue number here:** Resolves #3839 ## Description: A bunch of small updates to make the coordinate grid a lot nicer. - Removes black backgrounds on text. - Allows user to modify the opacity of the coordinate grid - Persist the enable state of the coordinate grid ### Before <img width="2344" height="1168" alt="image" src="https://github.com/user-attachments/assets/22c2fb77-9db6-41bf-a50a-987f651cc19a" /> ### After <img width="2331" height="1174" alt="image" src="https://github.com/user-attachments/assets/0e5a9575-8a79-407b-8d78-8564df02b259" /> <img width="407" height="947" alt="image" src="https://github.com/user-attachments/assets/b9e5f9f1-3cc1-4832-b7d4-38e1f5e93d57" /> ## Please complete the following: - [X] 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: FrederikJA
This commit is contained in:
@@ -972,6 +972,8 @@
|
||||
"territory_sat_desc": "How vivid the territory fill colors are (lower mutes them)",
|
||||
"territory_alpha_label": "Territory opacity",
|
||||
"territory_alpha_desc": "How opaque the territory fill is (lower lets terrain show through)",
|
||||
"coordinate_grid_opacity_label": "Coordinate grid opacity",
|
||||
"coordinate_grid_opacity_desc": "How opaque the coordinate grid is (lower lets more things show through)",
|
||||
"rail_distance_label": "Train track draw distance",
|
||||
"rail_distance_desc": "How far zoomed out train tracks remain visible",
|
||||
"rail_thickness_label": "Train track thickness",
|
||||
|
||||
@@ -52,6 +52,10 @@ const TERRITORY_ALPHA_MIN = 0;
|
||||
const TERRITORY_ALPHA_MAX = 1;
|
||||
const TERRITORY_ALPHA_STEP = 0.01;
|
||||
|
||||
const COORDINATE_GRID_OPACITY_MIN = 0;
|
||||
const COORDINATE_GRID_OPACITY_MAX = 1;
|
||||
const COORDINATE_GRID_OPACITY_STEP = 0.01;
|
||||
|
||||
// Train track "draw distance" is presented inverted: a higher slider value means
|
||||
// tracks stay visible when more zoomed out, i.e. a lower railMinZoom.
|
||||
const RAIL_ZOOM_MIN = 0;
|
||||
@@ -252,6 +256,13 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
|
||||
);
|
||||
}
|
||||
|
||||
private currentCoordinateGridOpacity(): number {
|
||||
return (
|
||||
this.userSettings.graphicsOverrides().mapOverlay?.coordinateGridOpacity ??
|
||||
renderDefaults.mapOverlay.coordinateGridOpacity
|
||||
);
|
||||
}
|
||||
|
||||
private currentRailMinZoom(): number {
|
||||
return (
|
||||
this.userSettings.graphicsOverrides().railroad?.railMinZoom ??
|
||||
@@ -291,6 +302,11 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
|
||||
this.patchMapOverlay({ territoryAlpha: value });
|
||||
}
|
||||
|
||||
private onCoordinateGridOpacityChange(event: Event) {
|
||||
const value = parseFloat((event.target as HTMLInputElement).value);
|
||||
this.patchMapOverlay({ coordinateGridOpacity: value });
|
||||
}
|
||||
|
||||
private onRailDrawDistanceChange(event: Event) {
|
||||
const drawDistance = parseFloat((event.target as HTMLInputElement).value);
|
||||
// Invert: higher draw distance => tracks visible when more zoomed out.
|
||||
@@ -412,6 +428,7 @@ export class GraphicsSettingsModal extends LitElement implements Controller {
|
||||
const highlightThicken = this.currentHighlightThicken();
|
||||
const territorySat = this.currentTerritorySat();
|
||||
const territoryAlpha = this.currentTerritoryAlpha();
|
||||
const coordinateGridOpacity = this.currentCoordinateGridOpacity();
|
||||
const railDrawDistance = RAIL_ZOOM_MAX - this.currentRailMinZoom();
|
||||
const railThickness = this.currentRailThickness();
|
||||
const colorblind = this.currentColorblind();
|
||||
@@ -751,6 +768,35 @@ 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.coordinate_grid_opacity_label",
|
||||
)}
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
${translateText(
|
||||
"graphics_setting.coordinate_grid_opacity_desc",
|
||||
)}
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
min=${COORDINATE_GRID_OPACITY_MIN}
|
||||
max=${COORDINATE_GRID_OPACITY_MAX}
|
||||
step=${COORDINATE_GRID_OPACITY_STEP}
|
||||
.value=${String(coordinateGridOpacity)}
|
||||
@input=${this.onCoordinateGridOpacityChange}
|
||||
class="w-full border border-slate-500 rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400 w-12 text-right">
|
||||
${coordinateGridOpacity.toFixed(2)}
|
||||
</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"
|
||||
>
|
||||
|
||||
@@ -24,6 +24,7 @@ export const GraphicsOverridesSchema = z
|
||||
highlightThicken: z.number(),
|
||||
territorySaturation: z.number(),
|
||||
territoryAlpha: z.number(),
|
||||
coordinateGridOpacity: z.number(),
|
||||
})
|
||||
.partial(),
|
||||
railroad: z
|
||||
|
||||
@@ -56,6 +56,10 @@ export function applyGraphicsOverrides(
|
||||
if (overrides.mapOverlay?.territoryAlpha !== undefined) {
|
||||
settings.mapOverlay.territoryAlpha = overrides.mapOverlay.territoryAlpha;
|
||||
}
|
||||
if (overrides.mapOverlay?.coordinateGridOpacity !== undefined) {
|
||||
settings.mapOverlay.coordinateGridOpacity =
|
||||
overrides.mapOverlay.coordinateGridOpacity;
|
||||
}
|
||||
if (overrides.railroad?.railMinZoom !== undefined) {
|
||||
settings.railroad.railMinZoom = overrides.railroad.railMinZoom;
|
||||
}
|
||||
|
||||
@@ -113,6 +113,7 @@ export interface RenderSettings {
|
||||
territorySaturation: number;
|
||||
/** Absolute opacity of the territory fill. 1 = fully opaque (terrain hidden), ~0.588 = default. */
|
||||
territoryAlpha: number;
|
||||
coordinateGridOpacity: number;
|
||||
staleNukeBase: number;
|
||||
staleNukeVariation: number;
|
||||
staleNukeAlpha: number;
|
||||
|
||||
@@ -91,6 +91,8 @@ const SAM_RADIUS_HIGHLIGHT_TYPES = new Set([
|
||||
"Hydrogen Bomb",
|
||||
]);
|
||||
|
||||
const GRID_VIEW_KEY = "renderer:grid_view_enabled";
|
||||
|
||||
export class GPURenderer {
|
||||
private gl: WebGL2RenderingContext;
|
||||
private camera: Camera;
|
||||
@@ -526,6 +528,11 @@ export class GPURenderer {
|
||||
mapH,
|
||||
this.settings,
|
||||
);
|
||||
try {
|
||||
this.gridView = window.localStorage.getItem(GRID_VIEW_KEY) === "true";
|
||||
} catch {
|
||||
this.setGridView(false);
|
||||
}
|
||||
|
||||
for (const p of header.players) {
|
||||
if (p.team !== null) this.playerTeams.set(p.smallID, p.team);
|
||||
@@ -1078,6 +1085,11 @@ export class GPURenderer {
|
||||
|
||||
setGridView(active: boolean): void {
|
||||
this.gridView = active;
|
||||
try {
|
||||
window.localStorage.setItem(GRID_VIEW_KEY, active ? "true" : "false");
|
||||
} catch {
|
||||
// Ignore if we are unable to use localstorage.
|
||||
}
|
||||
}
|
||||
|
||||
getSettings(): RenderSettings {
|
||||
|
||||
@@ -31,6 +31,7 @@ export class CoordinateGridPass {
|
||||
private uCellSize: WebGLUniformLocation;
|
||||
private uZoom: WebGLUniformLocation;
|
||||
private uFontSize: WebGLUniformLocation;
|
||||
private uOpacity: WebGLUniformLocation;
|
||||
|
||||
private mapW: number;
|
||||
private mapH: number;
|
||||
@@ -57,6 +58,7 @@ export class CoordinateGridPass {
|
||||
this.uCellSize = gl.getUniformLocation(this.program, "uCellSize")!;
|
||||
this.uZoom = gl.getUniformLocation(this.program, "uZoom")!;
|
||||
this.uFontSize = gl.getUniformLocation(this.program, "uFontSize")!;
|
||||
this.uOpacity = gl.getUniformLocation(this.program, "uOpacity")!;
|
||||
|
||||
gl.useProgram(this.program);
|
||||
gl.uniform1i(gl.getUniformLocation(this.program, "uGlyphTex"), 0);
|
||||
@@ -73,6 +75,7 @@ export class CoordinateGridPass {
|
||||
gl.uniform1f(this.uCellSize, this.cellSize);
|
||||
gl.uniform1f(this.uZoom, zoom);
|
||||
gl.uniform1f(this.uFontSize, this.settings.altView.gridFontSize);
|
||||
gl.uniform1f(this.uOpacity, this.settings.mapOverlay.coordinateGridOpacity);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.glyphTex);
|
||||
@@ -95,14 +98,16 @@ export class CoordinateGridPass {
|
||||
canvas.height = GLYPH_H;
|
||||
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.strokeStyle = "black";
|
||||
ctx.lineWidth = 4;
|
||||
ctx.fillStyle = "white";
|
||||
ctx.font = `bold ${GLYPH_H - 8}px monospace`;
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
|
||||
for (let i = 0; i < CHARS.length; i++) {
|
||||
ctx.strokeText(CHARS[i], i * GLYPH_W + GLYPH_W / 2, GLYPH_H / 2);
|
||||
ctx.fillText(CHARS[i], i * GLYPH_W + GLYPH_W / 2, GLYPH_H / 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
"territoryDefenseDarken": 0.85,
|
||||
"territorySaturation": 1,
|
||||
"territoryAlpha": 0.588,
|
||||
"coordinateGridOpacity": 0.5,
|
||||
"staleNukeBase": 0,
|
||||
"staleNukeVariation": 0.05,
|
||||
"staleNukeAlpha": 1,
|
||||
|
||||
@@ -6,6 +6,7 @@ uniform float uCellSize;
|
||||
uniform float uZoom;
|
||||
uniform float uFontSize;
|
||||
uniform sampler2D uGlyphTex;
|
||||
uniform float uOpacity;
|
||||
|
||||
in vec2 vWorldPos;
|
||||
out vec4 fragColor;
|
||||
@@ -29,7 +30,7 @@ void main() {
|
||||
|
||||
// --- Grid lines (at cell boundaries) ---
|
||||
if (localX < lineW || localY < lineW) {
|
||||
fragColor = vec4(1.0, 1.0, 1.0, 0.35);
|
||||
fragColor = vec4(1.0, 1.0, 1.0, uOpacity);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,7 +42,6 @@ void main() {
|
||||
float gw = fontSize * 0.6 * px; // glyph width in world units
|
||||
float gh = fontSize * px; // glyph height
|
||||
float pad = 8.0 * px; // padding from cell corner
|
||||
float bgPad = 2.0 * px; // background extends beyond text
|
||||
|
||||
float lx = localX - pad;
|
||||
float ly = localY - pad;
|
||||
@@ -73,32 +73,24 @@ void main() {
|
||||
|
||||
float totalW = float(nc) * gw;
|
||||
|
||||
// Check label background area (text + padding)
|
||||
if (lx < -bgPad || ly < -bgPad || lx >= totalW + bgPad || ly >= gh + bgPad)
|
||||
discard;
|
||||
|
||||
// Check if on actual glyph
|
||||
if (lx >= 0.0 && ly >= 0.0 && lx < totalW && ly < gh) {
|
||||
int ci = int(floor(lx / gw));
|
||||
if (ci < nc) {
|
||||
int g;
|
||||
if (ci == 0) g = c0;
|
||||
else if (ci == 1) g = c1;
|
||||
else if (ci == 2) g = c2;
|
||||
else g = c3;
|
||||
|
||||
float cu = fract(lx / gw);
|
||||
float cv = ly / gh;
|
||||
float au = (float(g) + cu) / GLYPH_COUNT;
|
||||
float mask = texture(uGlyphTex, vec2(au, cv)).r;
|
||||
|
||||
if (mask > 0.3) {
|
||||
fragColor = vec4(1.0, 1.0, 1.0, 0.9);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (lx < 0.0 || ly < 0.0 || lx >= totalW || ly >= gh) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// Background behind label
|
||||
fragColor = vec4(0.08, 0.08, 0.08, 0.7);
|
||||
int ci = int(floor(lx / gw));
|
||||
if (ci < nc) {
|
||||
int g;
|
||||
if (ci == 0) g = c0;
|
||||
else if (ci == 1) g = c1;
|
||||
else if (ci == 2) g = c2;
|
||||
else g = c3;
|
||||
|
||||
float cu = fract(lx / gw);
|
||||
float cv = ly / gh;
|
||||
float au = (float(g) + cu) / GLYPH_COUNT;
|
||||
vec4 gColor = texture(uGlyphTex, vec2(au, cv));
|
||||
fragColor = gColor.a * vec4(gColor.rgb, uOpacity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user