1619 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1619 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2002-2012 Nikolaus Gebhardt
 | |
| // This file is part of the "Irrlicht Engine".
 | |
| // For conditions of distribution and use, see copyright notice in irrlicht.h
 | |
| 
 | |
| 
 | |
| #ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
 | |
| 
 | |
| #if defined (__STRICT_ANSI__)
 | |
|     #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.
 | |
| #endif
 | |
| 
 | |
| #include "CIrrDeviceWin32.h"
 | |
| #include "IEventReceiver.h"
 | |
| #include "os.h"
 | |
| 
 | |
| #include "CTimer.h"
 | |
| #include "irrString.h"
 | |
| #include "COSOperator.h"
 | |
| #include "dimension2d.h"
 | |
| #include "IGUISpriteBank.h"
 | |
| #include <winuser.h>
 | |
| #include "SExposedVideoData.h"
 | |
| 
 | |
| #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
 | |
| #include <mmsystem.h>
 | |
| #include <regstr.h>
 | |
| #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
 | |
| #define DIRECTINPUT_VERSION 0x0800
 | |
| #include <dinput.h>
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)
 | |
| #include "CEGLManager.h"
 | |
| #endif
 | |
| 
 | |
| #if defined(_IRR_COMPILE_WITH_OPENGL_)
 | |
| #include "CWGLManager.h"
 | |
| #endif
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| 	namespace video
 | |
| 	{
 | |
| #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
 | |
| 		IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, HWND window);
 | |
| #endif
 | |
| 
 | |
| #ifdef _IRR_COMPILE_WITH_OPENGL_
 | |
| 		IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
 | |
| #endif
 | |
| 
 | |
| #ifdef _IRR_COMPILE_WITH_OGLES1_
 | |
|         IVideoDriver* createOGLES1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
 | |
| #endif
 | |
| 
 | |
| #ifdef _IRR_COMPILE_WITH_OGLES2_
 | |
|         IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
 | |
| #endif
 | |
| 	}
 | |
| } // end namespace irr
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
|     struct SJoystickWin32Control
 | |
|     {
 | |
|         CIrrDeviceWin32* Device;
 | |
| 
 | |
|     #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
 | |
|         IDirectInput8* DirectInputDevice;
 | |
|     #endif
 | |
|     #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
 | |
|         struct JoystickInfo
 | |
|         {
 | |
|             u32 Index;
 | |
|     #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
 | |
|             core::stringc Name;
 | |
|             GUID guid;
 | |
|             LPDIRECTINPUTDEVICE8 lpdijoy;
 | |
|             DIDEVCAPS devcaps;
 | |
|             u8 axisValid[8];
 | |
|     #else
 | |
|             JOYCAPS Caps;
 | |
|     #endif
 | |
|         };
 | |
|         core::array<JoystickInfo> ActiveJoysticks;
 | |
|     #endif
 | |
| 
 | |
|         SJoystickWin32Control(CIrrDeviceWin32* dev);
 | |
|         ~SJoystickWin32Control();
 | |
| 
 | |
|     #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
 | |
|         static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp);
 | |
|         void directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi);
 | |
|     #endif
 | |
| 
 | |
|         void pollJoysticks();
 | |
|         bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo);
 | |
|         irr::core::stringc findJoystickName(int index, const JOYCAPS &caps) const;
 | |
|     };
 | |
| 
 | |
| 
 | |
| 	SJoystickWin32Control::SJoystickWin32Control(CIrrDeviceWin32* dev) : Device(dev)
 | |
| 	{
 | |
| #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
 | |
| 		DirectInputDevice=0;
 | |
| 		if (DI_OK != (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInputDevice, NULL)))
 | |
| 		{
 | |
| 			os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING);
 | |
| 			return;
 | |
| 		}
 | |
| #endif
 | |
| 	}
 | |
| 
 | |
| 	SJoystickWin32Control::~SJoystickWin32Control()
 | |
| 	{
 | |
| #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
 | |
| 		for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
 | |
| 		{
 | |
| 			LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy;
 | |
| 			if (dev)
 | |
| 			{
 | |
| 				dev->Unacquire();
 | |
| 				dev->Release();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (DirectInputDevice)
 | |
| 			DirectInputDevice->Release();
 | |
| #endif
 | |
| 	}
 | |
| 
 | |
| #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
 | |
| 	BOOL CALLBACK SJoystickWin32Control::EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp)
 | |
| 	{
 | |
| 		SJoystickWin32Control* p=(SJoystickWin32Control*)cp;
 | |
| 		p->directInputAddJoystick(lpddi);
 | |
| 		return DIENUM_CONTINUE;
 | |
| 	}
 | |
| 	void SJoystickWin32Control::directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi)
 | |
| 	{
 | |
| 		//Get the GUID of the joystuck
 | |
| 		const GUID guid = lpddi->guidInstance;
 | |
| 
 | |
| 		JoystickInfo activeJoystick;
 | |
| 		activeJoystick.Index=ActiveJoysticks.size();
 | |
| 		activeJoystick.guid=guid;
 | |
| 		activeJoystick.Name=lpddi->tszProductName;
 | |
| 		if (FAILED(DirectInputDevice->CreateDevice(guid, &activeJoystick.lpdijoy, NULL)))
 | |
| 		{
 | |
| 			os::Printer::log("Could not create DirectInput device", ELL_WARNING);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		activeJoystick.devcaps.dwSize=sizeof(activeJoystick.devcaps);
 | |
| 		if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps)))
 | |
| 		{
 | |
| 			os::Printer::log("Could not create DirectInput device", ELL_WARNING);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE)))
 | |
| 		{
 | |
| 			os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2)))
 | |
| 		{
 | |
| 			os::Printer::log("Could not set DirectInput device data format", ELL_WARNING);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (FAILED(activeJoystick.lpdijoy->Acquire()))
 | |
| 		{
 | |
| 			os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		DIJOYSTATE2 info;
 | |
| 		if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info),&info)))
 | |
| 		{
 | |
| 			os::Printer::log("Could not read DirectInput device state", ELL_WARNING);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		ZeroMemory(activeJoystick.axisValid,sizeof(activeJoystick.axisValid));
 | |
| 		activeJoystick.axisValid[0]= (info.lX!=0) ? 1 : 0;
 | |
| 		activeJoystick.axisValid[1]= (info.lY!=0) ? 1 : 0;
 | |
| 		activeJoystick.axisValid[2]= (info.lZ!=0) ? 1 : 0;
 | |
| 		activeJoystick.axisValid[3]= (info.lRx!=0) ? 1 : 0;
 | |
| 		activeJoystick.axisValid[4]= (info.lRy!=0) ? 1 : 0;
 | |
| 		activeJoystick.axisValid[5]= (info.lRz!=0) ? 1 : 0;
 | |
| 
 | |
| 		int caxis=0;
 | |
| 		for (u8 i=0; i<6; i++)
 | |
| 		{
 | |
| 			if (activeJoystick.axisValid[i])
 | |
| 				caxis++;
 | |
| 		}
 | |
| 
 | |
| 		for (u8 i=0; i<(activeJoystick.devcaps.dwAxes)-caxis; i++)
 | |
| 		{
 | |
| 			if (i+caxis < 8)
 | |
| 				activeJoystick.axisValid[i+caxis]=1;
 | |
| 		}
 | |
| 
 | |
| 		ActiveJoysticks.push_back(activeJoystick);
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| void SJoystickWin32Control::pollJoysticks()
 | |
| {
 | |
| #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
 | |
| #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
 | |
| 	if(0 == ActiveJoysticks.size())
 | |
| 		return;
 | |
| 
 | |
| 	u32 joystick;
 | |
| 	DIJOYSTATE2 info;
 | |
| 
 | |
| 	for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
 | |
| 	{
 | |
| 		// needs to be reset for each joystick
 | |
| 		// request ALL values and POV as continuous if possible
 | |
| 
 | |
| 		const DIDEVCAPS & caps = ActiveJoysticks[joystick].devcaps;
 | |
| 		// if no POV is available don't ask for POV values
 | |
| 
 | |
| 		if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info),&info)))
 | |
