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