[c] 4.0 porting, texture atlas parsing and key value storage in regions.

This commit is contained in:
badlogic 2021-05-12 15:18:39 +02:00
parent 7ee6b78da6
commit 5411717c1a
3 changed files with 208 additions and 138 deletions

View File

@ -31,6 +31,7 @@
#define SPINE_ATLAS_H_
#include <spine/dll.h>
#include <spine/Array.h>
#ifdef __cplusplus
extern "C" {
@ -84,6 +85,13 @@ struct spAtlasPage {
SP_API spAtlasPage* spAtlasPage_create (spAtlas* atlas, const char* name);
SP_API void spAtlasPage_dispose (spAtlasPage* self);
/**/
typedef struct spKeyValue {
char *name;
float values[5];
} spKeyValue;
_SP_ARRAY_DECLARE_TYPE(spKeyValueArray, spKeyValue)
/**/
typedef struct spAtlasRegion spAtlasRegion;
struct spAtlasRegion {
@ -96,9 +104,7 @@ struct spAtlasRegion {
int degrees;
int* splits;
int* pads;
char** names;
float* values;
int numValues;
spKeyValueArray *keyValues;
spAtlasPage* page;

View File

@ -31,6 +31,63 @@
#include <ctype.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* self = NEW(spAtlasPage);
CONST_CAST(spAtlas*, self->atlas) = atlas;
@ -47,7 +104,9 @@ void spAtlasPage_dispose(spAtlasPage* self) {
/**/
spAtlasRegion* spAtlasRegion_create() {
return NEW(spAtlasRegion);
spAtlasRegion *region = NEW(spAtlasRegion);
region->keyValues = spKeyValueArray_create(2);
return region;
}
void spAtlasRegion_dispose(spAtlasRegion* self) {
@ -55,11 +114,10 @@ void spAtlasRegion_dispose(spAtlasRegion* self) {
FREE(self->name);
FREE(self->splits);
FREE(self->pads);
for (i = 0, n = self->numValues; i < n; i++) {
FREE(self->names[i]);
for (i = 0, n = self->keyValues->size; i < n; i++) {
FREE(self->keyValues->items[i].name);
}
FREE(self->names);
FREE(self->values);
spKeyValueArray_dispose(self->keyValues);
FREE(self);
}
@ -183,80 +241,88 @@ 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",
"RGBA8888"};
static const char *textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest",
"MipMapLinearNearest",
"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* self;
AtlasInput reader;
SimpleString *line;
SimpleString entry[5];
spAtlasPage *page = NULL;
spAtlasPage *lastPage = NULL;
spAtlasRegion *lastRegion = NULL;
int count;
const char* end = begin + length;
int dirLength = (int)strlen(dir);
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->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);
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;
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);
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 (!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;
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");
}
}
@ -269,68 +335,66 @@ spAtlas* spAtlas_create(const char* begin, int length, const char* dir, void* re
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->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 (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 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 {
region->u2 = (region->x + region->width) / (float)page->width;
region->v2 = (region->y + region->height) / (float)page->height;
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]);
}
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);
spKeyValueArray_add(region->keyValues, keyValue);
}
}
if (region->originalWidth == 0 && region->originalHeight == 0) {
region->originalWidth = region->width;
region->originalHeight = region->height;
}
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);
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;
}
}
}

View File

@ -292,7 +292,7 @@ void Atlas::load(const char *begin, int length, const char *dir, bool createText
region->page = page;
region->name = String(line->copy(), true);
while (true) {
line = line = reader.readLine();
line = reader.readLine();
int count = reader.readEntry(entry, line);
if (count == 0) break;
if (entry[0].equals("xy")) {