| 		{
 | |
| 			SEvent event;
 | |
| 
 | |
| 			event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
 | |
| 			event.JoystickEvent.Joystick = (u8)joystick;
 | |
| 
 | |
| 			event.JoystickEvent.POV = (u16)info.rgdwPOV[0];
 | |
| 			// set to undefined if no POV value was returned or the value
 | |
| 			// is out of range
 | |
| 			if ((caps.dwPOVs==0) || (event.JoystickEvent.POV > 35900))
 | |
| 				event.JoystickEvent.POV = 65535;
 | |
| 
 | |
| 			for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)
 | |
| 				event.JoystickEvent.Axis[axis] = 0;
 | |
| 
 | |
| 			u16 dxAxis=0;
 | |
| 			u16 irrAxis=0;
 | |
| 
 | |
| 			while (dxAxis < 6 && irrAxis <caps.dwAxes)
 | |
| 			{
 | |
| 				bool axisFound=0;
 | |
| 				s32 axisValue=0;
 | |
| 
 | |
| 				switch (dxAxis)
 | |
| 				{
 | |
| 				case 0:
 | |
| 					axisValue=info.lX;
 | |
| 					break;
 | |
| 				case 1:
 | |
| 					axisValue=info.lY;
 | |
| 					break;
 | |
| 				case 2:
 | |
| 					axisValue=info.lZ;
 | |
| 					break;
 | |
| 				case 3:
 | |
| 					axisValue=info.lRx;
 | |
| 					break;
 | |
| 				case 4:
 | |
| 					axisValue=info.lRy;
 | |
| 					break;
 | |
| 				case 5:
 | |
| 					axisValue=info.lRz;
 | |
| 					break;
 | |
| 				case 6:
 | |
| 					axisValue=info.rglSlider[0];
 | |
| 					break;
 | |
| 				case 7:
 | |
| 					axisValue=info.rglSlider[1];
 | |
| 					break;
 | |
| 				default:
 | |
| 					break;
 | |
| 				}
 | |
| 
 | |
| 				if (ActiveJoysticks[joystick].axisValid[dxAxis]>0)
 | |
| 					axisFound=1;
 | |
| 
 | |
| 				if (axisFound)
 | |
| 				{
 | |
| 					s32 val=axisValue - 32768;
 | |
| 
 | |
| 					if (val <-32767) val=-32767;
 | |
| 					if (val > 32767) val=32767;
 | |
| 					event.JoystickEvent.Axis[irrAxis]=(s16)(val);
 | |
| 					irrAxis++;
 | |
| 				}
 | |
| 
 | |
| 				dxAxis++;
 | |
| 			}
 | |
| 
 | |
| 			u32 buttons=0;
 | |
| 			BYTE* bytebuttons=info.rgbButtons;
 | |
| 			for (u16 i=0; i<32; i++)
 | |
| 			{
 | |
| 				if (bytebuttons[i] >0)
 | |
| 				{
 | |
| 					buttons |= (1 << i);
 | |
| 				}
 | |
| 			}
 | |
| 			event.JoystickEvent.ButtonStates = buttons;
 | |
| 
 | |
| 			(void)Device->postEventFromUser(event);
 | |
| 		}
 | |
| 	}
 | |
| #else
 | |
| 	if (0 == ActiveJoysticks.size())
 | |
| 		return;
 | |
| 
 | |
| 	u32 joystick;
 | |
| 	JOYINFOEX info;
 | |
| 
 | |
| 	for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
 | |
| 	{
 | |
| 		// needs to be reset for each joystick
 | |
| 		// request ALL values and POV as continuous if possible
 | |
| 		info.dwSize = sizeof(info);
 | |
| 		info.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;
 | |
| 		const JOYCAPS & caps = ActiveJoysticks[joystick].Caps;
 | |
| 		// if no POV is available don't ask for POV values
 | |
| 		if (!(caps.wCaps & JOYCAPS_HASPOV))
 | |
| 			info.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS);
 | |
| 		if(JOYERR_NOERROR == joyGetPosEx(ActiveJoysticks[joystick].Index, &info))
 | |
| 		{
 | |
| 			SEvent event;
 | |
| 
 | |
| 			event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
 | |
| 			event.JoystickEvent.Joystick = (u8)joystick;
 | |
| 
 | |
| 			event.JoystickEvent.POV = (u16)info.dwPOV;
 | |
| 			// set to undefined if no POV value was returned or the value
 | |
| 			// is out of range
 | |
| 			if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900))
 | |
| 				event.JoystickEvent.POV = 65535;
 | |
| 
 | |
| 			for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)
 | |
| 				event.JoystickEvent.Axis[axis] = 0;
 | |
| 
 | |
| 			event.JoystickEvent.ButtonStates = info.dwButtons;
 | |
| 
 | |
| 			switch(caps.wNumAxes)
 | |
| 			{
 | |
| 			default:
 | |
| 			case 6:
 | |
| 				event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] =
 | |
| 					(s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768);
 | |
| 
 | |
| 			case 5:
 | |
| 				event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] =
 | |
| 					(s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768);
 | |
| 
 | |
| 			case 4:
 | |
| 				event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] =
 | |
| 					(s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768);
 | |
| 
 | |
| 			case 3:
 | |
| 				event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] =
 | |
| 					(s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768);
 | |
| 
 | |
| 			case 2:
 | |
| 				event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] =
 | |
| 					(s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768);
 | |
| 
 | |
| 			case 1:
 | |
| 				event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] =
 | |
| 					(s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768);
 | |
| 			}
 | |
| 
 | |
| 			(void)Device->postEventFromUser(event);
 | |
| 		}
 | |
| 	}
 | |
| #endif
 | |
| #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
 | |
| }
 | |
| 
 | |
| /** This function is ported from SDL and released under zlib-license:
 | |
|   * Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> */
 | |
| irr::core::stringc SJoystickWin32Control::findJoystickName(int index, const JOYCAPS &caps) const
 | |
| {
 | |
| #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
 | |
| 
 | |
|     // As a default use the name given in the joystick structure.
 | |
|     // It is always the same name, independent of joystick.
 | |
|     irr::core::stringc result(caps.szPname);
 | |
| 
 | |
|     core::stringc key = core::stringc(REGSTR_PATH_JOYCONFIG)+ "\\" + caps.szRegKey + "\\" + REGSTR_KEY_JOYCURR;
 | |
|     HKEY hTopKey = HKEY_LOCAL_MACHINE;
 | |
|     HKEY hKey;
 | |
|     long regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);
 | |
|     if (regresult != ERROR_SUCCESS)
 | |
|     {
 | |
|         hTopKey = HKEY_CURRENT_USER;
 | |
|         regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);
 | |
|     }
 | |
|     if (regresult != ERROR_SUCCESS)
 | |
|         return result;
 | |
| 
 | |
|     /* find the registry key name for the joystick's properties */
 | |
|     char regname[256];
 | |
|     DWORD regsize = sizeof(regname);
 | |
|     core::stringc regvalue = core::stringc("Joystick")+core::stringc(index+1) + REGSTR_VAL_JOYOEMNAME;
 | |
|     regresult = RegQueryValueExA(hKey, regvalue.c_str(), 0, 0, (LPBYTE)regname, ®size);
 | |
|     RegCloseKey(hKey);
 | |
|     if (regresult != ERROR_SUCCESS)
 | |
|         return result;
 | |
| 
 | |
|     /* open that registry key */
 | |
|     core::stringc regkey = core::stringc(REGSTR_PATH_JOYOEM) + "\\" + regname;
 | |
