123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2013 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platformWin32/platformWin32.h"
- #include "platform/platform.h"
- #include "platformWin32/winWindow.h"
- #include "platformWin32/platformGL.h"
- #include "platform/platformVideo.h"
- #include "platformWin32/winOGLVideo.h"
- #include "platform/event.h"
- #include "console/console.h"
- #include "platformWin32/winConsole.h"
- #include "platformWin32/winDirectInput.h"
- #include "game/gameInterface.h"
- #include "math/mRandom.h"
- #include "io/fileStream.h"
- #include "game/resource.h"
- #include "string/unicode.h"
- #include "gui/guiCanvas.h"
- #include "platform/menus/popupMenu.h"
- #include "debug/profiler.h"
- //-------------------------------------- Resource Includes
- #include "graphics/gBitmap.h"
- #include <sys/stat.h>
- extern void createFontInit();
- extern void createFontShutdown();
- #ifdef UNICODE
- static const UTF16 *windowClassName = L"Darkstar Window Class";
- static UTF16 windowName[256] = L"Darkstar Window";
- #else
- static const char *windowClassName = "Darkstar Window Class";
- static char windowName[256] = "Darkstar Window";
- #endif
- static bool gWindowCreated = false;
- static bool windowNotActive = false;
- static RandomLCG sgPlatRandom;
- static bool sgQueueEvents;
- // is keyboard input a standard (non-changing) VK keycode
- #define dIsStandardVK(c) (((0x08 <= (c)) && ((c) <= 0x12)) || \
- ((c) == 0x1b) || \
- ((0x20 <= (c)) && ((c) <= 0x2e)) || \
- ((0x30 <= (c)) && ((c) <= 0x39)) || \
- ((0x41 <= (c)) && ((c) <= 0x5a)) || \
- ((0x70 <= (c)) && ((c) <= 0x7B)))
- extern U16 DIK_to_Key( U8 dikCode );
- Win32PlatState winState;
- //-----------------------------------------------------------------------------------------------------------------------------------------------------------
- //
- // Microsoft Layer for Unicode
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mslu/winprog/compiling_your_application_with_the_microsoft_layer_for_unicode.asp
- //
- //-----------------------------------------------------------------------------------------------------------------------------------------------------------
- #ifdef UNICODE
- HMODULE LoadUnicowsProc(void)
- {
- return(LoadLibraryA("unicows.dll"));
- }
- #ifdef _cplusplus
- extern "C" {
- #endif
- extern FARPROC _PfnLoadUnicows = (FARPROC) &LoadUnicowsProc;
- #ifdef _cplusplus
- }
- #endif
- #endif
- //--------------------------------------
- Win32PlatState::Win32PlatState()
- {
- log_fp = NULL;
- hinstOpenGL = NULL;
- hinstGLU = NULL;
- hinstOpenAL = NULL;
- appWindow = NULL;
- appDC = NULL;
- appInstance = NULL;
- currentTime = 0;
- processId = 0;
- appMenu = NULL;
- nMessagesPerFrame = 10;
- }
- static bool windowLocked = false;
- static BYTE keyboardState[256];
- static bool mouseButtonState[3];
- static bool capsLockDown = false;
- static S32 modifierKeys = 0;
- static bool windowActive = true;
- static Point2I lastCursorPos(0,0);
- static Point2I windowSize;
- static bool sgDoubleByteEnabled = false;
- //--------------------------------------
- static const char *getMessageName(S32 msg)
- {
- switch(msg)
- {
- case WM_KEYDOWN:
- return "WM_KEYDOWN";
- case WM_KEYUP:
- return "WM_KEYUP";
- case WM_SYSKEYUP:
- return "WM_SYSKEYUP";
- case WM_SYSKEYDOWN:
- return "WM_SYSKEYDOWN";
- default:
- return "Unknown!!";
- }
- }
- void Platform::restartInstance()
- {
- if( Game->isRunning() )
- {
- //Con::errorf( "Error restarting instance, Game is still running!");
- return;
- }
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- ZeroMemory( &si, sizeof(si) );
- si.cb = sizeof(si);
- ZeroMemory( &pi, sizeof(pi) );
- char cen_buf[2048];
- GetModuleFileNameA( NULL, cen_buf, 2047);
- #ifdef UNICODE
- UTF16 b[512];
- convertUTF8toUTF16((UTF8 *)cen_buf, b, sizeof(b));
- #else
- const char* b = cen_buf;
- #endif
- // Start the child process.
- if( CreateProcess( b,
- NULL, // Command line
- NULL, // Process handle not inheritable
- NULL, // Thread handle not inheritable
- FALSE, // Set handle inheritance to FALSE
- 0, // No creation flags
- NULL, // Use parent's environment block
- NULL, // Use parent's starting directory
- &si, // Pointer to STARTUPINFO structure
- &pi ) // Pointer to PROCESS_INFORMATION structure
- != false )
- {
- WaitForInputIdle( pi.hProcess, 5000 );
- CloseHandle( pi.hProcess );
- CloseHandle( pi.hThread );
- }
- }
- //--------------------------------------
- void Platform::AlertOK(const char *windowTitle, const char *message)
- {
- ShowCursor(true);
- #ifdef UNICODE
- UTF16 m[1024], t[512];
- convertUTF8toUTF16((UTF8 *)windowTitle, t, sizeof(t));
- convertUTF8toUTF16((UTF8 *)message, m, sizeof(m));
- MessageBox(winState.appWindow, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OK);
- #else
- MessageBox(winState.appWindow, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OK);
- #endif
- }
- //--------------------------------------
- bool Platform::AlertOKCancel(const char *windowTitle, const char *message)
- {
- ShowCursor(true);
- #ifdef UNICODE
- UTF16 m[1024], t[512];
- convertUTF8toUTF16((UTF8 *)windowTitle, t, sizeof(t));
- convertUTF8toUTF16((UTF8 *)message, m, sizeof(m));
- return MessageBox(winState.appWindow, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OKCANCEL) == IDOK;
- #else
- return MessageBox(winState.appWindow, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_OKCANCEL) == IDOK;
- #endif
- }
- //--------------------------------------
- bool Platform::AlertRetry(const char *windowTitle, const char *message)
- {
- ShowCursor(true);
- #ifdef UNICODE
- UTF16 m[1024], t[512];
- convertUTF8toUTF16((UTF8 *)windowTitle, t, sizeof(t));
- convertUTF8toUTF16((UTF8 *)message, m, sizeof(m));
- return (MessageBox(winState.appWindow, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_RETRYCANCEL) == IDRETRY);
- #else
- return (MessageBox(winState.appWindow, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_RETRYCANCEL) == IDRETRY);
- #endif
- }
- //Luma: YesNo alert message
- bool Platform::AlertYesNo(const char *windowTitle, const char *message)
- {
- ShowCursor(true);
- #ifdef UNICODE
- UTF16 m[1024], t[512];
- convertUTF8toUTF16((UTF8 *)windowTitle, t, sizeof(t));
- convertUTF8toUTF16((UTF8 *)message, m, sizeof(m));
- return MessageBox(winState.appWindow, m, t, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_YESNO) == IDYES;
- #else
- return MessageBox(winState.appWindow, message, windowTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TASKMODAL | MB_YESNO) == IDYES;
- #endif
- }
- //--------------------------------------
- HIMC gIMEContext;
- static void InitInput()
- {
- #ifndef TORQUE_LIB
- #ifdef UNICODE
- gIMEContext = ImmGetContext(winState.appWindow);
- ImmReleaseContext( winState.appWindow, gIMEContext );
- #endif
- #endif
- dMemset( keyboardState, 0, 256 );
- dMemset( mouseButtonState, 0, sizeof( mouseButtonState ) );
- capsLockDown = (GetKeyState(VK_CAPITAL) & 0x01);
- if (capsLockDown)
- {
- keyboardState[VK_CAPITAL] |= 0x01;
- }
- }
- //--------------------------------------
- static void setMouseClipping()
- {
- ClipCursor(NULL);
- if(windowActive)
- {
- RECT r;
- GetWindowRect(winState.appWindow, &r);
- if(windowLocked)
- {
- POINT p;
- GetCursorPos(&p);
- lastCursorPos.set(p.x - r.left, p.y - r.top);
- ClipCursor(&r);
- S32 centerX = (r.right + r.left) >> 1;
- S32 centerY = (r.bottom + r.top) >> 1;
- if(!windowNotActive)
- SetCursorPos(centerX, centerY);
- }
- else
- {
- if(!windowNotActive && false)
- SetCursorPos(lastCursorPos.x + r.left, lastCursorPos.y + r.top);
- }
- }
- }
- //--------------------------------------
- static bool sgTaskbarHidden = false;
- static HWND sgTaskbar = NULL;
- static void hideTheTaskbar()
- {
- // if ( !sgTaskbarHidden )
- // {
- // sgTaskbar = FindWindow( "Shell_TrayWnd", NULL );
- // if ( sgTaskbar )
- // {
- // APPBARDATA abData;
- // dMemset( &abData, 0, sizeof( abData ) );
- // abData.cbSize = sizeof( abData );
- // abData.hWnd = sgTaskbar;
- // SHAppBarMessage( ABM_REMOVE, &abData );
- // //ShowWindow( sgTaskbar, SW_HIDE );
- // sgTaskbarHidden = true;
- // }
- // }
- }
- static void restoreTheTaskbar()
- {
- // if ( sgTaskbarHidden )
- // {
- // APPBARDATA abData;
- // dMemset( &abData, 0, sizeof( abData ) );
- // abData.cbSize = sizeof( abData );
- // abData.hWnd = sgTaskbar;
- // SHAppBarMessage( ABM_ACTIVATE, &abData );
- // //ShowWindow( sgTaskbar, SW_SHOW );
- // sgTaskbarHidden = false;
- // }
- }
- //--------------------------------------
- void Platform::enableKeyboardTranslation(void)
- {
- #ifdef UNICODE
- // Con::printf("translating...");
- ImmAssociateContext( winState.appWindow, winState.imeHandle );
- #endif
- }
- //--------------------------------------
- void Platform::disableKeyboardTranslation(void)
- {
- #ifdef UNICODE
- // Con::printf("not translating...");
- ImmAssociateContext( winState.appWindow, NULL );
- #endif
- }
- //--------------------------------------
- void Platform::setMouseLock(bool locked)
- {
- windowLocked = locked;
- setMouseClipping();
- }
- //--------------------------------------
- void Platform::minimizeWindow()
- {
- ShowWindow(winState.appWindow, SW_MINIMIZE);
- restoreTheTaskbar();
- }
- void Platform::restoreWindow()
- {
- ShowWindow(winState.appWindow, SW_RESTORE);
- }
- //--------------------------------------
- static void processKeyMessage(UINT message, WPARAM wParam, LPARAM lParam)
- {
- S32 repeatCount = lParam & 0xffff;
- S32 scanCode = (lParam >> 16) & 0xff;
- S32 nVirtkey = dIsStandardVK(wParam) ? TranslateOSKeyCode(wParam) : DIK_to_Key(scanCode);
- S32 keyCode;
- if ( wParam == VK_PROCESSKEY && sgDoubleByteEnabled )
- keyCode = MapVirtualKey( scanCode, 1 ); // This is the REAL virtual key...
- else
- keyCode = wParam;
- bool extended = (lParam >> 24) & 1;
- bool repeat = (lParam >> 30) & 1;
- bool make = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN);
- S32 newVirtKey = nVirtkey;
- switch(nVirtkey)
- {
- case KEY_ALT:
- newVirtKey = extended ? KEY_RALT : KEY_LALT;
- break;
- case KEY_CONTROL:
- newVirtKey = extended ? KEY_RCONTROL : KEY_LCONTROL;
- break;
- case KEY_SHIFT:
- newVirtKey = ( scanCode == 54 ) ? KEY_RSHIFT : KEY_LSHIFT;
- break;
- case KEY_RETURN:
- if ( extended )
- newVirtKey = KEY_NUMPADENTER;
- break;
- }
- S32 modKey = modifierKeys;
- if(make)
- {
- switch (newVirtKey)
- {
- case KEY_LSHIFT: modifierKeys |= SI_LSHIFT; modKey = 0; break;
- case KEY_RSHIFT: modifierKeys |= SI_RSHIFT; modKey = 0; break;
- case KEY_LCONTROL: modifierKeys |= SI_LCTRL; modKey = 0; break;
- case KEY_RCONTROL: modifierKeys |= SI_RCTRL; modKey = 0; break;
- case KEY_LALT: modifierKeys |= SI_LALT; modKey = 0; break;
- case KEY_RALT: modifierKeys |= SI_RALT; modKey = 0; break;
- }
- if(nVirtkey == KEY_CAPSLOCK)
- {
- capsLockDown = !capsLockDown;
- if(capsLockDown)
- keyboardState[keyCode] |= 0x01;
- else
- keyboardState[keyCode] &= 0xFE;
- }
- keyboardState[keyCode] |= 0x80;
- }
- else
- {
- switch (newVirtKey)
- {
- case KEY_LSHIFT: modifierKeys &= ~SI_LSHIFT; modKey = 0; break;
- case KEY_RSHIFT: modifierKeys &= ~SI_RSHIFT; modKey = 0; break;
- case KEY_LCONTROL: modifierKeys &= ~SI_LCTRL; modKey = 0; break;
- case KEY_RCONTROL: modifierKeys &= ~SI_RCTRL; modKey = 0; break;
- case KEY_LALT: modifierKeys &= ~SI_LALT; modKey = 0; break;
- case KEY_RALT: modifierKeys &= ~SI_RALT; modKey = 0; break;
- }
- keyboardState[keyCode] &= 0x7f;
- }
- U16 ascii[3];
- WORD asciiCode = 0;
- dMemset( &ascii, 0, sizeof( ascii ) );
- S32 res = ToUnicode( keyCode, scanCode, keyboardState, ascii, 3, 0 );
- // This should only happen on Window 9x/ME systems
- if (res == 0)
- res = ToAscii( keyCode, scanCode, keyboardState, ascii, 0 );
- if (res == 2)
- {
- asciiCode = ascii[1];
- }
- else if ((res == 1) || (res < 0))
- {
- asciiCode = ascii[0];
- }
- InputEvent event;
- event.deviceInst = 0;
- event.deviceType = KeyboardDeviceType;
- event.objType = SI_KEY;
- event.objInst = newVirtKey;
- event.action = make ? (repeat ? SI_REPEAT : SI_MAKE ) : SI_BREAK;
- event.modifier = modKey;
- event.ascii = asciiCode;
- event.fValue = make ? 1.0f : 0.0f;
- // Store the current modifier keys
- Input::setModifierKeys(modifierKeys);
- Game->postEvent(event);
- }
- static void processCharMessage( WPARAM wParam, LPARAM lParam )
- {
- TCHAR charCode = wParam;
- UTF16 tmpString[2] = { charCode, 0 };
- UTF8 out[256];
- convertUTF16toUTF8(tmpString, out, 250);
- // Con::printf("Got IME char code %x (%s)", charCode, out);
- InputEvent event;
- event.deviceInst = 0;
- event.deviceType = KeyboardDeviceType;
- event.objType = SI_KEY;
- event.action = SI_MAKE;
- event.ascii = charCode;
- // Deal with some silly cases like <BS>. This might be indicative of a
- // missing MapVirtualKey step, not quite sure how to deal with this.
- if(event.ascii == 0x8)
- event.objInst = KEY_BACKSPACE; // Note we abuse objInst.
- Game->postEvent(event);
- // And put it back up as well, they can't hold it!
- event.action = SI_BREAK;
- Game->postEvent(event);
- }
- static S32 mouseX = 0xFFFFFFFF;
- static S32 mouseY = 0xFFFFFFFF;
- //--------------------------------------
- static void CheckCursorPos()
- {
- if(windowLocked && windowActive)
- {
- POINT mousePos;
- GetCursorPos(&mousePos);
- RECT r;
- GetWindowRect(winState.appWindow, &r);
- S32 centerX = (r.right + r.left) >> 1;
- S32 centerY = (r.bottom + r.top) >> 1;
- if(mousePos.x != centerX)
- {
- InputEvent event;
- event.deviceInst = 0;
- event.deviceType = MouseDeviceType;
- event.objType = SI_XAXIS;
- event.objInst = 0;
- event.action = SI_MOVE;
- event.modifier = modifierKeys;
- event.ascii = 0;
- event.fValue = (F32)(mousePos.x - centerX);
- Game->postEvent(event);
- }
- if(mousePos.y != centerY)
- {
- InputEvent event;
- event.deviceInst = 0;
- event.deviceType = MouseDeviceType;
- event.objType = SI_YAXIS;
- event.objInst = 0;
- event.action = SI_MOVE;
- event.modifier = modifierKeys;
- event.ascii = 0;
- event.fValue = (F32)(mousePos.y - centerY);
- Game->postEvent(event);
- }
- SetCursorPos(centerX, centerY);
- }
- }
- //--------------------------------------
- static void mouseButtonEvent(S32 action, S32 objInst)
- {
- CheckCursorPos();
- if(!windowLocked)
- {
- if(action == SI_MAKE)
- SetCapture(winState.appWindow);
- else
- ReleaseCapture();
- }
- U32 buttonId = objInst - KEY_BUTTON0;
- if ( buttonId < 3 )
- mouseButtonState[buttonId] = ( action == SI_MAKE ) ? true : false;
- InputEvent event;
- event.deviceInst = 0;
- event.deviceType = MouseDeviceType;
- event.objType = SI_BUTTON;
- event.objInst = objInst;
- event.action = action;
- event.modifier = modifierKeys;
- event.ascii = 0;
- event.fValue = action == SI_MAKE ? 1.0f : 0.0f;
- Game->postEvent(event);
- }
- //--------------------------------------
- static void mouseWheelEvent( S32 delta )
- {
- static S32 _delta = 0;
- _delta += delta;
- if ( abs( delta ) >= WHEEL_DELTA )
- {
- _delta = 0;
- InputEvent event;
- event.deviceInst = 0;
- event.deviceType = MouseDeviceType;
- event.objType = SI_ZAXIS;
- event.objInst = 0;
- event.action = SI_MOVE;
- event.modifier = modifierKeys;
- event.ascii = 0;
- event.fValue = (F32)delta;
- Game->postEvent( event );
- }
- }
- struct WinMessage
- {
- UINT message;
- WPARAM wParam;
- LPARAM lParam;
- WinMessage() {};
- WinMessage(UINT m, WPARAM w, LPARAM l) : message(m), wParam(w), lParam(l) {}
- };
- Vector<WinMessage> sgWinMessages;
- #ifndef PBT_APMQUERYSUSPEND
- #define PBT_APMQUERYSUSPEND 0x0000
- #endif
- bool sgKeyboardStateDirty = false;
- //--------------------------------------
- static LRESULT PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- switch ( message )
- {
- // Window DragDrop-enabled [12/14/2006 justind]
- case WM_CREATE:
- DragAcceptFiles(hWnd, TRUE);
- break;
- case WM_DESTROY:
- DragAcceptFiles(hWnd, FALSE);
- break;
- case WM_DROPFILES:
- // Retrieve Number of files
-
- // Strict policy on these things, better safe than sorry
- if( !Con::isFunction( "onDropBegin") || !Con::isFunction("onDropFile")
- || !Con::isFunction("onDropEnd") )
- break;
- int nFileCount; // Number of Files
- HDROP hTheDrop; // The Drop Handle
- hTheDrop = (HDROP)wParam;
- nFileCount = DragQueryFile(hTheDrop, 0xFFFFFFFF, NULL, 0);
- if( nFileCount == 0 )
- break;
- // Notify Drop-Begin
- Con::executef( 2, "onDropBegin", Con::getIntArg( nFileCount ) );
- int nI;
- for (nI = 0; nI < nFileCount; nI++)
- {
- LPTSTR pszTheBuffer[MAX_PATH];
- ZeroMemory( pszTheBuffer, MAX_PATH );
- // Query it
- // FIXME: Deal with Unicode
- DragQueryFileA(hTheDrop, nI, (LPSTR)pszTheBuffer, sizeof(pszTheBuffer));
- // Notify Drop
- if (Platform::isFile( (const char*)pszTheBuffer ))
- {
- // The timeout for waiting for files (ms).
- U32 timeout = 5000;
- // Need to make sure the file is copyable. When ganking images from Firefox, it
- // isn't necessarily since Firefox insists on redownloading the file instead of
- // using the local copy.
- U32 time = Platform::getRealMilliseconds() + timeout;
- HANDLE hfile;
- while((hfile = ::CreateFileA((const char*)pszTheBuffer, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
- {
- // Don't wait too long.
- if(Platform::getRealMilliseconds() > time)
- break;
- }
- if(hfile == INVALID_HANDLE_VALUE)
- continue;
- CloseHandle(hfile);
- Con::executef( 2, "onDropFile", StringTable->insert((const char*)pszTheBuffer) );
- }
- }
- DragFinish(hTheDrop);
- // Notify Drop-Begin
- Con::executef( 2, "onDropEnd", Con::getIntArg( nFileCount ) );
- break;
- // Window Min Extents - [9/20/2006 justind]
- case WM_GETMINMAXINFO:
- MINMAXINFO *winfo;
- winfo = (MINMAXINFO*)(lParam);
- //MIN_RESOLUTION defined in platformWin32/platformGL.h
- winfo->ptMinTrackSize.x = MIN_RESOLUTION_X;
- winfo->ptMinTrackSize.y = MIN_RESOLUTION_Y;
- break;
- case WM_POWERBROADCAST:
- {
- if(wParam == PBT_APMQUERYSUSPEND)
- return BROADCAST_QUERY_DENY;
- return true;
- }
- case WM_ACTIVATEAPP:
- if ((bool) wParam)
- {
- Video::reactivate();
- if ( Video::isFullScreen() )
- hideTheTaskbar();
- // HACK: Windows 98 (after switching from fullscreen to windowed mode)
- SetForegroundWindow( winState.appWindow );
- // If our keyboard state is dirty, clear it
- if( sgKeyboardStateDirty == true )
- {
- sgKeyboardStateDirty = false;
- InitInput();
- }
- }
- else
- {
- // Window lost focus so set a dirty flag on the keyboard state
- if ( lParam == 0 )
- sgKeyboardStateDirty = true;
-
- Video::deactivate();
- restoreTheTaskbar();
- }
- break;
- case WM_SYSCOMMAND:
- switch(wParam)
- {
- case SC_KEYMENU:
- case SC_SCREENSAVE:
- case SC_MONITORPOWER:
- if(GetForegroundWindow() == winState.appWindow)
- {
- return 0;
- }
- break;
- // Catch Close button press event [1/5/2007 justind]
- case SC_CLOSE:
- if (Con::isFunction("onClosePressed"))
- {
- Con::executef( 1, "onClosePressed" );
- return 0;
- }
- break;
- }
- break;
- case WM_ACTIVATE:
- windowActive = LOWORD(wParam) != WA_INACTIVE;
- if( Game->isRunning() )
- {
- if (Con::isFunction("onWindowFocusChange"))
- Con::executef( 2, "onWindowFocusChange", windowActive ? "1" : "0" );
- }
- if ( windowActive )
- {
- setMouseClipping();
- windowNotActive = false;
- Game->refreshWindow();
- Input::activate();
- }
- else
- {
- setMouseClipping();
- windowNotActive = true;
- DInputManager* mgr = dynamic_cast<DInputManager*>( Input::getManager() );
- if ( !mgr || !mgr->isMouseActive() )
- {
- // Deactivate all the mouse triggers:
- for ( U32 i = 0; i < 3; i++ )
- {
- if ( mouseButtonState[i] )
- mouseButtonEvent( SI_BREAK, KEY_BUTTON0 + i );
- }
- }
- Input::deactivate();
- }
- break;
- case WM_MOVE:
- Game->refreshWindow();
- break;
- // This override will keep windows from blacking out the background, wee!
- case WM_ERASEBKGND:
- return 0;
- case WM_SIZE:
- if(wParam != SIZE_MINIMIZED) // DAW: If window is minimized, don't do an internal resize or the universe will end
- {
- S32 nWidth, nHeight;
- nWidth = LOWORD(lParam);
- nHeight = HIWORD(lParam);
- Platform::setWindowSize( nWidth, nHeight );
-
- Game->gameReactivate();
- // MP: Commented out the if check to expose this variable no matter what the resizing is. This will help out the teams
- // that rely on knowing the windowRes for their tools (like Black Jack's card generator).
- //
- // If we're greater than MIN_RESOLUTION and less than our client desktop area, store as windowed mode pref resolution
- //if( ( nWidth > MIN_RESOLUTION_X && nWidth < winState.desktopClientWidth ) && ( nHeight > MIN_RESOLUTION_Y && nHeight < winState.desktopClientHeight ) )
- //{
- char tempBuf[32];
- dSprintf( tempBuf, sizeof(char) * 32, "%d %d %d", nWidth,nHeight, 16 );
- Con::setVariable( "$pref::Video::windowedRes", tempBuf );
- //}
- }
- else
- {
- // Deactivate ourselves when we're hidden
- Game->gameDeactivate( true );
- }
- break;
- case MM_MCINOTIFY:
- //handleRedBookCallback(wParam, lParam);
- break;
- //case WM_DESTROY:
- case WM_CLOSE:
- PostQuitMessage(0);
- break;
- case WM_SETFOCUS:
- winState.renderThreadBlocked = false;
- break;
- case WM_KILLFOCUS:
- winState.renderThreadBlocked = true;
- break;
- case WM_COMMAND:
- if(HIWORD(wParam) == 0)
- {
- winState.renderThreadBlocked = false;
- // This command came from a menu choice. Pass along the menu ID to a
- // script function
- // [tom, 8/21/2006] Pass off to the relevant PopupMenu
- S32 numItems = GetMenuItemCount(winState.appMenu);
- for(S32 i = 0;i < numItems;i++)
- {
- MENUITEMINFOA mi;
- mi.cbSize = sizeof(mi);
- mi.fMask = MIIM_DATA;
- if(GetMenuItemInfoA(winState.appMenu, i, TRUE, &mi))
- {
- if(mi.fMask & MIIM_DATA)
- {
- PopupMenu *mnu = (PopupMenu *)mi.dwItemData;
- if(mnu->canHandleID(LOWORD(wParam)))
- mnu->handleSelect(LOWORD(wParam));
- }
- }
- }
- }
- break;
- case WM_MENUSELECT:
- winState.renderThreadBlocked = true;
- case WM_PAINT:
- if(winState.renderThreadBlocked)
- Canvas->renderFrame(false);
- break;
- #ifdef UNICODE
- case WM_INPUTLANGCHANGE:
- // Con::printf("IME lang change");
- break;
- case WM_IME_SETCONTEXT:
- // Con::printf("IME set context");
- break;
- case WM_IME_COMPOSITION:
- // Con::printf("IME comp");
- break;
- case WM_IME_STARTCOMPOSITION:
- // Con::printf("IME start comp");
- break;
- #endif
- default:
- {
- if (sgQueueEvents)
- {
- WinMessage msg(message,wParam,lParam);
- sgWinMessages.push_front(msg);
- }
- }
- }
- return DefWindowProc(hWnd, message, wParam, lParam);
- }
- //--------------------------------------
- static void OurDispatchMessages()
- {
- WinMessage msg(0,0,0);
- UINT message;
- WPARAM wParam;
- LPARAM lParam;
- DInputManager* mgr = dynamic_cast<DInputManager*>( Input::getManager() );
- while (sgWinMessages.size())
- {
- msg = sgWinMessages.front();
- sgWinMessages.pop_front();
- message = msg.message;
- wParam = msg.wParam;
- lParam = msg.lParam;
- if ( !mgr || !mgr->isMouseActive() )
- {
- switch ( message )
- {
- #ifdef UNICODE
- case WM_IME_COMPOSITION:
- {
- // Con::printf("OMG IME comp");
- break;
- }
- case WM_IME_ENDCOMPOSITION:
- {
- // Con::printf("OMG IME end comp");
- break;
- }
- case WM_IME_NOTIFY:
- {
- // Con::printf("OMG IME notify");
- break;
- }
- case WM_IME_CHAR:
- processCharMessage( wParam, lParam );
- break;
- #endif
- // We want to show the system cursor whenever we leave
- // our window, and it'd be simple, except for one problem:
- // showcursor isn't a toggle. so, keep hammering it until
- // the cursor is *actually* going to be shown.
- case WM_NCMOUSEMOVE:
- {
- break;
- }
- case WM_MOUSEMOVE:
- // keep trying until we actually show it
- Input::refreshCursor();
- if ( !windowLocked )
- {
- MouseMoveEvent event;
- S16 xPos = LOWORD(lParam);
- S16 yPos = HIWORD(lParam);
- event.xPos = xPos; // horizontal position of cursor
- if( winState.appMenu != NULL )
- {
- S32 menuHeight = GetSystemMetrics(SM_CYMENU);
- event.yPos = ( yPos ); // vertical position of cursor
- }
- else
- event.yPos = yPos; // vertical position of cursor
- event.modifier = modifierKeys;
- Game->postEvent(event);
- }
- break;
- case WM_LBUTTONDOWN:
- mouseButtonEvent(SI_MAKE, KEY_BUTTON0);
- break;
- case WM_MBUTTONDOWN:
- mouseButtonEvent(SI_MAKE, KEY_BUTTON2);
- break;
- case WM_RBUTTONDOWN:
- mouseButtonEvent(SI_MAKE, KEY_BUTTON1);
- break;
- case WM_LBUTTONUP:
- mouseButtonEvent(SI_BREAK, KEY_BUTTON0);
- break;
- case WM_MBUTTONUP:
- mouseButtonEvent(SI_BREAK, KEY_BUTTON2);
- break;
- case WM_RBUTTONUP:
- mouseButtonEvent(SI_BREAK, KEY_BUTTON1);
- break;
- case WM_MOUSEWHEEL:
- mouseWheelEvent( (S16) HIWORD( wParam ) );
- break;
- }
- }
- if ( !mgr || !mgr->isKeyboardActive() )
- {
- switch ( message )
- {
- case WM_KEYUP:
- case WM_SYSKEYUP:
- case WM_KEYDOWN:
- case WM_SYSKEYDOWN:
- processKeyMessage(message, wParam, lParam);
- break;
- }
- }
- }
- }
- //--------------------------------------
- static bool ProcessMessages()
- {
- MSG msg;
- PROFILE_SCOPE(ProcessMessages_MAIN);
- S32 nMessagesDispatched = 0;
- while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
- {
- if(msg.message == WM_QUIT)
- return false;
- PROFILE_START(TranslateMessage);
- TranslateMessage(&msg);
- PROFILE_END();
- PROFILE_START(DispatchMessage);
- DispatchMessage(&msg);
- PROFILE_END();
- PROFILE_START(OurDispatchMessages);
- OurDispatchMessages();
- PROFILE_END();
- nMessagesDispatched++;
- if( nMessagesDispatched >= winState.nMessagesPerFrame )
- break;
- }
- return true;
- }
- //--------------------------------------
- void Platform::process()
- {
- PROFILE_START(GetInputManager);
- DInputManager* mgr = dynamic_cast<DInputManager*>( Input::getManager() );
- PROFILE_END();
- if ( !mgr || !mgr->isMouseActive() )
- {
- PROFILE_SCOPE(InputManagerCheckCursor);
- CheckCursorPos();
- }
- PROFILE_START(WinConsoleProcess);
- WindowsConsole->process();
- PROFILE_END();
- PROFILE_START(ProcessMessages);
- if(!ProcessMessages())
- {
- PROFILE_SCOPE(PostEvent);
- // generate a quit event
- Event quitEvent;
- quitEvent.type = QuitEventType;
- Game->postEvent(quitEvent);
- }
- PROFILE_END();
- PROFILE_START(GetForegroundWindow);
- HWND window = GetForegroundWindow();
- PROFILE_END();
- // assume that we are in the foreground,
- winState.backgrounded = false;
- // unless we see that the foreground window does not belong to this process.
- if (window && window != winState.appWindow && gWindowCreated)
- {
- DWORD foregroundProcessId;
- GetWindowThreadProcessId(window, &foregroundProcessId);
- if (foregroundProcessId != winState.processId)
- winState.backgrounded = true;
- }
- PROFILE_SCOPE(InputProcess);
- Input::process();
- }
- extern U32 calculateCRC(void * buffer, S32 len, U32 crcVal );
- #if defined(TORQUE_DEBUG) || defined(INTERNAL_RELEASE)
- static U32 stubCRC = 0;
- #else
- static U32 stubCRC = 0xEA63F56C;
- #endif
- //--------------------------------------
- static void InitWindowClass()
- {
- WNDCLASS wc;
- dMemset(&wc, 0, sizeof(wc));
- wc.style = CS_OWNDC;
- wc.lpfnWndProc = WindowProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = winState.appInstance;
- wc.hIcon = LoadIcon(winState.appInstance, MAKEINTRESOURCE(IDI_TORQUE2D));
- wc.hCursor = LoadCursor (NULL,IDC_ARROW);
- wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
- wc.lpszMenuName = 0;
- wc.lpszClassName = windowClassName;
- RegisterClass( &wc );
- // Curtain window class:
- wc.lpfnWndProc = DefWindowProc;
- wc.hCursor = NULL;
- wc.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
- wc.lpszClassName = dT("Curtain");
- RegisterClass( &wc );
- }
- //--------------------------------------
- Resolution Video::getDesktopResolution()
- {
- Resolution Result;
- RECT clientRect;
- HWND hDesktop = GetDesktopWindow();
- HDC hDeskDC = GetDC( hDesktop );
- // Retrieve Resolution Information.
- Result.bpp = winState.desktopBitsPixel = GetDeviceCaps( hDeskDC, BITSPIXEL );
- Result.w = winState.desktopWidth = GetDeviceCaps( hDeskDC, HORZRES );
- Result.h = winState.desktopHeight = GetDeviceCaps( hDeskDC, VERTRES );
- // Release Device Context.
- ReleaseDC( hDesktop, hDeskDC );
- SystemParametersInfo(SPI_GETWORKAREA, 0, &clientRect, 0);
- winState.desktopClientWidth = clientRect.right;
- winState.desktopClientHeight = clientRect.bottom;
- // Return Result;
- return Result;
- }
- //--------------------------------------
- HWND CreateOpenGLWindow( U32 width, U32 height, bool fullScreen, bool allowSizing )
- {
- S32 windowStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
- S32 exWindowStyle = 0;
- if ( fullScreen )
- windowStyle |= ( WS_POPUP | WS_MAXIMIZE );
- else
- if (!allowSizing)
- windowStyle |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
- else
- windowStyle |= ( WS_OVERLAPPEDWINDOW );
- return CreateWindowEx(
- exWindowStyle,
- windowClassName,
- windowName,
- windowStyle,
- 0, 0, width, height,
- NULL, NULL,
- winState.appInstance,
- NULL);
- }
- //--------------------------------------
- HWND CreateCurtain( U32 width, U32 height )
- {
- return CreateWindow(
- dT("Curtain"),
- dT(""),
- ( WS_POPUP | WS_MAXIMIZE ),
- 0, 0,
- width, height,
- NULL, NULL,
- winState.appInstance,
- NULL );
- }
- //--------------------------------------
- void CreatePixelFormat( PIXELFORMATDESCRIPTOR *pPFD, S32 colorBits, S32 depthBits, S32 stencilBits, bool stereo )
- {
- PIXELFORMATDESCRIPTOR src =
- {
- sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
- 1, // version number
- PFD_DRAW_TO_WINDOW | // support window
- PFD_SUPPORT_OPENGL | // support OpenGL
- PFD_DOUBLEBUFFER, // double buffered
- PFD_TYPE_RGBA, // RGBA type
- colorBits, // color depth
- 0, 0, 0, 0, 0, 0, // color bits ignored
- 0, // no alpha buffer
- 0, // shift bit ignored
- 0, // no accumulation buffer
- 0, 0, 0, 0, // accum bits ignored
- depthBits, // z-buffer
- stencilBits, // stencil buffer
- 0, // no auxiliary buffer
- PFD_MAIN_PLANE, // main layer
- 0, // reserved
- 0, 0, 0 // layer masks ignored
- };
- if ( stereo )
- {
- //ri.Printf( PRINT_ALL, "...attempting to use stereo\n" );
- src.dwFlags |= PFD_STEREO;
- //glConfig.stereoEnabled = true;
- }
- else
- {
- //glConfig.stereoEnabled = qfalse;
- }
- *pPFD = src;
- }
- //--------------------------------------
- enum WinConstants { MAX_PFDS = 256 };
- #ifndef PFD_GENERIC_ACCELERATED
- #define PFD_GENERIC_ACCELERATED 0x00001000
- #endif
- S32 ChooseBestPixelFormat(HDC hDC, PIXELFORMATDESCRIPTOR *pPFD)
- {
- PIXELFORMATDESCRIPTOR pfds[MAX_PFDS+1];
- S32 i;
- S32 bestMatch = 0;
- S32 maxPFD = dwglDescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), &pfds[0]);
- if(maxPFD > MAX_PFDS)
- maxPFD = MAX_PFDS;
- bool accelerated = false;
- for(i = 1; i <= maxPFD; i++)
- {
- dwglDescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfds[i]);
- // make sure this has hardware acceleration:
- if ( ( pfds[i].dwFlags & PFD_GENERIC_FORMAT ) != 0 )
- continue;
- // verify pixel type
- if ( pfds[i].iPixelType != PFD_TYPE_RGBA )
- continue;
- // verify proper flags
- if ( ( ( pfds[i].dwFlags & pPFD->dwFlags ) & pPFD->dwFlags ) != pPFD->dwFlags )
- continue;
- accelerated = !(pfds[i].dwFlags & PFD_GENERIC_FORMAT);
- //
- // selection criteria (in order of priority):
- //
- // PFD_STEREO
- // colorBits
- // depthBits
- // stencilBits
- //
- if ( bestMatch )
- {
- // check stereo
- if ( ( pfds[i].dwFlags & PFD_STEREO ) && ( !( pfds[bestMatch].dwFlags & PFD_STEREO ) ) && ( pPFD->dwFlags & PFD_STEREO ) )
- {
- bestMatch = i;
- continue;
- }
- if ( !( pfds[i].dwFlags & PFD_STEREO ) && ( pfds[bestMatch].dwFlags & PFD_STEREO ) && ( pPFD->dwFlags & PFD_STEREO ) )
- {
- bestMatch = i;
- continue;
- }
- // check color
- if ( pfds[bestMatch].cColorBits != pPFD->cColorBits )
- {
- // prefer perfect match
- if ( pfds[i].cColorBits == pPFD->cColorBits )
- {
- bestMatch = i;
- continue;
- }
- // otherwise if this PFD has more bits than our best, use it
- else if ( pfds[i].cColorBits > pfds[bestMatch].cColorBits )
- {
- bestMatch = i;
- continue;
- }
- }
- // check depth
- if ( pfds[bestMatch].cDepthBits != pPFD->cDepthBits )
- {
- // prefer perfect match
- if ( pfds[i].cDepthBits == pPFD->cDepthBits )
- {
- bestMatch = i;
- continue;
- }
- // otherwise if this PFD has more bits than our best, use it
- else if ( pfds[i].cDepthBits > pfds[bestMatch].cDepthBits )
- {
- bestMatch = i;
- continue;
- }
- }
- // check stencil
- if ( pfds[bestMatch].cStencilBits != pPFD->cStencilBits )
- {
- // prefer perfect match
- if ( pfds[i].cStencilBits == pPFD->cStencilBits )
- {
- bestMatch = i;
- continue;
- }
- // otherwise if this PFD has more bits than our best, use it
- else if ( ( pfds[i].cStencilBits > pfds[bestMatch].cStencilBits ) &&
- ( pPFD->cStencilBits > 0 ) )
- {
- bestMatch = i;
- continue;
- }
- }
- }
- else
- {
- bestMatch = i;
- }
- }
- if ( !bestMatch )
- return 0;
- else if ( pfds[bestMatch].dwFlags & PFD_GENERIC_ACCELERATED )
- {
- // MCD
- }
- else
- {
- // ICD
- }
- *pPFD = pfds[bestMatch];
- return bestMatch;
- }
- //--------------------------------------
- //
- // This function exists so DirectInput can communicate with the Windows mouse
- // in windowed mode.
- //
- //--------------------------------------
- void setModifierKeys( S32 modKeys )
- {
- modifierKeys = modKeys;
- }
- //--------------------------------------
- const Point2I &Platform::getWindowSize()
- {
- return windowSize;
- }
- //--------------------------------------
- void Platform::setWindowSize( U32 newWidth, U32 newHeight )
- {
- windowSize.set( newWidth, newHeight );
- }
- //RectI Platform::getWindowClientRect()
- //{
- // RECT rClientRect;
- // GetClientRect( winState.appWindow, &rClientRect );
- //
- // if( winState.appMenu == NULL )
- // return RectI( rClientRect.left, rClientRect.top, rClientRect.right - rClientRect.left, rClientRect.bottom - rClientRect.top );
- //
- // S32 menuHeight = GetSystemMetrics(SM_CYMENU);
- // return RectI( rClientRect.left, rClientRect.top + menuHeight, rClientRect.right - rClientRect.left, rClientRect.bottom - ( rClientRect.top + menuHeight ) );
- //}
- //--------------------------------------
- static void InitWindow(const Point2I &initialSize)
- {
- windowSize = initialSize;
- // The window is created when the display device is activated. BH
- winState.processId = GetCurrentProcessId();
- }
- //--------------------------------------
- static void InitOpenGL()
- {
- // The OpenGL initialization stuff has been mostly moved to the display
- // devices' activate functions. BH
- DisplayDevice::init();
- bool fullScreen = Con::getBoolVariable( "$pref::Video::fullScreen" );
- const char* resString = Con::getVariable( ( fullScreen ? "$pref::Video::resolution" : "$pref::Video::windowedRes" ) );
- // Get the video settings from the prefs:
- char* tempBuf = new char[dStrlen( resString ) + 1];
- dStrcpy( tempBuf, resString );
- char* temp = dStrtok( tempBuf, " x\0" );
- //MIN_RESOLUTION defined in platformWin32/platformGL.h
- U32 width = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_X );
- temp = dStrtok( NULL, " x\0" );
- U32 height = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_Y );
- temp = dStrtok( NULL, "\0" );
- U32 bpp = ( temp ? dAtoi( temp ) : MIN_RESOLUTION_BIT_DEPTH );
- delete [] tempBuf;
- // If no device is specified, see which ones we have...
- if ( !Video::setDevice( Con::getVariable( "$pref::Video::displayDevice" ), width, height, bpp, fullScreen ) )
- {
- // First, try the default OpenGL device:
- if ( !Video::setDevice( "OpenGL", width, height, bpp, fullScreen ) )
- {
- AssertFatal( false, "Could not find a compatible display device!" );
- return;
- }
- }
- }
- //--------------------------------------
- void Platform::init()
- {
- // Set the platform variable for the scripts
- Con::setVariable( "$platform", "windows" );
- WinConsole::create();
- if ( !WinConsole::isEnabled() )
- Input::init();
- InitInput(); // in case DirectInput falls through
- InitWindowClass();
- Video::getDesktopResolution();
- //installRedBookDevices();
- sgDoubleByteEnabled = GetSystemMetrics( SM_DBCSENABLED );
- sgQueueEvents = true;
- }
- //--------------------------------------
- void Platform::shutdown()
- {
- sgQueueEvents = false;
- setMouseLock( false );
- Video::destroy();
- Input::destroy();
- WinConsole::destroy();
- }
- class WinTimer
- {
- private:
- U32 mTickCountCurrent;
- U32 mTickCountNext;
- S64 mPerfCountCurrent;
- S64 mPerfCountNext;
- S64 mFrequency;
- F64 mPerfCountRemainderCurrent;
- F64 mPerfCountRemainderNext;
- bool mUsingPerfCounter;
- public:
- WinTimer()
- {
- SetProcessAffinityMask( GetCurrentProcess(), 1 );
- mPerfCountRemainderCurrent = 0.0f;
- mUsingPerfCounter = QueryPerformanceFrequency((LARGE_INTEGER *) &mFrequency);
- if(mUsingPerfCounter)
- mUsingPerfCounter = QueryPerformanceCounter((LARGE_INTEGER *) &mPerfCountCurrent);
- if(!mUsingPerfCounter)
- mTickCountCurrent = GetTickCount();
- }
- U32 getElapsedMS()
- {
- if(mUsingPerfCounter)
- {
- QueryPerformanceCounter( (LARGE_INTEGER *) &mPerfCountNext);
- F64 elapsedF64 = (1000.0 * F64(mPerfCountNext - mPerfCountCurrent) / F64(mFrequency));
- elapsedF64 += mPerfCountRemainderCurrent;
- U32 elapsed = (U32)mFloor((F32)elapsedF64);
- mPerfCountRemainderNext = elapsedF64 - F64(elapsed);
- return elapsed;
- }
- else
- {
- mTickCountNext = GetTickCount();
- return mTickCountNext - mTickCountCurrent;
- }
- }
- void advance()
- {
- mTickCountCurrent = mTickCountNext;
- mPerfCountCurrent = mPerfCountNext;
- mPerfCountRemainderCurrent = mPerfCountRemainderNext;
- }
- };
- static WinTimer gTimer;
- extern bool LinkConsoleFunctions;
- //--------------------------------------
- static S32 run(S32 argc, const char **argv)
- {
- // Initialize fonts.
- createFontInit();
- windowSize.set(0,0);
- // Finish if the game didn't initialize.
- if(!Game->mainInitialize(argc, argv) )
- return 0;
- // run the game main loop.
- while( Game->isRunning() )
- {
- Game->mainLoop();
- }
- // Shut the game down.
- Game->mainShutdown();
- // Destroy fonts.
- createFontShutdown();
- return 0;
- }
- //--------------------------------------
- void Platform::initWindow(const Point2I &initialSize, const char *name)
- {
- MSG msg;
- Con::printSeparator();
- Con::printf("Video Initialization:");
- Video::init();
- PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
- if ( Video::installDevice( OpenGLDevice::create() ) )
- Con::printf( " Accelerated OpenGL display device detected." );
- else
- Con::printf( " Accelerated OpenGL display device not detected." );
- Con::printf( "" );
- gWindowCreated = true;
- #ifdef UNICODE
- convertUTF8toUTF16((UTF8 *)name, windowName, sizeof(windowName));
- #else
- dStrcpy(windowName, name);
- #endif
- PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
- InitWindow(initialSize);
- PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
- InitOpenGL();
- PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
- }
- void Platform::setWindowTitle( const char* title )
- {
- if( !title || !title[0] )
- return;
- #ifdef UNICODE
- convertUTF8toUTF16((UTF8 *)title, windowName, sizeof(windowName));
- #else
- dStrcpy(windowName, title);
- #endif
- if( winState.appWindow )
- #ifdef UNICODE
- SetWindowTextW( winState.appWindow, windowName );
- #else
- SetWindowTextA( winState.appWindow, windowName );
- #endif
- }
- //--------------------------------------
- S32 main(S32 argc, const char **argv)
- {
- winState.appInstance = GetModuleHandle(NULL);
- return run(argc, argv);
- }
- //--------------------------------------
- S32 PASCAL WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, S32)
- {
- Vector<char *> argv;
- char moduleName[256];
- GetModuleFileNameA(NULL, moduleName, sizeof(moduleName));
- argv.push_back(moduleName);
- for (const char* word,*ptr = lpszCmdLine; *ptr; ) {
- // Eat white space
- for (; dIsspace(*ptr) && *ptr; ptr++)
- ;
- // Pick out the next word
- bool quote = false;
- for (word = ptr; !(dIsspace(*ptr) && !quote) && *ptr; ptr++)
- {
- if(*ptr == '\"') quote = ! quote;
- }
- if(*word == '\"') ++word;
-
- // Add the word to the argument list.
- if (*word) {
- int len = ptr - word;
- if(*(ptr-1) == '\"') --len;
- char *arg = (char *) dMalloc(len + 1);
- dStrncpy(arg, word, len);
- arg[len] = 0;
- argv.push_back(arg);
- }
- }
- winState.appInstance = hInstance;
- S32 retVal = run(argv.size(), (const char **) argv.address());
- for(U32 j = 1; j < (U32)argv.size(); j++)
- dFree(argv[j]);
- return retVal;
- }
- //--------------------------------------
- void TimeManager::process()
- {
- if( winState.backgrounded )
- winState.sleepTicks = Platform::getBackgroundSleepTime();
- else
- winState.sleepTicks = sgTimeManagerProcessInterval;
- U32 elapsedTime = gTimer.getElapsedMS();
- if( elapsedTime < winState.sleepTicks)
- {
- MsgWaitForMultipleObjects(0, NULL, false, winState.sleepTicks - elapsedTime, QS_ALLINPUT);
- }
-
- TimeEvent event;
- event.elapsedTime = gTimer.getElapsedMS();
- gTimer.advance();
- Game->postEvent(event);
- }
- F32 Platform::getRandom()
- {
- return sgPlatRandom.randF();
- }
- ////--------------------------------------
- /// Spawn the default Operating System web browser with a URL
- /// @param webAddress URL to pass to browser
- /// @return true if browser successfully spawned
- bool Platform::openWebBrowser( const char* webAddress )
- {
- static bool sHaveKey = false;
- static wchar_t sWebKey[512];
- char utf8WebKey[512];
- {
- HKEY regKey;
- DWORD size = sizeof( sWebKey );
- if ( RegOpenKeyEx( HKEY_CLASSES_ROOT, dT("\\http\\shell\\open\\command"), 0, KEY_QUERY_VALUE, ®Key ) != ERROR_SUCCESS )
- {
- Con::errorf( ConsoleLogEntry::General, "Platform::openWebBrowser - Failed to open the HKCR\\http registry key!!!");
- return( false );
- }
- if ( RegQueryValueEx( regKey, dT(""), NULL, NULL, (unsigned char *)sWebKey, &size ) != ERROR_SUCCESS )
- {
- Con::errorf( ConsoleLogEntry::General, "Platform::openWebBrowser - Failed to query the open command registry key!!!" );
- return( false );
- }
- RegCloseKey( regKey );
- sHaveKey = true;
- convertUTF16toUTF8(sWebKey,utf8WebKey,512);
- #ifdef UNICODE
- char *p = dStrstr((const char *)utf8WebKey, "%1");
- #else
- char *p = dStrstr( (const char *) sWebKey , "%1");
- #endif
- if (p) *p = 0;
- }
- STARTUPINFO si;
- dMemset( &si, 0, sizeof( si ) );
- si.cb = sizeof( si );
- char buf[1024];
- #ifdef UNICODE
- dSprintf( buf, sizeof( buf ), "%s %s", utf8WebKey, webAddress );
- UTF16 szCommandLine[1024];
- convertUTF8toUTF16((UTF8 *)buf, szCommandLine, sizeof(szCommandLine));
- #else
- UTF8 szCommandLine[1024];
- dSprintf( szCommandLine, sizeof( szCommandLine ), "%s %s", sWebKey, webAddress );
- #endif
- //Con::errorf( ConsoleLogEntry::General, "** Web browser command = %s **", buf );
- PROCESS_INFORMATION pi;
- dMemset( &pi, 0, sizeof( pi ) );
- CreateProcess( NULL,
- szCommandLine,
- NULL,
- NULL,
- false,
- CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
- NULL,
- NULL,
- &si,
- &pi );
- return( true );
- }
- //--------------------------------------
- // Platform functions for window menu
- //--------------------------------------
- // Creates the menu bar for the window
- void CreateWin32MenuBar( void )
- {
- if( HasWin32MenuBar() )
- {
- DrawMenuBar( winState.appWindow );
- return;
- }
- HMENU menu = CreateMenu();
- if(menu)
- {
- winState.appMenu = menu;
- SetMenu(winState.appWindow, menu);
- DrawMenuBar(winState.appWindow);
- }
- }
- void DestroyWin32MenuBar( void )
- {
- if( HasWin32MenuBar() )
- DestroyMenu( winState.appMenu );
- // Need to update platform window child rect?
- DrawMenuBar(winState.appWindow);
- }
- bool HasWin32MenuBar( void )
- {
- return (bool)IsMenu( winState.appMenu );
- }
|