[cpp] More 4.0 porting, Atlas, fixes.

This commit is contained in:
badlogic 2021-03-05 15:44:19 +01:00
parent 4375342576
commit cf3a28e3a4
4 changed files with 258 additions and 265 deletions

View File

@ -74,10 +74,11 @@ public:
TextureWrap uWrap;
TextureWrap vWrap;
int width, height;
bool pma;
explicit AtlasPage(const String &inName) : name(inName), format(Format_RGBA8888), minFilter(TextureFilter_Nearest),
magFilter(TextureFilter_Nearest), uWrap(TextureWrap_ClampToEdge),
vWrap(TextureWrap_ClampToEdge), width(0), height(0) {
vWrap(TextureWrap_ClampToEdge), width(0), height(0), pma(false) {
}
};
@ -94,6 +95,8 @@ public:
int degrees;
Vector<int> splits;
Vector<int> pads;
Vector<String> names;
Vector<float> values;
};
class TextureLoader;
@ -123,34 +126,6 @@ private:
TextureLoader *_textureLoader;
void load(const char *begin, int length, const char *dir, bool createTexture);
class Str {
public:
const char *begin;
const char *end;
};
static void trim(Str *str);
/// Tokenize string without modification. Returns 0 on failure
static int readLine(const char **begin, const char *end, Str *str);
/// Moves str->begin past the first occurence of c. Returns 0 on failure
static int beginPast(Str *str, char c);
/// Returns 0 on failure
static int readValue(const char **begin, const char *end, Str *str);
/// Returns the number of tuple values read (1, 2, 4, or 0 for failure)
static int readTuple(const char **begin, const char *end, Str tuple[]);
static char *mallocString(Str *str);
static int indexOf(const char **array, int count, Str *str);
static int equals(Str *str, const char *other);
static int toInt(Str *str);
};
}

View File

@ -60,8 +60,6 @@ namespace spine {
static const int SCALEX = 4;
static const int SCALEY = 5;
static const int SHEARY = 6;
Vector<float> _frames;
};
}

View File

