sunrize 2.0.3 → 2.0.5

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.
@@ -3,14 +3,19 @@
3
3
  const
4
4
  $ = require ("jquery"),
5
5
  X3D = require ("../X3D"),
6
- LibraryPane = require ("./LibraryPane");
6
+ LibraryPane = require ("./LibraryPane"),
7
+ _ = require ("../Application/GetText");
7
8
 
8
9
  module .exports = class Materials extends LibraryPane
9
10
  {
10
11
  id = "MATERIALS";
11
12
  description = "Materials";
12
13
 
14
+ #scene;
13
15
  #list;
16
+ #physicalButton;
17
+ #cancelRendering;
18
+ #rendering;
14
19
 
15
20
  async update ()
16
21
  {
@@ -33,9 +38,29 @@ module .exports = class Materials extends LibraryPane
33
38
  browser = canvas .prop ("browser"),
34
39
  scene = await browser .createX3DFromURL (new X3D .MFString (`file://${__dirname}/Materials.x3d`));
35
40
 
41
+ // Buttons
42
+
43
+ const buttons = $("<li></li>")
44
+ .appendTo (this .#list);
45
+
46
+ this .#physicalButton = $("<input></input>")
47
+ .attr ("title", _("Requires an EnvironmentLight node."))
48
+ .attr ("type", "checkbox")
49
+ .attr ("id", "use-physical-material")
50
+ .prop ("checked", this .config .global .convertToPhysical)
51
+ .on ("change", () => this .#rendering = this .onChangeMaterials ())
52
+ .appendTo (buttons);
53
+
54
+ $("<label></label>")
55
+ .attr ("title", _("Requires an EnvironmentLight node."))
56
+ .attr ("for", "use-physical-material")
57
+ .text (_("Create Physical Material"))
58
+ .appendTo (buttons);
59
+
60
+ // Materials
61
+
36
62
  const
37
63
  materials = scene .getExportedNode ("Materials"),
38
- viewpoint = scene .getExportedNode ("Viewpoint"),
39
64
  nodes = [ ];
40
65
 
41
66
  for (const [g, group] of materials .children .entries ())
@@ -51,16 +76,53 @@ module .exports = class Materials extends LibraryPane
51
76
 
52
77
  nodes .push ($("<li></li>")
53
78
  .addClass (["node", "icon"])
79
+ .attr ("title", material .getNodeDisplayName ())
54
80
  .attr ("group", g)
55
81
  .attr ("child", c)
56
82
  .append ($("<span></span>")
57
83
  .addClass ("text")
58
84
  .text (`${group .getNodeName ()} ${c + 1}`))
59
85
  .appendTo (this .#list)
60
- .on ("dblclick", () => this .importX3D (material .getNodeName (), material .toXMLString ())));
86
+ .on ("click", () => this .importMaterial (material .getNodeName ())));
61
87
  }
62
88
  }
63
89
 
90
+ browser .dispose ();
91
+ canvas .remove ();
92
+
93
+ this .#rendering = this .onChangeMaterials ();
94
+ }
95
+
96
+ importMaterial (name)
97
+ {
98
+ const material = this .#scene .getNamedNode (name);
99
+
100
+ this .importX3D (material .getNodeName (), material .toXMLString ());
101
+ }
102
+
103
+ async onChangeMaterials ()
104
+ {
105
+ this .#cancelRendering = true;
106
+
107
+ await this .#rendering;
108
+
109
+ this .#cancelRendering = false;
110
+
111
+ this .config .global .convertToPhysical = this .#physicalButton .is (":checked");
112
+
113
+ const
114
+ canvas = $("<x3d-canvas preserveDrawingBuffer='true' xrSessionMode='NONE'></x3d-canvas>"),
115
+ browser = canvas .prop ("browser"),
116
+ scene = await browser .createX3DFromURL (new X3D .MFString (`file://${__dirname}/Materials.x3d`));
117
+
118
+ scene .addComponent (browser .getComponent ("X_ITE"));
119
+
120
+ this .#scene = scene;
121
+
122
+ const
123
+ materials = scene .getExportedNode ("Materials"),
124
+ viewpoint = scene .getExportedNode ("Viewpoint");
125
+
64
126
  // Create icons.
65
127
 
66
128
  canvas
@@ -72,11 +134,26 @@ module .exports = class Materials extends LibraryPane
72
134
 
73
135
  for (const element of Array .from (this .output .find (".node"), e => $(e)))
74
136
  {
137
+ if (this .#cancelRendering)
138
+ break;
139
+
75
140
  const
76
- group = element .attr ("group"),
77
- child = element .attr ("child"),
78
- section = materials .children [group],
79
- node = section .children [child];
141
+ group = element .attr ("group"),
142
+ child = element .attr ("child"),
143
+ section = materials .children [group],
144
+ node = section .children [child],
145
+ appearance = node .children [0] .appearance;
146
+
147
+ if (this .config .global .convertToPhysical)
148
+ {
149
+ const material = this .convertPhongToPhysical (scene, appearance .material);
150
+
151
+ scene .updateNamedNode (appearance .material .getNodeName (), material);
152
+
153
+ appearance .material = material;
154
+ }
155
+
156
+ // console .log (appearance .material .getNodeName ());
80
157
 
81
158
  materials .whichChoice = group;
82
159
  section .whichChoice = child;
@@ -93,4 +170,49 @@ module .exports = class Materials extends LibraryPane
93
170
  browser .dispose ();
94
171
  canvas .remove ();
95
172
  }
173
+
174
+ convertPhongToPhysical (executionContext, phong)
175
+ {
176
+ let
177
+ physical = executionContext .createNode ("PhysicalMaterial"),
178
+ baseColor = phong .diffuseColor .sRGBToLinear (),
179
+ specularColor = phong .specularColor .sRGBToLinear (),
180
+ specularIntensity = Math .max (... specularColor),
181
+ metallic = Math .min (Math .max ((specularIntensity - 0.04) / (1.0 - 0.04), 0), 1) * 0.5,
182
+ roughness = 1 - phong .shininess,
183
+ emissiveColor = phong .emissiveColor .sRGBToLinear (),
184
+ transparency = phong .transparency,
185
+ transmission = transparency ** (1/3);
186
+
187
+ if ([... specularColor] .some (Boolean) && roughness)
188
+ {
189
+ const specularMaterial = executionContext .createNode ("SpecularMaterialExtension");
190
+
191
+ specularMaterial .specularColor = specularColor;
192
+ specularMaterial .specularStrength = 10 * roughness;
193
+
194
+ physical .extensions .push (specularMaterial);
195
+
196
+ metallic *= 0.1;
197
+ roughness *= 0.5;
198
+ }
199
+
200
+ if (transparency)
201
+ {
202
+ const transmissionMaterial = executionContext .createNode ("TransmissionMaterialExtension");
203
+
204
+ transmissionMaterial .transmission = transmission;
205
+
206
+ physical .extensions .push (transmissionMaterial);
207
+
208
+ roughness *= 0.5 * (1 - transparency);
209
+ }
210
+
211
+ physical .baseColor = baseColor;
212
+ physical .metallic = metallic;
213
+ physical .roughness = roughness;
214
+ physical .emissiveColor = emissiveColor;
215
+
216
+ return physical;
217
+ }
96
218
  };
@@ -77,7 +77,7 @@ module .exports = class NodesLibrary extends LibraryPane
77
77
  .text (node .typeName)
78
78
  .attr ("componentName", node .componentInfo .name)
79
79
  .appendTo (this .#list)
80
- .on ("dblclick", () => this .createNode (node .typeName, node .componentInfo .name));
80
+ .on ("click", () => this .createNode (node .typeName, node .componentInfo .name));
81
81
  }
82
82
  }
83
83
 
@@ -97,7 +97,7 @@ module .exports = class NodesLibrary extends LibraryPane
97
97
  .addClass ("node")
98
98
  .text (proto .name)
99
99
  .appendTo (this .#list)
100
- .on ("dblclick", () => this .createProto (proto));
100
+ .on ("click", () => this .createProto (proto));
101
101
  }
102
102
  }
