From c7cedcb719c49959e54ab1aee585fe07df256307 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sat, 10 Dec 2022 18:34:58 +0100 Subject: [PATCH] Implement loading. --- gif_loader.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++-- gif_loader.h | 21 ++++++-- register_types.cpp | 3 ++ 3 files changed, 137 insertions(+), 6 deletions(-) diff --git a/gif_loader.cpp b/gif_loader.cpp index 3fc07b3..ac874e7 100644 --- a/gif_loader.cpp +++ b/gif_loader.cpp @@ -1,17 +1,130 @@ #include "gif_loader.h" -Array GIFLoader::load_gif(const String &file) { - Array images; +#include "./thirdparty/gif_load/gif_load.h" +#include "core/os/file_access.h" - return images; +Array GIFLoader::get_images() { + return _images; +} + +void GIFLoader::gif_frame(void *data, struct GIF_WHDR *whdr) { + uint32_t *pict, *prev, x, y, yoff, iter, ifin, dsrc, ddst; + //uint8_t head[18] = { 0 }; + GIFLoader *loader = (GIFLoader *)data; + +#define BGRA(i) ((whdr->bptr[i] == whdr->tran) ? 0 : ((uint32_t)(whdr->cpal[whdr->bptr[i]].R << ((GIF_BIGE) ? 8 : 16)) | (uint32_t)(whdr->cpal[whdr->bptr[i]].G << ((GIF_BIGE) ? 16 : 8)) | (uint32_t)(whdr->cpal[whdr->bptr[i]].B << ((GIF_BIGE) ? 24 : 0)) | ((GIF_BIGE) ? 0xFF : 0xFF000000))) + + /* + if (!whdr->ifrm) { + // TGA doesn`t support heights over 0xFFFF, so we have to trim: + whdr->nfrm = ((whdr->nfrm < 0) ? -whdr->nfrm : whdr->nfrm) * whdr->ydim; + whdr->nfrm = (whdr->nfrm < 0xFFFF) ? whdr->nfrm : 0xFFFF; + // this is the very first frame, so we must write the header + head[2] = 2; + head[12] = (uint8_t)(whdr->xdim); + head[13] = (uint8_t)(whdr->xdim >> 8); + head[14] = (uint8_t)(whdr->nfrm); + head[15] = (uint8_t)(whdr->nfrm >> 8); + head[16] = 32; // 32 bits depth + head[17] = 0x20; // top-down flag + write(stat->uuid, head, 18UL); + ddst = (uint32_t)(whdr->xdim * whdr->ydim); + stat->pict = calloc(sizeof(uint32_t), ddst); + stat->prev = calloc(sizeof(uint32_t), ddst); + } + */ + + //ddst = (uint32_t)(whdr->xdim * whdr->ydim); + + if (!whdr->ifrm) { + //forst frame, alloc + ddst = (uint32_t)(whdr->xdim * whdr->ydim); + loader->pictd.resize(ddst * sizeof(uint32_t)); + loader->prevd.resize(ddst * sizeof(uint32_t)); + } + + PoolByteArray::Write pictw = loader->pictd.write(); + + /** [TODO:] the frame is assumed to be inside global bounds, + however it might exceed them in some GIFs; fix me. **/ + pict = (uint32_t *)pictw.ptr(); + ddst = (uint32_t)(whdr->xdim * whdr->fryo + whdr->frxo); + ifin = (!(iter = (whdr->intr) ? 0 : 4)) ? 4 : 5; /** interlacing support **/ + for (dsrc = (uint32_t)-1; iter < ifin; iter++) { + for (yoff = 16U >> ((iter > 1) ? iter : 1), y = (8 >> iter) & 7; y < (uint32_t)whdr->fryd; y += yoff) { + for (x = 0; x < (uint32_t)whdr->frxd; x++) { + if (whdr->tran != (long)whdr->bptr[++dsrc]) { + pict[(uint32_t)whdr->xdim * y + x + ddst] = BGRA(dsrc); + } + } + } + } + + pictw.release(); + + Ref img; + img.instance(); + img->create(whdr->xdim, whdr->ydim, false, Image::FORMAT_RGBA8, loader->pictd); + loader->_images.push_back(img); + + pict = (uint32_t *)pictw.ptr(); + + pictw = loader->pictd.write(); + PoolByteArray::Write prevdw = loader->prevd.write(); + + if ((whdr->mode == GIF_PREV) && !loader->last) { + whdr->frxd = whdr->xdim; + whdr->fryd = whdr->ydim; + whdr->mode = GIF_BKGD; + ddst = 0; + } else { + loader->last = (whdr->mode == GIF_PREV) ? loader->last : (unsigned long)(whdr->ifrm + 1); + pict = (uint32_t *)((whdr->mode == GIF_PREV) ? pictw.ptr() : prevdw.ptr()); + prev = (uint32_t *)((whdr->mode == GIF_PREV) ? prevdw.ptr() : pictw.ptr()); + + for (x = (uint32_t)(whdr->xdim * whdr->ydim); --x; pict[x - 1] = prev[x - 1]) { + } + } + + if (whdr->mode == GIF_BKGD) { /** cutting a hole for the next frame **/ + for (whdr->bptr[0] = (uint8_t)((whdr->tran >= 0) ? whdr->tran : whdr->bkgd), y = 0, pict = (uint32_t *)pictw.ptr(); y < (uint32_t)whdr->fryd; y++) { + for (x = 0; x < (uint32_t)whdr->frxd; x++) { + pict[(uint32_t)whdr->xdim * y + x + ddst] = BGRA(0); + } + } + } + +#undef BGRA +} + +void GIFLoader::load_gif(const String &file) { + _images.clear(); + + FileAccess *f = FileAccess::open(file, FileAccess::READ); + ERR_FAIL_COND(!f); + + //gif_load seems to need +2 bytes at the end + data.resize(f->get_len() + 2); + f->get_buffer(data.ptrw(), data.size() - 2); + data.set(data.size() - 2, 0); + data.set(data.size() - 1, 0); + + memdelete(f); + + GIF_Load((void *)data.ptrw(), (long)data.size(), gif_frame, 0, (void *)this, 0L); + + data.clear(); } GIFLoader::GIFLoader() { + size = 0; + last = 0; } GIFLoader::~GIFLoader() { } void GIFLoader::_bind_methods() { ClassDB::bind_method(D_METHOD("load_gif", "file"), &GIFLoader::load_gif); + ClassDB::bind_method(D_METHOD("get_images"), &GIFLoader::get_images); } \ No newline at end of file diff --git a/gif_loader.h b/gif_loader.h index 3f96704..c60abab 100644 --- a/gif_loader.h +++ b/gif_loader.h @@ -6,17 +6,32 @@ #include "core/io/image.h" +struct GIF_WHDR; + class GIFLoader : public Reference { - GDCLASS(GIFLoader, Reference); + GDCLASS(GIFLoader, Reference); public: - Array load_gif(const String &file); + Array get_images(); + + void load_gif(const String &file); GIFLoader(); ~GIFLoader(); private: static void _bind_methods(); + + static void gif_frame(void *data, struct GIF_WHDR *whdr); + + Array _images; + + Vector data; + PoolByteArray pictd; + PoolByteArray prevd; + + unsigned long size; + unsigned long last; }; -#endif +#endif diff --git a/register_types.cpp b/register_types.cpp index 1913c35..c485c8b 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -1,6 +1,9 @@ #include "register_types.h" +#include "gif_loader.h" + void register_gif_loader_types() { + ClassDB::register_class(); } void unregister_gif_loader_types() {