1 /**
  2  * potree.js 
  3  * http://potree.org
  4  *
  5  * Copyright 2012, Markus Sch�tz
  6  * Licensed under the GPL Version 2 or later.
  7  * - http://potree.org/wp/?page_id=7
  8  * - http://www.gnu.org/licenses/gpl-3.0.html
  9  *
 10  */
 11 
 12 
 13 /**
 14  * holds the WebGL context
 15  */
 16 var gl = null;
 17 
 18 /**
 19  *
 20  * @class
 21  */
 22 function Potree(){
 23 	this.camHandler = null;
 24 }
 25 
 26 /**
 27  * a list of all js files that must be included by Potree
 28  */
 29 Potree.includes = [
 30 	"config.js",
 31 	"libs/mjs/mjs.js",
 32 	"libs/WebglDebug/webgl-debug.js",
 33 	"libs/other/other.js",
 34 	"src/extensions/Array.js",
 35 	"src/extensions/mjs.js",
 36 	"src/extensions/String.js",
 37 	"src/extensions/ArrayBuffer.js",
 38 	"src/extensions/Float32Array.js",
 39 	"src/utils/utils.js",
 40 	"src/KeyListener.js",
 41 	"src/MouseListener.js",
 42 	"src/ResourceManager/TextureManager.js",
 43 	"src/ResourceManager/MaterialManager.js",
 44 	"src/shader/Shader.js",
 45 	"src/utils/Plane.js",
 46 	"src/utils/Frustum.js",
 47 	"src/rendering/Renderer.js",
 48 	"src/scenegraph/AABB.js",
 49 	"src/scenegraph/SceneNode.js",
 50 	"src/scenegraph/Camera.js",
 51 	"src/scenegraph/Scene.js",
 52 	"src/scenegraph/MeshNode.js",
 53 	"src/scenegraph/Light.js",
 54 	"src/scenegraph/Sphere.js",
 55 //	"src/scenegraph/Plane.js",
 56 	"src/objects/Mesh.js",
 57 	"src/Viewport.js",
 58 	"src/navigation/CamHandler.js",
 59 	"src/navigation/FreeFlightCamHandler.js",
 60 	"src/Framebuffer.js",
 61 	"src/FramebufferFloat32.js",
 62 	"src/ResourceManager/ShaderManager.js",
 63 	"src/utils/MeshUtils.js",
 64 	"src/scenegraph/PointcloudOctreeSceneNode.js",
 65 	"src/scenegraph/PointCloudSceneNode.js",
 66 	"src/objects/PointCloud.js",
 67 	"src/objects/PointcloudOctreeNode.js",
 68 	"src/objects/PointcloudOctree.js",
 69 	"src/materials/Material.js",
 70 	"src/materials/WeightedPointSizeMaterial.js",
 71 	"src/materials/FixedPointSizeMaterial.js",
 72 	"src/materials/PointCloudMaterial.js",
 73 	"src/materials/FlatMaterial.js",
 74 	"src/materials/FilteredSplatsMaterial.js",
 75 	"src/loader/POCLoader.js",
 76 	"src/loader/PointAttributes.js",
 77 	"src/loader/ProceduralPointcloudGenerator.js",
 78 	"src/loader/PlyLoader.js",
 79 	"src/utils/LRU.js",
 80                   ];
 81 
 82 Potree.Settings = new Object();
 83 
 84 //settings
 85 Potree.Settings.showBoundingBoxes = false;
 86 Potree.Settings.LOD = true;
 87 Potree.Settings.LODMultiplicator = 10.0;
 88 Potree.Settings.pointSize = 1;
 89 Potree.Settings.backgroundColor = [0,0,0,1];//[ 0.3, 0.3, 0.4, 1 ];
 90 Potree.Settings.showGrid = false;
 91 Potree.Settings.frustumCulling = true;
 92 
 93 //other
 94 Potree.testFBO = null;
 95 Potree.gridSceneNode = null;
 96 Potree.canvas = null;
 97 Potree.initialized = false;
 98 
 99 