|     regresult = RegOpenKeyExA(hTopKey, regkey.c_str(), 0, KEY_READ, &hKey);
 | |
|     if (regresult != ERROR_SUCCESS)
 | |
|         return result;
 | |
| 
 | |
|     /* find the size for the OEM name text */
 | |
|     regsize = sizeof(regvalue);
 | |
|     regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,
 | |
|                                  NULL, ®size);
 | |
|     if (regresult == ERROR_SUCCESS)
 | |
|     {
 | |
|         char *name;
 | |
|         /* allocate enough memory for the OEM name text ... */
 | |
|         name = new char[regsize];
 | |
|         if (name)
 | |
|         {
 | |
|             /* ... and read it from the registry */
 | |
|             regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,
 | |
|                                          (LPBYTE)name, ®size );
 | |
|             result = name;
 | |
|         }
 | |
|         delete[] name;
 | |
|     }
 | |
|     RegCloseKey(hKey);
 | |
| 
 | |
|     return result;
 | |
| #endif
 | |
| 	return "";
 | |
| }
 | |
| 
 | |
| bool SJoystickWin32Control::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
 | |
| {
 | |
| #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
 | |
| 	joystickInfo.clear();
 | |
| 	ActiveJoysticks.clear();
 | |
| #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
 | |
| 	if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY )))
 | |
| 	{
 | |
| 		os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
 | |
| 	{
 | |
| 		JoystickInfo& activeJoystick = ActiveJoysticks[joystick];
 | |
| 		SJoystickInfo info;
 | |
| 		info.Axes=activeJoystick.devcaps.dwAxes;
 | |
| 		info.Buttons=activeJoystick.devcaps.dwButtons;
 | |
| 		info.Name=activeJoystick.Name;
 | |
| 		info.PovHat = (activeJoystick.devcaps.dwPOVs  != 0)
 | |
| 				? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;
 | |
| 		joystickInfo.push_back(info);
 | |
| 	}
 | |
| 	return true;
 | |
| #else
 | |
| 	const u32 numberOfJoysticks = ::joyGetNumDevs();
 | |
| 	JOYINFOEX info;
 | |
| 	info.dwSize = sizeof(info);
 | |
| 	info.dwFlags = JOY_RETURNALL;
 | |
| 
 | |
| 	JoystickInfo activeJoystick;
 | |
| 	SJoystickInfo returnInfo;
 | |
| 
 | |
| 	joystickInfo.reallocate(numberOfJoysticks);
 | |
| 	ActiveJoysticks.reallocate(numberOfJoysticks);
 | |
| 
 | |
| 	u32 joystick = 0;
 | |
| 	for(; joystick < numberOfJoysticks; ++joystick)
 | |
| 	{
 | |
| 		if(JOYERR_NOERROR == joyGetPosEx(joystick, &info)
 | |
| 			&&
 | |
| 			JOYERR_NOERROR == joyGetDevCaps(joystick,
 | |
| 											&activeJoystick.Caps,
 | |
| 											sizeof(activeJoystick.Caps)))
 | |
| 		{
 | |
| 			activeJoystick.Index = joystick;
 | |
| 			ActiveJoysticks.push_back(activeJoystick);
 | |
| 
 | |
| 			returnInfo.Joystick = (u8)joystick;
 | |
| 			returnInfo.Axes = activeJoystick.Caps.wNumAxes;
 | |
| 			returnInfo.Buttons = activeJoystick.Caps.wNumButtons;
 | |
| 			returnInfo.Name = findJoystickName(joystick, activeJoystick.Caps);
 | |
| 			returnInfo.PovHat = ((activeJoystick.Caps.wCaps & JOYCAPS_HASPOV) == JOYCAPS_HASPOV)
 | |
| 								? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;
 | |
| 
 | |
| 			joystickInfo.push_back(returnInfo);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for(joystick = 0; joystick < joystickInfo.size(); ++joystick)
 | |
| 	{
 | |
| 		char logString[256];
 | |
| 		snprintf_irr(logString, sizeof(logString), "Found joystick %d, %d axes, %d buttons '%s'",
 | |
| 			joystick, joystickInfo[joystick].Axes,
 | |
| 			joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());
 | |
| 		os::Printer::log(logString, ELL_INFORMATION);
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| #endif
 | |
| #else
 | |
| 	return false;
 | |
| #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
 | |
| }
 | |
| } // end namespace irr
 | |
| 
 | |
| namespace
 | |
| {
 | |
| 	struct SEnvMapper
 | |
| 	{
 | |
| 		HWND hWnd;
 | |
| 		irr::CIrrDeviceWin32* irrDev;
 | |
| 	};
 | |
| 	// NOTE: This is global. We can have more than one Irrlicht Device at same time.
 | |
| 	irr::core::array<SEnvMapper> EnvMap;
 | |
| 
 | |
| 	HKL KEYBOARD_INPUT_HKL=0;
 | |
| }
 | |
| 
 | |
| irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)
 | |
| {
 | |
| 	const irr::u32 end = EnvMap.size();
 | |
| 	for ( irr::u32 i=0; i < end; ++i )
 | |
| 	{
 | |
| 		const SEnvMapper& env = EnvMap[i];
 | |
| 		if ( env.hWnd == hWnd )
 | |
| 			return env.irrDev;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 | |
| {
 | |
| 	#ifndef WHEEL_DELTA
 | |
| 	#define WHEEL_DELTA 120
 | |
| 	#endif
 | |
| 
 | |
| 	irr::CIrrDeviceWin32* dev = 0;
 | |
| 	irr::SEvent event;
 | |
| 
 | |
| 	static irr::s32 ClickCount=0;
 | |
| 	if (GetCapture() != hWnd && ClickCount > 0)
 | |
| 		ClickCount = 0;
 | |
| 
 | |
| 
 | |
| 	struct messageMap
 | |
| 	{
 | |
| 		irr::s32 group;
 | |
| 		UINT winMessage;
 | |
| 		irr::s32 irrMessage;
 | |
| 	};
 | |
| 
 | |
| 	static messageMap mouseMap[] =
 | |
| 	{
 | |
| 		{0, WM_LBUTTONDOWN, irr::EMIE_LMOUSE_PRESSED_DOWN},
 | |
| 		{1, WM_LBUTTONUP,   irr::EMIE_LMOUSE_LEFT_UP},
 | |
| 		{0, WM_RBUTTONDOWN, irr::EMIE_RMOUSE_PRESSED_DOWN},
 | |
| 		{1, WM_RBUTTONUP,   irr::EMIE_RMOUSE_LEFT_UP},
 | |
| 		{0, WM_MBUTTONDOWN, irr::EMIE_MMOUSE_PRESSED_DOWN},
 | |
| 		{1, WM_MBUTTONUP,   irr::EMIE_MMOUSE_LEFT_UP},
 | |
| 		{2, WM_MOUSEMOVE,   irr::EMIE_MOUSE_MOVED},
 | |
| 		{3, WM_MOUSEWHEEL,  irr::EMIE_MOUSE_WHEEL},
 | |
| 		{-1, 0, 0}
 | |
| 	};
 | |
| 
 | |
| 	// handle grouped events
 | |
| 	messageMap * m = mouseMap;
 | |
| 	while ( m->group >=0 && m->winMessage != message )
 | |
| 		m += 1;
 | |
| 
 | |
| 	if ( m->group >= 0 )
 | |
| 	{
 | |
| 		if ( m->group == 0 )	// down
 | |
| 		{
 | |
| 			ClickCount++;
 | |
| 			SetCapture(hWnd);
 | |
| 		}
 | |
| 		else
 | |
| 		if ( m->group == 1 )	// up
 | |
| 		{
 | |
| 			ClickCount--;
 | |
| 			if (ClickCount<1)
 | |
| 			{
 | |
| 				ClickCount=0;
 | |
| 				ReleaseCapture();
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		event.EventType = irr::EET_MOUSE_INPUT_EVENT;
 | |
| 		event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT) m->irrMessage;
 | |
| 		event.MouseInput.X = (short)LOWORD(lParam);
 | |
| 		event.MouseInput.Y = (short)HIWORD(lParam);
 | |
| 		event.MouseInput.Shift = ((LOWORD(wParam) & MK_SHIFT) != 0);
 | |
| 		event.MouseInput.Control = ((LOWORD(wParam) & MK_CONTROL) != 0);
 | |
| 		// left and right mouse buttons
 | |
| 		event.MouseInput.ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON);
 | |
| 		// middle and extra buttons
 | |
| 		if (wParam & MK_MBUTTON)
 | |
| 			event.MouseInput.ButtonStates |= irr::EMBSM_MIDDLE;
 | |
| 		if (wParam & MK_XBUTTON1)
 | |
| 			event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA1;
 | |
| 		if (wParam & MK_XBUTTON2)
 | |
| 			event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA2;
 | |
| 		event.MouseInput.Wheel = 0.f;
 | |
| 
 | |
| 		// wheel
 | |
| 		if ( m->group == 3 )
 | |
| 		{
 | |
| 			POINT p; // fixed by jox
 | |
| 			p.x = 0; p.y = 0;
 | |
| 			ClientToScreen(hWnd, &p);
 | |
| 			event.MouseInput.X -= p.x;
 | |
| 			event.MouseInput.Y -= p.y;
 | |
| 			event.MouseInput.Wheel = ((irr::f32)((short)HIWORD(wParam))) / (irr::f32)WHEEL_DELTA;
 | |
| 		}
 | |
| 
 | |
| 		dev = getDeviceFromHWnd(hWnd);
 | |
| 		if (dev)
 | |
| 		{
 | |
| 			dev->postEventFromUser(event);
 | |
| 
 | |
| 			if ( event.MouseInput.Event >= irr::EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= irr::EMIE_MMOUSE_PRESSED_DOWN )
 | |
| 			{
 | |
| 				irr::u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event);
 | |
| 				if ( clicks == 2 )
 | |
| 				{
 | |
| 					event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_DOUBLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);
 | |
| 					dev->postEventFromUser(event);
 | |
| 				}
 | |
| 				else if ( clicks == 3 )
 | |
| 				{
 | |
| 					event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_TRIPLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);
 | |
| 					dev->postEventFromUser(event);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	switch (message)
 | |
| 	{
 | |
| 	case WM_PAINT:
 | |
| 		{
 | |
| 			PAINTSTRUCT ps;
 | |
| 			BeginPaint(hWnd, &ps);
 | |
| 			EndPaint(hWnd, &ps);
 | |
| 		}
 | |
| 		return 0;
 | |
| 
 | |
| 	case WM_ERASEBKGND:
 | |
| 		return 0;
 | |
| 
 | |
| 	case WM_SYSKEYDOWN:
 | |
| 	case WM_SYSKEYUP:
 | |
| 	case WM_KEYDOWN:
 | |
| 	case WM_KEYUP:
 | |
| 		{
 | |
| 			BYTE allKeys[256];
 | |
| 
 | |
| 			event.EventType = irr::EET_KEY_INPUT_EVENT;
 | |
| 			event.KeyInput.Key = (irr::EKEY_CODE)wParam;
 | |
| 			event.KeyInput.PressedDown = (message==WM_KEYDOWN || message == WM_SYSKEYDOWN);
 | |
| 
 | |
| 			if ( event.KeyInput.Key == irr::KEY_SHIFT )
 | |
| 			{
 | |
| 				event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );
 | |
| 			}
 | |
| 			if ( event.KeyInput.Key == irr::KEY_CONTROL )
 | |
| 			{
 | |
| 				event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );
 | |
| 				// some keyboards will just return LEFT for both - left and right keys. So also check extend bit.
 | |
| 				if (lParam & 0x1000000)
 | |
| 					event.KeyInput.Key = irr::KEY_RCONTROL;
 | |
| 			}
 | |
| 			if ( event.KeyInput.Key == irr::KEY_MENU )
 | |
| 			{
 | |
| 				event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );
 | |
| 				if (lParam & 0x1000000)
 | |
| 					event.KeyInput.Key = irr::KEY_RMENU;
 | |
| 			}
 | |
| 
 | |
| 			GetKeyboardState(allKeys);
 | |
| 
 | |
| 			event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80)!=0);
 | |
| 			event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80)!=0);
 | |
