287 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| #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::CustomTextRenderer * s_pTextRenderer = 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
 | ||
| 	);
 | ||
| 
 | ||
| 	ASSERT(SUCCEEDED(hr), "Create ID2D1Factory Failed!");
 | ||
| 
 | ||
| 	if (SUCCEEDED(hr))
 | ||
| 	{
 | ||
| 		// 创建 WIC 绘图工厂,用于统一处理各种格式的图片
 | ||
| 		hr = CoCreateInstance(
 | ||
| 			CLSID_WICImagingFactory,
 | ||
| 			NULL,
 | ||
| 			CLSCTX_INPROC_SERVER,
 | ||
| 			IID_IWICImagingFactory,
 | ||
| 			reinterpret_cast<void**>(&s_pIWICFactory)
 | ||
| 		);
 | ||
| 		ASSERT(SUCCEEDED(hr), "Create IWICImagingFactory Failed!");
 | ||
| 	}
 | ||
| 
 | ||
| 	if (SUCCEEDED(hr))
 | ||
| 	{
 | ||
| 		// 创建 DirectWrite 工厂
 | ||
| 		hr = DWriteCreateFactory(
 | ||
| 			DWRITE_FACTORY_TYPE_SHARED,
 | ||
| 			__uuidof(IDWriteFactory),
 | ||
| 			reinterpret_cast<IUnknown**>(&s_pDWriteFactory)
 | ||
| 		);
 | ||
| 		ASSERT(SUCCEEDED(hr), "Create IDWriteFactory Failed!");
 | ||
| 	}
 | ||
| 
 | ||
| 	if (SUCCEEDED(hr))
 | ||
| 	{
 | ||
| 		// 工厂将返回当前的系统 DPI,这个值也将用来创建窗口
 | ||
| 		Renderer::getID2D1Factory()->GetDesktopDpi(&s_fDpiScaleX, &s_fDpiScaleY);
 | ||
| 	}
 | ||
| 
 | ||
| 	if (SUCCEEDED(hr))
 | ||
| 	{
 | ||
| 		// 创建文本格式化对象
 | ||
| 		hr = s_pDWriteFactory->CreateTextFormat(
 | ||
| 			L"",
 | ||
| 			NULL,
 | ||
| 			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
 | ||
| 		);
 | ||
| 
 | ||
| 		ASSERT(SUCCEEDED(hr), "Create ID2D1HwndRenderTarget Failed!");
 | ||
| 
 | ||
| 		if (SUCCEEDED(hr))
 | ||
| 		{
 | ||
| 			// 创建画刷
 | ||
| 			hr = s_pRenderTarget->CreateSolidColorBrush(
 | ||
| 				D2D1::ColorF(D2D1::ColorF::White),
 | ||
| 				&s_pSolidBrush
 | ||
| 			);
 | ||
| 			ASSERT(SUCCEEDED(hr), "Create ID2D1SolidColorBrush Failed!");
 | ||
| 		}
 | ||
| 
 | ||
| 		if (SUCCEEDED(hr))
 | ||
| 		{
 | ||
| 			// 创建自定义的文字渲染器
 | ||
| 			s_pTextRenderer = new (std::nothrow) CustomTextRenderer(
 | ||
| 				s_pDirect2dFactory,
 | ||
| 				s_pRenderTarget,
 | ||
| 				s_pSolidBrush
 | ||
| 			);
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	return SUCCEEDED(hr);
 | ||
| }
 | ||
| 
 | ||
| void e2d::Renderer::__discardDeviceResources()
 | ||
| {
 | ||
| 	SafeReleaseInterface(&s_pRenderTarget);
 | ||
| 	SafeReleaseInterface(&s_pSolidBrush);
 | ||
| 	SafeReleaseInterface(&s_pTextRenderer);
 | ||
| }
 | ||
| 
 | ||
| void e2d::Renderer::__discardResources()
 | ||
| {
 | ||
| 	SafeReleaseInterface(&s_pTextFormat);
 | ||
| 	SafeReleaseInterface(&s_pDirect2dFactory);
 | ||
| 	SafeReleaseInterface(&s_pRenderTarget);
 | ||
| 	SafeReleaseInterface(&s_pSolidBrush);
 | ||
| 	SafeReleaseInterface(&s_pTextRenderer);
 | ||
| 	SafeReleaseInterface(&s_pIWICFactory);
 | ||
| 	SafeReleaseInterface(&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)
 | ||
| 	{
 | ||
| 		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(
 | ||
| 			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(NULL, s_pTextRenderer, 10, 0);
 | ||
| 
 | ||
| 			SafeReleaseInterface(&pTextLayout);
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	// 终止渲染
 | ||
| 	hr = s_pRenderTarget->EndDraw();
 | ||
| 
 | ||
| 	if (hr == D2DERR_RECREATE_TARGET)
 | ||
| 	{
 | ||
| 		// 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源
 | ||
| 		// 并在下一次调用时重建资源
 | ||
| 		hr = S_OK;
 | ||
| 		Renderer::__discardDeviceResources();
 | ||
| 	}
 | ||
| 
 | ||
| 	if (FAILED(hr))
 | ||
| 	{
 | ||
| 		// 渲染时产生了未知的错误,退出游戏
 | ||
| 		ASSERT(false, L"Renderer error: %#X!", hr);
 | ||
| 		Game::quit();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 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.toColorF();
 | ||
| }
 | ||
| 
 | ||
| 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::CustomTextRenderer * e2d::Renderer::getCustomTextRenderer()
 | ||
| {
 | ||
| 	return s_pTextRenderer;
 | ||
| }
 |