mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 08:20:50 +00:00
Fix WorldTextPass labels scaling with device-pixel-ratio
Attack troop labels, the ghost-cost chip, and the bonusPopup minScreenScale floor were dividing by `zoom`, which Camera.ts stores as device-pixels-per-world-unit (canvasW = cssWidth * dpr). The result was constant device-pixel size — labels rendered ~2x larger on DPR=1 displays than on retina. Multiply each screen-relative scale by dpr so the on-screen size stays constant in CSS pixels. Retune the now-correct sizes: attack labels 34 -> 17, ghost-cost screenScale 30 -> 18, screenYOffset 50 -> 25.
This commit is contained in:
@@ -44,7 +44,7 @@ const GHOST_COST_OUTLINE_WIDTH = 1.4;
|
||||
* zoom each frame so the on-screen label size stays constant regardless of
|
||||
* how far the camera is zoomed.
|
||||
*/
|
||||
const ATTACK_LABEL_SCREEN_SCALE = 34.0;
|
||||
const ATTACK_LABEL_SCREEN_SCALE = 17.0;
|
||||
const ATTACK_LABEL_OUTLINE_WIDTH = 1.2;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -397,6 +397,9 @@ export class WorldTextPass {
|
||||
|
||||
private rebuildInstances(now: number, zoom: number): void {
|
||||
let count = 0;
|
||||
// canvasW in Camera is cssWidth*dpr, so `zoom` is device-px-per-world-unit.
|
||||
// Multiply screen-relative scales by dpr to keep a constant CSS-pixel size.
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
|
||||
for (const popup of this.active) {
|
||||
const elapsed = now - popup.startMs;
|
||||
@@ -442,7 +445,8 @@ export class WorldTextPass {
|
||||
// Attack troop labels — persistent, no fade. Controller interpolates
|
||||
// positions before pushing. Scale is divided by zoom so the label keeps
|
||||
// a constant on-screen size regardless of how zoomed-in the camera is.
|
||||
const attackScale = ATTACK_LABEL_SCREEN_SCALE / Math.max(zoom, 0.0001);
|
||||
const attackScale =
|
||||
(ATTACK_LABEL_SCREEN_SCALE * dpr) / Math.max(zoom, 0.0001);
|
||||
for (const label of this.attackTroopLabels) {
|
||||
layoutString(
|
||||
label.text,
|
||||
@@ -478,8 +482,9 @@ export class WorldTextPass {
|
||||
const label = this.ghostCostLabel;
|
||||
if (label) {
|
||||
const invZoom = 1 / Math.max(zoom, 0.0001);
|
||||
const ghostScale = this.settings.ghostCost.screenScale * invZoom;
|
||||
const ghostY = label.y + this.settings.ghostCost.screenYOffset * invZoom;
|
||||
const ghostScale = this.settings.ghostCost.screenScale * dpr * invZoom;
|
||||
const ghostY =
|
||||
label.y + this.settings.ghostCost.screenYOffset * dpr * invZoom;
|
||||
layoutString(
|
||||
label.text,
|
||||
this.glyph,
|
||||
@@ -536,7 +541,11 @@ export class WorldTextPass {
|
||||
gl.useProgram(this.program);
|
||||
gl.uniformMatrix3fv(this.uCamera, false, cameraMatrix);
|
||||
gl.uniform1f(this.uZoom, zoom);
|
||||
gl.uniform1f(this.uMinScreenScale, this.settings.bonusPopup.minScreenScale);
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
gl.uniform1f(
|
||||
this.uMinScreenScale,
|
||||
this.settings.bonusPopup.minScreenScale * dpr,
|
||||
);
|
||||
gl.uniform1f(this.uDistRange, this.distanceRange);
|
||||
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
|
||||
@@ -270,8 +270,8 @@
|
||||
"cullZoom": 0.3
|
||||
},
|
||||
"ghostCost": {
|
||||
"screenScale": 30,
|
||||
"screenYOffset": 50
|
||||
"screenScale": 18,
|
||||
"screenYOffset": 25
|
||||
},
|
||||
"spawnOverlay": {
|
||||
"highlightRadius": 9,
|
||||
|
||||
Reference in New Issue
Block a user