otsdaq_utilities  v2_05_02_indev
Viewer3d.js
1 //=====================================================================================
2 //
3 // Created Aug, 2013
4 // by Ryan Rivera ((rrivera at fnal.gov)) and Dan Parilla
5 //
6 // Viewer3d.js
7 //
8 // requires an omni div, that will be made full window size (window.innerWidth and
9 // window.innerHeight) at position 0,0
10 //
11 // note: good tutorial http://learningwebgl.com/blog/?p=28
12 // expanded glMatrix library: http://code.google.com/p/glmatrix/source/browse/glMatrix.js?spec=svne5ad8f6975eef038de668914a44ed36e2c611966&r=e5ad8f6975eef038de668914a44ed36e2c611966
13 // reference card: http://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf
14 // public function list:
15 // Viewer3d.launch()
16 //
17 //=====================================================================================
18 
19 var Viewer3d = Viewer3d || {}; //define namespace
20 
21 
23 //public function definitions
24 
25 // Viewer3d.launch ~~
26 // called to start 3d viewer
27 Viewer3d.launch = function() {
28 
29  Debug.log("Viewer3d.launch");
30 
31  Viewer3d.omni = document.getElementById("omni");
32  Viewer3d.omni.innerHTML = ""; //clear all content
33 
34  //initialize with loading message in center
35  var w = Viewer3d.w = window.innerWidth;
36  var h = Viewer3d.h = window.innerHeight;
37 
38  Viewer3d.omni.style.position = "absolute";
39  Viewer3d.omni.style.left = 0 + "px";
40  Viewer3d.omni.style.top = 0 + "px";
41  Viewer3d.omni.style.width = w + "px";
42  Viewer3d.omni.style.height = h + "px";
43  Viewer3d.omni.style.backgroundColor = "rgb(30,30,30)";
44 
45  Viewer3d.omni.innerHTML = "<center><div style='margin-top:" + (h/2-8) + "px'>Loading 3-D...</div></center>";
46 
47 
48  //load/insert libraries and shaders into header and setup webgl
49  // steps:
50  // - load WebGL libraries
51  // - setup canvas behind "loading..."
52  // - init WebGL
53  // - load WebGL shaders
54  // - setup hud
55  // - get default geometry from server
56  // - bring canvas in front of "loading..."
57 
58  Viewer3d.loadScripts();
59 }
60 
61 //end public function definitions
63 
64 
65 Viewer3d.CANVAS_MIN_SIZE = 300; //dont allow w or h to go less than this
66 Viewer3d.HUD_WIDTH = 200;
67 Viewer3d.HUD_MARGIN_RIGHT = 10;
68 Viewer3d.HUD_DROP_DOWN_SPEED = 10;
69 Viewer3d.WEBGL_NEAR_CLIPPING_DEPTH = 1000.0;
70 Viewer3d.WEBGL_FAR_CLIPPING_DEPTH = 10000000.0;
71 Viewer3d.WEBGL_RESET_CAMERA_POS = [-300000, 50000, -300000];
72 Viewer3d.WEBGL_RESET_CAMERA_FOCUS = [0, 50000, 0];
73 Viewer3d.WEBGL_RESET_CAMERA_UP = [0, 1, 0];
74 Viewer3d.WEBGL_AXES_LENGTH = 1000000; //microns
75 Viewer3d.WEBGL_GRID_SPACING = 50000; //microns
76 Viewer3d.WEBGL_GRID_EXPANSE = 1000000; //microns
77 Viewer3d.WEBGL_GRID_YOFF = -100000; //microns
78 Viewer3d.TICK_REFRESH_PERIOD = 30; //ms
79 Viewer3d.KEY_ROT_SPEED_FAST = 0.06;
80 Viewer3d.KEY_ROT_SPEED_SLOW = 0.01;
81 Viewer3d.KEY_MOVE_SPEED_FAST = 10000; //incremental size of key navigation in fast mode
82 Viewer3d.KEY_MOVE_SPEED_SLOW = 1000; //incremental size of key navigation in slow mode
83 Viewer3d.MOUSE_NAV_SPEED = 0.005;
84 Viewer3d.MOUSE_WHEEL_SPEED_SLOW = 10000;
85 Viewer3d.MOUSE_WHEEL_SPEED_FAST = 100000;
86 Viewer3d.TOUCH_NAV_SPEED = 0.001;
87 Viewer3d.TOUCH_ZOOM_SPEED = 10000;
88 Viewer3d.DOUBLE_TAP_RESET_TIME = 600; //ms
89 Viewer3d.DOUBLE_TAP_HUD_Y_ACCEPT = 300;
90 Viewer3d.Z_SQUASH_FACTOR = 10.0;
91 
92 Viewer3d.FLY_BY_ROT_RATE = 0.003;
93 Viewer3d.FLY_BY_HEIGHT_MAX = 10000; //0
94 Viewer3d.FLY_BY_HEIGHT_RATE = 0.001;
95 Viewer3d.FLY_BY_RADIUS_RATE = 0.002;
96 Viewer3d.FLY_BY_RADIUS_SWING = 100000; //0
97 Viewer3d.FLY_BY_RADIUS_MIN = 10000; //0
98 Viewer3d.FLY_BY_FOCUS = [0,Viewer3d.FLY_BY_HEIGHT_MAX/10,0];
99 Viewer3d.FLY_BY_EVENT_TIME = 500; //ms for each event
100 Viewer3d.FLY_BY_ACCUM_TIME = 5000; //ms for alternating between accumulated time individual events
101 
102 
103 Viewer3d.omni;
104 Viewer3d.hud;
105 Viewer3d.canvas;
106 Viewer3d.textureCanvas;
107 Viewer3d.textureContext;
108 Viewer3d.cTexture;
109 Viewer3d.gl;
110 Viewer3d.w;
111 Viewer3d.h;
112 Viewer3d.tickTimer;
113 
114 Viewer3d.lastMousePos = [-1,-1];
115 Viewer3d.lastTwoTouchMag = 0; //used for pinch zooming
116 Viewer3d.lastTouchTime = 0; //used for double tap recognition
117 Viewer3d.cameraAction = false; //used to redraw if mouse nav occurs
118 Viewer3d.keysDown = []; //12 keys. 1 pressed, 0 unpressed: Q, W, E, R, A, S, D, F, Up, Left, Down, Right
119 Viewer3d.cameraPos; //position of camera
120 Viewer3d.cameraFocus; //3d point for camera focus
121 Viewer3d.cameraUp; //unit direction vector for camera up
122 Viewer3d.cameraKeyNavFast = false;
123 
124 Viewer3d.drawAxesFlag = true;
125 Viewer3d.drawGridFlag = true;
126 Viewer3d.drawTracksFlag = true;
127 Viewer3d.enableMouseNav = true;
128 Viewer3d.enableFlyBy = true;
129 Viewer3d.accumulateEvents = true;
130 Viewer3d.enableFlyByParameter = 0;
131 Viewer3d.flyByEvent = 0;
132 Viewer3d.flyByModeAlarm = 0; //to change fly-by mode, 0 is unset
133 Viewer3d.flyByEventAlarm = 0; //to change fly-by event, 0 is unset
134 Viewer3d.axes;
135 Viewer3d.grid;
136 Viewer3d.geometry;
137 Viewer3d.events; //array of events, where an event has glBuffer .clusters and .tracks
138 Viewer3d.eventToDisplay = 0; //index of event to display, -1 is all events
139 Viewer3d.runNumber = -1; //index of run to display, -1 is no run loaded
140 
141 Viewer3d.scriptLoadedCount;
142 Viewer3d.SCRIPTS_TO_LOAD = 2;
143 
144 Viewer3d.fragmentShader;
145 Viewer3d.vertexShader;
146 Viewer3d.shaderProgram;
147 Viewer3d.perspectiveMatrix;
148 Viewer3d.modelViewMatrix;
149 Viewer3d.modelViewMatrixStack = [];
150 
151 //"private" function list
152 //Viewer3d.handleScriptLoaded
153 //Viewer3d.initCanvas
154 //Viewer3d.tick
155 //Viewer3d.handleCanvasKeyDown
156 //Viewer3d.handleCanvasKeyUp
157 //Viewer3d.checkKeyAction
158 //Viewer3d.handleCanvasMouseWheel
159 //Viewer3d.zoomCameraByDelta
160 //Viewer3d.handleCanvasTouchMove
161 //Viewer3d.handleCanvasMouseMove
162 //Viewer3d.handleCanvasTouchStart
163 //Viewer3d.handleCanvasMouseDown
164 //Viewer3d.panCameraByDelta
165 //Viewer3d.handleWindowResize
166 //Viewer3d.initWebGL
167 //Viewer3d.resetCamera
168 //Viewer3d.initShaders
169 //Viewer3d.createHud
170 // this.handleWindowResize
171 // this.checkboxUpdate
172 // this.update
173 // this.handleControlDown
174 // this.handleControlUp
175 // this.handleRunChange
176 //Viewer3d.getEvents
177 //Viewer3d.getEventsHandler
178 //Viewer3d.getGeometry
179 //Viewer3d.getGeometryHandler
180 //Viewer3d.mvPushMatrix
181 //Viewer3d.mvPopMatrix
182 //Viewer3d.setMatrixUniforms
183 //Viewer3d.redraw
184 //Viewer3d.initForDraw
185 //Viewer3d.initAxesAndGridBuffers
186 //Viewer3d.drawAxes
187 //Viewer3d.drawGrid
188 //Viewer3d.drawGeometry
189 //Viewer3d.drawClusters
190 //Viewer3d.drawTracks
191 
192 //first step is to load webGl libraries
193 Viewer3d.loadScripts = function() {
194 
195  Viewer3d.scriptLoadedCount = 0;
196 
197  var head = document.getElementsByTagName('head')[0];
198  var script;
199 
200  //webgl libraries
201  script = document.createElement('script');
202  script.type = 'text/javascript';
203  script.src = '/WebPath/js/js_lib/glMatrix-0.9.5.min.js';
204  script.onload = Viewer3d.handleScriptLoaded;
205  head.appendChild(script);
206 
207  script = document.createElement('script');
208  script.type = 'text/javascript';
209  script.src = '/WebPath/js/js_lib/webgl-utils.js';
210  script.onload = Viewer3d.handleScriptLoaded;
211  head.appendChild(script);
212 }
213 
214 Viewer3d.handleScriptLoaded = function() {
215  ++Viewer3d.scriptLoadedCount;
216  Debug.log("Viewer3d.handleScriptLoaded " + Viewer3d.scriptLoadedCount);
217  if(Viewer3d.SCRIPTS_TO_LOAD == Viewer3d.scriptLoadedCount) //done, goto next step
218  Viewer3d.initCanvas();
219 }
220 
221 Viewer3d.initCanvas = function() {
222 
223  Viewer3d.canvas = document.createElement('canvas');
224  Viewer3d.canvas.style.position = "absolute";
225  Viewer3d.canvas.style.left = 0 + "px";
226  Viewer3d.canvas.style.top = 0 + "px";
227  Viewer3d.canvas.style.zIndex = -1; //-1 is not visible.. change to 0 to bring to front
228  Viewer3d.omni.appendChild(Viewer3d.canvas);
229 
230  Viewer3d.textureCanvas = document.createElement('canvas');
231  Viewer3d.textureContext = Viewer3d.textureCanvas.getContext('2d');
232 
233  Viewer3d.textureCanvas.width = 128; //must be power of 2 (?)
234  Viewer3d.textureCanvas.height = 128;
235  Viewer3d.textureContext.fillStyle = "#FF33FF"; // This determines the text colour, it can take a hex value or rgba value (e.g. rgba(255,0,0,0.5))
236  Viewer3d.textureContext.textAlign = "center"; // This determines the alignment of text, e.g. left, center, right
237  Viewer3d.textureContext.textBaseline = "middle"; // This determines the baseline of the text, e.g. top, middle, bottom
238  Viewer3d.textureContext.font = "12px monospace"; // This determines the size of the text and the font family used
239  Viewer3d.textureContext.fillText("3D Pixel Sensor",Viewer3d.textureCanvas.width/2, Viewer3d.textureCanvas.height/2);
240 
241  Viewer3d.initWebGL();
242 
243  initBuffers();
244 
245  Viewer3d.initTexture();
246 
247 
248  Viewer3d.hud = new Viewer3d.createHud();
249 
250  window.onresize = Viewer3d.handleWindowResize;
251  Viewer3d.handleWindowResize();
252 
253  Viewer3d.getGeometry();
254  Viewer3d.getEvents();
255 
256  if(Viewer3d.tickTimer) clearInterval(Viewer3d.tickTimer);
257  Viewer3d.tickTimer = setInterval(Viewer3d.tick, Viewer3d.TICK_REFRESH_PERIOD);
258 
259  Viewer3d.canvas.onmousedown = Viewer3d.handleCanvasMouseDown;
260  Viewer3d.canvas.onmousemove = Viewer3d.handleCanvasMouseMove;
261  Viewer3d.canvas.onmousewheel = Viewer3d.handleCanvasMouseWheel;
262  Viewer3d.canvas.addEventListener('touchstart',Viewer3d.handleCanvasTouchStart);
263  Viewer3d.canvas.addEventListener('touchmove',Viewer3d.handleCanvasTouchMove);
264  window.onkeydown = Viewer3d.handleCanvasKeyDown;
265  window.onkeyup = Viewer3d.handleCanvasKeyUp;
266  Viewer3d.redraw();
267 }
268 
269 function handleLoadedTexture(texture, textureCanvas) {
270  Debug.log("Viewer3d handleLoadedTexture");
271  var gl = Viewer3d.gl;
272  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
273 
274  gl.bindTexture(gl.TEXTURE_2D, texture);
275  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureCanvas);
276  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
277  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
278  gl.generateMipmap(gl.TEXTURE_2D);
279 
280  gl.bindTexture(gl.TEXTURE_2D, null);
281 }
282 
283 //Viewer3d.tick ~~
284 // always check keys and periodically check for data
285 // and animate camera for fly by
286 Viewer3d.initTexture = function() {
287  Debug.log("Viewer3d initTexture");
288  Viewer3d.cTexture = Viewer3d.gl.createTexture();
289  handleLoadedTexture(Viewer3d.cTexture, Viewer3d.textureCanvas);
290 }
291 
292 
293 //Viewer3d.tick ~~
294 // always check keys and periodically check for data
295 // and animate camera for fly by
296 Viewer3d.tick = function() {
297 
298  if(Viewer3d.enableFlyBy)
299  {
300  var radius = Math.sin(Viewer3d.enableFlyByParameter*Viewer3d.FLY_BY_RADIUS_RATE)*Viewer3d.FLY_BY_RADIUS_SWING/2 +
301  Viewer3d.FLY_BY_RADIUS_SWING/2 + Viewer3d.FLY_BY_RADIUS_MIN;
302  var height = Math.cos(Viewer3d.enableFlyByParameter*Viewer3d.FLY_BY_HEIGHT_RATE)*Viewer3d.FLY_BY_HEIGHT_MAX;// + Viewer3d.FLY_BY_HEIGHT_MAX;
303 
304  vec3.set([Math.cos(Viewer3d.enableFlyByParameter*Viewer3d.FLY_BY_ROT_RATE)*radius,
305  height,
306  Math.sin(Viewer3d.enableFlyByParameter*Viewer3d.FLY_BY_ROT_RATE)*radius],
307  Viewer3d.cameraPos);
308  vec3.set(Viewer3d.FLY_BY_FOCUS, Viewer3d.cameraFocus);
309 
310 
311 
312  //select event to display
313  if(!Viewer3d.flyByModeAlarm || //reset alarm and switch mode
314  (new Date()).getTime() > Viewer3d.flyByModeAlarm)
315  {
316  if(Viewer3d.eventToDisplay < 0) //now in accum mode, switch to individual event
317  {
318  Viewer3d.eventToDisplay = Viewer3d.flyByEvent;
319  //reset event timer
320  Viewer3d.flyByEventAlarm = (new Date()).getTime() + Viewer3d.FLY_BY_EVENT_TIME;
321 
322  Debug.log("Viewer3d tick Fly-by Mode: Individual");
323  }
324  else //now in individual event mode, switch to accum mode
325  {
326  Viewer3d.eventToDisplay = -1;
327  Viewer3d.drawTracksFlag = !Viewer3d.drawTracksFlag; //alternate with/without tracks
328 
329  Debug.log("Viewer3d tick Fly-by Mode: Accum");
330  }
331 
332  //reset mode timer
333  Viewer3d.flyByModeAlarm = (new Date()).getTime() + Viewer3d.FLY_BY_ACCUM_TIME;
334  }
335 
336  if(Viewer3d.eventToDisplay >= 0 && //then in individual event mode, so check for timer update
337  (new Date()).getTime() > Viewer3d.flyByEventAlarm)
338  {
339  ++Viewer3d.flyByEvent;
340  if(!Viewer3d.events || Viewer3d.flyByEvent >= Viewer3d.events.length)
341  Viewer3d.flyByEvent = 0;
342  Viewer3d.eventToDisplay = Viewer3d.flyByEvent;
343 
344  //reset event timer
345  Viewer3d.flyByEventAlarm = (new Date()).getTime() + Viewer3d.FLY_BY_EVENT_TIME;
346 
347  Debug.log("Viewer3d tick Fly-by Event: " + Viewer3d.eventToDisplay);
348  }
349 
350  //select event to display DONE
351 
352 
353 
354 
355 
356  Viewer3d.redraw();
357 
358  ++Viewer3d.enableFlyByParameter;
359  }
360  else //keys deactivated during fly by
361  {
362  if(Viewer3d.checkKeyAction() || Viewer3d.cameraAction) //if active key, redraw scene
363  Viewer3d.redraw();
364  }
365 }
366 
367 Viewer3d.handleCanvasKeyDown = function(event) {
368  var c = String.fromCharCode(event.keyCode);
369  //Debug.log(event.keyCode + " handleKeyDown " + c);
370  if((
371  c == "A" || c == "S" || c == "D" || c == "W" ||
372  c == "Q" || c == "E" || c == "R" || c == "F" ||
373  c == "%" || c == "(" || c == "'" || c == "&") //Left, Down, Right, Up
374  && !Viewer3d.keysDown[c])
375  Viewer3d.keysDown[c] = 1;
376 }
377 
378 Viewer3d.handleCanvasKeyUp = function(event) {
379  var c = String.fromCharCode(event.keyCode);
380  if(
381  c == "A" || c == "S" || c == "D" || c == "W" ||
382  c == "Q" || c == "E" || c == "R" || c == "F" ||
383  c == "%" || c == "(" || c == "'" || c == "&") //Left, Down, Right, Up
384  Viewer3d.keysDown[c] = 0;
385  else if(c == " " || event.keyCode == 16) //space or shift change speed mode
386  {
387  Viewer3d.cameraKeyNavFast = !Viewer3d.cameraKeyNavFast;
388  Viewer3d.hud.update(); //update hud
389  }
390  else if(c == "Z") //Z reset camera
391  {
392  Viewer3d.resetCamera();
393  Viewer3d.redraw();
394  }
395 }
396 
397 Viewer3d.checkKeyAction = function(event) {
398 
399  // Debug.log("Viewer3d.checkKeyAction ");
400  var actionTaken = false;
401 
402  if(Viewer3d.keysDown["Q"] || Viewer3d.keysDown["E"]) //rotate left or right
403  {
404  var dir = [];
405  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
406 
407  var left = [];
408  vec3.cross(Viewer3d.cameraUp,dir,left);
409  vec3.normalize(left);
410  vec3.scale(left,Viewer3d.cameraKeyNavFast?Viewer3d.KEY_ROT_SPEED_FAST:Viewer3d.KEY_ROT_SPEED_SLOW);
411 
412  if(Viewer3d.keysDown["Q"]) vec3.add(Viewer3d.cameraFocus, left, Viewer3d.cameraFocus);
413  else vec3.subtract(Viewer3d.cameraFocus, left, Viewer3d.cameraFocus);
414 
415  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
416  vec3.normalize(dir);
417  vec3.add(Viewer3d.cameraPos, dir, Viewer3d.cameraFocus);
418 
419  actionTaken = true;
420  }
421 
422  if(Viewer3d.keysDown["R"] || Viewer3d.keysDown["F"]) //rotate down or up
423  {
424  var dir = [];
425  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
426 
427  var up = [];
428  vec3.set(Viewer3d.cameraUp,up);
429  vec3.normalize(up);
430  vec3.scale(up,Viewer3d.cameraKeyNavFast?Viewer3d.KEY_ROT_SPEED_FAST:Viewer3d.KEY_ROT_SPEED_SLOW);
431 
432  if(Viewer3d.keysDown["R"]) vec3.add(Viewer3d.cameraFocus, up, Viewer3d.cameraFocus);
433  else vec3.subtract(Viewer3d.cameraFocus, up, Viewer3d.cameraFocus);
434 
435  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
436  vec3.normalize(dir);
437  vec3.add(Viewer3d.cameraPos, dir, Viewer3d.cameraFocus);
438 
439  actionTaken = true;
440  }
441 
442  if(Viewer3d.keysDown["A"] || Viewer3d.keysDown["D"] ||
443  Viewer3d.keysDown["%"] || Viewer3d.keysDown["'"]) //slide left or right
444  {
445  var dir = [];
446  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
447 
448  var left = [];
449  vec3.cross(Viewer3d.cameraUp,dir,left);
450  vec3.normalize(left);
451  vec3.scale(left,Viewer3d.cameraKeyNavFast?Viewer3d.KEY_MOVE_SPEED_FAST:Viewer3d.KEY_MOVE_SPEED_SLOW);
452 
453  if(Viewer3d.keysDown["%"] || Viewer3d.keysDown["A"]) vec3.add(Viewer3d.cameraPos, left);
454  else vec3.subtract(Viewer3d.cameraPos, left);
455 
456  vec3.normalize(dir);
457  vec3.add(Viewer3d.cameraPos, dir, Viewer3d.cameraFocus);
458  actionTaken = true;
459  }
460 
461  if(Viewer3d.keysDown["("] || Viewer3d.keysDown["&"]) //slide up or down
462  {
463  var dir = [];
464  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
465 
466  var up = [];
467  vec3.set(Viewer3d.cameraUp,up);
468  vec3.normalize(up);
469  vec3.scale(up,Viewer3d.cameraKeyNavFast?Viewer3d.KEY_MOVE_SPEED_FAST:Viewer3d.KEY_MOVE_SPEED_SLOW);
470 
471  if(Viewer3d.keysDown["&"]) vec3.add(Viewer3d.cameraPos, up);
472  else vec3.subtract(Viewer3d.cameraPos, up);
473 
474  vec3.normalize(dir);
475  vec3.add(Viewer3d.cameraPos, dir, Viewer3d.cameraFocus);
476  actionTaken = true;
477  }
478 
479  if(Viewer3d.keysDown["W"] || Viewer3d.keysDown["S"]) //move forward or backward
480  {
481  var dir = [];
482  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
483  vec3.normalize(dir);
484  vec3.scale(dir,Viewer3d.cameraKeyNavFast?Viewer3d.KEY_MOVE_SPEED_FAST:Viewer3d.KEY_MOVE_SPEED_SLOW);
485 
486  if(Viewer3d.keysDown["W"]) vec3.add(Viewer3d.cameraPos, dir);
487  else vec3.subtract(Viewer3d.cameraPos, dir);
488 
489  vec3.normalize(dir);
490  vec3.add(Viewer3d.cameraPos, dir, Viewer3d.cameraFocus);
491  actionTaken = true;
492  }
493 
494  if(Viewer3d.keysDown["W"] || Viewer3d.keysDown["S"]) //move forward or backward
495  {
496  actionTaken = true;
497  }
498 
499  return actionTaken;
500 }
501 
502 Viewer3d.handleCanvasMouseWheel = function(event) {
503  var delta = event.wheelDelta/120;
504  Viewer3d.zoomCameraByDelta(delta,
505  Viewer3d.cameraKeyNavFast?Viewer3d.MOUSE_WHEEL_SPEED_FAST:Viewer3d.MOUSE_WHEEL_SPEED_SLOW);
506 }
507 
508 Viewer3d.zoomCameraByDelta = function(delta, speed) {
509  if(!delta) return; //0 delta do nothing
510 
511  var dir = [];
512  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
513  vec3.normalize(dir);
514  vec3.scale(dir,speed);
515 
516  if(delta > 0) vec3.add(Viewer3d.cameraPos, dir);
517  else vec3.subtract(Viewer3d.cameraPos, dir);
518 
519  vec3.normalize(dir);
520  vec3.add(Viewer3d.cameraPos, dir, Viewer3d.cameraFocus);
521 
522  Viewer3d.cameraAction = true;
523 }
524 
525 Viewer3d.handleCanvasTouchMove = function(touchEvent) {
526 
527  touchEvent.preventDefault(); //fix chrome issue of only 2 fires
528  touchEvent.cancelBubble=true; //eat event away so scrolling doesnt happen
529  Viewer3d.lastTouchTime = 0; //prevent a moving finger from firing double tap reset camera view
530 
531  var touch = touchEvent.targetTouches[0];
532  var newMousePos = [touch.pageX, touch.pageY];
533  var touch2 = touchEvent.targetTouches[1];
534  if(touch2) //second finger detected, so do zoom action
535  {
536  var mag = Math.sqrt((touch2.pageX-touch.pageX)*(touch2.pageX-touch.pageX) +
537  (touch2.pageY-touch.pageY)*(touch2.pageY-touch.pageY));
538  //Debug.log("Viewer3d touch2 " + touch2.pageX + "-" + touch2.pageY + "=" + mag);
539  if(Viewer3d.lastTwoTouchMag)
540  Viewer3d.zoomCameraByDelta(mag-Viewer3d.lastTwoTouchMag, Viewer3d.TOUCH_ZOOM_SPEED);
541  Viewer3d.lastTwoTouchMag = mag;
542  Viewer3d.lastMousePos = [-1,-1]; //prevent weird jumps in transition from zoom to move
543  return;
544  }
545 
546  var delta = [Viewer3d.lastMousePos[0] - newMousePos[0],
547  Viewer3d.lastMousePos[1] - newMousePos[1]];
548  if(Viewer3d.lastMousePos[0] > 0) //prevent weird jumps in transition from zoom to move
549  Viewer3d.panCameraByDelta(delta,Viewer3d.TOUCH_NAV_SPEED);
550  Viewer3d.lastMousePos = newMousePos;
551 }
552 
553 Viewer3d.handleCanvasMouseMove = function(event) {
554 
555  if(Viewer3d.enableMouseNav && event.which == 1) //left mouse button
556  {
557  var newMousePos = [event.clientX, event.clientY];
558 
559  var delta = [newMousePos[0] - Viewer3d.lastMousePos[0],
560  newMousePos[1] - Viewer3d.lastMousePos[1]];
561 
562  Viewer3d.panCameraByDelta(delta,Viewer3d.MOUSE_NAV_SPEED);
563  Viewer3d.lastMousePos = newMousePos;
564  }
565 }
566 
567 Viewer3d.handleCanvasTouchStart = function(touchEvent) {
568  var touchTime = new Date().getTime();
569  var touch = touchEvent.targetTouches[0];
570  Viewer3d.lastMousePos = [touch.pageX, touch.pageY];
571  if(Viewer3d.lastTouchTime && !touchEvent.targetTouches[1] && //test if single-finger double tap occured
572  touchTime - Viewer3d.lastTouchTime < Viewer3d.DOUBLE_TAP_RESET_TIME)
573  { //double tap detected!!
574 
575  touchEvent.preventDefault(); //prevent native zoom action
576 
577  if(touch.pageY < Viewer3d.DOUBLE_TAP_HUD_Y_ACCEPT && //expand 3d hud!
578  touch.pageX > window.innerWidth - Viewer3d.hud.hudMouseOverDiv.offsetWidth - 2*Viewer3d.HUD_MARGIN_RIGHT)
579  {
580  Viewer3d.hud.mouseOverDropDown();
581  return;
582  }
583 
584  if(touch.pageY < Viewer3d.DOUBLE_TAP_HUD_Y_ACCEPT && //expand top level visualization hud!
585  touch.pageX < Viewer3d.hud.hudMouseOverDiv.offsetWidth + 2*Viewer3d.HUD_MARGIN_RIGHT)
586  {
587  mouseOverDropDown();
588  return;
589  }
590 
591  //else reset camera view
592  Debug.log("Viewer3d handleCanvasTouchStart Double Tap Reset Camera! " + (touchTime - Viewer3d.lastTouchTime));
593  Viewer3d.resetCamera();
594  Viewer3d.redraw();
595  return;
596  }
597 
598  Viewer3d.lastTouchTime = touchTime;
599  Viewer3d.hud.mouseOutDropDown(); //elevate drop downs if touches going on
600  mouseOutDropDown(); //top level visualization drop down hud
601 }
602 
603 Viewer3d.handleCanvasMouseDown = function(event) {
604  Debug.log("Viewer3d handleCanvasMouseDown ");
605  Viewer3d.lastMousePos = [event.clientX, event.clientY];
606  window.focus(); //manual focus since return false
607  if(Viewer3d.hud) //manual remove focus from any text inputs!
608  Viewer3d.hud.hudRunNumberInput.blur();
609  return false; //return false to cancel drag and drop action
610 }
611 
612 Viewer3d.panCameraByDelta = function(delta, speed) {
613  if(!delta[0] && !delta[1]) return;
614 
615  //rotate left/right
616  var dir = [];
617  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
618 
619  var left = [];
620  vec3.cross(Viewer3d.cameraUp,dir,left);
621  vec3.normalize(left);
622  vec3.scale(left,-delta[0]*speed);
623 
624  vec3.add(Viewer3d.cameraFocus, left, Viewer3d.cameraFocus);
625 
626  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
627  vec3.normalize(dir);
628  vec3.add(Viewer3d.cameraPos, dir, Viewer3d.cameraFocus);
629 
630  //rotate up/down
631  var up = [];
632  vec3.set(Viewer3d.cameraUp,up);
633  vec3.normalize(up);
634  vec3.scale(up,-delta[1]*speed);
635 
636  vec3.add(Viewer3d.cameraFocus, up, Viewer3d.cameraFocus);
637  vec3.subtract(Viewer3d.cameraFocus,Viewer3d.cameraPos,dir);
638  vec3.normalize(dir);
639  vec3.add(Viewer3d.cameraPos, dir, Viewer3d.cameraFocus);
640 
641  Viewer3d.cameraAction = true;
642 }
643 
644 Viewer3d.handleWindowResize = function() {
645 
646  var w = window.innerWidth < Viewer3d.CANVAS_MIN_SIZE? Viewer3d.CANVAS_MIN_SIZE:window.innerWidth;
647  var h = window.innerHeight < Viewer3d.CANVAS_MIN_SIZE? Viewer3d.CANVAS_MIN_SIZE:window.innerHeight;
648 
649  Debug.log("Viewer3d.handleWindowResize " + w + "-" + h);
650 
651  Viewer3d.omni.style.width = w + "px";
652  Viewer3d.omni.style.height = h + "px";
653  Viewer3d.canvas.style.width = w + "px";
654  Viewer3d.canvas.style.height = h + "px";
655  Viewer3d.canvas.width = w;
656  Viewer3d.canvas.height = h;
657 
658  //resize webGL
659  var gl = Viewer3d.gl;
660  gl.viewportWidth = Viewer3d.canvas.width;
661  gl.viewportHeight = Viewer3d.canvas.height;
662  gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
663  gl.enable(Viewer3d.gl.DEPTH_TEST); // Enable depth testing
664  gl.depthFunc(Viewer3d.gl.LEQUAL); // Near things obscure far things
665  gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
666  mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, Viewer3d.WEBGL_NEAR_CLIPPING_DEPTH, Viewer3d.WEBGL_FAR_CLIPPING_DEPTH, Viewer3d.perspectiveMatrix);
667 
668  //reposition HUD
669  Viewer3d.hud.handleWindowResize();
670 
671  //redraw 3d world
672  Viewer3d.redraw();
673 }
674 
675 // Viewer3d.initWebGL ~~
676 // warns user that their browser is incompatible
677 Viewer3d.initWebGL = function() {
678  try {
679  Viewer3d.gl = Viewer3d.canvas.getContext("webgl") || Viewer3d.canvas.getContext("experimental-webgl");
680  }
681  catch (e) { alert("Could not initialize WebGL, sorry :-("); return; }
682 
683  if (!Viewer3d.gl) { alert("Could not initialize WebGL! sorry :-("); return; }
684 
685  Viewer3d.initShaders();
686 
687  Viewer3d.perspectiveMatrix = mat4.create();
688  Viewer3d.modelViewMatrix = mat4.create();
689 
690  Viewer3d.resetCamera();
691  Viewer3d.initAxesAndGridBuffers();
692 }
693 
694 Viewer3d.resetCamera = function() {
695  Viewer3d.cameraPos = [];
696  Viewer3d.cameraUp = [];
697  Viewer3d.cameraFocus = [];
698  vec3.set(Viewer3d.WEBGL_RESET_CAMERA_POS, Viewer3d.cameraPos);
699  vec3.set(Viewer3d.WEBGL_RESET_CAMERA_UP, Viewer3d.cameraUp);
700  vec3.set(Viewer3d.WEBGL_RESET_CAMERA_FOCUS, Viewer3d.cameraFocus);
701 
702  //gaurantee vectors are normalized
703  vec3.normalize(Viewer3d.cameraUp);
704 
705  Debug.log("Viewer3d.resetCamera to pos: " + Viewer3d.cameraPos + " focus: " + Viewer3d.cameraFocus + " up: " + Viewer3d.cameraUp);
706 
707 }
708 
709 Viewer3d.initShaders = function() {
710 
711  //get fragment shader
712  var req = new XMLHttpRequest();
713  req.open("GET",'/WebPath/js/js_lib/webgl_shader-fs.shader', false);
714  req.send(null);
715  var fsCode = (req.status == 200) ? req.responseText : null;
716  if(!fsCode) { alert("Could not initialize WebGL fs shaders, sorry :-("); return; }
717  Viewer3d.fragmentShader = Viewer3d.gl.createShader(Viewer3d.gl.FRAGMENT_SHADER);
718  //Debug.log("fragmentShader" + fsCode);
719  Viewer3d.gl.shaderSource(Viewer3d.fragmentShader, fsCode);
720  Viewer3d.gl.compileShader(Viewer3d.fragmentShader);
721  if (!Viewer3d.gl.getShaderParameter(Viewer3d.fragmentShader, Viewer3d.gl.COMPILE_STATUS))
722  {
723  alert("An error occurred compiling the fragment shader: " + Viewer3d.gl.getShaderInfoLog(Viewer3d.fragmentShader));
724  return;
725  }
726 
727  //get vertex shader
728  req = new XMLHttpRequest();
729  req.open("GET",'/WebPath/js/js_lib/webgl_shader-vs.shader', false);
730  req.send(null);
731  var vsCode = (req.status == 200) ? req.responseText : null;
732  if(!vsCode) { alert("Could not initialize WebGL vs shaders, sorry :-("); return; }
733  Viewer3d.vertexShader = Viewer3d.gl.createShader(Viewer3d.gl.VERTEX_SHADER);
734  //Debug.log("vertexShader" + vsCode);
735  Viewer3d.gl.shaderSource(Viewer3d.vertexShader, vsCode);
736  Viewer3d.gl.compileShader(Viewer3d.vertexShader);
737  if (!Viewer3d.gl.getShaderParameter(Viewer3d.vertexShader, Viewer3d.gl.COMPILE_STATUS))
738  {
739  alert("An error occurred compiling the vertex shader: " + Viewer3d.gl.getShaderInfoLog(Viewer3d.vertexShader));
740  return;
741  }
742 
743  //setup shader progam
744  Viewer3d.shaderProgram = Viewer3d.gl.createProgram();
745  Viewer3d.gl.attachShader(Viewer3d.shaderProgram, Viewer3d.vertexShader);
746  Viewer3d.gl.attachShader(Viewer3d.shaderProgram, Viewer3d.fragmentShader);
747  Viewer3d.gl.linkProgram(Viewer3d.shaderProgram);
748 
749  if (!Viewer3d.gl.getProgramParameter(Viewer3d.shaderProgram, Viewer3d.gl.LINK_STATUS))
750  { alert("Could not initialize shader program"); return; }
751 
752  Viewer3d.gl.useProgram(Viewer3d.shaderProgram);
753 
754  Viewer3d.shaderProgram.vertexPositionAttribute = Viewer3d.gl.getAttribLocation(Viewer3d.shaderProgram, "aVertexPosition");
755  Viewer3d.gl.enableVertexAttribArray(Viewer3d.shaderProgram.vertexPositionAttribute);
756 
757  Viewer3d.shaderProgram.vertexColorAttribute = Viewer3d.gl.getAttribLocation(Viewer3d.shaderProgram, "aVertexColor");
758  Viewer3d.gl.enableVertexAttribArray(Viewer3d.shaderProgram.vertexColorAttribute);
759 
760  Viewer3d.shaderProgram.pMatrixUniform = Viewer3d.gl.getUniformLocation(Viewer3d.shaderProgram, "uPMatrix");
761  Viewer3d.shaderProgram.mvMatrixUniform = Viewer3d.gl.getUniformLocation(Viewer3d.shaderProgram, "uMVMatrix");
762 }
763 
764 Viewer3d.createHud = function() {
765 
766  var hudMouseOverDiv;
767  var animationTargetTop, isDropDownAnimating, isDropDownDown;
768  var controlMouseIsDown = false;
769  var controlMouseTimeout = 0;
770  var getEventsTimeout = 0;
771 
772  this.isInMotion = function() { return isDropDownAnimating; }
773 
774  this.handleWindowResize = function() {
775  Debug.log("Viewer3d Hud handleWindowResize");
776  this.hudMouseOverDiv.style.left = window.innerWidth - this.hudMouseOverDiv.offsetWidth - Viewer3d.HUD_MARGIN_RIGHT + "px";
777 
778  this.hudNavSpeedDiv.style.left = 5 + "px";
779  this.hudNavSpeedDiv.style.top = window.innerHeight - 95 + "px";
780 
781  this.update();
782  }
783 
784  this.checkboxUpdate = function(i) {
785  var chk = document.getElementById("hudCheckbox" + i);
786  Debug.log("Viewer3d Hud checkboxUpdate " + i + "=" + chk.checked);
787 
788  if(i==0) Viewer3d.drawAxesFlag = chk.checked; //axes
789  else if(i==1) Viewer3d.drawGridFlag = chk.checked; //grid
790  else if(i==2) Viewer3d.drawTracksFlag = chk.checked; //tracks
791  else if(i==3) Viewer3d.enableMouseNav = chk.checked; //mouse nav
792  else if(i==4) Viewer3d.enableFlyBy = chk.checked; //fly-by
793  else if(i==5) Viewer3d.accumulateEvents = chk.checked; //accumulate
794 
795  Viewer3d.redraw();
796  this.update();
797  }
798 
799  this.update = function() {
800 
801  this.hudNavSpeedDiv.innerHTML = "Tests of radiation-hard sensors for the SLHC<br>";
802  this.hudNavSpeedDiv.innerHTML += "at the Fermi Test Beam Facility.<br>";
803  this.hudNavSpeedDiv.innerHTML += "Devices under test for this run were 3D Pixel Sensors.<br>";
804  if(Viewer3d.enableFlyBy)
805  this.hudNavSpeedDiv.innerHTML += "Fly-by Mode";
806  else
807  this.hudNavSpeedDiv.innerHTML += "Nav Speed: " + (Viewer3d.cameraKeyNavFast?"Fast":"Slow");
808 
809  var str = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + ((Viewer3d.accumulateEvents && Viewer3d.eventToDisplay<0)?"Events Accumulated":("Event: " +
810  (Viewer3d.eventToDisplay<0?"All":Viewer3d.eventToDisplay)));
811  str += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + "Run: " + (Viewer3d.runNumber < 0?"Not found":Viewer3d.runNumber);
812  this.hudNavSpeedDiv.innerHTML += str;
813 
814  this.hudEventNumber.innerHTML = "Event #: " + (Viewer3d.eventToDisplay<0?"All":Viewer3d.eventToDisplay);
815 
816  if(Viewer3d.accumulateEvents)
817  this.hudEventNumberControls.style.display = "none";
818  else
819  this.hudEventNumberControls.style.display = "block";
820  }
821 
822  // animateDropDown ~~
823  var animateDropDown = function() {
824  var dir = (animationTargetTop - hudMouseOverDiv.offsetTop > 0)? 1: -1;
825 
826  var tmpTop = hudMouseOverDiv.offsetTop + dir*Viewer3d.HUD_DROP_DOWN_SPEED;
827  if(Math.abs(tmpTop - animationTargetTop) <= Viewer3d.HUD_DROP_DOWN_SPEED) //done
828  {
829  hudMouseOverDiv.style.top = animationTargetTop + "px";
830  isDropDownAnimating = false;
831  return;
832  }
833  //else still going towards target
834  hudMouseOverDiv.style.top = tmpTop + "px";
835  window.setTimeout(animateDropDown,30);
836  }
837 
838  // mouseOverDropDown ~~
839  var mouseOverDropDown = this.mouseOverDropDown = function() {
840  if(isDropDownAnimating) return; //do nothing if animating currently
841 
842  if(!isDropDownDown) //start animation
843  {
844  isDropDownDown = true;
845  isDropDownAnimating = true;
846  animationTargetTop = -15;
847  window.setTimeout(animateDropDown,30);
848  }
849  }
850 
851  // mouseOutDropDown ~~
852  var mouseOutDropDown = this.mouseOutDropDown = function(event) {
853  if(isDropDownAnimating) return; //do nothing if animating currently
854 
855  if(event)
856  {
857  var e = event.toElement || event.relatedTarget;
858  while(e) //if moving within drop down menu ignore
859  {
860  if(e == this) return;
861  e = e.parentNode;
862  }
863  }
864 
865  if(isDropDownDown) //start animation
866  {
867  isDropDownDown = false;
868  isDropDownAnimating = true;
869  animationTargetTop = 15 - hudMouseOverDiv.offsetHeight;
870  window.setTimeout(animateDropDown,30);
871  }
872  }
873 
874  //for event and run number buttons
875  this.handleControlDown = function(i,evt) {
876  //Debug.log("hud control down " + i);
877 
878  var to = 500;
879  if(controlMouseIsDown) //already mouse down, so do action
880  {
881  to = 10;
882  doControlAction(i);
883  }
884  else if(evt)
885  controlMouseIsDown = true;
886 
887  if(controlMouseIsDown)
888  {
889  if(controlMouseTimeout) window.clearTimeout(controlMouseTimeout);
890  controlMouseTimeout = window.setTimeout(function() {Viewer3d.hud.handleControlDown(i)},to);
891  }
892  }
893 
894  //for event and run number buttons
895  this.handleControlUp = function(i) {
896  if(!controlMouseIsDown) return;
897 
898  //Debug.log("hud control up " + i);
899 
900  if(controlMouseTimeout) window.clearTimeout(controlMouseTimeout);
901  controlMouseIsDown = false;
902  doControlAction(i); //do action on mouse up
903  }
904 
905  //for event and run number buttons
906  var doControlAction = function(i) {
907  switch(i)
908  {
909  case 0:
910  case 1:
911  case 2:
912  case 3:
913  if(i!=1 && i!=2)
914  Viewer3d.eventToDisplay += (i==0?-1:1)*parseInt(Viewer3d.events.length/5+1);
915  else
916  Viewer3d.eventToDisplay += (i==1?-1:1);
917 
918  if(Viewer3d.eventToDisplay < 0)
919  Viewer3d.eventToDisplay = 0;
920  if(Viewer3d.eventToDisplay >= Viewer3d.events.length)
921  Viewer3d.eventToDisplay = Viewer3d.events.length - 1;
922  break;
923  case 4: //dec run #
924  case 5: //inc run #
925  Viewer3d.hud.hudRunNumberInput.value = parseInt(Viewer3d.hud.hudRunNumberInput.value) + (i*2-9);
926  if(Viewer3d.hud.hudRunNumberInput.value < 0) Viewer3d.hud.hudRunNumberInput.value = 0;
927  if(getEventsTimeout) window.clearTimeout(getEventsTimeout);
928  getEventsTimeout = window.setTimeout(Viewer3d.getEvents,1000);
929  break;
930  default:
931  Debug.log("hud doControlAction unknown action" + i);
932  return;
933  }
934 
935  Viewer3d.hud.update();
936  }
937 
938  //only allow positive integers, remove all non numbers and parse as int
939  this.handleRunChange = function() {
940  //Debug.log("hud handleRunChange " );
941  var s = this.hudRunNumberInput.value;
942  for(var i=0;i<s.length;++i)
943  {
944  if(!(parseInt(s[i])+1)) //remove non numbers
945  {
946  s = s.substr(0,i) + s.substr(i+1);
947  --i; //rewind
948  }
949  }
950  s = parseInt(s);
951  if(s+"" != this.hudRunNumberInput.value) //string comparison
952  {
953  this.hudRunNumberInput.value = s;
954  Debug.log("hud handleRunChange " + s);
955  }
956  }
957 
958 
959  this.hudNavSpeedDiv = document.createElement('div');
960  this.hudNavSpeedDiv.setAttribute("id", "Viewer3d-hudNavSpeedOverlay");
961  this.hudNavSpeedDiv.style.position = "absolute";
962  this.hudNavSpeedDiv.style.zIndex = 100;
963  Viewer3d.omni.appendChild(this.hudNavSpeedDiv);
964 
965 
966  hudMouseOverDiv = this.hudMouseOverDiv = document.createElement('div');
967  hudMouseOverDiv.setAttribute("id", "Viewer3d-hudMouseOver");
968  hudMouseOverDiv.style.position = "absolute";
969  hudMouseOverDiv.style.zIndex = 100;
970 
971  this.hudDiv = document.createElement('div');
972  this.hudDiv.setAttribute("id", "Viewer3d-hud");
973  var chkLabels = ["Show Axes","Show Grid","Show Tracks", "Mouse Nav","Fly-By","Accumulated"];
974  var chkDefaults = ["checked","checked","checked","checked",Viewer3d.enableFlyBy?"checked":"",Viewer3d.accumulateEvents?"checked":""];
975  var str = "";
976  for(var i=0;i<chkLabels.length;++i)
977  str += "<input type='checkbox' id='hudCheckbox" + i + "' onchange='Viewer3d.hud.checkboxUpdate(" + i +
978  ");' " + chkDefaults[i] + "><label for='hudCheckbox" + i + "'>" + chkLabels[i] + "</label><br>";
979 
980  //add event controls
981  str += "<center><div id='Viewer3d-hudEventNumberControls'><div id='Viewer3d-hudEventNumber'></div>";
982  var evtNumBtns = ["<<","<",">",">>"];
983  for(var i=0;i<evtNumBtns.length;++i)
984  str += "<input type='button' onmousedown='Viewer3d.hud.handleControlDown(" + i + ",event);' " +
985  "onmouseup='Viewer3d.hud.handleControlUp(" + i + ");' " +
986  "onmouseout='Viewer3d.hud.handleControlUp(" + i + ");' " +
987  "value='" + evtNumBtns[i] + "' />";
988  str += "</div></center>";
989 
990  //add run controls
991  if(DesktopContent._theDesktopWindow) //only add if successful login
992  {
993  str += "<div id='Viewer3d-hudRunNumberControls'>Run #: " +
994  "<input id='Viewer3d-hudRunNumberControls-textInput' oninput='Viewer3d.hud.handleRunChange();' type='text' value='40' > ";
995  evtNumBtns = ["<",">"];
996  for(var i=0;i<evtNumBtns.length;++i)
997  str += "<input type='button' onmousedown='Viewer3d.hud.handleControlDown(" + (i+4) + ",event);' " +
998  "onmouseup='Viewer3d.hud.handleControlUp(" + (i+4) + ");' " +
999  "onmouseout='Viewer3d.hud.handleControlUp(" + (i+4) + ");' " +
1000  "value='" + evtNumBtns[i] + "' />";
1001  str += "</div>";
1002  }
1003  else
1004  {
1005  str += "<input id='Viewer3d-hudRunNumberControls-textInput' type='hidden' value='40' >";
1006 
1007  this.hudUrlOverlay = document.createElement('div');
1008  this.hudUrlOverlay.setAttribute("id", "Viewer3d-hudUrlOverlay");
1009  this.hudUrlOverlay.style.position = "absolute";
1010  this.hudUrlOverlay.style.zIndex = 100;
1011  this.hudUrlOverlay.style.left = 5 + "px";
1012  this.hudUrlOverlay.style.top = 5 + "px";
1013  this.hudUrlOverlay.innerHTML = "Try on your own mobile device!<br>http://tinyurl.com/q6lhdrm";
1014  Viewer3d.omni.appendChild(this.hudUrlOverlay);
1015  }
1016 
1017  this.hudDiv.innerHTML = str;
1018 
1019 // _historyEl.onmousewheel = handleUserInputScroll;
1020 // _historyEl.onmousedown = handleUserInputScroll;
1021 // this.hudEventScrollbar.onscroll = this.handleEventScroll;
1022 // _historyEl.onmousemove = handleMouseMoveScroll;
1023 
1024  hudMouseOverDiv.appendChild(this.hudDiv);
1025 
1026  hudMouseOverDiv.style.top = hudMouseOverDiv.offsetHeight - 15 + "px";
1027  hudMouseOverDiv.style.width = Viewer3d.HUD_WIDTH + "px";
1028  hudMouseOverDiv.onmouseover = mouseOverDropDown;
1029  hudMouseOverDiv.onmouseout = mouseOutDropDown;
1030  Viewer3d.omni.appendChild(hudMouseOverDiv);
1031 
1032  this.hudEventNumber = document.getElementById('Viewer3d-hudEventNumber'); //get reference
1033  this.hudEventNumberControls = document.getElementById('Viewer3d-hudEventNumberControls'); //get reference
1034  this.hudRunNumberInput = document.getElementById('Viewer3d-hudRunNumberControls-textInput'); //get reference
1035 
1036  //setup dropdown effect
1037  isDropDownDown = false;
1038  isDropDownAnimating = true;
1039  animationTargetTop = 15 - hudMouseOverDiv.offsetHeight;
1040  window.setTimeout(animateDropDown,30);
1041  this.handleWindowResize();
1042 }
1043 
1044 
1045 Viewer3d.getEvents = function() {
1046  Debug.log("Viewer3d getEvents for run " + Viewer3d.hud.hudRunNumberInput.value);
1047  DesktopContent.XMLHttpRequest("Request?RequestType=getEvents&run=" +
1048  parseInt(Viewer3d.hud.hudRunNumberInput.value), "", Viewer3d.getEventsHandler);
1049 }
1050 
1051 //Viewer3d.getEventsHandler ~~
1052 Viewer3d.getEventsHandler = function (req) {
1053  //Debug.log("Viewer3d getEventsHandler " + req.responseText.substr(1000));
1054  Viewer3d.runNumber = Viewer3d.hud.hudRunNumberInput.value; //update loaded run number
1055  var events = req.responseXML.getElementsByTagName("event");
1056 
1057  Viewer3d.events = [];
1058  var evt, cnt;
1059  var gl = Viewer3d.gl;
1060  var locPoints, xyzPoints, slopes, intercepts;
1061  var locSlope = [];
1062  var locIntcpt = [];
1063  var pixelSz = 200;
1064  var trackSz = 1000000;
1065  for(var i=0;i<events.length;++i)
1066  {
1067  xyzPoints = events[i].getElementsByTagName("xyz_point");
1068 
1069  //create a new event to hold clusters and tracks
1070  evt = Viewer3d.events.length;
1071  Viewer3d.events[evt] = Viewer3d.events[evt] || {};
1072  Viewer3d.events[evt].clusters = [];
1073 
1074  //clusters
1075  locPoints = [];
1076  for(var j=0;j<xyzPoints.length;++j) //for each cluster point, make a square
1077  {
1078  if(j%3==2) //have the x,y of cluster point started, finish it
1079  {
1080  locPoints[locPoints.length] = xyzPoints[j].getAttribute("value")/Viewer3d.Z_SQUASH_FACTOR;
1081 
1082  for(var k=0;k<3;++k) //make the 3 other points of square, original point is top left, and then two adj, and then opposite for TRIANGLE_STRIP
1083  {
1084  locPoints[locPoints.length] = locPoints[locPoints.length-3*(k+1)] + (k==0?pixelSz:(k==1?0:pixelSz));
1085  locPoints[locPoints.length] = locPoints[locPoints.length-3*(k+1)] + (k==0?0:(k==1?pixelSz:pixelSz));
1086  locPoints[locPoints.length] = locPoints[locPoints.length-3*(k+1)];
1087  }
1088 
1089  //a new cluster is complete
1090 
1091  cnt = Viewer3d.events[evt].clusters.length;
1092  Viewer3d.events[evt].clusters[cnt] = gl.createBuffer();
1093  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.events[evt].clusters[cnt]);
1094  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(locPoints), gl.STATIC_DRAW);
1095  Viewer3d.events[evt].clusters[cnt].itemSize = 3;
1096  Viewer3d.events[evt].clusters[cnt].numItems = locPoints.length/3;
1097  locPoints = [];
1098  }
1099  else //get x and y
1100  locPoints[locPoints.length] = xyzPoints[j].getAttribute("value") - pixelSz/2;
1101  }
1102 
1103  //tracks
1104  slopes = events[i].getElementsByTagName("slope");
1105  intercepts = events[i].getElementsByTagName("intcpt");
1106  locPoints = [];
1107  for(var j=0;j<slopes.length;j+=2) //for each track, make a line
1108  {
1109  locSlope[0] = parseInt(slopes[j].getAttribute("value"))/Viewer3d.Z_SQUASH_FACTOR;
1110  locSlope[1] = parseInt(slopes[j+1].getAttribute("value"))/Viewer3d.Z_SQUASH_FACTOR;
1111  locIntcpt[0] = parseInt(intercepts[j].getAttribute("value"));
1112  locIntcpt[1] = parseInt(intercepts[j+1].getAttribute("value"));
1113  locPoints[locPoints.length] = locSlope[0]*-trackSz + locIntcpt[0]; //x
1114  locPoints[locPoints.length] = locSlope[1]*-trackSz + locIntcpt[1]; //y
1115  locPoints[locPoints.length] = -trackSz; //z
1116  locPoints[locPoints.length] = locSlope[0]*trackSz + locIntcpt[0]; //x
1117  locPoints[locPoints.length] = locSlope[1]*trackSz + locIntcpt[1]; //y
1118  locPoints[locPoints.length] = trackSz; //z
1119  }
1120  //Debug.log("Viewer3d getEventsHandler event locPoints " + locPoints);
1121 
1122  Viewer3d.events[evt].tracks = gl.createBuffer();
1123  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.events[evt].tracks);
1124  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(locPoints), gl.STATIC_DRAW);
1125  Viewer3d.events[evt].tracks.itemSize = 3;
1126  Viewer3d.events[evt].tracks.numItems = locPoints.length/3;
1127  }
1128 
1129  Debug.log("Viewer3d getEventsHandler event count " + Viewer3d.events.length);
1130  Viewer3d.cameraAction = true;
1131 }
1132 
1133 Viewer3d.getGeometry = function() {
1134  Debug.log("Viewer3d.getGeometry ");
1135  DesktopContent.XMLHttpRequest("Request?RequestType=getGeometry", "", Viewer3d.getGeometryHandler);
1136 }
1137 
1138 // Viewer3d.getGeometryHandler ~~
1139 Viewer3d.getGeometryHandler = function (req) {
1140  //Debug.log("Viewer3d getGeometryHandler " + req.responseText);
1141 
1142  var objects = req.responseXML.getElementsByTagName("object");
1143 
1144  Viewer3d.geometry = [];
1145  var gi;
1146  var gl = Viewer3d.gl;
1147  var locPoints, xyzPoints, objectType;
1148  for(var i=0;i<objects.length;++i)
1149  {
1150  //TODO if different geometries, use object type
1151  //objectType = objects[i].getElementsByTagName("object_type");
1152  //Debug.log("Rotating3d getGeometry objectType " + objectType[0].getAttribute("value"));
1153 
1154  xyzPoints = objects[i].getElementsByTagName("xyz_point");
1155 
1156  locPoints = [];
1157  for(var j=0;j<xyzPoints.length;++j)
1158  locPoints[locPoints.length] = xyzPoints[j].getAttribute("value")/(j%3==2?Viewer3d.Z_SQUASH_FACTOR:1.0);
1159 
1160 
1161  gi = Viewer3d.geometry.length;
1162  Viewer3d.geometry[gi] = gl.createBuffer();
1163  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.geometry[gi]);
1164  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(locPoints), gl.STATIC_DRAW);
1165  Viewer3d.geometry[gi].itemSize = 3;
1166  Viewer3d.geometry[gi].numItems = locPoints.length/3;
1167  }
1168 
1169  Debug.log("Viewer3d getGeometryHandler geometry objects " + Viewer3d.geometry.length);
1170  Viewer3d.canvas.style.zIndex = 0; //Bring canvas to front, above "Loading..." if not already there
1171 
1172  Viewer3d.cameraAction = true;
1173 }
1174 
1175 Viewer3d.mvPushMatrix = function() {
1176  copy = mat4.create();
1177  mat4.set(Viewer3d.modelViewMatrix, copy);
1178  Viewer3d.modelViewMatrixStack.push(copy);
1179 }
1180 
1181 Viewer3d.mvPopMatrix = function() {
1182  if (Viewer3d.modelViewMatrixStack.length == 0) {
1183  throw "Invalid popMatrix!";
1184  }
1185  Viewer3d.modelViewMatrix = Viewer3d.modelViewMatrixStack.pop();
1186 }
1187 
1188 //Viewer3d.setMatrixUniforms ~~
1189 // pushes the shader matrices to the from js to webgl world
1190 // need to call any time matrices are modified
1191 Viewer3d.setMatrixUniforms = function() {
1192  Viewer3d.gl.uniformMatrix4fv(Viewer3d.shaderProgram.pMatrixUniform, false, Viewer3d.perspectiveMatrix);
1193  Viewer3d.gl.uniformMatrix4fv(Viewer3d.shaderProgram.mvMatrixUniform, false, Viewer3d.modelViewMatrix);
1194 }
1195 
1196 
1197 //Viewer3d.redraw ~~
1198 // called to redraw 3d objects
1199 Viewer3d.redraw = function () {
1200 
1201  if(Viewer3d.hud.isInMotion()) return;
1202 
1203  Viewer3d.initForDraw();
1204  if(Viewer3d.drawAxesFlag) Viewer3d.drawAxes();
1205  if(Viewer3d.drawGridFlag) Viewer3d.drawGrid();
1206  Viewer3d.drawGeometry();
1207 
1208  //drawScene();
1209 
1210  Viewer3d.drawClusters((Viewer3d.accumulateEvents && !Viewer3d.enableFlyBy)?-1:Viewer3d.eventToDisplay);
1211  if(Viewer3d.drawTracksFlag) Viewer3d.drawTracks((Viewer3d.accumulateEvents && !Viewer3d.enableFlyBy)?-1:Viewer3d.eventToDisplay);
1212  Viewer3d.hud.update(); //update hud
1213 }
1214 
1215 Viewer3d.initForDraw = function() {
1216 
1217  var gl = Viewer3d.gl;
1218  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
1219  mat4.identity(Viewer3d.modelViewMatrix);
1220 
1221  //generate camera lookAt matrix and apply
1222  var tmpLookAtMatrix = [];
1223  mat4.lookAt(Viewer3d.cameraPos, Viewer3d.cameraFocus, Viewer3d.cameraUp, tmpLookAtMatrix);
1224  mat4.multiply(Viewer3d.modelViewMatrix,tmpLookAtMatrix); //apply camera rotation
1225  Viewer3d.setMatrixUniforms();
1226 }
1227 
1228 Viewer3d.initAxesAndGridBuffers = function() {
1229  var gl = Viewer3d.gl;
1230 
1231  //for axes
1232  var tmpArray = [ //for gl.LINE
1233  0,0,0,
1234  Viewer3d.WEBGL_AXES_LENGTH,0,0,
1235  0,0,0,
1236  0,Viewer3d.WEBGL_AXES_LENGTH,0,
1237  0,0,0,
1238  0,0,Viewer3d.WEBGL_AXES_LENGTH ]
1239 
1240  Viewer3d.axes = gl.createBuffer();
1241  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.axes);
1242  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tmpArray), gl.STATIC_DRAW);
1243  Viewer3d.axes.itemSize = 3;
1244  Viewer3d.axes.numItems = tmpArray.length/3;
1245 
1246  //for grid
1247  tmpArray = [];
1248  var ti = 0;
1249  for(var x = 0; x <= 2; x+=2) //lines parallel to x axis and then to z axis
1250  for(var i = -Viewer3d.WEBGL_GRID_EXPANSE; i <= Viewer3d.WEBGL_GRID_EXPANSE; i += Viewer3d.WEBGL_GRID_SPACING)
1251  for(var j = -Viewer3d.WEBGL_GRID_EXPANSE; j <= Viewer3d.WEBGL_GRID_EXPANSE; j += Viewer3d.WEBGL_GRID_EXPANSE*2, ++ti)
1252  {
1253  tmpArray[ti*3 + x] = j; //first time this is x coord, second time z
1254  tmpArray[ti*3 + 2 - x] = i; //first time this is z coord, second time x
1255  tmpArray[ti*3 + 1] = Viewer3d.WEBGL_GRID_YOFF;
1256  }
1257 
1258  Viewer3d.grid = gl.createBuffer();
1259  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.grid);
1260  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tmpArray), gl.STATIC_DRAW);
1261  Viewer3d.grid.itemSize = 3;
1262  Viewer3d.grid.numItems = tmpArray.length/3;
1263 
1264  //Debug.log(tmpArray);
1265 }
1266 
1267 Viewer3d.drawAxes = function() {
1268  var gl = Viewer3d.gl;
1269 
1270  var geometryColorBuffer = gl.createBuffer();
1271  gl.bindBuffer(gl.ARRAY_BUFFER, geometryColorBuffer);
1272  var colors = [];
1273  for (var i=0; i < Viewer3d.axes.numItems; i++)
1274  colors = colors.concat([1.0, 1.0, 1.0, 1.0]);
1275  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
1276  gl.bindBuffer(gl.ARRAY_BUFFER, geometryColorBuffer);
1277  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
1278 
1279  gl.lineWidth(2.0);
1280  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.axes);
1281  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexPositionAttribute, Viewer3d.axes.itemSize, gl.FLOAT, false, 0, 0);
1282  gl.drawArrays(gl.LINES, 0, Viewer3d.axes.numItems);
1283 }
1284 
1285 Viewer3d.drawGrid = function() {
1286  var gl = Viewer3d.gl;
1287 
1288 
1289  var geometryColorBuffer = gl.createBuffer();
1290  gl.bindBuffer(gl.ARRAY_BUFFER, geometryColorBuffer);
1291  var colors = [];
1292  for (var i=0; i < Viewer3d.grid.numItems; i++)
1293  colors = colors.concat([0.5, 0.5, 0.5, 1.0]);
1294  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
1295  gl.bindBuffer(gl.ARRAY_BUFFER, geometryColorBuffer);
1296  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
1297 
1298  gl.lineWidth(1.0);
1299  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.grid);
1300  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexPositionAttribute, Viewer3d.grid.itemSize, gl.FLOAT, false, 0, 0);
1301  gl.drawArrays(gl.LINES, 0, Viewer3d.grid.numItems);
1302 }
1303 
1304 Viewer3d.drawGeometry = function() {
1305 
1306  if(!Viewer3d.geometry) return;
1307 
1308  var gl = Viewer3d.gl;
1309  gl.lineWidth(4.0);
1310 
1311  var geometryColorBuffer = gl.createBuffer();
1312  gl.bindBuffer(gl.ARRAY_BUFFER, geometryColorBuffer);
1313  var colors = [];
1314  for (var i=0; i < 4; i++)
1315  colors = colors.concat([0.0, 0.0, 1.0, 1.0]);
1316  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
1317  gl.bindBuffer(gl.ARRAY_BUFFER, geometryColorBuffer);
1318  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
1319 
1320  for(var i=0;i<Viewer3d.geometry.length;++i)
1321  {
1322  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.geometry[i]);
1323  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexPositionAttribute, Viewer3d.geometry[i].itemSize, gl.FLOAT, false, 0, 0);
1324 
1325  gl.activeTexture(gl.TEXTURE0);
1326  gl.bindTexture(gl.TEXTURE_2D, Viewer3d.cTexture);
1327 
1328  //gl.drawArrays(gl.TRIANGLE_STRIP, 0, Viewer3d.geometry[i].numItems);
1329  gl.drawArrays(gl.LINE_LOOP, 0, Viewer3d.geometry[i].numItems);
1330  }
1331 
1332 }
1333 
1334 
1335 Viewer3d.drawClusters = function(evt) {
1336 
1337  if(!Viewer3d.events) return;
1338 
1339  var gl = Viewer3d.gl;
1340  gl.lineWidth(2.0);
1341 
1342  var clusterColorBuffer = gl.createBuffer();
1343  gl.bindBuffer(gl.ARRAY_BUFFER, clusterColorBuffer);
1344  var colors = [];
1345  for (var i=0; i < 4; i++)
1346  colors = colors.concat([1.0, 0.0, 0.0, 1.0]);
1347  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
1348  gl.bindBuffer(gl.ARRAY_BUFFER, clusterColorBuffer);
1349  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
1350 
1351  var lo = evt < 0?0:evt;
1352  var hi = evt < 0?Viewer3d.events.length:(evt+1);
1353  for(var i=lo;i<hi && i<Viewer3d.events.length;++i)
1354  {
1355  for(var c=0;c<Viewer3d.events[i].clusters.length;++c) //clusters
1356  {
1357  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.events[i].clusters[c]);
1358  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexPositionAttribute,
1359  Viewer3d.events[i].clusters[c].itemSize, gl.FLOAT, false, 0, 0);
1360  gl.drawArrays(gl.TRIANGLE_STRIP, 0, Viewer3d.events[i].clusters[c].numItems);
1361  }
1362  }
1363 }
1364 
1365 
1366 Viewer3d.drawTracks = function(evt) {
1367 
1368  if(!Viewer3d.events) return;
1369 
1370  var gl = Viewer3d.gl;
1371  gl.lineWidth(2.0);
1372 
1373  var clusterColorBuffer = gl.createBuffer();
1374  gl.bindBuffer(gl.ARRAY_BUFFER, clusterColorBuffer);
1375  var colors = [];
1376  for (var i=0; i < 4; i++)
1377  colors = colors.concat([1%2, 1.0, 0.0, 1.0]);
1378  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
1379  gl.bindBuffer(gl.ARRAY_BUFFER, clusterColorBuffer);
1380  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexColorAttribute, 2, gl.FLOAT, false, 0, 0);
1381 
1382  var lo = evt < 0?0:evt;
1383  var hi = evt < 0?Viewer3d.events.length:(evt+1);
1384  for(var i=lo;i<hi && i<Viewer3d.events.length;++i)
1385  {
1386  gl.bindBuffer(gl.ARRAY_BUFFER, Viewer3d.events[i].tracks);
1387  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexPositionAttribute,
1388  Viewer3d.events[i].tracks.itemSize, gl.FLOAT, false, 0, 0);
1389  gl.drawArrays(gl.LINES, 0, Viewer3d.events[i].tracks.numItems);
1390  }
1391 }
1392 
1393 var cubeVertexPositionBuffer;
1394 var cubeVertexNormalBuffer;
1395 var cubeVertexTextureCoordBuffer;
1396 var cubeVertexIndexBuffer;
1397 
1398 function initBuffers() {
1399  var gl = Viewer3d.gl;
1400  cubeVertexPositionBuffer = gl.createBuffer();
1401  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
1402  vertices = [
1403  // Front face
1404  -1.0, -1.0, 1.0,
1405  1.0, -1.0, 1.0,
1406  1.0, 1.0, 1.0,
1407  -1.0, 1.0, 1.0,
1408 
1409  // Back face
1410  -1.0, -1.0, -1.0,
1411  -1.0, 1.0, -1.0,
1412  1.0, 1.0, -1.0,
1413  1.0, -1.0, -1.0,
1414 
1415  // Top face
1416  -1.0, 1.0, -1.0,
1417  -1.0, 1.0, 1.0,
1418  1.0, 1.0, 1.0,
1419  1.0, 1.0, -1.0,
1420 
1421  // Bottom face
1422  -1.0, -1.0, -1.0,
1423  1.0, -1.0, -1.0,
1424  1.0, -1.0, 1.0,
1425  -1.0, -1.0, 1.0,
1426 
1427  // Right face
1428  1.0, -1.0, -1.0,
1429  1.0, 1.0, -1.0,
1430  1.0, 1.0, 1.0,
1431  1.0, -1.0, 1.0,
1432 
1433  // Left face
1434  -1.0, -1.0, -1.0,
1435  -1.0, -1.0, 1.0,
1436  -1.0, 1.0, 1.0,
1437  -1.0, 1.0, -1.0,
1438  ];
1439  //for(var i = 0;i<vertices.length;++i)
1440  // vertices[i] *= 1.0;//10000;
1441  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
1442  cubeVertexPositionBuffer.itemSize = 3;
1443  cubeVertexPositionBuffer.numItems = 24;
1444 
1445  cubeVertexNormalBuffer = gl.createBuffer();
1446  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexNormalBuffer);
1447  var vertexNormals = [
1448  // Front face
1449  0.0, 0.0, 1.0,
1450  0.0, 0.0, 1.0,
1451  0.0, 0.0, 1.0,
1452  0.0, 0.0, 1.0,
1453 
1454  // Back face
1455  0.0, 0.0, -1.0,
1456  0.0, 0.0, -1.0,
1457  0.0, 0.0, -1.0,
1458  0.0, 0.0, -1.0,
1459 
1460  // Top face
1461  0.0, 1.0, 0.0,
1462  0.0, 1.0, 0.0,
1463  0.0, 1.0, 0.0,
1464  0.0, 1.0, 0.0,
1465 
1466  // Bottom face
1467  0.0, -1.0, 0.0,
1468  0.0, -1.0, 0.0,
1469  0.0, -1.0, 0.0,
1470  0.0, -1.0, 0.0,
1471 
1472  // Right face
1473  1.0, 0.0, 0.0,
1474  1.0, 0.0, 0.0,
1475  1.0, 0.0, 0.0,
1476  1.0, 0.0, 0.0,
1477 
1478  // Left face
1479  -1.0, 0.0, 0.0,
1480  -1.0, 0.0, 0.0,
1481  -1.0, 0.0, 0.0,
1482  -1.0, 0.0, 0.0
1483  ];
1484  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals), gl.STATIC_DRAW);
1485  cubeVertexNormalBuffer.itemSize = 3;
1486  cubeVertexNormalBuffer.numItems = 24;
1487 
1488  cubeVertexTextureCoordBuffer = gl.createBuffer();
1489  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
1490  var textureCoords = [
1491  // Front face
1492  0.0, 0.0,
1493  1.0, 0.0,
1494  1.0, 1.0,
1495  0.0, 1.0,
1496 
1497  // Back face
1498  1.0, 0.0,
1499  1.0, 1.0,
1500  0.0, 1.0,
1501  0.0, 0.0,
1502 
1503  // Top face
1504  0.0, 1.0,
1505  0.0, 0.0,
1506  1.0, 0.0,
1507  1.0, 1.0,
1508 
1509  // Bottom face
1510  1.0, 1.0,
1511  0.0, 1.0,
1512  0.0, 0.0,
1513  1.0, 0.0,
1514 
1515  // Right face
1516  1.0, 0.0,
1517  1.0, 1.0,
1518  0.0, 1.0,
1519  0.0, 0.0,
1520 
1521  // Left face
1522  0.0, 0.0,
1523  1.0, 0.0,
1524  1.0, 1.0,
1525  0.0, 1.0
1526  ];
1527  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
1528  cubeVertexTextureCoordBuffer.itemSize = 2;
1529  cubeVertexTextureCoordBuffer.numItems = 24;
1530 
1531  cubeVertexIndexBuffer = gl.createBuffer();
1532  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
1533  var cubeVertexIndices = [
1534  0, 1, 2, 0, 2, 3, // Front face
1535  4, 5, 6, 4, 6, 7, // Back face
1536  8, 9, 10, 8, 10, 11, // Top face
1537  12, 13, 14, 12, 14, 15, // Bottom face
1538  16, 17, 18, 16, 18, 19, // Right face
1539  20, 21, 22, 20, 22, 23 // Left face
1540  ];
1541  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
1542  cubeVertexIndexBuffer.itemSize = 1;
1543  cubeVertexIndexBuffer.numItems = 36;
1544 }
1545 
1546 //http://delphic.me.uk/webgltext.html
1547 function drawScene() {
1548  var gl = Viewer3d.gl;
1549 
1550 
1551  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
1552  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
1553 
1554  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexNormalBuffer);
1555  gl.vertexAttribPointer(Viewer3d.shaderProgram.vertexNormalAttribute, cubeVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);
1556 
1557  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
1558  gl.vertexAttribPointer(Viewer3d.shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
1559 
1560  gl.activeTexture(gl.TEXTURE0);
1561  gl.bindTexture(gl.TEXTURE_2D, Viewer3d.cTexture);
1562  gl.uniform1i(Viewer3d.shaderProgram.samplerUniform, 0);
1563  var lighting = true;
1564  gl.uniform1i(Viewer3d.shaderProgram.useLightingUniform, lighting);
1565  if (lighting) {
1566  gl.uniform3f(Viewer3d.shaderProgram.ambientColorUniform, 0.2, 0.2, 0.2);
1567 
1568  var lightingDirection = [ -0.25, -0.25, -1 ];
1569  var adjustedLD = vec3.create();
1570  vec3.normalize(lightingDirection, adjustedLD);
1571  vec3.scale(adjustedLD, -1);
1572  gl.uniform3fv(Viewer3d.shaderProgram.lightingDirectionUniform, adjustedLD);
1573  gl.uniform3f(Viewer3d.shaderProgram.directionalColorUniform, 0.8, 0.8, 0.8);
1574  }
1575 
1576  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
1577  Viewer3d.setMatrixUniforms();
1578  gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
1579 }
1580 
1581 
1582 
1583 
1584