void GetTileServerInfo(TILE_SERVER server, TileInfo ti, out string url) { string[] subservers = { "a", "b", "c" }; subserverSeq++; if (subserverSeq > 100000) { subserverSeq = 0; } switch (_tileServer) { case TILE_SERVER.OpenStreeMap: url = "http://" + subservers[subserverSeq % 3] + ".tile.openstreetmap.org/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.OpenStreeMapDE: url = "http://" + subservers[subserverSeq % 3] + ".tile.openstreetmap.de/tiles/osmde/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.StamenToner: url = "http://tile.stamen.com/toner/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.StamenTerrain: url = "http://tile.stamen.com/terrain/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.StamenWaterColor: url = "http://tile.stamen.com/watercolor/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoLightAll: url = "http://" + subservers[subserverSeq % 3] + ".basemaps.cartocdn.com/light_all/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoDarkAll: url = "http://" + subservers[subserverSeq % 3] + ".basemaps.cartocdn.com/dark_all/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoNoLabels: url = "http://" + subservers[subserverSeq % 3] + ".basemaps.cartocdn.com/light_nolabels/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoOnlyLabels: url = "http://" + subservers[subserverSeq % 3] + ".basemaps.cartocdn.com/light_only_labels/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoDarkNoLabels: url = "http://" + subservers[subserverSeq % 3] + ".basemaps.cartocdn.com/dark_nolabels/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoDarkOnlyLabels: url = "http://" + subservers[subserverSeq % 3] + ".basemaps.cartocdn.com/dark_only_labels/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.WikiMediaAtlas: url = "http://" + subservers[subserverSeq % 3] + ".tiles.wmflabs.org/bw-mapnik/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.ThunderForestLandscape: url = "http://" + subservers[subserverSeq % 3] + ".tile.thunderforest.com/landscape/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.OpenTopoMap: url = "http://" + subservers[subserverSeq % 3] + ".tile.opentopomap.org/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.MapBoxSatellite: url = "http://" + subservers[subserverSeq % 3] + ".tiles.mapbox.com/v3/tmcw.map-j5fsp01s/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.Sputnik: url = "http://" + subservers[subserverSeq % 3] + ".tiles.maps.sputnik.ru/tiles/kmt2/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; default: Debug.LogError("Tile server not defined: " + tileServer.ToString()); url = ""; break; } }
public string GetTileURL(TILE_SERVER server, TileInfo ti) { string url; string[] subservers = { "a", "b", "c" }; subserverSeq++; if (subserverSeq > 100000) { subserverSeq = 0; } switch (_tileServer) { case TILE_SERVER.OpenStreeMap: url = "http://" + subservers [subserverSeq % 3] + ".tile.openstreetmap.org/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.OpenStreeMapDE: url = "http://" + subservers [subserverSeq % 3] + ".tile.openstreetmap.de/tiles/osmde/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.StamenToner: url = "http://tile.stamen.com/toner/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.StamenTerrain: url = "http://tile.stamen.com/terrain/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.StamenWaterColor: url = "http://tile.stamen.com/watercolor/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoLightAll: url = "http://" + subservers [subserverSeq % 3] + ".basemaps.cartocdn.com/light_all/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoDarkAll: url = "http://" + subservers [subserverSeq % 3] + ".basemaps.cartocdn.com/dark_all/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoNoLabels: url = "http://" + subservers [subserverSeq % 3] + ".basemaps.cartocdn.com/light_nolabels/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoOnlyLabels: url = "http://" + subservers [subserverSeq % 3] + ".basemaps.cartocdn.com/light_only_labels/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoDarkNoLabels: url = "http://" + subservers [subserverSeq % 3] + ".basemaps.cartocdn.com/dark_nolabels/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.CartoDarkOnlyLabels: url = "http://" + subservers [subserverSeq % 3] + ".basemaps.cartocdn.com/dark_only_labels/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.WikiMediaAtlas: url = "http://" + subservers [subserverSeq % 3] + ".tiles.wmflabs.org/bw-mapnik/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.ThunderForestLandscape: url = "http://" + subservers [subserverSeq % 3] + ".tile.thunderforest.com/landscape/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.OpenTopoMap: url = "http://" + subservers [subserverSeq % 3] + ".tile.opentopomap.org/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.MapBoxSatellite: url = "http://" + subservers [subserverSeq % 3] + ".tiles.mapbox.com/v3/tmcw.map-j5fsp01s/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.Sputnik: url = "http://" + subservers [subserverSeq % 3] + ".tiles.maps.sputnik.ru/tiles/kmt2/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + ".png"; break; case TILE_SERVER.AerisWeather: //https://maps[server].aerisapi.com/[client_id]_[client_key]/[type]/[zoom]/[x]/[y]/[offset].png url = "http://maps" + ((subserverSeq % 4) + 1).ToString() + ".aerisapi.com/" + _tileServerClientId + "_" + _tileServerAPIKey + "/" + _tileServerLayerTypes + "/" + ti.zoomLevel + "/" + ti.x + "/" + ti.y + "/" + _tileServerTimeOffset + ".png"; break; case TILE_SERVER.Custom: StringBuilder sb = new StringBuilder(_tileServerCustomUrl); sb.Replace("$n$", subservers [subserverSeq % 3]); sb.Replace("$N$", subservers [subserverSeq % 3]); sb.Replace("$X$", ti.x.ToString()); sb.Replace("$x$", ti.x.ToString()); sb.Replace("$Y$", ti.y.ToString()); sb.Replace("$y$", ti.y.ToString()); sb.Replace("$Z$", ti.zoomLevel.ToString()); sb.Replace("$z$", ti.zoomLevel.ToString()); url = sb.ToString(); break; default: Debug.LogError("Tile server not defined: " + tileServer.ToString()); url = ""; break; } if (_tileServer != TILE_SERVER.Custom && _tileServerAPIKey != null && _tileServerAPIKey.Length > 0) { url += "?" + _tileServerAPIKey; } return(url); }
void CreateTile(TileInfo ti) { Vector2 latLonTL = ti.latlons [0]; Vector2 latLonBR; ZoomLevelInfo zi = zoomLevelsInfo [ti.zoomLevel]; int tileCode = GetTileHashCode(ti.x + 1, ti.y + 1, ti.zoomLevel); TileInfo cachedTile; if (cachedTiles.TryGetValue(tileCode, out cachedTile)) { latLonBR = cachedTile.latlons [0]; } else { latLonBR = Conversion.GetLatLonFromTile(ti.x + 1, ti.y + 1, ti.zoomLevel); } // Avoid seams on very close distance to surface if (ti.zoomLevel >= 16) { float tao = 0.000002f * (ti.zoomLevel - 15); latLonTL.x += tao; latLonTL.y -= tao; latLonBR.x -= tao; latLonBR.y += tao; } // Create container GameObject parentObj; if (ti.parent == null) { parentObj = zi.tilesContainer; if (parentObj == null) { parentObj = new GameObject("Tiles" + ti.zoomLevel); parentObj.transform.SetParent(tilesRoot, false); zi.tilesContainer = parentObj; } } else { parentObj = ti.parent.gameObject; } // Prepare mesh vertices Vector3[] tileCorners = new Vector3[4]; tileCorners [0] = Conversion.GetSpherePointFromLatLon(latLonTL); tileCorners [1] = Conversion.GetSpherePointFromLatLon(new Vector2(latLonTL.x, latLonBR.y)); tileCorners [2] = Conversion.GetSpherePointFromLatLon(latLonBR); tileCorners [3] = Conversion.GetSpherePointFromLatLon(new Vector2(latLonBR.x, latLonTL.y)); // Setup tile materials TileInfo parent = ti.parent != null ? ti.parent : ti; if (parent.normalMat == null) { parent.normalMat = Instantiate(tileMatRef); parent.normalMat.hideFlags = HideFlags.DontSave; } if (parent.transMat == null) { parent.transMat = Instantiate(tileMatTransRef); parent.transMat.hideFlags = HideFlags.DontSave; } Material tileMat = ti.zoomLevel < TILE_MIN_ZOOM_LEVEL ? parent.normalMat : parent.transMat; // UVs wrt Earth texture Vector2 tl = new Vector2((latLonTL.y + 180) / 360f, (latLonTL.x + 90) / 180f); Vector2 br = new Vector2((latLonBR.y + 180) / 360f, (latLonBR.x + 90) / 180f); if (tl.x > 0.5f && br.x < 0.5f) { br.x = 1f; } ti.worldTextureCoords = new Vector4(tl.x, br.y, br.x, tl.y); ti.ClearPlaceholderImage(); if (ti.zoomLevel < TILE_MIN_ZOOM_LEVEL) { ti.loadStatus = TILE_LOAD_STATUS.Loaded; } ti.texture = currentEarthTexture; ti.renderer = CreateObject(parentObj.transform, "Tile", tileCorners, tileIndices, tileUV, tileMat, ti.subquadIndex); ti.gameObject = ti.renderer.gameObject; ti.renderer.enabled = false; ti.created = true; #if DEBUG_TILES ti.gameObject.AddComponent <TileInfoEx> (); #endif }
internal IEnumerator LoadTileContentBackground(TileInfo ti) { yield return(new WaitForEndOfFrame()); string url = GetTileURL(_tileServer, ti); if (string.IsNullOrEmpty(url)) { Debug.LogError("Tile server url not set. Aborting"); yield break; } long downloadedBytes = 0; string error = null; string filePath = ""; byte[] textureBytes = null; ti.source = TILE_SOURCE.Unknown; // Check if tile is given by external event if (OnTileRequest != null) { if (OnTileRequest(ti.zoomLevel, ti.x, ti.y, out ti.texture, out error) && ti.texture != null) { ti.source = TILE_SOURCE.Resources; } } // Check if tile is in Resources if (ti.source == TILE_SOURCE.Unknown && _tileEnableOfflineTiles) { string path = GetTileResourcePath(ti.x, ti.y, ti.zoomLevel, false); ResourceRequest request = Resources.LoadAsync <Texture2D> (path); yield return(request); if (request.asset != null) { ti.texture = (Texture2D)request.asset; ti.source = TILE_SOURCE.Resources; } else if (tileOfflineTilesOnly) { ti.texture = tileResourceFallbackTexture; ti.source = TILE_SOURCE.Resources; } } CustomWWW www = null; if (ti.source == TILE_SOURCE.Unknown) { www = getCachedWWW(url, ti); yield return(www); error = www.error; } for (int tries = 0; tries < 100; tries++) { if (spreadLoadAmongFrames > 0) { break; } yield return(new WaitForEndOfFrame()); } spreadLoadAmongFrames--; _concurrentLoads--; if (!ti.visible) // non visible textures are ignored { ti.loadStatus = TILE_LOAD_STATUS.InQueue; yield break; } if (!string.IsNullOrEmpty(error)) { _tileLastError = "Error getting tile: " + error + " url=" + url; _tileLastErrorDate = DateTime.Now; if (_tileDebugErrors) { Debug.Log(_tileLastErrorDate + " " + _tileLastError); } ti.loadStatus = TILE_LOAD_STATUS.InQueue; yield break; } // Load texture if (ti.source != TILE_SOURCE.Resources) { downloadedBytes = www.bytesDownloaded; textureBytes = www.bytes; ti.texture = www.textureNonReadable; www.Dispose(); www = null; // Check texture consistency if (ti.loadedFromCache || _tileEnableLocalCache) { filePath = GetLocalFilePathForURL(url, ti); } if (ti.loadedFromCache && ti.texture.width <= 16) // Invalid texture in local cache, retry { if (File.Exists(filePath)) { File.Delete(filePath); } ti.loadStatus = TILE_LOAD_STATUS.Inactive; ti.queueTime = Time.time; yield break; } } ti.texture.wrapMode = TextureWrapMode.Clamp; _tileSize = ti.texture.width; // Save texture if (_tileEnableLocalCache && ti.source != TILE_SOURCE.Resources && !File.Exists(filePath)) { _tileCurrentCacheUsage += textureBytes.Length; BackgroundSaver saver = new BackgroundSaver(textureBytes, filePath); saver.Start(); } // Update stats switch (ti.source) { case TILE_SOURCE.Cache: _cacheLoads++; _cacheLoadTotalSize += downloadedBytes; break; case TILE_SOURCE.Resources: _resourceLoads++; break; default: _webDownloads++; _webDownloadTotalSize += downloadedBytes; break; } if (loadQueue.Contains(ti)) { loadQueue.Remove(ti); } FinishLoadingTile(ti); }
void CheckTiles(TileInfo parent, int currentZoomLevel, int xTile, int yTile, int zoomLevel, int subquadIndex) { // Is this tile visible? TileInfo ti; int tileCode = GetTileHashCode(xTile, yTile, zoomLevel); if (!cachedTiles.TryGetValue(tileCode, out ti)) { ti = new TileInfo(xTile, yTile, zoomLevel, subquadIndex, currentEarthTexture); ti.parent = parent; if (parent != null) { if (parent.children == null) { parent.children = new List <TileInfo> (); } parent.children.Add(ti); } for (int k = 0; k < 4; k++) { Vector2 latlon = Conversion.GetLatLonFromTile(xTile + offsets [k].x, yTile + offsets [k].y, zoomLevel); ti.latlons [k] = latlon; Vector3 spherePos = Conversion.GetSpherePointFromLatLon(latlon); ti.spherePos [k] = spherePos; } cachedTiles [tileCode] = ti; } // Check if any tile corner is visible // Phase I #if DEBUG_TILES if (ti.gameObject != null && ti.gameObject.GetComponent <TileInfoEx> ().debug) { Debug.Log("this"); } #endif bool cornersOccluded = true; Vector3 minWorldPos = Misc.Vector3Max; Vector3 maxWorldPos = Misc.Vector3Min; Vector3 tmp = Misc.Vector3zero; for (int c = 0; c < 4; c++) { Vector3 wpos = transform.TransformPoint(ti.spherePos [c]); ti.cornerWorldPos [c] = wpos; if (wpos.x < minWorldPos.x) { minWorldPos.x = wpos.x; } if (wpos.y < minWorldPos.y) { minWorldPos.y = wpos.y; } if (wpos.z < minWorldPos.z) { minWorldPos.z = wpos.z; } if (wpos.x > maxWorldPos.x) { maxWorldPos.x = wpos.x; } if (wpos.y > maxWorldPos.y) { maxWorldPos.y = wpos.y; } if (wpos.z > maxWorldPos.z) { maxWorldPos.z = wpos.z; } if (cornersOccluded) { float radiusSqr = (wpos.x - globePos.x) * (wpos.x - globePos.x) + (wpos.y - globePos.y) * (wpos.y - globePos.y) + (wpos.z - globePos.z) * (wpos.z - globePos.z); // Vector3.SqrMagnitude (wpos - globePos); // Vector3 camDir = (currentCameraPosition - wpos).normalized; FastVector.NormalizedDirection(ref wpos, ref currentCameraPosition, ref tmp); // Vector3 st = wpos + ndir * (0.01f * transform.localScale.x); Vector3 st = wpos; FastVector.Add(ref st, ref tmp, localScaleFactor); float mag = (st.x - globePos.x) * (st.x - globePos.x) + (st.y - globePos.y) * (st.y - globePos.y) + (st.z - globePos.z) * (st.z - globePos.z); if (mag > radiusSqr) { cornersOccluded = false; } } } // Bounds bounds = new Bounds ((minWorldPos + maxWorldPos) * 0.5f, maxWorldPos - minWorldPos); FastVector.Average(ref minWorldPos, ref maxWorldPos, ref tmp); Bounds bounds = new Bounds(tmp, maxWorldPos - minWorldPos); Vector3 tileMidPoint = bounds.center; // Check center of quad if (cornersOccluded) { float radiusSqr = (tileMidPoint.x - globePos.x) * (tileMidPoint.x - globePos.x) + (tileMidPoint.y - globePos.y) * (tileMidPoint.y - globePos.y) + (tileMidPoint.z - globePos.z) * (tileMidPoint.z - globePos.z); // Vector3.SqrMagnitude (tileMidPoint - globePos); // Vector3 camDir = (currentCameraPosition - tileMidPoint).normalized; FastVector.NormalizedDirection(ref tileMidPoint, ref currentCameraPosition, ref tmp); // Vector3 st = tileMidPoint + tmp * (0.01f * transform.localScale.x); Vector3 st = tileMidPoint; FastVector.Add(ref st, ref tmp, localScaleFactor); float mag = (st.x - globePos.x) * (st.x - globePos.x) + (st.y - globePos.y) * (st.y - globePos.y) + (st.z - globePos.z) * (st.z - globePos.z); if (mag > radiusSqr) { cornersOccluded = false; } } #if DEBUG_TILES if (root == null) { root = new GameObject(); root.transform.SetParent(transform); root.transform.localPosition = Vector3.zero; root.transform.localRotation = Misc.QuaternionZero; //Quaternion.Euler (0, 0, 0); } #endif bool insideViewport = false; float minX = currentCamera.pixelWidth * 2f, minY = currentCamera.pixelHeight * 2f; float maxX = -minX, maxY = -minY; if (!cornersOccluded) { // Phase II for (int c = 0; c < 4; c++) { Vector3 scrPos = currentCamera.WorldToScreenPoint(ti.cornerWorldPos [c]); insideViewport = insideViewport || (scrPos.z > 0 && scrPos.x >= 0 && scrPos.x < currentCamera.pixelWidth && scrPos.y >= 0 && scrPos.y < currentCamera.pixelHeight); if (scrPos.x < minX) { minX = scrPos.x; } if (scrPos.x > maxX) { maxX = scrPos.x; } if (scrPos.y < minY) { minY = scrPos.y; } if (scrPos.y > maxY) { maxY = scrPos.y; } } if (!insideViewport) { insideViewport = GeometryUtility.TestPlanesAABB(cameraPlanes, bounds); } } ti.insideViewport = insideViewport; ti.visible = false; if (insideViewport) { if (!ti.created) { CreateTile(ti); } if (!ti.gameObject.activeSelf) { ti.gameObject.SetActive(true); } // Manage hierarchy of tiles bool tileIsBig = false; FastVector.NormalizedDirection(ref globePos, ref tileMidPoint, ref tmp); // float dd = Vector3.Dot (currentCameraForward, (tileMidPoint - globePos).normalized); float dd = Vector3.Dot(currentCameraForward, tmp); if (dd > -0.8f || currentZoomLevel > 9) // prevents big seams on initial zooms { float aparentSize = Mathf.Max(maxX - minX, maxY - minY); tileIsBig = aparentSize > currentTileSize; } else { tileIsBig = ti.zoomLevel < currentZoomLevel; } #if DEBUG_TILES if (ti.gameObject != null) { ti.gameObject.GetComponent <TileInfoEx> ().bigTile = tileIsBig; ti.gameObject.GetComponent <TileInfoEx> ().zoomLevel = ti.zoomLevel; } #endif if ((tileIsBig || zoomLevel < TILE_MIN_ZOOM_LEVEL) && zoomLevel < _tileMaxZoomLevel) { // Load nested tiles CheckTiles(ti, currentZoomLevel, xTile * 2, yTile * 2, zoomLevel + 1, 0); CheckTiles(ti, currentZoomLevel, xTile * 2 + 1, yTile * 2, zoomLevel + 1, 1); CheckTiles(ti, currentZoomLevel, xTile * 2, yTile * 2 + 1, zoomLevel + 1, 2); CheckTiles(ti, currentZoomLevel, xTile * 2 + 1, yTile * 2 + 1, zoomLevel + 1, 3); ti.renderer.enabled = false; } else { ti.visible = true; // Show tile renderer if (!ti.renderer.enabled) { ti.renderer.enabled = true; } // If parent tile is loaded then use that as placeholder texture if (ti.zoomLevel > TILE_MIN_ZOOM_LEVEL && ti.parent.loadStatus == TILE_LOAD_STATUS.Loaded && !ti.placeholderImageSet) { ti.placeholderImageSet = true; ti.parentTextureCoords = placeHolderUV [ti.subquadIndex]; ti.SetPlaceholderImage(ti.parent.texture); } if (ti.loadStatus == TILE_LOAD_STATUS.Loaded) { if (!ti.hasAnimated) { ti.hasAnimated = true; ti.Animate(1f, AnimationEnded); } } else if (ti.loadStatus == TILE_LOAD_STATUS.Inactive) { ti.distToCamera = FastVector.SqrDistance(ref ti.cornerWorldPos [0], ref currentCameraPosition) * ti.zoomLevel; ti.loadStatus = TILE_LOAD_STATUS.InQueue; ti.queueTime = Time.time; loadQueue.Add(ti); } if (ti.children != null) { for (int k = 0; k < 4; k++) { TileInfo tiChild = ti.children [k]; HideTile(tiChild); } } } } else { HideTile(ti); } }
void AnimationEnded(TileInfo ti) { shouldCheckTiles = true; // Switch tile material to solid ti.renderer.sharedMaterial = ti.parent.normalMat; }
void MonitorInactiveTiles() { int inactiveCount = inactiveTiles.Count; bool changes = false; bool releasedMemory = false; for (int k = 0; k < inactiveCount; k++) { TileInfo ti = inactiveTiles [k]; if (ti == null || ti.gameObject == null || ti.visible || ti.texture == currentEarthTexture || ti.loadStatus != TILE_LOAD_STATUS.Loaded) { inactiveTiles [k] = null; ti.isAddedToInactive = false; changes = true; continue; } if (Time.time - ti.inactiveTime > _tileKeepAlive) { inactiveTiles [k] = null; ti.isAddedToInactive = false; ti.loadStatus = TILE_LOAD_STATUS.Inactive; // tile is now invisible, setup material for when it appears again: ti.ClearPlaceholderImage(); if (ti.source != TILE_SOURCE.Resources) { Destroy(ti.texture); } ti.texture = currentEarthTexture; // Reset parentcoords on children if (ti.children != null) { int cCount = ti.children.Count; for (int c = 0; c < cCount; c++) { TileInfo tiChild = ti.children [c]; if (!tiChild.animationFinished) { tiChild.ClearPlaceholderImage(); } } } changes = true; releasedMemory = true; } } if (changes) { List <TileInfo> newInactiveList = new List <TileInfo> (); for (int k = 0; k < inactiveCount; k++) { if (inactiveTiles [k] != null) { newInactiveList.Add(inactiveTiles [k]); } } inactiveTiles.Clear(); inactiveTiles = newInactiveList; if (releasedMemory) { Resources.UnloadUnusedAssets(); GC.Collect(); } } }
void CheckTilesContent(int currentZoomLevel) { int qCount = loadQueue.Count; bool cleanQueue = false; for (int k = 0; k < qCount; k++) { TileInfo ti = loadQueue [k]; if (ti == null) { cleanQueue = true; continue; } if (ti.loadStatus == TILE_LOAD_STATUS.InQueue) { if (ti.zoomLevel <= currentZoomLevel && ti.visible) { if (_tilePreloadTiles && ti.zoomLevel == TILE_MIN_ZOOM_LEVEL && ReloadTextureFromCacheOrMarkForDownload(ti)) { loadQueue [k] = null; cleanQueue = true; continue; } if (_concurrentLoads <= _tileMaxConcurrentDownloads) { ti.loadStatus = TILE_LOAD_STATUS.Loading; _concurrentLoads++; StartCoroutine(LoadTileContentBackground(ti)); } } else if (Time.time - ti.queueTime > TILE_MAX_QUEUE_TIME) { ti.loadStatus = TILE_LOAD_STATUS.Inactive; loadQueue [k] = null; cleanQueue = true; } } } if (cleanQueue) { if (newQueue == null) { newQueue = new List <TileInfo> (qCount); } else { newQueue.Clear(); } for (int k = 0; k < qCount; k++) { TileInfo ti = loadQueue [k]; if (ti != null) { newQueue.Add(ti); } } loadQueue.Clear(); loadQueue.AddRange(newQueue); } }
void CreatePole(TileInfo ti) { Vector3 polePos; Vector3 latLon0; string name; bool isNorth = (ti.y == 0); if (isNorth) { if (northPoleObj != null) { return; } polePos = Misc.Vector3up * 0.5f; latLon0 = ti.latlons [0]; name = "North Pole"; } else { if (southPoleObj != null) { return; } polePos = Misc.Vector3down * 0.5f; latLon0 = ti.latlons [2]; name = "South Pole"; } Vector3 latLon3 = latLon0; float lonDX = 360f / zoomLevelsInfo [ti.zoomLevel].xMax; latLon3.y += lonDX; int steps = (int)(360f / lonDX); int vertexCount = steps * 3; List <Vector3> vertices = new List <Vector3> (vertexCount); List <int> indices = new List <int> (vertexCount); List <Vector2> uv = new List <Vector2> (vertexCount); for (int k = 0; k < steps; k++) { Vector3 p0 = Conversion.GetSpherePointFromLatLon(latLon0); Vector3 p1 = Conversion.GetSpherePointFromLatLon(latLon3); latLon0 = latLon3; latLon3.y += lonDX; vertices.Add(p0); vertices.Add(p1); vertices.Add(polePos); indices.Add(k * 3); if (isNorth) { indices.Add(k * 3 + 2); indices.Add(k * 3 + 1); } else { indices.Add(k * 3 + 1); indices.Add(k * 3 + 2); } uv.Add(Misc.Vector2zero); uv.Add(Misc.Vector2up); uv.Add(Misc.Vector2right); } Renderer obj = CreateObject(tilesRoot.transform, name, vertices.ToArray(), indices.ToArray(), uv.ToArray(), ti.parent.normalMat, 0); if (isNorth) { northPoleObj = obj; } else { southPoleObj = obj; } }
internal IEnumerator LoadTileContentBackground(TileInfo ti) { yield return(new WaitForEndOfFrame()); string url; GetTileServerInfo(_tileServer, ti, out url); if (url == null) { Debug.LogError("Tile server url not set. Aborting"); yield break; } if (tileServerAPIKey != null && tileServerAPIKey.Length > 0) { url += "?" + _tileServerAPIKey; } WWW www = getCachedWWW(url, ti); yield return(www); _concurrentLoads--; if (www.error != null) { _tileLastError = "Error getting tile: " + www.error + " url=" + url; _tileLastErrorDate = DateTime.Now; if (_tileDebugErrors) { Debug.Log(_tileLastErrorDate + " " + _tileLastError); } ti.loadStatus = TILE_LOAD_STATUS.InQueue; yield break; } // Check texture consistency string filePath = GetLocalFilePathForUrl(url, ti); long downloadedBytes = www.size; ti.texture = new Texture2D(www.texture.width, www.texture.height); www.LoadImageIntoTexture(ti.texture); www.Dispose(); www = null; if (ti.texture.width <= 16 && ti.loadedFromCache) // Invalid texture in local cache, retry { if (File.Exists(filePath)) { File.Delete(filePath); } ti.loadStatus = TILE_LOAD_STATUS.Inactive; ti.queueTime = Time.time; yield break; } ti.texture.wrapMode = TextureWrapMode.Clamp; _tileSize = ti.texture.width; // Save texture if (!File.Exists(filePath)) { byte[] texBytes = ti.texture.EncodeToJPG(); _tileCurrentCacheUsage += texBytes.Length; BackgroundSaver saver = new BackgroundSaver(texBytes, filePath); saver.Start(); } // Update stats if (ti.loadedFromCache) { _cacheLoads++; _cacheLoadTotalSize += downloadedBytes; } else { _webDownloads++; _webDownloadTotalSize += downloadedBytes; } // Good to go, update tile info switch (ti.subquadIndex) { case 0: ti.parent.transMat.SetTexture("_MainTex", ti.texture); ti.parent.normalMat.SetTexture("_MainTex", ti.texture); break; case 1: ti.parent.transMat.SetTexture("_MainTex1", ti.texture); ti.parent.normalMat.SetTexture("_MainTex1", ti.texture); break; case 2: ti.parent.transMat.SetTexture("_MainTex2", ti.texture); ti.parent.normalMat.SetTexture("_MainTex2", ti.texture); break; case 3: ti.parent.transMat.SetTexture("_MainTex3", ti.texture); ti.parent.normalMat.SetTexture("_MainTex3", ti.texture); break; } ti.loadStatus = TILE_LOAD_STATUS.Loaded; if (loadQueue.Contains(ti)) { loadQueue.Remove(ti); } if (ti.zoomLevel >= TILE_MIN_ZOOM_LEVEL) { if (ti.y == 0 || ti.y == zoomLevelsInfo [ti.zoomLevel].yMax - 1) { CreatePole(ti); } } shouldCheckTiles = true; }
void CreateTile(TileInfo ti) { Vector2 latLonTL = ti.latlons [0]; Vector2 latLonBR; ZoomLevelInfo zi = zoomLevelsInfo [ti.zoomLevel]; int tileCode = GetTileHashCode(ti.x + 1, ti.y + 1, ti.zoomLevel); if (cachedTiles.ContainsKey(tileCode)) { latLonBR = cachedTiles [tileCode].latlons [0]; } else { latLonBR = GetLatLonFromTile(ti.x + 1, ti.y + 1, ti.zoomLevel); } // Create container GameObject parentObj; if (ti.parent == null) { parentObj = zi.tilesContainer; if (parentObj == null) { parentObj = new GameObject("Tiles" + ti.zoomLevel); parentObj.transform.SetParent(tilesRoot, false); zi.tilesContainer = parentObj; } } else { parentObj = ti.parent.gameObject; } // Prepare mesh vertices Vector3[] tileCorners = new Vector3[4]; tileCorners [0] = Conversion.GetSpherePointFromLatLon(latLonTL); tileCorners [1] = Conversion.GetSpherePointFromLatLon(new Vector2(latLonTL.x, latLonBR.y)); tileCorners [2] = Conversion.GetSpherePointFromLatLon(latLonBR); tileCorners [3] = Conversion.GetSpherePointFromLatLon(new Vector2(latLonBR.x, latLonTL.y)); Vector2[] meshUV; if (ti.zoomLevel < TILE_MIN_ZOOM_LEVEL) { Vector2[] uv = new Vector2[4]; uv [0] = new Vector2((latLonTL.y + 180) / 360f, (latLonTL.x + 90) / 180f); uv [1] = new Vector2((latLonBR.y + 180) / 360f, (latLonTL.x + 90) / 180f); uv [2] = new Vector2((latLonBR.y + 180) / 360f, (latLonBR.x + 90) / 180f); uv [3] = new Vector2((latLonTL.y + 180) / 360f, (latLonBR.x + 90) / 180f); meshUV = uv; } else { meshUV = tileUV; } Material tileMat; if (ti.parent != null) { if (ti.parent.normalMat == null) { ti.parent.normalMat = Instantiate(tileMatRef); ti.parent.normalMat.hideFlags = HideFlags.DontSave; } if (ti.zoomLevel < TILE_MIN_ZOOM_LEVEL) { tileMat = ti.parent.normalMat; } else { if (ti.parent.transMat == null) { ti.parent.transMat = Instantiate(tileMatTransRef); ti.parent.transMat.hideFlags = HideFlags.DontSave; } tileMat = ti.parent.transMat; } } else { ti.normalMat = Instantiate(tileMatRef); ti.normalMat.hideFlags = HideFlags.DontSave; tileMat = ti.normalMat; } ti.renderer = CreateObject(parentObj.transform, "Tile", tileCorners, tileIndices, meshUV, tileMat, ti.subquadIndex); ti.gameObject = ti.renderer.gameObject; ti.created = true; }
// GameObject root; void CheckTiles(TileInfo parent, int currentZoomLevel, int xTile, int yTile, int zoomLevel, int subquadIndex) { // Is this tile visible? TileInfo ti; int tileCode = GetTileHashCode(xTile, yTile, zoomLevel); if (cachedTiles.ContainsKey(tileCode)) { ti = cachedTiles [tileCode]; } else { ti = new TileInfo(xTile, yTile, zoomLevel, subquadIndex); ti.parent = parent; if (parent != null) { if (parent.children == null) { parent.children = new List <TileInfo> (); } parent.children.Add(ti); } for (int k = 0; k < 4; k++) { Vector2 latlon = GetLatLonFromTile(xTile + offsets [k].x, yTile + offsets [k].y, zoomLevel); ti.latlons [k] = latlon; Vector3 spherePos = Conversion.GetSpherePointFromLatLon(latlon); ti.spherePos [k] = spherePos; } cachedTiles [tileCode] = ti; } // Check if any tile corner is visible // Phase I // float distCam = Vector3.SqrMagnitude ((transform.position - Camera.main.transform.position) * 0.95f); // float distCam = Vector3.Distance (transform.position, Camera.main.transform.position) * 0.95f; // ((transform.position - Camera.main.transform.position) * 0.95f); bool cornersOccluded = true; for (int c = 0; c < 4; c++) { ti.cornerWorldPos [c] = transform.TransformPoint(ti.spherePos [c]); if (cornersOccluded) { float radiusSqr = Vector3.SqrMagnitude(ti.cornerWorldPos [c] - transform.position); Vector3 camDir = (Camera.main.transform.position - ti.cornerWorldPos [c]).normalized; Vector3 st = ti.cornerWorldPos [c] + camDir * 0.01f; if (Vector3.SqrMagnitude(st - transform.position) > radiusSqr) { // if ( Vector3.SqrMagnitude (ti.cornerWorldPos [c] - Camera.main.transform.position) < distCam) { cornersOccluded = false; } } } bool insideViewport = false; float minX = 2f, minY = 2f, maxX = -2f, maxY = -2f, maxZ = -1; if (!cornersOccluded) { // Phase II for (int c = 0; c < 4; c++) { Vector3 scrPos = Camera.main.WorldToViewportPoint(ti.cornerWorldPos [c]); if (scrPos.z < 0) { scrPos.x *= -1f; scrPos.y *= -1f; } insideViewport = insideViewport || (scrPos.z > 0 && scrPos.x >= 0 && scrPos.x < 1f && scrPos.y >= 0 && scrPos.y < 1); if (scrPos.x < minX) { minX = scrPos.x; } if (scrPos.x > maxX) { maxX = scrPos.x; } if (scrPos.y < minY) { minY = scrPos.y; } if (scrPos.y > maxY) { maxY = scrPos.y; } if (scrPos.z > maxZ) { maxZ = scrPos.z; } } if (!insideViewport && maxZ > 0) { // Check if rectangles overlap insideViewport = !(minX > 1 || maxX < 0 || minY > 1 || maxY < 0); // completely outside of screen? } } if (ti.debug) { Debug.Log("this"); } ti.insideViewport = insideViewport; ti.visible = false; if (insideViewport) { // if (root==null) { // root = new GameObject(); // root.transform.SetParent(transform); // root.transform.localPosition = Vector3.zero; // root.transform.localRotation = Quaternion.Euler(0,0,0); // } if (!ti.created) { CreateTile(ti); } if (!ti.gameObject.activeSelf) { ti.gameObject.SetActive(true); } float aparentSize = Mathf.Max((maxX - minX) * (float)Camera.main.pixelWidth, (maxY - minY) * (float)Camera.main.pixelHeight); bool tileIsBig = aparentSize > currentTileSize; // if (zoomLevel < currentZoomLevel && (tileIsBig || zoomLevel<TILE_MIN_ZOOM_LEVEL)) { if (tileIsBig || zoomLevel < TILE_MIN_ZOOM_LEVEL) { // if (tileIsBig) { // GameObject mark = GameObject.CreatePrimitive(PrimitiveType.Cube); // mark.transform.SetParent(root.transform); // mark.transform.position = ti.cornerWorldPos[0]; // mark.transform.localScale = Vector3.one * 0.3f; // TileInfoEx tie = mark.AddComponent<TileInfoEx>(); // tie.maxX = aparentSize; // } // Load nested tiles CheckTiles(ti, currentZoomLevel, xTile * 2, yTile * 2, zoomLevel + 1, 0); CheckTiles(ti, currentZoomLevel, xTile * 2 + 1, yTile * 2, zoomLevel + 1, 1); CheckTiles(ti, currentZoomLevel, xTile * 2, yTile * 2 + 1, zoomLevel + 1, 2); CheckTiles(ti, currentZoomLevel, xTile * 2 + 1, yTile * 2 + 1, zoomLevel + 1, 3); // Should I hide this tile? Only if children are all loaded bool allLoaded = true; if (ti.children != null) { for (int k = 0; k < 4; k++) { TileInfo children = ti.children [k]; if (children.insideViewport) { allLoaded = allLoaded && children.isLoadedOrHasAllChildrenLoaded; } if (!allLoaded) { break; } } } ti.isLoadedOrHasAllChildrenLoaded = allLoaded; ti.renderer.enabled = !allLoaded && (ti.loadStatus == TILE_LOAD_STATUS.Loaded || zoomLevel < TILE_MIN_ZOOM_LEVEL); if (ti.parent != null && ti.renderer.enabled && ti.renderer.sharedMaterial == ti.parent.transMat) { ti.renderer.sharedMaterial = ti.parent.normalMat; } } else { ti.visible = true; if (ti.loadStatus == TILE_LOAD_STATUS.Loaded) { if (!ti.renderer.enabled) { ShowTile(ti); } } else { if (ti.loadStatus == TILE_LOAD_STATUS.Inactive) { ti.distToCamera = (ti.cornerWorldPos [0] - Camera.main.transform.position).sqrMagnitude * ti.zoomLevel; ti.loadStatus = TILE_LOAD_STATUS.InQueue; ti.queueTime = Time.time; loadQueue.Add(ti); } if (ti.renderer.enabled) { ti.renderer.enabled = false; } } ti.isLoadedOrHasAllChildrenLoaded = ti.renderer.enabled && ti.animationFinished; if (ti.children != null) { for (int k = 0; k < 4; k++) { TileInfo tiChild = ti.children [k]; if (tiChild.gameObject != null && tiChild.gameObject.activeSelf) { tiChild.gameObject.SetActive(false); ti.visible = false; } } } } } else { if (ti.gameObject != null && ti.gameObject.activeSelf) { ti.gameObject.SetActive(false); // if (ti.texture!=null) { // Destroy(ti.texture); // ti.texture = null; // ti.loadStatus = TILE_LOAD_STATUS.Inactive; // if (gcCount++>100) { // gcCount = 0; // Resources.UnloadUnusedAssets(); // System.GC.Collect(); // Debug.Log ("Gc collect!"); // } // } } } // if (ti.visible) { // visibleTiles++; // } }
bool ReloadTextureFromCacheOrMarkForDownload(TileInfo ti) { if (!_tileEnableLocalCache) { return(false); } string url; GetTileServerInfo(_tileServer, ti, out url); if (url == null) { return(false); } if (tileServerAPIKey != null && tileServerAPIKey.Length > 0) { url += "?" + _tileServerAPIKey; } string filePath = GetLocalFilePathForUrl(url, ti); if (System.IO.File.Exists(filePath)) { //check how old System.DateTime written = File.GetLastWriteTimeUtc(filePath); System.DateTime now = System.DateTime.UtcNow; double totalHours = now.Subtract(written).TotalHours; if (totalHours > 300) { File.Delete(filePath); return(false); } } else { return(false); } byte[] bb = System.IO.File.ReadAllBytes(filePath); ti.texture = new Texture2D(_tileSize, _tileSize); ti.texture.LoadImage(bb); if (ti.texture.width <= 16) // Invalid texture in local cache, retry { if (File.Exists(filePath)) { File.Delete(filePath); } return(false); } ti.texture.wrapMode = TextureWrapMode.Clamp; _cacheLoads++; _cacheLoadTotalSize += bb.Length; // Good to go, update tile info switch (ti.subquadIndex) { case 0: ti.parent.transMat.SetTexture("_MainTex", ti.texture); ti.parent.normalMat.SetTexture("_MainTex", ti.texture); break; case 1: ti.parent.transMat.SetTexture("_MainTex1", ti.texture); ti.parent.normalMat.SetTexture("_MainTex1", ti.texture); break; case 2: ti.parent.transMat.SetTexture("_MainTex2", ti.texture); ti.parent.normalMat.SetTexture("_MainTex2", ti.texture); break; case 3: ti.parent.transMat.SetTexture("_MainTex3", ti.texture); ti.parent.normalMat.SetTexture("_MainTex3", ti.texture); break; } ti.loadStatus = TILE_LOAD_STATUS.Loaded; if (ti.zoomLevel >= TILE_MIN_ZOOM_LEVEL) { if (ti.y == 0 || ti.y == zoomLevelsInfo [ti.zoomLevel].yMax - 1) { CreatePole(ti); } } shouldCheckTiles = true; return(true); }