Merge branch 'master' of github.com:KaiRo-at/lantea
[lantea.git] / js / map.js
index b734113d1cec49c88f95ed76bf2bb60ac36a20a3..b3ddc11cc6343346db25cf5df3edc83b7d17d081 100644 (file)
--- a/js/map.js
+++ b/js/map.js
@@ -72,11 +72,19 @@ function initMap() {
               gGLMapCanvas.getContext("experimental-webgl", {depth: false});
   }
   catch(e) {}
-  // If we don't have a GL context, give up now
   if (!gMap.gl) {
+    // If we don't have a GL context, give up now
     showGLWarningDialog();
     gMap.gl = null;
   }
+  else {
+    // GL context can be lost at any time, handle that.
+    // See http://www.khronos.org/webgl/wiki/HandlingContextLost
+    gGLMapCanvas.addEventListener("webglcontextlost",
+                                  gMap.handleContextLost, false);
+    gGLMapCanvas.addEventListener("webglcontextrestored",
+                                  gMap.handleContextRestored, false);
+  }
   gTrackCanvas = document.getElementById("track");
   gTrackContext = gTrackCanvas.getContext("2d");
   if (!gMap.activeMap)
@@ -321,8 +329,13 @@ var gMap = {
       gMap.glTxCleanIntervalID = window.setInterval(gMap.cleanTextures, 30 * 1000);
     }
 
-    var throwEv = new CustomEvent("mapinit-done");
-    gAction.dispatchEvent(throwEv);
+    if (!gAppInitDone) {
+      // We may be called when context was lost and destroyed,
+      // only send event when we are in app startup
+      // (gAppInitDone is set to true right after we return this event).
+      var throwEv = new CustomEvent("mapinit-done");
+      gAction.dispatchEvent(throwEv);
+    }
   },
 
   draw: function() {
@@ -478,8 +491,8 @@ var gMap = {
                                   y: Math.ceil((gMap.pos.y + gMap.baseDim.ht / 2) / gMap.baseDim.tsize) + 1,
                                   z: gMap.pos.z});
       console.log("In range: " + tMin.x + "," + tMin.y + "," + tMin.z + " - " + tMax.x + "," + tMax.y + "," + tMax.z);
-      for (aTileKey in gMap.glTextures) {
-        var keyMatches = aTileKey.match(/([^:]+)::(\d+),(\d+),(\d+)/);
+      for (var tileKey in gMap.glTextures) {
+        var keyMatches = tileKey.match(/([^:]+)::(\d+),(\d+),(\d+)/);
         if (keyMatches && keyMatches[1] != "loading") {
           var txData = {
             style: keyMatches[1],
@@ -506,15 +519,27 @@ var gMap = {
           }
           if (delTx) {
             // Delete texture from GL and from the array we are holding.
-            gMap.gl.deleteTexture(gMap.glTextures[aTileKey]);
-            delete gMap.glTextures[aTileKey];
+            gMap.gl.deleteTexture(gMap.glTextures[tileKey]);
+            delete gMap.glTextures[tileKey];
           }
         }
       }
       console.log("Cleaning complete, " + Object.keys(gMap.glTextures).length + " textures left)");
-      //clearInterval(gMap.glTxCleanIntervalID);
     }
   },
+
+  handleContextLost: function(event) {
+    event.preventDefault();
+    // GL context is gone, let's reset everything that depends on it.
+    clearInterval(gMap.glTxCleanIntervalID);
+    gMap.glTextures = {};
+  },
+
+  handleContextRestored: function(event) {
+    // When GL context is back, init GL again and draw.
+    gMap.initGL();
+    gMap.draw();
+  },
 }
 
 // Using scale(x, y) together with drawing old data on scaled canvas would be an improvement for zooming.
@@ -1078,8 +1103,8 @@ var gTileService = {
                   .replace("{x}", norm.x)
                   .replace("{y}", norm.y)
                   .replace("{z}", norm.z)
-                  .replace("[a-c]", String.fromCharCode(97 + Math.floor(Math.random() * 2)))
-                  .replace("[1-4]", 1 + Math.floor(Math.random() * 3)),
+                  .replace("[a-c]", String.fromCharCode(97 + Math.floor(Math.random() * 3)))
+                  .replace("[1-4]", 1 + Math.floor(Math.random() * 4)),
                 true);
       XHR.responseType = "blob";
       XHR.addEventListener("load", function () {