@ -102,232 +102,252 @@ Vector<AtlasRegion*> &Atlas::getRegions() {
return _regions;
}
struct SimpleString {
char* start;
char* end;
int length;
SimpleString trim() {
while (isspace((unsigned char) *start) && start < end)
start++;
if (start == end) return *this;
end--;
while (((unsigned char)*end == '\r') && end >= start)
end--;
end++;
length = end - start;
return *this;
}
int indexOf(char needle) {
char *c = start;
while (c < end) {
if (*c == needle) return c - start;
c++;
}
return -1;
}
int indexOf(char needle, int at) {
char *c = start + at;
while (c < end) {
if (*c == needle) return c - start;
c++;
}
return -1;
}
SimpleString substr(int s, int e) {
e = s + e;
SimpleString result;
result.start = start + s;
result.end = start + e;
result.length = e - s;
return result;
}
SimpleString substr(int s) {
SimpleString result;
result.start = start + s;
result.end = end;
result.length = result.end - result.start;
return result;
}
bool equals(const char *str) {
int otherLen = strlen(str);
if (length != otherLen) return false;
for (int i = 0; i < length; i++) {
if (start[i] != str[i]) return false;
}
return true;
}
char *copy() {
char *string = SpineExtension::calloc<char>(length + 1, __FILE__, __LINE__);
memcpy(string, start, length);
string[length] = '\0';
return string;
}
int toInt() {
return (int) strtol(start, &end, 10);
}
};
struct AtlasInput {
const char *start;
const char *end;
char *index;
int length;
SimpleString line;
AtlasInput(const char *data, int length) : start(data), end(data + length), index((char*)data), length(length) {}
SimpleString *readLine() {
if (index >= end) return 0;
line.start = index;
while (index < end && *index != '\n')
index++;
line.end = index;
if (index != end) index++;
line = line.trim();
line.length = end - start;
return &line;
}
static int readEntry(SimpleString entry[5], SimpleString *line) {
if (line == NULL) return 0;
line->trim();
if (line->length == 0) return 0;
int colon = line->indexOf(':');
if (colon == -1) return 0;
entry[0] = line->substr(0, colon).trim();
for (int i = 1, lastMatch = colon + 1;; i++) {
int comma = line->indexOf(',', lastMatch);
if (comma == -1) {
entry[i] = line->substr(lastMatch).trim();
return i;
}
entry[i] = line->substr(lastMatch, comma - lastMatch).trim();
lastMatch = comma + 1;
if (i == 4) return 4;
}
}
};
int indexOf(const char **array, int count, SimpleString *str) {
for (int i = 0; i < count; i++)
if (str->equals(array[i])) return i;
return 0;
}
void Atlas::load(const char *begin, int length, const char *dir, bool createTexture) {
static const char *formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888", "RGBA8888"};
static const char *textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest", "MipMapLinearNearest",
"MipMapNearestLinear", "MipMapLinearLinear"};
static const char *formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888",
"RGBA8888"};
static const char *textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest",
"MipMapLinearNearest",
"MipMapNearestLinear", "MipMapLinearLinear"};
int count;
const char *end = begin + length;
int dirLength = (int) strlen(dir);
int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
int dirLength = (int) strlen(dir);
int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
AtlasInput reader(begin, length);
SimpleString entry[5];
AtlasPage *page = NULL;
AtlasPage *page = NULL;
Str str;
Str tuple[4];
SimpleString *line = reader.readLine();
while (line != NULL && line->length == 0)
line = reader.readLine();
while (readLine(&begin, end, &str)) {
if (str.end - str.begin == 0) {
page = 0;
} else if (!page) {
char *name = mallocString(&str);
char *path = SpineExtension::calloc<char>(dirLength + needsSlash + strlen(name) + 1, __FILE__, __LINE__);
memcpy(path, dir, dirLength);
if (needsSlash) path[dirLength] = '/';
strcpy(path + dirLength + needsSlash, name);
while (true) {
if (line == NULL || line->length == 0) break;
if (reader.readEntry(entry, line) == 0) break;
line = reader.readLine();
}
page = new(__FILE__, __LINE__) AtlasPage(String(name, true));
while (true) {
if (line == NULL) break;
if (line->trim().length == 0) {
page = NULL;
line = reader.readLine();
} else if (page == NULL) {
char *name = line->copy();
char *path = SpineExtension::calloc<char>(dirLength + needsSlash + strlen(name) + 1, __FILE__, __LINE__);
memcpy(path, dir, dirLength);
if (needsSlash) path[dirLength] = '/';
strcpy(path + dirLength + needsSlash, name);
page = new(__FILE__, __LINE__) AtlasPage(String(name, true));
int tupleVal = readTuple(&begin, end, tuple);
assert(tupleVal == 2);
while (true) {
line = line = reader.readLine();
if (reader.readEntry(entry, line) == 0) break;
if (entry[0].equals("size")) {
page->width = entry[1].toInt();
page->height = entry[2].toInt();
} else if (entry[0].equals("format")) {
page->format = (Format) indexOf(formatNames, 8, &entry[1]);
} else if (entry[0].equals("filter")) {
page->minFilter = (TextureFilter) indexOf(textureFilterNames, 8, &entry[1]);
page->magFilter = (TextureFilter) indexOf(textureFilterNames, 8, &entry[2]);
} else if (entry[0].equals("repeat")) {
page->uWrap = TextureWrap_ClampToEdge;
page->vWrap = TextureWrap_ClampToEdge;
if (entry[1].indexOf('x') != -1) page->uWrap = TextureWrap_Repeat;
if (entry[1].indexOf('y') != -1) page->vWrap = TextureWrap_Repeat;
} else if (entry[0].equals("pma")) {
page->pma = entry[1].equals("true");
}
}
/* size is only optional for an atlas packed with an old TexturePacker. */
page->width = toInt(tuple);
page->height = toInt(tuple + 1);
readTuple(&begin, end, tuple);
if (createTexture) {
if (_textureLoader) _textureLoader->load(*page, String(path));
SpineExtension::free(path, __FILE__, __LINE__);
} else {
page->texturePath = String(path, true);
}
_pages.add(page);
} else {
AtlasRegion *region = new(__FILE__, __LINE__) AtlasRegion();
region->page = page;
region->name = String(line->copy(), true);
while (true) {
line = line = reader.readLine();
int count = reader.readEntry(entry, line);
if (count == 0) break;
if (entry[0].equals("xy")) {
region->x = entry[1].toInt();
region->y = entry[2].toInt();
} else if (entry[0].equals("size")) {
region->width = entry[1].toInt();
region->height = entry[2].toInt();
} else if (entry[0].equals("bounds")) {
region->x = entry[1].toInt();
region->y = entry[2].toInt();
region->width = entry[3].toInt();
region->height = entry[4].toInt();
} else if (entry[0].equals("offset")) {
region->offsetX = entry[1].toInt();
region->offsetY = entry[2].toInt();
} else if (entry[0].equals("orig")) {
region->originalWidth = entry[1].toInt();
region->originalHeight = entry[2].toInt();
} else if (entry[0].equals("offsets")) {
region->offsetX = entry[1].toInt();
region->offsetY = entry[2].toInt();
region->originalWidth = entry[3].toInt();
region->originalHeight = entry[4].toInt();
} else if (entry[0].equals("rotate")) {
if (entry[1].equals("true")) {
region->degrees = 90;
} else if (!entry[1].equals("false")) {
region->degrees = entry[1].toInt();
}
} else if (entry[0].equals("index")) {
region->index = entry[1].toInt();
} else {
region->names.add(String(entry[0].copy()));
for (int i = 0; i < count; i++) {
region->values.add(entry[i + 1].toInt());
}
}
}
if (region->originalWidth == 0 && region->originalHeight == 0) {
region->originalWidth = region->width;
region->originalHeight = region->height;
}
page->format = (Format) indexOf(formatNames, 8, tuple);
readTuple(&begin, end, tuple);
page->minFilter = (TextureFilter) indexOf(textureFilterNames, 8, tuple);
page->magFilter = (TextureFilter) indexOf(textureFilterNames, 8, tuple + 1);
readValue(&begin, end, &str);
page->uWrap = TextureWrap_ClampToEdge;
page->vWrap = TextureWrap_ClampToEdge;
if (!equals(&str, "none")) {
if (str.end - str.begin == 1) {
if (*str.begin == 'x') {
page->uWrap = TextureWrap_Repeat;
} else if (*str.begin == 'y') {
page->vWrap = TextureWrap_Repeat;
}
} else if (equals(&str, "xy")) {
page->uWrap = TextureWrap_Repeat;
page->vWrap = TextureWrap_Repeat;
}
}
if (createTexture) {
if (_textureLoader) _textureLoader->load(*page, String(path));
SpineExtension::free(path, __FILE__, __LINE__);
} else
page->texturePath = String(path, true);
_pages.add(page);
} else {
AtlasRegion *region = new(__FILE__, __LINE__) AtlasRegion();
region->page = page;
region->name = String(mallocString(&str), true);
readValue(&begin, end, &str);
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;
readTuple(&begin, end, tuple);
region->x = toInt(tuple);
region->y = toInt(tuple + 1);
readTuple(&begin, end, tuple);
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);
assert(count);
if (count == 4) {
/* split is optional */
region->splits.setSize(4, 0);
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);
assert(count);
if (count == 4) {
/* pad is optional, but only present with splits */
region->pads.setSize(4, 0);
region->pads[0] = toInt(tuple);
region->pads[1] = toInt(tuple + 1);
region->pads[2] = toInt(tuple + 2);
region->pads[3] = toInt(tuple + 3);
readTuple(&begin, end, tuple);
}
}
region->originalWidth = toInt(tuple);
region->originalHeight = toInt(tuple + 1);
readTuple(&begin, end, tuple);
region->offsetX = (float)toInt(tuple);
region->offsetY = (float)toInt(tuple + 1);
readValue(&begin, end, &str);
region->index = toInt(&str);
_regions.add(region);
}
}
region->u = region->x / page->width;
region->v = region->y / page->height;
if (region->degrees == 90) {
region->u2 = (region->x + region->height) / page->width;
region->v2 = (region->y + region->width) / page->height;
} else {
region->u2 = (region->x + region->width) / page->width;
region->v2 = (region->y + region->height) / page->height;
}
_regions.add(region);
}
}
}
void Atlas::trim(Str *str) {
while (isspace((unsigned char) *str->begin) && str->begin < str->end)
(str->begin)++;
if (str->begin == str->end) return;
str->end--;
while (((unsigned char)*str->end == '\r') && str->end >= str->begin)
str->end--;
str->end++;
}
int Atlas::readLine(const char **begin, const char *end, Str *str) {
if (*begin == end) return 0;
str->begin = *begin;
/* Find next delimiter. */
while (*begin != end && **begin != '\n')
(*begin)++;
str->end = *begin;
trim(str);
if (*begin != end) (*begin)++;
return 1;
}
int Atlas::beginPast(Str *str, char c) {
const char *begin = str->begin;
while (true) {
char lastSkippedChar = *begin;
if (begin == str->end) return 0;
begin++;
if (lastSkippedChar == c) break;
}
str->begin = begin;
return 1;
}
int Atlas::readValue(const char **begin, const char *end, Str *str) {
readLine(begin, end, str);
if (!beginPast(str, ':')) return 0;
trim(str);
return 1;
}
int Atlas::readTuple(const char **begin, const char *end, Str tuple[]) {
int i;
Str str = {NULL, NULL};
readLine(begin, end, &str);
if (!beginPast(&str, ':')) return 0;
for (i = 0; i < 3; ++i) {
tuple[i].begin = str.begin;
if (!beginPast(&str, ',')) break;
tuple[i].end = str.begin - 2;
trim(&tuple[i]);
}
tuple[i].begin = str.begin;
tuple[i].end = str.end;
trim(&tuple[i]);
return i + 1;
}
char *Atlas::mallocString(Str *str) {
int length = (int) (str->end - str->begin);
char *string = SpineExtension::calloc<char>(length + 1, __FILE__, __LINE__);
memcpy(string, str->begin, length);
string[length] = '\0';
return string;
}
int Atlas::indexOf(const char **array, int count, Str *str) {
int length = (int) (str->end - str->begin);
int i;
for (i = count - 1; i >= 0; i--)
if (strncmp(array[i], str->begin, length) == 0) return i;
return 0;
}
int Atlas::equals(Str *str, const char *other) {
return strncmp(other, str->begin, str->end - str->begin) == 0;
}
int Atlas::toInt(Str *str) {
return (int) strtol(str->begin, (char **) &str->end, 10);
}

