#include AL_IGNORE_WARNING("-Wunused-function") AL_IGNORE_WARNING("-Wmissing-field-initializers") #define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_STATIC #ifdef MAURI_LOCAL_STB #include #else #include #endif #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_STATIC #define STBI_NO_STDIO #define STBI_NO_FAILURE_STRINGS #ifdef MAURI_LOCAL_STB #include #else #include #endif AL_IGNORE_WARNING_END #include #include #include "texture.h" #include "log.h" using namespace Mauri; Texture::Texture(Asset *asset) { this->wrapped = false; //std::string_view type = asset->reads(9); //std::string_view itype = asset->reads(9); asset->seek(18); TextureFormat format = (TextureFormat)asset->read(); this->flags.i = asset->read(); //u32 texture_width = asset->read(); //u32 texture_height = asset->read(); asset->seek(8); this->width = asset->read(); this->height = asset->read(); asset->seek(4); std::string_view container = asset->reads(9); TextureVersion version; bool has_container = false; u32 image_count = asset->read(); if (container.compare(0, 8, "TEXB0003") == 0) { has_container = asset->read() != -1; version = TEXB0003; } else if (container.compare(0, 8, "TEXB0002") == 0) { version = TEXB0002; } //else if (container.compare(0, 8, "TEXB0001") == 0) else { version = TEXB0001; } this->textures.resize(image_count); this->texture_resolutions.resize(image_count); for (u32 s = 0; s < image_count; s++) { u32 mm_count = asset->read(); bool clamp = this->flags.m.CLAMP_UV == 1; bool no_interp = this->flags.m.NO_INTERPOLATION == 1; RenderTexture *texture = new RenderTexture(no_interp, clamp, true, mm_count); this->textures[s] = texture; this->texture_resolutions[s] = vec4{0.f, 0.f, this->width, this->height}; for (u32 i = 0; i < mm_count; i++) { u32 mm_width = asset->read(); u32 mm_height = asset->read(); bool lz4_compressed = false; u32 decompressed_byte_count = 0; if (version == TEXB0002 || version == TEXB0003) { lz4_compressed = asset->read() == 1; decompressed_byte_count = asset->read(); } u32 byte_count = asset->read(); if (!lz4_compressed) decompressed_byte_count = byte_count; byte *buffer = asset->ptr(); if (lz4_compressed) { char *decompressed = new char[decompressed_byte_count]; LZ4_decompress_safe((char *)buffer, decompressed, byte_count, decompressed_byte_count); buffer = (byte *)decompressed; } if (!has_container) { assert(buffer); switch (format) { case RGBA8888: texture->format = GL_RGBA; texture->upload(buffer, mm_width, mm_height, i); break; case DXT5: { warn("DXT5 texture"); u32 *decompressed = new u32[(mm_width + 3) * (mm_height + 3)]; BlockDecompressImageDXT5(mm_width, mm_height, buffer, decompressed); texture->format = GL_RGBA; texture->upload((byte *)decompressed, mm_width, mm_height, i, GL_UNSIGNED_INT_8_8_8_8); delete[] decompressed; break; } case DXT1: { warn("DXT1 texture"); u32 *decompressed = new u32[(mm_width + 3) * (mm_height + 3)]; BlockDecompressImageDXT1(mm_width, mm_height, buffer, decompressed); texture->format = GL_RGBA; texture->upload((byte *)decompressed, mm_width, mm_height, i, GL_UNSIGNED_INT_8_8_8_8); delete[] decompressed; break; } case DXT3: warn("DXT3 texture"); break; case RG88: texture->format = GL_RG; texture->upload(buffer, mm_width, mm_height, i); break; case R8: texture->format = GL_RED; texture->upload(buffer, mm_width, mm_height, i); break; default: warn("uknown texture format"); break; } if (i == 0) { this->textures[s]->width = mm_width; this->textures[s]->height = mm_height; } } else { s32 w, h, channels; byte *data = stbi_load_from_memory(buffer, byte_count, &w, &h, &channels, 0); assert(data); switch (channels) { case 1: texture->format = GL_RED; break; case 2: texture->format = GL_RG; break; case 3: texture->format = GL_RGB; break; case 4: default: texture->format = GL_RGBA; break; } texture->upload(data, w, h, i); stbi_image_free(data); if (i == 0) { this->textures[s]->width = w; this->textures[s]->height = h; } } if (lz4_compressed) delete[] buffer; asset->seek(byte_count); } this->texture_resolutions[s][0] = this->textures[s]->width; this->texture_resolutions[s][1] = this->textures[s]->height; } this->texture = this->textures[0]; this->texture_resolution = &this->texture_resolutions[0]; if (this->is_gif()) { std::string_view gif_container = asset->reads(9); u32 gif_frame_count = asset->read(); if (gif_container.compare(0, 8, "TEXS0002") == 0) {} else if (gif_container.compare(0, 8, "TEXS0003") == 0) { this->gif_width = asset->read(); this->gif_height = asset->read(); } this->frames.resize(gif_frame_count); for (u32 i = 0; i < gif_frame_count; i++) { this->frames[i] = TextureFrame{ asset->read(), asset->read(), asset->read(), asset->read(), asset->read(), asset->read(), asset->read(), asset->read(), }; } } asset->reset(); } Texture::Texture(RenderFramebuffer *buffer) { this->wrapped = true; this->texture = buffer->texture; this->width = buffer->width; this->height = buffer->height; this->texture->width = buffer->width; this->texture->height = buffer->height; this->texture_resolutions.resize(1); this->texture_resolutions[0][0] = buffer->width; this->texture_resolutions[0][1] = buffer->height; this->texture_resolutions[0][2] = buffer->width; this->texture_resolutions[0][3] = buffer->height; this->texture_resolution = &this->texture_resolutions[0]; } auto Texture::update(f32 time) -> void { if (!this->is_gif() || time < this->gif_update) return; TextureFrame *frame = &this->frames[this->gif_index]; this->texture = this->textures[frame->id]; this->texture_resolution = &this->texture_resolutions[frame->id]; // Scale texture cordinates to size of one frame. this->texture_rotation[0] = frame->width / (f32)this->texture->width; //this->texture_rotation[1] = 0.f; //this->texture_rotation[2] = 0.f; this->texture_rotation[1] = frame->unknown0 / (f32)this->texture->width; this->texture_rotation[2] = frame->unknown1 / (f32)this->texture->height; this->texture_rotation[3] = frame->height / (f32)this->texture->height; // Offset texture cordinates to the current frame // in the spritesheet. this->texture_translation[0] = frame->x / (f32)this->texture->width; this->texture_translation[1] = frame->y / (f32)this->texture->height; this->gif_index = (this->gif_index + 1) % this->frames.size(); this->gif_update = time + frame->frame_time; } auto Texture::bind(s32 index) -> void { this->texture->bind(index); } auto Texture::save_to_file(const std::string &filename) -> void { for (u32 i = 0; i < this->textures.size(); i++) { u32 width = this->textures[i]->width; u32 height = this->textures[i]->height; u32 *data = this->textures[i]->pixels.data(); stbi_write_png((filename + std::to_string(i)).c_str(), width, height, 4, data, 4 * width); } } Texture::~Texture() { if (!this->wrapped) delete this->texture; } Framebuffer::Framebuffer(std::string name, s32 width, s32 height, f32 scale) : name(name) { this->buffer = new RenderFramebuffer(width, height, scale); this->texture = new Texture(this->buffer); } Framebuffer::~Framebuffer() { if (this->buffer) delete this->buffer; if (this->texture) delete this->texture; }