156 lines
4.3 KiB
C++
156 lines
4.3 KiB
C++
|
|
#include <renderer/texture.h>
|
||
|
|
#include <utils/logger.h>
|
||
|
|
#include <glad/glad.h>
|
||
|
|
#define STB_IMAGE_IMPLEMENTATION
|
||
|
|
#include <stb/stb_image.h>
|
||
|
|
|
||
|
|
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
|