text: #include "pbpch.h"
  #include "Target/RenderAPI/OpenGL/OpenGLTexture.h"
  
  #include <glad/gl.h>
  #include <stb_image.h>
  
  namespace Parabol {
  
      OpenGLTexture2D::OpenGLTexture2D(uint32_t width, uint32_t height) : m_Width(width), m_Height(height) {
          PB_PROFILE_FUNCTION();
  
          m_InternalFormat = GL_RGBA8;
          m_DataFormat = GL_RGBA;
  
          glCreateTextures(GL_TEXTURE_2D, 1, &m_ProgramID);
          glTextureStorage2D(m_ProgramID, 1, m_InternalFormat, m_Width, m_Height);
  
          glTextureParameteri(m_ProgramID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTextureParameteri(m_ProgramID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  
          glTextureParameteri(m_ProgramID, GL_TEXTURE_WRAP_S, GL_REPEAT);
          glTextureParameteri(m_ProgramID, GL_TEXTURE_WRAP_T, GL_REPEAT);
      }
  
      OpenGLTexture2D::OpenGLTexture2D(const std::string& path) : m_Path(path) {
          PB_PROFILE_FUNCTION();
  
          int width, height, channels;
          stbi_set_flip_vertically_on_load(1);
          stbi_uc* data = nullptr;
          {
              PB_PROFILE_SCOPE("stbi_load - OpenGLTexture2D::OpenGLTexture2D(const std::string&)");
              data = stbi_load(m_Path.c_str(), &width, &height, &channels, 0);
          }
  
          if (stbi_failure_reason())
              PB_LOG_ERROR("Error: stbi_image ({0})", stbi_failure_reason());
  
          PB_CORE_ASSERT(data, "Failed to load image!");
  
          m_Width = width;
          m_Height = height;
  
          GLenum internalFormat = 0, dataFormat = 0;
  
          if (channels == 4) {
              internalFormat = GL_RGBA8;
              dataFormat = GL_RGBA;
          } else if (channels == 3) {
              internalFormat = GL_RGB8;
              dataFormat = GL_RGB;
          }
  
          m_InternalFormat = internalFormat;
          m_DataFormat = dataFormat;
  
          PB_CORE_ASSERT(internalFormat & dataFormat, "Texture2D format not supported!");
  
          glCreateTextures(GL_TEXTURE_2D, 1, &m_ProgramID);
          glTextureStorage2D(m_ProgramID, 1, internalFormat, m_Width, m_Height);
  
          glTextureParameteri(m_ProgramID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
          glTextureParameteri(m_ProgramID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  
          glTextureParameteri(m_ProgramID, GL_TEXTURE_WRAP_S, GL_REPEAT);
          glTextureParameteri(m_ProgramID, GL_TEXTURE_WRAP_T, GL_REPEAT);
  
          glTextureSubImage2D(m_ProgramID, 0, 0, 0, m_Width, m_Height, dataFormat, GL_UNSIGNED_BYTE, data);
          stbi_image_free(data);
      }
  
      OpenGLTexture2D::~OpenGLTexture2D() {
          PB_PROFILE_FUNCTION();
  
          glDeleteTextures(1, &m_ProgramID);
      }
  
      void OpenGLTexture2D::SetData(void* data, uint32_t size) {
          PB_PROFILE_FUNCTION();
  
          uint32_t bytesPerPixel = m_DataFormat == GL_RGBA ? 4 : 3;
          PB_CORE_ASSERT(size == m_Width * m_Height * bytesPerPixel, "Data must be entire texture!");
          glTextureSubImage2D(m_ProgramID, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, data);
      }
  
      void OpenGLTexture2D::Bind(uint32_t slot) const {
          PB_PROFILE_FUNCTION();
  
          glBindTextureUnit(slot, m_ProgramID);
      }
  }
  