sunrize 2.0.7 → 2.0.9

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 CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "sunrize",
3
3
  "productName": "Sunrize X3D Editor",
4
- "version": "2.0.7",
5
- "description": "A Multi-Platform X3D Editor",
4
+ "version": "2.0.9",
5
+ "description": "Sunrize — A Multi-Platform X3D Editor",
6
6
  "main": "src/main.js",
7
7
  "bin": {
8
8
  "sunrize": "bin/sunrize.js"
@@ -89,10 +89,10 @@
89
89
  "shell-tools": "^1.1.9"
90
90
  },
91
91
  "dependencies": {
92
- "@vscode/codicons": "^0.0.44",
92
+ "@vscode/codicons": "^0.0.45",
93
93
  "capitalize": "^2.0.4",
94
94
  "console": "^0.7.2",
95
- "electron": "^40.8.0",
95
+ "electron": "^41.0.2",
96
96
  "electron-prompt": "^1.7.0",
97
97
  "electron-squirrel-startup": "^1.0.1",
98
98
  "electron-tabs": "^1.0.4",
@@ -109,9 +109,9 @@
109
109
  "qtip2": "^3.0.3",
110
110
  "spectrum-colorpicker2": "^2.0.10",
111
111
  "string-similarity": "^4.0.4",
112
- "tweakpane": "^3.1.10",
112
+ "tweakpane": "^4.0.5",
113
113
  "update-electron-app": "^3.1.2",
114
- "x_ite": "^14.0.8",
114
+ "x_ite": "^14.0.9",
115
115
  "x3d-traverse": "^1.0.22"
116
116
  }
117
117
  }
@@ -51,6 +51,8 @@ module .exports = class Application
51
51
 
52
52
  constructor ()
53
53
  {
54
+ // process .env .SUNRISE_ENVIRONMENT = "DEVELOPMENT"; // Windows test
55
+
54
56
  if (process .env .SUNRISE_ENVIRONMENT === "DEVELOPMENT")
55
57
  process .env .ELECTRON_ENABLE_LOGGING = 1;
56
58
 
@@ -527,15 +529,6 @@ module .exports = class Application
527
529
  label: _("Show All Objects"),
528
530
  click: () => this .mainWindow .webContents .send ("show-all-objects"),
529
531
  },
530
- { type: "separator" },
531
- {
532
- label: _("Transform to Zero"),
533
- click: () => this .mainWindow .webContents .send ("transform-to-zero"),
534
- },
535
- {
536
- label: _("Remove Empty Groups"),
537
- click: () => this .mainWindow .webContents .send ("remove-empty-groups"),
538
- },
539
532
  ],
540
533
  },
541
534
  {
@@ -1267,6 +1267,8 @@ Viewpoint {
1267
1267
  label: _("Viewpoints"),
1268
1268
  submenu: viewpoints .filter ((_, index) => index > 0) .map ((viewpointNode, index) => ({
1269
1269
  label: `${viewpointNode ._description .getValue () || viewpointNode .getDisplayName () || `VP${index + 1}}`}`,
1270
+ type: "radio",
1271
+ checked: viewpointNode ._isBound .getValue (),
1270
1272
  args: ["bindViewpoint", index + 1],
1271
1273
  })),
1272
1274
  },
@@ -37,26 +37,22 @@ $.fn.materialPreviewPopover = async function (node)
37
37
  // Create material node.
38
38
 
39
39
  const
40
- appearanceNode = browser .currentScene .getExportedNode ("Appearance"),
41
- previewNode = node .copy (scene);
40
+ x3dSyntax = await Editor .exportX3D (node .getExecutionContext (), [node]),
41
+ nodes = await Editor .importX3D (scene, x3dSyntax),
42
+ previewNode = nodes [0],
43
+ appearanceNode = browser .currentScene .getExportedNode ("Appearance");
42
44
 
43
45
  // Assign material node.
44
46
 
45
47
  for (const field of previewNode .getFields ())
48
+ connect (field, node .getField (field .getName ()));
49
+
50
+ for (const [i, extension] of previewNode ._extensions ?.entries () ?? [ ])
46
51
  {
47
- switch (field .getType ())
48
- {
49
- case X3D .X3DConstants .SFNode:
50
- field .setValue (null);
51
- break
52
- case X3D .X3DConstants .MFNode:
53
- field .length = 0;
54
- break;
55
- default:
56
- field .addReference (node .getField (field .getName ()));
57
- field .removeFieldInterest (node .getField (field .getName ()));
58
- break;
59
- }
52
+ const original = node ._extensions [i] .getValue ();
53
+
54
+ for (const field of extension .getValue () .getFields ())
55
+ connect (field, original .getField (field .getName ()));
60
56
  }
61
57
 
62
58
  previewNode .setup ();
@@ -90,16 +86,7 @@ $.fn.materialPreviewPopover = async function (node)
90
86
  field = backPreviewNode .getField (name),
91
87
  back = `back${name [0] .toUpperCase ()}${name .slice (1)}`;
92
88
 
93
- switch (field .getType ())
94
- {
95
- case X3D .X3DConstants .SFNode:
96
- case X3D .X3DConstants .MFNode:
97
- break;
98
- default:
99
- field .addReference (node .getField (back));
100
- field .removeFieldInterest (node .getField (back));
101
- break;
102
- }
89
+ connect (field, node .getField (back));
103
90
  }
104
91
 
105
92
  appearanceNode .material = backPreviewNode;