| 
 | |
| 			// Handle unicode and deadkeys
 | |
| 			WCHAR keyChars[2];
 | |
| 			UINT scanCode = HIWORD(lParam);
 | |
| 			int conversionResult = ToUnicodeEx(static_cast<UINT>(wParam),scanCode,allKeys,keyChars,2,0,KEYBOARD_INPUT_HKL);
 | |
| 			if (conversionResult == 1)
 | |
| 				event.KeyInput.Char = keyChars[0];
 | |
| 			else
 | |
| 				event.KeyInput.Char = 0;
 | |
| 
 | |
| 			// allow composing characters like '@' with Alt Gr on non-US keyboards
 | |
| 			if ((allKeys[VK_MENU] & 0x80) != 0)
 | |
| 				event.KeyInput.Control = 0;
 | |
| 
 | |
| 			dev = getDeviceFromHWnd(hWnd);
 | |
| 			if (dev)
 | |
| 				dev->postEventFromUser(event);
 | |
| 
 | |
| 			if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)
 | |
| 				return DefWindowProcW(hWnd, message, wParam, lParam);
 | |
| 			else
 | |
| 				return 0;
 | |
| 		}
 | |
| 
 | |
| 	case WM_SIZE:
 | |
| 		{
 | |
| 			// resize
 | |
| 			dev = getDeviceFromHWnd(hWnd);
 | |
| 			if (dev)
 | |
| 				dev->OnResized();
 | |
| 		}
 | |
| 		return 0;
 | |
| 
 | |
| 	case WM_DESTROY:
 | |
| 		PostQuitMessage(0);
 | |
| 		return 0;
 | |
| 
 | |
| 	case WM_SYSCOMMAND:
 | |
| 		// prevent screensaver or monitor powersave mode from starting
 | |
| 		if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
 | |
| 			(wParam & 0xFFF0) == SC_MONITORPOWER ||
 | |
| 			(wParam & 0xFFF0) == SC_KEYMENU
 | |
| 			)
 | |
| 			return 0;
 | |
| 
 | |
| 		break;
 | |
| 
 | |
| 	case WM_USER:
 | |
| 		event.EventType = irr::EET_USER_EVENT;
 | |
| 		event.UserEvent.UserData1 = static_cast<size_t>(wParam);
 | |
| 		event.UserEvent.UserData2 = static_cast<size_t>(lParam);
 | |
| 		dev = getDeviceFromHWnd(hWnd);
 | |
| 
 | |
| 		if (dev)
 | |
| 			dev->postEventFromUser(event);
 | |
| 
 | |
| 		return 0;
 | |
| 
 | |
| 	case WM_SETCURSOR:
 | |
| 		// because Windows forgot about that in the meantime
 | |
| 		dev = getDeviceFromHWnd(hWnd);
 | |
| 		if (dev)
 | |
| 		{
 | |
| 			dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() );
 | |
| 			dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() );
 | |
| 		}
 | |
| 		break;
 | |
| 
 | |
| 	case WM_INPUTLANGCHANGE:
 | |
| 		// get the new codepage used for keyboard input
 | |
| 		KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return DefWindowProcW(hWnd, message, wParam, lParam);
 | |
| }
 | |
| 
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| 
 | |
| //! constructor
 | |
| CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)
 | |
| : CIrrDeviceStub(params), HWnd(0), Resized(false),
 | |
