Val_Kir

Лекция 5

Apr 21st, 2021
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.93 KB | None | 0 0
  1. Lec5Pg7
  2. basewin.h
  3. #pragma once
  4. template <class DERIVED_TYPE>
  5. class BaseWindow
  6. {
  7. public:
  8. static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  9. {
  10. DERIVED_TYPE *pThis = NULL;
  11. if (uMsg == WM_NCCREATE)
  12. {
  13. CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
  14. pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
  15. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
  16. pThis->m_hwnd = hwnd;
  17. }
  18. else
  19. {
  20. pThis = (DERIVED_TYPE*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  21. }
  22. if (pThis)
  23. {
  24. return pThis->HandleMessage(uMsg, wParam, lParam);
  25. }
  26. else
  27. {
  28. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  29. }
  30. }
  31. BaseWindow() : m_hwnd(NULL) { }
  32. BOOL Create(
  33. PCWSTR lpWindowName,
  34. DWORD dwStyle,
  35. DWORD dwExStyle = 0,
  36. int x = CW_USEDEFAULT,
  37. int y = CW_USEDEFAULT,
  38. int nWidth = CW_USEDEFAULT,
  39. int nHeight = CW_USEDEFAULT,
  40. HWND hWndParent = 0,
  41. HMENU hMenu = 0
  42. )
  43. {
  44. WNDCLASS wc = { 0 };
  45. wc.lpfnWndProc = DERIVED_TYPE::WindowProc;
  46. wc.hInstance = GetModuleHandle(NULL);
  47. wc.lpszClassName = ClassName();
  48. RegisterClass(&wc);
  49. m_hwnd = CreateWindowEx(
  50. dwExStyle, ClassName(), lpWindowName, dwStyle, x, y,
  51. nWidth, nHeight, hWndParent, hMenu, GetModuleHandle(NULL), this
  52. );
  53. return (m_hwnd ? TRUE : FALSE);
  54. }
  55. HWND Window() const { return m_hwnd; }
  56. protected:
  57. virtual PCWSTR ClassName() const = 0;
  58. HWND m_hwnd;
  59. };
  60. Source.cpp
  61. #include <windows.h>
  62. #include <d2d1.h>
  63. #pragma comment(lib, "d2d1")
  64. #include <Dwrite.h>
  65. #pragma comment(lib, "DWrite")
  66. #include "basewin.h"
  67. template <class T> void SafeRelease(T **ppT)
  68. {
  69. if (*ppT)
  70. {
  71. (*ppT)->Release();
  72. *ppT = NULL;
  73. }
  74. }
  75. class MainWindow : public BaseWindow<MainWindow>
  76. {
  77. ID2D1Factory *pFactory;
  78. ID2D1HwndRenderTarget *pRenderTarget;
  79. void CalculateLayout() {}
  80. HRESULT CreateGraphicsResources();
  81. void DiscardGraphicsResources();
  82. void OnPaint();
  83. void Resize();
  84. HRESULT DrawHelloWorld(
  85. ID2D1HwndRenderTarget* pIRenderTarget
  86. );
  87. public:
  88. MainWindow() : pFactory(NULL), pRenderTarget(NULL)
  89. {
  90. }
  91. PCWSTR ClassName() const { return L"Hello Window Class"; }
  92. LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  93. };
  94. HRESULT MainWindow::CreateGraphicsResources()
  95. {
  96. HRESULT hr = S_OK;
  97. if (pRenderTarget == NULL)
  98. {
  99. RECT rc;
  100. GetClientRect(m_hwnd, &rc);
  101. D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
  102. hr = pFactory->CreateHwndRenderTarget(
  103. D2D1::RenderTargetProperties(),
  104. D2D1::HwndRenderTargetProperties(m_hwnd, size),
  105. &pRenderTarget);
  106. }
  107. return hr;
  108. }
  109. void MainWindow::DiscardGraphicsResources()
  110. {
  111. SafeRelease(&pRenderTarget);
  112. }
  113. void MainWindow::OnPaint()
  114. {
  115. HRESULT hr = CreateGraphicsResources();
  116. if (SUCCEEDED(hr))
  117. {
  118. PAINTSTRUCT ps;
  119. BeginPaint(m_hwnd, &ps);
  120. pRenderTarget->BeginDraw();
  121. pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue));
  122. hr = DrawHelloWorld(pRenderTarget);
  123. hr = pRenderTarget->EndDraw();
  124. if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
  125. {
  126. DiscardGraphicsResources();
  127. }
  128. EndPaint(m_hwnd, &ps);
  129. }
  130. }
  131. void MainWindow::Resize()
  132. {
  133. if (pRenderTarget != NULL)
  134. {
  135. RECT rc;
  136. GetClientRect(m_hwnd, &rc);
  137. D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
  138. pRenderTarget->Resize(size);
  139. CalculateLayout();
  140. InvalidateRect(m_hwnd, NULL, FALSE);
  141. }
  142. }
  143. HRESULT MainWindow::DrawHelloWorld(
  144. ID2D1HwndRenderTarget* pIRenderTarget
  145. )
  146. {
  147. HRESULT hr = S_OK;
  148. ID2D1SolidColorBrush* pIRedBrush = NULL;
  149. IDWriteTextFormat* pITextFormat = NULL;
  150. IDWriteFactory* pIDWriteFactory = NULL;
  151. if (SUCCEEDED(hr))
  152. {
  153. hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
  154. __uuidof(IDWriteFactory),
  155. reinterpret_cast<IUnknown**>(&pIDWriteFactory));
  156. }
  157. if (SUCCEEDED(hr))
  158. {
  159. hr = pIDWriteFactory->CreateTextFormat(
  160. L"Arial",
  161. NULL,
  162. DWRITE_FONT_WEIGHT_NORMAL,
  163. DWRITE_FONT_STYLE_NORMAL,
  164. DWRITE_FONT_STRETCH_NORMAL,
  165. 24.0f * 96.0f / 72.0f,
  166. L"en-US",
  167. &pITextFormat
  168. );
  169. }
  170. if (SUCCEEDED(hr))
  171. {
  172. hr = pIRenderTarget->CreateSolidColorBrush(
  173. D2D1::ColorF(D2D1::ColorF::Red),
  174. &pIRedBrush
  175. );
  176. }
  177. D2D1_RECT_F layoutRect = D2D1::RectF(0.f, 0.f, 250.f, 100.f);
  178. // Вывести текст в начало координат.
  179. if (SUCCEEDED(hr))
  180. {
  181. pIRenderTarget->DrawText(
  182. L"Hello World",
  183. wcslen(L"Hello World"),
  184. pITextFormat,
  185. layoutRect,
  186. pIRedBrush
  187. );
  188. }
  189. // Clean up.
  190. SafeRelease(&pIRedBrush);
  191. SafeRelease(&pITextFormat);
  192. SafeRelease(&pIDWriteFactory);
  193. return hr;
  194. }
  195. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow)
  196. {
  197. MainWindow win;
  198. if (!win.Create(L"Hello", WS_OVERLAPPEDWINDOW))
  199. {
  200. return 0;
  201. }
  202. ShowWindow(win.Window(), nCmdShow);
  203. // Цикл обработки сообщений.
  204. MSG msg = {};
  205. while (GetMessage(&msg, NULL, 0, 0))
  206. {
  207. TranslateMessage(&msg);
  208. DispatchMessage(&msg);
  209. }
  210. return 0;
  211. }
  212. LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  213. {
  214. switch (uMsg)
  215. {
  216. case WM_CREATE:
  217. if (FAILED(D2D1CreateFactory(
  218. D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
  219. {
  220. return -1; // Неудача CreateWindowEx.
  221. }
  222. return 0;
  223. case WM_DESTROY:
  224. DiscardGraphicsResources();
  225. SafeRelease(&pFactory);
  226. PostQuitMessage(0);
  227. return 0;
  228. case WM_PAINT:
  229. OnPaint();
  230. return 0;
  231.  
  232. case WM_SIZE:
  233. Resize();
  234. return 0;
  235. }
  236. return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
  237. }
  238. Lec5Pg10
  239. Source.cpp
  240. #include <dwrite.h>
  241. #include <string.h>
  242. #include <stdio.h>
  243. #include <new>
  244. // SafeRelease inline function.
  245. template <class T> inline void SafeRelease(T **ppT)
  246. {
  247. if (*ppT)
  248. {
  249. (*ppT)->Release();
  250. *ppT = NULL;
  251. }
  252. }
  253. void wmain()
  254. {
  255. IDWriteFactory* pDWriteFactory = NULL;
  256. HRESULT hr = DWriteCreateFactory(
  257. DWRITE_FACTORY_TYPE_SHARED,
  258. __uuidof(IDWriteFactory),
  259. reinterpret_cast<IUnknown**>(&pDWriteFactory)
  260. );
  261. IDWriteFontCollection* pFontCollection = NULL;
  262. // Get the system font collection.
  263. if (SUCCEEDED(hr))
  264. {
  265. hr = pDWriteFactory->GetSystemFontCollection(&pFontCollection);
  266. }
  267. UINT32 familyCount = 0;
  268. wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
  269. // Get the default locale for this user.
  270. int defaultLocaleSuccess = GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH);
  271. wprintf(L"ln=%s\n", localeName);
  272. // Get the number of font families in the collection.
  273. if (SUCCEEDED(hr))
  274. {
  275. familyCount = pFontCollection->GetFontFamilyCount();
  276. }
  277. for (UINT32 i = 0; i < familyCount; ++i)
  278. {
  279. IDWriteFontFamily* pFontFamily = NULL;
  280. // Get the font family.
  281. if (SUCCEEDED(hr))
  282. {
  283. hr = pFontCollection->GetFontFamily(i, &pFontFamily);
  284. }
  285. IDWriteLocalizedStrings* pFamilyNames = NULL;
  286. // Get a list of localized strings for the family name.
  287. if (SUCCEEDED(hr))
  288. {
  289. hr = pFontFamily->GetFamilyNames(&pFamilyNames);
  290. }
  291. UINT32 index = 0;
  292. BOOL exists = false;
  293. if (SUCCEEDED(hr))
  294. {
  295. // If the default locale is returned, find that locale name, otherwise use "en-us".
  296. if (defaultLocaleSuccess)
  297. {
  298. hr = pFamilyNames->FindLocaleName(localeName, &index, &exists);
  299. }
  300. if (SUCCEEDED(hr) && !exists) // if the above find did not find a match, retry with US English
  301. {
  302. hr = pFamilyNames->FindLocaleName(L"en-us", &index, &exists);
  303. }
  304. }
  305. // If the specified locale doesn't exist, select the first on the list.
  306. if (!exists)
  307. index = 0;
  308. UINT32 length = 0;
  309. // Get the string length.
  310. if (SUCCEEDED(hr))
  311. {
  312. hr = pFamilyNames->GetStringLength(index, &length);
  313. }
  314. // Allocate a string big enough to hold the name.
  315. wchar_t* name = new (std::nothrow) wchar_t[length + 1];
  316. if (name == NULL)
  317. {
  318. hr = E_OUTOFMEMORY;
  319. }
  320. // Get the family name.
  321. if (SUCCEEDED(hr))
  322. {
  323. hr = pFamilyNames->GetString(index, name, length + 1);
  324. }
  325. if (SUCCEEDED(hr))
  326. {
  327. // Print out the family name.
  328. wprintf(L"%s\n", name);
  329. }
  330. SafeRelease(&pFontFamily);
  331. SafeRelease(&pFamilyNames);
  332. delete[] name;
  333. }
  334. SafeRelease(&pFontCollection);
  335. SafeRelease(&pDWriteFactory);
  336. char c;
  337. scanf_s("%c", &c, 1);
  338. }
  339. Lec5Pg14
  340. basewin.h
  341. #pragma once
  342. template <class DERIVED_TYPE>
  343. class BaseWindow
  344. {
  345. public:
  346. static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  347. {
  348. DERIVED_TYPE *pThis = NULL;
  349. if (uMsg == WM_NCCREATE)
  350. {
  351. CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
  352. pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
  353. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
  354. pThis->m_hwnd = hwnd;
  355. }
  356. else
  357. {
  358. pThis = (DERIVED_TYPE*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  359. }
  360. if (pThis)
  361. {
  362. return pThis->HandleMessage(uMsg, wParam, lParam);
  363. }
  364. else
  365. {
  366. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  367. }
  368. }
  369. BaseWindow() : m_hwnd(NULL) { }
  370. BOOL Create(
  371. PCWSTR lpWindowName,
  372. DWORD dwStyle,
  373. DWORD dwExStyle = 0,
  374. int x = CW_USEDEFAULT,
  375. int y = CW_USEDEFAULT,
  376. int nWidth = CW_USEDEFAULT,
  377. int nHeight = CW_USEDEFAULT,
  378. HWND hWndParent = 0,
  379. HMENU hMenu = 0
  380. )
  381. {
  382. WNDCLASS wc = { 0 };
  383. wc.lpfnWndProc = DERIVED_TYPE::WindowProc;
  384. wc.hInstance = GetModuleHandle(NULL);
  385. wc.lpszClassName = ClassName();
  386. //wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  387. RegisterClass(&wc);
  388. m_hwnd = CreateWindowEx(
  389. dwExStyle, ClassName(), lpWindowName, dwStyle, x, y,
  390. nWidth, nHeight, hWndParent, hMenu, GetModuleHandle(NULL), this
  391. );
  392. return (m_hwnd ? TRUE : FALSE);
  393. }
  394. HWND Window() const { return m_hwnd; }
  395. protected:
  396. virtual PCWSTR ClassName() const = 0;
  397. HWND m_hwnd;
  398. };
  399. Direct2D.cpp
  400. #include "Direct2D.h"
  401. #pragma comment(lib, "d2d1")
  402. #pragma comment(lib, "DWrite")
  403. float DPIScale::scaleX = 1.0f;
  404. float DPIScale::scaleY = 1.0f;
  405. Direct2D::Direct2D() : pFactory(NULL), pRenderTarget(NULL), pBlackBrush_(NULL)
  406. {
  407. wszText_ = L"Hello World using DirectWrite!";
  408. cTextLength_ = (UINT32)wcslen(wszText_);
  409. }
  410.  
  411. Direct2D::~Direct2D()
  412. {
  413. }
  414. bool Direct2D::CreateDeviceIndependentResources()
  415. {
  416. HRESULT hr = D2D1CreateFactory(
  417. D2D1_FACTORY_TYPE_SINGLE_THREADED,
  418. &pFactory);
  419. if (SUCCEEDED(hr))
  420. {
  421. DPIScale::Initialize(pFactory);
  422. hr = DWriteCreateFactory(
  423. DWRITE_FACTORY_TYPE_SHARED,
  424. __uuidof(IDWriteFactory),
  425. reinterpret_cast<IUnknown**>(&pDWriteFactory_)
  426. );
  427. }
  428. if (SUCCEEDED(hr))
  429. {
  430. hr = pDWriteFactory_->CreateTextFormat(
  431. L"Gabriola", // Font family name.
  432. NULL, // Font collection (NULL sets it to use the system font collection).
  433. DWRITE_FONT_WEIGHT_REGULAR,
  434. DWRITE_FONT_STYLE_NORMAL,
  435. DWRITE_FONT_STRETCH_NORMAL,
  436. 72.0f,
  437. L"en-us",
  438. &pTextFormat_
  439. );
  440. }
  441. if (SUCCEEDED(hr))
  442. {
  443. hr = pTextFormat_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
  444. }
  445. if (SUCCEEDED(hr))
  446. {
  447. hr = pTextFormat_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
  448. }
  449. return SUCCEEDED(hr);
  450. }
  451. HRESULT Direct2D::CreateGraphicsResources(HWND m_hwnd)
  452. {
  453. HRESULT hr = S_OK;
  454. if (pRenderTarget == NULL)
  455. {
  456. RECT rc;
  457. GetClientRect(m_hwnd, &rc);
  458. D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
  459. hr = pFactory->CreateHwndRenderTarget(
  460. D2D1::RenderTargetProperties(),
  461. D2D1::HwndRenderTargetProperties(m_hwnd, size),
  462. &pRenderTarget);
  463. if (SUCCEEDED(hr))
  464. {
  465. const D2D1_COLOR_F color = D2D1::ColorF(D2D1::ColorF::Black);
  466. hr = pRenderTarget->CreateSolidColorBrush(color, &pBlackBrush_);
  467. if (SUCCEEDED(hr))
  468. {
  469. CalculateLayout();
  470. }
  471. }
  472. }
  473. return hr;
  474. }
  475. void Direct2D::DiscardGraphicsResources()
  476. {
  477. SafeRelease(&pRenderTarget);
  478. SafeRelease(&pBlackBrush_);
  479. }
  480. // Пересчет изображения при изменении размера окна.
  481. void Direct2D::CalculateLayout()
  482. {
  483. }
  484. void Direct2D::OnPaintScene(HWND m_hwnd)
  485. {
  486. HRESULT hr = CreateGraphicsResources(m_hwnd);
  487. if (SUCCEEDED(hr))
  488. {
  489. RECT rc;
  490. GetClientRect(m_hwnd, &rc);
  491. const float dipX = DPIScale::PixelsToDipsX(rc.right);
  492. const float dipY = DPIScale::PixelsToDipsY(rc.bottom);
  493. D2D1_RECT_F layoutRect = D2D1::RectF(0.0f, 0.0f, dipX, dipY);
  494. pRenderTarget->BeginDraw();
  495. pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
  496. pRenderTarget->DrawText(
  497. wszText_, // The string to render.
  498. cTextLength_, // The string's length.
  499. pTextFormat_, // The text format.
  500. layoutRect, // The region of the window where the text will be rendered.
  501. pBlackBrush_ // The brush used to draw the text.
  502. );
  503. hr = pRenderTarget->EndDraw();
  504. if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
  505. {
  506. DiscardGraphicsResources();
  507. }
  508. }
  509. }
  510. Direct2D.h
  511. #pragma once
  512. #include <d2d1.h>
  513. #include <dwrite.h>
  514. class DPIScale
  515. {
  516. static float scaleX;
  517. static float scaleY;
  518. public:
  519. static void Initialize(ID2D1Factory *pFactory)
  520. {
  521. FLOAT dpiX, dpiY;
  522. pFactory->GetDesktopDpi(&dpiX, &dpiY);
  523. scaleX = dpiX / 96.0f;
  524. scaleY = dpiY / 96.0f;
  525. }
  526. template <typename T>
  527. static float PixelsToDipsX(T x)
  528. {
  529. return static_cast<float>(x) / scaleX;
  530. }
  531. template <typename T>
  532. static float PixelsToDipsY(T y)
  533. {
  534. return static_cast<float>(y) / scaleY;
  535. }
  536. template <typename T>
  537. static D2D1_POINT_2F PixelsToDips(T x, T y)
  538. {
  539. return D2D1::Point2F(static_cast<float>(x) / scaleX, static_cast<float>(y) / scaleY);
  540. }
  541. };
  542. template <class T> void SafeRelease(T **ppT)
  543. {
  544. if (*ppT)
  545. {
  546. (*ppT)->Release();
  547. *ppT = NULL;
  548. }
  549. }
  550. class Direct2D
  551. {
  552. ID2D1Factory * pFactory;
  553. public:
  554. ID2D1SolidColorBrush *pBlackBrush_;
  555. ID2D1HwndRenderTarget * pRenderTarget;
  556. IDWriteFactory* pDWriteFactory_;
  557. IDWriteTextFormat* pTextFormat_;
  558. const wchar_t* wszText_;
  559. UINT32 cTextLength_;
  560. Direct2D();
  561. ~Direct2D();
  562. bool CreateDeviceIndependentResources();
  563. HRESULT CreateGraphicsResources(HWND m_hwnd);
  564. void DiscardGraphicsResources();
  565. void ReleaseFactory()
  566. {
  567. SafeRelease(&pFactory);
  568. SafeRelease(&pDWriteFactory_);
  569. }
  570. void CalculateLayout();
  571. void OnPaintScene(HWND m_hwnd);
  572. };
  573. MainWindow.cpp
  574. #include <Windows.h>
  575. #include "MainWindow.h"
  576. void MainWindow::OnPaint()
  577. {
  578. PAINTSTRUCT ps;
  579. BeginPaint(m_hwnd, &ps);
  580. d2d.OnPaintScene(m_hwnd);
  581. EndPaint(m_hwnd, &ps);
  582. }
  583. void MainWindow::Resize()
  584. {
  585. if (d2d.pRenderTarget != NULL)
  586. {
  587. RECT rc;
  588. GetClientRect(m_hwnd, &rc);
  589. D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
  590. d2d.pRenderTarget->Resize(size);
  591. d2d.CalculateLayout();
  592. InvalidateRect(m_hwnd, NULL, FALSE);
  593. }
  594. }
  595. LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  596. {
  597. switch (uMsg)
  598. {
  599. case WM_CREATE:
  600. if (!d2d.CreateDeviceIndependentResources())
  601. {
  602. return -1; // Неудача CreateWindowEx.
  603. }
  604. return 0;
  605. case WM_DESTROY:
  606. d2d.DiscardGraphicsResources();
  607. d2d.ReleaseFactory();
  608. PostQuitMessage(0);
  609. return 0;
  610. case WM_PAINT:
  611. OnPaint();
  612. return 0;
  613.  
  614. case WM_SIZE:
  615. Resize();
  616. return 0;
  617. }
  618. return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
  619. }
  620. MainWindow.h
  621. #pragma once
  622. #include "basewin.h"
  623. #include "Direct2D.h"
  624. class MainWindow : public BaseWindow<MainWindow> {
  625. Direct2D d2d;
  626. public:
  627. void OnPaint();
  628. void Resize();
  629. PCWSTR ClassName() const { return L"SimpleText Window Class"; }
  630. LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  631. };
  632. Source.cpp
  633. #include <windows.h>
  634. #include "MainWindow.h"
  635. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
  636. {
  637. MainWindow win;
  638. if (!win.Create(L"Простой текст", WS_OVERLAPPEDWINDOW))
  639. {
  640. return 0;
  641. }
  642. ShowWindow(win.Window(), nCmdShow);
  643. // Run the message loop.
  644. MSG msg = {};
  645. while (GetMessage(&msg, NULL, 0, 0))
  646. {
  647. TranslateMessage(&msg);
  648. DispatchMessage(&msg);
  649. }
  650. return 0;
  651. }
  652. Lec5Pg19
  653. basewin.h
  654. #pragma once
  655. template <class DERIVED_TYPE>
  656. class BaseWindow
  657. {
  658. public:
  659. static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  660. {
  661. DERIVED_TYPE *pThis = NULL;
  662. if (uMsg == WM_NCCREATE)
  663. {
  664. CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
  665. pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
  666. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
  667. pThis->m_hwnd = hwnd;
  668. }
  669. else
  670. {
  671. pThis = (DERIVED_TYPE*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  672. }
  673. if (pThis)
  674. {
  675. return pThis->HandleMessage(uMsg, wParam, lParam);
  676. }
  677. else
  678. {
  679. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  680. }
  681. }
  682. BaseWindow() : m_hwnd(NULL) { }
  683. BOOL Create(
  684. PCWSTR lpWindowName,
  685. DWORD dwStyle,
  686. DWORD dwExStyle = 0,
  687. int x = CW_USEDEFAULT,
  688. int y = CW_USEDEFAULT,
  689. int nWidth = CW_USEDEFAULT,
  690. int nHeight = CW_USEDEFAULT,
  691. HWND hWndParent = 0,
  692. HMENU hMenu = 0
  693. )
  694. {
  695. WNDCLASS wc = { 0 };
  696. wc.lpfnWndProc = DERIVED_TYPE::WindowProc;
  697. wc.hInstance = GetModuleHandle(NULL);
  698. wc.lpszClassName = ClassName();
  699. //wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  700. RegisterClass(&wc);
  701. m_hwnd = CreateWindowEx(
  702. dwExStyle, ClassName(), lpWindowName, dwStyle, x, y,
  703. nWidth, nHeight, hWndParent, hMenu, GetModuleHandle(NULL), this
  704. );
  705. return (m_hwnd ? TRUE : FALSE);
  706. }
  707. HWND Window() const { return m_hwnd; }
  708. protected:
  709. virtual PCWSTR ClassName() const = 0;
  710. HWND m_hwnd;
  711. };
  712. Direct2D.cpp
  713. #include "Direct2D.h"
  714. #pragma comment(lib, "d2d1")
  715. #pragma comment(lib, "DWrite")
  716. float DPIScale::scaleX = 1.0f;
  717. float DPIScale::scaleY = 1.0f;
  718. Direct2D::Direct2D() : pFactory(NULL), pRenderTarget(NULL), pBlackBrush_(NULL), pTextLayout_(NULL)
  719. {
  720. wszText_ = L"Hello World using DirectWrite!";
  721. cTextLength_ = (UINT32)wcslen(wszText_);
  722. }
  723.  
  724. Direct2D::~Direct2D()
  725. {
  726. }
  727. bool Direct2D::CreateDeviceIndependentResources(HWND m_hwnd)
  728. {
  729. HRESULT hr = D2D1CreateFactory(
  730. D2D1_FACTORY_TYPE_SINGLE_THREADED,
  731. &pFactory);
  732. if (SUCCEEDED(hr))
  733. {
  734. DPIScale::Initialize(pFactory);
  735. hr = DWriteCreateFactory(
  736. DWRITE_FACTORY_TYPE_SHARED,
  737. __uuidof(IDWriteFactory),
  738. reinterpret_cast<IUnknown**>(&pDWriteFactory_)
  739. );
  740. }
  741. if (SUCCEEDED(hr))
  742. {
  743. hr = pDWriteFactory_->CreateTextFormat(
  744. L"Gabriola", // Font family name.
  745. NULL, // Font collection (NULL sets it to use the system font collection).
  746. DWRITE_FONT_WEIGHT_REGULAR,
  747. DWRITE_FONT_STYLE_NORMAL,
  748. DWRITE_FONT_STRETCH_NORMAL,
  749. 72.0f,
  750. L"en-us",
  751. &pTextFormat_
  752. );
  753. }
  754. if (SUCCEEDED(hr))
  755. {
  756. hr = pTextFormat_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
  757. }
  758. if (SUCCEEDED(hr))
  759. {
  760. hr = pTextFormat_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
  761. }
  762. if (SUCCEEDED(hr))
  763. {
  764. // Create a text layout using the text format.
  765. RECT rc;
  766. GetClientRect(m_hwnd, &rc);
  767. float width = DPIScale::PixelsToDipsX(rc.right);
  768. float height = DPIScale::PixelsToDipsY(rc.bottom);
  769. HRESULT hr = pDWriteFactory_->CreateTextLayout(
  770. wszText_, // The string to be laid out and formatted.
  771. cTextLength_, // The length of the string.
  772. pTextFormat_, // The text format to apply to the string (contains font information, etc).
  773. width, // The width of the layout box.
  774. height, // The height of the layout box.
  775. &pTextLayout_ // The IDWriteTextLayout interface pointer.
  776. );
  777. }
  778. if (SUCCEEDED(hr))
  779. {
  780. DWRITE_TEXT_RANGE textRange = { 19, // Start index where "DirectWrite" appears.
  781. 6 }; // Length of the substring "Direct" in "DirectWrite".
  782. hr = pTextLayout_->SetFontSize(100.0f, textRange);
  783. }
  784. // Format the word "DWrite" to be underlined.
  785. if (SUCCEEDED(hr))
  786. {
  787. DWRITE_TEXT_RANGE textRange = { 19, // Start index where "DirectWrite" appears.
  788. 11 }; // Length of the substring "DirectWrite".
  789. hr = pTextLayout_->SetUnderline(TRUE, textRange);
  790. }
  791. if (SUCCEEDED(hr))
  792. {
  793. // Format the word "DWrite" to be bold.
  794. DWRITE_TEXT_RANGE textRange = { 19,
  795. 11 };
  796. hr = pTextLayout_->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, textRange);
  797. }
  798. // Create a typography interface object.
  799. if (SUCCEEDED(hr))
  800. {
  801. hr = pDWriteFactory_->CreateTypography(&pTypography);
  802. }
  803. // Set the stylistic set.
  804. DWRITE_FONT_FEATURE fontFeature = { DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7,
  805. 1 };
  806. if (SUCCEEDED(hr))
  807. {
  808. hr = pTypography->AddFontFeature(fontFeature);
  809. }
  810. if (SUCCEEDED(hr))
  811. {
  812. // Set the typography for the entire string.
  813. DWRITE_TEXT_RANGE textRange = { 0,
  814. cTextLength_ };
  815. hr = pTextLayout_->SetTypography(pTypography, textRange);
  816. }
  817. return SUCCEEDED(hr);
  818. }
  819. HRESULT Direct2D::CreateGraphicsResources(HWND m_hwnd)
  820. {
  821. HRESULT hr = S_OK;
  822. if (pRenderTarget == NULL)
  823. {
  824. RECT rc;
  825. GetClientRect(m_hwnd, &rc);
  826. D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
  827. hr = pFactory->CreateHwndRenderTarget(
  828. D2D1::RenderTargetProperties(),
  829. D2D1::HwndRenderTargetProperties(m_hwnd, size),
  830. &pRenderTarget);
  831. if (SUCCEEDED(hr))
  832. {
  833. const D2D1_COLOR_F color = D2D1::ColorF(D2D1::ColorF::Black);
  834. hr = pRenderTarget->CreateSolidColorBrush(color, &pBlackBrush_);
  835. if (SUCCEEDED(hr))
  836. {
  837. CalculateLayout(m_hwnd);
  838. }
  839. }
  840. }
  841. return hr;
  842. }
  843. void Direct2D::DiscardGraphicsResources()
  844. {
  845. SafeRelease(&pRenderTarget);
  846. SafeRelease(&pBlackBrush_);
  847. }
  848. // Пересчет изображения при изменении размера окна.
  849. void Direct2D::CalculateLayout(HWND m_hwnd)
  850. {
  851. RECT rc;
  852. GetClientRect(m_hwnd, &rc);
  853. if (pTextLayout_)
  854. {
  855. const float dipX = DPIScale::PixelsToDipsX(rc.right);
  856. const float dipY = DPIScale::PixelsToDipsY(rc.bottom);
  857. pTextLayout_->SetMaxWidth(dipX);
  858. pTextLayout_->SetMaxHeight(dipY);
  859. }
  860. }
  861. void Direct2D::OnPaintScene(HWND m_hwnd)
  862. {
  863. HRESULT hr = CreateGraphicsResources(m_hwnd);
  864. if (SUCCEEDED(hr))
  865. {
  866. D2D1_POINT_2F origin = D2D1::Point2F(0.0f, 0.0f);
  867. pRenderTarget->BeginDraw();
  868. pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
  869. pRenderTarget->DrawTextLayout(
  870. origin,
  871. pTextLayout_,
  872. pBlackBrush_
  873. );
  874. hr = pRenderTarget->EndDraw();
  875. if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
  876. {
  877. DiscardGraphicsResources();
  878. }
  879. }
  880. }
  881. Direct2D.h
  882. #pragma once
  883. #include <d2d1.h>
  884. #include <dwrite.h>
  885. class DPIScale
  886. {
  887. static float scaleX;
  888. static float scaleY;
  889. public:
  890. static void Initialize(ID2D1Factory *pFactory)
  891. {
  892. FLOAT dpiX, dpiY;
  893. pFactory->GetDesktopDpi(&dpiX, &dpiY);
  894. scaleX = dpiX / 96.0f;
  895. scaleY = dpiY / 96.0f;
  896. }
  897. template <typename T>
  898. static float PixelsToDipsX(T x)
  899. {
  900. return static_cast<float>(x) / scaleX;
  901. }
  902. template <typename T>
  903. static float PixelsToDipsY(T y)
  904. {
  905. return static_cast<float>(y) / scaleY;
  906. }
  907. template <typename T>
  908. static D2D1_POINT_2F PixelsToDips(T x, T y)
  909. {
  910. return D2D1::Point2F(static_cast<float>(x) / scaleX, static_cast<float>(y) / scaleY);
  911. }
  912. };
  913. template <class T> void SafeRelease(T **ppT)
  914. {
  915. if (*ppT)
  916. {
  917. (*ppT)->Release();
  918. *ppT = NULL;
  919. }
  920. }
  921. class Direct2D
  922. {
  923. ID2D1Factory * pFactory;
  924. public:
  925. ID2D1SolidColorBrush *pBlackBrush_;
  926. ID2D1HwndRenderTarget * pRenderTarget;
  927. IDWriteFactory* pDWriteFactory_;
  928. IDWriteTextFormat* pTextFormat_;
  929. IDWriteTextLayout* pTextLayout_;
  930. IDWriteTypography* pTypography = NULL;
  931. const wchar_t* wszText_;
  932. UINT32 cTextLength_;
  933. Direct2D();
  934. ~Direct2D();
  935. bool CreateDeviceIndependentResources(HWND m_hwnd);
  936. HRESULT CreateGraphicsResources(HWND m_hwnd);
  937. void DiscardGraphicsResources();
  938. void ReleaseFactory()
  939. {
  940. SafeRelease(&pFactory);
  941. SafeRelease(&pDWriteFactory_);
  942. }
  943. void CalculateLayout(HWND m_hwnd);
  944. void OnPaintScene(HWND m_hwnd);
  945. };
  946. MainWindow.cpp
  947. #include <Windows.h>
  948. #include "MainWindow.h"
  949. void MainWindow::OnPaint()
  950. {
  951. PAINTSTRUCT ps;
  952. BeginPaint(m_hwnd, &ps);
  953. d2d.OnPaintScene(m_hwnd);
  954. EndPaint(m_hwnd, &ps);
  955. }
  956. void MainWindow::Resize()
  957. {
  958. if (d2d.pRenderTarget != NULL)
  959. {
  960. RECT rc;
  961. GetClientRect(m_hwnd, &rc);
  962. D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
  963. d2d.pRenderTarget->Resize(size);
  964. d2d.CalculateLayout(m_hwnd);
  965. InvalidateRect(m_hwnd, NULL, FALSE);
  966. }
  967. }
  968. LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  969. {
  970. switch (uMsg)
  971. {
  972. case WM_CREATE:
  973. if (!d2d.CreateDeviceIndependentResources(m_hwnd))
  974. {
  975. return -1; // Неудача CreateWindowEx.
  976. }
  977. return 0;
  978. case WM_DESTROY:
  979. d2d.DiscardGraphicsResources();
  980. d2d.ReleaseFactory();
  981. PostQuitMessage(0);
  982. return 0;
  983. case WM_PAINT:
  984. OnPaint();
  985. return 0;
  986.  
  987. case WM_SIZE:
  988. Resize();
  989. return 0;
  990. }
  991. return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
  992. }
  993. MainWindow.h
  994. #pragma once
  995. #include "basewin.h"
  996. #include "Direct2D.h"
  997. class MainWindow : public BaseWindow<MainWindow> {
  998. Direct2D d2d;
  999. public:
  1000. void OnPaint();
  1001. void Resize();
  1002. PCWSTR ClassName() const { return L"MultiformattedText Window Class"; }
  1003. LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  1004. };
  1005. Source.cpp
  1006. #include <windows.h>
  1007. #include "MainWindow.h"
  1008. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
  1009. {
  1010. MainWindow win;
  1011. if (!win.Create(L"Многоформатный текст", WS_OVERLAPPEDWINDOW))
  1012. {
  1013. return 0;
  1014. }
  1015. ShowWindow(win.Window(), nCmdShow);
  1016. // Run the message loop.
  1017. MSG msg = {};
  1018. while (GetMessage(&msg, NULL, 0, 0))
  1019. {
  1020. TranslateMessage(&msg);
  1021. DispatchMessage(&msg);
  1022. }
  1023. return 0;
  1024. }
Advertisement
Add Comment
Please, Sign In to add comment