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