@forgeax/engine-vfx-render 0.1.3 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,3 @@
1
- import type { RenderFeatureMaterialShaderBindingContract } from '@forgeax/engine-render';
2
1
  import {
3
2
  err,
4
3
  type MaterialAsset,
@@ -157,13 +156,6 @@ export function particleMaterialPass(
157
156
  };
158
157
  }
159
158
 
160
- /** Scene-depth is a shader binding contract, not a renderer-kind convention. */
161
- export function particleMaterialUsesSceneDepth(
162
- contract: RenderFeatureMaterialShaderBindingContract | 'view-with-resource',
163
- ): boolean {
164
- return contract === 'group-0-resource' || contract === 'view-with-resource';
165
- }
166
-
167
159
  /** True when the authored particle shader consumes the standard material bind group. */
168
160
  export function particleMaterialUsesBindings(material: MaterialAsset | undefined): boolean {
169
161
  return (material?.parameters?.length ?? 0) > 0;
@@ -1,5 +1,8 @@
1
- import type { RenderFeatureGpuBindingsRef, RenderFeatureGpuDispatch } from '@forgeax/engine-render';
2
1
  import type { VfxGpuStageReflection } from '@forgeax/engine-vfx';
2
+ import type {
3
+ RenderFeatureGpuBindingsRef,
4
+ RenderFeatureGpuDispatch,
5
+ } from '../../../render/src/features/prepared-gpu-work.js';
3
6
 
4
7
  const MANAGED_STAGES = new Set(['spawn', 'update', 'scan', 'compact']);
5
8
  const RESOURCE_NAMES = new Set([
@@ -1,4 +1,5 @@
1
- import type { AssetRegistry } from '@forgeax/engine-assets-runtime';
1
+ import type { AssetRegistry as LegacyAssetRegistry } from '@forgeax/engine-assets-runtime';
2
+ import type { AssetRegistry as CoreAssetRegistry } from '@forgeax/engine-assets-runtime/internal';
2
3
  import {
3
4
  type AssetRegistryResolver,
4
5
  getAssetRegistryResolver,
@@ -21,6 +22,7 @@ import {
21
22
  VFX_GPU_RUNTIME_RESOURCE_KEY,
22
23
  type VfxGpuRuntime,
23
24
  vfxGpuEffectContribution,
25
+ vfxGpuEffectPackLoader,
24
26
  vfxGpuRuntimePlugin,
25
27
  } from '@forgeax/engine-vfx';
26
28
  import type { ParticleRenderCameraSource } from '../feature/camera.js';
@@ -30,6 +32,8 @@ import {
30
32
  type VfxDataInterfaceRegistry,
31
33
  } from './data-interface-providers.js';
32
34
 
35
+ type AssetRegistry = LegacyAssetRegistry | CoreAssetRegistry;
36
+
33
37
  export interface VfxRuntimeHostOptions {
34
38
  readonly camera: ParticleRenderCameraSource;
35
39
  readonly maxQueuedTicks?: number;
@@ -108,8 +112,8 @@ export interface VfxRuntimeHost {
108
112
  }): Promise<Result<{ readonly state: 'detached' | 'not-attached' }, VfxRuntimeHostError>>;
109
113
  }
110
114
 
111
- /** Install the VFX owner decoder into the one host registry. */
112
- export function installVfxRuntimeDecoder(registry: AssetRegistry): AssetDecoderLease {
115
+ /** Install the VFX owner decoder into the core registry. */
116
+ export function installVfxRuntimeDecoder(registry: CoreAssetRegistry): AssetDecoderLease {
113
117
  return registry.installDecoder(vfxGpuEffectContribution.kind, vfxGpuEffectContribution.decoder);
114
118
  }
115
119
 
@@ -142,7 +146,7 @@ function controlFailure(
142
146
  }
143
147
 
144
148
  export function createVfxRuntimeHost(options: VfxRuntimeHostOptions): VfxRuntimeHost {
145
- const decoderLeases = new WeakMap<AssetRegistry, AssetDecoderLease>();
149
+ const registries = new WeakSet<AssetRegistry>();
146
150
  const worlds = new WeakMap<
147
151
  World,
148
152
  {
@@ -169,12 +173,19 @@ export function createVfxRuntimeHost(options: VfxRuntimeHostOptions): VfxRuntime
169
173
  const key = `${kind}:${guid.toLowerCase()}`;
170
174
  const cached = attached.renderAssets.get(key);
171
175
  if (cached?.kind === kind) return cached as Kind extends 'material' ? MaterialAsset : MeshAsset;
176
+ if ('lookup' in attached.assets) {
177
+ const legacy = attached.assets.lookup(guid);
178
+ if (legacy?.kind === kind) {
179
+ attached.renderAssets.set(key, legacy);
180
+ return legacy as Kind extends 'material' ? MaterialAsset : MeshAsset;
181
+ }
182
+ }
172
183
  const resolved = attached.resolver?.lookup<MaterialAsset | MeshAsset>(guid);
173
184
  if (resolved?.kind === kind) {
174
185
  attached.renderAssets.set(key, resolved);
175
186
  return resolved as Kind extends 'material' ? MaterialAsset : MeshAsset;
176
187
  }
177
- if (!attached.pendingRenderAssets.has(key)) {
188
+ if ('load' in attached.assets && !attached.pendingRenderAssets.has(key)) {
178
189
  const epoch = attached.catalogEpoch;
179
190
  const request = attached.assets
180
191
  .load(guid, kind)
@@ -314,15 +325,20 @@ export function createVfxRuntimeHost(options: VfxRuntimeHostOptions): VfxRuntime
314
325
  dataInterfaces.resolve(requirements, generation),
315
326
  attachWorld: async ({ world, assets }) => {
316
327
  if (worlds.has(world)) return ok({ state: 'already-attached' });
317
- if (!decoderLeases.has(assets)) {
328
+ if (!registries.has(assets)) {
318
329
  try {
319
- decoderLeases.set(assets, installVfxRuntimeDecoder(assets));
330
+ if ('installDecoder' in assets) {
331
+ assets.installDecoder(vfxGpuEffectContribution.kind, vfxGpuEffectContribution.decoder);
332
+ } else {
333
+ assets.loaders.registerPackLoader(vfxGpuEffectPackLoader);
334
+ }
335
+ registries.add(assets);
320
336
  } catch (cause) {
321
337
  return err(
322
338
  failure(
323
339
  'vfx-host-loader-install-failed',
324
- 'the VFX owner decoder to be installed once in the runtime core',
325
- 'remove a conflicting particle-effect decoder and retry attachWorld',
340
+ 'the v2 VFX loader to be registered once',
341
+ 'remove a conflicting particle-effect loader and retry attachWorld',
326
342
  cause,
327
343
  ),
328
344
  );
@@ -346,10 +362,12 @@ export function createVfxRuntimeHost(options: VfxRuntimeHostOptions): VfxRuntime
346
362
  );
347
363
  }
348
364
  let resolver: AssetRegistryResolver | undefined;
349
- try {
350
- resolver = getAssetRegistryResolver(assets);
351
- } catch {
352
- resolver = undefined;
365
+ if ('installDecoder' in assets) {
366
+ try {
367
+ resolver = getAssetRegistryResolver(assets);
368
+ } catch {
369
+ resolver = undefined;
370
+ }
353
371
  }
354
372
  const attached = {
355
373
  assets,
@@ -359,14 +377,13 @@ export function createVfxRuntimeHost(options: VfxRuntimeHostOptions): VfxRuntime
359
377
  renderAssets: new Map<string, MaterialAsset | MeshAsset>(),
360
378
  pendingRenderAssets: new Map<string, Promise<void>>(),
361
379
  catalogEpoch:
362
- typeof (assets as { readonly snapshot?: unknown }).snapshot === 'function'
380
+ 'snapshot' in assets && typeof assets.snapshot === 'function'
363
381
  ? assets.snapshot().epoch
364
382
  : 0,
365
383
  unsubscribeAssets: () => {},
366
384
  };
367
- const subscribe = (assets as { readonly subscribe?: AssetRegistry['subscribe'] }).subscribe;
368
- if (subscribe !== undefined) {
369
- attached.unsubscribeAssets = subscribe((snapshot) => {
385
+ if ('subscribe' in assets && typeof assets.subscribe === 'function') {
386
+ attached.unsubscribeAssets = assets.subscribe((snapshot) => {
370
387
  if (snapshot.epoch === attached.catalogEpoch) return;
371
388
  attached.catalogEpoch = snapshot.epoch;
372
389
  attached.renderAssets.clear();
package/src/index.ts CHANGED
@@ -10,7 +10,6 @@ export {
10
10
  VFX_EVENT_COUNTER_BYTES,
11
11
  VFX_EVENT_INPUT_BYTES,
12
12
  } from './feature/event-resources.js';
13
- export type { VfxGpuRenderObservation } from './feature/gpu-particle-feature.js';
14
13
  export {
15
14
  createVfxRenderInspectSnapshot,
16
15
  gpuParticleRenderFeature,