rev |
line source |
nuclear@1
|
1 /*
|
nuclear@1
|
2 D3DUT - Simple window creation and event handling for Direct3D 11 applications.
|
nuclear@1
|
3 Copyright (C) 2013 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@1
|
4
|
nuclear@1
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@1
|
6 it under the terms of the GNU Lesser General Public License as published by
|
nuclear@1
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@1
|
8 (at your option) any later version.
|
nuclear@1
|
9
|
nuclear@1
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@1
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@1
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@1
|
13 GNU Lesser General Public License for more details.
|
nuclear@1
|
14
|
nuclear@1
|
15 You should have received a copy of the GNU Lesser General Public License
|
nuclear@1
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@1
|
17 */
|
nuclear@0
|
18 #include <dxgi.h>
|
nuclear@0
|
19 #include "d3dut.h"
|
nuclear@0
|
20 #include "win.h"
|
nuclear@0
|
21 #include "logmsg.h"
|
nuclear@0
|
22
|
nuclear@0
|
23 std::vector<Window*> windows;
|
nuclear@0
|
24 int active_win = -1;
|
nuclear@0
|
25
|
nuclear@0
|
26 int create_window(const char *title, int xsz, int ysz, unsigned int dmflags)
|
nuclear@0
|
27 {
|
nuclear@0
|
28 IDXGIDevice *dxgidev;
|
nuclear@0
|
29 if(d3dut_dev->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgidev) != 0) {
|
nuclear@0
|
30 fatal_error("failed to get IDXGIDevice interface\n");
|
nuclear@0
|
31 return 0;
|
nuclear@0
|
32 }
|
nuclear@0
|
33 IDXGIAdapter *adapter;
|
nuclear@0
|
34 if(dxgidev->GetParent(__uuidof(IDXGIAdapter), (void**)&adapter) != 0) {
|
nuclear@0
|
35 fatal_error("failed to get IDXGIAdapter pointer\n");
|
nuclear@0
|
36 return 0;
|
nuclear@0
|
37 }
|
nuclear@0
|
38 IDXGIFactory *dxgi_factory;
|
nuclear@0
|
39 if(adapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgi_factory) != 0) {
|
nuclear@0
|
40 fatal_error("failed to get IDXGIFactory pointer\n");
|
nuclear@0
|
41 return 0;
|
nuclear@0
|
42 }
|
nuclear@0
|
43 adapter->Release();
|
nuclear@0
|
44 dxgidev->Release();
|
nuclear@0
|
45
|
nuclear@0
|
46 Window *win = new Window;
|
nuclear@0
|
47 memset(win, 0, sizeof *win);
|
nuclear@0
|
48 win->must_redisplay = true;
|
nuclear@0
|
49 win->changed_size = true;
|
nuclear@0
|
50 win->width = xsz;
|
nuclear@0
|
51 win->height = ysz;
|
nuclear@0
|
52
|
nuclear@0
|
53 int xpos = (GetSystemMetrics(SM_CXSCREEN) - xsz) / 2;
|
nuclear@0
|
54 int ypos = (GetSystemMetrics(SM_CYSCREEN) - ysz) / 2;
|
nuclear@0
|
55 win->win = CreateWindow(WINCLASSNAME, title, WS_OVERLAPPEDWINDOW, xpos, ypos, xsz, ysz, 0, 0, GetModuleHandle(0), 0);
|
nuclear@0
|
56 if(!win->win) {
|
nuclear@0
|
57 fprintf(stderr, "failed to create window: %s\n", title);
|
nuclear@0
|
58 return 0;
|
nuclear@0
|
59 }
|
nuclear@0
|
60 ShowWindow(win->win, SW_SHOW);
|
nuclear@0
|
61
|
nuclear@0
|
62 unsigned int nsamples = 1;
|
nuclear@0
|
63 unsigned int quality = 0;
|
nuclear@0
|
64 if(dmflags & D3DUT_MULTISAMPLE) {
|
nuclear@0
|
65 nsamples = D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT;
|
nuclear@0
|
66 d3dut_dev->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, nsamples, &quality);
|
nuclear@0
|
67 }
|
nuclear@0
|
68
|
nuclear@0
|
69 DXGI_SWAP_CHAIN_DESC sd;
|
nuclear@0
|
70 memset(&sd, 0, sizeof sd);
|
nuclear@0
|
71 sd.OutputWindow = win->win;
|
nuclear@0
|
72 sd.BufferDesc.Width = xsz;
|
nuclear@0
|
73 sd.BufferDesc.Height = ysz;
|
nuclear@0
|
74 sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
nuclear@0
|
75 //sd.Stereo = (dmflags & D3DUT_STEREO) ? 1 : 0;
|
nuclear@0
|
76 sd.BufferDesc.RefreshRate.Numerator = 60;
|
nuclear@0
|
77 sd.BufferDesc.RefreshRate.Denominator = 1;
|
nuclear@0
|
78 sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
nuclear@0
|
79 sd.BufferCount = (dmflags & D3DUT_DOUBLE) ? 1 : 0;
|
nuclear@0
|
80 sd.SampleDesc.Count = nsamples;
|
nuclear@0
|
81 sd.SampleDesc.Quality = quality;
|
nuclear@0
|
82 sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
nuclear@0
|
83 sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
nuclear@0
|
84 sd.Windowed = 1;
|
nuclear@0
|
85
|
nuclear@0
|
86 if(dxgi_factory->CreateSwapChain(d3dut_dev, &sd, &win->swap) != 0) {
|
nuclear@0
|
87 warning("failed to create swap chain\n");
|
nuclear@0
|
88 return 0;
|
nuclear@0
|
89 }
|
nuclear@0
|
90 dxgi_factory->Release();
|
nuclear@0
|
91
|
nuclear@0
|
92 ID3D11Texture2D *rtex;
|
nuclear@0
|
93 if(win->swap->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&rtex) != 0) {
|
nuclear@0
|
94 warning("failed to get default render target texture\n");
|
nuclear@0
|
95 return 0;
|
nuclear@0
|
96 }
|
nuclear@0
|
97 if(d3dut_dev->CreateRenderTargetView(rtex, 0, &win->rtarg_view) != 0) {
|
nuclear@0
|
98 warning("failed to create render target view\n");
|
nuclear@0
|
99 rtex->Release();
|
nuclear@0
|
100 return 0;
|
nuclear@0
|
101 }
|
nuclear@0
|
102 rtex->Release();
|
nuclear@0
|
103 d3dut_ctx->OMSetRenderTargets(1, &win->rtarg_view, 0);
|
nuclear@0
|
104
|
nuclear@0
|
105 int idx = (int)windows.size();
|
nuclear@0
|
106 windows.push_back(win);
|
nuclear@0
|
107 set_active_win(idx);
|
nuclear@0
|
108 return idx;
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 void destroy_window(int idx)
|
nuclear@0
|
112 {
|
nuclear@0
|
113 if(idx < 0 || idx >= (int)windows.size()) {
|
nuclear@0
|
114 warning("destroy_window: invalid index: %d\n", idx);
|
nuclear@0
|
115 return;
|
nuclear@0
|
116 }
|
nuclear@0
|
117
|
nuclear@0
|
118 Window *win = windows[idx];
|
nuclear@0
|
119 if(win) {
|
nuclear@0
|
120 DestroyWindow(win->win);
|
nuclear@0
|
121 win->rtarg_view->Release();
|
nuclear@0
|
122 win->swap->Release();
|
nuclear@0
|
123 delete win;
|
nuclear@0
|
124 windows[idx] = 0;
|
nuclear@0
|
125 }
|
nuclear@0
|
126 }
|
nuclear@0
|
127
|
nuclear@0
|
128 void set_active_win(int idx)
|
nuclear@0
|
129 {
|
nuclear@0
|
130 if(idx < 0 || idx >= (int)windows.size()) {
|
nuclear@0
|
131 warning("set_active_win: invalid window: %d\n", idx);
|
nuclear@0
|
132 return;
|
nuclear@0
|
133 }
|
nuclear@0
|
134 d3dut_rtview = windows[idx]->rtarg_view;
|
nuclear@0
|
135 active_win = idx;
|
nuclear@0
|
136 }
|
nuclear@0
|
137
|
nuclear@0
|
138 int get_active_win()
|
nuclear@0
|
139 {
|
nuclear@0
|
140 return active_win;
|
nuclear@0
|
141 }
|
nuclear@0
|
142
|
nuclear@0
|
143 Window *get_window(int idx)
|
nuclear@0
|
144 {
|
nuclear@0
|
145 if(idx < 0) {
|
nuclear@0
|
146 idx = active_win;
|
nuclear@0
|
147 }
|
nuclear@0
|
148 if(idx < 0 || idx >= (int)windows.size()) {
|
nuclear@0
|
149 return 0;
|
nuclear@0
|
150 }
|
nuclear@0
|
151 return windows[idx];
|
nuclear@0
|
152 }
|
nuclear@0
|
153
|
nuclear@0
|
154 static int find_window(HWND syswin)
|
nuclear@0
|
155 {
|
nuclear@0
|
156 for(size_t i=0; i<windows.size(); i++) {
|
nuclear@0
|
157 if(windows[i]->win == syswin) {
|
nuclear@0
|
158 return i;
|
nuclear@0
|
159 }
|
nuclear@0
|
160 }
|
nuclear@0
|
161 return -1;
|
nuclear@0
|
162 }
|
nuclear@0
|
163
|
nuclear@0
|
164 static void mouse_handler(Window *win, int bn, bool pressed);
|
nuclear@0
|
165
|
nuclear@0
|
166 long CALLBACK win_handle_event(HWND syswin, unsigned int msg, unsigned int wparam, long lparam)
|
nuclear@0
|
167 {
|
nuclear@0
|
168 Window *win = 0;
|
nuclear@0
|
169 int winid = find_window(syswin);
|
nuclear@0
|
170 if(winid != -1) {
|
nuclear@0
|
171 set_active_win(winid);
|
nuclear@0
|
172 win = get_window();
|
nuclear@0
|
173 }
|
nuclear@0
|
174
|
nuclear@0
|
175 switch(msg) {
|
nuclear@0
|
176 case WM_PAINT:
|
nuclear@0
|
177 win->must_redisplay = true;
|
nuclear@0
|
178 ValidateRect(win->win, 0);
|
nuclear@0
|
179 break;
|
nuclear@0
|
180
|
nuclear@0
|
181 case WM_CLOSE:
|
nuclear@0
|
182 destroy_window(winid);
|
nuclear@0
|
183 break;
|
nuclear@0
|
184
|
nuclear@0
|
185 case WM_SIZE:
|
nuclear@0
|
186 win->width = LOWORD(lparam);
|
nuclear@0
|
187 win->height = HIWORD(lparam);
|
nuclear@0
|
188 win->changed_size = true;
|
nuclear@0
|
189 break;
|
nuclear@0
|
190
|
nuclear@0
|
191 case WM_KEYDOWN:
|
nuclear@0
|
192 if(wparam < 256) {
|
nuclear@0
|
193 if(win->keyboard_func) {
|
nuclear@0
|
194 win->keyboard_func(wparam, win->mousex, win->mousey);
|
nuclear@0
|
195 }
|
nuclear@0
|
196 } else {
|
nuclear@0
|
197 if(win->special_func) {
|
nuclear@0
|
198 win->special_func(wparam, win->mousex, win->mousey);
|
nuclear@0
|
199 }
|
nuclear@0
|
200 }
|
nuclear@0
|
201 break;
|
nuclear@0
|
202
|
nuclear@0
|
203 case WM_KEYUP:
|
nuclear@0
|
204 if(wparam < 256) {
|
nuclear@0
|
205 if(win->keyboard_up_func) {
|
nuclear@0
|
206 win->keyboard_up_func(wparam, win->mousex, win->mousey);
|
nuclear@0
|
207 }
|
nuclear@0
|
208 } else {
|
nuclear@0
|
209 if(win->special_up_func) {
|
nuclear@0
|
210 win->special_up_func(wparam, win->mousex, win->mousey);
|
nuclear@0
|
211 }
|
nuclear@0
|
212 }
|
nuclear@0
|
213 break;
|
nuclear@0
|
214
|
nuclear@0
|
215 case WM_MOUSEMOVE:
|
nuclear@0
|
216 win->mousex = LOWORD(lparam);
|
nuclear@0
|
217 win->mousey = HIWORD(lparam);
|
nuclear@0
|
218
|
nuclear@0
|
219 if(wparam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) {
|
nuclear@0
|
220 if(win->motion_func) {
|
nuclear@0
|
221 win->motion_func(win->mousex, win->mousey);
|
nuclear@0
|
222 }
|
nuclear@0
|
223 } else {
|
nuclear@0
|
224 if(win->passive_motion_func) {
|
nuclear@0
|
225 win->passive_motion_func(win->mousex, win->mousey);
|
nuclear@0
|
226 }
|
nuclear@0
|
227 }
|
nuclear@0
|
228 break;
|
nuclear@0
|
229
|
nuclear@0
|
230 case WM_LBUTTONDOWN:
|
nuclear@0
|
231 mouse_handler(win, D3DUT_LEFT_BUTTON, true);
|
nuclear@0
|
232 break;
|
nuclear@0
|
233 case WM_RBUTTONDOWN:
|
nuclear@0
|
234 mouse_handler(win, D3DUT_RIGHT_BUTTON, true);
|
nuclear@0
|
235 break;
|
nuclear@0
|
236 case WM_MBUTTONDOWN:
|
nuclear@0
|
237 mouse_handler(win, D3DUT_MIDDLE_BUTTON, true);
|
nuclear@0
|
238 break;
|
nuclear@0
|
239 case WM_LBUTTONUP:
|
nuclear@0
|
240 mouse_handler(win, D3DUT_LEFT_BUTTON, false);
|
nuclear@0
|
241 break;
|
nuclear@0
|
242 case WM_RBUTTONUP:
|
nuclear@0
|
243 mouse_handler(win, D3DUT_RIGHT_BUTTON, false);
|
nuclear@0
|
244 break;
|
nuclear@0
|
245 case WM_MBUTTONUP:
|
nuclear@0
|
246 mouse_handler(win, D3DUT_MIDDLE_BUTTON, false);
|
nuclear@0
|
247 break;
|
nuclear@0
|
248
|
nuclear@0
|
249 case WM_MOUSEWHEEL:
|
nuclear@0
|
250 {
|
nuclear@0
|
251 int delta = GET_WHEEL_DELTA_WPARAM(wparam);
|
nuclear@0
|
252 mouse_handler(win, delta < 0 ? D3DUT_WHEELDOWN_BUTTON : D3DUT_WHEELUP_BUTTON, true);
|
nuclear@0
|
253 }
|
nuclear@0
|
254 break;
|
nuclear@0
|
255
|
nuclear@0
|
256 default:
|
nuclear@0
|
257 return DefWindowProc(syswin, msg, wparam, lparam);
|
nuclear@0
|
258 }
|
nuclear@0
|
259
|
nuclear@0
|
260 return 0;
|
nuclear@0
|
261 }
|
nuclear@0
|
262
|
nuclear@0
|
263 static void mouse_handler(Window *win, int bn, bool pressed)
|
nuclear@0
|
264 {
|
nuclear@0
|
265 if(win->mouse_func) {
|
nuclear@0
|
266 win->mouse_func(bn, pressed ? D3DUT_DOWN : D3DUT_UP, win->mousex, win->mousey);
|
nuclear@0
|
267 }
|
nuclear@1
|
268 }
|