#include #include #include #define STB_IMAGE_IMPLEMENTATION #include namespace extra2d { // OpenGL 格式转换函数 static GLint getTextureInternalFormat(TextureFormat format) { switch (format) { case TextureFormat::RGBA8: return GL_RGBA8; case TextureFormat::RGB8: return GL_RGB8; case TextureFormat::RGBA4: return GL_RGBA4; case TextureFormat::R8: return GL_R8; case TextureFormat::RG8: return GL_RG8; default: return GL_RGBA8; } } static GLenum getTextureFormat(TextureFormat format) { switch (format) { case TextureFormat::RGBA8: case TextureFormat::RGBA4: return GL_RGBA; case TextureFormat::RGB8: return GL_RGB; case TextureFormat::R8: return GL_RED; case TextureFormat::RG8: return GL_RG; default: return GL_RGBA; } } Texture::Texture() = default; Texture::~Texture() { if (texture_ != 0) { glDeleteTextures(1, &texture_); texture_ = 0; } } bool Texture::loadFromFile(const std::string& path) { // 加载图片 int channels; stbi_set_flip_vertically_on_load(true); unsigned char* data = stbi_load(path.c_str(), &width_, &height_, &channels, 0); if (!data) { E2D_LOG_ERROR("Failed to load texture: {}", path); return false; } // 根据通道数确定格式 TextureFormat format; switch (channels) { case 1: format = TextureFormat::R8; break; case 2: format = TextureFormat::RG8; break; case 3: format = TextureFormat::RGB8; break; case 4: format = TextureFormat::RGBA8; break; default: format = TextureFormat::RGBA8; break; } bool result = loadFromMemory(data, width_, height_, format); stbi_image_free(data); if (result) { E2D_LOG_DEBUG("Texture loaded: {} ({}x{})", path, width_, height_); } return result; } bool Texture::loadFromMemory(const uint8_t* data, int width, int height, TextureFormat format) { if (texture_ != 0) { glDeleteTextures(1, &texture_); texture_ = 0; } width_ = width; height_ = height; format_ = format; // 创建纹理 glGenTextures(1, &texture_); glBindTexture(GL_TEXTURE_2D, texture_); // 设置纹理参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 上传纹理数据 glTexImage2D(GL_TEXTURE_2D, 0, getTextureInternalFormat(format_), width_, height_, 0, getTextureFormat(format_), GL_UNSIGNED_BYTE, data); // 生成 mipmap glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); return true; } bool Texture::create(int width, int height, TextureFormat format) { if (texture_ != 0) { glDeleteTextures(1, &texture_); texture_ = 0; } width_ = width; height_ = height; format_ = format; // 创建纹理 glGenTextures(1, &texture_); glBindTexture(GL_TEXTURE_2D, texture_); // 设置纹理参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 分配纹理存储(无数据) glTexImage2D(GL_TEXTURE_2D, 0, getTextureInternalFormat(format_), width_, height_, 0, getTextureFormat(format_), GL_UNSIGNED_BYTE, nullptr); glBindTexture(GL_TEXTURE_2D, 0); return true; } void Texture::bind(uint32_t slot) const { if (texture_ != 0) { glActiveTexture(GL_TEXTURE0 + slot); glBindTexture(GL_TEXTURE_2D, texture_); } } void Texture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } } // namespace extra2d