| 	ExternalWindow(false), Win32CursorControl(0), JoyControl(0),
 | |
| 	WindowMaximized(params.WindowMaximized)
 | |
| {
 | |
| 	#ifdef _DEBUG
 | |
| 	setDebugName("CIrrDeviceWin32");
 | |
| 	#endif
 | |
| 
 | |
| 	// get windows version and create OS operator
 | |
| 	core::stringc winversion;
 | |
| 	getWindowsVersion(winversion);
 | |
| 	Operator = new COSOperator(winversion);
 | |
| 	os::Printer::log(winversion.c_str(), ELL_INFORMATION);
 | |
| 
 | |
| 	// get handle to exe file
 | |
| 	HINSTANCE hInstance = GetModuleHandle(0);
 | |
| 
 | |
| 	// create the window if we need to and we do not use the null device
 | |
| 	if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL)
 | |
| 	{
 | |
| 		const wchar_t* ClassName = L"CIrrDeviceWin32";
 | |
| 
 | |
| 		// Register Class
 | |
| 		WNDCLASSEXW wcex;
 | |
| 		wcex.cbSize			= sizeof(WNDCLASSEXW);
 | |
| 		wcex.style			= CS_HREDRAW | CS_VREDRAW;
 | |
| 		wcex.lpfnWndProc	= WndProc;
 | |
| 		wcex.cbClsExtra		= 0;
 | |
| 		wcex.cbWndExtra		= 0;
 | |
| 		wcex.hInstance		= hInstance;
 | |
| 		wcex.hIcon			= NULL;
 | |
| 		wcex.hCursor		= 0; // LoadCursor(NULL, IDC_ARROW);
 | |
| 		wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
 | |
| 		wcex.lpszMenuName	= 0;
 | |
| 		wcex.lpszClassName	= ClassName;
 | |
| 		wcex.hIconSm		= 0;
 | |
| 
 | |
| 		// if there is an icon, load it
 | |
| 		wcex.hIcon = (HICON)LoadImageW(hInstance, L"irrlicht.ico", IMAGE_ICON, 0,0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
 | |
| 
 | |
| 		RegisterClassExW(&wcex);
 | |
| 
 | |
| 		// calculate client size
 | |
| 
 | |
| 		RECT clientSize;
 | |
| 		clientSize.top = 0;
 | |
| 		clientSize.left = 0;
 | |
| 		clientSize.right = CreationParams.WindowSize.Width;
 | |
| 		clientSize.bottom = CreationParams.WindowSize.Height;
 | |
| 
 | |
| 		DWORD style = getWindowStyle(CreationParams.Fullscreen, CreationParams.WindowResizable > 0 ? true : false);
 | |
| 		AdjustWindowRect(&clientSize, style, FALSE);
 | |
| 
 | |
| 		const s32 realWidth = clientSize.right - clientSize.left;
 | |
| 		const s32 realHeight = clientSize.bottom - clientSize.top;
 | |
| 
 | |
| 		s32 windowLeft = (CreationParams.WindowPosition.X == -1 ?
 | |
| 		                     (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2 :
 | |
| 		                     CreationParams.WindowPosition.X);
 | |
| 		s32 windowTop = (CreationParams.WindowPosition.Y == -1 ?
 | |
| 		                     (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2 :
 | |
| 		                     CreationParams.WindowPosition.Y);
 | |
| 
 | |
| 		if ( windowLeft < 0 )
 | |
| 			windowLeft = 0;
 | |
| 		if ( windowTop < 0 )
 | |
| 			windowTop = 0;	// make sure window menus are in screen on creation
 | |
| 
 | |
| 		if (CreationParams.Fullscreen)
 | |
| 		{
 | |
| 			windowLeft = 0;
 | |
| 			windowTop = 0;
 | |
| 		}
 | |
| 
 | |
| 		// create window
 | |
| 		HWnd = CreateWindowW( ClassName, L"", style, windowLeft, windowTop,
 | |
| 					realWidth, realHeight, NULL, NULL, hInstance, NULL);
 | |
| 		if (!HWnd)
 | |
| 		{
 | |
| 			os::Printer::log("Window could not be created.", ELL_ERROR);
 | |
| 		}
 | |
| 
 | |
| 		CreationParams.WindowId = HWnd;
 | |
| //		CreationParams.WindowSize.Width = realWidth;
 | |
| //		CreationParams.WindowSize.Height = realHeight;
 | |
| 
 | |
| 		ShowWindow(HWnd, SW_SHOWNORMAL);
 | |
| 		UpdateWindow(HWnd);
 | |
| 
 | |
| 		// fix ugly ATI driver bugs. Thanks to ariaci
 | |
| 		MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE);
 | |
| 
 | |
| 		// make sure everything gets updated to the real sizes
 | |
| 		Resized = true;
 | |
| 	}
 | |
| 	else if (CreationParams.WindowId)
 | |
| 	{
 | |
| 		// attach external window
 | |
| 		HWnd = static_cast<HWND>(CreationParams.WindowId);
 | |
| 		RECT r;
 | |
| 		GetWindowRect(HWnd, &r);
 | |
| 		CreationParams.WindowSize.Width = r.right - r.left;
 | |
| 		CreationParams.WindowSize.Height = r.bottom - r.top;
 | |
| 		CreationParams.Fullscreen = false;
 | |
| 		ExternalWindow = true;
 | |
| 	}
 | |
| 
 | |
| 	// create cursor control
 | |
| 
 | |
| 	Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen);
 | |
| 	CursorControl = Win32CursorControl;
 | |
| 	JoyControl = new SJoystickWin32Control(this);
 | |
| 
 | |
| 	// initialize doubleclicks with system values
 | |
| 	MouseMultiClicks.DoubleClickTime = GetDoubleClickTime();
 | |
| 
 | |
| 	// create driver
 | |
| 
 | |
| 	createDriver();
 | |
| 
 | |
| 	if (VideoDriver)
 | |
| 		createGUIAndScene();
 | |
| 
 | |
| 	// register environment
 | |
| 
 | |
| 	SEnvMapper em;
 | |
| 	em.irrDev = this;
 | |
| 	em.hWnd = HWnd;
 | |
| 	EnvMap.push_back(em);
 | |
| 
 | |
| 	// set this as active window
 | |
| 	if (!ExternalWindow)
 | |
| 	{
 | |
| 		SetActiveWindow(HWnd);
 | |
| 		SetForegroundWindow(HWnd);
 | |
| 	}
 | |
| 
 | |
| 	KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
 | |
| 
 | |
| 	// inform driver about the window size etc.
 | |
| 	resizeIfNecessary();
 | |
| 
 | |
| 	if (params.WindowMaximized)
 | |
| 		maximizeWindow();
 | |
| }
 | |
| 
 | |
| 
 | |
| //! destructor
 | |
| CIrrDeviceWin32::~CIrrDeviceWin32()
 | |
| {
 | |
| 	delete JoyControl;
 | |
| 
 | |
| 	// unregister environment
 | |
| 	for (u32 i=0; i< EnvMap.size(); ++i)
 | |
| 	{
 | |
| 		if (EnvMap[i].hWnd == HWnd)
 | |
| 		{
 | |
| 			EnvMap.erase(i);
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| //! create the driver
 | |
| void CIrrDeviceWin32::createDriver()
 | |
| {
 | |
| 	switch(CreationParams.DriverType)
 | |
| 	{
 | |
| 	case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:
 | |
| 		os::Printer::log("DIRECT3D8 Driver is no longer supported in Irrlicht. Try another one.", ELL_ERROR);
 | |
| 		break;
 | |
| 	case video::EDT_DIRECT3D9:
 | |
| #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
 | |
| 		VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd);
 | |
| 
 | |
| 		if (!VideoDriver)
 | |
| 			os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR);
 | |
| #else
 | |
| 		os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR);
 | |
| #endif
 | |
| 		break;
 | |
| 	case video::EDT_OPENGL:
 | |
| #ifdef _IRR_COMPILE_WITH_OPENGL_
 | |
| 		switchToFullScreen();
 | |
| 
 | |
| 		ContextManager = new video::CWGLManager();
 | |
| 		ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
 | |
| 
 | |
| 		VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);
 | |
| 
 | |
| 		if (!VideoDriver)
 | |
| 			os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);
 | |
