#include "..\e2dbase.h" #include "..\e2dmanager.h" #include "..\e2dnode.h" static bool s_bShowFps = false; static float s_fDpiScaleX = 0; static float s_fDpiScaleY = 0; static IDWriteTextFormat * s_pTextFormat = nullptr; static ID2D1Factory * s_pDirect2dFactory = nullptr; static ID2D1HwndRenderTarget * s_pRenderTarget = nullptr; static ID2D1SolidColorBrush * s_pSolidBrush = nullptr; static IWICImagingFactory * s_pIWICFactory = nullptr; static IDWriteFactory * s_pDWriteFactory = nullptr; static e2d::TextRenderer * s_pTextRenderer = nullptr; static ID2D1StrokeStyle * s_pMiterStrokeStyle = nullptr; static ID2D1StrokeStyle * s_pBevelStrokeStyle = nullptr; static ID2D1StrokeStyle * s_pRoundStrokeStyle = nullptr; static D2D1_COLOR_F s_nClearColor = D2D1::ColorF(D2D1::ColorF::Black); bool e2d::Renderer::__createDeviceIndependentResources() { // 创建设备无关资源,它们的生命周期和程序的时长相同 HRESULT hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, &s_pDirect2dFactory ); // 工厂将返回当前的系统 DPI,这个值也将用来创建窗口 if (SUCCEEDED(hr)) { s_pDirect2dFactory->GetDesktopDpi(&s_fDpiScaleX, &s_fDpiScaleY); } if (FAILED(hr)) { throw SystemException(L"Create ID2D1Factory failed"); } else { hr = s_pDirect2dFactory->CreateStrokeStyle( D2D1::StrokeStyleProperties( D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, D2D1_LINE_JOIN_MITER, 2.0f, D2D1_DASH_STYLE_SOLID, 0.0f), nullptr, 0, &s_pMiterStrokeStyle ); } if (FAILED(hr)) { throw SystemException(L"Create ID2D1StrokeStyle failed"); } else { hr = s_pDirect2dFactory->CreateStrokeStyle( D2D1::StrokeStyleProperties( D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, D2D1_LINE_JOIN_BEVEL, 2.0f, D2D1_DASH_STYLE_SOLID, 0.0f), nullptr, 0, &s_pBevelStrokeStyle ); } if (FAILED(hr)) { throw SystemException(L"Create ID2D1StrokeStyle failed"); } else { hr = s_pDirect2dFactory->CreateStrokeStyle( D2D1::StrokeStyleProperties( D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_FLAT, D2D1_LINE_JOIN_ROUND, 2.0f, D2D1_DASH_STYLE_SOLID, 0.0f), nullptr, 0, &s_pRoundStrokeStyle ); } if (FAILED(hr)) { throw SystemException(L"Create ID2D1StrokeStyle failed"); } else { // 创建 WIC 绘图工厂,用于统一处理各种格式的图片 hr = CoCreateInstance( CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast(&s_pIWICFactory) ); } if (FAILED(hr)) { throw SystemException(L"Create IWICImagingFactory failed"); } else { // 创建 DirectWrite 工厂 hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast(&s_pDWriteFactory) ); } if (FAILED(hr)) { throw SystemException(L"Create IDWriteFactory failed"); } else { // 创建文本格式化对象 hr = s_pDWriteFactory->CreateTextFormat( L"", nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 20, L"", &s_pTextFormat ); if (SUCCEEDED(hr)) { s_pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); } } return SUCCEEDED(hr); } bool e2d::Renderer::__createDeviceResources() { HRESULT hr = S_OK; if (!s_pRenderTarget) { HWND hWnd = Window::getHWnd(); // 创建设备相关资源。这些资源应在 Direct3D 设备消失时重建, // 比如当 isVisiable 被修改,等等 RECT rc; GetClientRect(hWnd, &rc); D2D1_SIZE_U size = D2D1::SizeU( rc.right - rc.left, rc.bottom - rc.top ); // 创建一个 Direct2D 渲染目标 hr = s_pDirect2dFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties( hWnd, size), &s_pRenderTarget ); if (FAILED(hr)) { throw SystemException(L"Create ID2D1HwndRenderTarget failed"); } else { // 创建画刷 hr = s_pRenderTarget->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::White), &s_pSolidBrush ); } if (FAILED(hr)) { throw SystemException(L"Create ID2D1SolidColorBrush failed"); } else { // 创建自定义的文字渲染器 s_pTextRenderer = TextRenderer::Create( s_pDirect2dFactory, s_pRenderTarget, s_pSolidBrush ); } } return SUCCEEDED(hr); } void e2d::Renderer::__discardDeviceResources() { SafeRelease(s_pRenderTarget); SafeRelease(s_pSolidBrush); SafeRelease(s_pTextRenderer); SafeRelease(s_pMiterStrokeStyle); SafeRelease(s_pBevelStrokeStyle); SafeRelease(s_pRoundStrokeStyle); } void e2d::Renderer::__discardResources() { SafeRelease(s_pTextFormat); SafeRelease(s_pDirect2dFactory); SafeRelease(s_pRenderTarget); SafeRelease(s_pSolidBrush); SafeRelease(s_pTextRenderer); SafeRelease(s_pMiterStrokeStyle); SafeRelease(s_pBevelStrokeStyle); SafeRelease(s_pRoundStrokeStyle); SafeRelease(s_pIWICFactory); SafeRelease(s_pDWriteFactory); } void e2d::Renderer::__render() { HRESULT hr = S_OK; // 创建设备相关资源 Renderer::__createDeviceResources(); // 开始渲染 s_pRenderTarget->BeginDraw(); // 使用背景色清空屏幕 s_pRenderTarget->Clear(s_nClearColor); // 渲染场景 SceneManager::__render(); // 渲染 FPS if (s_bShowFps && s_pTextFormat) { static int s_nRenderTimes = 0; static double s_fLastRenderTime = 0; static String s_sFpsText; ++s_nRenderTimes; double fDelay = Time::getTotalTime() - s_fLastRenderTime; if (fDelay >= 0.3) { s_sFpsText = String::format(L"FPS: %.1lf", (1 / fDelay) * s_nRenderTimes); s_fLastRenderTime = Time::getTotalTime(); s_nRenderTimes = 0; } IDWriteTextLayout * pTextLayout = nullptr; hr = s_pDWriteFactory->CreateTextLayout( (const WCHAR *)s_sFpsText, (UINT32)s_sFpsText.getLength(), s_pTextFormat, 0, 0, &pTextLayout ); if (SUCCEEDED(hr)) { s_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); s_pSolidBrush->SetOpacity(1.0f); s_pTextRenderer->SetTextStyle( D2D1::ColorF(D2D1::ColorF::White), TRUE, D2D1::ColorF(D2D1::ColorF::Black, 0.4f), 1.5f, D2D1_LINE_JOIN_ROUND ); pTextLayout->Draw(nullptr, s_pTextRenderer, 10, 0); SafeRelease(pTextLayout); } } // 终止渲染 hr = s_pRenderTarget->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 // 并在下一次调用时重建资源 hr = S_OK; Renderer::__discardDeviceResources(); } if (FAILED(hr)) { throw SystemException(L"Device loss recovery failed"); } } e2d::Color e2d::Renderer::getBackgroundColor() { return Color(s_nClearColor.r, s_nClearColor.g, s_nClearColor.b, s_nClearColor.a); } void e2d::Renderer::setBackgroundColor(Color color) { s_nClearColor = color.toD2DColorF(); } void e2d::Renderer::showFps(bool show) { s_bShowFps = show; } float e2d::Renderer::getDpiScaleX() { return s_fDpiScaleX; } float e2d::Renderer::getDpiScaleY() { return s_fDpiScaleY; } ID2D1Factory * e2d::Renderer::getID2D1Factory() { return s_pDirect2dFactory; } ID2D1HwndRenderTarget * e2d::Renderer::getRenderTarget() { return s_pRenderTarget; } ID2D1SolidColorBrush * e2d::Renderer::getSolidColorBrush() { return s_pSolidBrush; } IWICImagingFactory * e2d::Renderer::getIWICImagingFactory() { return s_pIWICFactory; } IDWriteFactory * e2d::Renderer::getIDWriteFactory() { return s_pDWriteFactory; } e2d::TextRenderer * e2d::Renderer::getTextRenderer() { return s_pTextRenderer; } ID2D1StrokeStyle * e2d::Renderer::getMiterID2D1StrokeStyle() { return s_pMiterStrokeStyle; } ID2D1StrokeStyle * e2d::Renderer::getBevelID2D1StrokeStyle() { return s_pBevelStrokeStyle; } ID2D1StrokeStyle * e2d::Renderer::getRoundID2D1StrokeStyle() { return s_pRoundStrokeStyle; }