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 // include GDI+ headers
20d86ed7fbStbbdev #include <gdiplus.h>
21d86ed7fbStbbdev // and another headers
22d86ed7fbStbbdev #include <stdio.h>
23d86ed7fbStbbdev
24d86ed7fbStbbdev // tag linking library
25d86ed7fbStbbdev #pragma comment(lib, "gdiplus.lib")
26d86ed7fbStbbdev
27d86ed7fbStbbdev // global specific variables
28d86ed7fbStbbdev Gdiplus::Bitmap* g_pBitmap; // main drawing bitmap
29d86ed7fbStbbdev ULONG_PTR gdiplusToken;
30d86ed7fbStbbdev Gdiplus::GdiplusStartupInput gdiplusStartupInput; // GDI+
31d86ed7fbStbbdev
32d86ed7fbStbbdev //! display system error
DisplayError(LPSTR lpstrErr,HRESULT hres)33d86ed7fbStbbdev bool DisplayError(LPSTR lpstrErr, HRESULT hres) {
34d86ed7fbStbbdev static bool InError = false;
35d86ed7fbStbbdev int retval = 0;
36d86ed7fbStbbdev if (!InError) {
37d86ed7fbStbbdev InError = true;
38d86ed7fbStbbdev LPCSTR lpMsgBuf;
39d86ed7fbStbbdev if (!hres)
40d86ed7fbStbbdev hres = GetLastError();
41d86ed7fbStbbdev FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
42d86ed7fbStbbdev FORMAT_MESSAGE_IGNORE_INSERTS,
4357f524caSIlya Isaev nullptr,
44d86ed7fbStbbdev hres,
45d86ed7fbStbbdev MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
46d86ed7fbStbbdev (LPTSTR)&lpMsgBuf,
47d86ed7fbStbbdev 0,
4857f524caSIlya Isaev nullptr);
49d86ed7fbStbbdev retval = MessageBox(g_hAppWnd, lpstrErr, lpMsgBuf, MB_OK | MB_ICONERROR);
50d86ed7fbStbbdev LocalFree((HLOCAL)lpMsgBuf);
51d86ed7fbStbbdev InError = false;
52d86ed7fbStbbdev }
53d86ed7fbStbbdev return false;
54d86ed7fbStbbdev }
55d86ed7fbStbbdev
56d86ed7fbStbbdev //! Win event processing function
InternalWndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)57d86ed7fbStbbdev LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
58d86ed7fbStbbdev switch (iMsg) {
59d86ed7fbStbbdev case WM_MOVE:
60d86ed7fbStbbdev // Check to make sure our window exists before we tell it to repaint.
61d86ed7fbStbbdev // This will fail the first time (while the window is being created).
62d86ed7fbStbbdev if (hwnd) {
6357f524caSIlya Isaev InvalidateRect(hwnd, nullptr, FALSE);
64d86ed7fbStbbdev UpdateWindow(hwnd);
65d86ed7fbStbbdev }
66d86ed7fbStbbdev return 0L;
67d86ed7fbStbbdev
68d86ed7fbStbbdev case WM_PAINT: {
69d86ed7fbStbbdev PAINTSTRUCT ps;
70d86ed7fbStbbdev Gdiplus::Graphics graphics(BeginPaint(hwnd, &ps));
71d86ed7fbStbbdev // redraw just requested area. This call is as fast as simple DrawImage() call.
72d86ed7fbStbbdev if (g_video->updating)
73d86ed7fbStbbdev graphics.DrawImage(g_pBitmap,
74d86ed7fbStbbdev ps.rcPaint.left,
75d86ed7fbStbbdev ps.rcPaint.top,
76d86ed7fbStbbdev ps.rcPaint.left,
77d86ed7fbStbbdev ps.rcPaint.top,
78d86ed7fbStbbdev ps.rcPaint.right,
79d86ed7fbStbbdev ps.rcPaint.bottom,
80d86ed7fbStbbdev Gdiplus::UnitPixel);
81d86ed7fbStbbdev EndPaint(hwnd, &ps);
82d86ed7fbStbbdev }
83d86ed7fbStbbdev return 0L;
84d86ed7fbStbbdev
85d86ed7fbStbbdev // Process all mouse and keyboard events
86d86ed7fbStbbdev case WM_LBUTTONDOWN: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), 1); break;
87d86ed7fbStbbdev case WM_LBUTTONUP: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), -1); break;
88d86ed7fbStbbdev case WM_RBUTTONDOWN: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), 2); break;
89d86ed7fbStbbdev case WM_RBUTTONUP: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), -2); break;
90d86ed7fbStbbdev case WM_MBUTTONDOWN: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), 3); break;
91d86ed7fbStbbdev case WM_MBUTTONUP: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), -3); break;
92d86ed7fbStbbdev case WM_CHAR: g_video->on_key((int)wParam); break;
93d86ed7fbStbbdev
94d86ed7fbStbbdev // some useless stuff
95d86ed7fbStbbdev case WM_ERASEBKGND: return 1; // keeps erase-background events from happening, reduces chop
96d86ed7fbStbbdev case WM_DISPLAYCHANGE: return 0;
97d86ed7fbStbbdev
98d86ed7fbStbbdev // Now, shut down the window...
99d86ed7fbStbbdev case WM_DESTROY: PostQuitMessage(0); return 0;
100d86ed7fbStbbdev }
101d86ed7fbStbbdev // call user defined proc, if exists
102d86ed7fbStbbdev return g_pUserProc ? g_pUserProc(hwnd, iMsg, wParam, lParam)
103d86ed7fbStbbdev : DefWindowProc(hwnd, iMsg, wParam, lParam);
104d86ed7fbStbbdev }
105d86ed7fbStbbdev
106d86ed7fbStbbdev ///////////// video functions ////////////////
107d86ed7fbStbbdev
init_window(int sizex,int sizey)108d86ed7fbStbbdev bool video::init_window(int sizex, int sizey) {
109d86ed7fbStbbdev assert(win_hInstance != 0);
110d86ed7fbStbbdev g_sizex = sizex;
111d86ed7fbStbbdev g_sizey = sizey;
112d86ed7fbStbbdev if (!WinInit(win_hInstance, win_iCmdShow, gWndClass, title, true)) {
113d86ed7fbStbbdev DisplayError("Unable to initialize the program's window.");
114d86ed7fbStbbdev return false;
115d86ed7fbStbbdev }
116d86ed7fbStbbdev ShowWindow(g_hAppWnd, SW_SHOW);
11757f524caSIlya Isaev Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
118d86ed7fbStbbdev g_pImg = new unsigned int[sizex * sizey];
119d86ed7fbStbbdev g_pBitmap =
120d86ed7fbStbbdev new Gdiplus::Bitmap(g_sizex, g_sizey, 4 * g_sizex, PixelFormat32bppRGB, (BYTE*)g_pImg);
121d86ed7fbStbbdev running = true;
122d86ed7fbStbbdev return true;
123d86ed7fbStbbdev }
124d86ed7fbStbbdev
terminate()125d86ed7fbStbbdev void video::terminate() {
126d86ed7fbStbbdev delete g_pBitmap;
12757f524caSIlya Isaev g_pBitmap = nullptr;
128ba947f18SIlya Isaev
129d86ed7fbStbbdev Gdiplus::GdiplusShutdown(gdiplusToken);
13057f524caSIlya Isaev g_video = nullptr;
131d86ed7fbStbbdev running = false;
132ba947f18SIlya Isaev
133d86ed7fbStbbdev delete[] g_pImg;
13457f524caSIlya Isaev g_pImg = nullptr;
135d86ed7fbStbbdev }
136d86ed7fbStbbdev
137d86ed7fbStbbdev //////////// drawing area constructor & destructor /////////////
138d86ed7fbStbbdev
drawing_area(int x,int y,int sizex,int sizey)139d86ed7fbStbbdev drawing_area::drawing_area(int x, int y, int sizex, int sizey)
140d86ed7fbStbbdev : base_index(y * g_sizex + x),
141d86ed7fbStbbdev max_index(g_sizex * g_sizey),
142d86ed7fbStbbdev index_stride(g_sizex),
143d86ed7fbStbbdev pixel_depth(24),
144d86ed7fbStbbdev ptr32(g_pImg),
145d86ed7fbStbbdev start_x(x),
146d86ed7fbStbbdev start_y(y),
147d86ed7fbStbbdev size_x(sizex),
148d86ed7fbStbbdev size_y(sizey) {
149d86ed7fbStbbdev assert(x < g_sizex);
150d86ed7fbStbbdev assert(y < g_sizey);
151d86ed7fbStbbdev assert(x + sizex <= g_sizex);
152d86ed7fbStbbdev assert(y + sizey <= g_sizey);
153d86ed7fbStbbdev
154d86ed7fbStbbdev index = base_index; // current index
155d86ed7fbStbbdev }
156d86ed7fbStbbdev
update()157d86ed7fbStbbdev void drawing_area::update() {
158d86ed7fbStbbdev if (g_video->updating) {
159d86ed7fbStbbdev RECT r;
160d86ed7fbStbbdev r.left = start_x;
161d86ed7fbStbbdev r.right = start_x + size_x;
162d86ed7fbStbbdev r.top = start_y;
163d86ed7fbStbbdev r.bottom = start_y + size_y;
164d86ed7fbStbbdev InvalidateRect(g_hAppWnd, &r, false);
165d86ed7fbStbbdev }
166d86ed7fbStbbdev }
167