Extra2D/src/renderer/texture.cpp

232 lines
6.3 KiB
C++
Raw Normal View History

#include <renderer/texture.h>
#include <renderer/rhi_module.h>
#include <utils/logger.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
namespace extra2d {
Texture::Texture() = default;
Texture::~Texture() {
// RHI 纹理句柄是轻量级句柄,不需要显式释放
// 实际的纹理资源由 RHI 设备管理
handle_ = TextureHandle();
}
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) {
// 释放旧纹理
handle_ = TextureHandle();
width_ = width;
height_ = height;
format_ = format;
// 获取 RHI 设备
auto* rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return false;
}
auto* device = rhiModule->getDevice();
if (!device) {
E2D_LOG_ERROR("RHIDevice not available");
return false;
}
// 创建纹理描述
TextureDesc desc;
desc.width = static_cast<uint32_t>(width);
desc.height = static_cast<uint32_t>(height);
desc.format = format;
desc.mipLevels = 1; // 初始创建 1 层,后续生成 mipmap
// 创建 RHI 纹理
auto texture = device->createTexture(desc);
if (!texture) {
E2D_LOG_ERROR("Failed to create RHI texture");
return false;
}
// 上传纹理数据
if (data) {
// 注意update 方法的参数需要根据实际 RHI 接口调整
// 这里假设 update 接受数据指针
texture->update(data, static_cast<size_t>(width * height * getBytesPerPixel(format)));
// 生成 mipmap
// 注意generateMipmap 方法需要在 RHI 接口中实现
}
// 获取纹理句柄
handle_ = TextureHandle(texture.release());
return true;
}
bool Texture::create(int width, int height, TextureFormat format) {
// 释放旧纹理
handle_ = TextureHandle();
width_ = width;
height_ = height;
format_ = format;
// 获取 RHI 设备
auto* rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return false;
}
auto* device = rhiModule->getDevice();
if (!device) {
E2D_LOG_ERROR("RHIDevice not available");
return false;
}
// 创建纹理描述
TextureDesc desc;
desc.width = static_cast<uint32_t>(width);
desc.height = static_cast<uint32_t>(height);
desc.format = format;
desc.mipLevels = 1; // 不生成 mipmap
// 创建 RHI 纹理
auto texture = device->createTexture(desc);
if (!texture) {
E2D_LOG_ERROR("Failed to create RHI texture");
return false;
}
// 获取纹理句柄
handle_ = TextureHandle(texture.release());
return true;
}
bool Texture::reloadFromFile(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 reload 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 = reloadFromMemory(data, width_, height_, format);
stbi_image_free(data);
if (result) {
E2D_LOG_INFO("Texture reloaded: {} ({}x{})", path, width_, height_);
}
return result;
}
bool Texture::reloadFromMemory(const uint8_t* data, int width, int height, TextureFormat format) {
// 更新尺寸和格式
width_ = width;
height_ = height;
format_ = format;
// 获取 RHI 设备
auto* rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHIModule not available");
return false;
}
auto* device = rhiModule->getDevice();
if (!device) {
E2D_LOG_ERROR("RHIDevice not available");
return false;
}
// 创建新的纹理描述
TextureDesc desc;
desc.width = static_cast<uint32_t>(width);
desc.height = static_cast<uint32_t>(height);
desc.format = format;
desc.mipLevels = 1;
// 创建新的 RHI 纹理
auto texture = device->createTexture(desc);
if (!texture) {
E2D_LOG_ERROR("Failed to create RHI texture during reload");
return false;
}
// 上传纹理数据
if (data) {
texture->update(data, static_cast<size_t>(width * height * getBytesPerPixel(format)));
}
// 替换旧的纹理句柄
handle_ = TextureHandle(texture.release());
return true;
}
// 辅助函数:获取每个像素的字节数
uint32_t Texture::getBytesPerPixel(TextureFormat format) {
switch (format) {
case TextureFormat::R8: return 1;
case TextureFormat::RG8: return 2;
case TextureFormat::RGB8: return 3;
case TextureFormat::RGBA8:
case TextureFormat::RGBA8_SRGB: return 4;
case TextureFormat::Depth16: return 2;
case TextureFormat::Depth24: return 3;
case TextureFormat::Depth32F: return 4;
case TextureFormat::Depth24Stencil8: return 4;
case TextureFormat::Depth32FStencil8: return 5;
default: return 4;
}
}
} // namespace extra2d