@zephyr3d/scene 0.8.2 → 0.9.1
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/dist/animation/animationset.js +473 -60
- package/dist/animation/animationset.js.map +1 -1
- package/dist/animation/cloth/gpu_cloth_system.js +2516 -0
- package/dist/animation/cloth/gpu_cloth_system.js.map +1 -0
- package/dist/animation/fixed_geometry_cache_track.js +138 -0
- package/dist/animation/fixed_geometry_cache_track.js.map +1 -0
- package/dist/animation/geometry_cache_utils.js +120 -0
- package/dist/animation/geometry_cache_utils.js.map +1 -0
- package/dist/animation/ik_modifier.js +9 -1
- package/dist/animation/ik_modifier.js.map +1 -1
- package/dist/animation/joint_dynamics/collision.js +469 -0
- package/dist/animation/joint_dynamics/collision.js.map +1 -0
- package/dist/animation/joint_dynamics/constraints.js +329 -0
- package/dist/animation/joint_dynamics/constraints.js.map +1 -0
- package/dist/animation/joint_dynamics/controller.js +699 -0
- package/dist/animation/joint_dynamics/controller.js.map +1 -0
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +393 -0
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -0
- package/dist/animation/joint_dynamics/solver.js +794 -0
- package/dist/animation/joint_dynamics/solver.js.map +1 -0
- package/dist/animation/joint_dynamics/types.js +19 -0
- package/dist/animation/joint_dynamics/types.js.map +1 -0
- package/dist/animation/joint_dynamics/vrm_spring_bone.js +46 -0
- package/dist/animation/joint_dynamics/vrm_spring_bone.js.map +1 -0
- package/dist/animation/joint_dynamics_modifier.js +51 -0
- package/dist/animation/joint_dynamics_modifier.js.map +1 -0
- package/dist/animation/pca_geometry_cache_track.js +222 -0
- package/dist/animation/pca_geometry_cache_track.js.map +1 -0
- package/dist/animation/skeleton.js +2011 -139
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/animation/skeleton_modifier.js +3 -5
- package/dist/animation/skeleton_modifier.js.map +1 -1
- package/dist/animation/spring/multi_chain_spring_system.js +2 -0
- package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
- package/dist/animation/spring/spring_chain.js +3 -2
- package/dist/animation/spring/spring_chain.js.map +1 -1
- package/dist/animation/spring/spring_collider.js +35 -5
- package/dist/animation/spring/spring_collider.js.map +1 -1
- package/dist/animation/spring/spring_particle.js +1 -0
- package/dist/animation/spring/spring_particle.js.map +1 -1
- package/dist/animation/spring/spring_system.js +325 -28
- package/dist/animation/spring/spring_system.js.map +1 -1
- package/dist/animation/spring2/collision.js +469 -0
- package/dist/animation/spring2/collision.js.map +1 -0
- package/dist/animation/spring2/constraints.js +329 -0
- package/dist/animation/spring2/constraints.js.map +1 -0
- package/dist/animation/spring2/controller.js +434 -0
- package/dist/animation/spring2/controller.js.map +1 -0
- package/dist/animation/spring2/math.js +16 -0
- package/dist/animation/spring2/math.js.map +1 -0
- package/dist/animation/spring2/solver.js +624 -0
- package/dist/animation/spring2/solver.js.map +1 -0
- package/dist/animation/spring2/spring_system.js +118 -0
- package/dist/animation/spring2/spring_system.js.map +1 -0
- package/dist/animation/spring2/types.js +19 -0
- package/dist/animation/spring2/types.js.map +1 -0
- package/dist/animation/spring_modifier.js +17 -1
- package/dist/animation/spring_modifier.js.map +1 -1
- package/dist/app/engine.js +42 -15
- package/dist/app/engine.js.map +1 -1
- package/dist/app/runtimescript.js +132 -1
- package/dist/app/runtimescript.js.map +1 -1
- package/dist/app/screen.js +3 -3
- package/dist/app/screen.js.map +1 -1
- package/dist/app/scriptingsystem.js +69 -37
- package/dist/app/scriptingsystem.js.map +1 -1
- package/dist/app/scriptregistry.js +14 -3
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +2 -1
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/loaders/zabc/zabc_loader.js +570 -0
- package/dist/asset/loaders/zabc/zabc_loader.js.map +1 -0
- package/dist/asset/model.js +192 -0
- package/dist/asset/model.js.map +1 -1
- package/dist/camera/base.js +26 -7
- package/dist/camera/base.js.map +1 -1
- package/dist/camera/camera.js +146 -24
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/fps.js +2 -2
- package/dist/camera/fps.js.map +1 -1
- package/dist/camera/orbit.js +2 -2
- package/dist/camera/orbit.js.map +1 -1
- package/dist/index.d.ts +11728 -8535
- package/dist/index.js +29 -8
- package/dist/index.js.map +1 -1
- package/dist/material/lambert.js +1 -1
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +9 -3
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +54 -7
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +17 -7
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js +7 -2
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +108 -16
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +209 -14
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +24 -12
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +11 -8
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +72 -5
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/pbrblueprint.js +148 -1
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/material/pbrmr.js +115 -2
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/shader/helper.js +10 -4
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/water.js +2 -2
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/coloradjust.js +145 -0
- package/dist/posteffect/coloradjust.js.map +1 -0
- package/dist/posteffect/taa.js +68 -32
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/render/cluster_light.js +17 -12
- package/dist/render/cluster_light.js.map +1 -1
- package/dist/render/deferredlightpass.js +510 -0
- package/dist/render/deferredlightpass.js.map +1 -0
- package/dist/render/deferredshadowlightpass.js +428 -0
- package/dist/render/deferredshadowlightpass.js.map +1 -0
- package/dist/render/drawable.js.map +1 -1
- package/dist/render/drawable_mixin.js +21 -12
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/envlight.js +20 -22
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/gbufferpass.js +50 -0
- package/dist/render/gbufferpass.js.map +1 -0
- package/dist/render/lightpass.js +1 -2
- package/dist/render/lightpass.js.map +1 -1
- package/dist/render/primitive.js +1 -1
- package/dist/render/primitive.js.map +1 -1
- package/dist/render/render_queue.js +3 -2
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +5 -358
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/rendergraph/executor.js +15 -12
- package/dist/render/rendergraph/executor.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +144 -88
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/history_resource_manager.js +178 -0
- package/dist/render/rendergraph/history_resource_manager.js.map +1 -0
- package/dist/render/rendergraph/rendergraph.js +12 -1
- package/dist/render/rendergraph/rendergraph.js.map +1 -1
- package/dist/render/rendergraph/types.js +2 -2
- package/dist/render/rendergraph/types.js.map +1 -1
- package/dist/render/sky.js +26 -9
- package/dist/render/sky.js.map +1 -1
- package/dist/scene/basesprite.js +4 -3
- package/dist/scene/basesprite.js.map +1 -1
- package/dist/scene/batchgroup.js +4 -4
- package/dist/scene/environment.js +7 -4
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/light.js +184 -18
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/mesh.js +30 -0
- package/dist/scene/mesh.js.map +1 -1
- package/dist/scene/particlesys.js +3 -2
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/raycast_visitor.js +29 -3
- package/dist/scene/raycast_visitor.js.map +1 -1
- package/dist/scene/scene.js +86 -19
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/scene_node.js +87 -31
- package/dist/scene/scene_node.js.map +1 -1
- package/dist/scene/script_attachment.js +59 -0
- package/dist/scene/script_attachment.js.map +1 -0
- package/dist/scene/terrain-cm/grass.js +3 -2
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +4 -3
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/water.js +3 -2
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/shadow.js +2 -2
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shadow/shadowmapper.js +74 -4
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shapes/box.js +163 -0
- package/dist/shapes/box.js.map +1 -1
- package/dist/shapes/capsule.js +216 -0
- package/dist/shapes/capsule.js.map +1 -0
- package/dist/shapes/cylinder.js +91 -0
- package/dist/shapes/cylinder.js.map +1 -1
- package/dist/shapes/plane.js +32 -0
- package/dist/shapes/plane.js.map +1 -1
- package/dist/shapes/tetrahedron.js +211 -0
- package/dist/shapes/tetrahedron.js.map +1 -1
- package/dist/shapes/torus.js +173 -0
- package/dist/shapes/torus.js.map +1 -1
- package/dist/utility/blueprint/common/math.js +111 -1
- package/dist/utility/blueprint/common/math.js.map +1 -1
- package/dist/utility/blueprint/material/inputs.js +235 -1
- package/dist/utility/blueprint/material/inputs.js.map +1 -1
- package/dist/utility/blueprint/material/ir.js +154 -10
- package/dist/utility/blueprint/material/ir.js.map +1 -1
- package/dist/utility/blueprint/material/texture.js +273 -19
- package/dist/utility/blueprint/material/texture.js.map +1 -1
- package/dist/utility/serialization/json.js +12 -2
- package/dist/utility/serialization/json.js.map +1 -1
- package/dist/utility/serialization/manager.js +30 -11
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +250 -7
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +4 -2
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +154 -2
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/cloth_script.js +834 -0
- package/dist/utility/serialization/scene/cloth_script.js.map +1 -0
- package/dist/utility/serialization/scene/common.js +7 -0
- package/dist/utility/serialization/scene/common.js.map +1 -1
- package/dist/utility/serialization/scene/light.js +120 -4
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +453 -1
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +4 -2
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +298 -10
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/particle.js +4 -2
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/primitive.js +100 -3
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/scene.js +130 -3
- package/dist/utility/serialization/scene/scene.js.map +1 -1
- package/dist/utility/serialization/scene/script.js +66 -0
- package/dist/utility/serialization/scene/script.js.map +1 -0
- package/dist/utility/serialization/scene/spring_script.js +596 -0
- package/dist/utility/serialization/scene/spring_script.js.map +1 -0
- package/dist/utility/serialization/scene/sprite.js +5 -3
- package/dist/utility/serialization/scene/sprite.js.map +1 -1
- package/dist/utility/serialization/scene/terrain.js +4 -2
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +4 -2
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/serialization/types.js.map +1 -1
- package/dist/values.js +5 -1
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
package/dist/app/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sources":["../../src/app/engine.ts"],"sourcesContent":["import type { IDisposable, Nullable, ReadOptions } from '@zephyr3d/base';\r\nimport { MemoryFS, objectEntries } from '@zephyr3d/base';\r\nimport { DRef } from '@zephyr3d/base';\r\nimport { HttpFS, type VFS } from '@zephyr3d/base';\r\nimport { ScriptingSystem } from './scriptingsystem';\r\nimport type { Host } from './scriptingsystem';\r\nimport type { RuntimeScript } from './runtimescript';\r\nimport { ResourceManager } from '../utility/serialization/manager';\r\nimport type { Scene } from '../scene';\r\nimport { BoxShape, CylinderShape, PlaneShape, SphereShape, TetrahedronShape, TorusShape } from '../shapes';\r\nimport {\r\n BlinnMaterial,\r\n LambertMaterial,\r\n PBRMetallicRoughnessMaterial,\r\n PBRSpecularGlossinessMaterial,\r\n UnlitMaterial\r\n} from '../material';\r\nimport { StandardSpriteMaterial } from '../material/sprite_std';\r\nimport { ScreenAdapter } from './screen';\r\n\r\n/**\r\n * Interface for objects that can be rendered.\r\n *\r\n * @public\r\n */\r\nexport interface IRenderable extends IDisposable {\r\n render(): void;\r\n}\r\n\r\n/**\r\n * Interface for render hooks to customize rendering behavior.\r\n *\r\n * @public\r\n */\r\nexport interface IRenderHook {\r\n // If presents, called before rendering the renderable. Return `false` to skip rendering.\r\n beforeRender?: (renderable: any) => boolean | void;\r\n // If presents, called after rendering the renderable.\r\n afterRender?: (renderable: any) => void;\r\n}\r\n\r\n/**\r\n * Core engine class managing scripting, serialization, and rendering.\r\n *\r\n * Responsibilities:\r\n * - Manages a {@link ScriptingSystem} for dynamic script attachment and lifecycle.\r\n * - Manages a {@link ResourceManager} for loading scenes and assets.\r\n * - Maintains a list of active renderable objects to be rendered each frame.\r\n * - Provides methods to attach/detach scripts, update scripts, load scenes, and read files.\r\n * - Supports enabling/disabling of runtime operations.\r\n *\r\n * @remarks\r\n * The engine can be configured with a virtual file system (VFS) and script root path.\r\n * It exposes methods to manage scripts on host objects, update scripts each frame,\r\n * load scenes from files, and render active objects.\r\n *\r\n * @public\r\n */\r\nexport class Engine {\r\n private _builtinsVFS: Nullable<MemoryFS>;\r\n private _scriptingSystem: ScriptingSystem;\r\n private _resourceManager: ResourceManager;\r\n private _enabled: boolean;\r\n private _screen: ScreenAdapter;\r\n protected _activeRenderables: {\r\n renderable: DRef<IRenderable>;\r\n hook: Nullable<IRenderHook>;\r\n }[];\r\n private _loadingScenes: Partial<Record<string, Promise<Nullable<Scene>>>>;\r\n /**\r\n * Creates a new runtime manager.\r\n *\r\n * @param VFS - Optional virtual file system passed to the internal {@link ScriptingSystem}.\r\n * @param scriptsRoot - Optional scripts root path within the VFS. Defaults as in `ScriptingSystem`.\r\n * @param enabled - Whether runtime operations are active. Defaults to `true`.\r\n */\r\n constructor(VFS?: VFS, scriptsRoot?: string, enabled?: boolean) {\r\n VFS = VFS ?? new HttpFS('./');\r\n this._builtinsVFS = null;\r\n this._scriptingSystem = new ScriptingSystem({ VFS, scriptsRoot });\r\n this._resourceManager = new ResourceManager(VFS);\r\n this._enabled = enabled ?? true;\r\n this._activeRenderables = [];\r\n this._loadingScenes = {};\r\n this._screen = new ScreenAdapter();\r\n }\r\n /**\r\n * Exposes the instance of {@link ScriptingSystem}.\r\n */\r\n get scriptingSystem() {\r\n return this._scriptingSystem;\r\n }\r\n /**\r\n * Exposes the virtual file system used by the underlying {@link ScriptingSystem}'s registry.\r\n */\r\n get VFS() {\r\n return this._scriptingSystem.registry.VFS;\r\n }\r\n set VFS(vfs: VFS) {\r\n if (vfs !== this._resourceManager.VFS) {\r\n this._resourceManager.VFS?.close();\r\n this._resourceManager.VFS = vfs;\r\n this._scriptingSystem.registry.VFS = vfs;\r\n this.ensureBuiltinVFS();\r\n }\r\n }\r\n /**\r\n * Exposes the instance of {@link ResourceManager}.\r\n */\r\n get resourceManager() {\r\n return this._resourceManager;\r\n }\r\n /**\r\n * Exposes the instanceof {@link Screen}\r\n */\r\n get screen() {\r\n return this._screen;\r\n }\r\n /** @internal */\r\n async init() {\r\n await this.ensureBuiltinVFS();\r\n }\r\n /**\r\n * Detaches all scripts from all hosts, if enabled.\r\n *\r\n * No-op when `enabled === false`.\r\n */\r\n detachAllScripts() {\r\n if (this._enabled) {\r\n this._scriptingSystem.detachAllScripts();\r\n }\r\n }\r\n /**\r\n * Attaches a script module to the given host, if enabled.\r\n *\r\n * When disabled, this method resolves to `null` without side effects.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - Host object to attach the script to.\r\n * @param module - Module identifier to resolve and load.\r\n * @returns The `RuntimeScript<T>` instance, or `null` if disabled or on failure.\r\n */\r\n async attachScript<T extends Host>(host: Nullable<T>, module: string) {\r\n return this._enabled ? await this._scriptingSystem.attachScript(host, module) : null;\r\n }\r\n /**\r\n * Detaches a script from a host, by module ID or instance, if enabled.\r\n *\r\n * No-op when disabled.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - Host to detach from.\r\n * @param idOrInstance - Target script by module ID or instance reference.\r\n */\r\n detachScript<T extends Host>(host: T, idOrInstance: string | RuntimeScript<T>) {\r\n if (this._enabled) {\r\n this._scriptingSystem.detachScript(host, idOrInstance);\r\n }\r\n }\r\n /**\r\n * Gets all scripts attached to a host.\r\n *\r\n * Delegates to {@link ScriptingSystem.getScriptObjects}.\r\n *\r\n * @typeParam T - Expected script type.\r\n * @param host - Host object to query.\r\n * @returns Script instances attached to the host, or an empty array.\r\n */\r\n getScriptObjects<T extends RuntimeScript<any>>(host: unknown) {\r\n return this._scriptingSystem.getScriptObjects(host) as T[];\r\n }\r\n /**\r\n * Ticks all attached scripts by calling their `onUpdate` hooks, if enabled.\r\n *\r\n * Delegates to {@link ScriptingSystem.update}. No-op when disabled.\r\n *\r\n * @param deltaTime - Time since last update in Seconds.\r\n * @param elapsedTime - Total elapsed time in Seconds.\r\n */\r\n update(deltaTime: number, elapsedTime: number) {\r\n if (this._enabled) {\r\n this._scriptingSystem.update(deltaTime, elapsedTime);\r\n }\r\n }\r\n async loadSceneFromFile(path: string) {\r\n path = this.VFS.normalizePath(path);\r\n if (!this._loadingScenes[path]) {\r\n this._loadingScenes[path] = this._loadScene(path);\r\n }\r\n return this._loadingScenes[path]!;\r\n }\r\n setRenderable(renderable: Nullable<IRenderable>, layer = 0, hook?: IRenderHook) {\r\n if (!this._activeRenderables[layer]) {\r\n this._activeRenderables[layer] = {\r\n renderable: new DRef<IRenderable>(null),\r\n hook: null\r\n };\r\n }\r\n this._activeRenderables[layer].hook = hook ?? null;\r\n this._activeRenderables[layer].renderable.set(renderable);\r\n }\r\n async readFile<T extends ReadOptions['encoding'] = 'binary'>(path: string, encoding?: T) {\r\n try {\r\n const content = await this.VFS.readFile(path, { encoding: encoding ?? 'binary' });\r\n return content as T extends 'binary' ? ArrayBuffer : string;\r\n } catch (err) {\r\n console.error(`Read file '${path}' failed: ${err}`);\r\n return null;\r\n }\r\n }\r\n async startup(\r\n startupScene?: Nullable<string>,\r\n splashScreen?: Nullable<string>,\r\n startupScript?: Nullable<string>\r\n ) {\r\n const splashScreenLayer = 9999;\r\n if (splashScreen) {\r\n const splashScreenScene = await this.loadSceneFromFile(splashScreen);\r\n if (splashScreenScene) {\r\n this.setRenderable(splashScreenScene, splashScreenLayer);\r\n }\r\n }\r\n if (startupScript) {\r\n const path =\r\n startupScript.toLowerCase().endsWith('.ts') || startupScript.toLowerCase().endsWith('.js')\r\n ? startupScript.slice(0, -3)\r\n : startupScript;\r\n await this.attachScript(null, path);\r\n }\r\n if (startupScene) {\r\n const scene = await this.loadSceneFromFile(startupScene);\r\n this.setRenderable(scene, 0);\r\n }\r\n this.setRenderable(null, splashScreenLayer);\r\n }\r\n render() {\r\n this._activeRenderables.forEach((info) => {\r\n const render = info.hook?.beforeRender\r\n ? (info.hook.beforeRender(info.renderable.get() ?? null) ?? true)\r\n : true;\r\n if (render) {\r\n info.renderable.get()?.render();\r\n }\r\n if (info.hook?.afterRender) {\r\n info.hook.afterRender(info.renderable.get() ?? null);\r\n }\r\n });\r\n }\r\n private async ensureBuiltinVFS() {\r\n if (!this._builtinsVFS) {\r\n this._builtinsVFS = await this.createBuiltinVFS();\r\n }\r\n this.VFS.unmount('/assets/@builtins');\r\n this.VFS.mount('/assets/@builtins', this._builtinsVFS);\r\n }\r\n private async createBuiltinVFS() {\r\n const fs = new MemoryFS();\r\n const shapeClsMap = {\r\n '/primitives/box.zmsh': BoxShape,\r\n '/primitives/sphere.zmsh': SphereShape,\r\n '/primitives/cylinder.zmsh': CylinderShape,\r\n '/primitives/plane.zmsh': PlaneShape,\r\n '/primitives/torus.zmsh': TorusShape,\r\n '/primitives/tetrahedron.zmsh': TetrahedronShape,\r\n '/materials/unlit.zmtl': UnlitMaterial,\r\n '/materials/lambert.zmtl': LambertMaterial,\r\n '/materials/blinnphong.zmtl': BlinnMaterial,\r\n '/materials/pbr_metallic_roughness.zmtl': PBRMetallicRoughnessMaterial,\r\n '/materials/pbr_specular_glossiness.zmtl': PBRSpecularGlossinessMaterial,\r\n '/materials/sprite_std.zmtl': StandardSpriteMaterial\r\n } as const;\r\n for (const [key] of objectEntries(shapeClsMap)) {\r\n const obj = new shapeClsMap[key]();\r\n await this.writeSerializableObject(fs, 'Default', obj, key);\r\n obj.dispose();\r\n }\r\n fs.readOnly = true;\r\n return fs;\r\n }\r\n private async writeSerializableObject(VFS: VFS, type: string, obj: any, path: string) {\r\n try {\r\n const data = await this.resourceManager.serializeObject(obj);\r\n const content = JSON.stringify({ type, data }, null, 2);\r\n await VFS.writeFile(path, content, { encoding: 'utf8', create: true });\r\n } catch (err) {\r\n console.error(`Write file '${path}' failed: ${err}`);\r\n }\r\n }\r\n private async _loadScene(path: string) {\r\n try {\r\n const scene = await this._resourceManager.loadScene(path);\r\n if (scene) {\r\n if (scene.script) {\r\n try {\r\n await this.attachScript(scene, scene.script);\r\n } catch (err) {\r\n console.error(`Attach script failed: ${err}`);\r\n }\r\n }\r\n const P: Promise<any>[] = [];\r\n const scripts: string[] = [];\r\n scene.rootNode.iterate((node) => {\r\n if (node.script) {\r\n scripts.push(node.script);\r\n P.push(this.attachScript(node, node.script));\r\n }\r\n });\r\n if (P.length > 0) {\r\n const result = await Promise.allSettled(P);\r\n for (let i = 0; i < result.length; i++) {\r\n if (result[i].status === 'rejected') {\r\n console.error(`Attach script failed: ${scripts[i]}`);\r\n }\r\n }\r\n }\r\n }\r\n return scene;\r\n } catch (err) {\r\n console.error(`Load scene from '${path}' failed: ${err}`);\r\n return null;\r\n }\r\n }\r\n}\r\n"],"names":["Engine","_builtinsVFS","_scriptingSystem","_resourceManager","_enabled","_screen","_activeRenderables","_loadingScenes","VFS","scriptsRoot","enabled","HttpFS","ScriptingSystem","ResourceManager","ScreenAdapter","scriptingSystem","registry","vfs","close","ensureBuiltinVFS","resourceManager","screen","init","detachAllScripts","attachScript","host","module","detachScript","idOrInstance","getScriptObjects","update","deltaTime","elapsedTime","loadSceneFromFile","path","normalizePath","_loadScene","setRenderable","renderable","layer","hook","DRef","set","readFile","encoding","content","err","console","error","startup","startupScene","splashScreen","startupScript","splashScreenLayer","splashScreenScene","toLowerCase","endsWith","slice","scene","render","forEach","info","beforeRender","get","afterRender","createBuiltinVFS","unmount","mount","fs","MemoryFS","shapeClsMap","BoxShape","SphereShape","CylinderShape","PlaneShape","TorusShape","TetrahedronShape","UnlitMaterial","LambertMaterial","BlinnMaterial","PBRMetallicRoughnessMaterial","PBRSpecularGlossinessMaterial","StandardSpriteMaterial","key","objectEntries","obj","writeSerializableObject","dispose","readOnly","type","data","serializeObject","JSON","stringify","writeFile","create","loadScene","script","P","scripts","rootNode","iterate","node","push","length","result","Promise","allSettled","i","status"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"engine.js","sources":["../../src/app/engine.ts"],"sourcesContent":["import type { GenericConstructor, IDisposable, Nullable, ReadOptions } from '@zephyr3d/base';\r\nimport { MemoryFS, objectEntries } from '@zephyr3d/base';\r\nimport { DRef } from '@zephyr3d/base';\r\nimport { HttpFS, type VFS } from '@zephyr3d/base';\r\nimport { ScriptingSystem } from './scriptingsystem';\r\nimport type { Host } from './scriptingsystem';\r\nimport type { RuntimeScript, RuntimeScriptConfig } from './runtimescript';\r\nimport { ResourceManager } from '../utility/serialization/manager';\r\nimport type { Scene } from '../scene';\r\nimport {\r\n BoxShape,\r\n CapsuleShape,\r\n CylinderShape,\r\n PlaneShape,\r\n SphereShape,\r\n TetrahedronShape,\r\n TorusShape\r\n} from '../shapes';\r\nimport {\r\n BlinnMaterial,\r\n LambertMaterial,\r\n PBRMetallicRoughnessMaterial,\r\n PBRSpecularGlossinessMaterial,\r\n UnlitMaterial\r\n} from '../material';\r\nimport { StandardSpriteMaterial } from '../material/sprite_std';\r\nimport { ScreenAdapter } from './screen';\r\n\r\n/**\r\n * Interface for objects that can be rendered.\r\n *\r\n * @public\r\n */\r\nexport interface IRenderable extends IDisposable {\r\n render(): void;\r\n}\r\n\r\n/**\r\n * Interface for render hooks to customize rendering behavior.\r\n *\r\n * @public\r\n */\r\nexport interface IRenderHook {\r\n // If presents, called before rendering the renderable. Return `false` to skip rendering.\r\n beforeRender?: (renderable: any) => boolean | void;\r\n // If presents, called after rendering the renderable.\r\n afterRender?: (renderable: any) => void;\r\n}\r\n\r\n/**\r\n * Core engine class managing scripting, serialization, and rendering.\r\n *\r\n * Responsibilities:\r\n * - Manages a {@link ScriptingSystem} for dynamic script attachment and lifecycle.\r\n * - Manages a {@link ResourceManager} for loading scenes and assets.\r\n * - Maintains a list of active renderable objects to be rendered each frame.\r\n * - Provides methods to attach/detach scripts, update scripts, load scenes, and read files.\r\n * - Supports enabling/disabling of runtime operations.\r\n *\r\n * @remarks\r\n * The engine can be configured with a virtual file system (VFS) and script root path.\r\n * It exposes methods to manage scripts on host objects, update scripts each frame,\r\n * load scenes from files, and render active objects.\r\n *\r\n * @public\r\n */\r\nexport class Engine {\r\n private _builtinsVFS: Nullable<MemoryFS>;\r\n private _scriptingSystem: ScriptingSystem;\r\n private _resourceManager: ResourceManager;\r\n private _enabled: boolean;\r\n private _screen: ScreenAdapter;\r\n protected _activeRenderables: {\r\n renderable: DRef<IRenderable>;\r\n hook: Nullable<IRenderHook>;\r\n }[];\r\n private _loadingScenes: Partial<Record<string, Promise<Nullable<Scene>>>>;\r\n /**\r\n * Creates a new runtime manager.\r\n *\r\n * @param VFS - Optional virtual file system passed to the internal {@link ScriptingSystem}.\r\n * @param scriptsRoot - Optional scripts root path within the VFS. Defaults as in `ScriptingSystem`.\r\n * @param enabled - Whether runtime operations are active. Defaults to `true`.\r\n */\r\n constructor(VFS?: VFS, scriptsRoot?: string, enabled?: boolean) {\r\n VFS = VFS ?? new HttpFS('./');\r\n this._builtinsVFS = null;\r\n this._scriptingSystem = new ScriptingSystem({ VFS, scriptsRoot });\r\n this._resourceManager = new ResourceManager(VFS);\r\n this._enabled = enabled ?? true;\r\n this._activeRenderables = [];\r\n this._loadingScenes = {};\r\n this._screen = new ScreenAdapter();\r\n }\r\n /**\r\n * Exposes the instance of {@link ScriptingSystem}.\r\n */\r\n get scriptingSystem() {\r\n return this._scriptingSystem;\r\n }\r\n /**\r\n * Exposes the virtual file system used by the underlying {@link ScriptingSystem}'s registry.\r\n */\r\n get VFS() {\r\n return this._scriptingSystem.registry.VFS;\r\n }\r\n set VFS(vfs: VFS) {\r\n if (vfs !== this._resourceManager.VFS) {\r\n this._resourceManager.VFS?.close();\r\n this._resourceManager.VFS = vfs;\r\n this._scriptingSystem.registry.VFS = vfs;\r\n this.ensureBuiltinVFS();\r\n }\r\n }\r\n /**\r\n * Exposes the instance of {@link ResourceManager}.\r\n */\r\n get resourceManager() {\r\n return this._resourceManager;\r\n }\r\n /**\r\n * Exposes the instanceof {@link Screen}\r\n */\r\n get screen() {\r\n return this._screen;\r\n }\r\n /** @internal */\r\n async init() {\r\n await this.ensureBuiltinVFS();\r\n }\r\n /**\r\n * Detaches all scripts from all hosts, if enabled.\r\n *\r\n * No-op when `enabled === false`.\r\n */\r\n detachAllScripts() {\r\n if (this._enabled) {\r\n this._scriptingSystem.detachAllScripts();\r\n }\r\n }\r\n /**\r\n * Loads a runtime script class from file\r\n * @param module - file path\r\n * @returns The runtime script class or null\r\n */\r\n async loadRuntimeScriptClass<T extends Host = Host>(\r\n module: string\r\n ): Promise<Nullable<{ url: string; cls: GenericConstructor<RuntimeScript<T>> }>> {\r\n return await this._scriptingSystem.loadRuntimeScriptClass(module);\r\n }\r\n /**\r\n * Attaches a script module to the given host, if enabled.\r\n *\r\n * When disabled, this method resolves to `null` without side effects.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - Host object to attach the script to.\r\n * @param module - Module identifier to resolve and load.\r\n * @returns The `RuntimeScript<T>` instance, or `null` if disabled or on failure.\r\n */\r\n async attachScript<T extends Host>(\r\n host: Nullable<T>,\r\n module: string,\r\n config?: Nullable<RuntimeScriptConfig>\r\n ) {\r\n return this._enabled ? await this._scriptingSystem.attachScript(host, module, config) : null;\r\n }\r\n /**\r\n * Detaches a script from a host, by module ID or instance, if enabled.\r\n *\r\n * No-op when disabled.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - Host to detach from.\r\n * @param idOrInstance - Target script by module ID or instance reference.\r\n */\r\n detachScript<T extends Host>(host: T, idOrInstance: string | RuntimeScript<T>) {\r\n if (this._enabled) {\r\n this._scriptingSystem.detachScript(host, idOrInstance);\r\n }\r\n }\r\n /**\r\n * Gets all scripts attached to a host.\r\n *\r\n * Delegates to {@link ScriptingSystem.getScriptObjects}.\r\n *\r\n * @typeParam T - Expected script type.\r\n * @param host - Host object to query.\r\n * @returns Script instances attached to the host, or an empty array.\r\n */\r\n getScriptObjects<T extends RuntimeScript<any>>(host: unknown) {\r\n return this._scriptingSystem.getScriptObjects(host) as T[];\r\n }\r\n /**\r\n * Ticks all attached scripts by calling their `onUpdate` hooks, if enabled.\r\n *\r\n * Delegates to {@link ScriptingSystem.update}. No-op when disabled.\r\n *\r\n * @param deltaTime - Time since last update in Seconds.\r\n * @param elapsedTime - Total elapsed time in Seconds.\r\n */\r\n update(deltaTime: number, elapsedTime: number) {\r\n if (this._enabled) {\r\n this._scriptingSystem.update(deltaTime, elapsedTime);\r\n }\r\n }\r\n async loadSceneFromFile(path: string) {\r\n path = this.VFS.normalizePath(path);\r\n if (!this._loadingScenes[path]) {\r\n this._loadingScenes[path] = this._loadScene(path);\r\n }\r\n return this._loadingScenes[path]!;\r\n }\r\n setRenderable(renderable: Nullable<IRenderable>, layer = 0, hook?: IRenderHook) {\r\n if (!this._activeRenderables[layer]) {\r\n this._activeRenderables[layer] = {\r\n renderable: new DRef<IRenderable>(null),\r\n hook: null\r\n };\r\n }\r\n this._activeRenderables[layer].hook = hook ?? null;\r\n this._activeRenderables[layer].renderable.set(renderable);\r\n }\r\n async readFile<T extends ReadOptions['encoding'] = 'binary'>(path: string, encoding?: T) {\r\n try {\r\n const content = await this.VFS.readFile(path, { encoding: encoding ?? 'binary' });\r\n return content as T extends 'binary' ? ArrayBuffer : string;\r\n } catch (err) {\r\n console.error(`Read file '${path}' failed: ${err}`);\r\n return null;\r\n }\r\n }\r\n async startup(\r\n startupScene?: Nullable<string>,\r\n splashScreen?: Nullable<string>,\r\n startupScript?: Nullable<string>\r\n ) {\r\n const splashScreenLayer = 9999;\r\n if (splashScreen) {\r\n const splashScreenScene = await this.loadSceneFromFile(splashScreen);\r\n if (splashScreenScene) {\r\n this.setRenderable(splashScreenScene, splashScreenLayer);\r\n }\r\n }\r\n if (startupScript) {\r\n const path =\r\n startupScript.toLowerCase().endsWith('.ts') || startupScript.toLowerCase().endsWith('.js')\r\n ? startupScript.slice(0, -3)\r\n : startupScript;\r\n await this.attachScript(null, path);\r\n }\r\n if (startupScene) {\r\n const scene = await this.loadSceneFromFile(startupScene);\r\n this.setRenderable(scene, 0);\r\n }\r\n this.setRenderable(null, splashScreenLayer);\r\n }\r\n render() {\r\n this._activeRenderables.forEach((info) => {\r\n const render = info.hook?.beforeRender\r\n ? (info.hook.beforeRender(info.renderable.get() ?? null) ?? true)\r\n : true;\r\n if (render) {\r\n info.renderable.get()?.render();\r\n }\r\n if (info.hook?.afterRender) {\r\n info.hook.afterRender(info.renderable.get() ?? null);\r\n }\r\n });\r\n }\r\n private async ensureBuiltinVFS() {\r\n if (!this._builtinsVFS) {\r\n this._builtinsVFS = await this.createBuiltinVFS();\r\n }\r\n this.VFS.unmount('/assets/@builtins');\r\n this.VFS.mount('/assets/@builtins', this._builtinsVFS);\r\n }\r\n private async createBuiltinVFS() {\r\n const fs = new MemoryFS();\r\n const shapeClsMap = {\r\n '/primitives/box.zmsh': BoxShape,\r\n '/primitives/sphere.zmsh': SphereShape,\r\n '/primitives/cylinder.zmsh': CylinderShape,\r\n '/primitives/plane.zmsh': PlaneShape,\r\n '/primitives/torus.zmsh': TorusShape,\r\n '/primitives/tetrahedron.zmsh': TetrahedronShape,\r\n '/primitives/capsule.zmsh': CapsuleShape,\r\n '/materials/unlit.zmtl': UnlitMaterial,\r\n '/materials/lambert.zmtl': LambertMaterial,\r\n '/materials/blinnphong.zmtl': BlinnMaterial,\r\n '/materials/pbr_metallic_roughness.zmtl': PBRMetallicRoughnessMaterial,\r\n '/materials/pbr_specular_glossiness.zmtl': PBRSpecularGlossinessMaterial,\r\n '/materials/sprite_std.zmtl': StandardSpriteMaterial\r\n } as const;\r\n for (const [key] of objectEntries(shapeClsMap)) {\r\n const obj = new shapeClsMap[key]();\r\n await this.writeSerializableObject(fs, 'Default', obj, key);\r\n obj.dispose();\r\n }\r\n fs.readOnly = true;\r\n return fs;\r\n }\r\n private async writeSerializableObject(VFS: VFS, type: string, obj: any, path: string) {\r\n try {\r\n const data = await this.resourceManager.serializeObject(obj);\r\n const content = JSON.stringify({ type, data }, null, 2);\r\n await VFS.writeFile(path, content, { encoding: 'utf8', create: true });\r\n } catch (err) {\r\n console.error(`Write file '${path}' failed: ${err}`);\r\n }\r\n }\r\n private async _loadScene(path: string) {\r\n try {\r\n const scene = await this._resourceManager.loadScene(path);\r\n if (scene) {\r\n const sceneScripts =\r\n scene.scripts.length > 0\r\n ? scene.scripts\r\n : scene.script\r\n ? [{ script: scene.script, config: scene.scriptConfig }]\r\n : [];\r\n for (const attachment of sceneScripts) {\r\n if (!attachment.script) {\r\n continue;\r\n }\r\n try {\r\n await this.attachScript(\r\n scene,\r\n attachment.script,\r\n (attachment.config ?? null) as RuntimeScriptConfig | null\r\n );\r\n } catch (err) {\r\n console.error(`Attach script failed: ${err}`);\r\n }\r\n }\r\n const nodes: (typeof scene.rootNode)[] = [];\r\n scene.rootNode.iterate((node) => {\r\n nodes.push(node);\r\n });\r\n const attachTasks = nodes.map(async (node) => {\r\n const attachments =\r\n node.scripts.length > 0\r\n ? node.scripts\r\n : node.script\r\n ? [{ script: node.script, config: node.scriptConfig }]\r\n : [];\r\n for (const attachment of attachments) {\r\n if (!attachment.script) {\r\n continue;\r\n }\r\n try {\r\n await this.attachScript(\r\n node,\r\n attachment.script,\r\n (attachment.config ?? null) as RuntimeScriptConfig | null\r\n );\r\n } catch (err) {\r\n console.error(`Attach script failed: ${err}`);\r\n }\r\n }\r\n });\r\n if (attachTasks.length > 0) {\r\n await Promise.allSettled(attachTasks);\r\n }\r\n }\r\n return scene;\r\n } catch (err) {\r\n console.error(`Load scene from '${path}' failed: ${err}`);\r\n return null;\r\n }\r\n }\r\n}\r\n"],"names":["Engine","_builtinsVFS","_scriptingSystem","_resourceManager","_enabled","_screen","_activeRenderables","_loadingScenes","VFS","scriptsRoot","enabled","HttpFS","ScriptingSystem","ResourceManager","ScreenAdapter","scriptingSystem","registry","vfs","close","ensureBuiltinVFS","resourceManager","screen","init","detachAllScripts","loadRuntimeScriptClass","module","attachScript","host","config","detachScript","idOrInstance","getScriptObjects","update","deltaTime","elapsedTime","loadSceneFromFile","path","normalizePath","_loadScene","setRenderable","renderable","layer","hook","DRef","set","readFile","encoding","content","err","console","error","startup","startupScene","splashScreen","startupScript","splashScreenLayer","splashScreenScene","toLowerCase","endsWith","slice","scene","render","forEach","info","beforeRender","get","afterRender","createBuiltinVFS","unmount","mount","fs","MemoryFS","shapeClsMap","BoxShape","SphereShape","CylinderShape","PlaneShape","TorusShape","TetrahedronShape","CapsuleShape","UnlitMaterial","LambertMaterial","BlinnMaterial","PBRMetallicRoughnessMaterial","PBRSpecularGlossinessMaterial","StandardSpriteMaterial","key","objectEntries","obj","writeSerializableObject","dispose","readOnly","type","data","serializeObject","JSON","stringify","writeFile","create","loadScene","sceneScripts","scripts","length","script","scriptConfig","attachment","nodes","rootNode","iterate","node","push","attachTasks","map","attachments","Promise","allSettled"],"mappings":"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"}
|
|
@@ -1,3 +1,127 @@
|
|
|
1
|
+
const runtimeScriptPropertiesKey = Symbol('zephyr3d.runtimeScriptProperties');
|
|
2
|
+
function cloneRuntimeScriptValue(value) {
|
|
3
|
+
if (Array.isArray(value)) {
|
|
4
|
+
return value.map((item)=>cloneRuntimeScriptValue(item));
|
|
5
|
+
}
|
|
6
|
+
if (value && typeof value === 'object') {
|
|
7
|
+
const result = {};
|
|
8
|
+
for (const [key, item] of Object.entries(value)){
|
|
9
|
+
result[key] = cloneRuntimeScriptValue(item);
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
function getOwnRuntimeScriptProperties(ctor) {
|
|
16
|
+
return ctor[runtimeScriptPropertiesKey] ?? [];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Marks a runtime script field as configurable and serializable in editor/runtime tooling.
|
|
20
|
+
*
|
|
21
|
+
* @param options - Metadata describing how the field should be edited and serialized.
|
|
22
|
+
* @returns A property decorator.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/ function scriptProp(options) {
|
|
26
|
+
return (target, propertyKey)=>{
|
|
27
|
+
if (typeof propertyKey !== 'string') {
|
|
28
|
+
throw new Error('Runtime script property name must be a string');
|
|
29
|
+
}
|
|
30
|
+
const ctor = target.constructor;
|
|
31
|
+
const own = getOwnRuntimeScriptProperties(ctor).slice();
|
|
32
|
+
const normalized = options.type === 'object_array' ? {
|
|
33
|
+
...options,
|
|
34
|
+
default: cloneRuntimeScriptValue(options.default) ?? [],
|
|
35
|
+
name: propertyKey
|
|
36
|
+
} : {
|
|
37
|
+
...options,
|
|
38
|
+
default: cloneRuntimeScriptValue(options.default),
|
|
39
|
+
name: propertyKey
|
|
40
|
+
};
|
|
41
|
+
const index = own.findIndex((item)=>item.name === propertyKey);
|
|
42
|
+
if (index >= 0) {
|
|
43
|
+
own[index] = normalized;
|
|
44
|
+
} else {
|
|
45
|
+
own.push(normalized);
|
|
46
|
+
}
|
|
47
|
+
Object.defineProperty(ctor, runtimeScriptPropertiesKey, {
|
|
48
|
+
configurable: true,
|
|
49
|
+
enumerable: false,
|
|
50
|
+
writable: true,
|
|
51
|
+
value: own
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Gets the serialized parameter metadata declared on a runtime script class.
|
|
57
|
+
*
|
|
58
|
+
* Inheritance is supported: base-class metadata is returned before derived-class metadata,
|
|
59
|
+
* and derived declarations override base declarations with the same property name.
|
|
60
|
+
*
|
|
61
|
+
* @param ctor - Runtime script constructor.
|
|
62
|
+
* @returns Declared parameter metadata.
|
|
63
|
+
*
|
|
64
|
+
* @public
|
|
65
|
+
*/ function getRuntimeScriptProperties(ctor) {
|
|
66
|
+
const chain = [];
|
|
67
|
+
let current = ctor;
|
|
68
|
+
while(typeof current === 'function' && current !== RuntimeScript && current !== Function.prototype){
|
|
69
|
+
chain.unshift(current);
|
|
70
|
+
current = Object.getPrototypeOf(current);
|
|
71
|
+
}
|
|
72
|
+
const merged = new Map();
|
|
73
|
+
for (const type of chain){
|
|
74
|
+
for (const prop of getOwnRuntimeScriptProperties(type)){
|
|
75
|
+
const normalized = prop.type === 'object_array' ? {
|
|
76
|
+
...prop,
|
|
77
|
+
default: cloneRuntimeScriptValue(prop.default) ?? []
|
|
78
|
+
} : {
|
|
79
|
+
...prop,
|
|
80
|
+
default: cloneRuntimeScriptValue(prop.default)
|
|
81
|
+
};
|
|
82
|
+
merged.set(prop.name, normalized);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return [
|
|
86
|
+
...merged.values()
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Merges user-provided script configuration with declared defaults.
|
|
91
|
+
*
|
|
92
|
+
* Only decorated fields are included in the result.
|
|
93
|
+
*
|
|
94
|
+
* @param ctor - Runtime script constructor.
|
|
95
|
+
* @param config - Serialized configuration payload.
|
|
96
|
+
* @returns Normalized configuration object.
|
|
97
|
+
*
|
|
98
|
+
* @public
|
|
99
|
+
*/ function normalizeRuntimeScriptConfig(ctor, config) {
|
|
100
|
+
const result = {};
|
|
101
|
+
for (const prop of getRuntimeScriptProperties(ctor)){
|
|
102
|
+
if (config && Object.prototype.hasOwnProperty.call(config, prop.name)) {
|
|
103
|
+
result[prop.name] = cloneRuntimeScriptValue(config[prop.name]);
|
|
104
|
+
} else if (prop.default !== undefined) {
|
|
105
|
+
result[prop.name] = cloneRuntimeScriptValue(prop.default);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Applies normalized configuration values onto a runtime script instance.
|
|
112
|
+
*
|
|
113
|
+
* Values are assigned before lifecycle hooks such as `onCreated()` run.
|
|
114
|
+
*
|
|
115
|
+
* @param instance - Runtime script instance.
|
|
116
|
+
* @param config - Serialized configuration payload.
|
|
117
|
+
*
|
|
118
|
+
* @public
|
|
119
|
+
*/ function applyRuntimeScriptConfig(instance, config) {
|
|
120
|
+
const normalized = normalizeRuntimeScriptConfig(instance.constructor, config);
|
|
121
|
+
for (const [key, value] of Object.entries(normalized)){
|
|
122
|
+
instance[key] = cloneRuntimeScriptValue(value);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
1
125
|
/**
|
|
2
126
|
* Base class for runtime scripts that can be attached to a host object.
|
|
3
127
|
*
|
|
@@ -19,6 +143,13 @@
|
|
|
19
143
|
* @public
|
|
20
144
|
*/ class RuntimeScript {
|
|
21
145
|
/**
|
|
146
|
+
* Gets merged serialized property metadata for this runtime script class.
|
|
147
|
+
*
|
|
148
|
+
* @returns Declared parameter metadata for the current class.
|
|
149
|
+
*/ static getScriptProperties() {
|
|
150
|
+
return getRuntimeScriptProperties(this);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
22
153
|
* Called once after construction, before the first attachment to a host.
|
|
23
154
|
*
|
|
24
155
|
* Use this to initialize internal state, allocate resources, or kick off
|
|
@@ -58,5 +189,5 @@
|
|
|
58
189
|
*/ onDestroy() {}
|
|
59
190
|
}
|
|
60
191
|
|
|
61
|
-
export { RuntimeScript };
|
|
192
|
+
export { RuntimeScript, applyRuntimeScriptConfig, getRuntimeScriptProperties, normalizeRuntimeScriptConfig, scriptProp };
|
|
62
193
|
//# sourceMappingURL=runtimescript.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimescript.js","sources":["../../src/app/runtimescript.ts"],"sourcesContent":["import type { IDisposable, Nullable } from '@zephyr3d/base';\r\n\r\n/**\r\n * Base class for runtime scripts that can be attached to a host object.\r\n *\r\n * Lifecycle overview:\r\n * - onCreated(): Called once per script instance right after construction,\r\n * before any host is attached.\r\n * - onAttached(host): Called each time this instance is attached to a host.\r\n * - onUpdate(deltaTime, elapsedTime): Called every frame/tick while attached.\r\n * - onDetached(host): Called when detached from a host.\r\n * - onDestroy(): Called when the instance is no longer attached to any host\r\n * and is about to be discarded.\r\n *\r\n * Notes:\r\n * - Hooks may return a Promise to perform asynchronous work (e.g., asset loading).\r\n * - The generic host type `T` can be `IDisposable` or `null`. If `null`, the script\r\n * may operate without a concrete host.\r\n *\r\n * @typeParam T - The host type that this script attaches to. Typically implements `IDisposable`.\r\n * @public\r\n */\r\nexport class RuntimeScript<T extends IDisposable | null> {\r\n /**\r\n * Called once after construction, before the first attachment to a host.\r\n *\r\n * Use this to initialize internal state, allocate resources, or kick off\r\n * asynchronous loading needed by the script.\r\n *\r\n * @returns Optionally a Promise to await initialization.\r\n */\r\n onCreated(): void | Promise<void> {}\r\n /**\r\n * Called when the script is attached to a host.\r\n *\r\n * This may be called multiple times if the same instance attaches to different\r\n * hosts over its lifetime.\r\n *\r\n * @param _host - The host the script is being attached to.\r\n * @returns Optionally a Promise to await asynchronous setup.\r\n */\r\n onAttached(_host: Nullable<T>): void | Promise<void> {}\r\n /**\r\n * Called every update/tick while the script is active.\r\n *\r\n * Typical usage includes per-frame logic, animation, and input handling.\r\n *\r\n * @param _deltaTime - Time since last update in seconds.\r\n * @param _elapsedTime - Total elapsed time since start in seconds.\r\n */\r\n onUpdate(_deltaTime: number, _elapsedTime: number) {}\r\n /**\r\n * Called when the script is detached from a host.\r\n *\r\n * Use this to stop host-specific behaviors and release host-bound resources.\r\n *\r\n * @param _host - The host the script is being detached from.\r\n */\r\n onDetached(_host: T) {}\r\n /**\r\n * Called when the script has no remaining hosts and is about to be discarded.\r\n *\r\n * Use this to release global resources and finalize the script's lifecycle.\r\n * This is the terminal lifecycle hook for an instance.\r\n */\r\n onDestroy() {}\r\n}\r\n"],"names":["RuntimeScript","onCreated","onAttached","_host","onUpdate","_deltaTime","_elapsedTime","onDetached","onDestroy"],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;AAmBC,IACM,MAAMA,aAAAA,CAAAA;AACX;;;;;;;AAOC,MACDC,YAAkC;AAClC;;;;;;;;MASAC,UAAAA,CAAWC,KAAkB,EAAwB;AACrD;;;;;;;AAOC,MACDC,QAASC,CAAAA,UAAkB,EAAEC,YAAoB,EAAE;AACnD;;;;;;MAOAC,UAAAA,CAAWJ,KAAQ,EAAE;AACrB;;;;;AAKC,MACDK,YAAY;AACd;;;;"}
|
|
1
|
+
{"version":3,"file":"runtimescript.js","sources":["../../src/app/runtimescript.ts"],"sourcesContent":["import type { GenericConstructor, IDisposable, Nullable } from '@zephyr3d/base';\r\n\r\n/**\r\n * Supported serialized field types for runtime script parameters.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptPropertyType =\r\n | 'bool'\r\n | 'int'\r\n | 'float'\r\n | 'int2'\r\n | 'int3'\r\n | 'int4'\r\n | 'vec2'\r\n | 'vec3'\r\n | 'vec4'\r\n | 'rgb'\r\n | 'rgba'\r\n | 'string'\r\n | 'asset'\r\n | 'node'\r\n | 'object_array';\r\n\r\n/**\r\n * Runtime script property types that can be used as a single value or array element.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptValueType = Exclude<RuntimeScriptPropertyType, 'object_array'>;\r\n\r\n/**\r\n * Additional editor hints for runtime script parameters.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptPropertyOptions = {\r\n label?: string;\r\n group?: string;\r\n hidden?: boolean;\r\n minValue?: number;\r\n maxValue?: number;\r\n speed?: number;\r\n mimeTypes?: string[];\r\n sceneNode?: {\r\n kind?: 'node' | 'mesh';\r\n };\r\n enum?: {\r\n labels: string[];\r\n values: unknown[];\r\n };\r\n};\r\n\r\n/**\r\n * Decorator configuration for a serialized runtime script parameter element.\r\n *\r\n * This shape is used for scalar values and for `object_array.element`.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptValueDeclaration = RuntimeScriptPropertyOptions & {\r\n type: RuntimeScriptValueType;\r\n default?: unknown;\r\n};\r\n\r\n/**\r\n * Decorator configuration for a named field inside a structured object-array element.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptObjectFieldDeclaration = RuntimeScriptValueDeclaration & {\r\n name: string;\r\n};\r\n\r\n/**\r\n * Decorator configuration for a structured object-array element.\r\n *\r\n * This is only valid as `object_array.element`.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptObjectDeclaration = {\r\n type: 'object';\r\n fields: RuntimeScriptObjectFieldDeclaration[];\r\n default?: Record<string, unknown>;\r\n};\r\n\r\n/**\r\n * Supported element declarations for `object_array`.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptArrayElementDeclaration =\r\n | RuntimeScriptValueDeclaration\r\n | RuntimeScriptObjectDeclaration;\r\n\r\n/**\r\n * Decorator configuration for an array-typed runtime script parameter.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptArrayDeclaration = RuntimeScriptPropertyOptions & {\r\n type: 'object_array';\r\n element: RuntimeScriptArrayElementDeclaration;\r\n default?: unknown[];\r\n};\r\n\r\n/**\r\n * Decorator configuration for a serialized runtime script parameter.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptPropertyDeclaration = RuntimeScriptValueDeclaration | RuntimeScriptArrayDeclaration;\r\n\r\n/**\r\n * Resolved runtime script parameter metadata.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptPropertyInfo = RuntimeScriptPropertyDeclaration & {\r\n name: string;\r\n};\r\n\r\n/**\r\n * Serialized runtime script configuration payload.\r\n *\r\n * @public\r\n */\r\nexport type RuntimeScriptConfig = Record<string, unknown>;\r\n\r\nconst runtimeScriptPropertiesKey = Symbol('zephyr3d.runtimeScriptProperties');\r\n\r\nfunction cloneRuntimeScriptValue<T>(value: T): T {\r\n if (Array.isArray(value)) {\r\n return value.map((item) => cloneRuntimeScriptValue(item)) as T;\r\n }\r\n if (value && typeof value === 'object') {\r\n const result: Record<string, unknown> = {};\r\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\r\n result[key] = cloneRuntimeScriptValue(item);\r\n }\r\n return result as T;\r\n }\r\n return value;\r\n}\r\n\r\nfunction getOwnRuntimeScriptProperties(ctor: GenericConstructor) {\r\n return ((ctor as any)[runtimeScriptPropertiesKey] ?? []) as RuntimeScriptPropertyInfo[];\r\n}\r\n\r\n/**\r\n * Marks a runtime script field as configurable and serializable in editor/runtime tooling.\r\n *\r\n * @param options - Metadata describing how the field should be edited and serialized.\r\n * @returns A property decorator.\r\n *\r\n * @public\r\n */\r\nexport function scriptProp(options: RuntimeScriptPropertyDeclaration): PropertyDecorator {\r\n return (target, propertyKey) => {\r\n if (typeof propertyKey !== 'string') {\r\n throw new Error('Runtime script property name must be a string');\r\n }\r\n const ctor = target.constructor as GenericConstructor;\r\n const own = getOwnRuntimeScriptProperties(ctor).slice();\r\n const normalized: RuntimeScriptPropertyInfo =\r\n options.type === 'object_array'\r\n ? {\r\n ...options,\r\n default: (cloneRuntimeScriptValue(options.default) as unknown[]) ?? [],\r\n name: propertyKey\r\n }\r\n : {\r\n ...options,\r\n default: cloneRuntimeScriptValue(options.default),\r\n name: propertyKey\r\n };\r\n const index = own.findIndex((item) => item.name === propertyKey);\r\n if (index >= 0) {\r\n own[index] = normalized;\r\n } else {\r\n own.push(normalized);\r\n }\r\n Object.defineProperty(ctor, runtimeScriptPropertiesKey, {\r\n configurable: true,\r\n enumerable: false,\r\n writable: true,\r\n value: own\r\n });\r\n };\r\n}\r\n\r\n/**\r\n * Gets the serialized parameter metadata declared on a runtime script class.\r\n *\r\n * Inheritance is supported: base-class metadata is returned before derived-class metadata,\r\n * and derived declarations override base declarations with the same property name.\r\n *\r\n * @param ctor - Runtime script constructor.\r\n * @returns Declared parameter metadata.\r\n *\r\n * @public\r\n */\r\nexport function getRuntimeScriptProperties(ctor: GenericConstructor): RuntimeScriptPropertyInfo[] {\r\n const chain: GenericConstructor[] = [];\r\n let current: any = ctor;\r\n while (typeof current === 'function' && current !== RuntimeScript && current !== Function.prototype) {\r\n chain.unshift(current);\r\n current = Object.getPrototypeOf(current);\r\n }\r\n const merged = new Map<string, RuntimeScriptPropertyInfo>();\r\n for (const type of chain) {\r\n for (const prop of getOwnRuntimeScriptProperties(type)) {\r\n const normalized =\r\n prop.type === 'object_array'\r\n ? ({\r\n ...prop,\r\n default: (cloneRuntimeScriptValue(prop.default) as unknown[]) ?? []\r\n } satisfies RuntimeScriptPropertyInfo)\r\n : ({\r\n ...prop,\r\n default: cloneRuntimeScriptValue(prop.default)\r\n } satisfies RuntimeScriptPropertyInfo);\r\n merged.set(prop.name, normalized);\r\n }\r\n }\r\n return [...merged.values()];\r\n}\r\n\r\n/**\r\n * Merges user-provided script configuration with declared defaults.\r\n *\r\n * Only decorated fields are included in the result.\r\n *\r\n * @param ctor - Runtime script constructor.\r\n * @param config - Serialized configuration payload.\r\n * @returns Normalized configuration object.\r\n *\r\n * @public\r\n */\r\nexport function normalizeRuntimeScriptConfig(\r\n ctor: GenericConstructor,\r\n config?: Nullable<RuntimeScriptConfig>\r\n): RuntimeScriptConfig {\r\n const result: RuntimeScriptConfig = {};\r\n for (const prop of getRuntimeScriptProperties(ctor)) {\r\n if (config && Object.prototype.hasOwnProperty.call(config, prop.name)) {\r\n result[prop.name] = cloneRuntimeScriptValue(config[prop.name]);\r\n } else if (prop.default !== undefined) {\r\n result[prop.name] = cloneRuntimeScriptValue(prop.default);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Applies normalized configuration values onto a runtime script instance.\r\n *\r\n * Values are assigned before lifecycle hooks such as `onCreated()` run.\r\n *\r\n * @param instance - Runtime script instance.\r\n * @param config - Serialized configuration payload.\r\n *\r\n * @public\r\n */\r\nexport function applyRuntimeScriptConfig<T extends RuntimeScript<any>>(\r\n instance: T,\r\n config?: Nullable<RuntimeScriptConfig>\r\n) {\r\n const normalized = normalizeRuntimeScriptConfig(instance.constructor as GenericConstructor, config);\r\n for (const [key, value] of Object.entries(normalized)) {\r\n (instance as Record<string, unknown>)[key] = cloneRuntimeScriptValue(value);\r\n }\r\n}\r\n\r\n/**\r\n * Base class for runtime scripts that can be attached to a host object.\r\n *\r\n * Lifecycle overview:\r\n * - onCreated(): Called once per script instance right after construction,\r\n * before any host is attached.\r\n * - onAttached(host): Called each time this instance is attached to a host.\r\n * - onUpdate(deltaTime, elapsedTime): Called every frame/tick while attached.\r\n * - onDetached(host): Called when detached from a host.\r\n * - onDestroy(): Called when the instance is no longer attached to any host\r\n * and is about to be discarded.\r\n *\r\n * Notes:\r\n * - Hooks may return a Promise to perform asynchronous work (e.g., asset loading).\r\n * - The generic host type `T` can be `IDisposable` or `null`. If `null`, the script\r\n * may operate without a concrete host.\r\n *\r\n * @typeParam T - The host type that this script attaches to. Typically implements `IDisposable`.\r\n * @public\r\n */\r\nexport class RuntimeScript<T extends IDisposable | null> {\r\n /**\r\n * Gets merged serialized property metadata for this runtime script class.\r\n *\r\n * @returns Declared parameter metadata for the current class.\r\n */\r\n static getScriptProperties(this: GenericConstructor) {\r\n return getRuntimeScriptProperties(this);\r\n }\r\n /**\r\n * Called once after construction, before the first attachment to a host.\r\n *\r\n * Use this to initialize internal state, allocate resources, or kick off\r\n * asynchronous loading needed by the script.\r\n *\r\n * @returns Optionally a Promise to await initialization.\r\n */\r\n onCreated(): void | Promise<void> {}\r\n /**\r\n * Called when the script is attached to a host.\r\n *\r\n * This may be called multiple times if the same instance attaches to different\r\n * hosts over its lifetime.\r\n *\r\n * @param _host - The host the script is being attached to.\r\n * @returns Optionally a Promise to await asynchronous setup.\r\n */\r\n onAttached(_host: Nullable<T>): void | Promise<void> {}\r\n /**\r\n * Called every update/tick while the script is active.\r\n *\r\n * Typical usage includes per-frame logic, animation, and input handling.\r\n *\r\n * @param _deltaTime - Time since last update in seconds.\r\n * @param _elapsedTime - Total elapsed time since start in seconds.\r\n */\r\n onUpdate(_deltaTime: number, _elapsedTime: number) {}\r\n /**\r\n * Called when the script is detached from a host.\r\n *\r\n * Use this to stop host-specific behaviors and release host-bound resources.\r\n *\r\n * @param _host - The host the script is being detached from.\r\n */\r\n onDetached(_host: T) {}\r\n /**\r\n * Called when the script has no remaining hosts and is about to be discarded.\r\n *\r\n * Use this to release global resources and finalize the script's lifecycle.\r\n * This is the terminal lifecycle hook for an instance.\r\n */\r\n onDestroy() {}\r\n}\r\n"],"names":["runtimeScriptPropertiesKey","Symbol","cloneRuntimeScriptValue","value","Array","isArray","map","item","result","key","Object","entries","getOwnRuntimeScriptProperties","ctor","scriptProp","options","target","propertyKey","Error","own","slice","normalized","type","default","name","index","findIndex","push","defineProperty","configurable","enumerable","writable","getRuntimeScriptProperties","chain","current","RuntimeScript","Function","prototype","unshift","getPrototypeOf","merged","Map","prop","set","values","normalizeRuntimeScriptConfig","config","hasOwnProperty","call","undefined","applyRuntimeScriptConfig","instance","getScriptProperties","onCreated","onAttached","_host","onUpdate","_deltaTime","_elapsedTime","onDetached","onDestroy"],"mappings":"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"}
|
package/dist/app/screen.js
CHANGED
|
@@ -293,14 +293,14 @@ import { getDevice } from './api.js';
|
|
|
293
293
|
* Resolves the current viewport, updating internal state as needed.
|
|
294
294
|
*/ resolveViewport() {
|
|
295
295
|
const device = getDevice();
|
|
296
|
-
const vp = this._viewport
|
|
296
|
+
const vp = this._viewport ?? [
|
|
297
297
|
0,
|
|
298
298
|
0,
|
|
299
299
|
device.deviceXToScreen(device.getDrawingBufferWidth()),
|
|
300
300
|
device.deviceYToScreen(device.getDrawingBufferHeight())
|
|
301
301
|
];
|
|
302
|
-
if (this._resolvedViewport !== vp) {
|
|
303
|
-
this._resolvedViewport = vp;
|
|
302
|
+
if (!this._resolvedViewport || this._resolvedViewport[0] !== vp[0] || this._resolvedViewport[1] !== vp[1] || this._resolvedViewport[2] !== vp[2] || this._resolvedViewport[3] !== vp[3]) {
|
|
303
|
+
this._resolvedViewport = vp.slice();
|
|
304
304
|
this._version++;
|
|
305
305
|
this._transform = null;
|
|
306
306
|
}
|
package/dist/app/screen.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen.js","sources":["../../src/app/screen.ts"],"sourcesContent":["import type { Immutable, Nullable, Rect } from '@zephyr3d/base';\r\nimport { Vector2 } from '@zephyr3d/base';\r\nimport { getDevice } from './api';\r\n\r\n/**\r\n * Scaling mode used to adapt the design resolution to the viewport.\r\n *\r\n * - 'fit' – Preserve aspect ratio, show whole design area, may add letterboxing (black bars).\r\n * - 'fit-width' – Match viewport width exactly; height follows aspect ratio (may crop or letterbox vertically).\r\n * - 'fit-height' – Match viewport height exactly; width follows aspect ratio (may crop or letterbox horizontall\r\n * - 'cover' – Preserve aspect ratio, fill the entire viewport, design area may be cropped.\r\n * - 'stretch' – Do not preserve aspect ratio, stretch to fill the viewport.\r\n *\r\n * @public\r\n */\r\nexport type ScreenScaleMode = 'fit' | 'fit-width' | 'fit-height' | 'cover' | 'stretch';\r\n\r\n/**\r\n * Screen adapter configuration\r\n *\r\n * @public\r\n */\r\nexport type ScreenConfig = {\r\n /** Logical width in the design resolution coordinate system. */\r\n designWidth: number;\r\n /** Logical height in the design resolution coordinate system. */\r\n designHeight: number;\r\n /** Scaling mode used to adapt the design resolution to the viewport. */\r\n scaleMode: ScreenScaleMode;\r\n};\r\n\r\n/**\r\n * Parameters used to describe a 2D affine transform in the form:\r\n *\r\n * outX = inX * scaleX + offsetX\r\n * outY = inY * scaleY + offsetY\r\n */\r\nexport type PointTransform = {\r\n scaleX: number;\r\n scaleY: number;\r\n offsetX: number;\r\n offsetY: number;\r\n};\r\n\r\n/**\r\n * Resolution transform information derived from a {@link ScreenConfig}\r\n * and a concrete viewport rectangle.\r\n */\r\nexport type ResolutionTransform = {\r\n /**\r\n * X position of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportX: number;\r\n /**\r\n * Y position of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportY: number;\r\n /**\r\n * Width of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportWidth: number;\r\n /**\r\n * Height of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportHeight: number;\r\n /**\r\n * Visible part of the adjusted viewport, i.e. intersection with original viewport.\r\n **/\r\n croppedViewport: Rect;\r\n /**\r\n * Transform from canvas coordinates to the adjusted viewport's local coordinates.\r\n *\r\n * Typically used to convert mouse / pointer positions into the active rendering region.\r\n */\r\n canvasToViewport: PointTransform;\r\n /**\r\n * Transform from canvas coordinates to logical coordinates in the\r\n * design resolution space.\r\n *\r\n * Typically used for UI editing and interaction, so that logic consistently\r\n * works in designWidth × designHeight space.\r\n */\r\n canvasToLogic: PointTransform;\r\n};\r\n\r\n/**\r\n * Adapts a given physical viewport to a logical design resolution,\r\n * and provides coordinate transforms between canvas and logical spaces.\r\n *\r\n * @public\r\n */\r\nexport class ScreenAdapter {\r\n private _config!: ScreenConfig;\r\n private _transform: Nullable<ResolutionTransform>;\r\n private _viewport: Nullable<Immutable<number[]>>;\r\n private _resolvedViewport: Nullable<Immutable<number[]>>;\r\n private _version: number;\r\n /**\r\n * Creates a new {@link ScreenAdapter}.\r\n *\r\n * @param config - Optional initial screen configuration. If omitted,\r\n * a default of 1280×720 with 'cover' mode is used.\r\n */\r\n constructor(config?: Immutable<ScreenConfig>) {\r\n this._viewport = null;\r\n this._transform = null;\r\n this._resolvedViewport = null;\r\n this._version = 1;\r\n this._config = { ...this.getDefaultConfig(), ...config };\r\n }\r\n /**\r\n * Returns the current design resolution configuration.\r\n */\r\n get config(): Immutable<ScreenConfig> {\r\n return this._config;\r\n }\r\n set config(config: Immutable<ScreenConfig>) {\r\n this._config = { ...this.getDefaultConfig(), ...config };\r\n this._transform = null;\r\n this._version++;\r\n }\r\n /**\r\n * Returns the viewport of the screen\r\n */\r\n get viewport(): Nullable<Immutable<number[]>> {\r\n return this._viewport;\r\n }\r\n set viewport(vp: Nullable<Immutable<number[]>>) {\r\n if (this._viewport !== vp) {\r\n this._viewport = vp?.slice() ?? null;\r\n this.resolveViewport();\r\n }\r\n }\r\n /**\r\n * Returns the version of the screen adapter\r\n */\r\n get version() {\r\n this.resolveViewport();\r\n return this._version;\r\n }\r\n /**\r\n * Returns the calculated resolution transform\r\n */\r\n get transform(): Immutable<ResolutionTransform> {\r\n this.resolveViewport();\r\n if (!this._transform) {\r\n this._transform = this.calculateResolutionTransform(\r\n this._resolvedViewport![0],\r\n this._resolvedViewport![1],\r\n this._resolvedViewport![2],\r\n this._resolvedViewport![3]\r\n );\r\n }\r\n return this._transform;\r\n }\r\n /**\r\n * Computes the resolution transform for a given viewport in canvas coordinates.\r\n *\r\n * @param viewportX - X position of the provided viewport (CSS pixels).\r\n * @param viewportY - Y position of the provided viewport (CSS pixels).\r\n * @param viewportWidth - Width of the provided viewport (CSS pixels).\r\n * @param viewportHeight - Height of the provided viewport (CSS pixels).\r\n * @returns A {@link ResolutionTransform} describing the adjusted viewport\r\n * and coordinate transforms. If any dimension is non-positive, a\r\n * transform with zero-sized viewport and identity-like transforms is returned.\r\n */\r\n calculateResolutionTransform(\r\n viewportX: number,\r\n viewportY: number,\r\n viewportWidth: number,\r\n viewportHeight: number\r\n ) {\r\n const { designWidth, designHeight, scaleMode } = this._config;\r\n\r\n // Guard against invalid dimensions.\r\n if (viewportWidth <= 0 || viewportHeight <= 0 || designWidth <= 0 || designHeight <= 0) {\r\n return {\r\n viewportX,\r\n viewportY,\r\n viewportWidth: 0,\r\n viewportHeight: 0,\r\n croppedViewport: { x: viewportX, y: viewportY, width: 0, height: 0 },\r\n canvasToViewport: { scaleX: 1, scaleY: 1, offsetX: 0, offsetY: 0 },\r\n canvasToLogic: { scaleX: 1, scaleY: 1, offsetX: 0, offsetY: 0 }\r\n };\r\n }\r\n\r\n const sx = viewportWidth / designWidth;\r\n const sy = viewportHeight / designHeight;\r\n\r\n let scaleX = 1;\r\n let scaleY = 1;\r\n let finalViewportWidth = viewportWidth;\r\n let finalViewportHeight = viewportHeight;\r\n let finalViewportX = viewportX;\r\n let finalViewportY = viewportY;\r\n\r\n switch (scaleMode) {\r\n case 'fit': {\r\n // Uniform scale, entire design area visible, may add letterboxing.\r\n const s = Math.min(sx, sy);\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s;\r\n finalViewportHeight = designHeight * s;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'cover': {\r\n // Uniform scale, viewport fully covered, design area may be cropped.\r\n const s = Math.max(sx, sy);\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s;\r\n finalViewportHeight = designHeight * s;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'stretch': {\r\n // Non-uniform scale, stretch to fill the viewport.\r\n scaleX = sx;\r\n scaleY = sy;\r\n finalViewportWidth = viewportWidth;\r\n finalViewportHeight = viewportHeight;\r\n finalViewportX = viewportX;\r\n finalViewportY = viewportY;\r\n break;\r\n }\r\n case 'fit-width': {\r\n // Match width exactly; height follows aspect ratio.\r\n const s = sx; // width-driven\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s; // == viewportWidth\r\n finalViewportHeight = designHeight * s; // may be > or < viewportHeight\r\n finalViewportX = viewportX;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'fit-height': {\r\n // Match height exactly; width follows aspect ratio.\r\n const s = sy; // height-driven\r\n scaleX = scaleY = s;\r\n finalViewportHeight = designHeight * s; // == viewportHeight\r\n finalViewportWidth = designWidth * s; // may be > or < viewportWidth\r\n finalViewportY = viewportY;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n break;\r\n }\r\n }\r\n\r\n // calculate cropped viewport\r\n const adjLeft = finalViewportX;\r\n const adjTop = finalViewportY;\r\n const adjRight = finalViewportX + finalViewportWidth;\r\n const adjBottom = finalViewportY + finalViewportHeight;\r\n\r\n const rawLeft = viewportX;\r\n const rawTop = viewportY;\r\n const rawRight = viewportX + viewportWidth;\r\n const rawBottom = viewportY + viewportHeight;\r\n\r\n const cropLeft = Math.max(adjLeft, rawLeft);\r\n const cropTop = Math.max(adjTop, rawTop);\r\n const cropRight = Math.min(adjRight, rawRight);\r\n const cropBottom = Math.min(adjBottom, rawBottom);\r\n\r\n let croppedViewport: Rect;\r\n if (cropRight <= cropLeft || cropBottom <= cropTop) {\r\n // No intersection\r\n croppedViewport = {\r\n x: viewportX,\r\n y: viewportY,\r\n width: 0,\r\n height: 0\r\n };\r\n } else {\r\n croppedViewport = {\r\n x: cropLeft,\r\n y: cropTop,\r\n width: cropRight - cropLeft,\r\n height: cropBottom - cropTop\r\n };\r\n }\r\n\r\n // Transform: canvas -> viewport-local\r\n // viewportLocalX = canvasX - finalViewportX\r\n // viewportLocalY = canvasY - finalViewportY\r\n const canvasToViewport: PointTransform = {\r\n scaleX: 1,\r\n scaleY: 1,\r\n offsetX: -finalViewportX,\r\n offsetY: -finalViewportY\r\n };\r\n\r\n // Transform: canvas -> logic (design space)\r\n //\r\n // canvas -> viewport-local:\r\n // vx = canvasX - finalViewportX\r\n // vy = canvasY - finalViewportY\r\n //\r\n // viewport-local -> logic:\r\n // logicX = vx / scaleX\r\n // logicY = vy / scaleY\r\n //\r\n // Combined:\r\n // logicX = (canvasX - finalViewportX) / scaleX\r\n // = (1 / scaleX) * canvasX + (-finalViewportX / scaleX)\r\n // logicY = (canvasY - finalViewportY) / scaleY\r\n // = (1 / scaleY) * canvasY + (-finalViewportY / scaleY)\r\n const canvasToLogic: PointTransform = {\r\n scaleX: 1 / scaleX,\r\n scaleY: 1 / scaleY,\r\n offsetX: -finalViewportX / scaleX,\r\n offsetY: -finalViewportY / scaleY\r\n };\r\n\r\n return {\r\n viewportX: finalViewportX,\r\n viewportY: finalViewportY,\r\n viewportWidth: finalViewportWidth,\r\n viewportHeight: finalViewportHeight,\r\n croppedViewport,\r\n canvasToViewport,\r\n canvasToLogic\r\n };\r\n }\r\n /**\r\n * Converts canvas coordinates into adjusted viewport-local coordinates.\r\n *\r\n * @remarks\r\n * This is mainly intended for picking / hit testing within the active\r\n * rendering region, where (0, 0) corresponds to the top-left of the\r\n * adapted viewport.\r\n *\r\n * @param canvasPos - Point in canvas coordinates (CSS pixels).\r\n * @param viewportPosOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The point in viewport-local coordinates.\r\n */\r\n canvasPosToViewport(canvasPos: Vector2, viewportPosOut?: Vector2) {\r\n return this.transformPoint(this.transform.canvasToViewport, canvasPos, viewportPosOut);\r\n }\r\n /**\r\n * Converts canvas coordinates into logical coordinates in the design\r\n * resolution space.\r\n *\r\n * @remarks\r\n * This is mainly intended for UI editing and interaction, so that logic\r\n * works consistently in the designWidth × designHeight coordinate system.\r\n *\r\n * @param canvasPos - Point in canvas coordinates (CSS pixels).\r\n * @param logicPosOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The point in logical (design resolution) coordinates.\r\n */\r\n canvasPosToLogic(canvasPos: Vector2, logicPosOut?: Vector2) {\r\n return this.transformPoint(this.transform.canvasToLogic, canvasPos, logicPosOut);\r\n }\r\n /**\r\n * Applies a 2D affine transform to a point.\r\n *\r\n * The transform is applied as:\r\n *\r\n * out.x = in.x * scaleX + offsetX\r\n * out.y = in.y * scaleY + offsetY\r\n *\r\n * @param transform - Transform parameters (scale and offset).\r\n * @param pointIn - Input point.\r\n * @param pointOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The transformed point.\r\n */\r\n transformPoint(transform: PointTransform, pointIn: Vector2, pointOut?: Vector2) {\r\n const out = pointOut ?? new Vector2();\r\n out.x = pointIn.x * transform.scaleX + transform.offsetX;\r\n out.y = pointIn.y * transform.scaleY + transform.offsetY;\r\n return out;\r\n }\r\n /**\r\n * Resolves the current viewport, updating internal state as needed.\r\n */\r\n resolveViewport() {\r\n const device = getDevice();\r\n const vp = this._viewport?.slice() ?? [\r\n 0,\r\n 0,\r\n device.deviceXToScreen(device.getDrawingBufferWidth()),\r\n device.deviceYToScreen(device.getDrawingBufferHeight())\r\n ];\r\n if (this._resolvedViewport !== vp) {\r\n this._resolvedViewport = vp;\r\n this._version++;\r\n this._transform = null;\r\n }\r\n }\r\n private getDefaultConfig(): ScreenConfig {\r\n return {\r\n designWidth: 1280,\r\n designHeight: 720,\r\n scaleMode: 'cover'\r\n };\r\n }\r\n}\r\n"],"names":["ScreenAdapter","_config","_transform","_viewport","_resolvedViewport","_version","config","getDefaultConfig","viewport","vp","slice","resolveViewport","version","transform","calculateResolutionTransform","viewportX","viewportY","viewportWidth","viewportHeight","designWidth","designHeight","scaleMode","croppedViewport","x","y","width","height","canvasToViewport","scaleX","scaleY","offsetX","offsetY","canvasToLogic","sx","sy","finalViewportWidth","finalViewportHeight","finalViewportX","finalViewportY","s","Math","min","max","adjLeft","adjTop","adjRight","adjBottom","rawLeft","rawTop","rawRight","rawBottom","cropLeft","cropTop","cropRight","cropBottom","canvasPosToViewport","canvasPos","viewportPosOut","transformPoint","canvasPosToLogic","logicPosOut","pointIn","pointOut","out","Vector2","device","getDevice","deviceXToScreen","getDrawingBufferWidth","deviceYToScreen","getDrawingBufferHeight"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"screen.js","sources":["../../src/app/screen.ts"],"sourcesContent":["import type { Immutable, Nullable, Rect } from '@zephyr3d/base';\r\nimport { Vector2 } from '@zephyr3d/base';\r\nimport { getDevice } from './api';\r\n\r\n/**\r\n * Scaling mode used to adapt the design resolution to the viewport.\r\n *\r\n * - 'fit' – Preserve aspect ratio, show whole design area, may add letterboxing (black bars).\r\n * - 'fit-width' – Match viewport width exactly; height follows aspect ratio (may crop or letterbox vertically).\r\n * - 'fit-height' – Match viewport height exactly; width follows aspect ratio (may crop or letterbox horizontall\r\n * - 'cover' – Preserve aspect ratio, fill the entire viewport, design area may be cropped.\r\n * - 'stretch' – Do not preserve aspect ratio, stretch to fill the viewport.\r\n *\r\n * @public\r\n */\r\nexport type ScreenScaleMode = 'fit' | 'fit-width' | 'fit-height' | 'cover' | 'stretch';\r\n\r\n/**\r\n * Screen adapter configuration\r\n *\r\n * @public\r\n */\r\nexport type ScreenConfig = {\r\n /** Logical width in the design resolution coordinate system. */\r\n designWidth: number;\r\n /** Logical height in the design resolution coordinate system. */\r\n designHeight: number;\r\n /** Scaling mode used to adapt the design resolution to the viewport. */\r\n scaleMode: ScreenScaleMode;\r\n};\r\n\r\n/**\r\n * Parameters used to describe a 2D affine transform in the form:\r\n *\r\n * outX = inX * scaleX + offsetX\r\n * outY = inY * scaleY + offsetY\r\n */\r\nexport type PointTransform = {\r\n scaleX: number;\r\n scaleY: number;\r\n offsetX: number;\r\n offsetY: number;\r\n};\r\n\r\n/**\r\n * Resolution transform information derived from a {@link ScreenConfig}\r\n * and a concrete viewport rectangle.\r\n */\r\nexport type ResolutionTransform = {\r\n /**\r\n * X position of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportX: number;\r\n /**\r\n * Y position of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportY: number;\r\n /**\r\n * Width of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportWidth: number;\r\n /**\r\n * Height of the adjusted viewport in canvas coordinates (CSS pixels).\r\n */\r\n viewportHeight: number;\r\n /**\r\n * Visible part of the adjusted viewport, i.e. intersection with original viewport.\r\n **/\r\n croppedViewport: Rect;\r\n /**\r\n * Transform from canvas coordinates to the adjusted viewport's local coordinates.\r\n *\r\n * Typically used to convert mouse / pointer positions into the active rendering region.\r\n */\r\n canvasToViewport: PointTransform;\r\n /**\r\n * Transform from canvas coordinates to logical coordinates in the\r\n * design resolution space.\r\n *\r\n * Typically used for UI editing and interaction, so that logic consistently\r\n * works in designWidth × designHeight space.\r\n */\r\n canvasToLogic: PointTransform;\r\n};\r\n\r\n/**\r\n * Adapts a given physical viewport to a logical design resolution,\r\n * and provides coordinate transforms between canvas and logical spaces.\r\n *\r\n * @public\r\n */\r\nexport class ScreenAdapter {\r\n private _config!: ScreenConfig;\r\n private _transform: Nullable<ResolutionTransform>;\r\n private _viewport: Nullable<Immutable<number[]>>;\r\n private _resolvedViewport: Nullable<Immutable<number[]>>;\r\n private _version: number;\r\n /**\r\n * Creates a new {@link ScreenAdapter}.\r\n *\r\n * @param config - Optional initial screen configuration. If omitted,\r\n * a default of 1280×720 with 'cover' mode is used.\r\n */\r\n constructor(config?: Immutable<ScreenConfig>) {\r\n this._viewport = null;\r\n this._transform = null;\r\n this._resolvedViewport = null;\r\n this._version = 1;\r\n this._config = { ...this.getDefaultConfig(), ...config };\r\n }\r\n /**\r\n * Returns the current design resolution configuration.\r\n */\r\n get config(): Immutable<ScreenConfig> {\r\n return this._config;\r\n }\r\n set config(config: Immutable<ScreenConfig>) {\r\n this._config = { ...this.getDefaultConfig(), ...config };\r\n this._transform = null;\r\n this._version++;\r\n }\r\n /**\r\n * Returns the viewport of the screen\r\n */\r\n get viewport(): Nullable<Immutable<number[]>> {\r\n return this._viewport;\r\n }\r\n set viewport(vp: Nullable<Immutable<number[]>>) {\r\n if (this._viewport !== vp) {\r\n this._viewport = vp?.slice() ?? null;\r\n this.resolveViewport();\r\n }\r\n }\r\n /**\r\n * Returns the version of the screen adapter\r\n */\r\n get version() {\r\n this.resolveViewport();\r\n return this._version;\r\n }\r\n /**\r\n * Returns the calculated resolution transform\r\n */\r\n get transform(): Immutable<ResolutionTransform> {\r\n this.resolveViewport();\r\n if (!this._transform) {\r\n this._transform = this.calculateResolutionTransform(\r\n this._resolvedViewport![0],\r\n this._resolvedViewport![1],\r\n this._resolvedViewport![2],\r\n this._resolvedViewport![3]\r\n );\r\n }\r\n return this._transform;\r\n }\r\n /**\r\n * Computes the resolution transform for a given viewport in canvas coordinates.\r\n *\r\n * @param viewportX - X position of the provided viewport (CSS pixels).\r\n * @param viewportY - Y position of the provided viewport (CSS pixels).\r\n * @param viewportWidth - Width of the provided viewport (CSS pixels).\r\n * @param viewportHeight - Height of the provided viewport (CSS pixels).\r\n * @returns A {@link ResolutionTransform} describing the adjusted viewport\r\n * and coordinate transforms. If any dimension is non-positive, a\r\n * transform with zero-sized viewport and identity-like transforms is returned.\r\n */\r\n calculateResolutionTransform(\r\n viewportX: number,\r\n viewportY: number,\r\n viewportWidth: number,\r\n viewportHeight: number\r\n ) {\r\n const { designWidth, designHeight, scaleMode } = this._config;\r\n\r\n // Guard against invalid dimensions.\r\n if (viewportWidth <= 0 || viewportHeight <= 0 || designWidth <= 0 || designHeight <= 0) {\r\n return {\r\n viewportX,\r\n viewportY,\r\n viewportWidth: 0,\r\n viewportHeight: 0,\r\n croppedViewport: { x: viewportX, y: viewportY, width: 0, height: 0 },\r\n canvasToViewport: { scaleX: 1, scaleY: 1, offsetX: 0, offsetY: 0 },\r\n canvasToLogic: { scaleX: 1, scaleY: 1, offsetX: 0, offsetY: 0 }\r\n };\r\n }\r\n\r\n const sx = viewportWidth / designWidth;\r\n const sy = viewportHeight / designHeight;\r\n\r\n let scaleX = 1;\r\n let scaleY = 1;\r\n let finalViewportWidth = viewportWidth;\r\n let finalViewportHeight = viewportHeight;\r\n let finalViewportX = viewportX;\r\n let finalViewportY = viewportY;\r\n\r\n switch (scaleMode) {\r\n case 'fit': {\r\n // Uniform scale, entire design area visible, may add letterboxing.\r\n const s = Math.min(sx, sy);\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s;\r\n finalViewportHeight = designHeight * s;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'cover': {\r\n // Uniform scale, viewport fully covered, design area may be cropped.\r\n const s = Math.max(sx, sy);\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s;\r\n finalViewportHeight = designHeight * s;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'stretch': {\r\n // Non-uniform scale, stretch to fill the viewport.\r\n scaleX = sx;\r\n scaleY = sy;\r\n finalViewportWidth = viewportWidth;\r\n finalViewportHeight = viewportHeight;\r\n finalViewportX = viewportX;\r\n finalViewportY = viewportY;\r\n break;\r\n }\r\n case 'fit-width': {\r\n // Match width exactly; height follows aspect ratio.\r\n const s = sx; // width-driven\r\n scaleX = scaleY = s;\r\n finalViewportWidth = designWidth * s; // == viewportWidth\r\n finalViewportHeight = designHeight * s; // may be > or < viewportHeight\r\n finalViewportX = viewportX;\r\n finalViewportY = viewportY + (viewportHeight - finalViewportHeight) * 0.5;\r\n break;\r\n }\r\n case 'fit-height': {\r\n // Match height exactly; width follows aspect ratio.\r\n const s = sy; // height-driven\r\n scaleX = scaleY = s;\r\n finalViewportHeight = designHeight * s; // == viewportHeight\r\n finalViewportWidth = designWidth * s; // may be > or < viewportWidth\r\n finalViewportY = viewportY;\r\n finalViewportX = viewportX + (viewportWidth - finalViewportWidth) * 0.5;\r\n break;\r\n }\r\n }\r\n\r\n // calculate cropped viewport\r\n const adjLeft = finalViewportX;\r\n const adjTop = finalViewportY;\r\n const adjRight = finalViewportX + finalViewportWidth;\r\n const adjBottom = finalViewportY + finalViewportHeight;\r\n\r\n const rawLeft = viewportX;\r\n const rawTop = viewportY;\r\n const rawRight = viewportX + viewportWidth;\r\n const rawBottom = viewportY + viewportHeight;\r\n\r\n const cropLeft = Math.max(adjLeft, rawLeft);\r\n const cropTop = Math.max(adjTop, rawTop);\r\n const cropRight = Math.min(adjRight, rawRight);\r\n const cropBottom = Math.min(adjBottom, rawBottom);\r\n\r\n let croppedViewport: Rect;\r\n if (cropRight <= cropLeft || cropBottom <= cropTop) {\r\n // No intersection\r\n croppedViewport = {\r\n x: viewportX,\r\n y: viewportY,\r\n width: 0,\r\n height: 0\r\n };\r\n } else {\r\n croppedViewport = {\r\n x: cropLeft,\r\n y: cropTop,\r\n width: cropRight - cropLeft,\r\n height: cropBottom - cropTop\r\n };\r\n }\r\n\r\n // Transform: canvas -> viewport-local\r\n // viewportLocalX = canvasX - finalViewportX\r\n // viewportLocalY = canvasY - finalViewportY\r\n const canvasToViewport: PointTransform = {\r\n scaleX: 1,\r\n scaleY: 1,\r\n offsetX: -finalViewportX,\r\n offsetY: -finalViewportY\r\n };\r\n\r\n // Transform: canvas -> logic (design space)\r\n //\r\n // canvas -> viewport-local:\r\n // vx = canvasX - finalViewportX\r\n // vy = canvasY - finalViewportY\r\n //\r\n // viewport-local -> logic:\r\n // logicX = vx / scaleX\r\n // logicY = vy / scaleY\r\n //\r\n // Combined:\r\n // logicX = (canvasX - finalViewportX) / scaleX\r\n // = (1 / scaleX) * canvasX + (-finalViewportX / scaleX)\r\n // logicY = (canvasY - finalViewportY) / scaleY\r\n // = (1 / scaleY) * canvasY + (-finalViewportY / scaleY)\r\n const canvasToLogic: PointTransform = {\r\n scaleX: 1 / scaleX,\r\n scaleY: 1 / scaleY,\r\n offsetX: -finalViewportX / scaleX,\r\n offsetY: -finalViewportY / scaleY\r\n };\r\n\r\n return {\r\n viewportX: finalViewportX,\r\n viewportY: finalViewportY,\r\n viewportWidth: finalViewportWidth,\r\n viewportHeight: finalViewportHeight,\r\n croppedViewport,\r\n canvasToViewport,\r\n canvasToLogic\r\n };\r\n }\r\n /**\r\n * Converts canvas coordinates into adjusted viewport-local coordinates.\r\n *\r\n * @remarks\r\n * This is mainly intended for picking / hit testing within the active\r\n * rendering region, where (0, 0) corresponds to the top-left of the\r\n * adapted viewport.\r\n *\r\n * @param canvasPos - Point in canvas coordinates (CSS pixels).\r\n * @param viewportPosOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The point in viewport-local coordinates.\r\n */\r\n canvasPosToViewport(canvasPos: Vector2, viewportPosOut?: Vector2) {\r\n return this.transformPoint(this.transform.canvasToViewport, canvasPos, viewportPosOut);\r\n }\r\n /**\r\n * Converts canvas coordinates into logical coordinates in the design\r\n * resolution space.\r\n *\r\n * @remarks\r\n * This is mainly intended for UI editing and interaction, so that logic\r\n * works consistently in the designWidth × designHeight coordinate system.\r\n *\r\n * @param canvasPos - Point in canvas coordinates (CSS pixels).\r\n * @param logicPosOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The point in logical (design resolution) coordinates.\r\n */\r\n canvasPosToLogic(canvasPos: Vector2, logicPosOut?: Vector2) {\r\n return this.transformPoint(this.transform.canvasToLogic, canvasPos, logicPosOut);\r\n }\r\n /**\r\n * Applies a 2D affine transform to a point.\r\n *\r\n * The transform is applied as:\r\n *\r\n * out.x = in.x * scaleX + offsetX\r\n * out.y = in.y * scaleY + offsetY\r\n *\r\n * @param transform - Transform parameters (scale and offset).\r\n * @param pointIn - Input point.\r\n * @param pointOut - Optional output vector. If provided, it will be\r\n * written into and returned; otherwise a new {@link Vector2} is allocated.\r\n * @returns The transformed point.\r\n */\r\n transformPoint(transform: PointTransform, pointIn: Vector2, pointOut?: Vector2) {\r\n const out = pointOut ?? new Vector2();\r\n out.x = pointIn.x * transform.scaleX + transform.offsetX;\r\n out.y = pointIn.y * transform.scaleY + transform.offsetY;\r\n return out;\r\n }\r\n /**\r\n * Resolves the current viewport, updating internal state as needed.\r\n */\r\n resolveViewport() {\r\n const device = getDevice();\r\n const vp = this._viewport ?? [\r\n 0,\r\n 0,\r\n device.deviceXToScreen(device.getDrawingBufferWidth()),\r\n device.deviceYToScreen(device.getDrawingBufferHeight())\r\n ];\r\n if (\r\n !this._resolvedViewport ||\r\n this._resolvedViewport[0] !== vp[0] ||\r\n this._resolvedViewport[1] !== vp[1] ||\r\n this._resolvedViewport[2] !== vp[2] ||\r\n this._resolvedViewport[3] !== vp[3]\r\n ) {\r\n this._resolvedViewport = vp.slice();\r\n this._version++;\r\n this._transform = null;\r\n }\r\n }\r\n private getDefaultConfig(): ScreenConfig {\r\n return {\r\n designWidth: 1280,\r\n designHeight: 720,\r\n scaleMode: 'cover'\r\n };\r\n }\r\n}\r\n"],"names":["ScreenAdapter","_config","_transform","_viewport","_resolvedViewport","_version","config","getDefaultConfig","viewport","vp","slice","resolveViewport","version","transform","calculateResolutionTransform","viewportX","viewportY","viewportWidth","viewportHeight","designWidth","designHeight","scaleMode","croppedViewport","x","y","width","height","canvasToViewport","scaleX","scaleY","offsetX","offsetY","canvasToLogic","sx","sy","finalViewportWidth","finalViewportHeight","finalViewportX","finalViewportY","s","Math","min","max","adjLeft","adjTop","adjRight","adjBottom","rawLeft","rawTop","rawRight","rawBottom","cropLeft","cropTop","cropRight","cropBottom","canvasPosToViewport","canvasPos","viewportPosOut","transformPoint","canvasPosToLogic","logicPosOut","pointIn","pointOut","out","Vector2","device","getDevice","deviceXToScreen","getDrawingBufferWidth","deviceYToScreen","getDrawingBufferHeight"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HttpFS } from '@zephyr3d/base';
|
|
2
2
|
import { ScriptRegistry } from './scriptregistry.js';
|
|
3
|
-
import { RuntimeScript } from './runtimescript.js';
|
|
3
|
+
import { RuntimeScript, applyRuntimeScriptConfig } from './runtimescript.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Script system that resolves, loads, and manages lifecycle of runtime scripts.
|
|
@@ -42,47 +42,57 @@ import { RuntimeScript } from './runtimescript.js';
|
|
|
42
42
|
return this._registry;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
45
|
+
* Loads a runtime script class from file
|
|
46
|
+
* @param module - file path
|
|
47
|
+
* @returns The runtime script class or null
|
|
48
|
+
*/ async loadRuntimeScriptClass(module) {
|
|
49
|
+
let mod = null;
|
|
50
|
+
const moduleName = module ? String(module).slice(0, 64) : '';
|
|
51
|
+
let url = '';
|
|
52
|
+
try {
|
|
53
|
+
url = await this._registry.resolveRuntimeUrl(module);
|
|
54
|
+
if (!url) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
mod = await import(url + (this._importComment ?? ''));
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.error(`Load module '${moduleName}' failed: ${e}`);
|
|
60
|
+
}
|
|
61
|
+
if (mod && typeof mod.default === 'function') {
|
|
62
|
+
return {
|
|
63
|
+
url,
|
|
64
|
+
id: module,
|
|
65
|
+
cls: mod.default
|
|
66
|
+
};
|
|
67
|
+
} else {
|
|
68
|
+
console.error(`No runtime class exported from '${moduleName}'`);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Creates a script from a dynamic loaded class and attachs it to a host and returns the `RuntimeScript` instance.
|
|
57
74
|
*
|
|
58
75
|
* @typeParam T - Host type.
|
|
59
76
|
* @param host - The host object to attach the script to.
|
|
60
|
-
* @param
|
|
77
|
+
* @param classInfo - The dynamic loaded class information
|
|
61
78
|
* @returns The instantiated `RuntimeScript<T>` or `null` on failure.
|
|
62
|
-
*/ async
|
|
79
|
+
*/ async attachScriptIndirect(host, classInfo, config) {
|
|
63
80
|
try {
|
|
64
|
-
const url =
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
instance = new mod.default();
|
|
73
|
-
if (instance instanceof RuntimeScript) {
|
|
74
|
-
if (!this._scriptHosts.has(instance)) {
|
|
75
|
-
const P = instance.onCreated();
|
|
76
|
-
if (P instanceof Promise) {
|
|
77
|
-
await P;
|
|
78
|
-
}
|
|
81
|
+
const { url, id, cls } = classInfo;
|
|
82
|
+
let instance = new cls();
|
|
83
|
+
if (instance instanceof RuntimeScript) {
|
|
84
|
+
applyRuntimeScriptConfig(instance, config);
|
|
85
|
+
if (!this._scriptHosts.has(instance)) {
|
|
86
|
+
const P = instance.onCreated();
|
|
87
|
+
if (P instanceof Promise) {
|
|
88
|
+
await P;
|
|
79
89
|
}
|
|
80
|
-
} else {
|
|
81
|
-
instance = null;
|
|
82
90
|
}
|
|
91
|
+
} else {
|
|
92
|
+
instance = null;
|
|
83
93
|
}
|
|
84
94
|
if (!instance) {
|
|
85
|
-
console.warn(`Script '${
|
|
95
|
+
console.warn(`Script '${url}' does not have RuntimeScript class exported as default`);
|
|
86
96
|
return null;
|
|
87
97
|
}
|
|
88
98
|
let hostList = this._scriptHosts.get(instance);
|
|
@@ -91,7 +101,7 @@ import { RuntimeScript } from './runtimescript.js';
|
|
|
91
101
|
this._scriptHosts.set(instance, hostList);
|
|
92
102
|
}
|
|
93
103
|
if (hostList.includes(host)) {
|
|
94
|
-
console.warn(`Script '${
|
|
104
|
+
console.warn(`Script '${url}' already attached`);
|
|
95
105
|
return instance;
|
|
96
106
|
}
|
|
97
107
|
hostList.push(host);
|
|
@@ -100,7 +110,7 @@ import { RuntimeScript } from './runtimescript.js';
|
|
|
100
110
|
await P;
|
|
101
111
|
}
|
|
102
112
|
const attached = {
|
|
103
|
-
id
|
|
113
|
+
id,
|
|
104
114
|
url,
|
|
105
115
|
instance
|
|
106
116
|
};
|
|
@@ -117,13 +127,35 @@ import { RuntimeScript } from './runtimescript.js';
|
|
|
117
127
|
list.push(attached);
|
|
118
128
|
return attached.instance;
|
|
119
129
|
} catch (e) {
|
|
120
|
-
const moduleName =
|
|
130
|
+
const moduleName = classInfo.id ? String(classInfo.id).slice(0, 64) : '';
|
|
121
131
|
console.error(`Load module '${moduleName}' failed: ${e}`);
|
|
122
|
-
this._onLoadError?.(e,
|
|
132
|
+
this._onLoadError?.(e, classInfo.id);
|
|
123
133
|
return null;
|
|
124
134
|
}
|
|
125
135
|
}
|
|
126
136
|
/**
|
|
137
|
+
* Attaches a script to a host and returns the `RuntimeScript` instance.
|
|
138
|
+
*
|
|
139
|
+
* Process:
|
|
140
|
+
* 1. Resolve module ID to a runtime URL via the registry.
|
|
141
|
+
* 2. Dynamically import the module.
|
|
142
|
+
* 3. Instantiate the default export if it is a constructor.
|
|
143
|
+
* 4. If this is the first time the instance is seen, call `onCreated()`.
|
|
144
|
+
* 5. Link the instance to the host, and call `onAttached(host)`.
|
|
145
|
+
* 6. Subscribe to the host's `'dispose'` event to auto-detach.
|
|
146
|
+
*
|
|
147
|
+
* If the module cannot be resolved or does not export a default `RuntimeScript`
|
|
148
|
+
* subclass, a warning is logged and `null` is returned.
|
|
149
|
+
*
|
|
150
|
+
* @typeParam T - Host type.
|
|
151
|
+
* @param host - The host object to attach the script to.
|
|
152
|
+
* @param module - Module identifier used by the registry (logical ID or path).
|
|
153
|
+
* @returns The instantiated `RuntimeScript<T>` or `null` on failure.
|
|
154
|
+
*/ async attachScript(host, module, config) {
|
|
155
|
+
const info = await this.loadRuntimeScriptClass(module);
|
|
156
|
+
return info ? await this.attachScriptIndirect(host, info, config) : null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
127
159
|
* Detaches script(s) from a host.
|
|
128
160
|
*
|
|
129
161
|
* Behavior:
|