Skip to content

Commit

Permalink
Merge pull request #2534 from BibliothecaDAO/feat/graphics-settings
Browse files Browse the repository at this point in the history
Feat/graphics settings
  • Loading branch information
ponderingdemocritus authored Dec 16, 2024
2 parents 0edd382 + e096993 commit 6fc4307
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 75 deletions.
105 changes: 58 additions & 47 deletions client/src/three/GameRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SetupResult } from "@/dojo/setup";
import useUIStore, { AppStore } from "@/hooks/store/useUIStore";
import { SceneName } from "@/types";
import { IS_LOW_GRAPHICS_ENABLED } from "@/ui/config";
import { GRAPHICS_SETTING, GraphicsSettings } from "@/ui/config";
import throttle from "lodash/throttle";
import {
BloomEffect,
Expand Down Expand Up @@ -69,10 +69,10 @@ export default class GameRenderer {
private sceneManager!: SceneManager;
private systemManager!: SystemManager;

private isLowGraphicsMode: boolean;
private graphicsSetting: GraphicsSettings;

constructor(dojoContext: SetupResult) {
this.isLowGraphicsMode = IS_LOW_GRAPHICS_ENABLED;
this.graphicsSetting = GRAPHICS_SETTING;
this.initializeRenderer();
this.dojo = dojoContext;
this.locationManager = new LocationManager();
Expand Down Expand Up @@ -165,16 +165,13 @@ export default class GameRenderer {
this.renderer = new THREE.WebGLRenderer({
powerPreference: "high-performance",
antialias: false,
stencil: false,
depth: false,
stencil: this.graphicsSetting === GraphicsSettings.LOW,
depth: this.graphicsSetting === GraphicsSettings.LOW,
});
this.renderer.setPixelRatio(this.isLowGraphicsMode ? 0.75 : window.devicePixelRatio);
this.renderer.shadowMap.enabled = !this.isLowGraphicsMode;
this.renderer.setPixelRatio(this.graphicsSetting !== GraphicsSettings.HIGH ? 0.75 : window.devicePixelRatio);
this.renderer.shadowMap.enabled = this.graphicsSetting !== GraphicsSettings.LOW;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.setSize(
this.isLowGraphicsMode ? window.innerWidth : window.innerWidth,
this.isLowGraphicsMode ? window.innerHeight : window.innerHeight,
);
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.toneMapping = THREE.NoToneMapping;
this.renderer.toneMappingExposure = 1;
this.renderer.autoClear = false;
Expand Down Expand Up @@ -207,7 +204,7 @@ export default class GameRenderer {
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.1;
this.controls.target.set(0, 0, 0);
if (this.isLowGraphicsMode) {
if (this.graphicsSetting !== GraphicsSettings.HIGH) {
this.controls.enableDamping = false;
}
this.controls.addEventListener(
Expand Down Expand Up @@ -296,41 +293,45 @@ export default class GameRenderer {

const obj = { brightness: -0.1, contrast: 0 };
const folder = GUIManager.addFolder("BrightnesContrastt");
const BCEffect = new BrightnessContrastEffect({
brightness: obj.brightness,
contrast: obj.contrast,
});
folder
.add(obj, "brightness")
.name("Brightness")
.min(-1)
.max(1)
.step(0.01)
.onChange((value: number) => {
BCEffect.brightness = value;
});
folder
.add(obj, "contrast")
.name("Contrast")
.min(-1)
.max(1)
.step(0.01)
.onChange((value: number) => {
BCEffect.contrast = value;
if (GRAPHICS_SETTING !== GraphicsSettings.LOW) {
const BCEffect = new BrightnessContrastEffect({
brightness: obj.brightness,
contrast: obj.contrast,
});
this.composer.addPass(
new EffectPass(
this.camera,

new FXAAEffect(),
new BloomEffect({
luminanceThreshold: 1.1,
mipmapBlur: true,
intensity: 0.25,
}),
BCEffect,
),
);

folder
.add(obj, "brightness")
.name("Brightness")
.min(-1)
.max(1)
.step(0.01)
.onChange((value: number) => {
BCEffect.brightness = value;
});
folder
.add(obj, "contrast")
.name("Contrast")
.min(-1)
.max(1)
.step(0.01)
.onChange((value: number) => {
BCEffect.contrast = value;
});

this.composer.addPass(
new EffectPass(
this.camera,

new FXAAEffect(),
new BloomEffect({
luminanceThreshold: 1.1,
mipmapBlur: true,
intensity: 0.25,
}),
BCEffect,
),
);
}

this.sceneManager.moveCameraForScene();
}
Expand Down Expand Up @@ -391,8 +392,19 @@ export default class GameRenderer {
});
return;
}

const currentTime = performance.now();
const deltaTime = (currentTime - this.lastTime) / 1000; // Convert to seconds

// Skip frame if not enough time has passed (for 30 FPS)
if (this.graphicsSetting !== GraphicsSettings.HIGH) {
const frameTime = 1000 / 30; // 33.33ms for 30 FPS
if (currentTime - this.lastTime < frameTime) {
requestAnimationFrame(() => this.animate());
return;
}
}

this.lastTime = currentTime;

if (this.stats) this.stats.update();
Expand Down Expand Up @@ -421,7 +433,6 @@ export default class GameRenderer {
this.renderer.render(this.hudScene.getScene(), this.hudScene.getCamera());
this.labelRenderer.render(this.hudScene.getScene(), this.hudScene.getCamera());

// Update the minimap
requestAnimationFrame(() => {
this.animate();
});
Expand Down
8 changes: 6 additions & 2 deletions client/src/three/components/ArmyModel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IS_LOW_GRAPHICS_ENABLED } from "@/ui/config";
import { GRAPHICS_SETTING, GraphicsSettings } from "@/ui/config";
import * as THREE from "three";
import { AnimationClip, AnimationMixer } from "three";
import { gltfLoader } from "../helpers/utils";
Expand Down Expand Up @@ -159,6 +159,10 @@ export class ArmyModel {
updateAnimations(deltaTime: number) {
const time = performance.now() * 0.001;

if (GRAPHICS_SETTING === GraphicsSettings.LOW) {
return;
}

this.models.forEach((modelData) => {
let needsMatrixUpdate = false;

Expand All @@ -184,7 +188,7 @@ export class ArmyModel {

for (let i = 0; i < modelData.mesh.count; i++) {
const animationState = this.animationStates[i];
if (IS_LOW_GRAPHICS_ENABLED && animationState === ANIMATION_STATE_IDLE) {
if (GRAPHICS_SETTING === GraphicsSettings.MID && animationState === ANIMATION_STATE_IDLE) {
continue;
}

Expand Down
5 changes: 5 additions & 0 deletions client/src/three/components/BattleModel.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GRAPHICS_SETTING, GraphicsSettings } from "@/ui/config";
import * as THREE from "three";
import { AnimationClip, AnimationMixer } from "three";
import { gltfLoader } from "../helpers/utils";
Expand Down Expand Up @@ -74,6 +75,10 @@ export class BattleModel {
}

updateAnimations(deltaTime: number) {
if (GRAPHICS_SETTING === GraphicsSettings.LOW) {
return;
}

if (this.mixer && this.mesh && this.animation) {
const time = performance.now() * 0.001;
for (let i = 0; i < this.mesh.count; i++) {
Expand Down
7 changes: 6 additions & 1 deletion client/src/three/components/InstancedBiome.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GRAPHICS_SETTING, GraphicsSettings } from "@/ui/config";
import * as THREE from "three";
import { AnimationClip, AnimationMixer } from "three";
import { PREVIEW_BUILD_COLOR_INVALID } from "../scenes/constants";
Expand Down Expand Up @@ -43,7 +44,7 @@ export default class InstancedModel {
tmp.userData.isInstanceModel = true;

if (!enableRaycast) {
tmp.raycast = () => {};
tmp.raycast = () => { };
}

this.mixer = new AnimationMixer(gltf.scene);
Expand Down Expand Up @@ -137,6 +138,10 @@ export default class InstancedModel {
}

updateAnimations(deltaTime: number) {
if (GRAPHICS_SETTING === GraphicsSettings.LOW) {
return;
}

if (this.mixer && this.animation) {
const time = performance.now() * 0.001;
this.instancedMeshes.forEach((mesh, meshIndex) => {
Expand Down
7 changes: 6 additions & 1 deletion client/src/three/components/InstancedModel.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GRAPHICS_SETTING, GraphicsSettings } from "@/ui/config";
import { ResourcesIds, StructureType } from "@bibliothecadao/eternum";
import * as THREE from "three";
import { AnimationClip, AnimationMixer } from "three";
Expand Down Expand Up @@ -73,7 +74,7 @@ export default class InstancedModel {
tmp.userData.isInstanceModel = true;

if (!enableRaycast) {
tmp.raycast = () => {};
tmp.raycast = () => { };
}

this.mixer = new AnimationMixer(gltf.scene);
Expand Down Expand Up @@ -168,6 +169,10 @@ export default class InstancedModel {
}

updateAnimations(deltaTime: number) {
if (GRAPHICS_SETTING === GraphicsSettings.LOW) {
return;
}

if (this.mixer && this.animation) {
const time = performance.now() * 0.001;
this.instancedMeshes.forEach((mesh, meshIndex) => {
Expand Down
32 changes: 25 additions & 7 deletions client/src/ui/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,47 @@ import { BuildingType, FELT_CENTER } from "@bibliothecadao/eternum";

export { FELT_CENTER };

const checkIfGameIsRunningOnLaptop = async () => {
export enum GraphicsSettings {
LOW = "LOW",
MID = "MID",
HIGH = "HIGH"
}

const checkGraphicsSettings = async () => {
// Handle migration from old LOW_GRAPHICS_FLAG
const oldLowGraphicsFlag = localStorage.getItem("LOW_GRAPHICS_FLAG");
if (oldLowGraphicsFlag !== null) {
// Migrate old setting to new format
const newSetting = oldLowGraphicsFlag === "true" ? GraphicsSettings.LOW : GraphicsSettings.HIGH;
localStorage.setItem("GRAPHICS_SETTING", newSetting);
localStorage.removeItem("LOW_GRAPHICS_FLAG"); // Clean up old setting
return newSetting;
}

// Check if initial laptop check has been done
if (!localStorage.getItem("INITIAL_LAPTOP_CHECK")) {
try {
const battery = await (navigator as any).getBattery();
if (battery.charging && battery.chargingTime === 0) {
// It's likely a desktop
localStorage.setItem("LOW_GRAPHICS_FLAG", "false");
localStorage.setItem("GRAPHICS_SETTING", GraphicsSettings.HIGH);
} else {
// It's likely a laptop or mobile device.
localStorage.setItem("LOW_GRAPHICS_FLAG", "true");
// It's likely a laptop or mobile device
localStorage.setItem("GRAPHICS_SETTING", GraphicsSettings.LOW);
}
} catch (error) {
console.error("Error calling getBattery():", error);
// Set default values if getBattery() is not supported
localStorage.setItem("LOW_GRAPHICS_FLAG", "true");
localStorage.setItem("GRAPHICS_SETTING", GraphicsSettings.LOW);
} finally {
localStorage.setItem("INITIAL_LAPTOP_CHECK", "true");
}
}
return localStorage.getItem("LOW_GRAPHICS_FLAG") === "true";

return localStorage.getItem("GRAPHICS_SETTING") as GraphicsSettings || GraphicsSettings.HIGH;
};

export const IS_LOW_GRAPHICS_ENABLED = await checkIfGameIsRunningOnLaptop();
export const GRAPHICS_SETTING = await checkGraphicsSettings();

export const IS_MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

Expand Down
41 changes: 24 additions & 17 deletions client/src/ui/modules/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useMusicPlayer } from "@/hooks/useMusic";
import useScreenOrientation from "@/hooks/useScreenOrientation";
import { settings } from "@/ui/components/navigation/Config";
import { OSWindow } from "@/ui/components/navigation/OSWindow";
import { IS_LOW_GRAPHICS_ENABLED } from "@/ui/config";
import { GraphicsSettings } from "@/ui/config";
import Avatar from "@/ui/elements/Avatar";
import Button from "@/ui/elements/Button";
import { Checkbox } from "@/ui/elements/Checkbox";
Expand Down Expand Up @@ -61,10 +61,11 @@ export const SettingsWindow = () => {

const isOpen = useUIStore((state) => state.isPopupOpen(settings));

const isLowGraphics = IS_LOW_GRAPHICS_ENABLED;
const GRAPHICS_SETTING = localStorage.getItem("GRAPHICS_SETTING") as GraphicsSettings || GraphicsSettings.HIGH;

return (
<OSWindow onClick={() => togglePopup(settings)} show={isOpen} title={settings}>
<div className="flex p-4 justify-between">
<div className="flex justify-between p-4">
<div className="relative">
<Avatar
onClick={() => setShowSettings(!showSettings)}
Expand Down Expand Up @@ -93,25 +94,31 @@ export const SettingsWindow = () => {
<Headline>Graphics</Headline>
<div className="flex space-x-2">
<Button
disabled={!!isLowGraphics}
variant={isLowGraphics ? "success" : "outline"}
disabled={GRAPHICS_SETTING === GraphicsSettings.LOW}
variant={GRAPHICS_SETTING === GraphicsSettings.LOW ? "success" : "outline"}
onClick={() => {
if (!isLowGraphics) {
localStorage.setItem("LOW_GRAPHICS_FLAG", "true");
window.location.reload();
}
localStorage.setItem("GRAPHICS_SETTING", GraphicsSettings.LOW);
window.location.reload();
}}
>
Low
</Button>
<Button
disabled={!isLowGraphics}
variant={isLowGraphics ? "outline" : "success"}
disabled={GRAPHICS_SETTING === GraphicsSettings.MID}
variant={GRAPHICS_SETTING === GraphicsSettings.MID ? "success" : "outline"}
onClick={() => {
localStorage.setItem("GRAPHICS_SETTING", GraphicsSettings.MID);
window.location.reload();
}}
>
Medium
</Button>
<Button
disabled={GRAPHICS_SETTING === GraphicsSettings.HIGH}
variant={GRAPHICS_SETTING === GraphicsSettings.HIGH ? "success" : "outline"}
onClick={() => {
if (isLowGraphics) {
localStorage.removeItem("LOW_GRAPHICS_FLAG");
window.location.reload();
}
localStorage.setItem("GRAPHICS_SETTING", GraphicsSettings.HIGH);
window.location.reload();
}}
>
High
Expand All @@ -122,11 +129,11 @@ export const SettingsWindow = () => {
<div className="flex space-x-2">
{isSoundOn ? (
<Button variant="outline" onClick={() => toggleSound()}>
<Unmuted className="w-4 cursor-pointer fill-gold" />
<Unmuted className="w-4 cursor-pointer fill-gold" />
</Button>
) : (
<Button variant="outline" onClick={() => toggleSound()}>
<Muted className="w-4 cursor-pointer fill-gold" />
<Muted className="w-4 cursor-pointer fill-gold" />
</Button>
)}

Expand Down

0 comments on commit 6fc4307

Please sign in to comment.