151 lines
5.2 KiB
JavaScript
151 lines
5.2 KiB
JavaScript
import { useThree, useLoader } from '@react-three/fiber';
|
|
import { CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader } from 'three';
|
|
import { RGBELoader, EXRLoader } from 'three-stdlib';
|
|
import { HDRJPGLoader, GainMapLoader } from '@monogrid/gainmap-js';
|
|
import { presetsObj } from '../helpers/environment-assets.js';
|
|
import { useLayoutEffect } from 'react';
|
|
|
|
const CUBEMAP_ROOT = 'https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/';
|
|
const isArray = arr => Array.isArray(arr);
|
|
const defaultFiles = ['/px.png', '/nx.png', '/py.png', '/ny.png', '/pz.png', '/nz.png'];
|
|
function useEnvironment({
|
|
files = defaultFiles,
|
|
path = '',
|
|
preset = undefined,
|
|
colorSpace = undefined,
|
|
extensions
|
|
} = {}) {
|
|
if (preset) {
|
|
validatePreset(preset);
|
|
files = presetsObj[preset];
|
|
path = CUBEMAP_ROOT;
|
|
}
|
|
|
|
// Everything else
|
|
const multiFile = isArray(files);
|
|
const {
|
|
extension,
|
|
isCubemap
|
|
} = getExtension(files);
|
|
const loader = getLoader(extension);
|
|
if (!loader) throw new Error('useEnvironment: Unrecognized file extension: ' + files);
|
|
const gl = useThree(state => state.gl);
|
|
useLayoutEffect(() => {
|
|
// Only required for gainmap
|
|
if (extension !== 'webp' && extension !== 'jpg' && extension !== 'jpeg') return;
|
|
function clearGainmapTexture() {
|
|
useLoader.clear(loader, multiFile ? [files] : files);
|
|
}
|
|
gl.domElement.addEventListener('webglcontextlost', clearGainmapTexture, {
|
|
once: true
|
|
});
|
|
}, [files, gl.domElement]);
|
|
const loaderResult = useLoader(loader, multiFile ? [files] : files, loader => {
|
|
// Gainmap requires a renderer
|
|
if (extension === 'webp' || extension === 'jpg' || extension === 'jpeg') {
|
|
// @ts-expect-error
|
|
loader.setRenderer(gl);
|
|
}
|
|
loader.setPath == null || loader.setPath(path);
|
|
// @ts-expect-error
|
|
if (extensions) extensions(loader);
|
|
});
|
|
let texture = multiFile ?
|
|
// @ts-ignore
|
|
loaderResult[0] : loaderResult;
|
|
if (extension === 'jpg' || extension === 'jpeg' || extension === 'webp') {
|
|
var _renderTarget;
|
|
texture = (_renderTarget = texture.renderTarget) == null ? void 0 : _renderTarget.texture;
|
|
}
|
|
texture.mapping = isCubemap ? CubeReflectionMapping : EquirectangularReflectionMapping;
|
|
texture.colorSpace = colorSpace !== null && colorSpace !== void 0 ? colorSpace : isCubemap ? 'srgb' : 'srgb-linear';
|
|
return texture;
|
|
}
|
|
const preloadDefaultOptions = {
|
|
files: defaultFiles,
|
|
path: '',
|
|
preset: undefined,
|
|
extensions: undefined
|
|
};
|
|
useEnvironment.preload = preloadOptions => {
|
|
const options = {
|
|
...preloadDefaultOptions,
|
|
...preloadOptions
|
|
};
|
|
let {
|
|
files,
|
|
path = ''
|
|
} = options;
|
|
const {
|
|
preset,
|
|
extensions
|
|
} = options;
|
|
if (preset) {
|
|
validatePreset(preset);
|
|
files = presetsObj[preset];
|
|
path = CUBEMAP_ROOT;
|
|
}
|
|
const {
|
|
extension
|
|
} = getExtension(files);
|
|
if (extension === 'webp' || extension === 'jpg' || extension === 'jpeg') {
|
|
throw new Error('useEnvironment: Preloading gainmaps is not supported');
|
|
}
|
|
const loader = getLoader(extension);
|
|
if (!loader) throw new Error('useEnvironment: Unrecognized file extension: ' + files);
|
|
useLoader.preload(loader, isArray(files) ? [files] : files, loader => {
|
|
loader.setPath == null || loader.setPath(path);
|
|
// @ts-expect-error
|
|
if (extensions) extensions(loader);
|
|
});
|
|
};
|
|
const clearDefaultOptins = {
|
|
files: defaultFiles,
|
|
preset: undefined
|
|
};
|
|
useEnvironment.clear = clearOptions => {
|
|
const options = {
|
|
...clearDefaultOptins,
|
|
...clearOptions
|
|
};
|
|
let {
|
|
files
|
|
} = options;
|
|
const {
|
|
preset
|
|
} = options;
|
|
if (preset) {
|
|
validatePreset(preset);
|
|
files = presetsObj[preset];
|
|
}
|
|
const {
|
|
extension
|
|
} = getExtension(files);
|
|
const loader = getLoader(extension);
|
|
if (!loader) throw new Error('useEnvironment: Unrecognized file extension: ' + files);
|
|
useLoader.clear(loader, isArray(files) ? [files] : files);
|
|
};
|
|
function validatePreset(preset) {
|
|
if (!(preset in presetsObj)) throw new Error('Preset must be one of: ' + Object.keys(presetsObj).join(', '));
|
|
}
|
|
function getExtension(files) {
|
|
var _firstEntry$split$pop;
|
|
const isCubemap = isArray(files) && files.length === 6;
|
|
const isGainmap = isArray(files) && files.length === 3 && files.some(file => file.endsWith('json'));
|
|
const firstEntry = isArray(files) ? files[0] : files;
|
|
|
|
// Everything else
|
|
const extension = isCubemap ? 'cube' : isGainmap ? 'webp' : firstEntry.startsWith('data:application/exr') ? 'exr' : firstEntry.startsWith('data:application/hdr') ? 'hdr' : firstEntry.startsWith('data:image/jpeg') ? 'jpg' : (_firstEntry$split$pop = firstEntry.split('.').pop()) == null || (_firstEntry$split$pop = _firstEntry$split$pop.split('?')) == null || (_firstEntry$split$pop = _firstEntry$split$pop.shift()) == null ? void 0 : _firstEntry$split$pop.toLowerCase();
|
|
return {
|
|
extension,
|
|
isCubemap,
|
|
isGainmap
|
|
};
|
|
}
|
|
function getLoader(extension) {
|
|
const loader = extension === 'cube' ? CubeTextureLoader : extension === 'hdr' ? RGBELoader : extension === 'exr' ? EXRLoader : extension === 'jpg' || extension === 'jpeg' ? HDRJPGLoader : extension === 'webp' ? GainMapLoader : null;
|
|
return loader;
|
|
}
|
|
|
|
export { useEnvironment };
|