diff --git a/src/components/map/MapDice.js b/src/components/map/MapDice.js
index fb7b7ae..1f606e0 100644
--- a/src/components/map/MapDice.js
+++ b/src/components/map/MapDice.js
@@ -4,6 +4,8 @@ import { Flex, IconButton } from "theme-ui";
import ExpandMoreDiceIcon from "../../icons/ExpandMoreDiceIcon";
import DiceTrayOverlay from "./dice/DiceTrayOverlay";
+import { DiceLoadingProvider } from "../../contexts/DiceLoadingContext";
+
function MapDice() {
const [isExpanded, setIsExpanded] = useState(false);
@@ -32,7 +34,9 @@ function MapDice() {
>
-
+
+
+
);
}
diff --git a/src/components/map/dice/DiceButtons.js b/src/components/map/dice/DiceButtons.js
index 08b1890..0d2d3c7 100644
--- a/src/components/map/dice/DiceButtons.js
+++ b/src/components/map/dice/DiceButtons.js
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
import { Flex, IconButton } from "theme-ui";
import D20Icon from "../../../icons/D20Icon";
@@ -20,10 +20,18 @@ import { dice } from "../../../dice";
function DiceButtons({
diceRolls,
onDiceAdd,
+ onDiceLoad,
diceTraySize,
onDiceTraySizeChange,
}) {
- const [currentDice, setCurrentDice] = useState(dice[0]);
+ const [currentDice, setCurrentDice] = useState();
+
+ useEffect(() => {
+ const initialDice = dice[0];
+ onDiceLoad(initialDice);
+ setCurrentDice(initialDice);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
const diceCounts = {};
for (let dice of diceRolls) {
@@ -34,6 +42,11 @@ function DiceButtons({
}
}
+ async function handleDiceChange(dice) {
+ await onDiceLoad(dice);
+ setCurrentDice(dice);
+ }
+
return (
diff --git a/src/components/map/dice/DiceControls.js b/src/components/map/dice/DiceControls.js
index df5ee28..4902f65 100644
--- a/src/components/map/dice/DiceControls.js
+++ b/src/components/map/dice/DiceControls.js
@@ -10,6 +10,7 @@ function DiceControls({
onDiceAdd,
onDiceClear,
onDiceReroll,
+ onDiceLoad,
diceTraySize,
onDiceTraySizeChange,
}) {
@@ -116,6 +117,7 @@ function DiceControls({
{ type, roll: "unknown" },
]);
}}
+ onDiceLoad={onDiceLoad}
onDiceTraySizeChange={onDiceTraySizeChange}
diceTraySize={diceTraySize}
/>
diff --git a/src/components/map/dice/DiceTrayOverlay.js b/src/components/map/dice/DiceTrayOverlay.js
index 6b0dbba..f47daf3 100644
--- a/src/components/map/dice/DiceTrayOverlay.js
+++ b/src/components/map/dice/DiceTrayOverlay.js
@@ -13,10 +13,12 @@ import environment from "../../../dice/environment.dds";
import Scene from "./DiceScene";
import DiceControls from "./DiceControls";
import Dice from "../../../dice/Dice";
+import LoadingOverlay from "../../LoadingOverlay";
import DiceTray from "../../../dice/diceTray/DiceTray";
import MapInteractionContext from "../../../contexts/MapInteractionContext";
+import DiceLoadingContext from "../../../contexts/DiceLoadingContext";
function DiceTrayOverlay({ isOpen }) {
const sceneRef = useRef();
@@ -29,6 +31,10 @@ function DiceTrayOverlay({ isOpen }) {
const diceTrayRef = useRef();
const [diceTraySize, setDiceTraySize] = useState("single");
+ const { assetLoadStart, assetLoadFinish, isLoading } = useContext(
+ DiceLoadingContext
+ );
+
useEffect(() => {
const diceTray = diceTrayRef.current;
let resizeTimout;
@@ -70,9 +76,11 @@ function DiceTrayOverlay({ isOpen }) {
sceneRef.current = scene;
initializeScene(scene);
engine.runRenderLoop(() => update(scene));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
async function initializeScene(scene) {
+ assetLoadStart();
let light = new BABYLON.DirectionalLight(
"DirectionalLight",
new BABYLON.Vector3(-0.5, -1, -0.5),
@@ -95,6 +103,7 @@ function DiceTrayOverlay({ isOpen }) {
let diceTray = new DiceTray("single", scene, shadowGenerator);
await diceTray.load();
diceTrayRef.current = diceTray;
+ assetLoadFinish();
}
function update(scene) {
@@ -194,6 +203,15 @@ function DiceTrayOverlay({ isOpen }) {
}
}
+ async function handleDiceLoad(dice) {
+ assetLoadStart();
+ const scene = sceneRef.current;
+ if (scene) {
+ await dice.class.load(scene);
+ }
+ assetLoadFinish();
+ }
+
const { setPreventMapInteraction } = useContext(MapInteractionContext);
return (
@@ -229,9 +247,11 @@ function DiceTrayOverlay({ isOpen }) {
onDiceAdd={handleDiceAdd}
onDiceClear={handleDiceClear}
onDiceReroll={handleDiceReroll}
+ onDiceLoad={handleDiceLoad}
diceTraySize={diceTraySize}
onDiceTraySizeChange={setDiceTraySize}
/>
+ {isLoading && }
);
}
diff --git a/src/contexts/DiceLoadingContext.js b/src/contexts/DiceLoadingContext.js
new file mode 100644
index 0000000..4d75d40
--- /dev/null
+++ b/src/contexts/DiceLoadingContext.js
@@ -0,0 +1,31 @@
+import React, { useState } from "react";
+
+const DiceLoadingContext = React.createContext();
+
+export function DiceLoadingProvider({ children }) {
+ const [loadingAssetCount, setLoadingAssetCount] = useState(0);
+
+ function assetLoadStart() {
+ setLoadingAssetCount((prevLoadingAssets) => prevLoadingAssets + 1);
+ }
+
+ function assetLoadFinish() {
+ setLoadingAssetCount((prevLoadingAssets) => prevLoadingAssets - 1);
+ }
+
+ const isLoading = loadingAssetCount > 0;
+
+ const value = {
+ assetLoadStart,
+ assetLoadFinish,
+ isLoading,
+ };
+
+ return (
+
+ {children}
+
+ );
+}
+
+export default DiceLoadingContext;
diff --git a/src/dice/galaxy/GalaxyDice.js b/src/dice/galaxy/GalaxyDice.js
index bdd0ec1..2c345ab 100644
--- a/src/dice/galaxy/GalaxyDice.js
+++ b/src/dice/galaxy/GalaxyDice.js
@@ -8,7 +8,7 @@ class GalaxyDice extends Dice {
static meshes;
static material;
- static async createInstance(diceType, scene) {
+ static async load(scene) {
if (!this.material) {
this.material = this.loadMaterial(
"galaxy_pbr",
@@ -19,6 +19,12 @@ class GalaxyDice extends Dice {
if (!this.meshes) {
this.meshes = await this.loadMeshes(this.material, scene);
}
+ }
+
+ static async createInstance(diceType, scene) {
+ if (!this.material || !this.meshes) {
+ throw Error("Dice not loaded, call load before creating an instance");
+ }
return Dice.createInstance(
this.meshes[diceType],
diff --git a/src/dice/iron/IronDice.js b/src/dice/iron/IronDice.js
index 61393e9..1f9c29f 100644
--- a/src/dice/iron/IronDice.js
+++ b/src/dice/iron/IronDice.js
@@ -13,7 +13,7 @@ class IronDice extends Dice {
return { mass: properties.mass * 2, friction: properties.friction };
}
- static async createInstance(diceType, scene) {
+ static async load(scene) {
if (!this.material) {
this.material = this.loadMaterial(
"iron_pbr",
@@ -24,6 +24,12 @@ class IronDice extends Dice {
if (!this.meshes) {
this.meshes = await this.loadMeshes(this.material, scene);
}
+ }
+
+ static async createInstance(diceType, scene) {
+ if (!this.material || !this.meshes) {
+ throw Error("Dice not loaded, call load before creating an instance");
+ }
return Dice.createInstance(
this.meshes[diceType],
diff --git a/src/dice/nebula/NebulaDice.js b/src/dice/nebula/NebulaDice.js
index 6e4c261..19f614b 100644
--- a/src/dice/nebula/NebulaDice.js
+++ b/src/dice/nebula/NebulaDice.js
@@ -8,10 +8,10 @@ class NebulaDice extends Dice {
static meshes;
static material;
- static async createInstance(diceType, scene) {
+ static async load(scene) {
if (!this.material) {
this.material = this.loadMaterial(
- "nebula_pbr",
+ "neubula_pbr",
{ albedo, metalRoughness, normal },
scene
);
@@ -19,6 +19,12 @@ class NebulaDice extends Dice {
if (!this.meshes) {
this.meshes = await this.loadMeshes(this.material, scene);
}
+ }
+
+ static async createInstance(diceType, scene) {
+ if (!this.material || !this.meshes) {
+ throw Error("Dice not loaded, call load before creating an instance");
+ }
return Dice.createInstance(
this.meshes[diceType],
diff --git a/src/dice/sunrise/SunriseDice.js b/src/dice/sunrise/SunriseDice.js
index e9cd654..62f0db1 100644
--- a/src/dice/sunrise/SunriseDice.js
+++ b/src/dice/sunrise/SunriseDice.js
@@ -8,7 +8,7 @@ class SunriseDice extends Dice {
static meshes;
static material;
- static async createInstance(diceType, scene) {
+ static async load(scene) {
if (!this.material) {
this.material = this.loadMaterial(
"sunrise_pbr",
@@ -19,6 +19,12 @@ class SunriseDice extends Dice {
if (!this.meshes) {
this.meshes = await this.loadMeshes(this.material, scene);
}
+ }
+
+ static async createInstance(diceType, scene) {
+ if (!this.material || !this.meshes) {
+ throw Error("Dice not loaded, call load before creating an instance");
+ }
return Dice.createInstance(
this.meshes[diceType],
diff --git a/src/dice/sunset/SunsetDice.js b/src/dice/sunset/SunsetDice.js
index e4240d8..5ea5d84 100644
--- a/src/dice/sunset/SunsetDice.js
+++ b/src/dice/sunset/SunsetDice.js
@@ -8,7 +8,7 @@ class SunsetDice extends Dice {
static meshes;
static material;
- static async createInstance(diceType, scene) {
+ static async load(scene) {
if (!this.material) {
this.material = this.loadMaterial(
"sunset_pbr",
@@ -19,6 +19,12 @@ class SunsetDice extends Dice {
if (!this.meshes) {
this.meshes = await this.loadMeshes(this.material, scene);
}
+ }
+
+ static async createInstance(diceType, scene) {
+ if (!this.material || !this.meshes) {
+ throw Error("Dice not loaded, call load before creating an instance");
+ }
return Dice.createInstance(
this.meshes[diceType],
diff --git a/src/dice/walnut/WalnutDice.js b/src/dice/walnut/WalnutDice.js
index f17c8eb..0ba0ae5 100644
--- a/src/dice/walnut/WalnutDice.js
+++ b/src/dice/walnut/WalnutDice.js
@@ -8,7 +8,7 @@ class WalnutDice extends Dice {
static meshes;
static material;
- static async createInstance(diceType, scene) {
+ static async load(scene) {
if (!this.material) {
this.material = this.loadMaterial(
"walnut_pbr",
@@ -19,6 +19,12 @@ class WalnutDice extends Dice {
if (!this.meshes) {
this.meshes = await this.loadMeshes(this.material, scene);
}
+ }
+
+ static async createInstance(diceType, scene) {
+ if (!this.material || !this.meshes) {
+ throw Error("Dice not loaded, call load before creating an instance");
+ }
return Dice.createInstance(
this.meshes[diceType],