| #else
 | |
| 		os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR);
 | |
| #endif
 | |
| 		break;
 | |
| 	case video::EDT_OGLES1:
 | |
| #ifdef _IRR_COMPILE_WITH_OGLES1_
 | |
| 		switchToFullScreen();
 | |
| 
 | |
| 		ContextManager = new video::CEGLManager();
 | |
| 		ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
 | |
| 
 | |
| 		VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager);
 | |
| 
 | |
| 		if (!VideoDriver)
 | |
| 			os::Printer::log("Could not create OpenGL-ES1 driver.", ELL_ERROR);
 | |
| #else
 | |
| 		os::Printer::log("OpenGL-ES1 driver was not compiled in.", ELL_ERROR);
 | |
| #endif
 | |
| 		break;
 | |
| 	case video::EDT_OGLES2:
 | |
| #ifdef _IRR_COMPILE_WITH_OGLES2_
 | |
| 		switchToFullScreen();
 | |
| 
 | |
| 		ContextManager = new video::CEGLManager();
 | |
| 		ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
 | |
| 
 | |
| 		VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);
 | |
| 
 | |
| 		if (!VideoDriver)
 | |
| 			os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR);
 | |
| #else
 | |
| 		os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR);
 | |
| #endif
 | |
| 		break;
 | |
| 	case video::EDT_WEBGL1:
 | |
| 		os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR);
 | |
| 		break;
 | |
| 	case video::EDT_NULL:
 | |
| 		VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
 | |
| 		break;
 | |
| 	default:
 | |
| 		os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
 | |
| 		break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| //! runs the device. Returns false if device wants to be deleted
 | |
| bool CIrrDeviceWin32::run()
 | |
| {
 | |
| 	os::Timer::tick();
 | |
| 
 | |
| 	static_cast<CCursorControl*>(CursorControl)->update();
 | |
| 
 | |
| 	handleSystemMessages();
 | |
| 
 | |
| 	if (!Close)
 | |
| 		resizeIfNecessary();
 | |
| 
 | |
| 	if(!Close && JoyControl)
 | |
| 		JoyControl->pollJoysticks();
 | |
| 
 | |
| 	return !Close;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Pause the current process for the minimum time allowed only to allow other processes to execute
 | |
| void CIrrDeviceWin32::yield()
 | |
| {
 | |
| 	Sleep(1);
 | |
| }
 | |
| 
 | |
| //! Pause execution and let other processes to run for a specified amount of time.
 | |
| void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer)
 | |
| {
 | |
| 	const bool wasStopped = Timer ? Timer->isStopped() : true;
 | |
| 	if (pauseTimer && !wasStopped)
 | |
| 		Timer->stop();
 | |
| 
 | |
| 	Sleep(timeMs);
 | |
| 
 | |
| 	if (pauseTimer && !wasStopped)
 | |
| 		Timer->start();
 | |
| }
 | |
| 
 | |
| 
 | |
| void CIrrDeviceWin32::resizeIfNecessary()
 | |
| {
 | |
| 	if (!Resized || !getVideoDriver())
 | |
| 		return;
 | |
| 
 | |
| 	RECT r;
 | |
| 	GetClientRect(HWnd, &r);
 | |
| 
 | |
| 	char tmp[255];
 | |
| 
 | |
| 	if (r.right < 2 || r.bottom < 2)
 | |
| 	{
 | |
| 		snprintf_irr(tmp, sizeof(tmp), "Ignoring resize operation to (%ld %ld)", r.right, r.bottom);
 | |
| 		os::Printer::log(tmp);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		snprintf_irr(tmp, sizeof(tmp), "Resizing window (%ld %ld)", r.right, r.bottom);
 | |
| 		os::Printer::log(tmp);
 | |
| 
 | |
| 		getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom));
 | |
| 		getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize());
 | |
| 	}
 | |
| 
 | |
| 	Resized = false;
 | |
| }
 | |
| 
 | |
| 
 | |
| DWORD CIrrDeviceWin32::getWindowStyle(bool fullscreen, bool resizable) const
 | |
| {
 | |
| 	if ( fullscreen )
 | |
| 		return WS_POPUP;
 | |
| 
 | |
| 	if ( resizable )
 | |
| 		return WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
 | |
| 
 | |
| 	return WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
 | |
| }
 | |
| 
 | |
| //! sets the caption of the window
 | |
| void CIrrDeviceWin32::setWindowCaption(const wchar_t* text)
 | |
