]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CIrrDeviceWin32.h
Use swap_control from MESA and EXT before SGI
[irrlicht.git] / source / Irrlicht / CIrrDeviceWin32.h
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #ifndef __C_IRR_DEVICE_WIN32_H_INCLUDED__\r
6 #define __C_IRR_DEVICE_WIN32_H_INCLUDED__\r
7 \r
8 #include "IrrCompileConfig.h"\r
9 #ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_\r
10 \r
11 #include "CIrrDeviceStub.h"\r
12 #include "IrrlichtDevice.h"\r
13 #include "IImagePresenter.h"\r
14 \r
15 #define WIN32_LEAN_AND_MEAN\r
16 #include <windows.h>\r
17 #include <mmsystem.h> // For JOYCAPS\r
18 #include <windowsx.h>\r
19 #if !defined(GET_X_LPARAM)\r
20 #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))\r
21 #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))\r
22 #endif\r
23 \r
24 namespace irr\r
25 {\r
26         struct SJoystickWin32Control;\r
27 \r
28         class CIrrDeviceWin32 : public CIrrDeviceStub, video::IImagePresenter\r
29         {\r
30         friend struct SJoystickWin32Control;\r
31         public:\r
32 \r
33                 //! constructor\r
34                 CIrrDeviceWin32(const SIrrlichtCreationParameters& params);\r
35 \r
36                 //! destructor\r
37                 virtual ~CIrrDeviceWin32();\r
38 \r
39                 //! runs the device. Returns false if device wants to be deleted\r
40                 bool run() override;\r
41 \r
42                 //! Cause the device to temporarily pause execution and let other processes to run\r
43                 // This should bring down processor usage without major performance loss for Irrlicht\r
44                 void yield() override;\r
45 \r
46                 //! Pause execution and let other processes to run for a specified amount of time.\r
47                 void sleep(u32 timeMs, bool pauseTimer) override;\r
48 \r
49                 //! sets the caption of the window\r
50                 void setWindowCaption(const wchar_t* text) override;\r
51 \r
52                 //! returns if window is active. if not, nothing need to be drawn\r
53                 bool isWindowActive() const override;\r
54 \r
55                 //! returns if window has focus\r
56                 bool isWindowFocused() const override;\r
57 \r
58                 //! returns if window is minimized\r
59                 bool isWindowMinimized() const override;\r
60 \r
61                 //! presents a surface in the client area\r
62                 bool present(video::IImage* surface, void* windowId=0, core::rect<s32>* src=0) override;\r
63 \r
64                 //! notifies the device that it should close itself\r
65                 void closeDevice() override;\r
66 \r
67                 //! Notifies the device, that it has been resized\r
68                 /** Must be publis as it is called from free function (event handler) */\r
69                 void OnResized();\r
70 \r
71                 //! Sets if the window should be resizable in windowed mode.\r
72                 void setResizable(bool resize=false) override;\r
73 \r
74                 //! Resize the render window.\r
75                 void setWindowSize(const irr::core::dimension2d<u32>& size) override;\r
76 \r
77                 //! Minimizes the window.\r
78                 void minimizeWindow() override;\r
79 \r
80                 //! Maximizes the window.\r
81                 void maximizeWindow() override;\r
82 \r
83                 //! Restores the window size.\r
84                 void restoreWindow() override;\r
85 \r
86                 //! Get the position of the window on screen\r
87                 core::position2di getWindowPosition() override;\r
88 \r
89                 //! Activate any joysticks, and generate events for them.\r
90                 bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo) override;\r
91 \r
92                 //! Remove all messages pending in the system message loop\r
93                 void clearSystemMessages() override;\r
94 \r
95                 //! Get the device type\r
96                 E_DEVICE_TYPE getType() const override\r
97                 {\r
98                         return EIDT_WIN32;\r
99                 }\r
100 \r
101                 //! Compares to the last call of this function to return double and triple clicks.\r
102                 //! \return Returns only 1,2 or 3. A 4th click will start with 1 again.\r
103                 u32 checkSuccessiveClicks(s32 mouseX, s32 mouseY, EMOUSE_INPUT_EVENT inputEvent ) override\r
104                 {\r
105                         // we just have to make it public\r
106                         return CIrrDeviceStub::checkSuccessiveClicks(mouseX, mouseY, inputEvent );\r
107                 }\r
108 \r
109                 //! Switch to fullscreen\r
110                 bool switchToFullScreen();\r
111 \r
112                 // convert an Irrlicht texture to a windows cursor\r
113                 HCURSOR TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot);\r
114 \r
115                 //! Implementation of the win32 cursor control\r
116                 class CCursorControl : public gui::ICursorControl\r
117                 {\r
118                 public:\r
119 \r
120                         CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen);\r
121                         ~CCursorControl();\r
122 \r
123                         //! Changes the visible state of the mouse cursor.\r
124                         void setVisible(bool visible) override\r
125                         {\r
126                                 CURSORINFO info;\r
127                                 info.cbSize = sizeof(CURSORINFO);\r
128                                 BOOL gotCursorInfo = GetCursorInfo(&info);\r
129                                 while ( gotCursorInfo )\r
130                                 {\r
131 #ifdef CURSOR_SUPPRESSED\r
132                                         // Since Windows 8 the cursor can be suppressed by a touch interface\r
133                                         if (visible && info.flags == CURSOR_SUPPRESSED)\r
134                                         {\r
135                                                 break;\r
136                                         }\r
137 #endif\r
138                                         if ( (visible && info.flags == CURSOR_SHOWING) || // visible\r
139                                                 (!visible && info.flags == 0 ) ) // hidden\r
140                                         {\r
141                                                 break;\r
142                                         }\r
143                                         // this only increases an internal\r
144                                         // display counter in windows, so it\r
145                                         // might have to be called some more\r
146                                         const int showResult = ShowCursor(visible);\r
147                                         // if result has correct sign we can\r
148                                         // stop here as well\r
149                                         if (( !visible && showResult < 0 ) ||\r
150                                                 (visible && showResult >= 0))\r
151                                                 break;\r
152                                         // yes, it really must be set each time\r
153                                         info.cbSize = sizeof(CURSORINFO);\r
154                                         gotCursorInfo = GetCursorInfo(&info);\r
155 \r
156 #ifdef CURSOR_SUPPRESSED\r
157                                         // Not sure if a cursor which we tried to hide still can be suppressed.\r
158                                         // I have no touch-display for testing this and MSDN doesn't describe it.\r
159                                         // But adding this check shouldn't hurt and might prevent an endless loop.\r
160                                         if (!visible && info.flags == CURSOR_SUPPRESSED)\r
161                                         {\r
162                                                 break;\r
163                                         }\r
164 #endif\r
165                                 }\r
166                                 IsVisible = visible;\r
167                         }\r
168 \r
169                         //! Returns if the cursor is currently visible.\r
170                         bool isVisible() const override\r
171                         {\r
172                                 return IsVisible;\r
173                         }\r
174 \r
175                         //! Sets the new position of the cursor.\r
176                         void setPosition(const core::position2d<f32> &pos) override\r
177                         {\r
178                                 setPosition(pos.X, pos.Y);\r
179                         }\r
180 \r
181                         //! Sets the new position of the cursor.\r
182                         void setPosition(f32 x, f32 y) override\r
183                         {\r
184                                 if (!UseReferenceRect)\r
185                                         setPosition(core::round32(x*WindowSize.Width), core::round32(y*WindowSize.Height));\r
186                                 else\r
187                                         setPosition(core::round32(x*ReferenceRect.getWidth()), core::round32(y*ReferenceRect.getHeight()));\r
188                         }\r
189 \r
190                         //! Sets the new position of the cursor.\r
191                         void setPosition(const core::position2d<s32> &pos) override\r
192                         {\r
193                                 setPosition(pos.X, pos.Y);\r
194                         }\r
195 \r
196                         //! Sets the new position of the cursor.\r
197                         void setPosition(s32 x, s32 y) override\r
198                         {\r
199                                 if (UseReferenceRect)\r
200                                 {\r
201                                         SetCursorPos(ReferenceRect.UpperLeftCorner.X + x,\r
202                                                                 ReferenceRect.UpperLeftCorner.Y + y);\r
203                                 }\r
204                                 else\r
205                                 {\r
206                                         RECT rect;\r
207                                         if (GetWindowRect(HWnd, &rect))\r
208                                                 SetCursorPos(x + rect.left + BorderX, y + rect.top + BorderY);\r
209                                 }\r
210 \r
211                                 CursorPos.X = x;\r
212                                 CursorPos.Y = y;\r
213                         }\r
214 \r
215                         //! Returns the current position of the mouse cursor.\r
216                         const core::position2d<s32>& getPosition(bool updateCursor) override\r
217                         {\r
218                                 if ( updateCursor )\r
219                                         updateInternalCursorPosition();\r
220                                 return CursorPos;\r
221                         }\r
222 \r
223                         //! Returns the current position of the mouse cursor.\r
224                         core::position2d<f32> getRelativePosition(bool updateCursor) override\r
225                         {\r
226                                 if ( updateCursor )\r
227                                         updateInternalCursorPosition();\r
228 \r
229                                 if (!UseReferenceRect)\r
230                                 {\r
231                                         return core::position2d<f32>(CursorPos.X * InvWindowSize.Width,\r
232                                                 CursorPos.Y * InvWindowSize.Height);\r
233                                 }\r
234 \r
235                                 return core::position2d<f32>(CursorPos.X / (f32)ReferenceRect.getWidth(),\r
236                                                 CursorPos.Y / (f32)ReferenceRect.getHeight());\r
237                         }\r
238 \r
239                         //! Sets an absolute reference rect for calculating the cursor position.\r
240                         void setReferenceRect(core::rect<s32>* rect=0) override\r
241                         {\r
242                                 if (rect)\r
243                                 {\r
244                                         ReferenceRect = *rect;\r
245                                         UseReferenceRect = true;\r
246 \r
247                                         // prevent division through zero and uneven sizes\r
248 \r
249                                         if (!ReferenceRect.getHeight() || ReferenceRect.getHeight()%2)\r
250                                                 ReferenceRect.LowerRightCorner.Y += 1;\r
251 \r
252                                         if (!ReferenceRect.getWidth() || ReferenceRect.getWidth()%2)\r
253                                                 ReferenceRect.LowerRightCorner.X += 1;\r
254                                 }\r
255                                 else\r
256                                         UseReferenceRect = false;\r
257                         }\r
258 \r
259                         /** Used to notify the cursor that the window was resized. */\r
260                         void OnResize(const core::dimension2d<u32>& size)\r
261                         {\r
262                                 WindowSize = size;\r
263                                 if (size.Width!=0)\r
264                                         InvWindowSize.Width = 1.0f / size.Width;\r
265                                 else\r
266                                         InvWindowSize.Width = 0.f;\r
267 \r
268                                 if (size.Height!=0)\r
269                                         InvWindowSize.Height = 1.0f / size.Height;\r
270                                 else\r
271                                         InvWindowSize.Height = 0.f;\r
272                         }\r
273 \r
274                         /** Used to notify the cursor that the window resizable settings changed. */\r
275                         void updateBorderSize(bool fullscreen, bool resizable)\r
276                         {\r
277                                 if (!fullscreen)\r
278                                 {\r
279                                         s32 paddingBorder = 0;\r
280                                         #ifdef SM_CXPADDEDBORDER\r
281                                                 paddingBorder = GetSystemMetrics(SM_CXPADDEDBORDER);\r
282                                         #endif\r
283 \r
284                                         if (resizable)\r
285                                         {\r
286                                                 BorderX = GetSystemMetrics(SM_CXSIZEFRAME) + paddingBorder;\r
287                                                 BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) + paddingBorder;\r
288                                         }\r
289                                         else\r
290                                         {\r
291                                                 BorderX = GetSystemMetrics(SM_CXDLGFRAME) + paddingBorder;\r
292                                                 BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME) + paddingBorder;\r
293                                         }\r
294                                 }\r
295                                 else\r
296                                 {\r
297                                         BorderX = BorderY = 0;\r
298                                 }\r
299                         }\r
300 \r
301 \r
302                         //! Sets the active cursor icon\r
303                         void setActiveIcon(gui::ECURSOR_ICON iconId) override;\r
304 \r
305                         //! Gets the currently active icon\r
306                         gui::ECURSOR_ICON getActiveIcon() const override\r
307                         {\r
308                                 return ActiveIcon;\r
309                         }\r
310 \r
311                         //! Add a custom sprite as cursor icon.\r
312                         gui::ECURSOR_ICON addIcon(const gui::SCursorSprite& icon) override;\r
313 \r
314                         //! replace the given cursor icon.\r
315                         void changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon) override;\r
316 \r
317                         //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.\r
318                         core::dimension2di getSupportedIconSize() const override;\r
319 \r
320                         void update();\r
321 \r
322                 private:\r
323 \r
324                         //! Updates the internal cursor position\r
325                         void updateInternalCursorPosition()\r
326                         {\r
327                                 POINT p;\r
328                                 if (!GetCursorPos(&p))\r
329                                 {\r
330                                         DWORD xy = GetMessagePos();\r
331                                         p.x = GET_X_LPARAM(xy);\r
332                                         p.y = GET_Y_LPARAM(xy);\r
333                                 }\r
334 \r
335                                 if (UseReferenceRect)\r
336                                 {\r
337                                         CursorPos.X = p.x - ReferenceRect.UpperLeftCorner.X;\r
338                                         CursorPos.Y = p.y - ReferenceRect.UpperLeftCorner.Y;\r
339                                 }\r
340                                 else\r
341                                 {\r
342                                         RECT rect;\r
343                                         if (GetWindowRect(HWnd, &rect))\r
344                                         {\r
345                                                 CursorPos.X = p.x-rect.left-BorderX;\r
346                                                 CursorPos.Y = p.y-rect.top-BorderY;\r
347                                         }\r
348                                         else\r
349                                         {\r
350                                                 // window seems not to be existent, so set cursor to\r
351                                                 // a negative value\r
352                                                 CursorPos.X = -1;\r
353                                                 CursorPos.Y = -1;\r
354                                         }\r
355                                 }\r
356                         }\r
357 \r
358                         CIrrDeviceWin32* Device;\r
359                         core::position2d<s32> CursorPos;\r
360                         core::dimension2d<u32> WindowSize;\r
361                         core::dimension2d<f32> InvWindowSize;\r
362                         HWND HWnd;\r
363 \r
364                         s32 BorderX, BorderY;\r
365                         core::rect<s32> ReferenceRect;\r
366                         bool UseReferenceRect;\r
367                         bool IsVisible;\r
368 \r
369 \r
370                         struct CursorFrameW32\r
371                         {\r
372                                 CursorFrameW32() : IconHW(0) {}\r
373                                 CursorFrameW32(HCURSOR icon) : IconHW(icon) {}\r
374 \r
375                                 HCURSOR IconHW; // hardware cursor\r
376                         };\r
377 \r
378                         struct CursorW32\r
379                         {\r
380                                 CursorW32() {}\r
381                                 explicit CursorW32(HCURSOR iconHw, u32 frameTime=0) : FrameTime(frameTime)\r
382                                 {\r
383                                         Frames.push_back( CursorFrameW32(iconHw) );\r
384                                 }\r
385                                 core::array<CursorFrameW32> Frames;\r
386                                 u32 FrameTime;\r
387                         };\r
388 \r
389                         core::array<CursorW32> Cursors;\r
390                         gui::ECURSOR_ICON ActiveIcon;\r
391                         u32 ActiveIconStartTime;\r
392 \r
393                         void initCursors();\r
394                 };\r
395 \r
396                 //! returns the win32 cursor control\r
397                 CCursorControl* getWin32CursorControl();\r
398 \r
399         private:\r
400 \r
401                 //! create the driver\r
402                 void createDriver();\r
403 \r
404                 //! Process system events\r
405                 void handleSystemMessages();\r
406 \r
407                 void getWindowsVersion(core::stringc& version);\r
408 \r
409                 void resizeIfNecessary();\r
410 \r
411                 DWORD getWindowStyle(bool fullscreen, bool resizable) const;\r
412 \r
413                 HWND HWnd;\r
414 \r
415                 bool Resized;\r
416                 bool ExternalWindow;\r
417                 CCursorControl* Win32CursorControl;\r
418 \r
419                 SJoystickWin32Control* JoyControl;\r
420         };\r
421 \r
422 } // end namespace irr\r
423 \r
424 #endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_\r
425 #endif // __C_IRR_DEVICE_WIN32_H_INCLUDED__\r