diff --git a/.vscode/launch.json b/.vscode/launch.json index ca84f7fe..2e4e70d0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,48 +5,23 @@ "version": "0.2.0", "configurations": [ { - "name": "(Chrome):Launch main demo", + "name": "(Chrome): Launch examples", "type": "chrome", "request": "launch", - "url": "http://127.0.0.1:8082/demos/index.html", + "url": "http://127.0.0.1:8082/examples/index.html", "webRoot": "${workspaceFolder}" }, - { - "name": "(Chrome):Launch WebGL demo", - "request": "launch", - "type": "chrome", - "url": "http://127.0.0.1:8082/demos/webgl.html", - "webRoot": "${workspaceFolder}" - }, - { - "type": "firefox", - "request": "launch", - "reAttach": true, - "name": "(FireFox):Launch main demo", - "url": "http://127.0.0.1:8082/demos/index.html", - "webRoot": "${workspaceFolder}", - "pathMappings": [ - { - "url": "http://127.0.0.1:8082/demos", - "path": "${workspaceFolder}/demos" - }, - { - "url": "http://127.0.0.1:8082/src", - "path": "${workspaceFolder}/src" - } - ] - }, { "type": "firefox", "request": "launch", "reAttach": true, - "name": "(FireFox):Launch WebGL demo", - "url": "http://127.0.0.1:8082/demos/webgl.html", + "name": "(FireFox): Launch examples", + "url": "http://127.0.0.1:8082/examples/index.html", "webRoot": "${workspaceFolder}", "pathMappings": [ { - "url": "http://127.0.0.1:8082/demos", - "path": "${workspaceFolder}/demos" + "url": "http://127.0.0.1:8082/examples", + "path": "${workspaceFolder}/examples" }, { "url": "http://127.0.0.1:8082/src", @@ -59,6 +34,6 @@ "name": "Run tests", "command": "npm run test", "request": "launch" - }, + } ] } \ No newline at end of file diff --git a/examples/samples/scene/basic2d.js b/examples/samples/scene/2d/basic.js similarity index 97% rename from examples/samples/scene/basic2d.js rename to examples/samples/scene/2d/basic.js index 59c88af5..f83098ed 100644 --- a/examples/samples/scene/basic2d.js +++ b/examples/samples/scene/2d/basic.js @@ -22,7 +22,7 @@ import { FPSDebugger, App } from 'wima' -import { HackPlugin, setupViewport } from '../utils.js' +import { HackPlugin, setupViewport } from '../../utils.js' const itemWidth = 50 const itemHeight = 50 diff --git a/examples/samples/scene/2d/index.js b/examples/samples/scene/2d/index.js new file mode 100644 index 00000000..86034e38 --- /dev/null +++ b/examples/samples/scene/2d/index.js @@ -0,0 +1,7 @@ +const basic = new URL('./basic.js', import.meta.url) +const multipleInstances = new URL('./multiple_instances.js', import.meta.url) + +export default { + 'basic': basic, + 'multiple_instances': multipleInstances +} diff --git a/examples/samples/scene/2d/multiple_instances.js b/examples/samples/scene/2d/multiple_instances.js new file mode 100644 index 00000000..5f89e7de --- /dev/null +++ b/examples/samples/scene/2d/multiple_instances.js @@ -0,0 +1,123 @@ +import { + Mesh, + createMovable2D, + World, + EntityCommands, + BasicMaterial, + Meshed, + Scene, + SceneInstance, + SceneAssets, + Assets, + Entity, + Query, + MeshAssets, + BasicMaterialAssets, + Color, + BasicMaterial2D, + AppSchedule, + Rotation2D, + rand, + RelationshipQuery, + Children, + Parent, + Canvas2DRendererPlugin, + DefaultPlugin, + DOMWindowPlugin, + FPSDebugger, + App, + Angular2DDamping, + Torque2D, + createTransform2D +} from 'wima' +import { addDefaultCamera2D, HackPlugin, setupViewport } from '../../utils.js' + +const app = new App() + +app + .registerPlugin(new HackPlugin()) + .registerPlugin(new DefaultPlugin()) + .registerPlugin(new DOMWindowPlugin()) + .registerPlugin(new Canvas2DRendererPlugin()) + .registerSystem(AppSchedule.Update, applyRandomDescendantTorque) + .registerSystem(AppSchedule.Startup, init) + .registerSystem(AppSchedule.Startup, addDefaultCamera2D) + .registerSystem(AppSchedule.Update, setupViewport) + .registerDebugger(new FPSDebugger()) + .run() + +/** + * @param {World} world + */ +function init(world) { + const commands = new EntityCommands(world) + const angularDamping = world.getResource(Angular2DDamping) + const scenes = world.getResource(SceneAssets) + const meshes = world.getResource(MeshAssets) + const materials = world.getResource(BasicMaterialAssets) + + const scene = scenes.add(createScene(meshes, materials)) + const instances = [ + { x: -0.5, y: -0.5 }, + { x: 0.5, y: -0.5 }, + { x: 0, y: 0.5 } + ] + + for (let i = 0; i < instances.length; i++) { + const { x, y } = instances[i] + + commands + .spawn() + .insertPrefab([...createMovable2D(x, y), new SceneInstance(scene)]) + .build() + } + + angularDamping.value = 0 +} + +/** + * @param {World} world + */ +function applyRandomDescendantTorque(world) { + const roots = new Query(world, [Entity, SceneInstance]) + const descendants = new RelationshipQuery(world, Children, Parent, [Torque2D]) + + roots.each(([entity]) => { + descendants.treebfs(entity, ([torque]) => { + torque.value = rand(-1.2, 1.2) + }) + }) +} + +/** + * @param {Assets} meshes + * @param {Assets} materials + */ +function createScene(meshes, materials) { + const scene = new Scene() + const mesh = meshes.add(Mesh.quad2D(0.05, 0.05)) + const material = materials.add(new BasicMaterial({ + color: new Color(1, 1, 1) + })) + + const offsets = [ + { x: -0.05, y: -0.05 }, + { x: 0.05, y: -0.05 }, + { x: 0, y: 0.05 } + ] + + for (let i = 0; i < offsets.length; i++) { + scene.set(new Entity(i, 1), [ + ...createTransform2D(offsets[i].x, offsets[i].y), + new Meshed(mesh.clone()), + new BasicMaterial2D(material.clone()), + new Rotation2D(), + new Torque2D() + ]) + } + + mesh.drop() + material.drop() + + return scene +} diff --git a/examples/samples/scene/basic3d.js b/examples/samples/scene/3d/basic.js similarity index 97% rename from examples/samples/scene/basic3d.js rename to examples/samples/scene/3d/basic.js index 8f9d9ede..fae2a06d 100644 --- a/examples/samples/scene/basic3d.js +++ b/examples/samples/scene/3d/basic.js @@ -22,7 +22,7 @@ import { FPSDebugger, WebglRendererPlugin } from 'wima' -import { HackPlugin, setupViewportWebgl } from '../utils.js' +import { HackPlugin, setupViewportWebgl } from '../../utils.js' const itemWidth = 0.5 const itemHeight = 0.5 diff --git a/examples/samples/scene/3d/index.js b/examples/samples/scene/3d/index.js new file mode 100644 index 00000000..86034e38 --- /dev/null +++ b/examples/samples/scene/3d/index.js @@ -0,0 +1,7 @@ +const basic = new URL('./basic.js', import.meta.url) +const multipleInstances = new URL('./multiple_instances.js', import.meta.url) + +export default { + 'basic': basic, + 'multiple_instances': multipleInstances +} diff --git a/examples/samples/scene/3d/multiple_instances.js b/examples/samples/scene/3d/multiple_instances.js new file mode 100644 index 00000000..2ff2b507 --- /dev/null +++ b/examples/samples/scene/3d/multiple_instances.js @@ -0,0 +1,130 @@ +import { + Mesh, + createRawMovable3D, + createTransform3D, + World, + EntityCommands, + BasicMaterial, + Meshed, + Scene, + SceneInstance, + SceneAssets, + Assets, + BasicMaterial3D, + Entity, + Query, + MeshAssets, + BasicMaterialAssets, + Color, + App, + AppSchedule, + Angular3DDamping, + Rotation3D, + rand, + Torque3D, + RelationshipQuery, + Children, + Parent, + DefaultPlugin, + DOMWindowPlugin, + FPSDebugger, + WebglRendererPlugin +} from 'wima' +import { addDefaultCamera3D, HackPlugin, setupViewportWebgl } from '../../utils.js' + +const instanceConfigs = [ + { offsetX: -1.7, offsetY: -0.35, offsetZ: -2 }, + { offsetX: 1.7, offsetY: 0.15, offsetZ: -1.35 }, + { offsetX: 0, offsetY: 0.5, offsetZ: -2.85 } +] + +const app = new App() + +app + .registerPlugin(new HackPlugin()) + .registerPlugin(new WebglRendererPlugin()) + .registerPlugin(new DefaultPlugin()) + .registerPlugin(new DOMWindowPlugin()) + .registerSystem(AppSchedule.Update, applyRandomDescendantTorque) + .registerDebugger(new FPSDebugger()) + .registerSystem(AppSchedule.Startup, init) + .registerSystem(AppSchedule.Startup, addDefaultCamera3D) + .registerSystem(AppSchedule.Update, setupViewportWebgl) + .run() + +/** + * @param {World} world + */ +function init(world) { + const commands = new EntityCommands(world) + const angularDamping = world.getResource(Angular3DDamping) + const scenes = world.getResource(SceneAssets) + const meshes = world.getResource(MeshAssets) + const materials = world.getResource(BasicMaterialAssets) + + const scene = scenes.add(createScene(meshes, materials)) + + for (let i = 0; i < instanceConfigs.length; i++) { + const { offsetX, offsetY, offsetZ } = instanceConfigs[i] + + commands + .spawn() + .insertPrefab([ + ...createTransform3D(offsetX, offsetY, offsetZ), + ...createRawMovable3D(), + new SceneInstance(scene) + ]) + .build() + } + + angularDamping.value = 0 +} + +/** + * @param {World} world + */ +function applyRandomDescendantTorque(world) { + const roots = new Query(world, [Entity, SceneInstance]) + const descendants = new RelationshipQuery(world, Children, Parent, [Torque3D]) + + roots.each(([entity]) => { + descendants.treebfs(entity, ([torque]) => { + torque.x = rand(-1.2, 1.2) + torque.y = rand(-1.2, 1.2) + torque.z = rand(-1.2, 1.2) + }) + }) +} + +/** + * @param {Assets} meshes + * @param {Assets} materials + */ +function createScene(meshes, materials) { + const scene = new Scene() + const mesh = meshes.add(Mesh.cube(0.8, 0.8, 0.8)) + const material = materials.add(new BasicMaterial({ + color: new Color(1, 1, 1) + })) + + const offsets = [ + { x: -0.6, y: -0.6, z: -0.6 }, + { x: 0.6, y: -0.6, z: -0.6 }, + { x: 0, y: 0.6, z: 0.6 } + ] + + for (let i = 0; i < offsets.length; i++) { + scene.set(new Entity(i, 1), [ + ...createTransform3D(offsets[i].x, offsets[i].y, offsets[i].z), + new Meshed(mesh.clone()), + new BasicMaterial3D(material.clone()), + new Rotation3D(), + new Torque3D() + ]) + } + + mesh.drop() + material.drop() + + return scene +} diff --git a/examples/samples/scene/index.js b/examples/samples/scene/index.js index 34a77f62..15ae735d 100644 --- a/examples/samples/scene/index.js +++ b/examples/samples/scene/index.js @@ -1,7 +1,7 @@ -const basic2d = new URL('./basic2d.js', import.meta.url) -const basic3d = new URL('./basic3d.js', import.meta.url) +import { default as d2 } from './2d/index.js' +import { default as d3 } from './3d/index.js' export default { - 'basic 2d': basic2d, - 'basic3d': basic3d + '2d': d2, + '3d': d3 } diff --git a/src/animation/components/player.js b/src/animation/components/player.js index 16924358..0f4e2eec 100644 --- a/src/animation/components/player.js +++ b/src/animation/components/player.js @@ -37,7 +37,7 @@ export class AnimationPlayer { * @param {AnimationPlayer} target */ static clone(target) { - return this.copy(target) + return AnimationPlayer.copy(target) } /** diff --git a/src/animation/components/target.js b/src/animation/components/target.js index 3d876efa..4894a631 100644 --- a/src/animation/components/target.js +++ b/src/animation/components/target.js @@ -36,6 +36,6 @@ export class AnimationTarget { * @param {AnimationTarget} target */ static clone(target) { - return this.copy(target) + return AnimationTarget.copy(target) } } diff --git a/src/animation/core/playback.js b/src/animation/core/playback.js index bdb7bd8c..fcf5397e 100644 --- a/src/animation/core/playback.js +++ b/src/animation/core/playback.js @@ -58,7 +58,7 @@ export class Playback { * @param {Playback} target */ static clone(target) { - return this.copy(target) + return Playback.copy(target) } start() { diff --git a/src/audio/components/audiooscillator.js b/src/audio/components/audiooscillator.js index ac3e678b..1176cafb 100644 --- a/src/audio/components/audiooscillator.js +++ b/src/audio/components/audiooscillator.js @@ -62,7 +62,7 @@ export class AudioOscillator { * @param {AudioOscillator} target */ static clone(target) { - return this.copy(target) + return AudioOscillator.copy(target) } } diff --git a/src/audio/components/audioplayer.js b/src/audio/components/audioplayer.js index 8a8edc72..b3df60a3 100644 --- a/src/audio/components/audioplayer.js +++ b/src/audio/components/audioplayer.js @@ -45,7 +45,7 @@ export class AudioPlayer { * @param {AudioPlayer} target */ static clone(target) { - return this.copy(target) + return AudioPlayer.copy(target) } } diff --git a/src/broadphase/components/hitbox.js b/src/broadphase/components/hitbox.js index e17ce4cd..c025df24 100644 --- a/src/broadphase/components/hitbox.js +++ b/src/broadphase/components/hitbox.js @@ -14,6 +14,6 @@ export class PhysicsHitbox extends BoundingBox2D { * @param {PhysicsHitbox} target */ static clone(target) { - return this.copy(target) + return PhysicsHitbox.copy(target) } } diff --git a/src/emitter/components/emitter.js b/src/emitter/components/emitter.js index 6a8b24e5..7c35ea3b 100644 --- a/src/emitter/components/emitter.js +++ b/src/emitter/components/emitter.js @@ -65,7 +65,7 @@ export class Emitter { * @param {Emitter} target */ static clone(target) { - return this.copy(target) + return Emitter.copy(target) } } diff --git a/src/emitter/components/particle.js b/src/emitter/components/particle.js index a932c067..a1b11093 100644 --- a/src/emitter/components/particle.js +++ b/src/emitter/components/particle.js @@ -12,6 +12,6 @@ export class Particle { * @param {Particle} target */ static clone(target) { - return this.copy(target) + return Particle.copy(target) } } diff --git a/src/hierarchy/components/children.js b/src/hierarchy/components/children.js index 16079951..c3410a34 100644 --- a/src/hierarchy/components/children.js +++ b/src/hierarchy/components/children.js @@ -34,7 +34,7 @@ export class Children { * @param {Children} target */ static clone(target) { - return this.copy(target) + return Children.copy(target) } /** diff --git a/src/hierarchy/components/parent.js b/src/hierarchy/components/parent.js index 69a78a3a..a0da1537 100644 --- a/src/hierarchy/components/parent.js +++ b/src/hierarchy/components/parent.js @@ -34,7 +34,7 @@ export class Parent { * @param {Parent} target */ static clone(target) { - return this.copy(target) + return Parent.copy(target) } visit() { return [this.entity] diff --git a/src/movable/components/2d/acceleration.js b/src/movable/components/2d/acceleration.js index 4824357d..0d535752 100644 --- a/src/movable/components/2d/acceleration.js +++ b/src/movable/components/2d/acceleration.js @@ -14,6 +14,6 @@ export class Acceleration2D extends Vector2 { * @param {Acceleration2D} target */ static clone(target) { - return this.copy(target) + return Acceleration2D.copy(target) } } diff --git a/src/movable/components/2d/rotation.js b/src/movable/components/2d/rotation.js index d590f47c..ddc6c7a2 100644 --- a/src/movable/components/2d/rotation.js +++ b/src/movable/components/2d/rotation.js @@ -16,6 +16,6 @@ export class Rotation2D extends Angle { * @param {Rotation2D} target */ static clone(target) { - return this.copy(target) + return Rotation2D.copy(target) } } diff --git a/src/movable/components/2d/torque.js b/src/movable/components/2d/torque.js index f877357f..38116939 100644 --- a/src/movable/components/2d/torque.js +++ b/src/movable/components/2d/torque.js @@ -16,6 +16,6 @@ export class Torque2D extends Angle { * @param {Torque2D} target */ static clone(target) { - return this.copy(target) + return Torque2D.copy(target) } } diff --git a/src/movable/components/2d/velocity.js b/src/movable/components/2d/velocity.js index 3d818a07..86bc41c0 100644 --- a/src/movable/components/2d/velocity.js +++ b/src/movable/components/2d/velocity.js @@ -14,6 +14,6 @@ export class Velocity2D extends Vector2 { * @param {Velocity2D} target */ static clone(target) { - return this.copy(target) + return Velocity2D.copy(target) } } diff --git a/src/movable/components/3d/acceleration.js b/src/movable/components/3d/acceleration.js index 7b065704..507a00a6 100644 --- a/src/movable/components/3d/acceleration.js +++ b/src/movable/components/3d/acceleration.js @@ -14,6 +14,6 @@ export class Acceleration3D extends Vector3 { * @param {Acceleration3D} target */ static clone(target) { - return this.copy(target) + return Acceleration3D.copy(target) } } diff --git a/src/movable/components/3d/rotation.js b/src/movable/components/3d/rotation.js index cec1da3c..16237466 100644 --- a/src/movable/components/3d/rotation.js +++ b/src/movable/components/3d/rotation.js @@ -14,6 +14,6 @@ export class Rotation3D extends Vector3 { * @param {Rotation3D} target */ static clone(target) { - return this.copy(target) + return Rotation3D.copy(target) } } diff --git a/src/movable/components/3d/torque.js b/src/movable/components/3d/torque.js index 0ae7fa16..1111be41 100644 --- a/src/movable/components/3d/torque.js +++ b/src/movable/components/3d/torque.js @@ -14,6 +14,6 @@ export class Torque3D extends Vector3 { * @param {Torque3D} target */ static clone(target) { - return this.copy(target) + return Torque3D.copy(target) } } diff --git a/src/movable/components/3d/velocity.js b/src/movable/components/3d/velocity.js index b36dcd04..676561c4 100644 --- a/src/movable/components/3d/velocity.js +++ b/src/movable/components/3d/velocity.js @@ -14,6 +14,6 @@ export class Velocity3D extends Vector3 { * @param {Velocity3D} target */ static clone(target) { - return this.copy(target) + return Velocity3D.copy(target) } } diff --git a/src/name/components/name.js b/src/name/components/name.js index d98e0c5e..076aa1bb 100644 --- a/src/name/components/name.js +++ b/src/name/components/name.js @@ -26,6 +26,6 @@ export class Name { * @param {Name} target */ static clone(target) { - return this.copy(target) + return Name.copy(target) } } diff --git a/src/physics/components/collider.js b/src/physics/components/collider.js index b9767997..6f0c1285 100644 --- a/src/physics/components/collider.js +++ b/src/physics/components/collider.js @@ -66,7 +66,7 @@ export class Collider2D { * @param {Collider2D} target */ static clone(target) { - return this.copy(target) + return Collider2D.copy(target) } /** diff --git a/src/physics/components/physicsproperties.js b/src/physics/components/physicsproperties.js index 6f058103..957e734b 100644 --- a/src/physics/components/physicsproperties.js +++ b/src/physics/components/physicsproperties.js @@ -27,6 +27,6 @@ export class PhysicsProperties { * @param {PhysicsProperties} target */ static clone(target) { - return this.copy(target) + return PhysicsProperties.copy(target) } } diff --git a/src/physics/components/softbody.js b/src/physics/components/softbody.js index ab7b16cb..c80c818b 100644 --- a/src/physics/components/softbody.js +++ b/src/physics/components/softbody.js @@ -12,7 +12,7 @@ export class SoftBody2D { * @param {SoftBody2D} target */ static clone(target) { - return this.copy(target) + return SoftBody2D.copy(target) } } @@ -30,6 +30,6 @@ export class SoftBody3D { * @param {SoftBody3D} target */ static clone(target) { - return this.copy(target) + return SoftBody3D.copy(target) } } diff --git a/src/render-core/components/camera.js b/src/render-core/components/camera.js index 7e468f83..b1d55091 100644 --- a/src/render-core/components/camera.js +++ b/src/render-core/components/camera.js @@ -41,7 +41,7 @@ export class Camera { * @param {Camera} target */ static clone(target) { - return this.copy(target) + return Camera.copy(target) } projectionMatrix() { return this.projection.asProjectionMatrix(this.near, this.far) diff --git a/src/render-core/components/material.js b/src/render-core/components/material.js index f974feff..ee0c7e71 100644 --- a/src/render-core/components/material.js +++ b/src/render-core/components/material.js @@ -2,6 +2,7 @@ import { Material } from '../assets/index.js' import { Handle } from '../../asset/index.js' /** + * @abstract * @template {Material} T */ export class Material2D { @@ -17,25 +18,6 @@ export class Material2D { constructor(handle) { this.handle = handle } - - /** - * @template {Material} U - * @param {Material2D} source - * @param {Material2D} target - */ - static copy(source, target = new this(source.handle)) { - target.handle = source.handle.clone() - - return target - } - - /** - * @template {Material} U - * @param {Material2D} target - */ - static clone(target) { - return this.copy(target) - } } /** @@ -54,23 +36,4 @@ export class Material3D { constructor(handle) { this.handle = handle } - - /** - * @template {Material} U - * @param {Material3D} source - * @param {Material3D} target - */ - static copy(source, target = new this(source.handle)) { - target.handle = source.handle.clone() - - return target - } - - /** - * @template {Material} U - * @param {Material3D} target - */ - static clone(target) { - return this.copy(target) - } } diff --git a/src/render-core/components/materials/index.js b/src/render-core/components/materials/index.js index 888096d3..f8b2aee5 100644 --- a/src/render-core/components/materials/index.js +++ b/src/render-core/components/materials/index.js @@ -4,9 +4,45 @@ import { Material2D, Material3D } from '../material.js' /** * @augments Material2D */ -export class BasicMaterial2D extends Material2D {} +export class BasicMaterial2D extends Material2D { + + /** + * @param {BasicMaterial2D} source + * @param {BasicMaterial2D} target + */ + static copy(source, target = new BasicMaterial2D(source.handle)) { + target.handle = source.handle.clone() + + return target + } + + /** + * @param {BasicMaterial2D} target + */ + static clone(target) { + return BasicMaterial2D.copy(target) + } +} /** * @augments Material3D */ -export class BasicMaterial3D extends Material3D {} +export class BasicMaterial3D extends Material3D { + + /** + * @param {BasicMaterial3D} source + * @param {BasicMaterial3D} target + */ + static copy(source, target = new BasicMaterial3D(source.handle)) { + target.handle = source.handle.clone() + + return target + } + + /** + * @param {BasicMaterial3D} target + */ + static clone(target) { + return BasicMaterial3D.copy(target) + } +} diff --git a/src/render-core/components/mesh.js b/src/render-core/components/mesh.js index 46eeec04..0ce081d4 100644 --- a/src/render-core/components/mesh.js +++ b/src/render-core/components/mesh.js @@ -29,6 +29,6 @@ export class Meshed { * @param {Meshed} target */ static clone(target) { - return this.copy(target) + return Meshed.copy(target) } } diff --git a/src/render-core/components/renderlists.js b/src/render-core/components/renderlists.js index cf3e8ac8..701a42d0 100644 --- a/src/render-core/components/renderlists.js +++ b/src/render-core/components/renderlists.js @@ -4,6 +4,7 @@ import { GlobalTransform2D, GlobalTransform3D } from '../../transform/index.js' /** * @template T + * @abstract */ export class RenderType { @@ -45,23 +46,6 @@ export class RenderLists { */ opaquePass = new Map() - /** - * @template U - * @param {RenderLists} _source - * @param {RenderLists} target - */ - static copy(_source, target = new this()) { - return target - } - - /** - * @template U - * @param {RenderLists} target - */ - static clone(target) { - return this.copy(target) - } - /** * @param {TypeId} id * @returns {RenderType[] | undefined} @@ -91,9 +75,43 @@ export class RenderLists { /** * @augments RenderLists */ -export class RenderLists2D extends RenderLists { } +export class RenderLists2D extends RenderLists { + + /** + * @param {RenderLists2D} _source + * @param {RenderLists2D} target + */ + static copy(_source, target = new RenderLists2D()) { + return target + } + + /** + * @param {RenderLists2D} target + */ + static clone(target) { + return RenderLists2D.copy(target) + } +} /** * @augments RenderLists */ -export class RenderLists3D extends RenderLists { } +export class RenderLists3D extends RenderLists { + + /** + * @template U + * @param {RenderLists3D} _source + * @param {RenderLists3D} target + */ + static copy(_source, target = new RenderLists3D()) { + return target + } + + /** + * @template U + * @param {RenderLists3D} target + */ + static clone(target) { + return RenderLists3D.copy(target) + } +} diff --git a/src/render-core/systems/types.js b/src/render-core/systems/types.js index dea999df..6b7b044c 100644 --- a/src/render-core/systems/types.js +++ b/src/render-core/systems/types.js @@ -1,13 +1,13 @@ /** @import { Constructor } from '../../type/index.js' */ import { World } from '../../ecs/index.js' -import { EnumInfo, Field, MapInfo, StructInfo } from '../../reflect/core/index.js' +import { EnumInfo, Field, MapInfo, OpaqueInfo, StructInfo } from '../../reflect/core/index.js' import { TypeRegistry } from '../../reflect/resources/index.js' import { setTypeId, typeid, typeidGeneric } from '../../type/index.js' import { Handle } from '../../asset/index.js' import { Color } from '../../color/index.js' import { Vector2 } from '../../math/index.js' -import { Camera, Meshed } from '../components/index.js' +import { Camera, Meshed, RenderLists2D, RenderLists3D } from '../components/index.js' import { BasicMaterial2D, BasicMaterial3D } from '../components/materials/index.js' import { MeshAttributeData } from '../core/attributedata.js' import { Projection, ShaderStage } from '../core/index.js' @@ -66,6 +66,14 @@ export function registerRenderCoreTypes(world) { })) registry.get(Camera)?.setMethod(Camera.copy) registry.get(Camera)?.setMethod(Camera.clone) + + registry.register(RenderLists2D, new OpaqueInfo()) + registry.get(RenderLists2D)?.setMethod(RenderLists2D.copy) + registry.get(RenderLists2D)?.setMethod(RenderLists2D.clone) + + registry.register(RenderLists3D, new OpaqueInfo()) + registry.get(RenderLists3D)?.setMethod(RenderLists3D.copy) + registry.get(RenderLists3D)?.setMethod(RenderLists3D.clone) } /** diff --git a/src/scene/assets/scene.js b/src/scene/assets/scene.js index 737ce06a..bcf37ccb 100644 --- a/src/scene/assets/scene.js +++ b/src/scene/assets/scene.js @@ -1,25 +1,47 @@ /** @import {EntityId} from '../../ecs/index.js' */ import { Entity, Query, World } from '../../ecs/index.js' +import { Parent } from '../../hierarchy/index.js' +import { warn } from '../../logger/index.js' import { TypeRegistry } from '../../reflect/index.js' import { SceneInstance } from '../components/index.js' export class Scene { - /** @type {Map } */ + /** @type {Map } */ entities = new Map() /** * @param {World} world * @param {SceneInstance} instance - * @param {TypeRegistry} _typeRegistry + * @param {TypeRegistry} typeRegistry + * @param {Entity} [instanceEntity] */ - toWorld(world, instance, _typeRegistry) { + toWorld(world, instance, typeRegistry, instanceEntity) { const { entityMap } = instance for (const [entity, components] of this.entities) { - // TODO: Actually clone them using the typeregistry. - const clonedComponents = components + const clonedComponents = components.map((component) => { + + const { constructor } = component + const clone = typeRegistry + .get(/** @type {import('../../type/index.js').Constructor} */(constructor)) + ?.call('clone', [component]) + + if (clone) { + return clone + } + + warn(`The component \`${constructor.name}\` has not been cloned as there is no clone method registered in the \`TypeRegistry\``) + + return undefined + + }).filter((e) => e !== undefined) + + if (!clonedComponents.some((c) => c.constructor === Parent)) { + clonedComponents.push(new Parent(instanceEntity)) + } + const worldEntity = world.spawn(clonedComponents) entityMap.set(worldEntity.id(), entity) @@ -28,19 +50,33 @@ export class Scene { /** * @param {World} world - * @param {TypeRegistry} _typeRegistry + * @param {TypeRegistry} typeRegistry */ - static fromWorld(world, _typeRegistry) { + static fromWorld(world, typeRegistry) { const scene = new Scene() const entities = new Query(world, [Entity]) entities.each(([entity]) => { const cell = world.getEntity(entity) - const components = cell - .components() + const typeIds = cell.components() + const components = [] + + for (let i = 0; i < typeIds.length; i++) { + const typeId = typeIds[i] + const component = cell.getTypeId(typeId) + const clone = /** @type {object} */(typeRegistry + .getByTypeId(typeId) + ?.call('clone', [component])) + + if (clone) { + components.push(clone) + } else { + const { constructor } = component + const name = constructor.name || 'Unknown' - // TODO: Clone the component instead using the type registry. - .map((id) => cell.getTypeId(id)) + warn(`The component \`${name}\` has not been cloned as there is no clone method registered in the \`TypeRegistry\``) + } + } scene.entities.set(entity.id(), components) }) diff --git a/src/scene/components/instance.js b/src/scene/components/instance.js index cd2b081a..752762be 100644 --- a/src/scene/components/instance.js +++ b/src/scene/components/instance.js @@ -35,6 +35,6 @@ export class SceneInstance { * @param {SceneInstance} target */ static clone(target) { - return this.copy(target) + return SceneInstance.copy(target) } } diff --git a/src/scene/systems/index.js b/src/scene/systems/index.js index 85ce4f4f..3cd2d8e1 100644 --- a/src/scene/systems/index.js +++ b/src/scene/systems/index.js @@ -1,4 +1,5 @@ import { Entity, Query, World } from '../../ecs/index.js' +import { TypeRegistry } from '../../reflect/resources/index.js' import { SceneInstance } from '../components/index.js' import { SceneAssets, SceneSpawner } from '../resources/index.js' @@ -9,6 +10,7 @@ export function spawnScenes(world) { const scenes = world.getResource(SceneAssets) const instances = new Query(world, [SceneInstance]) const spawner = world.getResource(SceneSpawner) + const typeRegistry = world.getResource(TypeRegistry) for (const assetId of spawner.assets()) { const scene = scenes.getByAssetId(assetId) @@ -23,9 +25,7 @@ export function spawnScenes(world) { if (!instance) continue - // TODO: Actually supply a type registry - // @ts-ignore - scene.toWorld(world, instance[0], undefined) + scene.toWorld(world, instance[0], typeRegistry, entity) } spawner.clear(assetId) diff --git a/src/time/components/timer.js b/src/time/components/timer.js index 3de47c9b..96c5182b 100644 --- a/src/time/components/timer.js +++ b/src/time/components/timer.js @@ -105,7 +105,7 @@ export class Timer { * @param {Timer} target */ static clone(target) { - return this.copy(target) + return Timer.copy(target) } elapsed() { diff --git a/src/transform/components/2d/globaltransform.js b/src/transform/components/2d/globaltransform.js index 46f6826d..7bbbc6c2 100644 --- a/src/transform/components/2d/globaltransform.js +++ b/src/transform/components/2d/globaltransform.js @@ -14,6 +14,6 @@ export class GlobalTransform2D extends Affine2 { * @param {GlobalTransform2D} target */ static clone(target) { - return this.copy(target) + return GlobalTransform2D.copy(target) } } diff --git a/src/transform/components/2d/orientation.js b/src/transform/components/2d/orientation.js index 4c746ab8..ce295044 100644 --- a/src/transform/components/2d/orientation.js +++ b/src/transform/components/2d/orientation.js @@ -14,6 +14,6 @@ export class Orientation2D extends Rotary { * @param {Orientation2D} target */ static clone(target) { - return this.copy(target) + return Orientation2D.copy(target) } } diff --git a/src/transform/components/2d/position.js b/src/transform/components/2d/position.js index ff3de892..0e89da58 100644 --- a/src/transform/components/2d/position.js +++ b/src/transform/components/2d/position.js @@ -14,6 +14,6 @@ export class Position2D extends Vector2 { * @param {Position2D} target */ static clone(target) { - return this.copy(target) + return Position2D.copy(target) } } diff --git a/src/transform/components/2d/remote.js b/src/transform/components/2d/remote.js index 3cb00307..dcb98e3f 100644 --- a/src/transform/components/2d/remote.js +++ b/src/transform/components/2d/remote.js @@ -53,6 +53,6 @@ export class RemoteTransform2D { * @param {RemoteTransform2D} target */ static clone(target) { - return this.copy(target) + return RemoteTransform2D.copy(target) } } diff --git a/src/transform/components/2d/scale.js b/src/transform/components/2d/scale.js index aed2eb19..708fd439 100644 --- a/src/transform/components/2d/scale.js +++ b/src/transform/components/2d/scale.js @@ -17,6 +17,6 @@ export class Scale2D extends Vector2 { * @param {Scale2D} target */ static clone(target) { - return this.copy(target) + return Scale2D.copy(target) } } diff --git a/src/transform/components/3d/globaltransform.js b/src/transform/components/3d/globaltransform.js index 2492968f..90a6ce15 100644 --- a/src/transform/components/3d/globaltransform.js +++ b/src/transform/components/3d/globaltransform.js @@ -14,6 +14,6 @@ export class GlobalTransform3D extends Affine3 { * @param {GlobalTransform3D} target */ static clone(target) { - return this.copy(target) + return GlobalTransform3D.copy(target) } } diff --git a/src/transform/components/3d/orientation.js b/src/transform/components/3d/orientation.js index 49569e04..36d6455b 100644 --- a/src/transform/components/3d/orientation.js +++ b/src/transform/components/3d/orientation.js @@ -14,6 +14,6 @@ export class Orientation3D extends Quaternion { * @param {Orientation3D} target */ static clone(target) { - return this.copy(target) + return Orientation3D.copy(target) } } diff --git a/src/transform/components/3d/position.js b/src/transform/components/3d/position.js index 58e8e1c2..13c9c709 100644 --- a/src/transform/components/3d/position.js +++ b/src/transform/components/3d/position.js @@ -14,6 +14,6 @@ export class Position3D extends Vector3 { * @param {Position3D} target */ static clone(target) { - return this.copy(target) + return Position3D.copy(target) } } diff --git a/src/transform/components/3d/remote.js b/src/transform/components/3d/remote.js index b746f0fa..08d5f80a 100644 --- a/src/transform/components/3d/remote.js +++ b/src/transform/components/3d/remote.js @@ -53,6 +53,6 @@ export class RemoteTransform3D { * @param {RemoteTransform3D} target */ static clone(target) { - return this.copy(target) + return RemoteTransform3D.copy(target) } } diff --git a/src/transform/components/3d/scale.js b/src/transform/components/3d/scale.js index 5d77c9ea..c78116e8 100644 --- a/src/transform/components/3d/scale.js +++ b/src/transform/components/3d/scale.js @@ -18,6 +18,6 @@ export class Scale3D extends Vector3 { * @param {Scale3D} target */ static clone(target) { - return this.copy(target) + return Scale3D.copy(target) } } diff --git a/src/tween/components/markers.js b/src/tween/components/markers.js index ce402422..eb39474c 100644 --- a/src/tween/components/markers.js +++ b/src/tween/components/markers.js @@ -12,7 +12,7 @@ export class TweenRepeat { * @param {TweenRepeat} target */ static clone(target) { - return this.copy(target) + return TweenRepeat.copy(target) } } @@ -30,6 +30,6 @@ export class TweenFlip { * @param {TweenFlip} target */ static clone(target) { - return this.copy(target) + return TweenFlip.copy(target) } } diff --git a/src/tween/components/tween.js b/src/tween/components/tween.js index a8787dca..d430d50f 100644 --- a/src/tween/components/tween.js +++ b/src/tween/components/tween.js @@ -93,6 +93,6 @@ export class Tween { * @param {Tween} target */ static clone(target) { - return this.copy(target) + return Tween.copy(target) } } diff --git a/src/window/components/main.js b/src/window/components/main.js index 286dd129..b863bb27 100644 --- a/src/window/components/main.js +++ b/src/window/components/main.js @@ -12,6 +12,6 @@ export class MainWindow { * @param {MainWindow} target */ static clone(target) { - return this.copy(target) + return MainWindow.copy(target) } } diff --git a/src/window/components/window.js b/src/window/components/window.js index fb752291..90eff42e 100644 --- a/src/window/components/window.js +++ b/src/window/components/window.js @@ -42,7 +42,7 @@ export class Window { * @param {Window} target */ static clone(target) { - return this.copy(target) + return Window.copy(target) } /**