winWindow.cc 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796
  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. break;
  817. }
  818. case WM_MOUSEMOVE:
  819. // keep trying until we actually show it
  820. Input::refreshCursor();
  821. if ( !windowLocked )
  822. {
  823. MouseMoveEvent event;
  824. S16 xPos = LOWORD(lParam);
  825. S16 yPos = HIWORD(lParam);
  826. event.xPos = xPos; // horizontal position of cursor
  827. if( winState.appMenu != NULL )
  828. {
  829. S32 menuHeight = GetSystemMetrics(SM_CYMENU);
  830. event.yPos = ( yPos ); // vertical position of cursor
  831. }
  832. else
  833. event.yPos = yPos; // vertical position of cursor
  834. event.modifier = modifierKeys;
  835. Game->postEvent(event);
  836. }
  837. break;
  838. case WM_SETCURSOR:
  839. if ((LOWORD(lParam) == HTCLIENT) && !(Canvas->getUseNativeCursor()))
  840. SetCursor(NULL);
  841. break;
  842. case WM_LBUTTONDOWN:
  843. mouseButtonEvent(SI_MAKE, KEY_BUTTON0);
  844. break;
  845. case WM_MBUTTONDOWN:
  846. mouseButtonEvent(SI_MAKE, KEY_BUTTON2);
  847. break;
  848. case WM_RBUTTONDOWN:
  849. mouseButtonEvent(SI_MAKE, KEY_BUTTON1);
  850. break;
  851. case WM_LBUTTONUP:
  852. mouseButtonEvent(SI_BREAK, KEY_BUTTON0);
  853. break;
  854. case WM_MBUTTONUP:
  855. mouseButtonEvent(SI_BREAK, KEY_BUTTON2);
  856. break;
  857. case WM_RBUTTONUP:
  858. mouseButtonEvent(SI_BREAK, KEY_BUTTON1);
  859. break;
  860. case WM_MOUSEWHEEL:
  861. mouseWheelEvent( (S16) HIWORD( wParam ) );
  862. break;
  863. }
  864. }
  865. if ( !mgr || !mgr->isKeyboardActive() )
  866. {
  867. switch ( message )
  868. {
  869. case WM_KEYUP:
  870. case WM_SYSKEYUP:
  871. case WM_KEYDOWN:
  872. case WM_SYSKEYDOWN:
  873. processKeyMessage(message, wParam, lParam);
  874. break;
  875. }
  876. }
  877. }
  878. }
  879. //--------------------------------------
  880. static bool ProcessMessages()
  881. {
  882. MSG msg;
  883. PROFILE_SCOPE(ProcessMessages_MAIN);
  884. S32 nMessagesDispatched = 0;
  885. while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
  886. {
  887. if(msg.message == WM_QUIT)
  888. return false;
  889. PROFILE_START(TranslateMessage);
  890. TranslateMessage(&msg);
  891. PROFILE_END();
  892. PROFILE_START(DispatchMessage);
  893. DispatchMessage(&msg);
  894. PROFILE_END();
  895. PROFILE_START(OurDispatchMessages);
  896. OurDispatchMessages();
  897. PROFILE_END();
  898. nMessagesDispatched++;
  899. if( nMessagesDispatched >= winState.nMessagesPerFrame )
  900. break;
  901. }
  902. return true;
  903. }
  904. //--------------------------------------
  905. void Platform::process()
  906. {
  907. PROFILE_START(GetInputManager);
  908. DInputManager* mgr = dynamic_cast<DInputManager*>( Input::getManager() );
  909. PROFILE_END();
  910. if ( !mgr || !mgr->isMouseActive() )
  911. {
  912. PROFILE_SCOPE(InputManagerCheckCursor);
  913. CheckCursorPos();
  914. }
  915. PROFILE_START(WinConsoleProcess);
  916. WindowsConsole->process();
  917. PROFILE_END();
  918. PROFILE_START(ProcessMessages);
  919. if(!ProcessMessages())
  920. {
  921. PROFILE_SCOPE(PostEvent);
  922. // generate a quit event
  923. Event quitEvent;
  924. quitEvent.type = QuitEventType;
  925. Game->postEvent(quitEvent);
  926. }
  927. PROFILE_END();
  928. PROFILE_START(GetForegroundWindow);
  929. HWND window = GetForegroundWindow();
  930. PROFILE_END();
  931. // assume that we are in the foreground,
  932. winState.backgrounded = false;
  933. // unless we see that the foreground window does not belong to this process.
  934. if (window && window != winState.appWindow && gWindowCreated)
  935. {
  936. DWORD foregroundProcessId;
  937. GetWindowThreadProcessId(window, &foregroundProcessId);
  938. if (foregroundProcessId != winState.processId)
  939. winState.backgrounded = true;
  940. }
  941. PROFILE_SCOPE(InputProcess);
  942. Input::process();
  943. }
  944. extern U32 calculateCRC(void * buffer, S32 len, U32 crcVal );
  945. #if defined(TORQUE_DEBUG) || defined(INTERNAL_RELEASE)
  946. static U32 stubCRC = 0;
  947. #else
  948. static U32 stubCRC = 0xEA63F56C;
  949. #endif
  950. //--------------------------------------
  951. static void InitWindowClass()
  952. {
  953. WNDCLASS wc;
  954. dMemset(&wc, 0, sizeof(wc));
  955. wc.style = CS_OWNDC;
  956. wc.lpfnWndProc = WindowProc;
  957. wc.cbClsExtra = 0;
  958. wc.cbWndExtra = 0;
  959. wc.hInstance = winState.appInstance;
  960. wc.hIcon = LoadIcon(winState.appInstance, MAKEINTRESOURCE(IDI_TORQUE2D));
  961. wc.hCursor = LoadCursor (NULL,IDC_ARROW);
  962. wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  963. wc.lpszMenuName = 0;
  964. wc.lpszClassName = windowClassName;
  965. RegisterClass( &wc );
  966. // Curtain window class:
  967. wc.lpfnWndProc = DefWindowProc;
  968. wc.hCursor = NULL;
  969. wc.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
  970. wc.lpszClassName = dT("Curtain");
  971. RegisterClass( &wc );
  972. }
  973. //--------------------------------------
  974. Resolution Video::getDesktopResolution()
  975. {
  976. Resolution Result;
  977. RECT clientRect;
  978. HWND hDesktop = GetDesktopWindow();
  979. HDC hDeskDC = GetDC( hDesktop );
  980. // Retrieve Resolution Information.
  981. Result.bpp = winState.desktopBitsPixel = GetDeviceCaps( hDeskDC, BITSPIXEL );
  982. Result.w = winState.desktopWidth = GetDeviceCaps( hDeskDC, HORZRES );
  983. Result.h = winState.desktopHeight = GetDeviceCaps( hDeskDC, VERTRES );
  984. // Release Device Context.
  985. ReleaseDC( hDesktop, hDeskDC );
  986. SystemParametersInfo(SPI_GETWORKAREA, 0, &clientRect, 0);
  987. winState.desktopClientWidth = clientRect.right;
  988. winState.desktopClientHeight = clientRect.bottom;
  989. // Return Result;
  990. return Result;
  991. }
  992. //--------------------------------------
  993. HWND CreateOpenGLWindow( U32 width, U32 height, bool fullScreen, bool allowSizing )
  994. {
  995. S32 windowStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  996. S32 exWindowStyle = 0;
  997. if ( fullScreen )
  998. windowStyle |= ( WS_POPUP | WS_MAXIMIZE );
  999. else
  1000. if (!allowSizing)
  1001. windowStyle |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
  1002. else
  1003. windowStyle |= ( WS_OVERLAPPEDWINDOW );
  1004. return CreateWindowEx(
  1005. exWindowStyle,
  1006. windowClassName,
  1007. windowName,
  1008. windowStyle,
  1009. 0, 0, width, height,
  1010. NULL, NULL,
  1011. winState.appInstance,
  1012. NULL);
  1013. }
  1014. //--------------------------------------
  1015. HWND CreateCurtain( U32 width, U32 height )
  1016. {
  1017. return CreateWindow(
  1018. dT("Curtain"),
  1019. dT(""),
  1020. ( WS_POPUP | WS_MAXIMIZE ),
  1021. 0, 0,
  1022. width, height,
  1023. NULL, NULL,
  1024. winState.appInstance,
  1025. NULL );
  1026. }
  1027. //--------------------------------------
  1028. void CreatePixelFormat( PIXELFORMATDESCRIPTOR *pPFD, S32 colorBits, S32 depthBits, S32 stencilBits, bool stereo )
  1029. {
  1030. PIXELFORMATDESCRIPTOR src =
  1031. {
  1032. sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
  1033. 1, // version number
  1034. PFD_DRAW_TO_WINDOW | // support window
  1035. PFD_SUPPORT_OPENGL | // support OpenGL
  1036. PFD_DOUBLEBUFFER, // double buffered
  1037. PFD_TYPE_RGBA, // RGBA type
  1038. colorBits, // color depth
  1039. 0, 0, 0, 0, 0, 0, // color bits ignored
  1040. 0, // no alpha buffer
  1041. 0, // shift bit ignored
  1042. 0, // no accumulation buffer
  1043. 0, 0, 0, 0, // accum bits ignored
  1044. depthBits, // z-buffer
  1045. stencilBits, // stencil buffer
  1046. 0, // no auxiliary buffer
  1047. PFD_MAIN_PLANE, // main layer
  1048. 0, // reserved
  1049. 0, 0, 0 // layer masks ignored
  1050. };
  1051. if ( stereo )
  1052. {
  1053. //ri.Printf( PRINT_ALL, "...attempting to use stereo\n" );
  1054. src.dwFlags |= PFD_STEREO;
  1055. //glConfig.stereoEnabled = true;
  1056. }
  1057. else
  1058. {
  1059. //glConfig.stereoEnabled = qfalse;
  1060. }
  1061. *pPFD = src;
  1062. }
  1063. //--------------------------------------
  1064. enum WinConstants { MAX_PFDS = 256 };
  1065. #ifndef PFD_GENERIC_ACCELERATED
  1066. #define PFD_GENERIC_ACCELERATED 0x00001000
  1067. #endif
  1068. S32 ChooseBestPixelFormat(HDC hDC, PIXELFORMATDESCRIPTOR *pPFD)
  1069. {
  1070. PIXELFORMATDESCRIPTOR pfds[MAX_PFDS+1];
  1071. S32 i;
  1072. S32 bestMatch = 0;
  1073. S32 maxPFD = dwglDescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), &pfds[0]);
  1074. if(maxPFD > MAX_PFDS)
  1075. maxPFD = MAX_PFDS;
  1076. bool accelerated = false;
  1077. for(i = 1; i <= maxPFD; i++)
  1078. {
  1079. dwglDescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfds[i]);
  1080. // make sure this has hardware acceleration:
  1081. if ( ( pfds[i].dwFlags & PFD_GENERIC_FORMAT ) != 0 )
  1082. continue;
  1083. // verify pixel type
  1084. if ( pfds[i].iPixelType != PFD_TYPE_RGBA )
  1085. continue;
  1086. // verify proper flags
  1087. if ( ( ( pfds[i].dwFlags & pPFD->dwFlags ) & pPFD->dwFlags ) != pPFD->dwFlags )
  1088. continue;
  1089. accelerated = !(pfds[i].dwFlags & PFD_GENERIC_FORMAT);
  1090. //
  1091. // selection criteria (in order of priority):
  1092. //
  1093. // PFD_STEREO
  1094. // colorBits
  1095. // depthBits
  1096. // stencilBits
  1097. //
  1098. if ( bestMatch )
  1099. {
  1100. // check stereo
  1101. if ( ( pfds[i].dwFlags & PFD_STEREO ) && ( !( pfds[bestMatch].dwFlags & PFD_STEREO ) ) && ( pPFD->dwFlags & PFD_STEREO ) )
  1102. {
  1103. bestMatch = i;
  1104. continue;
  1105. }
  1106. if ( !( pfds[i].dwFlags & PFD_STEREO ) && ( pfds[bestMatch].dwFlags & PFD_STEREO ) && ( pPFD->dwFlags & PFD_STEREO ) )
  1107. {
  1108. bestMatch = i;
  1109. continue;
  1110. }
  1111. // check color
  1112. if ( pfds[bestMatch].cColorBits != pPFD->cColorBits )
  1113. {
  1114. // prefer perfect match
  1115. if ( pfds[i].cColorBits == pPFD->cColorBits )
  1116. {
  1117. bestMatch = i;
  1118. continue;
  1119. }
  1120. // otherwise if this PFD has more bits than our best, use it
  1121. else if ( pfds[i].cColorBits > pfds[bestMatch].cColorBits )
  1122. {
  1123. bestMatch = i;
  1124. continue;
  1125. }
  1126. }
  1127. // check depth
  1128. if ( pfds[bestMatch].cDepthBits != pPFD->cDepthBits )
  1129. {
  1130. // prefer perfect match
  1131. if ( pfds[i].cDepthBits == pPFD->cDepthBits )
  1132. {
  1133. bestMatch = i;
  1134. continue;
  1135. }
  1136. // otherwise if this PFD has more bits than our best, use it
  1137. else if ( pfds[i].cDepthBits > pfds[bestMatch].cDepthBits )
  1138. {
  1139. bestMatch = i;
  1140. continue;
  1141. }
  1142. }
  1143. // check stencil
  1144. if ( pfds[bestMatch].cStencilBits != pPFD->cStencilBits )
  1145. {
  1146. // prefer perfect match
  1147. if ( pfds[i].cStencilBits == pPFD->cStencilBits )
  1148. {
  1149. bestMatch = i;
  1150. continue;
  1151. }
  1152. // otherwise if this PFD has more bits than our best, use it
  1153. else if ( ( pfds[i].cStencilBits > pfds[bestMatch].cStencilBits ) &&
  1154. ( pPFD->cStencilBits > 0 ) )
  1155. {
  1156. bestMatch = i;
  1157. continue;
  1158. }
  1159. }
  1160. }
  1161. else
  1162. {
  1163. bestMatch = i;
  1164. }
  1165. }
  1166. if ( !bestMatch )
  1167. return 0;
  1168. else if ( pfds[bestMatch].dwFlags & PFD_GENERIC_ACCELERATED )
  1169. {
  1170. // MCD
  1171. }
  1172. else
  1173. {
  1174. // ICD
  1175. }
  1176. *pPFD = pfds[bestMatch];
  1177. return bestMatch;
  1178. }
  1179. //--------------------------------------
  1180. //
  1181. // This function exists so DirectInput can communicate with the Windows mouse
  1182. // in windowed mode.
  1183. //
  1184. //--------------------------------------
  1185. void setModifierKeys( S32 modKeys )
  1186. {
  1187. modifierKeys = modKeys;
  1188. }
  1189. //--------------------------------------
  1190. const Point2I &Platform::getWindowSize()
  1191. {
  1192. return windowSize;
  1193. }
  1194. //--------------------------------------
  1195. void Platform::setWindowSize( U32 newWidth, U32 newHeight )
  1196. {
  1197. windowSize.set( newWidth, newHeight );
  1198. }
  1199. //RectI Platform::getWindowClientRect()
  1200. //{
  1201. // RECT rClientRect;
  1202. // GetClientRect( winState.appWindow, &rClientRect );
  1203. //
  1204. // if( winState.appMenu == NULL )
  1205. // return RectI( rClientRect.left, rClientRect.top, rClientRect.right - rClientRect.left, rClientRect.bottom - rClientRect.top );
  1206. //
  1207. // S32 menuHeight = GetSystemMetrics(SM_CYMENU);
  1208. // return RectI( rClientRect.left, rClientRect.top + menuHeight, rClientRect.right - rClientRect.left, rClientRect.bottom - ( rClientRect.top + menuHeight ) );
  1209. //}
  1210. //--------------------------------------
  1211. static void InitWindow(const Point2I &initialSize)
  1212. {
  1213. windowSize = initialSize;
  1214. // The window is created when the display device is activated. BH
  1215. winState.processId = GetCurrentProcessId();
  1216. }
  1217. //--------------------------------------
  1218. static void InitOpenGL()
  1219. {
  1220. // The OpenGL initialization stuff has been mostly moved to the display
  1221. // devices' activate functions. BH
  1222. DisplayDevice::init();
  1223. bool fullScreen = Con::getBoolVariable( "$pref::Video::fullScreen" );
  1224. const char* resString = Con::getVariable( ( fullScreen ? "$pref::Video::resolution" : "$pref::Video::windowedRes" ) );
  1225. // Get the video settings from the prefs:
  1226. char* tempBuf = new char[dStrlen( resString ) + 1];
  1227. dStrcpy( tempBuf, resString );
  1228. char* temp = dStrtok( tempBuf, " x\0" );
  1229. //MIN_RESOLUTION defined in platformWin32/platformGL.h
  1230. U32 width = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_X );
  1231. temp = dStrtok( NULL, " x\0" );
  1232. U32 height = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_Y );
  1233. temp = dStrtok( NULL, "\0" );
  1234. U32 bpp = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_BIT_DEPTH );
  1235. delete [] tempBuf;
  1236. // If no device is specified, see which ones we have...
  1237. if ( !Video::setDevice( Con::getVariable( "$pref::Video::displayDevice" ), width, height, bpp, fullScreen ) )
  1238. {
  1239. // First, try the default OpenGL device:
  1240. if ( !Video::setDevice( "OpenGL", width, height, bpp, fullScreen ) )
  1241. {
  1242. AssertFatal( false, "Could not find a compatible display device!" );
  1243. return;
  1244. }
  1245. }
  1246. }
  1247. //--------------------------------------
  1248. void Platform::init()
  1249. {
  1250. // Set the platform variable for the scripts
  1251. Con::setVariable( "$platform", "windows" );
  1252. WinConsole::create();
  1253. if ( !WinConsole::isEnabled() )
  1254. Input::init();
  1255. InitInput(); // in case DirectInput falls through
  1256. InitWindowClass();
  1257. Video::getDesktopResolution();
  1258. //installRedBookDevices();
  1259. sgDoubleByteEnabled = GetSystemMetrics( SM_DBCSENABLED );
  1260. sgQueueEvents = true;
  1261. }
  1262. //--------------------------------------
  1263. void Platform::shutdown()
  1264. {
  1265. sgQueueEvents = false;
  1266. setMouseLock( false );
  1267. Audio::OpenALShutdown();
  1268. Video::destroy();
  1269. Input::destroy();
  1270. WinConsole::destroy();
  1271. }
  1272. class WinTimer
  1273. {
  1274. private:
  1275. U32 mTickCountCurrent;
  1276. U32 mTickCountNext;
  1277. S64 mPerfCountCurrent;
  1278. S64 mPerfCountNext;
  1279. S64 mFrequency;
  1280. F64 mPerfCountRemainderCurrent;
  1281. F64 mPerfCountRemainderNext;
  1282. bool mUsingPerfCounter;
  1283. public:
  1284. WinTimer()
  1285. {
  1286. SetProcessAffinityMask( GetCurrentProcess(), 1 );
  1287. mPerfCountRemainderCurrent = 0.0f;
  1288. mUsingPerfCounter = QueryPerformanceFrequency((LARGE_INTEGER *) &mFrequency);
  1289. if(mUsingPerfCounter)
  1290. mUsingPerfCounter = QueryPerformanceCounter((LARGE_INTEGER *) &mPerfCountCurrent);
  1291. if(!mUsingPerfCounter)
  1292. mTickCountCurrent = GetTickCount();
  1293. }
  1294. U32 getElapsedMS()
  1295. {
  1296. if(mUsingPerfCounter)
  1297. {
  1298. QueryPerformanceCounter( (LARGE_INTEGER *) &mPerfCountNext);
  1299. F64 elapsedF64 = (1000.0 * F64(mPerfCountNext - mPerfCountCurrent) / F64(mFrequency));
  1300. elapsedF64 += mPerfCountRemainderCurrent;
  1301. U32 elapsed = (U32)mFloor((F32)elapsedF64);
  1302. mPerfCountRemainderNext = elapsedF64 - F64(elapsed);
  1303. return elapsed;
  1304. }
  1305. else
  1306. {
  1307. mTickCountNext = GetTickCount();
  1308. return mTickCountNext - mTickCountCurrent;
  1309. }
  1310. }
  1311. void advance()
  1312. {
  1313. mTickCountCurrent = mTickCountNext;
  1314. mPerfCountCurrent = mPerfCountNext;
  1315. mPerfCountRemainderCurrent = mPerfCountRemainderNext;
  1316. }
  1317. };
  1318. static WinTimer gTimer;
  1319. extern bool LinkConsoleFunctions;
  1320. //--------------------------------------
  1321. static S32 run(S32 argc, const char **argv)
  1322. {
  1323. // Initialize fonts.
  1324. createFontInit();
  1325. windowSize.set(0,0);
  1326. // Finish if the game didn't initialize.
  1327. if(!Game->mainInitialize(argc, argv) )
  1328. return 0;
  1329. // run the game main loop.
  1330. while( Game->isRunning() )
  1331. {
  1332. Game->mainLoop();
  1333. }
  1334. // Shut the game down.
  1335. Game->mainShutdown();
  1336. // Destroy fonts.
  1337. createFontShutdown();
  1338. return 0;
  1339. }
  1340. //--------------------------------------
  1341. void Platform::initWindow(const Point2I &initialSize, const char *name)
  1342. {
  1343. MSG msg;
  1344. Con::printSeparator();
  1345. Con::printf("Video Initialization:");
  1346. Video::init();
  1347. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1348. if ( Video::installDevice( OpenGLDevice::create() ) )
  1349. Con::printf( " Accelerated OpenGL display device detected." );
  1350. else
  1351. Con::printf( " Accelerated OpenGL display device not detected." );
  1352. Con::printf( "" );
  1353. gWindowCreated = true;
  1354. #ifdef UNICODE
  1355. convertUTF8toUTF16((UTF8 *)name, windowName, sizeof(windowName));
  1356. #else
  1357. dStrcpy(windowName, name);
  1358. #endif
  1359. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1360. InitWindow(initialSize);
  1361. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1362. InitOpenGL();
  1363. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  1364. }
  1365. void Platform::setWindowTitle( const char* title )
  1366. {
  1367. if( !title || !title[0] )
  1368. return;
  1369. #ifdef UNICODE
  1370. convertUTF8toUTF16((UTF8 *)title, windowName, sizeof(windowName));
  1371. #else
  1372. dStrcpy(windowName, title);
  1373. #endif
  1374. if( winState.appWindow )
  1375. #ifdef UNICODE
  1376. SetWindowTextW( winState.appWindow, windowName );
  1377. #else
  1378. SetWindowTextA( winState.appWindow, windowName );
  1379. #endif
  1380. }
  1381. //--------------------------------------
  1382. S32 main(S32 argc, const char **argv)
  1383. {
  1384. winState.appInstance = GetModuleHandle(NULL);
  1385. return run(argc, argv);
  1386. }
  1387. //--------------------------------------
  1388. S32 PASCAL WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, S32)
  1389. {
  1390. Vector<char *> argv;
  1391. char moduleName[256];
  1392. GetModuleFileNameA(NULL, moduleName, sizeof(moduleName));
  1393. argv.push_back(moduleName);
  1394. for (const char* word,*ptr = lpszCmdLine; *ptr; ) {
  1395. // Eat white space
  1396. for (; dIsspace(*ptr) && *ptr; ptr++)
  1397. ;
  1398. // Pick out the next word
  1399. bool quote = false;
  1400. for (word = ptr; !(dIsspace(*ptr) && !quote) && *ptr; ptr++)
  1401. {
  1402. if(*ptr == '\"') quote = ! quote;
  1403. }
  1404. if(*word == '\"') ++word;
  1405. // Add the word to the argument list.
  1406. if (*word) {
  1407. int len = ptr - word;
  1408. if(*(ptr-1) == '\"') --len;
  1409. char *arg = (char *) dMalloc(len + 1);
  1410. dStrncpy(arg, word, len);
  1411. arg[len] = 0;
  1412. argv.push_back(arg);
  1413. }
  1414. }
  1415. winState.appInstance = hInstance;
  1416. S32 retVal = run(argv.size(), (const char **) argv.address());
  1417. for(U32 j = 1; j < (U32)argv.size(); j++)
  1418. dFree(argv[j]);
  1419. return retVal;
  1420. }
  1421. //--------------------------------------
  1422. void TimeManager::process()
  1423. {
  1424. if( winState.backgrounded )
  1425. winState.sleepTicks = Platform::getBackgroundSleepTime();
  1426. else
  1427. winState.sleepTicks = sgTimeManagerProcessInterval;
  1428. U32 elapsedTime = gTimer.getElapsedMS();
  1429. if( elapsedTime < winState.sleepTicks)
  1430. {
  1431. MsgWaitForMultipleObjects(0, NULL, false, winState.sleepTicks - elapsedTime, QS_ALLINPUT);
  1432. }
  1433. TimeEvent event;
  1434. event.elapsedTime = gTimer.getElapsedMS();
  1435. gTimer.advance();
  1436. Game->postEvent(event);
  1437. }
  1438. F32 Platform::getRandom()
  1439. {
  1440. return sgPlatRandom.randF();
  1441. }
  1442. ////--------------------------------------
  1443. /// Spawn the default Operating System web browser with a URL
  1444. /// @param webAddress URL to pass to browser
  1445. /// @return true if browser successfully spawned
  1446. bool Platform::openWebBrowser( const char* webAddress )
  1447. {
  1448. static bool sHaveKey = false;
  1449. static wchar_t sWebKey[512];
  1450. char utf8WebKey[512];
  1451. {
  1452. HKEY regKey;
  1453. DWORD size = sizeof( sWebKey );
  1454. if ( RegOpenKeyEx( HKEY_CLASSES_ROOT, dT("\\http\\shell\\open\\command"), 0, KEY_QUERY_VALUE, &regKey ) != ERROR_SUCCESS )
  1455. {
  1456. Con::errorf( ConsoleLogEntry::General, "Platform::openWebBrowser - Failed to open the HKCR\\http registry key!!!");
  1457. return( false );
  1458. }
  1459. if ( RegQueryValueEx( regKey, dT(""), NULL, NULL, (unsigned char *)sWebKey, &size ) != ERROR_SUCCESS )
  1460. {
  1461. Con::errorf( ConsoleLogEntry::General, "Platform::openWebBrowser - Failed to query the open command registry key!!!" );
  1462. return( false );
  1463. }
  1464. RegCloseKey( regKey );
  1465. sHaveKey = true;
  1466. convertUTF16toUTF8(sWebKey,utf8WebKey,512);
  1467. #ifdef UNICODE
  1468. char *p = dStrstr(utf8WebKey, "%1");
  1469. #else
  1470. char *p = dStrstr(sWebKey, "%1");
  1471. #endif
  1472. if (p) *p = 0;
  1473. }
  1474. STARTUPINFO si;
  1475. dMemset( &si, 0, sizeof( si ) );
  1476. si.cb = sizeof( si );
  1477. char buf[1024];
  1478. #ifdef UNICODE
  1479. dSprintf( buf, sizeof( buf ), "%s %s", utf8WebKey, webAddress );
  1480. UTF16 szCommandLine[1024];
  1481. convertUTF8toUTF16((UTF8 *)buf, szCommandLine, sizeof(szCommandLine));
  1482. #else
  1483. UTF8 szCommandLine[1024];
  1484. dSprintf( szCommandLine, sizeof( szCommandLine ), "%s %s", sWebKey, webAddress );
  1485. #endif
  1486. //Con::errorf( ConsoleLogEntry::General, "** Web browser command = %s **", buf );
  1487. PROCESS_INFORMATION pi;
  1488. dMemset( &pi, 0, sizeof( pi ) );
  1489. CreateProcess( NULL,
  1490. szCommandLine,
  1491. NULL,
  1492. NULL,
  1493. false,
  1494. CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
  1495. NULL,
  1496. NULL,
  1497. &si,
  1498. &pi );
  1499. return( true );
  1500. }
  1501. //--------------------------------------
  1502. // Platform functions for window menu
  1503. //--------------------------------------
  1504. // Creates the menu bar for the window
  1505. void CreateWin32MenuBar( void )
  1506. {
  1507. if( HasWin32MenuBar() )
  1508. {
  1509. DrawMenuBar( winState.appWindow );
  1510. return;
  1511. }
  1512. HMENU menu = CreateMenu();
  1513. if(menu)
  1514. {
  1515. winState.appMenu = menu;
  1516. SetMenu(winState.appWindow, menu);
  1517. DrawMenuBar(winState.appWindow);
  1518. }
  1519. }
  1520. void DestroyWin32MenuBar( void )
  1521. {
  1522. if( HasWin32MenuBar() )
  1523. DestroyMenu( winState.appMenu );
  1524. // Need to update platform window child rect?
  1525. DrawMenuBar(winState.appWindow);
  1526. }
  1527. bool HasWin32MenuBar( void )
  1528. {
  1529. return (bool)IsMenu( winState.appMenu );
  1530. }