PlatformWindows.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. #ifdef WIN32
  2. #include "Base.h"
  3. #include "Platform.h"
  4. #include "FileSystem.h"
  5. #include "Game.h"
  6. #include "Form.h"
  7. #include "Vector2.h"
  8. #include "ScriptController.h"
  9. #include <GL/wglew.h>
  10. #include <windowsx.h>
  11. #include <shellapi.h>
  12. #ifdef GP_USE_GAMEPAD
  13. #include <XInput.h>
  14. #endif
  15. using gameplay::print;
  16. // Window defaults
  17. #define DEFAULT_RESOLUTION_X 1024
  18. #define DEFAULT_RESOLUTION_Y 768
  19. #define DEFAULT_COLOR_BUFFER_SIZE 32
  20. #define DEFAULT_DEPTH_BUFFER_SIZE 24
  21. #define DEFAULT_STENCIL_BUFFER_SIZE 8
  22. static double __timeTicksPerMillis;
  23. static double __timeStart;
  24. static double __timeAbsolute;
  25. static bool __vsync = WINDOW_VSYNC;
  26. static HINSTANCE __hinstance = 0;
  27. static HWND __hwnd = 0;
  28. static HDC __hdc = 0;
  29. static HGLRC __hrc = 0;
  30. static bool __mouseCaptured = false;
  31. static POINT __mouseCapturePoint = { 0, 0 };
  32. static bool __multiSampling = false;
  33. static bool __cursorVisible = true;
  34. static unsigned int __gamepadsConnected = 0;
  35. #ifdef GP_USE_GAMEPAD
  36. static const unsigned int XINPUT_BUTTON_COUNT = 14;
  37. static const unsigned int XINPUT_JOYSTICK_COUNT = 2;
  38. static const unsigned int XINPUT_TRIGGER_COUNT = 2;
  39. static XINPUT_STATE __xInputState;
  40. static bool __connectedXInput[4];
  41. static float normalizeXInputJoystickAxis(int axisValue, int deadZone)
  42. {
  43. int absAxisValue = abs(axisValue);
  44. if (absAxisValue < deadZone)
  45. {
  46. return 0.0f;
  47. }
  48. else
  49. {
  50. int value = axisValue;
  51. int maxVal;
  52. if (value < 0)
  53. {
  54. value = -1;
  55. maxVal = 32768;
  56. }
  57. else if (value > 0)
  58. {
  59. value = 1;
  60. maxVal = 32767;
  61. }
  62. else
  63. {
  64. return 0;
  65. }
  66. return value * (absAxisValue - deadZone) / (float)(maxVal - deadZone);
  67. }
  68. }
  69. #endif
  70. static gameplay::Keyboard::Key getKey(WPARAM win32KeyCode, bool shiftDown)
  71. {
  72. switch (win32KeyCode)
  73. {
  74. case VK_PAUSE:
  75. return gameplay::Keyboard::KEY_PAUSE;
  76. case VK_SCROLL:
  77. return gameplay::Keyboard::KEY_SCROLL_LOCK;
  78. case VK_PRINT:
  79. return gameplay::Keyboard::KEY_PRINT;
  80. case VK_ESCAPE:
  81. return gameplay::Keyboard::KEY_ESCAPE;
  82. case VK_BACK:
  83. return gameplay::Keyboard::KEY_BACKSPACE;
  84. case VK_TAB:
  85. return shiftDown ? gameplay::Keyboard::KEY_BACK_TAB : gameplay::Keyboard::KEY_TAB;
  86. case VK_RETURN:
  87. return gameplay::Keyboard::KEY_RETURN;
  88. case VK_CAPITAL:
  89. return gameplay::Keyboard::KEY_CAPS_LOCK;
  90. case VK_SHIFT:
  91. return gameplay::Keyboard::KEY_SHIFT;
  92. case VK_CONTROL:
  93. return gameplay::Keyboard::KEY_CTRL;
  94. case VK_MENU:
  95. return gameplay::Keyboard::KEY_ALT;
  96. case VK_APPS:
  97. return gameplay::Keyboard::KEY_MENU;
  98. case VK_LSHIFT:
  99. return gameplay::Keyboard::KEY_SHIFT;
  100. case VK_RSHIFT:
  101. return gameplay::Keyboard::KEY_SHIFT;
  102. case VK_LCONTROL:
  103. return gameplay::Keyboard::KEY_CTRL;
  104. case VK_RCONTROL:
  105. return gameplay::Keyboard::KEY_CTRL;
  106. case VK_LMENU:
  107. return gameplay::Keyboard::KEY_ALT;
  108. case VK_RMENU:
  109. return gameplay::Keyboard::KEY_ALT;
  110. case VK_LWIN:
  111. case VK_RWIN:
  112. return gameplay::Keyboard::KEY_HYPER;
  113. case VK_BROWSER_SEARCH:
  114. return gameplay::Keyboard::KEY_SEARCH;
  115. case VK_INSERT:
  116. return gameplay::Keyboard::KEY_INSERT;
  117. case VK_HOME:
  118. return gameplay::Keyboard::KEY_HOME;
  119. case VK_PRIOR:
  120. return gameplay::Keyboard::KEY_PG_UP;
  121. case VK_DELETE:
  122. return gameplay::Keyboard::KEY_DELETE;
  123. case VK_END:
  124. return gameplay::Keyboard::KEY_END;
  125. case VK_NEXT:
  126. return gameplay::Keyboard::KEY_PG_DOWN;
  127. case VK_LEFT:
  128. return gameplay::Keyboard::KEY_LEFT_ARROW;
  129. case VK_RIGHT:
  130. return gameplay::Keyboard::KEY_RIGHT_ARROW;
  131. case VK_UP:
  132. return gameplay::Keyboard::KEY_UP_ARROW;
  133. case VK_DOWN:
  134. return gameplay::Keyboard::KEY_DOWN_ARROW;
  135. case VK_NUMLOCK:
  136. return gameplay::Keyboard::KEY_NUM_LOCK;
  137. case VK_ADD:
  138. return gameplay::Keyboard::KEY_KP_PLUS;
  139. case VK_SUBTRACT:
  140. return gameplay::Keyboard::KEY_KP_MINUS;
  141. case VK_MULTIPLY:
  142. return gameplay::Keyboard::KEY_KP_MULTIPLY;
  143. case VK_DIVIDE:
  144. return gameplay::Keyboard::KEY_KP_DIVIDE;
  145. case VK_NUMPAD7:
  146. return gameplay::Keyboard::KEY_KP_HOME;
  147. case VK_NUMPAD8:
  148. return gameplay::Keyboard::KEY_KP_UP;
  149. case VK_NUMPAD9:
  150. return gameplay::Keyboard::KEY_KP_PG_UP;
  151. case VK_NUMPAD4:
  152. return gameplay::Keyboard::KEY_KP_LEFT;
  153. case VK_NUMPAD5:
  154. return gameplay::Keyboard::KEY_KP_FIVE;
  155. case VK_NUMPAD6:
  156. return gameplay::Keyboard::KEY_KP_RIGHT;
  157. case VK_NUMPAD1:
  158. return gameplay::Keyboard::KEY_KP_END;
  159. case VK_NUMPAD2:
  160. return gameplay::Keyboard::KEY_KP_DOWN;
  161. case VK_NUMPAD3:
  162. return gameplay::Keyboard::KEY_KP_PG_DOWN;
  163. case VK_NUMPAD0:
  164. return gameplay::Keyboard::KEY_KP_INSERT;
  165. case VK_DECIMAL:
  166. return gameplay::Keyboard::KEY_KP_DELETE;
  167. case VK_F1:
  168. return gameplay::Keyboard::KEY_F1;
  169. case VK_F2:
  170. return gameplay::Keyboard::KEY_F2;
  171. case VK_F3:
  172. return gameplay::Keyboard::KEY_F3;
  173. case VK_F4:
  174. return gameplay::Keyboard::KEY_F4;
  175. case VK_F5:
  176. return gameplay::Keyboard::KEY_F5;
  177. case VK_F6:
  178. return gameplay::Keyboard::KEY_F6;
  179. case VK_F7:
  180. return gameplay::Keyboard::KEY_F7;
  181. case VK_F8:
  182. return gameplay::Keyboard::KEY_F8;
  183. case VK_F9:
  184. return gameplay::Keyboard::KEY_F9;
  185. case VK_F10:
  186. return gameplay::Keyboard::KEY_F10;
  187. case VK_F11:
  188. return gameplay::Keyboard::KEY_F11;
  189. case VK_F12:
  190. return gameplay::Keyboard::KEY_F12;
  191. case VK_SPACE:
  192. return gameplay::Keyboard::KEY_SPACE;
  193. case 0x30:
  194. return shiftDown ? gameplay::Keyboard::KEY_RIGHT_PARENTHESIS : gameplay::Keyboard::KEY_ZERO;
  195. case 0x31:
  196. return shiftDown ? gameplay::Keyboard::KEY_EXCLAM : gameplay::Keyboard::KEY_ONE;
  197. case 0x32:
  198. return shiftDown ? gameplay::Keyboard::KEY_AT : gameplay::Keyboard::KEY_TWO;
  199. case 0x33:
  200. return shiftDown ? gameplay::Keyboard::KEY_NUMBER : gameplay::Keyboard::KEY_THREE;
  201. case 0x34:
  202. return shiftDown ? gameplay::Keyboard::KEY_DOLLAR : gameplay::Keyboard::KEY_FOUR;
  203. case 0x35:
  204. return shiftDown ? gameplay::Keyboard::KEY_PERCENT : gameplay::Keyboard::KEY_FIVE;
  205. case 0x36:
  206. return shiftDown ? gameplay::Keyboard::KEY_CIRCUMFLEX : gameplay::Keyboard::KEY_SIX;
  207. case 0x37:
  208. return shiftDown ? gameplay::Keyboard::KEY_AMPERSAND : gameplay::Keyboard::KEY_SEVEN;
  209. case 0x38:
  210. return shiftDown ? gameplay::Keyboard::KEY_ASTERISK : gameplay::Keyboard::KEY_EIGHT;
  211. case 0x39:
  212. return shiftDown ? gameplay::Keyboard::KEY_LEFT_PARENTHESIS : gameplay::Keyboard::KEY_NINE;
  213. case VK_OEM_PLUS:
  214. return shiftDown ? gameplay::Keyboard::KEY_EQUAL : gameplay::Keyboard::KEY_PLUS;
  215. case VK_OEM_COMMA:
  216. return shiftDown ? gameplay::Keyboard::KEY_LESS_THAN : gameplay::Keyboard::KEY_COMMA;
  217. case VK_OEM_MINUS:
  218. return shiftDown ? gameplay::Keyboard::KEY_UNDERSCORE : gameplay::Keyboard::KEY_MINUS;
  219. case VK_OEM_PERIOD:
  220. return shiftDown ? gameplay::Keyboard::KEY_GREATER_THAN : gameplay::Keyboard::KEY_PERIOD;
  221. case VK_OEM_1:
  222. return shiftDown ? gameplay::Keyboard::KEY_COLON : gameplay::Keyboard::KEY_SEMICOLON;
  223. case VK_OEM_2:
  224. return shiftDown ? gameplay::Keyboard::KEY_QUESTION : gameplay::Keyboard::KEY_SLASH;
  225. case VK_OEM_3:
  226. return shiftDown ? gameplay::Keyboard::KEY_TILDE : gameplay::Keyboard::KEY_GRAVE;
  227. case VK_OEM_4:
  228. return shiftDown ? gameplay::Keyboard::KEY_LEFT_BRACE : gameplay::Keyboard::KEY_LEFT_BRACKET;
  229. case VK_OEM_5:
  230. return shiftDown ? gameplay::Keyboard::KEY_BAR : gameplay::Keyboard::KEY_BACK_SLASH;
  231. case VK_OEM_6:
  232. return shiftDown ? gameplay::Keyboard::KEY_RIGHT_BRACE : gameplay::Keyboard::KEY_RIGHT_BRACKET;
  233. case VK_OEM_7:
  234. return shiftDown ? gameplay::Keyboard::KEY_QUOTE : gameplay::Keyboard::KEY_APOSTROPHE;
  235. case 0x41:
  236. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_A : gameplay::Keyboard::KEY_A;
  237. case 0x42:
  238. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_B : gameplay::Keyboard::KEY_B;
  239. case 0x43:
  240. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_C : gameplay::Keyboard::KEY_C;
  241. case 0x44:
  242. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_D : gameplay::Keyboard::KEY_D;
  243. case 0x45:
  244. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_E : gameplay::Keyboard::KEY_E;
  245. case 0x46:
  246. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_F : gameplay::Keyboard::KEY_F;
  247. case 0x47:
  248. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_G : gameplay::Keyboard::KEY_G;
  249. case 0x48:
  250. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_H : gameplay::Keyboard::KEY_H;
  251. case 0x49:
  252. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_I : gameplay::Keyboard::KEY_I;
  253. case 0x4A:
  254. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_J : gameplay::Keyboard::KEY_J;
  255. case 0x4B:
  256. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_K : gameplay::Keyboard::KEY_K;
  257. case 0x4C:
  258. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_L : gameplay::Keyboard::KEY_L;
  259. case 0x4D:
  260. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_M : gameplay::Keyboard::KEY_M;
  261. case 0x4E:
  262. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_N : gameplay::Keyboard::KEY_N;
  263. case 0x4F:
  264. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_O : gameplay::Keyboard::KEY_O;
  265. case 0x50:
  266. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_P : gameplay::Keyboard::KEY_P;
  267. case 0x51:
  268. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_Q : gameplay::Keyboard::KEY_Q;
  269. case 0x52:
  270. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_R : gameplay::Keyboard::KEY_R;
  271. case 0x53:
  272. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_S : gameplay::Keyboard::KEY_S;
  273. case 0x54:
  274. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_T : gameplay::Keyboard::KEY_T;
  275. case 0x55:
  276. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_U : gameplay::Keyboard::KEY_U;
  277. case 0x56:
  278. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_V : gameplay::Keyboard::KEY_V;
  279. case 0x57:
  280. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_W : gameplay::Keyboard::KEY_W;
  281. case 0x58:
  282. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_X : gameplay::Keyboard::KEY_X;
  283. case 0x59:
  284. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_Y : gameplay::Keyboard::KEY_Y;
  285. case 0x5A:
  286. return shiftDown ? gameplay::Keyboard::KEY_CAPITAL_Z : gameplay::Keyboard::KEY_Z;
  287. default:
  288. return gameplay::Keyboard::KEY_NONE;
  289. }
  290. }
  291. static void UpdateCapture(LPARAM lParam)
  292. {
  293. if ((lParam & MK_LBUTTON) || (lParam & MK_MBUTTON) || (lParam & MK_RBUTTON))
  294. SetCapture(__hwnd);
  295. else
  296. ReleaseCapture();
  297. }
  298. static void WarpMouse(int clientX, int clientY)
  299. {
  300. POINT p = { clientX, clientY };
  301. ClientToScreen(__hwnd, &p);
  302. SetCursorPos(p.x, p.y);
  303. }
  304. /**
  305. * Gets the width and height of the screen in pixels.
  306. */
  307. static void getDesktopResolution(int& width, int& height)
  308. {
  309. RECT desktop;
  310. const HWND hDesktop = GetDesktopWindow();
  311. // Get the size of screen to the variable desktop
  312. GetWindowRect(hDesktop, &desktop);
  313. width = desktop.right;
  314. height = desktop.bottom;
  315. }
  316. LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  317. {
  318. static gameplay::Game* game = gameplay::Game::getInstance();
  319. if (!game->isInitialized() || hwnd != __hwnd)
  320. {
  321. // Ignore messages that are not for our game window.
  322. return DefWindowProc(hwnd, msg, wParam, lParam);
  323. }
  324. static bool shiftDown = false;
  325. static bool capsOn = false;
  326. switch (msg)
  327. {
  328. case WM_CLOSE:
  329. DestroyWindow(__hwnd);
  330. return 0;
  331. case WM_DESTROY:
  332. gameplay::Platform::shutdownInternal();
  333. PostQuitMessage(0);
  334. return 0;
  335. case WM_LBUTTONDOWN:
  336. {
  337. int x = GET_X_LPARAM(lParam);
  338. int y = GET_Y_LPARAM(lParam);
  339. UpdateCapture(wParam);
  340. if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON, x, y, 0))
  341. {
  342. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, x, y, 0, true);
  343. }
  344. return 0;
  345. }
  346. case WM_LBUTTONUP:
  347. {
  348. int x = GET_X_LPARAM(lParam);
  349. int y = GET_Y_LPARAM(lParam);
  350. if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON, x, y, 0))
  351. {
  352. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, x, y, 0, true);
  353. }
  354. UpdateCapture(wParam);
  355. return 0;
  356. }
  357. case WM_RBUTTONDOWN:
  358. UpdateCapture(wParam);
  359. gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_PRESS_RIGHT_BUTTON, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0);
  360. break;
  361. case WM_RBUTTONUP:
  362. gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_RELEASE_RIGHT_BUTTON, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0);
  363. UpdateCapture(wParam);
  364. break;
  365. case WM_MBUTTONDOWN:
  366. UpdateCapture(wParam);
  367. gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_PRESS_MIDDLE_BUTTON, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0);
  368. break;
  369. case WM_MBUTTONUP:
  370. gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0);
  371. UpdateCapture(wParam);
  372. break;
  373. case WM_MOUSEMOVE:
  374. {
  375. int x = GET_X_LPARAM(lParam);
  376. int y = GET_Y_LPARAM(lParam);
  377. if (__mouseCaptured)
  378. {
  379. // If the incoming position is the mouse capture point, ignore this event
  380. // since this is the event that warped the cursor back.
  381. if (x == __mouseCapturePoint.x && y == __mouseCapturePoint.y)
  382. break;
  383. // Convert to deltas
  384. x -= __mouseCapturePoint.x;
  385. y -= __mouseCapturePoint.y;
  386. // Warp mouse back to center of screen.
  387. WarpMouse(__mouseCapturePoint.x, __mouseCapturePoint.y);
  388. }
  389. // Allow Game::mouseEvent a chance to handle (and possibly consume) the event.
  390. if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_MOVE, x, y, 0))
  391. {
  392. if ((wParam & MK_LBUTTON) == MK_LBUTTON)
  393. {
  394. // Mouse move events should be interpreted as touch move only if left mouse is held and the game did not consume the mouse event.
  395. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_MOVE, x, y, 0, true);
  396. return 0;
  397. }
  398. }
  399. break;
  400. }
  401. case WM_MOUSEWHEEL:
  402. tagPOINT point;
  403. point.x = GET_X_LPARAM(lParam);
  404. point.y = GET_Y_LPARAM(lParam);
  405. ScreenToClient(__hwnd, &point);
  406. gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_WHEEL, point.x, point.y, GET_WHEEL_DELTA_WPARAM(wParam) / 120);
  407. break;
  408. case WM_KEYDOWN:
  409. if (wParam == VK_SHIFT || wParam == VK_LSHIFT || wParam == VK_RSHIFT)
  410. shiftDown = true;
  411. if (wParam == VK_CAPITAL)
  412. capsOn = !capsOn;
  413. // Suppress key repeats.
  414. if ((lParam & 0x40000000) == 0)
  415. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, getKey(wParam, shiftDown ^ capsOn));
  416. break;
  417. case WM_KEYUP:
  418. if (wParam == VK_SHIFT || wParam == VK_LSHIFT || wParam == VK_RSHIFT)
  419. shiftDown = false;
  420. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_RELEASE, getKey(wParam, shiftDown ^ capsOn));
  421. break;
  422. case WM_CHAR:
  423. // Suppress key repeats.
  424. if ((lParam & 0x40000000) == 0)
  425. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
  426. break;
  427. case WM_UNICHAR:
  428. // Suppress key repeats.
  429. if ((lParam & 0x40000000) == 0)
  430. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
  431. break;
  432. case WM_SETFOCUS:
  433. break;
  434. case WM_KILLFOCUS:
  435. break;
  436. case WM_SIZE:
  437. // Window was resized.
  438. gameplay::Platform::resizeEventInternal((unsigned int)(short)LOWORD(lParam), (unsigned int)(short)HIWORD(lParam));
  439. break;
  440. }
  441. return DefWindowProc(hwnd, msg, wParam, lParam);
  442. }
  443. namespace gameplay
  444. {
  445. struct WindowCreationParams
  446. {
  447. RECT rect;
  448. std::wstring windowName;
  449. bool fullscreen;
  450. bool resizable;
  451. int samples;
  452. };
  453. extern void print(const char* format, ...)
  454. {
  455. va_list argptr;
  456. va_start(argptr, format);
  457. int sz = vfprintf(stderr, format, argptr);
  458. if (sz > 0)
  459. {
  460. char* buf = new char[sz + 1];
  461. vsprintf(buf, format, argptr);
  462. buf[sz] = 0;
  463. OutputDebugStringA(buf);
  464. SAFE_DELETE_ARRAY(buf);
  465. }
  466. va_end(argptr);
  467. }
  468. Platform::Platform(Game* game)
  469. : _game(game)
  470. {
  471. }
  472. Platform::~Platform()
  473. {
  474. if (__hwnd)
  475. {
  476. DestroyWindow(__hwnd);
  477. __hwnd = 0;
  478. }
  479. }
  480. bool createWindow(WindowCreationParams* params, HWND* hwnd, HDC* hdc)
  481. {
  482. bool fullscreen = false;
  483. bool resizable = false;
  484. RECT rect = { CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT };
  485. std::wstring windowName;
  486. if (params)
  487. {
  488. windowName = params->windowName;
  489. memcpy(&rect, &params->rect, sizeof(RECT));
  490. fullscreen = params->fullscreen;
  491. resizable = params->resizable;
  492. }
  493. // Set the window style.
  494. DWORD style, styleEx;
  495. if (fullscreen)
  496. {
  497. style = WS_POPUP;
  498. styleEx = WS_EX_APPWINDOW;
  499. }
  500. else
  501. {
  502. if (resizable)
  503. style = WS_OVERLAPPEDWINDOW;
  504. else
  505. style = WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU;
  506. styleEx = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  507. }
  508. style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  509. // Adjust the window rectangle so the client size is the requested size.
  510. AdjustWindowRectEx(&rect, style, FALSE, styleEx);
  511. // Create the native Windows window.
  512. *hwnd = CreateWindowEx(styleEx, L"gameplay", windowName.c_str(), style, 0, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, __hinstance, NULL);
  513. if (*hwnd == NULL)
  514. {
  515. GP_ERROR("Failed to create window.");
  516. return false;
  517. }
  518. // Get the drawing context.
  519. *hdc = GetDC(*hwnd);
  520. if (*hdc == NULL)
  521. {
  522. GP_ERROR("Failed to get device context.");
  523. return false;
  524. }
  525. // Center the window
  526. GetWindowRect(*hwnd, &rect);
  527. const int screenX = (GetSystemMetrics(SM_CXSCREEN) - rect.right) / 2;
  528. const int screenY = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) / 2;
  529. SetWindowPos(*hwnd, *hwnd, screenX, screenY, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  530. return true;
  531. }
  532. bool initializeGL(WindowCreationParams* params)
  533. {
  534. // Create a temporary window and context to we can initialize GLEW and get access
  535. // to additional OpenGL extension functions. This is a neccessary evil since the
  536. // function for querying GL extensions is a GL extension itself.
  537. HWND hwnd = NULL;
  538. HDC hdc = NULL;
  539. if (params)
  540. {
  541. if (!createWindow(params, &hwnd, &hdc))
  542. return false;
  543. }
  544. else
  545. {
  546. hwnd = __hwnd;
  547. hdc = __hdc;
  548. }
  549. PIXELFORMATDESCRIPTOR pfd;
  550. memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
  551. pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  552. pfd.nVersion = 1;
  553. pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
  554. pfd.iPixelType = PFD_TYPE_RGBA;
  555. pfd.cColorBits = DEFAULT_COLOR_BUFFER_SIZE;
  556. pfd.cDepthBits = DEFAULT_DEPTH_BUFFER_SIZE;
  557. pfd.cStencilBits = DEFAULT_STENCIL_BUFFER_SIZE;
  558. pfd.iLayerType = PFD_MAIN_PLANE;
  559. int pixelFormat = ChoosePixelFormat(hdc, &pfd);
  560. if (pixelFormat == 0)
  561. {
  562. DestroyWindow(hwnd);
  563. GP_ERROR("Failed to choose a pixel format.");
  564. return false;
  565. }
  566. if (!SetPixelFormat(hdc, pixelFormat, &pfd))
  567. {
  568. DestroyWindow(hwnd);
  569. GP_ERROR("Failed to set the pixel format.");
  570. return false;
  571. }
  572. HGLRC tempContext = wglCreateContext(hdc);
  573. if (!tempContext)
  574. {
  575. DestroyWindow(hwnd);
  576. GP_ERROR("Failed to create temporary context for initialization.");
  577. return false;
  578. }
  579. wglMakeCurrent(hdc, tempContext);
  580. // Initialize GLEW
  581. if (GLEW_OK != glewInit())
  582. {
  583. wglDeleteContext(tempContext);
  584. DestroyWindow(hwnd);
  585. GP_ERROR("Failed to initialize GLEW.");
  586. return false;
  587. }
  588. if( wglChoosePixelFormatARB && wglCreateContextAttribsARB )
  589. {
  590. // Choose pixel format using wglChoosePixelFormatARB, which allows us to specify
  591. // additional attributes such as multisampling.
  592. //
  593. // Note: Keep multisampling attributes at the start of the attribute lists since code below
  594. // assumes they are array elements 0 through 3.
  595. int attribList[] = {
  596. WGL_SAMPLES_ARB, params ? params->samples : 0,
  597. WGL_SAMPLE_BUFFERS_ARB, params ? (params->samples > 0 ? 1 : 0) : 0,
  598. WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
  599. WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
  600. WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
  601. WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
  602. WGL_COLOR_BITS_ARB, DEFAULT_COLOR_BUFFER_SIZE,
  603. WGL_DEPTH_BITS_ARB, DEFAULT_DEPTH_BUFFER_SIZE,
  604. WGL_STENCIL_BITS_ARB, DEFAULT_STENCIL_BUFFER_SIZE,
  605. 0
  606. };
  607. __multiSampling = params && params->samples > 0;
  608. UINT numFormats;
  609. if ( !wglChoosePixelFormatARB(hdc, attribList, NULL, 1, &pixelFormat, &numFormats) || numFormats == 0)
  610. {
  611. bool valid = false;
  612. if (params && params->samples > 0)
  613. {
  614. GP_WARN("Failed to choose pixel format with WGL_SAMPLES_ARB == %d. Attempting to fallback to lower samples setting.", params->samples);
  615. while (params->samples > 0)
  616. {
  617. params->samples /= 2;
  618. attribList[1] = params->samples;
  619. attribList[3] = params->samples > 0 ? 1 : 0;
  620. if (wglChoosePixelFormatARB(hdc, attribList, NULL, 1, &pixelFormat, &numFormats) && numFormats > 0)
  621. {
  622. valid = true;
  623. GP_WARN("Found pixel format with WGL_SAMPLES_ARB == %d.", params->samples);
  624. break;
  625. }
  626. }
  627. __multiSampling = params->samples > 0;
  628. }
  629. if (!valid)
  630. {
  631. wglDeleteContext(tempContext);
  632. DestroyWindow(hwnd);
  633. GP_ERROR("Failed to choose a pixel format.");
  634. return false;
  635. }
  636. }
  637. // Create new/final window if needed
  638. if (params)
  639. {
  640. DestroyWindow(hwnd);
  641. hwnd = NULL;
  642. hdc = NULL;
  643. if (!createWindow(params, &__hwnd, &__hdc))
  644. {
  645. wglDeleteContext(tempContext);
  646. return false;
  647. }
  648. }
  649. // Set final pixel format for window
  650. if (!SetPixelFormat(__hdc, pixelFormat, &pfd))
  651. {
  652. GP_ERROR("Failed to set the pixel format: %d.", (int)GetLastError());
  653. return false;
  654. }
  655. // Create our new GL context
  656. int attribs[] =
  657. {
  658. WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
  659. WGL_CONTEXT_MINOR_VERSION_ARB, 1,
  660. 0
  661. };
  662. if (!(__hrc = wglCreateContextAttribsARB(__hdc, 0, attribs) ) )
  663. {
  664. wglDeleteContext(tempContext);
  665. GP_ERROR("Failed to create OpenGL context.");
  666. return false;
  667. }
  668. // Delete the old/temporary context and window
  669. wglDeleteContext(tempContext);
  670. // Make the new context current
  671. if (!wglMakeCurrent(__hdc, __hrc) || !__hrc)
  672. {
  673. GP_ERROR("Failed to make the window current.");
  674. return false;
  675. }
  676. } else // fallback to OpenGL 2.0 if wglChoosePixelFormatARB or wglCreateContextAttribsARB is NULL.
  677. {
  678. // Context is already here, just use it.
  679. __hrc = tempContext;
  680. __hwnd = hwnd;
  681. __hdc = hdc;
  682. }
  683. // Vertical sync.
  684. wglSwapIntervalEXT(__vsync ? 1 : 0);
  685. // Some old graphics cards support EXT_framebuffer_object instead of ARB_framebuffer_object.
  686. // Patch ARB_framebuffer_object functions to EXT_framebuffer_object ones since semantic is same.
  687. if( !GLEW_ARB_framebuffer_object && GLEW_EXT_framebuffer_object )
  688. {
  689. glBindFramebuffer = glBindFramebufferEXT;
  690. glBindRenderbuffer = glBindRenderbufferEXT;
  691. glBlitFramebuffer = glBlitFramebufferEXT;
  692. glCheckFramebufferStatus = glCheckFramebufferStatusEXT;
  693. glDeleteFramebuffers = glDeleteFramebuffersEXT;
  694. glDeleteRenderbuffers = glDeleteRenderbuffersEXT;
  695. glFramebufferRenderbuffer = glFramebufferRenderbufferEXT;
  696. glFramebufferTexture1D = glFramebufferTexture1DEXT;
  697. glFramebufferTexture2D = glFramebufferTexture2DEXT;
  698. glFramebufferTexture3D = glFramebufferTexture3DEXT;
  699. glFramebufferTextureLayer = glFramebufferTextureLayerEXT;
  700. glGenFramebuffers = glGenFramebuffersEXT;
  701. glGenRenderbuffers = glGenRenderbuffersEXT;
  702. glGenerateMipmap = glGenerateMipmapEXT;
  703. glGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameterivEXT;
  704. glGetRenderbufferParameteriv = glGetRenderbufferParameterivEXT;
  705. glIsFramebuffer = glIsFramebufferEXT;
  706. glIsRenderbuffer = glIsRenderbufferEXT;
  707. glRenderbufferStorage = glRenderbufferStorageEXT;
  708. glRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT;
  709. }
  710. return true;
  711. }
  712. Platform* Platform::create(Game* game)
  713. {
  714. GP_ASSERT(game);
  715. FileSystem::setResourcePath("./");
  716. Platform* platform = new Platform(game);
  717. // Get the application module handle.
  718. __hinstance = ::GetModuleHandle(NULL);
  719. // Read window settings from config.
  720. WindowCreationParams params;
  721. params.fullscreen = false;
  722. params.resizable = false;
  723. params.rect.left = 0;
  724. params.rect.top = 0;
  725. params.rect.right = 0;
  726. params.rect.bottom = 0;
  727. params.samples = 0;
  728. if (game->getConfig())
  729. {
  730. Properties* config = game->getConfig()->getNamespace("window", true);
  731. if (config)
  732. {
  733. // Read window title.
  734. const char* title = config->getString("title");
  735. if (title)
  736. {
  737. int len = MultiByteToWideChar(CP_ACP, 0, title, -1, NULL, 0);
  738. wchar_t* wtitle = new wchar_t[len];
  739. MultiByteToWideChar(CP_ACP, 0, title, -1, wtitle, len);
  740. params.windowName = wtitle;
  741. SAFE_DELETE_ARRAY(wtitle);
  742. }
  743. // Read fullscreen state.
  744. params.fullscreen = config->getBool("fullscreen");
  745. // Read resizable state.
  746. params.resizable = config->getBool("resizable");
  747. // Read multisampling state.
  748. params.samples = config->getInt("samples");
  749. // Read window rect.
  750. int x = config->getInt("x");
  751. if (x != 0)
  752. params.rect.left = x;
  753. int y = config->getInt("y");
  754. if (y != 0)
  755. params.rect.top = y;
  756. int width = config->getInt("width");
  757. int height = config->getInt("height");
  758. if (width == 0 && height == 0 && params.fullscreen)
  759. getDesktopResolution(width, height);
  760. if (width != 0)
  761. params.rect.right = params.rect.left + width;
  762. if (height != 0)
  763. params.rect.bottom = params.rect.top + height;
  764. }
  765. }
  766. // If window size was not specified, set it to a default value
  767. if (params.rect.right == 0)
  768. params.rect.right = params.rect.left + DEFAULT_RESOLUTION_X;
  769. if (params.rect.bottom == 0)
  770. params.rect.bottom = params.rect.top + DEFAULT_RESOLUTION_Y;
  771. int width = params.rect.right - params.rect.left;
  772. int height = params.rect.bottom - params.rect.top;
  773. if (params.fullscreen)
  774. {
  775. // Enumerate all supposed display settings
  776. bool modeSupported = false;
  777. DWORD modeNum = 0;
  778. DEVMODE devMode;
  779. memset(&devMode, 0, sizeof(DEVMODE));
  780. devMode.dmSize = sizeof(DEVMODE);
  781. devMode.dmDriverExtra = 0;
  782. while (EnumDisplaySettings(NULL, modeNum++, &devMode) != 0)
  783. {
  784. // Is mode supported?
  785. if (devMode.dmPelsWidth == width &&
  786. devMode.dmPelsHeight == height &&
  787. devMode.dmBitsPerPel == DEFAULT_COLOR_BUFFER_SIZE)
  788. {
  789. modeSupported = true;
  790. break;
  791. }
  792. }
  793. // If the requested mode is not supported, fall back to a safe default
  794. if (!modeSupported)
  795. {
  796. width = DEFAULT_RESOLUTION_X;
  797. height = DEFAULT_RESOLUTION_Y;
  798. params.rect.right = params.rect.left + width;
  799. params.rect.bottom = params.rect.top + height;
  800. }
  801. }
  802. // Register our window class.
  803. WNDCLASSEX wc;
  804. wc.cbSize = sizeof(WNDCLASSEX);
  805. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  806. wc.lpfnWndProc = (WNDPROC)__WndProc;
  807. wc.cbClsExtra = 0;
  808. wc.cbWndExtra = 0;
  809. wc.hInstance = __hinstance;
  810. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  811. wc.hIconSm = NULL;
  812. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  813. wc.hbrBackground = NULL; // No brush - we are going to paint our own background
  814. wc.lpszMenuName = NULL; // No default menu
  815. wc.lpszClassName = L"gameplay";
  816. if (!::RegisterClassEx(&wc))
  817. {
  818. GP_ERROR("Failed to register window class.");
  819. goto error;
  820. }
  821. if (params.fullscreen)
  822. {
  823. DEVMODE dm;
  824. memset(&dm, 0, sizeof(dm));
  825. dm.dmSize= sizeof(dm);
  826. dm.dmPelsWidth = width;
  827. dm.dmPelsHeight = height;
  828. dm.dmBitsPerPel = DEFAULT_COLOR_BUFFER_SIZE;
  829. dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  830. // Try to set selected mode and get results. NOTE: CDS_FULLSCREEN gets rid of start bar.
  831. if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
  832. {
  833. params.fullscreen = false;
  834. GP_ERROR("Failed to start game in full-screen mode with resolution %dx%d.", width, height);
  835. goto error;
  836. }
  837. }
  838. if (!initializeGL(&params))
  839. goto error;
  840. // Show the window.
  841. ShowWindow(__hwnd, SW_SHOW);
  842. #ifdef GP_USE_GAMEPAD
  843. // Initialize XInputGamepads.
  844. for (DWORD i = 0; i < XUSER_MAX_COUNT; i++)
  845. {
  846. if (XInputGetState(i, &__xInputState) == NO_ERROR)
  847. {
  848. if (!__connectedXInput[i])
  849. {
  850. // Gamepad is connected.
  851. Platform::gamepadEventConnectedInternal(i, XINPUT_BUTTON_COUNT, XINPUT_JOYSTICK_COUNT, XINPUT_TRIGGER_COUNT, 0, 0, "Microsoft", "XBox360 Controller");
  852. __connectedXInput[i] = true;
  853. }
  854. }
  855. }
  856. #endif
  857. return platform;
  858. error:
  859. exit(0);
  860. return NULL;
  861. }
  862. int Platform::enterMessagePump()
  863. {
  864. GP_ASSERT(_game);
  865. // Get the initial time.
  866. LARGE_INTEGER tps;
  867. QueryPerformanceFrequency(&tps);
  868. __timeTicksPerMillis = (double)(tps.QuadPart / 1000L);
  869. LARGE_INTEGER queryTime;
  870. QueryPerformanceCounter(&queryTime);
  871. GP_ASSERT(__timeTicksPerMillis);
  872. __timeStart = queryTime.QuadPart / __timeTicksPerMillis;
  873. SwapBuffers(__hdc);
  874. if (_game->getState() != Game::RUNNING)
  875. _game->run();
  876. // Enter event dispatch loop.
  877. MSG msg;
  878. while (true)
  879. {
  880. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  881. {
  882. TranslateMessage(&msg);
  883. DispatchMessage(&msg);
  884. if (msg.message == WM_QUIT)
  885. {
  886. gameplay::Platform::shutdownInternal();
  887. return msg.wParam;
  888. }
  889. }
  890. else
  891. {
  892. #ifdef GP_USE_GAMEPAD
  893. // Check for connected XInput gamepads.
  894. for (DWORD i = 0; i < XUSER_MAX_COUNT; i++)
  895. {
  896. if (XInputGetState(i, &__xInputState) == NO_ERROR && !__connectedXInput[i])
  897. {
  898. // Gamepad was just connected.
  899. Platform::gamepadEventConnectedInternal(i, XINPUT_BUTTON_COUNT, XINPUT_JOYSTICK_COUNT, XINPUT_TRIGGER_COUNT, 0, 0, "Microsoft", "XBox360 Controller");
  900. __connectedXInput[i] = true;
  901. }
  902. else if (XInputGetState(i, &__xInputState) != NO_ERROR && __connectedXInput[i])
  903. {
  904. // Gamepad was just disconnected.
  905. __connectedXInput[i] = false;
  906. Platform::gamepadEventDisconnectedInternal(i);
  907. }
  908. }
  909. #endif
  910. _game->frame();
  911. SwapBuffers(__hdc);
  912. }
  913. // If we are done, then exit.
  914. if (_game->getState() == Game::UNINITIALIZED)
  915. break;
  916. }
  917. return 0;
  918. }
  919. void Platform::signalShutdown()
  920. {
  921. // nothing to do
  922. }
  923. bool Platform::canExit()
  924. {
  925. return true;
  926. }
  927. unsigned int Platform::getDisplayWidth()
  928. {
  929. static RECT rect;
  930. GetClientRect(__hwnd, &rect);
  931. return rect.right;
  932. }
  933. unsigned int Platform::getDisplayHeight()
  934. {
  935. static RECT rect;
  936. GetClientRect(__hwnd, &rect);
  937. return rect.bottom;
  938. }
  939. double Platform::getAbsoluteTime()
  940. {
  941. LARGE_INTEGER queryTime;
  942. QueryPerformanceCounter(&queryTime);
  943. GP_ASSERT(__timeTicksPerMillis);
  944. __timeAbsolute = queryTime.QuadPart / __timeTicksPerMillis;
  945. return __timeAbsolute - __timeStart;
  946. }
  947. void Platform::setAbsoluteTime(double time)
  948. {
  949. __timeAbsolute = time;
  950. }
  951. bool Platform::isVsync()
  952. {
  953. return __vsync;
  954. }
  955. void Platform::setVsync(bool enable)
  956. {
  957. wglSwapIntervalEXT(enable ? 1 : 0);
  958. __vsync = enable;
  959. }
  960. void Platform::swapBuffers()
  961. {
  962. if (__hdc)
  963. SwapBuffers(__hdc);
  964. }
  965. void Platform::sleep(long ms)
  966. {
  967. Sleep(ms);
  968. }
  969. void Platform::setMultiSampling(bool enabled)
  970. {
  971. if (enabled == __multiSampling)
  972. {
  973. return;
  974. }
  975. if (enabled)
  976. {
  977. glEnable(GL_MULTISAMPLE);
  978. }
  979. else
  980. {
  981. glDisable(GL_MULTISAMPLE);
  982. }
  983. __multiSampling = enabled;
  984. }
  985. bool Platform::isMultiSampling()
  986. {
  987. return __multiSampling;
  988. }
  989. void Platform::setMultiTouch(bool enabled)
  990. {
  991. // not supported
  992. }
  993. bool Platform::isMultiTouch()
  994. {
  995. return false;
  996. }
  997. bool Platform::hasAccelerometer()
  998. {
  999. return false;
  1000. }
  1001. void Platform::getAccelerometerValues(float* pitch, float* roll)
  1002. {
  1003. GP_ASSERT(pitch);
  1004. GP_ASSERT(roll);
  1005. *pitch = 0;
  1006. *roll = 0;
  1007. }
  1008. void Platform::getSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
  1009. {
  1010. if (accelX)
  1011. {
  1012. *accelX = 0;
  1013. }
  1014. if (accelY)
  1015. {
  1016. *accelY = 0;
  1017. }
  1018. if (accelZ)
  1019. {
  1020. *accelZ = 0;
  1021. }
  1022. if (gyroX)
  1023. {
  1024. *gyroX = 0;
  1025. }
  1026. if (gyroY)
  1027. {
  1028. *gyroY = 0;
  1029. }
  1030. if (gyroZ)
  1031. {
  1032. *gyroZ = 0;
  1033. }
  1034. }
  1035. void Platform::getArguments(int* argc, char*** argv)
  1036. {
  1037. if (argc)
  1038. *argc = __argc;
  1039. if (argv)
  1040. *argv = __argv;
  1041. }
  1042. bool Platform::hasMouse()
  1043. {
  1044. return true;
  1045. }
  1046. void Platform::setMouseCaptured(bool captured)
  1047. {
  1048. if (captured != __mouseCaptured)
  1049. {
  1050. if (captured)
  1051. {
  1052. // Hide the cursor and warp it to the center of the screen
  1053. __mouseCapturePoint.x = getDisplayWidth() / 2;
  1054. __mouseCapturePoint.y = getDisplayHeight() / 2;
  1055. ShowCursor(FALSE);
  1056. WarpMouse(__mouseCapturePoint.x, __mouseCapturePoint.y);
  1057. }
  1058. else
  1059. {
  1060. // Restore cursor
  1061. WarpMouse(__mouseCapturePoint.x, __mouseCapturePoint.y);
  1062. ShowCursor(TRUE);
  1063. }
  1064. __mouseCaptured = captured;
  1065. }
  1066. }
  1067. bool Platform::isMouseCaptured()
  1068. {
  1069. return __mouseCaptured;
  1070. }
  1071. void Platform::setCursorVisible(bool visible)
  1072. {
  1073. if (visible != __cursorVisible)
  1074. {
  1075. ShowCursor(visible ? TRUE : FALSE);
  1076. __cursorVisible = visible;
  1077. }
  1078. }
  1079. bool Platform::isCursorVisible()
  1080. {
  1081. return __cursorVisible;
  1082. }
  1083. void Platform::displayKeyboard(bool display)
  1084. {
  1085. // Do nothing.
  1086. }
  1087. bool Platform::isGestureSupported(Gesture::GestureEvent evt)
  1088. {
  1089. return false;
  1090. }
  1091. void Platform::registerGesture(Gesture::GestureEvent evt)
  1092. {
  1093. }
  1094. void Platform::unregisterGesture(Gesture::GestureEvent evt)
  1095. {
  1096. }
  1097. bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
  1098. {
  1099. return false;
  1100. }
  1101. #ifdef GP_USE_GAMEPAD
  1102. void Platform::pollGamepadState(Gamepad* gamepad)
  1103. {
  1104. GP_ASSERT(gamepad->_handle < XUSER_MAX_COUNT);
  1105. if (XInputGetState(gamepad->_handle, &__xInputState) == NO_ERROR)
  1106. {
  1107. WORD buttons = __xInputState.Gamepad.wButtons;
  1108. // Map XInput buttons to Gamepad::ButtonMappings enum.
  1109. static const unsigned int xInputMapping[16] = {
  1110. Gamepad::BUTTON_UP, // 0x0001
  1111. Gamepad::BUTTON_DOWN, // 0x0002
  1112. Gamepad::BUTTON_LEFT, // 0x0004
  1113. Gamepad::BUTTON_RIGHT, // 0x0008
  1114. Gamepad::BUTTON_MENU2, // 0x0010
  1115. Gamepad::BUTTON_MENU1, // 0x0020
  1116. Gamepad::BUTTON_L3, // 0x0040
  1117. Gamepad::BUTTON_R3, // 0x0080
  1118. Gamepad::BUTTON_L1, // 0x0100
  1119. Gamepad::BUTTON_R1, // 0x0200
  1120. 0,
  1121. 0,
  1122. Gamepad::BUTTON_A, // 0x1000
  1123. Gamepad::BUTTON_B, // 0x2000
  1124. Gamepad::BUTTON_X, // 0x4000
  1125. Gamepad::BUTTON_Y // 0x8000
  1126. };
  1127. const unsigned int *mapping = xInputMapping;
  1128. unsigned int mappedButtons;
  1129. for (mappedButtons = 0; buttons; buttons >>= 1, mapping++)
  1130. {
  1131. if (buttons & 1)
  1132. {
  1133. mappedButtons |= (1 << *mapping);
  1134. }
  1135. }
  1136. gamepad->setButtons(mappedButtons);
  1137. unsigned int i;
  1138. for (i = 0; i < gamepad->_joystickCount; ++i)
  1139. {
  1140. GP_ASSERT(i < 2);
  1141. float x;
  1142. float y;
  1143. switch (i)
  1144. {
  1145. case 0:
  1146. x = normalizeXInputJoystickAxis(__xInputState.Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
  1147. y = normalizeXInputJoystickAxis(__xInputState.Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
  1148. break;
  1149. case 1:
  1150. x = normalizeXInputJoystickAxis(__xInputState.Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
  1151. y = normalizeXInputJoystickAxis(__xInputState.Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
  1152. break;
  1153. }
  1154. gamepad->setJoystickValue(i, x, y);
  1155. }
  1156. for (i = 0; i < gamepad->_triggerCount; ++i)
  1157. {
  1158. GP_ASSERT(i < 2);
  1159. BYTE trigger;
  1160. switch (i)
  1161. {
  1162. case 0:
  1163. trigger = __xInputState.Gamepad.bLeftTrigger;
  1164. break;
  1165. case 1:
  1166. trigger = __xInputState.Gamepad.bRightTrigger;
  1167. break;
  1168. }
  1169. if (trigger < XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
  1170. {
  1171. gamepad->setTriggerValue(i, 0.0f);
  1172. }
  1173. else
  1174. {
  1175. gamepad->setTriggerValue(i, (float)trigger / 255.0f);
  1176. }
  1177. }
  1178. }
  1179. }
  1180. #else
  1181. void Platform::pollGamepadState(Gamepad* gamepad) { }
  1182. #endif
  1183. void Platform::shutdownInternal()
  1184. {
  1185. Game::getInstance()->shutdown();
  1186. }
  1187. bool Platform::launchURL(const char* url)
  1188. {
  1189. if (url == NULL || *url == '\0')
  1190. return false;
  1191. // Success when result code > 32
  1192. int len = MultiByteToWideChar(CP_ACP, 0, url, -1, NULL, 0);
  1193. wchar_t* wurl = new wchar_t[len];
  1194. MultiByteToWideChar(CP_ACP, 0, url, -1, wurl, len);
  1195. int r = (int)ShellExecute(NULL, NULL, wurl, NULL, NULL, SW_SHOWNORMAL);
  1196. SAFE_DELETE_ARRAY(wurl);
  1197. return (r > 32);
  1198. }
  1199. }
  1200. #endif