Win32_Platform.cpp
Go to the documentation of this file.
00001 /************************************************************************************
00002 
00003 Filename    :   Win32_Platform.cpp
00004 Content     :   Win32 implementation of Platform app infrastructure
00005 Created     :   September 6, 2012
00006 Authors     :   Andrew Reisse
00007 
00008 Copyright   :   Copyright 2012 Oculus VR, Inc. All Rights reserved.
00009 
00010 Licensed under the Apache License, Version 2.0 (the "License");
00011 you may not use this file except in compliance with the License.
00012 You may obtain a copy of the License at
00013 
00014 http://www.apache.org/licenses/LICENSE-2.0
00015 
00016 Unless required by applicable law or agreed to in writing, software
00017 distributed under the License is distributed on an "AS IS" BASIS,
00018 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019 See the License for the specific language governing permissions and
00020 limitations under the License.
00021 
00022 ************************************************************************************/
00023 
00024 #include "Kernel/OVR_System.h"
00025 #include "Kernel/OVR_Array.h"
00026 #include "Kernel/OVR_String.h"
00027 
00028 #include "Win32_Platform.h"
00029 #include "Win32_Gamepad.h"
00030 #include "../Render/Render_Device.h"
00031 
00032 namespace OVR { namespace Platform { namespace Win32 {
00033 
00034 
00035 PlatformCore::PlatformCore(Application* app, HINSTANCE hinst)
00036   : Platform::PlatformCore(app), hWnd(NULL), hInstance(hinst), Quit(0), MMode(Mouse_Normal),
00037     Cursor(0), Modifiers(0), WindowTitle("App")
00038 {
00039     pGamepadManager = *new Win32::GamepadManager();
00040 }
00041 
00042 PlatformCore::~PlatformCore()
00043 {
00044 }
00045 
00046 bool PlatformCore::SetupWindow(int w, int h)
00047 {
00048     WNDCLASS wc;
00049     memset(&wc, 0, sizeof(wc));
00050     wc.lpszClassName = L"OVRAppWindow";
00051     wc.style         = CS_OWNDC;
00052     wc.lpfnWndProc   = systemWindowProc;
00053     wc.cbWndExtra    = sizeof(PlatformCore*);
00054 
00055     RegisterClass(&wc);
00056 
00057     Width = w;
00058     Height = h;
00059     RECT winSize;
00060     winSize.left = winSize.top = 0;
00061     winSize.right = Width;
00062     winSize.bottom = Height;
00063     AdjustWindowRect(&winSize, WS_OVERLAPPEDWINDOW, false);
00064     hWnd = CreateWindowA("OVRAppWindow", WindowTitle.ToCStr(), WS_OVERLAPPEDWINDOW,
00065                           CW_USEDEFAULT, CW_USEDEFAULT,
00066                         //  1950, 10,
00067                           winSize.right-winSize.left, winSize.bottom-winSize.top,
00068                           NULL, NULL, hInstance, (LPVOID)this);
00069     Modifiers = 0;
00070 
00071     Cursor = LoadCursor(NULL, IDC_CROSS);    
00072 
00073     // Initialize Window center in screen coordinates
00074     POINT center = { Width / 2, Height / 2 };
00075     ::ClientToScreen(hWnd, &center);
00076     WindowCenter = center;
00077     
00078     if (MMode == Mouse_Relative)
00079     {
00080         ::SetCursorPos(WindowCenter.x, WindowCenter.y);
00081         ShowCursor(FALSE);
00082     }
00083     ::SetFocus(hWnd);
00084 
00085     return (hWnd != NULL);
00086 }
00087 
00088 void PlatformCore::DestroyWindow()
00089 {
00090     // Release renderer.
00091     pRender.Clear();
00092 
00093     // Release gamepad.
00094     pGamepadManager.Clear();
00095 
00096     // Release window resources.
00097     ::DestroyWindow(hWnd);
00098     UnregisterClass(L"OVRAppWindow", hInstance);
00099     hWnd = 0;
00100     Width = Height = 0;
00101 
00102     //DestroyCursor(Cursor);
00103     Cursor = 0;    
00104 }
00105 
00106 void PlatformCore::ShowWindow(bool visible)
00107 {
00108     ::ShowWindow(hWnd, visible ? SW_SHOW : SW_HIDE);
00109 }
00110 
00111 void PlatformCore::SetMouseMode(MouseMode mm)
00112 {
00113     if (mm == MMode)
00114         return;
00115 
00116     if (hWnd)
00117     {
00118         if (mm == Mouse_Relative)
00119         {
00120             ShowCursor(FALSE);
00121             ::SetCursorPos(WindowCenter.x, WindowCenter.y);
00122         }
00123         else
00124         {
00125             if (MMode == Mouse_Relative)
00126                 ShowCursor(TRUE);
00127         }
00128     }
00129     MMode = mm;
00130 }
00131 
00132 void PlatformCore::GetWindowSize(int* w, int* h) const
00133 {
00134     *w = Width;
00135     *h = Height;
00136 }
00137 
00138 
00139 void PlatformCore::SetWindowTitle(const char* title)
00140 {
00141     WindowTitle = title;
00142     if (hWnd)
00143     ::SetWindowTextA(hWnd, title);
00144 }
00145 
00146 static UByte KeyMap[][2] = 
00147 {
00148     { VK_BACK,      Key_Backspace },
00149     { VK_TAB,       Key_Tab },
00150     { VK_CLEAR,     Key_Clear },
00151     { VK_RETURN,    Key_Return },
00152     { VK_SHIFT,     Key_Shift },
00153     { VK_CONTROL,   Key_Control },
00154     { VK_MENU,      Key_Alt },
00155     { VK_PAUSE,     Key_Pause },
00156     { VK_CAPITAL,   Key_CapsLock },
00157     { VK_ESCAPE,    Key_Escape },
00158     { VK_SPACE,     Key_Space },
00159     { VK_PRIOR,     Key_PageUp },
00160     { VK_NEXT,      Key_PageDown },
00161     { VK_END,       Key_End },
00162     { VK_HOME,      Key_Home },
00163     { VK_LEFT,      Key_Left },
00164     { VK_UP,        Key_Up },
00165     { VK_RIGHT,     Key_Right },
00166     { VK_DOWN,      Key_Down },
00167     { VK_INSERT,    Key_Insert },
00168     { VK_DELETE,    Key_Delete },
00169     { VK_HELP,      Key_Help },
00170 
00171     { VK_NUMLOCK,   Key_NumLock },
00172     { VK_SCROLL,    Key_ScrollLock },
00173 
00174     { VK_OEM_1,     Key_Semicolon },
00175     { VK_OEM_PLUS,  Key_Equal },
00176     { VK_OEM_COMMA, Key_Comma },
00177     { VK_OEM_MINUS, Key_Minus },
00178     { VK_OEM_PERIOD,Key_Period },
00179     { VK_OEM_2,     Key_Slash },
00180     { VK_OEM_3,     Key_Bar },
00181     { VK_OEM_4,     Key_BracketLeft },
00182     { VK_OEM_5,     Key_Backslash },
00183     { VK_OEM_6,     Key_BracketRight },
00184     { VK_OEM_7,     Key_Quote },
00185 
00186     { VK_OEM_AX,        Key_OEM_AX },   //  'AX' key on Japanese AX keyboard.
00187     { VK_OEM_102,   Key_OEM_102 },  //  "<>" or "\|" on RT 102-key keyboard.
00188     { VK_ICO_HELP,  Key_ICO_HELP },
00189     { VK_ICO_00,        Key_ICO_00 }
00190 };
00191 
00192 
00193 KeyCode MapVKToKeyCode(unsigned vk)
00194 {
00195     unsigned key = Key_None;
00196 
00197     if ((vk >= '0') && (vk <= '9'))
00198     {
00199         key = vk - '0' + Key_Num0;
00200     }
00201     else if ((vk >= 'A') && (vk <= 'Z'))
00202     {
00203         key = vk - 'A' + Key_A;
00204     }
00205     else if ((vk >= VK_NUMPAD0) && (vk <= VK_DIVIDE))
00206     {
00207         key = vk - VK_NUMPAD0 + Key_KP_0;
00208     }
00209     else if ((vk >= VK_F1) && (vk <= VK_F15))
00210     {
00211         key = vk - VK_F1 + Key_F1;
00212     }
00213     else 
00214     {
00215         for (unsigned i = 0; i< (sizeof(KeyMap) / sizeof(KeyMap[1])); i++)
00216         {
00217             if (vk == KeyMap[i][0])
00218             {                
00219                 key = KeyMap[i][1];
00220                 break;
00221             }
00222         }
00223     }
00224 
00225     return (KeyCode)key;
00226 }
00227 
00228 
00229 
00230 LRESULT CALLBACK PlatformCore::systemWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
00231 {
00232     PlatformCore* self;  
00233 
00234     // WM_NCCREATE should be the first message to come it; use it to set class pointer.
00235     if (msg == WM_NCCREATE)
00236     {
00237         self = static_cast<PlatformCore*>(((LPCREATESTRUCT)lp)->lpCreateParams);
00238 
00239         if (self)
00240         {
00241             SetWindowLongPtr(hwnd, 0, (LONG_PTR)self);
00242             self->hWnd = hwnd;
00243         }
00244     }
00245     else
00246     {
00247         self = (PlatformCore*)(UPInt)GetWindowLongPtr(hwnd, 0);
00248     }
00249         
00250     return self ? self->WindowProc(msg, wp, lp) :
00251                   DefWindowProc(hwnd, msg, wp, lp);
00252 }
00253 
00254 
00255 LRESULT PlatformCore::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
00256 {
00257     KeyCode keyCode;
00258 
00259     switch (msg)
00260     {
00261     case WM_PAINT:
00262         {
00263             PAINTSTRUCT ps;
00264             BeginPaint(hWnd, &ps);
00265             EndPaint(hWnd, &ps);
00266         }
00267         return 0;
00268 
00269     case WM_SETCURSOR:
00270         ::SetCursor(Cursor);
00271         return 0;
00272 
00273     case WM_MOUSEMOVE:
00274         if (MMode == Mouse_Relative)
00275         {
00276             POINT newPos = { LOWORD(lp), HIWORD(lp) };
00277             ::ClientToScreen(hWnd, &newPos);
00278             if ((newPos.x == WindowCenter.x) && (newPos.y == WindowCenter.y))
00279                 break;
00280             ::SetCursorPos(WindowCenter.x, WindowCenter.y);
00281 
00282             LONG dx = newPos.x - WindowCenter.x;
00283             LONG dy = newPos.y - WindowCenter.y;
00284            
00285             pApp->OnMouseMove(dx, dy, Mod_MouseRelative);
00286         }
00287         else
00288         {
00289             pApp->OnMouseMove(LOWORD(lp), HIWORD(lp), 0);
00290         }
00291         break;
00292 
00293     case WM_MOVE:
00294         {
00295             RECT r;
00296             GetClientRect(hWnd, &r);
00297             WindowCenter.x = r.right/2;
00298             WindowCenter.y = r.bottom/2;
00299             ::ClientToScreen(hWnd, &WindowCenter);
00300         }
00301         break;
00302 
00303     case WM_KEYDOWN:        
00304         switch (wp)
00305         {
00306         case VK_CONTROL:        Modifiers |= Mod_Control; break;
00307         case VK_MENU:           Modifiers |= Mod_Alt; break;
00308         case VK_SHIFT:          Modifiers |= Mod_Shift; break;
00309         case VK_LWIN:
00310         case VK_RWIN:           Modifiers |= Mod_Meta; break;
00311         }
00312         if ((keyCode = MapVKToKeyCode((unsigned)wp)) != Key_None)
00313             pApp->OnKey(keyCode, 0, true, Modifiers);
00314 
00315         if (keyCode == Key_Escape && MMode == Mouse_Relative)
00316         {
00317             MMode = Mouse_RelativeEscaped;
00318             ShowCursor(TRUE);
00319         }
00320         break;
00321 
00322     case WM_KEYUP:
00323         if ((keyCode = MapVKToKeyCode((unsigned)wp)) != Key_None)
00324             pApp->OnKey(keyCode, 0, false, Modifiers);
00325         switch (wp)
00326         {
00327         case VK_CONTROL:        Modifiers &= ~Mod_Control; break;
00328         case VK_MENU:           Modifiers &= ~Mod_Alt; break;
00329         case VK_SHIFT:          Modifiers &= ~Mod_Shift; break;
00330         case VK_LWIN:
00331         case VK_RWIN:           Modifiers &= ~Mod_Meta; break;
00332         }
00333         break;
00334 
00335     case WM_LBUTTONDOWN:
00336         //App->OnMouseButton(0, 
00337 
00338         ::SetCapture(hWnd);
00339 
00340         if (MMode == Mouse_RelativeEscaped)
00341         {            
00342             ::SetCursorPos(WindowCenter.x, WindowCenter.y);
00343             ::ShowCursor(FALSE);
00344             MMode = Mouse_Relative;
00345         }
00346         break;
00347 
00348     case WM_LBUTTONUP:
00349         ReleaseCapture();
00350         break;
00351 
00352     case WM_SETFOCUS:
00353         // Do NOT restore the Relative mode here, since calling SetCursorPos
00354         // would screw up titlebar window dragging.
00355         // Let users click in the center instead to resume.        
00356         break;
00357 
00358     case WM_KILLFOCUS:
00359         if (MMode == Mouse_Relative)
00360         {            
00361             MMode = Mouse_RelativeEscaped;
00362             ShowCursor(TRUE);
00363         }
00364         break;
00365 
00366     case WM_SIZE:
00367         // Change window size as long as we're not being minimized. 
00368         if (wp != SIZE_MINIMIZED)
00369         {
00370         Width = LOWORD(lp);
00371         Height = HIWORD(lp);
00372         if (pRender)
00373             pRender->SetWindowSize(Width, Height);
00374         pApp->OnResize(Width,Height);
00375         }
00376         break;
00377 
00378     case WM_STYLECHANGING:
00379         // Resize the window. This is needed because the size includes any present system controls, and
00380         // windows does not adjust it when changing to fullscreen.
00381         {
00382             STYLESTRUCT* pss = (STYLESTRUCT*)lp;
00383             RECT winSize;
00384             winSize.left = winSize.top = 0;
00385             winSize.right = Width;
00386             winSize.bottom = Height;
00387             int w = winSize.right-winSize.left;
00388             int h = winSize.bottom-winSize.top;
00389             AdjustWindowRect(&winSize, pss->styleNew, false);
00390             ::SetWindowPos(hWnd, NULL, 0, 0, w, h, SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
00391         }
00392         break;
00393 
00394     case WM_QUIT:
00395     case WM_CLOSE:
00396         pApp->OnQuitRequest();
00397         return false;
00398     }
00399 
00400     return DefWindowProc(hWnd, msg, wp, lp);
00401 }
00402 
00403 int PlatformCore::Run()
00404 {
00405     while (!Quit)
00406     {
00407         MSG msg;
00408         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
00409         {
00410             TranslateMessage(&msg);
00411             DispatchMessage(&msg);
00412         }
00413         else
00414         {
00415             pApp->OnIdle();
00416 
00417             // Keep sleeping when we're minimized.
00418             if (IsIconic(hWnd))
00419             {
00420                 Sleep(10);
00421         }
00422     }
00423     }
00424 
00425     return ExitCode;
00426 }
00427 
00428 
00429 RenderDevice* PlatformCore::SetupGraphics(const SetupGraphicsDeviceSet& setupGraphicsDesc,
00430                                           const char* type, const Render::RendererParams& rp)
00431 {
00432     const SetupGraphicsDeviceSet* setupDesc = setupGraphicsDesc.PickSetupDevice(type);
00433     OVR_ASSERT(setupDesc);
00434 
00435     pRender = *setupDesc->pCreateDevice(rp, (void*)hWnd);
00436     if (pRender)
00437         pRender->SetWindowSize(Width, Height);
00438 
00439     ::ShowWindow(hWnd, SW_RESTORE);
00440     return pRender.GetPtr();
00441 }
00442 
00443 
00444 void PlatformCore::PlayMusicFile(const char *fileName)
00445 {
00446         PlaySoundA(fileName, NULL, SND_FILENAME | SND_LOOP | SND_ASYNC); 
00447 }
00448 
00449 
00450 //-----------------------------------------------------------------------------
00451 
00452 // Used to capture all the active monitor handles
00453 struct MonitorSet
00454 {
00455     enum { MaxMonitors = 8 };
00456     HMONITOR Monitors[MaxMonitors];
00457     int      MonitorCount;
00458     int      PrimaryCount;
00459 };
00460 
00461 
00462 BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
00463 {
00464     MonitorSet* monitorSet = (MonitorSet*)dwData;
00465     if (monitorSet->MonitorCount > MonitorSet::MaxMonitors)
00466         return FALSE;
00467 
00468     monitorSet->Monitors[monitorSet->MonitorCount] = hMonitor;
00469     monitorSet->MonitorCount++;
00470     return TRUE;
00471 };
00472 
00473 
00474 // Returns the number of active screens for extended displays and 1 for mirrored display
00475 int PlatformCore::GetDisplayCount()
00476 {
00477     // Get all the monitor handles
00478     MonitorSet monitors;
00479     monitors.MonitorCount = 0;
00480     EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&monitors);
00481 
00482     // Count the primary monitors
00483     int primary = 0;
00484     MONITORINFOEX info;
00485     for (int m=0; m < monitors.MonitorCount; m++)
00486     {
00487         info.cbSize = sizeof(MONITORINFOEX);
00488         GetMonitorInfo(monitors.Monitors[m], &info);
00489         
00490         if (info.dwFlags & MONITORINFOF_PRIMARY)
00491            primary++;
00492     }
00493 
00494     if (primary > 1)
00495         return 1;                      // Regard mirrored displays as a single screen
00496     else
00497         return monitors.MonitorCount;  // Return all extended displays 
00498 }
00499 
00500 //-----------------------------------------------------------------------------
00501 // Returns the device name for the given screen index or empty string for invalid index
00502 // The zero index will always return the primary screen name
00503 Render::DisplayId PlatformCore::GetDisplay(int screen)
00504 {
00505     // Get all the monitor handles
00506     MonitorSet monitors;
00507     monitors.MonitorCount = 0;
00508     EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&monitors);
00509 
00510     String screen_name;
00511 
00512     // Get the name of the suppled screen index with the requirement
00513     // that screen 0 is the primary monitor
00514     int non_primary_count = 0;
00515     MONITORINFOEX info;
00516     for (int m=0; m < monitors.MonitorCount; m++)
00517     {
00518         info.cbSize = sizeof(MONITORINFOEX);
00519         GetMonitorInfo(monitors.Monitors[m], &info);
00520         
00521         if (info.dwFlags & MONITORINFOF_PRIMARY)
00522         {
00523             if (screen == 0)
00524             {
00525                 screen_name = info.szDevice;
00526                 break;
00527             }
00528         }
00529         else
00530         {
00531             non_primary_count++;
00532             if (screen == non_primary_count)
00533             {
00534                 screen_name = info.szDevice;
00535                 break;
00536             }
00537         }
00538     }
00539 
00540     return screen_name;
00541 }
00542 
00543 
00544 }}}
00545 
00546 
00547 int WINAPI WinMain(HINSTANCE hinst, HINSTANCE prevInst, LPSTR inArgs, int show)
00548 {
00549     using namespace OVR;
00550     using namespace OVR::Platform;
00551 
00552     OVR_UNUSED2(prevInst, show);
00553     
00554     // CreateApplication must be the first call since it does OVR::System::Initialize.
00555     Application*     app = Application::CreateApplication();
00556     Win32::PlatformCore* platform = new Win32::PlatformCore(app, hinst);
00557     // The platform attached to an app will be deleted by DestroyApplication.
00558     app->SetPlatformCore(platform);
00559 
00560     int exitCode = 0;
00561 
00562     // Nested scope for container destructors to shutdown before DestroyApplication.
00563     {
00564         Array<String>      args;
00565         Array<const char*> argv;
00566         argv.PushBack("app");
00567 
00568         const char* p = inArgs;
00569         const char* pstart = inArgs;
00570         while (*p)
00571         {
00572             if (*p == ' ')
00573             {
00574                 args.PushBack(String(pstart, p - pstart));
00575                 while (*p == ' ')
00576                     p++;
00577                 pstart = p;
00578             }
00579             else
00580             {
00581                 p++;
00582             }
00583         }
00584         if (p != pstart)
00585             args.PushBack(String(pstart, p - pstart));
00586         for (UPInt i = 0; i < args.GetSize(); i++)
00587             argv.PushBack(args[i].ToCStr());
00588 
00589         exitCode = app->OnStartup((int)argv.GetSize(), &argv[0]);
00590         if (!exitCode)
00591             exitCode = platform->Run();
00592     }
00593 
00594     // No OVR functions involving memory are allowed after this.
00595     Application::DestroyApplication(app);
00596     app = 0;
00597 
00598     OVR_DEBUG_STATEMENT(_CrtDumpMemoryLeaks());
00599     return exitCode;
00600 }


oculus_sdk
Author(s):
autogenerated on Mon Oct 6 2014 03:01:19