2026-04-15 22:47:42 +08:00
|
|
|
#include "NativeRendererInternal.h"
|
2026-04-15 08:45:04 +08:00
|
|
|
|
|
|
|
|
#include <limits>
|
|
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::Host {
|
|
|
|
|
|
2026-04-15 22:47:42 +08:00
|
|
|
using namespace NativeRendererInternal;
|
2026-04-15 08:45:04 +08:00
|
|
|
|
|
|
|
|
bool NativeRenderer::DecodeTextureFile(
|
|
|
|
|
const std::filesystem::path& path,
|
|
|
|
|
NativeTextureResource& outTexture,
|
|
|
|
|
std::string& outError) {
|
|
|
|
|
outError.clear();
|
|
|
|
|
if (!EnsureWicFactory(outError)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::wstring widePath = path.wstring();
|
|
|
|
|
Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
|
|
|
|
|
HRESULT hr = m_wicFactory->CreateDecoderFromFilename(
|
|
|
|
|
widePath.c_str(),
|
|
|
|
|
nullptr,
|
|
|
|
|
GENERIC_READ,
|
|
|
|
|
WICDecodeMetadataCacheOnLoad,
|
|
|
|
|
decoder.ReleaseAndGetAddressOf());
|
|
|
|
|
if (FAILED(hr) || !decoder) {
|
|
|
|
|
outError = HrToString("IWICImagingFactory::CreateDecoderFromFilename", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> frame;
|
|
|
|
|
hr = decoder->GetFrame(0u, frame.ReleaseAndGetAddressOf());
|
|
|
|
|
if (FAILED(hr) || !frame) {
|
|
|
|
|
outError = HrToString("IWICBitmapDecoder::GetFrame", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DecodeTextureFrame(*frame.Get(), outTexture, outError);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NativeRenderer::DecodeTextureMemory(
|
|
|
|
|
const std::uint8_t* data,
|
|
|
|
|
std::size_t size,
|
|
|
|
|
NativeTextureResource& outTexture,
|
|
|
|
|
std::string& outError) {
|
|
|
|
|
outError.clear();
|
|
|
|
|
if (data == nullptr || size == 0u) {
|
|
|
|
|
outError = "DecodeTextureMemory rejected an empty image payload.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (size > static_cast<std::size_t>((std::numeric_limits<DWORD>::max)())) {
|
|
|
|
|
outError = "DecodeTextureMemory payload exceeds WIC stream limits.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!EnsureWicFactory(outError)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Microsoft::WRL::ComPtr<IWICStream> stream;
|
|
|
|
|
HRESULT hr = m_wicFactory->CreateStream(stream.ReleaseAndGetAddressOf());
|
|
|
|
|
if (FAILED(hr) || !stream) {
|
|
|
|
|
outError = HrToString("IWICImagingFactory::CreateStream", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hr = stream->InitializeFromMemory(
|
|
|
|
|
const_cast<BYTE*>(reinterpret_cast<const BYTE*>(data)),
|
|
|
|
|
static_cast<DWORD>(size));
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
outError = HrToString("IWICStream::InitializeFromMemory", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
|
|
|
|
|
hr = m_wicFactory->CreateDecoderFromStream(
|
|
|
|
|
stream.Get(),
|
|
|
|
|
nullptr,
|
|
|
|
|
WICDecodeMetadataCacheOnLoad,
|
|
|
|
|
decoder.ReleaseAndGetAddressOf());
|
|
|
|
|
if (FAILED(hr) || !decoder) {
|
|
|
|
|
outError = HrToString("IWICImagingFactory::CreateDecoderFromStream", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> frame;
|
|
|
|
|
hr = decoder->GetFrame(0u, frame.ReleaseAndGetAddressOf());
|
|
|
|
|
if (FAILED(hr) || !frame) {
|
|
|
|
|
outError = HrToString("IWICBitmapDecoder::GetFrame", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DecodeTextureFrame(*frame.Get(), outTexture, outError);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NativeRenderer::DecodeTextureFrame(
|
|
|
|
|
IWICBitmapSource& source,
|
|
|
|
|
NativeTextureResource& outTexture,
|
|
|
|
|
std::string& outError) {
|
|
|
|
|
outError.clear();
|
|
|
|
|
|
|
|
|
|
Microsoft::WRL::ComPtr<IWICFormatConverter> converter;
|
|
|
|
|
HRESULT hr = m_wicFactory->CreateFormatConverter(converter.ReleaseAndGetAddressOf());
|
|
|
|
|
if (FAILED(hr) || !converter) {
|
|
|
|
|
outError = HrToString("IWICImagingFactory::CreateFormatConverter", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hr = converter->Initialize(
|
|
|
|
|
&source,
|
|
|
|
|
GUID_WICPixelFormat32bppPBGRA,
|
|
|
|
|
WICBitmapDitherTypeNone,
|
|
|
|
|
nullptr,
|
|
|
|
|
0.0f,
|
|
|
|
|
WICBitmapPaletteTypeCustom);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
outError = HrToString("IWICFormatConverter::Initialize", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UINT width = 0u;
|
|
|
|
|
UINT height = 0u;
|
|
|
|
|
hr = converter->GetSize(&width, &height);
|
|
|
|
|
if (FAILED(hr) || width == 0u || height == 0u) {
|
|
|
|
|
outError = HrToString("IWICBitmapSource::GetSize", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::uint8_t> pixels(
|
|
|
|
|
static_cast<std::size_t>(width) * static_cast<std::size_t>(height) * 4u);
|
|
|
|
|
hr = converter->CopyPixels(
|
|
|
|
|
nullptr,
|
|
|
|
|
width * 4u,
|
|
|
|
|
static_cast<UINT>(pixels.size()),
|
|
|
|
|
pixels.data());
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
outError = HrToString("IWICBitmapSource::CopyPixels", hr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outTexture.pixels = std::move(pixels);
|
|
|
|
|
outTexture.width = width;
|
|
|
|
|
outTexture.height = height;
|
|
|
|
|
outTexture.cachedBitmap.Reset();
|
|
|
|
|
outTexture.cachedTarget = nullptr;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::Host
|