#include "NativeRendererSupport.h" #include #include #include namespace XCEngine::UI::Editor::Host { using namespace NativeRendererSupport; bool NativeRenderer::LoadTextureFromFile( const std::filesystem::path& path, ::XCEngine::UI::UITextureHandle& outTexture, std::string& outError) { outError.clear(); ReleaseTexture(outTexture); auto texture = std::make_unique(); if (!DecodeTextureFile(path, *texture, outError)) { outTexture = {}; return false; } outTexture.nativeHandle = reinterpret_cast(texture.get()); outTexture.width = texture->width; outTexture.height = texture->height; outTexture.kind = ::XCEngine::UI::UITextureHandleKind::DescriptorHandle; m_liveTextures.insert(texture.get()); texture.release(); return true; } bool NativeRenderer::LoadTextureFromMemory( const std::uint8_t* data, std::size_t size, ::XCEngine::UI::UITextureHandle& outTexture, std::string& outError) { outError.clear(); ReleaseTexture(outTexture); auto texture = std::make_unique(); if (!DecodeTextureMemory(data, size, *texture, outError)) { outTexture = {}; return false; } outTexture.nativeHandle = reinterpret_cast(texture.get()); outTexture.width = texture->width; outTexture.height = texture->height; outTexture.kind = ::XCEngine::UI::UITextureHandleKind::DescriptorHandle; m_liveTextures.insert(texture.get()); texture.release(); return true; } void NativeRenderer::ReleaseTexture(::XCEngine::UI::UITextureHandle& texture) { if (!texture.IsValid()) { texture = {}; return; } auto* resource = reinterpret_cast(texture.nativeHandle); if (resource != nullptr) { const auto found = m_liveTextures.find(resource); if (found != m_liveTextures.end()) { m_liveTextures.erase(found); delete resource; } } texture = {}; } 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 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 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::numeric_limits::max)())) { outError = "DecodeTextureMemory payload exceeds WIC stream limits."; return false; } if (!EnsureWicFactory(outError)) { return false; } Microsoft::WRL::ComPtr stream; HRESULT hr = m_wicFactory->CreateStream(stream.ReleaseAndGetAddressOf()); if (FAILED(hr) || !stream) { outError = HrToString("IWICImagingFactory::CreateStream", hr); return false; } hr = stream->InitializeFromMemory( const_cast(reinterpret_cast(data)), static_cast(size)); if (FAILED(hr)) { outError = HrToString("IWICStream::InitializeFromMemory", hr); return false; } Microsoft::WRL::ComPtr 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 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 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 pixels( static_cast(width) * static_cast(height) * 4u); hr = converter->CopyPixels( nullptr, width * 4u, static_cast(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; } bool NativeRenderer::ResolveTextureBitmap( ID2D1RenderTarget& renderTarget, NativeTextureResource& texture, Microsoft::WRL::ComPtr& outBitmap) { outBitmap.Reset(); if (texture.width == 0u || texture.height == 0u || texture.pixels.empty()) { return false; } if (texture.cachedBitmap && texture.cachedTarget == &renderTarget) { outBitmap = texture.cachedBitmap; return true; } Microsoft::WRL::ComPtr bitmap; const D2D1_BITMAP_PROPERTIES properties = D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), kBaseDpi, kBaseDpi); const HRESULT hr = renderTarget.CreateBitmap( D2D1::SizeU(texture.width, texture.height), texture.pixels.data(), texture.width * 4u, &properties, bitmap.ReleaseAndGetAddressOf()); if (FAILED(hr) || !bitmap) { return false; } if (&renderTarget == m_renderTarget.Get()) { texture.cachedBitmap = bitmap; texture.cachedTarget = &renderTarget; } outBitmap = std::move(bitmap); return true; } bool NativeRenderer::ResolveInteropBitmap( const ::XCEngine::UI::UITextureHandle& texture, Microsoft::WRL::ComPtr& outBitmap) const { return m_windowInterop.ResolveInteropBitmap(texture, outBitmap); } } // namespace XCEngine::UI::Editor::Host