Files
healer-man/src/scene/useGameGLTF.ts
T
2026-10-07 13:05:04 -04:00

68 lines
2.6 KiB
TypeScript

import { useGLTF } from "@react-three/drei";
import { useThree } from "@react-three/fiber";
import { useCallback, type ReactNode } from "react";
import type { WebGLRenderer } from "three";
import { KTX2Loader, type GLTFLoader } from "three-stdlib";
import { resolveContentUrl } from "../content/contentManager";
import { configureRunewakerTerrainLoader } from "./runewakerTerrainMaterial";
import { configureRunewakerSurfaceDetailLoader } from "./runewakerSurfaceDetailMaterial";
import { configureRunewakerWaterLoader } from "./runewakerWaterMaterial";
import { configureWowTerrainLoader } from "./wowTerrainMaterial";
export const KTX2_TRANSCODER_PATH = `${import.meta.env.BASE_URL}basis/`;
const ktx2Loaders = new WeakMap<WebGLRenderer, KTX2Loader>();
function ktx2LoaderFor(renderer: WebGLRenderer): KTX2Loader {
const cached = ktx2Loaders.get(renderer);
if (cached) return cached;
const loader = new KTX2Loader();
loader.setTranscoderPath(KTX2_TRANSCODER_PATH);
loader.detectSupport(renderer);
ktx2Loaders.set(renderer, loader);
return loader;
}
/**
* Marks the part of a Canvas that shares its GLTF decoder. KTX2Loader instances
* intentionally live with their weakly referenced renderer: disposing one from
* React cleanup can abort a GLB that is still decoding or cached by useGLTF.
*/
export function GameGltfLoaderLifecycle({ children }: { readonly children: ReactNode }) {
return children;
}
/**
* Loads shipped world and creature GLBs with Meshopt and KTX2 support.
* Keeping one KTX2Loader per renderer also keeps Three from creating a worker
* pool for every mounted model.
*/
export function useGameGLTF(url: string) {
const resolvedUrl = resolveContentUrl(url);
const renderer = useThree((state) => state.gl);
const extendLoader = useCallback((loader: GLTFLoader) => {
loader.setKTX2Loader(ktx2LoaderFor(renderer));
configureRunewakerTerrainLoader(loader);
configureRunewakerSurfaceDetailLoader(loader);
configureRunewakerWaterLoader(loader);
configureWowTerrainLoader(loader);
}, [renderer]);
return useGLTF(resolvedUrl, false, true, extendLoader);
}
export function useGameGLTFs(urls: readonly string[]) {
const resolvedUrls = urls.map(resolveContentUrl);
const renderer = useThree((state) => state.gl);
const extendLoader = useCallback((loader: GLTFLoader) => {
loader.setKTX2Loader(ktx2LoaderFor(renderer));
configureRunewakerTerrainLoader(loader);
configureRunewakerSurfaceDetailLoader(loader);
configureRunewakerWaterLoader(loader);
configureWowTerrainLoader(loader);
}, [renderer]);
return useGLTF(resolvedUrls, false, true, extendLoader);
}