From 496894ecced1b0a4ae5ab176902bbd0f43a31ed1 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 24 Oct 2014 12:56:30 -0700 Subject: Updating to 0.4.3 SDK --- Samples/CommonSrc/Platform/Gamepad.h | 2 +- Samples/CommonSrc/Platform/Linux_Gamepad.cpp | 451 +++++++ Samples/CommonSrc/Platform/Linux_Gamepad.h | 83 ++ Samples/CommonSrc/Platform/Linux_Platform.cpp | 1045 ++++++++++++++++ Samples/CommonSrc/Platform/Linux_Platform.h | 149 +++ Samples/CommonSrc/Platform/OSX_Platform.mm | 1661 +++++++++++++++++-------- Samples/CommonSrc/Platform/Platform.cpp | 2 +- Samples/CommonSrc/Platform/Platform.h | 2 +- Samples/CommonSrc/Platform/Platform_Default.h | 2 +- Samples/CommonSrc/Platform/Win32_Gamepad.cpp | 68 +- Samples/CommonSrc/Platform/Win32_Gamepad.h | 5 +- Samples/CommonSrc/Platform/Win32_Platform.cpp | 35 +- Samples/CommonSrc/Platform/Win32_Platform.h | 2 +- 13 files changed, 2912 insertions(+), 595 deletions(-) create mode 100644 Samples/CommonSrc/Platform/Linux_Gamepad.cpp create mode 100644 Samples/CommonSrc/Platform/Linux_Gamepad.h create mode 100644 Samples/CommonSrc/Platform/Linux_Platform.cpp create mode 100644 Samples/CommonSrc/Platform/Linux_Platform.h (limited to 'Samples/CommonSrc/Platform') diff --git a/Samples/CommonSrc/Platform/Gamepad.h b/Samples/CommonSrc/Platform/Gamepad.h index d078bdb..e6295ca 100644 --- a/Samples/CommonSrc/Platform/Gamepad.h +++ b/Samples/CommonSrc/Platform/Gamepad.h @@ -5,7 +5,7 @@ Content : Cross platform Gamepad interface. Created : May 6, 2013 Authors : Lee Cooper -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2012 Oculus VR, LLC All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Samples/CommonSrc/Platform/Linux_Gamepad.cpp b/Samples/CommonSrc/Platform/Linux_Gamepad.cpp new file mode 100644 index 0000000..c333efa --- /dev/null +++ b/Samples/CommonSrc/Platform/Linux_Gamepad.cpp @@ -0,0 +1,451 @@ +/************************************************************************************ + +Filename : Linux_Gamepad.cpp +Content : Linux implementation of Platform app infrastructure +Created : May 6, 2013 +Authors : Lee Cooper, Simon Hallam + +Copyright : Copyright 2012 Oculus VR, LLC. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "Linux_Gamepad.h" + + +namespace OVR { namespace OvrPlatform { namespace Linux { + +const char* pNameXbox360Wireless = "Xbox 360"; +const char* pNameXbox360Wired = "Microsoft X-Box 360"; + + +GamepadManager::GamepadManager() : + pDevice(NULL) +{ + if (!pDevice) + { + // get a list of paths to all the connected joystick devices + glob_t joystickGlobBuffer; + glob("/dev/input/js*", 0, NULL, &joystickGlobBuffer); + + // open each joystick device, until we find one that will work for our needs + for (UInt32 i = 0; i < joystickGlobBuffer.gl_pathc; i++) + { + pDevice = new Gamepad(); + if (pDevice->Open(joystickGlobBuffer.gl_pathv[i])) + { + + if (pDevice->IsSupportedType()) + { + break; + } + } + + // we don't know why the device was not useable, make sure it gets closed cleanly + pDevice->Close(); + pDevice = NULL; + } + } +} + +GamepadManager::~GamepadManager() +{ + // if we have an open device, close it + if (pDevice) + { + pDevice->Close(); + pDevice = NULL; + } +} + +UInt32 GamepadManager::GetGamepadCount() +{ + return 1; +} + +bool GamepadManager::GetGamepadState(UInt32 index, GamepadState *pState) +{ + if (pDevice) + { + // we have a device, so update it + pDevice->UpdateState(); + + // copy the device state into the struct param + memcpy(pState, pDevice->GetState(), sizeof(GamepadState)); + + // TODO: is the device still active/connected? if not, we should close it + // and clear pDevice, so that another device can take over + + return true; + } + else + { + return false; + } +} + +Gamepad::Gamepad() : + IsInitialized(false), + Name(String("Undefined")), + Type(UNDEFINED) +{ +} + +Gamepad::~Gamepad() +{ + this->Close(); +} + +bool Gamepad::Open(const String& devicePathName) +{ + Name = "Undefined"; + Type = UNDEFINED; + + FileDescriptor = ::open(devicePathName.ToCStr(), O_RDONLY | O_NONBLOCK); + if (FileDescriptor == -1) + { + return false; + } + + // get the device name + char name[128]; + if (ioctl(FileDescriptor, JSIOCGNAME(sizeof(name)), name) < 0) + { + return false; + } + + Name = name; + + // see if device name matches one of our supported devices + static const UInt32 Wireless360Len = String(pNameXbox360Wireless).GetLength(); + static const UInt32 Wired360Len = String(pNameXbox360Wired).GetLength(); + if (Name.Substring(0, Wireless360Len) == pNameXbox360Wireless) + { + Type = XBOX360GAMEPADWIRELESS; + return true; + } + else if(Name.Substring(0, Wired360Len) == pNameXbox360Wired) + { + Type = XBOX360GAMEPADWIRED; + return true; + } + + return false; +} + +bool Gamepad::Close() +{ + IsInitialized = false; + Name = "Undefined"; + Type = UNDEFINED; + return !::close(FileDescriptor); +} + +void Gamepad::UpdateState() +{ + GamepadState *pState = &State; + js_event gamepadEvent; + + // read the latest batch of events + while (read(FileDescriptor, &gamepadEvent, sizeof(struct js_event)) != -1) + { + switch (gamepadEvent.type) + { + case JS_EVENT_BUTTON: + IsInitialized = true; + SetStateButton(pState, gamepadEvent.number, gamepadEvent.value); + break; + + case JS_EVENT_AXIS: + IsInitialized = true; + SetStateAxis(pState, gamepadEvent.number, gamepadEvent.value); + break; + + case JS_EVENT_BUTTON | JS_EVENT_INIT: + if (IsInitialized) // skip the fake values during device event initialization + { + SetStateButton(pState, gamepadEvent.number, gamepadEvent.value); + } + break; + + case JS_EVENT_AXIS | JS_EVENT_INIT: + if (IsInitialized) // skip the fake values during device event initialization + { + SetStateAxis(pState, gamepadEvent.number, gamepadEvent.value); + } + break; + + default: + LogText("OVR::Linux::UpdateState unknown event type\n"); + } + } +} + +const GamepadState* Gamepad::GetState() +{ + return &State; +} + + +bool Gamepad::IsSupportedType() +{ + return Type != UNDEFINED; +} + +const String& Gamepad::GetIdentifier() +{ + return Name; +} + +static inline float NormalizeGamepadStickXbox360(SInt32 in) +{ + float v; + if (abs(in) < 9000) return 0; + else if (in > 9000) v = (float)in - 9000; + else v = (float)in + 9000; + return v / (32767 - 9000); +} + +static inline float NormalizeGamepadTriggerXbox360(SInt32 in, + SInt32 offset, + SInt32 deadBand, + float divisor) +{ + in += offset; + + if (in < deadBand) + { + return 0; + } + else + { + return float(in - deadBand) / divisor; + } +} + +static inline void UpdateButtonMaskAndBitfield(GamepadState *pState, + SInt32 value, + UInt32 buttonBitfield) +{ + if (value) + { + pState->Buttons |= buttonBitfield; + } + else + { + pState->Buttons = pState->Buttons & (0xFFFFFFFF ^ buttonBitfield); + } +} + +void Gamepad::SetStateAxis(GamepadState *pState, UInt32 axis, SInt32 value) +{ + // some pads/sticks have lots in common with one another, + // handle those shared cases first + switch (Type) + { + case XBOX360GAMEPADWIRELESS: + case XBOX360GAMEPADWIRED: + switch (axis) + { + case 0: + pState->LX = NormalizeGamepadStickXbox360(value); + break; + + case 1: + pState->LY = -NormalizeGamepadStickXbox360(value); + break; + + case 3: + pState->RX = NormalizeGamepadStickXbox360(value); + break; + + case 4: + pState->RY = -NormalizeGamepadStickXbox360(value); + break; + } + break; + + case UNDEFINED: + default: + break; + } + + // handle the special cases, or pads/sticks which are unique + switch (Type) + { + case XBOX360GAMEPADWIRELESS: + switch (axis) + { + case 2: + pState->LT = NormalizeGamepadTriggerXbox360(value, 0, 500, 32267); + break; + + case 5: + pState->RT = NormalizeGamepadTriggerXbox360(value, 0, 500, 32267); + break; + } + break; + + case XBOX360GAMEPADWIRED: + switch (axis) + { + case 2: + pState->LT = NormalizeGamepadTriggerXbox360(value, 32767, 1000, 64535); + break; + + case 5: + pState->RT = NormalizeGamepadTriggerXbox360(value, 32767, 1000, 64535); + break; + + case 6: + if (value == 0) + { + UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Left); + UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Right); + } + else if (value < 0) + { + UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Left); + } + else if (value > 0) + { + UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Right); + } + break; + + case 7: + if (value == 0) + { + UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Up); + UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Down); + } + else if (value < 0) + { + UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Up); + } + else if (value > 0) + { + UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Down); + } + break; + } + break; + + case UNDEFINED: + default: + break; + } +} + +void Gamepad::SetStateButton(GamepadState *pState, UInt32 button, SInt32 value) +{ + // some pads/sticks have lots in common with one another, + // handle those shared cases first + switch (Type) + { + case XBOX360GAMEPADWIRELESS: + case XBOX360GAMEPADWIRED: + switch (button) + { + case 0: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_A); + break; + + case 1: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_B); + break; + + case 2: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_X); + break; + + case 3: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_Y); + break; + + case 4: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_L1); + break; + + case 5: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_R1); + break; + + case 6: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_Back); + break; + + case 7: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_Start); + break; + + case 8: + // we have no value defined for the Xbox/power button + break; + + case 9: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_LStick); + break; + + case 10: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_RStick); + break; + } + break; + + case UNDEFINED: + default: + break; + } + + // handle the special cases, or pads/sticks which are unique + switch (Type) + { + case XBOX360GAMEPADWIRELESS: + switch (button) + { + case 11: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_Left); + break; + + case 12: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_Right); + break; + + case 13: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_Up); + break; + + case 14: + UpdateButtonMaskAndBitfield(pState, value, Gamepad_Down); + break; + } + + case XBOX360GAMEPADWIRED: + break; + + case UNDEFINED: + default: + break; + } +} + +}}} // OVR::OvrPlatform::Linux + diff --git a/Samples/CommonSrc/Platform/Linux_Gamepad.h b/Samples/CommonSrc/Platform/Linux_Gamepad.h new file mode 100644 index 0000000..e35e559 --- /dev/null +++ b/Samples/CommonSrc/Platform/Linux_Gamepad.h @@ -0,0 +1,83 @@ +/************************************************************************************ + +Filename : Linux_Gamepad.h +Content : Linux implementation of Gamepad functionality. +Created : May 6, 2013 +Authors : Lee Cooper, Simon Hallam + +Copyright : Copyright 2012 Oculus VR, LLC. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#ifndef OVR_Linux_Gamepad_h +#define OVR_Linux_Gamepad_h + +#include "Gamepad.h" + +namespace OVR { namespace OvrPlatform { namespace Linux { + +class Gamepad; // forward declaration for readability + +class GamepadManager : public OvrPlatform::GamepadManager +{ +public: + + GamepadManager(); + ~GamepadManager(); + + virtual UInt32 GetGamepadCount(); + virtual bool GetGamepadState(UInt32 index, GamepadState *pState); + +private: + + Gamepad *pDevice; +}; + +class Gamepad +{ +public: + + Gamepad(); + virtual ~Gamepad(); + + bool Open(const String& devicePathName); + bool Close(); + bool IsSupportedType(); + const String& GetIdentifier(); + void UpdateState(); + const GamepadState* GetState(); + +private: + + void SetStateAxis(GamepadState *pState, UInt32 axis, SInt32 value); + void SetStateButton(GamepadState *pState, UInt32 button, SInt32 value); + + enum GamepadType + { + UNDEFINED, + XBOX360GAMEPADWIRELESS, + XBOX360GAMEPADWIRED + }; + + UInt32 FileDescriptor; + bool IsInitialized; + String Name; + GamepadType Type; + GamepadState State; +}; + +}}} + +#endif // OVR_Linux_Gamepad_h diff --git a/Samples/CommonSrc/Platform/Linux_Platform.cpp b/Samples/CommonSrc/Platform/Linux_Platform.cpp new file mode 100644 index 0000000..c41ba3b --- /dev/null +++ b/Samples/CommonSrc/Platform/Linux_Platform.cpp @@ -0,0 +1,1045 @@ +/************************************************************************************ + +Filename : Platform_Linux.cpp +Content : Linux (X11) implementation of Platform app infrastructure +Created : September 6, 2012 +Authors : Andrew Reisse + +Copyright : Copyright 2012 Oculus VR, LLC. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#include "Kernel/OVR_System.h" +#include "Kernel/OVR_Array.h" +#include "Kernel/OVR_String.h" +#include "Kernel/OVR_Timer.h" +#include "Kernel/OVR_Threads.h" + +#include "Displays/OVR_Linux_SDKWindow.h" + +#include +#include +#include +#include + +//#include +#include // To be replaced with the above #include. + +#include "OVR_CAPI_GL.h" + +#include "Linux_Platform.h" +#include "Linux_Gamepad.h" + +#include "../../3rdParty/EDID/edid.h" +#include + + +namespace OVR { namespace OvrPlatform { namespace Linux { + +struct XDisplayInfo +{ + XDisplayInfo() : + valid(false), + output(0), + crtc(0) + {} + + bool valid; + RROutput output; + RRCrtc crtc; + int product; +}; + +static const char *AtomNames[] = {"WM_PROTOCOLS", "WM_DELETE_WINDOW"}; + +PlatformCore::PlatformCore(Application* app) + : OvrPlatform::PlatformCore(app), + StartVP(0, 0, 0, 0), + HasWM(false), Disp(NULL), Vis(NULL), Win(0), Quit(0), ExitCode(0), + Width(0), Height(0), MMode(Mouse_Normal), InvisibleCursor(), Atoms() +{ + pGamepadManager = *new Linux::GamepadManager(); +} + +PlatformCore::~PlatformCore() +{ + XFreeCursor(Disp, InvisibleCursor); + + if (Disp) + { + XCloseDisplay(Disp); + Disp = NULL; + } +} + +// Setup an X11 window in windowed mode. +void* PlatformCore::SetupWindow(int w, int h) +{ + if (!Disp) + { + XInitThreads(); + + Disp = XOpenDisplay(NULL); + if (!Disp) + { + OVR_DEBUG_LOG(("XOpenDisplay failed.")); + return NULL; + } + + XInternAtoms(Disp, const_cast(AtomNames), NumAtoms, false, Atoms); + } + + int screenNumber = DefaultScreen(Disp); + + // Determine if we are running under a WM. Window managers will set the + // substructure redirect mask on the root window. + XWindowAttributes rootWA; + XGetWindowAttributes(Disp, RootWindow(Disp, screenNumber), &rootWA); + HasWM = (rootWA.all_event_masks & SubstructureRedirectMask); + + XSetWindowAttributes winattr; + unsigned attrmask = CWEventMask | CWBorderPixel; + + winattr.event_mask = + ButtonPressMask|ButtonReleaseMask|KeyPressMask|KeyReleaseMask| + ButtonMotionMask|PointerMotionMask|StructureNotifyMask| + SubstructureNotifyMask; + winattr.border_pixel = 0; + + if (!Vis) + { + int attr[16]; + int nattr = 2; + + attr[0] = GLX_RGBA; + attr[1] = GLX_DOUBLEBUFFER; + attr[nattr++] = GLX_DEPTH_SIZE; + attr[nattr++] = 24; + attr[nattr] = 0; + + Vis = glXChooseVisual(Disp, screenNumber, attr); + + if (!Vis) + { + OVR_DEBUG_LOG(("glXChooseVisual failed.")); + return NULL; + } + } + + Window rootWindow = XRootWindow(Disp, Vis->screen); + + winattr.colormap = XCreateColormap(Disp, rootWindow, Vis->visual, AllocNone); + attrmask |= CWColormap; + + Win = XCreateWindow(Disp, rootWindow, 0, 0, w, h, 0, Vis->depth, + InputOutput, Vis->visual, attrmask, &winattr); + + if (!Win) + { + OVR_DEBUG_LOG(("XCreateWindow failed.")); + return NULL; + } + + XStoreName(Disp, Win, "OVR App"); + XSetWMProtocols(Disp, Win, &Atoms[WM_DELETE_WINDOW], 1); + + // Intialize empty cursor for show/hide. + XColor black; + static char noData[] = { 0,0,0,0,0,0,0,0 }; + black.red = black.green = black.blue = 0; + + Pixmap bitmapNoData = XCreateBitmapFromData(Disp, Win, noData, 8, 8); + InvisibleCursor = XCreatePixmapCursor(Disp, bitmapNoData, bitmapNoData, + &black, &black, 0, 0); + XDefineCursor(Disp, Win, InvisibleCursor); + + Width = w; + Height = h; + + return (void*)&Win; +} + +void PlatformCore::SetMouseMode(MouseMode mm) +{ + if (mm == MMode) + return; + + if (Win) + { + if (mm == Mouse_Relative) + { + XWarpPointer(Disp, Win, Win, 0,0,Width,Height, Width/2, Height/2); + } + else + { + //if (MMode == Mouse_Relative) + // ShowCursor(TRUE); + } + } + MMode = mm; +} + +void PlatformCore::GetWindowSize(int* w, int* h) const +{ + *w = Width; + *h = Height; +} + +void PlatformCore::SetWindowTitle(const char* title) +{ + XStoreName(Disp, Win, title); +} + +void PlatformCore::ShowWindow(bool show) +{ + if (show) + { + XRaiseWindow(Disp, Win); + } + else + { + XIconifyWindow(Disp, Win, 0); + } +} + +void PlatformCore::DestroyWindow() +{ + if (Win) + { + XDestroyWindow(Disp, Win); + } + Win = 0; +} + + +static int KeyMap[][2] = +{ + { XK_BackSpace, Key_Backspace }, + { XK_Tab, Key_Tab }, + { XK_Clear, Key_Clear }, + { XK_Return, Key_Return }, + { XK_Shift_L, Key_Shift }, + { XK_Control_L, Key_Control }, + { XK_Alt_L, Key_Alt }, + { XK_Shift_R, Key_Shift }, + { XK_Control_R, Key_Control }, + { XK_Alt_R, Key_Alt }, + { XK_Pause, Key_Pause }, + { XK_Caps_Lock, Key_CapsLock }, + { XK_Escape, Key_Escape }, + { XK_space, Key_Space }, + { XK_Page_Up, Key_PageUp }, + { XK_Page_Down, Key_PageDown }, + { XK_Prior, Key_PageUp }, + { XK_Next, Key_PageDown }, + { XK_End, Key_End }, + { XK_Home, Key_Home }, + { XK_Left, Key_Left }, + { XK_Up, Key_Up }, + { XK_Right, Key_Right }, + { XK_Down, Key_Down }, + { XK_Insert, Key_Insert }, + { XK_Delete, Key_Delete }, + { XK_Help, Key_Help }, + { XK_Num_Lock, Key_NumLock }, + { XK_Scroll_Lock, Key_ScrollLock }, +}; + + +static KeyCode MapXKToKeyCode(unsigned vk) +{ + unsigned key = Key_None; + + if ((vk >= 'a') && (vk <= 'z')) + { + key = vk - 'a' + Key_A; + } + else if ((vk >= ' ') && (vk <= '~')) + { + key = vk; + } + else if ((vk >= XK_KP_0) && (vk <= XK_KP_9)) + { + key = vk - XK_KP_0 + Key_KP_0; + } + else if ((vk >= XK_F1) && (vk <= XK_F15)) + { + key = vk - XK_F1 + Key_F1; + } + else + { + for (unsigned i = 0; i< (sizeof(KeyMap) / sizeof(KeyMap[1])); i++) + { + if (vk == KeyMap[i][0]) + { + key = KeyMap[i][1]; + break; + } + } + } + + return (KeyCode)key; +} + +static int MapModifiers(int xmod) +{ + int mod = 0; + if (xmod & ShiftMask) + mod |= Mod_Shift; + if (xmod & ControlMask) + mod |= Mod_Control; + if (xmod & Mod1Mask) + mod |= Mod_Alt; + if (xmod & Mod4Mask) + mod |= Mod_Meta; + return mod; +} + +void PlatformCore::processEvent(XEvent& event) +{ + switch (event.xany.type) + { + case ConfigureNotify: + if (event.xconfigure.width != Width || event.xconfigure.height != Height) + { + Width = event.xconfigure.width; + Height = event.xconfigure.height; + pApp->OnResize(Width, Height); + + if (pRender) + pRender->SetWindowSize(Width, Height); + } + break; + + case KeyPress: + case KeyRelease: + { + char chars[8] = {0}; + KeySym xk; + XComposeStatus comp; + XLookupString(&event.xkey, chars, sizeof(chars), &xk, &comp); + if (xk != XK_VoidSymbol) + pApp->OnKey(MapXKToKeyCode((unsigned)xk), chars[0], event.xany.type == KeyPress, MapModifiers(event.xkey.state)); + if (xk == XK_Escape && MMode == Mouse_Relative) + { + //ungrab + MMode = Mouse_RelativeEscaped; + showCursor(true); + } + } + break; + + case MotionNotify: + if (MMode == Mouse_Relative) + { + int dx = event.xmotion.x - Width/2; + int dy = event.xmotion.y - Height/2; + + // do not remove this check, WarpPointer generates events too. + if (dx == 0 && dy == 0) + break; + + XWarpPointer(Disp, Win, Win, 0,0,Width,Height, Width/2, Height/2); + pApp->OnMouseMove(dx, dy, Mod_MouseRelative|MapModifiers(event.xmotion.state)); + } + else + { + pApp->OnMouseMove(event.xmotion.x, event.xmotion.y, MapModifiers(event.xmotion.state)); + } + break; + + case MapNotify: + if (MMode == Mouse_Relative) + { + XWarpPointer(Disp, Win, Win, 0,0,Width,Height, Width/2, Height/2); + showCursor(false); + } + break; + + case ButtonPress: + if (event.xbutton.button == 1) + { + //grab + + if (MMode == Mouse_RelativeEscaped) + { + XWarpPointer(Disp, Win, Win, 0,0,Width,Height, Width/2, Height/2); + showCursor(false); + MMode = Mouse_Relative; + } + } + break; + + case FocusOut: + if (MMode == Mouse_Relative) + { + MMode = Mouse_RelativeEscaped; + showCursor(true); + } + break; + + case ClientMessage: + if (event.xclient.message_type == Atoms[WM_PROTOCOLS] && + Atom(event.xclient.data.l[0]) == Atoms[WM_DELETE_WINDOW]) + pApp->OnQuitRequest(); + break; + } +} + +int PlatformCore::Run() +{ + while (!Quit) + { + if (XPending(Disp)) + { + XEvent event; + XNextEvent(Disp, &event); + + if (pApp && event.xany.window == Win) + processEvent(event); + } + else + { + pApp->OnIdle(); + } + } + + return ExitCode; +} + +bool PlatformCore::determineScreenOffset(int screenId, int* screenOffsetX, int* screenOffsetY) +{ + bool foundScreen = false; + + RROutput primaryOutput = XRRGetOutputPrimary(Disp, DefaultRootWindow(Disp)); + XRRScreenResources* screen = XRRGetScreenResources(Disp, Win); + + int screenIndex = 0; + for (int i = 0; i < screen->ncrtc; ++i) + { + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(Disp, screen, screen->crtcs[i]); + + if (0 == crtcInfo->noutput) + { + XRRFreeCrtcInfo(crtcInfo); + // We intentionally do not increment screenIndex. We do not + // consider this a valid display. + continue; + } + + RROutput output = crtcInfo->outputs[0]; + for (int ii = 0; ii < crtcInfo->noutput; ++ii) + { + if (primaryOutput == crtcInfo->outputs[ii]) + { + output = primaryOutput; + break; + } + } + + XRROutputInfo* outputInfo = XRRGetOutputInfo(Disp, screen, output); + if (RR_Connected != outputInfo->connection) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + if (screenId == screenIndex) + { + *screenOffsetX = crtcInfo->x; + *screenOffsetY = crtcInfo->y; + foundScreen = true; + break; + } + + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + + ++screenIndex; + } + XRRFreeScreenResources(screen); + + return foundScreen; +} + +void PlatformCore::showWindowDecorations(bool show) +{ + // Declaration of 'MOTIF_WM_HINTS' struct and flags can be found at: + // https://people.gnome.org/~tthurman/docs/metacity/xprops_8h-source.html + typedef struct WMHints + { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long inputMode; + unsigned long status; + } Hints; + + #define MWM_DECOR_ALL (1L << 0) + #define MWM_DECOR_BORDER (1L << 1) + #define MWM_DECOR_RESIZEH (1L << 2) + #define MWM_DECOR_TITLE (1L << 3) + #define MWM_DECOR_MENU (1L << 4) + #define MWM_DECOR_MINIMIZE (1L << 5) + #define MWM_DECOR_MAXIMIZE (1L << 6) + + Atom property = XInternAtom(Disp, "_MOTIF_WM_HINTS", true); + + Hints hints; + hints.flags = 2; // We only want to specify decoration. + + if (show) + { + hints.decorations = MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE; + } + else + { + // Remove all window border items. + hints.decorations = 0; + } + + XChangeProperty(Disp,Win,property,property,32,PropModeReplace,(unsigned char *)&hints,5); +} + +int PlatformCore::IndexOf(Render::DisplayId id) +{ + int numScreens = GetDisplayCount(); + for (int i = 0; i < numScreens; i++) + { + if (GetDisplay(i).MonitorName == id.MonitorName) + { + return i; + } + } + return -1; +} + +bool PlatformCore::SetFullscreen(const Render::RendererParams& rp, int fullscreen) +{ + if (fullscreen == pRender->GetParams().Fullscreen) + return false; + + // Consume any X Configure Notify event. We will wait for a configure + // notify event after modifying our window. + XEvent report; + long eventMask = StructureNotifyMask | SubstructureNotifyMask; + while (XCheckWindowEvent(Disp, Win, eventMask, &report)); + + int displayIndex = IndexOf(rp.Display); + if (pRender->GetParams().Fullscreen == Render::Display_Window) + { + // Save the original window size and position so we can restore later. + + XWindowAttributes xwa; + XGetWindowAttributes(Disp, Win, &xwa); + int x, y; + Window unused; + XTranslateCoordinates(Disp, Win, DefaultRootWindow(Disp), xwa.x, xwa.y, &x, &y, &unused); + + StartVP.w = xwa.width;//Width; + StartVP.h = xwa.height;//Height; + StartVP.x = x; + StartVP.y = y; + } + else if (pRender->GetParams().Fullscreen == Render::Display_Fullscreen) + { + { + XEvent xev; + memset(&xev, 0, sizeof(xev)); + + xev.type = ClientMessage; + xev.xclient.window = Win; + xev.xclient.message_type = XInternAtom( Disp, "_NET_WM_STATE", False); + xev.xclient.format = 32; + xev.xclient.data.l[0] = 0; + xev.xclient.data.l[1] = XInternAtom( Disp, "_NET_WM_STATE_FULLSCREEN", False); + xev.xclient.data.l[2] = 0; + + XSendEvent( Disp, DefaultRootWindow( Disp ), False, SubstructureNotifyMask, &xev); + } + + XWindowChanges wc; + wc.width = StartVP.w; + wc.height = StartVP.h; + wc.x = StartVP.x; + wc.y = StartVP.y; + + XConfigureWindow(Disp, Win, CWWidth | CWHeight | CWX | CWY, &wc); + + showWindowDecorations(false); + } + + if (fullscreen == Render::Display_FakeFullscreen) + { + // Transitioning from windowed to fake fullscreen. + int xOffset; + int yOffset; + + if (!determineScreenOffset(displayIndex, &xOffset, &yOffset)) + { + return false; + } + + showWindowDecorations(false); + + XMoveWindow(Disp, Win, xOffset, yOffset); + XMapRaised(Disp, Win); + } + else if (fullscreen == Render::Display_Window) + { + // Transitioning from fake fullscreen to windowed. + showWindowDecorations(true); + + XMoveWindow(Disp, Win, StartVP.x, StartVP.y); + XMapRaised(Disp, Win); + } + else if (fullscreen == Render::Display_Fullscreen) + { + // Obtain display information so that we can make and informed + // decision about display modes. + XDisplayInfo displayInfo = getXDisplayInfo(rp.Display); + + XRRScreenResources* screen = XRRGetScreenResources(Disp, DefaultRootWindow(Disp)); + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(Disp, screen, displayInfo.crtc); + XRROutputInfo* outputInfo = XRRGetOutputInfo(Disp, screen, displayInfo.output); + + int xOffset; + int yOffset; + + if (!determineScreenOffset(displayIndex, &xOffset, &yOffset)) + return false; + + // We should probably always be fullscreen if we don't have a WM. + if (!HasWM) + { + // Determine if we are entering fullscreen on a rift device. + char deviceID[32]; + OVR_sprintf(deviceID, 32, "OVR%04d-%d", + displayInfo.product, displayInfo.crtc); + + LinuxDeviceScreen devScreen = SDKWindow::findDevScreenForDevID(deviceID); + if (devScreen.isValid()) + { + XMoveResizeWindow(Disp, Win, + devScreen.offsetX, devScreen.offsetY, + devScreen.width, devScreen.height); + } + } + + showWindowDecorations(false); + + XWindowChanges wc; + wc.x = xOffset; + wc.y = yOffset; + wc.stack_mode = 0; + + XConfigureWindow(Disp, Win, CWX | CWY | CWStackMode, &wc); + + // Make the window fullscreen in the window manager. + // If we are using override redirect, or are on a separate screen + // with no WM, the following code will have no effect. + { + XEvent xev; + memset(&xev, 0, sizeof(xev)); + + xev.type = ClientMessage; + xev.xclient.window = Win; + xev.xclient.message_type = XInternAtom( Disp, "_NET_WM_STATE", False); + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; + xev.xclient.data.l[1] = XInternAtom( Disp, "_NET_WM_STATE_FULLSCREEN", False); + xev.xclient.data.l[2] = 0; + + XSendEvent( Disp, DefaultRootWindow( Disp ), False, SubstructureNotifyMask, &xev); + } + } + + XMapRaised(Disp, Win); + XFlush(Disp); + + OvrPlatform::PlatformCore::SetFullscreen(rp, fullscreen); + + // Wait until we receive a configure notify event. If the WM redirected our + // structure, then WM should synthesize a configure notify event even + // if there was no change in the window layout. + XWindowEvent(Disp, Win, eventMask, &report); + + // Process the resize event. + processEvent(report); + + return true; +} + +int PlatformCore::GetDisplayCount() +{ + XRRScreenResources* screen = XRRGetScreenResources(Disp, Win); + RROutput primaryOutput = XRRGetOutputPrimary(Disp, DefaultRootWindow(Disp)); + + // Iterate through displays and ensure that they have valid outputs. + int numDisplays = 0; + for (int i = 0; i < screen->ncrtc; ++i) + { + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(Disp, screen, screen->crtcs[i]); + if (0 == crtcInfo->noutput) + { + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + RROutput output = crtcInfo->outputs[0]; + for (int ii = 0; ii < crtcInfo->noutput; ++ii) + { + if (primaryOutput == crtcInfo->outputs[ii]) + { + output = primaryOutput; + break; + } + } + + XRROutputInfo* outputInfo = XRRGetOutputInfo(Disp, screen, output); + if (RR_Connected != outputInfo->connection) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + if (RR_Connected == outputInfo->connection) + { + ++numDisplays; + } + + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + } + + XRRFreeScreenResources(screen); + return numDisplays; +} + +Render::DisplayId PlatformCore::GetDisplay(int screenId) +{ + char device_id[32] = ""; + + RROutput primaryOutput = XRRGetOutputPrimary(Disp, DefaultRootWindow(Disp)); + XRRScreenResources* screen = XRRGetScreenResources(Disp, Win); + + int screenIndex = 0; + for (int i = 0; i < screen->ncrtc; ++i) + { + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(Disp, screen, screen->crtcs[i]); + + if (0 == crtcInfo->noutput) + { + XRRFreeCrtcInfo(crtcInfo); + // We intentionally do not increment screenIndex. We do not + // consider this a valid display. + continue; + } + + RROutput output = crtcInfo->outputs[0]; + for (int ii = 0; ii < crtcInfo->noutput; ++ii) + { + if (primaryOutput == crtcInfo->outputs[ii]) + { + output = primaryOutput; + break; + } + } + + XRROutputInfo* outputInfo = XRRGetOutputInfo(Disp, screen, output); + if (RR_Connected != outputInfo->connection) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + MonitorInfo * mi = read_edid_data(Disp, output); + if (mi == NULL) + { + ++screenIndex; + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + if (screenIndex == screenId) + { + OVR_sprintf(device_id, 32, "%s%04d-%d", + mi->manufacturer_code, mi->product_code, + screen->crtcs[i]); + + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + + delete mi; + break; + } + + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + + delete mi; + ++screenIndex; + } + XRRFreeScreenResources(screen); + + return Render::DisplayId(device_id); +} + +XDisplayInfo PlatformCore::getXDisplayInfo(Render::DisplayId id) +{ + int screenId = IndexOf(id); + + // Locate and return XDisplayInfo + RROutput primaryOutput = XRRGetOutputPrimary(Disp, DefaultRootWindow(Disp)); + XRRScreenResources* screen = XRRGetScreenResources(Disp, Win); + + int screenIndex = 0; + for (int i = 0; i < screen->ncrtc; ++i) + { + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(Disp, screen, screen->crtcs[i]); + + if (0 == crtcInfo->noutput) + { + XRRFreeCrtcInfo(crtcInfo); + // We intentionally do not increment screenIndex. We do not + // consider this a valid display. + continue; + } + + RROutput output = crtcInfo->outputs[0]; + for (int ii = 0; ii < crtcInfo->noutput; ++ii) + { + if (primaryOutput == crtcInfo->outputs[ii]) + { + output = primaryOutput; + break; + } + } + + XRROutputInfo* outputInfo = XRRGetOutputInfo(Disp, screen, output); + if (RR_Connected != outputInfo->connection) + { + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + MonitorInfo * mi = read_edid_data(Disp, output); + if (mi == NULL) + { + ++screenIndex; + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + continue; + } + + if (screenIndex == screenId) + { + XDisplayInfo dinfo; + dinfo.valid = true; + dinfo.output = output; + dinfo.crtc = outputInfo->crtc; + dinfo.product= mi->product_code; + + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + + return dinfo; + } + + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); + + delete mi; + ++screenIndex; + } + XRRFreeScreenResources(screen); + + return XDisplayInfo(); +} + +RenderDevice* PlatformCore::SetupGraphics(const SetupGraphicsDeviceSet& setupGraphicsDesc, + const char* type, const Render::RendererParams& rp) +{ + const SetupGraphicsDeviceSet* setupDesc = setupGraphicsDesc.PickSetupDevice(type); + OVR_ASSERT(setupDesc); + + pRender = *setupDesc->pCreateDevice(rp, this); + if (pRender) + pRender->SetWindowSize(Width, Height); + + return pRender.GetPtr(); +} + +void PlatformCore::showCursor(bool show) +{ + if (show) + { + XUndefineCursor(Disp, Win); + } + else + { + XDefineCursor(Disp, Win, InvisibleCursor); + } +} + +}} + +// GL +namespace Render { namespace GL { namespace Linux { + + +// To do: We can do away with this function by using our GLEContext class, which already tracks extensions. +static bool IsGLXExtensionSupported(const char* extension, _XDisplay* pDisplay, int screen = 0) +{ + // const char* extensionList = glXQueryExtensionsString(pDisplay, screen); + const char* extensionList = glXGetClientString(pDisplay, GLX_EXTENSIONS); // This is returning more extensions than glXQueryExtensionsString does. + + if(extensionList) + { + const char* start = extensionList; + const char* where; + + static bool printed = false; + if(!printed) + { + OVR_DEBUG_LOG(("glX extensions: %s", extensionList)); + printed = true; + } + + while((where = (char*)strstr(start, extension)) != NULL) + { + if (where) + { + const char* term = (where + strlen(extension)); + + if ((where == start) || (where[-1] == ' ')) + { + if ((term[0] == ' ') || (term[0] == '\0')) + return true; + } + + start = term; + } + } + } + + return false; +} + +ovrRenderAPIConfig RenderDevice::Get_ovrRenderAPIConfig() const +{ + static ovrGLConfig cfg; + cfg.OGL.Header.API = ovrRenderAPI_OpenGL; + cfg.OGL.Header.RTSize = Sizei(WindowWidth, WindowHeight); + cfg.OGL.Header.Multisample = Params.Multisample; + cfg.OGL.Win = Win; + cfg.OGL.Disp = Disp; + return cfg.Config; +} + +Render::RenderDevice* RenderDevice::CreateDevice(const RendererParams& rp, void* oswnd) +{ + OvrPlatform::Linux::PlatformCore* PC = (OvrPlatform::Linux::PlatformCore*)oswnd; + + GLXContext context = glXCreateContext(PC->Disp, PC->Vis, 0, GL_TRUE); + + if (!context) + return NULL; + + if (!glXMakeCurrent(PC->Disp, PC->Win, context)) + { + glXDestroyContext(PC->Disp, context); + return NULL; + } + + XMapRaised(PC->Disp, PC->Win); + + InitGLExtensions(); + + XSync(PC->Disp, 0); + + for (XWindowAttributes attribute; attribute.map_state != IsViewable; ) + XGetWindowAttributes(PC->Disp,PC->Win,&attribute); + + XSetInputFocus(PC->Disp, PC->Win, RevertToParent, CurrentTime); + + return new Render::GL::Linux::RenderDevice(rp, PC->Disp, PC->Win, context); +} + +void RenderDevice::Present(bool withVsync) +{ + unsigned swapInterval = (withVsync) ? 1 : 0; + GLuint currentSwapInterval = 0; + glXQueryDrawable(Disp, Win, GLX_SWAP_INTERVAL_EXT, ¤tSwapInterval); + if (currentSwapInterval != swapInterval) + glXSwapIntervalEXT(Disp, Win, swapInterval); + + glXSwapBuffers(Disp, Win); +} + +void RenderDevice::Shutdown() +{ + if (Context) + { + glXMakeCurrent(Disp, 0, NULL); + glXDestroyContext(Disp, Context); + Context = NULL; + Win = 0; + } +} + +}}}} + +OVR::OvrPlatform::Linux::PlatformCore* gPlatform; + +static void handleSigInt(int sig) +{ + signal(SIGINT, SIG_IGN); + gPlatform->Exit(0); +} + +int main(int argc, const char* argv[]) +{ + using namespace OVR; + using namespace OVR::OvrPlatform; + + // SigInt for capturing Ctrl-c. + if (signal(SIGINT, handleSigInt) == SIG_ERR) + { + fprintf(stderr, "Failed setting SIGINT handler\n"); + return EXIT_FAILURE; + } + + // CreateApplication must be the first call since it does OVR::System::Initialize. + Application* app = Application::CreateApplication(); + gPlatform = new Linux::PlatformCore(app); + // The platform attached to an app will be deleted by DestroyApplication. + app->SetPlatformCore(gPlatform); + + int exitCode = app->OnStartup(argc, argv); + if (!exitCode) + exitCode = gPlatform->Run(); + + // No OVR functions involving memory are allowed after this. + Application::DestroyApplication(app); + app = 0; + + return exitCode; +} diff --git a/Samples/CommonSrc/Platform/Linux_Platform.h b/Samples/CommonSrc/Platform/Linux_Platform.h new file mode 100644 index 0000000..b8c5ca3 --- /dev/null +++ b/Samples/CommonSrc/Platform/Linux_Platform.h @@ -0,0 +1,149 @@ +/************************************************************************************ + +Filename : Platform_Linux.h +Content : Linux (X11) implementation of Platform app infrastructure +Created : September 6, 2012 +Authors : Andrew Reisse + +Copyright : Copyright 2012 Oculus VR, LLC. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +************************************************************************************/ + +#ifndef OVR_Platform_Linux_h +#define OVR_Platform_Linux_h + +#include "Platform.h" +#include "../Render/Render_GL_Device.h" + +#include +#include +#include + +namespace OVR { namespace Render { + class RenderDevice; +}} + +namespace OVR { namespace OvrPlatform { namespace Linux { + +struct XDisplayInfo; + +class PlatformCore : public OvrPlatform::PlatformCore +{ + Recti StartVP; + bool HasWM; + + int IndexOf(Render::DisplayId id); + XDisplayInfo getXDisplayInfo(Render::DisplayId id); + +public: + _XDisplay* Disp; + XVisualInfo* Vis; + Window Win; + + bool Quit; + int ExitCode; + int Width, Height; + + MouseMode MMode; + Cursor InvisibleCursor; + + enum + { + WM_PROTOCOLS, + WM_DELETE_WINDOW, + NumAtoms + }; + Atom Atoms[NumAtoms]; + + void processEvent(XEvent& event); + + Render::RenderDevice* SetupGraphics_GL(const Render::RendererParams& rp); + + void showCursor(bool show); + bool determineScreenOffset(int screenId, int* screenOffsetX, int* screenOffsetY); + void showWindowDecorations(bool show); + +public: + PlatformCore(Application* app); + ~PlatformCore(); + + void* SetupWindow(int w, int h); + void Exit(int exitcode) { Quit = 1; ExitCode = exitcode; } + + RenderDevice* SetupGraphics(const SetupGraphicsDeviceSet& setupGraphicsDesc, + const char* gtype, const Render::RendererParams& rp); + + void SetMouseMode(MouseMode mm); + void GetWindowSize(int* w, int* h) const; + + void SetWindowTitle(const char*title); + + void ShowWindow(bool show); + void DestroyWindow(); + bool SetFullscreen(const Render::RendererParams& rp, int fullscreen); + int GetDisplayCount(); + Render::DisplayId GetDisplay(int screen); + + int Run(); +}; + +}} +namespace Render { namespace GL { namespace Linux { + +class RenderDevice : public Render::GL::RenderDevice +{ + _XDisplay* Disp; + Window Win; + GLXContext Context; + +public: + RenderDevice(const Render::RendererParams& p, _XDisplay* disp, Window w, GLXContext gl) + : GL::RenderDevice(p), Disp(disp), Win(w), Context(gl) {} + + virtual void Shutdown(); + virtual void Present(bool withVsync); + virtual ovrRenderAPIConfig Get_ovrRenderAPIConfig() const; + + // oswnd = Linux::PlatformCore* + static Render::RenderDevice* CreateDevice(const RendererParams& rp, void* oswnd); +}; + +}}}} + + +// OVR_PLATFORM_APP_ARGS specifies the Application class to use for startup, +// providing it with startup arguments. +#define OVR_PLATFORM_APP_ARGS(AppClass, args) \ + OVR::OvrPlatform::Application* OVR::OvrPlatform::Application::CreateApplication() \ + { OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All)); \ + return new AppClass args; } \ + void OVR::OvrPlatform::Application::DestroyApplication(OVR::OvrPlatform::Application* app) \ + { OVR::OvrPlatform::PlatformCore* platform = app->pPlatform; \ + delete app; delete platform; OVR::System::Destroy(); }; + +// OVR_PLATFORM_APP_ARGS specifies the Application startup class with no args. +#define OVR_PLATFORM_APP(AppClass) OVR_PLATFORM_APP_ARGS(AppClass, ()) + +#define OVR_PLATFORM_APP_ARGS_WITH_LOG(AppClass, LogClass, args) \ + OVR::OvrPlatform::Application* OVR::OvrPlatform::Application::CreateApplication() \ + { static LogClass log; OVR::System::Init(&log); \ + return new AppClass args; } \ + void OVR::OvrPlatform::Application::DestroyApplication(OVR::OvrPlatform::Application* app) \ + { OVR::OvrPlatform::PlatformCore* platform = app->pPlatform; \ + delete app; delete platform; OVR::System::Destroy(); }; + +#define OVR_PLATFORM_APP_WITH_LOG(AppClass,LogClass) OVR_PLATFORM_APP_ARGS_WITH_LOG(AppClass,LogClass, ()) + +#endif diff --git a/Samples/CommonSrc/Platform/OSX_Platform.mm b/Samples/CommonSrc/Platform/OSX_Platform.mm index dfc29f8..4955337 100644 --- a/Samples/CommonSrc/Platform/OSX_Platform.mm +++ b/Samples/CommonSrc/Platform/OSX_Platform.mm @@ -1,553 +1,1108 @@ -/************************************************************************************ - -Filename : OSX_Platform.mm -Content : -Created : -Authors : - -Copyright : Copyright 2012 Oculus, Inc. All Rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -************************************************************************************/ - -#import "../Platform/OSX_PlatformObjc.h" - -using namespace OVR; -using namespace OVR::OvrPlatform; - -@implementation OVRApp - -- (void)dealloc -{ - [super dealloc]; -} - -- (void)run -{ - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - _running = YES; - OVR::OvrPlatform::Application* app; - { - using namespace OVR; - using namespace OVR::OvrPlatform; - - // CreateApplication must be the first call since it does OVR::System::Initialize. - app = Application::CreateApplication(); - OSX::PlatformCore* platform = new OSX::PlatformCore(app, self); - // The platform attached to an app will be deleted by DestroyApplication. - app->SetPlatformCore(platform); - - [self setApp:app]; - [self setPlatform:platform]; - - const char* argv[] = {"OVRApp"}; - int exitCode = app->OnStartup(1, argv); - if (exitCode) - { - Application::DestroyApplication(app); - exit(exitCode); - } - } - [self finishLaunching]; - [pool drain]; - - while ([self isRunning]) - { - pool = [[NSAutoreleasePool alloc] init]; - NSEvent* event = [self nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event) - { - [self sendEvent:event]; - } - _App->OnIdle(); - [pool drain]; - } - OVR::OvrPlatform::Application::DestroyApplication(app); -} - -@end - -static int KeyMap[][2] = -{ - { NSDeleteFunctionKey, OVR::Key_Delete }, - { '\t', OVR::Key_Tab }, - { '\n', OVR::Key_Return }, - { NSPauseFunctionKey, OVR::Key_Pause }, - { 27, OVR::Key_Escape }, - { 127, OVR::Key_Backspace }, - { ' ', OVR::Key_Space }, - { NSPageUpFunctionKey, OVR::Key_PageUp }, - { NSPageDownFunctionKey, OVR::Key_PageDown }, - { NSNextFunctionKey, OVR::Key_PageDown }, - { NSEndFunctionKey, OVR::Key_End }, - { NSHomeFunctionKey, OVR::Key_Home }, - { NSLeftArrowFunctionKey, OVR::Key_Left }, - { NSUpArrowFunctionKey, OVR::Key_Up }, - { NSRightArrowFunctionKey, OVR::Key_Right }, - { NSDownArrowFunctionKey, OVR::Key_Down }, - { NSInsertFunctionKey, OVR::Key_Insert }, - { NSDeleteFunctionKey, OVR::Key_Delete }, - { NSHelpFunctionKey, OVR::Key_Insert }, -}; - - -static KeyCode MapToKeyCode(wchar_t vk) -{ - unsigned key = Key_None; - - if ((vk >= 'a') && (vk <= 'z')) - { - key = vk - 'a' + Key_A; - } - else if ((vk >= ' ') && (vk <= '~')) - { - key = vk; - } - else if ((vk >= '0') && (vk <= '9')) - { - key = vk - '0' + Key_Num0; - } - else if ((vk >= NSF1FunctionKey) && (vk <= NSF15FunctionKey)) - { - key = vk - NSF1FunctionKey + Key_F1; - } - else - { - for (unsigned i = 0; i< (sizeof(KeyMap) / sizeof(KeyMap[1])); i++) - { - if (vk == KeyMap[i][0]) - { - key = KeyMap[i][1]; - break; - } - } - } - - return (KeyCode)key; -} - -static int MapModifiers(unsigned long xmod) -{ - int mod = 0; - if (xmod & NSShiftKeyMask) - mod |= OVR::OvrPlatform::Mod_Shift; - if (xmod & NSCommandKeyMask) - mod |= OVR::OvrPlatform::Mod_Control; - if (xmod & NSAlternateKeyMask) - mod |= OVR::OvrPlatform::Mod_Alt; - if (xmod & NSControlKeyMask) - mod |= OVR::OvrPlatform::Mod_Meta; - return mod; -} - -@implementation OVRView - --(BOOL) acceptsFirstResponder -{ - return YES; -} --(BOOL) acceptsFirstMouse:(NSEvent *)ev -{ - return YES; -} - -+(CGDirectDisplayID) displayFromScreen:(NSScreen *)s -{ - NSNumber* didref = (NSNumber*)[[s deviceDescription] objectForKey:@"NSScreenNumber"]; - CGDirectDisplayID disp = (CGDirectDisplayID)[didref longValue]; - return disp; -} - --(void) warpMouseToCenter -{ - NSPoint w; - w.x = _Platform->Width/2.0f; - w.y = _Platform->Height/2.0f; - w = [[self window] convertBaseToScreen:w]; - CGDirectDisplayID disp = [OVRView displayFromScreen:[[self window] screen]]; - CGPoint p = {w.x, CGDisplayPixelsHigh(disp)-w.y}; - CGDisplayMoveCursorToPoint(disp, p); -} - -static bool LookupKey(NSEvent* ev, wchar_t& ch, OVR::KeyCode& key, unsigned& mods) -{ - NSString* chars = [ev charactersIgnoringModifiers]; - if ([chars length] == 0) - return false; - ch = [chars characterAtIndex:0]; - mods = MapModifiers([ev modifierFlags]); - - // check for Cmd+Latin Letter - NSString* modchars = [ev characters]; - if ([modchars length]) - { - wchar_t modch = [modchars characterAtIndex:0]; - if (modch >= 'a' && modch <= 'z') - ch = modch; - } - key = MapToKeyCode(ch); - return true; -} - --(void) keyDown:(NSEvent*)ev -{ - OVR::KeyCode key; - unsigned mods; - wchar_t ch; - if (!LookupKey(ev, ch, key, mods)) - return; - if (key == Key_Escape && _Platform->MMode == Mouse_Relative) - { - [self warpMouseToCenter]; - CGAssociateMouseAndMouseCursorPosition(true); - [NSCursor unhide]; - _Platform->MMode = Mouse_RelativeEscaped; - } - _App->OnKey(key, ch, true, mods); -} --(void) keyUp:(NSEvent*)ev -{ - OVR::KeyCode key; - unsigned mods; - wchar_t ch; - if (LookupKey(ev, ch, key, mods)) - _App->OnKey(key, ch, false, mods); -} - -static const OVR::KeyCode ModifierKeys[] = {OVR::Key_None, OVR::Key_Shift, OVR::Key_Control, OVR::Key_Alt, OVR::Key_Meta}; - --(void)flagsChanged:(NSEvent *)ev -{ - unsigned long cmods = [ev modifierFlags]; - if ((cmods & 0xffff0000) != _Modifiers) - { - uint32_t mods = MapModifiers(cmods); - for (int i = 1; i <= 4; i++) - { - unsigned long m = (1 << (16+i)); - if ((cmods & m) != (_Modifiers & m)) - { - if (cmods & m) - _App->OnKey(ModifierKeys[i], 0, true, mods); - else - _App->OnKey(ModifierKeys[i], 0, false, mods); - } - } - _Modifiers = cmods & 0xffff0000; - } -} - --(void)ProcessMouse:(NSEvent*)ev -{ - switch ([ev type]) - { - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - case NSMouseMoved: - { - if (_Platform->MMode == OVR::OvrPlatform::Mouse_Relative) - { - int dx = [ev deltaX]; - int dy = [ev deltaY]; - - if (dx != 0 || dy != 0) - { - _App->OnMouseMove(dx, dy, Mod_MouseRelative|MapModifiers([ev modifierFlags])); - [self warpMouseToCenter]; - } - } - else - { - NSPoint p = [ev locationInWindow]; - _App->OnMouseMove(p.x, p.y, MapModifiers([ev modifierFlags])); - } - } - break; - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - break; - } -} - --(void) mouseMoved:(NSEvent*)ev -{ - [self ProcessMouse:ev]; -} --(void) mouseDragged:(NSEvent*)ev -{ - [self ProcessMouse:ev]; -} --(void) mouseDown:(NSEvent*)ev -{ - if (_Platform->MMode == Mouse_RelativeEscaped) - { - [self warpMouseToCenter]; - CGAssociateMouseAndMouseCursorPosition(false); - [NSCursor hide]; - _Platform->MMode = Mouse_Relative; - } -} - -//-(void) - --(id) initWithFrame:(NSRect)frameRect -{ - NSOpenGLPixelFormatAttribute attr[] = - { -// NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, -// NSOpenGLPFAWindow, - NSOpenGLPFADoubleBuffer, - NSOpenGLPFADepthSize, 24, - nil - }; - - NSOpenGLPixelFormat *pf = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attr] autorelease]; - - self = [super initWithFrame:frameRect pixelFormat:pf]; - GLint swap = 0; - [[self openGLContext] setValues:&swap forParameter:NSOpenGLCPSwapInterval]; - //[self setWantsBestResolutionOpenGLSurface:YES]; - return self; -} - --(void) reshape -{ - NSRect bounds = [self bounds]; - _App->OnResize(bounds.size.width, bounds.size.height); - - _Platform->Width = bounds.size.width; - _Platform->Height = bounds.size.height; - - if (_Platform->GetRenderer()) - _Platform->GetRenderer()->SetWindowSize(bounds.size.width, bounds.size.height); -} - --(BOOL)windowShouldClose:(id)sender -{ - if (_Platform) - _Platform->Exit(0); - else - exit(0); - return 1; -} - -@end - -namespace OVR { namespace OvrPlatform { namespace OSX { - -PlatformCore::PlatformCore(Application* app, void* nsapp) - : OvrPlatform::PlatformCore(app), NsApp(nsapp), Win(NULL), View(NULL), Quit(0), MMode(Mouse_Normal) -{ - pGamepadManager = *new OSX::GamepadManager(); -} -PlatformCore::~PlatformCore() -{ -} - -void PlatformCore::Exit(int exitcode) -{ - OVRApp* nsApp = (OVRApp*)NsApp; - [nsApp stop:nil]; -} - -String PlatformCore::GetContentDirectory() const -{ - NSBundle* bundle = [NSBundle mainBundle]; - if (bundle) - return String([[bundle bundlePath] UTF8String]) + "/Contents/Resources"; - else - return "."; -} - - -void PlatformCore::SetMouseMode(MouseMode mm) -{ - if (mm == MMode) - return; - - if (Win) - { - if (mm == Mouse_Relative) - { - [NSCursor hide]; - [(OVRView*)View warpMouseToCenter]; - CGAssociateMouseAndMouseCursorPosition(false); - } - else - { - if (MMode == Mouse_Relative) - { - CGAssociateMouseAndMouseCursorPosition(true); - [NSCursor unhide]; - [(OVRView*)View warpMouseToCenter]; - } - } - } - MMode = mm; -} - - -void PlatformCore::GetWindowSize(int* w, int* h) const -{ - *w = Width; - *h = Height; -} - -void* PlatformCore::SetupWindow(int w, int h) -{ - NSRect winrect; - winrect.origin.x = 0; - winrect.origin.y = 1000; - winrect.size.width = w; - winrect.size.height = h; - NSWindow* win = [[NSWindow alloc] initWithContentRect:winrect styleMask:NSTitledWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO]; - - OVRView* view = [[OVRView alloc] initWithFrame:winrect]; - [view setPlatform:this]; - [win setContentView:view]; - [win setAcceptsMouseMovedEvents:YES]; - [win setDelegate:view]; - [view setApp:pApp]; - Win = win; - View = view; - return (void*)[win windowNumber]; -} - -void PlatformCore::SetWindowTitle(const char* title) -{ - [((NSWindow*)Win) setTitle:[[NSString alloc] initWithBytes:title length:strlen(title) encoding:NSUTF8StringEncoding]]; -} - -void PlatformCore::ShowWindow(bool show) -{ - if (show) - [((NSWindow*)Win) makeKeyAndOrderFront:nil]; - else - [((NSWindow*)Win) orderOut:nil]; -} - -void PlatformCore::DestroyWindow() -{ - [((NSWindow*)Win) close]; - Win = NULL; -} - -RenderDevice* PlatformCore::SetupGraphics(const SetupGraphicsDeviceSet& setupGraphicsDesc, - const char* type, const Render::RendererParams& rp) -{ - const SetupGraphicsDeviceSet* setupDesc = setupGraphicsDesc.PickSetupDevice(type); - OVR_ASSERT(setupDesc); - - pRender = *setupDesc->pCreateDevice(rp, this); - if (pRender) - pRender->SetWindowSize(Width, Height); - - return pRender.GetPtr(); -} - -int PlatformCore::GetDisplayCount() -{ - return (int)[[NSScreen screens] count]; -} - -Render::DisplayId PlatformCore::GetDisplay(int i) -{ - NSScreen* s = (NSScreen*)[[NSScreen screens] objectAtIndex:i]; - return Render::DisplayId([OVRView displayFromScreen:s]); -} - -bool PlatformCore::SetFullscreen(const Render::RendererParams& rp, int fullscreen) -{ - if (fullscreen == Render::Display_Window) - [(OVRView*)View exitFullScreenModeWithOptions:nil]; - else - { - NSScreen* usescreen = [NSScreen mainScreen]; - NSArray* screens = [NSScreen screens]; - for (int i = 0; i < [screens count]; i++) - { - NSScreen* s = (NSScreen*)[screens objectAtIndex:i]; - CGDirectDisplayID disp = [OVRView displayFromScreen:s]; - - if (disp == rp.Display.CgDisplayId) - usescreen = s; - } - - [(OVRView*)View enterFullScreenMode:usescreen withOptions:nil]; - [(NSWindow*)Win setInitialFirstResponder:(OVRView*)View]; - [(NSWindow*)Win makeFirstResponder:(OVRView*)View]; - } - - if (pRender) - pRender->SetFullscreen((Render::DisplayMode)fullscreen); - return 1; -} - -}} -// GL -namespace Render { namespace GL { namespace OSX { - -ovrRenderAPIConfig RenderDevice::Get_ovrRenderAPIConfig() const -{ - ovrRenderAPIConfig result = ovrRenderAPIConfig(); - result.Header.API = ovrRenderAPI_OpenGL; - result.Header.RTSize = Sizei(WindowWidth, WindowHeight); - result.Header.Multisample = Params.Multisample; - return result; -} - -Render::RenderDevice* RenderDevice::CreateDevice(const RendererParams& rp, void* oswnd) -{ - OvrPlatform::OSX::PlatformCore* PC = (OvrPlatform::OSX::PlatformCore*)oswnd; - - OVRView* view = (OVRView*)PC->View; - NSOpenGLContext *context = [view openGLContext]; - if (!context) - return NULL; - - [context makeCurrentContext]; - [((NSWindow*)PC->Win) makeKeyAndOrderFront:nil]; - - return new Render::GL::OSX::RenderDevice(rp, context); -} - -void RenderDevice::Present(bool useVsync) -{ - NSOpenGLContext *context = (NSOpenGLContext*)Context; - [context flushBuffer]; -} - -void RenderDevice::Shutdown() -{ - Context = NULL; -} - -bool RenderDevice::SetFullscreen(DisplayMode fullscreen) -{ - Params.Fullscreen = fullscreen; - return 1; -} - -}}}} - - -int main(int argc, char *argv[]) -{ - NSApplication* nsapp = [OVRApp sharedApplication]; - [nsapp run]; - return 0; -} - +/************************************************************************************ + + + +Filename : OSX_Platform.mm + +Content : + +Created : + +Authors : + + + +Copyright : Copyright 2012 Oculus, Inc. All Rights reserved. + + + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + + +http://www.apache.org/licenses/LICENSE-2.0 + + + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + + + +************************************************************************************/ + + + +#import "../Platform/OSX_PlatformObjc.h" + + + +using namespace OVR; + +using namespace OVR::OvrPlatform; + + + +@implementation OVRApp + + + +- (void)dealloc + +{ + + [super dealloc]; + +} + + + +- (void)run + +{ + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + _running = YES; + + OVR::OvrPlatform::Application* app; + + { + + using namespace OVR; + + using namespace OVR::OvrPlatform; + + + + // CreateApplication must be the first call since it does OVR::System::Initialize. + + app = Application::CreateApplication(); + + OSX::PlatformCore* platform = new OSX::PlatformCore(app, self); + + // The platform attached to an app will be deleted by DestroyApplication. + + app->SetPlatformCore(platform); + + + + [self setApp:app]; + + [self setPlatform:platform]; + + + + const char* argv[] = {"OVRApp"}; + + int exitCode = app->OnStartup(1, argv); + + if (exitCode) + + { + + Application::DestroyApplication(app); + + exit(exitCode); + + } + + } + + [self finishLaunching]; + + [pool drain]; + + + + while ([self isRunning]) + + { + + pool = [[NSAutoreleasePool alloc] init]; + + NSEvent* event = [self nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]; + + if (event) + + { + + [self sendEvent:event]; + + } + + _App->OnIdle(); + + [pool drain]; + + } + + OVR::OvrPlatform::Application::DestroyApplication(app); + +} + + + +@end + + + +static int KeyMap[][2] = + +{ + + { NSDeleteFunctionKey, OVR::Key_Delete }, + + { '\t', OVR::Key_Tab }, + + { '\n', OVR::Key_Return }, + + { NSPauseFunctionKey, OVR::Key_Pause }, + + { 27, OVR::Key_Escape }, + + { 127, OVR::Key_Backspace }, + + { ' ', OVR::Key_Space }, + + { NSPageUpFunctionKey, OVR::Key_PageUp }, + + { NSPageDownFunctionKey, OVR::Key_PageDown }, + + { NSNextFunctionKey, OVR::Key_PageDown }, + + { NSEndFunctionKey, OVR::Key_End }, + + { NSHomeFunctionKey, OVR::Key_Home }, + + { NSLeftArrowFunctionKey, OVR::Key_Left }, + + { NSUpArrowFunctionKey, OVR::Key_Up }, + + { NSRightArrowFunctionKey, OVR::Key_Right }, + + { NSDownArrowFunctionKey, OVR::Key_Down }, + + { NSInsertFunctionKey, OVR::Key_Insert }, + + { NSDeleteFunctionKey, OVR::Key_Delete }, + + { NSHelpFunctionKey, OVR::Key_Insert }, + +}; + + + + + +static KeyCode MapToKeyCode(wchar_t vk) + +{ + + unsigned key = Key_None; + + + + if ((vk >= 'a') && (vk <= 'z')) + + { + + key = vk - 'a' + Key_A; + + } + + else if ((vk >= ' ') && (vk <= '~')) + + { + + key = vk; + + } + + else if ((vk >= '0') && (vk <= '9')) + + { + + key = vk - '0' + Key_Num0; + + } + + else if ((vk >= NSF1FunctionKey) && (vk <= NSF15FunctionKey)) + + { + + key = vk - NSF1FunctionKey + Key_F1; + + } + + else + + { + + for (unsigned i = 0; i< (sizeof(KeyMap) / sizeof(KeyMap[1])); i++) + + { + + if (vk == KeyMap[i][0]) + + { + + key = KeyMap[i][1]; + + break; + + } + + } + + } + + + + return (KeyCode)key; + +} + + + +static int MapModifiers(unsigned long xmod) + +{ + + int mod = 0; + + if (xmod & NSShiftKeyMask) + + mod |= OVR::OvrPlatform::Mod_Shift; + + if (xmod & NSCommandKeyMask) + + mod |= OVR::OvrPlatform::Mod_Control; + + if (xmod & NSAlternateKeyMask) + + mod |= OVR::OvrPlatform::Mod_Alt; + + if (xmod & NSControlKeyMask) + + mod |= OVR::OvrPlatform::Mod_Meta; + + return mod; + +} + + + +@implementation OVRView + + + +-(BOOL) acceptsFirstResponder + +{ + + return YES; + +} + +-(BOOL) acceptsFirstMouse:(NSEvent *)ev + +{ + + return YES; + +} + + + ++(CGDirectDisplayID) displayFromScreen:(NSScreen *)s + +{ + + NSNumber* didref = (NSNumber*)[[s deviceDescription] objectForKey:@"NSScreenNumber"]; + + CGDirectDisplayID disp = (CGDirectDisplayID)[didref longValue]; + + return disp; + +} + + + +-(void) warpMouseToCenter + +{ + + NSPoint w; + + w.x = _Platform->Width/2.0f; + + w.y = _Platform->Height/2.0f; + + w = [[self window] convertBaseToScreen:w]; + + CGDirectDisplayID disp = [OVRView displayFromScreen:[[self window] screen]]; + + CGPoint p = {w.x, CGDisplayPixelsHigh(disp)-w.y}; + + CGDisplayMoveCursorToPoint(disp, p); + +} + + + +static bool LookupKey(NSEvent* ev, wchar_t& ch, OVR::KeyCode& key, unsigned& mods) + +{ + + NSString* chars = [ev charactersIgnoringModifiers]; + + if ([chars length] == 0) + + return false; + + ch = [chars characterAtIndex:0]; + + mods = MapModifiers([ev modifierFlags]); + + + + // check for Cmd+Latin Letter + + NSString* modchars = [ev characters]; + + if ([modchars length]) + + { + + wchar_t modch = [modchars characterAtIndex:0]; + + if (modch >= 'a' && modch <= 'z') + + ch = modch; + + } + + key = MapToKeyCode(ch); + + return true; + +} + + + +-(void) keyDown:(NSEvent*)ev + +{ + + OVR::KeyCode key; + + unsigned mods; + + wchar_t ch; + + if (!LookupKey(ev, ch, key, mods)) + + return; + + if (key == Key_Escape && _Platform->MMode == Mouse_Relative) + + { + + [self warpMouseToCenter]; + + CGAssociateMouseAndMouseCursorPosition(true); + + [NSCursor unhide]; + + _Platform->MMode = Mouse_RelativeEscaped; + + } + + _App->OnKey(key, ch, true, mods); + +} + +-(void) keyUp:(NSEvent*)ev + +{ + + OVR::KeyCode key; + + unsigned mods; + + wchar_t ch; + + if (LookupKey(ev, ch, key, mods)) + + _App->OnKey(key, ch, false, mods); + +} + + + +static const OVR::KeyCode ModifierKeys[] = {OVR::Key_None, OVR::Key_Shift, OVR::Key_Control, OVR::Key_Alt, OVR::Key_Meta}; + + + +-(void)flagsChanged:(NSEvent *)ev + +{ + + unsigned long cmods = [ev modifierFlags]; + + if ((cmods & 0xffff0000) != _Modifiers) + + { + + uint32_t mods = MapModifiers(cmods); + + for (int i = 1; i <= 4; i++) + + { + + unsigned long m = (1 << (16+i)); + + if ((cmods & m) != (_Modifiers & m)) + + { + + if (cmods & m) + + _App->OnKey(ModifierKeys[i], 0, true, mods); + + else + + _App->OnKey(ModifierKeys[i], 0, false, mods); + + } + + } + + _Modifiers = cmods & 0xffff0000; + + } + +} + + + +-(void)ProcessMouse:(NSEvent*)ev + +{ + + switch ([ev type]) + + { + + case NSLeftMouseDragged: + + case NSRightMouseDragged: + + case NSOtherMouseDragged: + + case NSMouseMoved: + + { + + if (_Platform->MMode == OVR::OvrPlatform::Mouse_Relative) + + { + + int dx = [ev deltaX]; + + int dy = [ev deltaY]; + + + + if (dx != 0 || dy != 0) + + { + + _App->OnMouseMove(dx, dy, Mod_MouseRelative|MapModifiers([ev modifierFlags])); + + [self warpMouseToCenter]; + + } + + } + + else + + { + + NSPoint p = [ev locationInWindow]; + + _App->OnMouseMove(p.x, p.y, MapModifiers([ev modifierFlags])); + + } + + } + + break; + + case NSLeftMouseDown: + + case NSRightMouseDown: + + case NSOtherMouseDown: + + break; + + } + +} + + + +-(void) mouseMoved:(NSEvent*)ev + +{ + + [self ProcessMouse:ev]; + +} + +-(void) mouseDragged:(NSEvent*)ev + +{ + + [self ProcessMouse:ev]; + +} + +-(void) mouseDown:(NSEvent*)ev + +{ + + if (_Platform->MMode == Mouse_RelativeEscaped) + + { + + [self warpMouseToCenter]; + + CGAssociateMouseAndMouseCursorPosition(false); + + [NSCursor hide]; + + _Platform->MMode = Mouse_Relative; + + } + +} + + + +//-(void) + + + +-(id) initWithFrame:(NSRect)frameRect + +{ + + NSOpenGLPixelFormatAttribute attr[] = + + { + +// NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + +// NSOpenGLPFAWindow, + + NSOpenGLPFADoubleBuffer, + + NSOpenGLPFADepthSize, 24, + + 0 + + }; + + + + NSOpenGLPixelFormat *pf = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attr] autorelease]; + + + + self = [super initWithFrame:frameRect pixelFormat:pf]; + + GLint swap = 0; + + [[self openGLContext] setValues:&swap forParameter:NSOpenGLCPSwapInterval]; + + //[self setWantsBestResolutionOpenGLSurface:YES]; + + return self; + +} + + + +-(void) reshape + +{ + + NSRect bounds = [self bounds]; + + _App->OnResize(bounds.size.width, bounds.size.height); + + + + _Platform->Width = bounds.size.width; + + _Platform->Height = bounds.size.height; + + + + if (_Platform->GetRenderer()) + + _Platform->GetRenderer()->SetWindowSize(bounds.size.width, bounds.size.height); + +} + + + +-(BOOL)windowShouldClose:(id)sender + +{ + + if (_Platform) + + _Platform->Exit(0); + + else + + exit(0); + + return 1; + +} + + + +@end + + + +namespace OVR { namespace OvrPlatform { namespace OSX { + + + +PlatformCore::PlatformCore(Application* app, void* nsapp) + + : OvrPlatform::PlatformCore(app), NsApp(nsapp), Win(NULL), View(NULL), Quit(0), MMode(Mouse_Normal) + +{ + + pGamepadManager = *new OSX::GamepadManager(); + +} + +PlatformCore::~PlatformCore() + +{ + +} + + + +void PlatformCore::Exit(int exitcode) + +{ + + OVRApp* nsApp = (OVRApp*)NsApp; + + [nsApp stop:nil]; + +} + + + +String PlatformCore::GetContentDirectory() const + +{ + + NSBundle* bundle = [NSBundle mainBundle]; + + if (bundle) + + return String([[bundle bundlePath] UTF8String]) + "/Contents/Resources"; + + else + + return "."; + +} + + + + + +void PlatformCore::SetMouseMode(MouseMode mm) + +{ + + if (mm == MMode) + + return; + + + + if (Win) + + { + + if (mm == Mouse_Relative) + + { + + [NSCursor hide]; + + [(OVRView*)View warpMouseToCenter]; + + CGAssociateMouseAndMouseCursorPosition(false); + + } + + else + + { + + if (MMode == Mouse_Relative) + + { + + CGAssociateMouseAndMouseCursorPosition(true); + + [NSCursor unhide]; + + [(OVRView*)View warpMouseToCenter]; + + } + + } + + } + + MMode = mm; + +} + + + + + +void PlatformCore::GetWindowSize(int* w, int* h) const + +{ + + *w = Width; + + *h = Height; + +} + + + +void* PlatformCore::SetupWindow(int w, int h) + +{ + + NSRect winrect; + + winrect.origin.x = 0; + + winrect.origin.y = 1000; + + winrect.size.width = w; + + winrect.size.height = h; + + NSWindow* win = [[NSWindow alloc] initWithContentRect:winrect styleMask:NSTitledWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO]; + + + + OVRView* view = [[OVRView alloc] initWithFrame:winrect]; + + [view setPlatform:this]; + + [win setContentView:view]; + + [win setAcceptsMouseMovedEvents:YES]; + + [win setDelegate:view]; + + [view setApp:pApp]; + + Win = win; + + View = view; + + return (void*)[win windowNumber]; + +} + + + +void PlatformCore::SetWindowTitle(const char* title) + +{ + + NSString* nsTitle = [[[NSString alloc] initWithBytes:title length:strlen(title) encoding:NSUTF8StringEncoding] autorelease]; + + [((NSWindow*)Win) setTitle:nsTitle]; + +} + + + +void PlatformCore::ShowWindow(bool show) + +{ + + if (show) + + [((NSWindow*)Win) makeKeyAndOrderFront:nil]; + + else + + [((NSWindow*)Win) orderOut:nil]; + +} + + + +void PlatformCore::DestroyWindow() + +{ + + [((NSWindow*)Win) close]; + + Win = NULL; + +} + + + +RenderDevice* PlatformCore::SetupGraphics(const SetupGraphicsDeviceSet& setupGraphicsDesc, + + const char* type, const Render::RendererParams& rp) + +{ + + const SetupGraphicsDeviceSet* setupDesc = setupGraphicsDesc.PickSetupDevice(type); + + OVR_ASSERT(setupDesc && setupDesc->pCreateDevice); + + + + pRender = *setupDesc->pCreateDevice(rp, this); + + if (pRender) + + pRender->SetWindowSize(Width, Height); + + + + return pRender.GetPtr(); + +} + + + +int PlatformCore::GetDisplayCount() + +{ + + return (int)[[NSScreen screens] count]; + +} + + + +Render::DisplayId PlatformCore::GetDisplay(int i) + +{ + + NSScreen* s = (NSScreen*)[[NSScreen screens] objectAtIndex:i]; + + return Render::DisplayId([OVRView displayFromScreen:s]); + +} + + + +bool PlatformCore::SetFullscreen(const Render::RendererParams& rp, int fullscreen) + +{ + + if (fullscreen == Render::Display_Window) + + [(OVRView*)View exitFullScreenModeWithOptions:nil]; + + else + + { + + NSScreen* usescreen = [NSScreen mainScreen]; + + NSArray* screens = [NSScreen screens]; + + for (int i = 0; i < [screens count]; i++) + + { + + NSScreen* s = (NSScreen*)[screens objectAtIndex:i]; + + CGDirectDisplayID disp = [OVRView displayFromScreen:s]; + + + + if (disp == rp.Display.CgDisplayId) + + usescreen = s; + + } + + + + [(OVRView*)View enterFullScreenMode:usescreen withOptions:nil]; + + [(NSWindow*)Win setInitialFirstResponder:(OVRView*)View]; + + [(NSWindow*)Win makeFirstResponder:(OVRView*)View]; + + } + + + + if (pRender) + + pRender->SetFullscreen((Render::DisplayMode)fullscreen); + + return 1; + +} + + + +}} + +// GL + +namespace Render { namespace GL { namespace OSX { + + + +ovrRenderAPIConfig RenderDevice::Get_ovrRenderAPIConfig() const + +{ + + ovrRenderAPIConfig result = ovrRenderAPIConfig(); + + result.Header.API = ovrRenderAPI_OpenGL; + + result.Header.RTSize = Sizei(WindowWidth, WindowHeight); + + result.Header.Multisample = Params.Multisample; + + return result; + +} + + + +Render::RenderDevice* RenderDevice::CreateDevice(const RendererParams& rp, void* oswnd) + +{ + + OvrPlatform::OSX::PlatformCore* PC = (OvrPlatform::OSX::PlatformCore*)oswnd; + + + + OVRView* view = (OVRView*)PC->View; + + NSOpenGLContext *context = [view openGLContext]; + + if (!context) + + return NULL; + + + + [context makeCurrentContext]; + + [((NSWindow*)PC->Win) makeKeyAndOrderFront:nil]; + + + + return new Render::GL::OSX::RenderDevice(rp, context); + +} + + + +void RenderDevice::Present(bool useVsync) + +{ + + NSOpenGLContext *context = (NSOpenGLContext*)Context; + + [context flushBuffer]; + +} + + + +void RenderDevice::Shutdown() + +{ + + Context = NULL; + +} + + + +bool RenderDevice::SetFullscreen(DisplayMode fullscreen) + +{ + + Params.Fullscreen = fullscreen; + + return 1; + +} + + + +}}}} + + + + + +int main(int argc, char *argv[]) + +{ + + NSApplication* nsapp = [OVRApp sharedApplication]; + + [nsapp run]; + + return 0; + +} + + + diff --git a/Samples/CommonSrc/Platform/Platform.cpp b/Samples/CommonSrc/Platform/Platform.cpp index 40d7842..3b4f206 100644 --- a/Samples/CommonSrc/Platform/Platform.cpp +++ b/Samples/CommonSrc/Platform/Platform.cpp @@ -5,7 +5,7 @@ Content : Platform-independent app framework for Oculus samples Created : September 6, 2012 Authors : Andrew Reisse -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2012 Oculus VR, LLC All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Samples/CommonSrc/Platform/Platform.h b/Samples/CommonSrc/Platform/Platform.h index e9325a7..2eeb4df 100644 --- a/Samples/CommonSrc/Platform/Platform.h +++ b/Samples/CommonSrc/Platform/Platform.h @@ -5,7 +5,7 @@ Content : Platform-independent app and rendering framework for Oculus samp Created : September 6, 2012 Authors : Andrew Reisse -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2012 Oculus VR, LLC All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Samples/CommonSrc/Platform/Platform_Default.h b/Samples/CommonSrc/Platform/Platform_Default.h index 420b088..0ce02ad 100644 --- a/Samples/CommonSrc/Platform/Platform_Default.h +++ b/Samples/CommonSrc/Platform/Platform_Default.h @@ -5,7 +5,7 @@ Content : Default Platform class and RenderDevice selection file Created : October 4, 2012 Authors : -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2012 Oculus VR, LLC All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Samples/CommonSrc/Platform/Win32_Gamepad.cpp b/Samples/CommonSrc/Platform/Win32_Gamepad.cpp index 5186773..d10c4b1 100644 --- a/Samples/CommonSrc/Platform/Win32_Gamepad.cpp +++ b/Samples/CommonSrc/Platform/Win32_Gamepad.cpp @@ -5,7 +5,7 @@ Content : Win32 implementation of Platform app infrastructure Created : May 6, 2013 Authors : Lee Cooper -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2012 Oculus VR, LLC All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,9 +23,17 @@ limitations under the License. #include "Win32_Gamepad.h" + +OVR_DISABLE_MSVC_WARNING(28159) // C28159: GetTickCount: consider using another function instead. + + namespace OVR { namespace OvrPlatform { namespace Win32 { -GamepadManager::GamepadManager() +GamepadManager::GamepadManager() : + //hXInputModule(NULL), + pXInputGetState(NULL), + LastPadPacketNo(0xffffffff), + NextTryTime(0) { hXInputModule = ::LoadLibraryA("Xinput9_1_0.dll"); if (hXInputModule) @@ -73,29 +81,45 @@ bool GamepadManager::GetGamepadState(uint32_t index, GamepadState* pState) if (pXInputGetState) { - XINPUT_STATE xis; - - if (pXInputGetState(0, &xis)) - return false; - - if (xis.dwPacketNumber == LastPadPacketNo) - return false; - - // State changed. - pState->Buttons = xis.Gamepad.wButtons; // Currently matches Xinput - pState->LT = GamepadTrigger(xis.Gamepad.bLeftTrigger); - pState->RT = GamepadTrigger(xis.Gamepad.bRightTrigger); - pState->LX = GamepadStick(xis.Gamepad.sThumbLX); - pState->LY = GamepadStick(xis.Gamepad.sThumbLY); - pState->RX = GamepadStick(xis.Gamepad.sThumbRX); - pState->RY = GamepadStick(xis.Gamepad.sThumbRY); - - LastPadPacketNo = xis.dwPacketNumber; - - return true; + if((NextTryTime == 0) || (GetTickCount() >= NextTryTime)) // If the device is known to be present or if it's time to try testing for it again... + { + XINPUT_STATE xis; + DWORD dwResult = pXInputGetState(0, &xis); // This function is expensive, including if there is no connected device. + + if(dwResult == ERROR_SUCCESS) + { + if (xis.dwPacketNumber != LastPadPacketNo) + { + // State changed. + pState->Buttons = xis.Gamepad.wButtons; // Currently matches Xinput + pState->LT = GamepadTrigger(xis.Gamepad.bLeftTrigger); + pState->RT = GamepadTrigger(xis.Gamepad.bRightTrigger); + pState->LX = GamepadStick(xis.Gamepad.sThumbLX); + pState->LY = GamepadStick(xis.Gamepad.sThumbLY); + pState->RX = GamepadStick(xis.Gamepad.sThumbRX); + pState->RY = GamepadStick(xis.Gamepad.sThumbRY); + + LastPadPacketNo = xis.dwPacketNumber; + NextTryTime = 0; + + return true; + } + } + else if(dwResult == ERROR_DEVICE_NOT_CONNECTED) + { + // Don't bother wasting time on XInputGetState if one isn't connected, as it's very slow when one isn't connected. + // GetTickCount64 is available with Windows Vista+ and doesn't wrap around. + // GetTickCount wraps around every 49.7 days since the system started, but we don't need absolute time and it's OK + // if we have a false positive which would occur if NextTryTime is set to a value that has wrapped around to zero. + NextTryTime = GetTickCount() + 5000; + } + } } return false; } }}} // OVR::OvrPlatform::Win32 + +OVR_RESTORE_MSVC_WARNING() + diff --git a/Samples/CommonSrc/Platform/Win32_Gamepad.h b/Samples/CommonSrc/Platform/Win32_Gamepad.h index 6c80350..fc91413 100644 --- a/Samples/CommonSrc/Platform/Win32_Gamepad.h +++ b/Samples/CommonSrc/Platform/Win32_Gamepad.h @@ -5,7 +5,7 @@ Content : Win32 implementation of Gamepad functionality. Created : May 6, 2013 Authors : Lee Cooper -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2012 Oculus VR, LLC All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -49,7 +49,8 @@ private: typedef DWORD (WINAPI *PFn_XInputGetState)(DWORD dwUserIndex, XINPUT_STATE* pState); PFn_XInputGetState pXInputGetState; - uint32_t LastPadPacketNo; + uint32_t LastPadPacketNo; // Used to prevent reading the same packet twice. + uint32_t NextTryTime; // If no device was found then we don't try to access it again until some later time. }; }}} diff --git a/Samples/CommonSrc/Platform/Win32_Platform.cpp b/Samples/CommonSrc/Platform/Win32_Platform.cpp index a3e491d..6efd6aa 100644 --- a/Samples/CommonSrc/Platform/Win32_Platform.cpp +++ b/Samples/CommonSrc/Platform/Win32_Platform.cpp @@ -5,7 +5,7 @@ Content : Win32 implementation of Platform app infrastructure Created : September 6, 2012 Authors : Andrew Reisse -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2012 Oculus VR, LLC All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -39,9 +39,11 @@ namespace OVR { namespace OvrPlatform { namespace Win32 { PlatformCore::PlatformCore(Application* app, HINSTANCE hinst) - : OvrPlatform::PlatformCore(app), hWnd(NULL), hInstance(hinst), Quit(0), MMode(Mouse_Normal), - Cursor(0), Modifiers(0), WindowTitle("App") + : OvrPlatform::PlatformCore(app), hWnd(NULL), hInstance(hinst), Quit(false), ExitCode(0), Width(0), Height(0), MMode(Mouse_Normal), + /*WindowCenter,*/ Cursor(NULL), Modifiers(0), WindowTitle("App") { + WindowCenter.x = 0; + WindowCenter.y = 0; pGamepadManager = *new Win32::GamepadManager(); } @@ -49,17 +51,24 @@ PlatformCore::~PlatformCore() { } +static LPCWSTR WindowClassName = L"OVRPlatAppWindow"; + void* PlatformCore::SetupWindow(int w, int h) { - WNDCLASS wc; + WNDCLASSW wc; memset(&wc, 0, sizeof(wc)); - wc.lpszClassName = L"OVRAppWindow"; + wc.lpszClassName = WindowClassName; wc.style = CS_OWNDC; wc.lpfnWndProc = systemWindowProc; wc.cbWndExtra = sizeof(PlatformCore*); wc.hbrBackground = (HBRUSH)::GetStockObject(BLACK_BRUSH); - RegisterClass(&wc); + RegisterClassW(&wc); + + Array buffer; + intptr_t textLength = UTF8Util::GetLength(WindowTitle); + buffer.Resize(textLength + 1); + UTF8Util::DecodeString(&buffer[0], WindowTitle); Width = w; Height = h; @@ -69,7 +78,7 @@ void* PlatformCore::SetupWindow(int w, int h) winSize.bottom = Height; AdjustWindowRect(&winSize, WS_OVERLAPPEDWINDOW, false); // WS_CLIPCHILDREN is needed to support NotificationOverlay. - hWnd = CreateWindowA("OVRAppWindow", WindowTitle.ToCStr(), WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, + hWnd = CreateWindowW(WindowClassName, &buffer[0], WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, // 1950, 10, winSize.right-winSize.left, winSize.bottom-winSize.top, @@ -103,7 +112,7 @@ void PlatformCore::DestroyWindow() // Release window resources. ::DestroyWindow(hWnd); - UnregisterClass(L"OVRAppWindow", hInstance); + UnregisterClassW(WindowClassName, hInstance); hWnd = 0; Width = Height = 0; @@ -477,7 +486,7 @@ struct MonitorSet BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData) { MonitorSet* monitorSet = (MonitorSet*)dwData; - if (monitorSet->MonitorCount > MonitorSet::MaxMonitors) + if (monitorSet->MonitorCount >= MonitorSet::MaxMonitors) return FALSE; monitorSet->Monitors[monitorSet->MonitorCount] = hMonitor; @@ -594,19 +603,19 @@ NotificationOverlay::NotificationOverlay(PlatformCore* core, int fontHeightPixel // Create a static, centered TextField of specified font size. - hFont= CreateFont(fontHeightPixels, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, + hFont= CreateFontA(fontHeightPixels, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Arial"); + DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"); HDC dc = ::CreateCompatibleDC(0); ::SelectObject(dc, hFont); TextSize.cx = TextSize.cy = 0; - ::GetTextExtentPoint32(dc, &buffer[0], (int)textLength, &TextSize); + ::GetTextExtentPoint32W(dc, &buffer[0], (int)textLength, &TextSize); ::DeleteDC(dc); int vpos = (YOffest > 0) ? YOffest : (pCore->Height + YOffest - (TextSize.cy + 7)); - hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("STATIC"), + hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"STATIC", &buffer[0], WS_CHILD|WS_VISIBLE|SS_CENTER|WS_CLIPSIBLINGS, (core->Width-TextSize.cx+20)/2, vpos, TextSize.cx+20, TextSize.cy + 7, diff --git a/Samples/CommonSrc/Platform/Win32_Platform.h b/Samples/CommonSrc/Platform/Win32_Platform.h index b21bd0d..03d8e4a 100644 --- a/Samples/CommonSrc/Platform/Win32_Platform.h +++ b/Samples/CommonSrc/Platform/Win32_Platform.h @@ -5,7 +5,7 @@ Content : Win32 implementation of Platform app infrastructure Created : September 6, 2012 Authors : Andrew Reisse -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2012 Oculus VR, LLC All Rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. -- cgit v1.2.3