12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799 |
- //-----------------------------------------------------------------------------
- // 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;
- //--------------------------------------
- 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.fValues[0] = 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.fValues[0] = (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.fValues[0] = (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.fValues[0] = 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.fValues[0] = (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:
- {
- while (ShowCursor(TRUE) < 0);
- break;
- }
- case WM_MOUSEMOVE:
- // keep trying until we actually show it
- if(!Canvas->getUseNativeCursor())
- {
- while (ShowCursor(FALSE) >= 0);
- }
- 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_SETCURSOR:
- if ((LOWORD(lParam) == HTCLIENT) && !(Canvas->getUseNativeCursor()))
- SetCursor(NULL);
- 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 );
- Audio::OpenALShutdown();
- 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;
- 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(utf8WebKey, "%1");
- #else
- char *p = dStrstr(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 );
- }
|