winWindow.cc 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platformWin32/platformWin32.h"
  23. #include "platform/platform.h"
  24. #include "platformWin32/winWindow.h"
  25. #include "platformWin32/platformGL.h"
  26. #include "platform/platformVideo.h"
  27. #include "platformWin32/winOGLVideo.h"
  28. #include "platform/event.h"
  29. #include "console/console.h"
  30. #include "platformWin32/winConsole.h"
  31. #include "platformWin32/winDirectInput.h"
  32. #include "game/gameInterface.h"
  33. #include "math/mRandom.h"
  34. #include "io/fileStream.h"
  35. #include "game/resource.h"
  36. #include "string/unicode.h"
  37. #include "gui/guiCanvas.h"
  38. #include "platform/menus/popupMenu.h"
  39. #include "debug/profiler.h"
  40. //-------------------------------------- Resource Includes
  41. #include "graphics/gBitmap.h"
  42. #include <sys/stat.h>
  43. extern void createFontInit();
  44. extern void createFontShutdown();
  45. #ifdef UNICODE
  46. static const UTF16 *windowClassName = L"Darkstar Window Class";
  47. static UTF16 windowName[256] = L"Darkstar Window";
  48. #else
  49. static const char *windowClassName = "Darkstar Window Class";
  50. static char windowName[256] = "Darkstar Window";
  51. #endif
  52. static bool gWindowCreated = false;
  53. static bool windowNotActive = false;
  54. static RandomLCG sgPlatRandom;
  55. static bool sgQueueEvents;
  56. // is keyboard input a standard (non-changing) VK keycode
  57. #define dIsStandardVK(c) (((0x08 <= (c)) && ((c) <= 0x12)) || \
  58. ((c) == 0x1b) || \
  59. ((0x20 <= (c)) && ((c) <= 0x2e)) || \
  60. ((0x30 <= (c)) && ((c) <= 0x39)) || \
  61. ((0x41 <= (c)) && ((c) <= 0x5a)) || \
  62. ((0x70 <= (c)) && ((c) <= 0x7B)))
  63. extern U16 DIK_to_Key( U8 dikCode );
  64. Win32PlatState winState;
  65. //-----------------------------------------------------------------------------------------------------------------------------------------------------------
  66. //
  67. // Microsoft Layer for Unicode
  68. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mslu/winprog/compiling_your_application_with_the_microsoft_layer_for_unicode.asp
  69. //
  70. //-----------------------------------------------------------------------------------------------------------------------------------------------------------
  71. #ifdef UNICODE
  72. HMODULE LoadUnicowsProc(void)
  73. {
  74. return(LoadLibraryA("unicows.dll"));
  75. }
  76. #ifdef _cplusplus
  77. extern "C" {
  78. #endif
  79. extern FARPROC _PfnLoadUnicows = (FARPROC) &LoadUnicowsProc;
  80. #ifdef _cplusplus
  81. }
  82. #endif
  83. #endif
  84. //--------------------------------------
  85. Win32PlatState::Win32PlatState()
  86. {
  87. log_fp = NULL;
  88. hinstOpenGL = NULL;
  89. hinstGLU = NULL;
  90. hinstOpenAL = NULL;
  91. appWindow = NULL;
  92. appDC = NULL;
  93. appInstance = NULL;
  94. currentTime = 0;
  95. processId = 0;
  96. appMenu = NULL;
  97. nMessagesPerFrame = 10;
  98. }
  99. static bool windowLocked = false;
  100. static BYTE keyboardState[256];
  101. static bool mouseButtonState[3];
  102. static bool capsLockDown = false;
  103. static S32 modifierKeys = 0;
  104. static bool windowActive = true;
  105. static Point2I lastCursorPos(0,0);
  106. static Point2I windowSize;
  107. static bool sgDoubleByteEnabled = false;
  108. //--------------------------------------
  109. static const char *getMessageName(S32 msg)
  110. {
  111. switch(msg)
  112. {
  113. case WM_KEYDOWN:
  114. return "WM_KEYDOWN";
  115. case WM_KEYUP:
  116. return "WM_KEYUP";
  117. case WM_SYSKEYUP:
  118. return "WM_SYSKEYUP";
  119. case WM_SYSKEYDOWN:
  120. return "WM_SYSKEYDOWN";
  121. default:
  122. return "Unknown!!";
  123. }
  124. }
  125. void Platform::restartInstance()
  126. {
  127. if( Game->isRunning() )
  128. {
  129. //Con::errorf( "Error restarting instance, Game is still running!");
  130. return;
  131. }
  132. STARTUPINFO si;
  133. PROCESS_INFORMATION pi;
  134. ZeroMemory( &si, sizeof(si) );
  135. si.cb = sizeof(si);
  136. ZeroMemory( &pi, sizeof(pi) );
  137. char cen_buf[2048];
  138. GetModuleFileNameA( NULL, cen_buf, 2047);
  139. #ifdef UNICODE
  140. UTF16 b[512];
  141. convertUTF8toUTF16((UTF8 *)cen_buf, b, sizeof(b));
  142. #else
  143. const char* b = cen_buf;
  144. #endif
  145. // Start the child process.
  146. if( CreateProcess( b,
  147. NULL, // Command line
  148. NULL, // Process handle not inheritable
  149. NULL, // Thread handle not inheritable
  150. FALSE, // Set handle inheritance to FALSE
  151. 0, // No creation flags
  152. NULL, // Use parent's environment block
  153. NULL, // Use parent's starting directory
  154. &si, // Pointer to STARTUPINFO structure
  155. &pi ) // Pointer to PROCESS_INFORMATION structure
  156. != false )
  157. {
  158. WaitForInputIdle( pi.hProcess, 5000 );
  159. CloseHandle( pi.hProcess );
  160. CloseHandle( pi.hThread );
  161. }
  162. }
  163. //--------------------------------------
  164. void Platform::AlertOK(const char *windowTitle, const char *message)
  165. {
  166. ShowCursor(true);
  167. #ifdef UNICODE
  168. UTF16 m[1024], t[512];
  169. convertUTF8toUTF16((UTF8 *)windowTitle, t, sizeof(t));
  170. convertUTF8toUTF16((UTF8 *)message, m, sizeof(m));
  171. MessageBox(winState.appWindow, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OK);
  172. #else
  173. MessageBox(winState.appWindow, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OK);
  174. #endif
  175. }
  176. //--------------------------------------
  177. bool Platform::AlertOKCancel(const char *windowTitle, const char *message)
  178. {
  179. ShowCursor(true);
  180. #ifdef UNICODE
  181. UTF16 m[1024], t[512];
  182. convertUTF8toUTF16((UTF8 *)windowTitle, t, sizeof(t));
  183. convertUTF8toUTF16((UTF8 *)message, m, sizeof(m));
  184. return MessageBox(winState.appWindow, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OKCANCEL) == IDOK;
  185. #else
  186. return MessageBox(winState.appWindow, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OKCANCEL) == IDOK;
  187. #endif
  188. }
  189. //--------------------------------------
  190. bool Platform::AlertRetry(const char *windowTitle, const char *message)
  191. {
  192. ShowCursor(true);
  193. #ifdef UNICODE
  194. UTF16 m[1024], t[512];
  195. convertUTF8toUTF16((UTF8 *)windowTitle, t, sizeof(t));
  196. convertUTF8toUTF16((UTF8 *)message, m, sizeof(m));
  197. return (MessageBox(winState.appWindow, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_RETRYCANCEL) == IDRETRY);
  198. #else
  199. return (MessageBox(winState.appWindow, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_RETRYCANCEL) == IDRETRY);
  200. #endif
  201. }
  202. //Luma: YesNo alert message
  203. bool Platform::AlertYesNo(const char *windowTitle, const char *message)
  204. {
  205. ShowCursor(true);
  206. #ifdef UNICODE
  207. UTF16 m[1024], t[512];
  208. convertUTF8toUTF16((UTF8 *)windowTitle, t, sizeof(t));
  209. convertUTF8toUTF16((UTF8 *)message, m, sizeof(m));
  210. return MessageBox(winState.appWindow, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_YESNO) == IDYES;
  211. #else
  212. return MessageBox(winState.appWindow, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_YESNO) == IDYES;
  213. #endif
  214. }
  215. //--------------------------------------
  216. HIMC gIMEContext;
  217. static void InitInput()
  218. {
  219. #ifndef TORQUE_LIB
  220. #ifdef UNICODE
  221. gIMEContext = ImmGetContext(winState.appWindow);
  222. ImmReleaseContext( winState.appWindow, gIMEContext );
  223. #endif
  224. #endif
  225. dMemset( keyboardState, 0, 256 );
  226. dMemset( mouseButtonState, 0, sizeof( mouseButtonState ) );
  227. capsLockDown = (GetKeyState(VK_CAPITAL) & 0x01);
  228. if (capsLockDown)
  229. {
  230. keyboardState[VK_CAPITAL] |= 0x01;
  231. }
  232. }
  233. //--------------------------------------
  234. static void setMouseClipping()
  235. {
  236. ClipCursor(NULL);
  237. if(windowActive)
  238. {
  239. RECT r;
  240. GetWindowRect(winState.appWindow, &r);
  241. if(windowLocked)
  242. {
  243. POINT p;
  244. GetCursorPos(&p);
  245. lastCursorPos.set(p.x - r.left, p.y - r.top);
  246. ClipCursor(&r);
  247. S32 centerX = (r.right + r.left) >> 1;
  248. S32 centerY = (r.bottom + r.top) >> 1;
  249. if(!windowNotActive)
  250. SetCursorPos(centerX, centerY);
  251. }
  252. else
  253. {
  254. if(!windowNotActive && false)
  255. SetCursorPos(lastCursorPos.x + r.left, lastCursorPos.y + r.top);
  256. }
  257. }
  258. }
  259. //--------------------------------------
  260. static bool sgTaskbarHidden = false;
  261. static HWND sgTaskbar = NULL;
  262. static void hideTheTaskbar()
  263. {
  264. // if ( !sgTaskbarHidden )
  265. // {
  266. // sgTaskbar = FindWindow( "Shell_TrayWnd", NULL );
  267. // if ( sgTaskbar )
  268. // {
  269. // APPBARDATA abData;
  270. // dMemset( &abData, 0, sizeof( abData ) );
  271. // abData.cbSize = sizeof( abData );
  272. // abData.hWnd = sgTaskbar;
  273. // SHAppBarMessage( ABM_REMOVE, &abData );
  274. // //ShowWindow( sgTaskbar, SW_HIDE );
  275. // sgTaskbarHidden = true;
  276. // }
  277. // }
  278. }
  279. static void restoreTheTaskbar()
  280. {
  281. // if ( sgTaskbarHidden )
  282. // {
  283. // APPBARDATA abData;
  284. // dMemset( &abData, 0, sizeof( abData ) );
  285. // abData.cbSize = sizeof( abData );
  286. // abData.hWnd = sgTaskbar;
  287. // SHAppBarMessage( ABM_ACTIVATE, &abData );
  288. // //ShowWindow( sgTaskbar, SW_SHOW );
  289. // sgTaskbarHidden = false;
  290. // }
  291. }
  292. //--------------------------------------
  293. void Platform::enableKeyboardTranslation(void)
  294. {
  295. #ifdef UNICODE
  296. // Con::printf("translating...");
  297. ImmAssociateContext( winState.appWindow, winState.imeHandle );
  298. #endif
  299. }
  300. //--------------------------------------
  301. void Platform::disableKeyboardTranslation(void)
  302. {
  303. #ifdef UNICODE
  304. // Con::printf("not translating...");
  305. ImmAssociateContext( winState.appWindow, NULL );
  306. #endif
  307. }
  308. //--------------------------------------
  309. void Platform::setMouseLock(bool locked)
  310. {
  311. windowLocked = locked;
  312. setMouseClipping();
  313. }
  314. //--------------------------------------
  315. void Platform::minimizeWindow()
  316. {
  317. ShowWindow(winState.appWindow, SW_MINIMIZE);
  318. restoreTheTaskbar();
  319. }
  320. void Platform::restoreWindow()
  321. {
  322. ShowWindow(winState.appWindow, SW_RESTORE);
  323. }
  324. //--------------------------------------
  325. static void processKeyMessage(UINT message, WPARAM wParam, LPARAM lParam)
  326. {
  327. S32 repeatCount = lParam & 0xffff;
  328. S32 scanCode = (lParam >> 16) & 0xff;
  329. S32 nVirtkey = dIsStandardVK(wParam) ? TranslateOSKeyCode(wParam) : DIK_to_Key(scanCode);
  330. S32 keyCode;
  331. if ( wParam == VK_PROCESSKEY && sgDoubleByteEnabled )
  332. keyCode = MapVirtualKey( scanCode, 1 ); // This is the REAL virtual key...
  333. else
  334. keyCode = wParam;
  335. bool extended = (lParam >> 24) & 1;
  336. bool repeat = (lParam >> 30) & 1;
  337. bool make = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN);
  338. S32 newVirtKey = nVirtkey;
  339. switch(nVirtkey)
  340. {
  341. case KEY_ALT:
  342. newVirtKey = extended ? KEY_RALT : KEY_LALT;
  343. break;
  344. case KEY_CONTROL:
  345. newVirtKey = extended ? KEY_RCONTROL : KEY_LCONTROL;
  346. break;
  347. case KEY_SHIFT:
  348. newVirtKey = ( scanCode == 54 ) ? KEY_RSHIFT : KEY_LSHIFT;
  349. break;
  350. case KEY_RETURN:
  351. if ( extended )
  352. newVirtKey = KEY_NUMPADENTER;
  353. break;
  354. }
  355. S32 modKey = modifierKeys;
  356. if(make)
  357. {
  358. switch (newVirtKey)
  359. {
  360. case KEY_LSHIFT: modifierKeys |= SI_LSHIFT; modKey = 0; break;
  361. case KEY_RSHIFT: modifierKeys |= SI_RSHIFT; modKey = 0; break;
  362. case KEY_LCONTROL: modifierKeys |= SI_LCTRL; modKey = 0; break;
  363. case KEY_RCONTROL: modifierKeys |= SI_RCTRL; modKey = 0; break;
  364. case KEY_LALT: modifierKeys |= SI_LALT; modKey = 0; break;
  365. case KEY_RALT: modifierKeys |= SI_RALT; modKey = 0; break;
  366. }
  367. if(nVirtkey == KEY_CAPSLOCK)
  368. {
  369. capsLockDown = !capsLockDown;
  370. if(capsLockDown)
  371. keyboardState[keyCode] |= 0x01;
  372. else
  373. keyboardState[keyCode] &= 0xFE;
  374. }
  375. keyboardState[keyCode] |= 0x80;
  376. }
  377. else
  378. {
  379. switch (newVirtKey)
  380. {
  381. case KEY_LSHIFT: modifierKeys &= ~SI_LSHIFT; modKey = 0; break;
  382. case KEY_RSHIFT: modifierKeys &= ~SI_RSHIFT; modKey = 0; break;
  383. case KEY_LCONTROL: modifierKeys &= ~SI_LCTRL; modKey = 0; break;
  384. case KEY_RCONTROL: modifierKeys &= ~SI_RCTRL; modKey = 0; break;
  385. case KEY_LALT: modifierKeys &= ~SI_LALT; modKey = 0; break;
  386. case KEY_RALT: modifierKeys &= ~SI_RALT; modKey = 0; break;
  387. }
  388. keyboardState[keyCode] &= 0x7f;
  389. }
  390. U16 ascii[3];
  391. WORD asciiCode = 0;
  392. dMemset( &ascii, 0, sizeof( ascii ) );
  393. S32 res = ToUnicode( keyCode, scanCode, keyboardState, ascii, 3, 0 );
  394. // This should only happen on Window 9x/ME systems
  395. if (res == 0)
  396. res = ToAscii( keyCode, scanCode, keyboardState, ascii, 0 );
  397. if (res == 2)
  398. {
  399. asciiCode = ascii[1];
  400. }
  401. else if ((res == 1) || (res < 0))
  402. {
  403. asciiCode = ascii[0];
  404. }
  405. InputEvent event;
  406. event.deviceInst = 0;
  407. event.deviceType = KeyboardDeviceType;
  408. event.objType = SI_KEY;
  409. event.objInst = newVirtKey;
  410. event.action = make ? (repeat ? SI_REPEAT : SI_MAKE ) : SI_BREAK;
  411. event.modifier = modKey;
  412. event.ascii = asciiCode;
  413. event.fValues[0] = make ? 1.0f : 0.0f;
  414. // Store the current modifier keys
  415. Input::setModifierKeys(modifierKeys);
  416. Game->postEvent(event);
  417. }
  418. static void processCharMessage( WPARAM wParam, LPARAM lParam )
  419. {
  420. TCHAR charCode = wParam;
  421. UTF16 tmpString[2] = { charCode, 0 };
  422. UTF8 out[256];
  423. convertUTF16toUTF8(tmpString, out, 250);
  424. // Con::printf("Got IME char code %x (%s)", charCode, out);
  425. InputEvent event;
  426. event.deviceInst = 0;
  427. event.deviceType = KeyboardDeviceType;
  428. event.objType = SI_KEY;
  429. event.action = SI_MAKE;
  430. event.ascii = charCode;
  431. // Deal with some silly cases like <BS>. This might be indicative of a
  432. // missing MapVirtualKey step, not quite sure how to deal with this.
  433. if(event.ascii == 0x8)
  434. event.objInst = KEY_BACKSPACE; // Note we abuse objInst.
  435. Game->postEvent(event);
  436. // And put it back up as well, they can't hold it!
  437. event.action = SI_BREAK;
  438. Game->postEvent(event);
  439. }
  440. static S32 mouseX = 0xFFFFFFFF;
  441. static S32 mouseY = 0xFFFFFFFF;
  442. //--------------------------------------
  443. static void CheckCursorPos()
  444. {
  445. if(windowLocked && windowActive)
  446. {
  447. POINT mousePos;
  448. GetCursorPos(&mousePos);
  449. RECT r;
  450. GetWindowRect(winState.appWindow, &r);
  451. S32 centerX = (r.right + r.left) >> 1;
  452. S32 centerY = (r.bottom + r.top) >> 1;
  453. if(mousePos.x != centerX)
  454. {
  455. InputEvent event;
  456. event.deviceInst = 0;
  457. event.deviceType = MouseDeviceType;
  458. event.objType = SI_XAXIS;
  459. event.objInst = 0;
  460. event.action = SI_MOVE;
  461. event.modifier = modifierKeys;
  462. event.ascii = 0;
  463. event.fValues[0] = (F32)(mousePos.x - centerX);
  464. Game->postEvent(event);
  465. }
  466. if(mousePos.y != centerY)
  467. {
  468. InputEvent event;
  469. event.deviceInst = 0;
  470. event.deviceType = MouseDeviceType;
  471. event.objType = SI_YAXIS;
  472. event.objInst = 0;
  473. event.action = SI_MOVE;
  474. event.modifier = modifierKeys;
  475. event.ascii = 0;
  476. event.fValues[0] = (F32)(mousePos.y - centerY);
  477. Game->postEvent(event);
  478. }
  479. SetCursorPos(centerX, centerY);
  480. }
  481. }
  482. //--------------------------------------
  483. static void mouseButtonEvent(S32 action, S32 objInst)
  484. {
  485. CheckCursorPos();
  486. if(!windowLocked)
  487. {
  488. if(action == SI_MAKE)
  489. SetCapture(winState.appWindow);
  490. else
  491. ReleaseCapture();
  492. }
  493. U32 buttonId = objInst - KEY_BUTTON0;
  494. if ( buttonId < 3 )
  495. mouseButtonState[buttonId] = ( action == SI_MAKE ) ? true : false;
  496. InputEvent event;
  497. event.deviceInst = 0;
  498. event.deviceType = MouseDeviceType;
  499. event.objType = SI_BUTTON;
  500. event.objInst = objInst;
  501. event.action = action;
  502. event.modifier = modifierKeys;
  503. event.ascii = 0;
  504. event.fValues[0] = action == SI_MAKE ? 1.0f : 0.0f;
  505. Game->postEvent(event);
  506. }
  507. //--------------------------------------
  508. static void mouseWheelEvent( S32 delta )
  509. {
  510. static S32 _delta = 0;
  511. _delta += delta;
  512. if ( abs( delta ) >= WHEEL_DELTA )
  513. {
  514. _delta = 0;
  515. InputEvent event;
  516. event.deviceInst = 0;
  517. event.deviceType = MouseDeviceType;
  518. event.objType = SI_ZAXIS;
  519. event.objInst = 0;
  520. event.action = SI_MOVE;
  521. event.modifier = modifierKeys;
  522. event.ascii = 0;
  523. event.fValues[0] = (F32)delta;
  524. Game->postEvent( event );
  525. }
  526. }
  527. struct WinMessage
  528. {
  529. UINT message;
  530. WPARAM wParam;
  531. LPARAM lParam;
  532. WinMessage() {};
  533. WinMessage(UINT m, WPARAM w, LPARAM l) : message(m), wParam(w), lParam(l) {}
  534. };
  535. Vector<WinMessage> sgWinMessages;
  536. #ifndef PBT_APMQUERYSUSPEND
  537. #define PBT_APMQUERYSUSPEND 0x0000
  538. #endif
  539. bool sgKeyboardStateDirty = false;
  540. //--------------------------------------
  541. static LRESULT PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  542. {
  543. switch ( message )
  544. {
  545. // Window DragDrop-enabled [12/14/2006 justind]
  546. case WM_CREATE:
  547. DragAcceptFiles(hWnd, TRUE);
  548. break;
  549. case WM_DESTROY:
  550. DragAcceptFiles(hWnd, FALSE);
  551. break;
  552. case WM_DROPFILES:
  553. // Retrieve Number of files
  554. // Strict policy on these things, better safe than sorry
  555. if( !Con::isFunction( "onDropBegin") || !Con::isFunction("onDropFile")
  556. || !Con::isFunction("onDropEnd") )
  557. break;
  558. int nFileCount; // Number of Files
  559. HDROP hTheDrop; // The Drop Handle
  560. hTheDrop = (HDROP)wParam;
  561. nFileCount = DragQueryFile(hTheDrop, 0xFFFFFFFF, NULL, 0);
  562. if( nFileCount == 0 )
  563. break;
  564. // Notify Drop-Begin
  565. Con::executef( 2, "onDropBegin", Con::getIntArg( nFileCount ) );
  566. int nI;
  567. for (nI = 0; nI < nFileCount; nI++)
  568. {
  569. LPTSTR pszTheBuffer[MAX_PATH];
  570. ZeroMemory( pszTheBuffer, MAX_PATH );
  571. // Query it
  572. // FIXME: Deal with Unicode
  573. DragQueryFileA(hTheDrop, nI, (LPSTR)pszTheBuffer, sizeof(pszTheBuffer));
  574. // Notify Drop
  575. if (Platform::isFile( (const char*)pszTheBuffer ))
  576. {
  577. // The timeout for waiting for files (ms).
  578. U32 timeout = 5000;
  579. // Need to make sure the file is copyable. When ganking images from Firefox, it
  580. // isn't necessarily since Firefox insists on redownloading the file instead of
  581. // using the local copy.
  582. U32 time = Platform::getRealMilliseconds() + timeout;
  583. HANDLE hfile;
  584. while((hfile = ::CreateFileA((const char*)pszTheBuffer, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
  585. {
  586. // Don't wait too long.
  587. if(Platform::getRealMilliseconds() > time)
  588. break;
  589. }
  590. if(hfile == INVALID_HANDLE_VALUE)
  591. continue;
  592. CloseHandle(hfile);
  593. Con::executef( 2, "onDropFile", StringTable->insert((const char*)pszTheBuffer) );
  594. }
  595. }
  596. DragFinish(hTheDrop);
  597. // Notify Drop-Begin
  598. Con::executef( 2, "onDropEnd", Con::getIntArg( nFileCount ) );
  599. break;
  600. // Window Min Extents - [9/20/2006 justind]
  601. case WM_GETMINMAXINFO:
  602. MINMAXINFO *winfo;
  603. winfo = (MINMAXINFO*)(lParam);
  604. //MIN_RESOLUTION defined in platformWin32/platformGL.h
  605. winfo->ptMinTrackSize.x = MIN_RESOLUTION_X;
  606. winfo->ptMinTrackSize.y = MIN_RESOLUTION_Y;
  607. break;
  608. case WM_POWERBROADCAST:
  609. {
  610. if(wParam == PBT_APMQUERYSUSPEND)
  611. return BROADCAST_QUERY_DENY;
  612. return true;
  613. }
  614. case WM_ACTIVATEAPP:
  615. if ((bool) wParam)
  616. {
  617. Video::reactivate();
  618. if ( Video::isFullScreen() )
  619. hideTheTaskbar();
  620. // HACK: Windows 98 (after switching from fullscreen to windowed mode)
  621. SetForegroundWindow( winState.appWindow );
  622. // If our keyboard state is dirty, clear it
  623. if( sgKeyboardStateDirty == true )
  624. {
  625. sgKeyboardStateDirty = false;
  626. InitInput();
  627. }
  628. }
  629. else
  630. {
  631. // Window lost focus so set a dirty flag on the keyboard state
  632. if ( lParam == 0 )
  633. sgKeyboardStateDirty = true;
  634. Video::deactivate();
  635. restoreTheTaskbar();
  636. }
  637. break;
  638. case WM_SYSCOMMAND:
  639. switch(wParam)
  640. {
  641. case SC_KEYMENU:
  642. case SC_SCREENSAVE:
  643. case SC_MONITORPOWER:
  644. if(GetForegroundWindow() == winState.appWindow)
  645. {
  646. return 0;
  647. }
  648. break;
  649. // Catch Close button press event [1/5/2007 justind]
  650. case SC_CLOSE:
  651. if (Con::isFunction("onClosePressed"))
  652. {
  653. Con::executef( 1, "onClosePressed" );
  654. return 0;
  655. }
  656. break;
  657. }
  658. break;
  659. case WM_ACTIVATE:
  660. windowActive = LOWORD(wParam) != WA_INACTIVE;
  661. if( Game->isRunning() )
  662. {
  663. if (Con::isFunction("onWindowFocusChange"))
  664. Con::executef( 2, "onWindowFocusChange", windowActive ? "1" : "0" );
  665. }
  666. if ( windowActive )
  667. {
  668. setMouseClipping();
  669. windowNotActive = false;
  670. Game->refreshWindow();
  671. Input::activate();
  672. }
  673. else
  674. {
  675. setMouseClipping();
  676. windowNotActive = true;
  677. DInputManager* mgr = dynamic_cast<DInputManager*>( Input::getManager() );
  678. if ( !mgr || !mgr->isMouseActive() )
  679. {
  680. // Deactivate all the mouse triggers:
  681. for ( U32 i = 0; i < 3; i++ )
  682. {
  683. if ( mouseButtonState[i] )
  684. mouseButtonEvent( SI_BREAK, KEY_BUTTON0 + i );
  685. }
  686. }
  687. Input::deactivate();
  688. }
  689. break;
  690. case WM_MOVE:
  691. Game->refreshWindow();
  692. break;
  693. // This override will keep windows from blacking out the background, wee!
  694. case WM_ERASEBKGND:
  695. return 0;
  696. case WM_SIZE:
  697. if(wParam != SIZE_MINIMIZED) // DAW: If window is minimized, don't do an internal resize or the universe will end
  698. {
  699. S32 nWidth, nHeight;
  700. nWidth = LOWORD(lParam);
  701. nHeight = HIWORD(lParam);
  702. Platform::setWindowSize( nWidth, nHeight );
  703. Game->gameReactivate();
  704. // MP: Commented out the if check to expose this variable no matter what the resizing is. This will help out the teams
  705. // that rely on knowing the windowRes for their tools (like Black Jack's card generator).
  706. //
  707. // If we're greater than MIN_RESOLUTION and less than our client desktop area, store as windowed mode pref resolution
  708. //if( ( nWidth > MIN_RESOLUTION_X && nWidth < winState.desktopClientWidth ) && ( nHeight > MIN_RESOLUTION_Y && nHeight < winState.desktopClientHeight ) )
  709. //{
  710. char tempBuf[32];
  711. dSprintf( tempBuf, sizeof(char) * 32, "%d %d %d", nWidth,nHeight, 16 );
  712. Con::setVariable( "$pref::Video::windowedRes", tempBuf );
  713. //}
  714. }
  715. else
  716. {
  717. // Deactivate ourselves when we're hidden
  718. Game->gameDeactivate( true );
  719. }
  720. break;
  721. case MM_MCINOTIFY:
  722. //handleRedBookCallback(wParam, lParam);
  723. break;
  724. //case WM_DESTROY:
  725. case WM_CLOSE:
  726. PostQuitMessage(0);
  727. break;
  728. case WM_SETFOCUS:
  729. winState.renderThreadBlocked = false;
  730. break;
  731. case WM_KILLFOCUS:
  732. winState.renderThreadBlocked = true;
  733. break;
  734. case WM_COMMAND:
  735. if(HIWORD(wParam) == 0)
  736. {
  737. winState.renderThreadBlocked = false;
  738. // This command came from a menu choice. Pass along the menu ID to a
  739. // script function
  740. // [tom, 8/21/2006] Pass off to the relevant PopupMenu
  741. S32 numItems = GetMenuItemCount(winState.appMenu);
  742. for(S32 i = 0;i < numItems;i++)
  743. {
  744. MENUITEMINFOA mi;
  745. mi.cbSize = sizeof(mi);
  746. mi.fMask = MIIM_DATA;
  747. if(GetMenuItemInfoA(winState.appMenu, i, TRUE, &mi))
  748. {
  749. if(mi.fMask & MIIM_DATA)
  750. {
  751. PopupMenu *mnu = (PopupMenu *)mi.dwItemData;
  752. if(mnu->canHandleID(LOWORD(wParam)))
  753. mnu->handleSelect(LOWORD(wParam));
  754. }
  755. }
  756. }
  757. }
  758. break;
  759. case WM_MENUSELECT:
  760. winState.renderThreadBlocked = true;
  761. case WM_PAINT:
  762. if(winState.renderThreadBlocked)
  763. Canvas->renderFrame(false);
  764. break;
  765. #ifdef UNICODE
  766. case WM_INPUTLANGCHANGE:
  767. // Con::printf("IME lang change");
  768. break;
  769. case WM_IME_SETCONTEXT:
  770. // Con::printf("IME set context");
  771. break;
  772. case WM_IME_COMPOSITION:
  773. // Con::printf("IME comp");
  774. break;
  775. case WM_IME_STARTCOMPOSITION:
  776. // Con::printf("IME start comp");
  777. break;
  778. #endif
  779. default:
  780. {
  781. if (sgQueueEvents)
  782. {
  783. WinMessage msg(message,wParam,lParam);
  784. sgWinMessages.push_front(msg);
  785. }
  786. }
  787. }
  788. return DefWindowProc(hWnd, message, wParam, lParam);
  789. }
  790. //--------------------------------------
  791. static void OurDispatchMessages()
  792. {
  793. WinMessage msg(0,0,0);
  794. UINT message;
  795. WPARAM wParam;
  796. LPARAM lParam;
  797. DInputManager* mgr = dynamic_cast<DInputManager*>( Input::getManager() );
  798. while (sgWinMessages.size())
  799. {
  800. msg = sgWinMessages.front();
  801. sgWinMessages.pop_front();
  802. message = msg.message;
  803. wParam = msg.wParam;
  804. lParam = msg.lParam;
  805. if ( !mgr || !mgr->isMouseActive() )
  806. {
  807. switch ( message )
  808. {
  809. #ifdef UNICODE
  810. case WM_IME_COMPOSITION:
  811. {
  812. // Con::printf("OMG IME comp");
  813. break;
  814. }
  815. case WM_IME_ENDCOMPOSITION:
  816. {
  817. // Con::printf("OMG IME end comp");
  818. break;
  819. }
  820. case WM_IME_NOTIFY:
  821. {
  822. // Con::printf("OMG IME notify");
  823. break;
  824. }
  825. case WM_IME_CHAR:
  826. processCharMessage( wParam, lParam );
  827. break;
  828. #endif
  829. // We want to show the system cursor whenever we leave
  830. // our window, and it'd be simple, except for one problem:
  831. // showcursor isn't a toggle. so, keep hammering it until
  832. // the cursor is *actually* going to be shown.
  833. case WM_NCMOUSEMOVE:
  834. {
  835. break;
  836. }
  837. case WM_MOUSEMOVE:
  838. // keep trying until we actually show it
  839. Input::refreshCursor();
  840. if ( !windowLocked )
  841. {
  842. MouseMoveEvent event;
  843. S16 xPos = LOWORD(lParam);
  844. S16 yPos = HIWORD(lParam);
  845. event.xPos = xPos; // horizontal position of cursor
  846. if( winState.appMenu != NULL )
  847. {
  848. S32 menuHeight = GetSystemMetrics(SM_CYMENU);
  849. event.yPos = ( yPos ); // vertical position of cursor
  850. }
  851. else
  852. event.yPos = yPos; // vertical position of cursor
  853. event.modifier = modifierKeys;
  854. Game->postEvent(event);
  855. }
  856. break;
  857. case WM_SETCURSOR:
  858. if ((LOWORD(lParam) == HTCLIENT) && !(Canvas->getUseNativeCursor()))
  859. SetCursor(NULL);
  860. break;
  861. case WM_LBUTTONDOWN:
  862. mouseButtonEvent(SI_MAKE, KEY_BUTTON0);
  863. break;
  864. case WM_MBUTTONDOWN:
  865. mouseButtonEvent(SI_MAKE, KEY_BUTTON2);
  866. break;
  867. case WM_RBUTTONDOWN:
  868. mouseButtonEvent(SI_MAKE, KEY_BUTTON1);
  869. break;
  870. case WM_LBUTTONUP:
  871. mouseButtonEvent(SI_BREAK, KEY_BUTTON0);
  872. break;
  873. case WM_MBUTTONUP:
  874. mouseButtonEvent(SI_BREAK, KEY_BUTTON2);
  875. break;
  876. case WM_RBUTTONUP:
  877. mouseButtonEvent(SI_BREAK, KEY_BUTTON1);
  878. break;
  879. case WM_MOUSEWHEEL:
  880. mouseWheelEvent( (S16) HIWORD( wParam ) );
  881. break;
  882. }
  883. }
  884. if ( !mgr || !mgr->isKeyboardActive() )
  885. {
  886. switch ( message )
  887. {
  888. case WM_KEYUP:
  889. case WM_SYSKEYUP:
  890. case WM_KEYDOWN:
  891. case WM_SYSKEYDOWN:
  892. processKeyMessage(message, wParam, lParam);
  893. break;
  894. }
  895. }
  896. }
  897. }
  898. //--------------------------------------
  899. static bool ProcessMessages()
  900. {
  901. MSG msg;
  902. PROFILE_SCOPE(ProcessMessages_MAIN);
  903. S32 nMessagesDispatched = 0;
  904. while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
  905. {
  906. if(msg.message == WM_QUIT)
  907. return false;
  908. PROFILE_START(TranslateMessage);
  909. TranslateMessage(&msg);
  910. PROFILE_END();
  911. PROFILE_START(DispatchMessage);
  912. DispatchMessage(&msg);
  913. PROFILE_END();
  914. PROFILE_START(OurDispatchMessages);
  915. OurDispatchMessages();
  916. PROFILE_END();
  917. nMessagesDispatched++;
  918. if( nMessagesDispatched >= winState.nMessagesPerFrame )
  919. break;
  920. }
  921. return true;
  922. }
  923. //--------------------------------------
  924. void Platform::process()
  925. {
  926. PROFILE_START(GetInputManager);
  927. DInputManager* mgr = dynamic_cast<DInputManager*>( Input::getManager() );
  928. PROFILE_END();
  929. if ( !mgr || !mgr->isMouseActive() )
  930. {
  931. PROFILE_SCOPE(InputManagerCheckCursor);
  932. CheckCursorPos();
  933. }
  934. PROFILE_START(WinConsoleProcess);
  935. WindowsConsole->process();
  936. PROFILE_END();
  937. PROFILE_START(ProcessMessages);
  938. if(!ProcessMessages())
  939. {
  940. PROFILE_SCOPE(PostEvent);
  941. // generate a quit event
  942. Event quitEvent;
  943. quitEvent.type = QuitEventType;
  944. Game->postEvent(quitEvent);
  945. }
  946. PROFILE_END();
  947. PROFILE_START(GetForegroundWindow);
  948. HWND window = GetForegroundWindow();
  949. PROFILE_END();
  950. // assume that we are in the foreground,
  951. winState.backgrounded = false;
  952. // unless we see that the foreground window does not belong to this process.
  953. if (window && window != winState.appWindow && gWindowCreated)
  954. {
  955. DWORD foregroundProcessId;
  956. GetWindowThreadProcessId(window, &foregroundProcessId);
  957. if (foregroundProcessId != winState.processId)
  958. winState.backgrounded = true;
  959. }
  960. PROFILE_SCOPE(InputProcess);
  961. Input::process();
  962. }
  963. extern U32 calculateCRC(void * buffer, S32 len, U32 crcVal );
  964. #if defined(TORQUE_DEBUG) || defined(INTERNAL_RELEASE)
  965. static U32 stubCRC = 0;
  966. #else
  967. static U32 stubCRC = 0xEA63F56C;
  968. #endif
  969. //--------------------------------------
  970. static void InitWindowClass()
  971. {
  972. WNDCLASS wc;
  973. dMemset(&wc, 0, sizeof(wc));
  974. wc.style = CS_OWNDC;
  975. wc.lpfnWndProc = WindowProc;
  976. wc.cbClsExtra = 0;
  977. wc.cbWndExtra = 0;
  978. wc.hInstance = winState.appInstance;
  979. wc.hIcon = LoadIcon(winState.appInstance, MAKEINTRESOURCE(IDI_TORQUE2D));
  980. wc.hCursor = LoadCursor (NULL,IDC_ARROW);
  981. wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  982. wc.lpszMenuName = 0;
  983. wc.lpszClassName = windowClassName;
  984. RegisterClass( &wc );
  985. // Curtain window class:
  986. wc.lpfnWndProc = DefWindowProc;
  987. wc.hCursor = NULL;
  988. wc.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
  989. wc.lpszClassName = dT("Curtain");
  990. RegisterClass( &wc );
  991. }
  992. //--------------------------------------
  993. Resolution Video::getDesktopResolution()
  994. {
  995. Resolution Result;
  996. RECT clientRect;
  997. HWND hDesktop = GetDesktopWindow();
  998. HDC hDeskDC = GetDC( hDesktop );
  999. // Retrieve Resolution Information.
  1000. Result.bpp = winState.desktopBitsPixel = GetDeviceCaps( hDeskDC, BITSPIXEL );
  1001. Result.w = winState.desktopWidth = GetDeviceCaps( hDeskDC, HORZRES );
  1002. Result.h = winState.desktopHeight = GetDeviceCaps( hDeskDC, VERTRES );
  1003. // Release Device Context.
  1004. ReleaseDC( hDesktop, hDeskDC );
  1005. SystemParametersInfo(SPI_GETWORKAREA, 0, &clientRect, 0);
  1006. winState.desktopClientWidth = clientRect.right;
  1007. winState.desktopClientHeight = clientRect.bottom;
  1008. // Return Result;
  1009. return Result;
  1010. }
  1011. //--------------------------------------
  1012. HWND CreateOpenGLWindow( U32 width, U32 height, bool fullScreen, bool allowSizing )
  1013. {
  1014. S32 windowStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  1015. S32 exWindowStyle = 0;
  1016. if ( fullScreen )
  1017. windowStyle |= ( WS_POPUP | WS_MAXIMIZE );
  1018. else
  1019. if (!allowSizing)
  1020. windowStyle |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
  1021. else
  1022. windowStyle |= ( WS_OVERLAPPEDWINDOW );
  1023. return CreateWindowEx(
  1024. exWindowStyle,
  1025. windowClassName,
  1026. windowName,
  1027. windowStyle,
  1028. 0, 0, width, height,
  1029. NULL, NULL,
  1030. winState.appInstance,
  1031. NULL);
  1032. }
  1033. //--------------------------------------
  1034. HWND CreateCurtain( U32 width, U32 height )
  1035. {
  1036. return CreateWindow(
  1037. dT("Curtain"),
  1038. dT(""),
  1039. ( WS_POPUP | WS_MAXIMIZE ),
  1040. 0, 0,
  1041. width, height,
  1042. NULL, NULL,
  1043. winState.appInstance,
  1044. NULL );
  1045. }
  1046. //--------------------------------------
  1047. void CreatePixelFormat( PIXELFORMATDESCRIPTOR *pPFD, S32 colorBits, S32 depthBits, S32 stencilBits, bool stereo )
  1048. {
  1049. PIXELFORMATDESCRIPTOR src =
  1050. {
  1051. sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
  1052. 1, // version number
  1053. PFD_DRAW_TO_WINDOW | // support window
  1054. PFD_SUPPORT_OPENGL | // support OpenGL
  1055. PFD_DOUBLEBUFFER, // double buffered
  1056. PFD_TYPE_RGBA, // RGBA type
  1057. colorBits, // color depth
  1058. 0, 0, 0, 0, 0, 0, // color bits ignored
  1059. 0, // no alpha buffer
  1060. 0, // shift bit ignored
  1061. 0, // no accumulation buffer
  1062. 0, 0, 0, 0, // accum bits ignored
  1063. depthBits, // z-buffer
  1064. stencilBits, // stencil buffer
  1065. 0, // no auxiliary buffer
  1066. PFD_MAIN_PLANE, // main layer
  1067. 0, // reserved
  1068. 0, 0, 0 // layer masks ignored
  1069. };
  1070. if ( stereo )
  1071. {
  1072. //ri.Printf( PRINT_ALL, "...attempting to use stereo\n" );
  1073. src.dwFlags |= PFD_STEREO;
  1074. //glConfig.stereoEnabled = true;
  1075. }
  1076. else
  1077. {
  1078. //glConfig.stereoEnabled = qfalse;
  1079. }
  1080. *pPFD = src;
  1081. }
  1082. //--------------------------------------
  1083. enum WinConstants { MAX_PFDS = 256 };
  1084. #ifndef PFD_GENERIC_ACCELERATED
  1085. #define PFD_GENERIC_ACCELERATED 0x00001000
  1086. #endif
  1087. S32 ChooseBestPixelFormat(HDC hDC, PIXELFORMATDESCRIPTOR *pPFD)
  1088. {
  1089. PIXELFORMATDESCRIPTOR pfds[MAX_PFDS+1];
  1090. S32 i;
  1091. S32 bestMatch = 0;
  1092. S32 maxPFD = dwglDescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), &pfds[0]);
  1093. if(maxPFD > MAX_PFDS)
  1094. maxPFD = MAX_PFDS;
  1095. bool accelerated = false;
  1096. for(i = 1; i <= maxPFD; i++)
  1097. {
  1098. dwglDescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfds[i]);
  1099. // make sure this has hardware acceleration:
  1100. if ( ( pfds[i].dwFlags & PFD_GENERIC_FORMAT ) != 0 )
  1101. continue;
  1102. // verify pixel type
  1103. if ( pfds[i].iPixelType != PFD_TYPE_RGBA )
  1104. continue;
  1105. // verify proper flags
  1106. if ( ( ( pfds[i].dwFlags & pPFD->dwFlags ) & pPFD->dwFlags ) != pPFD->dwFlags )
  1107. continue;
  1108. accelerated = !(pfds[i].dwFlags & PFD_GENERIC_FORMAT);
  1109. //
  1110. // selection criteria (in order of priority):
  1111. //
  1112. // PFD_STEREO
  1113. // colorBits
  1114. // depthBits
  1115. // stencilBits
  1116. //
  1117. if ( bestMatch )
  1118. {
  1119. // check stereo
  1120. if ( ( pfds[i].dwFlags & PFD_STEREO ) && ( !( pfds[bestMatch].dwFlags & PFD_STEREO ) ) && ( pPFD->dwFlags & PFD_STEREO ) )
  1121. {
  1122. bestMatch = i;
  1123. continue;
  1124. }
  1125. if ( !( pfds[i].dwFlags & PFD_STEREO ) && ( pfds[bestMatch].dwFlags & PFD_STEREO ) && ( pPFD->dwFlags & PFD_STEREO ) )
  1126. {
  1127. bestMatch = i;
  1128. continue;
  1129. }
  1130. // check color
  1131. if ( pfds[bestMatch].cColorBits != pPFD->cColorBits )
  1132. {
  1133. // prefer perfect match
  1134. if ( pfds[i].cColorBits == pPFD->cColorBits )
  1135. {
  1136. bestMatch = i;
  1137. continue;
  1138. }
  1139. // otherwise if this PFD has more bits than our best, use it
  1140. else if ( pfds[i].cColorBits > pfds[bestMatch].cColorBits )
  1141. {
  1142. bestMatch = i;
  1143. continue;
  1144. }
  1145. }
  1146. // check depth
  1147. if ( pfds[bestMatch].cDepthBits != pPFD->cDepthBits )
  1148. {
  1149. // prefer perfect match
  1150. if ( pfds[i].cDepthBits == pPFD->cDepthBits )
  1151. {
  1152. bestMatch = i;
  1153. continue;
  1154. }
  1155. // otherwise if this PFD has more bits than our best, use it
  1156. else if ( pfds[i].cDepthBits > pfds[bestMatch].cDepthBits )
  1157. {
  1158. bestMatch = i;
  1159. continue;
  1160. }
  1161. }
  1162. // check stencil
  1163. if ( pfds[bestMatch].cStencilBits != pPFD->cStencilBits )
  1164. {
  1165. // prefer perfect match
  1166. if ( pfds[i].cStencilBits == pPFD->cStencilBits )
  1167. {
  1168. bestMatch = i;
  1169. continue;
  1170. }
  1171. // otherwise if this PFD has more bits than our best, use it
  1172. else if ( ( pfds[i].cStencilBits > pfds[bestMatch].cStencilBits ) &&
  1173. ( pPFD->cStencilBits > 0 ) )
  1174. {
  1175. bestMatch = i;
  1176. continue;
  1177. }
  1178. }
  1179. }
  1180. else
  1181. {
  1182. bestMatch = i;
  1183. }
  1184. }
  1185. if ( !bestMatch )
  1186. return 0;
  1187. else if ( pfds[bestMatch].dwFlags & PFD_GENERIC_ACCELERATED )
  1188. {
  1189. // MCD
  1190. }
  1191. else
  1192. {
  1193. // ICD
  1194. }
  1195. *pPFD = pfds[bestMatch];
  1196. return bestMatch;
  1197. }
  1198. //--------------------------------------
  1199. //
  1200. // This function exists so DirectInput can communicate with the Windows mouse
  1201. // in windowed mode.
  1202. //
  1203. //--------------------------------------
  1204. void setModifierKeys( S32 modKeys )
  1205. {
  1206. modifierKeys = modKeys;
  1207. }
  1208. //--------------------------------------
  1209. const Point2I &Platform::getWindowSize()
  1210. {
  1211. return windowSize;
  1212. }
  1213. //--------------------------------------
  1214. void Platform::setWindowSize( U32 newWidth, U32 newHeight )
  1215. {
  1216. windowSize.set( newWidth, newHeight );
  1217. }
  1218. //RectI Platform::getWindowClientRect()
  1219. //{
  1220. // RECT rClientRect;
  1221. // GetClientRect( winState.appWindow, &rClientRect );
  1222. //
  1223. // if( winState.appMenu == NULL )
  1224. // return RectI( rClientRect.left, rClientRect.top, rClientRect.right - rClientRect.left, rClientRect.bottom - rClientRect.top );
  1225. //
  1226. // S32 menuHeight = GetSystemMetrics(SM_CYMENU);
  1227. // return RectI( rClientRect.left, rClientRect.top + menuHeight, rClientRect.right - rClientRect.left, rClientRect.bottom - ( rClientRect.top + menuHeight ) );
  1228. //}
  1229. //--------------------------------------
  1230. static void InitWindow(const Point2I &initialSize)
  1231. {
  1232. windowSize = initialSize;
  1233. // The window is created when the display device is activated. BH
  1234. winState.processId = GetCurrentProcessId();
  1235. }
  1236. //--------------------------------------
  1237. static void InitOpenGL()
  1238. {
  1239. // The OpenGL initialization stuff has been mostly moved to the display
  1240. // devices' activate functions. BH
  1241. DisplayDevice::init();
  1242. bool fullScreen = Con::getBoolVariable( "$pref::Video::fullScreen" );
  1243. const char* resString = Con::getVariable( ( fullScreen ? "$pref::Video::resolution" : "$pref::Video::windowedRes" ) );
  1244. // Get the video settings from the prefs:
  1245. char* tempBuf = new char[dStrlen( resString ) + 1];
  1246. dStrcpy( tempBuf, resString );
  1247. char* temp = dStrtok( tempBuf, " x\0" );
  1248. //MIN_RESOLUTION defined in platformWin32/platformGL.h
  1249. U32 width = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_X );
  1250. temp = dStrtok( NULL, " x\0" );
  1251. U32 height = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_Y );
  1252. temp = dStrtok( NULL, "\0" );
  1253. U32 bpp = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_BIT_DEPTH );
  1254. delete [] tempBuf;
  1255. // If no device is specified, see which ones we have...
  1256. if ( !Video::setDevice( Con::getVariable( "$pref::Video::displayDevice" ), width, height, bpp, fullScreen ) )
  1257. {
  1258. // First, try the default OpenGL device:
  1259. if ( !Video::setDevice( "OpenGL", width, height, bpp, fullScreen ) )
  1260. {
  1261. AssertFatal( false, "Could not find a compatible display device!" );
  1262. return;
  1263. }
  1264. }
  1265. }
  1266. //--------------------------------------
  1267. void Platform::init()
  1268. {
  1269. // Set the platform variable for the scripts
  1270. Con::setVariable( "$platform", "windows" );
  1271. WinConsole::create();
  1272. if ( !WinConsole::isEnabled() )
  1273. Input::init();
  1274. InitInput(); // in case DirectInput falls through
  1275. InitWindowClass();
  1276. Video::getDesktopResolution();
  1277. //installRedBookDevices();
  1278. sgDoubleByteEnabled = GetSystemMetrics( SM_DBCSENABLED );
  1279. sgQueueEvents = true;
  1280. }
  1281. //--------------------------------------
  1282. void Platform::shutdown()
  1283. {
  1284. sgQueueEvents = false;
  1285. setMouseLock( false );
  1286. Audio::OpenALShutdown();
  1287. Video::destroy();
  1288. Input::destroy();
  1289. WinConsole::destroy();
  1290. }
  1291. class WinTimer
  1292. {
  1293. private:
  1294. U32 mTickCountCurrent;
  1295. U32 mTickCountNext;
  1296. S64 mPerfCountCurrent;
  1297. S64 mPerfCountNext;
  1298. S64 mFrequency;
  1299. F64 mPerfCountRemainderCurrent;
  1300. F64 mPerfCountRemainderNext;
  1301. bool mUsingPerfCounter;
  1302. public:
  1303. WinTimer()
  1304. {
  1305. SetProcessAffinityMask( GetCurrentProcess(), 1 );
  1306. mPerfCountRemainderCurrent = 0.0f;
  1307. mUsingPerfCounter = QueryPerformanceFrequency((LARGE_INTEGER *) &mFrequency);
  1308. if(mUsingPerfCounter)
  1309. mUsingPerfCounter = QueryPerformanceCounter((LARGE_INTEGER *) &mPerfCountCurrent);
  1310. if(!mUsingPerfCounter)
  1311. mTickCountCurrent = GetTickCount();
  1312. }
  1313. U32 getElapsedMS()
  1314. {
  1315. if(mUsingPerfCounter)
  1316. {
  1317. QueryPerformanceCounter( (LARGE_INTEGER *) &mPerfCountNext);
  1318. F64 elapsedF64 = (1000.0 * F64(mPerfCountNext - mPerfCountCurrent) / F64(mFrequency));
  1319. elapsedF64 += mPerfCountRemainderCurrent;
  1320. U32 elapsed = (U32)mFloor((F32)elapsedF64);
  1321. mPerfCountRemainderNext = elapsedF64 - F64(elapsed);
  1322. return elapsed;
  1323. }
  1324. else
  1325. {
  1326. mTickCountNext = GetTickCount();
  1327. return mTickCountNext - mTickCountCurrent;
  1328. }
  1329. }
  1330. void advance()
  1331. {
  1332. mTickCountCurrent = mTickCountNext;
  1333. mPerfCountCurrent = mPerfCountNext;
  1334. mPerfCountRemainderCurrent = mPerfCountRemainderNext;
  1335. }
  1336. };
  1337. static WinTimer gTimer;
  1338. extern bool LinkConsoleFunctions;
  1339. //--------------------------------------
  1340. static S32 run(S32 argc, const char **argv)
  1341. {
  1342. // Initialize fonts.
  1343. createFontInit();
  1344. windowSize.set(0,0);
  1345. // Finish if the game didn't initialize.
  1346. if(!Game->mainInitialize(argc, argv) )
  1347. return 0;
  1348. // run the game main loop.
  1349. while( Game->isRunning() )
  1350. {
  1351. Game->mainLoop();
  1352. }
  1353. // Shut the game down.
  1354. Game->mainShutdown();
  1355. // Destroy fonts.
  1356. createFontShutdown();
  1357. return 0;
  1358. }
  1359. //--------------------------------------
  1360. void Platform::initWindow(const Point2I &initialSize, const char *name)
  1361. {
  1362. MSG msg;
  1363. Con::printSeparator();
  1364. Con::printf("Video Initialization:");
  1365. Video::init();
  1366. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1367. if ( Video::installDevice( OpenGLDevice::create() ) )
  1368. Con::printf( " Accelerated OpenGL display device detected." );
  1369. else
  1370. Con::printf( " Accelerated OpenGL display device not detected." );
  1371. Con::printf( "" );
  1372. gWindowCreated = true;
  1373. #ifdef UNICODE
  1374. convertUTF8toUTF16((UTF8 *)name, windowName, sizeof(windowName));
  1375. #else
  1376. dStrcpy(windowName, name);
  1377. #endif
  1378. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1379. InitWindow(initialSize);
  1380. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1381. InitOpenGL();
  1382. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1383. }
  1384. void Platform::setWindowTitle( const char* title )
  1385. {
  1386. if( !title || !title[0] )
  1387. return;
  1388. #ifdef UNICODE
  1389. convertUTF8toUTF16((UTF8 *)title, windowName, sizeof(windowName));
  1390. #else
  1391. dStrcpy(windowName, title);
  1392. #endif
  1393. if( winState.appWindow )
  1394. #ifdef UNICODE
  1395. SetWindowTextW( winState.appWindow, windowName );
  1396. #else
  1397. SetWindowTextA( winState.appWindow, windowName );
  1398. #endif
  1399. }
  1400. //--------------------------------------
  1401. S32 main(S32 argc, const char **argv)
  1402. {
  1403. winState.appInstance = GetModuleHandle(NULL);
  1404. return run(argc, argv);
  1405. }
  1406. //--------------------------------------
  1407. S32 PASCAL WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, S32)
  1408. {
  1409. Vector<char *> argv;
  1410. char moduleName[256];
  1411. GetModuleFileNameA(NULL, moduleName, sizeof(moduleName));
  1412. argv.push_back(moduleName);
  1413. for (const char* word,*ptr = lpszCmdLine; *ptr; ) {
  1414. // Eat white space
  1415. for (; dIsspace(*ptr) && *ptr; ptr++)
  1416. ;
  1417. // Pick out the next word
  1418. bool quote = false;
  1419. for (word = ptr; !(dIsspace(*ptr) && !quote) && *ptr; ptr++)
  1420. {
  1421. if(*ptr == '\"') quote = ! quote;
  1422. }
  1423. if(*word == '\"') ++word;
  1424. // Add the word to the argument list.
  1425. if (*word) {
  1426. int len = ptr - word;
  1427. if(*(ptr-1) == '\"') --len;
  1428. char *arg = (char *) dMalloc(len + 1);
  1429. dStrncpy(arg, word, len);
  1430. arg[len] = 0;
  1431. argv.push_back(arg);
  1432. }
  1433. }
  1434. winState.appInstance = hInstance;
  1435. S32 retVal = run(argv.size(), (const char **) argv.address());
  1436. for(U32 j = 1; j < (U32)argv.size(); j++)
  1437. dFree(argv[j]);
  1438. return retVal;
  1439. }
  1440. //--------------------------------------
  1441. void TimeManager::process()
  1442. {
  1443. if( winState.backgrounded )
  1444. winState.sleepTicks = Platform::getBackgroundSleepTime();
  1445. else
  1446. winState.sleepTicks = sgTimeManagerProcessInterval;
  1447. U32 elapsedTime = gTimer.getElapsedMS();
  1448. if( elapsedTime < winState.sleepTicks)
  1449. {
  1450. MsgWaitForMultipleObjects(0, NULL, false, winState.sleepTicks - elapsedTime, QS_ALLINPUT);
  1451. }
  1452. TimeEvent event;
  1453. event.elapsedTime = gTimer.getElapsedMS();
  1454. gTimer.advance();
  1455. Game->postEvent(event);
  1456. }
  1457. F32 Platform::getRandom()
  1458. {
  1459. return sgPlatRandom.randF();
  1460. }
  1461. ////--------------------------------------
  1462. /// Spawn the default Operating System web browser with a URL
  1463. /// @param webAddress URL to pass to browser
  1464. /// @return true if browser successfully spawned
  1465. bool Platform::openWebBrowser( const char* webAddress )
  1466. {
  1467. static bool sHaveKey = false;
  1468. static wchar_t sWebKey[512];
  1469. char utf8WebKey[512];
  1470. {
  1471. HKEY regKey;
  1472. DWORD size = sizeof( sWebKey );
  1473. if ( RegOpenKeyEx( HKEY_CLASSES_ROOT, dT("\\http\\shell\\open\\command"), 0, KEY_QUERY_VALUE, &regKey ) != ERROR_SUCCESS )
  1474. {
  1475. Con::errorf( ConsoleLogEntry::General, "Platform::openWebBrowser - Failed to open the HKCR\\http registry key!!!");
  1476. return( false );
  1477. }
  1478. if ( RegQueryValueEx( regKey, dT(""), NULL, NULL, (unsigned char *)sWebKey, &size ) != ERROR_SUCCESS )
  1479. {
  1480. Con::errorf( ConsoleLogEntry::General, "Platform::openWebBrowser - Failed to query the open command registry key!!!" );
  1481. return( false );
  1482. }
  1483. RegCloseKey( regKey );
  1484. sHaveKey = true;
  1485. convertUTF16toUTF8(sWebKey,utf8WebKey,512);
  1486. #ifdef UNICODE
  1487. char *p = dStrstr((const char *)utf8WebKey, "%1");
  1488. #else
  1489. char *p = dStrstr( (const char *) sWebKey , "%1");
  1490. #endif
  1491. if (p) *p = 0;
  1492. }
  1493. STARTUPINFO si;
  1494. dMemset( &si, 0, sizeof( si ) );
  1495. si.cb = sizeof( si );
  1496. char buf[1024];
  1497. #ifdef UNICODE
  1498. dSprintf( buf, sizeof( buf ), "%s %s", utf8WebKey, webAddress );
  1499. UTF16 szCommandLine[1024];
  1500. convertUTF8toUTF16((UTF8 *)buf, szCommandLine, sizeof(szCommandLine));
  1501. #else
  1502. UTF8 szCommandLine[1024];
  1503. dSprintf( szCommandLine, sizeof( szCommandLine ), "%s %s", sWebKey, webAddress );
  1504. #endif
  1505. //Con::errorf( ConsoleLogEntry::General, "** Web browser command = %s **", buf );
  1506. PROCESS_INFORMATION pi;
  1507. dMemset( &pi, 0, sizeof( pi ) );
  1508. CreateProcess( NULL,
  1509. szCommandLine,
  1510. NULL,
  1511. NULL,
  1512. false,
  1513. CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
  1514. NULL,
  1515. NULL,
  1516. &si,
  1517. &pi );
  1518. return( true );
  1519. }
  1520. //--------------------------------------
  1521. // Platform functions for window menu
  1522. //--------------------------------------
  1523. // Creates the menu bar for the window
  1524. void CreateWin32MenuBar( void )
  1525. {
  1526. if( HasWin32MenuBar() )
  1527. {
  1528. DrawMenuBar( winState.appWindow );
  1529. return;
  1530. }
  1531. HMENU menu = CreateMenu();
  1532. if(menu)
  1533. {
  1534. winState.appMenu = menu;
  1535. SetMenu(winState.appWindow, menu);
  1536. DrawMenuBar(winState.appWindow);
  1537. }
  1538. }
  1539. void DestroyWin32MenuBar( void )
  1540. {
  1541. if( HasWin32MenuBar() )
  1542. DestroyMenu( winState.appMenu );
  1543. // Need to update platform window child rect?
  1544. DrawMenuBar(winState.appWindow);
  1545. }
  1546. bool HasWin32MenuBar( void )
  1547. {
  1548. return (bool)IsMenu( winState.appMenu );
  1549. }