diff options
Diffstat (limited to 'Samples/CommonSrc')
34 files changed, 4024 insertions, 907 deletions
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 <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <glob.h> +#include <linux/joystick.h> +#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 <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xmd.h> +#include <signal.h> + +//#include <CAPI/GL/CAPI_GLE.h> +#include <GL/glx.h> // 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 <X11/extensions/Xrandr.h> + + +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<char**>(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 <GL/glx.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +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<wchar_t> 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. diff --git a/Samples/CommonSrc/Render/Render_D3D10_Device.cpp b/Samples/CommonSrc/Render/Render_D3D10_Device.cpp index b5c0ca6..7bcac94 100644 --- a/Samples/CommonSrc/Render/Render_D3D10_Device.cpp +++ b/Samples/CommonSrc/Render/Render_D3D10_Device.cpp @@ -5,7 +5,7 @@ Content : Builds D3D10 renderer versions (to avoid duplication). Created : September 10, 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/Render/Render_D3D10_Device.h b/Samples/CommonSrc/Render/Render_D3D10_Device.h index ec06e51..fe74ed6 100644 --- a/Samples/CommonSrc/Render/Render_D3D10_Device.h +++ b/Samples/CommonSrc/Render/Render_D3D10_Device.h @@ -5,7 +5,7 @@ Content : Builds D3D10 renderer versions (to avoid duplication). Created : September 10, 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/Render/Render_D3D11_Device.cpp b/Samples/CommonSrc/Render/Render_D3D11_Device.cpp index 6ec7ed4..f25884f 100644 --- a/Samples/CommonSrc/Render/Render_D3D11_Device.cpp +++ b/Samples/CommonSrc/Render/Render_D3D11_Device.cpp @@ -5,7 +5,7 @@ Content : Builds D3D11 renderer versions (to avoid duplication). Created : September 10, 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/Render/Render_D3D11_Device.h b/Samples/CommonSrc/Render/Render_D3D11_Device.h index a243b16..89be286 100644 --- a/Samples/CommonSrc/Render/Render_D3D11_Device.h +++ b/Samples/CommonSrc/Render/Render_D3D11_Device.h @@ -5,7 +5,7 @@ Content : Builds D3D11 renderer versions (to avoid duplication). Created : September 10, 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/Render/Render_D3D1X_Device.cpp b/Samples/CommonSrc/Render/Render_D3D1X_Device.cpp index a904ee5..c40edf2 100644 --- a/Samples/CommonSrc/Render/Render_D3D1X_Device.cpp +++ b/Samples/CommonSrc/Render/Render_D3D1X_Device.cpp @@ -5,7 +5,7 @@ Content : RenderDevice implementation for D3DX10/11. Created : September 10, 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. @@ -31,6 +31,7 @@ limitations under the License. #include "Render_D3D1X_Device.h" #include "Util/Util_ImageWindow.h" +#include "Kernel/OVR_Log.h" #include "OVR_CAPI_D3D.h" @@ -711,6 +712,7 @@ static void ReportCOMError(HRESULT hr, const char* file, int line) } else { +#ifdef _UNICODE size_t len = wcslen(errMsg); char* data = new char[len + 1]; size_t count = len; @@ -720,8 +722,13 @@ static void ReportCOMError(HRESULT hr, const char* file, int line) len = count; } data[len] = '\0'; +#else + const char* data = errMsg; +#endif LogError("{ERR-018w} [D3D] Error in %s on line %d : %s", file, line, data); +#ifdef _UNICODE delete[] data; +#endif } OVR_ASSERT(false); @@ -737,15 +744,55 @@ static void ReportCOMError(HRESULT hr, const char* file, int line) #endif -RenderDevice::RenderDevice(const RendererParams& p, HWND window) -{ + +RenderDevice::RenderDevice(const RendererParams& p, HWND window) : + DXGIFactory(), + Window(window), + Device(), + Context(), + SwapChain(), + Adapter(), + FullscreenOutput(), + FSDesktopX(-1), + FSDesktopY(-1), + PreFullscreenX(0), + PreFullscreenY(0), + PreFullscreenW(0), + PreFullscreenH(0), + BackBuffer(), + BackBufferRT(), + CurRenderTarget(), + CurDepthBuffer(), + Rasterizer(), + BlendState(), + //DepthStates[] + CurDepthState(), + ModelVertexIL(), + DistortionVertexIL(), + HeightmapVertexIL(), + //SamplerStates[] + StdUniforms(), + //UniformBuffers[]; + //MaxTextureSet[]; + //VertexShaders[]; + //PixelShaders[]; + //pStereoShaders[]; + //CommonUniforms[]; + ExtraShaders(), + DefaultFill(), + QuadVertexBuffer(), + DepthBuffers() +{ + memset(&D3DViewport, 0, sizeof(D3DViewport)); + memset(MaxTextureSet, 0, sizeof(MaxTextureSet)); + HRESULT hr; RECT rc; if (p.Resolution == Sizei(0)) { GetClientRect(window, &rc); - UINT width = rc.right - rc.left; + UINT width = rc.right - rc.left; UINT height = rc.bottom - rc.top; ::OVR::Render::RenderDevice::SetWindowSize(width, height); } @@ -755,8 +802,6 @@ RenderDevice::RenderDevice(const RendererParams& p, HWND window) ::OVR::Render::RenderDevice::SetWindowSize(p.Resolution.w, p.Resolution.h); } - Window = window; - Params = p; DXGIFactory = NULL; hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&DXGIFactory.GetRawRef())); @@ -820,7 +865,7 @@ RenderDevice::RenderDevice(const RendererParams& p, HWND window) Context = NULL; D3D_FEATURE_LEVEL featureLevel; // TODO: Limit certain features based on D3D feature level hr = D3D11CreateDevice(Adapter, Adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, - NULL, flags, NULL, 0, D3D1x_(SDK_VERSION), + NULL, flags /*| D3D11_CREATE_DEVICE_DEBUG*/, NULL, 0, D3D1x_(SDK_VERSION), &Device.GetRawRef(), &featureLevel, &Context.GetRawRef()); #endif if (FAILED(hr)) @@ -1126,7 +1171,7 @@ bool RenderDevice::RecreateSwapChain() scDesc.BufferCount = 1; scDesc.BufferDesc.Width = WindowWidth; scDesc.BufferDesc.Height = WindowHeight; - scDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + scDesc.BufferDesc.Format = Params.SrgbBackBuffer ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM; // Use default refresh rate; switching rate on CC prototype can cause screen lockup. scDesc.BufferDesc.RefreshRate.Numerator = 0; scDesc.BufferDesc.RefreshRate.Denominator = 1; @@ -1526,7 +1571,7 @@ void* Buffer::Map(size_t start, size_t size, int flags) #endif } -bool Buffer::Unmap(void *m) +bool Buffer::Unmap(void* m) { OVR_UNUSED(m); @@ -1661,27 +1706,35 @@ ID3D10Blob* RenderDevice::CompileShader(const char* profile, const char* src, co } -ShaderBase::ShaderBase(RenderDevice* r, ShaderStage stage) - : Render::Shader(stage), Ren(r), UniformData(0) +ShaderBase::ShaderBase(RenderDevice* r, ShaderStage stage) : + Render::Shader(stage), + Ren(r), + UniformData(NULL), + UniformsSize(-1) { } + ShaderBase::~ShaderBase() { if (UniformData) { OVR_FREE(UniformData); + UniformData = NULL; } } bool ShaderBase::SetUniform(const char* name, int n, const float* v) { - for(unsigned i = 0; i < UniformInfo.GetSize(); i++) - if (!strcmp(UniformInfo[i].Name.ToCStr(), name)) + for (int i = 0; i < UniformInfo.GetSizeI(); i++) + { + if (UniformInfo[i].Name == name) { memcpy(UniformData + UniformInfo[i].Offset, v, n * sizeof(float)); - return 1; + return true; } - return 0; + } + + return false; } void ShaderBase::InitUniforms(ID3D10Blob* s) @@ -1887,9 +1940,19 @@ ID3D1xSamplerState* RenderDevice::GetSamplerState(int sm) return SamplerStates[sm]; } -Texture::Texture(RenderDevice* ren, int fmt, int w, int h) : Ren(ren), Tex(NULL), TexSv(NULL), TexRtv(NULL), TexDsv(NULL), Width(w), Height(h) +Texture::Texture(RenderDevice* ren, int fmt, int w, int h) : + Ren(ren), + Tex(NULL), + TexSv(NULL), + TexRtv(NULL), + TexDsv(NULL), + TexStaging(NULL), + Sampler(NULL), + Format(fmt), + Width(w), + Height(h), + Samples(0) { - OVR_UNUSED(fmt); Sampler = Ren->GetSamplerState(0); } @@ -1956,21 +2019,23 @@ void RenderDevice::GenerateSubresourceData( unsigned subresHeight = imageHeight; unsigned numMips = effectiveMipCount; + unsigned bytesPerBlock = 0; + switch(format) + { + case DXGI_FORMAT_BC1_UNORM_SRGB: // fall thru + case DXGI_FORMAT_BC1_UNORM: bytesPerBlock = 8; break; + + case DXGI_FORMAT_BC2_UNORM_SRGB: // fall thru + case DXGI_FORMAT_BC2_UNORM: bytesPerBlock = 16; break; + + case DXGI_FORMAT_BC3_UNORM_SRGB: // fall thru + case DXGI_FORMAT_BC3_UNORM: bytesPerBlock = 16; break; + + default: OVR_ASSERT(false); + } + for(unsigned i = 0; i < numMips; i++) { - unsigned bytesPerBlock = 0; - if (format == DXGI_FORMAT_BC1_UNORM) - { - bytesPerBlock = 8; - } - else if (format == DXGI_FORMAT_BC2_UNORM) - { - bytesPerBlock = 16; - } - else if (format == DXGI_FORMAT_BC3_UNORM) - { - bytesPerBlock = 16; - } unsigned blockWidth = 0; blockWidth = (subresWidth + 3) / 4; @@ -2067,21 +2132,28 @@ Texture* RenderDevice::CreateTexture(int format, int width, int height, const vo imageDimUpperLimit = 1024; } - if (format == Texture_DXT1 || format == Texture_DXT3 || format == Texture_DXT5) + if ((format & Texture_TypeMask) == Texture_DXT1 || + (format & Texture_TypeMask) == Texture_DXT3 || + (format & Texture_TypeMask) == Texture_DXT5) { int convertedFormat; - switch (format) { - case Texture_DXT1: - convertedFormat = DXGI_FORMAT_BC1_UNORM; - break; - case Texture_DXT3: - convertedFormat = DXGI_FORMAT_BC2_UNORM; - break; - case Texture_DXT5: - default: - convertedFormat = DXGI_FORMAT_BC3_UNORM; - break; - } + if((format & Texture_TypeMask) == Texture_DXT1) + { + convertedFormat = (format & Texture_SRGB) ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM; + } + else if((format & Texture_TypeMask) == Texture_DXT3) + { + convertedFormat = (format & Texture_SRGB) ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM; + } + else if((format & Texture_TypeMask) == Texture_DXT5) + { + convertedFormat = (format & Texture_SRGB) ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM; + } + else + { + OVR_ASSERT(false); return NULL; + } + unsigned largestMipWidth = 0; unsigned largestMipHeight = 0; unsigned effectiveMipCount = mipcount; @@ -2181,6 +2253,7 @@ Texture* RenderDevice::CreateTexture(int format, int width, int height, const vo d3dformat = createDepthSrv ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_D32_FLOAT; break; default: + OVR_ASSERT(false); return NULL; } @@ -2320,6 +2393,13 @@ Texture* RenderDevice::CreateTexture(int format, int width, int height, const vo // Rendering +void RenderDevice::ResolveMsaa(OVR::Render::Texture* msaaTex, OVR::Render::Texture* outputTex) +{ + int isSrgb = ((Texture*)msaaTex)->Format & Texture_SRGB; + + Context->ResolveSubresource(((Texture*)outputTex)->Tex, 0, ((Texture*)msaaTex)->Tex, 0, isSrgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM); +} + void RenderDevice::BeginRendering() { Context->RSSetState(Rasterizer); diff --git a/Samples/CommonSrc/Render/Render_D3D1X_Device.h b/Samples/CommonSrc/Render/Render_D3D1X_Device.h index cac104e..63e8e67 100644 --- a/Samples/CommonSrc/Render/Render_D3D1X_Device.h +++ b/Samples/CommonSrc/Render/Render_D3D1X_Device.h @@ -5,7 +5,7 @@ Content : RenderDevice implementation header for D3DX10/11. Created : September 10, 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. @@ -117,6 +117,7 @@ typedef D3D11_QUERY_DESC D3D1x_QUERY_DESC; class Buffer; + class ShaderBase : public Render::Shader { public: @@ -127,7 +128,8 @@ public: struct Uniform { String Name; - int Offset, Size; + int Offset; + int Size; }; Array<Uniform> UniformInfo; @@ -141,6 +143,7 @@ public: void UpdateBuffer(Buffer* b); }; + template<Render::ShaderStage SStage, class D3DShaderType> class Shader : public ShaderBase { @@ -186,7 +189,13 @@ public: bool Dynamic; public: - Buffer(RenderDevice* r) : Ren(r), Size(0), Use(0) {} + Buffer(RenderDevice* r) : + Ren(r), + Size(0), + Use(0), + Dynamic(false) + { + } ~Buffer(); ID3D1xBuffer* GetBuffer() @@ -199,10 +208,11 @@ public: return Size; } virtual void* Map(size_t start, size_t size, int flags = 0); - virtual bool Unmap(void *m); + virtual bool Unmap(void* m); virtual bool Data(int use, const void* buffer, size_t size); }; + class Texture : public Render::Texture { public: @@ -215,6 +225,7 @@ public: mutable Ptr<ID3D1xSamplerState> Sampler; int Width, Height; int Samples; + int Format; Texture(RenderDevice* r, int fmt, int w, int h); ~Texture(); @@ -239,9 +250,9 @@ public: virtual ovrTexture Get_ovrTexture(); virtual void* GetInternalImplementation(); - }; + class RenderDevice : public Render::RenderDevice { public: @@ -302,7 +313,7 @@ public: // to get the latest info about monitors (including just connected/ // disconnected ones). Note, SwapChain will be released in this case // and it should be recreated. - void UpdateMonitorOutputs(bool needRecreate = false); + void UpdateMonitorOutputs(bool needRecreate = false); virtual void SetViewport(const Recti& vp); virtual void SetWindowSize(int w, int h); @@ -337,6 +348,8 @@ public: Texture* GetDepthBuffer(int w, int h, int ms); + virtual void ResolveMsaa(OVR::Render::Texture* msaaTex, OVR::Render::Texture* outputTex) OVR_OVERRIDE; + virtual void BeginRendering(); virtual void SetRenderTarget(Render::Texture* color, Render::Texture* depth = NULL, Render::Texture* stencil = NULL); @@ -348,7 +361,7 @@ public: ExtraShaders = s; } - // Overrident to apply proper blend state. + // Overridden to apply proper blend state. virtual void FillRect(float left, float top, float right, float bottom, Color c, const Matrix4f* view=NULL); virtual void FillGradientRect(float left, float top, float right, float bottom, Color col_top, Color col_btm, const Matrix4f* view); virtual void RenderText(const struct Font* font, const char* str, float x, float y, float size, Color c, const Matrix4f* view=NULL); @@ -377,6 +390,7 @@ public: virtual void EndGpuEvent(); }; -}}} + +}}} // namespace OVR::Render::D3D1? #endif diff --git a/Samples/CommonSrc/Render/Render_Device.cpp b/Samples/CommonSrc/Render/Render_Device.cpp index 94ff680..7b95713 100644 --- a/Samples/CommonSrc/Render/Render_Device.cpp +++ b/Samples/CommonSrc/Render/Render_Device.cpp @@ -5,7 +5,7 @@ Content : Platform renderer for simple scene graph - implementation 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. @@ -1033,7 +1033,7 @@ namespace OVR { namespace Render { pCurVert->TexG = pCurRawVert->TanEyeAnglesG; pCurVert->TexB = pCurRawVert->TanEyeAnglesB; // Convert [0.0f,1.0f] to [0,255] - pCurVert->Col.R = (uint8_t)( floorf ( pCurRawVert->Shade * 255.999f ) ); + pCurVert->Col.R = (uint8_t)( floorf ( Alg::Max ( pCurRawVert->Shade, 0.0f ) * 255.999f ) ); pCurVert->Col.G = pCurVert->Col.R; pCurVert->Col.B = pCurVert->Col.R; pCurVert->Col.A = (uint8_t)( floorf ( pCurRawVert->TimewarpLerp * 255.999f ) ); @@ -1171,8 +1171,8 @@ namespace OVR { namespace Render { Matrix4f const &matRenderFromWorld = ( eyeNum == 0 ) ? matRenderFromWorldLeft : matRenderFromWorldRight; const StereoEyeParams &stereoParams = ( eyeNum == 0 ) ? stereoParamsLeft : stereoParamsRight; - Matrix4f matRenderFromNowStart = TimewarpComputePoseDelta ( matRenderFromWorld, matNowFromWorldStart, stereoParams.ViewAdjust ); - Matrix4f matRenderFromNowEnd = TimewarpComputePoseDelta ( matRenderFromWorld, matNowFromWorldEnd, stereoParams.ViewAdjust ); + Matrix4f matRenderFromNowStart = TimewarpComputePoseDelta ( matRenderFromWorld, matNowFromWorldStart, stereoParams.HmdToEyeViewOffset ); + Matrix4f matRenderFromNowEnd = TimewarpComputePoseDelta ( matRenderFromWorld, matNowFromWorldEnd, stereoParams.HmdToEyeViewOffset ); pPostProcessShader->SetUniform2f("EyeToSourceUVScale", stereoParams.EyeToSourceUV.Scale.x, stereoParams.EyeToSourceUV.Scale.y ); pPostProcessShader->SetUniform2f("EyeToSourceUVOffset", stereoParams.EyeToSourceUV.Offset.x, stereoParams.EyeToSourceUV.Offset.y ); @@ -1209,8 +1209,8 @@ namespace OVR { namespace Render { Matrix4f const &matRenderFromWorld = ( eyeNum == 0 ) ? matRenderFromWorldLeft : matRenderFromWorldRight; const StereoEyeParams &stereoParams = ( eyeNum == 0 ) ? stereoParamsLeft : stereoParamsRight; - Matrix4f matRenderFromNowStart = TimewarpComputePoseDelta ( matRenderFromWorld, matNowFromWorldStart, stereoParams.ViewAdjust ); - Matrix4f matRenderFromNowEnd = TimewarpComputePoseDelta ( matRenderFromWorld, matNowFromWorldEnd, stereoParams.ViewAdjust ); + Matrix4f matRenderFromNowStart = TimewarpComputePoseDelta ( matRenderFromWorld, matNowFromWorldStart, stereoParams.HmdToEyeViewOffset ); + Matrix4f matRenderFromNowEnd = TimewarpComputePoseDelta ( matRenderFromWorld, matNowFromWorldEnd, stereoParams.HmdToEyeViewOffset ); pPostProcessShader->SetUniform2f("EyeToSourceUVScale", stereoParams.EyeToSourceUV.Scale.x, stereoParams.EyeToSourceUV.Scale.y ); pPostProcessShader->SetUniform2f("EyeToSourceUVOffset", stereoParams.EyeToSourceUV.Offset.x, stereoParams.EyeToSourceUV.Offset.y ); @@ -1313,8 +1313,8 @@ namespace OVR { namespace Render { Matrix4f const &matRenderFromWorld = ( eyeNum == 0 ) ? matRenderFromWorldLeft : matRenderFromWorldRight; - Matrix4f matRenderFromNowStart = TimewarpComputePoseDeltaPosition ( matRenderFromWorld, matNowFromWorldStart, stereoParams.ViewAdjust ); - Matrix4f matRenderFromNowEnd = TimewarpComputePoseDeltaPosition ( matRenderFromWorld, matNowFromWorldEnd, stereoParams.ViewAdjust ); + Matrix4f matRenderFromNowStart = TimewarpComputePoseDeltaPosition ( matRenderFromWorld, matNowFromWorldStart, stereoParams.HmdToEyeViewOffset ); + Matrix4f matRenderFromNowEnd = TimewarpComputePoseDeltaPosition ( matRenderFromWorld, matNowFromWorldEnd, stereoParams.HmdToEyeViewOffset ); pPostProcessHeightmapShader->SetUniform2f("EyeToSourceUVScale", stereoParams.EyeToSourceUV.Scale.x, stereoParams.EyeToSourceUV.Scale.y ); pPostProcessHeightmapShader->SetUniform2f("EyeToSourceUVOffset", stereoParams.EyeToSourceUV.Offset.x, stereoParams.EyeToSourceUV.Offset.y ); diff --git a/Samples/CommonSrc/Render/Render_Device.h b/Samples/CommonSrc/Render/Render_Device.h index 1da49fe..5e9d270 100644 --- a/Samples/CommonSrc/Render/Render_Device.h +++ b/Samples/CommonSrc/Render/Render_Device.h @@ -5,7 +5,7 @@ Content : Platform renderer for simple scene graph 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. @@ -517,7 +517,7 @@ public: Ptr<Buffer> VertexBuffer; Ptr<Buffer> IndexBuffer; - Model(PrimitiveType t = Prim_Triangles) : Type(t), Fill(NULL), Visible(true) { } + Model(PrimitiveType t = Prim_Triangles) : Type(t), Fill(NULL), Visible(true), IsCollisionModel(false) { } ~Model() { } virtual NodeType GetType() const { return Node_Model; } @@ -753,13 +753,14 @@ struct DisplayId struct RendererParams { int Multisample; + bool SrgbBackBuffer; int Fullscreen; DisplayId Display; // Resolution of the rendering buffer used during creation. // Allows buffer of different size then the widow if not zero. Sizei Resolution; - RendererParams(int ms = 1) : Multisample(ms), Fullscreen(0), Resolution(0) {} + RendererParams(int ms = 1) : Multisample(ms), SrgbBackBuffer(false), Fullscreen(0), Resolution(0) {} bool IsDisplaySet() const { @@ -913,6 +914,9 @@ public: // Finish scene. virtual void FinishScene(); + virtual void ResolveMsaa(Texture* msaaTex, Texture* outputTex) + { OVR_UNUSED2(msaaTex, outputTex); }; + // Texture must have been created with Texture_RenderTarget. Use NULL for the default render target. // NULL depth buffer means use an internal, temporary one. virtual void SetRenderTarget(Texture* color, Texture* depth = NULL, Texture* stencil = NULL) @@ -946,7 +950,7 @@ public: // Returns width of text in same units as drawing. If strsize is not null, stores width and height. // Can optionally return char-range selection rectangle. - float MeasureText(const Font* font, const char* str, float size, float strsize[2] = NULL, + static float MeasureText(const Font* font, const char* str, float size, float strsize[2] = NULL, const size_t charRange[2] = 0, Vector2f charRangeRect[2] = 0); virtual void RenderText(const Font* font, const char* str, float x, float y, float size, Color c, const Matrix4f* view = NULL); diff --git a/Samples/CommonSrc/Render/Render_Font.h b/Samples/CommonSrc/Render/Render_Font.h index 3201b68..2e44e5d 100644 --- a/Samples/CommonSrc/Render/Render_Font.h +++ b/Samples/CommonSrc/Render/Render_Font.h @@ -5,7 +5,7 @@ Content : Font data structure used by renderer Created : September, 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/Render/Render_GL_Device.cpp b/Samples/CommonSrc/Render/Render_GL_Device.cpp index 54a2b9b..64da492 100644 --- a/Samples/CommonSrc/Render/Render_GL_Device.cpp +++ b/Samples/CommonSrc/Render/Render_GL_Device.cpp @@ -5,7 +5,7 @@ Content : RenderDevice implementation for OpenGL Created : September 10, 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. @@ -54,6 +54,7 @@ void (*GetFunction(const char *functionName))( void ) #endif +PFNGLGETSTRINGIPROC glGetStringi; PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; PFNGLDELETESHADERPROC glDeleteShader; @@ -95,6 +96,7 @@ PFNGLUNIFORM3FVPROC glUniform3fv; PFNGLUNIFORM2FVPROC glUniform2fv; PFNGLUNIFORM1FVPROC glUniform1fv; PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample; PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; @@ -102,6 +104,7 @@ PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebuffer; void InitGLExtensions() { @@ -115,6 +118,7 @@ void InitGLExtensions() glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) GetFunction("glXSwapIntervalEXT"); #endif + glGetStringi = (PFNGLGETSTRINGIPROC) GetFunction("glGetStringi"); glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) GetFunction("glGenFramebuffersEXT"); glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) GetFunction("glDeleteFramebuffersEXT"); glDeleteShader = (PFNGLDELETESHADERPROC) GetFunction("glDeleteShader"); @@ -156,6 +160,7 @@ void InitGLExtensions() glUniform2fv = (PFNGLUNIFORM2FVPROC) GetFunction("glUniform2fv"); glUniform1fv = (PFNGLUNIFORM1FVPROC) GetFunction("glUniform1fv"); glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) GetFunction("glCompressedTexImage2D"); + glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) GetFunction("glTexImage2DMultisample"); glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) GetFunction("glRenderbufferStorageEXT"); glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) GetFunction("glBindRenderbufferEXT"); glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) GetFunction("glGenRenderbuffersEXT"); @@ -163,13 +168,14 @@ void InitGLExtensions() glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) GetFunction("glGenVertexArrays"); glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) GetFunction("glDeleteVertexArrays"); glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) GetFunction("glBindVertexArray"); + glBlitFramebuffer = (PFNGLBLITFRAMEBUFFEREXTPROC) GetFunction("glBlitFramebufferEXT"); } #endif static const char* StdVertexShaderSrc = - "#version 110\n" - +"#version 110\n" + "uniform mat4 Proj;\n" "uniform mat4 View;\n" @@ -252,28 +258,28 @@ static const char* TextureFragShaderSrc = " discard;\n" "}\n"; -#define LIGHTING_COMMON \ +#define LIGHTING_COMMON \ "#version 110\n" \ - "uniform vec3 Ambient;\n" \ - "uniform vec4 LightPos[8];\n" \ - "uniform vec4 LightColor[8];\n" \ - "uniform float LightCount;\n" \ + "uniform vec3 Ambient;\n" \ + "uniform vec4 LightPos[8];\n" \ + "uniform vec4 LightColor[8];\n" \ + "uniform float LightCount;\n" \ "varying vec4 oColor;\n" \ "varying vec2 oTexCoord;\n" \ "varying vec3 oNormal;\n" \ "varying vec3 oVPos;\n" \ - "vec4 DoLight()\n" \ - "{\n" \ - " vec3 norm = normalize(oNormal);\n" \ - " vec3 light = Ambient;\n" \ - " for (int i = 0; i < int(LightCount); i++)\n" \ - " {\n" \ - " vec3 ltp = (LightPos[i].xyz - oVPos);\n" \ - " float ldist = length(ltp);\n" \ - " ltp = normalize(ltp);\n" \ + "vec4 DoLight()\n" \ + "{\n" \ + " vec3 norm = normalize(oNormal);\n" \ + " vec3 light = Ambient;\n" \ + " for (int i = 0; i < int(LightCount); i++)\n" \ + " {\n" \ + " vec3 ltp = (LightPos[i].xyz - oVPos);\n" \ + " float ldist = length(ltp);\n" \ + " ltp = normalize(ltp);\n" \ " light += clamp(LightColor[i].rgb * oColor.rgb * (dot(norm, ltp) / ldist), 0.0,1.0);\n" \ - " }\n" \ - " return vec4(light, oColor.a);\n" \ + " }\n" \ + " return vec4(light, oColor.a);\n" \ "}\n" static const char* LitSolidFragShaderSrc = @@ -308,21 +314,21 @@ static const char* AlphaTextureFragShaderSrc = "}\n"; static const char* AlphaBlendedTextureFragShaderSrc = - "#version 110\n" - - "uniform sampler2D Texture0;\n" + "#version 110\n" - "varying vec4 oColor;\n" - "varying vec2 oTexCoord;\n" + "uniform sampler2D Texture0;\n" - "void main()\n" - "{\n" + "varying vec4 oColor;\n" + "varying vec2 oTexCoord;\n" + + "void main()\n" + "{\n" " vec4 finalColor = oColor;\n" " finalColor *= texture2D(Texture0, oTexCoord);\n" // Blend state expects premultiplied alpha " finalColor.rgb *= finalColor.a;\n" - " gl_FragColor = finalColor;\n" - "}\n"; + " gl_FragColor = finalColor;\n" + "}\n"; static const char* MultiTextureFragShaderSrc = "#version 110\n" @@ -336,15 +342,15 @@ static const char* MultiTextureFragShaderSrc = "void main()\n" "{\n" - " vec4 color = texture2D(Texture0, oTexCoord);\n" + " vec4 color = texture2D(Texture0, oTexCoord);\n" - " gl_FragColor = texture2D(Texture1, oTexCoord1);\n" - " gl_FragColor.rgb = gl_FragColor.rgb * mix(1.9, 1.2, clamp(length(gl_FragColor.rgb),0.0,1.0));\n" + " gl_FragColor = texture2D(Texture1, oTexCoord1);\n" + " gl_FragColor.rgb = gl_FragColor.rgb * mix(1.9, 1.2, clamp(length(gl_FragColor.rgb),0.0,1.0));\n" - " gl_FragColor = color * gl_FragColor;\n" + " gl_FragColor = color * gl_FragColor;\n" - " if (gl_FragColor.a <= 0.6)\n" - " discard;\n" + " if (gl_FragColor.a <= 0.6)\n" + " discard;\n" "}\n"; static const char* PostProcessMeshFragShaderSrc = @@ -455,12 +461,12 @@ static const char* PostProcessMeshTimewarpVertexShaderSrc = // Accurate time warp lerp vs. faster #if 0 // Apply the two 3x3 timewarp rotations to these vectors. - " vec3 TransformedRStart = (EyeRotationStart * vec4(TanEyeAngleR, 0)).xyz;\n" - " vec3 TransformedGStart = (EyeRotationStart * vec4(TanEyeAngleG, 0)).xyz;\n" - " vec3 TransformedBStart = (EyeRotationStart * vec4(TanEyeAngleB, 0)).xyz;\n" - " vec3 TransformedREnd = (EyeRotationEnd * vec4(TanEyeAngleR, 0)).xyz;\n" - " vec3 TransformedGEnd = (EyeRotationEnd * vec4(TanEyeAngleG, 0)).xyz;\n" - " vec3 TransformedBEnd = (EyeRotationEnd * vec4(TanEyeAngleB, 0)).xyz;\n" + " vec3 TransformedRStart = (EyeRotationStart * vec4(TanEyeAngleR, 0)).xyz;\n" + " vec3 TransformedGStart = (EyeRotationStart * vec4(TanEyeAngleG, 0)).xyz;\n" + " vec3 TransformedBStart = (EyeRotationStart * vec4(TanEyeAngleB, 0)).xyz;\n" + " vec3 TransformedREnd = (EyeRotationEnd * vec4(TanEyeAngleR, 0)).xyz;\n" + " vec3 TransformedGEnd = (EyeRotationEnd * vec4(TanEyeAngleG, 0)).xyz;\n" + " vec3 TransformedBEnd = (EyeRotationEnd * vec4(TanEyeAngleB, 0)).xyz;\n" // And blend between them. " vec3 TransformedR = mix ( TransformedRStart, TransformedREnd, Color.a );\n" " vec3 TransformedG = mix ( TransformedGStart, TransformedGEnd, Color.a );\n" @@ -526,7 +532,7 @@ PostProcessMeshTimewarpVertexShaderSrc; "{\n" " vec2 eyeToSourceTexCoord = inTexCoord * EyeToSourceUVScale + EyeToSourceUVOffset;\n" " eyeToSourceTexCoord.y = 1.0 - eyeToSourceTexCoord.y;\n" - " float depth = texelFetch(Texture0, ivec2(eyeToSourceTexCoord * DepthDimSize), 0).x;\n" //FIXME: Use Texture2DLod for #version 110 support. + " float depth = texelFetch(Texture0, ivec2(eyeToSourceTexCoord * DepthDimSize), 0).x;\n" //FIXME: Use Texture2DLod for #version 110 support. " float linearDepth = DepthProjector.y / (depth - DepthProjector.x);\n" " vec4 retVal = vec4(inTexCoord, 1, 1);\n" " retVal.xyz *= linearDepth;\n" @@ -616,7 +622,7 @@ PostProcessMeshTimewarpVertexShaderSrc; " lerpedEyeRot[1] = mix(EyeXformStart[1], EyeXformEnd[1], timewarpLerpFactor);\n" " lerpedEyeRot[2] = mix(EyeXformStart[2], EyeXformEnd[2], timewarpLerpFactor);\n" " lerpedEyeRot[3] = mix(EyeXformStart[3], EyeXformEnd[3], timewarpLerpFactor);\n" - //" float4x4 lerpedEyeRot = EyeXformStart;\n" + //" float4x4 lerpedEyeRot = EyeXformStart;\n" // warped positions are a bit more involved, hence a separate function " gl_Position = TimewarpPos(Position.xy, oTexCoord0, lerpedEyeRot);\n" @@ -641,8 +647,8 @@ static const char* PostProcessFragShaderWithChromAbSrc = "varying vec4 oPosition;\n" "varying vec2 oTexCoord;\n" - - "void main()\n" + + "void main()\n" "{\n" // Input oTexCoord is [-1,1] across the half of the screen used for a single eye. " vec2 TanEyeAngleDistorted = oTexCoord * TanEyeAngleScale + TanEyeAngleOffset;\n" // Scales to tan(thetaX),tan(thetaY), but still distorted (i.e. only the center is correct) @@ -661,15 +667,15 @@ static const char* PostProcessFragShaderWithChromAbSrc = // Scale them into ([0,0.5],[0,1]) or ([0.5,0],[0,1]) UV lookup space (depending on eye) " vec2 SourceCoordR = TanEyeAngleR * EyeToSourceUVScale + EyeToSourceUVOffset;\n" - " SourceCoordR.y = 1.0 - SourceCoordR.y;\n" + " SourceCoordR.y = 1.0 - SourceCoordR.y;\n" " vec2 SourceCoordG = TanEyeAngleG * EyeToSourceUVScale + EyeToSourceUVOffset;\n" - " SourceCoordG.y = 1.0 - SourceCoordG.y;\n" + " SourceCoordG.y = 1.0 - SourceCoordG.y;\n" " vec2 SourceCoordB = TanEyeAngleB * EyeToSourceUVScale + EyeToSourceUVOffset;\n" - " SourceCoordB.y = 1.0 - SourceCoordB.y;\n" + " SourceCoordB.y = 1.0 - SourceCoordB.y;\n" // Find the distance to the nearest edge. " vec2 NDCCoord = TanEyeAngleG * EyeToSourceNDCScale + EyeToSourceNDCOffset;\n" - " float EdgeFadeIn = clamp ( EdgeFadeScale, 0.0, 1e5 ) * ( 1.0 - max ( abs ( NDCCoord.x ), abs ( NDCCoord.y ) ) );\n" + " float EdgeFadeIn = clamp ( EdgeFadeScale, 0.0, 1e5 ) * ( 1.0 - max ( abs ( NDCCoord.x ), abs ( NDCCoord.y ) ) );\n" " if ( EdgeFadeIn < 0.0 )\n" " {\n" " gl_FragColor = vec4(DistortionClearColor.r, DistortionClearColor.g, DistortionClearColor.b, 1.0);\n" @@ -692,7 +698,7 @@ static const char* VShaderSrcs[VShader_Count] = DirectVertexShaderSrc, StdVertexShaderSrc, PostProcessVertexShaderSrc, - PostProcessMeshVertexShaderSrc, + PostProcessMeshVertexShaderSrc, PostProcessMeshTimewarpVertexShaderSrc, PostProcessMeshPositionalTimewarpVertexShaderSrc, PostProcessHeightmapTimewarpVertexShaderSrc, @@ -703,7 +709,7 @@ static const char* FShaderSrcs[FShader_Count] = GouraudFragShaderSrc, TextureFragShaderSrc, AlphaTextureFragShaderSrc, - AlphaBlendedTextureFragShaderSrc, + AlphaBlendedTextureFragShaderSrc, PostProcessFragShaderWithChromAbSrc, LitSolidFragShaderSrc, LitTextureFragShaderSrc, @@ -716,11 +722,25 @@ static const char* FShaderSrcs[FShader_Count] = RenderDevice::RenderDevice(const RendererParams&) + : VertexShaders(), + FragShaders(), + DefaultFill(), + Proj(), + Vao(0), + CurRenderTarget(), + DepthBuffers(), + CurrentFbo(0), + MsaaFbo(0), + GLVersionInfo(), + DebugCallbackControl(), + Lighting(NULL) { + DebugCallbackControl.Initialize(); + GetGLVersionAndExtensions(GLVersionInfo); OVR_ASSERT(GLVersionInfo.MajorVersion >= 2); - + for (int i = 0; i < VShader_Count; i++) { OVR_ASSERT ( VShaderSrcs[i] != NULL ); // You forgot a shader! @@ -732,13 +752,14 @@ RenderDevice::RenderDevice(const RendererParams&) OVR_ASSERT ( FShaderSrcs[i] != NULL ); // You forgot a shader! FragShaders[i] = *new Shader(this, Shader_Fragment, FShaderSrcs[i]); } - + Ptr<ShaderSet> gouraudShaders = *new ShaderSet(); gouraudShaders->SetShader(VertexShaders[VShader_MVP]); gouraudShaders->SetShader(FragShaders[FShader_Gouraud]); DefaultFill = *new ShaderFill(gouraudShaders); glGenFramebuffers(1, &CurrentFbo); + glGenFramebuffers(1, &MsaaFbo); if (GLVersionInfo.SupportsVAO) { @@ -758,7 +779,8 @@ void RenderDevice::Shutdown() // This runs before the subclass's Shutdown(), where the context, etc, may be deleted. - glDeleteFramebuffers(1, &CurrentFbo); + glDeleteFramebuffers(1, &CurrentFbo); + glDeleteFramebuffers(1, &MsaaFbo); if (GLVersionInfo.SupportsVAO) { @@ -777,12 +799,14 @@ void RenderDevice::Shutdown() DefaultFill.Clear(); DepthBuffers.Clear(); + + DebugCallbackControl.Shutdown(); } void RenderDevice::FillTexturedRect(float left, float top, float right, float bottom, float ul, float vt, float ur, float vb, Color c, Ptr<OVR::Render::Texture> tex) { - Render::RenderDevice::FillTexturedRect(left, top, right, bottom, ul, vb, ur, vt, c, tex); + Render::RenderDevice::FillTexturedRect(left, top, right, bottom, ul, vt, ur, vb, c, tex); } @@ -829,12 +853,7 @@ void RenderDevice::SetDepthMode(bool enable, bool write, CompareFunc func) void RenderDevice::SetViewport(const Recti& vp) { - int wh; - if (CurRenderTarget) - wh = CurRenderTarget->Height; - else - wh = WindowHeight; - glViewport(vp.x, wh - vp.y - vp.h, vp.w, vp.h); + glViewport(vp.x, vp.y, vp.w, vp.h); } void RenderDevice::Flush() @@ -844,14 +863,14 @@ void RenderDevice::Flush() void RenderDevice::WaitUntilGpuIdle() { - glFlush(); - glFinish(); + glFlush(); + glFinish(); } void RenderDevice::Clear(float r, float g, float b, float a, float depth, bool clearColor /*= true*/, bool clearDepth /*= true*/) { - glClearColor(r,g,b,a); - glClearDepth(depth); + glClearColor(r,g,b,a); + glClearDepth(depth); glClear( ( clearColor ? ( GL_COLOR_BUFFER_BIT ) : 0 ) | ( clearDepth ? ( GL_DEPTH_BUFFER_BIT ) : 0 ) @@ -869,6 +888,31 @@ Texture* RenderDevice::GetDepthBuffer(int w, int h, int ms) return newDepth.GetPtr(); } +void RenderDevice::ResolveMsaa(OVR::Render::Texture* msaaTex, OVR::Render::Texture* outputTex) +{ + bool isMsaaTarget = msaaTex->GetSamples() > 1; + glBindFramebuffer( GL_READ_FRAMEBUFFER, MsaaFbo ); + glFramebufferTexture2D( GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + isMsaaTarget ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, + ((Texture*)msaaTex)->TexId, 0); + glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + OVR_ASSERT(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glBindFramebuffer( GL_DRAW_FRAMEBUFFER, CurrentFbo ); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ((Texture*)outputTex)->TexId, 0); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + + OVR_ASSERT(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + //glReadBuffer(GL_TEXTURE_2D_MULTISAMPLE); + //glDrawBuffer(GL_COLOR_ATTACHMENT0); + glBlitFramebuffer( 0, 0, msaaTex->GetWidth(), msaaTex->GetHeight(), + 0, 0, outputTex->GetWidth(), outputTex->GetHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + GLint err = glGetError(); + OVR_ASSERT(!err); OVR_UNUSED(err); +} + void RenderDevice::SetRenderTarget(Render::Texture* color, Render::Texture* depth, Render::Texture* stencil) { OVR_UNUSED(stencil); @@ -879,14 +923,19 @@ void RenderDevice::SetRenderTarget(Render::Texture* color, Render::Texture* dept glBindFramebuffer(GL_FRAMEBUFFER, 0); return; } - - if (depth == NULL) - depth = GetDepthBuffer(color->GetWidth(), color->GetHeight(), CurRenderTarget->GetSamples()); + + int sampleCount = CurRenderTarget->GetSamples(); + + if (depth == NULL) + depth = GetDepthBuffer(color->GetWidth(), color->GetHeight(), sampleCount); glBindFramebuffer(GL_FRAMEBUFFER, CurrentFbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ((Texture*)color)->TexId, 0); + + GLenum texTarget = (sampleCount > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texTarget, ((Texture*)color)->TexId, 0); if (depth) - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, ((Texture*)depth)->TexId, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texTarget, ((Texture*)depth)->TexId, 0); else glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); @@ -904,7 +953,7 @@ void RenderDevice::SetWorldUniforms(const Matrix4f& proj) void RenderDevice::SetTexture(Render::ShaderStage, int slot, const Texture* t) { glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_2D, ((Texture*)t)->TexId); + glBindTexture((t->GetSamples() > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, ((Texture*)t)->TexId); } Buffer* RenderDevice::CreateBuffer() @@ -979,11 +1028,11 @@ void RenderDevice::Render(const Fill* fill, Render::Buffer* vertices, Render::Bu Lighting->Set(shaders); } - glBindBuffer(GL_ARRAY_BUFFER, ((Buffer*)vertices)->GLBuffer); - for (int i = 0; i < 5; i++) - glEnableVertexAttribArray(i); + glBindBuffer(GL_ARRAY_BUFFER, ((Buffer*)vertices)->GLBuffer); + for (int i = 0; i < 5; i++) + glEnableVertexAttribArray(i); - switch (meshType) + switch (meshType) { case Mesh_Distortion: glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset) + offsetof(DistortionVertex, Pos)); @@ -1016,8 +1065,8 @@ void RenderDevice::Render(const Fill* fill, Render::Buffer* vertices, Render::Bu glDrawArrays(prim, 0, count); } - for (int i = 0; i < 5; i++) - glDisableVertexAttribArray(i); + for (int i = 0; i < 5; i++) + glDisableVertexAttribArray(i); } void RenderDevice::RenderWithAlpha(const Fill* fill, Render::Buffer* vertices, Render::Buffer* indices, @@ -1104,8 +1153,16 @@ bool Shader::Compile(const char* src) return 1; } -ShaderSet::ShaderSet() +ShaderSet::ShaderSet() : + //Prog(0), + UniformInfo(), + ProjLoc(0), + ViewLoc(0), + //TexLoc[8]; + UsesLighting(false), + LightingVer(0) { + memset(TexLoc, 0, sizeof(TexLoc)); Prog = glCreateProgram(); } ShaderSet::~ShaderSet() @@ -1155,9 +1212,9 @@ bool ShaderSet::Link() LightingVer = 0; UsesLighting = 0; - GLint uniformCount = 0; - glGetProgramiv(Prog, GL_ACTIVE_UNIFORMS, &uniformCount); - OVR_ASSERT(uniformCount >= 0); + GLint uniformCount = 0; + glGetProgramiv(Prog, GL_ACTIVE_UNIFORMS, &uniformCount); + OVR_ASSERT(uniformCount >= 0); for(GLuint i = 0; i < (GLuint)uniformCount; i++) { @@ -1260,7 +1317,7 @@ bool ShaderSet::SetUniform4x4f(const char* name, const Matrix4f& m) return 0; } -Texture::Texture(RenderDevice* r, int w, int h) : Ren(r), Width(w), Height(h) +Texture::Texture(RenderDevice* r, int w, int h, int samples) : Ren(r), Width(w), Height(h), Samples(samples) { glGenTextures(1, &TexId); } @@ -1278,7 +1335,7 @@ void Texture::Set(int slot, Render::ShaderStage stage) const void Texture::SetSampleMode(int sm) { - glBindTexture(GL_TEXTURE_2D, TexId); + glBindTexture((GetSamples() > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, TexId); switch (sm & Sample_FilterMask) { case Sample_Linear: @@ -1294,7 +1351,7 @@ void Texture::SetSampleMode(int sm) break; case Sample_Nearest: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); break; @@ -1321,8 +1378,8 @@ void Texture::SetSampleMode(int sm) ovrTexture Texture::Get_ovrTexture() { - ovrTexture tex; - OVR::Sizei newRTSize(Width, Height); + ovrTexture tex; + OVR::Sizei newRTSize(Width, Height); ovrGLTextureData* texData = (ovrGLTextureData*)&tex; texData->Header.API = ovrRenderAPI_OpenGL; @@ -1330,7 +1387,7 @@ ovrTexture Texture::Get_ovrTexture() texData->Header.RenderViewport = Recti(newRTSize); texData->TexId = TexId; - return tex; + return tex; } Texture* RenderDevice::CreateTexture(int format, int width, int height, const void* data, int mipcount) @@ -1340,23 +1397,34 @@ Texture* RenderDevice::CreateTexture(int format, int width, int height, const vo { case Texture_RGBA: glformat = GL_RGBA; break; case Texture_R: glformat = GL_RED; break; - case Texture_Depth: glformat = GL_DEPTH_COMPONENT; gltype = GL_FLOAT; break; + case Texture_Depth: glformat = GL_DEPTH_COMPONENT; gltype = GL_FLOAT; break; case Texture_DXT1: glformat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case Texture_DXT3: glformat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case Texture_DXT5: glformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; default: return NULL; } - Texture* NewTex = new Texture(this, width, height); - glBindTexture(GL_TEXTURE_2D, NewTex->TexId); - GLint err = glGetError(); + int samples = format & Texture_SamplesMask; + if(samples < 1 || + GLVersionInfo.WholeVersion < 302) // disallow MSAA for low GL context versions + { + samples = 1; + } + + GLenum textureTarget = (samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; + + Texture* NewTex = new Texture(this, width, height, samples); + glBindTexture(textureTarget, NewTex->TexId); + GLint err = glGetError(); + #if ! defined(OVR_OS_MAC) OVR_ASSERT(!err); + #endif - if( err ) - { - printf("%d\n", err); - } + if( err ) + { + printf("RenderDevice::CreateTexture glGetError result: %d\n", err); + } if (format & Texture_Compressed) { @@ -1374,14 +1442,17 @@ Texture* RenderDevice::CreateTexture(int format, int width, int height, const vo if (h < 1) h = 1; } } - else - { - bool isSRGB = ((format & Texture_TypeMask) == Texture_RGBA && (format & Texture_SRGB) != 0); - bool isDepth = ((format & Texture_Depth) != 0); - GLenum internalFormat = (isSRGB) ? GL_SRGB_ALPHA : (isDepth) ? GL_DEPTH_COMPONENT32F : glformat; + else + { + bool isSRGB = ((format & Texture_TypeMask) == Texture_RGBA && (format & Texture_SRGB) != 0); + bool isDepth = ((format & Texture_Depth) != 0); + GLenum internalFormat = (isSRGB) ? GL_SRGB8_ALPHA8 : (isDepth) ? GL_DEPTH_COMPONENT32F : glformat; - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, glformat, gltype, data); - } + if (samples > 1) + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, internalFormat, width, height, false); + else + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, glformat, gltype, data); + } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -1435,9 +1506,397 @@ RBuffer::~RBuffer() } -//// GLVersion -static void ParseGLVersion(GLVersionAndExtensions& versionInfo) + + + +DebugCallback::DebugCallback() + : Initialized(false), + MinLogSeverity(SeverityHigh), + MinAssertSeverity(SeverityHigh), + glDebugMessageCallback(NULL), + glDebugMessageControl(NULL), + glDebugMessageCallbackARB(NULL), + glDebugMessageControlARB(NULL), + glDebugMessageCallbackAMD(NULL), + glDebugMessageControlAMD(NULL) +{ +} + + +DebugCallback::~DebugCallback() +{ + Shutdown(); +} + + +bool DebugCallback::GetGLDebugCallback(PFNGLDEBUGMESSAGECALLBACKPROC* debugCallback, const void** userParam) const +{ + // Curiously, the KHR and ARB callbacks use the same glGetPointerv defines, which means you can only have + // one of them active concurrently. This also implies that an OpenGL implementation which implements both + // KHR and ARB implements the latter as simply a passthrough (or alias) of the former. + #if defined(GL_ARB_debug_output) || defined(GL_KHR_debug) + // glGetPointerv requires at least OpenGL 4.3 headers and implementation, + // but will be present in the headers if GL_ARB_debug_output or GL_KHR_debug are. + if(glDebugMessageCallback || glDebugMessageCallbackARB) + { + glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION, reinterpret_cast<GLvoid**>(debugCallback)); + glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM, const_cast<GLvoid**>(userParam)); + return true; + } + #endif + + // AMD_debug_output doesn't provide an option to get the debug callback. + debugCallback = NULL; + userParam = NULL; + return false; +} + + +void DebugCallback::DebugCallbackInternal(Severity s, const char* pSource, const char* pType, GLuint id, const char* pSeverity, const char* message) +{ + if(s >= MinLogSeverity) + { + OVR::LogError("{ERR-xxxx} [GL Error] %s %s %#x %s: %s", pSource, pType, id, pSeverity, message); + } + + if(s >= MinAssertSeverity) + { + OVR_ASSERT(s < MinAssertSeverity); // Unilateral fail. + } +} + + +void DebugCallback::Initialize() +{ + if(!Initialized) + { + Initialized = true; + + int err = glGetError(); + OVR_UNUSED(err); + + // Used to see if a callback was already registered. + PFNGLDEBUGMESSAGECALLBACKPROC debugCallbackPrev = NULL; + const void* userParamPrev = NULL; + + // Try getting the KHR interface. + #if defined(OVR_OS_MAC) // With Mac OpenGL, functions aren't dynamically linked. They are only directly called. + //glDebugMessageCallback = ::glDebugMessageCallback; // We can enable this some day when Apple includes support + //glDebugMessageControl = ::glDebugMessageControl; // for glDebugMessageCallback in their headers and SDK. + #else + glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) GetFunction("glDebugMessageCallback"); + glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) GetFunction("glDebugMessageControl"); + #endif + + if(glDebugMessageCallback) + { + GetGLDebugCallback(&debugCallbackPrev, &userParamPrev); + + if(!debugCallbackPrev) // If a callback isn't already registered... + { + glDebugMessageCallback(GLDEBUGPROC(DebugMessageCallback), this); + err = glGetError(); + if(err) + { + glDebugMessageCallback = NULL; + glDebugMessageControl = NULL; + OVR_DEBUG_LOG(("glDebugMessageCallback error: %x (%d)\n", err, err)); + } + + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + err = glGetError(); + if(err) + { + OVR_DEBUG_LOG(("GL_DEBUG_OUTPUT_SYNCHRONOUS error: %x (%d)\n", err, err)); + } + + // To consider: disable marker/push/pop + // glDebugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, GL_DONT_CARE, 0, NULL, GL_FALSE); + // glDebugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, GL_DONT_CARE, 0, NULL, GL_FALSE); + // glDebugMessageControl(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, GL_DONT_CARE, 0, NULL, GL_FALSE); + } + } + + if(!glDebugMessageCallback) // If KHR_debug wasn't found, try ARB_debug_output. + { + #if !defined(OVR_OS_MAC) + glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) GetFunction("glDebugMessageCallbackARB"); + glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GetFunction("glDebugMessageControlARB"); + #endif + + if(glDebugMessageCallbackARB) + { + GetGLDebugCallback(&debugCallbackPrev, &userParamPrev); + + if(!debugCallbackPrev) // If a callback isn't already registered... + { + glDebugMessageCallbackARB(GLDEBUGPROCARB(DebugMessageCallback), this); + err = glGetError(); + if(err) + { + glDebugMessageCallbackARB = NULL; + glDebugMessageControlARB = NULL; + OVR_DEBUG_LOG(("glDebugMessageCallbackARB error: %x (%d)\n", err, err)); + } + + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + err = glGetError(); + if(err) + { + OVR_DEBUG_LOG(("GL_DEBUG_OUTPUT_SYNCHRONOUS error: %x (%d)\n", err, err)); + } + + // To consider: disable marker/push/pop + // glDebugMessageControlARB(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, GL_DONT_CARE, 0, NULL, GL_FALSE); + // glDebugMessageControlARB(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PUSH_GROUP, GL_DONT_CARE, 0, NULL, GL_FALSE); + // glDebugMessageControlARB(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_POP_GROUP, GL_DONT_CARE, 0, NULL, GL_FALSE); + } + } + } + + if(!glDebugMessageCallback && !glDebugMessageCallbackARB)// If ARB_debug_output also wasn't found, try AMD_debug_output. + { + #if !defined(OVR_OS_MAC) + glDebugMessageCallbackAMD = (PFNGLDEBUGMESSAGECALLBACKAMDPROC) GetFunction("glDebugMessageCallbackAMD"); + glDebugMessageControlAMD = (PFNGLDEBUGMESSAGEENABLEAMDPROC) GetFunction("glDebugMessageControlAMD"); + #endif + + if(glDebugMessageCallbackAMD) + { + if(!debugCallbackPrev) // If a callback isn't already registered... + { + glDebugMessageCallbackAMD(GLDEBUGPROCAMD(DebugMessageCallbackAMD), this); + err = glGetError(); + if(err) + { + glDebugMessageCallbackAMD = NULL; + glDebugMessageControlAMD = NULL; + OVR_DEBUG_LOG(("glDebugMessageCallbackAMD error: %x (%d)\n", err, err)); + } + // There is no control for synchronous/asynchronous with AMD_debug_output. + } + } + } + } +} + + +void DebugCallback::Shutdown() +{ + if(Initialized) + { + if(glDebugMessageCallbackAMD) + { + glDebugMessageCallbackAMD(NULL, NULL); + glDebugMessageCallbackAMD = NULL; + } + + if(glDebugMessageCallbackARB) + { + glDebugMessageCallbackARB(NULL, NULL); + glDebugMessageCallbackARB = NULL; + } + + if(glDebugMessageCallback) + { + glDebugMessageCallback(NULL, NULL); + glDebugMessageCallback = NULL; + } + + Initialized = false; + } +} + + +void DebugCallback::SetMinSeverity(Severity minLogSeverity, Severity minAssertSeverity) +{ + MinLogSeverity = minLogSeverity; + MinAssertSeverity = minAssertSeverity; +} + + +DebugCallback::Implementation DebugCallback::GetImplementation() const +{ + if(glDebugMessageCallbackAMD) + return ImplementationAMD; + + if(glDebugMessageCallbackARB) + return ImplementationARB; + + if(glDebugMessageCallback) + return ImplementationKHR; + + return ImplementationNone; +} + + +void DebugCallback::DebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*length*/, const GLchar* message, GLvoid* userParam) +{ + const char* pSource = GetSource(source); + const char* pType = GetType(type); + const char* pSeverity = GetSeverity(severity); + Severity s; + + switch(severity) + { + default: + case GL_DEBUG_SEVERITY_NOTIFICATION: + s = SeverityNotification; + break; + case GL_DEBUG_SEVERITY_LOW: + s = SeverityLow; + break; + case GL_DEBUG_SEVERITY_MEDIUM: + s = SeverityMedium; + break; + case GL_DEBUG_SEVERITY_HIGH: + s = SeverityHigh; + break; + } + + DebugCallback* pThis = reinterpret_cast<DebugCallback*>(userParam); + pThis->DebugCallbackInternal(s, pSource, pType, id, pSeverity, message); +} + + +const char* DebugCallback::GetSource(GLenum Source) +{ + // There is one contiguous section of GL_DEBUG_SOURCE values. + static_assert((GL_DEBUG_SOURCE_OTHER - GL_DEBUG_SOURCE_API) == 5, "GL_DEBUG_SOURCE constants are not contiguous."); + + static const char* GL_SourceStrings[] = + { + "API", // GL_DEBUG_SOURCE_API + "System", // GL_DEBUG_SOURCE_WINDOW_SYSTEM + "ShaderCompiler", // GL_DEBUG_SOURCE_SHADER_COMPILER + "ThirdParty", // GL_DEBUG_SOURCE_THIRD_PARTY + "Application", // GL_DEBUG_SOURCE_APPLICATION + "Other" // GL_DEBUG_SOURCE_OTHER + }; + + if ((Source >= GL_DEBUG_SOURCE_API) && (Source <= GL_DEBUG_SOURCE_OTHER)) + return GL_SourceStrings[Source - GL_DEBUG_SOURCE_API]; + + return "Unknown"; +} + + + +const char* DebugCallback::GetType(GLenum Type) +{ + // There are two contiguous sections of GL_DEBUG_TYPE values. + static_assert((GL_DEBUG_TYPE_OTHER - GL_DEBUG_TYPE_ERROR) == 5, "GL_DEBUG_TYPE constants are not contiguous."); + static const char* TypeStrings[] = + { + "Error", // GL_DEBUG_TYPE_ERROR + "Deprecated", // GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR + "UndefinedBehavior", // GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR + "Portability", // GL_DEBUG_TYPE_PORTABILITY + "Performance", // GL_DEBUG_TYPE_PERFORMANCE + "Other" // GL_DEBUG_TYPE_OTHER + }; + + if ((Type >= GL_DEBUG_TYPE_ERROR) && (Type <= GL_DEBUG_TYPE_OTHER)) + return TypeStrings[Type - GL_DEBUG_TYPE_ERROR]; + + // KHR_debug marker/push/pop functionality. + static_assert((GL_DEBUG_TYPE_POP_GROUP - GL_DEBUG_TYPE_MARKER) == 2, "GL_DEBUG_TYPE constants are not contiguous."); + static const char* TypeStrings2[] = + { + "Marker", // GL_DEBUG_TYPE_MARKER + "PushGroup", // GL_DEBUG_TYPE_PUSH_GROUP + "PopGroup", // GL_DEBUG_TYPE_POP_GROUP + }; + + if ((Type >= GL_DEBUG_TYPE_MARKER) && (Type <= GL_DEBUG_TYPE_POP_GROUP)) + return TypeStrings2[Type - GL_DEBUG_TYPE_MARKER]; + + return "Unknown"; +} + + +const char* DebugCallback::GetSeverity(GLenum Severity) +{ + // There are two sections of GL_DEBUG_SEVERITY. + static_assert((GL_DEBUG_SEVERITY_LOW - GL_DEBUG_SEVERITY_HIGH) == 2, "GL_DEBUG_SEVERITY constants are not contiguous."); + static const char* SeverityStrings[] = + { + "High", + "Medium", + "Low" + }; + + if ((Severity >= GL_DEBUG_SEVERITY_HIGH) && (Severity <= GL_DEBUG_SEVERITY_LOW)) + return SeverityStrings[Severity - GL_DEBUG_SEVERITY_HIGH]; + + // There is just one value in this second section. + if(Severity == GL_DEBUG_SEVERITY_NOTIFICATION) + return "Notification"; + + return "Unknown"; +} + + +void DebugCallback::DebugMessageCallbackAMD(GLuint id, GLenum category, GLenum severity, GLsizei /*length*/, const GLchar *message, GLvoid *userParam) +{ + static_assert(GL_DEBUG_SEVERITY_LOW_AMD == GL_DEBUG_SEVERITY_LOW, "Severity mismatch"); // Verify that AMD_debug_output severity constants are identical to KHR_debug severity contstants. + + const char* pSource = GetCategoryAMD(category); + const char* pSeverity = GetSeverity(severity); + Severity s; + + switch(severity) + { + default: + case GL_DEBUG_SEVERITY_NOTIFICATION: + s = SeverityNotification; + break; + case GL_DEBUG_SEVERITY_LOW: + s = SeverityLow; + break; + case GL_DEBUG_SEVERITY_MEDIUM: + s = SeverityMedium; + break; + case GL_DEBUG_SEVERITY_HIGH: + s = SeverityHigh; + break; + } + + DebugCallback* pThis = reinterpret_cast<DebugCallback*>(userParam); + pThis->DebugCallbackInternal(s, pSource, "Other", id, pSeverity, message); +} + + +const char* DebugCallback::GetCategoryAMD(GLenum Category) +{ + static_assert((GL_DEBUG_CATEGORY_OTHER_AMD - GL_DEBUG_CATEGORY_API_ERROR_AMD) == 7, "GL_DEBUG_CATEGORY constants are not contiguous."); + static const char* CategoryStrings[] = + { + "API", // GL_DEBUG_CATEGORY_API_ERROR_AMD + "System", // GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD + "Deprecation", // GL_DEBUG_CATEGORY_DEPRECATION_AMD + "UndefinedBehavior", // GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD + "Performance", // GL_DEBUG_CATEGORY_PERFORMANCE_AMD + "ShaderCompiler", // GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD + "Application", // GL_DEBUG_CATEGORY_APPLICATION_AMD + "Other" // GL_DEBUG_CATEGORY_OTHER_AMD + }; + + if((Category >= GL_DEBUG_CATEGORY_API_ERROR_AMD) && (Category <= GL_DEBUG_CATEGORY_OTHER_AMD)) + return CategoryStrings[Category - GL_DEBUG_CATEGORY_API_ERROR_AMD]; + + return "Unknown"; +} + + + + + + + + +void GLVersionAndExtensions::ParseGLVersion() { const char* version = (const char*)glGetString(GL_VERSION); int fields = 0, major = 0, minor = 0; @@ -1448,23 +1907,14 @@ static void ParseGLVersion(GLVersionAndExtensions& versionInfo) { OVR_DEBUG_LOG(("GL_VERSION: %s", (const char*)version)); -#ifdef OVR_CC_MSVC - // Hack: This is using sscanf_s on MSVC to kill the security warning. - // Normally the two functions are not interchangeable because the string format - // is different for %s types, however we only use %d so it's fine. -#define TEMP_OVR_SSCANF sscanf_s -#else -#define TEMP_OVR_SSCANF sscanf -#endif - // Skip all leading non-digits before reading %d. // Example GL_VERSION strings: // "1.5 ATI-1.4.18" // "OpenGL ES-CM 3.2" - fields = TEMP_OVR_SSCANF(version, isdigit(*version) ? "%d.%d" : "%*[^0-9]%d.%d", &major, &minor); + OVR_DISABLE_MSVC_WARNING(4996) // "scanf may be unsafe" + fields = sscanf(version, isdigit(*version) ? "%d.%d" : "%*[^0-9]%d.%d", &major, &minor); isGLES = (strstr(version, "OpenGL ES") != NULL); - -#undef TEMP_OVR_SSCANF + OVR_RESTORE_MSVC_WARNING() } else { @@ -1481,81 +1931,122 @@ static void ParseGLVersion(GLVersionAndExtensions& versionInfo) } // Write version data - versionInfo.MajorVersion = major; - versionInfo.MinorVersion = minor; - versionInfo.IsGLES = isGLES; + MajorVersion = major; + MinorVersion = minor; + WholeVersion = (major * 100) + minor; + IsGLES = isGLES; + IsCoreProfile = (MajorVersion >= 3); // Until we get a better way to detect core profiles, we err on the conservative side and set to true if the version is >= 3. } -static bool HasGLExtension(const char* extensions, const char* searchKey) -{ - const int searchKeyLen = (int)strlen(searchKey); - const char* p = extensions; - for (;;) +bool GLVersionAndExtensions::HasGLExtension(const char* searchKey) const +{ + if (Extensions && Extensions[0]) // If we have an extension string to search for individual extensions... { - p = strstr(p, searchKey); + const int searchKeyLen = (int)strlen(searchKey); + const char* p = Extensions; - // If not found, - if (p == NULL) + for (;;) { - break; - } + p = strstr(p, searchKey); - // Only match full string - if ((p == extensions || p[-1] == ' ') && - (p[searchKeyLen] == '\0' || p[searchKeyLen] == ' ')) - { - return true; + // If not found, + if (p == NULL) + { + break; + } + + // Only match full string + if ((p == Extensions || p[-1] == ' ') && + (p[searchKeyLen] == '\0' || p[searchKeyLen] == ' ')) + { + return true; + } + + // Skip ahead + p += searchKeyLen; } + } + else + { + if (MajorVersion >= 3) // If glGetIntegerv(GL_NUM_EXTENSIONS, ...) is supported... + { + GLint extensionCount = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount); + GLenum err = glGetError(); - // Skip ahead - p += searchKeyLen; + if (err == 0) + { + for (GLint i = 0; i != extensionCount; ++i) + { + const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, (GLuint)i); + + if (extension) // glGetStringi returns NULL upon error. + { + if (strcmp(extension, searchKey) == 0) + return true; + } + else + break; + } + } + } } return false; } -static void ParseGLExtensions(GLVersionAndExtensions& versionInfo) +void GLVersionAndExtensions::ParseGLExtensions() { - const char* extensions = (const char*)glGetString(GL_EXTENSIONS); - - OVR_ASSERT(extensions); - if (!extensions) + if (MajorVersion >= 3) { - extensions = ""; // Note: glGetString() can return null - LogText("Warning: GL_EXTENSIONS was NULL\n"); + // Set to empty because we need to use glGetStringi to read extensions on recent OpenGL. + Extensions = ""; } else { - // Cannot print this to debug log: It's too long! - //OVR_DEBUG_LOG(("GL_EXTENSIONS: %s", (const char*)extensions)); + const char* extensions = (const char*)glGetString(GL_EXTENSIONS); + + OVR_ASSERT(extensions); + if (!extensions) + { + extensions = ""; // Note: glGetString() can return null + LogText("Warning: GL_EXTENSIONS was NULL\n"); + } + else + { + // Cannot print this to debug log: It's too long! + //OVR_DEBUG_LOG(("GL_EXTENSIONS: %s", (const char*)extensions)); + } + + Extensions = extensions; } - versionInfo.Extensions = extensions; + // To do: revise the code below to loop through calls to glGetStringi(GL_EXTENSIONS, ...) so that all extensions below + // can be searched with a single pass over the extensions instead of a full loop per HasGLExtensionCall. - if (versionInfo.MajorVersion >= 3) + if (MajorVersion >= 3) { - versionInfo.SupportsVAO = true; + SupportsVAO = true; } else { - versionInfo.SupportsVAO = - HasGLExtension(extensions, "GL_ARB_vertex_array_object") || - HasGLExtension(extensions, "GL_APPLE_vertex_array_object"); + SupportsVAO = + HasGLExtension("GL_ARB_vertex_array_object") || + HasGLExtension("GL_APPLE_vertex_array_object"); } - versionInfo.SupportsDrawBuffers = HasGLExtension(extensions, "GL_EXT_draw_buffers2"); + SupportsDrawBuffers = HasGLExtension("GL_EXT_draw_buffers2"); // Add more extension checks here... } void GetGLVersionAndExtensions(GLVersionAndExtensions& versionInfo) { - ParseGLVersion(versionInfo); - + versionInfo.ParseGLVersion(); // GL Version must be parsed before parsing extensions: - - ParseGLExtensions(versionInfo); + versionInfo.ParseGLExtensions(); + // To consider: Call to glGetStringi(GL_SHADING_LANGUAGE_VERSION, ...) check/validate the GLSL support. } diff --git a/Samples/CommonSrc/Render/Render_GL_Device.h b/Samples/CommonSrc/Render/Render_GL_Device.h index 0e24517..620d1bb 100644 --- a/Samples/CommonSrc/Render/Render_GL_Device.h +++ b/Samples/CommonSrc/Render/Render_GL_Device.h @@ -5,7 +5,7 @@ Content : RenderDevice implementation header for OpenGL Created : September 10, 2012 Authors : Andrew Reisse, David Borel -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. @@ -62,6 +62,7 @@ extern PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT; #endif +extern PFNGLGETSTRINGIPROC glGetStringi; extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; extern PFNGLDELETESHADERPROC glDeleteShader; @@ -102,6 +103,7 @@ extern PFNGLUNIFORM3FVPROC glUniform3fv; extern PFNGLUNIFORM2FVPROC glUniform2fv; extern PFNGLUNIFORM1FVPROC glUniform1fv; extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D; +extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample; extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; @@ -109,6 +111,7 @@ extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebuffer; extern void InitGLExtensions(); @@ -116,22 +119,26 @@ extern void InitGLExtensions(); -//// GLVersion - -/* - FIXME: CODE DUPLICATION WARNING - - Right now we have this same code in CommonSrc and in CAPI::GL. - At some point we need to consolidate these, in Kernel or Util. - Be sure to update both locations for now! -*/ - -struct GLVersionAndExtensions +//// GLVersionAndExtensions +// +// FIXME: CODE DUPLICATION WARNING +// Right now we have this same code in CommonSrc and in CAPI::GL. +// At some point we need to consolidate these, in Kernel or Util. +// Be sure to update both locations for now! +// +// This class needs to be initialized at runtime with GetGLVersionAndExtensions, +// after an OpenGL context has been created. It must be re-initialized any time +// a new OpenGL context is created, as the new context may differ in version or +// supported functionality. +class GLVersionAndExtensions { +public: // Version information int MajorVersion; // Best guess at major version int MinorVersion; // Best guess at minor version + int WholeVersion; // Equals ((MajorVersion * 100) + MinorVersion). Example usage: if(glv.WholeVersion >= 302) // If OpenGL v3.02+ ... bool IsGLES; // Open GL ES? + bool IsCoreProfile; // Is the current OpenGL context a core profile context? Its trueness may be a false positive but will never be a false negative. // Extension information bool SupportsVAO; // Supports Vertex Array Objects? @@ -139,19 +146,185 @@ struct GLVersionAndExtensions const char* Extensions; // Other extensions string (will not be null) GLVersionAndExtensions() + : MajorVersion(0), + MinorVersion(0), + WholeVersion(0), + IsGLES(false), + IsCoreProfile(false), + SupportsDrawBuffers(false), + SupportsVAO(false), + Extensions("") { - IsGLES = false; - MajorVersion = 0; - MinorVersion = 0; - SupportsDrawBuffers = false; - SupportsVAO = false; - Extensions = ""; } + + bool HasGLExtension(const char* searchKey) const; + +protected: + friend void GetGLVersionAndExtensions(GLVersionAndExtensions& versionInfo); + + void ParseGLVersion(); + void ParseGLExtensions(); }; void GetGLVersionAndExtensions(GLVersionAndExtensions& versionInfo); + +//// DebugCallback +// +// Used for high level usage and control of the various OpenGL debug output extensions. This is useful for +// intercepting all OpenGL errors in a single place. +// This functionality is specific to OpenGL and no analog exists in DirectX, as DirectX doesn't support +// debug callbacks. +// +// Example basic usage: +// DebugCallback glDebug; +// +// <initialize OpenGL context> +// glDebug.Initialize(); +// glDebug.SetMinSeverity(SeverityMedium, SeverityHigh); +// <use OpenGL. Debug output will be logged by default.> +// glDebug.Shutdown(); +// <destroy OpenGL context> +// +// There are three OpenGL API debug interfaces, each being an evolution of its predecessor: +// AMD_debug_output - https://www.opengl.org/registry/specs/AMD/debug_output.txt +// ARB_debug_output - https://www.opengl.org/registry/specs/ARB/debug_output.txt +// KHR_debug - https://www.opengl.org/registry/specs/KHR/debug.txt +// +// If the AMD_debug_output functionality is present in the OpenGL headers, GL_AMD_debug_output will be defined by glext.h. +// If the ARB_debug_output functionality is present in the OpenGL headers, GL_ARB_debug_output will be defined by glext.h. +// If the KHR_debug functionality is present in the OpenGL headers, GL_KHR_debug will be defined. +// +// As of at least XCode 5.1, debug functionality isn't yet supported by Macintosh OS X. +// KHR_debug is part of the OpenGL 4.3 core profile. It uses the same interface as the ARB extension along with some additions. +// The KHR_debug functionality doesn't include an API suffix (e.g. you would call glDebugMessageCallback). +// OpenGL ES supports KHR debug callbacks as of v3.1. However, for OpenGL ES entry points use the "KHR" suffix (e.g. glDebugMessageCallbackKHR). +// With the KHR version you can control debug messages at runtime with glEnable/glDisable(DEBUG_OUTPUT). +// The KHR_debug functionality requires that the OpenGL context be created with the CONTEXT_FLAG_DEBUG_BIT. +// Windows wglCreateContextAttribsARB should be done with WGL_CONTEXT_DEBUG_BIT_ARB with in WGL_CONTEXT_FLAGS. +// Linux glXCreateContext should be done with GLX_CONTEXT_DEBUG_BIT_ARB set in GLX_CONTEXT_FLAGS. + +// We manually declare types and define values that aren't already declared and defined. This is because this functionality +// is fairly recent (2010 through 2014) and isn't present in all OpenGL headers and implementations. +#ifndef GL_AMD_debug_output + typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam); + typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); + typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC)(GLDEBUGPROCAMD callback, GLvoid *userParam); + + #define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 + #define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 + #define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 +#endif + +#ifndef GL_ARB_debug_output + typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam); + typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); + typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, const void *userParam); + + // We don't define anything here because the defines are the same as the KHR defines below (aside from the _ARB suffix). +#endif + +#ifndef GL_KHR_debug // The following defines were added to OpenGL 4.3+ headers. + typedef void (APIENTRY *GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam); + typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); + typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam); + + #define GL_DEBUG_CALLBACK_FUNCTION 0x8244 + #define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 + #define GL_DEBUG_TYPE_MARKER 0x8268 + #define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 + #define GL_DEBUG_TYPE_POP_GROUP 0x826A + #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 + #define GL_DEBUG_SEVERITY_NOTIFICATION 0x826b + #define GL_DEBUG_SEVERITY_LOW 0x9148 + #define GL_DEBUG_SEVERITY_MEDIUM 0x9147 + #define GL_DEBUG_SEVERITY_HIGH 0x9146 + #define GL_DEBUG_SOURCE_APPLICATION 0x824A + #define GL_DEBUG_SOURCE_OTHER 0x824b + #define GL_DEBUG_SOURCE_API 0x8246 + #define GL_DEBUG_TYPE_ERROR 0x824C + #define GL_DEBUG_TYPE_OTHER 0x8251 + #define GL_DEBUG_OUTPUT 0x92E0 +#endif + + +class DebugCallback +{ +public: + DebugCallback(); + ~DebugCallback(); + + // Initialize must be called after the OpenGL context is created. + void Initialize(); + + // Shutdown must be called before the OpenGL context is destroyed. + void Shutdown(); + + enum Implementation + { + ImplementationNone, + ImplementationAMD, // Oldest version, deprecated by later versions. + ImplementationARB, // ARB version, deprecated by KHR version. + ImplementationKHR // OpenGL 4.3+ core profile version. + }; + + // Will return ImplementationNone until Initialize has been called, at which point it will return the version used. + Implementation GetImplementation() const; + + // Maps to glEnable(GL_DEBUG_OUTPUT) when it is available, else does nothing. This controls debug output at the driver + // level and can be used, for example, to temporarily disable debug output that some other application entity enabled + // via glDebugMessageCallback. In practice this is available only when KHR_debug is available + void EnableGLDebug(bool enabled); + + enum Severity // These are a mirror of the OpenGL types. + { + SeverityNone = 0, + SeverityNotification, + SeverityLow, + SeverityMedium, + SeverityHigh, + SeverityDisabled // When min severity is set to this level, it is never logged or assertion-failed. + }; + + // Set the severity required before we log or assert on a debug message. Default is SeverityHigh/SeverityHigh. + void SetMinSeverity(Severity minLogSeverity, Severity minAssertSeverity); + + // Returns the debug callback currently used by OpenGL. + // This works for both ARB and KHR implementations. The same debug callback is used by OpenGL implementations for both. + // However, you can call GetImplementation to see which of the two we are using. This functionality is not available + // with the AMD implementation. Returns false and sets debugCallback and userParam to NULL if there is no existing callback. + bool GetGLDebugCallback(PFNGLDEBUGMESSAGECALLBACKPROC* debugCallback, const void** userParam) const; + +protected: + void DebugCallbackInternal(Severity s, const char* pSource, const char* pType, GLuint id, const char* pSeverity, const char* message); + + // ARB and KHR debug handler + static void APIENTRY DebugMessageCallback(GLenum Source, GLenum Type, GLuint Id, GLenum Severity, GLsizei Length, const GLchar* Message, GLvoid* UserParam); + static const char* GetSource(GLenum Source); + static const char* GetType(GLenum Type); + static const char* GetSeverity(GLenum Severity); + + // AMD handler + static void APIENTRY DebugMessageCallbackAMD(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam); + static const char* GetCategoryAMD(GLenum Category); + +protected: + bool Initialized; + int MinLogSeverity; // Minimum severity for us to log the event. + int MinAssertSeverity; // Minimum severity for us to assertion-fail the event. + PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback; + PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl; + PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB; // glDebugMessageCallbackARB is the same as glDebugMessageCallback and may not need to be a separate variable. + PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; + PFNGLDEBUGMESSAGECALLBACKAMDPROC glDebugMessageCallbackAMD; + PFNGLDEBUGMESSAGEENABLEAMDPROC glDebugMessageControlAMD; +}; + + + + + class RenderDevice; class Buffer : public Render::Buffer @@ -179,16 +352,17 @@ class Texture : public Render::Texture public: RenderDevice* Ren; GLuint TexId; - int Width, Height; + int Width, Height, Samples; - Texture(RenderDevice* r, int w, int h); + Texture(RenderDevice* r, int w, int h, int samples); ~Texture(); virtual int GetWidth() const { return Width; } virtual int GetHeight() const { return Height; } + virtual int GetSamples() const { return Samples; } virtual void SetSampleMode(int); - virtual ovrTexture Get_ovrTexture(); + virtual ovrTexture Get_ovrTexture(); virtual void Set(int slot, ShaderStage stage = Shader_Fragment) const; }; @@ -204,7 +378,7 @@ public: Compile(src); } - ~Shader(); + ~Shader(); bool Compile(const char* src); GLenum GLStage() const @@ -231,6 +405,8 @@ public: String Name; int Location, Size; int Type; // currently number of floats in vector + + Uniform() : Name(), Location(0), Size(0), Type(0){} }; Array<Uniform> UniformInfo; @@ -243,7 +419,7 @@ public: ~ShaderSet(); virtual void SetShader(Render::Shader *s); - virtual void UnsetShader(int stage); + virtual void UnsetShader(int stage); virtual void Set(PrimitiveType prim) const; @@ -275,14 +451,15 @@ class RenderDevice : public Render::RenderDevice Matrix4f Proj; - GLuint Vao; + GLuint Vao; protected: Ptr<Texture> CurRenderTarget; Array<Ptr<Texture> > DepthBuffers; GLuint CurrentFbo; + GLuint MsaaFbo; GLVersionAndExtensions GLVersionInfo; - + DebugCallback DebugCallbackControl; const LightingParams* Lighting; public: @@ -290,11 +467,11 @@ public: virtual ~RenderDevice(); virtual void Shutdown(); - + virtual void FillTexturedRect(float left, float top, float right, float bottom, float ul, float vt, float ur, float vb, Color c, Ptr<OVR::Render::Texture> tex); virtual void SetViewport(const Recti& vp); - + virtual void WaitUntilGpuIdle(); virtual void Flush(); @@ -308,6 +485,8 @@ public: Texture* GetDepthBuffer(int w, int h, int ms); + virtual void ResolveMsaa(OVR::Render::Texture* msaaTex, OVR::Render::Texture* outputTex) OVR_OVERRIDE; + virtual void Present (bool withVsync){OVR_UNUSED(withVsync);}; virtual void SetRenderTarget(Render::Texture* color, Render::Texture* depth = NULL, Render::Texture* stencil = NULL); @@ -332,6 +511,7 @@ public: }; + }}} #endif diff --git a/Samples/CommonSrc/Render/Render_GL_Win32_Device.cpp b/Samples/CommonSrc/Render/Render_GL_Win32_Device.cpp index b2e2e10..465d16e 100644 --- a/Samples/CommonSrc/Render/Render_GL_Win32_Device.cpp +++ b/Samples/CommonSrc/Render/Render_GL_Win32_Device.cpp @@ -5,7 +5,7 @@ Content : Win32 OpenGL Device implementation Created : September 10, 2012 Authors : Andrew Reisse, Michael Antonov, David Borel -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. @@ -55,12 +55,16 @@ Render::RenderDevice* RenderDevice::CreateDevice(const RendererParams& rp, void* if (!DwmEnableComposition) { - HINSTANCE hInst = LoadLibrary( L"dwmapi.dll" ); + HINSTANCE hInst = LoadLibraryA( "dwmapi.dll" ); OVR_ASSERT(hInst); DwmEnableComposition = (PFNDWMENABLECOMPOSITIONPROC)GetProcAddress( hInst, "DwmEnableComposition" ); OVR_ASSERT(DwmEnableComposition); } + // Why do we need to disable composition for OpenGL rendering? + // "Enabling DWM in extended mode causes 60Hz judder on NVIDIA cards unless the Rift is the main display. " + // "Maybe the confusion is that GL goes through the same compositional pipeline as DX. To the kernel and DWM there is no difference between the two." + // "The judder does not occur with DX. My understanding is that for DWM, GL actually requires an additional blt whose timing is dependent on the main monitor." DwmEnableComposition(DWM_EC_DISABLECOMPOSITION); { PIXELFORMATDESCRIPTOR pfd; diff --git a/Samples/CommonSrc/Render/Render_GL_Win32_Device.h b/Samples/CommonSrc/Render/Render_GL_Win32_Device.h index 14d0b65..48046bd 100644 --- a/Samples/CommonSrc/Render/Render_GL_Win32_Device.h +++ b/Samples/CommonSrc/Render/Render_GL_Win32_Device.h @@ -5,7 +5,7 @@ Content : Win32 OpenGL Device implementation header Created : September 10, 2012 Authors : Andrew Reisse, Michael Antonov, David Borel -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/Render/Render_LoadTextureDDS.cpp b/Samples/CommonSrc/Render/Render_LoadTextureDDS.cpp index 08dda43..136a1d2 100644 --- a/Samples/CommonSrc/Render/Render_LoadTextureDDS.cpp +++ b/Samples/CommonSrc/Render/Render_LoadTextureDDS.cpp @@ -5,7 +5,7 @@ Content : A DDS file loader for cross-platform compressed texture support. Created : March 5, 2013 Authors : Peter Hoff, Dan Goodman, Bryan Croteau -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/Render/Render_LoadTextureTGA.cpp b/Samples/CommonSrc/Render/Render_LoadTextureTGA.cpp index 7c80c88..bdb5804 100644 --- a/Samples/CommonSrc/Render/Render_LoadTextureTGA.cpp +++ b/Samples/CommonSrc/Render/Render_LoadTextureTGA.cpp @@ -5,7 +5,7 @@ Content : Loading of TGA implementation Created : October, 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/Render/Render_XmlSceneLoader.cpp b/Samples/CommonSrc/Render/Render_XmlSceneLoader.cpp index 0eea8eb..d011ee9 100644 --- a/Samples/CommonSrc/Render/Render_XmlSceneLoader.cpp +++ b/Samples/CommonSrc/Render/Render_XmlSceneLoader.cpp @@ -5,7 +5,7 @@ Content : Imports and exports XML files - implementation Created : January 21, 2013 Authors : Robotic Arm Software - Peter Hoff, Dan Goodman, Bryan Croteau -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. @@ -26,7 +26,12 @@ limitations under the License. namespace OVR { namespace Render { -XmlHandler::XmlHandler() : pXmlDocument(NULL) +XmlHandler::XmlHandler() : + pXmlDocument(NULL), + textureCount(0), + modelCount(0), + collisionModelCount(0), + groundCollisionModelCount(0) { pXmlDocument = new tinyxml2::XMLDocument(); } @@ -63,6 +68,7 @@ bool XmlHandler::ReadFile(const char* fileName, OVR::Render::RenderDevice* pRend // Load the textures OVR_DEBUG_LOG_TEXT(("Loading textures...")); XMLElement* pXmlTexture = pXmlDocument->FirstChildElement("scene")->FirstChildElement("textures"); + OVR_ASSERT(pXmlTexture); if (pXmlTexture) { pXmlTexture->QueryIntAttribute("count", &textureCount); @@ -299,61 +305,68 @@ bool XmlHandler::ReadFile(const char* fileName, OVR::Render::RenderDevice* pRend { Ptr<CollisionModel> cm = *new CollisionModel(); int planeCount = 0; - pXmlCollisionModel->QueryIntAttribute("planeCount", &planeCount); - - pXmlPlane = pXmlCollisionModel->FirstChildElement("plane"); - for(int j = 0; j < planeCount; ++j) + + OVR_ASSERT(pXmlCollisionModel != NULL); // collisionModelCount should guarantee this. + if (pXmlCollisionModel) { - Vector3f norm; - pXmlPlane->QueryFloatAttribute("nx", &norm.x); - pXmlPlane->QueryFloatAttribute("ny", &norm.y); - pXmlPlane->QueryFloatAttribute("nz", &norm.z); - float D; - pXmlPlane->QueryFloatAttribute("d", &D); - D -= 0.5f; - if (i == 26) - D += 0.5f; // tighten the terrace collision so player can move right up to rail - Planef p(norm.z, norm.y, norm.x * -1.0f, D); - cm->Add(p); - pXmlPlane = pXmlPlane->NextSiblingElement("plane"); - } + pXmlCollisionModel->QueryIntAttribute("planeCount", &planeCount); + + pXmlPlane = pXmlCollisionModel->FirstChildElement("plane"); + for(int j = 0; j < planeCount; ++j) + { + Vector3f norm; + pXmlPlane->QueryFloatAttribute("nx", &norm.x); + pXmlPlane->QueryFloatAttribute("ny", &norm.y); + pXmlPlane->QueryFloatAttribute("nz", &norm.z); + float D; + pXmlPlane->QueryFloatAttribute("d", &D); + D -= 0.5f; + if (i == 26) + D += 0.5f; // tighten the terrace collision so player can move right up to rail + Planef p(norm.z, norm.y, norm.x * -1.0f, D); + cm->Add(p); + pXmlPlane = pXmlPlane->NextSiblingElement("plane"); + } - pCollisions->PushBack(cm); - pXmlCollisionModel = pXmlCollisionModel->NextSiblingElement("collisionModel"); + pCollisions->PushBack(cm); + pXmlCollisionModel = pXmlCollisionModel->NextSiblingElement("collisionModel"); + } } OVR_DEBUG_LOG(("done.")); //load the ground collision models OVR_DEBUG_LOG(("Loading ground collision models...")); pXmlCollisionModel = pXmlDocument->FirstChildElement("scene")->FirstChildElement("groundCollisionModels"); + OVR_ASSERT(pXmlCollisionModel); if (pXmlCollisionModel) { pXmlCollisionModel->QueryIntAttribute("count", &groundCollisionModelCount); pXmlCollisionModel = pXmlCollisionModel->FirstChildElement("collisionModel"); - } - pXmlPlane = NULL; - for(int i = 0; i < groundCollisionModelCount; ++i) - { - Ptr<CollisionModel> cm = *new CollisionModel(); - int planeCount = 0; - pXmlCollisionModel->QueryIntAttribute("planeCount", &planeCount); - pXmlPlane = pXmlCollisionModel->FirstChildElement("plane"); - for(int j = 0; j < planeCount; ++j) + pXmlPlane = NULL; + for (int i = 0; i < groundCollisionModelCount; ++i) { - Vector3f norm; - pXmlPlane->QueryFloatAttribute("nx", &norm.x); - pXmlPlane->QueryFloatAttribute("ny", &norm.y); - pXmlPlane->QueryFloatAttribute("nz", &norm.z); - float D; - pXmlPlane->QueryFloatAttribute("d", &D); - Planef p(norm.z, norm.y, norm.x * -1.0f, D); - cm->Add(p); - pXmlPlane = pXmlPlane->NextSiblingElement("plane"); - } + Ptr<CollisionModel> cm = *new CollisionModel(); + int planeCount = 0; + pXmlCollisionModel->QueryIntAttribute("planeCount", &planeCount); - pGroundCollisions->PushBack(cm); - pXmlCollisionModel = pXmlCollisionModel->NextSiblingElement("collisionModel"); + pXmlPlane = pXmlCollisionModel->FirstChildElement("plane"); + for (int j = 0; j < planeCount; ++j) + { + Vector3f norm; + pXmlPlane->QueryFloatAttribute("nx", &norm.x); + pXmlPlane->QueryFloatAttribute("ny", &norm.y); + pXmlPlane->QueryFloatAttribute("nz", &norm.z); + float D = 0.f; + pXmlPlane->QueryFloatAttribute("d", &D); + Planef p(norm.z, norm.y, norm.x * -1.0f, D); + cm->Add(p); + pXmlPlane = pXmlPlane->NextSiblingElement("plane"); + } + + pGroundCollisions->PushBack(cm); + pXmlCollisionModel = pXmlCollisionModel->NextSiblingElement("collisionModel"); + } } OVR_DEBUG_LOG(("done.")); return true; diff --git a/Samples/CommonSrc/Render/Render_XmlSceneLoader.h b/Samples/CommonSrc/Render/Render_XmlSceneLoader.h index 22c9ccd..94a2219 100644 --- a/Samples/CommonSrc/Render/Render_XmlSceneLoader.h +++ b/Samples/CommonSrc/Render/Render_XmlSceneLoader.h @@ -5,7 +5,7 @@ Content : Imports and exports XML files Created : January 21, 2013 Authors : Robotic Arm Software - Peter Hoff, Dan Goodman, Bryan Croteau -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/Util/OptionMenu.cpp b/Samples/CommonSrc/Util/OptionMenu.cpp index 2d3c3d0..b2cc0c9 100644 --- a/Samples/CommonSrc/Util/OptionMenu.cpp +++ b/Samples/CommonSrc/Util/OptionMenu.cpp @@ -5,7 +5,7 @@ Content : Option selection and editing for OculusWorldDemo Created : March 7, 2014 Authors : Michael Antonov, Caleb Leak -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. @@ -150,6 +150,7 @@ OptionVar::OptionVar(const char* name, void* pvar, VarType type, ShortcutDown.pNotify = new FunctionNotifyContext<OptionVar, bool>(this, &OptionVar::PrevValue); } + OptionVar::OptionVar(const char* name, int32_t* pvar, int32_t min, int32_t max, int32_t stepSize, const char* formatString, @@ -164,6 +165,11 @@ OptionVar::OptionVar(const char* name, int32_t* pvar, pNotify = 0; FormatString= formatString; + MaxFloat = MATH_FLOAT_MAXVALUE; + MinFloat = -MATH_FLOAT_MAXVALUE; + StepFloat = 1.0f; + FormatScale = 1.0f; + MinInt = min; MaxInt = max; StepInt = stepSize; @@ -194,6 +200,10 @@ OptionVar::OptionVar(const char* name, float* pvar, StepFloat = stepSize; FormatScale = formatScale; + MaxInt = 0x7FFFFFFF; + MinInt = -(MaxInt) - 1; + StepInt = 1; + SelectedIndex = 0; ShortcutUp.pNotify = new FunctionNotifyContext<OptionVar, bool>(this, &OptionVar::NextValue); @@ -243,9 +253,12 @@ void OptionVar::PrevValue(bool* pFastStep) switch (Type) { case Type_Enum: - *AsInt() = ((GetEnumIndex() + (uint32_t)EnumValues.GetSize() - 1) % EnumValues.GetSize()); + { + uint32_t size = (uint32_t)(EnumValues.GetSize() ? EnumValues.GetSize() : 1); + *AsInt() = ((GetEnumIndex() + (size - 1)) % size); break; - + } + case Type_Int: *AsInt() = Alg::Max<int32_t>(*AsInt() - StepInt * (fastStep ? 5 : 1), MinInt); break; diff --git a/Samples/CommonSrc/Util/OptionMenu.h b/Samples/CommonSrc/Util/OptionMenu.h index 5eea9bd..0c3c289 100644 --- a/Samples/CommonSrc/Util/OptionMenu.h +++ b/Samples/CommonSrc/Util/OptionMenu.h @@ -5,7 +5,7 @@ Content : Option selection and editing for OculusWorldDemo Created : March 7, 2014 Authors : Michael Antonov, Caleb Leak -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/Util/RenderProfiler.cpp b/Samples/CommonSrc/Util/RenderProfiler.cpp index 00bbdd9..cc617ff 100644 --- a/Samples/CommonSrc/Util/RenderProfiler.cpp +++ b/Samples/CommonSrc/Util/RenderProfiler.cpp @@ -5,7 +5,7 @@ Content : Profiling for render. Created : March 10, 2014 Authors : Caleb Leak -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. @@ -76,18 +76,19 @@ void RenderProfiler::DrawOverlay(RenderDevice* prender) const double* averages = GetAverages(); const double* lastSampleSet = GetLastSampleSet(); - for ( int timerNum = 1; timerNum < Sample_LAST; timerNum++ ) + static_assert((Sample_FrameStart == 0) && (Sample_AfterGameProcessing == 1) && (Sample_AfterPresent + 1 == Sample_LAST), "The following code depends on SampleType enum values."); + + for ( int timerNum = Sample_AfterGameProcessing; timerNum < Sample_LAST; timerNum++ ) { char const *pName = ""; switch ( timerNum ) { case Sample_AfterGameProcessing: pName = "AfterGameProcessing"; break; case Sample_AfterEyeRender : pName = "AfterEyeRender "; break; -// case Sample_BeforeDistortion : pName = "BeforeDistortion "; break; -// case Sample_AfterDistortion : pName = "AfterDistortion "; break; + //case Sample_BeforeDistortion : pName = "BeforeDistortion "; break; This enumerant is currently disabled in the enumeration declaration. + //case Sample_AfterDistortion : pName = "AfterDistortion "; break; case Sample_AfterPresent : pName = "AfterPresent "; break; -// case Sample_AfterFlush : pName = "AfterFlush "; break; - default: OVR_ASSERT ( false ); + //case Sample_AfterFlush : pName = "AfterFlush "; break; } char bufTemp[256]; OVR_sprintf ( bufTemp, sizeof(bufTemp), "\nRaw: %.2lfms\t400Ave: %.2lfms\t800%s", diff --git a/Samples/CommonSrc/Util/RenderProfiler.h b/Samples/CommonSrc/Util/RenderProfiler.h index 7494034..84e5013 100644 --- a/Samples/CommonSrc/Util/RenderProfiler.h +++ b/Samples/CommonSrc/Util/RenderProfiler.h @@ -5,7 +5,7 @@ Content : Profiling for render. Created : March 10, 2014 Authors : Caleb Leak -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. @@ -43,10 +43,10 @@ public: Sample_FrameStart , Sample_AfterGameProcessing , Sample_AfterEyeRender , - // Sample_BeforeDistortion , - // Sample_AfterDistortion , + //Sample_BeforeDistortion , + //Sample_AfterDistortion , Sample_AfterPresent , - // Sample_AfterFlush , + //Sample_AfterFlush , Sample_LAST }; |