@forgeax/engine-app 0.1.4 → 0.1.7
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.
- package/README.md +20 -14
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/create-app-error-retention.integration.test.d.ts +2 -0
- package/dist/__tests__/create-app-error-retention.integration.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-physics-plugin-failure.integration.test.d.ts +2 -0
- package/dist/__tests__/create-app-physics-plugin-failure.integration.test.d.ts.map +1 -0
- package/dist/animation-asset-lookup.d.ts +1 -2
- package/dist/animation-asset-lookup.d.ts.map +1 -1
- package/dist/browser-frame-signal.d.ts +17 -0
- package/dist/browser-frame-signal.d.ts.map +1 -0
- package/dist/create-app.d.ts +31 -10
- package/dist/create-app.d.ts.map +1 -1
- package/dist/engine-worker-runtime.mjs +72 -129
- package/dist/engine-worker-runtime.mjs.map +1 -1
- package/dist/errors.d.ts +3 -12
- package/dist/errors.d.ts.map +1 -1
- package/dist/execution/attached-world-swap.d.ts +1 -12
- package/dist/execution/attached-world-swap.d.ts.map +1 -1
- package/dist/execution/bootstrap-url.d.ts +5 -0
- package/dist/execution/bootstrap-url.d.ts.map +1 -0
- package/dist/execution/control.d.ts +0 -2
- package/dist/execution/control.d.ts.map +1 -1
- package/dist/execution/engine-worker.d.ts +1 -0
- package/dist/execution/engine-worker.d.ts.map +1 -1
- package/dist/execution/host-controller.d.ts.map +1 -1
- package/dist/execution/index.d.ts +1 -1
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/protocol.d.ts +4 -1
- package/dist/execution/protocol.d.ts.map +1 -1
- package/dist/execution/types.d.ts +17 -1
- package/dist/execution/types.d.ts.map +1 -1
- package/dist/game-context.d.ts +1 -1
- package/dist/game-context.d.ts.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +357 -359
- package/dist/index.mjs.map +1 -1
- package/dist/internal/assembled-engine-profile.d.ts.map +1 -1
- package/dist/internal/assets-world-plugin.d.ts +3 -17
- package/dist/internal/assets-world-plugin.d.ts.map +1 -1
- package/dist/internal/browser-remote-bridge.d.ts +1 -2
- package/dist/internal/browser-remote-bridge.d.ts.map +1 -1
- package/dist/internal/browser-rhi-debug-runtime.d.ts +1 -1
- package/dist/internal/browser-rhi-debug-runtime.d.ts.map +1 -1
- package/dist/internal/debug-draw.d.ts +9 -0
- package/dist/internal/debug-draw.d.ts.map +1 -0
- package/dist/internal/engine-profile-common.d.ts +2 -2
- package/dist/internal/engine-profile-common.d.ts.map +1 -1
- package/dist/internal/frame-loop.d.ts +7 -4
- package/dist/internal/frame-loop.d.ts.map +1 -1
- package/dist/internal/main-engine-profile.d.ts +4 -0
- package/dist/internal/main-engine-profile.d.ts.map +1 -1
- package/dist/internal/remote-serve-flag.d.ts +3 -7
- package/dist/internal/remote-serve-flag.d.ts.map +1 -1
- package/dist/internal/rhi-capture.d.ts +1 -1
- package/dist/internal/rhi-capture.d.ts.map +1 -1
- package/dist/internal/worker-engine-profile.d.ts +2 -0
- package/dist/internal/worker-engine-profile.d.ts.map +1 -1
- package/dist/renderer-plugin.d.ts +25 -0
- package/dist/renderer-plugin.d.ts.map +1 -0
- package/dist/tool-preview/bootstrap.d.ts.map +1 -1
- package/dist/types.d.ts +21 -61
- package/dist/types.d.ts.map +1 -1
- package/package.json +25 -26
- package/src/__tests__/callback-inference.test-d.ts +7 -3
- package/src/__tests__/consumer-migration.unit.test.ts +13 -0
- package/src/__tests__/create-app-error-retention.integration.test.ts +125 -0
- package/src/__tests__/create-app-features.test.ts +21 -10
- package/src/__tests__/create-app-listener-sync.test.ts +23 -19
- package/src/__tests__/create-app-physics-plugin-failure.integration.test.ts +142 -0
- package/src/__tests__/create-app-stop.test.ts +4 -12
- package/src/__tests__/create-app.test-d.ts +12 -11
- package/src/__tests__/create-app.test.ts +1 -60
- package/src/__tests__/create-renderer-error.integration.test.ts +3 -2
- package/src/__tests__/create-renderer-lifecycle.integration.test.ts +10 -5
- package/src/__tests__/draw-source-injected-world-update-visibility.test.ts +7 -13
- package/src/__tests__/draw-source-single-world-regression.test.ts +23 -24
- package/src/__tests__/engine-worker-bootstrap-channel.unit.test.ts +8 -0
- package/src/__tests__/engine-worker-world-swap.unit.test.ts +15 -22
- package/src/__tests__/errors-pointer-lock-failed.test.ts +4 -7
- package/src/__tests__/execution-bootstrap-isolation.unit.test.ts +5 -6
- package/src/__tests__/execution-frame-order.unit.test.ts +2 -2
- package/src/__tests__/execution-frame-protocol.unit.test.ts +3 -4
- package/src/__tests__/execution-public-api.test-d.ts +4 -0
- package/src/__tests__/frame-loop-time-elapsed.test.ts +1 -1
- package/src/__tests__/frame-loop-time.unit.test.ts +1 -1
- package/src/__tests__/frame-loop-world-array.test.ts +82 -73
- package/src/__tests__/plugin-profiles.unit.test.ts +3 -3
- package/src/__tests__/profiler-default-off.test.ts +1 -1
- package/src/__tests__/profiler-frame-token.test.ts +17 -30
- package/src/__tests__/profiler-phase-integration.test.ts +15 -27
- package/src/__tests__/surface-handoff.test.ts +1 -4
- package/src/__tests__/visibility-remote.integration.test.ts +2 -5
- package/src/__tests__/worker-execution-stop.test.ts +64 -7
- package/src/animation-asset-lookup.ts +2 -2
- package/src/browser-frame-signal.ts +44 -0
- package/src/create-app.ts +208 -295
- package/src/errors.ts +27 -39
- package/src/execution/attached-world-swap.ts +4 -38
- package/src/execution/bootstrap-url.ts +25 -0
- package/src/execution/control.ts +3 -7
- package/src/execution/engine-worker-runtime.ts +23 -40
- package/src/execution/engine-worker.ts +2 -0
- package/src/execution/host-controller.ts +8 -2
- package/src/execution/index.ts +1 -0
- package/src/execution/protocol.ts +4 -1
- package/src/execution/types.ts +18 -1
- package/src/game-context.ts +1 -1
- package/src/index.ts +18 -4
- package/src/internal/assembled-engine-profile.ts +3 -11
- package/src/internal/assets-world-plugin.ts +7 -53
- package/src/internal/browser-remote-bridge.ts +2 -3
- package/src/internal/browser-rhi-debug-runtime.ts +1 -1
- package/src/internal/debug-draw.ts +38 -0
- package/src/internal/engine-profile-common.ts +2 -3
- package/src/internal/frame-loop.ts +77 -63
- package/src/internal/main-engine-profile.ts +21 -17
- package/src/internal/remote-serve-flag.ts +5 -14
- package/src/internal/rhi-capture.ts +1 -1
- package/src/internal/worker-engine-profile.ts +10 -10
- package/src/renderer-plugin.ts +96 -0
- package/src/tool-preview/bootstrap.ts +1 -14
- package/src/types.ts +22 -77
- package/src/vite-env.d.ts +0 -2
- package/dist/__tests__/app-rebuild.test.d.ts +0 -2
- package/dist/__tests__/app-rebuild.test.d.ts.map +0 -1
- package/dist/__tests__/asset-registry-types.test-d.d.ts +0 -2
- package/dist/__tests__/asset-registry-types.test-d.d.ts.map +0 -1
- package/dist/__tests__/assets-runtime-assembly.integration.test.d.ts +0 -2
- package/dist/__tests__/assets-runtime-assembly.integration.test.d.ts.map +0 -1
- package/dist/__tests__/draw-source-headless-full-chain.test.d.ts +0 -2
- package/dist/__tests__/draw-source-headless-full-chain.test.d.ts.map +0 -1
- package/dist/__tests__/ecs-import.unit.test.d.ts +0 -2
- package/dist/__tests__/ecs-import.unit.test.d.ts.map +0 -1
- package/dist/__tests__/execution-world-health-owner.test-d.d.ts +0 -2
- package/dist/__tests__/execution-world-health-owner.test-d.d.ts.map +0 -1
- package/dist/__tests__/remote-serve-flag.test.d.ts +0 -2
- package/dist/__tests__/remote-serve-flag.test.d.ts.map +0 -1
- package/dist/assets-runtime-assembly.d.ts +0 -19
- package/dist/assets-runtime-assembly.d.ts.map +0 -1
- package/src/__tests__/app-rebuild.test.ts +0 -31
- package/src/__tests__/asset-registry-types.test-d.ts +0 -16
- package/src/__tests__/assets-runtime-assembly.integration.test.ts +0 -68
- package/src/__tests__/draw-source-headless-full-chain.test.ts +0 -226
- package/src/__tests__/ecs-import.unit.test.ts +0 -40
- package/src/__tests__/execution-world-health-owner.test-d.ts +0 -9
- package/src/__tests__/remote-serve-flag.test.ts +0 -24
- package/src/assets-runtime-assembly.ts +0 -70
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { Update, World, createWorldContext, componentDefinition } from '@forgeax/engine-ecs';
|
|
2
2
|
export { Context } from '@forgeax/engine-plugin';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import { err, ok } from '@forgeax/engine-types';
|
|
6
|
-
import { createAssetRegistry, createCatalogSource } from '@forgeax/engine-assets-runtime';
|
|
7
|
-
import { getAssetRegistryResolver } from '@forgeax/engine-assets-runtime/internal';
|
|
8
|
-
import { loadRhiPack, createDebugDrawOnReady, releaseDebugDraw } from '@forgeax/engine-render/internal';
|
|
3
|
+
export { createFullscreenRenderFeature } from '@forgeax/engine-render/authoring';
|
|
4
|
+
import { Camera, perspective, renderComponentsPlugin, CAMERA_PROJECTION_PERSPECTIVE } from '@forgeax/engine-render';
|
|
9
5
|
import { RhiError } from '@forgeax/engine-rhi';
|
|
10
|
-
import {
|
|
6
|
+
import { attachRecorder, decodeTape, openReplay, decodeToRgba8, buildTapeIndex, createRhiDebugError } from '@forgeax/engine-rhi-debug';
|
|
7
|
+
import * as engineRuntimeModule from '@forgeax/engine-runtime';
|
|
8
|
+
import { EngineEnvironmentError } from '@forgeax/engine-runtime';
|
|
9
|
+
import { loadRhiPack, constructRuntimeRendererHost } from '@forgeax/engine-runtime/internal/renderer-host';
|
|
10
|
+
import { ok, err } from '@forgeax/engine-types';
|
|
11
11
|
import { createHostAudioConsumer } from '@forgeax/engine-audio-webaudio';
|
|
12
12
|
import { INPUT_BACKEND_KEY, InputSet, InputFrameStartScan, attachBrowserInputBackend, inputBackendPlugin, ownedInputBackendPlugin, INPUT_MAP_KEY } from '@forgeax/engine-input';
|
|
13
13
|
import { componentSchema } from '@forgeax/engine-ecs/internal';
|
|
14
14
|
import { animationPayloadsPlugin, animationRuntimePlugin } from '@forgeax/engine-animation';
|
|
15
15
|
import { Transform, scenePlugin } from '@forgeax/engine-scene';
|
|
16
16
|
import { statePlugin } from '@forgeax/engine-state';
|
|
17
|
-
import {
|
|
17
|
+
import { createDebugDraw } from '@forgeax/engine-debug-draw';
|
|
18
18
|
import { createProfiler } from '@forgeax/engine-profiler';
|
|
19
19
|
import { isSerializableValue, createPreviewArtifactManifest, validatePreviewArtifactManifest, createArtifactRef, snapshotStaleError } from '@forgeax/engine-tool-runtime';
|
|
20
20
|
|
|
@@ -216,66 +216,34 @@ var init_browser_remote_bridge = __esm({
|
|
|
216
216
|
init_ecs_import();
|
|
217
217
|
}
|
|
218
218
|
});
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
} catch (cause) {
|
|
242
|
-
for (const lease of leases) lease.dispose();
|
|
243
|
-
const failed = assembledContributions[leases.length];
|
|
244
|
-
return err({
|
|
245
|
-
code: "asset-assembly-failed",
|
|
246
|
-
expected: "each owner decoder contribution to install exactly once in the realm registry",
|
|
247
|
-
hint: "remove the conflicting owner contribution and assemble the current realm again",
|
|
248
|
-
detail: { kind: failed?.kind.kind ?? "unknown", cause }
|
|
249
|
-
});
|
|
219
|
+
|
|
220
|
+
// src/browser-frame-signal.ts
|
|
221
|
+
var FORGEAX_FRAME_SUBMITTED_DATASET = "forgeaxFrameSubmitted";
|
|
222
|
+
var FORGEAX_FRAME_SUBMITTED_EVENT = "forgeax:frame-submitted";
|
|
223
|
+
function resetBrowserFrameSubmitted(canvas) {
|
|
224
|
+
const documentElement = canvas.ownerDocument?.documentElement;
|
|
225
|
+
if (documentElement !== void 0) {
|
|
226
|
+
delete documentElement.dataset[FORGEAX_FRAME_SUBMITTED_DATASET];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function publishBrowserFrameSubmitted(canvas, event) {
|
|
230
|
+
const documentElement = canvas.ownerDocument?.documentElement;
|
|
231
|
+
if (documentElement !== void 0) {
|
|
232
|
+
documentElement.dataset[FORGEAX_FRAME_SUBMITTED_DATASET] = String(event.frameId);
|
|
233
|
+
}
|
|
234
|
+
if (typeof CustomEvent === "function" && typeof canvas.dispatchEvent === "function") {
|
|
235
|
+
canvas.dispatchEvent(
|
|
236
|
+
new CustomEvent(FORGEAX_FRAME_SUBMITTED_EVENT, {
|
|
237
|
+
detail: Object.freeze({ ...event })
|
|
238
|
+
})
|
|
239
|
+
);
|
|
250
240
|
}
|
|
251
|
-
let disposed = false;
|
|
252
|
-
return ok({
|
|
253
|
-
registry,
|
|
254
|
-
leases: Object.freeze([...leases]),
|
|
255
|
-
dispose() {
|
|
256
|
-
if (disposed) return;
|
|
257
|
-
disposed = true;
|
|
258
|
-
for (const lease of leases) lease.dispose();
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
241
|
}
|
|
262
242
|
|
|
263
243
|
// src/animation-asset-lookup.ts
|
|
264
244
|
function createAnimationPayloadLookup(source) {
|
|
265
245
|
return (guid) => source?.lookup(guid);
|
|
266
246
|
}
|
|
267
|
-
function syncCameraAspect(world, canvasW, canvasH) {
|
|
268
|
-
if (canvasW <= 0 || canvasH <= 0) return;
|
|
269
|
-
const aspect = canvasW / canvasH;
|
|
270
|
-
const query = world.query({ with: [Camera] }).unwrap();
|
|
271
|
-
for (const row of query) {
|
|
272
|
-
const camera = world.get(row.entity, Camera);
|
|
273
|
-
if (!camera.ok) continue;
|
|
274
|
-
if (camera.value.autoAspect !== true) continue;
|
|
275
|
-
if (camera.value.projection !== CAMERA_PROJECTION_PERSPECTIVE) continue;
|
|
276
|
-
world.set(row.entity, Camera, { aspect });
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
247
|
|
|
280
248
|
// src/errors.ts
|
|
281
249
|
function summarizeCause(cause) {
|
|
@@ -338,10 +306,6 @@ var appErrorPolicy = {
|
|
|
338
306
|
expected: "canvas.isConnected === true at createApp(canvas) entry",
|
|
339
307
|
hint: "append the canvas to the document tree before calling createApp(canvas), or use the assemble entry createApp({ renderer, world }) when the host already manages canvas lifetime"
|
|
340
308
|
},
|
|
341
|
-
"app-invalid-canvas-pixel-ratio": {
|
|
342
|
-
expected: "maxCanvasPixelRatio is finite and greater than 0",
|
|
343
|
-
hint: "omit maxCanvasPixelRatio to keep the device pixel ratio, or pass a finite value > 0 from the Host policy"
|
|
344
|
-
},
|
|
345
309
|
"app-frame-step-invalid": {
|
|
346
310
|
expected: "stepFrame(deltaSeconds) runs only while the App is paused and deltaSeconds is finite and non-negative",
|
|
347
311
|
hint: "pause the App before deterministic stepping and pass an explicit finite delta; resume after the bounded step sequence completes"
|
|
@@ -737,20 +701,17 @@ function createLocalExecutionControl(initial, providers = {}) {
|
|
|
737
701
|
world: providers.world?.() ?? current.world,
|
|
738
702
|
audio: executionAudioReport(providers.audio?.())
|
|
739
703
|
}),
|
|
740
|
-
rebuild: async () =>
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
})
|
|
752
|
-
);
|
|
753
|
-
}
|
|
704
|
+
rebuild: async () => err(
|
|
705
|
+
new AppError({
|
|
706
|
+
code: "app-execution-rebuild-failed",
|
|
707
|
+
expected: APP_EXPECTED["app-execution-rebuild-failed"],
|
|
708
|
+
hint: APP_ERROR_HINTS["app-execution-rebuild-failed"],
|
|
709
|
+
detail: {
|
|
710
|
+
worldIdentity: current.world.identity,
|
|
711
|
+
cause: new Error("This local assembly has no bootstrap module.")
|
|
712
|
+
}
|
|
713
|
+
})
|
|
714
|
+
)
|
|
754
715
|
};
|
|
755
716
|
}
|
|
756
717
|
var ENGINE_WORKER_CAPABILITIES = [
|
|
@@ -825,6 +786,25 @@ function selectExecutionTier(input) {
|
|
|
825
786
|
sharedEvidencePassed: input.sharedEvidencePassed
|
|
826
787
|
});
|
|
827
788
|
}
|
|
789
|
+
function normalizeExecutionBootstrapUrl(bootstrap) {
|
|
790
|
+
const moduleUrl = typeof bootstrap === "string" ? bootstrap : bootstrap.href;
|
|
791
|
+
try {
|
|
792
|
+
return ok(new URL(bootstrap, globalThis.location?.href).href);
|
|
793
|
+
} catch (cause) {
|
|
794
|
+
return err(
|
|
795
|
+
new AppError({
|
|
796
|
+
code: "app-execution-bootstrap-failed",
|
|
797
|
+
expected: APP_EXPECTED["app-execution-bootstrap-failed"],
|
|
798
|
+
hint: APP_ERROR_HINTS["app-execution-bootstrap-failed"],
|
|
799
|
+
detail: {
|
|
800
|
+
phase: "prepare",
|
|
801
|
+
moduleUrl,
|
|
802
|
+
cause: cause instanceof TypeError ? cause : new TypeError(String(cause))
|
|
803
|
+
}
|
|
804
|
+
})
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
828
808
|
|
|
829
809
|
// src/internal/error-fanout.ts
|
|
830
810
|
var ErrorFanoutRegistry = class {
|
|
@@ -974,6 +954,7 @@ async function startEngineWorker(options) {
|
|
|
974
954
|
bootstrapUrl: options.bootstrapUrl,
|
|
975
955
|
...options.bootstrapData === void 0 ? {} : { bootstrapData: options.bootstrapData },
|
|
976
956
|
...options.bootstrapPort === void 0 ? {} : { bootstrapPort: options.bootstrapPort },
|
|
957
|
+
...options.assetCatalog === void 0 ? {} : { assetCatalog: options.assetCatalog },
|
|
977
958
|
...options.shaderManifestUrl !== void 0 ? { shaderManifestUrl: options.shaderManifestUrl } : {},
|
|
978
959
|
...options.time !== void 0 ? { time: options.time } : {},
|
|
979
960
|
tier: options.tier
|
|
@@ -1044,7 +1025,7 @@ var FrameCreditLedger = class {
|
|
|
1044
1025
|
nextFrameId = 1;
|
|
1045
1026
|
inFlight = null;
|
|
1046
1027
|
completed = 0;
|
|
1047
|
-
issue(deltaSeconds, sampleInput, canvasSize) {
|
|
1028
|
+
issue(deltaSeconds, sampleInput, canvasSize = { width: 0, height: 0 }) {
|
|
1048
1029
|
if (this.inFlight !== null) return void 0;
|
|
1049
1030
|
const frameId = this.nextFrameId;
|
|
1050
1031
|
this.nextFrameId += 1;
|
|
@@ -1106,15 +1087,18 @@ function runtimeError(message) {
|
|
|
1106
1087
|
async function createWorkerExecutionApp(options) {
|
|
1107
1088
|
const executionOptions = options.appOptions.execution;
|
|
1108
1089
|
if (executionOptions === void 0) throw new Error("execution options are required");
|
|
1109
|
-
const
|
|
1110
|
-
|
|
1090
|
+
const normalizedBootstrap = normalizeExecutionBootstrapUrl(executionOptions.bootstrap);
|
|
1091
|
+
if (!normalizedBootstrap.ok) return normalizedBootstrap;
|
|
1092
|
+
const bootstrapUrl = normalizedBootstrap.value;
|
|
1111
1093
|
const startupTimeoutMs = executionOptions.startupTimeoutMs ?? 1e4;
|
|
1112
1094
|
const frameTimeoutMs = executionOptions.frameTimeoutMs ?? 2e3;
|
|
1095
|
+
const syncCanvas = options.syncCanvas;
|
|
1113
1096
|
const started = await startEngineWorker({
|
|
1114
1097
|
canvas: options.canvas,
|
|
1115
1098
|
bootstrapUrl,
|
|
1116
1099
|
...executionOptions.bootstrapData === void 0 ? {} : { bootstrapData: executionOptions.bootstrapData },
|
|
1117
1100
|
...executionOptions.bootstrapPort === void 0 ? {} : { bootstrapPort: executionOptions.bootstrapPort },
|
|
1101
|
+
...executionOptions.assetCatalog === void 0 ? {} : { assetCatalog: executionOptions.assetCatalog },
|
|
1118
1102
|
...options.bundler?.shaderManifestUrl !== void 0 ? { shaderManifestUrl: options.bundler.shaderManifestUrl } : {},
|
|
1119
1103
|
...options.appOptions.time !== void 0 ? { time: options.appOptions.time } : {},
|
|
1120
1104
|
timeoutMs: startupTimeoutMs,
|
|
@@ -1450,61 +1434,99 @@ async function createWorkerExecutionApp(options) {
|
|
|
1450
1434
|
return ok(app);
|
|
1451
1435
|
}
|
|
1452
1436
|
|
|
1453
|
-
// src/
|
|
1454
|
-
|
|
1455
|
-
var ASSET_REGISTRY_RESOURCE_KEY = "AssetRegistry";
|
|
1456
|
-
function rendererAssetsPlugin() {
|
|
1437
|
+
// src/renderer-plugin.ts
|
|
1438
|
+
function createRenderFeatureHost(host) {
|
|
1457
1439
|
return {
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1440
|
+
async installFeature(feature) {
|
|
1441
|
+
const installed = await host.installRenderFeature(feature);
|
|
1442
|
+
if (!installed.ok) return installed;
|
|
1443
|
+
let released = false;
|
|
1444
|
+
return {
|
|
1445
|
+
ok: true,
|
|
1446
|
+
value: {
|
|
1447
|
+
release: async () => {
|
|
1448
|
+
if (released) return { ok: true, value: void 0 };
|
|
1449
|
+
released = true;
|
|
1450
|
+
return host.uninstallRenderFeature(feature);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
function rendererPlugin(renderer) {
|
|
1458
|
+
return {
|
|
1459
|
+
name: "renderer",
|
|
1460
|
+
provide: "renderer",
|
|
1461
1461
|
apply(ctx) {
|
|
1462
|
-
|
|
1463
|
-
ctx.provide("assets", ctx.renderer.assets);
|
|
1462
|
+
ctx.provide("renderer", renderer);
|
|
1464
1463
|
}
|
|
1465
1464
|
};
|
|
1466
1465
|
}
|
|
1467
|
-
function
|
|
1466
|
+
function ownedRendererPlugin(renderer) {
|
|
1468
1467
|
return {
|
|
1469
|
-
name: "
|
|
1470
|
-
provide: "
|
|
1468
|
+
name: "renderer",
|
|
1469
|
+
provide: "renderer",
|
|
1471
1470
|
apply(ctx) {
|
|
1472
|
-
ctx.provide("
|
|
1471
|
+
ctx.provide("renderer", renderer);
|
|
1472
|
+
ctx.effect(() => () => renderer.dispose(), "render/renderer");
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
function renderFeatureHostPlugin(host) {
|
|
1477
|
+
return {
|
|
1478
|
+
name: "render-feature-host",
|
|
1479
|
+
provide: "renderFeatureHost",
|
|
1480
|
+
apply(ctx) {
|
|
1481
|
+
ctx.provide("renderFeatureHost", host);
|
|
1482
|
+
}
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
function renderFeaturePlugin(feature) {
|
|
1486
|
+
return {
|
|
1487
|
+
name: `render-feature:${feature.identity}`,
|
|
1488
|
+
inject: ["renderFeatureHost"],
|
|
1489
|
+
async apply(ctx) {
|
|
1490
|
+
if (ctx.renderFeatureHost === void 0) {
|
|
1491
|
+
throw new Error("render-feature host capability is unavailable in this App realm");
|
|
1492
|
+
}
|
|
1493
|
+
const installed = await ctx.renderFeatureHost.installFeature(feature);
|
|
1494
|
+
if (!installed.ok) throw installed.error;
|
|
1473
1495
|
ctx.effect(
|
|
1474
|
-
() => () => {
|
|
1475
|
-
|
|
1476
|
-
|
|
1496
|
+
() => async () => {
|
|
1497
|
+
const removed = await installed.value.release();
|
|
1498
|
+
if (!removed.ok) throw removed.error;
|
|
1477
1499
|
},
|
|
1478
|
-
|
|
1500
|
+
`render-feature/${feature.identity}`
|
|
1479
1501
|
);
|
|
1480
1502
|
}
|
|
1481
1503
|
};
|
|
1482
1504
|
}
|
|
1483
|
-
|
|
1505
|
+
|
|
1506
|
+
// src/internal/assets-world-plugin.ts
|
|
1507
|
+
var ASSET_REGISTRY_RESOURCE_KEY = "AssetRegistry";
|
|
1508
|
+
function rendererAssetsPlugin(assets) {
|
|
1484
1509
|
return {
|
|
1485
|
-
name: "assets
|
|
1486
|
-
inject: ["
|
|
1510
|
+
name: "renderer-assets",
|
|
1511
|
+
inject: ["renderer"],
|
|
1512
|
+
provide: "assets",
|
|
1487
1513
|
apply(ctx) {
|
|
1488
|
-
ctx.
|
|
1489
|
-
ctx.world.insertResource(RENDER_ASSET_PORT_RESOURCE_KEY, ctx.assets);
|
|
1490
|
-
return () => {
|
|
1491
|
-
ctx.world.removeResource(RENDER_ASSET_PORT_RESOURCE_KEY);
|
|
1492
|
-
};
|
|
1493
|
-
}, "assets/world-render-projection");
|
|
1514
|
+
if (assets !== void 0) ctx.provide("assets", assets);
|
|
1494
1515
|
}
|
|
1495
1516
|
};
|
|
1496
1517
|
}
|
|
1497
|
-
function
|
|
1518
|
+
function assetsWorldPlugin() {
|
|
1498
1519
|
return {
|
|
1499
|
-
name: "
|
|
1500
|
-
inject: ["world", "
|
|
1520
|
+
name: "assets-world",
|
|
1521
|
+
inject: ["world", "assets"],
|
|
1501
1522
|
apply(ctx) {
|
|
1523
|
+
if (ctx.assets === void 0) return;
|
|
1502
1524
|
ctx.effect(() => {
|
|
1503
|
-
ctx.world.insertResource(ASSET_REGISTRY_RESOURCE_KEY, ctx.
|
|
1525
|
+
ctx.world.insertResource(ASSET_REGISTRY_RESOURCE_KEY, ctx.assets);
|
|
1504
1526
|
return () => {
|
|
1505
1527
|
ctx.world.removeResource(ASSET_REGISTRY_RESOURCE_KEY);
|
|
1506
1528
|
};
|
|
1507
|
-
}, "assets/world-
|
|
1529
|
+
}, "assets/world-resource");
|
|
1508
1530
|
}
|
|
1509
1531
|
};
|
|
1510
1532
|
}
|
|
@@ -1513,8 +1535,7 @@ function assetRegistryWorldPlugin() {
|
|
|
1513
1535
|
function assembledEngineProfile(options) {
|
|
1514
1536
|
return [
|
|
1515
1537
|
rendererPlugin(options.renderer),
|
|
1516
|
-
rendererAssetsPlugin(),
|
|
1517
|
-
...options.assetAssembly === void 0 ? [] : [assetRegistryPlugin(options.assetAssembly), assetRegistryWorldPlugin()],
|
|
1538
|
+
rendererAssetsPlugin(options.assets),
|
|
1518
1539
|
assetsWorldPlugin(),
|
|
1519
1540
|
...options.extensions ?? []
|
|
1520
1541
|
];
|
|
@@ -1677,7 +1698,6 @@ function resolveCaf(opts) {
|
|
|
1677
1698
|
}
|
|
1678
1699
|
function createFrameLoop(opts) {
|
|
1679
1700
|
const { world, renderer } = opts;
|
|
1680
|
-
const primaryDrawWorlds = [world];
|
|
1681
1701
|
const phaseCatalogRegistration = opts.profiler?.registerPhaseCatalog("app", APP_PHASE_CATALOG);
|
|
1682
1702
|
let releasePhaseCatalog = phaseCatalogRegistration?.ok === true ? phaseCatalogRegistration.value : void 0;
|
|
1683
1703
|
let drawSource = opts.drawSource;
|
|
@@ -1689,53 +1709,50 @@ function createFrameLoop(opts) {
|
|
|
1689
1709
|
let pendingFrameId = 0;
|
|
1690
1710
|
let profilerFrameId = 0;
|
|
1691
1711
|
let profilerCaptureId;
|
|
1692
|
-
|
|
1693
|
-
let activeInjectedWorlds;
|
|
1694
|
-
let nextInjectedWorlds;
|
|
1712
|
+
const leases = /* @__PURE__ */ new Map();
|
|
1695
1713
|
function attachPrimary(fireError) {
|
|
1696
|
-
if (
|
|
1714
|
+
if (leases.has(world)) return;
|
|
1697
1715
|
try {
|
|
1698
|
-
const result = renderer.
|
|
1699
|
-
|
|
1700
|
-
|
|
1716
|
+
const result = renderer.attach(world);
|
|
1717
|
+
if (result.ok) leases.set(world, result.value);
|
|
1718
|
+
else fireError(result.error);
|
|
1701
1719
|
} catch (cause) {
|
|
1702
1720
|
fireError(makeWorldUpdateError(cause));
|
|
1703
1721
|
}
|
|
1704
1722
|
}
|
|
1705
1723
|
function syncInjectedAttachments(worlds, fireError) {
|
|
1706
1724
|
if (worlds === void 0) {
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1725
|
+
for (const [attached, lease] of leases) {
|
|
1726
|
+
if (attached !== world) {
|
|
1727
|
+
lease.dispose();
|
|
1728
|
+
leases.delete(attached);
|
|
1729
|
+
}
|
|
1710
1730
|
}
|
|
1711
1731
|
return void 0;
|
|
1712
1732
|
}
|
|
1713
|
-
const next =
|
|
1714
|
-
nextInjectedWorlds = next;
|
|
1715
|
-
next.clear();
|
|
1716
|
-
const active = activeInjectedWorlds;
|
|
1733
|
+
const next = /* @__PURE__ */ new Set();
|
|
1717
1734
|
for (const candidate of worlds) {
|
|
1718
1735
|
if (candidate === world || next.has(candidate)) continue;
|
|
1719
|
-
if (
|
|
1736
|
+
if (leases.has(candidate)) {
|
|
1720
1737
|
next.add(candidate);
|
|
1721
1738
|
continue;
|
|
1722
1739
|
}
|
|
1723
1740
|
try {
|
|
1724
|
-
const result = renderer.
|
|
1725
|
-
if (result.ok)
|
|
1726
|
-
|
|
1741
|
+
const result = renderer.attach(candidate);
|
|
1742
|
+
if (result.ok) {
|
|
1743
|
+
leases.set(candidate, result.value);
|
|
1744
|
+
next.add(candidate);
|
|
1745
|
+
} else fireError?.(result.error);
|
|
1727
1746
|
} catch (cause) {
|
|
1728
1747
|
fireError?.(makeWorldUpdateError(cause));
|
|
1729
1748
|
}
|
|
1730
1749
|
}
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1750
|
+
for (const [attached, lease] of leases) {
|
|
1751
|
+
if (attached !== world && !next.has(attached)) {
|
|
1752
|
+
lease.dispose();
|
|
1753
|
+
leases.delete(attached);
|
|
1734
1754
|
}
|
|
1735
|
-
active.clear();
|
|
1736
1755
|
}
|
|
1737
|
-
activeInjectedWorlds = next;
|
|
1738
|
-
nextInjectedWorlds = active;
|
|
1739
1756
|
return next;
|
|
1740
1757
|
}
|
|
1741
1758
|
function releaseInjectedAttachments() {
|
|
@@ -1743,9 +1760,11 @@ function createFrameLoop(opts) {
|
|
|
1743
1760
|
}
|
|
1744
1761
|
function releaseAttachments() {
|
|
1745
1762
|
releaseInjectedAttachments();
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1763
|
+
const lease = leases.get(world);
|
|
1764
|
+
if (lease !== void 0) {
|
|
1765
|
+
lease.dispose();
|
|
1766
|
+
leases.delete(world);
|
|
1767
|
+
}
|
|
1749
1768
|
}
|
|
1750
1769
|
function runProfiledPhase(session, phase, action) {
|
|
1751
1770
|
const opened = beginPhase(session, phase);
|
|
@@ -1796,7 +1815,7 @@ function createFrameLoop(opts) {
|
|
|
1796
1815
|
});
|
|
1797
1816
|
const attachedInjectedWorlds = syncInjectedAttachments(injected?.worlds, reportError);
|
|
1798
1817
|
const updatedWorlds = injected === void 0 ? void 0 : /* @__PURE__ */ new Set();
|
|
1799
|
-
if (updatedWorlds !== void 0 && primaryUpdated &&
|
|
1818
|
+
if (updatedWorlds !== void 0 && primaryUpdated && leases.has(world)) {
|
|
1800
1819
|
updatedWorlds.add(world);
|
|
1801
1820
|
}
|
|
1802
1821
|
runProfiledPhase(session, "world-update-injected", () => {
|
|
@@ -1813,27 +1832,34 @@ function createFrameLoop(opts) {
|
|
|
1813
1832
|
});
|
|
1814
1833
|
runProfiledPhase(session, "renderer-draw", () => {
|
|
1815
1834
|
try {
|
|
1816
|
-
const profileOptions = profileFrame === void 0 ? {} : { profileFrame };
|
|
1817
1835
|
let drawResult;
|
|
1818
1836
|
if (injected === void 0) {
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1837
|
+
const primaryLease = leases.get(world);
|
|
1838
|
+
if (!primaryUpdated || primaryLease === void 0) return;
|
|
1839
|
+
drawResult = renderer.draw({
|
|
1840
|
+
leases: [primaryLease],
|
|
1841
|
+
camera: { lease: primaryLease },
|
|
1842
|
+
environment: { lease: primaryLease },
|
|
1843
|
+
...profileFrame === void 0 ? {} : { profileFrame }
|
|
1824
1844
|
});
|
|
1825
1845
|
} else {
|
|
1826
1846
|
if (updatedWorlds === void 0) return;
|
|
1827
|
-
const
|
|
1847
|
+
const readyEntries = injected.worlds.filter((candidate) => updatedWorlds.has(candidate)).map((candidate) => ({ candidate, lease: leases.get(candidate) })).filter(
|
|
1848
|
+
(entry) => entry.lease !== void 0
|
|
1849
|
+
);
|
|
1850
|
+
const readyLeases = readyEntries.map((entry) => entry.lease);
|
|
1828
1851
|
const cameraWorld = injected.worlds[injected.cameraOwner];
|
|
1829
|
-
const
|
|
1830
|
-
|
|
1831
|
-
const
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1852
|
+
const environmentWorld = injected.worlds[injected.resourceOwner];
|
|
1853
|
+
if (cameraWorld === void 0 || environmentWorld === void 0) return;
|
|
1854
|
+
const cameraLease = leases.get(cameraWorld);
|
|
1855
|
+
const environmentLease = leases.get(environmentWorld);
|
|
1856
|
+
if (readyLeases.length === 0 || cameraLease === void 0 || environmentLease === void 0)
|
|
1857
|
+
return;
|
|
1858
|
+
drawResult = renderer.draw({
|
|
1859
|
+
leases: readyLeases,
|
|
1860
|
+
camera: { lease: cameraLease },
|
|
1861
|
+
environment: { lease: environmentLease },
|
|
1862
|
+
...profileFrame === void 0 ? {} : { profileFrame }
|
|
1837
1863
|
});
|
|
1838
1864
|
}
|
|
1839
1865
|
if (drawResult !== void 0) {
|
|
@@ -1848,14 +1874,14 @@ function createFrameLoop(opts) {
|
|
|
1848
1874
|
});
|
|
1849
1875
|
});
|
|
1850
1876
|
endFrame(session);
|
|
1877
|
+
try {
|
|
1878
|
+
opts.debugRhi?.onFrameEnd();
|
|
1879
|
+
} catch {
|
|
1880
|
+
}
|
|
1851
1881
|
return frameError === void 0 ? ok(void 0) : err(frameError);
|
|
1852
1882
|
}
|
|
1853
1883
|
function tick() {
|
|
1854
1884
|
if (state !== "running") return;
|
|
1855
|
-
if (renderer.health?.().reason === "device-lost") {
|
|
1856
|
-
pendingFrameId = raf(tick);
|
|
1857
|
-
return;
|
|
1858
|
-
}
|
|
1859
1885
|
const timestamp = now();
|
|
1860
1886
|
const deltaSeconds = (timestamp - lastTimestamp) / 1e3;
|
|
1861
1887
|
lastTimestamp = timestamp;
|
|
@@ -2063,17 +2089,53 @@ function inputPlugin() {
|
|
|
2063
2089
|
};
|
|
2064
2090
|
}
|
|
2065
2091
|
|
|
2092
|
+
// ../render/src/record/render-context.ts
|
|
2093
|
+
function selectSwapChainFormat(storageBufferCapable) {
|
|
2094
|
+
if (!storageBufferCapable) return { storage: "rgba8unorm", view: "rgba8unorm-srgb" };
|
|
2095
|
+
const nav = globalThis.navigator;
|
|
2096
|
+
const gpu = nav?.gpu;
|
|
2097
|
+
const getPreferred = gpu?.getPreferredCanvasFormat;
|
|
2098
|
+
if (gpu !== void 0 && typeof getPreferred === "function") {
|
|
2099
|
+
const storage = getPreferred.call(gpu);
|
|
2100
|
+
const view = storage === "rgba8unorm" ? "rgba8unorm-srgb" : storage === "bgra8unorm" ? "bgra8unorm-srgb" : storage;
|
|
2101
|
+
return { storage, view };
|
|
2102
|
+
}
|
|
2103
|
+
return {
|
|
2104
|
+
storage: "rgba8unorm",
|
|
2105
|
+
view: "rgba8unorm-srgb",
|
|
2106
|
+
fallbackReason: "preferred-canvas-format-missing"
|
|
2107
|
+
};
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// src/internal/debug-draw.ts
|
|
2111
|
+
async function createDebugDrawOnReady(context, format) {
|
|
2112
|
+
const ready = await context.initialization;
|
|
2113
|
+
if (!ready.ok) throw ready.error;
|
|
2114
|
+
const resolvedFormat = selectSwapChainFormat(context.device.caps.storageBuffer).view;
|
|
2115
|
+
const result = await createDebugDraw({
|
|
2116
|
+
device: context.device,
|
|
2117
|
+
queue: context.device.queue,
|
|
2118
|
+
createShaderModule: context._internal_createShaderModule,
|
|
2119
|
+
format: resolvedFormat
|
|
2120
|
+
});
|
|
2121
|
+
if (!result.ok) throw result.error;
|
|
2122
|
+
context._internal_setRenderOverlay(result.value);
|
|
2123
|
+
return result.value;
|
|
2124
|
+
}
|
|
2125
|
+
function releaseDebugDraw(context, debugDraw) {
|
|
2126
|
+
context._internal_setRenderOverlay(void 0);
|
|
2127
|
+
debugDraw.destroy();
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2066
2130
|
// src/internal/main-engine-profile.ts
|
|
2067
|
-
function debugDrawPlugin(onReady) {
|
|
2131
|
+
function debugDrawPlugin(context, onReady) {
|
|
2068
2132
|
return {
|
|
2069
2133
|
name: "debug-draw",
|
|
2070
|
-
inject: ["renderer"],
|
|
2071
2134
|
async apply(ctx) {
|
|
2072
|
-
if (ctx.renderer === void 0) throw new Error("debug draw requires the renderer service");
|
|
2073
2135
|
try {
|
|
2074
|
-
const debugDraw = await createDebugDrawOnReady(
|
|
2136
|
+
const debugDraw = await createDebugDrawOnReady(context);
|
|
2075
2137
|
onReady(debugDraw);
|
|
2076
|
-
ctx.effect(() => () => releaseDebugDraw(debugDraw), "render/debug-draw");
|
|
2138
|
+
ctx.effect(() => () => releaseDebugDraw(context, debugDraw), "render/debug-draw");
|
|
2077
2139
|
} catch {
|
|
2078
2140
|
}
|
|
2079
2141
|
}
|
|
@@ -2083,8 +2145,8 @@ function mainEngineProfile(options) {
|
|
|
2083
2145
|
return [
|
|
2084
2146
|
ownedRendererPlugin(options.renderer),
|
|
2085
2147
|
renderComponentsPlugin(),
|
|
2086
|
-
|
|
2087
|
-
|
|
2148
|
+
...options.rendererFeatureHost === void 0 ? [] : [renderFeatureHostPlugin(options.rendererFeatureHost)],
|
|
2149
|
+
rendererAssetsPlugin(options.assets),
|
|
2088
2150
|
assetsWorldPlugin(),
|
|
2089
2151
|
...options.input === void 0 ? [] : [
|
|
2090
2152
|
options.inputDispose === void 0 ? inputBackendPlugin(options.input) : ownedInputBackendPlugin(options.input, options.inputDispose)
|
|
@@ -2093,7 +2155,7 @@ function mainEngineProfile(options) {
|
|
|
2093
2155
|
animationPayloadsPlugin(options.animationPayloads),
|
|
2094
2156
|
animationRuntimePlugin(),
|
|
2095
2157
|
statePlugin(),
|
|
2096
|
-
...options.onDebugDrawReady === void 0 ? [] : [debugDrawPlugin(options.onDebugDrawReady)],
|
|
2158
|
+
...options.onDebugDrawReady === void 0 || options.rendererDebugDrawHost === void 0 ? [] : [debugDrawPlugin(options.rendererDebugDrawHost, options.onDebugDrawReady)],
|
|
2097
2159
|
...options.input === void 0 ? [] : [inputPlugin()],
|
|
2098
2160
|
...options.inputMap === void 0 ? [] : [inputMapPlugin(options.inputMap)],
|
|
2099
2161
|
...options.extensions ?? []
|
|
@@ -2101,8 +2163,7 @@ function mainEngineProfile(options) {
|
|
|
2101
2163
|
}
|
|
2102
2164
|
|
|
2103
2165
|
// src/internal/remote-serve-flag.ts
|
|
2104
|
-
function resolveRemoteServeFlag(isDev, processEnv
|
|
2105
|
-
if (isBrowser) return false;
|
|
2166
|
+
function resolveRemoteServeFlag(isDev, processEnv) {
|
|
2106
2167
|
if (isDev === true) return true;
|
|
2107
2168
|
if (processEnv?.FORGEAX_ENGINE_REMOTE_SERVE === "1") return true;
|
|
2108
2169
|
return false;
|
|
@@ -2289,38 +2350,10 @@ function resolveRhiDebugFlag(importMetaEnv, processEnv) {
|
|
|
2289
2350
|
}
|
|
2290
2351
|
|
|
2291
2352
|
// src/create-app.ts
|
|
2292
|
-
var DEFAULT_ASSET_CATALOG_PATH = "pack-index.json";
|
|
2293
|
-
function defaultAssetCatalogUrl() {
|
|
2294
|
-
const base = typeof document !== "undefined" ? document.baseURI : globalThis.location?.href;
|
|
2295
|
-
return base === void 0 ? DEFAULT_ASSET_CATALOG_PATH : new URL(DEFAULT_ASSET_CATALOG_PATH, base).href;
|
|
2296
|
-
}
|
|
2297
|
-
function assembleAppAssetRuntime(catalog, contributions) {
|
|
2298
|
-
const registry = createAssetRegistry({
|
|
2299
|
-
catalog: catalog ?? createCatalogSource({ url: defaultAssetCatalogUrl() })
|
|
2300
|
-
});
|
|
2301
|
-
const assembled = assembleAssetRuntime(registry, contributions ?? []);
|
|
2302
|
-
if (!assembled.ok) registry.dispose();
|
|
2303
|
-
return assembled;
|
|
2304
|
-
}
|
|
2305
2353
|
function makeAppError2(code, expected, hint, detail) {
|
|
2306
2354
|
return new AppError({ code, expected, hint, detail });
|
|
2307
2355
|
}
|
|
2308
|
-
function
|
|
2309
|
-
const moduleUrl = typeof bootstrap === "string" ? bootstrap : bootstrap.href;
|
|
2310
|
-
try {
|
|
2311
|
-
return ok(new URL(bootstrap, globalThis.location?.href).href);
|
|
2312
|
-
} catch (cause) {
|
|
2313
|
-
return err(
|
|
2314
|
-
makeAppError2(
|
|
2315
|
-
"app-execution-bootstrap-failed",
|
|
2316
|
-
APP_EXPECTED["app-execution-bootstrap-failed"],
|
|
2317
|
-
APP_ERROR_HINTS["app-execution-bootstrap-failed"],
|
|
2318
|
-
{ phase: "prepare", moduleUrl, cause }
|
|
2319
|
-
)
|
|
2320
|
-
);
|
|
2321
|
-
}
|
|
2322
|
-
}
|
|
2323
|
-
function canvasAspectPlugin(canvas, maxCanvasPixelRatio) {
|
|
2356
|
+
function canvasAspectPlugin(canvas) {
|
|
2324
2357
|
return {
|
|
2325
2358
|
name: "canvas-aspect",
|
|
2326
2359
|
inject: ["world"],
|
|
@@ -2330,7 +2363,7 @@ function canvasAspectPlugin(canvas, maxCanvasPixelRatio) {
|
|
|
2330
2363
|
name: "app-sync-camera-aspect",
|
|
2331
2364
|
queries: [],
|
|
2332
2365
|
fn: () => {
|
|
2333
|
-
syncCanvasDrawingBuffer(canvas
|
|
2366
|
+
syncCanvasDrawingBuffer(canvas);
|
|
2334
2367
|
syncCameraAspect(ctx.world, canvas.width, canvas.height);
|
|
2335
2368
|
}
|
|
2336
2369
|
};
|
|
@@ -2355,17 +2388,6 @@ function createApp(arg, opts, bundler) {
|
|
|
2355
2388
|
return createAppFromAssemble(arg);
|
|
2356
2389
|
}
|
|
2357
2390
|
async function createAppFromCanvas(canvas, opts, bundler) {
|
|
2358
|
-
const maxCanvasPixelRatio = opts?.maxCanvasPixelRatio;
|
|
2359
|
-
if (maxCanvasPixelRatio !== void 0 && (!Number.isFinite(maxCanvasPixelRatio) || maxCanvasPixelRatio <= 0)) {
|
|
2360
|
-
return err(
|
|
2361
|
-
makeAppError2(
|
|
2362
|
-
"app-invalid-canvas-pixel-ratio",
|
|
2363
|
-
APP_EXPECTED["app-invalid-canvas-pixel-ratio"],
|
|
2364
|
-
APP_ERROR_HINTS["app-invalid-canvas-pixel-ratio"],
|
|
2365
|
-
{ value: maxCanvasPixelRatio }
|
|
2366
|
-
)
|
|
2367
|
-
);
|
|
2368
|
-
}
|
|
2369
2391
|
if (!canvas.isConnected) {
|
|
2370
2392
|
return err(
|
|
2371
2393
|
makeAppError2(
|
|
@@ -2376,22 +2398,18 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2376
2398
|
)
|
|
2377
2399
|
);
|
|
2378
2400
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
if (
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
if (opts?.execution !== void 0 && normalizedExecutionBootstrap?.ok === true) {
|
|
2401
|
+
syncCanvasDrawingBuffer(canvas);
|
|
2402
|
+
let executionBootstrapUrl;
|
|
2403
|
+
if (opts?.execution !== void 0) {
|
|
2404
|
+
const normalizedBootstrap = normalizeExecutionBootstrapUrl(opts.execution.bootstrap);
|
|
2405
|
+
if (!normalizedBootstrap.ok) return err(normalizedBootstrap.error);
|
|
2406
|
+
executionBootstrapUrl = normalizedBootstrap.value;
|
|
2386
2407
|
const realmBoundOption = [
|
|
2387
2408
|
["features", opts.features],
|
|
2388
2409
|
["plugins", opts.plugins],
|
|
2389
2410
|
["rhi", opts.rhi],
|
|
2390
|
-
["
|
|
2411
|
+
["rhiInstrumentation", opts.rhiInstrumentation],
|
|
2391
2412
|
["drawSource", opts.drawSource],
|
|
2392
|
-
["membershipTiming", opts.membershipTiming],
|
|
2393
|
-
["assetCatalog", opts.assetCatalog],
|
|
2394
|
-
["assetDecoders", opts.assetDecoders],
|
|
2395
2413
|
["bundler.importTransport", bundler?.importTransport]
|
|
2396
2414
|
].find(([, value]) => value !== void 0)?.[0];
|
|
2397
2415
|
if (realmBoundOption !== void 0) {
|
|
@@ -2402,7 +2420,7 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2402
2420
|
APP_ERROR_HINTS["app-execution-bootstrap-failed"],
|
|
2403
2421
|
{
|
|
2404
2422
|
phase: "prepare",
|
|
2405
|
-
moduleUrl:
|
|
2423
|
+
moduleUrl: executionBootstrapUrl,
|
|
2406
2424
|
cause: new TypeError(
|
|
2407
2425
|
`${realmBoundOption} must be constructed by the execution bootstrap module`
|
|
2408
2426
|
)
|
|
@@ -2413,11 +2431,10 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2413
2431
|
}
|
|
2414
2432
|
let executionContext;
|
|
2415
2433
|
let preparedExecutionBootstrap;
|
|
2416
|
-
if (opts?.execution !== void 0
|
|
2417
|
-
const executionOptions2 = opts.execution;
|
|
2434
|
+
if (opts?.execution !== void 0) {
|
|
2418
2435
|
const capabilities = await probeExecutionCapabilities(canvas);
|
|
2419
2436
|
const selected = selectExecutionTier({
|
|
2420
|
-
requestedTier:
|
|
2437
|
+
requestedTier: opts.execution.tier ?? "auto",
|
|
2421
2438
|
capabilities,
|
|
2422
2439
|
sharedEvidencePassed: true
|
|
2423
2440
|
});
|
|
@@ -2427,15 +2444,18 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2427
2444
|
return createWorkerExecutionApp({
|
|
2428
2445
|
canvas,
|
|
2429
2446
|
appOptions: opts,
|
|
2430
|
-
syncCanvas: () => measureCanvasDrawingBuffer(canvas
|
|
2447
|
+
syncCanvas: () => measureCanvasDrawingBuffer(canvas),
|
|
2431
2448
|
...bundler !== void 0 ? { bundler } : {},
|
|
2432
2449
|
capabilities,
|
|
2433
2450
|
selection: selected.value
|
|
2434
2451
|
});
|
|
2435
2452
|
}
|
|
2453
|
+
if (executionBootstrapUrl === void 0) {
|
|
2454
|
+
throw new Error("execution bootstrap URL was not normalized");
|
|
2455
|
+
}
|
|
2436
2456
|
const prepared = await prepareBootstrapEntry(
|
|
2437
|
-
|
|
2438
|
-
|
|
2457
|
+
executionBootstrapUrl,
|
|
2458
|
+
opts.execution.bootstrapData
|
|
2439
2459
|
);
|
|
2440
2460
|
if (!prepared.ok) return err(prepared.error);
|
|
2441
2461
|
preparedExecutionBootstrap = prepared.value;
|
|
@@ -2444,24 +2464,19 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2444
2464
|
if (opts?.rhi !== void 0) {
|
|
2445
2465
|
Object.assign(rendererOpts, { rhi: opts.rhi });
|
|
2446
2466
|
}
|
|
2447
|
-
if (opts?.rhiInstrumentation !== void 0) {
|
|
2448
|
-
Object.assign(rendererOpts, { rhiInstrumentation: opts.rhiInstrumentation });
|
|
2449
|
-
}
|
|
2450
|
-
if (opts?.rawDeviceForContextConfigure !== void 0) {
|
|
2451
|
-
Object.assign(rendererOpts, {
|
|
2452
|
-
rawDeviceForContextConfigure: opts.rawDeviceForContextConfigure
|
|
2453
|
-
});
|
|
2454
|
-
}
|
|
2455
2467
|
if (opts?.profiler !== void 0) {
|
|
2456
2468
|
Object.assign(rendererOpts, { profiler: opts.profiler });
|
|
2457
2469
|
}
|
|
2458
|
-
if (opts?.membershipTiming !== void 0) {
|
|
2459
|
-
Object.assign(rendererOpts, { membershipTiming: opts.membershipTiming });
|
|
2460
|
-
}
|
|
2461
2470
|
const rendererFeatures = preparedExecutionBootstrap?.features ?? opts?.features;
|
|
2462
2471
|
if (rendererFeatures !== void 0) {
|
|
2463
2472
|
Object.assign(rendererOpts, { features: rendererFeatures });
|
|
2464
2473
|
}
|
|
2474
|
+
if (opts?.standardProfile !== void 0) {
|
|
2475
|
+
Object.assign(rendererOpts, { standardProfile: opts.standardProfile });
|
|
2476
|
+
}
|
|
2477
|
+
if (opts?.rhiInstrumentation !== void 0) {
|
|
2478
|
+
Object.assign(rendererOpts, { rhiInstrumentation: opts.rhiInstrumentation });
|
|
2479
|
+
}
|
|
2465
2480
|
let rhiAttachment;
|
|
2466
2481
|
let rhiCapture;
|
|
2467
2482
|
let rhiDebugGlobal;
|
|
@@ -2479,61 +2494,54 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2479
2494
|
const rhiDebugFlag = resolveRhiDebugFlag(importMetaEnv, processEnv);
|
|
2480
2495
|
const nav = typeof globalThis !== "undefined" ? globalThis.navigator : void 0;
|
|
2481
2496
|
const hasWebGPU = nav !== void 0 && "gpu" in nav && nav.gpu !== void 0;
|
|
2482
|
-
if (
|
|
2483
|
-
const
|
|
2484
|
-
if (!hasWebGPU && "ensureReady" in
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
'@forgeax/engine-rhi-debug'
|
|
2489
|
-
);
|
|
2497
|
+
if ((browserBuildRhiDebugFlag === void 0 || browserBuildRhiDebugFlag === "1") && rhiDebugFlag === "1") {
|
|
2498
|
+
const realBackend = hasWebGPU ? await import('@forgeax/engine-rhi-webgpu') : await import('@forgeax/engine-rhi-wgpu');
|
|
2499
|
+
if (!hasWebGPU && "ensureReady" in realBackend) {
|
|
2500
|
+
await realBackend.ensureReady();
|
|
2501
|
+
}
|
|
2502
|
+
const pack = loadRhiPack(realBackend);
|
|
2490
2503
|
if (pack.createShaderModule === void 0) {
|
|
2491
|
-
throw new Error("RHI
|
|
2504
|
+
throw new Error("RHI-debug requires a backend createShaderModule capability");
|
|
2492
2505
|
}
|
|
2493
|
-
const
|
|
2494
|
-
const attached = debugModule.attachRecorder({
|
|
2506
|
+
const attached = attachRecorder({
|
|
2495
2507
|
rhi: pack.rhi,
|
|
2496
|
-
createShaderModule
|
|
2508
|
+
createShaderModule: pack.createShaderModule
|
|
2497
2509
|
});
|
|
2498
2510
|
if (!attached.ok) throw new Error(attached.error.hint);
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
const capture =
|
|
2502
|
-
|
|
2511
|
+
rhiAttachment = attached.value;
|
|
2512
|
+
rhiCapture = createRhiCapture(attached.value);
|
|
2513
|
+
const capture = rhiCapture;
|
|
2514
|
+
rhiDebugGlobal = { captureFrame: (options) => capture.captureFrame(options) };
|
|
2503
2515
|
Object.assign(rendererOpts, {
|
|
2504
|
-
rhi:
|
|
2505
|
-
rhiInstrumentation: createRhiInstrumentation(
|
|
2516
|
+
rhi: attached.value.backend.rhi,
|
|
2517
|
+
rhiInstrumentation: createRhiInstrumentation(attached.value)
|
|
2506
2518
|
});
|
|
2507
|
-
rhiDebugGlobal = {
|
|
2508
|
-
captureFrame: (options) => capture.captureFrame(options)
|
|
2509
|
-
};
|
|
2510
2519
|
globalThis.__forgeax = rhiDebugGlobal;
|
|
2511
2520
|
}
|
|
2512
|
-
const assetAssemblyResult = assembleAppAssetRuntime(opts?.assetCatalog, opts?.assetDecoders);
|
|
2513
|
-
if (!assetAssemblyResult.ok) {
|
|
2514
|
-
cleanupRhiDebugHost();
|
|
2515
|
-
return err(assetAssemblyResult.error);
|
|
2516
|
-
}
|
|
2517
|
-
const assetAssembly = assetAssemblyResult.value;
|
|
2518
2521
|
let renderer;
|
|
2522
|
+
let rendererDebugDrawHost;
|
|
2523
|
+
let rendererFeatureHost;
|
|
2524
|
+
let assets;
|
|
2519
2525
|
try {
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2526
|
+
const constructed = await constructRuntimeRendererHost(canvas, rendererOpts, bundler);
|
|
2527
|
+
if (!constructed.ok) throw constructed.error;
|
|
2528
|
+
renderer = constructed.value.renderer;
|
|
2529
|
+
rendererDebugDrawHost = constructed.value.debugDrawHost;
|
|
2530
|
+
rendererFeatureHost = createRenderFeatureHost(constructed.value.featureHost);
|
|
2531
|
+
assets = constructed.value.assets;
|
|
2524
2532
|
} catch (e) {
|
|
2525
2533
|
cleanupRhiDebugHost();
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2534
|
+
if (e instanceof EngineEnvironmentError) return err(e);
|
|
2535
|
+
const detail = e instanceof Error ? e : new Error(String(e));
|
|
2536
|
+
return err(
|
|
2537
|
+
new EngineEnvironmentError("renderer construction failed", {
|
|
2538
|
+
webgpuError: detail
|
|
2539
|
+
})
|
|
2540
|
+
);
|
|
2532
2541
|
}
|
|
2533
2542
|
const shouldStartRemote = resolveRemoteServeFlag(
|
|
2534
2543
|
typeof import.meta !== "undefined" ? import.meta.env?.DEV : void 0,
|
|
2535
|
-
globalThis.process?.env
|
|
2536
|
-
typeof window !== "undefined"
|
|
2544
|
+
globalThis.process?.env
|
|
2537
2545
|
);
|
|
2538
2546
|
let debugDraw;
|
|
2539
2547
|
const world = new World(opts?.time !== void 0 ? { time: opts.time } : {});
|
|
@@ -2557,8 +2565,10 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2557
2565
|
world,
|
|
2558
2566
|
mainEngineProfile({
|
|
2559
2567
|
renderer,
|
|
2560
|
-
|
|
2561
|
-
|
|
2568
|
+
rendererDebugDrawHost,
|
|
2569
|
+
rendererFeatureHost,
|
|
2570
|
+
assets,
|
|
2571
|
+
animationPayloads: createAnimationPayloadLookup(assets),
|
|
2562
2572
|
...inputBackend === void 0 ? {} : { input: inputBackend },
|
|
2563
2573
|
...inputHandle === void 0 ? {} : { inputDispose: inputHandle.cleanup },
|
|
2564
2574
|
...opts?.inputMap === void 0 ? {} : { inputMap: opts.inputMap },
|
|
@@ -2568,14 +2578,12 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2568
2578
|
extensions: [
|
|
2569
2579
|
rhiDebugHostPlugin(cleanupRhiDebugHost),
|
|
2570
2580
|
...userPlugins,
|
|
2571
|
-
canvasAspectPlugin(canvas
|
|
2581
|
+
canvasAspectPlugin(canvas)
|
|
2572
2582
|
]
|
|
2573
2583
|
})
|
|
2574
2584
|
);
|
|
2575
2585
|
} catch (cause) {
|
|
2576
2586
|
cleanupRhiDebugHost();
|
|
2577
|
-
assetAssembly.dispose();
|
|
2578
|
-
assetAssembly.registry.dispose();
|
|
2579
2587
|
return err(
|
|
2580
2588
|
makeAppError2(
|
|
2581
2589
|
"app-plugin-activation-failed",
|
|
@@ -2623,21 +2631,15 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2623
2631
|
})
|
|
2624
2632
|
}
|
|
2625
2633
|
);
|
|
2626
|
-
const remoteHandle = shouldStartRemote ? await startRemoteServer(
|
|
2627
|
-
world,
|
|
2628
|
-
renderer,
|
|
2629
|
-
assetAssembly.registry,
|
|
2630
|
-
rhiCapture,
|
|
2631
|
-
opts?.profiler,
|
|
2632
|
-
executionControl
|
|
2633
|
-
) : void 0;
|
|
2634
|
+
const remoteHandle = shouldStartRemote ? await startRemoteServer(world, renderer, assets, rhiCapture, opts?.profiler, executionControl) : void 0;
|
|
2634
2635
|
if (remoteHandle !== void 0) await pluginContext.plugin(remoteServerPlugin(remoteHandle));
|
|
2635
2636
|
const buildArgs = {
|
|
2636
2637
|
renderer,
|
|
2637
|
-
assets
|
|
2638
|
+
assets,
|
|
2638
2639
|
world,
|
|
2639
2640
|
pluginContext,
|
|
2640
2641
|
executionControl,
|
|
2642
|
+
onFrameSubmitted: (event) => publishBrowserFrameSubmitted(canvas, event),
|
|
2641
2643
|
...inputBackend !== void 0 ? { inputBackend } : {},
|
|
2642
2644
|
...inputHandle === void 0 ? {} : {
|
|
2643
2645
|
wireOnLockErrorDispatch: (dispatch) => {
|
|
@@ -2660,10 +2662,7 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2660
2662
|
Object.assign(buildArgs, { profiler: opts.profiler });
|
|
2661
2663
|
}
|
|
2662
2664
|
if (rhiCapture !== void 0) {
|
|
2663
|
-
Object.assign(buildArgs, {
|
|
2664
|
-
rhiCapture,
|
|
2665
|
-
...rhiAttachment === void 0 ? {} : { rhiAttachment }
|
|
2666
|
-
});
|
|
2665
|
+
Object.assign(buildArgs, { rhiCapture });
|
|
2667
2666
|
}
|
|
2668
2667
|
if (debugDraw !== void 0) {
|
|
2669
2668
|
Object.assign(buildArgs, { debugDraw });
|
|
@@ -2671,6 +2670,7 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2671
2670
|
if (remoteHandle !== void 0) {
|
|
2672
2671
|
Object.assign(buildArgs, { remoteHandle });
|
|
2673
2672
|
}
|
|
2673
|
+
resetBrowserFrameSubmitted(canvas);
|
|
2674
2674
|
const built = await buildApp(buildArgs);
|
|
2675
2675
|
if (!built.ok) {
|
|
2676
2676
|
await pluginContext.fiber.dispose();
|
|
@@ -2681,17 +2681,17 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2681
2681
|
const bridgePort = import.meta.env?.VITE_FORGEAX_ENGINE_BRIDGE_PORT ?? "5733";
|
|
2682
2682
|
await pluginContext.plugin({
|
|
2683
2683
|
name: "browser-remote-bridge",
|
|
2684
|
-
inject: ["world", "renderer", "
|
|
2684
|
+
inject: ["world", "renderer", "assets"],
|
|
2685
2685
|
async apply(ctx) {
|
|
2686
|
-
if (ctx.renderer === void 0 || ctx.
|
|
2687
|
-
throw new Error("browser remote bridge requires renderer and
|
|
2686
|
+
if (ctx.renderer === void 0 || ctx.assets === void 0) {
|
|
2687
|
+
throw new Error("browser remote bridge requires renderer and assets services");
|
|
2688
2688
|
}
|
|
2689
2689
|
try {
|
|
2690
2690
|
const bridge = await Promise.resolve().then(() => (init_browser_remote_bridge(), browser_remote_bridge_exports));
|
|
2691
2691
|
const teardown = await bridge.installBrowserRemoteBridge({
|
|
2692
2692
|
world: ctx.world,
|
|
2693
2693
|
renderer: ctx.renderer,
|
|
2694
|
-
assets: ctx.
|
|
2694
|
+
assets: ctx.assets,
|
|
2695
2695
|
runtimeModule: engineRuntimeModule,
|
|
2696
2696
|
...rhiCapture !== void 0 ? { rhiCapture } : {},
|
|
2697
2697
|
...opts?.profiler !== void 0 ? { profiler: opts.profiler } : {},
|
|
@@ -2707,43 +2707,62 @@ async function createAppFromCanvas(canvas, opts, bundler) {
|
|
|
2707
2707
|
}
|
|
2708
2708
|
return built;
|
|
2709
2709
|
}
|
|
2710
|
-
function syncCanvasDrawingBuffer(canvas
|
|
2711
|
-
const size = resolveCanvasDrawingBufferSize(canvas, maxCanvasPixelRatio);
|
|
2712
|
-
if (size === void 0) return { width: canvas.width, height: canvas.height };
|
|
2713
|
-
if (canvas.width !== size.width) canvas.width = size.width;
|
|
2714
|
-
if (canvas.height !== size.height) canvas.height = size.height;
|
|
2715
|
-
return size;
|
|
2716
|
-
}
|
|
2717
|
-
function measureCanvasDrawingBuffer(canvas, maxCanvasPixelRatio) {
|
|
2718
|
-
return resolveCanvasDrawingBufferSize(canvas, maxCanvasPixelRatio) ?? {
|
|
2719
|
-
width: canvas.width,
|
|
2720
|
-
height: canvas.height
|
|
2721
|
-
};
|
|
2722
|
-
}
|
|
2723
|
-
function resolveCanvasDrawingBufferSize(canvas, maxCanvasPixelRatio) {
|
|
2710
|
+
function syncCanvasDrawingBuffer(canvas) {
|
|
2724
2711
|
if (!Number.isFinite(canvas.clientWidth) || !Number.isFinite(canvas.clientHeight) || canvas.clientWidth <= 0 || canvas.clientHeight <= 0)
|
|
2725
|
-
return
|
|
2712
|
+
return;
|
|
2726
2713
|
const hasExplicitCssSize = (canvas.style?.width ?? "") !== "" || (canvas.style?.height ?? "") !== "";
|
|
2727
2714
|
if (!hasExplicitCssSize && canvas.clientWidth === canvas.width && canvas.clientHeight === canvas.height) {
|
|
2728
|
-
return
|
|
2715
|
+
return;
|
|
2729
2716
|
}
|
|
2730
|
-
const
|
|
2731
|
-
const dpr = maxCanvasPixelRatio === void 0 || !Number.isFinite(maxCanvasPixelRatio) || maxCanvasPixelRatio <= 0 ? devicePixelRatio : Math.min(devicePixelRatio, maxCanvasPixelRatio);
|
|
2717
|
+
const dpr = Math.max(1, globalThis.devicePixelRatio || 1);
|
|
2732
2718
|
const previous = syncedCanvasSizes.get(canvas);
|
|
2733
2719
|
const drawingBufferIsTheLayoutMeasurement = previous !== void 0 && canvas.width === previous.drawingWidth && canvas.height === previous.drawingHeight && canvas.clientWidth === previous.drawingWidth && canvas.clientHeight === previous.drawingHeight;
|
|
2734
2720
|
const cssWidth = drawingBufferIsTheLayoutMeasurement ? previous.cssWidth : canvas.clientWidth;
|
|
2735
2721
|
const cssHeight = drawingBufferIsTheLayoutMeasurement ? previous.cssHeight : canvas.clientHeight;
|
|
2736
2722
|
const width = Math.max(1, Math.round(cssWidth * dpr));
|
|
2737
2723
|
const height = Math.max(1, Math.round(cssHeight * dpr));
|
|
2724
|
+
if (canvas.width !== width) canvas.width = width;
|
|
2725
|
+
if (canvas.height !== height) canvas.height = height;
|
|
2738
2726
|
syncedCanvasSizes.set(canvas, {
|
|
2739
2727
|
cssWidth,
|
|
2740
2728
|
cssHeight,
|
|
2741
2729
|
drawingWidth: width,
|
|
2742
2730
|
drawingHeight: height
|
|
2743
2731
|
});
|
|
2744
|
-
|
|
2732
|
+
}
|
|
2733
|
+
function measureCanvasDrawingBuffer(canvas, maxCanvasPixelRatio) {
|
|
2734
|
+
if (!Number.isFinite(canvas.clientWidth) || !Number.isFinite(canvas.clientHeight) || canvas.clientWidth <= 0 || canvas.clientHeight <= 0) {
|
|
2735
|
+
return { width: canvas.width, height: canvas.height };
|
|
2736
|
+
}
|
|
2737
|
+
const hasExplicitCssSize = (canvas.style?.width ?? "") !== "" || (canvas.style?.height ?? "") !== "";
|
|
2738
|
+
if (!hasExplicitCssSize && canvas.clientWidth === canvas.width && canvas.clientHeight === canvas.height) {
|
|
2739
|
+
return { width: canvas.width, height: canvas.height };
|
|
2740
|
+
}
|
|
2741
|
+
const devicePixelRatio = Math.max(1, globalThis.devicePixelRatio || 1);
|
|
2742
|
+
const dpr = maxCanvasPixelRatio === void 0 || !Number.isFinite(maxCanvasPixelRatio) || maxCanvasPixelRatio <= 0 ? devicePixelRatio : Math.min(devicePixelRatio, maxCanvasPixelRatio);
|
|
2743
|
+
const previous = syncedCanvasSizes.get(canvas);
|
|
2744
|
+
const drawingBufferIsTheLayoutMeasurement = previous !== void 0 && canvas.width === previous.drawingWidth && canvas.height === previous.drawingHeight && canvas.clientWidth === previous.drawingWidth && canvas.clientHeight === previous.drawingHeight;
|
|
2745
|
+
const cssWidth = drawingBufferIsTheLayoutMeasurement ? previous.cssWidth : canvas.clientWidth;
|
|
2746
|
+
const cssHeight = drawingBufferIsTheLayoutMeasurement ? previous.cssHeight : canvas.clientHeight;
|
|
2747
|
+
return {
|
|
2748
|
+
width: Math.max(1, Math.round(cssWidth * dpr)),
|
|
2749
|
+
height: Math.max(1, Math.round(cssHeight * dpr))
|
|
2750
|
+
};
|
|
2745
2751
|
}
|
|
2746
2752
|
var syncedCanvasSizes = /* @__PURE__ */ new WeakMap();
|
|
2753
|
+
function syncCameraAspect(world, canvasW, canvasH) {
|
|
2754
|
+
if (canvasW <= 0 || canvasH <= 0) return;
|
|
2755
|
+
const aspect = canvasW / canvasH;
|
|
2756
|
+
const query = world.query({ with: [Camera] }).unwrap();
|
|
2757
|
+
for (const row of query) {
|
|
2758
|
+
const entity = row.entity;
|
|
2759
|
+
const r = world.get(entity, Camera);
|
|
2760
|
+
if (!r.ok) continue;
|
|
2761
|
+
if (r.value.autoAspect !== true) continue;
|
|
2762
|
+
if (r.value.projection !== CAMERA_PROJECTION_PERSPECTIVE) continue;
|
|
2763
|
+
world.set(entity, Camera, { aspect });
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2747
2766
|
async function startRemoteServer(world, renderer, assets, rhiCapture, profiler, execution) {
|
|
2748
2767
|
try {
|
|
2749
2768
|
const remoteServerMod = await import(
|
|
@@ -2769,22 +2788,17 @@ async function startRemoteServer(world, renderer, assets, rhiCapture, profiler,
|
|
|
2769
2788
|
return void 0;
|
|
2770
2789
|
}
|
|
2771
2790
|
async function createAppFromAssemble(args) {
|
|
2772
|
-
const assetAssemblyResult = assembleAppAssetRuntime(args.assetCatalog, args.assetDecoders);
|
|
2773
|
-
if (!assetAssemblyResult.ok) return err(assetAssemblyResult.error);
|
|
2774
|
-
const assetAssembly = assetAssemblyResult.value;
|
|
2775
2791
|
let pluginContext;
|
|
2776
2792
|
try {
|
|
2777
2793
|
pluginContext = await createWorldContext(
|
|
2778
2794
|
args.world,
|
|
2779
2795
|
assembledEngineProfile({
|
|
2780
2796
|
renderer: args.renderer,
|
|
2781
|
-
|
|
2797
|
+
...args.assets === void 0 ? {} : { assets: args.assets },
|
|
2782
2798
|
extensions: args.plugins ?? []
|
|
2783
2799
|
})
|
|
2784
2800
|
);
|
|
2785
2801
|
} catch (cause) {
|
|
2786
|
-
assetAssembly.dispose();
|
|
2787
|
-
assetAssembly.registry.dispose();
|
|
2788
2802
|
return err(
|
|
2789
2803
|
makeAppError2(
|
|
2790
2804
|
"app-plugin-activation-failed",
|
|
@@ -2826,7 +2840,7 @@ async function createAppFromAssemble(args) {
|
|
|
2826
2840
|
const remoteHandle = shouldStartRemote ? await startRemoteServer(
|
|
2827
2841
|
args.world,
|
|
2828
2842
|
args.renderer,
|
|
2829
|
-
|
|
2843
|
+
args.assets,
|
|
2830
2844
|
void 0,
|
|
2831
2845
|
args.profiler,
|
|
2832
2846
|
executionControl
|
|
@@ -2834,7 +2848,6 @@ async function createAppFromAssemble(args) {
|
|
|
2834
2848
|
if (remoteHandle !== void 0) await pluginContext.plugin(remoteServerPlugin(remoteHandle));
|
|
2835
2849
|
const buildArgs = {
|
|
2836
2850
|
renderer: args.renderer,
|
|
2837
|
-
assets: assetAssembly.registry,
|
|
2838
2851
|
world: args.world,
|
|
2839
2852
|
pluginContext,
|
|
2840
2853
|
executionControl,
|
|
@@ -2867,14 +2880,12 @@ async function createAppFromAssemble(args) {
|
|
|
2867
2880
|
async function buildApp(args) {
|
|
2868
2881
|
const {
|
|
2869
2882
|
renderer,
|
|
2870
|
-
assets,
|
|
2871
2883
|
world,
|
|
2872
2884
|
pluginContext,
|
|
2873
2885
|
inputBackend,
|
|
2874
2886
|
audioBackend,
|
|
2875
2887
|
silenceUnhandledErrors,
|
|
2876
2888
|
rhiCapture,
|
|
2877
|
-
rhiAttachment,
|
|
2878
2889
|
debugDraw,
|
|
2879
2890
|
remoteHandle,
|
|
2880
2891
|
profiler
|
|
@@ -2885,6 +2896,7 @@ async function buildApp(args) {
|
|
|
2885
2896
|
const fanout = new ErrorFanoutRegistry(
|
|
2886
2897
|
silenceUnhandledErrors !== void 0 ? { silenceUnhandledErrors } : {}
|
|
2887
2898
|
);
|
|
2899
|
+
let lastError;
|
|
2888
2900
|
const execution = args.executionControl ?? createLocalExecutionControl(
|
|
2889
2901
|
{
|
|
2890
2902
|
...createExecutionReport("main-serial", unavailableExecutionCapabilities("not required")),
|
|
@@ -2910,6 +2922,7 @@ async function buildApp(args) {
|
|
|
2910
2922
|
}
|
|
2911
2923
|
);
|
|
2912
2924
|
function dispatch(e) {
|
|
2925
|
+
lastError = e;
|
|
2913
2926
|
fanout.fire(e);
|
|
2914
2927
|
}
|
|
2915
2928
|
if (args.wireOnLockErrorDispatch) {
|
|
@@ -2927,7 +2940,7 @@ async function buildApp(args) {
|
|
|
2927
2940
|
Object.assign(loopOpts, { profiler });
|
|
2928
2941
|
}
|
|
2929
2942
|
const loop = createFrameLoop(loopOpts);
|
|
2930
|
-
if (rhiCapture !== void 0
|
|
2943
|
+
if (rhiCapture !== void 0) {
|
|
2931
2944
|
bindRhiCaptureFrameDriver(rhiCapture, {
|
|
2932
2945
|
getState: () => loop.getState(),
|
|
2933
2946
|
pause: () => {
|
|
@@ -2943,17 +2956,19 @@ async function buildApp(args) {
|
|
|
2943
2956
|
stepFrame: (deltaSeconds) => loop.stepFrame(deltaSeconds)
|
|
2944
2957
|
});
|
|
2945
2958
|
}
|
|
2946
|
-
let lastError;
|
|
2947
2959
|
let rendererUnsubscribe;
|
|
2948
2960
|
let resumeAfterSurfaceRestore = false;
|
|
2949
2961
|
function subscribeRendererErrors() {
|
|
2950
2962
|
if (rendererUnsubscribe !== void 0) {
|
|
2951
2963
|
return;
|
|
2952
2964
|
}
|
|
2953
|
-
rendererUnsubscribe = renderer.
|
|
2954
|
-
if (
|
|
2955
|
-
|
|
2965
|
+
rendererUnsubscribe = renderer.subscribe((event) => {
|
|
2966
|
+
if (event.kind === "frame-submitted") {
|
|
2967
|
+
args.onFrameSubmitted?.(event);
|
|
2968
|
+
return;
|
|
2956
2969
|
}
|
|
2970
|
+
if (event.kind !== "error") return;
|
|
2971
|
+
const e = event.error;
|
|
2957
2972
|
dispatch(e);
|
|
2958
2973
|
});
|
|
2959
2974
|
}
|
|
@@ -2965,7 +2980,7 @@ async function buildApp(args) {
|
|
|
2965
2980
|
}
|
|
2966
2981
|
const stub = {
|
|
2967
2982
|
renderer,
|
|
2968
|
-
assets,
|
|
2983
|
+
...args.assets === void 0 ? {} : { assets: args.assets },
|
|
2969
2984
|
world,
|
|
2970
2985
|
execution,
|
|
2971
2986
|
async releaseSurfacePreserveWorld() {
|
|
@@ -3060,7 +3075,7 @@ async function buildApp(args) {
|
|
|
3060
3075
|
loop.setDrawSource(drawSource);
|
|
3061
3076
|
},
|
|
3062
3077
|
/**
|
|
3063
|
-
* Most recent
|
|
3078
|
+
* Most recent dispatched error retained for host self-inspection.
|
|
3064
3079
|
*/
|
|
3065
3080
|
get lastError() {
|
|
3066
3081
|
return lastError;
|
|
@@ -3069,10 +3084,6 @@ async function buildApp(args) {
|
|
|
3069
3084
|
...debugDraw !== void 0 ? { debugDraw } : {},
|
|
3070
3085
|
...remoteHandle !== void 0 ? { remote: remoteHandle } : {}
|
|
3071
3086
|
};
|
|
3072
|
-
const readyResult = await renderer.ready;
|
|
3073
|
-
if (!readyResult.ok) {
|
|
3074
|
-
return err(readyResult.error);
|
|
3075
|
-
}
|
|
3076
3087
|
return ok(stub);
|
|
3077
3088
|
}
|
|
3078
3089
|
function ensureFallbackCamera(world, aspect = 1) {
|
|
@@ -3679,19 +3690,6 @@ async function createToolPreviewHost(options) {
|
|
|
3679
3690
|
const app = appResult.value;
|
|
3680
3691
|
const appErrors = [];
|
|
3681
3692
|
const unsubscribeAppErrors = app.onError((error) => appErrors.push(error));
|
|
3682
|
-
const rendererReady = await app.renderer.ready;
|
|
3683
|
-
if (!rendererReady.ok) {
|
|
3684
|
-
unsubscribeAppErrors();
|
|
3685
|
-
await app.dispose();
|
|
3686
|
-
await runtime.attachment.dispose();
|
|
3687
|
-
removeOwnedCanvas(canvas, ownsCanvas);
|
|
3688
|
-
return err({
|
|
3689
|
-
code: "tool-preview-bootstrap-failed",
|
|
3690
|
-
expected: "the real WebGPU Renderer to finish pipeline initialization before preview frames",
|
|
3691
|
-
hint: rendererReady.error.hint,
|
|
3692
|
-
detail: { phase: "renderer-ready", cause: rendererReady.error }
|
|
3693
|
-
});
|
|
3694
|
-
}
|
|
3695
3693
|
let resourceFacts;
|
|
3696
3694
|
try {
|
|
3697
3695
|
const prepared = await options.prepare?.(app);
|
|
@@ -3716,7 +3714,7 @@ async function createToolPreviewHost(options) {
|
|
|
3716
3714
|
detail: { phase: bootstrapFailure.phase, cause }
|
|
3717
3715
|
});
|
|
3718
3716
|
}
|
|
3719
|
-
const attached = app.renderer.
|
|
3717
|
+
const attached = app.renderer.attach(app.world);
|
|
3720
3718
|
if (!attached.ok) {
|
|
3721
3719
|
unsubscribeAppErrors();
|
|
3722
3720
|
await app.dispose();
|
|
@@ -3977,6 +3975,6 @@ function fitToolPreviewCameraToAabb(aabb, options) {
|
|
|
3977
3975
|
};
|
|
3978
3976
|
}
|
|
3979
3977
|
|
|
3980
|
-
export { APP_ERROR_HINTS, APP_EXPECTED, APP_PHASE_CATALOG, AppError, EXECUTION_CAPABILITY_NAMES, EXECUTION_REPORT_SCHEMA_VERSION, EXECUTION_REQUESTED_TIERS, EXECUTION_TIERS, LOAD_GAME_ERROR_HINTS, LOAD_GAME_EXPECTED, LoadGameError,
|
|
3978
|
+
export { APP_ERROR_HINTS, APP_EXPECTED, APP_PHASE_CATALOG, AppError, EXECUTION_CAPABILITY_NAMES, EXECUTION_REPORT_SCHEMA_VERSION, EXECUTION_REQUESTED_TIERS, EXECUTION_TIERS, FORGEAX_FRAME_SUBMITTED_DATASET, FORGEAX_FRAME_SUBMITTED_EVENT, LOAD_GAME_ERROR_HINTS, LOAD_GAME_EXPECTED, LoadGameError, createApp, createExecutionReport, createToolPreviewEvidence, createToolPreviewHost, createToolPreviewRecipe, ensureFallbackCamera, executionBootstrapHostPlugin, fitToolPreviewCameraToAabb, gameHostPlugin, inputPlugin, isAppError, isExecutionReport, isLoadGameError, joinResourcePreviewEvidence, joinToolPreviewEvidence, loadBootstrapEntry, loadGame, measureCanvasDrawingBuffer, missingExecutionCapabilities, ownedRendererPlugin, prepareBootstrapEntry, probeExecutionCapabilities, publishBrowserFrameSubmitted, renderFeatureHostPlugin, renderFeaturePlugin, rendererPlugin, replayToolPreviewCapture, resetBrowserFrameSubmitted, selectExecutionTier, syncCanvasDrawingBuffer, unavailableExecutionCapabilities, validateExecutionBootstrapData, validateToolPreviewTrace };
|
|
3981
3979
|
//# sourceMappingURL=index.mjs.map
|
|
3982
3980
|
//# sourceMappingURL=index.mjs.map
|