webgl-initial

This commit is contained in:
scamiv
2025-12-11 17:59:50 +01:00
parent fe927b9758
commit ad9af8eaf5
14 changed files with 2640 additions and 218 deletions
+137 -11
View File
@@ -41,6 +41,10 @@ import { UserSettings } from "./UserSettings";
const userSettings: UserSettings = new UserSettings();
const FRIENDLY_TINT_TARGET = { r: 0, g: 255, b: 0, a: 1 };
const EMBARGO_TINT_TARGET = { r: 255, g: 0, b: 0, a: 1 };
const BORDER_TINT_RATIO = 0.35;
export class UnitView {
public _wasUpdated = true;
public lastPos: TileRef[] = [];
@@ -184,9 +188,17 @@ export class PlayerView {
private _territoryColor: Colord;
private _borderColor: Colord;
// Update here to include structure light and dark colors
private _structureColors: { light: Colord; dark: Colord };
private _defendedBorderColors: { light: Colord; dark: Colord };
// Pre-computed border color variants
private _borderColorNeutral: Colord;
private _borderColorFriendly: Colord;
private _borderColorEmbargo: Colord;
private _borderColorDefendedNeutral: { light: Colord; dark: Colord };
private _borderColorDefendedFriendly: { light: Colord; dark: Colord };
private _borderColorDefendedEmbargo: { light: Colord; dark: Colord };
constructor(
private game: GameView,
@@ -248,11 +260,56 @@ export class PlayerView {
this.cosmetics.color?.color ??
maybeFocusedBorderColor.toHex(),
);
const theme = this.game.config().theme();
const baseRgb = this._borderColor.toRgb();
this._defendedBorderColors = this.game
.config()
.theme()
.defendedBorderColors(this._borderColor);
// Neutral is just the base color
this._borderColorNeutral = this._borderColor;
// Compute friendly tint
this._borderColorFriendly = colord({
r: Math.round(
baseRgb.r * (1 - BORDER_TINT_RATIO) +
FRIENDLY_TINT_TARGET.r * BORDER_TINT_RATIO,
),
g: Math.round(
baseRgb.g * (1 - BORDER_TINT_RATIO) +
FRIENDLY_TINT_TARGET.g * BORDER_TINT_RATIO,
),
b: Math.round(
baseRgb.b * (1 - BORDER_TINT_RATIO) +
FRIENDLY_TINT_TARGET.b * BORDER_TINT_RATIO,
),
a: baseRgb.a,
});
// Compute embargo tint
this._borderColorEmbargo = colord({
r: Math.round(
baseRgb.r * (1 - BORDER_TINT_RATIO) +
EMBARGO_TINT_TARGET.r * BORDER_TINT_RATIO,
),
g: Math.round(
baseRgb.g * (1 - BORDER_TINT_RATIO) +
EMBARGO_TINT_TARGET.g * BORDER_TINT_RATIO,
),
b: Math.round(
baseRgb.b * (1 - BORDER_TINT_RATIO) +
EMBARGO_TINT_TARGET.b * BORDER_TINT_RATIO,
),
a: baseRgb.a,
});
// Pre-compute defended variants
this._borderColorDefendedNeutral = theme.defendedBorderColors(
this._borderColorNeutral,
);
this._borderColorDefendedFriendly = theme.defendedBorderColors(
this._borderColorFriendly,
);
this._borderColorDefendedEmbargo = theme.defendedBorderColors(
this._borderColorEmbargo,
);
this.decoder =
pattern === undefined
@@ -275,18 +332,74 @@ export class PlayerView {
return this._structureColors;
}
/**
* Border color for a tile:
* - Tints by neighbor relations (embargo → red, friendly → green, else neutral).
* - If defended, applies theme checkerboard to the tinted color.
*/
borderColor(tile?: TileRef, isDefended: boolean = false): Colord {
if (tile === undefined || !isDefended) {
if (tile === undefined) {
return this._borderColor;
}
const { hasEmbargo, hasFriendly } = this.borderRelationFlags(tile);
let baseColor: Colord;
let defendedColors: { light: Colord; dark: Colord };
if (hasEmbargo) {
baseColor = this._borderColorEmbargo;
defendedColors = this._borderColorDefendedEmbargo;
} else if (hasFriendly) {
baseColor = this._borderColorFriendly;
defendedColors = this._borderColorDefendedFriendly;
} else {
baseColor = this._borderColorNeutral;
defendedColors = this._borderColorDefendedNeutral;
}
if (!isDefended) {
return baseColor;
}
const x = this.game.x(tile);
const y = this.game.y(tile);
const lightTile =
(x % 2 === 0 && y % 2 === 0) || (y % 2 === 1 && x % 2 === 1);
return lightTile
? this._defendedBorderColors.light
: this._defendedBorderColors.dark;
return lightTile ? defendedColors.light : defendedColors.dark;
}
/**
* Border relation flags for a tile, used by both CPU and WebGL renderers.
*/
borderRelationFlags(tile: TileRef): {
hasEmbargo: boolean;
hasFriendly: boolean;
} {
const mySmallID = this.smallID();
let hasEmbargo = false;
let hasFriendly = false;
for (const n of this.game.neighbors(tile)) {
if (!this.game.hasOwner(n)) {
continue;
}
const otherOwner = this.game.owner(n);
if (!otherOwner.isPlayer() || otherOwner.smallID() === mySmallID) {
continue;
}
if (this.hasEmbargo(otherOwner)) {
hasEmbargo = true;
break;
}
if (this.isFriendly(otherOwner) || otherOwner.isFriendly(this)) {
hasFriendly = true;
}
}
return { hasEmbargo, hasFriendly };
}
async actions(tile?: TileRef): Promise<PlayerActions> {
@@ -480,6 +593,7 @@ export class GameView implements GameMap {
private _map: GameMap;
private readonly usesSharedTileState: boolean;
private readonly terraNullius = new TerraNulliusImpl();
constructor(
public worker: WorkerClient,
@@ -635,11 +749,11 @@ export class GameView implements GameMap {
playerBySmallID(id: number): PlayerView | TerraNullius {
if (id === 0) {
return new TerraNulliusImpl();
return this.terraNullius;
}
const playerId = this.smallIDToID.get(id);
if (playerId === undefined) {
throw new Error(`small id ${id} not found`);
return this.terraNullius;
}
return this.player(playerId);
}
@@ -796,6 +910,18 @@ export class GameView implements GameMap {
return this._gameID;
}
hasSharedTileState(): boolean {
return this.usesSharedTileState;
}
sharedStateBuffer(): SharedArrayBuffer | undefined {
if (!this.usesSharedTileState) {
return undefined;
}
const buffer = this._mapData.sharedStateBuffer;
return buffer instanceof SharedArrayBuffer ? buffer : undefined;
}
focusedPlayer(): PlayerView | null {
return this.myPlayer();
}
+8
View File
@@ -61,6 +61,10 @@ export class UserSettings {
return this.get("settings.structureSprites", true);
}
territoryWebGL() {
return this.get("settings.territoryWebGL", true);
}
darkMode() {
return this.get("settings.darkMode", false);
}
@@ -115,6 +119,10 @@ export class UserSettings {
this.set("settings.structureSprites", !this.structureSprites());
}
toggleTerritoryWebGL() {
this.set("settings.territoryWebGL", !this.territoryWebGL());
}
toggleTerritoryPatterns() {
this.set("settings.territoryPatterns", !this.territoryPatterns());
}