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); } // 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); parentObj.layer = tilesRoot.gameObject.layer; zi.tilesContainer = parentObj; } } else { parentObj = ti.parent.gameObject; } // Prepare mesh vertices Vector3[] tileCorners = new Vector3[4]; tileCorners [0] = Conversion.GetLocalPositionFromLatLon(latLonTL); tileCorners [1] = Conversion.GetLocalPositionFromLatLon(new Vector2(latLonTL.x, latLonBR.y)); tileCorners [2] = Conversion.GetLocalPositionFromLatLon(latLonBR); tileCorners [3] = Conversion.GetLocalPositionFromLatLon(new Vector2(latLonBR.x, latLonTL.y)); // Add small offset to avoid seams on higher zoom levels if (ti.zoomLevel > 150) { const float offset = 0.00000001f; tileCorners [1].x += offset; tileCorners [2].x += offset; tileCorners [2].y -= offset; tileCorners [3].y -= offset; } // 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 }
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 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; ti.cornerLocalPos [k] = Conversion.GetLocalPositionFromLatLon(latlon); } cachedTiles [tileCode] = ti; } // Check if tile is within restricted area if (_tileRestrictToArea) { if (ti.latlons[0].x <_tileMinMaxLatLon.x || ti.latlons[2].x> _tileMinMaxLatLon.z || ti.latlons[0].y > _tileMinMaxLatLon.w || ti.latlons[2].y < _tileMinMaxLatLon.y) { return; } } // Check if any tile corner is visible // Phase I Vector3 minWorldPos = Misc.Vector3max; Vector3 maxWorldPos = Misc.Vector3min; Vector3 tmp = Misc.Vector3zero; for (int c = 0; c < 4; c++) { Vector3 wpos = transform.TransformPoint(ti.cornerLocalPos [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; } } FastVector.Average(ref minWorldPos, ref maxWorldPos, ref tmp); Bounds bounds = new Bounds(tmp, maxWorldPos - minWorldPos); Vector3 tileMidPoint = bounds.center; #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; 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); if (!insideViewport && _wrapHorizontally && _wrapCamera.enabled) { insideViewport = GeometryUtility.TestPlanesAABB(wrapCameraPlanes, 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 float aparentSize = maxY - minY; bool tileIsBig = aparentSize > currentTileSize; #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 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(); } } }