X-Git-Url: https://git-public.kairo.at/?p=lantea.git;a=blobdiff_plain;f=js%2Fmap.js;h=a25a1f5617f6d6163fcf25d9f920c8ff6f4496ab;hp=dc3ad9c776637595ddbc764b18b111e119dc67ba;hb=edc3be711416b6cbbccd73833c892de4fb3882c8;hpb=d07d7abcbf226716c7f1d6cb70942252d5af27ad diff --git a/js/map.js b/js/map.js index dc3ad9c..a25a1f5 100644 --- a/js/map.js +++ b/js/map.js @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -var gMapCanvas, gMapContext, gTrackCanvas, gTrackContext, gGeolocation; +var gMapCanvas, gMapContext, gGLMapCanvas, gTrackCanvas, gTrackContext, gGeolocation; var gDebug = false; var gTileSize = 256; @@ -72,8 +72,22 @@ var gCurPosMapCache; function initMap() { gGeolocation = navigator.geolocation; + // Set up canvas contexts. TODO: Remove 2D map once GL support works. gMapCanvas = document.getElementById("map"); gMapContext = gMapCanvas.getContext("2d"); + gGLMapCanvas = document.getElementById("glmap"); + try { + // Try to grab the standard context. If it fails, fallback to experimental. + // We also try to tell it we do not need a depth buffer. + gMap.gl = gGLMapCanvas.getContext("webgl", {depth: false}) || + gGLMapCanvas.getContext("experimental-webgl", {depth: false}); + } + catch(e) {} + // If we don't have a GL context, give up now + if (!gMap.gl) { + showGLWarningDialog(); + gMap.gl = null; + } gTrackCanvas = document.getElementById("track"); gTrackContext = gTrackCanvas.getContext("2d"); if (!gActiveMap) @@ -89,6 +103,8 @@ function initMap() { } } + gAction.addEventListener("prefload-done", gMap.initGL, false); + console.log("map vars set, loading prefs..."); loadPrefs(); } @@ -122,7 +138,7 @@ function loadPrefs(aEvent) { gLoadingTile = new Image(); gLoadingTile.src = "style/loading.png"; gLoadingTile.onload = function() { - var throwEv = new CustomEvent("mapinit-done"); + var throwEv = new CustomEvent("prefload-done"); gAction.dispatchEvent(throwEv); }; } @@ -163,13 +179,17 @@ function loadPrefs(aEvent) { }); gWaitCounter++; var trackLoadStarted = false; + var redrawBase = 100; gTrackStore.getListStepped(function(aTPoint) { if (aTPoint) { // Add in front and return new length. var tracklen = gTrack.unshift(aTPoint); - // Redraw track every 100 values (initial paint will do first anyhow). - if (tracklen % 100 == 0) + // Redraw track periodically, larger distance the longer it gets. + // Initial paint will do initial track drawing. + if (tracklen % redrawBase == 0) { drawTrack(); + redrawBase = tracklen; + } } else { // Last point received. @@ -186,15 +206,174 @@ function loadPrefs(aEvent) { } } +var gMap = { + gl: null, + glShaderProgram: null, + glVertexPositionAttr: null, + glTextureCoordAttr: null, + glResolutionAttr: null, + glMapTexture: null, + + getVertShaderSource: function() { + return 'attribute vec2 aVertexPosition;\n' + + 'attribute vec2 aTextureCoord;\n\n' + + 'uniform vec2 uResolution;\n\n' + + 'varying highp vec2 vTextureCoord;\n\n' + + 'void main(void) {\n' + + // convert the rectangle from pixels to -1.0 to +1.0 (clipspace) 0.0 to 1.0 + ' vec2 clipSpace = aVertexPosition * 2.0 / uResolution - 1.0;\n' + + ' gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);\n' + + ' vTextureCoord = aTextureCoord;\n' + + '}'; }, + getFragShaderSource:function() { + return 'varying highp vec2 vTextureCoord;\n\n' + + 'uniform sampler2D uImage;\n\n' + + 'void main(void) {\n' + + ' gl_FragColor = texture2D(uImage, vTextureCoord);\n' + + '}'; }, + + initGL: function() { + // When called from the event listener, the "this" reference doesn't work, so use the object name. + if (gMap.gl) { + gMap.gl.viewport(0, 0, gMap.gl.drawingBufferWidth, gMap.gl.drawingBufferHeight); + gMap.gl.clearColor(0.0, 0.0, 0.0, 0.5); // Set clear color to black, fully opaque. + gMap.gl.clear(gMap.gl.COLOR_BUFFER_BIT|gMap.gl.DEPTH_BUFFER_BIT); // Clear the color. + + // Create and initialize the shaders. + var vertShader = gMap.gl.createShader(gMap.gl.VERTEX_SHADER); + var fragShader = gMap.gl.createShader(gMap.gl.FRAGMENT_SHADER); + gMap.gl.shaderSource(vertShader, gMap.getVertShaderSource()); + // Compile the shader program. + gMap.gl.compileShader(vertShader); + // See if it compiled successfully. + if (!gMap.gl.getShaderParameter(vertShader, gMap.gl.COMPILE_STATUS)) { + console.log("An error occurred compiling the vertex shader: " + gMap.gl.getShaderInfoLog(vertShader)); + return null; + } + gMap.gl.shaderSource(fragShader, gMap.getFragShaderSource()); + // Compile the shader program. + gMap.gl.compileShader(fragShader); + // See if it compiled successfully. + if (!gMap.gl.getShaderParameter(fragShader, gMap.gl.COMPILE_STATUS)) { + console.log("An error occurred compiling the fragment shader: " + gMap.gl.getShaderInfoLog(fragShader)); + return null; + } + + gMap.glShaderProgram = gMap.gl.createProgram(); + gMap.gl.attachShader(gMap.glShaderProgram, vertShader); + gMap.gl.attachShader(gMap.glShaderProgram, fragShader); + gMap.gl.linkProgram(gMap.glShaderProgram); + // If creating the shader program failed, alert + if (!gMap.gl.getProgramParameter(gMap.glShaderProgram, gMap.gl.LINK_STATUS)) { + alert("Unable to initialize the shader program."); + } + gMap.gl.useProgram(gMap.glShaderProgram); + // Get locations of the attributes. + gMap.glVertexPositionAttr = gMap.gl.getAttribLocation(gMap.glShaderProgram, "aVertexPosition"); + gMap.glTextureCoordAttr = gMap.gl.getAttribLocation(gMap.glShaderProgram, "aTextureCoord"); + gMap.glResolutionAttr = gMap.gl.getUniformLocation(gMap.glShaderProgram, "uResolution"); + + var tileVerticesBuffer = gMap.gl.createBuffer(); + gMap.gl.bindBuffer(gMap.gl.ARRAY_BUFFER, tileVerticesBuffer); + // The vertices are the coordinates of the corner points of the square. + var vertices = [ + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 0.0, 1.0, + 1.0, 0.0, + 1.0, 1.0, + ]; + gMap.gl.bufferData(gMap.gl.ARRAY_BUFFER, new Float32Array(vertices), gMap.gl.STATIC_DRAW); + gMap.gl.enableVertexAttribArray(gMap.glTextureCoordAttr); + gMap.gl.vertexAttribPointer(gMap.glTextureCoordAttr, 2, gMap.gl.FLOAT, false, 0, 0); + + // Map Texture + gMap.glMapTexture = gMap.gl.createTexture(); + gMap.gl.activeTexture(gMap.gl.TEXTURE0); + gMap.gl.bindTexture(gMap.gl.TEXTURE_2D, gMap.glMapTexture); + gMap.gl.uniform1i(gMap.gl.getUniformLocation(gMap.glShaderProgram, "uImage"), 0); + // Set params for how the texture minifies and magnifies (wrap params are not needed as we're power-of-two). + gMap.gl.texParameteri(gMap.gl.TEXTURE_2D, gMap.gl.TEXTURE_MIN_FILTER, gMap.gl.NEAREST); + gMap.gl.texParameteri(gMap.gl.TEXTURE_2D, gMap.gl.TEXTURE_MAG_FILTER, gMap.gl.NEAREST); + // Upload the image into the texture. + gMap.gl.texImage2D(gMap.gl.TEXTURE_2D, 0, gMap.gl.RGBA, gMap.gl.RGBA, gMap.gl.UNSIGNED_BYTE, gLoadingTile); + + gMap.gl.uniform2f(gMap.glResolutionAttr, gGLMapCanvas.width, gGLMapCanvas.height); + + // Create a buffer for the position of the rectangle corners. + var mapVerticesTextureCoordBuffer = gMap.gl.createBuffer(); + gMap.gl.bindBuffer(gMap.gl.ARRAY_BUFFER, mapVerticesTextureCoordBuffer); + gMap.gl.enableVertexAttribArray(gMap.glVertexPositionAttr); + gMap.gl.vertexAttribPointer(gMap.glVertexPositionAttr, 2, gMap.gl.FLOAT, false, 0, 0); + } + + var throwEv = new CustomEvent("mapinit-done"); + gAction.dispatchEvent(throwEv); + }, + + drawGL: function() { + if (!gMap.gl) { return; } + + var x_start = 0; + var i_width = 256; + var y_start = 10; + var i_height = 256; + var textureCoordinates = [ + x_start, y_start, + x_start + i_width, y_start, + x_start, y_start + i_height, + x_start, y_start + i_height, + x_start + i_width, y_start, + x_start + i_width, y_start + i_height, + ]; + gMap.gl.bufferData(gMap.gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gMap.gl.STATIC_DRAW); + + // There are 6 indices in textureCoordinates. + gMap.gl.drawArrays(gMap.gl.TRIANGLES, 0, 6); + + var x_start = 400; + var i_width = 256; + var y_start = 10; + var i_height = 256; + var textureCoordinates = [ + x_start, y_start, + x_start + i_width, y_start, + x_start, y_start + i_height, + x_start, y_start + i_height, + x_start + i_width, y_start, + x_start + i_width, y_start + i_height, + ]; + gMap.gl.bufferData(gMap.gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gMap.gl.STATIC_DRAW); + // gMap.gl.bindTexture(gMap.gl.TEXTURE_2D, gMap.glMapTexture); + + // There are 6 indices in textureCoordinates. + gMap.gl.drawArrays(gMap.gl.TRIANGLES, 0, 6); + + }, + + resizeAndDrawGL: function() { + if (!gMap.gl) { return; } + + gMap.gl.viewport(0, 0, gMap.gl.drawingBufferWidth, gMap.gl.drawingBufferHeight); + gMap.gl.clear(gMap.gl.COLOR_BUFFER_BIT); // Clear the color. + gMap.gl.uniform2f(gMap.glResolutionAttr, gGLMapCanvas.width, gGLMapCanvas.height); + gMap.drawGL(); + }, +} + function resizeAndDraw() { var viewportWidth = Math.min(window.innerWidth, window.outerWidth); var viewportHeight = Math.min(window.innerHeight, window.outerHeight); - if (gMapCanvas && gTrackCanvas) { + if (gMapCanvas && gGLMapCanvas && gTrackCanvas) { gMapCanvas.width = viewportWidth; gMapCanvas.height = viewportHeight; + gGLMapCanvas.width = viewportWidth; + gGLMapCanvas.height = viewportHeight; gTrackCanvas.width = viewportWidth; gTrackCanvas.height = viewportHeight; drawMap(); + gMap.resizeAndDrawGL(); showUI(); } } @@ -458,6 +637,10 @@ var mapEvHandler = { handleEvent: function(aEvent) { var touchEvent = aEvent.type.indexOf('touch') != -1; + if (touchEvent) { + aEvent.stopPropagation(); + } + // Bail out if the event is happening on an input. if (aEvent.target.tagName.toLowerCase() == "input") return;