@@ -119,6 +106,9 @@ $.fn.materialPreviewPopover = async function (node)
119
106
  events: {
120
107
  hide: (event, api) =>
121
108
  {
109
+ for (const extension of Array .from (previewNode ._extensions ?? [ ]))
110
+ extension .dispose ();
111
+
122
112
  previewNode .dispose ();
123
113
  backPreviewNode ?.dispose ();
124
114
  browser .dispose ();
@@ -135,3 +125,16 @@ $.fn.materialPreviewPopover = async function (node)
135
125
  return this;
136
126
  };
137
127
 
128
+ function connect (field, original)
129
+ {
130
+ switch (field .getType ())
131
+ {
132
+ case X3D .X3DConstants .SFNode:
133
+ case X3D .X3DConstants .MFNode:
134
+ break;
135
+ default:
136
+ original .addFieldInterest (field);
137
+ field .assign (original);
138
+ break;
139
+ }
140
+ }
@@ -69,18 +69,7 @@ $.fn.texturePreviewPopover = async function (node)
69
69
  // Assign texture node.
70
70
 
71
71
  for (const field of previewNode .getFields ())
72
- {
73
- switch (field .getType ())
74
- {
75
- case X3D .X3DConstants .SFNode:
76
- case X3D .X3DConstants .MFNode:
77
- break;
78
- default:
79
- field .addReference (node .getField (field .getName ()));
80
- field .removeFieldInterest (node .getField (field .getName ()));
81
- break;
82
- }
83
- }
72
+ connect (field, node .getField (field .getName ()));
84
73
 
85
74
  appearanceNode .texture = previewNode;
86
75
 
@@ -194,3 +183,16 @@ $.fn.texturePreviewPopover = async function (node)
194
183
  return this;
195
184
  };
196
185
 
186
+ function connect (field, original)
187
+ {
188
+ switch (field .getType ())
189
+ {
190
+ case X3D .X3DConstants .SFNode:
191
+ case X3D .X3DConstants .MFNode:
192
+ break;
193
+ default:
194
+ original .addFieldInterest (field);
195
+ field .assign (original);
196
+ break;
197
+ }
198
+ }
@@ -188,7 +188,7 @@ module .exports = new class Library extends Dialog
188
188
  const node = nodes .find (node => node .text () .toLowerCase () === input)
189
189
  ?? nodes .sort ((a, b) => a .data ("similarity") - b .data ("similarity")) .at (-1);
190
190
 
191
- node .trigger ("click");
191
+ node .trigger ("dblclick");
192
192
  }
193
193
 
194
194
  update ()
@@ -84,7 +84,7 @@ module .exports = class MaterialsLibrary extends LibraryPane
84
84
  .addClass ("text")
85
85
  .text (`${group .getNodeName ()} ${c + 1}`))
86
86
  .appendTo (this .#list)
87
- .on ("click", () => this .importMaterial (material .getNodeName ())));
87
+ .on ("dblclick", () => this .importMaterial (material .getNodeName ())));
88
88
  }
89
89
  }
90
90
 
@@ -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 ("click", () => this .createNode (node .typeName, node .componentInfo .name));
80
+ .on ("dblclick", () => 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 ("click", () => this .createProto (proto));
100
+ .on ("dblclick", () => 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 ("click", () => this .createNode (node .typeName, node .componentInfo .name));
126
+ .on ("dblclick", () => this .createNode (node .typeName, node .componentInfo .name));
127
127
  }
128
128
  }
129
129
 
@@ -24,9 +24,6 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
24
24
 
25
25
  electron .ipcRenderer .on ("outline-editor", (event, key, ... args) => this [key] (... args));
26
26
 
27
- electron .ipcRenderer .on ("transform-to-zero", () => this .transformToZero ());
28
- electron .ipcRenderer .on ("remove-empty-groups", () => this .removeEmptyGroups ());
29
-
30
27
  this .setup ();
31
28
  }
32
29
 
@@ -54,26 +51,6 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
54
51
  ]);
55
52
  }
56
53
 
57
- transformToZero ()
58
- {
59
- const
60
- selection = this .sceneGraph .find (".node.primary, .node.manually"),
61
- ids = selection .map (function () { return this .id }) .get (),
62
- nodes = ids .length ? ids .map (id => this .getNode ($(`#${id}`))) : this .executionContext .rootNodes;
63
-
64
- Editor .transformToZero (this .executionContext, nodes);
65
- }
66
-
67
- removeEmptyGroups ()
68
- {
69
- const
70
- selection = this .sceneGraph .find (".node.primary, .node.manually"),
71
- ids = selection .map (function () { return this .id }) .get (),
72
- nodes = ids .length ? ids .map (id => this .getNode ($(`#${id}`))) : this .executionContext .rootNodes;
73
-
74
- Editor .removeEmptyGroups (this .executionContext, nodes);
75
- }
76
-
77
54
  showContextMenu (event)
78
55
  {
79
56
  const element = $(document .elementFromPoint (event .pageX, event .pageY))
@@ -433,6 +410,15 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
433
410
 
434
411
  continue;
435
412
  }
413
+ case X3D .X3DConstants .X3DTransformNode:
414
+ {
415
+ menu .push ({
416
+ label: _("Transform to Zero"),
417
+ args: ["transformToZero", element .attr ("id"), executionContext .getId (), node .getId ()],
418
+ });
419
+
420
+ continue;
421
+ }
436
422
  case X3D .X3DConstants .X3DUrlObject:
437
423
  {
438
424
  if (node ._url .some (fileURL => !fileURL .match (/^\s*(?:data|ecmascript|javascript|vrmlscript):/s)))
@@ -1353,6 +1339,25 @@ module .exports = class OutlineEditor extends OutlineRouteGraph
1353
1339
  UndoManager .shared .endUndo ();
1354
1340
  }
1355
1341
 
1342
+ transformToZero (id, executionContextId, nodeId)
1343
+ {
1344
+ const
1345
+ executionContext = this .objects .get (executionContextId),
1346
+ transformNode = this .objects .get (nodeId);
1347
+
1348
+ Editor .transformToZero (executionContext, [transformNode]);
1349
+ }
1350
+
1351
+ removeEmptyGroups ()
1352
+ {
1353
+ const
1354
+ selection = this .sceneGraph .find (".node.primary, .node.manually"),
1355
+ ids = selection .map (function () { return this .id }) .get (),
1356
+ nodes = ids .length ? ids .map (id => this .getNode ($(`#${id}`))) : this .executionContext .rootNodes;
1357
+
1358
+ Editor .removeEmptyGroups (this .executionContext, nodes);
1359
+ }
1360
+
1356
1361
  convertImageTextureToPixelTexture (id, executionContextId, nodeId)
1357
1362
  {
1358
1363
  const
@@ -29,10 +29,7 @@ module .exports = new class Panel extends Interface
29
29
  "top": "unset",
30
30
  });
