|
@@ -31,6 +31,63 @@
|
|
#include <ctype.h>
|
|
#include <ctype.h>
|
|
#include <spine/extension.h>
|
|
#include <spine/extension.h>
|
|
|
|
|
|
|
|
+spKeyValueArray *spKeyValueArray_create(int initialCapacity) {
|
|
|
|
+ spKeyValueArray *array = ((spKeyValueArray *) _spCalloc(1, sizeof(spKeyValueArray), "_file_name_", 39));
|
|
|
|
+ array->size = 0;
|
|
|
|
+ array->capacity = initialCapacity;
|
|
|
|
+ array->items = ((spKeyValue *) _spCalloc(initialCapacity, sizeof(spKeyValue), "_file_name_", 39));
|
|
|
|
+ return array;
|
|
|
|
+}
|
|
|
|
+void spKeyValueArray_dispose(spKeyValueArray *self) {
|
|
|
|
+ _spFree((void *) self->items);
|
|
|
|
+ _spFree((void *) self);
|
|
|
|
+}
|
|
|
|
+void spKeyValueArray_clear(spKeyValueArray *self) { self->size = 0; }
|
|
|
|
+spKeyValueArray *spKeyValueArray_setSize(spKeyValueArray *self, int newSize) {
|
|
|
|
+ self->size = newSize;
|
|
|
|
+ if (self->capacity < newSize) {
|
|
|
|
+ self->capacity = ((8) > ((int) (self->size * 1.75f)) ? (8) : ((int) (self->size * 1.75f)));
|
|
|
|
+ self->items = ((spKeyValue *) _spRealloc(self->items, sizeof(spKeyValue) * (self->capacity)));
|
|
|
|
+ }
|
|
|
|
+ return self;
|
|
|
|
+}
|
|
|
|
+void spKeyValueArray_ensureCapacity(spKeyValueArray *self, int newCapacity) {
|
|
|
|
+ if (self->capacity >= newCapacity)return;
|
|
|
|
+ self->capacity = newCapacity;
|
|
|
|
+ self->items = ((spKeyValue *) _spRealloc(self->items, sizeof(spKeyValue) * (self->capacity)));
|
|
|
|
+}
|
|
|
|
+void spKeyValueArray_add(spKeyValueArray *self, spKeyValue value) {
|
|
|
|
+ if (self->size == self->capacity) {
|
|
|
|
+ self->capacity = ((8) > ((int) (self->size * 1.75f)) ? (8) : ((int) (self->size * 1.75f)));
|
|
|
|
+ self->items = ((spKeyValue *) _spRealloc(self->items, sizeof(spKeyValue) * (self->capacity)));
|
|
|
|
+ }
|
|
|
|
+ self->items[self->size++] = value;
|
|
|
|
+}
|
|
|
|
+void spKeyValueArray_addAll(spKeyValueArray *self, spKeyValueArray *other) {
|
|
|
|
+ int i = 0;
|
|
|
|
+ for (; i < other->size; i++) { spKeyValueArray_add(self, other->items[i]); }
|
|
|
|
+}
|
|
|
|
+void spKeyValueArray_addAllValues(spKeyValueArray *self, spKeyValue *values, int offset, int count) {
|
|
|
|
+ int i = offset, n = offset + count;
|
|
|
|
+ for (; i < n; i++) { spKeyValueArray_add(self, values[i]); }
|
|
|
|
+}
|
|
|
|
+void spKeyValueArray_removeAt(spKeyValueArray *self, int index) {
|
|
|
|
+ self->size--;
|
|
|
|
+ __builtin___memmove_chk(self->items + index, self->items + index + 1, sizeof(spKeyValue) * (self->size - index),
|
|
|
|
+ __builtin_object_size(self->items + index, 0));
|
|
|
|
+}
|
|
|
|
+int spKeyValueArray_contains(spKeyValueArray *self, spKeyValue value) {
|
|
|
|
+ spKeyValue *items = self->items;
|
|
|
|
+ int i, n;
|
|
|
|
+ for (i = 0, n = self->size; i < n; i++) { if (!strcmp(items[i].name, value.name))return -1; }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+spKeyValue spKeyValueArray_pop(spKeyValueArray *self) {
|
|
|
|
+ spKeyValue item = self->items[--self->size];
|
|
|
|
+ return item;
|
|
|
|
+}
|
|
|
|
+spKeyValue spKeyValueArray_peek(spKeyValueArray *self) { return self->items[self->size - 1]; }
|
|
|
|
+
|
|
spAtlasPage* spAtlasPage_create(spAtlas* atlas, const char* name) {
|
|
spAtlasPage* spAtlasPage_create(spAtlas* atlas, const char* name) {
|
|
spAtlasPage* self = NEW(spAtlasPage);
|
|
spAtlasPage* self = NEW(spAtlasPage);
|
|
CONST_CAST(spAtlas*, self->atlas) = atlas;
|
|
CONST_CAST(spAtlas*, self->atlas) = atlas;
|
|
@@ -47,19 +104,20 @@ void spAtlasPage_dispose(spAtlasPage* self) {
|
|
/**/
|
|
/**/
|
|
|
|
|
|
spAtlasRegion* spAtlasRegion_create() {
|
|
spAtlasRegion* spAtlasRegion_create() {
|
|
- return NEW(spAtlasRegion);
|
|
|
|
|
|
+ spAtlasRegion *region = NEW(spAtlasRegion);
|
|
|
|
+ region->keyValues = spKeyValueArray_create(2);
|
|
|
|
+ return region;
|
|
}
|
|
}
|
|
|
|
|
|
void spAtlasRegion_dispose(spAtlasRegion* self) {
|
|
void spAtlasRegion_dispose(spAtlasRegion* self) {
|
|
- int i, n;
|
|
|
|
|
|
+ int i, n;
|
|
FREE(self->name);
|
|
FREE(self->name);
|
|
FREE(self->splits);
|
|
FREE(self->splits);
|
|
FREE(self->pads);
|
|
FREE(self->pads);
|
|
- for (i = 0, n = self->numValues; i < n; i++) {
|
|
|
|
- FREE(self->names[i]);
|
|
|
|
- }
|
|
|
|
- FREE(self->names);
|
|
|
|
- FREE(self->values);
|
|
|
|
|
|
+ for (i = 0, n = self->keyValues->size; i < n; i++) {
|
|
|
|
+ FREE(self->keyValues->items[i].name);
|
|
|
|
+ }
|
|
|
|
+ spKeyValueArray_dispose(self->keyValues);
|
|
FREE(self);
|
|
FREE(self);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -183,156 +241,162 @@ static int ai_readEntry(SimpleString entry[5], SimpleString *line) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static spAtlas* abortAtlas(spAtlas* self) {
|
|
|
|
- spAtlas_dispose(self);
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static const char *formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888",
|
|
static const char *formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888",
|
|
"RGBA8888"};
|
|
"RGBA8888"};
|
|
static const char *textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest",
|
|
static const char *textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest",
|
|
"MipMapLinearNearest",
|
|
"MipMapLinearNearest",
|
|
"MipMapNearestLinear", "MipMapLinearLinear"};
|
|
"MipMapNearestLinear", "MipMapLinearLinear"};
|
|
|
|
|
|
|
|
+int indexOf(const char **array, int count, SimpleString *str) {
|
|
|
|
+ int i;
|
|
|
|
+ for (i = 0; i < count; i++)
|
|
|
|
+ if (ss_equals(str, array[i])) return i;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
spAtlas* spAtlas_create(const char* begin, int length, const char* dir, void* rendererObject) {
|
|
spAtlas* spAtlas_create(const char* begin, int length, const char* dir, void* rendererObject) {
|
|
spAtlas* self;
|
|
spAtlas* self;
|
|
|
|
+ AtlasInput reader;
|
|
|
|
+ SimpleString *line;
|
|
|
|
+ SimpleString entry[5];
|
|
|
|
+ spAtlasPage *page = NULL;
|
|
|
|
+ spAtlasPage *lastPage = NULL;
|
|
|
|
+ spAtlasRegion *lastRegion = NULL;
|
|
|
|
|
|
int count;
|
|
int count;
|
|
- const char* end = begin + length;
|
|
|
|
int dirLength = (int)strlen(dir);
|
|
int dirLength = (int)strlen(dir);
|
|
int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
|
|
int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
|
|
|
|
|
|
- spAtlasPage *page = 0;
|
|
|
|
- spAtlasPage *lastPage = 0;
|
|
|
|
- spAtlasRegion *lastRegion = 0;
|
|
|
|
- Str str;
|
|
|
|
- Str tuple[4];
|
|
|
|
-
|
|
|
|
self = NEW(spAtlas);
|
|
self = NEW(spAtlas);
|
|
self->rendererObject = rendererObject;
|
|
self->rendererObject = rendererObject;
|
|
|
|
|
|
- while (readLine(&begin, end, &str)) {
|
|
|
|
- if (str.end - str.begin == 0)
|
|
|
|
- page = 0;
|
|
|
|
- else if (!page) {
|
|
|
|
- char* name = mallocString(&str);
|
|
|
|
- char* path = MALLOC(char, dirLength + needsSlash + strlen(name) + 1);
|
|
|
|
- memcpy(path, dir, dirLength);
|
|
|
|
- if (needsSlash) path[dirLength] = '/';
|
|
|
|
- strcpy(path + dirLength + needsSlash, name);
|
|
|
|
-
|
|
|
|
- page = spAtlasPage_create(self, name);
|
|
|
|
- FREE(name);
|
|
|
|
- if (lastPage)
|
|
|
|
- lastPage->next = page;
|
|
|
|
- else
|
|
|
|
- self->pages = page;
|
|
|
|
- lastPage = page;
|
|
|
|
-
|
|
|
|
- switch (readTuple(&begin, end, tuple)) {
|
|
|
|
- case 0:
|
|
|
|
- return abortAtlas(self);
|
|
|
|
- case 2: /* size is only optional for an atlas packed with an old TexturePacker. */
|
|
|
|
- page->width = toInt(tuple);
|
|
|
|
- page->height = toInt(tuple + 1);
|
|
|
|
- if (!readTuple(&begin, end, tuple)) return abortAtlas(self);
|
|
|
|
- }
|
|
|
|
- page->format = (spAtlasFormat)indexOf(formatNames, 8, tuple);
|
|
|
|
-
|
|
|
|
- if (!readTuple(&begin, end, tuple)) return abortAtlas(self);
|
|
|
|
- page->minFilter = (spAtlasFilter)indexOf(textureFilterNames, 8, tuple);
|
|
|
|
- page->magFilter = (spAtlasFilter)indexOf(textureFilterNames, 8, tuple + 1);
|
|
|
|
-
|
|
|
|
- if (!readValue(&begin, end, &str)) return abortAtlas(self);
|
|
|
|
-
|
|
|
|
- page->uWrap = SP_ATLAS_CLAMPTOEDGE;
|
|
|
|
- page->vWrap = SP_ATLAS_CLAMPTOEDGE;
|
|
|
|
- if (!equals(&str, "none")) {
|
|
|
|
- if (str.end - str.begin == 1) {
|
|
|
|
- if (*str.begin == 'x')
|
|
|
|
- page->uWrap = SP_ATLAS_REPEAT;
|
|
|
|
- else if (*str.begin == 'y')
|
|
|
|
- page->vWrap = SP_ATLAS_REPEAT;
|
|
|
|
- }
|
|
|
|
- else if (equals(&str, "xy")) {
|
|
|
|
- page->uWrap = SP_ATLAS_REPEAT;
|
|
|
|
- page->vWrap = SP_ATLAS_REPEAT;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _spAtlasPage_createTexture(page, path);
|
|
|
|
- FREE(path);
|
|
|
|
- } else {
|
|
|
|
- spAtlasRegion *region = spAtlasRegion_create();
|
|
|
|
- if (lastRegion)
|
|
|
|
- lastRegion->next = region;
|
|
|
|
- else
|
|
|
|
- self->regions = region;
|
|
|
|
- lastRegion = region;
|
|
|
|
-
|
|
|
|
- region->page = page;
|
|
|
|
- region->name = mallocString(&str);
|
|
|
|
-
|
|
|
|
- if (!readValue(&begin, end, &str)) return abortAtlas(self);
|
|
|
|
- if (equals(&str, "true"))
|
|
|
|
- region->degrees = 90;
|
|
|
|
- else if (equals(&str, "false"))
|
|
|
|
- region->degrees = 0;
|
|
|
|
- else
|
|
|
|
- region->degrees = toInt(&str);
|
|
|
|
- region->rotate = region->degrees == 90;
|
|
|
|
-
|
|
|
|
- if (readTuple(&begin, end, tuple) != 2) return abortAtlas(self);
|
|
|
|
- region->x = toInt(tuple);
|
|
|
|
- region->y = toInt(tuple + 1);
|
|
|
|
-
|
|
|
|
- if (readTuple(&begin, end, tuple) != 2) return abortAtlas(self);
|
|
|
|
- region->width = toInt(tuple);
|
|
|
|
- region->height = toInt(tuple + 1);
|
|
|
|
-
|
|
|
|
- region->u = region->x / (float)page->width;
|
|
|
|
- region->v = region->y / (float)page->height;
|
|
|
|
- if (region->rotate) {
|
|
|
|
- region->u2 = (region->x + region->height) / (float)page->width;
|
|
|
|
- region->v2 = (region->y + region->width) / (float)page->height;
|
|
|
|
- } else {
|
|
|
|
- region->u2 = (region->x + region->width) / (float)page->width;
|
|
|
|
- region->v2 = (region->y + region->height) / (float)page->height;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- count = readTuple(&begin, end, tuple);
|
|
|
|
- if (!count) return abortAtlas(self);
|
|
|
|
- if (count == 4) { /* split is optional */
|
|
|
|
- region->splits = MALLOC(int, 4);
|
|
|
|
- region->splits[0] = toInt(tuple);
|
|
|
|
- region->splits[1] = toInt(tuple + 1);
|
|
|
|
- region->splits[2] = toInt(tuple + 2);
|
|
|
|
- region->splits[3] = toInt(tuple + 3);
|
|
|
|
-
|
|
|
|
- count = readTuple(&begin, end, tuple);
|
|
|
|
- if (!count) return abortAtlas(self);
|
|
|
|
- if (count == 4) { /* pad is optional, but only present with splits */
|
|
|
|
- region->pads = MALLOC(int, 4);
|
|
|
|
- region->pads[0] = toInt(tuple);
|
|
|
|
- region->pads[1] = toInt(tuple + 1);
|
|
|
|
- region->pads[2] = toInt(tuple + 2);
|
|
|
|
- region->pads[3] = toInt(tuple + 3);
|
|
|
|
-
|
|
|
|
- if (!readTuple(&begin, end, tuple)) return abortAtlas(self);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- region->originalWidth = toInt(tuple);
|
|
|
|
- region->originalHeight = toInt(tuple + 1);
|
|
|
|
-
|
|
|
|
- readTuple(&begin, end, tuple);
|
|
|
|
- region->offsetX = toInt(tuple);
|
|
|
|
- region->offsetY = toInt(tuple + 1);
|
|
|
|
-
|
|
|
|
- if (!readValue(&begin, end, &str)) return abortAtlas(self);
|
|
|
|
- region->index = toInt(&str);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ reader.start = begin;
|
|
|
|
+ reader.end = begin + length;
|
|
|
|
+ reader.index = (char*)begin;
|
|
|
|
+ reader.length = length;
|
|
|
|
+
|
|
|
|
+ line = ai_readLine(&reader);
|
|
|
|
+ while (line != NULL && line->length == 0)
|
|
|
|
+ line = ai_readLine(&reader);
|
|
|
|
+
|
|
|
|
+ while (-1) {
|
|
|
|
+ if (line == NULL || line->length == 0) break;
|
|
|
|
+ if (ai_readEntry(entry, line) == 0) break;
|
|
|
|
+ line = ai_readLine(&reader);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (-1) {
|
|
|
|
+ if (line == NULL) break;
|
|
|
|
+ if (ss_trim(line)->length == 0) {
|
|
|
|
+ page = NULL;
|
|
|
|
+ line = ai_readLine(&reader);
|
|
|
|
+ } else if (page == NULL) {
|
|
|
|
+ char *name = ss_copy(line);
|
|
|
|
+ char *path = CALLOC(char, dirLength + needsSlash + strlen(name) + 1);
|
|
|
|
+ memcpy(path, dir, dirLength);
|
|
|
|
+ if (needsSlash) path[dirLength] = '/';
|
|
|
|
+ strcpy(path + dirLength + needsSlash, name);
|
|
|
|
+ page = spAtlasPage_create(self, name);
|
|
|
|
+ FREE(name);
|
|
|
|
+
|
|
|
|
+ if (lastPage)
|
|
|
|
+ lastPage->next = page;
|
|
|
|
+ else
|
|
|
|
+ self->pages = page;
|
|
|
|
+ lastPage = page;
|
|
|
|
+
|
|
|
|
+ while (-1) {
|
|
|
|
+ line = ai_readLine(&reader);
|
|
|
|
+ if (ai_readEntry(entry, line) == 0) break;
|
|
|
|
+ if (ss_equals(&entry[0], "size")) {
|
|
|
|
+ page->width = ss_toInt(&entry[1]);
|
|
|
|
+ page->height = ss_toInt(&entry[2]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "format")) {
|
|
|
|
+ page->format = (spAtlasFormat) indexOf(formatNames, 8, &entry[1]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "filter")) {
|
|
|
|
+ page->minFilter = (spAtlasFilter) indexOf(textureFilterNames, 8, &entry[1]);
|
|
|
|
+ page->magFilter = (spAtlasFilter) indexOf(textureFilterNames, 8, &entry[2]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "repeat")) {
|
|
|
|
+ page->uWrap = SP_ATLAS_CLAMPTOEDGE;
|
|
|
|
+ page->vWrap = SP_ATLAS_CLAMPTOEDGE;
|
|
|
|
+ if (ss_indexOf(&entry[1], 'x') != -1) page->uWrap = SP_ATLAS_REPEAT;
|
|
|
|
+ if (ss_indexOf(&entry[1], 'y') != -1) page->vWrap = SP_ATLAS_REPEAT;
|
|
|
|
+ } else if (ss_equals(&entry[0], "pma")) {
|
|
|
|
+ page->pma = ss_equals(&entry[1], "true");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ _spAtlasPage_createTexture(page, path);
|
|
|
|
+ FREE(path);
|
|
|
|
+ } else {
|
|
|
|
+ spAtlasRegion *region = spAtlasRegion_create();
|
|
|
|
+ if (lastRegion)
|
|
|
|
+ lastRegion->next = region;
|
|
|
|
+ else
|
|
|
|
+ self->regions = region;
|
|
|
|
+ lastRegion = region;
|
|
|
|
+ region->page = page;
|
|
|
|
+ region->name = ss_copy(line);
|
|
|
|
+ while (-1) {
|
|
|
|
+ line = ai_readLine(&reader);
|
|
|
|
+ count = ai_readEntry(entry, line);
|
|
|
|
+ if (count == 0) break;
|
|
|
|
+ if (ss_equals(&entry[0], "xy")) {
|
|
|
|
+ region->x = ss_toInt(&entry[1]);
|
|
|
|
+ region->y = ss_toInt(&entry[2]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "size")) {
|
|
|
|
+ region->width = ss_toInt(&entry[1]);
|
|
|
|
+ region->height = ss_toInt(&entry[2]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "bounds")) {
|
|
|
|
+ region->x = ss_toInt(&entry[1]);
|
|
|
|
+ region->y = ss_toInt(&entry[2]);
|
|
|
|
+ region->width = ss_toInt(&entry[3]);
|
|
|
|
+ region->height = ss_toInt(&entry[4]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "offset")) {
|
|
|
|
+ region->offsetX = ss_toInt(&entry[1]);
|
|
|
|
+ region->offsetY = ss_toInt(&entry[2]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "orig")) {
|
|
|
|
+ region->originalWidth = ss_toInt(&entry[1]);
|
|
|
|
+ region->originalHeight = ss_toInt(&entry[2]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "offsets")) {
|
|
|
|
+ region->offsetX = ss_toInt(&entry[1]);
|
|
|
|
+ region->offsetY = ss_toInt(&entry[2]);
|
|
|
|
+ region->originalWidth = ss_toInt(&entry[3]);
|
|
|
|
+ region->originalHeight = ss_toInt(&entry[4]);
|
|
|
|
+ } else if (ss_equals(&entry[0], "rotate")) {
|
|
|
|
+ if (ss_equals(&entry[1], "true")) {
|
|
|
|
+ region->degrees = 90;
|
|
|
|
+ } else if (!ss_equals(&entry[1], "false")) {
|
|
|
|
+ region->degrees = ss_toInt(&entry[1]);
|
|
|
|
+ }
|
|
|
|
+ } else if (ss_equals(&entry[0], "index")) {
|
|
|
|
+ region->index = ss_toInt(&entry[1]);
|
|
|
|
+ } else {
|
|
|
|
+ int i = 0;
|
|
|
|
+ spKeyValue keyValue;
|
|
|
|
+ keyValue.name = ss_copy(&entry[0]);
|
|
|
|
+ for (i = 0; i < count; i++) {
|
|
|
|
+ keyValue.values[i] = ss_toInt(&entry[i + 1]);
|
|
|
|
+ }
|
|
|
|
+ spKeyValueArray_add(region->keyValues, keyValue);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (region->originalWidth == 0 && region->originalHeight == 0) {
|
|
|
|
+ region->originalWidth = region->width;
|
|
|
|
+ region->originalHeight = region->height;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ region->u = (float)region->x / page->width;
|
|
|
|
+ region->v = (float)region->y / page->height;
|
|
|
|
+ if (region->degrees == 90) {
|
|
|
|
+ region->u2 = (float)(region->x + region->height) / page->width;
|
|
|
|
+ region->v2 = (float)(region->y + region->width) / page->height;
|
|
|
|
+ } else {
|
|
|
|
+ region->u2 = (float)(region->x + region->width) / page->width;
|
|
|
|
+ region->v2 = (float)(region->y + region->height) / page->height;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
return self;
|
|
return self;
|
|
}
|
|
}
|