#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
#include "CIrrDeviceWin32.h"
#include "IEventReceiver.h"
#include "irrList.h"
#include "os.h"
#include "CTimer.h"
#include "irrString.h"
#include "COSOperator.h"
#include "dimension2d.h"
#include "IGUISpriteBank.h"
#include <winuser.h>
namespace irr
{
namespace video
{
#ifdef _IRR_COMPILE_WITH_DIRECT3D_8_
IVideoDriver* createDirectX8Driver(const core::dimension2d<u32>& screenSize, HWND window,
u32 bits, bool fullscreen, bool stencilbuffer, io::IFileSystem* io,
bool pureSoftware, bool highPrecisionFPU, bool vsync, u8 antiAlias, u32 displayAdapter);
#endif
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
IVideoDriver* createDirectX9Driver(const core::dimension2d<u32>& screenSize, HWND window,
u32 bits, bool fullscreen, bool stencilbuffer, io::IFileSystem* io,
bool pureSoftware, bool highPrecisionFPU, bool vsync, u8 antiAlias, u32 displayAdapter);
#endif
#ifdef _IRR_COMPILE_WITH_OPENGL_
IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params,
io::IFileSystem* io, CIrrDeviceWin32* device);
#endif
}
}
static unsigned int LocaleIdToCodepage(unsigned int lcid)
{
switch ( lcid )
{
case 1098:
case 1095:
case 1094:
case 1103:
case 1111:
case 1114:
case 1099:
case 1102:
case 1125:
case 1067:
case 1081:
case 1079:
case 1097:
return 0;
case 1054:
return 874;
case 1041:
return 932;
case 2052:
case 4100:
return 936;
case 1042:
return 949;
case 5124:
case 3076:
case 1028:
return 950;
case 1048:
case 1060:
case 1038:
case 1051:
case 1045:
case 1052:
case 2074:
case 1050:
case 1029:
return 1250;
case 1104:
case 1071:
case 2115:
case 1058:
case 2092:
case 1092:
case 1087:
case 1059:
case 1088:
case 1026:
case 3098:
case 1049:
return 1251;
case 8201:
case 3084:
case 1036:
case 5132:
case 5129:
case 6153:
case 1043:
case 9225:
case 4108:
case 4105:
case 1110:
case 10249:
case 3079:
case 6156:
case 12297:
case 1069:
case 2067:
case 2060:
case 1035:
case 1080:
case 1031:
case 3081:
case 1033:
case 2057:
case 1027:
case 11273:
case 7177:
case 1030:
case 13321:
case 15370:
case 9226:
case 5130:
case 7178:
case 12298:
case 17418:
case 4106:
case 18442:
case 3082:
case 13322:
case 19466:
case 2058:
case 10250:
case 20490:
case 1034:
case 14346:
case 8202:
case 1089:
case 1053:
case 2077:
case 5127:
case 1078:
case 6154:
case 4103:
case 16394:
case 2055:
case 1039:
case 1057:
case 1040:
case 2064:
case 2068:
case 11274:
case 1046:
case 1044:
case 1086:
case 2110:
case 2070:
return 1252;
case 1032:
return 1253;
case 1091:
case 1068:
case 1055:
return 1254;
case 1037:
return 1255;
case 5121:
case 15361:
case 9217:
case 3073:
case 2049:
case 11265:
case 13313:
case 12289:
case 4097:
case 6145:
case 8193:
case 16385:
case 1025:
case 10241:
case 14337:
case 1065:
case 1056:
case 7169:
return 1256;
case 1061:
case 1062:
case 1063:
return 1257;
case 1066:
return 1258;
}
return 65001;
}
namespace
{
struct SEnvMapper
{
HWND hWnd;
irr::CIrrDeviceWin32* irrDev;
};
irr::core::list<SEnvMapper> EnvMap;
HKL KEYBOARD_INPUT_HKL=0;
unsigned int KEYBOARD_INPUT_CODEPAGE = 1252;
};
SEnvMapper* getEnvMapperFromHWnd(HWND hWnd)
{
irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin();
for (; it!= EnvMap.end(); ++it)
if ((*it).hWnd == hWnd)
return &(*it);
return 0;
}
irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)
{
irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin();
for (; it!= EnvMap.end(); ++it)
if ((*it).hWnd == hWnd)
return (*it).irrDev;
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL 0x020A
#endif
#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}
};
messageMap * m = mouseMap;
while ( m->group >=0 && m->winMessage != message )
m += 1;
if ( m->group >= 0 )
{
if ( m->group == 0 )
{
ClickCount++;
SetCapture(hWnd);
}
else
if ( m->group == 1 )
{
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);
event.MouseInput.ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON);
if (wParam & MK_MBUTTON)
event.MouseInput.ButtonStates |= irr::EMBSM_MIDDLE;
#if(_WIN32_WINNT >= 0x0500)
if (wParam & MK_XBUTTON1)
event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA1;
if (wParam & MK_XBUTTON2)
event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA2;
#endif
event.MouseInput.Wheel = 0.f;
if ( m->group == 3 )
{
POINT p;
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);
const UINT MY_MAPVK_VSC_TO_VK_EX = 3;
if ( event.KeyInput.Key == irr::KEY_SHIFT )
{
event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX );
}
if ( event.KeyInput.Key == irr::KEY_CONTROL )
{
event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX );
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), MY_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);
WORD keyChars[2];
UINT scanCode = HIWORD(lParam);
int conversionResult = ToAsciiEx(wParam,scanCode,allKeys,keyChars,0,KEYBOARD_INPUT_HKL);
if (conversionResult == 1)
{
WORD unicodeChar;
MultiByteToWideChar(
KEYBOARD_INPUT_CODEPAGE,
MB_PRECOMPOSED,
(LPCSTR)keyChars,
sizeof(keyChars),
(WCHAR*)&unicodeChar,
1 );
event.KeyInput.Char = unicodeChar;
}
else
event.KeyInput.Char = 0;
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 DefWindowProc(hWnd, message, wParam, lParam);
else
return 0;
}
case WM_SIZE:
{
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->OnResized();
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_SYSCOMMAND:
if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
(wParam & 0xFFF0) == SC_MONITORPOWER ||
(wParam & 0xFFF0) == SC_KEYMENU
)
return 0;
break;
case WM_ACTIVATE:
dev = getDeviceFromHWnd(hWnd);
if (dev)
{
if ((wParam&0xFF)==WA_INACTIVE)
dev->switchToFullScreen(true);
else
dev->switchToFullScreen();
}
break;
case WM_USER:
event.EventType = irr::EET_USER_EVENT;
event.UserEvent.UserData1 = (irr::s32)wParam;
event.UserEvent.UserData2 = (irr::s32)lParam;
dev = getDeviceFromHWnd(hWnd);
if (dev)
dev->postEventFromUser(event);
return 0;
case WM_SETCURSOR:
dev = getDeviceFromHWnd(hWnd);
if (dev)
{
dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() );
dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() );
}
break;
case WM_INPUTLANGCHANGE:
KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
namespace irr
{
CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)
: CIrrDeviceStub(params), HWnd(0), ChangedToFullScreen(false),
IsNonNTWindows(false), Resized(false),
ExternalWindow(false), Win32CursorControl(0)
{
#ifdef _DEBUG
setDebugName("CIrrDeviceWin32");
#endif
core::stringc winversion;
getWindowsVersion(winversion);
Operator = new COSOperator(winversion.c_str());
os::Printer::log(winversion.c_str(), ELL_INFORMATION);
HINSTANCE hInstance = GetModuleHandle(0);
if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL)
{
const fschar_t* ClassName = __TEXT("CIrrDeviceWin32");
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = 0;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = ClassName;
wcex.hIconSm = 0;
wcex.hIcon = (HICON)LoadImage(hInstance, __TEXT("irrlicht.ico"), IMAGE_ICON, 0,0, LR_LOADFROMFILE);
RegisterClassEx(&wcex);
RECT clientSize;
clientSize.top = 0;
clientSize.left = 0;
clientSize.right = CreationParams.WindowSize.Width;
clientSize.bottom = CreationParams.WindowSize.Height;
DWORD style = WS_POPUP;
if (!CreationParams.Fullscreen)
style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
AdjustWindowRect(&clientSize, style, FALSE);
const s32 realWidth = clientSize.right - clientSize.left;
const s32 realHeight = clientSize.bottom - clientSize.top;
s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;
s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;
if ( windowLeft < 0 )
windowLeft = 0;
if ( windowTop < 0 )
windowTop = 0;
if (CreationParams.Fullscreen)
{
windowLeft = 0;
windowTop = 0;
}
HWnd = CreateWindow( ClassName, __TEXT(""), style, windowLeft, windowTop,
realWidth, realHeight, NULL, NULL, hInstance, NULL);
CreationParams.WindowId = HWnd;
ShowWindow(HWnd, SW_SHOWNORMAL);
UpdateWindow(HWnd);
MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE);
Resized = true;
}
else if (CreationParams.WindowId)
{
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;
}
Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen);
CursorControl = Win32CursorControl;
MouseMultiClicks.DoubleClickTime = GetDoubleClickTime();
createDriver();
if (VideoDriver)
createGUIAndScene();
SEnvMapper em;
em.irrDev = this;
em.hWnd = HWnd;
EnvMap.push_back(em);
if ( HWnd )
{
SetActiveWindow(HWnd);
SetForegroundWindow(HWnd);
}
KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );
}
CIrrDeviceWin32::~CIrrDeviceWin32()
{
irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin();
for (; it!= EnvMap.end(); ++it)
{
if ((*it).hWnd == HWnd)
{
EnvMap.erase(it);
break;
}
}
switchToFullScreen(true);
}
void CIrrDeviceWin32::createDriver()
{
switch(CreationParams.DriverType)
{
case video::EDT_DIRECT3D8:
#ifdef _IRR_COMPILE_WITH_DIRECT3D_8_
VideoDriver = video::createDirectX8Driver(CreationParams.WindowSize, HWnd,
CreationParams.Bits, CreationParams.Fullscreen, CreationParams.Stencilbuffer,
FileSystem, false, CreationParams.HighPrecisionFPU, CreationParams.Vsync,
CreationParams.AntiAlias, CreationParams.DisplayAdapter);
if (!VideoDriver)
{
os::Printer::log("Could not create DIRECT3D8 Driver.", ELL_ERROR);
}
#else
os::Printer::log("DIRECT3D8 Driver was not compiled into this dll. Try another one.", ELL_ERROR);
#endif
break;
case video::EDT_DIRECT3D9:
#ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
VideoDriver = video::createDirectX9Driver(CreationParams.WindowSize, HWnd,
CreationParams.Bits, CreationParams.Fullscreen, CreationParams.Stencilbuffer,
FileSystem, false, CreationParams.HighPrecisionFPU, CreationParams.Vsync,
CreationParams.AntiAlias, CreationParams.DisplayAdapter);
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();
VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this);
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_SOFTWARE:
#ifdef _IRR_COMPILE_WITH_SOFTWARE_
switchToFullScreen();
VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
#else
os::Printer::log("Software driver was not compiled in.", ELL_ERROR);
#endif
break;
case video::EDT_BURNINGSVIDEO:
#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
switchToFullScreen();
VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
#else
os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR);
#endif
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;
}
}
bool CIrrDeviceWin32::run()
{
os::Timer::tick();
static_cast<CCursorControl*>(CursorControl)->update();
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (ExternalWindow && msg.hwnd == HWnd)
WndProc(HWnd, msg.message, msg.wParam, msg.lParam);
else
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
Close = true;
}
if (!Close)
resizeIfNecessary();
if(!Close)
pollJoysticks();
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return !Close;
}
void CIrrDeviceWin32::yield()
{
Sleep(1);
}
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)
return;
RECT r;
GetClientRect(HWnd, &r);
char tmp[255];
if (r.right < 2 || r.bottom < 2)
{
sprintf(tmp, "Ignoring resize operation to (%ld %ld)", r.right, r.bottom);
os::Printer::log(tmp);
}
else
{
sprintf(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;
}
void CIrrDeviceWin32::setWindowCaption(const wchar_t* text)
{
DWORD dwResult;
if (IsNonNTWindows)
{
const core::stringc s = text;
#if defined(_WIN64) || defined(WIN64)
SetWindowTextA(HWnd, s.c_str());
#else
SendMessageTimeout(HWnd, WM_SETTEXT, 0,
reinterpret_cast<LPARAM>(s.c_str()),
SMTO_ABORTIFHUNG, 2000, &dwResult);
#endif
}
else
{
#if defined(_WIN64) || defined(WIN64)
SetWindowTextW(HWnd, text);
#else
SendMessageTimeoutW(HWnd, WM_SETTEXT, 0,
reinterpret_cast<LPARAM>(text),
SMTO_ABORTIFHUNG, 2000, &dwResult);
#endif
}
}
bool CIrrDeviceWin32::present(video::IImage* image, void* windowId, core::rect<s32>* src)
{
HWND hwnd = HWnd;
if ( windowId )
hwnd = reinterpret_cast<HWND>(windowId);
HDC dc = GetDC(hwnd);
if ( dc )
{
RECT rect;
GetClientRect(hwnd, &rect);
const void* memory = (const void *)image->lock();
BITMAPV4HEADER bi;
ZeroMemory (&bi, sizeof(bi));
bi.bV4Size = sizeof(BITMAPINFOHEADER);
bi.bV4BitCount = (WORD)image->getBitsPerPixel();
bi.bV4Planes = 1;
bi.bV4Width = image->getDimension().Width;
bi.bV4Height = -((s32)image->getDimension().Height);
bi.bV4V4Compression = BI_BITFIELDS;
bi.bV4AlphaMask = image->getAlphaMask();
bi.bV4RedMask = image->getRedMask();
bi.bV4GreenMask = image->getGreenMask();
bi.bV4BlueMask = image->getBlueMask();
if ( src )
{
StretchDIBits(dc, 0,0, rect.right, rect.bottom,
src->UpperLeftCorner.X, src->UpperLeftCorner.Y,
src->getWidth(), src->getHeight(),
memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY);
}
else
{
StretchDIBits(dc, 0,0, rect.right, rect.bottom,
0, 0, image->getDimension().Width, image->getDimension().Height,
memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY);
}
image->unlock();
ReleaseDC(hwnd, dc);
}
return true;
}
void CIrrDeviceWin32::closeDevice()
{
MSG msg;
PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
PostQuitMessage(0);
PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
if (!ExternalWindow)
{
DestroyWindow(HWnd);
const fschar_t* ClassName = __TEXT("CIrrDeviceWin32");
HINSTANCE hInstance = GetModuleHandle(0);
UnregisterClass(ClassName, hInstance);
}
Close=true;
}
bool CIrrDeviceWin32::isWindowActive() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return (GetActiveWindow() == HWnd);
}
bool CIrrDeviceWin32::isWindowFocused() const
{
bool ret = (GetFocus() == HWnd);
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return ret;
}
bool CIrrDeviceWin32::isWindowMinimized() const
{
WINDOWPLACEMENT plc;
plc.length=sizeof(WINDOWPLACEMENT);
bool ret=false;
if (GetWindowPlacement(HWnd,&plc))
ret=(plc.showCmd & SW_SHOWMINIMIZED)!=0;
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return ret;
}
bool CIrrDeviceWin32::switchToFullScreen(bool reset)
{
if (!CreationParams.Fullscreen)
return true;
if (reset)
{
if (ChangedToFullScreen)
return (ChangeDisplaySettings(NULL,0)==DISP_CHANGE_SUCCESSFUL);
else
return true;
}
DEVMODE dm;
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(dm);
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm);
dm.dmPelsWidth = CreationParams.WindowSize.Width;
dm.dmPelsHeight = CreationParams.WindowSize.Height;
dm.dmBitsPerPel = CreationParams.Bits;
dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
LONG res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
if (res != DISP_CHANGE_SUCCESSFUL)
{
dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
}
bool ret = false;
switch(res)
{
case DISP_CHANGE_SUCCESSFUL:
ChangedToFullScreen = true;
ret = true;
break;
case DISP_CHANGE_RESTART:
os::Printer::log("Switch to fullscreen: The computer must be restarted in order for the graphics mode to work.", ELL_ERROR);
break;
case DISP_CHANGE_BADFLAGS:
os::Printer::log("Switch to fullscreen: An invalid set of flags was passed in.", ELL_ERROR);
break;
case DISP_CHANGE_BADPARAM:
os::Printer::log("Switch to fullscreen: An invalid parameter was passed in. This can include an invalid flag or combination of flags.", ELL_ERROR);
break;
case DISP_CHANGE_FAILED:
os::Printer::log("Switch to fullscreen: The display driver failed the specified graphics mode.", ELL_ERROR);
break;
case DISP_CHANGE_BADMODE:
os::Printer::log("Switch to fullscreen: The graphics mode is not supported.", ELL_ERROR);
break;
default:
os::Printer::log("An unknown error occured while changing to fullscreen.", ELL_ERROR);
break;
}
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return ret;
}
CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl()
{
return Win32CursorControl;
}
video::IVideoModeList* CIrrDeviceWin32::getVideoModeList()
{
if (!VideoModeList.getVideoModeCount())
{
DWORD i=0;
DEVMODE mode;
memset(&mode, 0, sizeof(mode));
mode.dmSize = sizeof(mode);
while (EnumDisplaySettings(NULL, i, &mode))
{
VideoModeList.addMode(core::dimension2d<u32>(mode.dmPelsWidth, mode.dmPelsHeight),
mode.dmBitsPerPel);
++i;
}
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode))
VideoModeList.setDesktop(mode.dmBitsPerPel, core::dimension2d<u32>(mode.dmPelsWidth, mode.dmPelsHeight));
}
return &VideoModeList;
}
typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
#define PRODUCT_ULTIMATE 0x00000001
#define PRODUCT_HOME_BASIC 0x00000002
#define PRODUCT_HOME_PREMIUM 0x00000003
#define PRODUCT_ENTERPRISE 0x00000004
#define PRODUCT_HOME_BASIC_N 0x00000005
#define PRODUCT_BUSINESS 0x00000006
#define PRODUCT_STARTER 0x0000000B
#define PRODUCT_BUSINESS_N 0x00000010
#define PRODUCT_HOME_PREMIUM_N 0x0000001A
#define PRODUCT_ENTERPRISE_N 0x0000001B
#define PRODUCT_ULTIMATE_N 0x0000001C
#define PRODUCT_STARTER_N 0x0000002F
#define PRODUCT_PROFESSIONAL 0x00000030
#define PRODUCT_PROFESSIONAL_N 0x00000031
#define PRODUCT_STARTER_E 0x00000042
#define PRODUCT_HOME_BASIC_E 0x00000043
#define PRODUCT_HOME_PREMIUM_E 0x00000044
#define PRODUCT_PROFESSIONAL_E 0x00000045
#define PRODUCT_ENTERPRISE_E 0x00000046
#define PRODUCT_ULTIMATE_E 0x00000047
void CIrrDeviceWin32::getWindowsVersion(core::stringc& out)
{
OSVERSIONINFOEX osvi;
PGPI pGPI;
BOOL bOsVersionInfoEx;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
if (!bOsVersionInfoEx)
{
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (! GetVersionEx((OSVERSIONINFO *) &osvi))
return;
}
switch (osvi.dwPlatformId)
{
case VER_PLATFORM_WIN32_NT:
if (osvi.dwMajorVersion <= 4)
out.append("Microsoft Windows NT ");
else
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
out.append("Microsoft Windows 2000 ");
else
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
out.append("Microsoft Windows XP ");
else
if (osvi.dwMajorVersion == 6 )
{
if (osvi.dwMinorVersion == 0)
{
if (osvi.wProductType == VER_NT_WORKSTATION)
out.append("Microsoft Windows Vista ");
else
out.append("Microsoft Windows Server 2008 ");
}
else if (osvi.dwMinorVersion == 1)
{
if (osvi.wProductType == VER_NT_WORKSTATION)
out.append("Microsoft Windows 7 ");
else
out.append("Microsoft Windows Server 2008 R2 ");
}
}
if (bOsVersionInfoEx)
{
if (osvi.dwMajorVersion == 6)
{
DWORD dwType;
pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo");
pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
switch (dwType)
{
case PRODUCT_ULTIMATE:
case PRODUCT_ULTIMATE_E:
case PRODUCT_ULTIMATE_N:
out.append("Ultimate Edition ");
break;
case PRODUCT_PROFESSIONAL:
case PRODUCT_PROFESSIONAL_E:
case PRODUCT_PROFESSIONAL_N:
out.append("Professional Edition ");
break;
case PRODUCT_HOME_BASIC:
case PRODUCT_HOME_BASIC_E:
case PRODUCT_HOME_BASIC_N:
out.append("Home Basic Edition ");
break;
case PRODUCT_HOME_PREMIUM:
case PRODUCT_HOME_PREMIUM_E:
case PRODUCT_HOME_PREMIUM_N:
out.append("Home Premium Edition ");
break;
case PRODUCT_ENTERPRISE:
case PRODUCT_ENTERPRISE_E:
case PRODUCT_ENTERPRISE_N:
out.append("Enterprise Edition ");
break;
case PRODUCT_BUSINESS:
case PRODUCT_BUSINESS_N:
out.append("Business Edition ");
break;
case PRODUCT_STARTER:
case PRODUCT_STARTER_E:
case PRODUCT_STARTER_N:
out.append("Starter Edition ");
break;
}
}
#ifdef VER_SUITE_ENTERPRISE
else
if (osvi.wProductType == VER_NT_WORKSTATION)
{
#ifndef __BORLANDC__
if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
out.append("Personal ");
else
out.append("Professional ");
#endif
}
else if (osvi.wProductType == VER_NT_SERVER)
{
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
out.append("DataCenter Server ");
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
out.append("Advanced Server ");
else
out.append("Server ");
}
#endif
}
else
{
HKEY hKey;
char szProductType[80];
DWORD dwBufLen;
RegOpenKeyEx( HKEY_LOCAL_MACHINE,
__TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
0, KEY_QUERY_VALUE, &hKey );
RegQueryValueEx( hKey, __TEXT("ProductType"), NULL, NULL,
(LPBYTE) szProductType, &dwBufLen);
RegCloseKey( hKey );
if (_strcmpi( "WINNT", szProductType) == 0 )
out.append("Professional ");
if (_strcmpi( "LANMANNT", szProductType) == 0)
out.append("Server ");
if (_strcmpi( "SERVERNT", szProductType) == 0)
out.append("Advanced Server ");
}
char tmp[255];
if (osvi.dwMajorVersion <= 4 )
{
sprintf(tmp, "version %ld.%ld %s (Build %ld)",
osvi.dwMajorVersion,
osvi.dwMinorVersion,
osvi.szCSDVersion,
osvi.dwBuildNumber & 0xFFFF);
}
else
{
sprintf(tmp, "%s (Build %ld)", osvi.szCSDVersion,
osvi.dwBuildNumber & 0xFFFF);
}
out.append(tmp);
break;
case VER_PLATFORM_WIN32_WINDOWS:
IsNonNTWindows = true;
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
{
out.append("Microsoft Windows 95 ");
if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )
out.append("OSR2 " );
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
{
out.append("Microsoft Windows 98 ");
if ( osvi.szCSDVersion[1] == 'A' )
out.append( "SE " );
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
out.append("Microsoft Windows Me ");
break;
case VER_PLATFORM_WIN32s:
IsNonNTWindows = true;
out.append("Microsoft Win32s ");
break;
}
}
void CIrrDeviceWin32::OnResized()
{
Resized = true;
}
void CIrrDeviceWin32::setResizable(bool resize)
{
if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)
return;
LONG_PTR style = WS_POPUP;
if (!resize)
style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
else
style = WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
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, 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);
}
void CIrrDeviceWin32::minimizeWindow()
{
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(HWnd, &wndpl);
wndpl.showCmd = SW_SHOWMINNOACTIVE;
SetWindowPlacement(HWnd, &wndpl);
}
void CIrrDeviceWin32::maximizeWindow()
{
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(HWnd, &wndpl);
wndpl.showCmd = SW_SHOWMAXIMIZED;
SetWindowPlacement(HWnd, &wndpl);
}
void CIrrDeviceWin32::restoreWindow()
{
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(HWnd, &wndpl);
wndpl.showCmd = SW_SHOWNORMAL;
SetWindowPlacement(HWnd, &wndpl);
}
bool CIrrDeviceWin32::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
{
#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
joystickInfo.clear();
ActiveJoysticks.clear();
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 = activeJoystick.Caps.szPname;
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];
(void)sprintf(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;
#else
return false;
#endif
}
void CIrrDeviceWin32::pollJoysticks()
{
#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
if(0 == ActiveJoysticks.size())
return;
u32 joystick;
JOYINFOEX info;
for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
{
info.dwSize = sizeof(info);
info.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;
const JOYCAPS & caps = ActiveJoysticks[joystick].Caps;
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;
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;
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);
}
event.JoystickEvent.ButtonStates = info.dwButtons;
(void)postEventFromUser(event);
}
}
#endif
}
bool CIrrDeviceWin32::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast )
{
bool r;
u16 ramp[3][256];
calculateGammaRamp( ramp[0], red, brightness, contrast );
calculateGammaRamp( ramp[1], green, brightness, contrast );
calculateGammaRamp( ramp[2], blue, brightness, contrast );
HDC dc = GetDC(0);
r = SetDeviceGammaRamp ( dc, ramp ) == TRUE;
ReleaseDC(HWnd, dc);
return r;
}
bool CIrrDeviceWin32::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast )
{
bool r;
u16 ramp[3][256];
HDC dc = GetDC(0);
r = GetDeviceGammaRamp ( dc, ramp ) == TRUE;
ReleaseDC(HWnd, dc);
if ( r )
{
calculateGammaFromRamp(red, ramp[0]);
calculateGammaFromRamp(green, ramp[1]);
calculateGammaFromRamp(blue, ramp[2]);
}
brightness = 0.f;
contrast = 0.f;
return r;
}
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))
{}
}
void CIrrDeviceWin32::ReportLastWinApiError()
{
LPCTSTR pszCaption = __TEXT("Windows SDK Error Report");
DWORD dwError = GetLastError();
if(NOERROR == dwError)
{
MessageBox(NULL, __TEXT("No error"), pszCaption, MB_OK);
}
else
{
const DWORD dwFormatControl = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM;
LPVOID pTextBuffer = NULL;
DWORD dwCount = FormatMessage(dwFormatControl,
NULL,
dwError,
0,
(LPTSTR) &pTextBuffer,
0,
NULL);
if(0 != dwCount)
{
MessageBox(NULL, (LPCTSTR)pTextBuffer, pszCaption, MB_OK|MB_ICONERROR);
LocalFree(pTextBuffer);
}
else
{
MessageBox(NULL, __TEXT("Unknown error"), pszCaption, MB_OK|MB_ICONERROR);
}
}
}
HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
{
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 )
{
SetPixel(andDc, x, y, RGB(255,255,255));
SetPixel(xorDc, x, y, RGB(0,0,0));
}
else
{
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);
ICONINFO iconinfo;
iconinfo.fIcon = false;
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 )
{
u32 now = Device->getTimer()->getRealTime();
u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();
SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW );
}
}
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 );
}
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;
}
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;
}
}
core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const
{
core::dimension2di result;
result.Width = GetSystemMetrics(SM_CXCURSOR);
result.Height = GetSystemMetrics(SM_CYCURSOR);
return result;
}
}
#endif