#include "texture.hpp"
#include <png.h>
#include <cstring>
#include "../render.h"
#include "gpuMemory.hpp"


namespace render::kernel
{

Texture::Texture(const char *path)
{
    this->Load(path);
}

Texture::~Texture()
{
    delete this->buffer;
}

void Texture::BindVertex(unsigned int slot)
{
    sceGxmSetVertexTexture(render::GetContext(), slot, &this->texture);
}

void Texture::BindFragment(unsigned int slot) const
{
    sceGxmSetFragmentTexture(render::GetContext(), slot, &this->texture);
}

void Texture::Load(const char *path)
{
    unsigned char header[8];
    FILE *texFile = fopen(path, "rb");
    fread(header, 1, 8, texFile);

    png_sig_cmp(header, 0, 8);

    png_structp img = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);

    png_infop img_info = png_create_info_struct(img);

    setjmp(png_jmpbuf(img));

    png_init_io(img, texFile);
    png_set_sig_bytes(img, 8);

    png_read_info(img, img_info);

    long width = png_get_image_width(img, img_info);
    long height = png_get_image_height(img, img_info);
    int color = png_get_color_type(img, img_info);

    SceGxmTextureFormat format;
    int size;

    switch (color) {
    case PNG_COLOR_TYPE_RGB:
        size = 3;
        format = SCE_GXM_TEXTURE_FORMAT_U8U8U8_BGR;
        break;
    case PNG_COLOR_TYPE_RGBA:
        size = 4;
        format = SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ABGR;
        break;
    default:
        break;
        // i dunno
    }

    this->buffer = new GpuBuffer(
        SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW,
        SCE_GXM_MEMORY_ATTRIB_RW,
        width * height * size);

    for(int i = 0; i < height; i++) {
        png_read_row(img, (png_bytep)(this->buffer->data + i * ALIGN(width, 4) * size), nullptr);
    }

    png_destroy_read_struct(&img, &img_info, nullptr);

    fclose(texFile);

    sceGxmTextureInitLinear(&this->texture, this->buffer->data, format, width, height, 1);
}

} // namespace render::kernel
