From 99715d1accd13d45e134350f0ebae76700a5588b Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Tue, 13 Sep 2022 01:07:05 +0200 Subject: [PATCH 01/70] `.eslintrc.cjs` prepare config for fixing remaining ESLint Warnings and Errors (#170) --- .eslintrc.cjs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 20fff36..1b51eb4 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -7,25 +7,25 @@ module.exports = { plugins: ["svelte3", "@typescript-eslint"], //(default) check *.svelte and *.ts files - // ignorePatterns: ["*.cjs"], + ignorePatterns: ["*.cjs"], // check only *.svelte files - ignorePatterns: ["*.cjs", "*.ts"], + //ignorePatterns: ["*.cjs", "*.ts"], overrides: [ { files: ["*.svelte"], - processor: "svelte3/svelte3", + processor: "svelte3/svelte3" // checking specific rules (set to "off" / "error") // errors only - rules: { + /* rules: { "no-inferrable-types": "error", "no-undef": "error", "no-empty": "error", "no-case-declarations": "error", "no-prototype-builtins": "error" - } + } */ } ], settings: { From b149d73f2f13b244a9e689922288ca175c40dd4b Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Tue, 20 Sep 2022 23:38:20 +0200 Subject: [PATCH 02/70] `.gitignore` Ignore Error tests folder (for now) --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 67cbd7f..c4a67e4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,7 @@ node_modules /generator /src/lib/components-check /src/lib/components-internal-check -generate_svelthree_components.js \ No newline at end of file +generate_svelthree_components.js + +# Error tests +src/routes/tests \ No newline at end of file From 82a60d014e8e30f52f5d546ba25a92169a2edb09 Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Tue, 20 Sep 2022 23:39:59 +0200 Subject: [PATCH 03/70] `postprocess_package.js` Fix setter replacement --- postprocess_package.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postprocess_package.js b/postprocess_package.js index 352fed4..05b9e63 100644 --- a/postprocess_package.js +++ b/postprocess_package.js @@ -164,7 +164,7 @@ const get_process_comments_fn = (file_path) => { for (let [prop_name, comment] of comments_map) { const str_setter = `set ${prop_name}` - const regex_setter = new RegExp("\\b" + str_setter + "\\b") + const regex_setter = new RegExp(str_setter) const test_setter = content.match(regex_setter) const acc_comment = comment.replace( `/**`, @@ -172,7 +172,7 @@ const get_process_comments_fn = (file_path) => { ) if (test_setter) { - new_content = new_content.replace(`set ${prop_name}`, `${acc_comment}\n\tset ${prop_name}`) + new_content = new_content.replace(`set ${prop_name}(_`, `${acc_comment}\n\tset ${prop_name}(_`) } else { const str_getter = `get ${prop_name}` const regex_getter = new RegExp("\\b" + str_getter + "\\b") From c47bdb8d96f6478d99f894b35ebf2b10205b0029 Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Tue, 20 Sep 2022 23:40:27 +0200 Subject: [PATCH 04/70] `postprocess_package.js` Make replace tasks optional --- postprocess_package.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/postprocess_package.js b/postprocess_package.js index 05b9e63..5cb4ecc 100644 --- a/postprocess_package.js +++ b/postprocess_package.js @@ -201,6 +201,8 @@ const get_process_comments_fn = (file_path) => { // --- ENTRY POINT --- +const schedule_code_replacement_tasks = true + /** * - Fix generic `mat` shorthand property type when using accessors: * - Replace `mat` accessors type definitions (accessor getter and setter) -> only `Mesh` and `Points`, @@ -217,10 +219,12 @@ const do_postprocess = async () => { console.log("🤖 SVELTHREE > post-processing package: started...") // schedule code replacement tasks - console.log("🤖 SVELTHREE > post-processing package: scheduling replacement tasks...") - for (let i = 0; i < replace_tasks.length; i++) { - const task = replace_tasks[i] - fns.push(exec_replace_task(task)) + if (schedule_code_replacement_tasks) { + console.log("🤖 SVELTHREE > post-processing package: scheduling replacement tasks...") + for (let i = 0; i < replace_tasks.length; i++) { + const task = replace_tasks[i] + fns.push(exec_replace_task(task)) + } } // schedule accessors-comments optimization in `d.ts` files From 713bdcefd9b8fc86fe3517267bb4246e0868e72a Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Tue, 20 Sep 2022 23:43:08 +0200 Subject: [PATCH 05/70] Delete default `+page.svelte` --- src/routes/+page.svelte | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 src/routes/+page.svelte diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte deleted file mode 100644 index 0a45b69..0000000 --- a/src/routes/+page.svelte +++ /dev/null @@ -1,3 +0,0 @@ -

Welcome to your library project

-

Create your package using @sveltejs/package and preview/showcase your work with SvelteKit

-

Visit kit.svelte.dev to read the documentation

From 3ec20262f2ff2e759e8ecbcf5fa93a6a0e7d6120 Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Wed, 21 Sep 2022 00:31:14 +0200 Subject: [PATCH 06/70] Remove remaining `@author` jsdoc --- src/lib/utils/CameraUtils.ts | 4 ---- src/lib/utils/LightUtils.ts | 4 ---- src/lib/utils/PropUtils.ts | 4 ---- src/lib/utils/Propeller.ts | 4 ---- 4 files changed, 16 deletions(-) diff --git a/src/lib/utils/CameraUtils.ts b/src/lib/utils/CameraUtils.ts index d2ee741..1cc4e82 100644 --- a/src/lib/utils/CameraUtils.ts +++ b/src/lib/utils/CameraUtils.ts @@ -1,7 +1,3 @@ -/** - * @author Vatroslav Vrbanic @see https://github.com/vatro - */ - import type { OrthographicCamera, PerspectiveCamera } from "three" import { CameraValues } from "../constants" diff --git a/src/lib/utils/LightUtils.ts b/src/lib/utils/LightUtils.ts index 87a7750..953d552 100644 --- a/src/lib/utils/LightUtils.ts +++ b/src/lib/utils/LightUtils.ts @@ -1,7 +1,3 @@ -/** - * @author Vatroslav Vrbanic @see https://github.com/vatro - */ - import { has_prop } from "svelte/internal" import type { Light, Scene } from "three" import { Color, Object3D } from "three" diff --git a/src/lib/utils/PropUtils.ts b/src/lib/utils/PropUtils.ts index 9d4a827..87bdbbf 100644 --- a/src/lib/utils/PropUtils.ts +++ b/src/lib/utils/PropUtils.ts @@ -1,7 +1,3 @@ -/** - * @author Vatroslav Vrbanic @see https://github.com/vatro - */ - import type { Light, Material, Object3D, Scene } from "three" import { Color, Euler, Matrix4, Quaternion, Vector3 } from "three" import type { ComplexValueType, LightWithShadow } from "../types/types-extra" diff --git a/src/lib/utils/Propeller.ts b/src/lib/utils/Propeller.ts index 2c73574..7fd0cf7 100644 --- a/src/lib/utils/Propeller.ts +++ b/src/lib/utils/Propeller.ts @@ -1,7 +1,3 @@ -/** - * @author Vatroslav Vrbanic @see https://github.com/vatro - */ - import type { WebGLCubeRenderTarget } from "three" import PropUtils from "./PropUtils" import type { ComplexValueType } from "../types/types-extra" From 6e2f14f84f31a5a302b3274dfe0c453657286d8c Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Wed, 21 Sep 2022 00:38:02 +0200 Subject: [PATCH 07/70] Remove the `number[ ]` type from values (#170) it's actually like a wildcard, making other Array-like types obsolete and it feels wrong, but I'm not 100% sure about this decission, may be reverted again, but in a more centralized manner (changing value types at one place). Remove the `number[ ]` type from values (#170) --- src/lib/components/AmbientLight.svelte | 2 +- src/lib/components/HemisphereLight.svelte | 2 +- src/lib/components/PointLight.svelte | 2 +- src/lib/components/RectAreaLight.svelte | 2 +- src/lib/components/Scene.svelte | 3 +-- src/lib/components/SpotLight.svelte | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/lib/components/AmbientLight.svelte b/src/lib/components/AmbientLight.svelte index 701ff90..b23aeec 100644 --- a/src/lib/components/AmbientLight.svelte +++ b/src/lib/components/AmbientLight.svelte @@ -268,7 +268,7 @@ AmbientLight cannot be used to cast shadows as it doesn't have a direction. Posi sProps.update(props) } - export let color: Color | string | number | [r: number, g: number, b: number] | number[] | Vector3 = undefined + export let color: Color | string | number | [r: number, g: number, b: number] | Vector3 = undefined $: if (light && color) set_color() function set_color(): void { if (verbose && log_rs) console.debug(...c_rs(c_name, "color", color)) diff --git a/src/lib/components/HemisphereLight.svelte b/src/lib/components/HemisphereLight.svelte index e7ab716..70bdbff 100644 --- a/src/lib/components/HemisphereLight.svelte +++ b/src/lib/components/HemisphereLight.svelte @@ -271,7 +271,7 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` sProps.update(props) } - export let color: Color | string | number | [r: number, g: number, b: number] | number[] | Vector3 = undefined + export let color: Color | string | number | [r: number, g: number, b: number] | Vector3 = undefined $: if (light && color) set_color() function set_color(): void { if (verbose && log_rs) console.debug(...c_rs(c_name, "color", color)) diff --git a/src/lib/components/PointLight.svelte b/src/lib/components/PointLight.svelte index 2c50b60..16f175c 100644 --- a/src/lib/components/PointLight.svelte +++ b/src/lib/components/PointLight.svelte @@ -335,7 +335,7 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` PropUtils.setMatrixFromValue(light, matrix) } - export let color: Color | string | number | [r: number, g: number, b: number] | number[] | Vector3 = undefined + export let color: Color | string | number | [r: number, g: number, b: number] | Vector3 = undefined $: if (light && color) set_color() function set_color(): void { if (verbose && log_rs) console.debug(...c_rs(c_name, "color", color)) diff --git a/src/lib/components/RectAreaLight.svelte b/src/lib/components/RectAreaLight.svelte index 2d97e3a..41c6ec4 100644 --- a/src/lib/components/RectAreaLight.svelte +++ b/src/lib/components/RectAreaLight.svelte @@ -356,7 +356,7 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` light.width = width } - export let color: Color | string | number | [r: number, g: number, b: number] | number[] | Vector3 = undefined + export let color: Color | string | number | [r: number, g: number, b: number] | Vector3 = undefined $: if (light && color) set_color() function set_color(): void { if (verbose && log_rs) console.debug(...c_rs(c_name, "color", color)) diff --git a/src/lib/components/Scene.svelte b/src/lib/components/Scene.svelte index 9a9e325..6201bf9 100644 --- a/src/lib/components/Scene.svelte +++ b/src/lib/components/Scene.svelte @@ -450,8 +450,7 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` $: if (receiveShadow !== undefined && scene) scene.receiveShadow = receiveShadow /** Scene `.background`. */ - export let bg: Texture | Color | string | number | [r: number, g: number, b: number] | number[] | Vector3 = - undefined + export let bg: Texture | Color | string | number | [r: number, g: number, b: number] | Vector3 = undefined $: if (bg) set_bg() function set_bg(): void { diff --git a/src/lib/components/SpotLight.svelte b/src/lib/components/SpotLight.svelte index b9e2dff..204673c 100644 --- a/src/lib/components/SpotLight.svelte +++ b/src/lib/components/SpotLight.svelte @@ -414,7 +414,7 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` light.power = power } - export let color: Color | string | number | [r: number, g: number, b: number] | number[] | Vector3 = undefined + export let color: Color | string | number | [r: number, g: number, b: number] | Vector3 = undefined $: if (light && color) set_color() function set_color(): void { if (verbose && log_rs) console.debug(...c_rs(c_name, "color", color)) From bb838ae41882c913859471230e5ad147624ab7d0 Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Wed, 21 Sep 2022 00:27:57 +0200 Subject: [PATCH 08/70] `.prettierrc` Different (wider) formating of `src/lib/types/*.ts` --- .prettierrc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.prettierrc b/.prettierrc index b61947c..31cb27e 100644 --- a/.prettierrc +++ b/.prettierrc @@ -8,5 +8,18 @@ "endOfLine": "crlf", "pluginSearchDirs": ["."], "bracketSameLine": false, - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] + "overrides": [ + { + "files": "*.svelte", + "options": { + "parser": "svelte" + } + }, + { + "files": "src/lib/types/*.ts", + "options": { + "printWidth": 160 + } + } + ] } From 4bc31ccd49ea8616a432c1ea5dcd32f1202495ac Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Wed, 21 Sep 2022 01:31:46 +0200 Subject: [PATCH 09/70] Major types refactor of the `SvelthreeProps` / `Propeller` / `PropUtils` pipeline + `*Properties` to `Prop*` / `Props*` types refactor (#170) - incl. significant refactor of `Propeller` and `PropUtils`: also fixes. - incl. refactor of `types\types-extra.ts`, cleanup + changed / new types e.g.: - simplified `OnlyWritableNonFunctionPropsOverwritten` and `OnlyWritableNonFunctionProps` - new internal utility Types `get_props_overwritten` and `get_props` - new public generic utility type `prop` (in order get types of props via prop<"foo", ...>) - incl. refactor of `types\types-comp-props.ts`, refactored / new / renamed types: - `*Properties` to `Prop*` / `Props*` + `Prop*` types are now exported via `index.ts` - new generic `PropMat` type utility for retrieving `Material` props Object Literal type (internal and public usage) - `SvelthreePropsObjectLiteral` (`PropsSvelthree`) etc. --- src/lib/index.ts | 67 ++-- src/lib/types/types-comp-props.ts | 301 +++++++++------ src/lib/types/types-extra.ts | 224 +++++++---- src/lib/utils/PropUtils.ts | 400 +++++++++++--------- src/lib/utils/Propeller.ts | 44 ++- src/lib/utils/SvelthreeProps.ts | 50 ++- src/lib/utils/props/PropArray3X.ts | 35 +- src/lib/utils/props/PropColorX.ts | 3 +- src/lib/utils/props/PropEulerArrayX.ts | 3 +- src/lib/utils/props/PropEulerX.ts | 3 +- src/lib/utils/props/PropMatrix4ArrayX.ts | 3 +- src/lib/utils/props/PropMatrix4X.ts | 3 +- src/lib/utils/props/PropQuaternionArrayX.ts | 3 +- src/lib/utils/props/PropQuaternionX.ts | 3 +- src/lib/utils/props/PropVector3X.ts | 3 +- 15 files changed, 711 insertions(+), 434 deletions(-) diff --git a/src/lib/index.ts b/src/lib/index.ts index f727072..d4e3823 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -21,6 +21,7 @@ export { default as CubeCamera } from "./components/CubeCamera.svelte" // export all THREE modules export * from "three" +// TODO export as `THREE_*`? /** export all THREE modules 'Foo' overridden by Svelte components as '_Foo' * so users can for example import _Mesh from 'svelthree' and create a native THREE Mesh instance */ @@ -42,33 +43,45 @@ export { Scene as _Scene } from "three" export { OrbitControls as _OrbitControls } from "three/examples/jsm/controls/OrbitControls" export { WebGLRenderer as _WebGLRenderer } from "three" -/* -//types -export type { - Mat -} from "./types/types-extra" +// generic type utilities +export type { prop } from "./types/types-extra" +export type { PropMat } from "./types/types-comp-props" -//types +// `props` Object Literal types export type { - Object3DProperties, - GroupProperties, - LoadedGLTFProperties, - SceneProperties, - WebGLRendererProperties, - MeshProperties, - PointsProperties, - CubeCameraProperties, - WebGLCubeRenderTargetProperties, - OrthographicCameraProperties, - PerspectiveCameraProperties, - HemisphereLightProperties, - AmbientLightProperties, - DirectionalLightProperties, - PointLightProperties, - RectAreaLightProperties, - SpotLightProperties, - OrbitControlsProperties, - ButtonProperties, - LinkProperties + PropsObject3D, + PropsGroup, + PropsLoadedGLTF, + PropsScene, + PropsWebGLRenderer, + PropsMesh, + PropsPoints, + PropsCubeCamera, + PropsWebGLCubeRenderTarget, + PropsOrthographicCamera, + PropsPerspectiveCamera, + PropsHemisphereLight, + PropsAmbientLight, + PropsDirectionalLight, + PropsPointLight, + PropsRectAreaLight, + PropsSpotLight, + PropsOrbitControls } from "./types/types-comp-props" -*/ + +// `foo` Object Literal types +export type { PropLink, PropButton, PropWebGLRenderTargetOptions } from "./types/types-comp-props" + +// TODO params + +// TODO config + +// misc +export type { TargetableSvelthreeComponent } from "./types/types-extra" + +// GLTF related +export type { + SvelthreeGLTFTreeMap, + ISvelthreeGLTFTreeMapMember, + GLTFSupportedSvelthreeComponents +} from "./types/types-extra" diff --git a/src/lib/types/types-comp-props.ts b/src/lib/types/types-comp-props.ts index 3c54702..74caf5f 100644 --- a/src/lib/types/types-comp-props.ts +++ b/src/lib/types/types-comp-props.ts @@ -1,206 +1,283 @@ import type { - OnlyWritableNonFunctionProps, - OnlyWritableNonFunctionPropsOverwritten, - PropBlackList + MeshAssignableMaterial, + PointsAssignableMaterial, + get_props_overwritten, + get_props, + lookAt_value, + color_value, + background_value, + pos_value, + scale_value, + rot_value, + quat_value, + matrix_value, + up_value } from "./types-extra" -import type { Object3D, Color, Quaternion, Vector3, Euler, Matrix4 } from "three" -import type { WebGLRenderer } from "three" -import type { Scene, Texture } from "three" -import type { Mesh, Points } from "three" -import type { AmbientLight, DirectionalLight, HemisphereLight, PointLight, RectAreaLight, SpotLight } from "three" -import type { CubeCamera, WebGLCubeRenderTarget } from "three" -import type { OrthographicCamera, PerspectiveCamera } from "three" +import type { + Object3D, + Mesh, + Points, + WebGLRenderer, + Scene, + AmbientLight, + DirectionalLight, + HemisphereLight, + PointLight, + RectAreaLight, + SpotLight, + OrthographicCamera, + PerspectiveCamera, + CubeCamera, + WebGLCubeRenderTarget, + WebGLRenderTargetOptions +} from "three" import type { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js" -// TODO GENERAL check / polish / fix usage of `OnlyWritableNonFunctionPropsPlus` vs. `OnlyWritableNonFunctionPropsOverwritten` // TODO At some point we sould type the `userData` interface! -> see https://github.com/vatro/svelthree/issues/95 -// --- EMPTY --- +type MeshLikeOnlyKeys = "customDepthMaterial" | "customDistanceMaterial" + +// --- Object3D --- -//export type Object3DProperties = OnlyWritableNonFunctionPropsPlus< -export type Object3DProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, +type WritableObject3DProperties = get_props_overwritten< + Object3D, { - position: Vector3 | Parameters - scale: Vector3 | Parameters - rotation: - | Euler - | Parameters - | Quaternion - | Parameters - | Vector3 - | Parameters - quaternion: Quaternion | Parameters - matrix: Matrix4 | Parameters - up: Vector3 | Parameters + position: pos_value + scale: scale_value + rotation: rot_value + quaternion: quat_value + matrix: matrix_value + up: up_value } > +export type PropsObject3D = { [P in keyof WritableObject3DProperties]: WritableObject3DProperties[P] } + // intellisense test -//const obj3d_props: Object3DProperties = {} +//const obj3d_props: PropsObject3D = {} -export type GroupProperties = Object3DProperties -export type LoadedGLTFProperties = Object3DProperties +export type PropsGroup = PropsObject3D +export type PropsLoadedGLTF = PropsObject3D // -- SCENE -- -export type SceneProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, +type WritableSceneProperties = get_props_overwritten< + Scene, { - background?: Texture | Color | string | number | [r: number, g: number, b: number] | number[] | Vector3 - } & { [P in keyof Object3DProperties]: Object3DProperties[P] } + background?: background_value + } & { [P in keyof PropsObject3D]: PropsObject3D[P] } > +export type PropsScene = { [P in keyof WritableSceneProperties]: WritableSceneProperties[P] } // intellisense test -//const scene_props: SceneProperties = {} +//const scene_props: PropsScene = {} // TODO check / polish -export type WebGLRendererProperties = OnlyWritableNonFunctionProps> +type WritableWebGLRendererProperties = get_props +export type PropsWebGLRenderer = { [P in keyof WritableWebGLRendererProperties]: WritableWebGLRendererProperties[P] } + +// intellisense test +//const weggl_renderer_props: PropsWebGLRenderer = {} // --- MESH --- -export type MeshProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, - { [P in keyof Object3DProperties]: Object3DProperties[P] } -> +type WritableMeshProperties = get_props_overwritten +export type PropsMesh = { [P in keyof WritableMeshProperties]: WritableMeshProperties[P] } // intellisense test -//const mesh_props: MeshProperties = {} +//const mesh_props: PropsMesh = {} // --- POINTS --- -export type PointsProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, - { [P in keyof Object3DProperties]: Object3DProperties[P] } -> +type WritablePointsProperties = get_props_overwritten +export type PropsPoints = { [P in keyof WritablePointsProperties]: WritablePointsProperties[P] } // intellisense test -//const points_props: PointsProperties = {} +//const points_props: PropsPoints = {} // --- CAMERAS --- -export type CubeCameraProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, - { [P in keyof Object3DProperties]: Object3DProperties[P] } -> +type WritableCubeCameraProperties = get_props_overwritten +export type PropsCubeCamera = { [P in keyof WritableCubeCameraProperties]: WritableCubeCameraProperties[P] } // intellisense test -//const cubecam_props: CubeCameraProperties = {} +//const cubecam_props: PropsCubeCamera = {} -export type WebGLCubeRenderTargetProperties = OnlyWritableNonFunctionProps> +type WritableWebGLCubeRenderTargetProperties = get_props +export type PropsWebGLCubeRenderTarget = { + [P in keyof WritableWebGLCubeRenderTargetProperties]: WritableWebGLCubeRenderTargetProperties[P] +} // intellisense test -//const cubecam_rendertarget_props: WebGLCubeRenderTargetProperties = {} +//const cubecam_rendertarget_props: PropsWebGLCubeRenderTarget = {} -export type OrthographicCameraProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, - { [P in keyof Object3DProperties]: Object3DProperties[P] } -> +type WritableOrthographicCameraProperties = get_props_overwritten +export type PropsOrthographicCamera = { + [P in keyof WritableOrthographicCameraProperties]: WritableOrthographicCameraProperties[P] +} // intellisense test -//const orthocam_props: OrthographicCameraProperties = {} +//const orthocam_props: PropsOrthographicCamera = {} -export type PerspectiveCameraProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, +type WritablePerspectiveCameraProperties = get_props_overwritten< + PerspectiveCamera, { - lookAt: Vector3 | Parameters | Object3D - } & { [P in keyof Object3DProperties]: Object3DProperties[P] } + lookAt: lookAt_value + } & { [P in keyof PropsObject3D]: PropsObject3D[P] } > +export type PropsPerspectiveCamera = { + [P in keyof WritablePerspectiveCameraProperties]: WritablePerspectiveCameraProperties[P] +} // intellisense test -//const perspcam_props: PerspectiveCameraProperties = {} +//const perspcam_props: PropsPerspectiveCamera = {} // --- LIGHTS --- -export type HemisphereLightProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, +type ObsoleteLightHasNoShadowKeys = MeshLikeOnlyKeys | "castShadow" | "receiveShadow" | "shadow" +type ObsoleteLightHasShadowKeys = MeshLikeOnlyKeys | "receiveShadow" +// EXCLUDED THREE :Lights with `target` property use the target for rotation calculation! +type ObsoleteLightHasShadowAndTargetKeys = ObsoleteLightHasShadowKeys | "rotation" | "quaternion" + +type WritableHemisphereLightProperties = get_props_overwritten< + HemisphereLight, { - color: Color | string | number | [r: number, g: number, b: number] | Vector3 - groundColor: Color | string | number | [r: number, g: number, b: number] | Vector3 - } & { [P in keyof Object3DProperties]: Object3DProperties[P] } + color: color_value + groundColor: color_value + } & { [P in keyof PropsObject3D]: PropsObject3D[P] } > +type PropsHemisphereLightClean = Omit +export type PropsHemisphereLight = { [P in keyof PropsHemisphereLightClean]: PropsHemisphereLightClean[P] } // intellisense test -//const hemisphere_light_props: HemisphereLightProperties = {} +//const hemisphere_light_props: PropsHemisphereLight = {} -export type AmbientLightProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, +type WritableAmbientLightProperties = get_props_overwritten< + AmbientLight, { - color: Color | string | number | [r: number, g: number, b: number] | Vector3 - } & { [P in keyof Object3DProperties]: Object3DProperties[P] } + color: color_value + } & { [P in keyof PropsObject3D]: PropsObject3D[P] } > +type PropsAmbientLightClean = Omit +export type PropsAmbientLight = { [P in keyof PropsAmbientLightClean]: PropsAmbientLightClean[P] } // intellisense test -//const ambient_light_props: AmbientLightProperties = {} - -// EXCLUDED THREE :Lights with `target` property use the target for rotation calculation! -type LightWithTargetObject3DProperties = Omit +//const ambient_light_props: PropsAmbientLight = {} // TODO Nail down manipulating matrix. -export type DirectionalLightProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, +type WritableDirectionalLightProperties = get_props_overwritten< + DirectionalLight, { - color: Color | string | number | [r: number, g: number, b: number] | Vector3 - // CUSTOM actually no `lookAt` on DirectionalLight, we're using custom solution! - lookAt: Vector3 | Parameters | Object3D - } & { [P in keyof LightWithTargetObject3DProperties]: LightWithTargetObject3DProperties[P] } + color: color_value + /** CUSTOM there's actually no `lookAt` property on THREE.DirectionalLight, `svelthree` is using a custom solution! */ + lookAt: lookAt_value + } & { [P in keyof PropsObject3D]: PropsObject3D[P] } > +type PropsDirectionalLightClean = Omit +export type PropsDirectionalLight = { [P in keyof PropsDirectionalLightClean]: PropsDirectionalLightClean[P] } // intellisense test -//const directional_light_props: DirectionalLightProperties = {} +//const directional_light_props: PropsDirectionalLight = {} -export type PointLightProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, - { [P in keyof Object3DProperties]: Object3DProperties[P] } +type WritablePointLightProperties = get_props_overwritten< + PointLight, + { + color: color_value + } & { [P in keyof PropsObject3D]: PropsObject3D[P] } > +type PropsPointLightClean = Omit +export type PropsPointLight = { [P in keyof PropsPointLightClean]: PropsPointLightClean[P] } // intellisense test -//const point_light_props: PointLightProperties = {} +//const point_light_props: PropsPointLight = {} // TODO Nail down manipulating matrix. // TODO Nail down lookAt usage! -export type RectAreaLightProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, +type WritableRectAreaLightProperties = get_props_overwritten< + RectAreaLight, { - color: Color | string | number | [r: number, g: number, b: number] | Vector3 - // CUSTOM actually no `lookAt` on RectAreaLight, we're using custom solution! - lookAt: Vector3 | Parameters | Object3D - } & { [P in keyof LightWithTargetObject3DProperties]: LightWithTargetObject3DProperties[P] } + color: color_value + /** CUSTOM there's actually no `lookAt` property on THREE.RectAreaLight, `svelthree` isexport let props using a custom solution! */ + lookAt: lookAt_value + } & { [P in keyof PropsObject3D]: PropsObject3D[P] } > +/** + * Important Notes: + * - There is no shadow support. + * - Only `MeshStandardMaterial` and `MeshPhysicalMaterial` are supported. + */ +type PropsRectAreaLightClean = Omit +export type PropsRectAreaLight = { [P in keyof PropsRectAreaLightClean]: PropsRectAreaLightClean[P] } // intellisense test -//const rectarea_light_props: RectAreaLightProperties = {} +//const rectarea_light_props: PropsRectAreaLight = {} // TODO Nail down manipulating matrix. -export type SpotLightProperties = OnlyWritableNonFunctionPropsOverwritten< - Omit, +type WritableSpotLightProperties = get_props_overwritten< + SpotLight, { - color: Color | string | number | [r: number, g: number, b: number] | Vector3 - // CUSTOM actually no `lookAt` on SpotLight, we're using custom solution! - lookAt: Vector3 | Parameters | Object3D - } & { [P in keyof LightWithTargetObject3DProperties]: LightWithTargetObject3DProperties[P] } + color: color_value + /** CUSTOM there's actually no `lookAt` property on THREE.SpotLight, `svelthree` is using a custom solution! */ + lookAt: lookAt_value + } & { [P in keyof PropsObject3D]: PropsObject3D[P] } > +type PropsSpotLightClean = Omit +export type PropsSpotLight = { [P in keyof PropsSpotLightClean]: PropsSpotLightClean[P] } // intellisense test -//const spot_light_props: SpotLightProperties = {} +//const spot_light_props: PropsSpotLight = {} // TODO extensively test `OrbitControls` `props` atrribute usage. -export type OrbitControlsProperties = OnlyWritableNonFunctionProps> +type WritableOrbitControlsProperties = get_props +type OrbitControlsClean = Omit +export type PropsOrbitControls = { [P in keyof OrbitControlsClean]: OrbitControlsClean[P] } // intellisense test -//const orbitcontrols_props: OrbitControlsProperties = {} +//const orbitcontrols_props: PropsOrbitControls = {} -export type ButtonProperties = { - [P in keyof OnlyWritableNonFunctionProps]: OnlyWritableNonFunctionProps[P] -} +type WritableMaterialProps = T extends void ? never : get_props_overwritten +export type PropMat = { [P in keyof WritableMaterialProps]: WritableMaterialProps[P] } + +type WritableButtonProperties = get_props +export type PropButton = { [P in keyof WritableButtonProperties]: WritableButtonProperties[P] } // intellisense test -//const button_prop: ButtonProperties = {} +//const button_prop: PropButton = {} -export type LinkProperties = { - [P in keyof OnlyWritableNonFunctionProps]: OnlyWritableNonFunctionProps[P] -} +type WritableLinkProperties = get_props +export type PropLink = { [P in keyof WritableLinkProperties]: WritableLinkProperties[P] } + +// intellisense test +//const link_prop: PropLink = {} + +type WritableWebGLRenderTargetOptions = get_props +export type PropWebGLRenderTargetOptions = { [P in keyof WritableWebGLRenderTargetOptions]: WritableWebGLRenderTargetOptions[P] } // intellisense test -//const link_prop: ButtonProperties = {} +//const webglrendertarget_opt: PropWebGLRenderTargetOptions = {} + +type PropsSvelthree = + | PropButton + | PropLink + | PropWebGLRenderTargetOptions + | PropsAmbientLight + | PropsCubeCamera + | PropsDirectionalLight + | PropsGroup + | PropsHemisphereLight + | PropsLoadedGLTF + | PropsMesh + | PropsObject3D + | PropsOrbitControls + | PropsOrthographicCamera + | PropsPerspectiveCamera + | PropsPointLight + | PropsPoints + | PropsRectAreaLight + | PropsScene + | PropsSpotLight + | PropsWebGLCubeRenderTarget + | PropsWebGLRenderer + +export type SvelthreePropsObjectLiteral = PropsSvelthree | PropMat | PropMat diff --git a/src/lib/types/types-extra.ts b/src/lib/types/types-extra.ts index b3f417c..1decd62 100644 --- a/src/lib/types/types-extra.ts +++ b/src/lib/types/types-extra.ts @@ -1,68 +1,53 @@ -export type Constructor = { - new (...args: any[]): T - prototype: T -} - -export type Array3 = [number, number, number] -export type Array4 = [number, number, number, string] - -// see https://stackoverflow.com/questions/49579094/typescript-conditional-types-filter-out-readonly-properties-pick-only-requir -export type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 - ? A - : B - -export type WritableKeys = { - [P in keyof T]-?: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, P> -}[keyof T] - -export type ReadonlyKeys = { - [P in keyof T]-?: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, never, P> -}[keyof T] - -/** this returns only NON function keys */ -// eslint-disable-next-line @typescript-eslint/ban-types -export type OnlyNonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] - -/** this returns only function keys */ -// eslint-disable-next-line @typescript-eslint/ban-types -export type OnlyFunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] - -// this returns as expected only function props -export type OnlyFunctionProps = Omit> - -// this returns as expected only NON function props -export type OnlyNonFunctionProps = Omit> - -export type Overwrite = Pick, Exclude, keyof U>> & U -export type Overwrite2 = Pick, Exclude, keyof U>> & U - -export type ExposedProps> = Pick, E> - -export type OnlyExposedPropsOverwritten, V> = Partial< - Overwrite, V> +type OnlyWritableNonFunctionPropsOverwritten = Partial< + Omit< + Pick< + T, + { + [P in keyof T]-?: (() => U extends { [Q in P]: T[P] } ? 1 : 2) extends () => U extends { + -readonly [Q in P]: T[P] + } + ? 1 + : 2 + ? // eslint-disable-next-line @typescript-eslint/ban-types + T[P] extends Function + ? never + : P + : never + }[keyof T] + >, + PropBlackList | keyof V + > & + V & { readonly $T?: T } > -export type OnlyExposedProps> = Partial, E>> -export type OnlyNonFunctionPropsOverwritten = Partial, U>> +export type get_props_overwritten = OnlyWritableNonFunctionPropsOverwritten + +type OnlyWritableNonFunctionProps = Partial< + Omit< + Pick< + T, + { + [P in keyof T]-?: (() => U extends { [Q in P]: T[P] } ? 1 : 2) extends () => U extends { + -readonly [Q in P]: T[P] + } + ? 1 + : 2 + ? // eslint-disable-next-line @typescript-eslint/ban-types + T[P] extends Function + ? never + : P + : never + }[keyof T] + >, + PropBlackList + > & { readonly $T?: T } +> -export type OnlyWritableNonFunctionKeys = WritableKeys> -export type OnlyWritableNonFunctionProps = Partial>> -export type OnlyWritableNonFunctionPropsPlus = Partial> & U> -export type OnlyWritableNonFunctionPropsOverwritten = Partial, U>> +export type get_props = OnlyWritableNonFunctionProps export type RemoveFirst = T extends [unknown, ...infer R] ? R : T export type RemoveLast = T extends [...infer H, unknown] ? H : T -// Get props of a generic `Material` - -type AnyMaterialProps = OnlyWritableNonFunctionPropsOverwritten< - Omit, - { color: THREE.Color | string | number | [r: number, g: number, b: number] | number[] | THREE.Vector3 } -> - -export type WritableMaterialProperties = { [P in keyof AnyMaterialProps]: AnyMaterialProps[P] } -export type Mat = WritableMaterialProperties - export type MeshAssignableMaterial = THREE.Material | THREE.Material[] export type PointsAssignableMaterial = THREE.Material | THREE.Material[] | THREE.PointsMaterial @@ -118,6 +103,7 @@ export interface SvelthreeAnimationFunction { } export type LightWithShadow = THREE.DirectionalLight | THREE.SpotLight | THREE.PointLight +export type LightWithTarget = THREE.DirectionalLight | THREE.SpotLight export type LightShadowProps = OnlyWritableNonFunctionProps> export type LightShadowCamProps = OnlyWritableNonFunctionProps> @@ -164,6 +150,8 @@ import type { default as Scene } from "../components/Scene.svelte" import type { default as SpotLight } from "../components/SpotLight.svelte" import type { default as WebGLRenderer } from "../components/WebGLRenderer.svelte" +import type { PropMat } from "./types-comp-props" + export type AnySvelthreeComponent = | AmbientLight | Canvas @@ -196,7 +184,7 @@ export type SvelthreeComponentShadowDOMChild = | LoadedGLTF | Mesh | Object3D - //| OrbitControls + | OrbitControls | OrthographicCamera | PerspectiveCamera | PointLight @@ -235,17 +223,17 @@ type AllMeshMaterials = THREE.MeshToonMaterial & export type AnyMeshMaterialProps = OnlyWritableNonFunctionProps> -type AllLights = THREE.SpotLight & - THREE.PointLight & - THREE.AmbientLight & - THREE.RectAreaLight & - THREE.HemisphereLight & - THREE.DirectionalLight +type AllLights = THREE.SpotLight & THREE.PointLight & THREE.AmbientLight & THREE.RectAreaLight & THREE.HemisphereLight & THREE.DirectionalLight export type AnyLightProps = OnlyWritableNonFunctionProps> -export type RaycastableSvelthreeComponents = Mesh | Group | Object3D -export type GLTFSupportedSvelthreeComponents = Mesh | Group | Object3D | Scene +export type RaycastableSvelthreeComponents = Mesh | Group | Object3D +export type GLTFSupportedSvelthreeComponents = Mesh | Group | Object3D | Scene + +/* +export type RaycastableSvelthreeComponents = Mesh | Group | Object3D +export type GLTFSupportedSvelthreeComponents = Mesh | Group | Object3D | Scene +*/ export interface ISvelthreeGLTFTreeMapMember { obj: THREE.Object3D @@ -306,3 +294,105 @@ export type StoreBody = { export type WebGLRendererMode = "auto" | "always" export type SvelthreeShadowDOMElement = HTMLDivElement | HTMLButtonElement | HTMLAnchorElement + +import type { PropsWebGLCubeRenderTarget, PropsOrbitControls } from "./types-comp-props" +export type SvelthreePropsOwner = + | THREE.Object3D + | THREE.Material + | THREE.Material[] + | THREE.WebGLRenderer + | THREE.LightShadow + | PropsOrbitControls + | PropsWebGLCubeRenderTarget + +// shorthand attribute values / also s + +/** (_for internal usage_) Types of **shorthand properties**. */ +interface SHTypes { + aria: Partial + background: THREE.Texture | THREE.Color | string | number | [r: number, g: number, b: number] | THREE.Vector3 + cam: PerspectiveCamera | OrthographicCamera | THREE.PerspectiveCamera | THREE.OrthographicCamera // OrbitControls + camera: THREE.PerspectiveCamera | THREE.OrthographicCamera | THREE.CubeCamera + color: THREE.Color | string | number | [r: number, g: number, b: number] | THREE.Vector3 + geometry: THREE.BufferGeometry + lookAt: THREE.Vector3 | Parameters | Targetable + material: THREE.Material | THREE.Material[] + matrix: THREE.Matrix4 | Parameters + pos: THREE.Vector3 | Parameters + quat: THREE.Quaternion | Parameters + rot: + | THREE.Euler + | Parameters + | THREE.Quaternion + | Parameters + | THREE.Vector3 + | Parameters + scale: THREE.Vector3 | Parameters | number +} + +/** (_for internal usage_) generally overriden property-types (_**not** used as **shorthand properties**_). */ +interface GTypes { + up: THREE.Vector3 | Parameters +} + +// for internal usage see SvelthreeProps -> ... -> PropUtils pipeline +export type aria_value = SHTypes["aria"] +export type background_value = SHTypes["background"] +export type color_value = SHTypes["color"] +export type geometry_value = SHTypes["geometry"] +export type lookAt_value = SHTypes["lookAt"] +export type material_value = SHTypes["material"] +export type matrix_value = SHTypes["matrix"] +export type pos_value = SHTypes["pos"] +export type quat_value = SHTypes["quat"] +export type rot_value = SHTypes["rot"] +export type scale_value = SHTypes["scale"] + +// general (not used as shorthand prop) +export type up_value = GTypes["up"] + +/** for internal usage see SvelthreeProps -> ... -> PropUtils pipeline */ +export type any_propeller_value = + | background_value + | color_value + | lookAt_value + | matrix_value + | pos_value + | rot_value + | scale_value + | up_value + | [number, number, number] + +/** for internal usage see SvelthreeProps -> ... -> PropUtils pipeline */ +export type any_proputils_value = any_propeller_value + +/** (_`svelthree` internal generic interface_) + * + * Defines types of all shorthand properties (keys) across all components. + * Type of `props` requires type parameter `S`. + */ +interface SvelthreeShorthandProperties { + // get types from internal interface (if S is NOT provided) or from components (if S is provided) + aria: S extends void ? SHTypes["aria"] : S extends AnySvelthreeComponent ? (S extends { aria: unknown } ? S["aria"] : undefined) : never + cam: S extends void ? SHTypes["cam"] : S extends AnySvelthreeComponent ? (S extends { cam: unknown } ? S["cam"] : undefined) : never // OrbitControls only + camera: S extends void ? SHTypes["camera"] : S extends AnySvelthreeComponent ? (S extends { camera: unknown } ? S["camera"] : undefined) : never + color: S extends void ? SHTypes["color"] : S extends AnySvelthreeComponent ? (S extends { color: unknown } ? S["color"] : undefined) : never + geometry: S extends void ? SHTypes["geometry"] : S extends AnySvelthreeComponent ? (S extends { geometry: unknown } ? S["geometry"] : undefined) : never + lookAt: S extends void ? SHTypes["lookAt"] : S extends AnySvelthreeComponent ? (S extends { lookAt: unknown } ? S["lookAt"] : undefined) : never + material: S extends void ? SHTypes["material"] : S extends AnySvelthreeComponent ? (S extends { material: unknown } ? S["material"] : undefined) : never + matrix: S extends void ? SHTypes["matrix"] : S extends AnySvelthreeComponent ? (S extends { matrix: unknown } ? S["matrix"] : undefined) : never + pos: S extends void ? SHTypes["pos"] : S extends AnySvelthreeComponent ? (S extends { pos: unknown } ? S["pos"] : undefined) : never + quat: S extends void ? SHTypes["quat"] : S extends AnySvelthreeComponent ? (S extends { quat: unknown } ? S["quat"] : undefined) : never + rot: S extends void ? SHTypes["rot"] : S extends AnySvelthreeComponent ? (S extends { rot: unknown } ? S["rot"] : undefined) : never + scale: S extends void ? SHTypes["scale"] : S extends AnySvelthreeComponent ? (S extends { scale: unknown } ? S["scale"] : undefined) : never + + // get types from components only (S needs to be provided) + config: S extends AnySvelthreeComponent ? (S extends { config: unknown } ? S["config"] : undefined) : never + params: S extends AnySvelthreeComponent ? (S extends { params: unknown } ? S["params"] : undefined) : never + props: S extends AnySvelthreeComponent ? (S extends { props: unknown } ? S["props"] : undefined) : never + + // mat (special) + mat: S extends MeshAssignableMaterial | PointsAssignableMaterial ? PropMat : never +} + +export type prop, S = void> = SvelthreeShorthandProperties[K] diff --git a/src/lib/utils/PropUtils.ts b/src/lib/utils/PropUtils.ts index 87bdbbf..f11a525 100644 --- a/src/lib/utils/PropUtils.ts +++ b/src/lib/utils/PropUtils.ts @@ -1,6 +1,17 @@ import type { Light, Material, Object3D, Scene } from "three" import { Color, Euler, Matrix4, Quaternion, Vector3 } from "three" -import type { ComplexValueType, LightWithShadow } from "../types/types-extra" +import type { ComplexValueType, LightWithShadow, LightWithTarget } from "../types/types-extra" +import type { + matrix_value, + pos_value, + rot_value, + scale_value, + lookAt_value, + quat_value, + color_value, + //background_value, + any_proputils_value +} from "../types/types-extra" import type { Targetable, TargetableSvelthreeComponent } from "../types/types-extra" import { verbose_mode, log_prop_utils } from "../utils/SvelthreeLogger" @@ -11,7 +22,7 @@ import { verbose_mode, log_prop_utils } from "../utils/SvelthreeLogger" * - `SvelthreeProps` (`sProps`) via `Propeller` */ export default class PropUtils { - public static getShortHandAttrWarnings(prefix: string): { [key: string]: any } { + public static getShortHandAttrWarnings(prefix: string): { [key: string]: string } { const warnings = { rot: `${prefix} 'rot' attribute ignored! : overridden by either 'matrix' or 'quat' attribute!`, pos: `${prefix} 'pos' attribute ignored! : overridden by 'matrix' attribute!`, @@ -27,87 +38,93 @@ export default class PropUtils { console.warn(message) } - public static isArray3Nums(p: any): boolean { - return Array.isArray(p) && p.length === 3 && p.every((el: any) => !isNaN(el)) + public static isArray3Nums(p: number[]): boolean { + return Array.isArray(p) && PropUtils.is3Nums(p) } /** Check if an Array contains exactly 3 numbers. */ - public static is3Nums(p: any): boolean { - return p.length === 3 && p.every((el: any) => !isNaN(el)) + public static is3Nums(p: number[]): boolean { + return p.length === 3 && p.every((el: number) => !isNaN(el)) } - public static isMatrix4ParamsArray(p: any): boolean { - return Array.isArray(p) && p.length === 16 && p.every((el: any) => !isNaN(el)) + public static isMatrix4ParamsArray(p: matrix_value): boolean { + return Array.isArray(p) && p.length === 16 && p.every((el: number) => !isNaN(el)) } /** Check if an Array contains exactly 16 numbers. */ - public static isMatrix4Params(p: any): boolean { - return p.length === 16 && p.every((el: any) => !isNaN(el)) + public static isMatrix4Params(p: number[]): boolean { + return p.length === 16 && p.every((el: number) => !isNaN(el)) } - public static isEulerParamsArray(p: any): boolean { + public static isEulerParamsArray(p: (number | string)[]): boolean { return ( Array.isArray(p) && p.length === 4 && - !isNaN(p[0]) && - !isNaN(p[1]) && - !isNaN(p[2]) && + !isNaN(p[0] as number) && + !isNaN(p[1] as number) && + !isNaN(p[2] as number) && typeof p[3] === "string" ) } /** Check if an Array contains exactly three numbers and one string. */ - public static isEulerParams(p: any): boolean { - return p.length === 4 && !isNaN(p[0]) && !isNaN(p[1]) && !isNaN(p[2]) && typeof p[3] === "string" + public static isEulerParams(p: (number | string)[]): boolean { + return ( + p.length === 4 && + !isNaN(p[0] as number) && + !isNaN(p[1] as number) && + !isNaN(p[2] as number) && + typeof p[3] === "string" + ) } - public static isQuaternionParamsArray(p: any): boolean { - return Array.isArray(p) && p.length === 4 && p.every((el: any) => !isNaN(el)) + public static isQuaternionParamsArray(p: number[]): boolean { + return Array.isArray(p) && p.length === 4 && p.every((el: number) => !isNaN(el)) } /** Check if an Array contains exactly 4 numbers. */ - public static isQuaternionParams(p: any): boolean { - return p.length === 4 && p.every((el: any) => !isNaN(el)) + public static isQuaternionParams(p: number[]): boolean { + return p.length === 4 && p.every((el: number) => !isNaN(el)) } - public static checkIfComplexValueType(val: any): ComplexValueType | undefined { + public static checkIfComplexValueType(val: any_proputils_value): ComplexValueType | undefined { if (Array.isArray(val)) { - if (PropUtils.is3Nums(val)) return "Array3Nums" - if (PropUtils.isEulerParams(val)) return "EulerParamsArray" - if (PropUtils.isQuaternionParams(val)) return "QuaternionParamsArray" - if (PropUtils.isMatrix4Params(val)) return "Matrix4ParamsArray" + if (PropUtils.is3Nums(val as number[])) return "Array3Nums" + if (PropUtils.isEulerParams(val as (number | string)[])) return "EulerParamsArray" + if (PropUtils.isQuaternionParams(val as number[])) return "QuaternionParamsArray" + if (PropUtils.isMatrix4Params(val as number[])) return "Matrix4ParamsArray" } else if (val) { - if (val.isVector3) return "Vector3" - if (val.isColor) return "Color" - if (val.isEuler) return "Euler" - if (val.isQuaternion) return "Quaternion" - if (val.isMatrix4) return "Matrix4" + if ((val as Vector3).isVector3) return "Vector3" + if ((val as Color).isColor) return "Color" + if ((val as Euler).isEuler) return "Euler" + if ((val as Quaternion).isQuaternion) return "Quaternion" + if ((val as Matrix4)["isMatrix4"]) return "Matrix4" } return undefined } - public static setRotationFromValue(obj: Object3D, val: any, complex?: ComplexValueType): void { + public static setRotationFromValue(obj: Object3D, val: rot_value, complex?: ComplexValueType): void { switch (complex) { case undefined: if (Array.isArray(val)) { - PropUtils.is3Nums(val) + PropUtils.is3Nums(val as number[]) ? PropUtils.setRotArray3(obj, val as Parameters) : PropUtils.isEulerParams(val) ? PropUtils.setRotEulerArray(obj, val as Parameters) - : PropUtils.isQuaternionParams(val) + : PropUtils.isQuaternionParams(val as number[]) ? PropUtils.setRotQuaternionArray(obj, val as Parameters) : console.error("[ PropUtils ] -> setRotationFromValue : invalid 'rotation' value!", { obj: obj, value: val }) } else if (val) { - val.isEuler - ? PropUtils.setRotEuler(obj, val) - : val.isVector3 - ? PropUtils.setRotVector3(obj, val) - : val.isQuaternion - ? PropUtils.setRotQuaternion(obj, val) + ;(val as Euler).isEuler + ? PropUtils.setRotEuler(obj, val as Euler) + : (val as Vector3).isVector3 + ? PropUtils.setRotVector3(obj, val as Vector3) + : (val as Quaternion).isQuaternion + ? PropUtils.setRotQuaternion(obj, val as Quaternion) : console.error("[ PropUtils ] -> setRotationFromValue : invalid 'rotation' value!", { obj: obj, value: val @@ -120,22 +137,22 @@ export default class PropUtils { } break case "Euler": - PropUtils.setRotEuler(obj, val) + PropUtils.setRotEuler(obj, val as Euler) break case "EulerParamsArray": - PropUtils.setRotEulerArray(obj, val) + PropUtils.setRotEulerArray(obj, val as Parameters) break case "Vector3": - PropUtils.setRotVector3(obj, val) + PropUtils.setRotVector3(obj, val as Vector3) break case "Array3Nums": - PropUtils.setRotArray3(obj, val) + PropUtils.setRotArray3(obj, val as Parameters) break case "Quaternion": - PropUtils.setRotQuaternion(obj, val) + PropUtils.setRotQuaternion(obj, val as Quaternion) break case "QuaternionParamsArray": - PropUtils.setRotQuaternionArray(obj, val) + PropUtils.setRotQuaternionArray(obj, val as Parameters) break default: console.error( @@ -182,17 +199,13 @@ export default class PropUtils { obj.quaternion.set(val[0], val[1], val[2], val[3]) } - public static setPositionFromValue( - obj: Object3D, - val: Vector3 | Parameters, - complex?: ComplexValueType - ): any { + public static setPositionFromValue(obj: Object3D, val: pos_value, complex?: ComplexValueType): void { if (verbose_mode() && log_prop_utils(obj)) { console.debug("[ PropUtils ] -> setPositionFromValue : ", { obj, val, complex }) } switch (complex) { case undefined: - PropUtils.isArray3Nums(val) + PropUtils.isArray3Nums(val as number[]) ? PropUtils.setPositionFromArray3(obj, val as Parameters) : val?.["isVector3"] ? PropUtils.setPositionFromVector3(obj, val as Vector3) @@ -234,21 +247,19 @@ export default class PropUtils { obj.position.set(val[0], val[1], val[2]) } - public static setScaleFromValue( - obj: Object3D, - val: Vector3 | Parameters, - complex?: ComplexValueType - ): void { + public static setScaleFromValue(obj: Object3D, val: scale_value, complex?: ComplexValueType): void { if (verbose_mode() && log_prop_utils(obj)) { console.debug("[ PropUtils ] -> setScaleFromValue : ", { obj, val, complex }) } switch (complex) { case undefined: if (val) { - PropUtils.isArray3Nums(val) + PropUtils.isArray3Nums(val as number[]) ? PropUtils.setScaleFromArray3(obj, val as Parameters) - : val["isVector3"] + : (val as Vector3).isVector3 ? PropUtils.setScaleFromVector3(obj, val as Vector3) + : !isNaN(val as number) + ? PropUtils.setScaleFromNumber(obj, val as number) : console.error("[ PropUtils ] -> setScaleFromValue : invalid 'scale' value!", { obj: obj, value: val @@ -285,6 +296,12 @@ export default class PropUtils { obj.scale.copy(val as Vector3) } + public static setScaleFromNumber(obj: Object3D, val: number) { + if (verbose_mode() && log_prop_utils(obj)) console.debug("[ PropUtils ] -> setScaleFromNumber : ", { obj, val }) + // uniform scale + obj.scale.set(val, val, val) + } + public static setScaleFromArray3(obj: Object3D, val: Parameters) { if (verbose_mode() && log_prop_utils(obj)) console.debug("[ PropUtils ] -> setScaleFromArray3 : ", { obj, val }) obj.scale.set(val[0], val[1], val[2]) @@ -304,99 +321,111 @@ export default class PropUtils { TEST: ... the last one updated will be applied */ - public static setLookAtFromValue(obj: Object3D, val: any, complex?: ComplexValueType) { + + public static setLookAtFromValue(obj: Object3D | LightWithTarget, val: lookAt_value, complex?: ComplexValueType) { if (verbose_mode() && log_prop_utils(obj)) console.debug("[ PropUtils ] -> setLookAtFromValue!", { obj, val }) // IMPORTANT update Matrix before setting `lookAt`--> lookAt has to be applied as last. // this way we apply all other transforms before lookAt-update! obj.updateMatrix() - let tVal: any + let t_val: Vector3 | Parameters | null if (val) { // TODO TOFIX this seems to be broken?! (Spotlight) // can use Object3D as `lookAt` value - tVal = - Object.getPrototypeOf(Object.getPrototypeOf(val)).constructor.name === "Object3D" - ? (val as Object3D).position - : val - - // limit using manipulating `target` via `lookAt` to lights only - if (obj["isLight"]) { - // THREE IMPORTANT Only DirectionalLight and SpotLight have own `target` properties. Object3D does not. - if (Object.prototype.hasOwnProperty.call(obj, "target")) { - if (obj["target"].isObject3D) { - if (obj.matrixAutoUpdate === false) { - obj["target"].matrixAutoUpdate = false - } + if (!(val as TargetableSvelthreeComponent).is_svelthree_component && (val as Object3D).isObject3D) { + t_val = (val as Object3D).position + } else if ((val as TargetableSvelthreeComponent).is_svelthree_component) { + t_val = (val as TargetableSvelthreeComponent).get_instance().position + } else if ((val as Vector3).isVector3) { + t_val = val as Vector3 + } else if (PropUtils.isArray3Nums(val as number[])) { + t_val = val as Parameters + } else { + t_val = null + } + + if (t_val) { + // Use 'target': IMPORTANT Manipulating `target` via `lookAt` shorthand attribute is limited to `Lights` with 'target' property only (DirectionalLight | SpotLight) + if (obj["isLight"]) { + if (Object.prototype.hasOwnProperty.call(obj, "target")) { + if ((obj as LightWithTarget).target.isObject3D) { + if ((obj as LightWithTarget).matrixAutoUpdate === false) { + ;(obj as LightWithTarget).target.matrixAutoUpdate = false + } - if (obj["target"].parent === null) { - // add target to parent of obj (light) - if (obj.parent !== null) { - // target has no parent, add target to parent of obj - obj.parent.add(obj["target"]) - console.warn( - `[ PropUtils ] -> setLookAtFromValue : 'target' of ${obj.type} was added to the parent of ${obj.type}!`, - { obj, target: obj["target"] } - ) - - // set position of the target - PropUtils.setPositionFromValue(obj["target"], tVal, complex) + if ((obj as LightWithTarget).target.parent === null) { + // add target to parent of obj (light) + if ((obj as LightWithTarget).parent !== null) { + // target has no parent, add target to parent of obj + ;(obj as LightWithTarget).parent.add((obj as LightWithTarget).target) + console.warn( + `[ PropUtils ] -> setLookAtFromValue : 'target' of ${obj.type} was added to the parent of ${obj.type}!`, + { obj, target: (obj as LightWithTarget).target } + ) + + // set position of the target + PropUtils.setPositionFromValue((obj as LightWithTarget).target, t_val, complex) + } else { + // obj has no parent + console.error( + `[ PropUtils ] -> setLookAtFromValue : 'target' of ${ + (obj as LightWithTarget).type + } couldn't be added to the parent of ${(obj as LightWithTarget).type}! ${ + (obj as LightWithTarget).type + } has no parent!`, + { obj, target: (obj as LightWithTarget).target } + ) + } } else { - // obj has no parent - console.error( - `[ PropUtils ] -> setLookAtFromValue : 'target' of ${obj.type} couldn't be added to the parent of ${obj.type}! ${obj.type} has no parent!`, - { obj, target: obj["target"] } - ) + // target has parent, set position of the target + PropUtils.setPositionFromValue(obj["target"], t_val, complex) } } else { - // target has parent, set position of the target - PropUtils.setPositionFromValue(obj["target"], tVal, complex) + // target is not Object3D + console.error(`[ PropUtils ] -> setLookAtFromValue : 'target' has to be an 'Object3D'!`, { + obj, + target: (obj as LightWithTarget).target + }) } } else { - // target is not Object3D - console.error(`[ PropUtils ] -> setLookAtFromValue : 'target' has to be an 'Object3D'!`, { - obj, - target: obj["target"] + console.error(`[ PropUtils ] -> setLookAtFromValue : ${obj.type} has no 'target' property!`, { + obj }) } } else { - console.error(`[ PropUtils ] -> setLookAtFromValue : ${obj.type} has no 'target' property!`, { - obj - }) - } - } else { - if (tVal) { - if (PropUtils.isArray3Nums(tVal)) { - obj.lookAt(tVal[0], tVal[1], tVal[2]) - } else if (tVal?.isVector3) { - obj.lookAt(tVal as Vector3) + // Use `Object3D.lookAt` function (not 'target') on any `Object3D` + if (PropUtils.isArray3Nums(t_val as number[])) { + obj.lookAt(t_val[0], t_val[1], t_val[2]) + } else if ((t_val as Vector3).isVector3) { + obj.lookAt(t_val as Vector3) } else { console.error("[ PropUtils ] -> setLookAtFromValue : invalid 'lookAt' value!", { obj: obj, - value: tVal + value: t_val }) } - } else { - console.error("[ PropUtils ] -> setLookAtFromValue : invalid 'lookAt' value!", { - obj: obj, - value: tVal - }) } + } else { + console.error("[ PropUtils ] -> setLookAtFromValue : invalid 'lookAt' value!", { + obj: obj, + value: t_val + }) } } else { console.error("[ PropUtils ] -> setLookAtFromValue : invalid 'lookAt' value!", { obj: obj, - value: tVal + value: val }) } } // we know that 'obj' has property 'key', see 'Propeller' public static setColorFromValueKey( - obj: Object3D | Material | Light | Scene, - val: any, + obj: Material | Light | Scene, + val: color_value, key: string, complex?: ComplexValueType ) { @@ -405,14 +434,14 @@ export default class PropUtils { } // color value can be `0` if (val || val === 0) { - PropUtils.isArray3Nums(val) - ? PropUtils.setColorFromArray(obj, val, key) - : !isNaN(val) - ? PropUtils.setColorFromNumber(obj, val, key) - : val.isColor - ? PropUtils.setColorFromColor(obj, val, key) - : val.isVector3 - ? PropUtils.setColorFromVector3(obj, val, key) + PropUtils.isArray3Nums(val as number[]) + ? PropUtils.setColorFromArray(obj, val as [r: number, g: number, b: number], key) + : !isNaN(val as number) + ? PropUtils.setColorFromNumber(obj, val as number, key) + : (val as Color).isColor + ? PropUtils.setColorFromColor(obj, val as Color, key) + : (val as Vector3).isVector3 + ? PropUtils.setColorFromVector3(obj, val as Vector3, key) : typeof val === "string" ? PropUtils.setColorFromString(obj, val, key) : console.error(`[ PropUtils ] -> setColorFromValueKey : invalid '${key}' value!`, { @@ -427,6 +456,13 @@ export default class PropUtils { } } + // TODO handle background as `Texture` + /* + public static setBackgroundAsTextureFromValueKey() { + // TODO + } + */ + public static setColorFromArray(obj: Object3D | Material, val: [r: number, g: number, b: number], key: string) { if (verbose_mode() && log_prop_utils(obj)) { console.debug("[ PropUtils ] -> setColorFromArray : ", { obj, val, key }) @@ -498,26 +534,10 @@ export default class PropUtils { light.castShadow = castShadow } - public static setShadowCameraProp(light: LightWithShadow, key: string, val: any) { - if (verbose_mode() && log_prop_utils(light)) { - console.debug("[ PropUtils ] -> setShadowCameraProp : ", { light, key, val }) - } - light.shadow.camera[key] = val - light.shadow.camera.updateProjectionMatrix() - } - - public static setShadowProp(light: Light, key: string, val: any) { - if (verbose_mode() && log_prop_utils(light)) { - console.debug("[ PropUtils ] -> setShadowProp : ", { light, key, val }) - } - light.shadow[key] = val - light.shadow.needsUpdate = true - } - /** * TODO : test / polish this! */ - public static setLightTarget(obj: Object3D, val: Targetable) { + public static setLightTarget(obj: LightWithTarget, val: Targetable) { if (verbose_mode() && log_prop_utils(obj)) console.debug("[ PropUtils ] -> setLightTarget : ", { obj, val }) if (!val) { console.warn(`[ PropUtils ] -> setLightTarget : invalid 'target' value!`, { val }) @@ -525,11 +545,10 @@ export default class PropUtils { // TODO : Check why this being called twice on init! Not severe problem, but still to be checked. //console.warn("SVELTHREE > Propeller > setLightTarget : " + this.objTypeStr + " : target in 'props' now defined!!") - if (val["isObject3D"]) { - obj["target"] = val - } else if (val["is_svelthree_component"]) { - const obj3d: Object3D = (val as TargetableSvelthreeComponent).get_instance() - obj["target"] = obj3d + if ((val as TargetableSvelthreeComponent).is_svelthree_component) { + ;(obj as LightWithTarget).target = (val as TargetableSvelthreeComponent).get_instance() + } else if ((val as Object3D).isObject3D) { + obj["target"] = val as Object3D } else { console.error(`[ PropUtils ] -> setLightTarget : invalid 'target' value!`, { val }) } @@ -541,55 +560,64 @@ export default class PropUtils { * IMPORTANT Setting "manually" updating the `matrix` property will automatically set `matrixAutoUpdate` to `false`. * Applying transformations via `position`, `rotation`, `scale` etc. will automatically set `matrixAutoUpdate` to `true` again. */ - public static setMatrixFromValue(obj: Object3D, val: any) { + public static setMatrixFromValue(obj: Object3D, val: matrix_value) { if (verbose_mode() && log_prop_utils(obj)) console.debug("[ PropUtils ] -> obj.matrixAutoUpdate before! : ", obj.matrixAutoUpdate) if (verbose_mode() && log_prop_utils(obj)) console.debug("[ PropUtils ] -> setMatrixFromValue! : ", { obj, val }) + if (val) { + if ((val as Matrix4)["isMatrix4"]) { + // see https://stackoverflow.com/questions/60393190/threejs-transform-by-applymatrix4-doesnt-preserve-eigen-vectors-direction + //mesh.applyMatrix4(matrix) + + if (verbose_mode() && log_prop_utils(obj)) + console.debug("[ PropUtils ] -> setMatrixFromValue! is Matrix4 BEFORE : ", { + obj, + val, + m: obj.matrix + }) - if (val?.isMatrix4) { - // see https://stackoverflow.com/questions/60393190/threejs-transform-by-applymatrix4-doesnt-preserve-eigen-vectors-direction - //mesh.applyMatrix4(matrix) - - if (verbose_mode() && log_prop_utils(obj)) - console.debug("[ PropUtils ] -> setMatrixFromValue! is Matrix4 BEFORE : ", { obj, val, m: obj.matrix }) - - // save initial `matrixAutoUpdate` value - const initialMatrixAutoUpdate: boolean = obj.matrixAutoUpdate + // save initial `matrixAutoUpdate` value + const initialMatrixAutoUpdate: boolean = obj.matrixAutoUpdate - // force disable `matrixAutoUpdate` before matrix manipulation - obj.matrixAutoUpdate = false + // force disable `matrixAutoUpdate` before matrix manipulation + obj.matrixAutoUpdate = false - obj.matrix.copy(val as Matrix4) // copy is faster + obj.matrix.copy(val as Matrix4) // copy is faster - // reset inital `matrixAutoUpdate` value - obj.matrixAutoUpdate = initialMatrixAutoUpdate + // reset inital `matrixAutoUpdate` value + obj.matrixAutoUpdate = initialMatrixAutoUpdate - // mark for matrixWorld update (as updateMatrix() normally would) - obj.matrixWorldNeedsUpdate = true + // mark for matrixWorld update (as updateMatrix() normally would) + obj.matrixWorldNeedsUpdate = true - if (verbose_mode() && log_prop_utils(obj)) - console.debug("[ PropUtils ] -> setMatrixFromValue! is Matrix4 AFTER : ", { obj, val, m: obj.matrix }) - } else if (PropUtils.isMatrix4ParamsArray(val)) { - // save initial `matrixAutoUpdate` value - const initialMatrixAutoUpdate: boolean = obj.matrixAutoUpdate + if (verbose_mode() && log_prop_utils(obj)) + console.debug("[ PropUtils ] -> setMatrixFromValue! is Matrix4 AFTER : ", { + obj, + val, + m: obj.matrix + }) + } else if (PropUtils.isMatrix4ParamsArray(val)) { + // save initial `matrixAutoUpdate` value + const initialMatrixAutoUpdate: boolean = obj.matrixAutoUpdate - // force disable `matrixAutoUpdate` before matrix manipulation - obj.matrixAutoUpdate = false + // force disable `matrixAutoUpdate` before matrix manipulation + obj.matrixAutoUpdate = false - obj.matrix.set(...(val as Parameters)).transpose() - // TODO Nail down updating matrix / matrixWorld + obj.matrix.set(...(val as Parameters)).transpose() + // TODO Nail down updating matrix / matrixWorld - // reset inital `matrixAutoUpdate` value - obj.matrixAutoUpdate = initialMatrixAutoUpdate + // reset inital `matrixAutoUpdate` value + obj.matrixAutoUpdate = initialMatrixAutoUpdate - // mark for matrixWorld update (as updateMatrix() normally would) - obj.matrixWorldNeedsUpdate = true - } else { - console.error(`[ PropUtils ] -> setMatrixFromValue : invalid 'matrix' value!`, { - obj: obj, - value: val - }) + // mark for matrixWorld update (as updateMatrix() normally would) + obj.matrixWorldNeedsUpdate = true + } else { + console.error(`[ PropUtils ] -> setMatrixFromValue : invalid 'matrix' value!`, { + obj: obj, + value: val + }) + } } if (verbose_mode() && log_prop_utils(obj)) @@ -598,12 +626,12 @@ export default class PropUtils { console.debug("[ PropUtils ] -> setMatrixFromValue! AFTER : ", { obj, val, m: obj.matrix }) } - public static setQuaternionFromValue(obj: Object3D, val: any, complex?: ComplexValueType) { + public static setQuaternionFromValue(obj: Object3D, val: quat_value, complex?: ComplexValueType) { if (verbose_mode() && log_prop_utils(obj)) { console.debug("[ PropUtils ] -> setLightTarget : ", { obj, val, complex }) } - if (val?.isQuaternion) { + if (val && (val as Quaternion).isQuaternion) { // see https://threejs.org/docs/#api/en/core/Object3D.setRotationFromQuaternion // Copy the given quat into '.quat'. @@ -623,14 +651,14 @@ export default class PropUtils { } /** Simply set property `a` to value `x` -> no special method was assigned to the prop via `Propeller`. */ - public static applyValueToProp(obj: any, val: any, key: string, complex?: ComplexValueType) { + public static applyValueToProp(obj: unknown, value: unknown, key: string, complex?: ComplexValueType) { if (verbose_mode() && log_prop_utils(obj)) { - console.debug("[ PropUtils ] -> applyValueToProp : ", { obj, val, key, complex }) + console.debug("[ PropUtils ] -> applyValueToProp : ", { obj, value, key, complex }) } try { - obj[key] = val + obj[key] = value } catch (error) { - console.error(`[ PropUtils ] -> applyValueToProp : failed!`, { obj: obj, value: val, key: key }) + console.error(`[ PropUtils ] -> applyValueToProp : failed!`, { obj, value, key }) } } } diff --git a/src/lib/utils/Propeller.ts b/src/lib/utils/Propeller.ts index 7fd0cf7..ef3438b 100644 --- a/src/lib/utils/Propeller.ts +++ b/src/lib/utils/Propeller.ts @@ -1,18 +1,29 @@ -import type { WebGLCubeRenderTarget } from "three" +import type { WebGLCubeRenderTarget, Object3D, Material, Light, Scene } from "three" +import type { + matrix_value, + pos_value, + rot_value, + scale_value, + lookAt_value, + quat_value, + color_value, + //background_value, + any_propeller_value +} from "../types/types-extra" import PropUtils from "./PropUtils" -import type { ComplexValueType } from "../types/types-extra" +import type { ComplexValueType, SvelthreePropsOwner, Targetable, LightWithTarget } from "../types/types-extra" /** ⚙️ `Propeller`'s `update` method redirects some `props` object properties to specific `PropUtils` update * methods and also allows special handling if needed when updating a specific `props` object's property. - * It's used internally by `SvelthreeProps` (+`valuators`). */ + * It's used **only** internally by `SvelthreeProps` (+`valuators`) **only**. */ export default class Propeller { /** Used internally by `SvelthreeProps` (+`valuators`) -> redirects some `props` object properties to specific `PropUtils` update methods and also * allows special handling if needed when updating a specific `props` object's property. */ public static update( - obj: any, + obj: SvelthreePropsOwner, obj_type: string, key: string, - value: any, + value: any_propeller_value, origin: string | null, complex?: ComplexValueType ): void { @@ -20,28 +31,35 @@ export default class Propeller { if (origin === "own") { switch (key) { case "position": - PropUtils.setPositionFromValue(obj, value, complex) + PropUtils.setPositionFromValue(obj as Object3D, value as pos_value, complex) break case "rotation": - PropUtils.setRotationFromValue(obj, value, complex) + PropUtils.setRotationFromValue(obj as Object3D, value as rot_value, complex) break case "scale": - PropUtils.setScaleFromValue(obj, value, complex) + PropUtils.setScaleFromValue(obj as Object3D, value as scale_value, complex) break case "quaternion": - PropUtils.setQuaternionFromValue(obj, value, complex) + PropUtils.setQuaternionFromValue(obj as Object3D, value as quat_value, complex) break case "matrix": - PropUtils.setMatrixFromValue(obj, value) + PropUtils.setMatrixFromValue(obj as Object3D, value as matrix_value) break case "color": case "groundColor": + PropUtils.setColorFromValueKey(obj as Material | Light, value as color_value, key, complex) + break case "background": - PropUtils.setColorFromValueKey(obj, value, key, complex) + if (!(value as THREE.Texture).isTexture) { + PropUtils.setColorFromValueKey(obj as Scene, value as color_value, key, complex) + } else { + // TODO handle background as `Texture` + //PropUtils.setBackgroundAsTextureFromValueKey(obj as Scene, value as Texture, key, complex) + } break case "target": if (obj_type === "DirectionalLight" || obj_type === "SpotLight") { - PropUtils.setLightTarget(obj, value) + PropUtils.setLightTarget(obj as LightWithTarget, value as Targetable) } break @@ -54,7 +72,7 @@ export default class Propeller { } else if (origin === "inherited") { switch (key) { case "lookAt": - PropUtils.setLookAtFromValue(obj, value, complex) + PropUtils.setLookAtFromValue(obj as Object3D | LightWithTarget, value as lookAt_value, complex) break default: // update `CubeCamera`'s `renderTargetProps` prop (`CubeTexture`) diff --git a/src/lib/utils/SvelthreeProps.ts b/src/lib/utils/SvelthreeProps.ts index 51aef4c..3d27070 100644 --- a/src/lib/utils/SvelthreeProps.ts +++ b/src/lib/utils/SvelthreeProps.ts @@ -12,24 +12,45 @@ import { import { safe_not_equal, has_prop } from "svelte/internal" import Propeller from "./Propeller" import PropUtils from "./PropUtils" -import type { ComplexValueType } from "../types/types-extra" +import type { ComplexValueType, SvelthreePropsOwner } from "../types/types-extra" +import type { SvelthreePropsObjectLiteral } from "../types/types-comp-props" export type PropOrigin = "own" | "inherited" +type ComplexValuator = + | typeof PropArray3X + | typeof PropColorX + | typeof PropEulerX + | typeof PropMatrix4X + | typeof PropVector3X + | typeof PropEulerArrayX + | typeof PropQuaternionX + | typeof PropMatrix4ArrayX + | typeof PropQuaternionArrayX + +type ComplexValuatorInstance = + | PropArray3X + | PropColorX + | PropEulerX + | PropMatrix4X + | PropVector3X + | PropEulerArrayX + | PropQuaternionX + | PropMatrix4ArrayX + | PropQuaternionArrayX + type ComplexValueItem = { key: string - value: any + value: ComplexValuatorInstance complex: ComplexValueType } type SimpleValueItem = { key: string - value: any + value: unknown origin: PropOrigin | null } -type ComplexValuator = typeof PropArray3X - /** * Analyzes the type `props` object's properties, and updates corresponding `three` instance's properties via `Propeller`: * - **"reactive" _complex_ values**: if any part of a _complex_ value has changed, like e.g. `c` of a `Matrix4` type property, @@ -49,15 +70,15 @@ type ComplexValuator = typeof PropArray3X * allows special handling if needed when updating a specific `props` object's property. */ export default class SvelthreeProps { - obj: any + obj: SvelthreePropsOwner obj_type: string | null - propsPrev: { [key: string]: any } + propsPrev: SvelthreePropsObjectLiteral simpleValues: SimpleValueItem[] updatedKeys: string[] complexValues: ComplexValueItem[] - complexValuators: { [key in ComplexValueType]: any } = { + complexValuators: { [key in ComplexValueType]: ComplexValuator } = { Vector3: PropVector3X, Array3Nums: PropArray3X, Euler: PropEulerX, @@ -69,7 +90,7 @@ export default class SvelthreeProps { Color: PropColorX } - constructor(obj: any | null) { + constructor(obj: SvelthreePropsOwner | null) { this.obj = obj this.obj_type = this.get_obj_type() } @@ -89,7 +110,7 @@ export default class SvelthreeProps { * as their `valuator` will be assigned only once the unique `props` object was assigned, * not at each (reactive) properties change._ */ - public update(props: { [key: string]: any }): string[] { + public update(props: SvelthreePropsObjectLiteral): string[] { if (this.obj) { // UPDATE -> `props` has already been processed at least once -> `this.propsPrev` available if (this.propsPrev) { @@ -119,7 +140,7 @@ export default class SvelthreeProps { } // `props` object is a new one (changed) - resetAndMap(props: { [key: string]: any }) { + resetAndMap(props: SvelthreePropsObjectLiteral) { this.simpleValues = [] this.complexValues = [] this.updatedKeys = [] @@ -127,6 +148,7 @@ export default class SvelthreeProps { // analyze and sort `props` object's properties for (const k in props) { const complexType: ComplexValueType | undefined = PropUtils.checkIfComplexValueType(props[k]) + // eslint-disable-next-line @typescript-eslint/no-explicit-any const is_own_prop: any = has_prop(this.obj, k) const is_inherited_prop: boolean = is_own_prop ? false : this.obj[k] ? true : false const origin: PropOrigin | null = is_own_prop ? "own" : is_inherited_prop ? "inherited" : null @@ -162,18 +184,18 @@ export default class SvelthreeProps { } // `props` object is the same one - checkProps(props: { [key: string]: any }) { + checkProps(props: SvelthreePropsObjectLiteral) { // check complex props // reassign / update only if the 'complex' value object itself or any of its parts have changed. for (let i = 0; i < this.complexValues.length; i++) { - const k = this.complexValues[i].key + const k: string = this.complexValues[i].key const updated: boolean = this.complexValues[i].value.update(this.obj, props[k]) if (updated) this.updatedKeys.push(k) } // check 'simple' props (nummeric, strings, boolean... + objects and functions) for (let j = 0; j < this.simpleValues.length; j++) { - const k = this.simpleValues[j].key + const k: string = this.simpleValues[j].key const prop_value = this.simpleValues[j].value const prop_origin = this.simpleValues[j].origin diff --git a/src/lib/utils/props/PropArray3X.ts b/src/lib/utils/props/PropArray3X.ts index 224f08d..46d7cbd 100644 --- a/src/lib/utils/props/PropArray3X.ts +++ b/src/lib/utils/props/PropArray3X.ts @@ -1,21 +1,28 @@ import { not_equal } from "svelte/internal" -import type { Array3 } from "../../types/types-extra" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropArray3X { // previous value reference - prev: Array3 - prevValues: Array3 + prev: [number, number, number] + prevValues: [number, number, number] constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Array3): boolean { + public update(obj: SvelthreePropsOwner, value: [number, number, number]): boolean { //v1 switch (this.prev) { case undefined: this.prev = value // hot! - Propeller.update(obj, this.obj_type, this.key, value, this.origin, "Array3Nums") + Propeller.update( + obj, + this.obj_type, + this.key, + value as [number, number, number], + this.origin, + "Array3Nums" + ) this.prevValues = [value[0], value[1], value[2]] return true @@ -23,7 +30,14 @@ export default class PropArray3X { // same object, perform deep check for (let i = 0; i < 3; i++) { if (not_equal(this.prevValues[i], value[i])) { - Propeller.update(obj, this.obj_type, this.key, value, this.origin, "Array3Nums") + Propeller.update( + obj, + this.obj_type, + this.key, + value as [number, number, number], + this.origin, + "Array3Nums" + ) this.prevValues = [value[0], value[1], value[2]] this.prev = value return true @@ -33,7 +47,14 @@ export default class PropArray3X { return false default: // not undefined but !== value --> hot! - Propeller.update(obj, this.obj_type, this.key, value, this.origin, "Array3Nums") + Propeller.update( + obj, + this.obj_type, + this.key, + value as [number, number, number], + this.origin, + "Array3Nums" + ) this.prevValues = [value[0], value[1], value[2]] this.prev = value return true diff --git a/src/lib/utils/props/PropColorX.ts b/src/lib/utils/props/PropColorX.ts index d24dc6c..1e4a9fb 100644 --- a/src/lib/utils/props/PropColorX.ts +++ b/src/lib/utils/props/PropColorX.ts @@ -1,6 +1,7 @@ import type { Color } from "three" import { not_equal } from "svelte/internal" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropColorX { // previous value reference @@ -9,7 +10,7 @@ export default class PropColorX { constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Color): boolean { + public update(obj: SvelthreePropsOwner, value: Color): boolean { switch (this.prev) { case undefined: this.prev = value diff --git a/src/lib/utils/props/PropEulerArrayX.ts b/src/lib/utils/props/PropEulerArrayX.ts index 3397f1c..7cee56c 100644 --- a/src/lib/utils/props/PropEulerArrayX.ts +++ b/src/lib/utils/props/PropEulerArrayX.ts @@ -1,6 +1,7 @@ import type { Euler } from "three" import { not_equal } from "svelte/internal" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropEulerArrayX { // previous value reference @@ -9,7 +10,7 @@ export default class PropEulerArrayX { constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Parameters): boolean { + public update(obj: SvelthreePropsOwner, value: Parameters): boolean { switch (this.prev) { case undefined: this.prev = value diff --git a/src/lib/utils/props/PropEulerX.ts b/src/lib/utils/props/PropEulerX.ts index aa353c9..9df862d 100644 --- a/src/lib/utils/props/PropEulerX.ts +++ b/src/lib/utils/props/PropEulerX.ts @@ -1,6 +1,7 @@ import type { Euler } from "three" import { not_equal } from "svelte/internal" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropEulerX { // previous value reference @@ -9,7 +10,7 @@ export default class PropEulerX { constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Euler): boolean { + public update(obj: SvelthreePropsOwner, value: Euler): boolean { switch (this.prev) { case undefined: this.prev = value diff --git a/src/lib/utils/props/PropMatrix4ArrayX.ts b/src/lib/utils/props/PropMatrix4ArrayX.ts index f4ad171..483a80b 100644 --- a/src/lib/utils/props/PropMatrix4ArrayX.ts +++ b/src/lib/utils/props/PropMatrix4ArrayX.ts @@ -1,6 +1,7 @@ import type { Matrix4 } from "three" import { not_equal } from "svelte/internal" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropMatrix4ArrayX { // previous value reference @@ -9,7 +10,7 @@ export default class PropMatrix4ArrayX { constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Matrix4): boolean { + public update(obj: SvelthreePropsOwner, value: Matrix4): boolean { switch (this.prev) { case undefined: this.prev = value diff --git a/src/lib/utils/props/PropMatrix4X.ts b/src/lib/utils/props/PropMatrix4X.ts index a11dde1..1d591b2 100644 --- a/src/lib/utils/props/PropMatrix4X.ts +++ b/src/lib/utils/props/PropMatrix4X.ts @@ -1,6 +1,7 @@ import type { Matrix4 } from "three" import { not_equal } from "svelte/internal" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropMatrix4X { // previous value reference @@ -9,7 +10,7 @@ export default class PropMatrix4X { constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Matrix4): boolean { + public update(obj: SvelthreePropsOwner, value: Matrix4): boolean { switch (this.prev) { case undefined: this.prev = value diff --git a/src/lib/utils/props/PropQuaternionArrayX.ts b/src/lib/utils/props/PropQuaternionArrayX.ts index e815f34..130a795 100644 --- a/src/lib/utils/props/PropQuaternionArrayX.ts +++ b/src/lib/utils/props/PropQuaternionArrayX.ts @@ -1,6 +1,7 @@ import type { Quaternion } from "three" import { not_equal } from "svelte/internal" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropQuaternionArrayX { // previous value reference @@ -9,7 +10,7 @@ export default class PropQuaternionArrayX { constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Parameters): boolean { + public update(obj: SvelthreePropsOwner, value: Parameters): boolean { switch (this.prev) { case undefined: this.prev = value diff --git a/src/lib/utils/props/PropQuaternionX.ts b/src/lib/utils/props/PropQuaternionX.ts index 696ed25..8b55d34 100644 --- a/src/lib/utils/props/PropQuaternionX.ts +++ b/src/lib/utils/props/PropQuaternionX.ts @@ -1,6 +1,7 @@ import type { Quaternion } from "three" import { not_equal } from "svelte/internal" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropQuaternionX { // previous value reference @@ -9,7 +10,7 @@ export default class PropQuaternionX { constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Quaternion): boolean { + public update(obj: SvelthreePropsOwner, value: Quaternion): boolean { switch (this.prev) { case undefined: this.prev = value diff --git a/src/lib/utils/props/PropVector3X.ts b/src/lib/utils/props/PropVector3X.ts index 0905742..fdc0ab6 100644 --- a/src/lib/utils/props/PropVector3X.ts +++ b/src/lib/utils/props/PropVector3X.ts @@ -1,6 +1,7 @@ import type { Vector3 } from "three" import { not_equal } from "svelte/internal" import { Propeller } from "./utils" +import type { SvelthreePropsOwner } from "../../types/types-extra" export default class PropVector3X { // previous value reference @@ -9,7 +10,7 @@ export default class PropVector3X { constructor(private key: string, private obj_type: string, private origin: string) {} - public update(obj: any, value: Vector3): boolean { + public update(obj: SvelthreePropsOwner, value: Vector3): boolean { switch (this.prev) { case undefined: this.prev = value From b8603c63cedf96b28ea230c0e2862b92aa6bfeaf Mon Sep 17 00:00:00 2001 From: Vatroslav Vrbanic Date: Wed, 21 Sep 2022 01:45:22 +0200 Subject: [PATCH 10/70] Use new `Prop*` / `Props*` types in components (#170) --- src/lib/components/AmbientLight.svelte | 4 ++-- src/lib/components/CubeCamera.svelte | 15 +++++++++------ src/lib/components/DirectionalLight.svelte | 6 +++--- src/lib/components/Group.svelte | 10 +++++----- src/lib/components/HemisphereLight.svelte | 4 ++-- src/lib/components/LoadedGLTF.svelte | 12 ++++++------ src/lib/components/Mesh.svelte | 14 +++++++------- src/lib/components/Object3D.svelte | 10 +++++----- src/lib/components/OrbitControls.svelte | 4 ++-- src/lib/components/OrthographicCamera.svelte | 4 ++-- src/lib/components/PerspectiveCamera.svelte | 4 ++-- src/lib/components/PointLight.svelte | 4 ++-- src/lib/components/Points.svelte | 14 +++++++------- src/lib/components/RectAreaLight.svelte | 4 ++-- src/lib/components/Scene.svelte | 10 +++++----- src/lib/components/SpotLight.svelte | 4 ++-- src/lib/components/WebGLRenderer.svelte | 4 ++-- 17 files changed, 65 insertions(+), 62 deletions(-) diff --git a/src/lib/components/AmbientLight.svelte b/src/lib/components/AmbientLight.svelte index b23aeec..85d628a 100644 --- a/src/lib/components/AmbientLight.svelte +++ b/src/lib/components/AmbientLight.svelte @@ -28,7 +28,7 @@ AmbientLight cannot be used to cast shadows as it doesn't have a direction. Posi import type { SvelthreeAnimationFunction } from "../types/types-extra" import { AmbientLight as THREE_AmbientLight } from "three" - import type { AmbientLightProperties } from "../types/types-comp-props" + import type { PropsAmbientLight } from "../types/types-comp-props" import type { Color, Vector3 } from "three" import type { Object3D as THREE_Object3D } from "three" import { get_root_scene } from "../utils/SceneUtils" @@ -259,7 +259,7 @@ AmbientLight cannot be used to cast shadows as it doesn't have a direction. Posi // IMPORTANT `props` will be overridden by 'shorthand' attributes! /** **shorthand** attribute for setting properties using key-value pairs in an `Object`. */ - export let props: { [P in keyof AmbientLightProperties]: AmbientLightProperties[P] } = undefined + export let props: PropsAmbientLight = undefined $: if (!sProps && light && props) sProps = new SvelthreeProps(light) $: if (props && sProps) update_props() diff --git a/src/lib/components/CubeCamera.svelte b/src/lib/components/CubeCamera.svelte index 85d47ac..a81d6da 100644 --- a/src/lib/components/CubeCamera.svelte +++ b/src/lib/components/CubeCamera.svelte @@ -32,12 +32,16 @@ Renders a `CubeMap` which can be used with **non-PBR** materials having an `.env import { CubeCamera as THREE_CubeCamera } from "three" import { WebGLCubeRenderTarget } from "three" - import type { CubeCameraProperties, WebGLCubeRenderTargetProperties } from "../types/types-comp-props" + import type { + PropsCubeCamera, + PropsWebGLCubeRenderTarget, + PropWebGLRenderTargetOptions + } from "../types/types-comp-props" // custom CubeCameraHelper import { CubeCameraHelper } from "../utils" import { get_root_scene } from "../utils/SceneUtils" import { Vector3 } from "three" - import type { CubeTexture, WebGLRenderer, WebGLRenderTargetOptions, Camera, Mesh } from "three" + import type { CubeTexture, WebGLRenderer, Camera, Mesh } from "three" import type { Material, MeshBasicMaterialParameters, @@ -467,7 +471,7 @@ Renders a `CubeMap` which can be used with **non-PBR** materials having an `.env let sPropsTarget: SvelthreeProps /** **shorthand** attribute for setting properties using key-value pairs in an `Object`. */ - export let renderTargetOptions: { [P in keyof WebGLRenderTargetOptions]: WebGLRenderTargetOptions[P] } = undefined + export let renderTargetOptions: PropWebGLRenderTargetOptions = undefined $: if (renderTargetOptions && camera_updated) recreate_render_target() function recreate_render_target() { @@ -506,8 +510,7 @@ Renders a `CubeMap` which can be used with **non-PBR** materials having an `.env } /** **shorthand** attribute for setting properties using key-value pairs in an `Object`. */ - export let renderTargetProps: { [P in keyof WebGLCubeRenderTargetProperties]: WebGLCubeRenderTargetProperties[P] } = - undefined + export let renderTargetProps: PropsWebGLCubeRenderTarget = undefined $: if (!sPropsTarget && renderTargetProps && renderTargetProps) sPropsTarget = new SvelthreeProps(renderTargetProps) $: if (renderTargetProps && sPropsTarget) update_render_target_props() @@ -518,7 +521,7 @@ Renders a `CubeMap` which can be used with **non-PBR** materials having an `.env // IMPORTANT `props` will be overridden by 'shorthand' attributes! /** **shorthand** attribute for setting properties using key-value pairs in an `Object`. */ - export let props: { [P in keyof CubeCameraProperties]: CubeCameraProperties[P] } = undefined + export let props: PropsCubeCamera = undefined $: if (!sProps && camera && props) sProps = new SvelthreeProps(camera) $: if (props && sProps) update_props() diff --git a/src/lib/components/DirectionalLight.svelte b/src/lib/components/DirectionalLight.svelte index 8967af8..61ea184 100644 --- a/src/lib/components/DirectionalLight.svelte +++ b/src/lib/components/DirectionalLight.svelte @@ -38,7 +38,7 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` import { DirectionalLight as THREE_DirectionalLight } from "three" import { DirectionalLightHelper } from "three" - import type { DirectionalLightProperties } from "../types/types-comp-props" + import type { PropsDirectionalLight } from "../types/types-comp-props" import type { DirectionalLightShadow } from "three" import type { Color } from "three" import type { RemoveFirst } from "../types/types-extra" @@ -333,7 +333,7 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` // IMPORTANT `props` will be overridden by 'shorthand' attributes! /** **shorthand** attribute for setting properties using key-value pairs in an `Object`. */ - export let props: { [P in keyof DirectionalLightProperties]: DirectionalLightProperties[P] } = undefined + export let props: PropsDirectionalLight = undefined $: if (!sProps && light && props) sProps = new SvelthreeProps(light) $: if (props && sProps) update_props() @@ -369,7 +369,7 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` PropUtils.setMatrixFromValue(light, matrix) } - export let color: Color | string | number | [r: number, g: number, b: number] | number[] | Vector3 = undefined + export let color: Color | string | number | [r: number, g: number, b: number] | Vector3 = undefined $: if (light && color) set_color() function set_color(): void { if (verbose && log_rs) console.debug(...c_rs(c_name, "color", color)) diff --git a/src/lib/components/Group.svelte b/src/lib/components/Group.svelte index cf01127..03f8ef4 100644 --- a/src/lib/components/Group.svelte +++ b/src/lib/components/Group.svelte @@ -34,9 +34,9 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` import { get_root_scene } from "../utils/SceneUtils" import { Group as THREE_Group } from "three" - import type { GroupProperties } from "../types/types-comp-props" + import type { PropsGroup } from "../types/types-comp-props" import type { RemoveFirst } from "../types/types-extra" - import type { ButtonProperties, LinkProperties } from "../types/types-comp-props" + import type { PropButton, PropLink } from "../types/types-comp-props" /** * SVELTEKIT SSR / @@ -86,10 +86,10 @@ svelthree uses svelte-accmod, where accessors are always `true`, regardless of ` export const get_shadow_dom_el = (): SvelthreeShadowDOMElement => shadow_dom_el /** Specify the component / three.js object instance to act as an HTML `