lavavu-osmesa 1.9.9__cp313-cp313-manylinux_2_28_x86_64.whl

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 (65) hide show
  1. lavavu/LavaVuPython.py +561 -0
  2. lavavu/_LavaVuPython.cpython-313-x86_64-linux-gnu.so +0 -0
  3. lavavu/__init__.py +15 -0
  4. lavavu/__main__.py +12 -0
  5. lavavu/amalgamate.py +15 -0
  6. lavavu/aserver.py +359 -0
  7. lavavu/control.py +1731 -0
  8. lavavu/convert.py +888 -0
  9. lavavu/dict.json +2528 -0
  10. lavavu/font.bin +0 -0
  11. lavavu/html/LavaVu-amalgamated.css +282 -0
  12. lavavu/html/OK-min.js +99 -0
  13. lavavu/html/baseviewer.js +307 -0
  14. lavavu/html/control.css +104 -0
  15. lavavu/html/control.js +340 -0
  16. lavavu/html/dat-gui-light-theme.css +68 -0
  17. lavavu/html/dat.gui.min.js +2 -0
  18. lavavu/html/draw.js +2259 -0
  19. lavavu/html/drawbox.js +1039 -0
  20. lavavu/html/emscripten-template.js +184 -0
  21. lavavu/html/emscripten.css +92 -0
  22. lavavu/html/favicon.ico +0 -0
  23. lavavu/html/gl-matrix-min.js +47 -0
  24. lavavu/html/gui.css +25 -0
  25. lavavu/html/menu.js +615 -0
  26. lavavu/html/server.js +226 -0
  27. lavavu/html/stats.min.js +5 -0
  28. lavavu/html/styles.css +58 -0
  29. lavavu/html/webview-template.html +43 -0
  30. lavavu/html/webview.html +43 -0
  31. lavavu/lavavu.py +6200 -0
  32. lavavu/osmesa/LavaVuPython.py +561 -0
  33. lavavu/osmesa/_LavaVuPython.cpython-313-x86_64-linux-gnu.so +0 -0
  34. lavavu/osmesa/__init__.py +0 -0
  35. lavavu/points.py +191 -0
  36. lavavu/server.py +343 -0
  37. lavavu/shaders/default.frag +14 -0
  38. lavavu/shaders/default.vert +17 -0
  39. lavavu/shaders/fontShader.frag +20 -0
  40. lavavu/shaders/fontShader.vert +18 -0
  41. lavavu/shaders/lineShader.frag +39 -0
  42. lavavu/shaders/lineShader.vert +26 -0
  43. lavavu/shaders/pointShader.frag +127 -0
  44. lavavu/shaders/pointShader.vert +53 -0
  45. lavavu/shaders/triShader.frag +153 -0
  46. lavavu/shaders/triShader.vert +49 -0
  47. lavavu/shaders/volumeShader.frag +400 -0
  48. lavavu/shaders/volumeShader.vert +5 -0
  49. lavavu/tracers.py +207 -0
  50. lavavu/vutils.py +211 -0
  51. lavavu_osmesa-1.9.9.dist-info/METADATA +323 -0
  52. lavavu_osmesa-1.9.9.dist-info/RECORD +65 -0
  53. lavavu_osmesa-1.9.9.dist-info/WHEEL +5 -0
  54. lavavu_osmesa-1.9.9.dist-info/entry_points.txt +2 -0
  55. lavavu_osmesa-1.9.9.dist-info/licenses/LICENSE.md +179 -0
  56. lavavu_osmesa-1.9.9.dist-info/top_level.txt +1 -0
  57. lavavu_osmesa.libs/libLLVM-17-51492e70.so +0 -0
  58. lavavu_osmesa.libs/libOSMesa-f6a8f160.so.8.0.0 +0 -0
  59. lavavu_osmesa.libs/libdrm-b0291a67.so.2.4.0 +0 -0
  60. lavavu_osmesa.libs/libffi-3a37023a.so.6.0.2 +0 -0
  61. lavavu_osmesa.libs/libglapi-520b284c.so.0.0.0 +0 -0
  62. lavavu_osmesa.libs/libpcre2-8-516f4c9d.so.0.7.1 +0 -0
  63. lavavu_osmesa.libs/libselinux-d0805dcb.so.1 +0 -0
  64. lavavu_osmesa.libs/libtinfo-3a2cb85b.so.6.1 +0 -0
  65. lavavu_osmesa.libs/libzstd-76b78bac.so.1.4.4 +0 -0
