@tomorrowevening/hermes 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +7 -0
  2. package/dist/hermes.js +2533 -718
  3. package/dist/hermes.umd.cjs +88 -11
  4. package/dist/images/android-chrome-192x192.png +0 -0
  5. package/dist/images/android-chrome-512x512.png +0 -0
  6. package/dist/images/apple-touch-icon.png +0 -0
  7. package/dist/images/favicon-16x16.png +0 -0
  8. package/dist/images/favicon-32x32.png +0 -0
  9. package/dist/images/favicon.ico +0 -0
  10. package/dist/images/milkyWay/dark-s_nx.jpg +0 -0
  11. package/dist/images/milkyWay/dark-s_ny.jpg +0 -0
  12. package/dist/images/milkyWay/dark-s_nz.jpg +0 -0
  13. package/dist/images/milkyWay/dark-s_px.jpg +0 -0
  14. package/dist/images/milkyWay/dark-s_py.jpg +0 -0
  15. package/dist/images/milkyWay/dark-s_pz.jpg +0 -0
  16. package/dist/images/site.webmanifest +1 -0
  17. package/dist/images/uv_grid_opengl.jpg +0 -0
  18. package/dist/index-0a798fe4.js +6862 -0
  19. package/dist/index-7bad599d.css +1 -0
  20. package/dist/index.html +18 -0
  21. package/dist/models/Flair.fbx +0 -0
  22. package/dist/models/Thriller2.fbx +0 -0
  23. package/dist/models/Thriller4.fbx +0 -0
  24. package/dist/style.css +1 -1
  25. package/package.json +9 -4
  26. package/src/core/Application.ts +28 -36
  27. package/src/core/RemoteController.ts +148 -98
  28. package/src/core/remote/BaseRemote.ts +3 -3
  29. package/src/core/remote/RemoteComponents.ts +5 -8
  30. package/src/core/remote/RemoteTheatre.ts +56 -54
  31. package/src/core/remote/RemoteThree.ts +77 -0
  32. package/src/core/remote/RemoteTweakpane.ts +71 -78
  33. package/src/core/types.ts +14 -4
  34. package/src/editor/Editor.tsx +8 -6
  35. package/src/editor/components/Draggable.tsx +20 -20
  36. package/src/editor/components/DraggableItem.tsx +6 -6
  37. package/src/editor/components/Dropdown.tsx +22 -14
  38. package/src/editor/components/DropdownItem.tsx +19 -19
  39. package/src/editor/components/NavButton.tsx +1 -1
  40. package/src/editor/components/content.ts +2 -0
  41. package/src/editor/components/icons/CloseIcon.tsx +1 -1
  42. package/src/editor/components/icons/DragIcon.tsx +1 -1
  43. package/src/editor/global.ts +9 -4
  44. package/src/editor/sceneHierarchy/Accordion.tsx +40 -0
  45. package/src/editor/sceneHierarchy/ChildObject.tsx +17 -17
  46. package/src/editor/sceneHierarchy/ContainerObject.tsx +7 -8
  47. package/src/editor/sceneHierarchy/SceneHierarchy.tsx +52 -49
  48. package/src/editor/sceneHierarchy/ToggleBtn.tsx +26 -0
  49. package/src/editor/sceneHierarchy/inspector/Inspector.tsx +82 -0
  50. package/src/editor/sceneHierarchy/inspector/InspectorField.tsx +178 -0
  51. package/src/editor/sceneHierarchy/inspector/InspectorGroup.tsx +55 -0
  52. package/src/editor/sceneHierarchy/inspector/MultiView/CameraWindow.tsx +61 -0
  53. package/src/editor/sceneHierarchy/inspector/MultiView/InfiniteGridHelper.ts +24 -0
  54. package/src/editor/sceneHierarchy/inspector/MultiView/InfiniteGridMaterial.ts +127 -0
  55. package/src/editor/sceneHierarchy/inspector/MultiView/MultiView.scss +93 -0
  56. package/src/editor/sceneHierarchy/inspector/MultiView/MultiView.tsx +450 -0
  57. package/src/editor/sceneHierarchy/inspector/SceneInspector.tsx +72 -0
  58. package/src/editor/sceneHierarchy/inspector/inspector.scss +150 -0
  59. package/src/editor/sceneHierarchy/inspector/utils/InspectCamera.tsx +75 -0
  60. package/src/editor/sceneHierarchy/inspector/utils/InspectLight.tsx +62 -0
  61. package/src/editor/sceneHierarchy/inspector/utils/InspectMaterial.tsx +340 -0
  62. package/src/editor/sceneHierarchy/inspector/utils/InspectTransform.tsx +124 -0
  63. package/src/editor/sceneHierarchy/types.ts +116 -5
  64. package/src/editor/sceneHierarchy/utils.ts +207 -11
  65. package/src/editor/scss/_debug.scss +9 -19
  66. package/src/editor/scss/_dropdown.scss +1 -0
  67. package/src/editor/scss/_sceneHierarchy.scss +148 -48
  68. package/src/editor/scss/index.scss +13 -6
  69. package/src/editor/utils.ts +42 -5
  70. package/src/example/CustomEditor.tsx +40 -0
  71. package/src/example/components/App.tsx +164 -0
  72. package/src/example/constants.ts +40 -9
  73. package/src/example/main.tsx +5 -45
  74. package/src/example/three/CustomMaterial.ts +58 -0
  75. package/src/example/three/ExampleScene.ts +176 -0
  76. package/src/example/three/FBXAnimation.ts +39 -0
  77. package/src/index.ts +23 -14
  78. package/types/core/Application.d.ts +7 -13
  79. package/types/core/remote/RemoteComponents.d.ts +0 -2
  80. package/types/core/remote/RemoteThree.d.ts +12 -0
  81. package/types/core/remote/RemoteTweakpane.d.ts +3 -3
  82. package/types/core/types.d.ts +4 -3
  83. package/types/editor/Editor.d.ts +2 -1
  84. package/types/editor/components/content.d.ts +2 -0
  85. package/types/editor/global.d.ts +7 -2
  86. package/types/editor/sceneHierarchy/Accordion.d.ts +10 -0
  87. package/types/editor/sceneHierarchy/SceneHierarchy.d.ts +5 -5
  88. package/types/editor/sceneHierarchy/ToggleBtn.d.ts +7 -0
  89. package/types/editor/sceneHierarchy/inspector/Inspector.d.ts +3 -0
  90. package/types/editor/sceneHierarchy/inspector/InspectorField.d.ts +13 -0
  91. package/types/editor/sceneHierarchy/inspector/InspectorGroup.d.ts +7 -0
  92. package/types/editor/sceneHierarchy/inspector/MultiView/CameraWindow.d.ts +16 -0
  93. package/types/editor/sceneHierarchy/inspector/MultiView/InfiniteGridHelper.d.ts +7 -0
  94. package/types/editor/sceneHierarchy/inspector/MultiView/InfiniteGridMaterial.d.ts +13 -0
  95. package/types/editor/sceneHierarchy/inspector/MultiView/MultiView.d.ts +11 -0
  96. package/types/editor/sceneHierarchy/inspector/SceneInspector.d.ts +7 -0
  97. package/types/editor/sceneHierarchy/inspector/utils/InspectCamera.d.ts +3 -0
  98. package/types/editor/sceneHierarchy/inspector/utils/InspectLight.d.ts +3 -0
  99. package/types/editor/sceneHierarchy/inspector/utils/InspectMaterial.d.ts +8 -0
  100. package/types/editor/sceneHierarchy/inspector/utils/InspectTransform.d.ts +3 -0
  101. package/types/editor/sceneHierarchy/types.d.ts +98 -7
  102. package/types/editor/sceneHierarchy/utils.d.ts +7 -1
  103. package/types/editor/utils.d.ts +3 -0
  104. package/types/example/CustomEditor.d.ts +1 -0
  105. package/types/example/constants.d.ts +15 -3
  106. package/types/example/three/CustomMaterial.d.ts +5 -0
  107. package/types/example/three/ExampleScene.d.ts +18 -0
  108. package/types/example/three/FBXAnimation.d.ts +6 -0
  109. package/types/index.d.ts +8 -0
  110. package/src/example/App.tsx +0 -88
  111. package/types/core/remote/RemoteDebug.d.ts +0 -23
  112. package/types/debug/Editor.d.ts +0 -8
  113. package/types/debug/components/Draggable.d.ts +0 -2
  114. package/types/debug/components/DraggableItem.d.ts +0 -2
  115. package/types/debug/components/Dropdown.d.ts +0 -2
  116. package/types/debug/components/DropdownItem.d.ts +0 -2
  117. package/types/debug/components/NavButton.d.ts +0 -5
  118. package/types/debug/components/icons/CloseIcon.d.ts +0 -2
  119. package/types/debug/components/icons/DragIcon.d.ts +0 -2
  120. package/types/debug/components/types.d.ts +0 -31
  121. package/types/debug/global.d.ts +0 -9
  122. package/types/debug/sceneHierarchy/ChildObject.d.ts +0 -2
  123. package/types/debug/sceneHierarchy/ContainerObject.d.ts +0 -2
  124. package/types/debug/sceneHierarchy/SceneHierarchy.d.ts +0 -13
  125. package/types/debug/sceneHierarchy/types.d.ts +0 -8
  126. package/types/debug/sceneHierarchy/utils.d.ts +0 -2
  127. package/types/debug/utils.d.ts +0 -4
  128. package/types/library.d.ts +0 -14
  129. /package/src/example/{App.css → components/App.css} +0 -0
  130. /package/types/example/{App.d.ts → components/App.d.ts} +0 -0