100 /**
101  * includes the javascript file at {path} by adding a script tag to the document.
102  * 
103  * @param path Potree library path
104  * @returns
105  */
106 Potree.importScripts = function(path){
107 	var importText = "";
108 	for(var i = 0; i < Potree.includes.length; i++){
109 		var include = Potree.includes[i];
110 		//document.write("<scri" + "pt type=\"text/javascript\" src=\"" + path + "/" +include+"\"></scri" + "pt>");
111 		importText += "<scri" + "pt type=\"text/javascript\" src=\"" + path + "/" +include+"\"></scri" + "pt>\n";
112 	}
113 	document.write(importText);
114 };
115 
116 
117 Potree.isWebGLEnabled = function(canvas){
118 	var names = [ "webgl", "experimental-webgl", "moz-webgl", "webkit-3d" ];
119 	for ( var i = 0; names.length > i; i++) {
120 		try {
121 			gl = canvas.getContext(names[i], {
122 				antialias : false
123 			});
124 			if (gl) {
125 				break;
126 			}
127 		} catch (e) {
128 		}
129 	}
130 	if (!gl) {
131 		console.log("No known OpenGL context detected! Is it enabled?");
132 		return false;
133 	}
134 	
135 	return true;
136 };
137 
138 /**
139  * 
140  * @param canvas the canvas element for rendering.
141  * Potree can only be intialized once.
142  * @returns
143  */
144 Potree.init = function(canvas) {
145 	if(Potree.initialized){
146 		console.log("Potree has already been initialized");
147 		return true;
148 	}
149 	
150 	Potree.canvas = canvas;
151 	Potree.currentScene = new Scene("default");
152 	
153 	if(!Potree.initGL()){
154 		// init failed -> display error message
155 		var soSorry = document.createElement("div");
156 		var msg = "<br>Could not create a WebGL context. ";
157 		msg += "<br><br>Try using <a href='http://www.mozilla.org' style='color: red'>Firefox</a> ";
158 		msg += "or <a href='www.google.com/chrome/' style='color: red'>Chrome</a>.";
159 		msg += "<br>Other WebGL enabled browsers are not supported but they might work as well.";
160 		soSorry.innerHTML = msg;
161 		soSorry.style.fontSize = "large";
162 		soSorry.style.fontWeight = "bold";
163 		soSorry.style.color = "#FFF";
164 		soSorry.style.textShadow = "black 0 0 4px, black 0 0 4px, black 0 0 4px, black 0 0 4px, black 0 0 4px, black 0 0 4px";
165 		soSorry.style.textAlign = "center";
166 		soSorry.style.verticalAlign = "bottom";
167 		soSorry.style.height = "100%";
168 		canvas.parentNode.replaceChild(soSorry, canvas);
169 		
170 		return false;
171 	}
172 	
173 	{// register mouse and key listener
174 		var mousewheelevt=(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel"; //FF doesn't recognize mousewheel as of FF3.x
175 		if (document.attachEvent){ //if IE (and Opera depending on user setting)
176 		    document.attachEvent("on"+mousewheelevt,MouseListener.mouseWheel);
177 		}else if (document.addEventListener){ //WC3 browsers
178 		    document.addEventListener(mousewheelevt, MouseListener.mouseWheel, false);
179 		}
180 		document.onkeydown = KeyListener.keyDown;
181 		document.onkeyup = KeyListener.keyUp;
182 		document.onkeypress = KeyListener.keyPress;
183 		document.onmousedown = MouseListener.mouseDown;
184 		document.onmouseup = MouseListener.mouseUp;
185 		document.onmousemove = MouseListener.mouseMove;
186 	}
187 	
188 	
189 	{// install cam handler
190 		Potree.camHandler = new FreeFlightCamHandler(Potree.currentScene.activeCamera);
191 		canvas.onfocus = function(){
192 			KeyListener.addListener(Potree.camHandler);
193 			MouseListener.addListener(Potree.camHandler);
194 		};
195 	
196 		canvas.onblur= function(){
197 			KeyListener.removeListener(Potree.camHandler);
198 			MouseListener.removeListener(Potree.camHandler);
199 		};
200 	}
201 	
202 	Potree.initialized = true;
203 	
204 	// shaders
205 	var drawTextureShader = new Shader("drawTexture", "drawTexture.vs", "drawTexture.fs");
206 	
207 	// materials
208 	var pointCloudMaterial = new PointCloudMaterial("pointCloud");
209 	
210 	Potree.mainLoop();
211 	
212 	return Potree.initialized;
213 };
214 
215 /**
216  * creates the WebGL context
217  * 
218  */
219 Potree.initGL = function() {
220 	
221 	viewportWidth = Potree.canvas.width;
222 	viewportHeight = Potree.canvas.height;
223 
224 	var names = [ "webgl", "experimental-webgl", "moz-webgl", "webkit-3d" ];
225 	for ( var i = 0; names.length > i; i++) {
226 		try {
227 			gl = Potree.canvas.getContext(names[i], {
228 				antialias : false
229 			});
230 			if (gl) {
231 				break;
232 			}
233 		} catch (e) {
234 		}
235 	}
236 	if (!gl) {
237 		console.log("No known OpenGL context detected! Is it enabled?");
238 		return false;
239 	}
240 
241 //	if(Potree.useDebugContext){
242 //		 Logger.warn("using WebGLDebugUtils - debugcontext. Performance may suffer.");
243 //		 gl = WebGLDebugUtils.makeDebugContext(gl);
244 //	}
245 	
246 	// extensions
247 	if (!gl.getExtension("OES_texture_float")) {
248 		console.log("some functions require OES_texture_float extension");
249 		return false;
250 	}
251 	
252 	// basic settings
253 	var cColor = Potree.Settings.backgroundColor;
254 	gl.clearColor(cColor.r, cColor.g, cColor.b, cColor.a);
255 	gl.enable(gl.DEPTH_TEST);
256 	gl.enable(gl.BLEND);
257 	gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
258 
259 	this.gridSceneNode = Potree.createGridNode();
260 
261 	return true;
262 };
263 
264 /**
265  * a grid at the origin.
266  * 
267  * @returns {SceneNode}
268  */
269 Potree.createGridNode = function createGridNode() {
270 	// materials
271 	var matXAxis = new FlatMaterial("xAxis", [1.0, 0.0, 0.0, 1.0]);
272 	var matYAxis = new FlatMaterial("yAxis", [0.0, 1.0, 0.0, 1.0]);
273 	var matZAxis = new FlatMaterial("zAxis", [0.0, 0.0, 1.0, 1.0]);
274 //	var gridMaterial = new FlatMaterial("grid");
275 //	gridMaterial.setColor(new Colour(0.7, 0.7, 0.7, 1.0));
276 	
277 	var gridNode = new SceneNode("gridNode", null);
278 	var mGrid = MeshUtils.createGrid(1, 20, 20);
279 	var nGrid = new MeshNode("grid", mGrid, gridNode);
280 
281 	// unfortunately, lineWidth is not supported/does not work so create 3 lines
282 	// instead of one thick line
283 	{
284 		var mXAxis = MeshUtils.createLine( [ 0, 0, 0 ], [ 1, 0, 0 ]);
285 		mXAxis.setMaterial(matXAxis);
286 		var nXAxis = new MeshNode("xAxis", mXAxis, gridNode);
287 		var nXAxis1 = new MeshNode("xAxis1", mXAxis, gridNode);
288 		nXAxis1.translate(0, 0, 0.0001);
289 		var nXAxis2 = new MeshNode("xAxis2", mXAxis, gridNode);
290 		nXAxis2.translate(0, 0, -0.0001);
291 	}
292 
293 	{
294 		var mYAxis = MeshUtils.createLine( [ 0, 0, 0 ], [ 0, 1, 0 ]);
295 		mYAxis.setMaterial(matYAxis);
296 		var nYAxis = new MeshNode("yAxis", mYAxis, gridNode);
297 		var nYAxis1 = new MeshNode("yAxis1", mYAxis, gridNode);
298 		nYAxis1.translate(0, 0, 0.0001);
299 		var nYAxis2 = new MeshNode("yAxis2", mYAxis, gridNode);
300 		nYAxis2.translate(0, 0, -0.0001);
301 	}
302 
303 	{
304 		var mZAxis = MeshUtils.createLine( [ 0, 0, 0 ], [ 0, 0, 1 ]);
305 		mZAxis.setMaterial(matZAxis);
306 		var nZAxis = new MeshNode("zAxis", mZAxis, gridNode);
307 		var nZAxis1 = new MeshNode("zAxis1", mZAxis, gridNode);
308 		nZAxis1.translate(0.0001, 0, 0);
309 		var nZAxis2 = new MeshNode("zAxis2", mZAxis, gridNode);
310 		nZAxis2.translate(-0.0001, 0, 0);
311 	}
312 	
313 	return gridNode;
314 };
315 
316 /**
317  * draws a frame to the canvas
318  */
319 Potree.draw = function() {
320 	Potree.canvas.width = Potree.canvas.clientWidth;
321 	Potree.canvas.height = Potree.canvas.clientHeight;
322 
323 	var scene = Potree.currentScene;
324 	var cam = scene.activeCamera;
325 	cam.aspectRatio = Potree.canvas.clientWidth / Potree.canvas.clientHeight;
326 	gl.viewport(0, 0, Potree.canvas.clientWidth, Potree.canvas.clientHeight);
327 	var cColor = Potree.Settings.backgroundColor;
328 	gl.clearColor(cColor.r, cColor.g, cColor.b, cColor.a);
329 	gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
330 
331 	Renderer.render(scene);
332 	
333 	if(Potree.Settings.showGrid){
334 		Potree.gridSceneNode.render(cam);
335 	}
336 
337 //	 window.mozRequestAnimationFrame(Potree.draw);
338 //	 window.webkitRequestAnimationFrame (Potree.draw);
339 	//setTimeout(Potree.draw, 0);
340 };
341 
342 
343 Potree.mainLoop = function mainLoop(){
344 	Potree.calculateTimeSinceLastFrame();
345 	
346 //	var pcl = Potree.currentScene.rootNode.children["test"];
347 //	if(pcl != null){
348 //		pcl.rotateY(timeSinceLastFrame*0.7);
349 //	}
350 
351 	Potree.update(timeSinceLastFrame);
352 	Potree.draw();
353 	
354 	// with 0ms, interaction becomes a lot slower in firefox.
355 	setTimeout(mainLoop, 10);
356 };
357 
358 var lastLoopTime = null;
359 var timeSinceLastFrame = null;
360 Potree.calculateTimeSinceLastFrame = function calculateTimeSinceLastFrame(){
361 	var newDrawTime = new Date().getTime();
362 	if (lastLoopTime != null) {
363 		timeSinceLastFrame = (newDrawTime - lastLoopTime) / 1000.0;
364 	}else{
365 		timeSinceLastFrame = 0;
366 	}
367 	lastLoopTime = new Date().getTime();
368 
369 };
370 
371 var fpsHistory = new Array();
372 Potree.update = function update(time){
373 	
374 	var fps = 1 / time;
375 
376 	fpsHistory.push(fps);
377 	if(fpsHistory.length > 10){
378 		fpsHistory.splice(0, 1);
379 	}
380 	var mean = 0;
381 	for(var i = 0; i < fpsHistory.length; i++){
382 		mean += fpsHistory[i];
383 	}
384 	mean = mean / fpsHistory.length;
385 	
386 	Potree.currentScene.rootNode.addTime(time);
387 	PointcloudOctreeNode.nodesLoadedThisFrame = 0;
388 	
389 	Potree.camHandler.update(time);
390 	
391 	var pcl = Potree.currentScene.rootNode["test"];
392 	if(pcl != null){
393 		pcl.rotateY(time);
394 	}
395 };
396 
397 
398 
399 
400 
401 
402 
403 
404 
405 
406