@@ -11,6 +11,7 @@ import {
11
11
afterNextRender ,
12
12
computed ,
13
13
contentChild ,
14
+ effect ,
14
15
inject ,
15
16
input ,
16
17
output ,
@@ -165,6 +166,7 @@ export function injectEnvironment(
165
166
: firstEntry . startsWith ( 'data:image/jpeg' )
166
167
? 'jpg'
167
168
: firstEntry . split ( '.' ) . pop ( ) ?. split ( '?' ) ?. shift ( ) ?. toLowerCase ( ) ;
169
+
168
170
return { multiFile, extension, isCubeMap } ;
169
171
} ) ;
170
172
@@ -190,74 +192,79 @@ export function injectEnvironment(
190
192
return loader as typeof Loader ;
191
193
} ) ;
192
194
193
- const assertedInjector = inject ( Injector ) ;
194
- const autoEffect = injectAutoEffect ( ) ;
195
195
const store = injectStore ( ) ;
196
196
const gl = store . select ( 'gl' ) ;
197
197
198
198
const texture = signal < Texture | CubeTexture | null > ( null ) ;
199
- afterNextRender ( ( ) => {
200
- autoEffect ( ( ) => {
201
- const [ { extension, multiFile } , _files ] = [ untracked ( resultOptions ) , files ( ) ] ;
202
-
203
- if ( extension !== 'webp' && extension !== 'jpg' && extension !== 'jpeg' ) return ;
204
-
205
- gl ( ) . domElement . addEventListener (
206
- 'webglcontextlost' ,
207
- ( ) => {
208
- // @ts -expect-error - files is correctly passed
209
- injectLoader . clear ( multiFile ? [ _files ] : _files ) ;
210
- } ,
211
- { once : true } ,
212
- ) ;
213
- } ) ;
214
199
215
- const result = injectLoader (
216
- loader ,
217
- // @ts -expect-error - ensure the files is an array
200
+ effect ( ( ) => {
201
+ const [ { extension, multiFile } , _files ] = [ untracked ( resultOptions ) , files ( ) ] ;
202
+
203
+ if ( extension !== 'webp' && extension !== 'jpg' && extension !== 'jpeg' ) return ;
204
+
205
+ gl ( ) . domElement . addEventListener (
206
+ 'webglcontextlost' ,
218
207
( ) => {
219
- const { files } = adjustedOptions ( ) ;
220
- return Array . isArray ( files ) ? [ files ] : files ;
221
- } ,
222
- {
223
- injector : assertedInjector ,
224
- extensions : ( loader ) => {
225
- const { extensions, path } = adjustedOptions ( ) ;
226
- const { extension } = resultOptions ( ) ;
227
- if ( extension === 'webp' || extension === 'jpg' || extension === 'jpeg' ) {
228
- // @ts -expect-error - Gainmap requires a renderer
229
- loader . setRenderer ( gl ( ) ) ;
230
- }
231
-
232
- loader . setPath ?.( path ) ;
233
- if ( extensions ) extensions ( loader ) ;
234
- } ,
208
+ // @ts -expect-error - files is correctly passed
209
+ injectLoader . clear ( multiFile ? [ _files ] : _files ) ;
235
210
} ,
211
+ { once : true } ,
236
212
) ;
213
+ } ) ;
214
+
215
+ const result = injectLoader (
216
+ loader ,
217
+ // @ts -expect-error - ensure the files is an array
218
+ ( ) => {
219
+ const { files } = adjustedOptions ( ) ;
220
+ return Array . isArray ( files ) ? [ files ] : files ;
221
+ } ,
222
+ {
223
+ extensions : ( loader ) => {
224
+ const { extensions, path } = adjustedOptions ( ) ;
225
+ const { extension } = resultOptions ( ) ;
226
+ if ( extension === 'webp' || extension === 'jpg' || extension === 'jpeg' ) {
227
+ // @ts -expect-error - Gainmap requires a renderer
228
+ loader . setRenderer ( gl ( ) ) ;
229
+ }
230
+
231
+ loader . setPath ?.( path ) ;
232
+ if ( extensions ) extensions ( loader ) ;
233
+ } ,
234
+ } ,
235
+ ) ;
237
236
238
- autoEffect ( ( ) => {
239
- const loaderResult = result ( ) ;
240
- if ( ! loaderResult ) return ;
237
+ effect ( ( ) => {
238
+ const loaderResult = result ( ) ;
239
+ if ( ! loaderResult ) return ;
241
240
242
- untracked ( ( ) => {
243
- const { multiFile, extension, isCubeMap } = resultOptions ( ) ;
244
- const { encoding } = adjustedOptions ( ) ;
241
+ untracked ( ( ) => {
242
+ const { multiFile, extension, isCubeMap } = resultOptions ( ) ;
243
+ const { encoding } = adjustedOptions ( ) ;
245
244
246
- // @ts -expect-error - ensure textureResult is a Texture or CubeTexture
247
- let textureResult = ( multiFile ? loaderResult [ 0 ] : loaderResult ) as Texture | CubeTexture ;
245
+ // @ts -expect-error - ensure textureResult is a Texture or CubeTexture
246
+ let textureResult = ( multiFile ? loaderResult [ 0 ] : loaderResult ) as Texture | CubeTexture ;
248
247
249
- if ( extension === 'jpg' || extension === 'jpeg' || extension === 'webp' ) {
250
- textureResult = ( textureResult as any ) . renderTarget ?. texture ;
251
- }
248
+ // NOTE: racing condition, we can skip this
249
+ // we just said above that if multiFile is false, it is a single Texture
250
+ if ( ! multiFile && Array . isArray ( textureResult ) && textureResult [ 0 ] instanceof CubeTexture ) {
251
+ return ;
252
+ }
253
+
254
+ if (
255
+ ! ( textureResult instanceof CubeTexture ) &&
256
+ ( extension === 'jpg' || extension === 'jpeg' || extension === 'webp' )
257
+ ) {
258
+ textureResult = ( textureResult as any ) . renderTarget ?. texture ;
259
+ }
252
260
253
- textureResult . mapping = isCubeMap ? CubeReflectionMapping : EquirectangularReflectionMapping ;
261
+ textureResult . mapping = isCubeMap ? CubeReflectionMapping : EquirectangularReflectionMapping ;
254
262
255
- if ( 'colorSpace' in textureResult )
256
- ( textureResult as any ) . colorSpace = encoding ?? ( isCubeMap ? 'srgb' : 'srgb-linear' ) ;
257
- else ( textureResult as any ) . encoding = encoding ?? ( isCubeMap ? sRGBEncoding : LinearEncoding ) ;
263
+ if ( 'colorSpace' in textureResult )
264
+ ( textureResult as any ) . colorSpace = encoding ?? ( isCubeMap ? 'srgb' : 'srgb-linear' ) ;
265
+ else ( textureResult as any ) . encoding = encoding ?? ( isCubeMap ? sRGBEncoding : LinearEncoding ) ;
258
266
259
- texture . set ( textureResult ) ;
260
- } ) ;
267
+ texture . set ( textureResult ) ;
261
268
} ) ;
262
269
} ) ;
263
270
@@ -295,11 +302,11 @@ export class NgtsEnvironmentMap {
295
302
options = input ( defaultBackground , { transform : mergeInputs ( defaultBackground ) } ) ;
296
303
envSet = output < void > ( ) ;
297
304
298
- autoEffect = injectAutoEffect ( ) ;
299
- store = injectStore ( ) ;
300
- defaultScene = this . store . select ( 'scene' ) ;
305
+ private autoEffect = injectAutoEffect ( ) ;
306
+ private store = injectStore ( ) ;
307
+ private defaultScene = this . store . select ( 'scene' ) ;
301
308
302
- envConfig = computed ( ( ) => {
309
+ private envConfig = computed ( ( ) => {
303
310
const {
304
311
background = false ,
305
312
scene,
@@ -323,7 +330,7 @@ export class NgtsEnvironmentMap {
323
330
} ;
324
331
} ) ;
325
332
326
- map = pick ( this . options , 'map' ) ;
333
+ private map = pick ( this . options , 'map' ) ;
327
334
328
335
constructor ( ) {
329
336
afterNextRender ( ( ) => {
@@ -344,11 +351,12 @@ export class NgtsEnvironmentCube {
344
351
options = input ( defaultBackground , { transform : mergeInputs ( defaultBackground ) } ) ;
345
352
envSet = output < void > ( ) ;
346
353
347
- autoEffect = injectAutoEffect ( ) ;
348
- store = injectStore ( ) ;
349
- defaultScene = this . store . select ( 'scene' ) ;
354
+ private autoEffect = injectAutoEffect ( ) ;
355
+ private store = injectStore ( ) ;
356
+ private defaultScene = this . store . select ( 'scene' ) ;
357
+ private injector = inject ( Injector ) ;
350
358
351
- envConfig = computed ( ( ) => {
359
+ private envConfig = computed ( ( ) => {
352
360
const {
353
361
background = false ,
354
362
scene,
@@ -372,16 +380,12 @@ export class NgtsEnvironmentCube {
372
380
} ;
373
381
} ) ;
374
382
375
- environmentOptions = computed ( ( ) => {
376
- const { encoding, preset, files, path, extensions } = this . options ( ) ;
377
- return { encoding, preset, files, path, extensions } ;
378
- } ) ;
379
- texture = injectEnvironment ( this . environmentOptions ) ;
380
-
381
383
constructor ( ) {
382
384
afterNextRender ( ( ) => {
385
+ const _texture = injectEnvironment ( this . options , { injector : this . injector } ) ;
386
+
383
387
this . autoEffect ( ( ) => {
384
- const texture = this . texture ( ) ;
388
+ const texture = _texture ( ) ;
385
389
if ( ! texture ) return ;
386
390
const { background = false , scene, ...config } = this . envConfig ( ) ;
387
391
const cleanup = setEnvProps ( background , scene , this . defaultScene ( ) , texture , config ) ;
@@ -553,21 +557,35 @@ export class NgtsEnvironmentGround {
553
557
options = input ( { } as NgtsEnvironmentOptions ) ;
554
558
envSet = output < void > ( ) ;
555
559
556
- private defaultTexture = injectEnvironment ( this . options ) ;
557
- private texture = computed ( ( ) => this . options ( ) . map || this . defaultTexture ( ) ) ;
560
+ args = signal < [ Texture | null ] > ( [ null ] ) ;
558
561
559
- args = computed ( ( ) => [ this . texture ( ) ] ) ;
560
562
height = computed ( ( ) => ( this . options ( ) . ground as any ) ?. height ) ;
561
563
radius = computed ( ( ) => ( this . options ( ) . ground as any ) ?. radius ) ;
562
564
scale = computed ( ( ) => ( this . options ( ) . ground as any ) ?. scale ?? 1000 ) ;
563
565
564
566
envMapOptions = computed ( ( ) => {
565
567
const { map : _ , ...options } = this . options ( ) ;
566
- return Object . assign ( options , { map : this . texture ( ) } ) as NgtsEnvironmentOptions ;
568
+ const [ map ] = this . args ( ) ;
569
+ return Object . assign ( options , { map } ) as NgtsEnvironmentOptions ;
567
570
} ) ;
568
571
569
572
constructor ( ) {
570
573
extend ( { GroundProjectedEnv } ) ;
574
+
575
+ const injector = inject ( Injector ) ;
576
+ const autoEffect = injectAutoEffect ( ) ;
577
+
578
+ afterNextRender ( ( ) => {
579
+ const defaultTexture = injectEnvironment ( this . options , { injector } ) ;
580
+ const texture = computed ( ( ) => this . options ( ) . map || defaultTexture ( ) ) ;
581
+
582
+ autoEffect (
583
+ ( ) => {
584
+ this . args . set ( [ texture ( ) ] ) ;
585
+ } ,
586
+ { allowSignalWrites : true } ,
587
+ ) ;
588
+ } ) ;
571
589
}
572
590
}
573
591
0 commit comments