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/drawbox.js ADDED
@@ -0,0 +1,1039 @@
1
+ //Bounding box only in WebGL
2
+ //Urgent TODO: move shared code with draw.js into common file
3
+ //maintaining two copies currently!
4
+ //Re-init using previous callback data
5
+
6
+ function initBox(el, cmd_callback, fixedsize) {
7
+ //console.log("INITBOX: " + el.id);
8
+ var canvas = document.createElement("canvas");
9
+ canvas.classList.add("resized");
10
+ if (!el) el = document.body.firstChild;
11
+ canvas.id = "canvas_" + el.id;
12
+ canvas.imgtarget = el
13
+ el.parentElement.appendChild(canvas);
14
+ canvas.style.cssText = "position: absolute; width: 100%; height: 100%; margin: 0px; padding: 0px; top: 0; left: 0; bottom: 0; right: 0; z-index: 11; border: none;"
15
+ var viewer = new BoxViewer(canvas);
16
+
17
+ //Canvas event handling
18
+ canvas.mouse = new Mouse(canvas, new MouseEventHandler(canvasBoxMouseClick, canvasBoxMouseWheel, canvasBoxMouseMove, canvasBoxMouseDown, null, null, canvasBoxMousePinch));
19
+ //Following two settings should probably be defaults?
20
+ canvas.mouse.moveUpdate = true; //Continual update of deltaX/Y
21
+ //canvas.mouse.setDefault();
22
+ canvas.mouse.wheelTimer = true; //Accumulate wheel scroll (prevents too many events backing up)
23
+ defaultMouse = document.mouse = canvas.mouse;
24
+
25
+ //Attach viewer object to canvas
26
+ canvas.viewer = viewer;
27
+
28
+ //Disable context menu and prevent bubbling
29
+ canvas.addEventListener('contextmenu', e => {e.preventDefault(); e.stopPropagation();});
30
+
31
+ //Command callback function
32
+ viewer.command = cmd_callback;
33
+
34
+ //Data dict and colourmap names stored in globals
35
+ viewer.dict = window.dictionary;
36
+ viewer.defaultcolourmaps = window.defaultcolourmaps;
37
+
38
+ //Enable to forward key presses to server directly
39
+ //(only used for full size viewers)
40
+ if (fixedsize == 1)
41
+ document.addEventListener('keyup', function(event) {keyPress(event, viewer);});
42
+
43
+ return viewer;
44
+ }
45
+
46
+ function keyModifiers(event) {
47
+ modifiers = '';
48
+ if (event.ctrlKey) modifiers += 'C';
49
+ if (event.shiftKey) modifiers += 'S';
50
+ if (event.altKey) modifiers += 'A';
51
+ if (event.metaKey) modifiers += 'M';
52
+ return modifiers;
53
+ }
54
+
55
+ function keyPress(event, viewer) {
56
+ // space and arrow keys, prevent scrolling
57
+ if ([' ', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key))
58
+ event.preventDefault();
59
+
60
+ if (event.target.tagName == 'INPUT') return;
61
+
62
+ //Special key codes
63
+ if (event.key == 'ArrowUp') key = 17;
64
+ else if (event.key == 'ArrowDown') key = 18;
65
+ else if (event.key == 'ArrowLeft') key = 20;
66
+ else if (event.key == 'ArrowRight') key = 19;
67
+ else if (event.key == 'PageUp') key = 24;
68
+ else if (event.key == 'PageDown') key = 25;
69
+ else if (event.key == 'PageUp') key = 24;
70
+ else if (event.key == 'Home') key = 22;
71
+ else if (event.key == 'End') key = 23;
72
+ else if (event.key == 'Backspace') key = 8;
73
+ else if (event.key == 'Tab') key = 9;
74
+ else if (event.key == 'Escape') key = 27;
75
+ else if (event.key == 'Enter') key = 13;
76
+ else if (event.key == 'Insert') key = 21;
77
+ else if (event.key == 'Delete') key = 127;
78
+ else if (event.key[0] == 'F' && event.key.length > 1)
79
+ key = 189 + parseInt(event.key.substr(1));
80
+ else if (event.key.length == 1) {
81
+ key = event.key.charCodeAt(0);
82
+ if (key > 127 && event.code.length == 4 && event.code.substr(0,3) == 'Key')
83
+ key = event.code.charCodeAt(3);
84
+ } else
85
+ return;
86
+
87
+ //console.log(event.key);
88
+ //console.log(event.code);
89
+ //console.log(key);
90
+
91
+ var modifiers = keyModifiers(event);
92
+
93
+ //Ignore CTRL+R, CTRL+SHIFT+R
94
+ if (key == 114 && modifiers == 'C' || key == 82 && modifiers == 'CS') return;
95
+
96
+ cmd = 'key key=' + key + ',modifiers=' + modifiers + ",x=" + defaultMouse.x + ",y=" + defaultMouse.y;
97
+ //console.log(cmd);
98
+ viewer.command(cmd);
99
+ }
100
+
101
+ function canvasBoxMouseClick(event, mouse) {
102
+ mouse.element.viewer.check_context(mouse);
103
+
104
+ if (mouse.element.viewer.rotating)
105
+ mouse.element.viewer.command('' + mouse.element.viewer.getRotationString());
106
+ else
107
+ mouse.element.viewer.command('' + mouse.element.viewer.getTranslationString());
108
+
109
+ if (mouse.element.viewer.rotating) {
110
+ mouse.element.viewer.rotating = false;
111
+ //mouse.element.viewer.reload = true;
112
+ }
113
+
114
+ //Clear the webgl box
115
+ mouse.element.viewer.clear();
116
+
117
+ return false;
118
+ }
119
+
120
+ function canvasBoxMouseDown(event, mouse) {
121
+ mouse.element.viewer.check_context(mouse);
122
+ //Just draw so the box appears
123
+ mouse.element.viewer.draw();
124
+ return false;
125
+ }
126
+
127
+ var hideBoxTimer;
128
+
129
+ function canvasBoxMouseMove(event, mouse) {
130
+ //GUI elements to show on mouseover
131
+ if (mouse.element && mouse.element.viewer && Object.keys(mouse.element.viewer.vis).length) {
132
+ var gui = mouse.element.viewer.gui;
133
+ var rect = mouse.element.getBoundingClientRect();
134
+ x = event.clientX-rect.left;
135
+ y = event.clientY-rect.top;
136
+ if (x >= 0 && y >= 0 && x < rect.width && y < rect.height) {
137
+ if (!gui && mouse.element.imgtarget)
138
+ mouse.element.imgtarget.nextElementSibling.style.display = "block";
139
+
140
+ if (gui) {
141
+ if (mouse.element.imgtarget) mouse.element.imgtarget.nextElementSibling.style.display = "none";
142
+ gui.domElement.style.display = "block";
143
+ }
144
+
145
+ if (hideBoxTimer)
146
+ clearTimeout(hideBoxTimer);
147
+
148
+ hideBoxTimer = setTimeout(function () { hideMenu(mouse.element, gui);}, 1000 );
149
+ }
150
+ }
151
+
152
+ if (!mouse.isdown || !mouse.element.viewer) return true;
153
+ mouse.element.viewer.rotating = false;
154
+
155
+ //Switch buttons for translate/rotate
156
+ var button = mouse.button;
157
+
158
+ if (mouse.element.viewer.mode == "Translate") {
159
+ //Swap rotate/translate buttons
160
+ if (button == 0)
161
+ button = 2
162
+ else if (button == 2)
163
+ button = 0;
164
+ } else if (button==0 && mouse.element.viewer.mode == "Zoom") {
165
+ button = 100;
166
+ }
167
+
168
+ //console.log(mouse.deltaX + "," + mouse.deltaY);
169
+ switch (button)
170
+ {
171
+ case 0:
172
+ mouse.element.viewer.rotateY(mouse.deltaX/5);
173
+ mouse.element.viewer.rotateX(mouse.deltaY/5);
174
+ mouse.element.viewer.rotating = true;
175
+ break;
176
+ case 1:
177
+ mouse.element.viewer.rotateZ(Math.sqrt(mouse.deltaX*mouse.deltaX + mouse.deltaY*mouse.deltaY)/5);
178
+ mouse.element.viewer.rotating = true;
179
+ break;
180
+ case 2:
181
+ var adjust = mouse.element.viewer.modelsize / 1000; //1/1000th of size
182
+ mouse.element.viewer.translate[0] += mouse.deltaX * adjust;
183
+ mouse.element.viewer.translate[1] -= mouse.deltaY * adjust;
184
+ break;
185
+ case 100:
186
+ var adjust = mouse.element.viewer.modelsize / 1000; //1/1000th of size
187
+ mouse.element.viewer.translate[2] += mouse.deltaX * adjust;
188
+ break;
189
+ }
190
+
191
+ mouse.element.viewer.draw();
192
+
193
+ //Instant updates
194
+ if (mouse.element.viewer.alwaysdraw) {
195
+ if (mouse.element.viewer.rotating)
196
+ mouse.element.viewer.command('' + mouse.element.viewer.getRotationString());
197
+ else
198
+ mouse.element.viewer.command('' + mouse.element.viewer.getTranslationString());
199
+ }
200
+
201
+ return false;
202
+ }
203
+
204
+ function canvasBoxMouseWheel(event, mouse) {
205
+ mouse.element.viewer.check_context(mouse);
206
+ var scroll = event.deltaY < 0 ? 0.01 : -0.01;
207
+ //console.log(event.shiftKey,event.deltaY * -0.01);
208
+ if (event.shiftKey) {
209
+ mouse.element.viewer.zoomClip(scroll);
210
+ //mouse.element.viewer.zoomClip(event.spin*0.01);
211
+ } else {
212
+ mouse.element.viewer.zoom(scroll);
213
+ //mouse.element.viewer.zoom(event.spin*0.01);
214
+ }
215
+ return false; //Prevent default
216
+ }
217
+
218
+ function canvasBoxMousePinch(event, mouse) {
219
+ mouse.element.viewer.check_context(mouse);
220
+ if (event.distance != 0) {
221
+ var factor = event.distance * 0.0001;
222
+ mouse.element.viewer.zoom(factor);
223
+ //Clear the box after a second
224
+ setTimeout(function() {mouse.element.viewer.clear();}, 1000);
225
+ }
226
+ return false; //Prevent default
227
+ }
228
+
229
+ //This object encapsulates a vertex buffer and shader set
230
+ function BoxRenderer(gl, colour) {
231
+ this.gl = gl;
232
+ if (colour)
233
+ this.colour = colour;
234
+ else
235
+ this.colour = [0.5, 0.5, 0.5, 1.0];
236
+
237
+ //Line renderer
238
+ this.attribSizes = [3 * Float32Array.BYTES_PER_ELEMENT];
239
+
240
+ this.elements = 0;
241
+ this.elementSize = 0;
242
+ for (var i=0; i<this.attribSizes.length; i++)
243
+ this.elementSize += this.attribSizes[i];
244
+ }
245
+
246
+ var vs = "precision highp float; \n \
247
+ attribute vec3 aVertexPosition; \n \
248
+ attribute vec4 aVertexColour; \n \
249
+ uniform mat4 uMVMatrix; \n \
250
+ uniform mat4 uPMatrix; \n \
251
+ uniform vec4 uColour; \n \
252
+ varying vec4 vColour; \n \
253
+ void main(void) \n \
254
+ { \n \
255
+ vec4 mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0); \n \
256
+ gl_Position = uPMatrix * mvPosition; \n \
257
+ vColour = uColour; \n \
258
+ }";
259
+
260
+ var fs = "precision highp float; \n \
261
+ varying vec4 vColour; \n \
262
+ void main(void) \n \
263
+ { \n \
264
+ gl_FragColor = vColour; \n \
265
+ }";
266
+
267
+ BoxRenderer.prototype.init = function() {
268
+ //Compile the shaders
269
+ this.program = new WebGLProgram(this.gl, vs, fs);
270
+ if (this.program.errors) console.log(this.program.errors);
271
+ //Setup attribs/uniforms (flag set to skip enabling attribs)
272
+ this.program.setup(undefined, undefined, true);
273
+
274
+ return true;
275
+ }
276
+
277
+ BoxRenderer.prototype.updateBuffers = function(view) {
278
+ //Create buffer if not yet allocated
279
+ if (this.vertexBuffer == undefined) {
280
+ //Init shaders etc...
281
+ if (!this.init()) return;
282
+ this.vertexBuffer = this.gl.createBuffer();
283
+ this.indexBuffer = this.gl.createBuffer();
284
+ }
285
+
286
+ //Bind buffers
287
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
288
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
289
+
290
+ this.box(view.min, view.max);
291
+ }
292
+
293
+ BoxRenderer.prototype.box = function(min, max) {
294
+ var zero = [min[0]+0.5*(max[0] - min[0]), min[1]+0.5*(max[1] - min[1]), min[2]+0.5*(max[2] - min[2])];
295
+ var min10 = [min[0] + 0.45*(max[0] - min[0]), min[1]+0.45*(max[1] - min[1]), min[2]+0.45*(max[2] - min[2])];
296
+ var max10 = [min[0] + 0.55*(max[0] - min[0]), min[1]+0.55*(max[1] - min[1]), min[2]+0.55*(max[2] - min[2])];
297
+ var vertices = new Float32Array(
298
+ [
299
+ /* Bounding box */
300
+ min[0], min[1], max[2],
301
+ min[0], max[1], max[2],
302
+ max[0], max[1], max[2],
303
+ max[0], min[1], max[2],
304
+ min[0], min[1], min[2],
305
+ min[0], max[1], min[2],
306
+ max[0], max[1], min[2],
307
+ max[0], min[1], min[2],
308
+ /* 10% box */
309
+ min10[0], min10[1], max10[2],
310
+ min10[0], max10[1], max10[2],
311
+ max10[0], max10[1], max10[2],
312
+ max10[0], min10[1], max10[2],
313
+ min10[0], min10[1], min10[2],
314
+ min10[0], max10[1], min10[2],
315
+ max10[0], max10[1], min10[2],
316
+ max10[0], min10[1], min10[2],
317
+ /* Axis lines */
318
+ min[0], zero[1], zero[2],
319
+ max[0], zero[1], zero[2],
320
+ zero[0], min[1], zero[2],
321
+ zero[0], max[1], zero[2],
322
+ zero[0], zero[1], min[2],
323
+ zero[0], zero[1], max[2]
324
+ ]);
325
+
326
+ var indices = new Uint16Array(
327
+ [
328
+ /* Bounding box */
329
+ 0, 1, 1, 2, 2, 3, 3, 0,
330
+ 4, 5, 5, 6, 6, 7, 7, 4,
331
+ 0, 4, 3, 7, 1, 5, 2, 6,
332
+ /* 10% box */
333
+ 8, 9, 9, 10, 10, 11, 11, 8,
334
+ 12, 13, 13, 14, 14, 15, 15, 12,
335
+ 8, 12, 11, 15, 9, 13, 10, 14,
336
+ /* Axis lines */
337
+ 16, 17,
338
+ 18, 19,
339
+ 20, 21
340
+ ]
341
+ );
342
+ this.gl.bufferData(this.gl.ARRAY_BUFFER, vertices, this.gl.STATIC_DRAW);
343
+ this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, indices, this.gl.STATIC_DRAW);
344
+ this.elements = 24+24+6;
345
+ }
346
+
347
+ BoxRenderer.prototype.draw = function(webgl, nobox, noaxes) {
348
+ if (!this.elements) return;
349
+
350
+ if (this.program.attributes["aVertexPosition"] == undefined) return; //Require vertex buffer
351
+
352
+ webgl.use(this.program);
353
+ webgl.setMatrices();
354
+
355
+ //Bind buffers
356
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
357
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
358
+
359
+ //Enable attributes
360
+ for (var key in this.program.attributes)
361
+ this.gl.enableVertexAttribArray(this.program.attributes[key]);
362
+
363
+
364
+ //Line box render
365
+ this.gl.vertexAttribPointer(this.program.attributes["aVertexPosition"], 3, this.gl.FLOAT, false, 0, 0);
366
+ //Bounding box
367
+ if (!nobox) {
368
+ this.gl.uniform4f(this.program.uniforms["uColour"], this.colour[0], this.colour[1], this.colour[2], this.colour[3]);
369
+ this.gl.drawElements(this.gl.LINES, 24, this.gl.UNSIGNED_SHORT, 0);
370
+ }
371
+
372
+ //10% box (always draw)
373
+ this.gl.drawElements(this.gl.LINES, 24, this.gl.UNSIGNED_SHORT, 24 * 2);
374
+
375
+ //Axes (2 bytes per unsigned short)
376
+ if (!noaxes) {
377
+ this.gl.uniform4f(this.program.uniforms["uColour"], 1.0, 0.0, 0.0, 1.0);
378
+ this.gl.drawElements(this.gl.LINES, 2, this.gl.UNSIGNED_SHORT, (24+24) * 2);
379
+ this.gl.uniform4f(this.program.uniforms["uColour"], 0.0, 1.0, 0.0, 1.0);
380
+ this.gl.drawElements(this.gl.LINES, 2, this.gl.UNSIGNED_SHORT, (24+24+2) * 2);
381
+ this.gl.uniform4f(this.program.uniforms["uColour"], 0.0, 0.0, 1.0, 1.0);
382
+ this.gl.drawElements(this.gl.LINES, 2, this.gl.UNSIGNED_SHORT, (24+24+4) * 2);
383
+ }
384
+
385
+ //Disable attribs
386
+ for (var key in this.program.attributes)
387
+ this.gl.disableVertexAttribArray(this.program.attributes[key]);
388
+
389
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
390
+ this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);
391
+ this.gl.useProgram(null);
392
+ }
393
+
394
+ //This object holds the viewer details and calls the renderers
395
+ function BoxViewer(canvas) {
396
+ this.vis = {};
397
+ this.vis.objects = [];
398
+ this.vis.colourmaps = [];
399
+ this.canvas = canvas;
400
+ if (!canvas) {alert("Invalid Canvas"); return;}
401
+ try {
402
+ this.webgl = new WebGL(this.canvas, {antialias: true}); //, premultipliedAlpha: false});
403
+ this.gl = this.webgl.gl;
404
+ canvas.addEventListener("webglcontextlost", function(event) {
405
+ //event.preventDefault();
406
+ console.log("Context loss detected, clearing data/state and flagging defunct");
407
+ this.mouse.lostContext = true;
408
+ }, false);
409
+
410
+ canvas.addEventListener("webglcontextrestored", function(event) {
411
+ console.log("Context restored");
412
+ }, false);
413
+
414
+ } catch(e) {
415
+ //No WebGL
416
+ console.log("No WebGL: " + e);
417
+ }
418
+
419
+ this.rotating = false;
420
+ this.translate = [0,0,0];
421
+ this.rotate = quat4.create();
422
+ quat4.identity(this.rotate);
423
+ this.fov = 45;
424
+ this.focus = [0,0,0];
425
+ this.centre = [0,0,0];
426
+ this.near_clip = this.far_clip = 0.0;
427
+ this.modelsize = 1;
428
+ this.scale = [1, 1, 1];
429
+ this.orientation = 1.0; //1.0 for RH, -1.0 for LH
430
+
431
+ //Non-persistant settings
432
+ this.mode = 'Rotate';
433
+ this.alwaysdraw = false;
434
+ if (!this.gl) return;
435
+
436
+ //Create the renderers
437
+ this.border = new BoxRenderer(this.gl, [0.5,0.5,0.5,1]);
438
+
439
+ this.gl.enable(this.gl.DEPTH_TEST);
440
+ this.gl.depthFunc(this.gl.LEQUAL);
441
+ //this.gl.depthMask(this.gl.FALSE);
442
+ this.gl.enable(this.gl.BLEND);
443
+ //this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
444
+ //this.gl.blendFuncSeparate(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA, this.gl.ZERO, this.gl.ONE);
445
+ this.gl.blendFuncSeparate(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA, this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA);
446
+ }
447
+
448
+ BoxViewer.prototype.check_context = function(mouse) {
449
+ if (mouse.lostContext) {
450
+ console.log("Recreating viewer after context loss");
451
+ //Reinit on timer? on click?
452
+ var box = initBox(this.canvas.imgtarget, this.command);
453
+ box.loadFile(JSON.stringify(this.vis));
454
+ //Delete the old canvas now
455
+ this.canvas.parentNode.removeChild(this.canvas);
456
+ this.vis = null;
457
+ mouse.lostContext = false;
458
+ this.deleted = true;
459
+ }
460
+ }
461
+
462
+ BoxViewer.prototype.reload = function() {
463
+ this.command('reload');
464
+ }
465
+
466
+ BoxViewer.prototype.checkPointMinMax = function(coord) {
467
+ for (var i=0; i<3; i++) {
468
+ this.view.min[i] = Math.min(coord[i], this.view.min[i]);
469
+ this.view.max[i] = Math.max(coord[i], this.view.max[i]);
470
+ }
471
+ //console.log(JSON.stringify(this.view.min) + " -- " + JSON.stringify(this.view.max));
472
+ }
473
+
474
+ function Merge(obj1, obj2) {
475
+ for (var p in obj2) {
476
+ try {
477
+ //console.log(p + " ==> " + obj2[p].constructor);
478
+ // Property in destination object set; update its value.
479
+ if (!obj2.hasOwnProperty(p)) continue;
480
+ if (obj2[p].constructor == Object || obj2[p].constructor == Array) {
481
+ obj1[p] = Merge(obj1[p], obj2[p]);
482
+ } else {
483
+ //Just copy
484
+ obj1[p] = obj2[p];
485
+ }
486
+ } catch(e) {
487
+ // Property in destination object not set; create it and set its value.
488
+ obj1[p] = obj2[p];
489
+ }
490
+ }
491
+
492
+ //Clear any keys in obj1 that are not in obj2
493
+ for (var p in obj1) {
494
+ if (!obj1.hasOwnProperty(p)) continue; //Ignore built in keys
495
+ if (p in obj2) continue;
496
+ if (typeof(obj1[p]) != 'object') {
497
+ //Just delete
498
+ delete obj1[p]
499
+ }
500
+ }
501
+
502
+ return obj1;
503
+ }
504
+
505
+ BoxViewer.prototype.exportJson = function(nocam) {
506
+ return {"objects" : this.exportObjects(),
507
+ "colourmaps" : this.vis.colourmaps,
508
+ "views" : this.exportView(nocam),
509
+ "properties" : this.vis.properties};
510
+ }
511
+
512
+ BoxViewer.prototype.sendState = function(reload) {
513
+ var exp = this.exportJson();
514
+ exp.reload = reload;
515
+ this.command(JSON.stringify(exp));
516
+ }
517
+
518
+ BoxViewer.prototype.toString = function(nocam, reload, noformat) {
519
+ var exp = this.exportJson(nocam);
520
+ exp.exported = true;
521
+ exp.reload = reload ? true : false;
522
+
523
+ if (noformat)
524
+ return JSON.stringify(exp);
525
+ //Export with 2 space indentation
526
+ return JSON.stringify(exp, undefined, 2);
527
+ }
528
+
529
+ BoxViewer.prototype.exportView = function(nocam) {
530
+ //Update camera settings of current view
531
+ if (nocam)
532
+ this.view = {};
533
+ else {
534
+ this.view.rotate = this.getRotation();
535
+ this.view.focus = this.focus;
536
+ this.view.translate = this.translate;
537
+ //Allows scale editing in UI by commenting this
538
+ //this.view.scale = this.scale;
539
+ }
540
+ /*
541
+ * If we overwrite these, changes from menu will not apply
542
+ *
543
+ this.view.fov = this.fov;
544
+ this.view.near = this.near_clip;
545
+ this.view.far = this.far_clip;
546
+ this.view.border = this.showBorder ? 1 : 0;
547
+ this.view.axis = this.axes;
548
+ */
549
+ //this.view.background = this.background.toString();
550
+
551
+ //Never export min/max
552
+ var V = Object.assign(this.view);
553
+ V.min = undefined;
554
+ V.max = undefined;
555
+ return [V];
556
+ }
557
+
558
+ BoxViewer.prototype.exportObjects = function() {
559
+ objs = [];
560
+ for (var id in this.vis.objects) {
561
+ objs[id] = {};
562
+ //Skip geometry data
563
+ for (var type in this.vis.objects[id]) {
564
+ if (type != "triangles" && type != "points" && type != 'lines' && type != "volume") {
565
+ objs[id][type] = this.vis.objects[id][type];
566
+ }
567
+ }
568
+ }
569
+ //console.log("OBJECTS: " + JSON.stringify(objs));
570
+
571
+ return objs;
572
+ }
573
+
574
+ BoxViewer.prototype.exportColourMaps = function() {
575
+ return this.vis.colourmaps;
576
+ //DEPRECATED
577
+ //Below extracts map from gui editor, not needed unless editor hasn't updated vis object
578
+ cmaps = [];
579
+ if (this.vis.colourmaps) {
580
+ for (var i=0; i<this.vis.colourmaps.length; i++) {
581
+ console.log(i + " - " + this.vis.colourmaps[i].palette);
582
+ if (!this.vis.colourmaps[i].palette) continue;
583
+ cmaps[i] = this.vis.colourmaps[i].palette.get();
584
+ //Copy additional properties
585
+ for (var type in this.vis.colourmaps[i]) {
586
+ if (type != "palette" && type != "colours")
587
+ cmaps[i][type] = this.vis.colourmaps[i][type];
588
+ }
589
+ }
590
+ }
591
+ return cmaps;
592
+ }
593
+
594
+ BoxViewer.prototype.exportFile = function() {
595
+ window.open('data:text/plain;base64,' + window.btoa(this.toString(false, true)));
596
+ }
597
+
598
+ BoxViewer.prototype.loadFile = function(source) {
599
+ //Skip update to rotate/translate etc if in process of updating
600
+ //if (document.mouse.isdown) return;
601
+ if (source.length < 3) {
602
+ console.log('Invalid source data, ignoring');
603
+ console.log(source);
604
+ console.log(BoxViewer.prototype.loadFile.caller);
605
+ return; //Invalid
606
+ }
607
+
608
+ if (!this.vis)
609
+ this.vis = {};
610
+
611
+ //Parse data
612
+ var src = {};
613
+ try {
614
+ src = JSON.parse(source);
615
+ } catch(e) {
616
+ console.log(source);
617
+ console.log("Parse Error: " + e);
618
+ return;
619
+ }
620
+
621
+ //Before merge, delete all colourmap data if changed
622
+ for (var c in this.vis.colourmaps) {
623
+ //Name or colour count mismatch? delete so can be recreated
624
+ if (this.vis.colourmaps[c].name != src.colourmaps[c].name ||
625
+ this.vis.colourmaps[c].colours.length != src.colourmaps[c].colours.length) {
626
+ //Delete the colourmap folder for this map, will be re-created
627
+ if (this.cgui && this.cgui.__folders[this.vis.colourmaps[c].name]) {
628
+ this.cgui.removeFolder(this.cgui.__folders[this.vis.colourmaps[c].name]);
629
+ this.cgui.__folders[this.vis.colourmaps[c].name] = undefined;
630
+ }
631
+ //Clear all the colours so new data will replace in merge
632
+ this.vis.colourmaps[c].colours = undefined;
633
+ }
634
+ }
635
+
636
+ //Merge keys - preserves original objects for gui access
637
+ Merge(this.vis, src);
638
+
639
+ //No model loaded? Prevents errors so default are loaded
640
+ if (!this.vis.properties)
641
+ this.vis.properties = {};
642
+
643
+ //Set active view (always first for now)
644
+ this.view = this.vis.views[0];
645
+
646
+ //Always set a bounding box, get from objects if not in view
647
+ var objbb = false;
648
+ if (!this.view.min || !this.view.max) {
649
+ this.view.min = [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE];
650
+ this.view.max = [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE];
651
+ objbb = true;
652
+ }
653
+ //console.log(JSON.stringify(this.view,null, 2));
654
+
655
+ if (this.view) {
656
+ this.fov = this.view.fov || 45;
657
+ this.near_clip = this.view.near || 0;
658
+ this.far_clip = this.view.far || 0;
659
+ this.orientation = this.view.orientation || 1;
660
+ this.axes = this.view.axis == undefined ? true : this.view.axis;
661
+ }
662
+
663
+ if (this.vis.properties.resolution && this.vis.properties.resolution[0] && this.vis.properties.resolution[1]) {
664
+ this.width = this.vis.properties.resolution[0];
665
+ this.height = this.vis.properties.resolution[1];
666
+ //this.canvas.style.width = "";
667
+ //this.canvas.style.height = "";
668
+ } else {
669
+ //Autosize when img loaded
670
+ this.width = 0;
671
+ this.height = 0;
672
+ }
673
+
674
+ //Process object data
675
+ for (var id in this.vis.objects) {
676
+ //Apply object bounding box
677
+ if (objbb && this.vis.objects[id].min)
678
+ this.checkPointMinMax(this.vis.objects[id].min);
679
+ if (objbb && this.vis.objects[id].max)
680
+ this.checkPointMinMax(this.vis.objects[id].max);
681
+ }
682
+
683
+ this.updateDims(this.view);
684
+
685
+ //Update display
686
+ if (!this.gl) return;
687
+ this.draw();
688
+ this.clear();
689
+
690
+ //Create UI - disable by omitting dat.gui.min.js
691
+ //(If menu doesn't exist or is open, update immediately
692
+ // otherwise, wait until clicked/opened as update is slow)
693
+ if (!this.gui || !this.gui.closed)
694
+ this.menu();
695
+ else
696
+ this.reloadgui = true;
697
+
698
+ //Copy updated values to all generated controls
699
+ //This allows data changed by other means (ie: through python) to
700
+ // be reflected in the HTML control values
701
+ var that = this;
702
+ var getValWithIndex = function(prop, val, idx) {
703
+ if (val === undefined) return;
704
+ if (idx != null && idx >= 0 && val.length > idx)
705
+ val = val[idx];
706
+ //Round off floating point numbers
707
+ if (that.dict[property].type.indexOf('real') >= 0)
708
+ return val.toFixed(6) / 1; //toFixed() / 1 rounds to fixed position and removes trailing zeros
709
+ return val;
710
+ }
711
+ var pel = this.canvas.parentElement.parentElement;
712
+ var children = pel.getElementsByTagName('*');
713
+ for (var i=0; i<children.length; i++) {
714
+ //Process property controls
715
+ var id = children[i].id;
716
+ if (id.indexOf('lvctrl') >= 0) {
717
+ var target = children[i].getAttribute("data-target");
718
+ var property = children[i].getAttribute("data-property");
719
+ var idx = children[i].getAttribute("data-index");
720
+ //console.log(id + " : " + target + " : " + property + " [" + idx + "]");
721
+ if (property) {
722
+ if (target) {
723
+ //Loop through objects, find those whose name matches element target
724
+ for (var o in this.vis.objects) {
725
+ var val = this.vis.objects[o][property];
726
+ if (val === undefined) continue;
727
+ if (this.vis.objects[o].name == target) {
728
+ if (idx != null && idx >= 0)
729
+ val = val[idx];
730
+ //console.log(target + " ==> SET " + id + " : ['" + property + "'] VALUE TO " + val);
731
+ //console.log("TAG: " + children[i].tagName);
732
+ if (children[i].type == 'checkbox')
733
+ children[i].checked = val;
734
+ else if (children[i].tagName == 'SELECT') {
735
+ //If integer, set by index, otherwise set by value
736
+ var parsed = parseInt(val);
737
+ if (isNaN(parsed) || parsed.toString() != val) {
738
+ //If the value is in the options, set it, otherwise leave as is
739
+ for (var c in children[i].options) {
740
+ if (children[i].options[c].value == val) {
741
+ children[i].selectedIndex = c;
742
+ break;
743
+ }
744
+ }
745
+ } else {
746
+ children[i].selectedIndex = parsed;
747
+ }
748
+ } else if (children[i].tagName == 'DIV') {
749
+ children[i].style.background = new Colour(val).html();
750
+ } else if (children[i].tagName == 'CANVAS' && children[i].gradient) {
751
+ //Store full list of colourmaps
752
+ var el = children[i]; //canvas element
753
+ //Ensure we aren't merging the same object
754
+ el.colourmaps = Merge(JSON.parse(JSON.stringify(el.colourmaps)), this.vis.colourmaps);
755
+ //Load the initial colourmap
756
+ if (!el.selectedIndex >= 0) {
757
+ //Get the selected index from the property value
758
+ for (var c in this.vis.colourmaps) {
759
+ if (this.vis.colourmaps[c].name == val) {
760
+ el.selectedIndex = c;
761
+ //Copy, don't link
762
+ el.currentmap = JSON.parse(JSON.stringify(this.vis.colourmaps[c]));
763
+ //el.currentmap = Object.assign(this.vis.colourmaps[c]);
764
+ break;
765
+ }
766
+ }
767
+ }
768
+ //Can't use gradient.read() here as it triggers another state load,
769
+ //looping infinitely - so load the palette change directly
770
+ el.gradient.palette = new Palette(this.vis.colourmaps[el.selectedIndex].colours, true);
771
+ //el.gradient.reset(); //For some reason this screws up colour editing
772
+ el.gradient.update(true); //Update without triggering callback that triggers a state reload
773
+ } else {
774
+ //console.log(id + " : " + target + " : " + property + " = " + val);
775
+ children[i].value = getValWithIndex(property, val, idx);
776
+ }
777
+ }
778
+ }
779
+ } else if (this.vis.views[0][property] != null) {
780
+ //View property
781
+ var val = this.vis.views[0][property];
782
+ //console.log("SET " + id + " : ['" + property + "'] VIEW PROP VALUE TO " + val);
783
+ children[i].value = getValWithIndex(property, val, idx);
784
+ } else if (this.vis.properties[property] != null) {
785
+ //Global property
786
+ var val = this.vis.properties[property];
787
+ //console.log("SET " + id + " : ['" + property + "'] GLOBAL VALUE TO " + val);
788
+ children[i].value = getValWithIndex(property, val, idx);
789
+ }
790
+ }
791
+ }
792
+ }
793
+ }
794
+
795
+ BoxViewer.prototype.menu = function() {
796
+ //Create UI - disable by omitting dat.gui.min.js
797
+ //This is slow! Don't call while animating
798
+ var viewer = this;
799
+ var changefn = function(value, reload) {
800
+ //console.log(JSON.stringify(Object.keys(this)));
801
+ //console.log(value);
802
+ if (reload == undefined) {
803
+ reload = true;
804
+ if (this.property && viewer.dict[this.property])
805
+ {
806
+ //Get reload level from prop dict
807
+ //console.log(this.property + " REDRAW: " + viewer.dict[this.property].redraw);
808
+ reload = viewer.dict[this.property].redraw;
809
+ }
810
+ }
811
+
812
+ //Sync state and reload
813
+ viewer.sendState(reload);
814
+ };
815
+
816
+ if (!this.gui || this.gui.closed) {
817
+ //Re-create from scratch if closed or not present
818
+ createMenu(this, changefn);
819
+ } else {
820
+ updateMenu(this, changefn);
821
+ }
822
+ this.reloadgui = false;
823
+ }
824
+
825
+ BoxViewer.prototype.clear = function() {
826
+ if (!this.gl) return;
827
+ this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
828
+ }
829
+
830
+ BoxViewer.prototype.draw = function() {
831
+ if (!this.canvas) return;
832
+
833
+ //Get the dimensions from the current canvas
834
+ if (this.width != this.canvas.offsetWidth || this.height != this.canvas.offsetHeight) {
835
+ this.width = this.canvas.offsetWidth;
836
+ this.height = this.canvas.offsetHeight;
837
+ //Need to set this too for some reason
838
+ this.canvas.width = this.width;
839
+ this.canvas.height = this.height;
840
+ if (this.gl) {
841
+ this.gl.viewportWidth = this.width;
842
+ this.gl.viewportHeight = this.height;
843
+ this.webgl.viewport = new Viewport(0, 0, this.width, this.height);
844
+ }
845
+ }
846
+
847
+ /*/Attempt to prevent element resizing to 0,0 when a frame is dropped
848
+ if (this.width)
849
+ this.canvas.parentElement.style.minWidth = this.width + 'px';
850
+ if (this.height)
851
+ this.canvas.parentElement.style.minHeight = this.height + 'px';
852
+ */
853
+
854
+ if (!this.gl) return;
855
+
856
+ //Check isContextLost
857
+ if (this.gl.isContextLost()) {
858
+ console.log("boxviewer_draw_: context lost");
859
+ this.mouse.lostContext = true;
860
+ return;
861
+ }
862
+
863
+ this.gl.viewport(0, 0, this.gl.viewportWidth, this.gl.viewportHeight);
864
+ //this.gl.clearColor(1, 1, 1, 0);
865
+ this.gl.clearColor(0, 0, 0, 0);
866
+ this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
867
+
868
+ this.webgl.view(this);
869
+
870
+ //Render objects
871
+ this.border.draw(this.webgl, false, true);
872
+
873
+ //Remove translation and re-render axes
874
+ var tr = this.translate.slice();
875
+ this.translate = [0,0,-this.modelsize*1.25];
876
+ this.webgl.apply(this);
877
+ this.border.draw(this.webgl, true, false);
878
+ this.translate = tr;
879
+ }
880
+
881
+ BoxViewer.prototype.syncRotation = function(rot) {
882
+ if (rot)
883
+ this.rotate = quat4.create(rot);
884
+ this.rotated = true;
885
+ this.draw();
886
+ rstr = '' + this.getRotationString();
887
+ that = this;
888
+ window.requestAnimationFrame(function() {that.command(rstr);});
889
+ }
890
+
891
+ BoxViewer.prototype.rotateX = function(deg) {
892
+ this.rotation(deg, [1,0,0]);
893
+ }
894
+
895
+ BoxViewer.prototype.rotateY = function(deg) {
896
+ this.rotation(deg, [0,1,0]);
897
+ }
898
+
899
+ BoxViewer.prototype.rotateZ = function(deg) {
900
+ this.rotation(deg, [0,0,1]);
901
+ }
902
+
903
+ BoxViewer.prototype.rotation = function(deg, axis) {
904
+ //Quaterion rotate
905
+ var arad = deg * Math.PI / 180.0;
906
+ var rotation = quat4.fromAngleAxis(arad, axis);
907
+ rotation = quat4.normalize(rotation);
908
+ this.rotate = quat4.multiply(rotation, this.rotate);
909
+ }
910
+
911
+ BoxViewer.prototype.getRotation = function() {
912
+ return [this.rotate[0], this.rotate[1], this.rotate[2], this.rotate[3]];
913
+ }
914
+
915
+ BoxViewer.prototype.getRotationString = function() {
916
+ //Return current rotation quaternion as string
917
+ var q = this.getRotation();
918
+ return 'rotation ' + q[0] + ' ' + q[1] + ' ' + q[2] + ' ' + q[3];
919
+ }
920
+
921
+ BoxViewer.prototype.getTranslationString = function() {
922
+ return 'translation ' + this.translate[0] + ' ' + this.translate[1] + ' ' + this.translate[2];
923
+ }
924
+
925
+ BoxViewer.prototype.reset = function() {
926
+ if (this.gl) {
927
+ this.updateDims(this.view);
928
+ this.draw();
929
+ }
930
+
931
+ this.command('reset');
932
+ }
933
+
934
+ BoxViewer.prototype.zoom = function(factor) {
935
+ if (this.gl) {
936
+ this.translate[2] += factor * Math.max(0.01*this.modelsize, Math.abs(this.translate[2]));
937
+ this.draw();
938
+ }
939
+
940
+ var that = this;
941
+ if (this.zoomTimer)
942
+ clearTimeout(this.zoomTimer);
943
+ this.zoomTimer = setTimeout(function () {that.command('' + that.getTranslationString()); that.clear(); that.zoomTimer = null;}, 500 );
944
+
945
+ //this.command('' + this.getTranslationString());
946
+ //this.command('zoom ' + factor);
947
+ }
948
+
949
+ BoxViewer.prototype.zoomClip = function(factor) {
950
+ var near_clip = this.near_clip + factor * this.modelsize;
951
+ if (near_clip >= this.modelsize * 0.001)
952
+ this.near_clip = near_clip;
953
+
954
+ if (this.gl) this.draw();
955
+
956
+ var that = this;
957
+ if (this.zoomTimer) clearTimeout(this.zoomTimer);
958
+ //this.zoomTimer = setTimeout(function () {that.command('zoomclip ' + factor); that.clear();}, 500 );
959
+ this.zoomTimer = setTimeout(function () {that.command('nearclip ' + that.near_clip); that.clear();}, 500 );
960
+
961
+ //this.command('zoomclip ' + factor);
962
+ }
963
+
964
+ BoxViewer.prototype.updateDims = function(view) {
965
+ if (!view) return;
966
+ var oldsize = this.modelsize;
967
+
968
+ //Check for valid dims
969
+ for (var i=0; i<3; i++) {
970
+ if (view.bounds && view.max[i] < view.bounds.max[i])
971
+ view.max[i] = view.bounds.max[i];
972
+ if (view.bounds && view.min[i] > view.bounds.min[i])
973
+ view.min[i] = view.bounds.min[i];
974
+ /*if (view.max[i] < view.min[i] <= 0.0) {
975
+ view.max[i] = 1.0;
976
+ view.min[i] = -1.0;
977
+ }
978
+ }*/
979
+ }
980
+
981
+ this.dims = [view.max[0] - view.min[0], view.max[1] - view.min[1], view.max[2] - view.min[2]];
982
+ this.modelsize = Math.sqrt(this.dims[0]*this.dims[0] + this.dims[1]*this.dims[1] + this.dims[2]*this.dims[2]);
983
+
984
+ this.focus = [view.min[0] + 0.5*this.dims[0], view.min[1] + 0.5*this.dims[1], view.min[2] + 0.5*this.dims[2]];
985
+ this.centre = [this.focus[0],this.focus[1],this.focus[2]];
986
+
987
+ this.translate = [0,0,0];
988
+ if (this.modelsize != oldsize) this.translate[2] = -this.modelsize*1.25;
989
+
990
+ if (this.near_clip == 0.0) this.near_clip = this.modelsize / 10.0;
991
+ if (this.far_clip == 0.0) this.far_clip = this.modelsize * 10.0;
992
+
993
+ quat4.identity(this.rotate);
994
+
995
+ if (view) {
996
+ //Initial rotation
997
+ if (view.rotate) {
998
+ if (view.rotate.length == 3) {
999
+ this.rotateZ(-view.rotate[2]);
1000
+ this.rotateY(-view.rotate[1]);
1001
+ this.rotateX(-view.rotate[0]);
1002
+ } else if (view.rotate.length == 4) {
1003
+ this.rotate = quat4.create(view.rotate);
1004
+ }
1005
+ }
1006
+
1007
+ //Translate
1008
+ if (view.translate) {
1009
+ this.translate[0] = view.translate[0];
1010
+ this.translate[1] = view.translate[1];
1011
+ this.translate[2] = view.translate[2];
1012
+ }
1013
+
1014
+ //Scale
1015
+ if (view.scale) {
1016
+ this.scale[0] = view.scale[0];
1017
+ this.scale[1] = view.scale[1];
1018
+ this.scale[2] = view.scale[2];
1019
+ }
1020
+
1021
+ //Focal point
1022
+ if (view.focus) {
1023
+ this.focus[0] = this.centre[0] = view.focus[0];
1024
+ this.focus[1] = this.centre[1] = view.focus[1];
1025
+ this.focus[2] = this.centre[2] = view.focus[2];
1026
+ }
1027
+
1028
+ }
1029
+
1030
+ //console.log("DIMS: " + view.min[0] + " to " + view.max[0] + "," + view.min[1] + " to " + view.max[1] + "," + view.min[2] + " to " + view.max[2]);
1031
+ //console.log("New model size: " + this.modelsize + ", Focal point: " + this.focus[0] + "," + this.focus[1] + "," + this.focus[2]);
1032
+ //console.log("Translate: " + this.translate[0] + "," + this.translate[1] + "," + this.translate[2]);
1033
+
1034
+ if (!this.gl) return;
1035
+
1036
+ //Create the bounding box vertex buffer
1037
+ this.border.updateBuffers(this.view);
1038
+ }
1039
+