xref: /oneTBB/examples/common/gui/d2dvideo.cpp (revision 18e06f7f)
1 /*
2     Copyright (c) 2005-2022 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 // common Windows parts
18 #include "winvideo.hpp"
19 
20 // and another headers
21 #include <cassert>
22 #include <stdio.h>
23 #include <dxsdkver.h>
24 #if _DXSDK_PRODUCT_MAJOR < 9
25 #error DXSDK Version 9 and above required.
26 #endif
27 #include <d2d1.h>
28 #include <d2d1helper.h>
29 #pragma comment(lib, "d2d1.lib")
30 
31 ID2D1Factory *m_pD2DFactory;
32 ID2D1HwndRenderTarget *m_pRenderTarget;
33 ID2D1Bitmap *m_pBitmap;
34 D2D1_SIZE_U bitmapSize;
35 
36 HANDLE g_hVSync;
37 
38 #include <DXErr.h>
39 #pragma comment(lib, "DxErr.lib")
40 
41 //! Create a dialog box and tell the user what went wrong
42 bool DisplayError(LPSTR lpstrErr, HRESULT hres) {
43     if (hres != S_OK) {
44         static bool InError = false;
45         int retval = 0;
46         if (!InError) {
47             InError = true;
48             const char *message = hres ? DXGetErrorString(hres) : 0;
49             retval =
50                 MessageBoxA(g_hAppWnd, lpstrErr, hres ? message : "Error!", MB_OK | MB_ICONERROR);
51             InError = false;
52         }
53     }
54     return false;
55 }
56 
57 void DrawBitmap() {
58     HRESULT hr = S_OK;
59     if (m_pRenderTarget) {
60         m_pRenderTarget->BeginDraw();
61         if (m_pBitmap)
62             hr = m_pBitmap->CopyFromMemory(nullptr, (BYTE *)g_pImg, 4 * g_sizex);
63         DisplayError("DrawBitmap error", hr);
64         m_pRenderTarget->DrawBitmap(m_pBitmap);
65         m_pRenderTarget->EndDraw();
66     }
67     return;
68 }
69 
70 inline void mouse(int k, LPARAM lParam) {
71     int x = (int)LOWORD(lParam);
72     int y = (int)HIWORD(lParam);
73     RECT rc;
74     GetClientRect(g_hAppWnd, &rc);
75     g_video->on_mouse(x * g_sizex / (rc.right - rc.left), y * g_sizey / (rc.bottom - rc.top), k);
76 }
77 
78 //! Win event processing function
79 LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
80     switch (iMsg) {
81         case WM_MOVE:
82             // Check to make sure our window exists before we tell it to repaint.
83             // This will fail the first time (while the window is being created).
84             if (hwnd) {
85                 InvalidateRect(hwnd, nullptr, FALSE);
86                 UpdateWindow(hwnd);
87             }
88             return 0L;
89 
90         case WM_SIZE:
91         case WM_PAINT:
92             if (g_video->running && g_video->updating) {
93                 DrawBitmap();
94                 Sleep(0);
95             }
96             break;
97         // Process all mouse and keyboard events
98         case WM_LBUTTONDOWN: mouse(1, lParam); break;
99         case WM_LBUTTONUP: mouse(-1, lParam); break;
100         case WM_RBUTTONDOWN: mouse(2, lParam); break;
101         case WM_RBUTTONUP: mouse(-2, lParam); break;
102         case WM_MBUTTONDOWN: mouse(3, lParam); break;
103         case WM_MBUTTONUP: mouse(-3, lParam); break;
104         case WM_CHAR: g_video->on_key((int)wParam); break;
105 
106         // some useless stuff
107         case WM_ERASEBKGND: return 1; // keeps erase-background events from happening, reduces chop
108         case WM_DISPLAYCHANGE: return 0;
109 
110         // Now, shut down the window...
111         case WM_DESTROY: PostQuitMessage(0); return 0;
112     }
113     // call user defined proc, if exists
114     return g_pUserProc ? g_pUserProc(hwnd, iMsg, wParam, lParam)
115                        : DefWindowProc(hwnd, iMsg, wParam, lParam);
116 }
117 
118 bool video::init_window(int sizex, int sizey) {
119     assert(win_hInstance != 0);
120     g_sizex = sizex;
121     g_sizey = sizey;
122     if (!WinInit(win_hInstance, win_iCmdShow, gWndClass, title, false)) {
123         DisplayError("Unable to initialize the program's window.");
124         return false;
125     }
126     ShowWindow(g_hAppWnd, SW_SHOW);
127     g_pImg = new unsigned int[sizex * sizey];
128 
129     HRESULT hr = S_OK;
130 
131     hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
132     // Create a Direct2D render target.
133     if (SUCCEEDED(hr) && !m_pRenderTarget) {
134         RECT rc;
135         GetClientRect(g_hAppWnd, &rc);
136 
137         bitmapSize = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
138 
139         hr = m_pD2DFactory->CreateHwndRenderTarget(
140             D2D1::RenderTargetProperties(),
141             D2D1::HwndRenderTargetProperties(g_hAppWnd, bitmapSize),
142             &m_pRenderTarget);
143         if (SUCCEEDED(hr) && !m_pBitmap) {
144             D2D1_PIXEL_FORMAT pixelFormat =
145                 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
146             D2D1_BITMAP_PROPERTIES bitmapProperties;
147             bitmapProperties.pixelFormat = pixelFormat;
148             m_pRenderTarget->GetDpi(&bitmapProperties.dpiX, &bitmapProperties.dpiY);
149             m_pRenderTarget->CreateBitmap(bitmapSize, bitmapProperties, &m_pBitmap);
150             m_pRenderTarget->DrawBitmap(m_pBitmap);
151         }
152     }
153 
154     running = true;
155     return true;
156 }
157 
158 void video::terminate() {
159     if (m_pBitmap)
160         m_pBitmap->Release();
161     if (m_pRenderTarget)
162         m_pRenderTarget->Release();
163     if (m_pD2DFactory)
164         m_pD2DFactory->Release();
165     g_video = nullptr;
166     running = false;
167 
168     delete[] g_pImg;
169     g_pImg = nullptr;
170 }
171 
172 //////////// drawing area constructor & destructor /////////////
173 
174 drawing_area::drawing_area(int x, int y, int sizex, int sizey)
175         : base_index(y * g_sizex + x),
176           max_index(g_sizex * g_sizey),
177           index_stride(g_sizex),
178           pixel_depth(24),
179           ptr32(g_pImg),
180           start_x(x),
181           start_y(y),
182           size_x(sizex),
183           size_y(sizey) {
184     assert(x < g_sizex);
185     assert(y < g_sizey);
186     assert(x + sizex <= g_sizex);
187     assert(y + sizey <= g_sizey);
188 
189     index = base_index; // current index
190 }
191 
192 void drawing_area::update() {
193     if (g_video->updating) {
194         RECT r;
195         r.left = start_x;
196         r.right = start_x + size_x;
197         r.top = start_y;
198         r.bottom = start_y + size_y;
199         InvalidateRect(g_hAppWnd, &r, false);
200     }
201 }
202