源战役客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 lines
9.5 KiB

  1. /******************************************************************************
  2. * Spine Runtimes Software License v2.5
  3. *
  4. * Copyright (c) 2013-2016, Esoteric Software
  5. * All rights reserved.
  6. *
  7. * You are granted a perpetual, non-exclusive, non-sublicensable, and
  8. * non-transferable license to use, install, execute, and perform the Spine
  9. * Runtimes software and derivative works solely for personal or internal
  10. * use. Without the written permission of Esoteric Software (see Section 2 of
  11. * the Spine Software License Agreement), you may not (a) modify, translate,
  12. * adapt, or develop new applications using the Spine Runtimes or otherwise
  13. * create derivative works or improvements of the Spine Runtimes or (b) remove,
  14. * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
  15. * or other intellectual property or proprietary rights notices on or in the
  16. * Software, including any copy thereof. Redistributions in binary or source
  17. * form must include this license and terms.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
  20. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  22. * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
  25. * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  26. * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. *****************************************************************************/
  30. #if (UNITY_5 || UNITY_5_3_OR_NEWER || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1)
  31. #define IS_UNITY
  32. #endif
  33. using System;
  34. using System.Collections.Generic;
  35. using System.IO;
  36. using System.Reflection;
  37. #if WINDOWS_STOREAPP
  38. using System.Threading.Tasks;
  39. using Windows.Storage;
  40. #endif
  41. namespace Spine {
  42. public class Atlas : IEnumerable<AtlasRegion> {
  43. readonly List<AtlasPage> pages = new List<AtlasPage>();
  44. List<AtlasRegion> regions = new List<AtlasRegion>();
  45. TextureLoader textureLoader;
  46. #region IEnumerable implementation
  47. public IEnumerator<AtlasRegion> GetEnumerator () {
  48. return regions.GetEnumerator();
  49. }
  50. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () {
  51. return regions.GetEnumerator();
  52. }
  53. #endregion
  54. #if !(IS_UNITY)
  55. #if WINDOWS_STOREAPP
  56. private async Task ReadFile(string path, TextureLoader textureLoader) {
  57. var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
  58. var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false);
  59. using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) {
  60. try {
  61. Load(reader, Path.GetDirectoryName(path), textureLoader);
  62. } catch (Exception ex) {
  63. throw new Exception("Error reading atlas file: " + path, ex);
  64. }
  65. }
  66. }
  67. public Atlas(string path, TextureLoader textureLoader) {
  68. this.ReadFile(path, textureLoader).Wait();
  69. }
  70. #else
  71. public Atlas (string path, TextureLoader textureLoader) {
  72. #if WINDOWS_PHONE
  73. Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path);
  74. using (StreamReader reader = new StreamReader(stream)) {
  75. #else
  76. using (StreamReader reader = new StreamReader(path)) {
  77. #endif // WINDOWS_PHONE
  78. try {
  79. Load(reader, Path.GetDirectoryName(path), textureLoader);
  80. } catch (Exception ex) {
  81. throw new Exception("Error reading atlas file: " + path, ex);
  82. }
  83. }
  84. }
  85. #endif // WINDOWS_STOREAPP
  86. #endif
  87. public Atlas (TextReader reader, string dir, TextureLoader textureLoader) {
  88. Load(reader, dir, textureLoader);
  89. }
  90. public Atlas (List<AtlasPage> pages, List<AtlasRegion> regions) {
  91. this.pages = pages;
  92. this.regions = regions;
  93. this.textureLoader = null;
  94. }
  95. private void Load (TextReader reader, string imagesDir, TextureLoader textureLoader) {
  96. if (textureLoader == null) throw new ArgumentNullException("textureLoader", "textureLoader cannot be null.");
  97. this.textureLoader = textureLoader;
  98. string[] tuple = new string[4];
  99. AtlasPage page = null;
  100. while (true) {
  101. string line = reader.ReadLine();
  102. if (line == null) break;
  103. if (line.Trim().Length == 0)
  104. page = null;
  105. else if (page == null) {
  106. page = new AtlasPage();
  107. page.name = line;
  108. if (ReadTuple(reader, tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker.
  109. page.width = int.Parse(tuple[0]);
  110. page.height = int.Parse(tuple[1]);
  111. ReadTuple(reader, tuple);
  112. }
  113. page.format = (Format)Enum.Parse(typeof(Format), tuple[0], false);
  114. ReadTuple(reader, tuple);
  115. page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0], false);
  116. page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1], false);
  117. string direction = ReadValue(reader);
  118. page.uWrap = TextureWrap.ClampToEdge;
  119. page.vWrap = TextureWrap.ClampToEdge;
  120. if (direction == "x")
  121. page.uWrap = TextureWrap.Repeat;
  122. else if (direction == "y")
  123. page.vWrap = TextureWrap.Repeat;
  124. else if (direction == "xy")
  125. page.uWrap = page.vWrap = TextureWrap.Repeat;
  126. textureLoader.Load(page, Path.Combine(imagesDir, line));
  127. pages.Add(page);
  128. } else {
  129. AtlasRegion region = new AtlasRegion();
  130. region.name = line;
  131. region.page = page;
  132. region.rotate = Boolean.Parse(ReadValue(reader));
  133. ReadTuple(reader, tuple);
  134. int x = int.Parse(tuple[0]);
  135. int y = int.Parse(tuple[1]);
  136. ReadTuple(reader, tuple);
  137. int width = int.Parse(tuple[0]);
  138. int height = int.Parse(tuple[1]);
  139. region.u = x / (float)page.width;
  140. region.v = y / (float)page.height;
  141. if (region.rotate) {
  142. region.u2 = (x + height) / (float)page.width;
  143. region.v2 = (y + width) / (float)page.height;
  144. } else {
  145. region.u2 = (x + width) / (float)page.width;
  146. region.v2 = (y + height) / (float)page.height;
  147. }
  148. region.x = x;
  149. region.y = y;
  150. region.width = Math.Abs(width);
  151. region.height = Math.Abs(height);
  152. if (ReadTuple(reader, tuple) == 4) { // split is optional
  153. region.splits = new [] {int.Parse(tuple[0]), int.Parse(tuple[1]),
  154. int.Parse(tuple[2]), int.Parse(tuple[3])};
  155. if (ReadTuple(reader, tuple) == 4) { // pad is optional, but only present with splits
  156. region.pads = new [] {int.Parse(tuple[0]), int.Parse(tuple[1]),
  157. int.Parse(tuple[2]), int.Parse(tuple[3])};
  158. ReadTuple(reader, tuple);
  159. }
  160. }
  161. region.originalWidth = int.Parse(tuple[0]);
  162. region.originalHeight = int.Parse(tuple[1]);
  163. ReadTuple(reader, tuple);
  164. region.offsetX = int.Parse(tuple[0]);
  165. region.offsetY = int.Parse(tuple[1]);
  166. region.index = int.Parse(ReadValue(reader));
  167. regions.Add(region);
  168. }
  169. }
  170. }
  171. static string ReadValue (TextReader reader) {
  172. string line = reader.ReadLine();
  173. int colon = line.IndexOf(':');
  174. if (colon == -1) throw new Exception("Invalid line: " + line);
  175. return line.Substring(colon + 1).Trim();
  176. }
  177. /// <summary>Returns the number of tuple values read (1, 2 or 4).</summary>
  178. static int ReadTuple (TextReader reader, string[] tuple) {
  179. string line = reader.ReadLine();
  180. int colon = line.IndexOf(':');
  181. if (colon == -1) throw new Exception("Invalid line: " + line);
  182. int i = 0, lastMatch = colon + 1;
  183. for (; i < 3; i++) {
  184. int comma = line.IndexOf(',', lastMatch);
  185. if (comma == -1) break;
  186. tuple[i] = line.Substring(lastMatch, comma - lastMatch).Trim();
  187. lastMatch = comma + 1;
  188. }
  189. tuple[i] = line.Substring(lastMatch).Trim();
  190. return i + 1;
  191. }
  192. public void FlipV () {
  193. for (int i = 0, n = regions.Count; i < n; i++) {
  194. AtlasRegion region = regions[i];
  195. region.v = 1 - region.v;
  196. region.v2 = 1 - region.v2;
  197. }
  198. }
  199. /// <summary>Returns the first region found with the specified name. This method uses string comparison to find the region, so the result
  200. /// should be cached rather than calling this method multiple times.</summary>
  201. /// <returns>The region, or null.</returns>
  202. public AtlasRegion FindRegion (string name) {
  203. for (int i = 0, n = regions.Count; i < n; i++)
  204. if (regions[i].name == name) return regions[i];
  205. return null;
  206. }
  207. public void Dispose () {
  208. if (textureLoader == null) return;
  209. for (int i = 0, n = pages.Count; i < n; i++)
  210. textureLoader.Unload(pages[i].rendererObject);
  211. }
  212. }
  213. public enum Format {
  214. Alpha,
  215. Intensity,
  216. LuminanceAlpha,
  217. RGB565,
  218. RGBA4444,
  219. RGB888,
  220. RGBA8888
  221. }
  222. public enum TextureFilter {
  223. Nearest,
  224. Linear,
  225. MipMap,
  226. MipMapNearestNearest,
  227. MipMapLinearNearest,
  228. MipMapNearestLinear,
  229. MipMapLinearLinear
  230. }
  231. public enum TextureWrap {
  232. MirroredRepeat,
  233. ClampToEdge,
  234. Repeat
  235. }
  236. public class AtlasPage {
  237. public string name;
  238. public Format format;
  239. public TextureFilter minFilter;
  240. public TextureFilter magFilter;
  241. public TextureWrap uWrap;
  242. public TextureWrap vWrap;
  243. public Object rendererObject;
  244. public int width, height;
  245. }
  246. public class AtlasRegion {
  247. public AtlasPage page;
  248. public string name;
  249. public int x, y, width, height;
  250. public float u, v, u2, v2;
  251. public float offsetX, offsetY;
  252. public int originalWidth, originalHeight;
  253. public int index;
  254. public bool rotate;
  255. public int[] splits;
  256. public int[] pads;
  257. }
  258. public interface TextureLoader {
  259. void Load (AtlasPage page, string path);
  260. void Unload (Object texture);
  261. }
  262. }