mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-28 02:34:16 +00:00
Add Classic Icons toggle to Graphics Settings
Adds a "Classic icons" toggle in the structure-icons section of the Graphics Settings modal. Off (default) keeps today's renderer look; on switches to a classic style — lighter player-colored shape behind a dark icon glyph, with 0.75 alpha for a subtle translucent feel. Exposes the underlying tuning as new render-settings knobs (`structure.fillDarken`, `borderDarken`, `iconAlpha`, `iconR/G/B`) and threads them through the structure shader as uniforms, replacing the previously hardcoded `darken(_, 0.65)` / `darken(_, 0.35)` calls and the hardcoded white `vec3(1.0)` icon color. The `classicIcons` boolean in the override schema is the single user-facing knob; the generator derives the five underlying field values from it. Extends the ClientGameRunner live-apply path to copy the `structure` slice too, and adds tests covering the schema and preset derivation.
This commit is contained in:
@@ -9,6 +9,11 @@ export const GraphicsOverridesSchema = z
|
||||
darkNames: z.boolean(),
|
||||
})
|
||||
.partial(),
|
||||
structure: z
|
||||
.object({
|
||||
classicIcons: z.boolean(),
|
||||
})
|
||||
.partial(),
|
||||
})
|
||||
.partial();
|
||||
|
||||
|
||||
@@ -102,6 +102,16 @@ export interface RenderSettings {
|
||||
shapes: Record<string, { scale: number; iconFill: number }>;
|
||||
highlightOutlineWidth: number;
|
||||
highlightDimAlpha: number;
|
||||
/** HSV value multiplier applied to the icon fill (interior). 1.0 = no darkening. */
|
||||
fillDarken: number;
|
||||
/** HSV value multiplier applied to the icon border (outer ring). 1.0 = no darkening. */
|
||||
borderDarken: number;
|
||||
/** Multiplier on final icon alpha. 1.0 = opaque. */
|
||||
iconAlpha: number;
|
||||
/** RGB color of the inner icon glyph */
|
||||
iconR: number;
|
||||
iconG: number;
|
||||
iconB: number;
|
||||
};
|
||||
structureLevel: {
|
||||
scale: number;
|
||||
@@ -279,6 +289,16 @@ export function generateRenderSettings(
|
||||
if (overrides.name?.cullThreshold !== undefined) {
|
||||
settings.name.cullThreshold = overrides.name.cullThreshold;
|
||||
}
|
||||
if (overrides.structure?.classicIcons === true) {
|
||||
// Classic look: lighter player-colored shape behind a dark icon glyph,
|
||||
// with a touch of translucency.
|
||||
settings.structure.borderDarken = 0.7;
|
||||
settings.structure.fillDarken = 1.0;
|
||||
settings.structure.iconR = 0;
|
||||
settings.structure.iconG = 0;
|
||||
settings.structure.iconB = 0;
|
||||
settings.structure.iconAlpha = 0.75;
|
||||
}
|
||||
if (overrides.name?.darkNames !== undefined) {
|
||||
const dark = overrides.name.darkNames;
|
||||
// Dark: black fill + player-colored outline. Force outline RGB to black
|
||||
|
||||
@@ -85,6 +85,10 @@ export class StructurePass {
|
||||
private uHighlightMask: WebGLUniformLocation;
|
||||
private uHighlightOutlineW: WebGLUniformLocation;
|
||||
private uHighlightDimAlpha: WebGLUniformLocation;
|
||||
private uFillDarken: WebGLUniformLocation;
|
||||
private uBorderDarken: WebGLUniformLocation;
|
||||
private uIconAlpha: WebGLUniformLocation;
|
||||
private uIconColor: WebGLUniformLocation;
|
||||
|
||||
private vao: WebGLVertexArrayObject;
|
||||
private instanceBuf: DynamicInstanceBuffer;
|
||||
@@ -166,6 +170,10 @@ export class StructurePass {
|
||||
this.program,
|
||||
"uHighlightDimAlpha",
|
||||
)!;
|
||||
this.uFillDarken = gl.getUniformLocation(this.program, "uFillDarken")!;
|
||||
this.uBorderDarken = gl.getUniformLocation(this.program, "uBorderDarken")!;
|
||||
this.uIconAlpha = gl.getUniformLocation(this.program, "uIconAlpha")!;
|
||||
this.uIconColor = gl.getUniformLocation(this.program, "uIconColor")!;
|
||||
|
||||
// Texture unit bindings + ghost defaults
|
||||
gl.useProgram(this.program);
|
||||
@@ -358,6 +366,10 @@ export class StructurePass {
|
||||
gl.uniform1i(this.uHighlightMask, this.highlightMask);
|
||||
gl.uniform1f(this.uHighlightOutlineW, ss.highlightOutlineWidth);
|
||||
gl.uniform1f(this.uHighlightDimAlpha, ss.highlightDimAlpha);
|
||||
gl.uniform1f(this.uFillDarken, ss.fillDarken);
|
||||
gl.uniform1f(this.uBorderDarken, ss.borderDarken);
|
||||
gl.uniform1f(this.uIconAlpha, ss.iconAlpha);
|
||||
gl.uniform3f(this.uIconColor, ss.iconR, ss.iconG, ss.iconB);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.paletteTex);
|
||||
|
||||
@@ -116,7 +116,13 @@
|
||||
}
|
||||
},
|
||||
"highlightOutlineWidth": 0.04,
|
||||
"highlightDimAlpha": 0.3
|
||||
"highlightDimAlpha": 0.3,
|
||||
"fillDarken": 0.65,
|
||||
"borderDarken": 0.35,
|
||||
"iconAlpha": 1.0,
|
||||
"iconR": 1.0,
|
||||
"iconG": 1.0,
|
||||
"iconB": 1.0
|
||||
},
|
||||
"structureLevel": {
|
||||
"scale": 1.2,
|
||||
|
||||
@@ -11,6 +11,10 @@ uniform int uAltView;
|
||||
uniform int uHighlightMask; // bitmask of atlas columns to highlight (0 = off)
|
||||
uniform float uHighlightOutlineW; // outline width for highlighted structures
|
||||
uniform float uHighlightDimAlpha; // alpha multiplier for non-highlighted structures
|
||||
uniform float uFillDarken; // HSV value multiplier on icon fill
|
||||
uniform float uBorderDarken; // HSV value multiplier on icon border
|
||||
uniform float uIconAlpha; // global multiplier on final icon alpha
|
||||
uniform vec3 uIconColor; // color of the inner icon glyph (was white)
|
||||
|
||||
in vec2 vLocalPos;
|
||||
in vec2 vAtlasUV;
|
||||
@@ -91,8 +95,8 @@ void main() {
|
||||
|
||||
if (uAltView != 0 && vUnderConstruction < 0.5) {
|
||||
vec3 ac = texelFetch(uAffiliation, ivec2(int(vOwnerID), 1), 0).rgb;
|
||||
fillColor = vec4(darken(ac, 0.65), 1.0);
|
||||
borderColor = vec4(darken(ac, 0.35), 1.0);
|
||||
fillColor = vec4(darken(ac, uFillDarken), 1.0);
|
||||
borderColor = vec4(darken(ac, uBorderDarken), 1.0);
|
||||
} else if (vUnderConstruction > 0.5) {
|
||||
fillColor = vec4(198.0/255.0, 198.0/255.0, 198.0/255.0, 1.0);
|
||||
borderColor = vec4(127.0/255.0, 127.0/255.0, 127.0/255.0, 1.0);
|
||||
@@ -102,8 +106,8 @@ void main() {
|
||||
borderColor = texture(uPalette, vec2(u, 0.75));
|
||||
// Darken via HSV value so hue/saturation stay intact
|
||||
// vScale < 1.0 = darker, > 1.0 = brighter
|
||||
fillColor.rgb = darken(fillColor.rgb, 0.65);
|
||||
borderColor.rgb = darken(borderColor.rgb, 0.35);
|
||||
fillColor.rgb = darken(fillColor.rgb, uFillDarken);
|
||||
borderColor.rgb = darken(borderColor.rgb, uBorderDarken);
|
||||
fillColor.a = 1.0;
|
||||
borderColor.a = 1.0;
|
||||
}
|
||||
@@ -127,8 +131,8 @@ void main() {
|
||||
iconAlpha = iconSample.a * borderMask * inBounds;
|
||||
}
|
||||
|
||||
// Composite: white icon over player-colored shape
|
||||
vec3 finalRGB = mix(bgColor.rgb, vec3(1.0), iconAlpha);
|
||||
// Composite: tinted icon over player-colored shape
|
||||
vec3 finalRGB = mix(bgColor.rgb, uIconColor, iconAlpha);
|
||||
|
||||
// Red X overlay for units marked for deletion
|
||||
if (vMarkedForDeletion > 0.5) {
|
||||
@@ -147,7 +151,7 @@ void main() {
|
||||
float tintActive = step(0.01, dot(uOutlineColor, uOutlineColor));
|
||||
finalRGB = mix(finalRGB, uOutlineColor, tintActive * 0.5);
|
||||
|
||||
float finalAlpha = bgColor.a * outerAlpha * uGhostAlpha;
|
||||
float finalAlpha = bgColor.a * outerAlpha * uGhostAlpha * uIconAlpha;
|
||||
|
||||
// Build-button hover highlight: white outline on matching types, dim the rest
|
||||
if (uHighlightMask != 0) {
|
||||
|
||||
Reference in New Issue
Block a user