| {
 | |
| 	// We use SendMessage instead of SetText to ensure proper
 | |
| 	// function even in cases where the HWND was created in a different thread
 | |
| 	DWORD_PTR dwResult;
 | |
| 	SendMessageTimeoutW(HWnd, WM_SETTEXT, 0,
 | |
| 			reinterpret_cast<LPARAM>(text),
 | |
| 			SMTO_ABORTIFHUNG, 2000, &dwResult);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Sets the window icon.
 | |
| bool CIrrDeviceWin32::setWindowIcon(const video::IImage *img)
 | |
| {
 | |
| 	// Ignore the img, instead load the ICON from resource file
 | |
| 	// (This is minetest-specific!)
 | |
| 	const HICON hicon = LoadIcon(GetModuleHandle(NULL),
 | |
| 			MAKEINTRESOURCE(130) // The ID of the ICON defined in
 | |
| 					     // winresource.rc
 | |
| 	);
 | |
| 
 | |
| 	if (hicon) {
 | |
| 		SendMessage(HWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hicon));
 | |
| 		SendMessage(HWnd, WM_SETICON, ICON_SMALL,
 | |
| 				reinterpret_cast<LPARAM>(hicon));
 | |
| 		return true;
 | |
| 	}
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! notifies the device that it should close itself
 | |
| void CIrrDeviceWin32::closeDevice()
 | |
| {
 | |
| 	if (!ExternalWindow)
 | |
| 	{
 | |
| 		MSG msg;
 | |
| 		PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
 | |
| 		PostQuitMessage(0);
 | |
| 		PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
 | |
| 		DestroyWindow(HWnd);
 | |
| 		const wchar_t* ClassName = L"CIrrDeviceWin32";
 | |
| 		HINSTANCE hInstance = GetModuleHandle(0);
 | |
| 		UnregisterClassW(ClassName, hInstance);
 | |
| 	}
 | |
| 	Close=true;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! returns if window is active. if not, nothing needs to be drawn
 | |
| bool CIrrDeviceWin32::isWindowActive() const
 | |
| {
 | |
| 	return (GetActiveWindow() == HWnd);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! returns if window has focus
 | |
| bool CIrrDeviceWin32::isWindowFocused() const
 | |
| {
 | |
| 	bool ret = (GetFocus() == HWnd);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! returns if window is minimized
 | |
| bool CIrrDeviceWin32::isWindowMinimized() const
 | |
| {
 | |
| 	WINDOWPLACEMENT plc;
 | |
| 	plc.length=sizeof(WINDOWPLACEMENT);
 | |
| 	bool ret=false;
 | |
| 	if (GetWindowPlacement(HWnd,&plc))
 | |
| 		ret = plc.showCmd == SW_SHOWMINIMIZED;
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! returns last state from maximizeWindow() and restoreWindow()
 | |
| bool CIrrDeviceWin32::isWindowMaximized() const
 | |
| {
 | |
| 	return WindowMaximized;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! switches to fullscreen
 | |
| bool CIrrDeviceWin32::switchToFullScreen()
 | |
| {
 | |
| 	if (!CreationParams.Fullscreen)
 | |
| 		return true;
 | |
| 
 | |
| 	// No border, title bar, etc. is already set up through getWindowStyle()
 | |
| 	// We only set the window size to match the monitor.
 | |
| 
 | |
| 	MONITORINFO mi;
 | |
| 	mi.cbSize = sizeof(mi);
 | |
| 	if (GetMonitorInfo(MonitorFromWindow(HWnd,MONITOR_DEFAULTTOPRIMARY),&mi))
 | |
| 	{
 | |
| 		UINT flags = SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_FRAMECHANGED;
 | |
| 		SetWindowPos(HWnd, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,
 | |
| 			mi.rcMonitor.right - mi.rcMonitor.left,
 | |
| 			mi.rcMonitor.bottom - mi.rcMonitor.top, flags);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		CreationParams.Fullscreen = false;
 | |
| 	}
 | |
| 
 | |
| 	return CreationParams.Fullscreen;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! returns the win32 cursor control
 | |
| CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl()
 | |
| {
 | |
| 	return Win32CursorControl;
 | |
| }
 | |
| 
 | |
| void CIrrDeviceWin32::getWindowsVersion(core::stringc& out)
 | |
| {
 | |
| 	OSVERSIONINFO osvi;
 | |
| 
 | |
| 	ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
 | |
| 	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 | |
| 	GetVersionEx(&osvi);
 | |
| 
 | |
| 	char tmp[255];
 | |
| 	snprintf(tmp, sizeof(tmp), "Microsoft Windows %lu.%lu %s", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion);
 | |
| 	out.append(tmp);
 | |
| }
 | |
| 
 | |
| //! Notifies the device, that it has been resized
 | |
| void CIrrDeviceWin32::OnResized()
 | |
| {
 | |
| 	Resized = true;
 | |
| }
 | |
| 
 | |
| //! Resize the render window.
 | |
| void CIrrDeviceWin32::setWindowSize(const irr::core::dimension2d<u32>& size)
 | |
| {
 | |
| 	if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)
 | |
| 		return;
 | |
| 
 | |
| 	// get size of the window for the give size of the client area
 | |
| 	DWORD style = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_STYLE));
 | |
| 	DWORD exStyle = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_EXSTYLE));
 | |
| 	RECT clientSize;
 | |
| 	clientSize.top = 0;
 | |
| 	clientSize.left = 0;
 | |
| 	clientSize.right = size.Width;
 | |
| 	clientSize.bottom = size.Height;
 | |
| 	AdjustWindowRectEx(&clientSize, style, false, exStyle);
 | |
| 	const s32 realWidth = clientSize.right - clientSize.left;
 | |
| 	const s32 realHeight = clientSize.bottom - clientSize.top;
 | |
| 
 | |
| 	UINT flags = SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;
 | |
| 	SetWindowPos(HWnd, HWND_TOP, 0, 0, realWidth, realHeight, flags);
 | |
| }
 | |
| 
 | |
| //! Sets if the window should be resizable in windowed mode.
 | |
| void CIrrDeviceWin32::setResizable(bool resize)
 | |
| {
 | |
| 	if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)
 | |
| 		return;
 | |
| 
 | |
| 	LONG_PTR style = (LONG_PTR)getWindowStyle(false, resize);
 | |
| 	if (!SetWindowLongPtr(HWnd, GWL_STYLE, style))
 | |
| 		os::Printer::log("Could not change window style.");
 | |
| 
 | |
| 	RECT clientSize;
 | |
| 	clientSize.top = 0;
 | |
| 	clientSize.left = 0;
 | |
| 	clientSize.right = getVideoDriver()->getScreenSize().Width;
 | |
| 	clientSize.bottom = getVideoDriver()->getScreenSize().Height;
 | |
| 
 | |
| 	AdjustWindowRect(&clientSize, static_cast<DWORD>(style), FALSE);
 | |
| 
 | |
| 	const s32 realWidth = clientSize.right - clientSize.left;
 | |
| 	const s32 realHeight = clientSize.bottom - clientSize.top;
 | |
| 
 | |
| 	const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;
 | |
| 	const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;
 | |
| 
 | |
| 	SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight,
 | |
| 		SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW);
 | |
| 
 | |
| 	static_cast<CCursorControl*>(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Minimizes the window.
 | |
| void CIrrDeviceWin32::minimizeWindow()
 | |
| {
 | |
| 	WINDOWPLACEMENT wndpl;
 | |
| 	wndpl.length = sizeof(WINDOWPLACEMENT);
 | |
| 	GetWindowPlacement(HWnd, &wndpl);
 | |
| 	wndpl.showCmd = SW_SHOWMINNOACTIVE;
 | |
| 	SetWindowPlacement(HWnd, &wndpl);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Maximizes the window.
 | |
| void CIrrDeviceWin32::maximizeWindow()
 | |
| {
 | |
| 	WINDOWPLACEMENT wndpl;
 | |
| 	wndpl.length = sizeof(WINDOWPLACEMENT);
 | |
| 	GetWindowPlacement(HWnd, &wndpl);
 | |
| 	wndpl.showCmd = SW_SHOWMAXIMIZED;
 | |
| 	SetWindowPlacement(HWnd, &wndpl);
 | |
| 
 | |
| 	WindowMaximized = true;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Restores the window to its original size.
 | |
| void CIrrDeviceWin32::restoreWindow()
 | |
| {
 | |
| 	WINDOWPLACEMENT wndpl;
 | |
| 	wndpl.length = sizeof(WINDOWPLACEMENT);
 | |
| 	GetWindowPlacement(HWnd, &wndpl);
 | |
| 	wndpl.showCmd = SW_SHOWNORMAL;
 | |
| 	SetWindowPlacement(HWnd, &wndpl);
 | |
| 
 | |
| 	WindowMaximized = false;
 | |
| }
 | |
| 
 | |
| core::position2di CIrrDeviceWin32::getWindowPosition()
 | |
| {
 | |
| 	WINDOWPLACEMENT wndpl;
 | |
| 	wndpl.length = sizeof(WINDOWPLACEMENT);
 | |
| 	if (GetWindowPlacement(HWnd, &wndpl))
 | |
| 	{
 | |
| 		return core::position2di((int)wndpl.rcNormalPosition.left,
 | |
| 		                         (int)wndpl.rcNormalPosition.top);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		// No reason for this to happen
 | |
| 		os::Printer::log("Failed to retrieve window location", ELL_ERROR);
 | |
| 		return core::position2di(-1, -1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| bool CIrrDeviceWin32::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
 | |
| {
 | |
| 	if (JoyControl)
 | |
| 		return JoyControl->activateJoysticks(joystickInfo);
 | |
| 	else
 | |
| 		return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Process system events
 | |
| void CIrrDeviceWin32::handleSystemMessages()
 | |
| {
 | |
| 	MSG msg;
 | |
| 
 | |
| 	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
 | |
| 	{
 | |
| 		if (ExternalWindow && msg.hwnd == HWnd)
 | |
| 		{
 | |
| 			if (msg.hwnd == HWnd)
 | |
|             {
 | |
| 				WndProc(HWnd, msg.message, msg.wParam, msg.lParam);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 TranslateMessage(&msg);
 | |
|                 DispatchMessage(&msg);
 | |
|             }
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			// No message translation because we don't use WM_CHAR and it would conflict with our
 | |
| 			// deadkey handling.
 | |
| 			DispatchMessage(&msg);
 | |
| 		}
 | |
| 
 | |
| 		if (msg.message == WM_QUIT)
 | |
| 			Close = true;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Remove all messages pending in the system message loop
 | |
| void CIrrDeviceWin32::clearSystemMessages()
 | |
| {
 | |
| 	MSG msg;
 | |
| 	while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
 | |
| 	{}
 | |
| 	while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
 | |
| 	{}
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Get the display density in dots per inch.
 | |
| float CIrrDeviceWin32::getDisplayDensity() const
 | |
| {
 | |
| 	HDC hdc = GetDC(HWnd);
 | |
| 	float dpi = GetDeviceCaps(hdc, LOGPIXELSX);
 | |
| 	ReleaseDC(HWnd, hdc);
 | |
| 	return dpi;
 | |
| }
 | |
| 
 | |
| 
 | |
| // Convert an Irrlicht texture to a Windows cursor
 | |
| // Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/
 | |
| HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
 | |
| {
 | |
| 	//
 | |
| 	// create the bitmaps needed for cursors from the texture
 | |
| 
 | |
| 	HDC dc = GetDC(hwnd);
 | |
| 	HDC andDc = CreateCompatibleDC(dc);
 | |
| 	HDC xorDc = CreateCompatibleDC(dc);
 | |
| 	HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());
 | |
| 	HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());
 | |
| 
 | |
| 	HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap);
 | |
| 	HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap);
 | |
| 
 | |
| 
 | |
| 	video::ECOLOR_FORMAT format = tex->getColorFormat();
 | |
| 	u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;
 | |
| 	u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;
 | |
| 	u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;
 | |
| 	const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);
 | |
| 	data += sourceRect.UpperLeftCorner.Y*tex->getPitch();
 | |
| 	for ( s32 y = 0; y < sourceRect.getHeight(); ++y )
 | |
| 	{
 | |
| 		data += bytesLeftGap;
 | |
| 		for ( s32 x = 0; x < sourceRect.getWidth(); ++x )
 | |
| 		{
 | |
| 			video::SColor pixelCol;
 | |
| 			pixelCol.setData((const void*)data, format);
 | |
| 			data += bytesPerPixel;
 | |
| 
 | |
| 			if ( pixelCol.getAlpha() == 0 )	// transparent
 | |
| 			{
 | |
| 				SetPixel(andDc, x, y, RGB(255,255,255));
 | |
| 				SetPixel(xorDc, x, y, RGB(0,0,0));
 | |
| 			}
 | |
| 			else	// color
 | |
| 			{
 | |
| 				SetPixel(andDc, x, y, RGB(0,0,0));
 | |
| 				SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue()));
 | |
| 			}
 | |
| 		}
 | |
| 		data += bytesRightGap;
 | |
| 	}
 | |
| 	tex->unlock();
 | |
| 
 | |
| 	SelectObject(andDc, oldAndBitmap);
 | |
| 	SelectObject(xorDc, oldXorBitmap);
 | |
| 
 | |
| 	DeleteDC(xorDc);
 | |
| 	DeleteDC(andDc);
 | |
| 
 | |
| 	ReleaseDC(hwnd, dc);
 | |
| 
 | |
| 	// create the cursor
 | |
| 
 | |
| 	ICONINFO iconinfo;
 | |
| 	iconinfo.fIcon = false;	// type is cursor not icon
 | |
| 	iconinfo.xHotspot = hotspot.X;
 | |
| 	iconinfo.yHotspot = hotspot.Y;
 | |
| 	iconinfo.hbmMask = andBitmap;
 | |
| 	iconinfo.hbmColor = xorBitmap;
 | |
| 
 | |
| 	HCURSOR cursor = CreateIconIndirect(&iconinfo);
 | |
| 
 | |
| 	DeleteObject(andBitmap);
 | |
| 	DeleteObject(xorBitmap);
 | |
| 
 | |
| 	return cursor;
 | |
| }
 | |
| 
 | |
| 
 | |
| CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen)
 | |
| 	: Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f),
 | |
| 		HWnd(hwnd), BorderX(0), BorderY(0),
 | |
| 		UseReferenceRect(false), IsVisible(true)
 | |
| 		, ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)
 | |
| {
 | |
| 	if (WindowSize.Width!=0)
 | |
| 		InvWindowSize.Width = 1.0f / WindowSize.Width;
 | |
| 
 | |
| 	if (WindowSize.Height!=0)
 | |
| 		InvWindowSize.Height = 1.0f / WindowSize.Height;
 | |
| 
 | |
| 	updateBorderSize(fullscreen, false);
 | |
| 	initCursors();
 | |
| }
 | |
| 
 | |
| CIrrDeviceWin32::CCursorControl::~CCursorControl()
 | |
| {
 | |
| 	for ( u32 i=0; i < Cursors.size(); ++i )
 | |
| 	{
 | |
| 		for ( u32 f=0; f < Cursors[i].Frames.size(); ++f )
 | |
| 		{
 | |
| 			DestroyCursor(Cursors[i].Frames[f].IconHW);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| void CIrrDeviceWin32::CCursorControl::initCursors()
 | |
| {
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_ARROW)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_CROSS)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HAND)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HELP)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_IBEAM)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_NO)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_WAIT)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEALL)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENESW)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENWSE)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENS)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEWE)) );
 | |
