增加spine4.1
This commit is contained in:
372
SpineRuntimes/SpineRuntime41/Atlas.cs
Normal file
372
SpineRuntimes/SpineRuntime41/Atlas.cs
Normal file
@@ -0,0 +1,372 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated July 28, 2023. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2023, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
||||
* otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC 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 THE
|
||||
* SPINE RUNTIMES, 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.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
#if WINDOWS_STOREAPP
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
#endif
|
||||
|
||||
namespace SpineRuntime41 {
|
||||
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
|
||||
|
||||
public List<AtlasRegion> Regions { get { return regions; } }
|
||||
public List<AtlasPage> Pages { get { return pages; } }
|
||||
|
||||
#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 (StreamReader reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) {
|
||||
try {
|
||||
Atlas atlas = new Atlas(reader, Path.GetDirectoryName(path), textureLoader);
|
||||
this.pages = atlas.pages;
|
||||
this.regions = atlas.regions;
|
||||
this.textureLoader = atlas.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 {
|
||||
Atlas atlas = new Atlas(reader, Path.GetDirectoryName(path), textureLoader);
|
||||
this.pages = atlas.pages;
|
||||
this.regions = atlas.regions;
|
||||
this.textureLoader = atlas.textureLoader;
|
||||
} catch (Exception ex) {
|
||||
throw new Exception("Error reading atlas file: " + path, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // WINDOWS_STOREAPP
|
||||
#endif
|
||||
|
||||
public Atlas (List<AtlasPage> pages, List<AtlasRegion> regions) {
|
||||
if (pages == null) throw new ArgumentNullException("pages", "pages cannot be null.");
|
||||
if (regions == null) throw new ArgumentNullException("regions", "regions cannot be null.");
|
||||
this.pages = pages;
|
||||
this.regions = regions;
|
||||
this.textureLoader = null;
|
||||
}
|
||||
|
||||
public Atlas (TextReader reader, string imagesDir, TextureLoader textureLoader) {
|
||||
if (reader == null) throw new ArgumentNullException("reader", "reader cannot be null.");
|
||||
if (imagesDir == null) throw new ArgumentNullException("imagesDir", "imagesDir cannot be null.");
|
||||
if (textureLoader == null) throw new ArgumentNullException("textureLoader", "textureLoader cannot be null.");
|
||||
this.textureLoader = textureLoader;
|
||||
|
||||
string[] entry = new string[5];
|
||||
AtlasPage page = null;
|
||||
AtlasRegion region = null;
|
||||
|
||||
Dictionary<string, Action> pageFields = new Dictionary<string, Action>(5);
|
||||
pageFields.Add("size", () => {
|
||||
page.width = int.Parse(entry[1], CultureInfo.InvariantCulture);
|
||||
page.height = int.Parse(entry[2], CultureInfo.InvariantCulture);
|
||||
});
|
||||
pageFields.Add("format", () => {
|
||||
page.format = (Format)Enum.Parse(typeof(Format), entry[1], false);
|
||||
});
|
||||
pageFields.Add("filter", () => {
|
||||
page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), entry[1], false);
|
||||
page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), entry[2], false);
|
||||
});
|
||||
pageFields.Add("repeat", () => {
|
||||
if (entry[1].IndexOf('x') != -1) page.uWrap = TextureWrap.Repeat;
|
||||
if (entry[1].IndexOf('y') != -1) page.vWrap = TextureWrap.Repeat;
|
||||
});
|
||||
pageFields.Add("pma", () => {
|
||||
page.pma = entry[1] == "true";
|
||||
});
|
||||
|
||||
Dictionary<string, Action> regionFields = new Dictionary<string, Action>(8);
|
||||
regionFields.Add("xy", () => { // Deprecated, use bounds.
|
||||
region.x = int.Parse(entry[1], CultureInfo.InvariantCulture);
|
||||
region.y = int.Parse(entry[2], CultureInfo.InvariantCulture);
|
||||
});
|
||||
regionFields.Add("size", () => { // Deprecated, use bounds.
|
||||
region.width = int.Parse(entry[1], CultureInfo.InvariantCulture);
|
||||
region.height = int.Parse(entry[2], CultureInfo.InvariantCulture);
|
||||
});
|
||||
regionFields.Add("bounds", () => {
|
||||
region.x = int.Parse(entry[1], CultureInfo.InvariantCulture);
|
||||
region.y = int.Parse(entry[2], CultureInfo.InvariantCulture);
|
||||
region.width = int.Parse(entry[3], CultureInfo.InvariantCulture);
|
||||
region.height = int.Parse(entry[4], CultureInfo.InvariantCulture);
|
||||
});
|
||||
regionFields.Add("offset", () => { // Deprecated, use offsets.
|
||||
region.offsetX = int.Parse(entry[1], CultureInfo.InvariantCulture);
|
||||
region.offsetY = int.Parse(entry[2], CultureInfo.InvariantCulture);
|
||||
});
|
||||
regionFields.Add("orig", () => { // Deprecated, use offsets.
|
||||
region.originalWidth = int.Parse(entry[1], CultureInfo.InvariantCulture);
|
||||
region.originalHeight = int.Parse(entry[2], CultureInfo.InvariantCulture);
|
||||
});
|
||||
regionFields.Add("offsets", () => {
|
||||
region.offsetX = int.Parse(entry[1], CultureInfo.InvariantCulture);
|
||||
region.offsetY = int.Parse(entry[2], CultureInfo.InvariantCulture);
|
||||
region.originalWidth = int.Parse(entry[3], CultureInfo.InvariantCulture);
|
||||
region.originalHeight = int.Parse(entry[4], CultureInfo.InvariantCulture);
|
||||
});
|
||||
regionFields.Add("rotate", () => {
|
||||
string value = entry[1];
|
||||
if (value == "true")
|
||||
region.degrees = 90;
|
||||
else if (value != "false")
|
||||
region.degrees = int.Parse(value, CultureInfo.InvariantCulture);
|
||||
});
|
||||
regionFields.Add("index", () => {
|
||||
region.index = int.Parse(entry[1], CultureInfo.InvariantCulture);
|
||||
});
|
||||
|
||||
string line = reader.ReadLine();
|
||||
// Ignore empty lines before first entry.
|
||||
while (line != null && line.Trim().Length == 0)
|
||||
line = reader.ReadLine();
|
||||
// Header entries.
|
||||
while (true) {
|
||||
if (line == null || line.Trim().Length == 0) break;
|
||||
if (ReadEntry(entry, line) == 0) break; // Silently ignore all header fields.
|
||||
line = reader.ReadLine();
|
||||
}
|
||||
// Page and region entries.
|
||||
List<string> names = null;
|
||||
List<int[]> values = null;
|
||||
while (true) {
|
||||
if (line == null) break;
|
||||
if (line.Trim().Length == 0) {
|
||||
page = null;
|
||||
line = reader.ReadLine();
|
||||
} else if (page == null) {
|
||||
page = new AtlasPage();
|
||||
page.name = line.Trim();
|
||||
while (true) {
|
||||
if (ReadEntry(entry, line = reader.ReadLine()) == 0) break;
|
||||
Action field;
|
||||
if (pageFields.TryGetValue(entry[0], out field)) field(); // Silently ignore unknown page fields.
|
||||
}
|
||||
textureLoader.Load(page, Path.Combine(imagesDir, page.name));
|
||||
pages.Add(page);
|
||||
} else {
|
||||
region = new AtlasRegion();
|
||||
region.page = page;
|
||||
region.name = line;
|
||||
while (true) {
|
||||
int count = ReadEntry(entry, line = reader.ReadLine());
|
||||
if (count == 0) break;
|
||||
Action field;
|
||||
if (regionFields.TryGetValue(entry[0], out field))
|
||||
field();
|
||||
else {
|
||||
if (names == null) {
|
||||
names = new List<string>(8);
|
||||
values = new List<int[]>(8);
|
||||
}
|
||||
names.Add(entry[0]);
|
||||
int[] entryValues = new int[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
int.TryParse(entry[i + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out entryValues[i]); // Silently ignore non-integer values.
|
||||
values.Add(entryValues);
|
||||
}
|
||||
}
|
||||
if (region.originalWidth == 0 && region.originalHeight == 0) {
|
||||
region.originalWidth = region.width;
|
||||
region.originalHeight = region.height;
|
||||
}
|
||||
if (names != null && names.Count > 0) {
|
||||
region.names = names.ToArray();
|
||||
region.values = values.ToArray();
|
||||
names.Clear();
|
||||
values.Clear();
|
||||
}
|
||||
region.u = region.x / (float)page.width;
|
||||
region.v = region.y / (float)page.height;
|
||||
if (region.degrees == 90) {
|
||||
region.u2 = (region.x + region.height) / (float)page.width;
|
||||
region.v2 = (region.y + region.width) / (float)page.height;
|
||||
|
||||
int tempSwap = region.packedWidth;
|
||||
region.packedWidth = region.packedHeight;
|
||||
region.packedHeight = tempSwap;
|
||||
} else {
|
||||
region.u2 = (region.x + region.width) / (float)page.width;
|
||||
region.v2 = (region.y + region.height) / (float)page.height;
|
||||
}
|
||||
regions.Add(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static private int ReadEntry (string[] entry, string line) {
|
||||
if (line == null) return 0;
|
||||
line = line.Trim();
|
||||
if (line.Length == 0) return 0;
|
||||
int colon = line.IndexOf(':');
|
||||
if (colon == -1) return 0;
|
||||
entry[0] = line.Substring(0, colon).Trim();
|
||||
for (int i = 1, lastMatch = colon + 1; ; i++) {
|
||||
int comma = line.IndexOf(',', lastMatch);
|
||||
if (comma == -1) {
|
||||
entry[i] = line.Substring(lastMatch).Trim();
|
||||
return i;
|
||||
}
|
||||
entry[i] = line.Substring(lastMatch, comma - lastMatch).Trim();
|
||||
lastMatch = comma + 1;
|
||||
if (i == 4) return 4;
|
||||
}
|
||||
}
|
||||
|
||||
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 int width, height;
|
||||
public Format format = Format.RGBA8888;
|
||||
public TextureFilter minFilter = TextureFilter.Nearest;
|
||||
public TextureFilter magFilter = TextureFilter.Nearest;
|
||||
public TextureWrap uWrap = TextureWrap.ClampToEdge;
|
||||
public TextureWrap vWrap = TextureWrap.ClampToEdge;
|
||||
public bool pma;
|
||||
public object rendererObject;
|
||||
|
||||
public AtlasPage Clone () {
|
||||
return MemberwiseClone() as AtlasPage;
|
||||
}
|
||||
}
|
||||
|
||||
public class AtlasRegion : TextureRegion {
|
||||
public AtlasPage page;
|
||||
public string name;
|
||||
public int x, y;
|
||||
public float offsetX, offsetY;
|
||||
public int originalWidth, originalHeight;
|
||||
public int packedWidth { get { return width; } set { width = value; } }
|
||||
public int packedHeight { get { return height; } set { height = value; } }
|
||||
public int degrees;
|
||||
public bool rotate;
|
||||
public int index;
|
||||
public string[] names;
|
||||
public int[][] values;
|
||||
|
||||
override public int OriginalWidth { get { return originalWidth; } }
|
||||
override public int OriginalHeight { get { return originalHeight; } }
|
||||
|
||||
public AtlasRegion Clone () {
|
||||
return MemberwiseClone() as AtlasRegion;
|
||||
}
|
||||
}
|
||||
|
||||
public interface TextureLoader {
|
||||
void Load (AtlasPage page, string path);
|
||||
void Unload (Object texture);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user