View File

@ -858,7 +858,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
for (frame = 0, bezier = 0;;++frame) {
timeline->setFrame(frame, time, color.r, color.g, color.b, color.a);
nextMap = keyMap->_next;
if (!keyMap) break;
if (!nextMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
toColor(newColor, Json::getString(nextMap, "color", 0), true);
curve = Json::getItem(keyMap, "curve");
@ -884,7 +884,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
for (frame = 0, bezier = 0;;++frame) {
timeline->setFrame(frame, time, color.r, color.g, color.b);
nextMap = keyMap->_next;
if (!keyMap) break;
if (!nextMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
toColor(newColor, Json::getString(nextMap, "color", 0), false);
curve = Json::getItem(keyMap, "curve");
@ -899,7 +899,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
}
timelines.add(timeline);
} else if (strcmp(timelineMap->_name, "alpha") == 0) {
timelines.add(readTimeline(timelineMap, new (__FILE__, __LINE__) AlphaTimeline(timelineMap->_size, timelineMap->_size, slotIndex), 0, 1));
timelines.add(readTimeline(timelineMap->_child, new (__FILE__, __LINE__) AlphaTimeline(timelineMap->_size, timelineMap->_size, slotIndex), 0, 1));
} else if (strcmp(timelineMap->_name, "rgba2") == 0) {
int frameCount = timelineMap->_size;
int bezierCount = frameCount * 7;
@ -912,7 +912,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
for (frame = 0, bezier = 0;;++frame) {
timeline->setFrame(frame, time, color.r, color.g, color.b, color.a, color2.g, color2.g, color2.b);
nextMap = keyMap->_next;
if (!keyMap) break;
if (!nextMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
toColor(newColor, Json::getString(nextMap, "light", 0), true);
toColor(newColor2, Json::getString(nextMap, "dark", 0), false);
@ -944,7 +944,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
for (frame = 0, bezier = 0;;++frame) {
timeline->setFrame(frame, time, color.r, color.g, color.b, color.a, color2.r, color2.g, color2.b);
nextMap = keyMap->_next;
if (!keyMap) break;
if (!nextMap) break;
float time2 = Json::getFloat(nextMap, "time", 0);
toColor(newColor, Json::getString(nextMap, "light", 0), false);
toColor(newColor2, Json::getString(nextMap, "dark", 0), false);
@ -986,34 +986,34 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
if (timelineMap->_size == 0) continue;
if (strcmp(timelineMap->_name, "rotate") == 0) {
timelines.add(readTimeline(timelineMap, new RotateTimeline(timelineMap->_size, timelineMap->_size, boneIndex), 0, 1));
timelines.add(readTimeline(timelineMap->_child, new RotateTimeline(timelineMap->_size, timelineMap->_size, boneIndex), 0, 1));
} else if (strcmp(timelineMap->_name, "translate") == 0) {
TranslateTimeline *timeline = new TranslateTimeline(timelineMap->_size, timelineMap->_size << 1, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, "x", "y", 0, _scale));
timelines.add(readTimeline(timelineMap->_child, timeline, "x", "y", 0, _scale));
} else if (strcmp(timelineMap->_name, "translatex") == 0) {
TranslateXTimeline *timeline = new TranslateXTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 0, _scale));
timelines.add(readTimeline(timelineMap->_child, timeline, 0, _scale));
} else if (strcmp(timelineMap->_name, "translatey") == 0) {
TranslateYTimeline *timeline = new TranslateYTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 0, _scale));
timelines.add(readTimeline(timelineMap->_child, timeline, 0, _scale));
} else if (strcmp(timelineMap->_name, "scale") == 0) {
ScaleTimeline *timeline = new (__FILE__, __LINE__) ScaleTimeline(timelineMap->_size, timelineMap->_size << 1, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, "x", "y", 1, 1));
timelines.add(readTimeline(timelineMap->_child, timeline, "x", "y", 1, 1));
} else if (strcmp(timelineMap->_name, "scalex") == 0) {
ScaleXTimeline *timeline = new (__FILE__, __LINE__) ScaleXTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 1, 1));
timelines.add(readTimeline(timelineMap->_child, timeline, 1, 1));
} else if (strcmp(timelineMap->_name, "scaley") == 0) {
ScaleYTimeline *timeline = new (__FILE__, __LINE__) ScaleYTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 1, 1));
timelines.add(readTimeline(timelineMap->_child, timeline, 1, 1));
} else if (strcmp(timelineMap->_name, "shear") == 0) {
ShearTimeline *timeline = new (__FILE__, __LINE__) ShearTimeline(timelineMap->_size, timelineMap->_size << 1, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, "x", "y", 0, 1));
timelines.add(readTimeline(timelineMap->_child, timeline, "x", "y", 0, 1));
} else if (strcmp(timelineMap->_name, "shearx") == 0) {
ShearXTimeline *timeline = new (__FILE__, __LINE__) ShearXTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 0, 1));
timelines.add(readTimeline(timelineMap->_child, timeline, 0, 1));
} else if (strcmp(timelineMap->_name, "sheary") == 0) {
ShearYTimeline *timeline = new (__FILE__, __LINE__) ShearYTimeline(timelineMap->_size, timelineMap->_size, boneIndex);
timelines.add(readTimeline(timelineMap, timeline, 0, 1));
timelines.add(readTimeline(timelineMap->_child, timeline, 0, 1));
} else {
ContainerUtil::cleanUpVectorOfPointers(timelines);
setError(NULL, "Invalid timeline type for a bone: ", timelineMap->_name);