31
31
 
32
- this .container
33
- .on ("mouseenter", event => this .onmouseenter (event))
34
- .on ("mouseleave", event => this .onmouseleave (event))
35
- .on ("mousedown", event => this .onmousedown (event));
32
+ this .container .get (0) .addEventListener ("mousedown", event => this .onmousedown (event), true);
36
33
 
37
34
  this .browser .getBrowserOptions () ._ColorSpace .addFieldCallback ("Panel", () => this .updateNode ());
38
35
 
@@ -68,16 +65,6 @@ module .exports = new class Panel extends Interface
68
65
  this .container .hide (300, () => this .removeNode (this .node));
69
66
  }
70
67
 
71
- onmouseenter ()
72
- {
73
- this .hovered = true;
74
- }
75
-
76
- onmouseleave ()
77
- {
78
- this .hovered = false;
79
- }
80
-
81
68
  onmousedown (event)
82
69
  {
83
70
  $(document) .on ("mouseup.Panel", () => this .onmouseup ());
@@ -92,6 +79,17 @@ module .exports = new class Panel extends Interface
92
79
  $(document) .off (".Panel");
93
80
 
94
81
  this .mousedown = false;
82
+
83
+ if (!this .original)
84
+ return;
85
+
86
+ const { executionContext, node, field, previous } = this .original;
87
+ const value = field .copy ();
88
+
89
+ field .assign (previous);
90
+ this .assign (executionContext, node, field, value);
91
+
92
+ this .original = null;
95
93
  }
96
94
 
97
95
  onmousemove (event)
@@ -141,8 +139,26 @@ module .exports = new class Panel extends Interface
141
139
  const concreteNode = X3DUOM .find (`ConcreteNode[name="${node .getTypeName ()}"]`);
142
140
 
143
141
  this .browser .currentScene .units .addInterest ("updateNode", this);
144
- node .getPredefinedFields () .addInterest ("updateNode", this);
145
- node .getUserDefinedFields () .addInterest ("updateNode", this);
142
+
143
+ node .getPredefinedFields () .addInterest ("updateNode", this);
144
+ node .getUserDefinedFields () .addInterest ("updateNode", this);
145
+
146
+ for (const type of node .getType () .toReversed ())
147
+ {
148
+ switch (type)
149
+ {
150
+ case X3D .X3DConstants .X3DBoundedObject:
151
+ {
152
+ this .browser .currentScene .bbox_changed .addInterest ("refreshBBox", this);
153
+ break;
154
+ }
155
+ case X3D .X3DConstants .X3DGeometryNode:
156
+ {
157
+ node ._rebuild .addInterest ("refreshGeometry", this);
158
+ break;
159
+ }
160
+ }
161
+ }
146
162
 
147
163
  this .addBlades (node, concreteNode);
148
164
 
@@ -220,8 +236,26 @@ module .exports = new class Panel extends Interface
220
236
  // Disconnect interests.
221
237
 
222
238
  this .browser .currentScene .units .removeInterest ("updateNode", this);
223
- node .getPredefinedFields () .removeInterest ("updateNode", this);
224
- node .getUserDefinedFields () .removeInterest ("updateNode", this);
239
+
240
+ node .getPredefinedFields () .removeInterest ("updateNode", this);
241
+ node .getUserDefinedFields () .removeInterest ("updateNode", this);
242
+
243
+ for (const type of node .getType () .toReversed ())
244
+ {
245
+ switch (type)
246
+ {
247
+ case X3D .X3DConstants .X3DBoundedObject:
248
+ {
249
+ this .browser .currentScene .bbox_changed .removeInterest ("refreshBBox", this);
250
+ break;
251
+ }
252
+ case X3D .X3DConstants .X3DGeometryNode:
253
+ {
254
+ node ._rebuild .removeInterest ("refreshGeometry", this);
255
+ break;
256
+ }
257
+ }
258
+ }
225
259
 
226
260
  for (const field of node .getFields ())
227
261
  field .removeFieldCallback (this);
@@ -311,18 +345,60 @@ module .exports = new class Panel extends Interface
311
345
  const parameter = { };
312
346
 
313
347
  for (const name of fields)
