2026-04-15 22:47:42 +08:00
|
|
|
#include "NativeRendererInternal.h"
|
2026-04-15 08:24:06 +08:00
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::Host {
|
|
|
|
|
|
2026-04-15 22:47:42 +08:00
|
|
|
using namespace NativeRendererInternal;
|
2026-04-15 08:24:06 +08:00
|
|
|
|
|
|
|
|
bool NativeRenderer::Initialize(HWND hwnd) {
|
|
|
|
|
Shutdown();
|
|
|
|
|
|
|
|
|
|
if (hwnd == nullptr) {
|
|
|
|
|
m_lastRenderError = "Initialize rejected a null hwnd.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_hwnd = hwnd;
|
|
|
|
|
D2D1_FACTORY_OPTIONS factoryOptions = {};
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
factoryOptions.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
|
|
|
|
|
#endif
|
|
|
|
|
HRESULT hr = D2D1CreateFactory(
|
|
|
|
|
D2D1_FACTORY_TYPE_SINGLE_THREADED,
|
|
|
|
|
__uuidof(ID2D1Factory1),
|
|
|
|
|
&factoryOptions,
|
|
|
|
|
reinterpret_cast<void**>(m_d2dFactory.ReleaseAndGetAddressOf()));
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
m_lastRenderError = HrToString("D2D1CreateFactory", hr);
|
|
|
|
|
Shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hr = DWriteCreateFactory(
|
|
|
|
|
DWRITE_FACTORY_TYPE_SHARED,
|
|
|
|
|
__uuidof(IDWriteFactory),
|
|
|
|
|
reinterpret_cast<IUnknown**>(m_dwriteFactory.ReleaseAndGetAddressOf()));
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
m_lastRenderError = HrToString("DWriteCreateFactory", hr);
|
|
|
|
|
Shutdown();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_lastRenderError.clear();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NativeRenderer::Shutdown() {
|
|
|
|
|
DetachWindowRenderer();
|
|
|
|
|
while (!m_liveTextures.empty()) {
|
|
|
|
|
auto it = m_liveTextures.begin();
|
|
|
|
|
delete *it;
|
|
|
|
|
m_liveTextures.erase(it);
|
|
|
|
|
}
|
|
|
|
|
m_textFormats.clear();
|
|
|
|
|
m_solidBrush.Reset();
|
|
|
|
|
m_renderTarget.Reset();
|
|
|
|
|
m_wicFactory.Reset();
|
|
|
|
|
m_dwriteFactory.Reset();
|
|
|
|
|
m_d2dFactory.Reset();
|
|
|
|
|
if (m_wicComInitialized) {
|
|
|
|
|
CoUninitialize();
|
|
|
|
|
m_wicComInitialized = false;
|
|
|
|
|
}
|
|
|
|
|
m_hwnd = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NativeRenderer::SetDpiScale(float dpiScale) {
|
|
|
|
|
m_dpiScale = ClampDpiScale(dpiScale);
|
|
|
|
|
if (m_renderTarget) {
|
|
|
|
|
m_renderTarget->SetDpi(kBaseDpi, kBaseDpi);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float NativeRenderer::GetDpiScale() const {
|
|
|
|
|
return m_dpiScale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string& NativeRenderer::GetLastRenderError() const {
|
|
|
|
|
return m_lastRenderError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NativeRenderer::EnsureWicFactory(std::string& outError) {
|
|
|
|
|
outError.clear();
|
|
|
|
|
if (m_wicFactory) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const HRESULT initHr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
|
|
|
if (FAILED(initHr) && initHr != RPC_E_CHANGED_MODE) {
|
|
|
|
|
outError = HrToString("CoInitializeEx", initHr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (SUCCEEDED(initHr)) {
|
|
|
|
|
m_wicComInitialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const HRESULT factoryHr = CoCreateInstance(
|
|
|
|
|
CLSID_WICImagingFactory,
|
|
|
|
|
nullptr,
|
|
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
|
IID_PPV_ARGS(m_wicFactory.ReleaseAndGetAddressOf()));
|
|
|
|
|
if (FAILED(factoryHr)) {
|
|
|
|
|
outError = HrToString("CoCreateInstance(CLSID_WICImagingFactory)", factoryHr);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::Host
|