/// <summary> /// Setup a custom font from the sprite sheet. /// </summary> /// <remarks>The glyphs in your sprite sheet should be organized into a grid, with each cell size being the same. If <paramref name="monospaced"/> is false then RetroBlit will automatically trim any /// horizontal empty space on either side of the glyph. If <paramref name="monospaced"/> is true then the empty space is retained.</remarks> /// <param name="characterList">List of all characters in this font. Must be in same order as glyphSprites</param> /// <param name="glyphSprites">List of packed sprites to use for the glyphs. Must be in same order as characterList</param> /// <param name="spriteSheet">The sprite sheet containing the font</param> /// <param name="characterSpacing">Spacing between characters</param> /// <param name="lineSpacing">Line spacing between lines of text</param> /// <param name="monospaced">True if font is monospaced</param> /// <returns>Setup status</returns> public RB.AssetStatus Setup(List <char> characterList, List <string> glyphSprites, SpriteSheetAsset spriteSheet, int characterSpacing, int lineSpacing, bool monospaced) { InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.BadParam); progress = 0; if (spriteSheet == null) { Debug.LogError("Invalid sprite sheet"); return(status); } if (spriteSheet.status != RB.AssetStatus.Ready) { Debug.LogError("Sprite sheet is not ready or not loaded"); return(status); } if (glyphSprites == null) { Debug.LogError("Glyph sprites list is null!"); return(status); } if (characterList.Count != glyphSprites.Count) { Debug.LogError("Expected " + characterList.Count + " glyph sprites to cover the given unicode range, was given " + glyphSprites.Count + " glyph sprites"); return(status); } var glyphSprites2 = new List <PackedSprite>(glyphSprites.Count); for (int i = 0; i < glyphSprites.Count; i++) { glyphSprites2.Add(RB.PackedSpriteGet(glyphSprites[i], spriteSheet)); } RetroBlitInternal.RBAPI.instance.Font.FontSetup(this, 0, 0, characterList, glyphSprites2, spriteSheet, characterSpacing, lineSpacing, monospaced, true); InternalSetErrorStatus(RB.AssetStatus.Ready, RB.Result.Success); progress = 1; return(status); }
/// <summary> /// Load a sprite sheet or sprite pack from the given file, or create a blank one of given size, or load from an existing texture /// </summary> /// <param name="asset">Asset object to load into</param> /// <param name="size">Size of new empty spritesheet if no filename is specified</param> /// <param name="fileName">Filename</param> /// <param name="texture">Existing texture to use</param> /// <param name="source">Source type</param> /// <param name="sheetType">Sheet type</param> /// <returns>True if successful</returns> public bool SpriteSheetLoad(SpriteSheetAsset asset, Vector2i size, string fileName, RenderTexture texture, RB.AssetSource source, SpriteSheetAsset.SheetType sheetType) { if (asset == null) { return(false); } asset.progress = 0; // Release any existing asset SpriteSheetUnload(asset); asset.InternalSetErrorStatus(RB.AssetStatus.Invalid, RB.Result.Undefined); if (fileName != null) { fileName.Replace('\\', '/'); if (fileName.EndsWith(".sp.rb")) { Debug.LogError("Do not specify the .sp.rb file extension when loading a sprite pack"); asset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.BadParam); return(false); } else if ((sheetType == SpriteSheetAsset.SheetType.SpriteSheet && source != RB.AssetSource.WWW) && (fileName.EndsWith(".png") || fileName.EndsWith(".jpg") || fileName.EndsWith(".jpeg") || fileName.EndsWith(".gif") || fileName.EndsWith(".tif") || fileName.EndsWith(".tga") || fileName.EndsWith(".psd"))) { // Does not apply to WWW, must specify extension there to form valid http request Debug.LogError("Do not specify the image file extension when loading a sprite. For example, use \"hero\", instead of \"hero.png\""); asset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.BadParam); return(false); } } // Async loading implies we are not creating an empty texture, nor initializing from an existing texture if (source != RB.AssetSource.Resources && fileName == null) { asset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.BadParam); } else { if (sheetType == SpriteSheetAsset.SheetType.SpritePack) { // Abort any existing async load for this asset AbortAsyncSpritePackLoad(asset); var asyncSpritePackResource = new RBSpritePackLoader(); asyncSpritePackResource.Load(fileName, asset, source); if (asset.status == RB.AssetStatus.Ready) { return(true); } // Always add to async queue, even if immediately failed. This gives out consistent async method of error checking mASyncSpritePacks.Add(asyncSpritePackResource); return(true); } else if (sheetType == SpriteSheetAsset.SheetType.SpriteSheet) { // Abort any existing async load for this asset AbortAsyncSpriteSheetLoad(asset); var asyncResource = new RBSpriteSheetLoader(); asyncResource.Load(fileName, texture, size, asset, source); if (asset.status == RB.AssetStatus.Ready) { return(true); } // Always add to async queue, even if immediately failed. This gives out consistent async method of error checking mASyncSpriteSheets.Add(asyncResource); return(true); } else { asset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.BadParam); return(false); } } return(false); }
/// <summary> /// Setup a custom font from the sprite sheet. /// </summary> /// <remarks>The glyphs in your sprite sheet should be organized into a grid, with each cell size being the same. If <paramref name="monospaced"/> is false then RetroBlit will automatically trim any /// horizontal empty space on either side of the glyph. If <paramref name="monospaced"/> is true then the empty space is retained.</remarks> /// <param name="unicodeStart">First unicode character in the font</param> /// <param name="unicodeEnd">Last unicode character in the font</param> /// <param name="glyphSprites">List of packed sprites to use for the glyphs</param> /// <param name="spriteSheet">The sprite sheet containing the font</param> /// <param name="characterSpacing">Spacing between characters</param> /// <param name="lineSpacing">Line spacing between lines of text</param> /// <param name="monospaced">True if font is monospaced</param> /// <returns>Setup status</returns> public RB.AssetStatus Setup(char unicodeStart, char unicodeEnd, List <PackedSprite> glyphSprites, SpriteSheetAsset spriteSheet, int characterSpacing, int lineSpacing, bool monospaced) { InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.BadParam); progress = 0; if (unicodeStart < 0 || unicodeEnd < unicodeStart) { Debug.LogError("Invalid unicode range"); return(status); } if (spriteSheet == null) { Debug.LogError("Invalid sprite sheet"); return(status); } if (spriteSheet.status != RB.AssetStatus.Ready) { Debug.LogError("Sprite sheet is not ready or not loaded"); return(status); } if (glyphSprites == null) { Debug.LogError("Glyph sprites list is null!"); return(status); } if ((unicodeEnd - unicodeStart + 1) != glyphSprites.Count) { Debug.LogError("Expected " + (unicodeEnd - unicodeStart + 1) + " glyph sprites to cover the given unicode range, was given " + glyphSprites.Count + " glyph sprites"); return(status); } RetroBlitInternal.RBAPI.instance.Font.FontSetup(this, unicodeStart, unicodeEnd, null, glyphSprites, spriteSheet, characterSpacing, lineSpacing, monospaced, true); InternalSetErrorStatus(RB.AssetStatus.Ready, RB.Result.Success); progress = 1; return(status); }
/// <summary> /// Load sprite sheet asset /// </summary> /// <param name="path">Path to asset</param> /// <param name="existingTexture">Existing texture to load from</param> /// <param name="size">Size of the texture</param> /// <param name="asset">SpriteSheetAsset to load into</param> /// <param name="source">Asset source type</param> /// <returns>True if successful</returns> public bool Load(string path, RenderTexture existingTexture, Vector2i size, SpriteSheetAsset asset, RB.AssetSource source) { this.spriteSheetAsset = asset; this.path = path; if (asset == null) { Debug.LogError("SpriteSheetAsset is null!"); return(false); } if (source == RB.AssetSource.Resources) { // Empty texture if (path == null && existingTexture == null) { if (size.x <= 0 || size.y <= 0) { spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.BadParam); return(false); } RenderTexture tex = new RenderTexture(size.x, size.y, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default); if (tex == null) { spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.NoResources); return(false); } tex.filterMode = FilterMode.Point; tex.wrapMode = TextureWrapMode.Clamp; tex.anisoLevel = 0; tex.antiAliasing = 1; tex.autoGenerateMips = false; tex.depth = 0; tex.useMipMap = false; tex.Create(); asset.internalState.texture = tex; asset.internalState.textureWidth = (ushort)tex.width; asset.internalState.textureHeight = (ushort)tex.height; #if MESH_UPLOAD_2019_3 asset.internalState.texelWidth = 0xFFFF / (float)tex.width; asset.internalState.texelHeight = 0xFFFF / (float)tex.height; #endif asset.internalState.spriteGrid.cellSize.width = (ushort)tex.width; asset.internalState.spriteGrid.cellSize.height = (ushort)tex.height; asset.internalState.columns = (ushort)(asset.internalState.textureWidth / asset.internalState.spriteGrid.cellSize.width); asset.internalState.rows = (ushort)(asset.internalState.textureHeight / asset.internalState.spriteGrid.cellSize.height); asset.internalState.needsClear = true; if (asset.internalState.columns < 1) { asset.internalState.columns = 1; } if (asset.internalState.rows < 1) { asset.internalState.rows = 1; } // If there is no spritesheet set then set this one as the current one if (RetroBlitInternal.RBAPI.instance.Renderer.CurrentSpriteSheet == null) { RetroBlitInternal.RBAPI.instance.Renderer.SpriteSheetSet(asset); } asset.progress = 1; spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Ready, RB.Result.Success); return(true); } else if (existingTexture != null) { asset.internalState.texture = existingTexture; asset.internalState.textureWidth = (ushort)existingTexture.width; asset.internalState.textureHeight = (ushort)existingTexture.height; #if MESH_UPLOAD_2019_3 asset.internalState.texelWidth = 0xFFFF / (float)existingTexture.width; asset.internalState.texelHeight = 0xFFFF / (float)existingTexture.height; #endif asset.internalState.spriteGrid.cellSize.width = (ushort)existingTexture.width; asset.internalState.spriteGrid.cellSize.height = (ushort)existingTexture.height; asset.internalState.columns = (ushort)(asset.internalState.textureWidth / asset.internalState.spriteGrid.cellSize.width); asset.internalState.rows = (ushort)(asset.internalState.textureHeight / asset.internalState.spriteGrid.cellSize.height); if (asset.internalState.columns < 1) { asset.internalState.columns = 1; } if (asset.internalState.rows < 1) { asset.internalState.rows = 1; } // If there is no spritesheet set then set this one as the current one if (RetroBlitInternal.RBAPI.instance.Renderer.CurrentSpriteSheet == null) { RetroBlitInternal.RBAPI.instance.Renderer.SpriteSheetSet(asset); } asset.progress = 1; spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Ready, RB.Result.Success); return(true); } else { // Synchronous load var spritesTextureOriginal = Resources.Load <Texture2D>(path); if (spritesTextureOriginal == null) { Debug.LogError("Could not load sprite sheet from " + path + ", make sure the resource is placed somehwere in Assets/Resources folder. " + "If you're trying to load a Sprite Pack then please specify \"SpriteSheetAsset.SheetType.SpritePack\" as \"sheetType\". " + "If you're trying to load from an WWW address, or Addressable Assets then please specify so with the \"source\" parameter."); asset.internalState.texture = null; spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.NotFound); return(false); } FinalizeTexture(spritesTextureOriginal); return(asset.status == RB.AssetStatus.Ready ? true : false); } } else if (source == RB.AssetSource.WWW) { if (!ImageTypeSupported(path)) { Debug.LogError("WWW source supports only PNG and JPG images"); spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.NotSupported); return(false); } mWebRequest = UnityWebRequestTexture.GetTexture(path, true); if (mWebRequest == null) { spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.NoResources); return(false); } if (mWebRequest.SendWebRequest() == null) { spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.NoResources); return(false); } spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Loading, RB.Result.Pending); return(true); } else if (source == RB.AssetSource.ResourcesAsync) { mResourceRequest = Resources.LoadAsync <Texture2D>(this.path); if (mResourceRequest == null) { spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Failed, RB.Result.NoResources); return(false); } } #if ADDRESSABLES_PACKAGE_AVAILABLE else if (source == RB.AssetSource.AddressableAssets) { // Exceptions on LoadAssetAsync can't actually be caught... this might work in the future so leaving it here try { mAddressableRequest = Addressables.LoadAssetAsync <Texture2D>(path); } catch (UnityEngine.AddressableAssets.InvalidKeyException e) { RBUtil.Unused(e); spriteSheetAsset.SetErrorStatus(RB.AssetStatus.Failed, RB.Result.NotFound); return(false); } catch (Exception e) { RBUtil.Unused(e); spriteSheetAsset.SetErrorStatus(RB.AssetStatus.Failed, RB.Result.Undefined); return(false); } // Check for an immediate failure if (mAddressableRequest.Status == AsyncOperationStatus.Failed) { Addressables.Release(mAddressableRequest); spriteSheetAsset.SetErrorStatus(RB.AssetStatus.Failed, RB.Result.Undefined); return(false); } spriteSheetAsset.progress = 0; spriteSheetAsset.SetErrorStatus(RB.AssetStatus.Loading, RB.Result.Pending); return(true); } #endif spriteSheetAsset.InternalSetErrorStatus(RB.AssetStatus.Loading, RB.Result.Pending); return(true); }