diff --git a/Assets/FetchMapTile.cs b/Assets/FetchMapTile.cs index bc75162..ba6a308 100644 --- a/Assets/FetchMapTile.cs +++ b/Assets/FetchMapTile.cs @@ -5,36 +5,57 @@ using Raindrop.Map.Model; using Raindrop.ServiceLocator; using UnityEngine; +// a simple view to get a maptile from the map service. public class FetchMapTile : MonoBehaviour { public int Grid_X = 1000; public int Grid_Y = 1000; - private bool modified = true; + private bool _needsTextureRefresh = true; public TexturePlane image; - + public MapTile MapTile; + // Update is called once per frame void Start() { - SyncMapTile_blocking(image, Grid_X, Grid_Y); - modified = false; + MapTile = RetrieveMapTile_blocking(image, Grid_X, Grid_Y); + _needsTextureRefresh = true; + } + + // todo: refactor into a routine + void update() + { + if (_needsTextureRefresh == false) + { + return; + } + + lock (MapTile) + { + if (MapTile.isReady) + { + image.ApplyTexture(MapTile.getTex()); + } + } } //blocks until tex is successfully printed. - private void SyncMapTile_blocking(TexturePlane texturePlane, int gridX, int gridY) + private MapTile RetrieveMapTile_blocking(TexturePlane texturePlane, int gridX, int gridY) { - MapFetcher mf = new MapFetcher(); + MapService mapService = new MapService(); - MapTile mt = mf.GetRegionTileExternal(Utils.UIntsToLong(1000,1000), 1); - while (mt.isReady == false) - { - continue; - } - - lock (mt.getTex()) - { - texturePlane.ApplyTexture(mt.getTex()); - } + bool isReady; + MapTile mt = mapService.GetMapTile(Utils.UIntsToLong(1000,1000), 1, out isReady); + return mt; + // while (mt.isReady == false) + // { + // continue; + // } + // + // lock (mt.getTex()) + // { + // texturePlane.ApplyTexture(mt.getTex()); + // } } } diff --git a/Assets/Raindrop/Render/TerrainSplat.cs b/Assets/Raindrop/Render/TerrainSplat.cs index 3bc5a6d..062ec15 100644 --- a/Assets/Raindrop/Render/TerrainSplat.cs +++ b/Assets/Raindrop/Render/TerrainSplat.cs @@ -385,8 +385,9 @@ namespace Raindrop.Rendering { if (state == TextureRequestState.Finished && assetTexture?.AssetData != null) { - Texture2D img; - img = T2D.LoadT2DWithoutMipMaps(assetTexture.AssetData); + Texture2D img + = new Texture2D(1, 1, TextureFormat.ARGB32, false); + T2D.LoadT2DWithoutMipMaps(assetTexture.AssetData, img); detailTexture[i] = (Texture2D)img; } textureDone.Set(); diff --git a/Assets/Raindrop/Services/Bootstrap/UIBootstrapper.cs b/Assets/Raindrop/Services/Bootstrap/UIBootstrapper.cs index 7bc9605..7cdb2aa 100644 --- a/Assets/Raindrop/Services/Bootstrap/UIBootstrapper.cs +++ b/Assets/Raindrop/Services/Bootstrap/UIBootstrapper.cs @@ -30,10 +30,10 @@ namespace Raindrop.Services.Bootstrap private void Start() { //1. mapfetcher - logic, not ui. please refactor - if (!ServiceLocator.ServiceLocator.Instance.IsRegistered()) + if (!ServiceLocator.ServiceLocator.Instance.IsRegistered()) { Debug.Log("UIBootstrapper creating and registering MapBackend.MapFetcher!"); - ServiceLocator.ServiceLocator.Instance.Register(new MapFetcher()); + ServiceLocator.ServiceLocator.Instance.Register(new MapService()); //return; } diff --git a/Assets/Raindrop/UI/map/MapModel.cs b/Assets/Raindrop/UI/map/MapModel.cs index 29c3d66..d507ac7 100644 --- a/Assets/Raindrop/UI/map/MapModel.cs +++ b/Assets/Raindrop/UI/map/MapModel.cs @@ -22,7 +22,7 @@ namespace Raindrop.UI.Model class MapModel { // i fetch images. - private MapFetcher mapFetcher; + private MapService _mapService; // i cache images to disk. private MapCache mapCache; diff --git a/Assets/Raindrop/UI/map/model/MapService.cs b/Assets/Raindrop/UI/map/model/MapService.cs new file mode 100644 index 0000000..724f416 --- /dev/null +++ b/Assets/Raindrop/UI/map/model/MapService.cs @@ -0,0 +1,86 @@ +using OpenMetaverse; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using Raindrop.ServiceLocator; +using UnityEngine; + +namespace Raindrop.Map.Model +{ + /// + /// Provides the map textures on demand. + /// + /// previously...: + /// Contains logic to fetch and decode the map textures. + /// + public class MapService : IGameService + { + public static uint regionSize = 256; + + // fixme: unused + public class MapData + { + ulong gridLoc; + byte[] dataJPG; + + public MapData(ulong gridLoc, byte[] dataJPG) + { + this.gridLoc = gridLoc; + this.dataJPG = dataJPG; + } + } + + + //a queue of map data that want to be decoded. + // fixme: unused + ConcurrentQueue receivedDataQueue = new ConcurrentQueue(); + + // fixme: unused + UnityMainThreadDispatcher mainThreadInstance; + private object mapDataQueue_lock = new object(); + + private MapTilesRAM _mapTilesRam; + private MapTilesNetwork mapTilesNetwork; + + public MapService() + { + mainThreadInstance = UnityMainThreadDispatcher.Instance(); + + //the cache. + _mapTilesRam = new MapTilesRAM(10, receivedDataQueue); + // the disk. + // mapTilesDisk = new MapTilesDisk(); + // the network. + mapTilesNetwork = new MapTilesNetwork(2); + } + + /// + /// API to Get the map tile at specific region handle and zoom level. + /// - you will need to poll the ready flag in the Maptile until it is ready. + /// Caveats: + /// - Only zoom level 1 is supported. + /// - if not present, a webrequest for the tile will be made. + /// + /// + /// + /// if the returned MapTile is ready for display. + /// + public MapTile GetMapTile(ulong handle, int zoom, out bool isReady) + { + MapTile res = null; + bool isTileAvailable = _mapTilesRam.tryGetTile_RAM(handle, out res); + if (isTileAvailable) + { + isReady = true; + return res; + } + //this call to network, returns a maptile that is empty inside for now. + res = mapTilesNetwork.GetRegionTileExternal(handle, 1); + isReady = false; + return res; + } + + + } +} diff --git a/Assets/Raindrop/UI/map/model/MapFetcher.cs.meta b/Assets/Raindrop/UI/map/model/MapService.cs.meta similarity index 100% rename from Assets/Raindrop/UI/map/model/MapFetcher.cs.meta rename to Assets/Raindrop/UI/map/model/MapService.cs.meta diff --git a/Assets/Raindrop/UI/map/model/MapFetcher.cs b/Assets/Raindrop/UI/map/model/MapTilesNetwork.cs similarity index 51% rename from Assets/Raindrop/UI/map/model/MapFetcher.cs rename to Assets/Raindrop/UI/map/model/MapTilesNetwork.cs index 80318a4..2b9a49e 100644 --- a/Assets/Raindrop/UI/map/model/MapFetcher.cs +++ b/Assets/Raindrop/UI/map/model/MapTilesNetwork.cs @@ -1,81 +1,38 @@ -using OpenMetaverse; -using Raindrop.Network; -using Raindrop.UI; -using System; +using System; using System.Collections; using System.Collections.Generic; -using System.IO; -using Raindrop.ServiceLocator; -using UniRx; +using OpenMetaverse; using UnityEngine; namespace Raindrop.Map.Model { - /// - /// Contains logic to fetch and decode the map textures. - /// - public class MapFetcher : IGameService + // for you to get map tiles from the network. + public class MapTilesNetwork { - public class MapData - { - ulong gridLoc; - byte[] dataJPG; - - public MapData(ulong gridLoc, byte[] dataJPG) - { - gridLoc = this.gridLoc; - dataJPG = this.dataJPG; - } - } - - //MapTilesManager mapTilesManager; List tileRequests = new List(); // a list of pending fetch requests. the ulongs are the x and y world coordinates (gridX * 256), packed. - uint regionSize = 256; - private ParallelDownloader downloader; - int poolSize = 10; - - Queue gottenData; - + private DownloadManager downloader; UnityMainThreadDispatcher mainThreadInstance; - private object mapDataQueue; - public MapFetcher() + public MapTilesNetwork(int parallelDownloads) { - //mapTilesManager = new MapTilesManager(10); - - downloader = new ParallelDownloader(); - + downloader = new DownloadManager(); + downloader.ParallelDownloads = parallelDownloads; mainThreadInstance = UnityMainThreadDispatcher.Instance(); } - /// - /// API to Get the map tile at specific region handle and zoom level. Only zoom level 1 is supported. - /// gets the map tile at handle if present. - /// if not present, a webrequest for the tile will be made. a notification of download success will not be reported to the caller of this function. - /// - /// - /// - /// - public MapTile tryGetMapTile(ulong handle, int zoom) - { - MapTile res = null; - //res = mapTilesManager.tryGetTile(handle); - return res; - } - - //get region tile using SL map API -- JPEG images. // obtains the image from URL, decodes it in main thread, the stores data in the appropriate maptile. public MapTile GetRegionTileExternal(ulong handle, int zoom) { zoom = 1; - if (tryGetMapTile(handle, 1) != null) - { - return tryGetMapTile(handle, 1); - } - else - { + // if (tryGetMapTile(handle, 1) != null) + // { + // //since tile is ready in the memory, return it. + // return tryGetMapTile(handle, 1); + // } + // else + // { lock (tileRequests) { if (tileRequests.Contains(handle)) return null; @@ -84,11 +41,11 @@ namespace Raindrop.Map.Model uint regX, regY; OpenMetaverse.Utils.LongToUInts(handle, out regX, out regY); - regX /= regionSize; - regY /= regionSize; + regX /= MapService.regionSize; + regY /= MapService.regionSize; //int zoom = 1; MapTile res = new MapTile(256,256); - downloader.QueueDownlad( + downloader.QueueDownload(new DownloadRequest( new Uri(string.Format("http://map.secondlife.com/map-{0}-{1}-{2}-objects.jpg", zoom, regX, regY)), 20 * 1000, null, @@ -100,31 +57,29 @@ namespace Raindrop.Map.Model try { //1. download is ready now. - //2. decode the image. - //3. add it to the hashtable in the model (memory) + //3. add it to the hashtable in the model (memory) + //2. decode the image on the main thread. //4. exit. Debug.Log("fetching the texture was successful!"); - //lock (mapData.sceneTiles) - //{ - //decode http response data into texture2d - //MapTile tex = mapData.getTile(); - lock (mapDataQueue) - { - gottenData.Enqueue(new MapData(handle, responseData)); - } + // removed. reason: initially we wanted to push into a queue. + // now realise want to simplify. just decode on main thread, + // let the view keep polling the maptile object for ready flag. + // lock (mapDataQueue_lock) + // { + // receivedDataQueue.Enqueue(new MapService.MapData(handle, responseData)); + // } - - //run jpeg decoding on the main thread, for now. + //start to run jpeg decoding on the main thread. mainThreadInstance.Enqueue(DecodeDataToTexAsync(res, responseData)); - + + // remove from request list lock (tileRequests) { if (tileRequests.Contains(handle)) tileRequests.Remove(handle); } - //res = tile; } catch (Exception e) { @@ -132,28 +87,32 @@ namespace Raindrop.Map.Model } } } - + ) ); - return res; // inside res, it is notready. + return res; // the tile is created. but inside the tile, it is not ready and the texture is the empty texture static //lock (mapData.sceneTiles) //{ // mapData.sceneTiles[handle] = mapData.acquireTile(); //wtf! //} - } + // } } - - private IEnumerator DecodeDataToTexAsync(MapTile output_tile, byte[] responseData) + + // decode jpg bytes to texture2d. + //must be run on the main thread as we are manipulating T2D + // 1. decode JPEGbytes to texture2d + // 2. replace the corresponding tiles's T2D + private IEnumerator DecodeDataToTexAsync(MapTile tile, byte[] responseData) { try { - lock (output_tile.getTex()) + lock (tile) //lock the tile that you want to write into. { - Texture2D _tex = output_tile.getTex(); - bool success = _tex.LoadImage(responseData); //warn: main thread only. - output_tile.isReady = true; + Texture2D _tex = tile.getTex(); + bool success = _tex.LoadImage(responseData); //warn: main thread only. fixme. + tile.isReady = true; } } @@ -165,5 +124,7 @@ namespace Raindrop.Map.Model yield return null; } + } -} + +} \ No newline at end of file diff --git a/Assets/Raindrop/UI/map/model/MapTilesNetwork.cs.meta b/Assets/Raindrop/UI/map/model/MapTilesNetwork.cs.meta new file mode 100644 index 0000000..7c25acb --- /dev/null +++ b/Assets/Raindrop/UI/map/model/MapTilesNetwork.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 551a208562ef49b1bf29bfac4b99f040 +timeCreated: 1642786871 \ No newline at end of file diff --git a/Assets/Raindrop/UI/map/model/MapTilesPool.cs b/Assets/Raindrop/UI/map/model/MapTilesPool.cs index 3d0f416..458b1e9 100644 --- a/Assets/Raindrop/UI/map/model/MapTilesPool.cs +++ b/Assets/Raindrop/UI/map/model/MapTilesPool.cs @@ -8,7 +8,7 @@ namespace Raindrop.Map.Model { private Queue tilePool; - public int count => tilePool.Count; + public int Count => tilePool.Count; public MapTilesPool(int poolSize) @@ -23,7 +23,7 @@ namespace Raindrop.Map.Model // gets a unused maptile from pool. public MapTile acquireTile() { - if (count <= 0) + if (Count <= 0) { throw new Exception("ran out of memory in mapdatapool! Please implement data recycling logic."); } diff --git a/Assets/Raindrop/UI/map/model/MapTilesManager.cs b/Assets/Raindrop/UI/map/model/MapTilesRAM.cs similarity index 84% rename from Assets/Raindrop/UI/map/model/MapTilesManager.cs rename to Assets/Raindrop/UI/map/model/MapTilesRAM.cs index 59ce167..297be57 100644 --- a/Assets/Raindrop/UI/map/model/MapTilesManager.cs +++ b/Assets/Raindrop/UI/map/model/MapTilesRAM.cs @@ -1,5 +1,6 @@ using OpenMetaverse; using System; +using System.Collections.Concurrent; using System.Collections.Generic; namespace Raindrop.Map.Model @@ -7,16 +8,19 @@ namespace Raindrop.Map.Model /// /// API to retrieve, delete, modify, create MapTiles in the scene /// - public class MapTilesManager + public class MapTilesRAM { //number of tiles that are in the scene. public int visibleCount => sceneTiles.Count; - + int poolSize => pool.Count; + //tiles that are in the scene. private Dictionary sceneTiles = new Dictionary(); private MapTilesPool pool; - public MapTilesManager(int poolSize) + + private ConcurrentQueue readyForDecode_DataQueue; + public MapTilesRAM(int poolSize, ConcurrentQueue receivedDataQueue) { pool = new MapTilesPool(poolSize); } @@ -36,11 +40,11 @@ namespace Raindrop.Map.Model /// /// the region handle of the tile to get ; gridCoords * 256 and pack X&Y together. /// Tile - public MapTile tryGetTile(ulong handle) + public bool tryGetTile_RAM(ulong handle, out MapTile tile) { - MapTile tile = null; + // MapTile tile = null; bool success = sceneTiles.TryGetValue(handle, out tile); - return tile; + return success; } /// diff --git a/Assets/Raindrop/UI/map/model/MapTilesManager.cs.meta b/Assets/Raindrop/UI/map/model/MapTilesRAM.cs.meta similarity index 100% rename from Assets/Raindrop/UI/map/model/MapTilesManager.cs.meta rename to Assets/Raindrop/UI/map/model/MapTilesRAM.cs.meta diff --git a/Assets/Raindrop/UI/map/model/SpawnableObject.cs b/Assets/Raindrop/UI/map/model/SpawnableObject.cs deleted file mode 100644 index 003a537..0000000 --- a/Assets/Raindrop/UI/map/model/SpawnableObject.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Raindrop -{ - public interface SpawnableObject - { - void Spawn(); - void DeSpawn(); - } -} \ No newline at end of file diff --git a/Assets/Raindrop/UI/map/model/SpawnableObject.cs.meta b/Assets/Raindrop/UI/map/model/SpawnableObject.cs.meta deleted file mode 100644 index 73e5a7e..0000000 --- a/Assets/Raindrop/UI/map/model/SpawnableObject.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: af6f4e5269f7aba4fa7a0d038cca70e4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Raindrop/UI/testing/MapViewer_SingleStatic_NoZoom.cs b/Assets/Raindrop/UI/testing/MapViewer_SingleStatic_NoZoom.cs index 61420c0..17e153b 100644 --- a/Assets/Raindrop/UI/testing/MapViewer_SingleStatic_NoZoom.cs +++ b/Assets/Raindrop/UI/testing/MapViewer_SingleStatic_NoZoom.cs @@ -20,7 +20,7 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour { [SerializeField] - public MapFetcher mapFetcher; + public MapService MapService; [SerializeField] public GameObject mapTileGO; @@ -43,7 +43,7 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour System.Threading.Timer repaint; private void Awake() { - mapFetcher = new MapFetcher(); + MapService = new MapService(); } @@ -78,7 +78,7 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour throw new System.Exception("mapMoverGO is fucked"); // fix exception type plz } - mapFetcher = new MapFetcher(); + MapService = new MapService(); // for testing @@ -93,11 +93,13 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour ulong handle = mapMover.GetLookAt(); int zoom = (int)zoomSlider.value; // how 2 convert look at floats into uints? (uints are gridpos * 256) - if (mapFetcher.tryGetMapTile(handle, 1) == null) //hack for now. - { - mapFetcher.GetRegionTileExternal(handle, 1); - } - + MapTile mt = MapService.GetMapTile(handle, 1, out bool isReady); + // + // if (MapService.GetMapTile(handle, 1) == null) //hack for now. + // { + // MapService.GetMapTile(handle, 1, out bool isReady); + // } + // needRepaint = true; Debug.Log("refreshed internal images. fetching images if any.."); @@ -119,12 +121,13 @@ public class MapViewer_SingleStatic_NoZoom : MonoBehaviour return; } ulong handle = mapMover.GetLookAt(); - MapTile tex = mapFetcher.tryGetMapTile(handle, 1); - - if (tex != null) - { - iv.setRawImage(tex.getTex()); - } - Debug.Log("drew images."); + // MapTile tex = MapService.GetMapTile(handle, 1); + throw new NotImplementedException("we recently refactored the mapservice interface."); + + // if (tex != null) + // { + // iv.setRawImage(tex.getTex()); + // } + // Debug.Log("drew images."); } } diff --git a/Assets/Raindrop/UI/testing/TestTextureFetcher.cs b/Assets/Raindrop/UI/testing/TestTextureFetcher.cs index 349a054..5dca58a 100644 --- a/Assets/Raindrop/UI/testing/TestTextureFetcher.cs +++ b/Assets/Raindrop/UI/testing/TestTextureFetcher.cs @@ -17,13 +17,13 @@ namespace Raindrop class TestTextureFetcher : MonoBehaviour { [SerializeField] - public MapFetcher mapFetcher; //fetching logic + pooling data here + public MapService MapService; //fetching logic + pooling data here private void Awake() { MainThreadDispatcher.Initialize(); - mapFetcher = new MapFetcher(); + MapService = new MapService(); } @@ -36,7 +36,8 @@ namespace Raindrop var handle = Utils.UIntsToLong(256 * 1000, 256 * 1000); - mapFetcher.GetRegionTileExternal(handle, 1); + throw new NotImplementedException("we recently refactored the mapservice interface."); + // MapService.GetRegionTileExternal(handle, 1); Debug.Log("end of initial fetch call."); }