/******************************************************************************
*	File		-	frame_buffer.h
*	Author		-	Joey Pollack
*	Date		-	2022/07/13 (y/m/d)
*	Mod Date	-	2022/07/13 (y/m/d)
*	Description	-	OpenGL Frame buffer object
******************************************************************************/

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

namespace lunarium
{
    FrameBuffer::FrameBuffer()
        : mGLID(0), mTexture(nullptr), mRenderBufferID(0)
    {

    }

    FrameBuffer* FrameBuffer::Create(int width, int height)
    {
		FrameBuffer* fb = new FrameBuffer;
        fb->Resize(width, height);
        return fb;
    }
    
    void FrameBuffer::Destroy(FrameBuffer** ppBuf)
    {
        (*ppBuf)->Unbind();
        glDeleteFramebuffers(1, &(*ppBuf)->mGLID);
        (*ppBuf) = nullptr;
    }
    

    void FrameBuffer::Resize(int width, int height)
    {
        if (mGLID != 0)
        {
		    glDeleteFramebuffers(1, &mGLID);
        }

        if (mTexture)
        {
            Texture::Destroy(&mTexture);
        }

        mTexture = Texture::Create(nullptr, width, height);

        glGenFramebuffers(1, &mGLID);
        Bind();

		// Attach texture
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture->GetGLID(), 0);

        // Render Buffer for depth/stencil testing
        if (mRenderBufferID)
        {
            glDeleteRenderbuffers(1, &mRenderBufferID);
        }
		glGenRenderbuffers(1, &mRenderBufferID);
		glBindRenderbuffer(GL_RENDERBUFFER, mRenderBufferID);
		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
		glBindRenderbuffer(GL_RENDERBUFFER, 0);

		// Atach the render buffer
		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mRenderBufferID);

        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
		{
			Logger::Error(LogCategory::GRAPHICS, "Failed to create FrameBuffer object");
			glBindFramebuffer(GL_FRAMEBUFFER, 0);
		}

        Unbind();
    }
    
    void FrameBuffer::Bind()
    {
        glBindFramebuffer(GL_FRAMEBUFFER, mGLID);
        glViewport(0, 0, mTexture->GetWidth(), mTexture->GetHeight());
    }
    
    void FrameBuffer::Unbind()
    {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
    
    Texture* FrameBuffer::GetTexture()
    {
        return mTexture;
    }

}