/// <summary> /// Downloads a Google uploaded panorama image using the URL as a Promise /// </summary> /// <param name="url">The URL of the pano</param> /// <param name="size">The <see cref="PanoSize"/> of the pano image to be downloaded</param> //public IPromise<Texture32> Download(string panoID, PanoSize size, TextureFormat format) { // var promise = new Promise<Texture32>(); // Download(panoID, size, format, // result => promise.Resolve(result), // exception => promise.Reject(exception) // ); // return promise; //} /// <summary> /// Downloads a Google uploaded panorama image using the URL /// </summary> /// <param name="url">The URL of the pano</param> /// <param name="size">The <see cref="PanoSize"/> of the pano image to be downloaded</param> /// <param name="onResult">Callback for result texture when the download is successful</param> /// <param name="onException">Callback for exception when the download fails</param> public void Download(string panoID, PanoSize size, TextureFormat format, Action <Texture32> onResult, Action <Exception> onException) { Stop(); Dispatcher.Enqueue(() => { Runnable.Run(DownloadCo(panoID, size, format, onResult, onException)); }); }
/// <summary> /// Downloads the panorama texture. /// </summary> /// <param name="panoID">The ID of the panorama to be downloaded</param> /// <param name="size">Size of the texture to be downloaded</param> /// <param name="onResult">Callback when the download is successful</param> /// <param name="onException">Callback when the download is unsuccessful</param> public void Download(string panoID, PanoSize size, TextureFormat format, Action <Texture32> onResult, Action <Exception> onException) { // We first try to download as a Google Pano m_GoogleDownloader.IsAvailable(panoID) .Then(isGooglePano => { if (isGooglePano) { GoogleDownload(panoID, size, format, onResult, onException); } else { m_UserDownloader.IsAvailable(panoID) .Then(isUserPano => { if (isUserPano) { UserDownload(panoID, size, format, onResult, onException); } else { onException.TryInvoke(new Exception("Pano cannot be downloaded!")); Stop(); } }); } }); }
void GoogleDownload(string panoID, PanoSize size, TextureFormat format, Action <Texture32> onResult, Action <Exception> onException) { if (m_UserDownloader != null) { m_UserDownloader.ClearTexture(); m_UserDownloader.Stop(); } m_GoogleDownloader.Download(panoID, size, format, onResult, onException); }
/// <summary> /// Downloads the panorama texture as a Promise /// </summary> /// <param name="panoID">The ID of the panorama to be downloaded</param> /// <param name="size">Size of the texture to be downloaded</param> public Task <Texture32> Download(string panoID, PanoSize size, TextureFormat format) { var source = new TaskCompletionSource <Texture32>(); Download(panoID, size, format, texture => source.SetResult(texture), exception => source.SetException(exception) ); return(source.Task); }
IPromise <Texture2D> DownloadTile(string panoID, int x, int y, PanoSize size, TextureFormat format) { var promise = new Promise <Texture2D>(); DownloadTile(panoID, x, y, size, format, result => promise.Resolve(result), exception => promise.Reject(exception) ); return(promise); }
/// <summary> /// Downloads the panorama texture as a Promise /// </summary> /// <param name="panoID">The ID of the panorama to be downloaded</param> /// <param name="size">Size of the texture to be downloaded</param> public IPromise <Texture32> Download(string panoID, PanoSize size, TextureFormat format) { var promise = new Promise <Texture32>(); Download(panoID, size, format, texture => promise.Resolve(texture), exception => promise.Reject(exception) ); return(promise); }
/// <summary> /// Downloads the panorama image using the known PanoID as a Promise /// </summary> /// <param name="id">The Pano ID to be downloaded</param> /// <param name="size">The <see cref="PanoSize"/> of the image to be downloaded</param> /// <returns></returns> public IPromise <Texture32> Download(string id, PanoSize size, TextureFormat format) { var promise = new Promise <Texture32>(); Download(id, size, format, result => promise.Resolve(result), exception => promise.Reject(exception) ); return(promise); }
Task <Texture2D> DownloadTile(string panoID, int x, int y, PanoSize size, TextureFormat format) { var source = new TaskCompletionSource <Texture2D>(); DownloadTile(panoID, x, y, size, format, result => source.SetResult(result), exception => source.SetException(exception) ); return(source.Task); }
/// <summary> /// Downloads the panorama image using the known PanoID as a Promise /// </summary> /// <param name="id">The Pano ID to be downloaded</param> /// <param name="size">The <see cref="PanoSize"/> of the image to be downloaded</param> /// <returns></returns> public Task <Texture32> Download(string id, PanoSize size, TextureFormat format) { var promise = new TaskCompletionSource <Texture32>(); Download(id, size, format, result => promise.SetResult(result), exception => promise.SetException(exception) ); return(promise.Task); }
void DownloadTile(string panoID, int x, int y, PanoSize size, TextureFormat format, Action <Texture2D> onResult = null, Action <Exception> onException = null) { m_Running = true; var url = "https://geo0.ggpht.com/cbk?cb_client=maps_sv.tactile&authuser=0&hl=en" + "&panoid=" + panoID + "&output=tile" + "&x=" + x + "&y=" + y + "&zoom=" + PanoUtility.GetZoomValue(size) + "&nbt&fover=2"; RestRequestAsyncHandle handle = null; m_Handles.Add(handle); var client = new RestClient(); var request = new RestRequest(url, Method.GET); client.ExecuteAsync(request, out handle) .Then(response => { if (!m_Running) { return; } Dispatcher.Enqueue(() => { if (response.IsSuccess()) { var tile = new Texture2D(2, 2, format, true); tile.LoadImage(response.RawBytes); onResult.TryInvoke(tile); } else { onException.TryInvoke(response.GetException()); } }); }) .Catch(exception => { if (!m_Running) { return; } onException.TryInvoke(exception); }); }
// Removes the blank parts of the texture // Similar to StitchTexture, we try to use Graphics.CopyTexture wherever possible // however on VeryLarge PanoSize on Android devices, we use an extenion method called // Texture2D.Crop, which is slower than Graphics.CopyTexture and is a last resort void CropTexture(PanoSize level) { var uRes = PanoUtility.GetUntrimmedResolution(level); var tRes = PanoUtility.DetectBlankBands(m_Texture); tRes = new Vector2( PanoUtility.DetectWidth(m_Texture), tRes.y ); // If the trimmed resolutionm is the same as untrimmed, we don't need to if (tRes.x == uRes.x && tRes.y == uRes.y) { return; } m_Texture.Crop(0, (int)uRes.y - (int)tRes.y, (int)tRes.x, (int)tRes.y); }
/// <summary> /// Downloads the panorama image using the known PanoID /// </summary> /// <param name="panoID">The PanoID to be downloaded</param> /// <param name="size">The <see cref="PanoSize"/> of the image to be downloaded.</param> /// <param name="onResult">Callback containing the Texture2D of the pano image</param> /// <param name="onException">Callback containing the exception when the download fails</param> public void Download(string panoID, PanoSize size, TextureFormat format, Action <Texture32> onResult = null, Action <Exception> onException = null) { var width = PanoUtility.GetUserPanoWidth(size); string url = "https://lh5.googleusercontent.com/p/" + panoID + "=w" + width; m_Running = true; OnStarted.TryInvoke(); new RestClient().ExecuteAsync(new RestRequest(url, Method.GET), out m_Handle) .Then(response => { if (!m_Running) { return; } Dispatcher.Enqueue(() => { if (response.IsSuccess()) { var texture = new Texture2D(1, 1, format, true); texture.LoadImage(response.RawBytes); var result = Texture32.FromTexture2D(texture); MonoBehaviour.Destroy(texture); texture = null; onResult.TryInvoke(result); OnLoaded.TryInvoke(result); } else { OnFailed.TryInvoke(response.GetException()); onException.TryInvoke(response.GetException()); } }); }) .Catch(exception => { if (!m_Running) { return; } onException.TryInvoke(exception); }); }
public static int GetUserPanoWidth(PanoSize size) { switch (size) { case PanoSize.VerySmall: return(512); case PanoSize.Small: return(1024); case PanoSize.Medium: return(2048); case PanoSize.Large: return(4096); case PanoSize.VeryLarge: return(8192); default: return(1); } }
public static Vector2 GetTileCount(PanoSize level) { switch (level) { case PanoSize.VerySmall: return(new Vector2(1, 1)); case PanoSize.Small: return(new Vector2(2, 1)); case PanoSize.Medium: return(new Vector2(4, 2)); case PanoSize.Large: return(new Vector2(8, 4)); case PanoSize.VeryLarge: return(new Vector2(16, 8)); default: return(Vector2.zero); } }
public static Vector2 GetUntrimmedResolution(PanoSize level) { switch (level) { case PanoSize.VerySmall: return(new Vector2(512, 512)); case PanoSize.Small: return(new Vector2(1024, 512)); case PanoSize.Medium: return(new Vector2(2048, 1024)); case PanoSize.Large: return(new Vector2(4096, 2048)); case PanoSize.VeryLarge: return(new Vector2(8192, 4096)); default: return(Vector2.zero); } }
public static int GetZoomValue(PanoSize level) { switch (level) { case PanoSize.VerySmall: return(0); case PanoSize.Small: return(1); case PanoSize.Medium: return(2); case PanoSize.Large: return(3); case PanoSize.VeryLarge: return(4); default: return(-1); } }
// Copies the tile to the right place in the complete (large) texture // On Android devices, Graphics.CopyTexture results in the editor freezing // when the PanoSize is set to VeryLast. For this reason we use an extension method // called Texture2D.Copy. However Graphics.Copytexture is faster so we use that // wherever possible void StitchTexture(Texture2D tile, PanoSize size, int x, int y) { m_Texture.ReplaceBlock(x * tile.width, y * tile.height, Texture32.FromTexture2D(tile)); MonoBehaviour.Destroy(tile); tile = null; }
/// <summary> /// Starts the downloads of a panorama and doesn't return any objects to listen to it /// </summary> /// <param name="panoID"></param> /// <param name="size"></param> /// <param name="format"></param> public void DownloadAndForget(string panoID, PanoSize size, TextureFormat format) { Download(panoID, size, format, null, null); }
IEnumerator DownloadCo(string panoID, PanoSize size, TextureFormat format, Action <Texture32> onResult, Action <Exception> onException) { OnStarted?.Invoke(); var uRes = PanoUtility.GetUntrimmedResolution(size); m_Texture = new Texture32((int)uRes.x, (int)uRes.y); var count = PanoUtility.GetTileCount(size); int xCount = (int)count.x; int yCount = (int)count.y; int req = xCount * yCount; int success = 0; int failed = 0; bool done = false; for (int i = 0; i < xCount; i++) { for (int j = 0; j < yCount; j++) { var x = i; var y = j; DownloadTile(panoID, x, y, size, format, tile => { success++; StitchTexture(tile, size, x, ((int)count.y - 1) - y); if (success == req) { done = true; CropTexture(size); onResult?.Invoke(m_Texture); OnLoaded?.Invoke(m_Texture); } }, exception => { if (x == 0 && yCount > y) { yCount = y; req = xCount * yCount; } if (y == 0 && xCount > x) { xCount = x; req = xCount * yCount; } failed++; if (failed == req) { var thrown = new Exception("Could not download the pano image. ID or URL is incorrect."); OnFailed?.Invoke(thrown); onException?.Invoke(thrown); return; } if (success == req && !done) { done = true; CropTexture(size); onResult?.Invoke(m_Texture); OnLoaded?.Invoke(m_Texture); } } ); yield return(null); } } }