348
+ this .addBinding (folder, parameter, node, node .getField (name), concreteNode);
349
+
350
+ switch (title)
314
351
  {
315
- if (name .match (/^-+$/))
316
- folder .addSeparator ();
317
- else
318
- this .addInput (folder, parameter, node, node .getField (name), concreteNode);
352
+ case "X3DBoundedObject":
353
+ {
354
+ folder .addBlade ({ view: "separator" });
355
+
356
+ const options = {
357
+ format: value => this .format (this .#vector, value),
358
+ };
359
+
360
+ for (const key in this .#vector)
361
+ options [key] = { format: options .format };
362
+
363
+ this .refreshBBox ();
364
+
365
+ this .bbox .bboxSizeInput = folder .addBinding (this .bbox, "calculatedSize", options);
366
+ this .bbox .bboxCenterInput = folder .addBinding (this .bbox, "calculatedCenter", options);
367
+
368
+ $(this .bbox .bboxSizeInput .element) .find ("input") .attr ("readonly", "");
369
+ $(this .bbox .bboxCenterInput .element) .find ("input") .attr ("readonly", "");
370
+
371
+ $(this .bbox .bboxSizeInput .element) .find (".tp-txtv_k") .detach ();
372
+ $(this .bbox .bboxCenterInput .element) .find (".tp-txtv_k") .detach ();
373
+ break;
374
+ }
375
+ case "X3DGeometryNode":
376
+ {
377
+ this .refreshGeometry ();
378
+
379
+ switch (node .getGeometryType ())
380
+ {
381
+ case 0:
382
+ this .numPrimitives .monitor = folder .addBinding (this .numPrimitives, "numberOfPoints", { readonly: true });
383
+ break
384
+ case 1:
385
+ this .numPrimitives .monitor = folder .addBinding (this .numPrimitives, "numberOfLines", { readonly: true });
386
+ break
387
+ case 2:
388
+ case 3:
389
+ this .numPrimitives .monitor = folder .addBinding (this .numPrimitives, "numberOfTriangles", { readonly: true });
390
+ break
391
+ }
392
+
393
+ break;
394
+ }
319
395
  }
320
396
 
321
397
  if (!folder .children .length)
322
398
  folder .dispose ();
323
399
  }
324
400
 
325
- addInput (folder, parameter, node, field, concreteNode)
401
+ addBinding (folder, parameter, node, field, concreteNode)
326
402
  {
327
403
  if (!field .isInitializable ())
328
404
  return;
@@ -374,6 +450,10 @@ module .exports = new class Panel extends Interface
374
450
  case X3D .X3DConstants .SFDouble:
375
451
  case X3D .X3DConstants .SFFloat:
376
452
  case X3D .X3DConstants .SFInt32:
453
+ case X3D .X3DConstants .SFMatrix3d:
454
+ case X3D .X3DConstants .SFMatrix3f:
455
+ case X3D .X3DConstants .SFMatrix4d:
456
+ case X3D .X3DConstants .SFMatrix4f:
377
457
  case X3D .X3DConstants .SFRotation:
378
458
  case X3D .X3DConstants .SFString:
379
459
  case X3D .X3DConstants .SFTime:
@@ -414,7 +494,7 @@ module .exports = new class Panel extends Interface
414
494
 
415
495
  this .refresh (parameter, node, field);
416
496
 
417
- const input = $.try (() => folder .addInput (parameter, field .getName (), options));
497
+ const input = $.try (() => folder .addBinding (parameter, field .getName (), options));
418
498
 
419
499
  if (!input)
420
500
  break;
@@ -438,10 +518,6 @@ module .exports = new class Panel extends Interface
438
518
  break;
439
519
  }
440
520
  case X3D .X3DConstants .SFImage:
441
- case X3D .X3DConstants .SFMatrix3d:
442
- case X3D .X3DConstants .SFMatrix3f:
443
- case X3D .X3DConstants .SFMatrix4d:
444
- case X3D .X3DConstants .SFMatrix4f:
445
521
  case X3D .X3DConstants .MFBool:
446
522
  case X3D .X3DConstants .MFColor:
447
523
  case X3D .X3DConstants .MFColorRGBA:
@@ -463,17 +539,18 @@ module .exports = new class Panel extends Interface
463
539
  case X3D .X3DConstants .MFVec4d:
464
540
  case X3D .X3DConstants .MFVec4f:
465
541
  {
466
- const tooMuchValues = (field instanceof X3D .X3DArrayField) && field .length >= 10_000;
542
+ const tooMuchValues = (field instanceof X3D .X3DArrayField) && field .length >= 1_000;
467
543
 
468
544
  if (tooMuchValues)
469
545
  parameter [field .getName ()] = util .format (_("%s values"), field .length .toLocaleString (_.locale));
470
546
  else
471
547
  this .refresh (parameter, node, field);
472
548
 
473
- const input = folder .addMonitor (parameter, field .getName (),
549
+ const input = folder .addBinding (parameter, field .getName (),
474
550
  {
475
- multiline: true,
476
- lineCount: tooMuchValues ? 1 : 2,
551
+ readonly: true,
552
+ multiline: !tooMuchValues,
553
+ rows: tooMuchValues ? 1 : 3,
477
554
  });
478
555
 
479
556
  $(input .element) .on ("mouseenter", () =>
@@ -484,9 +561,16 @@ module .exports = new class Panel extends Interface
484
561
  if (tooMuchValues)
485
562
  break;
486
563
 
487
- const textarea = $(input .element) .find ("textarea") .removeAttr ("readonly");
564
+ const
565
+ original = $(input .element) .find ("textarea"),
566
+ textarea = $("<textarea></textarea>");
488
567
 
489
- textarea .on ("focusout", () => this .onchange (node, field, textarea .val ()));
568
+ textarea
569
+ .attr ("class", original .attr ("class"))
570
+ .val (parameter [field .getName ()])
571
+ .on ("focusout", () => this .onchange (node, field, textarea .val ()));
572
+
573
+ original .replaceWith (textarea);
490
574
 
491
575
  field .addFieldCallback (this, () =>
492
576
  {
@@ -666,7 +750,7 @@ module .exports = new class Panel extends Interface
666
750
  executionContext = node .getExecutionContext (),
667
751
  category = field .getUnit ();
668
752
 
669
- if (!(this .hovered || this .container .find (":focus") .length))
753
+ if (!(this .mousedown || this .container .find (":focus") .is ("input, textarea, select")))
670
754
  return;
671
755
 
672
756
  this .changing = true;
@@ -799,7 +883,12 @@ module .exports = new class Panel extends Interface
799
883
  {
800
884
  if (this .mousedown)
801
885
  {
802
- this .original ??= field .copy ();
886
+ this .original ??= {
887
+ executionContext,
888
+ node,
889
+ field: field,
890
+ previous: field .copy (),
891
+ };
803
892
 
804
893
  field .setValue (value);
805
894
 
@@ -807,13 +896,66 @@ module .exports = new class Panel extends Interface
807
896
  }
808
897
  else
809
898
  {
810
- if (this .original)
811
- field .assign (this .original);
899
+ Editor .setFieldValue (executionContext, node, field, value);
900
+ }
901
+ }
812
902
 
813
- this .original = null;
903
+ #box = new X3D .Box3 ();
904
+ #vector = new X3D .SFVec3f ();
814
905
 
815
- Editor .setFieldValue (executionContext, node, field, value);
906
+ bbox = {
907
+ calculatedSize: { },
908
+ calculatedCenter: { },
909
+ bboxSizeInput: null,
910
+ bboxCenterInput: null,
911
+ };
912
+
913
+ refreshBBox ()
914
+ {
915
+ const bbox = this .node .getBBox (this .#box);
916
+
917
+ this .#vector .setValue (bbox .size);
918
+ this .#vector .setName ("calculatedSize");
919
+ this .#vector .setUnit ("length");
920
+
921
+ this .refresh (this .bbox, this .node, this .#vector)
922
+
923
+ this .#vector .setValue (bbox .center);
924
+ this .#vector .setName ("calculatedCenter");
925
+ this .#vector .setUnit ("length");
926
+
927
+ this .refresh (this .bbox, this .node, this .#vector)
928
+
929
+ this .bbox .bboxSizeInput ?.refresh ();
930
+ this .bbox .bboxCenterInput ?.refresh ();
931
+ }
932
+
933
+ numPrimitives = {
934
+ numberOfPoints: "0",
935
+ numberOfLines: "0",
936
+ numberOfTriangles: "0",
937
+ monitor: null,
938
+ }
939
+
940
+ refreshGeometry ()
941
+ {
942
+ const numVertices = this .node .getVertices () .length / 4;
943
+
944
+ switch (this .node .getGeometryType ())
945
+ {
946
+ case 0:
947
+ this .numPrimitives .numberOfPoints = (numVertices) .toLocaleString (_.locale);
948
+ break
949
+ case 1:
950
+ this .numPrimitives .numberOfLines = (numVertices / 2) .toLocaleString (_.locale);
951
+ break
952
+ case 2:
953
+ case 3:
954
+ this .numPrimitives .numberOfTriangles = (numVertices / 3) .toLocaleString (_.locale);
955
+ break
816
956
  }
957
+
958
+ this .numPrimitives .monitor ?.refresh ();
817
959
  }
818
960
 
819
961
  getNodeTitle (node, nodeElement)
@@ -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 ("click", () => this .createRecentNode (nodes, typeName));
70
+ .on ("dblclick", () => 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 ("click", () => this .createNode (node));
94
+ .on ("dblclick", () => this .createNode (node));
95
95
  }
96
96
  }
97
97
 
@@ -74,7 +74,7 @@ module .exports = class ScriptEditor extends Interface
74
74
  .attr ("title", _("Apply script source to node."))
75
75
  .text ("check_circle")
76
76
  .appendTo (this .toolbar)
77
- .on ("click", () => this .apply ());
77
+ .on ("click", () => this .apply (true));
78
78
 
79
79
  $("<span></span>") .addClass ("separator") .appendTo (this .toolbar);
80
80
 
@@ -924,7 +924,7 @@ main ()
924
924
  this .nodeList .setNode (nodes [0] ._parts [0] .getValue ());
925
925
  }
926
926
 
927
- apply ()
927
+ apply (force)
928
928
  {
929
929
  if (!this .node)
930
930
  return;
@@ -936,12 +936,21 @@ main ()
936
936
  string = this .editor .getModel () .getValue (),
937
937
  value = this .node ._url .toSpliced (0, 1, Editor .encodeURI (string));
938
938
 
939
- if (this .node ._url .equals (value))
939
+ if (!this .node ._url .equals (value))
940
+ {
941
+ this .node ._url .addFieldCallback (this, () => this .node ._url .addFieldCallback (this, this .set_url .bind (this)));
942
+
943
+ Editor .setFieldValue (this .node .getExecutionContext (), this .node, this .node ._url, value);
944
+ }
945
+
946
+ if (!force)
940
947
  return;
941
948
 
942
949
  this .node ._url .addFieldCallback (this, () => this .node ._url .addFieldCallback (this, this .set_url .bind (this)));
943
950
 
944
- Editor .setFieldValue (this .node .getExecutionContext (), this .node, this .node ._url, value);
951
+ this .node ._url = value;
952
+
953
+ Editor .requestUpdateInstances (this .node);
945
954
  }
946
955
 
947
956
  set_url ()
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
 
3
3
  const
4
- X3DLineGeometryNodeTool = require ("../Rendering/X3DLineGeometryNodeTool"),
5
- ToolColors = require ("../Core/ToolColors"),
6
- X3D = require ("../../X3D"),
7
- _ = require ("../../Application/GetText");
4
+ X3DGeometryNodeTool = require ("../Rendering/X3DGeometryNodeTool"),
5
+ ToolColors = require ("../Core/ToolColors"),
6
+ X3D = require ("../../X3D"),
7
+ _ = require ("../../Application/GetText");
8
8
 
9
- class Arc2DTool extends X3DLineGeometryNodeTool
9
+ class Arc2DTool extends X3DGeometryNodeTool
10
10
  {
11
11
  #transformNode = null;
12
12
  #changing = false;
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
 
3
3
  const
4
- X3DLineGeometryNodeTool = require ("../Rendering/X3DLineGeometryNodeTool"),
5
- ToolColors = require ("../Core/ToolColors"),
6
- X3D = require ("../../X3D"),
7
- _ = require ("../../Application/GetText");
4
+ X3DGeometryNodeTool = require ("../Rendering/X3DGeometryNodeTool"),
5
+ ToolColors = require ("../Core/ToolColors"),
6
+ X3D = require ("../../X3D"),
7
+ _ = require ("../../Application/GetText");
8
8
 
9
- class Circle2DTool extends X3DLineGeometryNodeTool
9
+ class Circle2DTool extends X3DGeometryNodeTool
10
10
  {
11
11
  #transformNode = null;
12
12
  #changing = false;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
- const X3DLineGeometryNodeTool = require ("../Rendering/X3DLineGeometryNodeTool");
3
+ const X3DGeometryNodeTool = require ("../Rendering/X3DGeometryNodeTool");
4
4
 
5
- class Polyline2DTool extends X3DLineGeometryNodeTool { }
5
+ class Polyline2DTool extends X3DGeometryNodeTool { }
6
6
 
7
7
  module .exports = Polyline2DTool;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
- const X3DPointGeometryNodeTool = require ("../Rendering/X3DPointGeometryNodeTool");
3
+ const X3DGeometryNodeTool = require ("../Rendering/X3DGeometryNodeTool");
4
4
 
5
- class Polypoint2DTool extends X3DPointGeometryNodeTool { }
5
+ class Polypoint2DTool extends X3DGeometryNodeTool { }
6
6
 
7
7
  module .exports = Polypoint2DTool;
@@ -2,9 +2,9 @@
2
2
 
3
3
  const
4
4
  X3DParametricGeometryNodeTool = require ("./X3DParametricGeometryNodeTool"),
5
- X3DLineGeometryNodeTool = require ("../Rendering/X3DLineGeometryNodeTool");
5
+ X3DGeometryNodeTool = require ("../Rendering/X3DGeometryNodeTool");
6
6
 
7
- class NurbsCurveTool extends X3DParametricGeometryNodeTool (X3DLineGeometryNodeTool)
7
+ class NurbsCurveTool extends X3DParametricGeometryNodeTool (X3DGeometryNodeTool)
8
8
  {
9
9
  async initializeTool ()
10
10
  {
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
- const X3DLineGeometryNodeTool = require ("./X3DLineGeometryNodeTool");
3
+ const X3DGeometryNodeTool = require ("./X3DGeometryNodeTool");
4
4
 
5
- class IndexedLineSetTool extends X3DLineGeometryNodeTool { }
5
+ class IndexedLineSetTool extends X3DGeometryNodeTool { }
6
6
 
7
7
  module .exports = IndexedLineSetTool;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
- const X3DLineGeometryNodeTool = require ("./X3DLineGeometryNodeTool");
3
+ const X3DGeometryNodeTool = require ("./X3DGeometryNodeTool");
4
4
 
5
- class LineSetTool extends X3DLineGeometryNodeTool { }
5
+ class LineSetTool extends X3DGeometryNodeTool { }
6
6
 
7
7
  module .exports = LineSetTool;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
- const X3DPointGeometryNodeTool = require ("./X3DPointGeometryNodeTool");
3
+ const X3DGeometryNodeTool = require ("./X3DGeometryNodeTool");
4
4
 
5
- class PointSetTool extends X3DPointGeometryNodeTool { }
5
+ class PointSetTool extends X3DGeometryNodeTool { }
6
6
 
7
7
  module .exports = PointSetTool;
@@ -10,14 +10,16 @@ class X3DGeometryNodeTool extends X3DNodeTool
10
10
  {
11
11
  await super .loadTool ("tool", __dirname, "X3DGeometryNodeTool.x3d");
12
12
 
13
- this .tool .linesColor = ToolColors .BLUE;
13
+ this .tool .linesColor = ToolColors .BLUE;
14
+ this .tool .pointsColor = ToolColors .BLUE;
14
15
 
15
16
  if (type === "CUSTOM")
16
17
  return;
17
18
 
18
19
  this .node ._rebuild .addInterest ("set_toolRebuildGeometry", this);
19
20
 
20
- this .tool .linesCoord = this .getToolScene () .createNode ("CoordinateDouble");
21
+ this .tool .linesCoord = this .getToolScene () .createNode ("CoordinateDouble");
22
+ this .tool .pointsCoord = this .getToolScene () .createNode ("CoordinateDouble");
21
23
 
22
24
  this .set_toolRebuildGeometry ();
23
25
  }
@@ -31,21 +33,43 @@ class X3DGeometryNodeTool extends X3DNodeTool
31
33
 
32
34
  set_toolRebuildGeometry ()
33
35
  {
34
- const
35
- points = this .node .getVertices () .filter ((_, i) => i % 4 < 3),
36
- numPoints = points .length / 3;
37
-
38
- if (numPoints !== this .tool .linesCoord .point .length)
36
+ switch (this .getGeometryType ())
39
37
  {
40
- const coordIndex = [ ];
41
-
42
- for (let i = 0; i < numPoints; i += 3)
43
- coordIndex .push (i, i + 1, i + 2, i, -1);
44
-
45
- this .tool .set_linesCoordIndex = coordIndex;
38
+ case 0:
39
+ case 1:
40
+ {
41
+ this .tool .pointsDisplay = true;
42
+ this .tool .linesDisplay = false;
43
+
44
+ const points = this .node .getVertices () .filter ((_, i) => i % 4 < 3);
45
+
46
+ this .tool .pointsCoord .point = points;
47
+ break;
48
+ }
49
+ case 2:
50
+ case 3:
51
+ {
52
+ this .tool .pointsDisplay = false;
53
+ this .tool .linesDisplay = true;
54
+
55
+ const
56
+ points = this .node .getVertices () .filter ((_, i) => i % 4 < 3),
57
+ numPoints = points .length / 3;
58
+
59
+ if (numPoints !== this .tool .linesCoord .point .length)
60
+ {
61
+ const coordIndex = [ ];
62
+
63
+ for (let i = 0; i < numPoints; i += 3)
64
+ coordIndex .push (i, i + 1, i + 2, i, -1);
65
+
66
+ this .tool .set_linesCoordIndex = coordIndex;
67
+ }
68
+
69
+ this .tool .linesCoord .point = points;
70
+ break;
71
+ }
46
72
  }
47
-
48
- this .tool .linesCoord .point = points;
49
73
  }
50
74
 
51
75
  traverseBefore (type, renderObject)
@@ -1,16 +1,20 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 4.0//EN" "http://www.web3d.org/specifications/x3d-4.0.dtd">
3
- <X3D profile='Interchange' version='4.0' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-4.0.xsd'>
2
+ <!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 4.1//EN" "https://www.web3d.org/specifications/x3d-4.1.dtd">
3
+ <X3D profile='Interchange' version='4.1' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='https://www.web3d.org/specifications/x3d-4.1.xsd'>
4
4
  <head>
5
+ <component name='Core' level='2'/>
6
+ <component name='Shaders' level='1'/>
5
7
  <component name='X_ITE' level='1'/>
6
8
  <meta name='created' content='Tue, 28 Nov 2023 21:59:27 GMT'/>
7
9
  <meta name='comment' content='Rise and Shine'/>
8
10
  <meta name='creator' content='Holger Seelig'/>
9
- <meta name='generator' content='Sunrize X3D Editor V1.7.1, https://create3000.github.io/sunrize/'/>
10
- <meta name='modified' content='Sat, 29 Jun 2024 10:51:34 GMT'/>
11
+ <meta name='generator' content='Sunrize X3D Editor V2.0.7, https://create3000.github.io/sunrize/'/>
12
+ <meta name='modified' content='Sun, 08 Mar 2026 19:34:05 GMT'/>
11
13
  </head>
12
14
  <Scene>
13
- <ExternProtoDeclare name='ToolShader' url='"../Shaders/ToolShader.x3d"'/>
15
+ <ExternProtoDeclare name='ToolShader' url='"../Shaders/ToolShader.x3d"'>
16
+ <field accessType='inputOutput' type='SFBool' name='instanced'/>
17
+ </ExternProtoDeclare>
14
18
  <ProtoDeclare name='X3DGeometryNodeTool'>
15
19
  <ProtoInterface>
16
20
  <field accessType='inputOutput' type='SFBool' name='selected'/>
@@ -22,6 +26,10 @@
22
26
  <field accessType='inputOutput' type='SFColor' name='linesColor' value='1 1 1'/>
23
27
  <field accessType='inputOnly' type='MFInt32' name='set_linesCoordIndex'/>
24
28
  <field accessType='inputOutput' type='SFNode' name='linesCoord'/>
29
+ <field accessType='inputOutput' type='SFBool' name='pointsDisplay'/>
30
+ <field accessType='inputOutput' type='SFFloat' name='pointSize' value='5'/>
31
+ <field accessType='inputOutput' type='SFColor' name='pointsColor' value='1 1 1'/>
32
+ <field accessType='inputOutput' type='SFNode' name='pointsCoord'/>
25
33
  <field accessType='inputOnly' type='MFNode' name='addChildren'/>
26
34
  <field accessType='inputOnly' type='MFNode' name='removeChildren'/>
27
35
  </ProtoInterface>
@@ -35,7 +43,7 @@
35
43
  <IS>
36
44
  <connect nodeField='scale' protoField='size'/>
37
45
  </IS>
38
- <Shape>
46
+ <Shape DEF='Lines'>
39
47
  <IS>
40
48
  <connect nodeField='visible' protoField='linesDisplay'/>
41
49
  </IS>
@@ -51,8 +59,8 @@
51
59
  <connect nodeField='emissiveColor' protoField='linesColor'/>
52
60
  </IS>
53
61
  </Material>
54
- <ProtoInstance name='ToolShader' DEF='_999' containerField='shaders'/>
55
- <DepthMode
62
+ <ProtoInstance name='ToolShader' DEF='_1' containerField='shaders'/>
63
+ <DepthMode DEF='_2'
56
64
  polygonOffset='-1 -1'/>
57
65
  </Appearance>
58
66
  <IndexedLineSet>
@@ -62,6 +70,33 @@
62
70
  </IS>
63
71
  </IndexedLineSet>
64
72
  </Shape>
73
+ <Shape DEF='Points'>
74
+ <IS>
75
+ <connect nodeField='visible' protoField='pointsDisplay'/>
76
+ </IS>
77
+ <Appearance>
78
+ <PointProperties>
79
+ <IS>
80
+ <connect nodeField='pointSizeScaleFactor' protoField='pointSize'/>
81
+ <connect nodeField='pointSizeMinValue' protoField='pointSize'/>
82
+ <connect nodeField='pointSizeMaxValue' protoField='pointSize'/>
83
+ </IS>
84
+ </PointProperties>
85
+ <Material
86
+ diffuseColor='0 0 0'>
87
+ <IS>
88
+ <connect nodeField='emissiveColor' protoField='pointsColor'/>
89
+ </IS>
90
+ </Material>
91
+ <ProtoInstance name='ToolShader' USE='_1' containerField='shaders'/>
92
+ <DepthMode USE='_2'/>
93
+ </Appearance>
94
+ <PointSet>
95
+ <IS>
96
+ <connect nodeField='coord' protoField='pointsCoord'/>
97
+ </IS>
98
+ </PointSet>
99
+ </Shape>
65
100
  </Transform>
66
101
  </Group>
67
102
  </ProtoBody>
@@ -1,40 +0,0 @@
1
- "use strict";
2
-
3
- const
4
- X3DGeometryNodeTool = require ("./X3DGeometryNodeTool"),
5
- ToolColors = require ("../Core/ToolColors");
6
-
7
- class X3DLineGeometryNodeTool extends X3DGeometryNodeTool
8
- {
9
- async initializeTool (type)
10
- {
11
- await super .loadTool ("tool", __dirname, "X3DLineGeometryNodeTool.x3d");
12
-
13
- this .tool .pointsColor = ToolColors .BLUE;
14
-
15
- if (type === "CUSTOM")
16
- return;
17
-
18
- this .node ._rebuild .addInterest ("set_toolRebuildGeometry", this);
19
-
20
- this .tool .pointsCoord = this .getToolScene () .createNode ("CoordinateDouble");
21
-
22
- this .set_toolRebuildGeometry ();
23
- }
24
-
25
- disposeTool ()
26
- {
27
- this .node ._rebuild .removeInterest ("set_toolRebuildGeometry", this);
28
-
29
- super .disposeTool ();
30
- }
31
-
32
- set_toolRebuildGeometry ()
33
- {
34
- const points = this .node .getVertices () .filter ((_, i) => i % 4 < 3);
35
-
36
- this .tool .pointsCoord .point = points;
37
- }
38
- }
39
-
40
- module .exports = X3DLineGeometryNodeTool;
@@ -1,64 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 4.0//EN" "http://www.web3d.org/specifications/x3d-4.0.dtd">
3
- <X3D profile='Interchange' version='4.0' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-4.0.xsd'>
4
- <head>
5
- <component name='X_ITE' level='1'/>
6
- <meta name='created' content='Tue, 28 Nov 2023 21:59:27 GMT'/>
7
- <meta name='comment' content='Rise and Shine'/>
8
- <meta name='creator' content='Holger Seelig'/>
9
- <meta name='generator' content='Sunrize X3D Editor V1.7.1, https://create3000.github.io/sunrize/'/>
10
- <meta name='modified' content='Sat, 29 Jun 2024 10:52:22 GMT'/>
11
- </head>
12
- <Scene>
13
- <ExternProtoDeclare name='ToolShader' url='"../Shaders/ToolShader.x3d"'/>
14
- <ProtoDeclare name='X3DLineGeometryNodeTool'>
15
- <ProtoInterface>
16
- <field accessType='inputOutput' type='SFBool' name='selected'/>
17
- <field accessType='inputOutput' type='SFString' name='group' value='NONE'/>
18
- <field accessType='inputOutput' type='SFBool' name='undo'/>
19
- <field accessType='inputOutput' type='SFBool' name='pointsDisplay' value='true'/>
20
- <field accessType='inputOutput' type='SFFloat' name='pointSize' value='5'/>
21
- <field accessType='inputOutput' type='SFColor' name='pointsColor' value='1 1 1'/>
22
- <field accessType='inputOutput' type='SFNode' name='pointsCoord'/>
23
- <field accessType='inputOnly' type='MFNode' name='addChildren'/>
24
- <field accessType='inputOnly' type='MFNode' name='removeChildren'/>
25
- </ProtoInterface>
26
- <ProtoBody>
27
- <Group>
28
- <IS>
29
- <connect nodeField='addChildren' protoField='addChildren'/>
30
- <connect nodeField='removeChildren' protoField='removeChildren'/>
31
- </IS>
32
- <Shape DEF='Lines'>
33
- <IS>
34
- <connect nodeField='visible' protoField='pointsDisplay'/>
35
- </IS>
36
- <Appearance>
37
- <PointProperties>
38
- <IS>
39
- <connect nodeField='pointSizeScaleFactor' protoField='pointSize'/>
40
- <connect nodeField='pointSizeMinValue' protoField='pointSize'/>
41
- <connect nodeField='pointSizeMaxValue' protoField='pointSize'/>
42
- </IS>
43
- </PointProperties>
44
- <Material
45
- diffuseColor='0 0 0'>
46
- <IS>
47
- <connect nodeField='emissiveColor' protoField='pointsColor'/>
48
- </IS>
49
- </Material>
50
- <ProtoInstance name='ToolShader' DEF='_999' containerField='shaders'/>
51
- <DepthMode
52
- polygonOffset='-1 -1'/>
53
- </Appearance>
54
- <PointSet>
55
- <IS>
56
- <connect nodeField='coord' protoField='pointsCoord'/>
57
- </IS>
58
- </PointSet>
59
- </Shape>
60
- </Group>
61
- </ProtoBody>
62
- </ProtoDeclare>
63
- </Scene>
64
- </X3D>
@@ -1,40 +0,0 @@
1
- "use strict";
2
-
3
- const
4
- X3DGeometryNodeTool = require ("./X3DGeometryNodeTool"),
5
- ToolColors = require ("../Core/ToolColors");
6
-
7
- class X3DPointGeometryNodeTool extends X3DGeometryNodeTool
8
- {
9
- async initializeTool (type)
10
- {
11
- await super .loadTool ("tool", __dirname, "X3DPointGeometryNodeTool.x3d");
12
-
13
- this .tool .pointsColor = ToolColors .BLUE;
14
-
15
- if (type === "CUSTOM")
16
- return;
17
-
18
- this .node ._rebuild .addInterest ("set_toolRebuildGeometry", this);
19
-
20
- this .tool .pointsCoord = this .getToolScene () .createNode ("CoordinateDouble");
21
-
22
- this .set_toolRebuildGeometry ();
23
- }
24
-
25
- disposeTool ()
26
- {
27
- this .node ._rebuild .removeInterest ("set_toolRebuildGeometry", this);
28
-
29
- super .disposeTool ();
30
- }
31
-
32
- set_toolRebuildGeometry ()
33
- {
34
- const points = this .node .getVertices () .filter ((_, i) => i % 4 < 3);
35
-
36
- this .tool .pointsCoord .point = points;
37
- }
38
- }
39
-
40
- module .exports = X3DPointGeometryNodeTool;
@@ -1,54 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 4.0//EN" "http://www.web3d.org/specifications/x3d-4.0.dtd">
3
- <X3D profile='Interchange' version='4.0' xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-4.0.xsd'>
4
- <head>
5
- <component name='X_ITE' level='1'/>
6
- <meta name='created' content='Tue, 28 Nov 2023 21:59:27 GMT'/>
7
- <meta name='comment' content='Rise and Shine'/>
8
- <meta name='creator' content='Holger Seelig'/>
9
- <meta name='generator' content='Sunrize X3D Editor V1.7.1, https://create3000.github.io/sunrize/'/>
10
- <meta name='modified' content='Sat, 29 Jun 2024 10:52:33 GMT'/>
11
- </head>
12
- <Scene>
13
- <ExternProtoDeclare name='ToolShader' url='"../Shaders/ToolShader.x3d"'/>
14
- <ProtoDeclare name='X3DPointGeometryNodeTool'>
15
- <ProtoInterface>
16
- <field accessType='inputOutput' type='SFBool' name='selected'/>
17
- <field accessType='inputOutput' type='SFBool' name='pointsDisplay' value='true'/>
18
- <field accessType='inputOutput' type='SFFloat' name='pointSize' value='5'/>
19
- <field accessType='inputOutput' type='SFColor' name='pointsColor' value='1 1 1'/>
20
- <field accessType='inputOutput' type='SFNode' name='pointsCoord'/>
21
- </ProtoInterface>
22
- <ProtoBody>
23
- <Shape DEF='Lines'>
24
- <IS>
25
- <connect nodeField='visible' protoField='pointsDisplay'/>
26
- </IS>
27
- <Appearance>
28
- <PointProperties>
29
- <IS>
30
- <connect nodeField='pointSizeScaleFactor' protoField='pointSize'/>
31
- <connect nodeField='pointSizeMinValue' protoField='pointSize'/>
32
- <connect nodeField='pointSizeMaxValue' protoField='pointSize'/>
33
- </IS>
34
- </PointProperties>
35
- <Material
36
- diffuseColor='0 0 0'>
37
- <IS>
38
- <connect nodeField='emissiveColor' protoField='pointsColor'/>
39
- </IS>
40
- </Material>
41
- <ProtoInstance name='ToolShader' DEF='_999' containerField='shaders'/>
42
- <DepthMode
43
- polygonOffset='-1 -1'/>
44
- </Appearance>
45
- <PointSet>
46
- <IS>
47
- <connect nodeField='coord' protoField='pointsCoord'/>
48
- </IS>
49
- </PointSet>
50
- </Shape>
51
- </ProtoBody>
52
- </ProtoDeclare>
53
- </Scene>
54
- </X3D>