winWindow.cc 50 KB

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