| 	Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_UPARROW)) );
 | |
| }
 | |
| 
 | |
| 
 | |
| void CIrrDeviceWin32::CCursorControl::update()
 | |
| {
 | |
| 	if ( !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime )
 | |
| 	{
 | |
| 		// 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)
 | |
| 		u32 now = Device->getTimer()->getRealTime();
 | |
| 		u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();
 | |
| 		SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW );
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //! Sets the active cursor icon
 | |
| void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId)
 | |
| {
 | |
| 	if ( iconId >= (s32)Cursors.size() )
 | |
| 		return;
 | |
| 
 | |
| 	ActiveIcon = iconId;
 | |
| 	ActiveIconStartTime = Device->getTimer()->getRealTime();
 | |
| 	if ( Cursors[ActiveIcon].Frames.size() )
 | |
| 		SetCursor( Cursors[ActiveIcon].Frames[0].IconHW );
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Add a custom sprite as cursor icon.
 | |
| gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite& icon)
 | |
| {
 | |
| 	if ( icon.SpriteId >= 0 )
 | |
| 	{
 | |
| 		CursorW32 cW32;
 | |
| 		cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
 | |
| 
 | |
| 		for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
 | |
| 		{
 | |
| 			irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
 | |
| 			irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
 | |
| 			irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
 | |
| 
 | |
| 			HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
 | |
| 			cW32.Frames.push_back( CursorFrameW32(hc) );
 | |
| 		}
 | |
| 
 | |
| 		Cursors.push_back( cW32 );
 | |
| 		return (gui::ECURSOR_ICON)(Cursors.size() - 1);
 | |
| 	}
 | |
| 	return gui::ECI_NORMAL;
 | |
| }
 | |
| 
 | |
| 
 | |
| //! replace the given cursor icon.
 | |
| void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon)
 | |
| {
 | |
| 	if ( iconId >= (s32)Cursors.size() )
 | |
| 		return;
 | |
| 
 | |
| 	for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i )
 | |
| 		DestroyCursor(Cursors[iconId].Frames[i].IconHW);
 | |
| 
 | |
| 	if ( icon.SpriteId >= 0 )
 | |
| 	{
 | |
| 		CursorW32 cW32;
 | |
| 		cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
 | |
| 		for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
 | |
| 		{
 | |
| 			irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
 | |
| 			irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
 | |
| 			irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
 | |
| 
 | |
| 			HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
 | |
| 			cW32.Frames.push_back( CursorFrameW32(hc) );
 | |
| 		}
 | |
| 
 | |
| 		Cursors[iconId] = cW32;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.
 | |
| core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const
 | |
| {
 | |
| 	core::dimension2di result;
 | |
| 
 | |
| 	result.Width = GetSystemMetrics(SM_CXCURSOR);
 | |
| 	result.Height = GetSystemMetrics(SM_CYCURSOR);
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| } // end namespace
 | |
| 
 | |
| #endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_
 |