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.
- lavavu/LavaVuPython.py +561 -0
- lavavu/_LavaVuPython.cpython-313-x86_64-linux-gnu.so +0 -0
- lavavu/__init__.py +15 -0
- lavavu/__main__.py +12 -0
- lavavu/amalgamate.py +15 -0
- lavavu/aserver.py +359 -0
- lavavu/control.py +1731 -0
- lavavu/convert.py +888 -0
- lavavu/dict.json +2528 -0
- lavavu/font.bin +0 -0
- lavavu/html/LavaVu-amalgamated.css +282 -0
- lavavu/html/OK-min.js +99 -0
- lavavu/html/baseviewer.js +307 -0
- lavavu/html/control.css +104 -0
- lavavu/html/control.js +340 -0
- lavavu/html/dat-gui-light-theme.css +68 -0
- lavavu/html/dat.gui.min.js +2 -0
- lavavu/html/draw.js +2259 -0
- lavavu/html/drawbox.js +1039 -0
- lavavu/html/emscripten-template.js +184 -0
- lavavu/html/emscripten.css +92 -0
- lavavu/html/favicon.ico +0 -0
- lavavu/html/gl-matrix-min.js +47 -0
- lavavu/html/gui.css +25 -0
- lavavu/html/menu.js +615 -0
- lavavu/html/server.js +226 -0
- lavavu/html/stats.min.js +5 -0
- lavavu/html/styles.css +58 -0
- lavavu/html/webview-template.html +43 -0
- lavavu/html/webview.html +43 -0
- lavavu/lavavu.py +6200 -0
- lavavu/osmesa/LavaVuPython.py +561 -0
- lavavu/osmesa/_LavaVuPython.cpython-313-x86_64-linux-gnu.so +0 -0
- lavavu/osmesa/__init__.py +0 -0
- lavavu/points.py +191 -0
- lavavu/server.py +343 -0
- lavavu/shaders/default.frag +14 -0
- lavavu/shaders/default.vert +17 -0
- lavavu/shaders/fontShader.frag +20 -0
- lavavu/shaders/fontShader.vert +18 -0
- lavavu/shaders/lineShader.frag +39 -0
- lavavu/shaders/lineShader.vert +26 -0
- lavavu/shaders/pointShader.frag +127 -0
- lavavu/shaders/pointShader.vert +53 -0
- lavavu/shaders/triShader.frag +153 -0
- lavavu/shaders/triShader.vert +49 -0
- lavavu/shaders/volumeShader.frag +400 -0
- lavavu/shaders/volumeShader.vert +5 -0
- lavavu/tracers.py +207 -0
- lavavu/vutils.py +211 -0
- lavavu_osmesa-1.9.9.dist-info/METADATA +323 -0
- lavavu_osmesa-1.9.9.dist-info/RECORD +65 -0
- lavavu_osmesa-1.9.9.dist-info/WHEEL +5 -0
- lavavu_osmesa-1.9.9.dist-info/entry_points.txt +2 -0
- lavavu_osmesa-1.9.9.dist-info/licenses/LICENSE.md +179 -0
- lavavu_osmesa-1.9.9.dist-info/top_level.txt +1 -0
- lavavu_osmesa.libs/libLLVM-17-51492e70.so +0 -0
- lavavu_osmesa.libs/libOSMesa-f6a8f160.so.8.0.0 +0 -0
- lavavu_osmesa.libs/libdrm-b0291a67.so.2.4.0 +0 -0
- lavavu_osmesa.libs/libffi-3a37023a.so.6.0.2 +0 -0
- lavavu_osmesa.libs/libglapi-520b284c.so.0.0.0 +0 -0
- lavavu_osmesa.libs/libpcre2-8-516f4c9d.so.0.7.1 +0 -0
- lavavu_osmesa.libs/libselinux-d0805dcb.so.1 +0 -0
- lavavu_osmesa.libs/libtinfo-3a2cb85b.so.6.1 +0 -0
- 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
|
+
|