Last active
November 9, 2018 21:47
-
-
Save pharan/7414f73131939c2987e200ea8f63a36c to your computer and use it in GitHub Desktop.
NumberStyle-specified version of the Atlas.cs Spine atlas loader.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
* Spine Runtimes Software License v2.5 | |
* | |
* Copyright (c) 2013-2016, Esoteric Software | |
* All rights reserved. | |
* | |
* You are granted a perpetual, non-exclusive, non-sublicensable, and | |
* non-transferable license to use, install, execute, and perform the Spine | |
* Runtimes software and derivative works solely for personal or internal | |
* use. Without the written permission of Esoteric Software (see Section 2 of | |
* the Spine Software License Agreement), you may not (a) modify, translate, | |
* adapt, or develop new applications using the Spine Runtimes or otherwise | |
* create derivative works or improvements of the Spine Runtimes or (b) remove, | |
* delete, alter, or obscure any trademarks or any copyright, trademark, patent, | |
* or other intellectual property or proprietary rights notices on or in the | |
* Software, including any copy thereof. Redistributions in binary or source | |
* form must include this license and terms. | |
* | |
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF | |
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | |
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
*****************************************************************************/ | |
#if (UNITY_5 || UNITY_5_3_OR_NEWER || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) | |
#define IS_UNITY | |
#endif | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Reflection; | |
#if WINDOWS_STOREAPP | |
using System.Threading.Tasks; | |
using Windows.Storage; | |
#endif | |
namespace Spine { | |
public class Atlas : IEnumerable<AtlasRegion> { | |
readonly List<AtlasPage> pages = new List<AtlasPage>(); | |
List<AtlasRegion> regions = new List<AtlasRegion>(); | |
TextureLoader textureLoader; | |
#region IEnumerable implementation | |
public IEnumerator<AtlasRegion> GetEnumerator () { | |
return regions.GetEnumerator(); | |
} | |
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () { | |
return regions.GetEnumerator(); | |
} | |
#endregion | |
#if !(IS_UNITY) | |
#if WINDOWS_STOREAPP | |
private async Task ReadFile(string path, TextureLoader textureLoader) { | |
var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; | |
var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); | |
using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) { | |
try { | |
Load(reader, Path.GetDirectoryName(path), textureLoader); | |
} catch (Exception ex) { | |
throw new Exception("Error reading atlas file: " + path, ex); | |
} | |
} | |
} | |
public Atlas(string path, TextureLoader textureLoader) { | |
this.ReadFile(path, textureLoader).Wait(); | |
} | |
#else | |
public Atlas (string path, TextureLoader textureLoader) { | |
#if WINDOWS_PHONE | |
Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); | |
using (StreamReader reader = new StreamReader(stream)) { | |
#else | |
using (StreamReader reader = new StreamReader(path)) { | |
#endif // WINDOWS_PHONE | |
try { | |
Load(reader, Path.GetDirectoryName(path), textureLoader); | |
} catch (Exception ex) { | |
throw new Exception("Error reading atlas file: " + path, ex); | |
} | |
} | |
} | |
#endif // WINDOWS_STOREAPP | |
#endif | |
public Atlas (TextReader reader, string dir, TextureLoader textureLoader) { | |
Load(reader, dir, textureLoader); | |
} | |
public Atlas (List<AtlasPage> pages, List<AtlasRegion> regions) { | |
this.pages = pages; | |
this.regions = regions; | |
this.textureLoader = null; | |
} | |
private void Load (TextReader reader, string imagesDir, TextureLoader textureLoader) { | |
if (textureLoader == null) throw new ArgumentNullException("textureLoader", "textureLoader cannot be null."); | |
this.textureLoader = textureLoader; | |
const System.Globalization.NumberStyles IntStyle = System.Globalization.NumberStyles.Integer; | |
var InvariantCulture = System.Globalization.CultureInfo.InvariantCulture; | |
string[] tuple = new string[4]; | |
AtlasPage page = null; | |
while (true) { | |
string line = reader.ReadLine(); | |
if (line == null) break; | |
if (line.Trim().Length == 0) | |
page = null; | |
else if (page == null) { | |
page = new AtlasPage { | |
name = line | |
}; | |
if (ReadTuple(reader, tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. | |
page.width = int.Parse(tuple[0], IntStyle, InvariantCulture); | |
page.height = int.Parse(tuple[1], IntStyle, InvariantCulture); | |
ReadTuple(reader, tuple); | |
} | |
page.format = (Format)Enum.Parse(typeof(Format), tuple[0], false); | |
ReadTuple(reader, tuple); | |
page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0], false); | |
page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1], false); | |
string direction = ReadValue(reader); | |
page.uWrap = TextureWrap.ClampToEdge; | |
page.vWrap = TextureWrap.ClampToEdge; | |
if (direction == "x") | |
page.uWrap = TextureWrap.Repeat; | |
else if (direction == "y") | |
page.vWrap = TextureWrap.Repeat; | |
else if (direction == "xy") | |
page.uWrap = page.vWrap = TextureWrap.Repeat; | |
textureLoader.Load(page, Path.Combine(imagesDir, line)); | |
pages.Add(page); | |
} else { | |
AtlasRegion region = new AtlasRegion(); | |
region.name = line; | |
region.page = page; | |
region.rotate = Boolean.Parse(ReadValue(reader)); | |
ReadTuple(reader, tuple); | |
int x = int.Parse(tuple[0], IntStyle, InvariantCulture); | |
int y = int.Parse(tuple[1], IntStyle, InvariantCulture); | |
ReadTuple(reader, tuple); | |
int width = int.Parse(tuple[0], IntStyle, InvariantCulture); | |
int height = int.Parse(tuple[1], IntStyle, InvariantCulture); | |
region.u = x / (float)page.width; | |
region.v = y / (float)page.height; | |
if (region.rotate) { | |
region.u2 = (x + height) / (float)page.width; | |
region.v2 = (y + width) / (float)page.height; | |
} else { | |
region.u2 = (x + width) / (float)page.width; | |
region.v2 = (y + height) / (float)page.height; | |
} | |
region.x = x; | |
region.y = y; | |
region.width = Math.Abs(width); | |
region.height = Math.Abs(height); | |
if (ReadTuple(reader, tuple) == 4) { // split is optional | |
region.splits = new [] {int.Parse(tuple[0], IntStyle, InvariantCulture), int.Parse(tuple[1], IntStyle, InvariantCulture), | |
int.Parse(tuple[2], IntStyle, InvariantCulture), int.Parse(tuple[3], IntStyle, InvariantCulture)}; | |
if (ReadTuple(reader, tuple) == 4) { // pad is optional, but only present with splits | |
region.pads = new [] {int.Parse(tuple[0], IntStyle, InvariantCulture), int.Parse(tuple[1], IntStyle, InvariantCulture), | |
int.Parse(tuple[2], IntStyle, InvariantCulture), int.Parse(tuple[3], IntStyle, InvariantCulture)}; | |
ReadTuple(reader, tuple); | |
} | |
} | |
region.originalWidth = int.Parse(tuple[0], IntStyle, InvariantCulture); | |
region.originalHeight = int.Parse(tuple[1], IntStyle, InvariantCulture); | |
ReadTuple(reader, tuple); | |
region.offsetX = int.Parse(tuple[0], IntStyle, InvariantCulture); | |
region.offsetY = int.Parse(tuple[1], IntStyle, InvariantCulture); | |
region.index = int.Parse(ReadValue(reader), IntStyle, InvariantCulture); | |
regions.Add(region); | |
} | |
} | |
} | |
static string ReadValue (TextReader reader) { | |
string line = reader.ReadLine(); | |
int colon = line.IndexOf(':'); | |
if (colon == -1) throw new Exception("Invalid line: " + line); | |
return line.Substring(colon + 1).Trim(); | |
} | |
/// <summary>Returns the number of tuple values read (1, 2 or 4).</summary> | |
static int ReadTuple (TextReader reader, string[] tuple) { | |
string line = reader.ReadLine(); | |
int colon = line.IndexOf(':'); | |
if (colon == -1) throw new Exception("Invalid line: " + line); | |
int i = 0, lastMatch = colon + 1; | |
for (; i < 3; i++) { | |
int comma = line.IndexOf(',', lastMatch); | |
if (comma == -1) break; | |
tuple[i] = line.Substring(lastMatch, comma - lastMatch).Trim(); | |
lastMatch = comma + 1; | |
} | |
tuple[i] = line.Substring(lastMatch).Trim(); | |
return i + 1; | |
} | |
public void FlipV () { | |
for (int i = 0, n = regions.Count; i < n; i++) { | |
AtlasRegion region = regions[i]; | |
region.v = 1 - region.v; | |
region.v2 = 1 - region.v2; | |
} | |
} | |
/// <summary>Returns the first region found with the specified name. This method uses string comparison to find the region, so the result | |
/// should be cached rather than calling this method multiple times.</summary> | |
/// <returns>The region, or null.</returns> | |
public AtlasRegion FindRegion (string name) { | |
for (int i = 0, n = regions.Count; i < n; i++) | |
if (regions[i].name == name) return regions[i]; | |
return null; | |
} | |
public void Dispose () { | |
if (textureLoader == null) return; | |
for (int i = 0, n = pages.Count; i < n; i++) | |
textureLoader.Unload(pages[i].rendererObject); | |
} | |
} | |
public enum Format { | |
Alpha, | |
Intensity, | |
LuminanceAlpha, | |
RGB565, | |
RGBA4444, | |
RGB888, | |
RGBA8888 | |
} | |
public enum TextureFilter { | |
Nearest, | |
Linear, | |
MipMap, | |
MipMapNearestNearest, | |
MipMapLinearNearest, | |
MipMapNearestLinear, | |
MipMapLinearLinear | |
} | |
public enum TextureWrap { | |
MirroredRepeat, | |
ClampToEdge, | |
Repeat | |
} | |
public class AtlasPage { | |
public string name; | |
public Format format; | |
public TextureFilter minFilter; | |
public TextureFilter magFilter; | |
public TextureWrap uWrap; | |
public TextureWrap vWrap; | |
public Object rendererObject; | |
public int width, height; | |
} | |
public class AtlasRegion { | |
public AtlasPage page; | |
public string name; | |
public int x, y, width, height; | |
public float u, v, u2, v2; | |
public float offsetX, offsetY; | |
public int originalWidth, originalHeight; | |
public int index; | |
public bool rotate; | |
public int[] splits; | |
public int[] pads; | |
} | |
public interface TextureLoader { | |
void Load (AtlasPage page, string path); | |
void Unload (Object texture); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment