Extra2D/src/renderer/texture.cpp

232 lines
6.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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