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.h"
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
DisplayError(LPSTR lpstrErr,HRESULT hres)42 bool DisplayError(LPSTR lpstrErr, HRESULT hres)
43 {
44     if(hres != S_OK){
45         static bool InError = false;
46         int retval = 0;
47         if (!InError)
48         {
49             InError = true;
50             const char *message = hres?DXGetErrorString(hres):0;
51             retval = MessageBoxA(g_hAppWnd, lpstrErr, hres?message:"Error!", MB_OK|MB_ICONERROR);
52             InError = false;
53         }
54     }
55     return false;
56 }
57 
DrawBitmap()58 void DrawBitmap()
59 {
60     HRESULT hr = S_OK;
61     if (m_pRenderTarget) {
62         m_pRenderTarget->BeginDraw();
63         if (m_pBitmap)
64             hr = m_pBitmap->CopyFromMemory(NULL,(BYTE*)g_pImg, 4*g_sizex);
65         DisplayError( "DrawBitmap error", hr );
66         m_pRenderTarget->DrawBitmap(m_pBitmap);
67         m_pRenderTarget->EndDraw();
68     }
69     return;
70 }
71 
mouse(int k,LPARAM lParam)72 inline void mouse(int k, LPARAM lParam)
73 {
74     int x = (int)LOWORD(lParam);
75     int y = (int)HIWORD(lParam);
76     RECT rc;
77     GetClientRect(g_hAppWnd, &rc);
78     g_video->on_mouse( x*g_sizex/(rc.right - rc.left), y*g_sizey/(rc.bottom - rc.top), k );
79 }
80 
81 //! Win event processing function
InternalWndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)82 LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
83 {
84     switch (iMsg)
85     {
86         case WM_MOVE:
87             // Check to make sure our window exists before we tell it to repaint.
88             // This will fail the first time (while the window is being created).
89             if (hwnd) {
90                 InvalidateRect(hwnd, NULL, FALSE);
91                 UpdateWindow(hwnd);
92             }
93             return 0L;
94 
95         case WM_SIZE:
96         case WM_PAINT:
97             if( g_video->running && g_video->updating ) {
98                 DrawBitmap();
99                 Sleep(0);
100             }
101             break;
102         // Process all mouse and keyboard events
103         case WM_LBUTTONDOWN:    mouse( 1, lParam ); break;
104         case WM_LBUTTONUP:      mouse(-1, lParam ); break;
105         case WM_RBUTTONDOWN:    mouse( 2, lParam ); break;
106         case WM_RBUTTONUP:      mouse(-2, lParam ); break;
107         case WM_MBUTTONDOWN:    mouse( 3, lParam ); break;
108         case WM_MBUTTONUP:      mouse(-3, lParam ); break;
109         case WM_CHAR:           g_video->on_key( (int)wParam); break;
110 
111         // some useless stuff
112         case WM_ERASEBKGND:     return 1;  // keeps erase-background events from happening, reduces chop
113         case WM_DISPLAYCHANGE:  return 0;
114 
115         // Now, shut down the window...
116         case WM_DESTROY:        PostQuitMessage(0); return 0;
117     }
118     // call user defined proc, if exists
119     return g_pUserProc? g_pUserProc(hwnd, iMsg, wParam, lParam) : DefWindowProc(hwnd, iMsg, wParam, lParam);
120 }
121 
init_window(int sizex,int sizey)122 bool video::init_window(int sizex, int sizey)
123 {
124     assert(win_hInstance != 0);
125     g_sizex = sizex; g_sizey = sizey;
126     if (!WinInit(win_hInstance, win_iCmdShow, gWndClass, title, false)) {
127         DisplayError("Unable to initialize the program's window.");
128         return false;
129     }
130     ShowWindow(g_hAppWnd, SW_SHOW);
131     g_pImg = new unsigned int[sizex*sizey];
132 
133     HRESULT hr = S_OK;
134 
135     hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
136     // Create a Direct2D render target.
137     if (SUCCEEDED(hr) && !m_pRenderTarget){
138         RECT rc;
139         GetClientRect(g_hAppWnd, &rc);
140 
141         bitmapSize = D2D1::SizeU(
142             rc.right - rc.left,
143             rc.bottom - rc.top
144             );
145 
146         hr = m_pD2DFactory->CreateHwndRenderTarget(
147             D2D1::RenderTargetProperties(),
148             D2D1::HwndRenderTargetProperties(g_hAppWnd, bitmapSize),
149             &m_pRenderTarget
150             );
151         if (SUCCEEDED(hr) && !m_pBitmap){
152             D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat(
153                 DXGI_FORMAT_B8G8R8A8_UNORM,
154                 D2D1_ALPHA_MODE_IGNORE
155                 );
156             D2D1_BITMAP_PROPERTIES bitmapProperties;
157             bitmapProperties.pixelFormat = pixelFormat;
158             m_pRenderTarget->GetDpi( &bitmapProperties.dpiX, &bitmapProperties.dpiY );
159             m_pRenderTarget->CreateBitmap(bitmapSize,bitmapProperties,&m_pBitmap);
160             m_pRenderTarget->DrawBitmap(m_pBitmap);
161         }
162     }
163 
164     running = true;
165     return true;
166 }
167 
terminate()168 void video::terminate()
169 {
170     if (m_pBitmap) m_pBitmap->Release();
171     if (m_pRenderTarget) m_pRenderTarget->Release();
172     if (m_pD2DFactory) m_pD2DFactory->Release();
173     g_video = 0; running = false;
174     if(g_pImg) { delete[] g_pImg; g_pImg = 0; }
175 }
176 
177 //////////// drawing area constructor & destructor /////////////
178 
drawing_area(int x,int y,int sizex,int sizey)179 drawing_area::drawing_area(int x, int y, int sizex, int sizey)
180     : base_index(y*g_sizex + x), max_index(g_sizex*g_sizey), index_stride(g_sizex),
181     pixel_depth(24), ptr32(g_pImg), start_x(x), start_y(y), size_x(sizex), size_y(sizey)
182 {
183     assert(x < g_sizex); assert(y < g_sizey);
184     assert(x+sizex <= g_sizex); assert(y+sizey <= g_sizey);
185 
186     index = base_index; // current index
187 }
188 
update()189 void drawing_area::update()
190 {
191     if(g_video->updating) {
192         RECT r;
193         r.left = start_x; r.right  = start_x + size_x;
194         r.top  = start_y; r.bottom = start_y + size_y;
195         InvalidateRect(g_hAppWnd, &r, false);
196     }
197 }
198