sunrize 1.7.63 → 1.8.0
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.
- package/package.json +4 -4
- package/src/Application/ActionKeys.js +3 -3
- package/src/Application/Application.js +1 -1
- package/src/Application/Dashboard.js +87 -6
- package/src/Application/Document.js +144 -24
- package/src/Application/Hierarchy.js +268 -0
- package/src/Application/Selection.js +6 -6
- package/src/Components/Grouping/StaticGroup.js +1 -1
- package/src/Components/Grouping/Switch.js +34 -0
- package/src/Components/Navigation/Collision.js +70 -0
- package/src/Components/Navigation/LOD.js +34 -0
- package/src/Editors/Library.js +1 -1
- package/src/Editors/OutlineEditor.js +6 -2
- package/src/Editors/OutlineRouteGraph.js +4 -4
- package/src/Editors/OutlineView.js +210 -63
- package/src/Tools/Core/X3DNodeTool.js +2 -0
- package/src/Tools/EnvironmentalSensor/X3DEnvironmentalSensorNodeTool.x3d +1 -0
- package/src/Tools/Geometry2D/Arc2DTool.js +1 -0
- package/src/Tools/Geometry2D/ArcClose2DTool.js +1 -0
- package/src/Tools/Geometry2D/Circle2DTool.js +1 -0
- package/src/Tools/Geometry2D/Disk2DTool.js +2 -0
- package/src/Tools/Geometry2D/Rectangle2DTool.js +1 -0
- package/src/Tools/Geometry3D/BoxTool.js +1 -0
- package/src/Tools/Geometry3D/ConeTool.js +1 -0
- package/src/Tools/Geometry3D/CylinderTool.js +1 -0
- package/src/Tools/Geometry3D/SphereTool.js +1 -0
- package/src/Tools/Grouping/X3DBoundedObjectTool.x3d +28 -12
- package/src/Tools/Grouping/X3DTransformNodeTool.x3d +30 -12
- package/src/Tools/Lighting/X3DLightNodeTool.x3d +1 -0
- package/src/Tools/Navigation/X3DViewpointNodeTool.x3d +1 -0
- package/src/Tools/SnapTool/X3DSnapNodeTool.js +8 -6
- package/src/Tools/Sound/ListenerPointSourceTool.x3d +1 -0
- package/src/Tools/Sound/SoundTool.x3d +5 -0
- package/src/Tools/Sound/SpatialSoundTool.x3d +2 -1
- package/src/Tools/TextureProjection/X3DTextureProjectorNodeTool.x3d +1 -0
- package/src/Undo/Editor.js +1 -1
- package/src/Undo/UndoManager.js +4 -4
- package/src/X3D.js +1 -1
- package/src/assets/themes/default-template.css +6 -0
- package/src/assets/themes/default.css +6 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sunrize",
|
|
3
3
|
"productName": "Sunrize X3D Editor",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.8.0",
|
|
5
5
|
"description": "A Multi-Platform X3D Editor",
|
|
6
6
|
"main": "src/main.js",
|
|
7
7
|
"bin": {
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"capitalize": "^2.0.4",
|
|
92
92
|
"console": "^0.7.2",
|
|
93
|
-
"electron": "^35.1.
|
|
93
|
+
"electron": "^35.1.4",
|
|
94
94
|
"electron-prompt": "^1.7.0",
|
|
95
95
|
"electron-squirrel-startup": "^1.0.1",
|
|
96
96
|
"electron-tabs": "^1.0.4",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"jquery-ui-dist": "^1.13.3",
|
|
100
100
|
"jstree": "^3.3.17",
|
|
101
101
|
"material-icons": "^1.13.14",
|
|
102
|
-
"material-symbols": "^0.29.
|
|
102
|
+
"material-symbols": "^0.29.3",
|
|
103
103
|
"md5": "^2.3.0",
|
|
104
104
|
"mime-types": "^3.0.1",
|
|
105
105
|
"monaco-editor": "^0.50.0",
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
"string-similarity": "^4.0.4",
|
|
110
110
|
"tweakpane": "^3.1.10",
|
|
111
111
|
"update-electron-app": "^3.1.1",
|
|
112
|
-
"x_ite": "^11.5.
|
|
112
|
+
"x_ite": "^11.5.1",
|
|
113
113
|
"x3d-traverse": "^1.0.11"
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -58,7 +58,7 @@ module .exports = new class ActionKeys
|
|
|
58
58
|
if (this .value === value)
|
|
59
59
|
return;
|
|
60
60
|
|
|
61
|
-
this
|
|
61
|
+
this .#processInterests ();
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
onkeyup (event)
|
|
@@ -94,7 +94,7 @@ module .exports = new class ActionKeys
|
|
|
94
94
|
if (this .value === value)
|
|
95
95
|
return;
|
|
96
96
|
|
|
97
|
-
this
|
|
97
|
+
this .#processInterests ();
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
#interests = new Map ();
|
|
@@ -109,7 +109,7 @@ module .exports = new class ActionKeys
|
|
|
109
109
|
this .#interests .delete (key);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
processInterests ()
|
|
112
|
+
#processInterests ()
|
|
113
113
|
{
|
|
114
114
|
for (const callback of this .#interests .values ())
|
|
115
115
|
callback (this .value);
|
|
@@ -9,11 +9,12 @@ const
|
|
|
9
9
|
|
|
10
10
|
module .exports = class Dashboard extends Interface
|
|
11
11
|
{
|
|
12
|
-
constructor (element)
|
|
12
|
+
constructor (element, document)
|
|
13
13
|
{
|
|
14
14
|
super ("Sunrize.Dashboard.");
|
|
15
15
|
|
|
16
|
-
this .
|
|
16
|
+
this .document = document;
|
|
17
|
+
this .toolbar = element;
|
|
17
18
|
|
|
18
19
|
this .setup ();
|
|
19
20
|
}
|
|
@@ -44,12 +45,41 @@ module .exports = class Dashboard extends Interface
|
|
|
44
45
|
|
|
45
46
|
$("<span></span>") .addClass ("separator") .appendTo (this .toolbar);
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
const hierarchy = require ("./Hierarchy");
|
|
49
|
+
|
|
50
|
+
this .upButton = $("<span></span>")
|
|
51
|
+
.addClass (["material-icons", "disabled"])
|
|
52
|
+
.attr ("title", _("Select parent node(s)."))
|
|
53
|
+
.css ({ transform: "rotate(-90deg) scaleX(0.8)", "margin-top": "-6px", "margin-bottom": "-7px" })
|
|
54
|
+
.text ("play_arrow")
|
|
55
|
+
.appendTo (this .toolbar)
|
|
56
|
+
.on ("click", () => this .selectParent ());
|
|
57
|
+
|
|
58
|
+
this .downButton = $("<span></span>")
|
|
59
|
+
.addClass (["material-icons", "disabled"])
|
|
60
|
+
.attr ("title", _("Select child node(s)."))
|
|
61
|
+
.css ({ transform: "rotate(90deg) scaleX(0.8)", "margin-top": "-7px", "margin-bottom": "-6px" })
|
|
62
|
+
.text ("play_arrow")
|
|
63
|
+
.appendTo (this .toolbar)
|
|
64
|
+
.on ("click", () => this .selectChild ());
|
|
65
|
+
|
|
66
|
+
hierarchy .addInterest (this, () => this .onHierarchy ());
|
|
67
|
+
|
|
68
|
+
$("<span></span>") .addClass ("separator") .appendTo (this .toolbar);
|
|
69
|
+
|
|
70
|
+
this .viewSelectedButton = $("<span></span>")
|
|
48
71
|
.addClass (["material-symbols-outlined"])
|
|
49
72
|
.attr ("title", _("Look at selected objects."))
|
|
50
73
|
.text ("center_focus_strong")
|
|
51
74
|
.appendTo (this .toolbar)
|
|
52
|
-
.on ("click", () => this .viewAll ());
|
|
75
|
+
.on ("click", () => this .viewAll (true));
|
|
76
|
+
|
|
77
|
+
this .viewAllButton = $("<span></span>")
|
|
78
|
+
.addClass (["material-symbols-outlined"])
|
|
79
|
+
.attr ("title", _("Look at all objects in active layer."))
|
|
80
|
+
.text ("zoom_out_map")
|
|
81
|
+
.appendTo (this .toolbar)
|
|
82
|
+
.on ("click", () => this .viewAll (false));
|
|
53
83
|
|
|
54
84
|
this .straightenButton = $("<span></span>")
|
|
55
85
|
.addClass (["material-symbols-outlined", "active"])
|
|
@@ -130,13 +160,64 @@ module .exports = class Dashboard extends Interface
|
|
|
130
160
|
this .playButton .removeClass ("active");
|
|
131
161
|
}
|
|
132
162
|
|
|
133
|
-
|
|
163
|
+
selectParent ()
|
|
164
|
+
{
|
|
165
|
+
this .selectHierarchy ("up");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
selectChild ()
|
|
169
|
+
{
|
|
170
|
+
this .selectHierarchy ("down");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
selectHierarchy (direction)
|
|
174
|
+
{
|
|
175
|
+
const
|
|
176
|
+
hierarchy = require ("./Hierarchy"),
|
|
177
|
+
outlineEditor = this .document .sidebar .outlineEditor,
|
|
178
|
+
nodes = hierarchy [direction] ();
|
|
179
|
+
|
|
180
|
+
for (const node of nodes)
|
|
181
|
+
outlineEditor .expandTo (node, { expandObject: true, expandAll: true });
|
|
182
|
+
|
|
183
|
+
const elements = nodes .map (node => outlineEditor .sceneGraph .find (`.node[node-id=${node .getId ()}]`));
|
|
184
|
+
|
|
185
|
+
for (const [i, element] of elements .entries ())
|
|
186
|
+
outlineEditor .selectNodeElement (element, { add: i > 0 });
|
|
187
|
+
|
|
188
|
+
// Scroll element into view.
|
|
189
|
+
// Hide scrollbars during scroll to prevent overlay issue.
|
|
190
|
+
|
|
191
|
+
outlineEditor .treeView .css ("overflow", "hidden");
|
|
192
|
+
|
|
193
|
+
elements [0] ?.[0] ?.scrollIntoView ({ block: "center", inline: "start", behavior: "smooth" });
|
|
194
|
+
$(window) .scrollTop (0);
|
|
195
|
+
|
|
196
|
+
setTimeout (() => outlineEditor .treeView .css ("overflow", ""), 1000);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
onHierarchy ()
|
|
200
|
+
{
|
|
201
|
+
const hierarchy = require ("./Hierarchy");
|
|
202
|
+
|
|
203
|
+
if (hierarchy .canUp ())
|
|
204
|
+
this .upButton .removeClass ("disabled");
|
|
205
|
+
else
|
|
206
|
+
this .upButton .addClass ("disabled");
|
|
207
|
+
|
|
208
|
+
if (hierarchy .canDown ())
|
|
209
|
+
this .downButton .removeClass ("disabled");
|
|
210
|
+
else
|
|
211
|
+
this .downButton .addClass ("disabled");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
viewAll (selected)
|
|
134
215
|
{
|
|
135
216
|
const
|
|
136
217
|
selection = require ("./Selection"),
|
|
137
218
|
nodes = selection .nodes;
|
|
138
219
|
|
|
139
|
-
if (nodes .length)
|
|
220
|
+
if (selected && nodes .length)
|
|
140
221
|
{
|
|
141
222
|
const
|
|
142
223
|
executionContext = this .browser .currentScene,
|
|
@@ -28,9 +28,6 @@ module .exports = class Document extends Interface
|
|
|
28
28
|
{
|
|
29
29
|
super ("Sunrize.Document.");
|
|
30
30
|
|
|
31
|
-
// Add X3D to window to provide access in Script nodes.
|
|
32
|
-
window .X3D = X3D;
|
|
33
|
-
|
|
34
31
|
// Globals
|
|
35
32
|
|
|
36
33
|
this .config .global .setDefaultValues ({
|
|
@@ -41,7 +38,7 @@ module .exports = class Document extends Interface
|
|
|
41
38
|
|
|
42
39
|
this .verticalSplitter = new Splitter ($("#vertical-splitter"), "vertical");
|
|
43
40
|
this .horizontalSplitter = new Splitter ($("#horizontal-splitter"), "horizontal");
|
|
44
|
-
this .secondaryToolbar = new Dashboard ($("#secondary-toolbar"));
|
|
41
|
+
this .secondaryToolbar = new Dashboard ($("#secondary-toolbar"), this);
|
|
45
42
|
this .footer = new Footer ($("#footer"));
|
|
46
43
|
this .sidebar = new Sidebar ($("#sidebar"));
|
|
47
44
|
|
|
@@ -166,9 +163,10 @@ module .exports = class Document extends Interface
|
|
|
166
163
|
|
|
167
164
|
// Connect for Snap Target and Snap Source.
|
|
168
165
|
|
|
169
|
-
$(this .browser .element
|
|
166
|
+
$(this .browser .element)
|
|
170
167
|
.on ("mousedown", event => this .onmousedown (event))
|
|
171
|
-
.on ("mouseup", event => this .
|
|
168
|
+
.on ("mouseup", event => this .onsnaptool (event))
|
|
169
|
+
.on ("mouseup", event => this .onselect (event));
|
|
172
170
|
|
|
173
171
|
// Load components.
|
|
174
172
|
|
|
@@ -178,6 +176,9 @@ module .exports = class Document extends Interface
|
|
|
178
176
|
// Modify nodes.
|
|
179
177
|
|
|
180
178
|
this .browser .updateConcreteNode (require ("../Components/Grouping/StaticGroup"));
|
|
179
|
+
this .browser .updateConcreteNode (require ("../Components/Grouping/Switch"));
|
|
180
|
+
this .browser .updateConcreteNode (require ("../Components/Navigation/Collision"));
|
|
181
|
+
this .browser .updateConcreteNode (require ("../Components/Navigation/LOD"));
|
|
181
182
|
|
|
182
183
|
require ("../Components");
|
|
183
184
|
|
|
@@ -939,48 +940,79 @@ Viewpoint {
|
|
|
939
940
|
}
|
|
940
941
|
}
|
|
941
942
|
|
|
943
|
+
#select = false;
|
|
944
|
+
#pointer = new X3D .Vector2 ();
|
|
942
945
|
#snapTarget = null;
|
|
943
946
|
#snapSource = null;
|
|
944
947
|
|
|
945
948
|
async onmousedown (event)
|
|
946
949
|
{
|
|
947
|
-
|
|
950
|
+
this .#select = false;
|
|
951
|
+
|
|
952
|
+
if (!this .secondaryToolbar .arrowButton .hasClass ("active"))
|
|
948
953
|
return;
|
|
949
954
|
|
|
950
|
-
switch (
|
|
955
|
+
switch (event .button)
|
|
951
956
|
{
|
|
952
|
-
case
|
|
957
|
+
case 0:
|
|
953
958
|
{
|
|
954
|
-
if (
|
|
955
|
-
|
|
959
|
+
if (event .shiftKey && (event .ctrlKey || event .metaKey))
|
|
960
|
+
return;
|
|
956
961
|
|
|
957
|
-
this .
|
|
962
|
+
this .#pointer .assign (this .browser .getPointerFromEvent (event));
|
|
958
963
|
|
|
959
|
-
|
|
964
|
+
if (this .browser .touch (... this .#pointer))
|
|
965
|
+
{
|
|
966
|
+
if (this .browser .getHit () .sensors .size)
|
|
967
|
+
return;
|
|
968
|
+
|
|
969
|
+
this .#select = true;
|
|
970
|
+
}
|
|
971
|
+
else
|
|
972
|
+
{
|
|
973
|
+
this .#select = true;
|
|
974
|
+
}
|
|
960
975
|
|
|
961
|
-
this .#snapTarget .onmousedown (event, true);
|
|
962
976
|
break;
|
|
963
977
|
}
|
|
964
|
-
case
|
|
978
|
+
case 2:
|
|
965
979
|
{
|
|
966
|
-
|
|
967
|
-
|
|
980
|
+
switch (ActionKeys .value)
|
|
981
|
+
{
|
|
982
|
+
case ActionKeys .None:
|
|
983
|
+
{
|
|
984
|
+
if (this .#snapTarget ?._visible .getValue ())
|
|
985
|
+
break;
|
|
986
|
+
|
|
987
|
+
this .activateSnapTarget (true);
|
|
968
988
|
|
|
969
|
-
|
|
989
|
+
await this .#snapTarget .getToolInstance ();
|
|
970
990
|
|
|
971
|
-
|
|
991
|
+
this .#snapTarget .onmousedown (event, true);
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
case ActionKeys .Option:
|
|
995
|
+
{
|
|
996
|
+
if (this .#snapSource ?._visible .getValue ())
|
|
997
|
+
break;
|
|
998
|
+
|
|
999
|
+
this .activateSnapSource (true);
|
|
1000
|
+
|
|
1001
|
+
await this .#snapSource .getToolInstance ();
|
|
1002
|
+
|
|
1003
|
+
this .#snapSource .onmousedown (event, true);
|
|
1004
|
+
break;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
972
1007
|
|
|
973
|
-
this .#snapSource .onmousedown (event, true);
|
|
974
1008
|
break;
|
|
975
1009
|
}
|
|
976
1010
|
}
|
|
1011
|
+
|
|
977
1012
|
}
|
|
978
1013
|
|
|
979
|
-
async
|
|
1014
|
+
async onsnaptool (event)
|
|
980
1015
|
{
|
|
981
|
-
if (ActionKeys .value & ActionKeys .Control)
|
|
982
|
-
event .button = 2;
|
|
983
|
-
|
|
984
1016
|
if (event .button !== 2)
|
|
985
1017
|
return;
|
|
986
1018
|
|
|
@@ -991,6 +1023,94 @@ Viewpoint {
|
|
|
991
1023
|
this .#snapTarget ?.onmouseup (event);
|
|
992
1024
|
}
|
|
993
1025
|
|
|
1026
|
+
onselect (event)
|
|
1027
|
+
{
|
|
1028
|
+
if (!this .secondaryToolbar .arrowButton .hasClass ("active"))
|
|
1029
|
+
return;
|
|
1030
|
+
|
|
1031
|
+
if (event .button !== 0)
|
|
1032
|
+
return;
|
|
1033
|
+
|
|
1034
|
+
if (!this .#select)
|
|
1035
|
+
return;
|
|
1036
|
+
|
|
1037
|
+
const pointer = this .browser .getPointerFromEvent (event);
|
|
1038
|
+
|
|
1039
|
+
if (this .#pointer .distance (pointer) > this .browser .getRenderingProperty ("ContentScale"))
|
|
1040
|
+
return;
|
|
1041
|
+
|
|
1042
|
+
// Stop event propagation.
|
|
1043
|
+
|
|
1044
|
+
event .preventDefault ();
|
|
1045
|
+
|
|
1046
|
+
// Select or deselect.
|
|
1047
|
+
|
|
1048
|
+
const outlineEditor = this .sidebar .outlineEditor;
|
|
1049
|
+
|
|
1050
|
+
if (!this .browser .touch (... pointer))
|
|
1051
|
+
{
|
|
1052
|
+
outlineEditor .deselectAll ();
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// Select.
|
|
1057
|
+
|
|
1058
|
+
const
|
|
1059
|
+
shapeNode = this .browser .getHit () .shapeNode,
|
|
1060
|
+
geometryTool = shapeNode .getGeometry () ?.getTool (),
|
|
1061
|
+
tool = geometryTool ?? shapeNode .getExecutionContext () .getOuterNode () ?.getTool (),
|
|
1062
|
+
node = tool ?? shapeNode;
|
|
1063
|
+
|
|
1064
|
+
outlineEditor .expandTo (node, { expandObject: true, expandAll: true });
|
|
1065
|
+
|
|
1066
|
+
let elements = outlineEditor .sceneGraph .find (`.node[node-id=${node .getId ()}]`);
|
|
1067
|
+
|
|
1068
|
+
if (!elements .length)
|
|
1069
|
+
return;
|
|
1070
|
+
|
|
1071
|
+
if (outlineEditor .isEditable (elements))
|
|
1072
|
+
{
|
|
1073
|
+
if (tool)
|
|
1074
|
+
{
|
|
1075
|
+
elements = Array .from (elements);
|
|
1076
|
+
}
|
|
1077
|
+
else
|
|
1078
|
+
{
|
|
1079
|
+
const parentElements = Array .from (elements) .flatMap (element =>
|
|
1080
|
+
{
|
|
1081
|
+
const parentElements = Array .from ($(element) .parent () .closest (".node", outlineEditor .sceneGraph));
|
|
1082
|
+
|
|
1083
|
+
return parentElements .length ? parentElements : element;
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
elements = parentElements .map ((element, i) => outlineEditor .getNode ($(element)) .getType () .includes (X3D .X3DConstants .X3DGroupingNode) ? parentElements [i] : elements [i]);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
else
|
|
1090
|
+
{
|
|
1091
|
+
while (!outlineEditor .isEditable (elements))
|
|
1092
|
+
{
|
|
1093
|
+
elements .jstree ("close_node", elements);
|
|
1094
|
+
elements = elements .parent () .closest (".node, .scene", outlineEditor .sceneGraph);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
elements = Array .from (elements);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
for (const [i, element] of elements .entries ())
|
|
1101
|
+
outlineEditor .selectNodeElement ($(element), { add: (event .shiftKey || event .metaKey) || i > 0, target: true });
|
|
1102
|
+
|
|
1103
|
+
// Scroll element into view.
|
|
1104
|
+
// Hide scrollbars during scroll to prevent overlay issue.
|
|
1105
|
+
|
|
1106
|
+
outlineEditor .treeView .css ("overflow", "hidden");
|
|
1107
|
+
|
|
1108
|
+
elements [0] ?.scrollIntoView ({ block: "center", inline: "start", behavior: "smooth" });
|
|
1109
|
+
$(window) .scrollTop (0);
|
|
1110
|
+
|
|
1111
|
+
setTimeout (() => outlineEditor .treeView .css ("overflow", ""), 1000);
|
|
1112
|
+
}
|
|
1113
|
+
|
|
994
1114
|
activateSnapTarget (visible)
|
|
995
1115
|
{
|
|
996
1116
|
const SnapTarget = require ("../Tools/SnapTool/SnapTarget");
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
const
|
|
2
|
+
X3D = require ("../X3D"),
|
|
3
|
+
Interface = require ("./Interface"),
|
|
4
|
+
Traverse = require ("x3d-traverse") (X3D);
|
|
5
|
+
|
|
6
|
+
module .exports = new class Hierarchy extends Interface
|
|
7
|
+
{
|
|
8
|
+
#target = null;
|
|
9
|
+
#nodes = [ ];
|
|
10
|
+
#hierarchies = [ ];
|
|
11
|
+
|
|
12
|
+
constructor ()
|
|
13
|
+
{
|
|
14
|
+
super ("Sunrize.Hierarchy.");
|
|
15
|
+
|
|
16
|
+
this .setup ();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
configure ()
|
|
20
|
+
{
|
|
21
|
+
this .executionContext ?.sceneGraph_changed .removeInterest ("update", this);
|
|
22
|
+
|
|
23
|
+
this .executionContext = this .browser .currentScene;
|
|
24
|
+
|
|
25
|
+
this .executionContext .sceneGraph_changed .addInterest ("update", this);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
update ()
|
|
29
|
+
{
|
|
30
|
+
const
|
|
31
|
+
target = this .#target,
|
|
32
|
+
nodes = this .#nodes;
|
|
33
|
+
|
|
34
|
+
this .target (target ?.isLive () ? target : null);
|
|
35
|
+
nodes .forEach (node => this .add (node));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#targetTypes = new Set ([
|
|
39
|
+
X3D .X3DConstants .X3DShapeNode,
|
|
40
|
+
X3D .X3DConstants .Inline,
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
target (node)
|
|
44
|
+
{
|
|
45
|
+
node = node ?.valueOf () ?? null;
|
|
46
|
+
|
|
47
|
+
this .#target = node;
|
|
48
|
+
this .#nodes = [ ];
|
|
49
|
+
|
|
50
|
+
if (!node)
|
|
51
|
+
{
|
|
52
|
+
this .#hierarchies = [ ];
|
|
53
|
+
}
|
|
54
|
+
else if (!node .getType () .includes (X3D .X3DConstants .X3DShapeNode))
|
|
55
|
+
{
|
|
56
|
+
this .#hierarchies = [ ];
|
|
57
|
+
|
|
58
|
+
let flags = Traverse .NONE;
|
|
59
|
+
|
|
60
|
+
flags |= Traverse .PROTO_DECLARATIONS;
|
|
61
|
+
flags |= Traverse .PROTO_DECLARATION_BODY;
|
|
62
|
+
flags |= Traverse .ROOT_NODES;
|
|
63
|
+
|
|
64
|
+
for (const object of Traverse .traverse (node, flags))
|
|
65
|
+
{
|
|
66
|
+
if (!(object instanceof X3D .SFNode))
|
|
67
|
+
continue;
|
|
68
|
+
|
|
69
|
+
const node = object .getValue () .valueOf ();
|
|
70
|
+
|
|
71
|
+
if (!node .getType () .some (type => this .#targetTypes .has (type)))
|
|
72
|
+
continue;
|
|
73
|
+
|
|
74
|
+
const target = node .getGeometry ?.() ?.valueOf () ?? node;
|
|
75
|
+
|
|
76
|
+
for (const hierarchy of this .#find (target))
|
|
77
|
+
this .#hierarchies .push (hierarchy);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!this .#hierarchies .length)
|
|
81
|
+
this .#hierarchies = this .#find (node);
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
{
|
|
85
|
+
const target = node .getType () .includes (X3D .X3DConstants .X3DShapeNode)
|
|
86
|
+
? node .getGeometry () ?.valueOf () ?? node
|
|
87
|
+
: node;
|
|
88
|
+
|
|
89
|
+
this .#hierarchies = this .#find (target);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this .#processInterests ();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
set (node)
|
|
96
|
+
{
|
|
97
|
+
node = node ?.valueOf () ?? null;
|
|
98
|
+
|
|
99
|
+
if (!this .#has (node))
|
|
100
|
+
return;
|
|
101
|
+
|
|
102
|
+
this .#nodes = [node];
|
|
103
|
+
|
|
104
|
+
this .#processInterests ();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
add (node)
|
|
108
|
+
{
|
|
109
|
+
node = node ?.valueOf () ?? null;
|
|
110
|
+
|
|
111
|
+
if (!this .#has (node))
|
|
112
|
+
return;
|
|
113
|
+
|
|
114
|
+
if (this .#nodes .includes (node))
|
|
115
|
+
return;
|
|
116
|
+
|
|
117
|
+
this .#nodes .push (node);
|
|
118
|
+
|
|
119
|
+
this .#processInterests ();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
remove (node)
|
|
123
|
+
{
|
|
124
|
+
node = node ?.valueOf () ?? null;
|
|
125
|
+
|
|
126
|
+
this .#nodes = this .#nodes .filter (n => n !== node);
|
|
127
|
+
|
|
128
|
+
this .#processInterests ();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
clear ()
|
|
132
|
+
{
|
|
133
|
+
this .#target = null;
|
|
134
|
+
this .#nodes = [ ];
|
|
135
|
+
this .#hierarchies = [ ];
|
|
136
|
+
|
|
137
|
+
this .#processInterests ();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
#find (target)
|
|
141
|
+
{
|
|
142
|
+
if (!target)
|
|
143
|
+
return [ ];
|
|
144
|
+
|
|
145
|
+
// Find target node.
|
|
146
|
+
|
|
147
|
+
let flags = Traverse .NONE;
|
|
148
|
+
|
|
149
|
+
flags |= Traverse .PROTO_DECLARATIONS;
|
|
150
|
+
flags |= Traverse .PROTO_DECLARATION_BODY;
|
|
151
|
+
flags |= Traverse .ROOT_NODES;
|
|
152
|
+
|
|
153
|
+
return Array .from (this .executionContext .find (target, flags),
|
|
154
|
+
hierarchy => hierarchy .filter (object => object instanceof X3D .SFNode)
|
|
155
|
+
.map (node => node .getValue () .valueOf ()));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
#has (node)
|
|
159
|
+
{
|
|
160
|
+
return this .#hierarchies .some (hierarchy => hierarchy .includes (node));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#indices (node)
|
|
164
|
+
{
|
|
165
|
+
return this .#hierarchies .map (hierarchy => hierarchy .indexOf (node));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
up ()
|
|
169
|
+
{
|
|
170
|
+
this .#nodes = this .#nodes .flatMap (node => this .#indices (node) .map (index =>
|
|
171
|
+
{
|
|
172
|
+
return index - 1 >= 0 ? index - 1 : index;
|
|
173
|
+
})
|
|
174
|
+
.map ((index, i) => this .#hierarchies [i] [index])
|
|
175
|
+
.filter (node => node));
|
|
176
|
+
|
|
177
|
+
this .#nodes = Array .from (new Set (this .#nodes));
|
|
178
|
+
|
|
179
|
+
// Combine to most highest node.
|
|
180
|
+
|
|
181
|
+
const indices = Array .from (this .#hierarchies, hierarchy => hierarchy .length);
|
|
182
|
+
|
|
183
|
+
for (const node of this .#nodes)
|
|
184
|
+
{
|
|
185
|
+
for (const [i, index] of this .#indices (node) .entries ())
|
|
186
|
+
{
|
|
187
|
+
if (index < 0)
|
|
188
|
+
continue;
|
|
189
|
+
|
|
190
|
+
indices [i] = Math .min (indices [i], index);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this .#nodes = indices .map ((index, i) => this .#hierarchies [i] [index]) .filter (node => node);
|
|
195
|
+
this .#nodes = Array .from (new Set (this .#nodes));
|
|
196
|
+
|
|
197
|
+
// Propagate change.
|
|
198
|
+
|
|
199
|
+
this .#processInterests ();
|
|
200
|
+
|
|
201
|
+
return this .#nodes;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
down ()
|
|
205
|
+
{
|
|
206
|
+
this .#nodes = this .#nodes .flatMap (node => this .#indices (node) .map ((index, i) =>
|
|
207
|
+
{
|
|
208
|
+
return index >= 0 && index + 1 < this .#hierarchies [i] .length ? index + 1 : index;
|
|
209
|
+
})
|
|
210
|
+
.map ((index, i) => this .#hierarchies [i] [index])
|
|
211
|
+
.filter (node => node));
|
|
212
|
+
|
|
213
|
+
this .#nodes = Array .from (new Set (this .#nodes));
|
|
214
|
+
|
|
215
|
+
// Combine to most lowest node.
|
|
216
|
+
|
|
217
|
+
const indices = Array .from (this .#hierarchies, () => -1);
|
|
218
|
+
|
|
219
|
+
for (const node of this .#nodes)
|
|
220
|
+
{
|
|
221
|
+
for (const [i, index] of this .#indices (node) .entries ())
|
|
222
|
+
{
|
|
223
|
+
if (index < 0)
|
|
224
|
+
continue;
|
|
225
|
+
|
|
226
|
+
indices [i] = Math .max (indices [i], index);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
this .#nodes = indices .map ((index, i) => this .#hierarchies [i] [index]) .filter (node => node);
|
|
231
|
+
this .#nodes = Array .from (new Set (this .#nodes));
|
|
232
|
+
|
|
233
|
+
// Propagate change.
|
|
234
|
+
|
|
235
|
+
this .#processInterests ();
|
|
236
|
+
|
|
237
|
+
return this .#nodes;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
canUp ()
|
|
241
|
+
{
|
|
242
|
+
return this .#nodes .some (node => this .#indices (node) .some (index => index > 0));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
canDown ()
|
|
246
|
+
{
|
|
247
|
+
return this .#nodes .some (node => this .#indices (node)
|
|
248
|
+
.some ((index, i) => index >= 0 && index < this .#hierarchies [i] .length - 1));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
#interest = new Map ();
|
|
252
|
+
|
|
253
|
+
addInterest (key, callback)
|
|
254
|
+
{
|
|
255
|
+
this .#interest .set (key, callback);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
removeInterest (key)
|
|
259
|
+
{
|
|
260
|
+
this .#interest .delete (key);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
#processInterests ()
|
|
264
|
+
{
|
|
265
|
+
for (const callback of this .#interest .values ())
|
|
266
|
+
callback (this .nodes);
|
|
267
|
+
}
|
|
268
|
+
}
|