103
103
 
@@ -123,7 +123,7 @@ module .exports = class NodesLibrary extends LibraryPane
123
123
  .text (node .typeName)
124
124
  .attr ("componentName", node .componentInfo .name)
125
125
  .appendTo (this .#list)
126
- .on ("dblclick", () => this .createNode (node .typeName, node .componentInfo .name));
126
+ .on ("click", () => this .createNode (node .typeName, node .componentInfo .name));
127
127
  }
128
128
  }
129
129
 
@@ -29,7 +29,10 @@ module .exports = new class Panel extends Interface
29
29
  "top": "unset",
30
30
  });
31
31
 
32
- this .container .on ("mousedown", event => this .onmousedown (event));
32
+ this .container
33
+ .on ("mouseenter", event => this .onmouseenter (event))
34
+ .on ("mouseleave", event => this .onmouseleave (event))
35
+ .on ("mousedown", event => this .onmousedown (event));
33
36
 
34
37
  this .browser .getBrowserOptions () ._ColorSpace .addFieldCallback ("Panel", () => this .updateNode ());
35
38
 
@@ -65,6 +68,16 @@ module .exports = new class Panel extends Interface
65
68
  this .container .hide (300, () => this .removeNode (this .node));
66
69
  }
67
70
 
71
+ onmouseenter ()
72
+ {
73
+ this .hovered = true;
74
+ }
75
+
76
+ onmouseleave ()
77
+ {
78
+ this .hovered = false;
79
+ }
80
+
68
81
  onmousedown (event)