@@ -0,0 +1,72 @@
1
+ import RemoteThree from "@/core/remote/RemoteThree";
2
+ import { ToolEvents, debugDispatcher } from "@/editor/global";
3
+ import { useEffect } from "react";
4
+ import { Scene, Texture } from "three";
5
+ import { setItemProps, textureFromSrc } from "../utils";
6
+
7
+ export interface SceneInspectorProps {
8
+ scene: Scene
9
+ three: RemoteThree
10
+ }
11
+
12
+ export default function SceneInspector(props: SceneInspectorProps) {
13
+ const onGetObject = (evt: any) => {
14
+ const child = props.scene.getObjectByProperty('uuid', evt.value);
15
+ if (child !== undefined) props.three.setObject(child);
16
+ };
17
+
18
+ const setChildProps = (uuid: string, key: string, value: any) => {
19
+ const child = props.scene.getObjectByProperty('uuid', uuid);
20
+ if (child !== undefined) setItemProps(child, key, value);
21
+ };
22
+
23
+ const onUpdateObject = (evt: any) => {
24
+ const msg = evt.value;
25
+ const { key, value, uuid } = msg;
26
+ setChildProps(uuid, key, value);
27
+ };
28
+
29
+ const onCreateTexture = (evt: any) => {
30
+ const data = evt.value;
31
+ textureFromSrc(data.value).then((texture: Texture) => {
32
+ setChildProps(data.uuid, data.key, texture);
33
+ setChildProps(data.uuid, `material.needsUpdate`, true);
34
+ });
35
+ };
36
+
37
+ const onGetScene = () => {
38
+ props.three.setScene(props.scene);
39
+ };
40
+
41
+ const onRequestMethod = (evt: any) => {
42
+ const { key, uuid, value } = evt.value;
43
+ const child = props.scene.getObjectByProperty('uuid', uuid);
44
+ if (child !== undefined) {
45
+ try {
46
+ child[key](value);
47
+ } catch (err: any) {
48
+ console.log('Error requesting method:');
49
+ console.log(err);
50
+ console.log(key);
51
+ console.log(value);
52
+ }
53
+ }
54
+ };
55
+
56
+ useEffect(() => {
57
+ debugDispatcher.addEventListener(ToolEvents.GET_OBJECT, onGetObject);
58
+ debugDispatcher.addEventListener(ToolEvents.GET_SCENE, onGetScene);
59
+ debugDispatcher.addEventListener(ToolEvents.UPDATE_OBJECT, onUpdateObject);
60
+ debugDispatcher.addEventListener(ToolEvents.CREATE_TEXTURE, onCreateTexture);
61
+ debugDispatcher.addEventListener(ToolEvents.REQUEST_METHOD, onRequestMethod);
62
+ return () => {
63
+ debugDispatcher.removeEventListener(ToolEvents.GET_OBJECT, onGetObject);
64
+ debugDispatcher.removeEventListener(ToolEvents.GET_SCENE, onGetScene);
65
+ debugDispatcher.removeEventListener(ToolEvents.UPDATE_OBJECT, onUpdateObject);
66
+ debugDispatcher.removeEventListener(ToolEvents.CREATE_TEXTURE, onCreateTexture);
67
+ debugDispatcher.removeEventListener(ToolEvents.REQUEST_METHOD, onRequestMethod);
68
+ };
69
+ }, []);
70
+
71
+ return null;
72
+ }
@@ -0,0 +1,150 @@
1
+ $icon_folder: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAB1CAYAAADN5fjJAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAzklEQVR4nO3bwQqCUBBA0Yz+/5dt1eYRkVfKWZyzUgi5zEJSxm3f99tU96sDPhFXiavEVeIqcZW4anTcYzmf8P9pex2Mnpy4Slwlrhodt96Et7e/usjoyYmrxFXiKnGVuEpcJa4SV4mrxFXiKnGVuEpcJa4SV4mrxFXiKnGVuEpcJa4SV4mrxFXiqtFx69LLUd9sKuZFmtGTE1eJq8RV4ipx1T+2+o9e01b/aeIqcZW46uxWvweckcRV4ipxlbhqdNzZl4c//cJu9ORGxz0BUl8I9T4qXncAAAAASUVORK5CYII=');
2
+
3
+ #Inspector {
4
+ .field {
5
+ align-items: center;
6
+ background-color: #222;
7
+ display: flex;
8
+ flex-direction: row;
9
+ flex-wrap: wrap;
10
+ min-height: 21px;
11
+ overflow: hidden;
12
+ padding: 1px;
13
+
14
+ label {
15
+ line-height: normal;
16
+ margin: 0 10px;
17
+ max-width: 180px;
18
+ user-select: none;
19
+ width: fit-content;
20
+ min-width: 20px;
21
+ text-align: center;
22
+ }
23
+
24
+ input {
25
+ block-size: 11px;
26
+ flex: 1%;
27
+ margin: 0;
28
+ padding: 4px;
29
+ outline: none;
30
+ &.min {
31
+ height: 11px;
32
+ flex: none;
33
+ width: 30px;
34
+ margin-right: 1px;
35
+ }
36
+ &.color {
37
+ flex: none;
38
+ width: 60px;
39
+ }
40
+ }
41
+
42
+ input[type="checkbox"] {
43
+ flex: none;
44
+ }
45
+
46
+ input[type="color"] {
47
+ block-size: revert;
48
+ height: 21px;
49
+ padding-block: revert;
50
+ padding: 0;
51
+ margin: 0;
52
+ }
53
+
54
+ input[type="number"], input[type="range"] {
55
+ appearance: none;
56
+ height: 11px;
57
+ }
58
+
59
+ input[type="range"]::-webkit-slider-runnable-track {
60
+ border: none;
61
+ }
62
+
63
+ input[type="range"]::-webkit-slider-thumb {
64
+ appearance: none;
65
+ background-color: #666;
66
+ height: 17px;
67
+ width: 17px;
68
+ transition: 0.2s linear background-color;
69
+ &:hover {
70
+ background-color: #999;
71
+ }
72
+ }
73
+
74
+ textarea {
75
+ background-color: #191919;
76
+ font-size: 10px;
77
+ }
78
+
79
+ img {
80
+ border: 1px dotted #333;
81
+ cursor: pointer;
82
+ object-fit: contain;
83
+ max-width: 100%;
84
+ min-width: 50px;
85
+ min-height: 30px;
86
+ max-height: 50px;
87
+ position: relative;
88
+ left: 50%;
89
+ transform: translateX(-50%);
90
+ }
91
+
92
+ button {
93
+ background-color: #333;
94
+ border-top: 1px dotted #444;
95
+ height: 100%;
96
+ margin: 0;
97
+ padding: 0;
98
+ text-align: center;
99
+ transition: 0.2s background-color linear;
100
+ width: 100%;
101
+ &:hover {
102
+ background-color: #444;
103
+ }
104
+ }
105
+
106
+ &.block {
107
+ label {
108
+ display: block;
109
+ line-height: 21px;
110
+ max-width: 100%;
111
+ width: 100%;
112
+ }
113
+ }
114
+ }
115
+
116
+ .group {
117
+ background-color: #191919;
118
+ margin: 2px 0;
119
+ h4 {
120
+ display: inline;
121
+ font-weight: bold;
122
+ pointer-events: none;
123
+ width: fit-content;
124
+ }
125
+ .toggleBtn {
126
+ background-color: #191919;
127
+ background-image: $icon_folder;
128
+ background-position: 1px 1px;
129
+ background-repeat: no-repeat;
130
+ background-size: 15px 45px;
131
+ display: inline-block;
132
+ height: 15px;
133
+ opacity: 0.8;
134
+ overflow: hidden;
135
+ margin: 0 0 0 5px;
136
+ padding-left: 20px;
137
+ width: calc(100% - 7px);
138
+ transition: all 0.15s linear;
139
+ &:hover {
140
+ background-color: #222;
141
+ opacity: 1;
142
+ }
143
+ }
144
+ .fieldItems {
145
+ border-top: 1px dotted #333;
146
+ overflow-y: auto;
147
+ user-select: none;
148
+ }
149
+ }
150
+ }
@@ -0,0 +1,75 @@
1
+ import RemoteThree from '@/core/remote/RemoteThree';
2
+ import InspectorGroup from '../InspectorGroup';
3
+ import { RemoteObject } from "../../types";
4
+ import { setItemProps } from '../../utils';
5
+
6
+ function prettyName(name: string): string {
7
+ switch (name) {
8
+ case 'fov': return 'FOV';
9
+ case 'zoom': return 'Zoom';
10
+ case 'near': return 'Near';
11
+ case 'far': return 'Far';
12
+ case 'focus': return 'Focus';
13
+ case 'aspect': return 'Aspect';
14
+ case 'filmGauge': return 'Film Gauge';
15
+ case 'filmOffset': return 'Film Offset';
16
+ case 'left': return 'Left';
17
+ case 'right': return 'Right';
18
+ case 'top': return 'Top';
19
+ case 'bottom': return 'Bottom';
20
+ }
21
+ return name;
22
+ }
23
+
24
+ export function InspectCamera(object: RemoteObject, three: RemoteThree): any {
25
+ const items: any[] = [];
26
+
27
+ if (object.perspectiveCameraInfo !== undefined) {
28
+ for (const i in object.perspectiveCameraInfo) {
29
+ items.push({
30
+ title: prettyName(i),
31
+ prop: i,
32
+ type: 'number',
33
+ step: 0.01,
34
+ value: object.perspectiveCameraInfo[i],
35
+ onChange: (prop: string, value: any) => {
36
+ three.updateObject(object.uuid, prop, value);
37
+ three.requestMethod(object.uuid, 'updateProjectionMatrix');
38
+
39
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
40
+ if (child !== undefined) {
41
+ setItemProps(child, prop, value);
42
+ child['updateProjectionMatrix']();
43
+ }
44
+ }
45
+ });
46
+ }
47
+ } else if (object.orthographicCameraInfo !== undefined) {
48
+ for (const i in object.orthographicCameraInfo) {
49
+ items.push({
50
+ title: prettyName(i),
51
+ prop: i,
52
+ type: 'number',
53
+ step: 0.01,
54
+ value: object.perspectiveCameraInfo![i],
55
+ onChange: (prop: string, value: any) => {
56
+ three.updateObject(object.uuid, prop, value);
57
+ three.requestMethod(object.uuid, 'updateProjectionMatrix');
58
+
59
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
60
+ if (child !== undefined) {
61
+ setItemProps(child, prop, value);
62
+ child['updateProjectionMatrix']();
63
+ }
64
+ }
65
+ });
66
+ }
67
+ }
68
+
69
+ return (
70
+ <InspectorGroup
71
+ title="Camera"
72
+ items={items}
73
+ />
74
+ );
75
+ }
@@ -0,0 +1,62 @@
1
+ import InspectorGroup from '../InspectorGroup';
2
+ import { RemoteObject } from "../../types";
3
+ import RemoteThree from '@/core/remote/RemoteThree';
4
+ import { setItemProps } from '../../utils';
5
+ import { Color } from 'three';
6
+
7
+ function prettyName(value: string): string {
8
+ switch (value) {
9
+ case 'color': return 'Color';
10
+ case 'intensity': return 'Intensity';
11
+ case 'decay': return 'Decay';
12
+ case 'distance': return 'Distance';
13
+ case 'angle': return 'Angle';
14
+ case 'penumbra': return 'Penumbra';
15
+ case 'groundColor': return 'Ground Color';
16
+ }
17
+ return value;
18
+ }
19
+
20
+ export function InspectLight(obj: RemoteObject, three: RemoteThree) {
21
+ const items: any[] = [];
22
+ if (obj.lightInfo !== undefined) {
23
+ for (const i in obj.lightInfo) {
24
+ const value = obj.lightInfo[i];
25
+ if (value === undefined) continue;
26
+
27
+ if (value.isColor !== undefined) {
28
+ items.push({
29
+ title: prettyName(i),
30
+ prop: i,
31
+ type: 'color',
32
+ value: value,
33
+ onChange: (prop: string, value: any) => {
34
+ const color = new Color(value);
35
+ three.updateObject(obj.uuid, prop, color);
36
+ const child = three.scene?.getObjectByProperty('uuid', obj.uuid);
37
+ if (child !== undefined) setItemProps(child, prop, color);
38
+ }
39
+ });
40
+ } else {
41
+ items.push({
42
+ title: prettyName(i),
43
+ prop: i,
44
+ type: typeof value,
45
+ value: value,
46
+ step: typeof value === 'number' ? 0.01 : undefined,
47
+ onChange: (prop: string, value: any) => {
48
+ three.updateObject(obj.uuid, prop, value);
49
+ const child = three.scene?.getObjectByProperty('uuid', obj.uuid);
50
+ if (child !== undefined) setItemProps(child, prop, value);
51
+ }
52
+ });
53
+ }
54
+ }
55
+ }
56
+ return (
57
+ <InspectorGroup
58
+ title="Light"
59
+ items={items}
60
+ />
61
+ );
62
+ }
@@ -0,0 +1,340 @@
1
+ import { Color, Texture } from 'three';
2
+ import InspectorGroup from '../InspectorGroup';
3
+ import { RemoteMaterial, RemoteObject } from "../../types";
4
+ import RemoteThree from '@/core/remote/RemoteThree';
5
+ import { setItemProps, textureFromSrc } from '../../utils';
6
+
7
+ export function acceptedMaterialNames(name: string): boolean {
8
+ return !(
9
+ name === 'alphaHash' ||
10
+ name === 'alphaToCoverage' ||
11
+ name === 'attenuationDistance' ||
12
+ name === 'colorWrite' ||
13
+ name === 'combine' ||
14
+ name === 'defaultAttributeValues' ||
15
+ name === 'depthFunc' ||
16
+ name === 'forceSinglePass' ||
17
+ name === 'glslVersion' ||
18
+ name === 'linewidth' ||
19
+ name === 'normalMapType' ||
20
+ name === 'precision' ||
21
+ name === 'premultipliedAlpha' ||
22
+ name === 'shadowSide' ||
23
+ name === 'side' ||
24
+ name === 'toneMapped' ||
25
+ name === 'uniformsGroups' ||
26
+ name === 'uniformsNeedUpdate' ||
27
+ name === 'userData' ||
28
+ name === 'vertexColors' ||
29
+ name === 'version' ||
30
+ name === 'wireframeLinecap' ||
31
+ name === 'wireframeLinejoin' ||
32
+ name === 'wireframeLinewidth' ||
33
+ name.slice(0, 5) === 'blend' ||
34
+ name.slice(0, 4) === 'clip' ||
35
+ name.slice(0, 7) === 'polygon' ||
36
+ name.slice(0, 7) === 'stencil' ||
37
+ name.slice(0, 2) === 'is'
38
+ );
39
+ }
40
+
41
+ export function niceMaterialNames(name: string): string {
42
+ switch (name) {
43
+ case 'alphaMap': return 'Alpha Map';
44
+ case 'anisotropyRotation': return 'Anisotropy Rotation';
45
+ case 'aoMap': return 'AO Map';
46
+ case 'aoMapIntensity': return 'AO Map Intensity';
47
+ case 'attenuationColor': return 'Attenuation Color';
48
+ case 'bumpMap': return 'Bump Map';
49
+ case 'bumpScale': return 'Bump Scale';
50
+ case 'clearcoatNormalScale': return 'Clearcoat Normal Scale';
51
+ case 'clearcoatRoughness': return 'Clearcoat Roughness';
52
+ case 'color': return 'Color';
53
+ case 'defines': return 'Defines';
54
+ case 'depthTest': return 'Depth Test';
55
+ case 'depthWrite': return 'Depth Write';
56
+ case 'displacementBias': return 'Displacement Bias';
57
+ case 'displacementMap': return 'Displacement Map';
58
+ case 'displacementScale': return 'Displacement Scale';
59
+ case 'dithering': return 'Dithering';
60
+ case 'emissive': return 'Emissive';
61
+ case 'emissiveIntensity': return 'Emissive Intensity';
62
+ case 'envMap': return 'Environment Map';
63
+ case 'envMapIntensity': return 'Environment Map Intensity';
64
+ case 'extensions': return 'Extensions';
65
+ case 'flatShading': return 'Flat Shading';
66
+ case 'fragmentShader': return 'Fragment Shader';
67
+ case 'fog': return 'Fog';
68
+ case 'gradientMap': return 'Gradient Map';
69
+ case 'ior': return 'IOR';
70
+ case 'iridescenceIOR': return 'Iridescence IOR';
71
+ case 'iridescenceThicknessRange': return 'Iridescence Thickness Range';
72
+ case 'lights': return 'Lights';
73
+ case 'lightMap': return 'Light Map';
74
+ case 'lightMapIntensity': return 'Light Map Intensity';
75
+ case 'map': return 'Map';
76
+ case 'matcap': return 'Matcap';
77
+ case 'metalness': return 'Metalness';
78
+ case 'name': return 'Name';
79
+ case 'normalMap': return 'Normal Map';
80
+ case 'normalScale': return 'Normal Scale';
81
+ case 'opacity': return 'Opacity';
82
+ case 'reflectivity': return 'Reflectivity';
83
+ case 'refractionRatio': return 'Refraction Ratio';
84
+ case 'roughness': return 'Roughness';
85
+ case 'sheenColor': return 'Sheen Color';
86
+ case 'sheenRoughness': return 'Sheen Roughness';
87
+ case 'shininess': return 'Shininess';
88
+ case 'specular': return 'Specular';
89
+ case 'specularColor': return 'Specular Color';
90
+ case 'specularIntensity': return 'Specular Intensity';
91
+ case 'thickness': return 'Thickness';
92
+ case 'transparent': return 'Transparent';
93
+ case 'type': return 'Type';
94
+ case 'uuid': return 'UUID';
95
+ case 'uniforms': return 'Uniforms';
96
+ case 'vertexShader': return 'Vertex Shader';
97
+ case 'visible': return 'Visible';
98
+ case 'wireframe': return 'Wireframe';
99
+ }
100
+ return name;
101
+ }
102
+
103
+ export function clampedNames(name: string): boolean {
104
+ return (
105
+ name.toLowerCase().search('intensity') > -1 ||
106
+ name === 'anisotropyRotation' ||
107
+ name === 'bumpScale' ||
108
+ name === 'clearcoatRoughness' ||
109
+ name === 'displacementBias' ||
110
+ name === 'displacementScale' ||
111
+ name === 'metalness' ||
112
+ name === 'opacity' ||
113
+ name === 'reflectivity' ||
114
+ name === 'refractionRatio' ||
115
+ name === 'roughness' ||
116
+ name === 'sheenRoughness' ||
117
+ name === 'thickness'
118
+ );
119
+ }
120
+
121
+ export function uploadLocalImage(): Promise<string> {
122
+ const inputElement = document.createElement('input');
123
+ inputElement.type = 'file';
124
+ return new Promise((resolve: any, reject: any) => {
125
+ inputElement.addEventListener('change', function() {
126
+ if (inputElement.files === null) {
127
+ reject();
128
+ } else {
129
+ const selectedFile = inputElement.files[0];
130
+ const reader = new FileReader();
131
+ reader.onload = function(e: any) {
132
+ resolve(e.target.result);
133
+ };
134
+ reader.readAsDataURL(selectedFile);
135
+ }
136
+ });
137
+ inputElement.click();
138
+ });
139
+ }
140
+
141
+ export function inspectMaterialItems(material: RemoteMaterial, object: RemoteObject, three: RemoteThree): any[] {
142
+ const items: any[] = [];
143
+ for (const i in material) {
144
+ if (!acceptedMaterialNames(i)) continue;
145
+
146
+ const propType = typeof material[i];
147
+ const value = material[i];
148
+ if (propType === 'boolean' || propType === 'number' || propType === 'string') {
149
+ const newField = {
150
+ title: niceMaterialNames(i),
151
+ prop: i,
152
+ type: propType,
153
+ value: value,
154
+ min: undefined,
155
+ max: undefined,
156
+ onChange: (prop: string, value: any) => {
157
+ three.updateObject(object.uuid, `material.${prop}`, value);
158
+ if (propType === 'boolean') three.updateObject(object.uuid, 'material.needsUpdate', true);
159
+ // Local update
160
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
161
+ if (child !== undefined) setItemProps(child, `material.${prop}`, value);
162
+ },
163
+ };
164
+ if (clampedNames(i)) {
165
+ newField.value = Number(value);
166
+ // @ts-ignore
167
+ newField.type = 'range';
168
+ // @ts-ignore
169
+ newField.min = 0;
170
+ // @ts-ignore
171
+ newField.max = 1;
172
+ // @ts-ignore
173
+ newField.step = 0.01;
174
+ }
175
+ items.push(newField);
176
+ } else if (propType === 'object') {
177
+ if (value.isColor) {
178
+ items.push({
179
+ title: niceMaterialNames(i),
180
+ prop: i,
181
+ type: 'color',
182
+ value: value,
183
+ onChange: (prop: string, value: any) => {
184
+ const newValue = new Color(value);
185
+ three.updateObject(object.uuid, `material.${prop}`, newValue);
186
+ // Local update
187
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
188
+ if (child !== undefined) setItemProps(child, `material.${prop}`, newValue);
189
+ },
190
+ });
191
+ } else if (Array.isArray(value)) {
192
+ const subChildren: any[] = [];
193
+ for (const index in value) {
194
+ subChildren.push({
195
+ title: `${index}`,
196
+ type: `${typeof value[index]}`,
197
+ value: value[index],
198
+ onChange: (prop: string, value: any) => {
199
+ three.updateObject(object.uuid, `material.${i}`, value);
200
+ // Local update
201
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
202
+ if (child !== undefined) setItemProps(child, `material.${i}`, value);
203
+ },
204
+ });
205
+ }
206
+ items.push({
207
+ title: niceMaterialNames(i),
208
+ items: subChildren,
209
+ });
210
+ } else {
211
+ const subChildren: any[] = [];
212
+ for (const n in value) {
213
+ const propValue = value[n];
214
+ const propValueType = typeof propValue;
215
+ switch (propValueType) {
216
+ case 'boolean':
217
+ case 'number':
218
+ case 'string':
219
+ if (n === 'src') {
220
+ items.push({
221
+ title: niceMaterialNames(i),
222
+ type: 'image',
223
+ value: propValue,
224
+ onChange: (prop: string, value: any) => {
225
+ three.createTexture(object.uuid, `material.${i}`, value);
226
+ // Local update
227
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
228
+ if (child !== undefined) {
229
+ textureFromSrc(value).then((texture: Texture) => {
230
+ setItemProps(child, `material.${i}`, texture);
231
+ setItemProps(child, `material.needsUpdate`, true);
232
+ });
233
+ }
234
+ },
235
+ });
236
+ } else {
237
+ subChildren.push({
238
+ title: `${niceMaterialNames(n)}`,
239
+ prop: `material.${i}.${n}`,
240
+ type: `${typeof material[i][n]}`,
241
+ value: value[n],
242
+ onChange: (prop: string, value: any) => {
243
+ three.updateObject(object.uuid, `material.${i}.${n}`, value);
244
+ // Local update
245
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
246
+ if (child !== undefined) setItemProps(child, `material.${i}.${n}`, value);
247
+ },
248
+ });
249
+ }
250
+ break;
251
+ case 'object':
252
+ // Uniform textures
253
+ if (propValue.value !== undefined && propValue.value.src !== undefined) {
254
+ subChildren.push({
255
+ title: niceMaterialNames(n),
256
+ type: 'image',
257
+ value: propValue.value.src,
258
+ onChange: (prop: string, value: any) => {
259
+ three.createTexture(object.uuid, `material.${i}.${n}.value`, value);
260
+ // Local update
261
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
262
+ if (child !== undefined) {
263
+ textureFromSrc(value).then((texture: Texture) => {
264
+ setItemProps(child, `material.${i}.${n}.value`, texture);
265
+ });
266
+ }
267
+ },
268
+ });
269
+ } else {
270
+ subChildren.push({
271
+ title: n,
272
+ type: `${typeof propValue.value}`,
273
+ value: propValue.value,
274
+ onChange: (prop: string, value: any) => {
275
+ three.updateObject(object.uuid, `material.${i}.${n}.value`, value);
276
+ // Local update
277
+ const child = three.scene?.getObjectByProperty('uuid', object.uuid);
278
+ if (child !== undefined) setItemProps(child, `material.${i}.${n}.value`, value);
279
+ },
280
+ });
281
+ }
282
+ break;
283
+ }
284
+ }
285
+
286
+ if (subChildren.length > 0) {
287
+ items.push({
288
+ title: niceMaterialNames(i),
289
+ items: subChildren,
290
+ });
291
+ }
292
+ }
293
+ } else if (value !== undefined) {
294
+ console.log('other:', i, propType, value);
295
+ }
296
+ }
297
+
298
+ // Sort items
299
+ items.sort((a: any, b: any) => {
300
+ if (a.title < b.title) return -1;
301
+ if (a.title > b.title) return 1;
302
+ return 0;
303
+ });
304
+
305
+ items.push({
306
+ title: 'Update Material',
307
+ type: 'button',
308
+ onChange: () => {
309
+ three.updateObject(object.uuid, `material.needsUpdate`, true);
310
+ },
311
+ });
312
+
313
+ return items;
314
+ }
315
+
316
+ // RemoteMaterial | RemoteMaterial[]
317
+ export function InspectMaterial(object: RemoteObject, three: RemoteThree): any {
318
+ const material = object.material!;
319
+ if (Array.isArray(material)) {
320
+ const items: any[] = [];
321
+ const total = material.length;
322
+ for (let i = 0; i < total; i++) {
323
+ items.push(
324
+ <InspectorGroup
325
+ title={`Material ${i}`}
326
+ items={inspectMaterialItems(material[i], object, three)}
327
+ />
328
+ );
329
+ }
330
+ return <>{items}</>;
331
+ } else {
332
+ return (
333
+ <InspectorGroup
334
+ title="Material"
335
+ items={inspectMaterialItems(material, object, three)}
336
+ />
337
+ );
338
+ }
339
+ return null;
340
+ }