From 1597762374b9f6ceb1ecda7c83c81876d9c02b01 Mon Sep 17 00:00:00 2001
From: Wolfger Schramm <wolfger@spearwolf.de>
Date: Wed, 20 Mar 2024 16:20:51 +0100
Subject: [PATCH] minor refactorings

---
 packages/shadow-ents/src/entities/Kernel.ts   | 13 ++++++-
 .../shadow-objects/TestImage2OnCanvas2D.js    | 38 ++++++++++++-------
 .../src/shadow-objects/TestImageOnCanvas2D.js | 34 +++++++++++------
 packages/vfx/src/shadow-objects/VfxDisplay.js | 12 ++++--
 4 files changed, 67 insertions(+), 30 deletions(-)

diff --git a/packages/shadow-ents/src/entities/Kernel.ts b/packages/shadow-ents/src/entities/Kernel.ts
index 6595957..0e66326 100644
--- a/packages/shadow-ents/src/entities/Kernel.ts
+++ b/packages/shadow-ents/src/entities/Kernel.ts
@@ -171,6 +171,7 @@ export class Kernel extends Eventize {
 
   createShadowObjects(token: string, entityEntry?: EntityEntry) {
     return this.registry.findConstructors(token)?.map((constructor) => {
+      const unsubscribe = new Set<() => any>();
       const shadowObject = eventize(
         new constructor(
           entityEntry?.entity != null
@@ -189,13 +190,21 @@ export class Kernel extends Eventize {
                   return entityEntry.entity.getPropertyReader(name);
                 },
 
-                // TODO onDestroy <- shadow-object
-                // TODO onEvent ? (auto destroy subscription)
+                onDestroy(callback: () => any) {
+                  unsubscribe.add(callback);
+                },
               }
             : undefined,
         ),
       );
 
+      shadowObject.once(onDestroy, () => {
+        console.log('destroy shadow-object', shadowObject, Array.from(unsubscribe));
+        for (const callback of unsubscribe) {
+          callback();
+        }
+      });
+
       if (entityEntry) {
         // We want to keep track which shadow-objects are created by which constructors.
         // This will allow us to destroy the shadow-objects at a later time when we change the token.
diff --git a/packages/vfx/src/shadow-objects/TestImage2OnCanvas2D.js b/packages/vfx/src/shadow-objects/TestImage2OnCanvas2D.js
index 871ebee..6cb3ba0 100644
--- a/packages/vfx/src/shadow-objects/TestImage2OnCanvas2D.js
+++ b/packages/vfx/src/shadow-objects/TestImage2OnCanvas2D.js
@@ -1,23 +1,35 @@
-export function TestImage2OnCanvas2D({entity}) {
+export function TestImage2OnCanvas2D() {
   const [r, g, b] = [Math.floor(Math.random() * 255), Math.floor(Math.random() * 255), Math.floor(Math.random() * 255)];
   const fillStyle0 = `rgb(${r} ${g} ${b})`;
   const fillStyle1 = `rgb(${255 - r} ${255 - g} ${255 - b})`;
 
-  let ctx = null;
+  let canvas;
+  let ctx;
 
-  entity.on('onRenderFrame', ({canvas}) => {
-    ctx ??= canvas.getContext('2d');
+  return {
+    onRenderFrame(params) {
+      canvas ??= params.canvas;
+      ctx ??= canvas.getContext('2d');
 
-    const [w, h] = [canvas.width, canvas.height];
-    const halfH = Math.floor(h / 2);
-    const halfW = Math.floor(w / 2);
+      const [w, h] = [canvas.width, canvas.height];
+      const halfH = Math.floor(h / 2);
+      const halfW = Math.floor(w / 2);
 
-    ctx.clearRect(0, 0, w, h);
+      ctx.clearRect(0, 0, w, h);
 
-    ctx.fillStyle = fillStyle0;
-    ctx.fillRect(0, 0, halfW, halfH);
+      ctx.fillStyle = fillStyle0;
+      ctx.fillRect(0, 0, halfW, halfH);
 
-    ctx.fillStyle = fillStyle1;
-    ctx.fillRect(0, halfH, halfW, h - halfH);
-  });
+      ctx.fillStyle = fillStyle1;
+      ctx.fillRect(0, halfH, halfW, h - halfH);
+    },
+
+    onDestroy() {
+      if (canvas && ctx) {
+        ctx.fillStyle = 'red';
+        const halfW = Math.floor(canvas.width / 2);
+        ctx.fillRect(0, 0, halfW, canvas.height);
+      }
+    },
+  };
 }
diff --git a/packages/vfx/src/shadow-objects/TestImageOnCanvas2D.js b/packages/vfx/src/shadow-objects/TestImageOnCanvas2D.js
index ea06743..8f0d3e7 100644
--- a/packages/vfx/src/shadow-objects/TestImageOnCanvas2D.js
+++ b/packages/vfx/src/shadow-objects/TestImageOnCanvas2D.js
@@ -1,26 +1,36 @@
-export function TestImageOnCanvas2D({entity, useContext}) {
+export function TestImageOnCanvas2D({entity, useContext, onDestroy}) {
   const [r, g, b] = [Math.floor(Math.random() * 255), Math.floor(Math.random() * 255), Math.floor(Math.random() * 255)];
   const fillStyle0 = `rgb(${r} ${g} ${b})`;
   const fillStyle1 = `rgb(${255 - r} ${255 - g} ${255 - b})`;
 
   let ctx = null;
 
+  let consoleCount = 0;
+
   useContext('canvasSize')((size) => {
-    console.debug(`[TestImageOnCanvas2D] ${entity.uuid} canvas size changed to`, size);
+    if (consoleCount++ < 3) {
+      console.debug(`[TestImageOnCanvas2D] ${entity.uuid} canvas size changed to`, size);
+    }
   });
 
-  entity.on('onRenderFrame', ({canvas}) => {
-    ctx ??= canvas.getContext('2d');
+  console.log(`[TestImageOnCanvas2D] ${entity.uuid} Ready.`);
+
+  onDestroy(() => {
+    console.log(`[TestImageOnCanvas2D] ${entity.uuid} Thank you for the fish.`);
+  });
 
-    const [w, h] = [canvas.width, canvas.height];
-    const halfH = Math.floor(h / 2);
+  return {
+    onRenderFrame({canvas}) {
+      ctx ??= canvas.getContext('2d');
 
-    ctx.fillStyle = fillStyle0;
-    ctx.fillRect(0, 0, w, halfH);
+      const [w, h] = [canvas.width, canvas.height];
+      const halfH = Math.floor(h / 2);
 
-    ctx.fillStyle = fillStyle1;
-    ctx.fillRect(0, halfH, w, h - halfH);
-  });
+      ctx.fillStyle = fillStyle0;
+      ctx.fillRect(0, 0, w, halfH);
 
-  console.debug(`[TestImageOnCanvas2D] ${entity.uuid} ready`);
+      ctx.fillStyle = fillStyle1;
+      ctx.fillRect(0, halfH, w, h - halfH);
+    },
+  };
 }
diff --git a/packages/vfx/src/shadow-objects/VfxDisplay.js b/packages/vfx/src/shadow-objects/VfxDisplay.js
index 7c94ca4..ca3df95 100644
--- a/packages/vfx/src/shadow-objects/VfxDisplay.js
+++ b/packages/vfx/src/shadow-objects/VfxDisplay.js
@@ -1,4 +1,4 @@
-import {createEffect, createSignal} from '@spearwolf/signalize';
+import {createEffect, createSignal, destroySignal} from '@spearwolf/signalize';
 import {FrameLoop} from '../shared/FrameLoop.js';
 import {OffscreenCanvas, StartFrameLoop, StopFrameLoop} from '../shared/constants.js';
 
@@ -20,7 +20,7 @@ export class VfxDisplay {
     return this.isRunning && this.canvas != null && this.canvas.width > 0 && this.canvas.height > 0;
   }
 
-  constructor({entity, useContext, useProperty, provideContext}) {
+  constructor({entity, useContext, useProperty, provideContext, onDestroy}) {
     this.entity = entity;
 
     // TODO use shared vfx.canvas|multiViewRenderer --------
@@ -41,7 +41,7 @@ export class VfxDisplay {
     const getCanvasHeight = useProperty('canvasHeight');
     const getPixelRatio = useProperty('pixelRatio');
 
-    createEffect(() => {
+    const [, unsubscribe] = createEffect(() => {
       const canvas = getCanvas();
       if (canvas) {
         const w = getCanvasWidth();
@@ -76,6 +76,12 @@ export class VfxDisplay {
         enumerable: true,
       },
     });
+
+    onDestroy(() => {
+      console.log('[VfxDisplay] onDestroy: bye, bye!');
+      unsubscribe();
+      destroySignal(getCanvasSize);
+    });
   }
 
   onViewEvent(type, data) {