1 /* 2 Copyright (c) 2005-2020 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(NULL, (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, NULL, 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 = 0; 166 running = false; 167 if (g_pImg) { 168 delete[] g_pImg; 169 g_pImg = 0; 170 } 171 } 172 173 //////////// drawing area constructor & destructor ///////////// 174 175 drawing_area::drawing_area(int x, int y, int sizex, int sizey) 176 : base_index(y * g_sizex + x), 177 max_index(g_sizex * g_sizey), 178 index_stride(g_sizex), 179 pixel_depth(24), 180 ptr32(g_pImg), 181 start_x(x), 182 start_y(y), 183 size_x(sizex), 184 size_y(sizey) { 185 assert(x < g_sizex); 186 assert(y < g_sizey); 187 assert(x + sizex <= g_sizex); 188 assert(y + sizey <= g_sizey); 189 190 index = base_index; // current index 191 } 192 193 void drawing_area::update() { 194 if (g_video->updating) { 195 RECT r; 196 r.left = start_x; 197 r.right = start_x + size_x; 198 r.top = start_y; 199 r.bottom = start_y + size_y; 200 InvalidateRect(g_hAppWnd, &r, false); 201 } 202 } 203