aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp2068
1 files changed, 2068 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp
new file mode 100644
index 0000000..22c405e
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp
@@ -0,0 +1,2068 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "IrrCompileConfig.h"
6
7#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
8
9#include "CIrrDeviceWin32.h"
10#include "IEventReceiver.h"
11#include "irrList.h"
12#include "os.h"
13
14#include "CTimer.h"
15#include "irrString.h"
16#include "COSOperator.h"
17#include "dimension2d.h"
18#include "IGUISpriteBank.h"
19#include <winuser.h>
20#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
21#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
22#define DIRECTINPUT_VERSION 0x0800
23#include <dinput.h>
24#ifdef _MSC_VER
25#pragma comment(lib, "dinput8.lib")
26#pragma comment(lib, "dxguid.lib")
27#endif
28#else
29#ifdef _MSC_VER
30#pragma comment(lib, "winmm.lib")
31#endif
32#endif
33#endif
34
35namespace irr
36{
37 namespace video
38 {
39 #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_
40 IVideoDriver* createDirectX8Driver(const irr::SIrrlichtCreationParameters& params,
41 io::IFileSystem* io, HWND window);
42 #endif
43
44 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
45 IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params,
46 io::IFileSystem* io, HWND window);
47 #endif
48
49 #ifdef _IRR_COMPILE_WITH_OPENGL_
50 IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params,
51 io::IFileSystem* io, CIrrDeviceWin32* device);
52 #endif
53 }
54} // end namespace irr
55
56namespace irr
57{
58struct SJoystickWin32Control
59{
60 CIrrDeviceWin32* Device;
61
62#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
63 IDirectInput8* DirectInputDevice;
64#endif
65#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
66 struct JoystickInfo
67 {
68 u32 Index;
69#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
70 core::stringc Name;
71 GUID guid;
72 LPDIRECTINPUTDEVICE8 lpdijoy;
73 DIDEVCAPS devcaps;
74 u8 axisValid[8];
75#else
76 JOYCAPS Caps;
77#endif
78 };
79 core::array<JoystickInfo> ActiveJoysticks;
80#endif
81
82 SJoystickWin32Control(CIrrDeviceWin32* dev) : Device(dev)
83 {
84#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
85 DirectInputDevice=0;
86 if (DI_OK != (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInputDevice, NULL)))
87 {
88 os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING);
89 return;
90 }
91#endif
92 }
93 ~SJoystickWin32Control()
94 {
95#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
96 for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
97 {
98 LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy;
99 if (dev)
100 {
101 dev->Unacquire();
102 }
103 dev->Release();
104 }
105
106 if (DirectInputDevice)
107 DirectInputDevice->Release();
108#endif
109 }
110
111#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
112 static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp)
113 {
114 SJoystickWin32Control* p=(SJoystickWin32Control*)cp;
115 p->directInputAddJoystick(lpddi);
116 return DIENUM_CONTINUE;
117 }
118 void directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi)
119 {
120 //Get the GUID of the joystuck
121 const GUID guid = lpddi->guidInstance;
122
123 JoystickInfo activeJoystick;
124 activeJoystick.Index=ActiveJoysticks.size();
125 activeJoystick.guid=guid;
126 activeJoystick.Name=lpddi->tszProductName;
127 if (FAILED(DirectInputDevice->CreateDevice(guid, &activeJoystick.lpdijoy, NULL)))
128 {
129 os::Printer::log("Could not create DirectInput device", ELL_WARNING);
130 return;
131 }
132
133 activeJoystick.devcaps.dwSize=sizeof(activeJoystick.devcaps);
134 if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps)))
135 {
136 os::Printer::log("Could not create DirectInput device", ELL_WARNING);
137 return;
138 }
139
140 if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE)))
141 {
142 os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING);
143 return;
144 }
145
146 if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2)))
147 {
148 os::Printer::log("Could not set DirectInput device data format", ELL_WARNING);
149 return;
150 }
151
152 if (FAILED(activeJoystick.lpdijoy->Acquire()))
153 {
154 os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING);
155 return;
156 }
157
158 DIJOYSTATE2 info;
159 if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info),&info)))
160 {
161 os::Printer::log("Could not read DirectInput device state", ELL_WARNING);
162 return;
163 }
164
165 ZeroMemory(activeJoystick.axisValid,sizeof(activeJoystick.axisValid));
166 activeJoystick.axisValid[0]= (info.lX!=0) ? 1 : 0;
167 activeJoystick.axisValid[1]= (info.lY!=0) ? 1 : 0;
168 activeJoystick.axisValid[2]= (info.lZ!=0) ? 1 : 0;
169 activeJoystick.axisValid[3]= (info.lRx!=0) ? 1 : 0;
170 activeJoystick.axisValid[4]= (info.lRy!=0) ? 1 : 0;
171 activeJoystick.axisValid[5]= (info.lRz!=0) ? 1 : 0;
172
173 int caxis=0;
174 for (u8 i=0; i<6; i++)
175 {
176 if (activeJoystick.axisValid[i])
177 caxis++;
178 }
179
180 for (u8 i=0; i<(activeJoystick.devcaps.dwAxes)-caxis; i++)
181 {
182 if (i+caxis < 8)
183 activeJoystick.axisValid[i+caxis]=1;
184 }
185
186 ActiveJoysticks.push_back(activeJoystick);
187 }
188#endif
189
190void pollJoysticks()
191{
192#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
193#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
194 if(0 == ActiveJoysticks.size())
195 return;
196
197 u32 joystick;
198 DIJOYSTATE2 info;
199
200 for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
201 {
202 // needs to be reset for each joystick
203 // request ALL values and POV as continuous if possible
204
205 const DIDEVCAPS & caps = ActiveJoysticks[joystick].devcaps;
206 // if no POV is available don't ask for POV values
207
208 if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info),&info)))
209 {
210 SEvent event;
211
212 event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
213 event.JoystickEvent.Joystick = (u8)joystick;
214
215 event.JoystickEvent.POV = (u16)info.rgdwPOV[0];
216 // set to undefined if no POV value was returned or the value
217 // is out of range
218 if ((caps.dwPOVs==0) || (event.JoystickEvent.POV > 35900))
219 event.JoystickEvent.POV = 65535;
220
221 for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)
222 event.JoystickEvent.Axis[axis] = 0;
223
224 u16 dxAxis=0;
225 u16 irrAxis=0;
226
227 while (dxAxis < 6 && irrAxis <caps.dwAxes)
228 {
229 bool axisFound=0;
230 s32 axisValue=0;
231
232 switch (dxAxis)
233 {
234 case 0:
235 axisValue=info.lX;
236 break;
237 case 1:
238 axisValue=info.lY;
239 break;
240 case 2:
241 axisValue=info.lZ;
242 break;
243 case 3:
244 axisValue=info.lRx;
245 break;
246 case 4:
247 axisValue=info.lRy;
248 break;
249 case 5:
250 axisValue=info.lRz;
251 break;
252 case 6:
253 axisValue=info.rglSlider[0];
254 break;
255 case 7:
256 axisValue=info.rglSlider[1];
257 break;
258 default:
259 break;
260 }
261
262 if (ActiveJoysticks[joystick].axisValid[dxAxis]>0)
263 axisFound=1;
264
265 if (axisFound)
266 {
267 s32 val=axisValue - 32768;
268
269 if (val <-32767) val=-32767;
270 if (val > 32767) val=32767;
271 event.JoystickEvent.Axis[irrAxis]=(s16)(val);
272 irrAxis++;
273 }
274
275 dxAxis++;
276 }
277
278 u32 buttons=0;
279 BYTE* bytebuttons=info.rgbButtons;
280 for (u16 i=0; i<32; i++)
281 {
282 if (bytebuttons[i] >0)
283 {
284 buttons |= (1 << i);
285 }
286 }
287 event.JoystickEvent.ButtonStates = buttons;
288
289 (void)Device->postEventFromUser(event);
290 }
291 }
292#else
293 if (0 == ActiveJoysticks.size())
294 return;
295
296 u32 joystick;
297 JOYINFOEX info;
298
299 for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
300 {
301 // needs to be reset for each joystick
302 // request ALL values and POV as continuous if possible
303 info.dwSize = sizeof(info);
304 info.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;
305 const JOYCAPS & caps = ActiveJoysticks[joystick].Caps;
306 // if no POV is available don't ask for POV values
307 if (!(caps.wCaps & JOYCAPS_HASPOV))
308 info.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS);
309 if(JOYERR_NOERROR == joyGetPosEx(ActiveJoysticks[joystick].Index, &info))
310 {
311 SEvent event;
312
313 event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
314 event.JoystickEvent.Joystick = (u8)joystick;
315
316 event.JoystickEvent.POV = (u16)info.dwPOV;
317 // set to undefined if no POV value was returned or the value
318 // is out of range
319 if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900))
320 event.JoystickEvent.POV = 65535;
321
322 for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)
323 event.JoystickEvent.Axis[axis] = 0;
324
325 event.JoystickEvent.ButtonStates = info.dwButtons;
326
327 switch(caps.wNumAxes)
328 {
329 default:
330 case 6:
331 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] =
332 (s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768);
333
334 case 5:
335 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] =
336 (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768);
337
338 case 4:
339 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] =
340 (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768);
341
342 case 3:
343 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] =
344 (s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768);
345
346 case 2:
347 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] =
348 (s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768);
349
350 case 1:
351 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] =
352 (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768);
353 }
354
355 (void)Device->postEventFromUser(event);
356 }
357 }
358#endif
359#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
360}
361
362bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
363{
364#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
365#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
366 if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY )))
367 {
368 os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING);
369 return false;
370 }
371
372 for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
373 {
374 JoystickInfo& activeJoystick = ActiveJoysticks[joystick];
375 SJoystickInfo info;
376 info.Axes=activeJoystick.devcaps.dwAxes;
377 info.Buttons=activeJoystick.devcaps.dwButtons;
378 info.Name=activeJoystick.Name;
379 info.PovHat = (activeJoystick.devcaps.dwPOVs != 0)
380 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;
381 joystickInfo.push_back(info);
382 }
383 return true;
384#else
385 joystickInfo.clear();
386 ActiveJoysticks.clear();
387
388 const u32 numberOfJoysticks = ::joyGetNumDevs();
389 JOYINFOEX info;
390 info.dwSize = sizeof(info);
391 info.dwFlags = JOY_RETURNALL;
392
393 JoystickInfo activeJoystick;
394 SJoystickInfo returnInfo;
395
396 joystickInfo.reallocate(numberOfJoysticks);
397 ActiveJoysticks.reallocate(numberOfJoysticks);
398
399 u32 joystick = 0;
400 for(; joystick < numberOfJoysticks; ++joystick)
401 {
402 if(JOYERR_NOERROR == joyGetPosEx(joystick, &info)
403 &&
404 JOYERR_NOERROR == joyGetDevCaps(joystick,
405 &activeJoystick.Caps,
406 sizeof(activeJoystick.Caps)))
407 {
408 activeJoystick.Index = joystick;
409 ActiveJoysticks.push_back(activeJoystick);
410
411 returnInfo.Joystick = (u8)joystick;
412 returnInfo.Axes = activeJoystick.Caps.wNumAxes;
413 returnInfo.Buttons = activeJoystick.Caps.wNumButtons;
414 returnInfo.Name = activeJoystick.Caps.szPname;
415 returnInfo.PovHat = ((activeJoystick.Caps.wCaps & JOYCAPS_HASPOV) == JOYCAPS_HASPOV)
416 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;
417
418 joystickInfo.push_back(returnInfo);
419 }
420 }
421
422 for(joystick = 0; joystick < joystickInfo.size(); ++joystick)
423 {
424 char logString[256];
425 (void)sprintf(logString, "Found joystick %d, %d axes, %d buttons '%s'",
426 joystick, joystickInfo[joystick].Axes,
427 joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());
428 os::Printer::log(logString, ELL_INFORMATION);
429 }
430
431 return true;
432#endif
433#else
434 return false;
435#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
436}
437};
438} // end namespace irr
439
440// Get the codepage from the locale language id
441// Based on the table from http://www.science.co.il/Language/Locale-Codes.asp?s=decimal
442static unsigned int LocaleIdToCodepage(unsigned int lcid)
443{
444 switch ( lcid )
445 {
446 case 1098: // Telugu
447 case 1095: // Gujarati
448 case 1094: // Punjabi
449 case 1103: // Sanskrit
450 case 1111: // Konkani
451 case 1114: // Syriac
452 case 1099: // Kannada
453 case 1102: // Marathi
454 case 1125: // Divehi
455 case 1067: // Armenian
456 case 1081: // Hindi
457 case 1079: // Georgian
458 case 1097: // Tamil
459 return 0;
460 case 1054: // Thai
461 return 874;
462 case 1041: // Japanese
463 return 932;
464 case 2052: // Chinese (PRC)
465 case 4100: // Chinese (Singapore)
466 return 936;
467 case 1042: // Korean
468 return 949;
469 case 5124: // Chinese (Macau S.A.R.)
470 case 3076: // Chinese (Hong Kong S.A.R.)
471 case 1028: // Chinese (Taiwan)
472 return 950;
473 case 1048: // Romanian
474 case 1060: // Slovenian
475 case 1038: // Hungarian
476 case 1051: // Slovak
477 case 1045: // Polish
478 case 1052: // Albanian
479 case 2074: // Serbian (Latin)
480 case 1050: // Croatian
481 case 1029: // Czech
482 return 1250;
483 case 1104: // Mongolian (Cyrillic)
484 case 1071: // FYRO Macedonian
485 case 2115: // Uzbek (Cyrillic)
486 case 1058: // Ukrainian
487 case 2092: // Azeri (Cyrillic)
488 case 1092: // Tatar
489 case 1087: // Kazakh
490 case 1059: // Belarusian
491 case 1088: // Kyrgyz (Cyrillic)
492 case 1026: // Bulgarian
493 case 3098: // Serbian (Cyrillic)
494 case 1049: // Russian
495 return 1251;
496 case 8201: // English (Jamaica)
497 case 3084: // French (Canada)
498 case 1036: // French (France)
499 case 5132: // French (Luxembourg)
500 case 5129: // English (New Zealand)
501 case 6153: // English (Ireland)
502 case 1043: // Dutch (Netherlands)
503 case 9225: // English (Caribbean)
504 case 4108: // French (Switzerland)
505 case 4105: // English (Canada)
506 case 1110: // Galician
507 case 10249: // English (Belize)
508 case 3079: // German (Austria)
509 case 6156: // French (Monaco)
510 case 12297: // English (Zimbabwe)
511 case 1069: // Basque
512 case 2067: // Dutch (Belgium)
513 case 2060: // French (Belgium)
514 case 1035: // Finnish
515 case 1080: // Faroese
516 case 1031: // German (Germany)
517 case 3081: // English (Australia)
518 case 1033: // English (United States)
519 case 2057: // English (United Kingdom)
520 case 1027: // Catalan
521 case 11273: // English (Trinidad)
522 case 7177: // English (South Africa)
523 case 1030: // Danish
524 case 13321: // English (Philippines)
525 case 15370: // Spanish (Paraguay)
526 case 9226: // Spanish (Colombia)
527 case 5130: // Spanish (Costa Rica)
528 case 7178: // Spanish (Dominican Republic)
529 case 12298: // Spanish (Ecuador)
530 case 17418: // Spanish (El Salvador)
531 case 4106: // Spanish (Guatemala)
532 case 18442: // Spanish (Honduras)
533 case 3082: // Spanish (International Sort)
534 case 13322: // Spanish (Chile)
535 case 19466: // Spanish (Nicaragua)
536 case 2058: // Spanish (Mexico)
537 case 10250: // Spanish (Peru)
538 case 20490: // Spanish (Puerto Rico)
539 case 1034: // Spanish (Traditional Sort)
540 case 14346: // Spanish (Uruguay)
541 case 8202: // Spanish (Venezuela)
542 case 1089: // Swahili
543 case 1053: // Swedish
544 case 2077: // Swedish (Finland)
545 case 5127: // German (Liechtenstein)
546 case 1078: // Afrikaans
547 case 6154: // Spanish (Panama)
548 case 4103: // German (Luxembourg)
549 case 16394: // Spanish (Bolivia)
550 case 2055: // German (Switzerland)
551 case 1039: // Icelandic
552 case 1057: // Indonesian
553 case 1040: // Italian (Italy)
554 case 2064: // Italian (Switzerland)
555 case 2068: // Norwegian (Nynorsk)
556 case 11274: // Spanish (Argentina)
557 case 1046: // Portuguese (Brazil)
558 case 1044: // Norwegian (Bokmal)
559 case 1086: // Malay (Malaysia)
560 case 2110: // Malay (Brunei Darussalam)
561 case 2070: // Portuguese (Portugal)
562 return 1252;
563 case 1032: // Greek
564 return 1253;
565 case 1091: // Uzbek (Latin)
566 case 1068: // Azeri (Latin)
567 case 1055: // Turkish
568 return 1254;
569 case 1037: // Hebrew
570 return 1255;
571 case 5121: // Arabic (Algeria)
572 case 15361: // Arabic (Bahrain)
573 case 9217: // Arabic (Yemen)
574 case 3073: // Arabic (Egypt)
575 case 2049: // Arabic (Iraq)
576 case 11265: // Arabic (Jordan)
577 case 13313: // Arabic (Kuwait)
578 case 12289: // Arabic (Lebanon)
579 case 4097: // Arabic (Libya)
580 case 6145: // Arabic (Morocco)
581 case 8193: // Arabic (Oman)
582 case 16385: // Arabic (Qatar)
583 case 1025: // Arabic (Saudi Arabia)
584 case 10241: // Arabic (Syria)
585 case 14337: // Arabic (U.A.E.)
586 case 1065: // Farsi
587 case 1056: // Urdu
588 case 7169: // Arabic (Tunisia)
589 return 1256;
590 case 1061: // Estonian
591 case 1062: // Latvian
592 case 1063: // Lithuanian
593 return 1257;
594 case 1066: // Vietnamese
595 return 1258;
596 }
597 return 65001; // utf-8
598}
599
600namespace
601{
602 struct SEnvMapper
603 {
604 HWND hWnd;
605 irr::CIrrDeviceWin32* irrDev;
606 };
607 irr::core::list<SEnvMapper> EnvMap;
608
609 HKL KEYBOARD_INPUT_HKL=0;
610 unsigned int KEYBOARD_INPUT_CODEPAGE = 1252;
611}
612
613SEnvMapper* getEnvMapperFromHWnd(HWND hWnd)
614{
615 irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin();
616 for (; it!= EnvMap.end(); ++it)
617 if ((*it).hWnd == hWnd)
618 return &(*it);
619
620 return 0;
621}
622
623
624irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)
625{
626 irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin();
627 for (; it!= EnvMap.end(); ++it)
628 if ((*it).hWnd == hWnd)
629 return (*it).irrDev;
630
631 return 0;
632}
633
634
635LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
636{
637 #ifndef WM_MOUSEWHEEL
638 #define WM_MOUSEWHEEL 0x020A
639 #endif
640 #ifndef WHEEL_DELTA
641 #define WHEEL_DELTA 120
642 #endif
643
644 irr::CIrrDeviceWin32* dev = 0;
645 irr::SEvent event;
646
647 static irr::s32 ClickCount=0;
648 if (GetCapture() != hWnd && ClickCount > 0)
649 ClickCount = 0;
650
651
652 struct messageMap
653 {
654 irr::s32 group;
655 UINT winMessage;
656 irr::s32 irrMessage;
657 };
658
659 static messageMap mouseMap[] =
660 {
661 {0, WM_LBUTTONDOWN, irr::EMIE_LMOUSE_PRESSED_DOWN},
662 {1, WM_LBUTTONUP, irr::EMIE_LMOUSE_LEFT_UP},
663 {0, WM_RBUTTONDOWN, irr::EMIE_RMOUSE_PRESSED_DOWN},
664 {1, WM_RBUTTONUP, irr::EMIE_RMOUSE_LEFT_UP},
665 {0, WM_MBUTTONDOWN, irr::EMIE_MMOUSE_PRESSED_DOWN},
666 {1, WM_MBUTTONUP, irr::EMIE_MMOUSE_LEFT_UP},
667 {2, WM_MOUSEMOVE, irr::EMIE_MOUSE_MOVED},
668 {3, WM_MOUSEWHEEL, irr::EMIE_MOUSE_WHEEL},
669 {-1, 0, 0}
670 };
671
672 // handle grouped events
673 messageMap * m = mouseMap;
674 while ( m->group >=0 && m->winMessage != message )
675 m += 1;
676
677 if ( m->group >= 0 )
678 {
679 if ( m->group == 0 ) // down
680 {
681 ClickCount++;
682 SetCapture(hWnd);
683 }
684 else
685 if ( m->group == 1 ) // up
686 {
687 ClickCount--;
688 if (ClickCount<1)
689 {
690 ClickCount=0;
691 ReleaseCapture();
692 }
693 }
694
695 event.EventType = irr::EET_MOUSE_INPUT_EVENT;
696 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT) m->irrMessage;
697 event.MouseInput.X = (short)LOWORD(lParam);
698 event.MouseInput.Y = (short)HIWORD(lParam);
699 event.MouseInput.Shift = ((LOWORD(wParam) & MK_SHIFT) != 0);
700 event.MouseInput.Control = ((LOWORD(wParam) & MK_CONTROL) != 0);
701 // left and right mouse buttons
702 event.MouseInput.ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON);
703 // middle and extra buttons
704 if (wParam & MK_MBUTTON)
705 event.MouseInput.ButtonStates |= irr::EMBSM_MIDDLE;
706#if(_WIN32_WINNT >= 0x0500)
707 if (wParam & MK_XBUTTON1)
708 event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA1;
709 if (wParam & MK_XBUTTON2)
710 event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA2;
711#endif
712 event.MouseInput.Wheel = 0.f;
713
714 // wheel
715 if ( m->group == 3 )
716 {
717 POINT p; // fixed by jox
718 p.x = 0; p.y = 0;
719 ClientToScreen(hWnd, &p);
720 event.MouseInput.X -= p.x;
721 event.MouseInput.Y -= p.y;
722 event.MouseInput.Wheel = ((irr::f32)((short)HIWORD(wParam))) / (irr::f32)WHEEL_DELTA;
723 }
724
725 dev = getDeviceFromHWnd(hWnd);
726 if (dev)
727 {
728 dev->postEventFromUser(event);
729
730 if ( event.MouseInput.Event >= irr::EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= irr::EMIE_MMOUSE_PRESSED_DOWN )
731 {
732 irr::u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event);
733 if ( clicks == 2 )
734 {
735 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_DOUBLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);
736 dev->postEventFromUser(event);
737 }
738 else if ( clicks == 3 )
739 {
740 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_TRIPLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);
741 dev->postEventFromUser(event);
742 }
743 }
744 }
745 return 0;
746 }
747
748 switch (message)
749 {
750 case WM_PAINT:
751 {
752 PAINTSTRUCT ps;
753 BeginPaint(hWnd, &ps);
754 EndPaint(hWnd, &ps);
755 }
756 return 0;
757
758 case WM_ERASEBKGND:
759 return 0;
760
761 case WM_SYSKEYDOWN:
762 case WM_SYSKEYUP:
763 case WM_KEYDOWN:
764 case WM_KEYUP:
765 {
766 BYTE allKeys[256];
767
768 event.EventType = irr::EET_KEY_INPUT_EVENT;
769 event.KeyInput.Key = (irr::EKEY_CODE)wParam;
770 event.KeyInput.PressedDown = (message==WM_KEYDOWN || message == WM_SYSKEYDOWN);
771
772 const UINT MY_MAPVK_VSC_TO_VK_EX = 3; // MAPVK_VSC_TO_VK_EX should be in SDK according to MSDN, but isn't in mine.
773 if ( event.KeyInput.Key == irr::KEY_SHIFT )
774 {
775 // this will fail on systems before windows NT/2000/XP, not sure _what_ will return there instead.
776 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX );
777 }
778 if ( event.KeyInput.Key == irr::KEY_CONTROL )
779 {
780 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX );
781 // some keyboards will just return LEFT for both - left and right keys. So also check extend bit.
782 if (lParam & 0x1000000)
783 event.KeyInput.Key = irr::KEY_RCONTROL;
784 }
785 if ( event.KeyInput.Key == irr::KEY_MENU )
786 {
787 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX );
788 if (lParam & 0x1000000)
789 event.KeyInput.Key = irr::KEY_RMENU;
790 }
791
792 GetKeyboardState(allKeys);
793
794 event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80)!=0);
795 event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80)!=0);
796
797 // Handle unicode and deadkeys in a way that works since Windows 95 and nt4.0
798 // Using ToUnicode instead would be shorter, but would to my knowledge not run on 95 and 98.
799 WORD keyChars[2];
800 UINT scanCode = HIWORD(lParam);
801 int conversionResult = ToAsciiEx(wParam,scanCode,allKeys,keyChars,0,KEYBOARD_INPUT_HKL);
802 if (conversionResult == 1)
803 {
804 WORD unicodeChar;
805 MultiByteToWideChar(
806 KEYBOARD_INPUT_CODEPAGE,
807 MB_PRECOMPOSED, // default
808 (LPCSTR)keyChars,
809 sizeof(keyChars),
810 (WCHAR*)&unicodeChar,
811 1 );
812 event.KeyInput.Char = unicodeChar;
813 }
814 else
815 event.KeyInput.Char = 0;
816
817 // allow composing characters like '@' with Alt Gr on non-US keyboards
818 if ((allKeys[VK_MENU] & 0x80) != 0)
819 event.KeyInput.Control = 0;
820
821 dev = getDeviceFromHWnd(hWnd);
822 if (dev)
823 dev->postEventFromUser(event);
824
825 if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)
826 return DefWindowProc(hWnd, message, wParam, lParam);
827 else
828 return 0;
829 }
830
831 case WM_SIZE:
832 {
833 // resize
834 dev = getDeviceFromHWnd(hWnd);
835 if (dev)
836 dev->OnResized();
837 }
838 return 0;
839
840 case WM_DESTROY:
841 PostQuitMessage(0);
842 return 0;
843
844 case WM_SYSCOMMAND:
845 // prevent screensaver or monitor powersave mode from starting
846 if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
847 (wParam & 0xFFF0) == SC_MONITORPOWER ||
848 (wParam & 0xFFF0) == SC_KEYMENU
849 )
850 return 0;
851
852 break;
853
854 case WM_ACTIVATE:
855 // we need to take care for screen changes, e.g. Alt-Tab
856 dev = getDeviceFromHWnd(hWnd);
857 if (dev && dev->isFullscreen())
858 {
859 if ((wParam&0xFF)==WA_INACTIVE)
860 {
861 // If losing focus we minimize the app to show other one
862 ShowWindow(hWnd,SW_MINIMIZE);
863 // and switch back to default resolution
864 dev->switchToFullScreen(true);
865 }
866 else
867 {
868 // Otherwise we retore the fullscreen Irrlicht app
869 SetForegroundWindow(hWnd);
870 ShowWindow(hWnd, SW_RESTORE);
871 // and set the fullscreen resolution again
872 dev->switchToFullScreen();
873 }
874 }
875 break;
876
877 case WM_USER:
878 event.EventType = irr::EET_USER_EVENT;
879 event.UserEvent.UserData1 = (irr::s32)wParam;
880 event.UserEvent.UserData2 = (irr::s32)lParam;
881 dev = getDeviceFromHWnd(hWnd);
882
883 if (dev)
884 dev->postEventFromUser(event);
885
886 return 0;
887
888 case WM_SETCURSOR:
889 // because Windows forgot about that in the meantime
890 dev = getDeviceFromHWnd(hWnd);
891 if (dev)
892 {
893 dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() );
894 dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() );
895 }
896 break;
897
898 case WM_INPUTLANGCHANGE:
899 // get the new codepage used for keyboard input
900 KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
901 KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );
902 return 0;
903 }
904 return DefWindowProc(hWnd, message, wParam, lParam);
905}
906
907
908namespace irr
909{
910
911//! constructor
912CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)
913: CIrrDeviceStub(params), HWnd(0), ChangedToFullScreen(false), Resized(false),
914 ExternalWindow(false), Win32CursorControl(0), JoyControl(0)
915{
916 #ifdef _DEBUG
917 setDebugName("CIrrDeviceWin32");
918 #endif
919
920 // get windows version and create OS operator
921 core::stringc winversion;
922 getWindowsVersion(winversion);
923 Operator = new COSOperator(winversion);
924 os::Printer::log(winversion.c_str(), ELL_INFORMATION);
925
926 // get handle to exe file
927 HINSTANCE hInstance = GetModuleHandle(0);
928
929 // Store original desktop mode.
930
931 memset(&DesktopMode, 0, sizeof(DesktopMode));
932 DesktopMode.dmSize = sizeof(DesktopMode);
933
934 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DesktopMode);
935
936 // create the window if we need to and we do not use the null device
937 if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL)
938 {
939 const fschar_t* ClassName = __TEXT("CIrrDeviceWin32");
940
941 // Register Class
942 WNDCLASSEX wcex;
943 wcex.cbSize = sizeof(WNDCLASSEX);
944 wcex.style = CS_HREDRAW | CS_VREDRAW;
945 wcex.lpfnWndProc = WndProc;
946 wcex.cbClsExtra = 0;
947 wcex.cbWndExtra = 0;
948 wcex.hInstance = hInstance;
949 wcex.hIcon = NULL;
950 wcex.hCursor = 0; // LoadCursor(NULL, IDC_ARROW);
951 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
952 wcex.lpszMenuName = 0;
953 wcex.lpszClassName = ClassName;
954 wcex.hIconSm = 0;
955
956 // if there is an icon, load it
957 wcex.hIcon = (HICON)LoadImage(hInstance, __TEXT("irrlicht.ico"), IMAGE_ICON, 0,0, LR_LOADFROMFILE);
958
959 RegisterClassEx(&wcex);
960
961 // calculate client size
962
963 RECT clientSize;
964 clientSize.top = 0;
965 clientSize.left = 0;
966 clientSize.right = CreationParams.WindowSize.Width;
967 clientSize.bottom = CreationParams.WindowSize.Height;
968
969 DWORD style = WS_POPUP;
970
971 if (!CreationParams.Fullscreen)
972 style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
973
974 AdjustWindowRect(&clientSize, style, FALSE);
975
976 const s32 realWidth = clientSize.right - clientSize.left;
977 const s32 realHeight = clientSize.bottom - clientSize.top;
978
979 s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;
980 s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;
981
982 if ( windowLeft < 0 )
983 windowLeft = 0;
984 if ( windowTop < 0 )
985 windowTop = 0; // make sure window menus are in screen on creation
986
987 if (CreationParams.Fullscreen)
988 {
989 windowLeft = 0;
990 windowTop = 0;
991 }
992
993 // create window
994
995 HWnd = CreateWindow( ClassName, __TEXT(""), style, windowLeft, windowTop,
996 realWidth, realHeight, NULL, NULL, hInstance, NULL);
997 CreationParams.WindowId = HWnd;
998// CreationParams.WindowSize.Width = realWidth;
999// CreationParams.WindowSize.Height = realHeight;
1000
1001 ShowWindow(HWnd, SW_SHOWNORMAL);
1002 UpdateWindow(HWnd);
1003
1004 // fix ugly ATI driver bugs. Thanks to ariaci
1005 MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE);
1006
1007 // make sure everything gets updated to the real sizes
1008 Resized = true;
1009 }
1010 else if (CreationParams.WindowId)
1011 {
1012 // attach external window
1013 HWnd = static_cast<HWND>(CreationParams.WindowId);
1014 RECT r;
1015 GetWindowRect(HWnd, &r);
1016 CreationParams.WindowSize.Width = r.right - r.left;
1017 CreationParams.WindowSize.Height = r.bottom - r.top;
1018 CreationParams.Fullscreen = false;
1019 ExternalWindow = true;
1020 }
1021
1022 // create cursor control
1023
1024 Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen);
1025 CursorControl = Win32CursorControl;
1026 JoyControl = new SJoystickWin32Control(this);
1027
1028 // initialize doubleclicks with system values
1029 MouseMultiClicks.DoubleClickTime = GetDoubleClickTime();
1030
1031 // create driver
1032
1033 createDriver();
1034
1035 if (VideoDriver)
1036 createGUIAndScene();
1037
1038 // register environment
1039
1040 SEnvMapper em;
1041 em.irrDev = this;
1042 em.hWnd = HWnd;
1043 EnvMap.push_back(em);
1044
1045 // set this as active window
1046 if (!ExternalWindow)
1047 {
1048 SetActiveWindow(HWnd);
1049 SetForegroundWindow(HWnd);
1050 }
1051
1052 // get the codepage used for keyboard input
1053 KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
1054 KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );
1055
1056 // inform driver about the window size etc.
1057 resizeIfNecessary();
1058}
1059
1060
1061//! destructor
1062CIrrDeviceWin32::~CIrrDeviceWin32()
1063{
1064 delete JoyControl;
1065
1066 // unregister environment
1067
1068 irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin();
1069 for (; it!= EnvMap.end(); ++it)
1070 {
1071 if ((*it).hWnd == HWnd)
1072 {
1073 EnvMap.erase(it);
1074 break;
1075 }
1076 }
1077
1078 switchToFullScreen(true);
1079}
1080
1081
1082//! create the driver
1083void CIrrDeviceWin32::createDriver()
1084{
1085 switch(CreationParams.DriverType)
1086 {
1087 case video::EDT_DIRECT3D8:
1088 #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_
1089
1090 VideoDriver = video::createDirectX8Driver(CreationParams, FileSystem, HWnd);
1091
1092 if (!VideoDriver)
1093 {
1094 os::Printer::log("Could not create DIRECT3D8 Driver.", ELL_ERROR);
1095 }
1096 #else
1097 os::Printer::log("DIRECT3D8 Driver was not compiled into this dll. Try another one.", ELL_ERROR);
1098 #endif // _IRR_COMPILE_WITH_DIRECT3D_8_
1099
1100 break;
1101
1102 case video::EDT_DIRECT3D9:
1103 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
1104
1105 VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd);
1106
1107 if (!VideoDriver)
1108 {
1109 os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR);
1110 }
1111 #else
1112 os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR);
1113 #endif // _IRR_COMPILE_WITH_DIRECT3D_9_
1114
1115 break;
1116
1117 case video::EDT_OPENGL:
1118
1119 #ifdef _IRR_COMPILE_WITH_OPENGL_
1120 switchToFullScreen();
1121
1122 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this);
1123 if (!VideoDriver)
1124 {
1125 os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);
1126 }
1127 #else
1128 os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR);
1129 #endif
1130 break;
1131
1132 case video::EDT_SOFTWARE:
1133
1134 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
1135 switchToFullScreen();
1136
1137 VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
1138 #else
1139 os::Printer::log("Software driver was not compiled in.", ELL_ERROR);
1140 #endif
1141
1142 break;
1143
1144 case video::EDT_BURNINGSVIDEO:
1145 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
1146 switchToFullScreen();
1147
1148 VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
1149 #else
1150 os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR);
1151 #endif
1152 break;
1153
1154 case video::EDT_NULL:
1155 // create null driver
1156 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
1157 break;
1158
1159 default:
1160 os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
1161 break;
1162 }
1163}
1164
1165
1166//! runs the device. Returns false if device wants to be deleted
1167bool CIrrDeviceWin32::run()
1168{
1169 os::Timer::tick();
1170
1171 static_cast<CCursorControl*>(CursorControl)->update();
1172
1173 handleSystemMessages();
1174
1175 if (!Close)
1176 resizeIfNecessary();
1177
1178 if(!Close && JoyControl)
1179 JoyControl->pollJoysticks();
1180
1181 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
1182 return !Close;
1183}
1184
1185
1186//! Pause the current process for the minimum time allowed only to allow other processes to execute
1187void CIrrDeviceWin32::yield()
1188{
1189 Sleep(1);
1190}
1191
1192//! Pause execution and let other processes to run for a specified amount of time.
1193void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer)
1194{
1195 const bool wasStopped = Timer ? Timer->isStopped() : true;
1196 if (pauseTimer && !wasStopped)
1197 Timer->stop();
1198
1199 Sleep(timeMs);
1200
1201 if (pauseTimer && !wasStopped)
1202 Timer->start();
1203}
1204
1205
1206void CIrrDeviceWin32::resizeIfNecessary()
1207{
1208 if (!Resized || !getVideoDriver())
1209 return;
1210
1211 RECT r;
1212 GetClientRect(HWnd, &r);
1213
1214 char tmp[255];
1215
1216 if (r.right < 2 || r.bottom < 2)
1217 {
1218 sprintf(tmp, "Ignoring resize operation to (%ld %ld)", r.right, r.bottom);
1219 os::Printer::log(tmp);
1220 }
1221 else
1222 {
1223 sprintf(tmp, "Resizing window (%ld %ld)", r.right, r.bottom);
1224 os::Printer::log(tmp);
1225
1226 getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom));
1227 getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize());
1228 }
1229
1230 Resized = false;
1231}
1232
1233
1234//! sets the caption of the window
1235void CIrrDeviceWin32::setWindowCaption(const wchar_t* text)
1236{
1237 // We use SendMessage instead of SetText to ensure proper
1238 // function even in cases where the HWND was created in a different thread
1239 DWORD_PTR dwResult;
1240 SendMessageTimeoutW(HWnd, WM_SETTEXT, 0,
1241 reinterpret_cast<LPARAM>(text),
1242 SMTO_ABORTIFHUNG, 2000, &dwResult);
1243}
1244
1245
1246//! presents a surface in the client area
1247bool CIrrDeviceWin32::present(video::IImage* image, void* windowId, core::rect<s32>* src)
1248{
1249 HWND hwnd = HWnd;
1250 if ( windowId )
1251 hwnd = reinterpret_cast<HWND>(windowId);
1252
1253 HDC dc = GetDC(hwnd);
1254
1255 if ( dc )
1256 {
1257 RECT rect;
1258 GetClientRect(hwnd, &rect);
1259 const void* memory = (const void *)image->lock();
1260
1261 BITMAPV4HEADER bi;
1262 ZeroMemory (&bi, sizeof(bi));
1263 bi.bV4Size = sizeof(BITMAPINFOHEADER);
1264 bi.bV4BitCount = (WORD)image->getBitsPerPixel();
1265 bi.bV4Planes = 1;
1266 bi.bV4Width = image->getDimension().Width;
1267 bi.bV4Height = -((s32)image->getDimension().Height);
1268 bi.bV4V4Compression = BI_BITFIELDS;
1269 bi.bV4AlphaMask = image->getAlphaMask();
1270 bi.bV4RedMask = image->getRedMask();
1271 bi.bV4GreenMask = image->getGreenMask();
1272 bi.bV4BlueMask = image->getBlueMask();
1273
1274 if ( src )
1275 {
1276 StretchDIBits(dc, 0,0, rect.right, rect.bottom,
1277 src->UpperLeftCorner.X, src->UpperLeftCorner.Y,
1278 src->getWidth(), src->getHeight(),
1279 memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY);
1280 }
1281 else
1282 {
1283 StretchDIBits(dc, 0,0, rect.right, rect.bottom,
1284 0, 0, image->getDimension().Width, image->getDimension().Height,
1285 memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY);
1286 }
1287
1288 image->unlock();
1289
1290 ReleaseDC(hwnd, dc);
1291 }
1292 return true;
1293}
1294
1295
1296//! notifies the device that it should close itself
1297void CIrrDeviceWin32::closeDevice()
1298{
1299 MSG msg;
1300 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
1301 PostQuitMessage(0);
1302 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
1303 if (!ExternalWindow)
1304 {
1305 DestroyWindow(HWnd);
1306 const fschar_t* ClassName = __TEXT("CIrrDeviceWin32");
1307 HINSTANCE hInstance = GetModuleHandle(0);
1308 UnregisterClass(ClassName, hInstance);
1309 }
1310 Close=true;
1311}
1312
1313
1314//! returns if window is active. if not, nothing needs to be drawn
1315bool CIrrDeviceWin32::isWindowActive() const
1316{
1317 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
1318 return (GetActiveWindow() == HWnd);
1319}
1320
1321
1322//! returns if window has focus
1323bool CIrrDeviceWin32::isWindowFocused() const
1324{
1325 bool ret = (GetFocus() == HWnd);
1326 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
1327 return ret;
1328}
1329
1330
1331//! returns if window is minimized
1332bool CIrrDeviceWin32::isWindowMinimized() const
1333{
1334 WINDOWPLACEMENT plc;
1335 plc.length=sizeof(WINDOWPLACEMENT);
1336 bool ret=false;
1337 if (GetWindowPlacement(HWnd,&plc))
1338 ret=(plc.showCmd & SW_SHOWMINIMIZED)!=0;
1339 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
1340 return ret;
1341}
1342
1343
1344//! switches to fullscreen
1345bool CIrrDeviceWin32::switchToFullScreen(bool reset)
1346{
1347 if (!CreationParams.Fullscreen)
1348 return true;
1349
1350 if (reset)
1351 {
1352 if (ChangedToFullScreen)
1353 {
1354 return (ChangeDisplaySettings(&DesktopMode,0)==DISP_CHANGE_SUCCESSFUL);
1355 }
1356 else
1357 return true;
1358 }
1359
1360 // use default values from current setting
1361
1362 DEVMODE dm;
1363 memset(&dm, 0, sizeof(dm));
1364 dm.dmSize = sizeof(dm);
1365
1366 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm);
1367 dm.dmPelsWidth = CreationParams.WindowSize.Width;
1368 dm.dmPelsHeight = CreationParams.WindowSize.Height;
1369 dm.dmBitsPerPel = CreationParams.Bits;
1370 dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
1371
1372 LONG res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
1373 if (res != DISP_CHANGE_SUCCESSFUL)
1374 { // try again without forcing display frequency
1375 dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1376 res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
1377 }
1378
1379 bool ret = false;
1380 switch(res)
1381 {
1382 case DISP_CHANGE_SUCCESSFUL:
1383 ChangedToFullScreen = true;
1384 ret = true;
1385 break;
1386 case DISP_CHANGE_RESTART:
1387 os::Printer::log("Switch to fullscreen: The computer must be restarted in order for the graphics mode to work.", ELL_ERROR);
1388 break;
1389 case DISP_CHANGE_BADFLAGS:
1390 os::Printer::log("Switch to fullscreen: An invalid set of flags was passed in.", ELL_ERROR);
1391 break;
1392 case DISP_CHANGE_BADPARAM:
1393 os::Printer::log("Switch to fullscreen: An invalid parameter was passed in. This can include an invalid flag or combination of flags.", ELL_ERROR);
1394 break;
1395 case DISP_CHANGE_FAILED:
1396 os::Printer::log("Switch to fullscreen: The display driver failed the specified graphics mode.", ELL_ERROR);
1397 break;
1398 case DISP_CHANGE_BADMODE:
1399 os::Printer::log("Switch to fullscreen: The graphics mode is not supported.", ELL_ERROR);
1400 break;
1401 default:
1402 os::Printer::log("An unknown error occured while changing to fullscreen.", ELL_ERROR);
1403 break;
1404 }
1405 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
1406 return ret;
1407}
1408
1409
1410//! returns the win32 cursor control
1411CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl()
1412{
1413 return Win32CursorControl;
1414}
1415
1416
1417//! \return Returns a pointer to a list with all video modes supported
1418//! by the gfx adapter.
1419video::IVideoModeList* CIrrDeviceWin32::getVideoModeList()
1420{
1421 if (!VideoModeList.getVideoModeCount())
1422 {
1423 // enumerate video modes.
1424 DWORD i=0;
1425 DEVMODE mode;
1426 memset(&mode, 0, sizeof(mode));
1427 mode.dmSize = sizeof(mode);
1428
1429 while (EnumDisplaySettings(NULL, i, &mode))
1430 {
1431 VideoModeList.addMode(core::dimension2d<u32>(mode.dmPelsWidth, mode.dmPelsHeight),
1432 mode.dmBitsPerPel);
1433
1434 ++i;
1435 }
1436
1437 if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode))
1438 VideoModeList.setDesktop(mode.dmBitsPerPel, core::dimension2d<u32>(mode.dmPelsWidth, mode.dmPelsHeight));
1439 }
1440
1441 return &VideoModeList;
1442}
1443
1444typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
1445// Needed for old windows apis
1446// depending on the SDK version and compilers some defines might be available
1447// or not
1448#ifndef PRODUCT_ULTIMATE
1449#define PRODUCT_ULTIMATE 0x00000001
1450#define PRODUCT_HOME_BASIC 0x00000002
1451#define PRODUCT_HOME_PREMIUM 0x00000003
1452#define PRODUCT_ENTERPRISE 0x00000004
1453#define PRODUCT_HOME_BASIC_N 0x00000005
1454#define PRODUCT_BUSINESS 0x00000006
1455#define PRODUCT_STARTER 0x0000000B
1456#endif
1457#ifndef PRODUCT_ULTIMATE_N
1458#define PRODUCT_BUSINESS_N 0x00000010
1459#define PRODUCT_HOME_PREMIUM_N 0x0000001A
1460#define PRODUCT_ENTERPRISE_N 0x0000001B
1461#define PRODUCT_ULTIMATE_N 0x0000001C
1462#endif
1463#ifndef PRODUCT_STARTER_N
1464#define PRODUCT_STARTER_N 0x0000002F
1465#endif
1466#ifndef PRODUCT_PROFESSIONAL
1467#define PRODUCT_PROFESSIONAL 0x00000030
1468#define PRODUCT_PROFESSIONAL_N 0x00000031
1469#endif
1470#ifndef PRODUCT_ULTIMATE_E
1471#define PRODUCT_STARTER_E 0x00000042
1472#define PRODUCT_HOME_BASIC_E 0x00000043
1473#define PRODUCT_HOME_PREMIUM_E 0x00000044
1474#define PRODUCT_PROFESSIONAL_E 0x00000045
1475#define PRODUCT_ENTERPRISE_E 0x00000046
1476#define PRODUCT_ULTIMATE_E 0x00000047
1477#endif
1478
1479void CIrrDeviceWin32::getWindowsVersion(core::stringc& out)
1480{
1481 OSVERSIONINFOEX osvi;
1482 PGPI pGPI;
1483 BOOL bOsVersionInfoEx;
1484
1485 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
1486 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
1487
1488 bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
1489 if (!bOsVersionInfoEx)
1490 {
1491 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1492 if (! GetVersionEx((OSVERSIONINFO *) &osvi))
1493 return;
1494 }
1495
1496 switch (osvi.dwPlatformId)
1497 {
1498 case VER_PLATFORM_WIN32_NT:
1499 if (osvi.dwMajorVersion <= 4)
1500 out.append("Microsoft Windows NT ");
1501 else
1502 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
1503 out.append("Microsoft Windows 2000 ");
1504 else
1505 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
1506 out.append("Microsoft Windows XP ");
1507 else
1508 if (osvi.dwMajorVersion == 6 )
1509 {
1510 if (osvi.dwMinorVersion == 0)
1511 {
1512 if (osvi.wProductType == VER_NT_WORKSTATION)
1513 out.append("Microsoft Windows Vista ");
1514 else
1515 out.append("Microsoft Windows Server 2008 ");
1516 }
1517 else if (osvi.dwMinorVersion == 1)
1518 {
1519 if (osvi.wProductType == VER_NT_WORKSTATION)
1520 out.append("Microsoft Windows 7 ");
1521 else
1522 out.append("Microsoft Windows Server 2008 R2 ");
1523 }
1524 }
1525
1526 if (bOsVersionInfoEx)
1527 {
1528 if (osvi.dwMajorVersion == 6)
1529 {
1530 DWORD dwType;
1531 pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo");
1532 pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
1533
1534 switch (dwType)
1535 {
1536 case PRODUCT_ULTIMATE:
1537 case PRODUCT_ULTIMATE_E:
1538 case PRODUCT_ULTIMATE_N:
1539 out.append("Ultimate Edition ");
1540 break;
1541 case PRODUCT_PROFESSIONAL:
1542 case PRODUCT_PROFESSIONAL_E:
1543 case PRODUCT_PROFESSIONAL_N:
1544 out.append("Professional Edition ");
1545 break;
1546 case PRODUCT_HOME_BASIC:
1547 case PRODUCT_HOME_BASIC_E:
1548 case PRODUCT_HOME_BASIC_N:
1549 out.append("Home Basic Edition ");
1550 break;
1551 case PRODUCT_HOME_PREMIUM:
1552 case PRODUCT_HOME_PREMIUM_E:
1553 case PRODUCT_HOME_PREMIUM_N:
1554 out.append("Home Premium Edition ");
1555 break;
1556 case PRODUCT_ENTERPRISE:
1557 case PRODUCT_ENTERPRISE_E:
1558 case PRODUCT_ENTERPRISE_N:
1559 out.append("Enterprise Edition ");
1560 break;
1561 case PRODUCT_BUSINESS:
1562 case PRODUCT_BUSINESS_N:
1563 out.append("Business Edition ");
1564 break;
1565 case PRODUCT_STARTER:
1566 case PRODUCT_STARTER_E:
1567 case PRODUCT_STARTER_N:
1568 out.append("Starter Edition ");
1569 break;
1570 }
1571 }
1572#ifdef VER_SUITE_ENTERPRISE
1573 else
1574 if (osvi.wProductType == VER_NT_WORKSTATION)
1575 {
1576#ifndef __BORLANDC__
1577 if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
1578 out.append("Personal ");
1579 else
1580 out.append("Professional ");
1581#endif
1582 }
1583 else if (osvi.wProductType == VER_NT_SERVER)
1584 {
1585 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
1586 out.append("DataCenter Server ");
1587 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
1588 out.append("Advanced Server ");
1589 else
1590 out.append("Server ");
1591 }
1592#endif
1593 }
1594 else
1595 {
1596 HKEY hKey;
1597 char szProductType[80];
1598 DWORD dwBufLen;
1599
1600 RegOpenKeyEx( HKEY_LOCAL_MACHINE,
1601 __TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
1602 0, KEY_QUERY_VALUE, &hKey );
1603 RegQueryValueEx( hKey, __TEXT("ProductType"), NULL, NULL,
1604 (LPBYTE) szProductType, &dwBufLen);
1605 RegCloseKey( hKey );
1606
1607 if (_strcmpi( "WINNT", szProductType) == 0 )
1608 out.append("Professional ");
1609 if (_strcmpi( "LANMANNT", szProductType) == 0)
1610 out.append("Server ");
1611 if (_strcmpi( "SERVERNT", szProductType) == 0)
1612 out.append("Advanced Server ");
1613 }
1614
1615 // Display version, service pack (if any), and build number.
1616
1617 char tmp[255];
1618
1619 if (osvi.dwMajorVersion <= 4 )
1620 {
1621 sprintf(tmp, "version %ld.%ld %s (Build %ld)",
1622 osvi.dwMajorVersion,
1623 osvi.dwMinorVersion,
1624 irr::core::stringc(osvi.szCSDVersion).c_str(),
1625 osvi.dwBuildNumber & 0xFFFF);
1626 }
1627 else
1628 {
1629 sprintf(tmp, "%s (Build %ld)", irr::core::stringc(osvi.szCSDVersion).c_str(),
1630 osvi.dwBuildNumber & 0xFFFF);
1631 }
1632
1633 out.append(tmp);
1634 break;
1635
1636 case VER_PLATFORM_WIN32_WINDOWS:
1637
1638 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
1639 {
1640 out.append("Microsoft Windows 95 ");
1641 if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )
1642 out.append("OSR2 " );
1643 }
1644
1645 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
1646 {
1647 out.append("Microsoft Windows 98 ");
1648 if ( osvi.szCSDVersion[1] == 'A' )
1649 out.append( "SE " );
1650 }
1651
1652 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
1653 out.append("Microsoft Windows Me ");
1654
1655 break;
1656
1657 case VER_PLATFORM_WIN32s:
1658 out.append("Microsoft Win32s ");
1659 break;
1660 }
1661}
1662
1663//! Notifies the device, that it has been resized
1664void CIrrDeviceWin32::OnResized()
1665{
1666 Resized = true;
1667}
1668
1669//! Sets if the window should be resizable in windowed mode.
1670void CIrrDeviceWin32::setResizable(bool resize)
1671{
1672 if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)
1673 return;
1674
1675 LONG_PTR style = WS_POPUP;
1676
1677 if (!resize)
1678 style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
1679 else
1680 style = WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1681
1682 if (!SetWindowLongPtr(HWnd, GWL_STYLE, style))
1683 os::Printer::log("Could not change window style.");
1684
1685 RECT clientSize;
1686 clientSize.top = 0;
1687 clientSize.left = 0;
1688 clientSize.right = getVideoDriver()->getScreenSize().Width;
1689 clientSize.bottom = getVideoDriver()->getScreenSize().Height;
1690
1691 AdjustWindowRect(&clientSize, style, FALSE);
1692
1693 const s32 realWidth = clientSize.right - clientSize.left;
1694 const s32 realHeight = clientSize.bottom - clientSize.top;
1695
1696 const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;
1697 const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;
1698
1699 SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight,
1700 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW);
1701
1702 static_cast<CCursorControl*>(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize);
1703}
1704
1705
1706//! Minimizes the window.
1707void CIrrDeviceWin32::minimizeWindow()
1708{
1709 WINDOWPLACEMENT wndpl;
1710 wndpl.length = sizeof(WINDOWPLACEMENT);
1711 GetWindowPlacement(HWnd, &wndpl);
1712 wndpl.showCmd = SW_SHOWMINNOACTIVE;
1713 SetWindowPlacement(HWnd, &wndpl);
1714}
1715
1716
1717//! Maximizes the window.
1718void CIrrDeviceWin32::maximizeWindow()
1719{
1720 WINDOWPLACEMENT wndpl;
1721 wndpl.length = sizeof(WINDOWPLACEMENT);
1722 GetWindowPlacement(HWnd, &wndpl);
1723 wndpl.showCmd = SW_SHOWMAXIMIZED;
1724 SetWindowPlacement(HWnd, &wndpl);
1725}
1726
1727
1728//! Restores the window to its original size.
1729void CIrrDeviceWin32::restoreWindow()
1730{
1731 WINDOWPLACEMENT wndpl;
1732 wndpl.length = sizeof(WINDOWPLACEMENT);
1733 GetWindowPlacement(HWnd, &wndpl);
1734 wndpl.showCmd = SW_SHOWNORMAL;
1735 SetWindowPlacement(HWnd, &wndpl);
1736}
1737
1738
1739bool CIrrDeviceWin32::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
1740{
1741 if (JoyControl)
1742 return JoyControl->activateJoysticks(joystickInfo);
1743 else
1744 return false;
1745}
1746
1747
1748//! Set the current Gamma Value for the Display
1749bool CIrrDeviceWin32::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast )
1750{
1751 bool r;
1752 u16 ramp[3][256];
1753
1754 calculateGammaRamp( ramp[0], red, brightness, contrast );
1755 calculateGammaRamp( ramp[1], green, brightness, contrast );
1756 calculateGammaRamp( ramp[2], blue, brightness, contrast );
1757
1758 HDC dc = GetDC(0);
1759 r = SetDeviceGammaRamp ( dc, ramp ) == TRUE;
1760 ReleaseDC(HWnd, dc);
1761 return r;
1762}
1763
1764//! Get the current Gamma Value for the Display
1765bool CIrrDeviceWin32::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast )
1766{
1767 bool r;
1768 u16 ramp[3][256];
1769
1770 HDC dc = GetDC(0);
1771 r = GetDeviceGammaRamp ( dc, ramp ) == TRUE;
1772 ReleaseDC(HWnd, dc);
1773
1774 if ( r )
1775 {
1776 calculateGammaFromRamp(red, ramp[0]);
1777 calculateGammaFromRamp(green, ramp[1]);
1778 calculateGammaFromRamp(blue, ramp[2]);
1779 }
1780
1781 brightness = 0.f;
1782 contrast = 0.f;
1783
1784 return r;
1785
1786}
1787
1788
1789//! Process system events
1790void CIrrDeviceWin32::handleSystemMessages()
1791{
1792 MSG msg;
1793
1794 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1795 {
1796 // No message translation because we don't use WM_CHAR and it would conflict with our
1797 // deadkey handling.
1798
1799 if (ExternalWindow && msg.hwnd == HWnd)
1800 WndProc(HWnd, msg.message, msg.wParam, msg.lParam);
1801 else
1802 DispatchMessage(&msg);
1803
1804 if (msg.message == WM_QUIT)
1805 Close = true;
1806 }
1807}
1808
1809
1810//! Remove all messages pending in the system message loop
1811void CIrrDeviceWin32::clearSystemMessages()
1812{
1813 MSG msg;
1814 while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
1815 {}
1816 while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
1817 {}
1818}
1819
1820// shows last error in a messagebox to help internal debugging.
1821void CIrrDeviceWin32::ReportLastWinApiError()
1822{
1823 // (based on code from ovidiucucu from http://www.codeguru.com/forum/showthread.php?t=318721)
1824 LPCTSTR pszCaption = __TEXT("Windows SDK Error Report");
1825 DWORD dwError = GetLastError();
1826
1827 if(NOERROR == dwError)
1828 {
1829 MessageBox(NULL, __TEXT("No error"), pszCaption, MB_OK);
1830 }
1831 else
1832 {
1833 const DWORD dwFormatControl = FORMAT_MESSAGE_ALLOCATE_BUFFER |
1834 FORMAT_MESSAGE_IGNORE_INSERTS |
1835 FORMAT_MESSAGE_FROM_SYSTEM;
1836
1837 LPVOID pTextBuffer = NULL;
1838 DWORD dwCount = FormatMessage(dwFormatControl,
1839 NULL,
1840 dwError,
1841 0,
1842 (LPTSTR) &pTextBuffer,
1843 0,
1844 NULL);
1845 if(0 != dwCount)
1846 {
1847 MessageBox(NULL, (LPCTSTR)pTextBuffer, pszCaption, MB_OK|MB_ICONERROR);
1848 LocalFree(pTextBuffer);
1849 }
1850 else
1851 {
1852 MessageBox(NULL, __TEXT("Unknown error"), pszCaption, MB_OK|MB_ICONERROR);
1853 }
1854 }
1855}
1856
1857// Convert an Irrlicht texture to a Windows cursor
1858// Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/
1859HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
1860{
1861 //
1862 // create the bitmaps needed for cursors from the texture
1863
1864 HDC dc = GetDC(hwnd);
1865 HDC andDc = CreateCompatibleDC(dc);
1866 HDC xorDc = CreateCompatibleDC(dc);
1867 HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());
1868 HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());
1869
1870 HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap);
1871 HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap);
1872
1873
1874 video::ECOLOR_FORMAT format = tex->getColorFormat();
1875 u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;
1876 u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;
1877 u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;
1878 const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);
1879 data += sourceRect.UpperLeftCorner.Y*tex->getPitch();
1880 for ( s32 y = 0; y < sourceRect.getHeight(); ++y )
1881 {
1882 data += bytesLeftGap;
1883 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )
1884 {
1885 video::SColor pixelCol;
1886 pixelCol.setData((const void*)data, format);
1887 data += bytesPerPixel;
1888
1889 if ( pixelCol.getAlpha() == 0 ) // transparent
1890 {
1891 SetPixel(andDc, x, y, RGB(255,255,255));
1892 SetPixel(xorDc, x, y, RGB(0,0,0));
1893 }
1894 else // color
1895 {
1896 SetPixel(andDc, x, y, RGB(0,0,0));
1897 SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue()));
1898 }
1899 }
1900 data += bytesRightGap;
1901 }
1902 tex->unlock();
1903
1904 SelectObject(andDc, oldAndBitmap);
1905 SelectObject(xorDc, oldXorBitmap);
1906
1907 DeleteDC(xorDc);
1908 DeleteDC(andDc);
1909
1910 ReleaseDC(hwnd, dc);
1911
1912 // create the cursor
1913
1914 ICONINFO iconinfo;
1915 iconinfo.fIcon = false; // type is cursor not icon
1916 iconinfo.xHotspot = hotspot.X;
1917 iconinfo.yHotspot = hotspot.Y;
1918 iconinfo.hbmMask = andBitmap;
1919 iconinfo.hbmColor = xorBitmap;
1920
1921 HCURSOR cursor = CreateIconIndirect(&iconinfo);
1922
1923 DeleteObject(andBitmap);
1924 DeleteObject(xorBitmap);
1925
1926 return cursor;
1927}
1928
1929
1930CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen)
1931 : Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f),
1932 HWnd(hwnd), BorderX(0), BorderY(0),
1933 UseReferenceRect(false), IsVisible(true)
1934 , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)
1935{
1936 if (WindowSize.Width!=0)
1937 InvWindowSize.Width = 1.0f / WindowSize.Width;
1938
1939 if (WindowSize.Height!=0)
1940 InvWindowSize.Height = 1.0f / WindowSize.Height;
1941
1942 updateBorderSize(fullscreen, false);
1943 initCursors();
1944}
1945
1946CIrrDeviceWin32::CCursorControl::~CCursorControl()
1947{
1948 for ( u32 i=0; i < Cursors.size(); ++i )
1949 {
1950 for ( u32 f=0; f < Cursors[i].Frames.size(); ++f )
1951 {
1952 DestroyCursor(Cursors[i].Frames[f].IconHW);
1953 }
1954 }
1955}
1956
1957
1958void CIrrDeviceWin32::CCursorControl::initCursors()
1959{
1960 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_ARROW)) );
1961 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_CROSS)) );
1962 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HAND)) );
1963 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HELP)) );
1964 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_IBEAM)) );
1965 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_NO)) );
1966 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_WAIT)) );
1967 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEALL)) );
1968 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENESW)) );
1969 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENWSE)) );
1970 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENS)) );
1971 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEWE)) );
1972 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_UPARROW)) );
1973}
1974
1975
1976void CIrrDeviceWin32::CCursorControl::update()
1977{
1978 if ( !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime )
1979 {
1980 // 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)
1981 u32 now = Device->getTimer()->getRealTime();
1982 u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();
1983 SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW );
1984 }
1985}
1986
1987//! Sets the active cursor icon
1988void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId)
1989{
1990 if ( iconId >= (s32)Cursors.size() )
1991 return;
1992
1993 ActiveIcon = iconId;
1994 ActiveIconStartTime = Device->getTimer()->getRealTime();
1995 if ( Cursors[ActiveIcon].Frames.size() )
1996 SetCursor( Cursors[ActiveIcon].Frames[0].IconHW );
1997}
1998
1999
2000//! Add a custom sprite as cursor icon.
2001gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite& icon)
2002{
2003 if ( icon.SpriteId >= 0 )
2004 {
2005 CursorW32 cW32;
2006 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
2007
2008 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
2009 {
2010 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
2011 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
2012 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
2013
2014 HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
2015 cW32.Frames.push_back( CursorFrameW32(hc) );
2016 }
2017
2018 Cursors.push_back( cW32 );
2019 return (gui::ECURSOR_ICON)(Cursors.size() - 1);
2020 }
2021 return gui::ECI_NORMAL;
2022}
2023
2024
2025//! replace the given cursor icon.
2026void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon)
2027{
2028 if ( iconId >= (s32)Cursors.size() )
2029 return;
2030
2031 for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i )
2032 DestroyCursor(Cursors[iconId].Frames[i].IconHW);
2033
2034 if ( icon.SpriteId >= 0 )
2035 {
2036 CursorW32 cW32;
2037 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
2038 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
2039 {
2040 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
2041 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
2042 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
2043
2044 HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
2045 cW32.Frames.push_back( CursorFrameW32(hc) );
2046 }
2047
2048 Cursors[iconId] = cW32;
2049 }
2050}
2051
2052
2053//! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.
2054core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const
2055{
2056 core::dimension2di result;
2057
2058 result.Width = GetSystemMetrics(SM_CXCURSOR);
2059 result.Height = GetSystemMetrics(SM_CYCURSOR);
2060
2061 return result;
2062}
2063
2064
2065
2066} // end namespace
2067
2068#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_