diff --git a/package.json b/package.json index b6ab3971f..193926200 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "dependencies": { "@babel/runtime": "^7.11.2", "@mediapipe/tasks-vision": "0.10.8", + "@monogrid/gainmap-js": "^3.0.4", "@react-spring/three": "~9.6.1", "@use-gesture/react": "^10.2.24", "camera-controls": "^2.4.2", diff --git a/src/core/useEnvironment.tsx b/src/core/useEnvironment.tsx index 6da57d590..037b8ac80 100644 --- a/src/core/useEnvironment.tsx +++ b/src/core/useEnvironment.tsx @@ -1,4 +1,4 @@ -import { useLoader } from '@react-three/fiber' +import { useLoader, useThree } from '@react-three/fiber' import { EquirectangularReflectionMapping, CubeTextureLoader, @@ -8,6 +8,7 @@ import { CubeTexture, } from 'three' import { RGBELoader, EXRLoader } from 'three-stdlib' +import { GainMapLoader, HDRJPGLoader } from '@monogrid/gainmap-js' import { presetsObj, PresetsType } from '../helpers/environment-assets' import { LinearEncoding, sRGBEncoding, TextureEncoding } from '../helpers/deprecated' @@ -30,7 +31,7 @@ export function useEnvironment({ extensions, }: Partial = {}) { let loader: typeof Loader | null = null - let isCubeMap: boolean = false + let multiFile: boolean = false let extension: string | false | undefined if (preset) { @@ -39,37 +40,65 @@ export function useEnvironment({ path = CUBEMAP_ROOT } + 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 - isCubeMap = isArray(files) - extension = isArray(files) + multiFile = isArray(files) + extension = isCubemap ? 'cube' - : files.startsWith('data:application/exr') + : isGainmap + ? 'webp' + : firstEntry.startsWith('data:application/exr') ? 'exr' - : files.startsWith('data:application/hdr') + : firstEntry.startsWith('data:application/hdr') ? 'hdr' - : files.split('.').pop()?.split('?')?.shift()?.toLowerCase() - loader = isCubeMap ? CubeTextureLoader : extension === 'hdr' ? RGBELoader : extension === 'exr' ? EXRLoader : null + : firstEntry.startsWith('data:image/jpeg') + ? 'jpg' + : firstEntry.split('.').pop()?.split('?')?.shift()?.toLowerCase() + loader = + extension === 'cube' + ? CubeTextureLoader + : extension === 'hdr' + ? RGBELoader + : extension === 'exr' + ? EXRLoader + : extension === 'jpg' || extension === 'jpeg' + ? (HDRJPGLoader as unknown as typeof Loader) + : extension === 'webp' + ? (GainMapLoader as unknown as typeof Loader) + : null if (!loader) throw new Error('useEnvironment: Unrecognized file extension: ' + files) + const gl = useThree((state) => state.gl) const loaderResult: Texture | Texture[] = useLoader( // @ts-expect-error loader, - isCubeMap ? [files] : files, + multiFile ? [files] : files, (loader) => { + // Gainmap requires a renderer + if (extension === 'webp' || extension === 'jpg' || extension === 'jpeg') { + loader.setRenderer(gl) + } loader.setPath?.(path) if (extensions) extensions(loader) } ) as Texture | Texture[] - const texture: Texture | CubeTexture = isCubeMap + let texture: Texture | CubeTexture = multiFile ? // @ts-ignore loaderResult[0] : loaderResult - texture.mapping = isCubeMap ? CubeReflectionMapping : EquirectangularReflectionMapping + if (extension === 'jpg' || extension === 'jpeg' || extension === 'webp') { + texture = (texture as any).renderTarget?.texture + } + + texture.mapping = isCubemap ? CubeReflectionMapping : EquirectangularReflectionMapping - if ('colorSpace' in texture) (texture as any).colorSpace = encoding ?? isCubeMap ? 'srgb' : 'srgb-linear' - else (texture as any).encoding = encoding ?? isCubeMap ? sRGBEncoding : LinearEncoding + if ('colorSpace' in texture) (texture as any).colorSpace = encoding ?? isCubemap ? 'srgb' : 'srgb-linear' + else (texture as any).encoding = encoding ?? isCubemap ? sRGBEncoding : LinearEncoding return texture } diff --git a/yarn.lock b/yarn.lock index b7c954a80..4ca69f145 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1880,6 +1880,13 @@ resolved "https://registry.yarnpkg.com/@mediapipe/tasks-vision/-/tasks-vision-0.10.8.tgz#a78e137018a19933b7a1d0e887d553d4ab833d10" integrity sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q== +"@monogrid/gainmap-js@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@monogrid/gainmap-js/-/gainmap-js-3.0.4.tgz#f822dcf208cadf7f97c1246c4e60cf0c68f304e6" + integrity sha512-6EDkW+z4wpiMfISRcWkqGiEOD73RG3rPvlIMAwrQ0xbnRTcyjNVsoKcOhm2OpXTD83fYWJO2bXMVYVdBx5m2hg== + dependencies: + promise-worker-transferable "^1.0.4" + "@ndelangen/get-tarball@^3.0.7": version "3.0.9" resolved "https://registry.yarnpkg.com/@ndelangen/get-tarball/-/get-tarball-3.0.9.tgz#727ff4454e65f34707e742a59e5e6b1f525d8964" @@ -7989,6 +7996,11 @@ ignore@^5.1.4, ignore@^5.2.0, ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -8404,6 +8416,11 @@ is-port-reachable@4.0.0: resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d" integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig== +is-promise@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + is-reference@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" @@ -9394,6 +9411,13 @@ libnpmversion@^4.0.2: proc-log "^3.0.0" semver "^7.3.7" +lie@^3.0.2: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + lil-gui@~0.17.0: version "0.17.0" resolved "https://registry.yarnpkg.com/lil-gui/-/lil-gui-0.17.0.tgz#b41ae55d0023fcd9185f7395a218db0f58189663" @@ -11204,6 +11228,14 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" +promise-worker-transferable@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz#2c72861ba053e5ae42b487b4a83b1ed3ae3786e8" + integrity sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw== + dependencies: + is-promise "^2.1.0" + lie "^3.0.2" + prompts@^2.0.1, prompts@^2.4.0: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"