Atlas.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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. #include <spine/Atlas.h>
  31. #include <ctype.h>
  32. #include <spine/extension.h>
  33. spAtlasPage* spAtlasPage_create (spAtlas* atlas, const char* name) {
  34. spAtlasPage* self = NEW(spAtlasPage);
  35. CONST_CAST(spAtlas*, self->atlas) = atlas;
  36. MALLOC_STR(self->name, name);
  37. return self;
  38. }
  39. void spAtlasPage_dispose (spAtlasPage* self) {
  40. _spAtlasPage_disposeTexture(self);
  41. FREE(self->name);
  42. FREE(self);
  43. }
  44. /**/
  45. spAtlasRegion* spAtlasRegion_create () {
  46. return NEW(spAtlasRegion);
  47. }
  48. void spAtlasRegion_dispose (spAtlasRegion* self) {
  49. FREE(self->name);
  50. FREE(self->splits);
  51. FREE(self->pads);
  52. FREE(self);
  53. }
  54. /**/
  55. typedef struct {
  56. const char* begin;
  57. const char* end;
  58. } Str;
  59. static void trim (Str* str) {
  60. while (isspace((unsigned char)*str->begin) && str->begin < str->end)
  61. (str->begin)++;
  62. if (str->begin == str->end) return;
  63. str->end--;
  64. while (isspace((unsigned char)*str->end) && str->end >= str->begin)
  65. str->end--;
  66. str->end++;
  67. }
  68. /* Tokenize string without modification. Returns 0 on failure. */
  69. static int readLine (const char** begin, const char* end, Str* str) {
  70. if (*begin == end) return 0;
  71. str->begin = *begin;
  72. /* Find next delimiter. */
  73. while (*begin != end && **begin != '\n')
  74. (*begin)++;
  75. str->end = *begin;
  76. trim(str);
  77. if (*begin != end) (*begin)++;
  78. return 1;
  79. }
  80. /* Moves str->begin past the first occurence of c. Returns 0 on failure. */
  81. static int beginPast (Str* str, char c) {
  82. const char* begin = str->begin;
  83. while (1) {
  84. char lastSkippedChar = *begin;
  85. if (begin == str->end) return 0;
  86. begin++;
  87. if (lastSkippedChar == c) break;
  88. }
  89. str->begin = begin;
  90. return 1;
  91. }
  92. /* Returns 0 on failure. */
  93. static int readValue (const char** begin, const char* end, Str* str) {
  94. readLine(begin, end, str);
  95. if (!beginPast(str, ':')) return 0;
  96. trim(str);
  97. return 1;
  98. }
  99. /* Returns the number of tuple values read (1, 2, 4, or 0 for failure). */
  100. static int readTuple (const char** begin, const char* end, Str tuple[]) {
  101. int i;
  102. Str str = {NULL, NULL};
  103. readLine(begin, end, &str);
  104. if (!beginPast(&str, ':')) return 0;
  105. for (i = 0; i < 3; ++i) {
  106. tuple[i].begin = str.begin;
  107. if (!beginPast(&str, ',')) break;
  108. tuple[i].end = str.begin - 2;
  109. trim(&tuple[i]);
  110. }
  111. tuple[i].begin = str.begin;
  112. tuple[i].end = str.end;
  113. trim(&tuple[i]);
  114. return i + 1;
  115. }
  116. static char* mallocString (Str* str) {
  117. int length = (int)(str->end - str->begin);
  118. char* string = MALLOC(char, length + 1);
  119. memcpy(string, str->begin, length);
  120. string[length] = '\0';
  121. return string;
  122. }
  123. static int indexOf (const char** array, int count, Str* str) {
  124. int length = (int)(str->end - str->begin);
  125. int i;
  126. for (i = count - 1; i >= 0; i--)
  127. if (strncmp(array[i], str->begin, length) == 0) return i;
  128. return 0;
  129. }
  130. static int equals (Str* str, const char* other) {
  131. return strncmp(other, str->begin, str->end - str->begin) == 0;
  132. }
  133. static int toInt (Str* str) {
  134. return (int)strtol(str->begin, (char**)&str->end, 10);
  135. }
  136. static spAtlas* abortAtlas (spAtlas* self) {
  137. spAtlas_dispose(self);
  138. return 0;
  139. }
  140. static const char* formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888", "RGBA8888"};
  141. static const char* textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest", "MipMapLinearNearest",
  142. "MipMapNearestLinear", "MipMapLinearLinear"};
  143. spAtlas* spAtlas_create (const char* begin, int length, const char* dir, void* rendererObject) {
  144. spAtlas* self;
  145. int count;
  146. const char* end = begin + length;
  147. int dirLength = (int)strlen(dir);
  148. int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
  149. spAtlasPage *page = 0;
  150. spAtlasPage *lastPage = 0;
  151. spAtlasRegion *lastRegion = 0;
  152. Str str;
  153. Str tuple[4];
  154. self = NEW(spAtlas);
  155. self->rendererObject = rendererObject;
  156. while (readLine(&begin, end, &str)) {
  157. if (str.end - str.begin == 0) {
  158. page = 0;
  159. } else if (!page) {
  160. char* name = mallocString(&str);
  161. char* path = MALLOC(char, dirLength + needsSlash + strlen(name) + 1);
  162. memcpy(path, dir, dirLength);
  163. if (needsSlash) path[dirLength] = '/';
  164. strcpy(path + dirLength + needsSlash, name);
  165. page = spAtlasPage_create(self, name);
  166. FREE(name);
  167. if (lastPage)
  168. lastPage->next = page;
  169. else
  170. self->pages = page;
  171. lastPage = page;
  172. switch (readTuple(&begin, end, tuple)) {
  173. case 0:
  174. return abortAtlas(self);
  175. case 2: /* size is only optional for an atlas packed with an old TexturePacker. */
  176. page->width = toInt(tuple);
  177. page->height = toInt(tuple + 1);
  178. if (!readTuple(&begin, end, tuple)) return abortAtlas(self);
  179. }
  180. page->format = (spAtlasFormat)indexOf(formatNames, 8, tuple);
  181. if (!readTuple(&begin, end, tuple)) return abortAtlas(self);
  182. page->minFilter = (spAtlasFilter)indexOf(textureFilterNames, 8, tuple);
  183. page->magFilter = (spAtlasFilter)indexOf(textureFilterNames, 8, tuple + 1);
  184. if (!readValue(&begin, end, &str)) return abortAtlas(self);
  185. page->uWrap = SP_ATLAS_CLAMPTOEDGE;
  186. page->vWrap = SP_ATLAS_CLAMPTOEDGE;
  187. if (!equals(&str, "none")) {
  188. if (str.end - str.begin == 1) {
  189. if (*str.begin == 'x')
  190. page->uWrap = SP_ATLAS_REPEAT;
  191. else if (*str.begin == 'y')
  192. page->vWrap = SP_ATLAS_REPEAT;
  193. } else if (equals(&str, "xy")) {
  194. page->uWrap = SP_ATLAS_REPEAT;
  195. page->vWrap = SP_ATLAS_REPEAT;
  196. }
  197. }
  198. _spAtlasPage_createTexture(page, path);
  199. FREE(path);
  200. } else {
  201. spAtlasRegion *region = spAtlasRegion_create();
  202. if (lastRegion)
  203. lastRegion->next = region;
  204. else
  205. self->regions = region;
  206. lastRegion = region;
  207. region->page = page;
  208. region->name = mallocString(&str);
  209. if (!readValue(&begin, end, &str)) return abortAtlas(self);
  210. region->rotate = equals(&str, "true");
  211. if (readTuple(&begin, end, tuple) != 2) return abortAtlas(self);
  212. region->x = toInt(tuple);
  213. region->y = toInt(tuple + 1);
  214. if (readTuple(&begin, end, tuple) != 2) return abortAtlas(self);
  215. region->width = toInt(tuple);
  216. region->height = toInt(tuple + 1);
  217. region->u = region->x / (float)page->width;
  218. region->v = region->y / (float)page->height;
  219. if (region->rotate) {
  220. region->u2 = (region->x + region->height) / (float)page->width;
  221. region->v2 = (region->y + region->width) / (float)page->height;
  222. } else {
  223. region->u2 = (region->x + region->width) / (float)page->width;
  224. region->v2 = (region->y + region->height) / (float)page->height;
  225. }
  226. if (!(count = readTuple(&begin, end, tuple))) return abortAtlas(self);
  227. if (count == 4) { /* split is optional */
  228. region->splits = MALLOC(int, 4);
  229. region->splits[0] = toInt(tuple);
  230. region->splits[1] = toInt(tuple + 1);
  231. region->splits[2] = toInt(tuple + 2);
  232. region->splits[3] = toInt(tuple + 3);
  233. if (!(count = readTuple(&begin, end, tuple))) return abortAtlas(self);
  234. if (count == 4) { /* pad is optional, but only present with splits */
  235. region->pads = MALLOC(int, 4);
  236. region->pads[0] = toInt(tuple);
  237. region->pads[1] = toInt(tuple + 1);
  238. region->pads[2] = toInt(tuple + 2);
  239. region->pads[3] = toInt(tuple + 3);
  240. if (!readTuple(&begin, end, tuple)) return abortAtlas(self);
  241. }
  242. }
  243. region->originalWidth = toInt(tuple);
  244. region->originalHeight = toInt(tuple + 1);
  245. readTuple(&begin, end, tuple);
  246. region->offsetX = toInt(tuple);
  247. region->offsetY = toInt(tuple + 1);
  248. if (!readValue(&begin, end, &str)) return abortAtlas(self);
  249. region->index = toInt(&str);
  250. }
  251. }
  252. return self;
  253. }
  254. spAtlas* spAtlas_createFromFile (const char* path, void* rendererObject) {
  255. int dirLength;
  256. char *dir;
  257. int length;
  258. const char* data;
  259. spAtlas* atlas = 0;
  260. /* Get directory from atlas path. */
  261. const char* lastForwardSlash = strrchr(path, '/');
  262. const char* lastBackwardSlash = strrchr(path, '\\');
  263. const char* lastSlash = lastForwardSlash > lastBackwardSlash ? lastForwardSlash : lastBackwardSlash;
  264. if (lastSlash == path) lastSlash++; /* Never drop starting slash. */
  265. dirLength = (int)(lastSlash ? lastSlash - path : 0);
  266. dir = MALLOC(char, dirLength + 1);
  267. memcpy(dir, path, dirLength);
  268. dir[dirLength] = '\0';
  269. data = _spUtil_readFile(path, &length);
  270. if (data) atlas = spAtlas_create(data, length, dir, rendererObject);
  271. FREE(data);
  272. FREE(dir);
  273. return atlas;
  274. }
  275. void spAtlas_dispose (spAtlas* self) {
  276. spAtlasRegion* region, *nextRegion;
  277. spAtlasPage* page = self->pages;
  278. while (page) {
  279. spAtlasPage* nextPage = page->next;
  280. spAtlasPage_dispose(page);
  281. page = nextPage;
  282. }
  283. region = self->regions;
  284. while (region) {
  285. nextRegion = region->next;
  286. spAtlasRegion_dispose(region);
  287. region = nextRegion;
  288. }
  289. FREE(self);
  290. }
  291. spAtlasRegion* spAtlas_findRegion (const spAtlas* self, const char* name) {
  292. spAtlasRegion* region = self->regions;
  293. while (region) {
  294. if (strcmp(region->name, name) == 0) return region;
  295. region = region->next;
  296. }
  297. return 0;
  298. }