69
82
  {
70
83
  $(document) .on ("mouseup.Panel", () => this .onmouseup ());
@@ -415,6 +428,9 @@ module .exports = new class Panel extends Interface
415
428
 
416
429
  field .addFieldCallback (this, () =>
417
430
  {
431
+ if (this .changing)
432
+ return;
433
+
418
434
  this .refresh (parameter, node, field);
419
435
  input .refresh ();
420
436
  });
@@ -474,6 +490,9 @@ module .exports = new class Panel extends Interface
474
490
 
475
491
  field .addFieldCallback (this, () =>
476
492
  {
493
+ if (this .changing)
494
+ return;
495
+
477
496
  this .refresh (parameter, node, field);
478
497
  textarea .val (parameter [field .getName ()]);
479
498
  });
@@ -647,6 +666,13 @@ module .exports = new class Panel extends Interface
647
666
  executionContext = node .getExecutionContext (),
648
667
  category = field .getUnit ();
649
668
 
669
+ if (!(this .hovered || this .container .find (":focus") .length))
670
+ return;
671
+
672
+ this .changing = true;
673
+
674
+ this .browser .nextFrame () .then (() => this .changing = false);
675
+
650
676
  switch (field .getType ())
651
677
  {
652
678
  case X3D .X3DConstants .SFBool:
@@ -446,7 +446,7 @@ DEF ScreenText Transform {
446
446
  componentInfo: { name: "Lighting" },
447
447
  typeName: "EnvironmentLight Cannon Exterior",
448
448
  x3dSyntax: `
449
- EnvironmentLight {
449
+ DEF CannonExterior EnvironmentLight {
450
450
  specularTexture ImageCubeMapTexture {
451
451
  url "https://cdn.jsdelivr.net/npm/x3d-image@2.2.0/src/images/cannon-exterior.avif"
452
452
  }
@@ -457,7 +457,7 @@ EnvironmentLight {
457
457
  componentInfo: { name: "Lighting" },
458
458
  typeName: "EnvironmentLight Helipad",
459
459
  x3dSyntax: `
460
- EnvironmentLight {
460
+ DEF Helipad EnvironmentLight {
461
461
  specularTexture ImageCubeMapTexture {
462
462
  url "https://cdn.jsdelivr.net/npm/x3d-image@2.2.0/src/images/helipad.avif"
463
463
  }
@@ -468,7 +468,7 @@ EnvironmentLight {
468
468
  componentInfo: { name: "Lighting" },
469
469
  typeName: "EnvironmentLight Footprint Court",
470
470
  x3dSyntax: `
471
- EnvironmentLight {
471
+ DEF FootprintCourt EnvironmentLight {
472
472
  specularTexture ImageCubeMapTexture {
473
473
  url "https://cdn.jsdelivr.net/npm/x3d-image@2.2.0/src/images/footprint-court.avif"
474
474
  }
@@ -67,7 +67,7 @@ module .exports = class PrimitivesLibrary extends LibraryPane
67
67
  .addClass ("node")
68
68
  .text (typeName)
69
69
  .appendTo (this .#list)
70
- .on ("dblclick", () => this .createRecentNode (nodes, typeName));
70
+ .on ("click", () => this .createRecentNode (nodes, typeName));
71
71
  }
72
72
  }
73
73
 
@@ -91,7 +91,7 @@ module .exports = class PrimitivesLibrary extends LibraryPane
91
91
  .addClass ("node")
92
92
  .text (node .typeName)
93
93
  .appendTo (this .#list)
94
- .on ("dblclick", () => this .createNode (node));
94
+ .on ("click", () => this .createNode (node));
95
95
  }
96
96
  }
97
97
 
@@ -616,6 +616,9 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
616
616
  }
617
617
  }
618
618
 
619
+ if (node ._url .equals (newURL))
620
+ return;
621
+
619
622
  const uniqueURL = new X3D .MFString (... new Set (newURL));
620
623
 
621
624
  this .setFieldValue (executionContext, node, node ._url, uniqueURL, undoManager);
@@ -675,16 +678,19 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
675
678
  */
676
679
  static getUsedComponents (scene)
677
680
  {
678
- const components = new Set ();
681
+ const components = new Map ();
679
682
 
680
683
  for (const object of scene .traverse (Traverse .PROTO_DECLARATIONS | Traverse .PROTO_DECLARATION_BODY | Traverse .ROOT_NODES | Traverse .PROTOTYPE_INSTANCES))
681
684
  {
682
685
  if (!(object instanceof X3D .SFNode))
683
686
  continue;
684
687
 
685
- const node = object .getValue ();
688
+ const
689
+ node = object .getValue (),
690
+ componentInfo = node .getComponentInfo ();
686
691
 
687
- components .add (node .getComponentInfo () .name);
692
+ if (components .get (componentInfo .name) ?? 0 < componentInfo .level)
693
+ components .set (componentInfo .name, componentInfo .level);
688
694
  }
689
695
 
690
696
  return components;
@@ -692,31 +698,46 @@ ${scene .toXMLString ({ html: true, indent: " " .repeat (6) }) .trimEnd () }
692
698
 
693
699
  static getProfileAndComponentsFromUsedComponents (browser, usedComponents)
694
700
  {
695
- const profiles = ["Interactive", "Interchange", "Immersive", "Full"] .map (name =>
701
+ const profiles = ["Interchange", "Interactive", "Immersive", "Full"] .map (name =>
696
702
  {
697
- return { profile: browser .getProfile (name), components: new Set (usedComponents) };
703
+ return { profile: browser .getProfile (name), components: new Map (usedComponents) };
698
704
  });
699
705
 
700
- profiles .forEach (object =>
706
+ profiles .forEach (({ profile, components }) =>
701
707
  {
702
- for (const component of object .profile .components)
703
- object .components .delete (component .name);
708
+ for (const component of profile .components)
709
+ {
710
+ const level = components .get (component .name);
711
+
712
+ if (level === undefined)
713
+ continue;
714
+
715
+ if (level > component .level)
716
+ continue;
717
+
718
+ components .delete (component .name);
719
+ }
704
720
  });
705
721
 
706
- const min = profiles .reduce ((min, object) =>
722
+ const { object } = profiles .reduce ((min, object) =>
707
723
  {
708
- const count = object .profile .components .length + object .components .size;
724
+ const count = new Set ([
725
+ ... [... object .profile .components] .map (component => component .name),
726
+ ... object .components .keys ()
727
+ ]) .size;
709
728
 
710
729
  return min .count < count ? min : {
711
- count: count,
712
- object: object,
730
+ count,
731
+ object,
713
732
  };
714
733
  },
715
734
  { count: Number .POSITIVE_INFINITY });
716
735
 
717
736
  return {
718
- profile: min .object .profile,
719
- components: Array .from (min .object .components) .sort () .map (name => browser .getSupportedComponents () .get (name)),
737
+ profile: object .profile,
738
+ components: Array .from (object .components .keys ())
739
+ .sort ()
740
+ .map (name => browser .getComponent (name, object .components .get (name))),
720
741
  };
721
742
  }
722
743
 
@@ -895,6 +895,10 @@ body.dark .ui-widget .library-list .component {
895
895
  background-position: 50%;
896
896
  }
897
897
 
898
+ .library-list.materials .icon:hover {
899
+ border: 1px solid light-dark(var(--system-gray0), var(--system-gray2));
900
+ }
901
+
898
902
  .library-list.materials .text {
899
903
  display: none;
900
904
  }