From 4cac624fdb0bc27f4b975c9725acaba4116ff191 Mon Sep 17 00:00:00 2001 From: AIFanatic <9558106+AIFanatic@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:25:03 +0000 Subject: [PATCH] improvements --- dist/trident.js | 98 +++++++++++++++++++++++-- src/Events.ts | 31 +++++++- src/GameObject.ts | 11 +++ src/Scene.ts | 15 ++++ src/components/Component.ts | 1 + src/components/Light.ts | 2 +- src/components/MeshletMesh.ts | 33 ++++++++- src/components/Transform.ts | 5 +- src/renderer/passes/PrepareSceneData.ts | 23 +++++- 9 files changed, 202 insertions(+), 17 deletions(-) diff --git a/dist/trident.js b/dist/trident.js index a9d32cc..ed1fdab 100644 --- a/dist/trident.js +++ b/dist/trident.js @@ -20,6 +20,25 @@ var EventSystem = class { } } }; +var EventSystemLocal = class { + static events = {}; + static on(event, callback, id) { + const eventId = id ? `${event}-${id}` : event; + if (!this.events[eventId]) this.events[eventId] = []; + this.events[eventId].push(callback); + console.log(`Registered ${eventId}`); + } + static emit(event, id, ...args) { + const eventId = `${event}-${id}`; + if (!this.events[eventId]) { + return; + } + console.log(`Listeners for ${this.events[eventId].length}`); + for (let i = 0; i < this.events[eventId].length; i++) { + this.events[eventId][i](...args); + } + } +}; // src/utils/Utils.ts var Utils = class { @@ -61,6 +80,8 @@ var Component = class _Component { } LateUpdate() { } + Destroy() { + } }; // src/math/Matrix4.ts @@ -797,11 +818,12 @@ var Transform = class extends Component { } onChanged() { EventSystem.emit("CallUpdate", this, true); - EventSystem.emit("TransformUpdated", this); } UpdateMatrices() { this._localToWorldMatrix.compose(this.position, this.rotation, this.scale); this._worldToLocalMatrix.copy(this._localToWorldMatrix).invert(); + EventSystem.emit("TransformUpdated", this); + EventSystemLocal.emit("TransformUpdated", this.gameObject.id, this); } Update() { this.UpdateMatrices(); @@ -867,6 +889,7 @@ var Camera = class _Camera extends Component { // src/GameObject.ts var GameObject = class { + id = Utils.UUID(); name = "GameObject"; scene; transform; @@ -909,6 +932,14 @@ var GameObject = class { } } } + Destroy() { + for (const component of this.componentsArray) { + component.Destroy(); + } + this.componentsArray = []; + this.componentsMapped.clear(); + this.scene.RemoveGameObject(this); + } }; // src/renderer/RenderGraph.ts @@ -7928,9 +7959,15 @@ var Meshletizer = class _Meshletizer { // src/components/MeshletMesh.ts var meshletsCache = /* @__PURE__ */ new Map(); var MeshletMesh = class extends Component { + geometry; materialsMapped = /* @__PURE__ */ new Map(); enableShadows = true; meshlets = []; + Start() { + EventSystemLocal.on("TransformUpdated", (transform) => { + EventSystem.emit("MeshletUpdated", this); + }, this.gameObject.id); + } AddMaterial(material) { if (!this.materialsMapped.has(material.constructor.name)) this.materialsMapped.set(material.constructor.name, []); this.materialsMapped.get(material.constructor.name)?.push(material); @@ -7939,9 +7976,12 @@ var MeshletMesh = class extends Component { return this.materialsMapped.get(type.name) || []; } async SetGeometry(geometry) { - const cached = meshletsCache.get(geometry); + this.geometry = geometry; + let cached = meshletsCache.get(geometry); if (cached) { - this.meshlets.push(...cached); + cached.instanceCount++; + meshletsCache.set(geometry, cached); + this.meshlets.push(...cached.meshlets); return; } const pa = geometry.attributes.get("position"); @@ -7958,7 +7998,18 @@ var MeshletMesh = class extends Component { await Meshoptimizer.load(); const allMeshlets = await Meshletizer.Build(interleavedVertices, indices); this.meshlets = allMeshlets; - meshletsCache.set(geometry, this.meshlets); + meshletsCache.set(geometry, { meshlets: this.meshlets, instanceCount: 0 }); + } + Destroy() { + EventSystem.emit("MeshletDeleted", this); + const cached = meshletsCache.get(this.geometry); + if (!cached) throw Error("Geometry should be in meshletsCache"); + cached.instanceCount--; + meshletsCache.set(this.geometry, cached); + if (cached.instanceCount <= 0) { + meshletsCache.delete(this.geometry); + } + EventSystem.emit("RemovedComponent", this, this.gameObject.scene); } }; @@ -8101,6 +8152,20 @@ var PrepareSceneData = class extends RenderPass { this.meshletInfoBuffer = new BufferMemoryAllocator(meshMatrixBufferSize); this.vertexBuffer = new BufferMemoryAllocator(meshMatrixBufferSize); this.objectInfoBufferV2 = new BufferMemoryAllocator(meshMatrixBufferSize); + EventSystem.on("MeshletUpdated", (mesh) => { + console.log("Meshlet updated"); + if (this.meshMatrixInfoBuffer.has(mesh.id)) { + this.meshMatrixInfoBuffer.set(mesh.id, mesh.transform.localToWorldMatrix.elements); + } + }); + EventSystem.on("MeshletDeleted", (mesh) => { + console.log("Meshlet deleted"); + if (this.meshMatrixInfoBuffer.has(mesh.id)) this.meshMatrixInfoBuffer.delete(mesh.id); + if (this.meshMaterialInfo.has(mesh.id)) this.meshMaterialInfo.delete(mesh.id); + for (const meshlet of mesh.meshlets) { + this.objectInfoBufferV2.delete(`${mesh.id}-${meshlet.id}`); + } + }); } getVertexInfo(meshlet) { return meshlet.vertices_gpu; @@ -8219,7 +8284,10 @@ var PrepareSceneData = class extends RenderPass { const meshCache = /* @__PURE__ */ new Map(); for (const mesh of sceneMeshlets) { if (!this.meshMaterialInfo.has(mesh.id)) this.meshMaterialInfo.set(mesh.id, this.getMeshMaterialInfo(mesh)); - if (!this.meshMatrixInfoBuffer.has(mesh.id)) this.meshMatrixInfoBuffer.set(mesh.id, mesh.transform.localToWorldMatrix.elements); + if (!this.meshMatrixInfoBuffer.has(mesh.id)) { + console.log(mesh.id, mesh.transform.localToWorldMatrix.elements); + this.meshMatrixInfoBuffer.set(mesh.id, mesh.transform.localToWorldMatrix.elements); + } let meshIndex = meshCache.get(mesh.id); if (meshIndex === void 0) { meshIndex = meshCache.size; @@ -8604,6 +8672,16 @@ var Scene = class { componentsArray.push(component); this.componentsByType.set(component.name, componentsArray); }); + EventSystem.on("RemovedComponent", (component, scene) => { + let componentsArray = this.componentsByType.get(component.name); + if (componentsArray) { + const index = componentsArray.indexOf(component); + if (index !== -1) { + componentsArray.splice(index, 1); + this.componentsByType.set(component.name, componentsArray); + } + } + }); } AddGameObject(gameObject) { this.gameObjects.push(gameObject); @@ -8614,6 +8692,10 @@ var Scene = class { GetComponents(type) { return this.componentsByType.get(type.name) || []; } + RemoveGameObject(gameObject) { + const index = this.gameObjects.indexOf(gameObject); + if (index !== -1) this.gameObjects.splice(index, 1); + } Start() { if (this.hasStarted) return; for (const gameObject of this.gameObjects) gameObject.Start(); @@ -8903,8 +8985,12 @@ async function Application() { } } setTimeout(() => { - console.log("Updtin"); + console.log("Updating"); lastMesh.transform.position.x += 2; + setTimeout(() => { + console.log("Destroying"); + lastMesh.transform.gameObject.Destroy(); + }, 5e3); }, 5e3); scene.Start(); } diff --git a/src/Events.ts b/src/Events.ts index 3aad658..700fd61 100644 --- a/src/Events.ts +++ b/src/Events.ts @@ -2,15 +2,17 @@ import { Scene } from "./Scene"; import { Camera } from "./components/Camera"; import { Component } from "./components/Component"; import { Light } from "./components/Light"; -import { Mesh } from "./components/Mesh"; +import { MeshletMesh } from "./components/MeshletMesh"; import { Transform } from "./components/Transform"; export interface Events { AddedComponent: (component: Component, scene: Scene) => void; + RemovedComponent: (component: Component, scene: Scene) => void; CallUpdate: (component: Component, flag: boolean) => void; TransformUpdated: (component: Transform) => void; LightUpdated: (light: Light) => void; - MeshUpdated: (mesh: Mesh) => void; + MeshletUpdated: (meshlet: MeshletMesh) => void; + MeshletDeleted: (meshlet: MeshletMesh) => void; MainCameraUpdated: (camera: Camera) => void; }; @@ -33,4 +35,29 @@ export class EventSystem { callbacks[i](...args); } } +} + + + +export class EventSystemLocal { + private static events: EventMap = {}; + + public static on(event: K, callback: Events[K], id?: string) { + const eventId = id ? `${event}-${id}` : event; + if (!this.events[eventId]) this.events[eventId] = []; + this.events[eventId].push(callback); + console.log(`Registered ${eventId}`); // Debugging line to confirm registration + } + + public static emit(event: K, id: string, ...args: Parameters) { + const eventId = `${event}-${id}`; + if (!this.events[eventId]) { + // console.log(`No listeners for ${eventId}`); // Debugging line to check if listeners are being called + return; + } + console.log(`Listeners for ${this.events[eventId].length}`); // Debugging line to check if listeners are being called + for (let i = 0; i < this.events[eventId].length; i++) { + this.events[eventId][i](...args); + } + } } \ No newline at end of file diff --git a/src/GameObject.ts b/src/GameObject.ts index 5cfa9fe..aa48e6e 100644 --- a/src/GameObject.ts +++ b/src/GameObject.ts @@ -2,8 +2,10 @@ import { Component } from "./components/Component"; import { Scene } from "./Scene"; import { Transform } from "./components/Transform"; import { Camera } from "./components/Camera"; +import { Utils } from "./utils/Utils"; export class GameObject { + public id = Utils.UUID(); public name: string = "GameObject"; public scene: Scene; @@ -57,4 +59,13 @@ export class GameObject { } } } + + public Destroy() { + for (const component of this.componentsArray) { + component.Destroy(); + } + this.componentsArray = []; + this.componentsMapped.clear(); + this.scene.RemoveGameObject(this); + } } \ No newline at end of file diff --git a/src/Scene.ts b/src/Scene.ts index 5c4f393..7dab55a 100644 --- a/src/Scene.ts +++ b/src/Scene.ts @@ -53,11 +53,26 @@ export class Scene { // } }); + + EventSystem.on("RemovedComponent", (component, scene) => { + let componentsArray = this.componentsByType.get(component.name); + if (componentsArray) { + const index = componentsArray.indexOf(component); + if (index !== -1) { + componentsArray.splice(index, 1); + this.componentsByType.set(component.name, componentsArray); + } + } + }); } public AddGameObject(gameObject: GameObject) { this.gameObjects.push(gameObject) } public GetGameObjects(): GameObject[] { return this.gameObjects } public GetComponents(type: new(...args: any[]) => T): T[] { return this.componentsByType.get(type.name) as T[] || [] } + public RemoveGameObject(gameObject: GameObject) { + const index = this.gameObjects.indexOf(gameObject); + if (index !== -1) this.gameObjects.splice(index, 1); + } public Start() { if (this.hasStarted) return; diff --git a/src/components/Component.ts b/src/components/Component.ts index f8f9341..cae4777 100644 --- a/src/components/Component.ts +++ b/src/components/Component.ts @@ -26,4 +26,5 @@ export class Component { public Start() {} public Update() {} public LateUpdate() {} + public Destroy() {} } \ No newline at end of file diff --git a/src/components/Light.ts b/src/components/Light.ts index 1cf52f0..de2a6a2 100644 --- a/src/components/Light.ts +++ b/src/components/Light.ts @@ -1,4 +1,4 @@ -import { EventSystem } from "../Events"; +import { EventSystem, EventSystemLocal } from "../Events"; import { Color } from "../math/Color"; import { Vector3 } from "../math/Vector3"; import { Renderer } from "../renderer/Renderer"; diff --git a/src/components/MeshletMesh.ts b/src/components/MeshletMesh.ts index 629f16c..7cc728a 100644 --- a/src/components/MeshletMesh.ts +++ b/src/components/MeshletMesh.ts @@ -4,16 +4,24 @@ import { Meshlet } from "../plugins/meshlets/Meshlet"; import { Geometry, InterleavedVertexAttribute } from "../Geometry"; import { Meshletizer } from "../plugins/meshlets/Meshletizer"; import { Meshoptimizer } from "../plugins/meshlets/Meshoptimizer"; +import { EventSystem, EventSystemLocal } from "../Events"; -const meshletsCache: Map = new Map(); +const meshletsCache: Map = new Map(); export class MeshletMesh extends Component { + private geometry: Geometry; private materialsMapped: Map = new Map(); public enableShadows: boolean = true; public meshlets: Meshlet[] = []; + public Start(): void { + EventSystemLocal.on("TransformUpdated", transform => { + EventSystem.emit("MeshletUpdated", this); + }, this.gameObject.id) + } + public AddMaterial(material: Material) { if (!this.materialsMapped.has(material.constructor.name)) this.materialsMapped.set(material.constructor.name, []); this.materialsMapped.get(material.constructor.name)?.push(material); @@ -24,9 +32,12 @@ export class MeshletMesh extends Component { } public async SetGeometry(geometry: Geometry) { - const cached = meshletsCache.get(geometry); + this.geometry = geometry; + let cached = meshletsCache.get(geometry); if (cached) { - this.meshlets.push(...cached); + cached.instanceCount++; + meshletsCache.set(geometry, cached); + this.meshlets.push(...cached.meshlets); return; } @@ -48,6 +59,20 @@ export class MeshletMesh extends Component { const allMeshlets = await Meshletizer.Build(interleavedVertices, indices); this.meshlets = allMeshlets; - meshletsCache.set(geometry, this.meshlets); + meshletsCache.set(geometry, {meshlets: this.meshlets, instanceCount: 0}); + } + + public Destroy() { + EventSystem.emit("MeshletDeleted", this); + const cached = meshletsCache.get(this.geometry); + if (!cached) throw Error("Geometry should be in meshletsCache"); + + cached.instanceCount--; + meshletsCache.set(this.geometry, cached); + if (cached.instanceCount <= 0) { + meshletsCache.delete(this.geometry); + } + + EventSystem.emit("RemovedComponent", this, this.gameObject.scene); } } \ No newline at end of file diff --git a/src/components/Transform.ts b/src/components/Transform.ts index 35ec31b..88bc842 100644 --- a/src/components/Transform.ts +++ b/src/components/Transform.ts @@ -1,4 +1,4 @@ -import { EventSystem } from "../Events"; +import { EventSystem, EventSystemLocal } from "../Events"; import { Matrix4 } from "../math/Matrix4"; import { ObservableQuaternion, Quaternion } from "../math/Quaternion"; import { ObservableVector3, Vector3 } from "../math/Vector3"; @@ -37,12 +37,13 @@ export class Transform extends Component { private onChanged() { EventSystem.emit("CallUpdate", this, true); - EventSystem.emit("TransformUpdated", this); } private UpdateMatrices() { this._localToWorldMatrix.compose(this.position, this.rotation, this.scale); this._worldToLocalMatrix.copy(this._localToWorldMatrix).invert(); + EventSystem.emit("TransformUpdated", this); + EventSystemLocal.emit("TransformUpdated", this.gameObject.id, this); } public Update() { diff --git a/src/renderer/passes/PrepareSceneData.ts b/src/renderer/passes/PrepareSceneData.ts index 8af8ead..572367f 100644 --- a/src/renderer/passes/PrepareSceneData.ts +++ b/src/renderer/passes/PrepareSceneData.ts @@ -8,6 +8,7 @@ import { Camera } from "../../components/Camera"; import { Debugger } from "../../plugins/Debugger"; import { PassParams } from "../RenderingPipeline"; import { BufferMemoryAllocator, MemoryAllocator, MemoryAllocatorViewer } from "../../utils/MemoryAllocator"; +import { EventSystem } from "../../Events"; interface SceneMesh { geometry: Meshlet; @@ -60,7 +61,22 @@ export class PrepareSceneData extends RenderPass { this.vertexBuffer = new BufferMemoryAllocator(meshMatrixBufferSize); this.objectInfoBufferV2 = new BufferMemoryAllocator(meshMatrixBufferSize); - // new MemoryAllocatorViewer(this.vertexBuffer); + EventSystem.on("MeshletUpdated", mesh => { + console.log("Meshlet updated"); + if (this.meshMatrixInfoBuffer.has(mesh.id)) { + this.meshMatrixInfoBuffer.set(mesh.id, mesh.transform.localToWorldMatrix.elements); + } + }) + + EventSystem.on("MeshletDeleted", mesh => { + console.log("Meshlet deleted"); + if (this.meshMatrixInfoBuffer.has(mesh.id)) this.meshMatrixInfoBuffer.delete(mesh.id); + if (this.meshMaterialInfo.has(mesh.id)) this.meshMaterialInfo.delete(mesh.id); + + for (const meshlet of mesh.meshlets) { + this.objectInfoBufferV2.delete(`${mesh.id}-${meshlet.id}`); + } + }) } private getVertexInfo(meshlet: Meshlet): Float32Array { @@ -173,7 +189,10 @@ export class PrepareSceneData extends RenderPass { for (const mesh of sceneMeshlets) { // Mesh material info if (!this.meshMaterialInfo.has(mesh.id)) this.meshMaterialInfo.set(mesh.id, this.getMeshMaterialInfo(mesh)); - if (!this.meshMatrixInfoBuffer.has(mesh.id)) this.meshMatrixInfoBuffer.set(mesh.id, mesh.transform.localToWorldMatrix.elements); + if (!this.meshMatrixInfoBuffer.has(mesh.id)) { + console.log(mesh.id, mesh.transform.localToWorldMatrix.elements); + this.meshMatrixInfoBuffer.set(mesh.id, mesh.transform.localToWorldMatrix.elements); + } // Just to get mesh index let meshIndex = meshCache.get(mesh.id);