/******************************************************************************
*	File		-	texture.h
*	Author		-	Joey Pollack
*	Date		-	2022/07/14 (y/m/d)
*	Mod Date	-	2022/07/14 (y/m/d)
*	Description	-	OpenGL texture 2D
******************************************************************************/

#include "texture.h"
#include <glad/gl.h>
#include <utils/logger.h>

namespace lunarium
{
    Texture::Texture()
        : mGLID(0), mWidth(0), mHeight(0), mFormat(TextureFormat::RGBA)
    {

    }

    Texture* Texture::Create(u8* data, u32 width, u32 height, TextureFormat format)
    {
        if (((i32)width) < 1 || ((i32)height) < 1)
        {
            Logger::Error(LogCategory::GRAPHICS, "Failed to create texture, width and/or height values invalid: %d, %d", width, height);
            return nullptr;
        }

        u32 formats[2] = { GL_RGB, GL_RGBA };
        Texture* t = new Texture();

        t->mFormat = format;
        t->mWidth = width;
        t->mHeight = height;

        glCreateTextures(GL_TEXTURE_2D, 1, &t->mGLID);
        t->Bind();
        
        glTexImage2D(GL_TEXTURE_2D, 0, formats[(int)format], width, height, 0, formats[(int)format], GL_UNSIGNED_BYTE, data);
        int error = glGetError();
        if (error > 0)
        {
            Logger::Error(LogCategory::GRAPHICS, "Error setting texture data");
        }


        glGenerateMipmap(GL_TEXTURE_2D);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        t->Unbind();
        return t;
    }
    
    void Texture::Destroy(Texture** ppTex)
    {
        (*ppTex)->Unbind();
        glDeleteTextures(1, &(*ppTex)->mGLID);
        (*ppTex) = nullptr;
    }
    

    void Texture::Bind(u32 slot) const
    {
       // glBindTextureUnit(slot, mGLID); 
        glActiveTexture(slot + GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, mGLID);
    }
    
    void Texture::Unbind() const
    {
        glBindTexture(GL_TEXTURE_2D, 0); 
    }
    

    u32 Texture::GetGLID() const
    {
        return mGLID;
    }
    
    u64 Texture::GetGLID64() const
    {
        return (u64) mGLID;
    }

    TextureFormat Texture::GetFormat() const
    {
        return mFormat;
    }

    u32 Texture::GetWidth() const
    {
        return mWidth;
    }

    u32 Texture::GetHeight() const
    {
        return mHeight;
    }

    
    u8* Texture::GetPixels() const
    {
        u32 format_size[2] = { 3, 4 };
        u32 formats[2] = { GL_RGB, GL_RGBA };
        u8* buffer = new u8[mWidth * mHeight * format_size[(int)mFormat]];

        Bind();
        glGetTexImage(GL_TEXTURE_2D, 0, formats[(int)mFormat], GL_UNSIGNED_BYTE, (void*)buffer);
        Unbind();

        return buffer;
    }

}