]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CIrrDeviceWin32.cpp
Reduce IrrCompileConfig usage to files that actually need it
[irrlicht.git] / source / Irrlicht / CIrrDeviceWin32.cpp
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 \r
6 #ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_\r
7 \r
8 #if defined (__STRICT_ANSI__)\r
9     #error Compiling with __STRICT_ANSI__ not supported. g++ does set this when compiling with -std=c++11 or -std=c++0x. Use instead -std=gnu++11 or -std=gnu++0x. Or use -U__STRICT_ANSI__ to disable strict ansi.\r
10 #endif\r
11 \r
12 #include "CIrrDeviceWin32.h"\r
13 #include "IEventReceiver.h"\r
14 #include "os.h"\r
15 \r
16 #include "CTimer.h"\r
17 #include "irrString.h"\r
18 #include "COSOperator.h"\r
19 #include "dimension2d.h"\r
20 #include "IGUISpriteBank.h"\r
21 #include <winuser.h>\r
22 #include "SExposedVideoData.h"\r
23 \r
24 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)\r
25 #include <mmsystem.h>\r
26 #include <regstr.h>\r
27 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_\r
28 #define DIRECTINPUT_VERSION 0x0800\r
29 #include <dinput.h>\r
30 #endif\r
31 #endif\r
32 \r
33 #if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)\r
34 #include "CEGLManager.h"\r
35 #endif\r
36 \r
37 #if defined(_IRR_COMPILE_WITH_OPENGL_)\r
38 #include "CWGLManager.h"\r
39 #endif\r
40 \r
41 namespace irr\r
42 {\r
43         namespace video\r
44         {\r
45 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_\r
46                 IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, HWND window);\r
47 #endif\r
48 \r
49 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
50                 IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
51 #endif\r
52 \r
53 #ifdef _IRR_COMPILE_WITH_OGLES1_\r
54         IVideoDriver* createOGLES1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
55 #endif\r
56 \r
57 #ifdef _IRR_COMPILE_WITH_OGLES2_\r
58         IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
59 #endif\r
60         }\r
61 } // end namespace irr\r
62 \r
63 namespace irr\r
64 {\r
65     struct SJoystickWin32Control\r
66     {\r
67         CIrrDeviceWin32* Device;\r
68 \r
69     #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)\r
70         IDirectInput8* DirectInputDevice;\r
71     #endif\r
72     #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)\r
73         struct JoystickInfo\r
74         {\r
75             u32 Index;\r
76     #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_\r
77             core::stringc Name;\r
78             GUID guid;\r
79             LPDIRECTINPUTDEVICE8 lpdijoy;\r
80             DIDEVCAPS devcaps;\r
81             u8 axisValid[8];\r
82     #else\r
83             JOYCAPS Caps;\r
84     #endif\r
85         };\r
86         core::array<JoystickInfo> ActiveJoysticks;\r
87     #endif\r
88 \r
89         SJoystickWin32Control(CIrrDeviceWin32* dev);\r
90         ~SJoystickWin32Control();\r
91 \r
92     #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)\r
93         static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp);\r
94         void directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi);\r
95     #endif\r
96 \r
97         void pollJoysticks();\r
98         bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo);\r
99         irr::core::stringc findJoystickName(int index, const JOYCAPS &caps) const;\r
100     };\r
101 \r
102 \r
103         SJoystickWin32Control::SJoystickWin32Control(CIrrDeviceWin32* dev) : Device(dev)\r
104         {\r
105 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)\r
106                 DirectInputDevice=0;\r
107                 if (DI_OK != (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInputDevice, NULL)))\r
108                 {\r
109                         os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING);\r
110                         return;\r
111                 }\r
112 #endif\r
113         }\r
114 \r
115         SJoystickWin32Control::~SJoystickWin32Control()\r
116         {\r
117 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)\r
118                 for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)\r
119                 {\r
120                         LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy;\r
121                         if (dev)\r
122                         {\r
123                                 dev->Unacquire();\r
124                         }\r
125                         dev->Release();\r
126                 }\r
127 \r
128                 if (DirectInputDevice)\r
129                         DirectInputDevice->Release();\r
130 #endif\r
131         }\r
132 \r
133 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)\r
134         BOOL CALLBACK SJoystickWin32Control::EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp)\r
135         {\r
136                 SJoystickWin32Control* p=(SJoystickWin32Control*)cp;\r
137                 p->directInputAddJoystick(lpddi);\r
138                 return DIENUM_CONTINUE;\r
139         }\r
140         void SJoystickWin32Control::directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi)\r
141         {\r
142                 //Get the GUID of the joystuck\r
143                 const GUID guid = lpddi->guidInstance;\r
144 \r
145                 JoystickInfo activeJoystick;\r
146                 activeJoystick.Index=ActiveJoysticks.size();\r
147                 activeJoystick.guid=guid;\r
148                 activeJoystick.Name=lpddi->tszProductName;\r
149                 if (FAILED(DirectInputDevice->CreateDevice(guid, &activeJoystick.lpdijoy, NULL)))\r
150                 {\r
151                         os::Printer::log("Could not create DirectInput device", ELL_WARNING);\r
152                         return;\r
153                 }\r
154 \r
155                 activeJoystick.devcaps.dwSize=sizeof(activeJoystick.devcaps);\r
156                 if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps)))\r
157                 {\r
158                         os::Printer::log("Could not create DirectInput device", ELL_WARNING);\r
159                         return;\r
160                 }\r
161 \r
162                 if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE)))\r
163                 {\r
164                         os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING);\r
165                         return;\r
166                 }\r
167 \r
168                 if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2)))\r
169                 {\r
170                         os::Printer::log("Could not set DirectInput device data format", ELL_WARNING);\r
171                         return;\r
172                 }\r
173 \r
174                 if (FAILED(activeJoystick.lpdijoy->Acquire()))\r
175                 {\r
176                         os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING);\r
177                         return;\r
178                 }\r
179 \r
180                 DIJOYSTATE2 info;\r
181                 if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info),&info)))\r
182                 {\r
183                         os::Printer::log("Could not read DirectInput device state", ELL_WARNING);\r
184                         return;\r
185                 }\r
186 \r
187                 ZeroMemory(activeJoystick.axisValid,sizeof(activeJoystick.axisValid));\r
188                 activeJoystick.axisValid[0]= (info.lX!=0) ? 1 : 0;\r
189                 activeJoystick.axisValid[1]= (info.lY!=0) ? 1 : 0;\r
190                 activeJoystick.axisValid[2]= (info.lZ!=0) ? 1 : 0;\r
191                 activeJoystick.axisValid[3]= (info.lRx!=0) ? 1 : 0;\r
192                 activeJoystick.axisValid[4]= (info.lRy!=0) ? 1 : 0;\r
193                 activeJoystick.axisValid[5]= (info.lRz!=0) ? 1 : 0;\r
194 \r
195                 int caxis=0;\r
196                 for (u8 i=0; i<6; i++)\r
197                 {\r
198                         if (activeJoystick.axisValid[i])\r
199                                 caxis++;\r
200                 }\r
201 \r
202                 for (u8 i=0; i<(activeJoystick.devcaps.dwAxes)-caxis; i++)\r
203                 {\r
204                         if (i+caxis < 8)\r
205                                 activeJoystick.axisValid[i+caxis]=1;\r
206                 }\r
207 \r
208                 ActiveJoysticks.push_back(activeJoystick);\r
209         }\r
210 #endif\r
211 \r
212 void SJoystickWin32Control::pollJoysticks()\r
213 {\r
214 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
215 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_\r
216         if(0 == ActiveJoysticks.size())\r
217                 return;\r
218 \r
219         u32 joystick;\r
220         DIJOYSTATE2 info;\r
221 \r
222         for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)\r
223         {\r
224                 // needs to be reset for each joystick\r
225                 // request ALL values and POV as continuous if possible\r
226 \r
227                 const DIDEVCAPS & caps = ActiveJoysticks[joystick].devcaps;\r
228                 // if no POV is available don't ask for POV values\r
229 \r
230                 if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info),&info)))\r
231                 {\r
232                         SEvent event;\r
233 \r
234                         event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;\r
235                         event.JoystickEvent.Joystick = (u8)joystick;\r
236 \r
237                         event.JoystickEvent.POV = (u16)info.rgdwPOV[0];\r
238                         // set to undefined if no POV value was returned or the value\r
239                         // is out of range\r
240                         if ((caps.dwPOVs==0) || (event.JoystickEvent.POV > 35900))\r
241                                 event.JoystickEvent.POV = 65535;\r
242 \r
243                         for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)\r
244                                 event.JoystickEvent.Axis[axis] = 0;\r
245 \r
246                         u16 dxAxis=0;\r
247                         u16 irrAxis=0;\r
248 \r
249                         while (dxAxis < 6 && irrAxis <caps.dwAxes)\r
250                         {\r
251                                 bool axisFound=0;\r
252                                 s32 axisValue=0;\r
253 \r
254                                 switch (dxAxis)\r
255                                 {\r
256                                 case 0:\r
257                                         axisValue=info.lX;\r
258                                         break;\r
259                                 case 1:\r
260                                         axisValue=info.lY;\r
261                                         break;\r
262                                 case 2:\r
263                                         axisValue=info.lZ;\r
264                                         break;\r
265                                 case 3:\r
266                                         axisValue=info.lRx;\r
267                                         break;\r
268                                 case 4:\r
269                                         axisValue=info.lRy;\r
270                                         break;\r
271                                 case 5:\r
272                                         axisValue=info.lRz;\r
273                                         break;\r
274                                 case 6:\r
275                                         axisValue=info.rglSlider[0];\r
276                                         break;\r
277                                 case 7:\r
278                                         axisValue=info.rglSlider[1];\r
279                                         break;\r
280                                 default:\r
281                                         break;\r
282                                 }\r
283 \r
284                                 if (ActiveJoysticks[joystick].axisValid[dxAxis]>0)\r
285                                         axisFound=1;\r
286 \r
287                                 if (axisFound)\r
288                                 {\r
289                                         s32 val=axisValue - 32768;\r
290 \r
291                                         if (val <-32767) val=-32767;\r
292                                         if (val > 32767) val=32767;\r
293                                         event.JoystickEvent.Axis[irrAxis]=(s16)(val);\r
294                                         irrAxis++;\r
295                                 }\r
296 \r
297                                 dxAxis++;\r
298                         }\r
299 \r
300                         u32 buttons=0;\r
301                         BYTE* bytebuttons=info.rgbButtons;\r
302                         for (u16 i=0; i<32; i++)\r
303                         {\r
304                                 if (bytebuttons[i] >0)\r
305                                 {\r
306                                         buttons |= (1 << i);\r
307                                 }\r
308                         }\r
309                         event.JoystickEvent.ButtonStates = buttons;\r
310 \r
311                         (void)Device->postEventFromUser(event);\r
312                 }\r
313         }\r
314 #else\r
315         if (0 == ActiveJoysticks.size())\r
316                 return;\r
317 \r
318         u32 joystick;\r
319         JOYINFOEX info;\r
320 \r
321         for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)\r
322         {\r
323                 // needs to be reset for each joystick\r
324                 // request ALL values and POV as continuous if possible\r
325                 info.dwSize = sizeof(info);\r
326                 info.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;\r
327                 const JOYCAPS & caps = ActiveJoysticks[joystick].Caps;\r
328                 // if no POV is available don't ask for POV values\r
329                 if (!(caps.wCaps & JOYCAPS_HASPOV))\r
330                         info.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS);\r
331                 if(JOYERR_NOERROR == joyGetPosEx(ActiveJoysticks[joystick].Index, &info))\r
332                 {\r
333                         SEvent event;\r
334 \r
335                         event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;\r
336                         event.JoystickEvent.Joystick = (u8)joystick;\r
337 \r
338                         event.JoystickEvent.POV = (u16)info.dwPOV;\r
339                         // set to undefined if no POV value was returned or the value\r
340                         // is out of range\r
341                         if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900))\r
342                                 event.JoystickEvent.POV = 65535;\r
343 \r
344                         for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)\r
345                                 event.JoystickEvent.Axis[axis] = 0;\r
346 \r
347                         event.JoystickEvent.ButtonStates = info.dwButtons;\r
348 \r
349                         switch(caps.wNumAxes)\r
350                         {\r
351                         default:\r
352                         case 6:\r
353                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] =\r
354                                         (s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768);\r
355 \r
356                         case 5:\r
357                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] =\r
358                                         (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768);\r
359 \r
360                         case 4:\r
361                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] =\r
362                                         (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768);\r
363 \r
364                         case 3:\r
365                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] =\r
366                                         (s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768);\r
367 \r
368                         case 2:\r
369                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] =\r
370                                         (s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768);\r
371 \r
372                         case 1:\r
373                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] =\r
374                                         (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768);\r
375                         }\r
376 \r
377                         (void)Device->postEventFromUser(event);\r
378                 }\r
379         }\r
380 #endif\r
381 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
382 }\r
383 \r
384 /** This function is ported from SDL and released under zlib-license:\r
385   * Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> */\r
386 irr::core::stringc SJoystickWin32Control::findJoystickName(int index, const JOYCAPS &caps) const\r
387 {\r
388 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
389 \r
390     // As a default use the name given in the joystick structure.\r
391     // It is always the same name, independent of joystick.\r
392     irr::core::stringc result(caps.szPname);\r
393 \r
394     core::stringc key = core::stringc(REGSTR_PATH_JOYCONFIG)+ "\\" + caps.szRegKey + "\\" + REGSTR_KEY_JOYCURR;\r
395     HKEY hTopKey = HKEY_LOCAL_MACHINE;\r
396     HKEY hKey;\r
397     long regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);\r
398     if (regresult != ERROR_SUCCESS)\r
399     {\r
400         hTopKey = HKEY_CURRENT_USER;\r
401         regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);\r
402     }\r
403     if (regresult != ERROR_SUCCESS)\r
404         return result;\r
405 \r
406     /* find the registry key name for the joystick's properties */\r
407     char regname[256];\r
408     DWORD regsize = sizeof(regname);\r
409     core::stringc regvalue = core::stringc("Joystick")+core::stringc(index+1) + REGSTR_VAL_JOYOEMNAME;\r
410     regresult = RegQueryValueExA(hKey, regvalue.c_str(), 0, 0, (LPBYTE)regname, &regsize);\r
411     RegCloseKey(hKey);\r
412     if (regresult != ERROR_SUCCESS)\r
413         return result;\r
414 \r
415     /* open that registry key */\r
416     core::stringc regkey = core::stringc(REGSTR_PATH_JOYOEM) + "\\" + regname;\r
417     regresult = RegOpenKeyExA(hTopKey, regkey.c_str(), 0, KEY_READ, &hKey);\r
418     if (regresult != ERROR_SUCCESS)\r
419         return result;\r
420 \r
421     /* find the size for the OEM name text */\r
422     regsize = sizeof(regvalue);\r
423     regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,\r
424                                  NULL, &regsize);\r
425     if (regresult == ERROR_SUCCESS)\r
426     {\r
427         char *name;\r
428         /* allocate enough memory for the OEM name text ... */\r
429         name = new char[regsize];\r
430         if (name)\r
431         {\r
432             /* ... and read it from the registry */\r
433             regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,\r
434                                          (LPBYTE)name, &regsize );\r
435             result = name;\r
436         }\r
437         delete[] name;\r
438     }\r
439     RegCloseKey(hKey);\r
440 \r
441     return result;\r
442 #endif\r
443         return "";\r
444 }\r
445 \r
446 bool SJoystickWin32Control::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)\r
447 {\r
448 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
449         joystickInfo.clear();\r
450         ActiveJoysticks.clear();\r
451 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_\r
452         if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY )))\r
453         {\r
454                 os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING);\r
455                 return false;\r
456         }\r
457 \r
458         for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)\r
459         {\r
460                 JoystickInfo& activeJoystick = ActiveJoysticks[joystick];\r
461                 SJoystickInfo info;\r
462                 info.Axes=activeJoystick.devcaps.dwAxes;\r
463                 info.Buttons=activeJoystick.devcaps.dwButtons;\r
464                 info.Name=activeJoystick.Name;\r
465                 info.PovHat = (activeJoystick.devcaps.dwPOVs  != 0)\r
466                                 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;\r
467                 joystickInfo.push_back(info);\r
468         }\r
469         return true;\r
470 #else\r
471         const u32 numberOfJoysticks = ::joyGetNumDevs();\r
472         JOYINFOEX info;\r
473         info.dwSize = sizeof(info);\r
474         info.dwFlags = JOY_RETURNALL;\r
475 \r
476         JoystickInfo activeJoystick;\r
477         SJoystickInfo returnInfo;\r
478 \r
479         joystickInfo.reallocate(numberOfJoysticks);\r
480         ActiveJoysticks.reallocate(numberOfJoysticks);\r
481 \r
482         u32 joystick = 0;\r
483         for(; joystick < numberOfJoysticks; ++joystick)\r
484         {\r
485                 if(JOYERR_NOERROR == joyGetPosEx(joystick, &info)\r
486                         &&\r
487                         JOYERR_NOERROR == joyGetDevCaps(joystick,\r
488                                                                                         &activeJoystick.Caps,\r
489                                                                                         sizeof(activeJoystick.Caps)))\r
490                 {\r
491                         activeJoystick.Index = joystick;\r
492                         ActiveJoysticks.push_back(activeJoystick);\r
493 \r
494                         returnInfo.Joystick = (u8)joystick;\r
495                         returnInfo.Axes = activeJoystick.Caps.wNumAxes;\r
496                         returnInfo.Buttons = activeJoystick.Caps.wNumButtons;\r
497                         returnInfo.Name = findJoystickName(joystick, activeJoystick.Caps);\r
498                         returnInfo.PovHat = ((activeJoystick.Caps.wCaps & JOYCAPS_HASPOV) == JOYCAPS_HASPOV)\r
499                                                                 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;\r
500 \r
501                         joystickInfo.push_back(returnInfo);\r
502                 }\r
503         }\r
504 \r
505         for(joystick = 0; joystick < joystickInfo.size(); ++joystick)\r
506         {\r
507                 char logString[256];\r
508                 snprintf_irr(logString, sizeof(logString), "Found joystick %d, %d axes, %d buttons '%s'",\r
509                         joystick, joystickInfo[joystick].Axes,\r
510                         joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());\r
511                 os::Printer::log(logString, ELL_INFORMATION);\r
512         }\r
513 \r
514         return true;\r
515 #endif\r
516 #else\r
517         return false;\r
518 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
519 }\r
520 } // end namespace irr\r
521 \r
522 namespace\r
523 {\r
524         struct SEnvMapper\r
525         {\r
526                 HWND hWnd;\r
527                 irr::CIrrDeviceWin32* irrDev;\r
528         };\r
529         // NOTE: This is global. We can have more than one Irrlicht Device at same time.\r
530         irr::core::array<SEnvMapper> EnvMap;\r
531 \r
532         HKL KEYBOARD_INPUT_HKL=0;\r
533 }\r
534 \r
535 irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)\r
536 {\r
537         const irr::u32 end = EnvMap.size();\r
538         for ( irr::u32 i=0; i < end; ++i )\r
539         {\r
540                 const SEnvMapper& env = EnvMap[i];\r
541                 if ( env.hWnd == hWnd )\r
542                         return env.irrDev;\r
543         }\r
544 \r
545         return 0;\r
546 }\r
547 \r
548 \r
549 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\r
550 {\r
551         #ifndef WHEEL_DELTA\r
552         #define WHEEL_DELTA 120\r
553         #endif\r
554 \r
555         irr::CIrrDeviceWin32* dev = 0;\r
556         irr::SEvent event;\r
557 \r
558         static irr::s32 ClickCount=0;\r
559         if (GetCapture() != hWnd && ClickCount > 0)\r
560                 ClickCount = 0;\r
561 \r
562 \r
563         struct messageMap\r
564         {\r
565                 irr::s32 group;\r
566                 UINT winMessage;\r
567                 irr::s32 irrMessage;\r
568         };\r
569 \r
570         static messageMap mouseMap[] =\r
571         {\r
572                 {0, WM_LBUTTONDOWN, irr::EMIE_LMOUSE_PRESSED_DOWN},\r
573                 {1, WM_LBUTTONUP,   irr::EMIE_LMOUSE_LEFT_UP},\r
574                 {0, WM_RBUTTONDOWN, irr::EMIE_RMOUSE_PRESSED_DOWN},\r
575                 {1, WM_RBUTTONUP,   irr::EMIE_RMOUSE_LEFT_UP},\r
576                 {0, WM_MBUTTONDOWN, irr::EMIE_MMOUSE_PRESSED_DOWN},\r
577                 {1, WM_MBUTTONUP,   irr::EMIE_MMOUSE_LEFT_UP},\r
578                 {2, WM_MOUSEMOVE,   irr::EMIE_MOUSE_MOVED},\r
579                 {3, WM_MOUSEWHEEL,  irr::EMIE_MOUSE_WHEEL},\r
580                 {-1, 0, 0}\r
581         };\r
582 \r
583         // handle grouped events\r
584         messageMap * m = mouseMap;\r
585         while ( m->group >=0 && m->winMessage != message )\r
586                 m += 1;\r
587 \r
588         if ( m->group >= 0 )\r
589         {\r
590                 if ( m->group == 0 )    // down\r
591                 {\r
592                         ClickCount++;\r
593                         SetCapture(hWnd);\r
594                 }\r
595                 else\r
596                 if ( m->group == 1 )    // up\r
597                 {\r
598                         ClickCount--;\r
599                         if (ClickCount<1)\r
600                         {\r
601                                 ClickCount=0;\r
602                                 ReleaseCapture();\r
603                         }\r
604                 }\r
605 \r
606                 event.EventType = irr::EET_MOUSE_INPUT_EVENT;\r
607                 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT) m->irrMessage;\r
608                 event.MouseInput.X = (short)LOWORD(lParam);\r
609                 event.MouseInput.Y = (short)HIWORD(lParam);\r
610                 event.MouseInput.Shift = ((LOWORD(wParam) & MK_SHIFT) != 0);\r
611                 event.MouseInput.Control = ((LOWORD(wParam) & MK_CONTROL) != 0);\r
612                 // left and right mouse buttons\r
613                 event.MouseInput.ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON);\r
614                 // middle and extra buttons\r
615                 if (wParam & MK_MBUTTON)\r
616                         event.MouseInput.ButtonStates |= irr::EMBSM_MIDDLE;\r
617                 if (wParam & MK_XBUTTON1)\r
618                         event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA1;\r
619                 if (wParam & MK_XBUTTON2)\r
620                         event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA2;\r
621                 event.MouseInput.Wheel = 0.f;\r
622 \r
623                 // wheel\r
624                 if ( m->group == 3 )\r
625                 {\r
626                         POINT p; // fixed by jox\r
627                         p.x = 0; p.y = 0;\r
628                         ClientToScreen(hWnd, &p);\r
629                         event.MouseInput.X -= p.x;\r
630                         event.MouseInput.Y -= p.y;\r
631                         event.MouseInput.Wheel = ((irr::f32)((short)HIWORD(wParam))) / (irr::f32)WHEEL_DELTA;\r
632                 }\r
633 \r
634                 dev = getDeviceFromHWnd(hWnd);\r
635                 if (dev)\r
636                 {\r
637                         dev->postEventFromUser(event);\r
638 \r
639                         if ( event.MouseInput.Event >= irr::EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= irr::EMIE_MMOUSE_PRESSED_DOWN )\r
640                         {\r
641                                 irr::u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event);\r
642                                 if ( clicks == 2 )\r
643                                 {\r
644                                         event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_DOUBLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);\r
645                                         dev->postEventFromUser(event);\r
646                                 }\r
647                                 else if ( clicks == 3 )\r
648                                 {\r
649                                         event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_TRIPLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);\r
650                                         dev->postEventFromUser(event);\r
651                                 }\r
652                         }\r
653                 }\r
654                 return 0;\r
655         }\r
656 \r
657         switch (message)\r
658         {\r
659         case WM_PAINT:\r
660                 {\r
661                         PAINTSTRUCT ps;\r
662                         BeginPaint(hWnd, &ps);\r
663                         EndPaint(hWnd, &ps);\r
664                 }\r
665                 return 0;\r
666 \r
667         case WM_ERASEBKGND:\r
668                 return 0;\r
669 \r
670         case WM_SYSKEYDOWN:\r
671         case WM_SYSKEYUP:\r
672         case WM_KEYDOWN:\r
673         case WM_KEYUP:\r
674                 {\r
675                         BYTE allKeys[256];\r
676 \r
677                         event.EventType = irr::EET_KEY_INPUT_EVENT;\r
678                         event.KeyInput.Key = (irr::EKEY_CODE)wParam;\r
679                         event.KeyInput.PressedDown = (message==WM_KEYDOWN || message == WM_SYSKEYDOWN);\r
680 \r
681                         if ( event.KeyInput.Key == irr::KEY_SHIFT )\r
682                         {\r
683                                 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );\r
684                         }\r
685                         if ( event.KeyInput.Key == irr::KEY_CONTROL )\r
686                         {\r
687                                 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );\r
688                                 // some keyboards will just return LEFT for both - left and right keys. So also check extend bit.\r
689                                 if (lParam & 0x1000000)\r
690                                         event.KeyInput.Key = irr::KEY_RCONTROL;\r
691                         }\r
692                         if ( event.KeyInput.Key == irr::KEY_MENU )\r
693                         {\r
694                                 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );\r
695                                 if (lParam & 0x1000000)\r
696                                         event.KeyInput.Key = irr::KEY_RMENU;\r
697                         }\r
698 \r
699                         GetKeyboardState(allKeys);\r
700 \r
701                         event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80)!=0);\r
702                         event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80)!=0);\r
703 \r
704                         // Handle unicode and deadkeys\r
705                         WCHAR keyChars[2];\r
706                         UINT scanCode = HIWORD(lParam);\r
707                         int conversionResult = ToUnicodeEx(static_cast<UINT>(wParam),scanCode,allKeys,keyChars,2,0,KEYBOARD_INPUT_HKL);\r
708                         if (conversionResult == 1)\r
709                                 event.KeyInput.Char = keyChars[0];\r
710                         else\r
711                                 event.KeyInput.Char = 0;\r
712 \r
713                         // allow composing characters like '@' with Alt Gr on non-US keyboards\r
714                         if ((allKeys[VK_MENU] & 0x80) != 0)\r
715                                 event.KeyInput.Control = 0;\r
716 \r
717                         dev = getDeviceFromHWnd(hWnd);\r
718                         if (dev)\r
719                                 dev->postEventFromUser(event);\r
720 \r
721                         if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)\r
722                                 return DefWindowProcW(hWnd, message, wParam, lParam);\r
723                         else\r
724                                 return 0;\r
725                 }\r
726 \r
727         case WM_SIZE:\r
728                 {\r
729                         // resize\r
730                         dev = getDeviceFromHWnd(hWnd);\r
731                         if (dev)\r
732                                 dev->OnResized();\r
733                 }\r
734                 return 0;\r
735 \r
736         case WM_DESTROY:\r
737                 PostQuitMessage(0);\r
738                 return 0;\r
739 \r
740         case WM_SYSCOMMAND:\r
741                 // prevent screensaver or monitor powersave mode from starting\r
742                 if ((wParam & 0xFFF0) == SC_SCREENSAVE ||\r
743                         (wParam & 0xFFF0) == SC_MONITORPOWER ||\r
744                         (wParam & 0xFFF0) == SC_KEYMENU\r
745                         )\r
746                         return 0;\r
747 \r
748                 break;\r
749 \r
750         case WM_USER:\r
751                 event.EventType = irr::EET_USER_EVENT;\r
752                 event.UserEvent.UserData1 = static_cast<size_t>(wParam);\r
753                 event.UserEvent.UserData2 = static_cast<size_t>(lParam);\r
754                 dev = getDeviceFromHWnd(hWnd);\r
755 \r
756                 if (dev)\r
757                         dev->postEventFromUser(event);\r
758 \r
759                 return 0;\r
760 \r
761         case WM_SETCURSOR:\r
762                 // because Windows forgot about that in the meantime\r
763                 dev = getDeviceFromHWnd(hWnd);\r
764                 if (dev)\r
765                 {\r
766                         dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() );\r
767                         dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() );\r
768                 }\r
769                 break;\r
770 \r
771         case WM_INPUTLANGCHANGE:\r
772                 // get the new codepage used for keyboard input\r
773                 KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);\r
774                 return 0;\r
775         }\r
776         return DefWindowProcW(hWnd, message, wParam, lParam);\r
777 }\r
778 \r
779 \r
780 namespace irr\r
781 {\r
782 \r
783 //! constructor\r
784 CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)\r
785 : CIrrDeviceStub(params), HWnd(0), Resized(false),\r
786         ExternalWindow(false), Win32CursorControl(0), JoyControl(0),\r
787         WindowMaximized(params.WindowMaximized)\r
788 {\r
789         #ifdef _DEBUG\r
790         setDebugName("CIrrDeviceWin32");\r
791         #endif\r
792 \r
793         // get windows version and create OS operator\r
794         core::stringc winversion;\r
795         getWindowsVersion(winversion);\r
796         Operator = new COSOperator(winversion);\r
797         os::Printer::log(winversion.c_str(), ELL_INFORMATION);\r
798 \r
799         // get handle to exe file\r
800         HINSTANCE hInstance = GetModuleHandle(0);\r
801 \r
802         // create the window if we need to and we do not use the null device\r
803         if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL)\r
804         {\r
805                 const wchar_t* ClassName = L"CIrrDeviceWin32";\r
806 \r
807                 // Register Class\r
808                 WNDCLASSEXW wcex;\r
809                 wcex.cbSize                     = sizeof(WNDCLASSEXW);\r
810                 wcex.style                      = CS_HREDRAW | CS_VREDRAW;\r
811                 wcex.lpfnWndProc        = WndProc;\r
812                 wcex.cbClsExtra         = 0;\r
813                 wcex.cbWndExtra         = 0;\r
814                 wcex.hInstance          = hInstance;\r
815                 wcex.hIcon                      = NULL;\r
816                 wcex.hCursor            = 0; // LoadCursor(NULL, IDC_ARROW);\r
817                 wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);\r
818                 wcex.lpszMenuName       = 0;\r
819                 wcex.lpszClassName      = ClassName;\r
820                 wcex.hIconSm            = 0;\r
821 \r
822                 // if there is an icon, load it\r
823                 wcex.hIcon = (HICON)LoadImageW(hInstance, L"irrlicht.ico", IMAGE_ICON, 0,0, LR_LOADFROMFILE | LR_DEFAULTSIZE);\r
824 \r
825                 RegisterClassExW(&wcex);\r
826 \r
827                 // calculate client size\r
828 \r
829                 RECT clientSize;\r
830                 clientSize.top = 0;\r
831                 clientSize.left = 0;\r
832                 clientSize.right = CreationParams.WindowSize.Width;\r
833                 clientSize.bottom = CreationParams.WindowSize.Height;\r
834 \r
835                 DWORD style = getWindowStyle(CreationParams.Fullscreen, CreationParams.WindowResizable > 0 ? true : false);\r
836                 AdjustWindowRect(&clientSize, style, FALSE);\r
837 \r
838                 const s32 realWidth = clientSize.right - clientSize.left;\r
839                 const s32 realHeight = clientSize.bottom - clientSize.top;\r
840 \r
841                 s32 windowLeft = (CreationParams.WindowPosition.X == -1 ?\r
842                                      (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2 :\r
843                                      CreationParams.WindowPosition.X);\r
844                 s32 windowTop = (CreationParams.WindowPosition.Y == -1 ?\r
845                                      (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2 :\r
846                                      CreationParams.WindowPosition.Y);\r
847 \r
848                 if ( windowLeft < 0 )\r
849                         windowLeft = 0;\r
850                 if ( windowTop < 0 )\r
851                         windowTop = 0;  // make sure window menus are in screen on creation\r
852 \r
853                 if (CreationParams.Fullscreen)\r
854                 {\r
855                         windowLeft = 0;\r
856                         windowTop = 0;\r
857                 }\r
858 \r
859                 // create window\r
860                 HWnd = CreateWindowW( ClassName, L"", style, windowLeft, windowTop,\r
861                                         realWidth, realHeight, NULL, NULL, hInstance, NULL);\r
862                 if (!HWnd)\r
863                 {\r
864                         os::Printer::log("Window could not be created.", ELL_ERROR);\r
865                 }\r
866 \r
867                 CreationParams.WindowId = HWnd;\r
868 //              CreationParams.WindowSize.Width = realWidth;\r
869 //              CreationParams.WindowSize.Height = realHeight;\r
870 \r
871                 ShowWindow(HWnd, SW_SHOWNORMAL);\r
872                 UpdateWindow(HWnd);\r
873 \r
874                 // fix ugly ATI driver bugs. Thanks to ariaci\r
875                 MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE);\r
876 \r
877                 // make sure everything gets updated to the real sizes\r
878                 Resized = true;\r
879         }\r
880         else if (CreationParams.WindowId)\r
881         {\r
882                 // attach external window\r
883                 HWnd = static_cast<HWND>(CreationParams.WindowId);\r
884                 RECT r;\r
885                 GetWindowRect(HWnd, &r);\r
886                 CreationParams.WindowSize.Width = r.right - r.left;\r
887                 CreationParams.WindowSize.Height = r.bottom - r.top;\r
888                 CreationParams.Fullscreen = false;\r
889                 ExternalWindow = true;\r
890         }\r
891 \r
892         // create cursor control\r
893 \r
894         Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen);\r
895         CursorControl = Win32CursorControl;\r
896         JoyControl = new SJoystickWin32Control(this);\r
897 \r
898         // initialize doubleclicks with system values\r
899         MouseMultiClicks.DoubleClickTime = GetDoubleClickTime();\r
900 \r
901         // create driver\r
902 \r
903         createDriver();\r
904 \r
905         if (VideoDriver)\r
906                 createGUIAndScene();\r
907 \r
908         // register environment\r
909 \r
910         SEnvMapper em;\r
911         em.irrDev = this;\r
912         em.hWnd = HWnd;\r
913         EnvMap.push_back(em);\r
914 \r
915         // set this as active window\r
916         if (!ExternalWindow)\r
917         {\r
918                 SetActiveWindow(HWnd);\r
919                 SetForegroundWindow(HWnd);\r
920         }\r
921 \r
922         KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);\r
923 \r
924         // inform driver about the window size etc.\r
925         resizeIfNecessary();\r
926 \r
927         if (params.WindowMaximized)\r
928                 maximizeWindow();\r
929 }\r
930 \r
931 \r
932 //! destructor\r
933 CIrrDeviceWin32::~CIrrDeviceWin32()\r
934 {\r
935         delete JoyControl;\r
936 \r
937         // unregister environment\r
938         for (u32 i=0; i< EnvMap.size(); ++i)\r
939         {\r
940                 if (EnvMap[i].hWnd == HWnd)\r
941                 {\r
942                         EnvMap.erase(i);\r
943                         break;\r
944                 }\r
945         }\r
946 }\r
947 \r
948 \r
949 //! create the driver\r
950 void CIrrDeviceWin32::createDriver()\r
951 {\r
952         switch(CreationParams.DriverType)\r
953         {\r
954         case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:\r
955                 os::Printer::log("DIRECT3D8 Driver is no longer supported in Irrlicht. Try another one.", ELL_ERROR);\r
956                 break;\r
957         case video::EDT_DIRECT3D9:\r
958 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_\r
959                 VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd);\r
960 \r
961                 if (!VideoDriver)\r
962                         os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR);\r
963 #else\r
964                 os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR);\r
965 #endif\r
966                 break;\r
967         case video::EDT_OPENGL:\r
968 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
969                 switchToFullScreen();\r
970 \r
971                 ContextManager = new video::CWGLManager();\r
972                 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));\r
973 \r
974                 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);\r
975 \r
976                 if (!VideoDriver)\r
977                         os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);\r
978 #else\r
979                 os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR);\r
980 #endif\r
981                 break;\r
982         case video::EDT_OGLES1:\r
983 #ifdef _IRR_COMPILE_WITH_OGLES1_\r
984                 switchToFullScreen();\r
985 \r
986                 ContextManager = new video::CEGLManager();\r
987                 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));\r
988 \r
989                 VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager);\r
990 \r
991                 if (!VideoDriver)\r
992                         os::Printer::log("Could not create OpenGL-ES1 driver.", ELL_ERROR);\r
993 #else\r
994                 os::Printer::log("OpenGL-ES1 driver was not compiled in.", ELL_ERROR);\r
995 #endif\r
996                 break;\r
997         case video::EDT_OGLES2:\r
998 #ifdef _IRR_COMPILE_WITH_OGLES2_\r
999                 switchToFullScreen();\r
1000 \r
1001                 ContextManager = new video::CEGLManager();\r
1002                 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));\r
1003 \r
1004                 VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);\r
1005 \r
1006                 if (!VideoDriver)\r
1007                         os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR);\r
1008 #else\r
1009                 os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR);\r
1010 #endif\r
1011                 break;\r
1012         case video::EDT_WEBGL1:\r
1013                 os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR);\r
1014                 break;\r
1015         case video::EDT_NULL:\r
1016                 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);\r
1017                 break;\r
1018         default:\r
1019                 os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);\r
1020                 break;\r
1021         }\r
1022 }\r
1023 \r
1024 \r
1025 //! runs the device. Returns false if device wants to be deleted\r
1026 bool CIrrDeviceWin32::run()\r
1027 {\r
1028         os::Timer::tick();\r
1029 \r
1030         static_cast<CCursorControl*>(CursorControl)->update();\r
1031 \r
1032         handleSystemMessages();\r
1033 \r
1034         if (!Close)\r
1035                 resizeIfNecessary();\r
1036 \r
1037         if(!Close && JoyControl)\r
1038                 JoyControl->pollJoysticks();\r
1039 \r
1040         return !Close;\r
1041 }\r
1042 \r
1043 \r
1044 //! Pause the current process for the minimum time allowed only to allow other processes to execute\r
1045 void CIrrDeviceWin32::yield()\r
1046 {\r
1047         Sleep(1);\r
1048 }\r
1049 \r
1050 //! Pause execution and let other processes to run for a specified amount of time.\r
1051 void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer)\r
1052 {\r
1053         const bool wasStopped = Timer ? Timer->isStopped() : true;\r
1054         if (pauseTimer && !wasStopped)\r
1055                 Timer->stop();\r
1056 \r
1057         Sleep(timeMs);\r
1058 \r
1059         if (pauseTimer && !wasStopped)\r
1060                 Timer->start();\r
1061 }\r
1062 \r
1063 \r
1064 void CIrrDeviceWin32::resizeIfNecessary()\r
1065 {\r
1066         if (!Resized || !getVideoDriver())\r
1067                 return;\r
1068 \r
1069         RECT r;\r
1070         GetClientRect(HWnd, &r);\r
1071 \r
1072         char tmp[255];\r
1073 \r
1074         if (r.right < 2 || r.bottom < 2)\r
1075         {\r
1076                 snprintf_irr(tmp, sizeof(tmp), "Ignoring resize operation to (%ld %ld)", r.right, r.bottom);\r
1077                 os::Printer::log(tmp);\r
1078         }\r
1079         else\r
1080         {\r
1081                 snprintf_irr(tmp, sizeof(tmp), "Resizing window (%ld %ld)", r.right, r.bottom);\r
1082                 os::Printer::log(tmp);\r
1083 \r
1084                 getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom));\r
1085                 getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize());\r
1086         }\r
1087 \r
1088         Resized = false;\r
1089 }\r
1090 \r
1091 \r
1092 DWORD CIrrDeviceWin32::getWindowStyle(bool fullscreen, bool resizable) const\r
1093 {\r
1094         if ( fullscreen )\r
1095                 return WS_POPUP;\r
1096 \r
1097         if ( resizable )\r
1098                 return WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;\r
1099 \r
1100         return WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;\r
1101 }\r
1102 \r
1103 //! sets the caption of the window\r
1104 void CIrrDeviceWin32::setWindowCaption(const wchar_t* text)\r
1105 {\r
1106         // We use SendMessage instead of SetText to ensure proper\r
1107         // function even in cases where the HWND was created in a different thread\r
1108         DWORD_PTR dwResult;\r
1109         SendMessageTimeoutW(HWnd, WM_SETTEXT, 0,\r
1110                         reinterpret_cast<LPARAM>(text),\r
1111                         SMTO_ABORTIFHUNG, 2000, &dwResult);\r
1112 }\r
1113 \r
1114 \r
1115 //! notifies the device that it should close itself\r
1116 void CIrrDeviceWin32::closeDevice()\r
1117 {\r
1118         if (!ExternalWindow)\r
1119         {\r
1120                 MSG msg;\r
1121                 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);\r
1122                 PostQuitMessage(0);\r
1123                 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);\r
1124                 DestroyWindow(HWnd);\r
1125                 const wchar_t* ClassName = L"CIrrDeviceWin32";\r
1126                 HINSTANCE hInstance = GetModuleHandle(0);\r
1127                 UnregisterClassW(ClassName, hInstance);\r
1128         }\r
1129         Close=true;\r
1130 }\r
1131 \r
1132 \r
1133 //! returns if window is active. if not, nothing needs to be drawn\r
1134 bool CIrrDeviceWin32::isWindowActive() const\r
1135 {\r
1136         return (GetActiveWindow() == HWnd);\r
1137 }\r
1138 \r
1139 \r
1140 //! returns if window has focus\r
1141 bool CIrrDeviceWin32::isWindowFocused() const\r
1142 {\r
1143         bool ret = (GetFocus() == HWnd);\r
1144         return ret;\r
1145 }\r
1146 \r
1147 \r
1148 //! returns if window is minimized\r
1149 bool CIrrDeviceWin32::isWindowMinimized() const\r
1150 {\r
1151         WINDOWPLACEMENT plc;\r
1152         plc.length=sizeof(WINDOWPLACEMENT);\r
1153         bool ret=false;\r
1154         if (GetWindowPlacement(HWnd,&plc))\r
1155                 ret = plc.showCmd == SW_SHOWMINIMIZED;\r
1156         return ret;\r
1157 }\r
1158 \r
1159 \r
1160 //! returns last state from maximizeWindow() and restoreWindow()\r
1161 bool CIrrDeviceWin32::isWindowMaximized() const\r
1162 {\r
1163         return WindowMaximized;\r
1164 }\r
1165 \r
1166 \r
1167 //! switches to fullscreen\r
1168 bool CIrrDeviceWin32::switchToFullScreen()\r
1169 {\r
1170         if (!CreationParams.Fullscreen)\r
1171                 return true;\r
1172 \r
1173         // No border, title bar, etc. is already set up through getWindowStyle()\r
1174         // We only set the window size to match the monitor.\r
1175 \r
1176         MONITORINFO mi;\r
1177         mi.cbSize = sizeof(mi);\r
1178         if (GetMonitorInfo(MonitorFromWindow(HWnd,MONITOR_DEFAULTTOPRIMARY),&mi))\r
1179         {\r
1180                 UINT flags = SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_FRAMECHANGED;\r
1181                 SetWindowPos(HWnd, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,\r
1182                         mi.rcMonitor.right - mi.rcMonitor.left,\r
1183                         mi.rcMonitor.bottom - mi.rcMonitor.top, flags);\r
1184         }\r
1185         else\r
1186         {\r
1187                 CreationParams.Fullscreen = false;\r
1188         }\r
1189 \r
1190         return CreationParams.Fullscreen;\r
1191 }\r
1192 \r
1193 \r
1194 //! returns the win32 cursor control\r
1195 CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl()\r
1196 {\r
1197         return Win32CursorControl;\r
1198 }\r
1199 \r
1200 void CIrrDeviceWin32::getWindowsVersion(core::stringc& out)\r
1201 {\r
1202         OSVERSIONINFO osvi;\r
1203 \r
1204         ZeroMemory(&osvi, sizeof(OSVERSIONINFO));\r
1205         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r
1206         GetVersionEx(&osvi);\r
1207 \r
1208         char tmp[255];\r
1209         snprintf(tmp, sizeof(tmp), "Microsoft Windows %lu.%lu %s", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion);\r
1210         out.append(tmp);\r
1211 }\r
1212 \r
1213 //! Notifies the device, that it has been resized\r
1214 void CIrrDeviceWin32::OnResized()\r
1215 {\r
1216         Resized = true;\r
1217 }\r
1218 \r
1219 //! Resize the render window.\r
1220 void CIrrDeviceWin32::setWindowSize(const irr::core::dimension2d<u32>& size)\r
1221 {\r
1222         if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)\r
1223                 return;\r
1224 \r
1225         // get size of the window for the give size of the client area\r
1226         DWORD style = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_STYLE));\r
1227         DWORD exStyle = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_EXSTYLE));\r
1228         RECT clientSize;\r
1229         clientSize.top = 0;\r
1230         clientSize.left = 0;\r
1231         clientSize.right = size.Width;\r
1232         clientSize.bottom = size.Height;\r
1233         AdjustWindowRectEx(&clientSize, style, false, exStyle);\r
1234         const s32 realWidth = clientSize.right - clientSize.left;\r
1235         const s32 realHeight = clientSize.bottom - clientSize.top;\r
1236 \r
1237         UINT flags = SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;\r
1238         SetWindowPos(HWnd, HWND_TOP, 0, 0, realWidth, realHeight, flags);\r
1239 }\r
1240 \r
1241 //! Sets if the window should be resizable in windowed mode.\r
1242 void CIrrDeviceWin32::setResizable(bool resize)\r
1243 {\r
1244         if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)\r
1245                 return;\r
1246 \r
1247         LONG_PTR style = (LONG_PTR)getWindowStyle(false, resize);\r
1248         if (!SetWindowLongPtr(HWnd, GWL_STYLE, style))\r
1249                 os::Printer::log("Could not change window style.");\r
1250 \r
1251         RECT clientSize;\r
1252         clientSize.top = 0;\r
1253         clientSize.left = 0;\r
1254         clientSize.right = getVideoDriver()->getScreenSize().Width;\r
1255         clientSize.bottom = getVideoDriver()->getScreenSize().Height;\r
1256 \r
1257         AdjustWindowRect(&clientSize, static_cast<DWORD>(style), FALSE);\r
1258 \r
1259         const s32 realWidth = clientSize.right - clientSize.left;\r
1260         const s32 realHeight = clientSize.bottom - clientSize.top;\r
1261 \r
1262         const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;\r
1263         const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;\r
1264 \r
1265         SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight,\r
1266                 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW);\r
1267 \r
1268         static_cast<CCursorControl*>(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize);\r
1269 }\r
1270 \r
1271 \r
1272 //! Minimizes the window.\r
1273 void CIrrDeviceWin32::minimizeWindow()\r
1274 {\r
1275         WINDOWPLACEMENT wndpl;\r
1276         wndpl.length = sizeof(WINDOWPLACEMENT);\r
1277         GetWindowPlacement(HWnd, &wndpl);\r
1278         wndpl.showCmd = SW_SHOWMINNOACTIVE;\r
1279         SetWindowPlacement(HWnd, &wndpl);\r
1280 }\r
1281 \r
1282 \r
1283 //! Maximizes the window.\r
1284 void CIrrDeviceWin32::maximizeWindow()\r
1285 {\r
1286         WINDOWPLACEMENT wndpl;\r
1287         wndpl.length = sizeof(WINDOWPLACEMENT);\r
1288         GetWindowPlacement(HWnd, &wndpl);\r
1289         wndpl.showCmd = SW_SHOWMAXIMIZED;\r
1290         SetWindowPlacement(HWnd, &wndpl);\r
1291 \r
1292         WindowMaximized = true;\r
1293 }\r
1294 \r
1295 \r
1296 //! Restores the window to its original size.\r
1297 void CIrrDeviceWin32::restoreWindow()\r
1298 {\r
1299         WINDOWPLACEMENT wndpl;\r
1300         wndpl.length = sizeof(WINDOWPLACEMENT);\r
1301         GetWindowPlacement(HWnd, &wndpl);\r
1302         wndpl.showCmd = SW_SHOWNORMAL;\r
1303         SetWindowPlacement(HWnd, &wndpl);\r
1304 \r
1305         WindowMaximized = false;\r
1306 }\r
1307 \r
1308 core::position2di CIrrDeviceWin32::getWindowPosition()\r
1309 {\r
1310         WINDOWPLACEMENT wndpl;\r
1311         wndpl.length = sizeof(WINDOWPLACEMENT);\r
1312         if (GetWindowPlacement(HWnd, &wndpl))\r
1313         {\r
1314                 return core::position2di((int)wndpl.rcNormalPosition.left,\r
1315                                          (int)wndpl.rcNormalPosition.top);\r
1316         }\r
1317         else\r
1318         {\r
1319                 // No reason for this to happen\r
1320                 os::Printer::log("Failed to retrieve window location", ELL_ERROR);\r
1321                 return core::position2di(-1, -1);\r
1322         }\r
1323 }\r
1324 \r
1325 bool CIrrDeviceWin32::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)\r
1326 {\r
1327         if (JoyControl)\r
1328                 return JoyControl->activateJoysticks(joystickInfo);\r
1329         else\r
1330                 return false;\r
1331 }\r
1332 \r
1333 \r
1334 //! Process system events\r
1335 void CIrrDeviceWin32::handleSystemMessages()\r
1336 {\r
1337         MSG msg;\r
1338 \r
1339         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))\r
1340         {\r
1341                 if (ExternalWindow && msg.hwnd == HWnd)\r
1342                 {\r
1343                         if (msg.hwnd == HWnd)\r
1344             {\r
1345                                 WndProc(HWnd, msg.message, msg.wParam, msg.lParam);\r
1346             }\r
1347             else\r
1348             {\r
1349                 TranslateMessage(&msg);\r
1350                 DispatchMessage(&msg);\r
1351             }\r
1352                 }\r
1353                 else\r
1354                 {\r
1355                         // No message translation because we don't use WM_CHAR and it would conflict with our\r
1356                         // deadkey handling.\r
1357                         DispatchMessage(&msg);\r
1358                 }\r
1359 \r
1360                 if (msg.message == WM_QUIT)\r
1361                         Close = true;\r
1362         }\r
1363 }\r
1364 \r
1365 \r
1366 //! Remove all messages pending in the system message loop\r
1367 void CIrrDeviceWin32::clearSystemMessages()\r
1368 {\r
1369         MSG msg;\r
1370         while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))\r
1371         {}\r
1372         while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))\r
1373         {}\r
1374 }\r
1375 \r
1376 // Convert an Irrlicht texture to a Windows cursor\r
1377 // Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/\r
1378 HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)\r
1379 {\r
1380         //\r
1381         // create the bitmaps needed for cursors from the texture\r
1382 \r
1383         HDC dc = GetDC(hwnd);\r
1384         HDC andDc = CreateCompatibleDC(dc);\r
1385         HDC xorDc = CreateCompatibleDC(dc);\r
1386         HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());\r
1387         HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());\r
1388 \r
1389         HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap);\r
1390         HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap);\r
1391 \r
1392 \r
1393         video::ECOLOR_FORMAT format = tex->getColorFormat();\r
1394         u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;\r
1395         u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;\r
1396         u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;\r
1397         const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);\r
1398         data += sourceRect.UpperLeftCorner.Y*tex->getPitch();\r
1399         for ( s32 y = 0; y < sourceRect.getHeight(); ++y )\r
1400         {\r
1401                 data += bytesLeftGap;\r
1402                 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )\r
1403                 {\r
1404                         video::SColor pixelCol;\r
1405                         pixelCol.setData((const void*)data, format);\r
1406                         data += bytesPerPixel;\r
1407 \r
1408                         if ( pixelCol.getAlpha() == 0 ) // transparent\r
1409                         {\r
1410                                 SetPixel(andDc, x, y, RGB(255,255,255));\r
1411                                 SetPixel(xorDc, x, y, RGB(0,0,0));\r
1412                         }\r
1413                         else    // color\r
1414                         {\r
1415                                 SetPixel(andDc, x, y, RGB(0,0,0));\r
1416                                 SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue()));\r
1417                         }\r
1418                 }\r
1419                 data += bytesRightGap;\r
1420         }\r
1421         tex->unlock();\r
1422 \r
1423         SelectObject(andDc, oldAndBitmap);\r
1424         SelectObject(xorDc, oldXorBitmap);\r
1425 \r
1426         DeleteDC(xorDc);\r
1427         DeleteDC(andDc);\r
1428 \r
1429         ReleaseDC(hwnd, dc);\r
1430 \r
1431         // create the cursor\r
1432 \r
1433         ICONINFO iconinfo;\r
1434         iconinfo.fIcon = false; // type is cursor not icon\r
1435         iconinfo.xHotspot = hotspot.X;\r
1436         iconinfo.yHotspot = hotspot.Y;\r
1437         iconinfo.hbmMask = andBitmap;\r
1438         iconinfo.hbmColor = xorBitmap;\r
1439 \r
1440         HCURSOR cursor = CreateIconIndirect(&iconinfo);\r
1441 \r
1442         DeleteObject(andBitmap);\r
1443         DeleteObject(xorBitmap);\r
1444 \r
1445         return cursor;\r
1446 }\r
1447 \r
1448 \r
1449 CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen)\r
1450         : Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f),\r
1451                 HWnd(hwnd), BorderX(0), BorderY(0),\r
1452                 UseReferenceRect(false), IsVisible(true)\r
1453                 , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)\r
1454 {\r
1455         if (WindowSize.Width!=0)\r
1456                 InvWindowSize.Width = 1.0f / WindowSize.Width;\r
1457 \r
1458         if (WindowSize.Height!=0)\r
1459                 InvWindowSize.Height = 1.0f / WindowSize.Height;\r
1460 \r
1461         updateBorderSize(fullscreen, false);\r
1462         initCursors();\r
1463 }\r
1464 \r
1465 CIrrDeviceWin32::CCursorControl::~CCursorControl()\r
1466 {\r
1467         for ( u32 i=0; i < Cursors.size(); ++i )\r
1468         {\r
1469                 for ( u32 f=0; f < Cursors[i].Frames.size(); ++f )\r
1470                 {\r
1471                         DestroyCursor(Cursors[i].Frames[f].IconHW);\r
1472                 }\r
1473         }\r
1474 }\r
1475 \r
1476 \r
1477 void CIrrDeviceWin32::CCursorControl::initCursors()\r
1478 {\r
1479         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_ARROW)) );\r
1480         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_CROSS)) );\r
1481         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HAND)) );\r
1482         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HELP)) );\r
1483         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_IBEAM)) );\r
1484         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_NO)) );\r
1485         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_WAIT)) );\r
1486         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEALL)) );\r
1487         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENESW)) );\r
1488         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENWSE)) );\r
1489         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENS)) );\r
1490         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEWE)) );\r
1491         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_UPARROW)) );\r
1492 }\r
1493 \r
1494 \r
1495 void CIrrDeviceWin32::CCursorControl::update()\r
1496 {\r
1497         if ( !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime )\r
1498         {\r
1499                 // update animated cursors. This could also be done by X11 in case someone wants to figure that out (this way was just easier to implement)\r
1500                 u32 now = Device->getTimer()->getRealTime();\r
1501                 u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();\r
1502                 SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW );\r
1503         }\r
1504 }\r
1505 \r
1506 //! Sets the active cursor icon\r
1507 void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId)\r
1508 {\r
1509         if ( iconId >= (s32)Cursors.size() )\r
1510                 return;\r
1511 \r
1512         ActiveIcon = iconId;\r
1513         ActiveIconStartTime = Device->getTimer()->getRealTime();\r
1514         if ( Cursors[ActiveIcon].Frames.size() )\r
1515                 SetCursor( Cursors[ActiveIcon].Frames[0].IconHW );\r
1516 }\r
1517 \r
1518 \r
1519 //! Add a custom sprite as cursor icon.\r
1520 gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite& icon)\r
1521 {\r
1522         if ( icon.SpriteId >= 0 )\r
1523         {\r
1524                 CursorW32 cW32;\r
1525                 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;\r
1526 \r
1527                 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )\r
1528                 {\r
1529                         irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;\r
1530                         irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;\r
1531                         irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];\r
1532 \r
1533                         HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);\r
1534                         cW32.Frames.push_back( CursorFrameW32(hc) );\r
1535                 }\r
1536 \r
1537                 Cursors.push_back( cW32 );\r
1538                 return (gui::ECURSOR_ICON)(Cursors.size() - 1);\r
1539         }\r
1540         return gui::ECI_NORMAL;\r
1541 }\r
1542 \r
1543 \r
1544 //! replace the given cursor icon.\r
1545 void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon)\r
1546 {\r
1547         if ( iconId >= (s32)Cursors.size() )\r
1548                 return;\r
1549 \r
1550         for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i )\r
1551                 DestroyCursor(Cursors[iconId].Frames[i].IconHW);\r
1552 \r
1553         if ( icon.SpriteId >= 0 )\r
1554         {\r
1555                 CursorW32 cW32;\r
1556                 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;\r
1557                 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )\r
1558                 {\r
1559                         irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;\r
1560                         irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;\r
1561                         irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];\r
1562 \r
1563                         HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);\r
1564                         cW32.Frames.push_back( CursorFrameW32(hc) );\r
1565                 }\r
1566 \r
1567                 Cursors[iconId] = cW32;\r
1568         }\r
1569 }\r
1570 \r
1571 \r
1572 //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.\r
1573 core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const\r
1574 {\r
1575         core::dimension2di result;\r
1576 \r
1577         result.Width = GetSystemMetrics(SM_CXCURSOR);\r
1578         result.Height = GetSystemMetrics(SM_CYCURSOR);\r
1579 \r
1580         return result;\r
1581 }\r
1582 \r
1583 \r
1584 \r
1585 } // end namespace\r
1586 \r
1587 #endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_\r