2020-02-29 20:51:14 +00:00
|
|
|
#include <cstring>
|
|
|
|
#include <cstdint>
|
2021-04-11 08:17:53 +00:00
|
|
|
#include <zstd.h>
|
2020-08-15 13:40:35 +00:00
|
|
|
|
2022-08-13 19:23:20 +00:00
|
|
|
#include "Common/Log.h"
|
2020-10-04 21:24:14 +00:00
|
|
|
#include "Common/Render/TextureAtlas.h"
|
2012-03-24 22:39:19 +00:00
|
|
|
|
2020-02-29 20:51:14 +00:00
|
|
|
class ByteReader {
|
|
|
|
public:
|
|
|
|
ByteReader(const uint8_t *data, size_t size) : data_(data), offset_(0), size_(size) {}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
T Read() {
|
2022-08-13 19:23:20 +00:00
|
|
|
_dbg_assert_(offset_ + sizeof(T) <= size_);
|
2020-02-29 20:51:14 +00:00
|
|
|
T x;
|
|
|
|
memcpy(&x, data_ + offset_, sizeof(T));
|
|
|
|
offset_ += sizeof(T);
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
void ReadInto(T *t) {
|
2022-08-13 19:23:20 +00:00
|
|
|
_dbg_assert_(offset_ + sizeof(T) <= size_);
|
2020-02-29 20:51:14 +00:00
|
|
|
memcpy(t, data_ + offset_, sizeof(T));
|
|
|
|
offset_ += sizeof(T);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T>
|
2021-04-11 08:17:53 +00:00
|
|
|
T *ReadMultipleAlloc(size_t count, bool compressed) {
|
2020-02-29 20:51:14 +00:00
|
|
|
T *t = new T[count];
|
2021-04-11 08:17:53 +00:00
|
|
|
if (!compressed) {
|
2022-08-13 19:23:20 +00:00
|
|
|
_dbg_assert_(offset_ + sizeof(T) * count <= size_);
|
2021-04-11 08:17:53 +00:00
|
|
|
memcpy(t, data_ + offset_, sizeof(T) * count);
|
|
|
|
offset_ += sizeof(T) * count;
|
|
|
|
} else {
|
2022-08-13 19:23:20 +00:00
|
|
|
_dbg_assert_(offset_ + sizeof(uint32_t) <= size_);
|
2021-04-11 08:17:53 +00:00
|
|
|
uint32_t compressed_size = 0;
|
|
|
|
memcpy(&compressed_size, data_ + offset_, sizeof(uint32_t));
|
|
|
|
offset_ += sizeof(uint32_t);
|
|
|
|
|
2022-08-13 19:23:20 +00:00
|
|
|
_dbg_assert_(offset_ + compressed_size <= size_);
|
2021-04-11 08:17:53 +00:00
|
|
|
ZSTD_decompress(t, sizeof(T) * count, data_ + offset_, compressed_size);
|
|
|
|
offset_ += compressed_size;
|
|
|
|
}
|
2020-02-29 20:51:14 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const uint8_t *data_;
|
|
|
|
size_t offset_;
|
|
|
|
size_t size_;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool Atlas::Load(const uint8_t *data, size_t data_size) {
|
|
|
|
ByteReader reader(data, data_size);
|
|
|
|
|
|
|
|
AtlasHeader header = reader.Read<AtlasHeader>();
|
|
|
|
num_images = header.numImages;
|
|
|
|
num_fonts = header.numFonts;
|
|
|
|
if (header.magic != ATLAS_MAGIC) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-04-11 08:17:53 +00:00
|
|
|
images = reader.ReadMultipleAlloc<AtlasImage>(num_images, header.version >= 1);
|
|
|
|
|
2020-02-29 20:51:14 +00:00
|
|
|
fonts = new AtlasFont[num_fonts];
|
2012-10-26 13:58:09 +00:00
|
|
|
for (int i = 0; i < num_fonts; i++) {
|
2020-02-29 20:51:14 +00:00
|
|
|
AtlasFontHeader font_header = reader.Read<AtlasFontHeader>();
|
|
|
|
fonts[i].padding = font_header.padding;
|
|
|
|
fonts[i].height = font_header.height;
|
|
|
|
fonts[i].ascend = font_header.ascend;
|
|
|
|
fonts[i].distslope = font_header.distslope;
|
|
|
|
fonts[i].numRanges = font_header.numRanges;
|
|
|
|
fonts[i].numChars = font_header.numChars;
|
2021-04-11 08:17:53 +00:00
|
|
|
fonts[i].ranges = reader.ReadMultipleAlloc<AtlasCharRange>(font_header.numRanges, header.version >= 1);
|
|
|
|
fonts[i].charData = reader.ReadMultipleAlloc<AtlasChar>(font_header.numChars, header.version >= 1);
|
2020-02-29 20:51:14 +00:00
|
|
|
memcpy(fonts[i].name, font_header.name, sizeof(font_header.name));
|
2012-10-26 13:58:09 +00:00
|
|
|
}
|
2020-02-29 20:51:14 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const AtlasFont *Atlas::getFont(FontID id) const {
|
|
|
|
if (id.isInvalid())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
for (int i = 0; i < num_fonts; i++) {
|
|
|
|
if (!strcmp(id.id, fonts[i].name))
|
|
|
|
return &fonts[i];
|
|
|
|
}
|
|
|
|
return nullptr;
|
2012-10-26 13:58:09 +00:00
|
|
|
}
|
|
|
|
|
2020-02-29 20:51:14 +00:00
|
|
|
const AtlasImage *Atlas::getImage(ImageID name) const {
|
|
|
|
if (name.isInvalid())
|
|
|
|
return nullptr;
|
|
|
|
|
2012-10-26 13:58:09 +00:00
|
|
|
for (int i = 0; i < num_images; i++) {
|
2020-02-29 20:51:14 +00:00
|
|
|
if (!strcmp(name.id, images[i].name))
|
2012-10-26 13:58:09 +00:00
|
|
|
return &images[i];
|
|
|
|
}
|
2020-02-29 20:51:14 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Atlas::measureImage(ImageID id, float *w, float *h) const {
|
|
|
|
const AtlasImage *image = getImage(id);
|
|
|
|
if (image) {
|
|
|
|
*w = (float)image->w;
|
|
|
|
*h = (float)image->h;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
*w = 0.0f;
|
|
|
|
*h = 0.0f;
|
|
|
|
return false;
|
|
|
|
}
|
2012-10-26 13:58:09 +00:00
|
|
|
}
|
2013-04-17 10:18:32 +00:00
|
|
|
|
|
|
|
const AtlasChar *AtlasFont::getChar(int utf32) const {
|
|
|
|
for (int i = 0; i < numRanges; i++) {
|
|
|
|
if (utf32 >= ranges[i].start && utf32 < ranges[i].end) {
|
2020-03-01 10:34:33 +00:00
|
|
|
const AtlasChar *c = &charData[ranges[i].result_index + utf32 - ranges[i].start];
|
2013-04-18 12:40:14 +00:00
|
|
|
if (c->ex == 0 && c->ey == 0)
|
2020-03-01 10:34:33 +00:00
|
|
|
return nullptr;
|
2013-04-18 12:40:14 +00:00
|
|
|
else
|
|
|
|
return c;
|
2013-04-17 10:18:32 +00:00
|
|
|
}
|
|
|
|
}
|
2020-03-01 10:34:33 +00:00
|
|
|
return nullptr;
|
2013-04-17 10:18:32 +00:00
|
|
|
}
|
2020-02-29 20:51:14 +00:00
|
|
|
|
|
|
|
Atlas::~Atlas() {
|
|
|
|
delete[] images;
|
|
|
|
delete[] fonts;
|
|
|
|
}
|
|
|
|
|
|
|
|
AtlasFont::~AtlasFont() {
|
|
|
|
delete[] ranges;
|
|
|
|
delete[] charData;
|
|
|
|
}
|