lavavu/html/menu.js ADDED
@@ -0,0 +1,615 @@
1
+ /* dat.gui menu */
2
+
3
+ function parseColour(input) {
4
+ if (typeof(input) != 'object') {
5
+ //var div = document.createElement('div');
6
+ var div = document.getElementById('hidden_style_div');
7
+ div.style.color = input;
8
+ //This triggers a full layout calc - can slow things down
9
+ c = getComputedStyle(div).color;
10
+ o = getComputedStyle(div).opacity;
11
+ C = new Colour(c);
12
+ //c.alpha = o;
13
+ //toFixed() / 1 rounds to fixed position and removes trailing zeros
14
+ c.alpha = parseFloat(o).toFixed(2) / 1;
15
+ } else {
16
+ C = new Colour(input);
17
+ }
18
+ return C.html();
19
+ }
20
+
21
+ //Attempts to get range from data/volume objects for range controls
22
+ function menu_getrange(obj, ctrl) {
23
+ //Ranged?
24
+ if (ctrl.length > 1 && ctrl[1].length == 3) {
25
+ var range = [ctrl[1][0], ctrl[1][1]];
26
+ //Mapped range?
27
+ if (ctrl[1][0] === ctrl[1][1] && ctrl[1][0] === 0.0) {
28
+ //Try volume range
29
+ if (obj.volume && obj.volume.minimum < obj.volume.maximum)
30
+ range = [obj.volume.minimum, obj.volume.maximum];
31
+ //Or value data range
32
+ else if (obj.values && obj.values.minimum < obj.values.maximum)
33
+ range = [obj.values.minimum, obj.values.maximum];
34
+ }
35
+ if (range[1] <= range[0]) {
36
+ //console.log(obj.name + " : range (invalid) = " + range);
37
+ return [0.0, 1.0]; //No valid range data, use a default
38
+ }
39
+ //console.log(obj.name + " : range = " + range);
40
+ return range;
41
+ }
42
+ return null;
43
+ }
44
+
45
+ //Add controls to menu, using property metadata
46
+ function menu_addctrl(menu, obj, viewer, prop, changefn) {
47
+ //TODO: implement delayed high quality render for faster interaction
48
+ //var changefn = function(value) {viewer.delayedRender(250);};
49
+ var ctrl = viewer.dict[prop].control;
50
+
51
+ //Query prop dict for data type, default, min/max/step etc
52
+ var dtype = viewer.dict[prop].type;
53
+ if (prop === 'colourmap') {
54
+ var maps = ['']
55
+ for (var i=0; i<viewer.vis.colourmaps.length; i++)
56
+ maps.push(viewer.vis.colourmaps[i].name);
57
+ //console.log(JSON.stringify(maps));
58
+ menu.add(obj, prop, maps).onFinishChange(changefn);
59
+
60
+ } else if (ctrl.length > 2 && ctrl[2] != null) {
61
+ //Select from list of options
62
+ menu.add(obj, prop, ctrl[2]).onFinishChange(changefn);
63
+
64
+ } else if ((dtype.indexOf('real') >= 0 || dtype.indexOf('integer') >= 0)) { // && typeof(obj[prop]) == 'number') {
65
+
66
+ //Ranged?
67
+ var range = menu_getrange(obj, ctrl);
68
+ var addnumeric = function(menu, obj, prop, range, changefn) {
69
+ if (range) {
70
+ if (obj[prop] < range[0]) obj[prop] = range[0];
71
+ if (obj[prop] > range[1]) obj[prop] = range[1];
72
+ return menu.add(obj, prop, range[0], range[1], ctrl[1][2]).onFinishChange(changefn);
73
+ } else {
74
+ return menu.add(obj, prop).onFinishChange(changefn);
75
+ }
76
+ }
77
+
78
+ //Array quantities
79
+ var dims = 1;
80
+ var p0 = dtype.indexOf('[');
81
+ var p1 = dtype.indexOf(']');
82
+ if (p0 >= 0 && p1 >= 0)
83
+ dims = parseInt(dtype.slice(p0+1, p1));
84
+ if (dims > 1) {
85
+ //2d, 3d ?
86
+ for (var d=0; d<dims; d++) {
87
+ //console.log("Adding DIM " + d);
88
+ var added = addnumeric(menu, obj[prop], "" + d, range, changefn)
89
+ added.name(prop + '[' + d + ']');
90
+ }
91
+
92
+ //Only add if a number, anything else will cause dat.gui to error
93
+ } else if (typeof(obj[prop]) == 'number') {
94
+ //1d
95
+ console.log("Adding ", prop, typeof(obj[prop]));
96
+ addnumeric(menu, obj, prop, range, changefn)
97
+ }
98
+
99
+ } else if (dtype === 'string' || dtype === 'boolean') {
100
+ menu.add(obj, prop).onFinishChange(changefn);
101
+ } else if (dtype === 'boolean') {
102
+ menu.add(obj, prop).onFinishChange(changefn);
103
+ } else if (dtype === 'colour') {
104
+ try {
105
+ //Convert to html colour first
106
+ obj[prop] = parseColour(obj[prop]);
107
+ menu.addColor(obj, prop).onChange(changefn);
108
+ } catch(e) {
109
+ console.log(e);
110
+ }
111
+ }
112
+ }
113
+
114
+ function menu_addctrls(menu, obj, viewer, onchange) {
115
+ //Loop through every available property
116
+ var extras = [];
117
+ for (var prop in viewer.dict) {
118
+
119
+ //Check if it is enabled in GUI
120
+ var ctrl = viewer.dict[prop].control;
121
+ if (!ctrl || ctrl[0] === false) continue; //Control disabled
122
+
123
+ //Check if it has been set on the target object
124
+ if (prop in obj) {
125
+ //console.log(prop + " ==> " + JSON.stringify(viewer.dict[prop]));
126
+ try {
127
+ //Catch errors and continue gracefully
128
+ menu_addctrl(menu, obj, viewer, prop, onchange);
129
+ } catch(e) {
130
+ console.log("Error adding control to menu: " + e);
131
+ }
132
+
133
+ } else {
134
+ //Save list of properties without controls
135
+ extras.push(prop);
136
+ continue;
137
+ }
138
+ }
139
+
140
+ //Sort into alphabetical order
141
+ extras.sort();
142
+
143
+ //Add the extra properties to a dropdown list
144
+ //Selecting a property will add a controller for it
145
+ var propadd = {"properties" : ""};
146
+ var propselfn = function(prop) {
147
+ //Set the property to the default value
148
+ propadd.ref[prop] = viewer.dict[prop]["default"];
149
+ //Add new property controller
150
+ menu_addctrl(propadd.menu, propadd.ref, viewer, prop, onchange);
151
+ //Remove, then add the props list back at the bottom, minus new prop
152
+ propadd.menu.remove(propadd.controller);
153
+ //Save the new filtered list
154
+ propadd.list = propadd.list.filter(word => word != prop);
155
+ propadd.controller = propadd.menu.add(propadd, "properties", propadd.list).name("More properties").onFinishChange(propadd.fn);
156
+ }
157
+ propadd.controller = menu.add(propadd, "properties", extras).name("More properties").onFinishChange(propselfn);
158
+ propadd.ref = obj;
159
+ propadd.menu = menu;
160
+ propadd.fn = propselfn;
161
+ propadd.list = extras;
162
+ }
163
+
164
+
165
+ function menu_addcmaps(menu, obj, viewer, onchange) {
166
+ //Colourmap editing menu
167
+ if (viewer.cgui.prmenu) viewer.cgui.remove(viewer.cgui.prmenu);
168
+ if (viewer.cgui.cmenu) viewer.cgui.remove(viewer.cgui.cmenu);
169
+ if (viewer.cgui.pomenu) viewer.cgui.remove(viewer.cgui.pomenu);
170
+ viewer.cgui.prmenu = viewer.cgui.addFolder("Properties");
171
+ viewer.cgui.cmenu = viewer.cgui.addFolder("Colours");
172
+ viewer.cgui.pomenu = viewer.cgui.addFolder("Positions");
173
+ //Loop through every available property
174
+ for (var prop in viewer.dict) {
175
+ //Check if it is enabled in GUI
176
+ var ctrl = viewer.dict[prop].control;
177
+ if (!ctrl || ctrl[0] === false) continue; //Control disabled
178
+
179
+ //Check if it applies to colourmap object
180
+ if (viewer.dict[prop]["target"] == 'colourmap') {
181
+ //console.log(prop + " ==> " + JSON.stringify(viewer.dict[prop]));
182
+ //Need to add property default if not set
183
+ if (!obj[prop])
184
+ obj[prop] = viewer.dict[prop].default;
185
+ menu_addctrl(menu.prmenu, obj, viewer, prop, onchange);
186
+ }
187
+ }
188
+
189
+ var reload_onchange = function() {onchange("", true);};
190
+
191
+ //Loop through colours
192
+ menu.cmenu.add({"Add Colour" : function() {obj.colours.unshift({"colour" : "rgba(0,0,0,1)", "position" : 0.0}); viewer.gui.close(); reload_onchange(); }}, "Add Colour");
193
+ //Need to add delete buttons in closure to get correct pos/index
194
+ function del_btn(pos) {menu.pomenu.add({"Delete" : function() {obj.colours.splice(pos, 1); viewer.gui.close(); reload_onchange(); }}, 'Delete').name('Delete ' + pos);}
195
+ for (var c in obj.colours) {
196
+ var o = obj.colours[c];
197
+ //Convert to html colour first
198
+ o.colour = parseColour(o.colour);
199
+ o.opacity = 1.0;
200
+ menu.cmenu.addColor(o, 'colour').onChange(reload_onchange).name('Colour ' + c);
201
+ menu.pomenu.add(o, 'position', 0.0, 1.0, 0.01).onFinishChange(reload_onchange).name('Position ' + c);
202
+ del_btn(c);
203
+ }
204
+ }
205
+
206
+ function createMenu(viewer, onchange, webglmode, global) {
207
+ if (!dat) return null;
208
+ //var t0 = performance.now();
209
+
210
+ //Exists? Destroy
211
+ if (viewer.gui)
212
+ viewer.gui.destroy();
213
+
214
+ var el = null;
215
+ //Insert within element rather than whole document
216
+ if (!global && viewer.canvas && viewer.canvas.parentElement != document.body && viewer.canvas.parentElement.parentElement != document.body) {
217
+ var pel = viewer.canvas.parentElement;
218
+ //A bit of a hack to detect converted HTML output and skip going up two parent elements
219
+ if (pel.parentElement.className != 'section')
220
+ pel = pel.parentElement;
221
+ pel.style.position = 'relative'; //Parent element relative prevents menu escaping wrapper div
222
+ //Jupyter notebook overflow hacks (allows gui to be larger than cell)
223
+ var e = pel;
224
+ //These parent elements need 'overflow: visible' to prevent scrolling or cut-off of menu
225
+ //Add the "pgui" class to all the parent containers
226
+ while (e != document.body) {
227
+ e.classList.add("pgui");
228
+ e = e.parentElement;
229
+ }
230
+ //pel.style.overflow = 'visible'; //Parent element relative prevents menu escaping wrapper div
231
+ //pel.parentElement.style.overflow = 'visible'; //Parent element relative prevents menu escaping wrapper div
232
+ var id = 'dat_gui_menu_' + (viewer.canvas ? viewer.canvas.id : 'default');
233
+ el = document.getElementById(id)
234
+ if (el)
235
+ el.parentNode.removeChild(el);
236
+ el = document.createElement("div");
237
+ el.id = id;
238
+ el.style.cssText = "position: absolute; top: 0em; right: 0em; z-index: 255;";
239
+ pel.insertBefore(el, pel.childNodes[0]);
240
+ }
241
+
242
+ var gui;
243
+ //Insert within element rather than whole document
244
+ if (el) {
245
+ gui = new dat.GUI({ autoPlace: false, width: 275, hideable: false });
246
+ el.appendChild(gui.domElement);
247
+ } else {
248
+ gui = new dat.GUI({ hideable: false, width: 275 });
249
+ }
250
+
251
+ //Re-create menu on element mouse down if we need to reload
252
+ //(Instead of calling whenever state changes, re-creation is slow!)
253
+ gui.domElement.onmousedown = function(e) {
254
+ if (viewer.reloadgui)
255
+ viewer.menu();
256
+ return true;
257
+ }
258
+
259
+ //Horrible hack to stop codemirror stealing events when menu is over an editor element
260
+ gui.domElement.onmouseenter = function(e) {
261
+ //console.log('mouseenter');
262
+ var stylesheet = document.styleSheets[0];
263
+ stylesheet.insertRule('.CodeMirror-code { pointer-events: none;}', 0);
264
+ };
265
+
266
+ gui.domElement.onmouseleave = function(e) {
267
+ //console.log('mouseleave');
268
+ var stylesheet = document.styleSheets[0];
269
+ if (stylesheet.cssRules[0].cssText.indexOf('CodeMirror') >= 0)
270
+ stylesheet.deleteRule(0);
271
+ };
272
+
273
+ //Hidden element for style compute, required to be on page for chrome, can't just use createElement
274
+ var elem = document.getElementById('hidden_style_div');
275
+ if (!elem) {
276
+ elem = document.createElement('div');
277
+ elem.style.display = 'none';
278
+ elem.id = 'hidden_style_div';
279
+ document.body.appendChild(elem);
280
+ }
281
+
282
+ //Move above other controls
283
+ gui.domElement.parentElement.style.zIndex = '255';
284
+ //Save close button for hide menu check
285
+ gui.closebtn = gui.domElement.getElementsByClassName('close-button')[0];
286
+ //Hide/show on mouseover (only if overlapping)
287
+ if (!viewer.reloadgui) {
288
+ //Create closed and hidden for the first time, leave as is otherwise
289
+ gui.close();
290
+ hideMenu(viewer.canvas, gui);
291
+ }
292
+
293
+ gui.add({"Reload" : function() {viewer.reload();}}, "Reload");
294
+ //VR supported? (WebGL only)
295
+ if (webglmode === 1 && navigator.getVRDisplays) {
296
+ viewer.vrDisplay = null;
297
+ viewer.inVR = false;
298
+ gui.add({"VR Mode" : function() {start_VR(viewer);}}, 'VR Mode');
299
+ }
300
+
301
+ if (!!window.chrome) //Stupid chrome disabled data URL open
302
+ gui.add({"Export" : function() {var w = window.open(); w.document.write('<pre>' + viewer.toString() + '</pre>');}}, 'Export');
303
+ else
304
+ gui.add({"Export" : function() {window.open('data:application/json;base64,' + window.btoa(viewer.toString()));}}, 'Export');
305
+ //gui.add({"loadFile" : function() {document.getElementById('fileupload').click();}}, 'loadFile'). name('Load Image file');
306
+
307
+ //Non-persistent settings
308
+ gui.add(viewer, "mode", ['Rotate', 'Translate', 'Zoom']);
309
+ if (webglmode === 0) {
310
+ viewer.cmd = '';
311
+ gui.add(viewer, "cmd").onFinishChange(function(cmd) {if (cmd.length) {viewer.command(cmd); viewer.cmd = '';}}).name('Command');
312
+ }
313
+
314
+ //var s = gui.addFolder('Settings');
315
+ if (webglmode === 1) {
316
+ //Old WebGL 1.0 mode
317
+ gui.add(viewer.vis, "interactive").name("Interactive Render");
318
+ gui.add(viewer.vis, "immediatesort").name("Immediate Sort");
319
+ gui.add(viewer.vis, "sortenabled").name('Sort Enabled');
320
+ } else if (webglmode === 2) {
321
+ //Emscripten WebGL2 mode
322
+ gui.add({"Full Screen" : function() {Module.requestFullscreen(false,true);}}, 'Full Screen');
323
+ var params = {loadBrowserFile : function() { document.getElementById('fileinput').click(); } };
324
+ gui.add(params, 'loadBrowserFile').name('Load file');
325
+ gui.add({"Export GLDB" : function() {window.commands.push('export');}}, 'Export GLDB');
326
+ } else if (viewer.canvas) {
327
+ //Server render
328
+ gui.add(viewer, "alwaysdraw");
329
+ var url = viewer.canvas.imgtarget.baseurl;
330
+ if (url)
331
+ gui.add({"Popup Viewer" : function() {window.open(url, "LavaVu", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=no,width=1024,height=768");}}, 'Popup Viewer');
332
+ }
333
+
334
+ var g = gui.addFolder('Globals/Defaults');
335
+ menu_addctrls(g, viewer.vis.properties, viewer, onchange);
336
+
337
+ var v = gui.addFolder('Views');
338
+ var ir2 = 1.0 / Math.sqrt(2.0);
339
+ v.add({"Reset" : function() {viewer.reset(); }}, 'Reset');
340
+ v.add({"XY" : function() {viewer.syncRotation([0, 0, 0, 1]); }}, 'XY');
341
+ v.add({"YX" : function() {viewer.syncRotation([0, 1, 0, 0]);}}, 'YX');
342
+ v.add({"XZ" : function() {viewer.syncRotation([ir2, 0, 0, -ir2]);}}, 'XZ');
343
+ v.add({"ZX" : function() {viewer.syncRotation([ir2, 0, 0, ir2]);}}, 'ZX');
344
+ v.add({"YZ" : function() {viewer.syncRotation([0, -ir2, 0, -ir2]);}}, 'YZ');
345
+ v.add({"ZY" : function() {viewer.syncRotation([0, -ir2, 0, ir2]);}}, 'ZY');
346
+ //console.log(JSON.stringify(viewer.view));
347
+ if (viewer.view)
348
+ menu_addctrls(v, viewer.view, viewer, onchange);
349
+ else
350
+ menu_addctrls(v, viewer.vis.views[0], viewer, onchange);
351
+
352
+ var o = gui.addFolder('Objects');
353
+ for (var id in viewer.vis.objects) {
354
+ var of = o.addFolder(viewer.vis.objects[id].name);
355
+ menu_addctrls(of, viewer.vis.objects[id], viewer, onchange);
356
+ }
357
+
358
+ viewer.gui = gui;
359
+ if (!viewer.selectedcolourmap) {
360
+ viewer.selectedcolourmap = "";
361
+ viewer.newcolourmap = "";
362
+ }
363
+ viewer.cgui = viewer.gui.addFolder('ColourMaps');
364
+
365
+ createColourMapMenu(viewer, onchange, webglmode === 1);
366
+
367
+ //var t1 = performance.now();
368
+ //console.log("Call to menu() took " + (t1 - t0) + " milliseconds.")
369
+ }
370
+
371
+ function createColourMapMenu(viewer, onchange, webglmode) {
372
+ //Remove existing entries
373
+ for (var i in viewer.cgui.__controllers)
374
+ viewer.cgui.__controllers[i].remove();
375
+
376
+ var cms = [];
377
+
378
+ //Dropdown to select a colourmap, when selected the editing menu will be populated
379
+ for (var id in viewer.vis.colourmaps)
380
+ cms.push(viewer.vis.colourmaps[id].name);
381
+
382
+ if (webglmode) {
383
+ //Add a default colourmap
384
+ viewer.cgui.add({"Add" : function() {viewer.addColourMap(); viewer.gui.close();}}, 'Add');
385
+ } else {
386
+ //Add a colourmap from list of defaults
387
+ cmapaddfn = function(value) {
388
+ if (!value || !value.length) return;
389
+ viewer.command("select; colourmap " + value + " " + value);
390
+ viewer.gui.close();
391
+ };
392
+
393
+ viewer.cgui.add(viewer, "newcolourmap", viewer.defaultcolourmaps).onFinishChange(cmapaddfn).name("Add");
394
+ }
395
+
396
+ //Do the rest only if colourmaps exist...
397
+ if (cms.length == 0) return;
398
+
399
+ //When selected, populate the Colours & Positions menus
400
+ cmapselfn = function(value) {
401
+ if (!value) return;
402
+ for (var id in viewer.vis.colourmaps) {
403
+ if (value == viewer.vis.colourmaps[id].name)
404
+ menu_addcmaps(viewer.cgui, viewer.vis.colourmaps[id], viewer, onchange);
405
+ }
406
+ };
407
+
408
+ viewer.cgui.cmap = viewer.cgui.add(viewer, "selectedcolourmap", cms).onFinishChange(cmapselfn).name("Colourmap");
409
+
410
+ //Re-select if previous value if any
411
+ if (viewer.selectedcolourmap)
412
+ cmapselfn(viewer.selectedcolourmap);
413
+ }
414
+
415
+ function updateMenu(viewer, onchange) {
416
+ //Attempt to update DAT.GUI controls
417
+ function updateDisplay(gui) {
418
+ for (var i in gui.__controllers)
419
+ gui.__controllers[i].updateDisplay();
420
+ for (var f in gui.__folders)
421
+ updateDisplay(gui.__folders[f]);
422
+ }
423
+ updateDisplay(viewer.gui);
424
+ updateDisplay(viewer.cgui);
425
+ }
426
+
427
+ function hideMenu(canvas, gui) {
428
+ //No menu, but hide the mode controls
429
+ if (!gui) {
430
+ if (canvas && canvas.imgtarget)
431
+ canvas.imgtarget.nextElementSibling.style.display = "none";
432
+ return;
433
+ }
434
+
435
+ //Requires menu to be closed and hiding enabled
436
+ if (!gui.closed) return;
437
+
438
+ //Only hide if overlapping the canvas (unless no canvas passed)
439
+ if (canvas) {
440
+ var rect0 = gui.closebtn.getBoundingClientRect();
441
+ var rect1 = canvas.getBoundingClientRect();
442
+ if (rect0.right < rect1.left || rect0.left > rect1.right ||
443
+ rect0.bottom < rect1.top || rect0.top > rect1.bottom) {
444
+ //No overlap, don't hide
445
+ return;
446
+ }
447
+ }
448
+
449
+ //Reached this point? Menu needs hiding
450
+ gui.domElement.style.display = "none";
451
+ }
452
+
453
+ //https://hacks.mozilla.org/2018/09/converting-a-webgl-application-to-webvr/
454
+ //https://github.com/Manishearth/webgl-to-webvr/
455
+ // This function is triggered when the user clicks the "enter VR" button
456
+ function start_VR(viewer) {
457
+ if (viewer.vrDisplay != null) {
458
+ if (!viewer.inVR) {
459
+ viewer.inVR = true;
460
+ // hand the canvas to the WebVR API
461
+ viewer.vrDisplay.requestPresent([{ source: viewer.canvas }]);
462
+ // requestPresent() will request permission to enter VR mode,
463
+ // and once the user has done this our `vrdisplaypresentchange`
464
+ // callback will be triggered
465
+
466
+ //Show stats
467
+ if (!document.getElementById("stats_info")) {
468
+ var stats = new Stats();
469
+ document.body.appendChild(stats.dom);
470
+ requestAnimationFrame(function loop() {
471
+ stats.update();
472
+ requestAnimationFrame(loop)
473
+ });
474
+ }
475
+
476
+ } else {
477
+ stop_VR(viewer);
478
+ }
479
+ }
480
+ }
481
+
482
+ function stop_VR(viewer) {
483
+ viewer.inVR = false;
484
+ // resize canvas to regular non-VR size if necessary
485
+ viewer.width = 0; //Auto resize
486
+ viewer.height = 0;
487
+ viewer.canvas.style.width = "100%";
488
+ viewer.canvas.style.height = "100%";
489
+
490
+ viewer.drawFrame();
491
+ viewer.draw();
492
+ }
493
+
494
+ function setup_VR(viewer) {
495
+ if (!navigator.getVRDisplays) {
496
+ alert("Your browser does not support WebVR");
497
+ return;
498
+ }
499
+
500
+ function display_setup(displays) {
501
+ if (displays.length === 0)
502
+ return;
503
+ //Use last in list
504
+ viewer.vrDisplay = displays[displays.length-1];
505
+ }
506
+
507
+ navigator.getVRDisplays().then(display_setup);
508
+
509
+ function VR_change() {
510
+ // no VR display, exit
511
+ if (viewer.vrDisplay == null)
512
+ return;
513
+
514
+ // are we entering or exiting VR?
515
+ if (viewer.vrDisplay.isPresenting) {
516
+ // optional, but recommended
517
+ viewer.vrDisplay.depthNear = viewer.near_clip;
518
+ viewer.vrDisplay.depthFar = viewer.far_clip;
519
+
520
+ // We should make our canvas the size expected
521
+ // by WebVR
522
+ const eye = viewer.vrDisplay.getEyeParameters("left");
523
+ // multiply by two since we're rendering both eyes side
524
+ // by side
525
+ viewer.width = eye.renderWidth * 2;
526
+ viewer.height = eye.renderHeight;
527
+ viewer.canvas.style.width = viewer.width + "px";
528
+ viewer.canvas.style.height = viewer.height + "px";
529
+ viewer.canvas.width = viewer.canvas.clientWidth;
530
+ viewer.canvas.height = viewer.canvas.clientHeight;
531
+
532
+ const vrCallback = () => {
533
+ if (viewer.vrDisplay == null || !viewer.inVR)
534
+ return;
535
+
536
+ // reregister callback if we're still in VR
537
+ viewer.vrDisplay.requestAnimationFrame(vrCallback);
538
+
539
+ // render scene
540
+ renderVR(viewer);
541
+ };
542
+
543
+ // register callback
544
+ viewer.vrDisplay.requestAnimationFrame(vrCallback);
545
+
546
+ } else {
547
+ stop_VR(viewer);
548
+ }
549
+ }
550
+
551
+ window.addEventListener('vrdisplaypresentchange', VR_change);
552
+ }
553
+
554
+ function renderVR(viewer) {
555
+ //Clear full canvas
556
+ viewer.gl.viewport(0, 0, viewer.canvas.width, viewer.canvas.height);
557
+ viewer.gl.clear(viewer.gl.COLOR_BUFFER_BIT | viewer.gl.DEPTH_BUFFER_BIT);
558
+
559
+ //Left eye
560
+ renderEye(viewer, true);
561
+
562
+ //Right eye
563
+ renderEye(viewer, false);
564
+
565
+ viewer.vrDisplay.submitFrame();
566
+ }
567
+
568
+ function renderEye(viewer, isLeft) {
569
+ let projection, mview;
570
+ let frameData = new VRFrameData();
571
+ var gl = viewer.webgl.gl;
572
+ var width = viewer.canvas.width / 2;
573
+ var height = viewer.canvas.height;
574
+
575
+ viewer.vrDisplay.getFrameData(frameData);
576
+
577
+ // choose which half of the canvas to draw on
578
+ if (isLeft) {
579
+ viewer.webgl.viewport = new Viewport(0, 0, width, height);
580
+ gl.viewport(0, 0, width, height);
581
+ //Apply the default camera
582
+ viewer.webgl.apply(viewer);
583
+
584
+ projection = frameData.leftProjectionMatrix;
585
+ mview = frameData.leftViewMatrix;
586
+ } else {
587
+ viewer.webgl.viewport = new Viewport(width, 0, width, height);
588
+ gl.viewport(width, 0, width, height);
589
+ //viewer.webgl.viewport = new Viewport(0, 0, width, height);
590
+ //gl.viewport(0, 0, width, height);
591
+ projection = frameData.rightProjectionMatrix;
592
+ mview = frameData.rightViewMatrix;
593
+ }
594
+
595
+ //Apply the default camera
596
+ viewer.webgl.apply(viewer);
597
+
598
+ //Update matrices with VR modified versions
599
+ //mat4.multiply(mview, viewer.webgl.modelView.matrix);
600
+ //viewer.webgl.modelView.matrix = mview;
601
+ mat4.multiply(viewer.webgl.modelView.matrix, mview);
602
+ //console.log(isLeft ? "LEFT " : "RIGHT "); printMatrix(mview);
603
+ //gl.uniformMatrix4fv(viewer.webgl.program.mvMatrixUniform, false, mview);
604
+
605
+ viewer.webgl.projection.matrix = projection;
606
+
607
+ //Render objects
608
+ for (var r in viewer.renderers) {
609
+ if (viewer.renderers[r].border && !viewer.showBorder) continue;
610
+ viewer.renderers[r].draw();
611
+ }
612
+
613
+ viewer.rotated = false; //Clear rotation flag
614
+ }
615
+