#include "pch.h" #include "TextureLoader.h" #include #include "DeviceResources.h" #include "App.h" #include "Logger.h" winrt::com_ptr LoadImg(const wchar_t* fileName) { winrt::com_ptr factory = App::Get().GetWICImageFactory(); if (!factory) { Logger::Get().Error("GetWICImageFactory 失败"); return nullptr; } // 读取图像文件 winrt::com_ptr decoder; HRESULT hr = factory->CreateDecoderFromFilename(fileName, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.put()); if (FAILED(hr)) { Logger::Get().ComError("CreateDecoderFromFilename 失败", hr); return nullptr; } winrt::com_ptr frame; hr = decoder->GetFrame(0, frame.put()); if (FAILED(hr)) { Logger::Get().ComError("IWICBitmapFrameDecode::GetFrame 失败", hr); return nullptr; } bool useFloatFormat = false; { WICPixelFormatGUID sourceFormat; hr = frame->GetPixelFormat(&sourceFormat); if (FAILED(hr)) { Logger::Get().ComError("GetPixelFormat 失败", hr); return nullptr; } winrt::com_ptr cInfo; hr = factory->CreateComponentInfo(sourceFormat, cInfo.put()); if (FAILED(hr)) { Logger::Get().ComError("CreateComponentInfo", hr); return nullptr; } winrt::com_ptr formatInfo = cInfo.try_as(); if (!formatInfo) { Logger::Get().Error("IWICComponentInfo 转换为 IWICPixelFormatInfo2 时失败"); return nullptr; } UINT bitsPerPixel; WICPixelFormatNumericRepresentation type; hr = formatInfo->GetBitsPerPixel(&bitsPerPixel); if (FAILED(hr)) { Logger::Get().ComError("GetBitsPerPixel", hr); return nullptr; } hr = formatInfo->GetNumericRepresentation(&type); if (FAILED(hr)) { Logger::Get().ComError("GetNumericRepresentation", hr); return nullptr; } useFloatFormat = bitsPerPixel > 32 || type == WICPixelFormatNumericRepresentationFixed || type == WICPixelFormatNumericRepresentationFloat; } // 转换格式 winrt::com_ptr formatConverter; hr = factory->CreateFormatConverter(formatConverter.put()); if (FAILED(hr)) { Logger::Get().ComError("CreateFormatConverter 失败", hr); return nullptr; } WICPixelFormatGUID targetFormat = useFloatFormat ? GUID_WICPixelFormat64bppRGBAHalf : GUID_WICPixelFormat32bppBGRA; hr = formatConverter->Initialize(frame.get(), targetFormat, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeCustom); if (FAILED(hr)) { Logger::Get().ComError("IWICFormatConverter::Initialize 失败", hr); return nullptr; } // 检查 D3D 纹理尺寸限制 UINT width, height; hr = formatConverter->GetSize(&width, &height); if (FAILED(hr)) { Logger::Get().ComError("GetSize 失败", hr); return nullptr; } if (width > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION || height > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION) { Logger::Get().Error("图像尺寸超出限制"); return nullptr; } UINT stride = width * (useFloatFormat ? 8 : 4); UINT size = stride * height; std::unique_ptr buf(new BYTE[size]); hr = formatConverter->CopyPixels(nullptr, stride, size, buf.get()); if (FAILED(hr)) { Logger::Get().ComError("CopyPixels 失败", hr); return nullptr; } D3D11_TEXTURE2D_DESC desc{}; desc.Width = width; desc.Height = height; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = useFloatFormat ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_B8G8R8A8_UNORM; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; D3D11_SUBRESOURCE_DATA initData{}; initData.pSysMem = buf.get(); initData.SysMemPitch = stride; winrt::com_ptr result; hr = App::Get().GetDeviceResources().GetD3DDevice()->CreateTexture2D(&desc, &initData, result.put()); if (FAILED(hr)) { Logger::Get().ComError("CreateTexture2D 失败", hr); return nullptr; } return result; } winrt::com_ptr LoadDDS(const wchar_t* fileName) { winrt::com_ptr result; DirectX::DDS_ALPHA_MODE alphaMode = DirectX::DDS_ALPHA_MODE_STRAIGHT; HRESULT hr = DirectX::CreateDDSTextureFromFileEx( App::Get().GetDeviceResources().GetD3DDevice(), fileName, 0, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, 0, 0, false, result.put(), nullptr, &alphaMode ); if (FAILED(hr)) { Logger::Get().ComInfo("CreateDDSTextureFromFile 失败,将尝试不作为渲染目标", hr); // 第二次尝试,不作为渲染目标 hr = DirectX::CreateDDSTextureFromFileEx( App::Get().GetDeviceResources().GetD3DDevice(), fileName, 0, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, false, result.put(), nullptr, &alphaMode ); if (FAILED(hr)) { Logger::Get().ComError("CreateDDSTextureFromFile 失败", hr); return nullptr; } } winrt::com_ptr tex = result.try_as(); if (!tex) { Logger::Get().Error("从 ID3D11Resource 获取 ID3D11Texture2D 失败"); return nullptr; } return tex; } winrt::com_ptr TextureLoader::Load(const wchar_t* fileName) { std::wstring_view sv(fileName); size_t npos = sv.find_last_of(L'.'); if (npos == std::wstring_view::npos) { Logger::Get().Error("文件名无后缀名"); return nullptr; } std::wstring_view suffix = sv.substr(npos + 1); static std::unordered_map(*)(const wchar_t*)> funcs = { {L"bmp", LoadImg}, {L"jpg", LoadImg}, {L"jpeg", LoadImg}, {L"png", LoadImg}, {L"tif", LoadImg}, {L"tiff", LoadImg}, {L"dds", LoadDDS} }; auto it = funcs.find(suffix); if (it == funcs.end()) { Logger::Get().Error("不支持读取该格式"); return nullptr; } return it->second(fileName); }