winWindow.cc 50 KB

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