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