From 47afda2549cdab0429047fcc64540a4ed5d0ede7 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 11:55:32 +0200 Subject: [PATCH 01/11] Removed useless function: GetGestureDetected() Use instead: IsGestureDetected() --- src/gestures.c | 7 ------- src/gestures.h | 7 +++---- src/raylib.h | 7 +++---- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/gestures.c b/src/gestures.c index 903716209..8e6005b3e 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -298,13 +298,6 @@ bool IsGestureDetected(int gesture) else return false; } -// Check gesture type -int GetGestureDetected(void) -{ - // Get current gesture only if enabled - return (enabledGestures & currentGesture); -} - // Get number of touch points int GetTouchPointsCount(void) { diff --git a/src/gestures.h b/src/gestures.h index f2bdaba47..ab5287ccf 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -90,13 +90,12 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- +void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags +bool IsGestureDetected(int gesture); // Check if a gesture have been detected void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) -bool IsGestureDetected(int gesture); // Check if a gesture have been detected -int GetGestureDetected(void); // Get latest detected gesture -void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -int GetTouchPointsCount(void); // Get touch points count +int GetTouchPointsCount(void); // Get touch points count float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle diff --git a/src/raylib.h b/src/raylib.h index bfcb9bf56..343e86f1c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -644,13 +644,12 @@ bool IsButtonReleased(int button); // Detect if an android //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ +void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags +bool IsGestureDetected(int gesture); // Check if a gesture have been detected void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (called automatically in PollInputEvents()) -bool IsGestureDetected(int gesture); // Check if a gesture have been detected -int GetGestureDetected(void); // Get latest detected gesture -void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -int GetTouchPointsCount(void); // Get touch points count +int GetTouchPointsCount(void); // Get touch points count float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle From 3d6be7fd8000bf7bd9da0b9ad8764021f86c0d01 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 12:01:57 +0200 Subject: [PATCH 02/11] Added GetGestureDetected() again... Required by gestures example.... --- src/gestures.c | 27 +++++++++++++++++---------- src/gestures.h | 1 + src/raylib.h | 1 + 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/gestures.c b/src/gestures.c index 8e6005b3e..57b96bd26 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -111,6 +111,19 @@ static double GetCurrentTime(void); // Module Functions Definition //---------------------------------------------------------------------------------- +// Enable only desired getures to be detected +void SetGesturesEnabled(unsigned int gestureFlags) +{ + enabledGestures = gestureFlags; +} + +// Check if a gesture have been detected +bool IsGestureDetected(int gesture) +{ + if ((enabledGestures & currentGesture) == gesture) return true; + else return false; +} + // Process gesture event and translate it into gestures void ProcessGestureEvent(GestureEvent event) { @@ -291,13 +304,6 @@ void UpdateGestures(void) } } -// Check if a gesture have been detected -bool IsGestureDetected(int gesture) -{ - if ((enabledGestures & currentGesture) == gesture) return true; - else return false; -} - // Get number of touch points int GetTouchPointsCount(void) { @@ -306,10 +312,11 @@ int GetTouchPointsCount(void) return pointCount; } -// Enable only desired getures to be detected -void SetGesturesEnabled(unsigned int gestureFlags) +// Get latest detected gesture +int GetGestureDetected(void) { - enabledGestures = gestureFlags; + // Get current gesture only if enabled + return (enabledGestures & currentGesture); } // Hold time measured in ms diff --git a/src/gestures.h b/src/gestures.h index ab5287ccf..912d0b926 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -96,6 +96,7 @@ void ProcessGestureEvent(GestureEvent event); // Process gesture event void UpdateGestures(void); // Update gestures detected (must be called every frame) int GetTouchPointsCount(void); // Get touch points count +int GetGestureDetected(void); // Get latest detected gesture float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle diff --git a/src/raylib.h b/src/raylib.h index 343e86f1c..9120ddc4b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -650,6 +650,7 @@ void ProcessGestureEvent(GestureEvent event); // Process gesture event void UpdateGestures(void); // Update gestures detected (called automatically in PollInputEvents()) int GetTouchPointsCount(void); // Get touch points count +int GetGestureDetected(void); // Get latest detected gesture float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle From 3a5fc0c32042714efde93c72903d2cd89c4cff50 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 12:12:02 +0200 Subject: [PATCH 03/11] Move global data to implementation --- src/raygui.h | 208 ++++++++++++++++++++++++++------------------------- 1 file changed, 107 insertions(+), 101 deletions(-) diff --git a/src/raygui.h b/src/raygui.h index 74f131d58..42cf264b2 100644 --- a/src/raygui.h +++ b/src/raygui.h @@ -242,106 +242,7 @@ typedef enum GuiProperty { //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static const char *guiPropertyName[] = { - "GLOBAL_BASE_COLOR", - "GLOBAL_BORDER_COLOR", - "GLOBAL_TEXT_COLOR", - "GLOBAL_TEXT_FONTSIZE", - "GLOBAL_BORDER_WIDTH", - "BACKGROUND_COLOR", - "LABEL_BORDER_WIDTH", - "LABEL_TEXT_COLOR", - "LABEL_TEXT_PADDING", - "BUTTON_BORDER_WIDTH", - "BUTTON_TEXT_PADDING", - "BUTTON_DEFAULT_BORDER_COLOR", - "BUTTON_DEFAULT_INSIDE_COLOR", - "BUTTON_DEFAULT_TEXT_COLOR", - "BUTTON_HOVER_BORDER_COLOR", - "BUTTON_HOVER_INSIDE_COLOR", - "BUTTON_HOVER_TEXT_COLOR", - "BUTTON_PRESSED_BORDER_COLOR", - "BUTTON_PRESSED_INSIDE_COLOR", - "BUTTON_PRESSED_TEXT_COLOR", - "TOGGLE_TEXT_PADDING", - "TOGGLE_BORDER_WIDTH", - "TOGGLE_DEFAULT_BORDER_COLOR", - "TOGGLE_DEFAULT_INSIDE_COLOR", - "TOGGLE_DEFAULT_TEXT_COLOR", - "TOGGLE_HOVER_BORDER_COLOR", - "TOGGLE_HOVER_INSIDE_COLOR", - "TOGGLE_HOVER_TEXT_COLOR", - "TOGGLE_PRESSED_BORDER_COLOR", - "TOGGLE_PRESSED_INSIDE_COLOR", - "TOGGLE_PRESSED_TEXT_COLOR", - "TOGGLE_ACTIVE_BORDER_COLOR", - "TOGGLE_ACTIVE_INSIDE_COLOR", - "TOGGLE_ACTIVE_TEXT_COLOR", - "TOGGLEGROUP_PADDING", - "SLIDER_BORDER_WIDTH", - "SLIDER_BUTTON_BORDER_WIDTH", - "SLIDER_BORDER_COLOR", - "SLIDER_INSIDE_COLOR", - "SLIDER_DEFAULT_COLOR", - "SLIDER_HOVER_COLOR", - "SLIDER_ACTIVE_COLOR", - "SLIDERBAR_BORDER_COLOR", - "SLIDERBAR_INSIDE_COLOR", - "SLIDERBAR_DEFAULT_COLOR", - "SLIDERBAR_HOVER_COLOR", - "SLIDERBAR_ACTIVE_COLOR", - "SLIDERBAR_ZERO_LINE_COLOR", - "PROGRESSBAR_BORDER_COLOR", - "PROGRESSBAR_INSIDE_COLOR", - "PROGRESSBAR_PROGRESS_COLOR", - "PROGRESSBAR_BORDER_WIDTH", - "SPINNER_LABEL_BORDER_COLOR", - "SPINNER_LABEL_INSIDE_COLOR", - "SPINNER_DEFAULT_BUTTON_BORDER_COLOR", - "SPINNER_DEFAULT_BUTTON_INSIDE_COLOR", - "SPINNER_DEFAULT_SYMBOL_COLOR", - "SPINNER_DEFAULT_TEXT_COLOR", - "SPINNER_HOVER_BUTTON_BORDER_COLOR", - "SPINNER_HOVER_BUTTON_INSIDE_COLOR", - "SPINNER_HOVER_SYMBOL_COLOR", - "SPINNER_HOVER_TEXT_COLOR", - "SPINNER_PRESSED_BUTTON_BORDER_COLOR", - "SPINNER_PRESSED_BUTTON_INSIDE_COLOR", - "SPINNER_PRESSED_SYMBOL_COLOR", - "SPINNER_PRESSED_TEXT_COLOR", - "COMBOBOX_PADDING", - "COMBOBOX_BUTTON_WIDTH", - "COMBOBOX_BUTTON_HEIGHT", - "COMBOBOX_BORDER_WIDTH", - "COMBOBOX_DEFAULT_BORDER_COLOR", - "COMBOBOX_DEFAULT_INSIDE_COLOR", - "COMBOBOX_DEFAULT_TEXT_COLOR", - "COMBOBOX_DEFAULT_LIST_TEXT_COLOR", - "COMBOBOX_HOVER_BORDER_COLOR", - "COMBOBOX_HOVER_INSIDE_COLOR", - "COMBOBOX_HOVER_TEXT_COLOR", - "COMBOBOX_HOVER_LIST_TEXT_COLOR", - "COMBOBOX_PRESSED_BORDER_COLOR", - "COMBOBOX_PRESSED_INSIDE_COLOR", - "COMBOBOX_PRESSED_TEXT_COLOR", - "COMBOBOX_PRESSED_LIST_BORDER_COLOR", - "COMBOBOX_PRESSED_LIST_INSIDE_COLOR", - "COMBOBOX_PRESSED_LIST_TEXT_COLOR", - "CHECKBOX_DEFAULT_BORDER_COLOR", - "CHECKBOX_DEFAULT_INSIDE_COLOR", - "CHECKBOX_HOVER_BORDER_COLOR", - "CHECKBOX_HOVER_INSIDE_COLOR", - "CHECKBOX_CLICK_BORDER_COLOR", - "CHECKBOX_CLICK_INSIDE_COLOR", - "CHECKBOX_STATUS_ACTIVE_COLOR", - "CHECKBOX_INSIDE_WIDTH", - "TEXTBOX_BORDER_WIDTH", - "TEXTBOX_BORDER_COLOR", - "TEXTBOX_INSIDE_COLOR", - "TEXTBOX_TEXT_COLOR", - "TEXTBOX_LINE_COLOR", - "TEXTBOX_TEXT_FONTSIZE" -}; +// ... //---------------------------------------------------------------------------------- // Module Functions Declaration @@ -517,6 +418,108 @@ static int style[NUM_PROPERTIES] = { 10 // TEXTBOX_TEXT_FONTSIZE }; +// GUI property names (to read/write style text files) +static const char *guiPropertyName[] = { + "GLOBAL_BASE_COLOR", + "GLOBAL_BORDER_COLOR", + "GLOBAL_TEXT_COLOR", + "GLOBAL_TEXT_FONTSIZE", + "GLOBAL_BORDER_WIDTH", + "BACKGROUND_COLOR", + "LABEL_BORDER_WIDTH", + "LABEL_TEXT_COLOR", + "LABEL_TEXT_PADDING", + "BUTTON_BORDER_WIDTH", + "BUTTON_TEXT_PADDING", + "BUTTON_DEFAULT_BORDER_COLOR", + "BUTTON_DEFAULT_INSIDE_COLOR", + "BUTTON_DEFAULT_TEXT_COLOR", + "BUTTON_HOVER_BORDER_COLOR", + "BUTTON_HOVER_INSIDE_COLOR", + "BUTTON_HOVER_TEXT_COLOR", + "BUTTON_PRESSED_BORDER_COLOR", + "BUTTON_PRESSED_INSIDE_COLOR", + "BUTTON_PRESSED_TEXT_COLOR", + "TOGGLE_TEXT_PADDING", + "TOGGLE_BORDER_WIDTH", + "TOGGLE_DEFAULT_BORDER_COLOR", + "TOGGLE_DEFAULT_INSIDE_COLOR", + "TOGGLE_DEFAULT_TEXT_COLOR", + "TOGGLE_HOVER_BORDER_COLOR", + "TOGGLE_HOVER_INSIDE_COLOR", + "TOGGLE_HOVER_TEXT_COLOR", + "TOGGLE_PRESSED_BORDER_COLOR", + "TOGGLE_PRESSED_INSIDE_COLOR", + "TOGGLE_PRESSED_TEXT_COLOR", + "TOGGLE_ACTIVE_BORDER_COLOR", + "TOGGLE_ACTIVE_INSIDE_COLOR", + "TOGGLE_ACTIVE_TEXT_COLOR", + "TOGGLEGROUP_PADDING", + "SLIDER_BORDER_WIDTH", + "SLIDER_BUTTON_BORDER_WIDTH", + "SLIDER_BORDER_COLOR", + "SLIDER_INSIDE_COLOR", + "SLIDER_DEFAULT_COLOR", + "SLIDER_HOVER_COLOR", + "SLIDER_ACTIVE_COLOR", + "SLIDERBAR_BORDER_COLOR", + "SLIDERBAR_INSIDE_COLOR", + "SLIDERBAR_DEFAULT_COLOR", + "SLIDERBAR_HOVER_COLOR", + "SLIDERBAR_ACTIVE_COLOR", + "SLIDERBAR_ZERO_LINE_COLOR", + "PROGRESSBAR_BORDER_COLOR", + "PROGRESSBAR_INSIDE_COLOR", + "PROGRESSBAR_PROGRESS_COLOR", + "PROGRESSBAR_BORDER_WIDTH", + "SPINNER_LABEL_BORDER_COLOR", + "SPINNER_LABEL_INSIDE_COLOR", + "SPINNER_DEFAULT_BUTTON_BORDER_COLOR", + "SPINNER_DEFAULT_BUTTON_INSIDE_COLOR", + "SPINNER_DEFAULT_SYMBOL_COLOR", + "SPINNER_DEFAULT_TEXT_COLOR", + "SPINNER_HOVER_BUTTON_BORDER_COLOR", + "SPINNER_HOVER_BUTTON_INSIDE_COLOR", + "SPINNER_HOVER_SYMBOL_COLOR", + "SPINNER_HOVER_TEXT_COLOR", + "SPINNER_PRESSED_BUTTON_BORDER_COLOR", + "SPINNER_PRESSED_BUTTON_INSIDE_COLOR", + "SPINNER_PRESSED_SYMBOL_COLOR", + "SPINNER_PRESSED_TEXT_COLOR", + "COMBOBOX_PADDING", + "COMBOBOX_BUTTON_WIDTH", + "COMBOBOX_BUTTON_HEIGHT", + "COMBOBOX_BORDER_WIDTH", + "COMBOBOX_DEFAULT_BORDER_COLOR", + "COMBOBOX_DEFAULT_INSIDE_COLOR", + "COMBOBOX_DEFAULT_TEXT_COLOR", + "COMBOBOX_DEFAULT_LIST_TEXT_COLOR", + "COMBOBOX_HOVER_BORDER_COLOR", + "COMBOBOX_HOVER_INSIDE_COLOR", + "COMBOBOX_HOVER_TEXT_COLOR", + "COMBOBOX_HOVER_LIST_TEXT_COLOR", + "COMBOBOX_PRESSED_BORDER_COLOR", + "COMBOBOX_PRESSED_INSIDE_COLOR", + "COMBOBOX_PRESSED_TEXT_COLOR", + "COMBOBOX_PRESSED_LIST_BORDER_COLOR", + "COMBOBOX_PRESSED_LIST_INSIDE_COLOR", + "COMBOBOX_PRESSED_LIST_TEXT_COLOR", + "CHECKBOX_DEFAULT_BORDER_COLOR", + "CHECKBOX_DEFAULT_INSIDE_COLOR", + "CHECKBOX_HOVER_BORDER_COLOR", + "CHECKBOX_HOVER_INSIDE_COLOR", + "CHECKBOX_CLICK_BORDER_COLOR", + "CHECKBOX_CLICK_INSIDE_COLOR", + "CHECKBOX_STATUS_ACTIVE_COLOR", + "CHECKBOX_INSIDE_WIDTH", + "TEXTBOX_BORDER_WIDTH", + "TEXTBOX_BORDER_COLOR", + "TEXTBOX_INSIDE_COLOR", + "TEXTBOX_TEXT_COLOR", + "TEXTBOX_LINE_COLOR", + "TEXTBOX_TEXT_FONTSIZE" +}; + //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- @@ -529,7 +532,9 @@ static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if p static const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' // NOTE: raygui depend on some raylib input and drawing functions -// TODO: Replace by your own functions +// TODO: To use raygui as standalone library, those functions must be overwrite by custom ones + +// Input management functions static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } static int IsMouseButtonDown(int button) { return 0; } static int IsMouseButtonPressed(int button) { return 0; } @@ -539,6 +544,7 @@ static int IsMouseButtonUp(int button) { return 0; } static int GetKeyPressed(void) { return 0; } // NOTE: Only used by GuiTextBox() static int IsKeyDown(int key) { return 0; } // NOTE: Only used by GuiSpinner() +// Drawing related functions static int MeasureText(const char *text, int fontSize) { return 0; } static void DrawText(const char *text, int posX, int posY, int fontSize, Color color) { } static void DrawRectangleRec(Rectangle rec, Color color) { } From c25b4cdc69999c851594f7644ce89556be039c70 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 15:42:04 +0200 Subject: [PATCH 04/11] Move OpenGL extensions loading to rlgl --- src/core.c | 20 +++----------------- src/rlgl.c | 21 ++++++++++++++++++++- src/rlgl.h | 3 ++- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/core.c b/src/core.c index 122453e35..bd49b5494 100644 --- a/src/core.c +++ b/src/core.c @@ -58,10 +58,6 @@ #define PLATFORM_DESKTOP // Enable PLATFORM_DESKTOP code-base #endif -#if defined(PLATFORM_DESKTOP) - #include "external/glad.h" // GLAD library: Manage OpenGL headers and extensions -#endif - #if defined(PLATFORM_OCULUS) #include "../examples/oculus_glfw_sample/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL #endif @@ -1747,19 +1743,9 @@ static void InitDisplay(int width, int height) #endif #if defined(PLATFORM_DESKTOP) - // Load OpenGL 3.3 extensions using GLAD - if (rlGetVersion() == OPENGL_33) - { - // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); - else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); - - if (GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); - else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); - - // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans - //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object - } + // Load OpenGL 3.3 extensions + // NOTE: GLFW loader function is passed as parameter + rlglLoadExtensions(glfwGetProcAddress); #endif // Enables GPU v-sync, so frames are not limited to screen refresh rate (60Hz -> 60 FPS) diff --git a/src/rlgl.c b/src/rlgl.c index e69ff983d..26961ca9e 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -872,6 +872,23 @@ int rlGetVersion(void) #endif } +// Load OpenGL extensions +// NOTE: External loader function could be passed as a pointer +void rlglLoadExtensions(void *loader) +{ +#if defined(GRAPHICS_API_OPENGL_33) + // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions + if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); + else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); + + if (GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); + else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); + + // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans + //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object +#endif +} + //---------------------------------------------------------------------------------- // Module Functions Definition - rlgl Functions //---------------------------------------------------------------------------------- @@ -1184,11 +1201,13 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma GLuint id = 0; // Check texture format support by OpenGL 1.1 (compressed textures not supported) - if ((rlGetVersion() == OPENGL_11) && (textureFormat >= 8)) +#if defined(GRAPHICS_API_OPENGL_11) + if (textureFormat >= 8) { TraceLog(WARNING, "OpenGL 1.1 does not support GPU compressed texture formats"); return id; } +#endif if ((!texCompDXTSupported) && ((textureFormat == COMPRESSED_DXT1_RGB) || (textureFormat == COMPRESSED_DXT1_RGBA) || (textureFormat == COMPRESSED_DXT3_RGBA) || (textureFormat == COMPRESSED_DXT5_RGBA))) diff --git a/src/rlgl.h b/src/rlgl.h index 9c25f7104..28c50b8f2 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -48,7 +48,7 @@ // Choose opengl version here or just define it at compile time: -DGRAPHICS_API_OPENGL_33 //#define GRAPHICS_API_OPENGL_11 // Only available on PLATFORM_DESKTOP -//#define GRAPHICS_API_OPENGL_33 // Only available on PLATFORM_DESKTOP +//#define GRAPHICS_API_OPENGL_33 // Only available on PLATFORM_DESKTOP or PLATFORM_OCULUS //#define GRAPHICS_API_OPENGL_ES2 // Only available on PLATFORM_ANDROID or PLATFORM_RPI or PLATFORM_WEB // Security check in case no GRAPHICS_API_OPENGL_* defined @@ -296,6 +296,7 @@ void rlglInit(void); // Initialize rlgl (shaders, VAO void rlglClose(void); // De-init rlgl void rlglDraw(void); // Draw VAO/VBO void rlglInitGraphics(int offsetX, int offsetY, int width, int height); // Initialize Graphics (OpenGL stuff) +void rlglLoadExtensions(void *loader); // Load OpenGL extensions unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments) From 0d0f306fc2f6bed7526df2044263698753811d0a Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 17:15:00 +0200 Subject: [PATCH 05/11] Add Oculus SDK LibOVR library to external deps. --- .../LibOVR/Include/Extras/OVR_CAPI_Util.h | 196 + .../LibOVR/Include/Extras/OVR_Math.h | 3785 +++++++++++++++++ .../Include/Extras/OVR_StereoProjection.h | 70 + .../OculusSDK/LibOVR/Include/OVR_CAPI.h | 2116 +++++++++ .../OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h | 76 + .../OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h | 155 + .../OculusSDK/LibOVR/Include/OVR_CAPI_GL.h | 99 + .../OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h | 53 + .../OculusSDK/LibOVR/Include/OVR_ErrorCode.h | 209 + .../OculusSDK/LibOVR/Include/OVR_Version.h | 60 + 10 files changed, 6819 insertions(+) create mode 100644 src/external/OculusSDK/LibOVR/Include/Extras/OVR_CAPI_Util.h create mode 100644 src/external/OculusSDK/LibOVR/Include/Extras/OVR_Math.h create mode 100644 src/external/OculusSDK/LibOVR/Include/Extras/OVR_StereoProjection.h create mode 100644 src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h create mode 100644 src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h create mode 100644 src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h create mode 100644 src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h create mode 100644 src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h create mode 100644 src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h create mode 100644 src/external/OculusSDK/LibOVR/Include/OVR_Version.h diff --git a/src/external/OculusSDK/LibOVR/Include/Extras/OVR_CAPI_Util.h b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_CAPI_Util.h new file mode 100644 index 000000000..552f3b125 --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_CAPI_Util.h @@ -0,0 +1,196 @@ +/********************************************************************************//** +\file OVR_CAPI_Util.h +\brief This header provides LibOVR utility function declarations +\copyright Copyright 2015-2016 Oculus VR, LLC All Rights reserved. +*************************************************************************************/ + +#ifndef OVR_CAPI_Util_h +#define OVR_CAPI_Util_h + + +#include "../OVR_CAPI.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/// Enumerates modifications to the projection matrix based on the application's needs. +/// +/// \see ovrMatrix4f_Projection +/// +typedef enum ovrProjectionModifier_ +{ + /// Use for generating a default projection matrix that is: + /// * Right-handed. + /// * Near depth values stored in the depth buffer are smaller than far depth values. + /// * Both near and far are explicitly defined. + /// * With a clipping range that is (0 to w). + ovrProjection_None = 0x00, + + /// Enable if using left-handed transformations in your application. + ovrProjection_LeftHanded = 0x01, + + /// After the projection transform is applied, far values stored in the depth buffer will be less than closer depth values. + /// NOTE: Enable only if the application is using a floating-point depth buffer for proper precision. + ovrProjection_FarLessThanNear = 0x02, + + /// When this flag is used, the zfar value pushed into ovrMatrix4f_Projection() will be ignored + /// NOTE: Enable only if ovrProjection_FarLessThanNear is also enabled where the far clipping plane will be pushed to infinity. + ovrProjection_FarClipAtInfinity = 0x04, + + /// Enable if the application is rendering with OpenGL and expects a projection matrix with a clipping range of (-w to w). + /// Ignore this flag if your application already handles the conversion from D3D range (0 to w) to OpenGL. + ovrProjection_ClipRangeOpenGL = 0x08, +} ovrProjectionModifier; + + +/// Return values for ovr_Detect. +/// +/// \see ovr_Detect +/// +typedef struct OVR_ALIGNAS(8) ovrDetectResult_ +{ + /// Is ovrFalse when the Oculus Service is not running. + /// This means that the Oculus Service is either uninstalled or stopped. + /// IsOculusHMDConnected will be ovrFalse in this case. + /// Is ovrTrue when the Oculus Service is running. + /// This means that the Oculus Service is installed and running. + /// IsOculusHMDConnected will reflect the state of the HMD. + ovrBool IsOculusServiceRunning; + + /// Is ovrFalse when an Oculus HMD is not detected. + /// If the Oculus Service is not running, this will be ovrFalse. + /// Is ovrTrue when an Oculus HMD is detected. + /// This implies that the Oculus Service is also installed and running. + ovrBool IsOculusHMDConnected; + + OVR_UNUSED_STRUCT_PAD(pad0, 6) ///< \internal struct padding + +} ovrDetectResult; + +OVR_STATIC_ASSERT(sizeof(ovrDetectResult) == 8, "ovrDetectResult size mismatch"); + + +/// Detects Oculus Runtime and Device Status +/// +/// Checks for Oculus Runtime and Oculus HMD device status without loading the LibOVRRT +/// shared library. This may be called before ovr_Initialize() to help decide whether or +/// not to initialize LibOVR. +/// +/// \param[in] timeoutMilliseconds Specifies a timeout to wait for HMD to be attached or 0 to poll. +/// +/// \return Returns an ovrDetectResult object indicating the result of detection. +/// +/// \see ovrDetectResult +/// +OVR_PUBLIC_FUNCTION(ovrDetectResult) ovr_Detect(int timeoutMilliseconds); + +// On the Windows platform, +#ifdef _WIN32 + /// This is the Windows Named Event name that is used to check for HMD connected state. + #define OVR_HMD_CONNECTED_EVENT_NAME L"OculusHMDConnected" +#endif // _WIN32 + + +/// Used to generate projection from ovrEyeDesc::Fov. +/// +/// \param[in] fov Specifies the ovrFovPort to use. +/// \param[in] znear Distance to near Z limit. +/// \param[in] zfar Distance to far Z limit. +/// \param[in] projectionModFlags A combination of the ovrProjectionModifier flags. +/// +/// \return Returns the calculated projection matrix. +/// +/// \see ovrProjectionModifier +/// +OVR_PUBLIC_FUNCTION(ovrMatrix4f) ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, unsigned int projectionModFlags); + + +/// Extracts the required data from the result of ovrMatrix4f_Projection. +/// +/// \param[in] projection Specifies the project matrix from which to extract ovrTimewarpProjectionDesc. +/// \param[in] projectionModFlags A combination of the ovrProjectionModifier flags. +/// \return Returns the extracted ovrTimewarpProjectionDesc. +/// \see ovrTimewarpProjectionDesc +/// +OVR_PUBLIC_FUNCTION(ovrTimewarpProjectionDesc) ovrTimewarpProjectionDesc_FromProjection(ovrMatrix4f projection, unsigned int projectionModFlags); + + +/// Generates an orthographic sub-projection. +/// +/// Used for 2D rendering, Y is down. +/// +/// \param[in] projection The perspective matrix that the orthographic matrix is derived from. +/// \param[in] orthoScale Equal to 1.0f / pixelsPerTanAngleAtCenter. +/// \param[in] orthoDistance Equal to the distance from the camera in meters, such as 0.8m. +/// \param[in] HmdToEyeOffsetX Specifies the offset of the eye from the center. +/// +/// \return Returns the calculated projection matrix. +/// +OVR_PUBLIC_FUNCTION(ovrMatrix4f) ovrMatrix4f_OrthoSubProjection(ovrMatrix4f projection, ovrVector2f orthoScale, + float orthoDistance, float HmdToEyeOffsetX); + + + +/// Computes offset eye poses based on headPose returned by ovrTrackingState. +/// +/// \param[in] headPose Indicates the HMD position and orientation to use for the calculation. +/// \param[in] hmdToEyeOffset Can be ovrEyeRenderDesc.HmdToEyeOffset returned from +/// ovr_GetRenderDesc. For monoscopic rendering, use a vector that is the average +/// of the two vectors for both eyes. +/// \param[out] outEyePoses If outEyePoses are used for rendering, they should be passed to +/// ovr_SubmitFrame in ovrLayerEyeFov::RenderPose or ovrLayerEyeFovDepth::RenderPose. +/// +OVR_PUBLIC_FUNCTION(void) ovr_CalcEyePoses(ovrPosef headPose, + const ovrVector3f hmdToEyeOffset[2], + ovrPosef outEyePoses[2]); + + +/// Returns the predicted head pose in outHmdTrackingState and offset eye poses in outEyePoses. +/// +/// This is a thread-safe function where caller should increment frameIndex with every frame +/// and pass that index where applicable to functions called on the rendering thread. +/// Assuming outEyePoses are used for rendering, it should be passed as a part of ovrLayerEyeFov. +/// The caller does not need to worry about applying HmdToEyeOffset to the returned outEyePoses variables. +/// +/// \param[in] hmd Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] frameIndex Specifies the targeted frame index, or 0 to refer to one frame after +/// the last time ovr_SubmitFrame was called. +/// \param[in] latencyMarker Specifies that this call is the point in time where +/// the "App-to-Mid-Photon" latency timer starts from. If a given ovrLayer +/// provides "SensorSampleTimestamp", that will override the value stored here. +/// \param[in] hmdToEyeOffset Can be ovrEyeRenderDesc.HmdToEyeOffset returned from +/// ovr_GetRenderDesc. For monoscopic rendering, use a vector that is the average +/// of the two vectors for both eyes. +/// \param[out] outEyePoses The predicted eye poses. +/// \param[out] outSensorSampleTime The time when this function was called. May be NULL, in which case it is ignored. +/// +OVR_PUBLIC_FUNCTION(void) ovr_GetEyePoses(ovrSession session, long long frameIndex, ovrBool latencyMarker, + const ovrVector3f hmdToEyeOffset[2], + ovrPosef outEyePoses[2], + double* outSensorSampleTime); + + + +/// Tracking poses provided by the SDK come in a right-handed coordinate system. If an application +/// is passing in ovrProjection_LeftHanded into ovrMatrix4f_Projection, then it should also use +/// this function to flip the HMD tracking poses to be left-handed. +/// +/// While this utility function is intended to convert a left-handed ovrPosef into a right-handed +/// coordinate system, it will also work for converting right-handed to left-handed since the +/// flip operation is the same for both cases. +/// +/// \param[in] inPose that is right-handed +/// \param[out] outPose that is requested to be left-handed (can be the same pointer to inPose) +/// +OVR_PUBLIC_FUNCTION(void) ovrPosef_FlipHandedness(const ovrPosef* inPose, ovrPosef* outPose); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // Header include guard diff --git a/src/external/OculusSDK/LibOVR/Include/Extras/OVR_Math.h b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_Math.h new file mode 100644 index 000000000..c182ed5b4 --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_Math.h @@ -0,0 +1,3785 @@ +/********************************************************************************//** +\file OVR_Math.h +\brief Implementation of 3D primitives such as vectors, matrices. +\copyright Copyright 2014-2016 Oculus VR, LLC All Rights reserved. +*************************************************************************************/ + +#ifndef OVR_Math_h +#define OVR_Math_h + + +// This file is intended to be independent of the rest of LibOVR and LibOVRKernel and thus +// has no #include dependencies on either. + +#include +#include +#include +#include +#include +#include +#include "../OVR_CAPI.h" // Currently required due to a dependence on the ovrFovPort_ declaration. + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4127) // conditional expression is constant +#endif + + +#if defined(_MSC_VER) + #define OVRMath_sprintf sprintf_s +#else + #define OVRMath_sprintf snprintf +#endif + + +//------------------------------------------------------------------------------------- +// ***** OVR_MATH_ASSERT +// +// Independent debug break implementation for OVR_Math.h. + +#if !defined(OVR_MATH_DEBUG_BREAK) + #if defined(_DEBUG) + #if defined(_MSC_VER) + #define OVR_MATH_DEBUG_BREAK __debugbreak() + #else + #define OVR_MATH_DEBUG_BREAK __builtin_trap() + #endif + #else + #define OVR_MATH_DEBUG_BREAK ((void)0) + #endif +#endif + + +//------------------------------------------------------------------------------------- +// ***** OVR_MATH_ASSERT +// +// Independent OVR_MATH_ASSERT implementation for OVR_Math.h. + +#if !defined(OVR_MATH_ASSERT) + #if defined(_DEBUG) + #define OVR_MATH_ASSERT(p) if (!(p)) { OVR_MATH_DEBUG_BREAK; } + #else + #define OVR_MATH_ASSERT(p) ((void)0) + #endif +#endif + + +//------------------------------------------------------------------------------------- +// ***** OVR_MATH_STATIC_ASSERT +// +// Independent OVR_MATH_ASSERT implementation for OVR_Math.h. + +#if !defined(OVR_MATH_STATIC_ASSERT) + #if defined(__cplusplus) && ((defined(_MSC_VER) && (defined(_MSC_VER) >= 1600)) || defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)) + #define OVR_MATH_STATIC_ASSERT static_assert + #else + #if !defined(OVR_SA_UNUSED) + #if defined(__GNUC__) || defined(__clang__) + #define OVR_SA_UNUSED __attribute__((unused)) + #else + #define OVR_SA_UNUSED + #endif + #define OVR_SA_PASTE(a,b) a##b + #define OVR_SA_HELP(a,b) OVR_SA_PASTE(a,b) + #endif + + #define OVR_MATH_STATIC_ASSERT(expression, msg) typedef char OVR_SA_HELP(compileTimeAssert, __LINE__) [((expression) != 0) ? 1 : -1] OVR_SA_UNUSED + #endif +#endif + + + +namespace OVR { + +template +const T OVRMath_Min(const T a, const T b) +{ return (a < b) ? a : b; } + +template +const T OVRMath_Max(const T a, const T b) +{ return (b < a) ? a : b; } + +template +void OVRMath_Swap(T& a, T& b) +{ T temp(a); a = b; b = temp; } + + +//------------------------------------------------------------------------------------- +// ***** Constants for 3D world/axis definitions. + +// Definitions of axes for coordinate and rotation conversions. +enum Axis +{ + Axis_X = 0, Axis_Y = 1, Axis_Z = 2 +}; + +// RotateDirection describes the rotation direction around an axis, interpreted as follows: +// CW - Clockwise while looking "down" from positive axis towards the origin. +// CCW - Counter-clockwise while looking from the positive axis towards the origin, +// which is in the negative axis direction. +// CCW is the default for the RHS coordinate system. Oculus standard RHS coordinate +// system defines Y up, X right, and Z back (pointing out from the screen). In this +// system Rotate_CCW around Z will specifies counter-clockwise rotation in XY plane. +enum RotateDirection +{ + Rotate_CCW = 1, + Rotate_CW = -1 +}; + +// Constants for right handed and left handed coordinate systems +enum HandedSystem +{ + Handed_R = 1, Handed_L = -1 +}; + +// AxisDirection describes which way the coordinate axis points. Used by WorldAxes. +enum AxisDirection +{ + Axis_Up = 2, + Axis_Down = -2, + Axis_Right = 1, + Axis_Left = -1, + Axis_In = 3, + Axis_Out = -3 +}; + +struct WorldAxes +{ + AxisDirection XAxis, YAxis, ZAxis; + + WorldAxes(AxisDirection x, AxisDirection y, AxisDirection z) + : XAxis(x), YAxis(y), ZAxis(z) + { OVR_MATH_ASSERT(abs(x) != abs(y) && abs(y) != abs(z) && abs(z) != abs(x));} +}; + +} // namespace OVR + + +//------------------------------------------------------------------------------------// +// ***** C Compatibility Types + +// These declarations are used to support conversion between C types used in +// LibOVR C interfaces and their C++ versions. As an example, they allow passing +// Vector3f into a function that expects ovrVector3f. + +typedef struct ovrQuatf_ ovrQuatf; +typedef struct ovrQuatd_ ovrQuatd; +typedef struct ovrSizei_ ovrSizei; +typedef struct ovrSizef_ ovrSizef; +typedef struct ovrSized_ ovrSized; +typedef struct ovrRecti_ ovrRecti; +typedef struct ovrVector2i_ ovrVector2i; +typedef struct ovrVector2f_ ovrVector2f; +typedef struct ovrVector2d_ ovrVector2d; +typedef struct ovrVector3f_ ovrVector3f; +typedef struct ovrVector3d_ ovrVector3d; +typedef struct ovrVector4f_ ovrVector4f; +typedef struct ovrVector4d_ ovrVector4d; +typedef struct ovrMatrix2f_ ovrMatrix2f; +typedef struct ovrMatrix2d_ ovrMatrix2d; +typedef struct ovrMatrix3f_ ovrMatrix3f; +typedef struct ovrMatrix3d_ ovrMatrix3d; +typedef struct ovrMatrix4f_ ovrMatrix4f; +typedef struct ovrMatrix4d_ ovrMatrix4d; +typedef struct ovrPosef_ ovrPosef; +typedef struct ovrPosed_ ovrPosed; +typedef struct ovrPoseStatef_ ovrPoseStatef; +typedef struct ovrPoseStated_ ovrPoseStated; + +namespace OVR { + +// Forward-declare our templates. +template class Quat; +template class Size; +template class Rect; +template class Vector2; +template class Vector3; +template class Vector4; +template class Matrix2; +template class Matrix3; +template class Matrix4; +template class Pose; +template class PoseState; + +// CompatibleTypes::Type is used to lookup a compatible C-version of a C++ class. +template +struct CompatibleTypes +{ + // Declaration here seems necessary for MSVC; specializations are + // used instead. + typedef struct {} Type; +}; + +// Specializations providing CompatibleTypes::Type value. +template<> struct CompatibleTypes > { typedef ovrQuatf Type; }; +template<> struct CompatibleTypes > { typedef ovrQuatd Type; }; +template<> struct CompatibleTypes > { typedef ovrMatrix2f Type; }; +template<> struct CompatibleTypes > { typedef ovrMatrix2d Type; }; +template<> struct CompatibleTypes > { typedef ovrMatrix3f Type; }; +template<> struct CompatibleTypes > { typedef ovrMatrix3d Type; }; +template<> struct CompatibleTypes > { typedef ovrMatrix4f Type; }; +template<> struct CompatibleTypes > { typedef ovrMatrix4d Type; }; +template<> struct CompatibleTypes > { typedef ovrSizei Type; }; +template<> struct CompatibleTypes > { typedef ovrSizef Type; }; +template<> struct CompatibleTypes > { typedef ovrSized Type; }; +template<> struct CompatibleTypes > { typedef ovrRecti Type; }; +template<> struct CompatibleTypes > { typedef ovrVector2i Type; }; +template<> struct CompatibleTypes > { typedef ovrVector2f Type; }; +template<> struct CompatibleTypes > { typedef ovrVector2d Type; }; +template<> struct CompatibleTypes > { typedef ovrVector3f Type; }; +template<> struct CompatibleTypes > { typedef ovrVector3d Type; }; +template<> struct CompatibleTypes > { typedef ovrVector4f Type; }; +template<> struct CompatibleTypes > { typedef ovrVector4d Type; }; +template<> struct CompatibleTypes > { typedef ovrPosef Type; }; +template<> struct CompatibleTypes > { typedef ovrPosed Type; }; + +//------------------------------------------------------------------------------------// +// ***** Math +// +// Math class contains constants and functions. This class is a template specialized +// per type, with Math and Math being distinct. +template +class Math +{ +public: + // By default, support explicit conversion to float. This allows Vector2 to + // compile, for example. + typedef float OtherFloatType; + + static int Tolerance() { return 0; } // Default value so integer types compile +}; + + +//------------------------------------------------------------------------------------// +// ***** double constants +#define MATH_DOUBLE_PI 3.14159265358979323846 +#define MATH_DOUBLE_TWOPI (2*MATH_DOUBLE_PI) +#define MATH_DOUBLE_PIOVER2 (0.5*MATH_DOUBLE_PI) +#define MATH_DOUBLE_PIOVER4 (0.25*MATH_DOUBLE_PI) +#define MATH_FLOAT_MAXVALUE (FLT_MAX) + +#define MATH_DOUBLE_RADTODEGREEFACTOR (360.0 / MATH_DOUBLE_TWOPI) +#define MATH_DOUBLE_DEGREETORADFACTOR (MATH_DOUBLE_TWOPI / 360.0) + +#define MATH_DOUBLE_E 2.71828182845904523536 +#define MATH_DOUBLE_LOG2E 1.44269504088896340736 +#define MATH_DOUBLE_LOG10E 0.434294481903251827651 +#define MATH_DOUBLE_LN2 0.693147180559945309417 +#define MATH_DOUBLE_LN10 2.30258509299404568402 + +#define MATH_DOUBLE_SQRT2 1.41421356237309504880 +#define MATH_DOUBLE_SQRT1_2 0.707106781186547524401 + +#define MATH_DOUBLE_TOLERANCE 1e-12 // a default number for value equality tolerance: about 4500*Epsilon; +#define MATH_DOUBLE_SINGULARITYRADIUS 1e-12 // about 1-cos(.0001 degree), for gimbal lock numerical problems + +//------------------------------------------------------------------------------------// +// ***** float constants +#define MATH_FLOAT_PI float(MATH_DOUBLE_PI) +#define MATH_FLOAT_TWOPI float(MATH_DOUBLE_TWOPI) +#define MATH_FLOAT_PIOVER2 float(MATH_DOUBLE_PIOVER2) +#define MATH_FLOAT_PIOVER4 float(MATH_DOUBLE_PIOVER4) + +#define MATH_FLOAT_RADTODEGREEFACTOR float(MATH_DOUBLE_RADTODEGREEFACTOR) +#define MATH_FLOAT_DEGREETORADFACTOR float(MATH_DOUBLE_DEGREETORADFACTOR) + +#define MATH_FLOAT_E float(MATH_DOUBLE_E) +#define MATH_FLOAT_LOG2E float(MATH_DOUBLE_LOG2E) +#define MATH_FLOAT_LOG10E float(MATH_DOUBLE_LOG10E) +#define MATH_FLOAT_LN2 float(MATH_DOUBLE_LN2) +#define MATH_FLOAT_LN10 float(MATH_DOUBLE_LN10) + +#define MATH_FLOAT_SQRT2 float(MATH_DOUBLE_SQRT2) +#define MATH_FLOAT_SQRT1_2 float(MATH_DOUBLE_SQRT1_2) + +#define MATH_FLOAT_TOLERANCE 1e-5f // a default number for value equality tolerance: 1e-5, about 84*EPSILON; +#define MATH_FLOAT_SINGULARITYRADIUS 1e-7f // about 1-cos(.025 degree), for gimbal lock numerical problems + + + +// Single-precision Math constants class. +template<> +class Math +{ +public: + typedef double OtherFloatType; + + static inline float Tolerance() { return MATH_FLOAT_TOLERANCE; }; // a default number for value equality tolerance + static inline float SingularityRadius() { return MATH_FLOAT_SINGULARITYRADIUS; }; // for gimbal lock numerical problems +}; + +// Double-precision Math constants class +template<> +class Math +{ +public: + typedef float OtherFloatType; + + static inline double Tolerance() { return MATH_DOUBLE_TOLERANCE; }; // a default number for value equality tolerance + static inline double SingularityRadius() { return MATH_DOUBLE_SINGULARITYRADIUS; }; // for gimbal lock numerical problems +}; + +typedef Math Mathf; +typedef Math Mathd; + +// Conversion functions between degrees and radians +// (non-templated to ensure passing int arguments causes warning) +inline float RadToDegree(float rad) { return rad * MATH_FLOAT_RADTODEGREEFACTOR; } +inline double RadToDegree(double rad) { return rad * MATH_DOUBLE_RADTODEGREEFACTOR; } + +inline float DegreeToRad(float deg) { return deg * MATH_FLOAT_DEGREETORADFACTOR; } +inline double DegreeToRad(double deg) { return deg * MATH_DOUBLE_DEGREETORADFACTOR; } + +// Square function +template +inline T Sqr(T x) { return x*x; } + +// Sign: returns 0 if x == 0, -1 if x < 0, and 1 if x > 0 +template +inline T Sign(T x) { return (x != T(0)) ? (x < T(0) ? T(-1) : T(1)) : T(0); } + +// Numerically stable acos function +inline float Acos(float x) { return (x > 1.0f) ? 0.0f : (x < -1.0f) ? MATH_FLOAT_PI : acosf(x); } +inline double Acos(double x) { return (x > 1.0) ? 0.0 : (x < -1.0) ? MATH_DOUBLE_PI : acos(x); } + +// Numerically stable asin function +inline float Asin(float x) { return (x > 1.0f) ? MATH_FLOAT_PIOVER2 : (x < -1.0f) ? -MATH_FLOAT_PIOVER2 : asinf(x); } +inline double Asin(double x) { return (x > 1.0) ? MATH_DOUBLE_PIOVER2 : (x < -1.0) ? -MATH_DOUBLE_PIOVER2 : asin(x); } + +#if defined(_MSC_VER) + inline int isnan(double x) { return ::_isnan(x); } +#elif !defined(isnan) // Some libraries #define isnan. + inline int isnan(double x) { return ::isnan(x); } +#endif + +template +class Quat; + + +//------------------------------------------------------------------------------------- +// ***** Vector2<> + +// Vector2f (Vector2d) represents a 2-dimensional vector or point in space, +// consisting of coordinates x and y + +template +class Vector2 +{ +public: + typedef T ElementType; + static const size_t ElementCount = 2; + + T x, y; + + Vector2() : x(0), y(0) { } + Vector2(T x_, T y_) : x(x_), y(y_) { } + explicit Vector2(T s) : x(s), y(s) { } + explicit Vector2(const Vector2::OtherFloatType> &src) + : x((T)src.x), y((T)src.y) { } + + static Vector2 Zero() { return Vector2(0, 0); } + + // C-interop support. + typedef typename CompatibleTypes >::Type CompatibleType; + + Vector2(const CompatibleType& s) : x(s.x), y(s.y) { } + + operator const CompatibleType& () const + { + OVR_MATH_STATIC_ASSERT(sizeof(Vector2) == sizeof(CompatibleType), "sizeof(Vector2) failure"); + return reinterpret_cast(*this); + } + + + bool operator== (const Vector2& b) const { return x == b.x && y == b.y; } + bool operator!= (const Vector2& b) const { return x != b.x || y != b.y; } + + Vector2 operator+ (const Vector2& b) const { return Vector2(x + b.x, y + b.y); } + Vector2& operator+= (const Vector2& b) { x += b.x; y += b.y; return *this; } + Vector2 operator- (const Vector2& b) const { return Vector2(x - b.x, y - b.y); } + Vector2& operator-= (const Vector2& b) { x -= b.x; y -= b.y; return *this; } + Vector2 operator- () const { return Vector2(-x, -y); } + + // Scalar multiplication/division scales vector. + Vector2 operator* (T s) const { return Vector2(x*s, y*s); } + Vector2& operator*= (T s) { x *= s; y *= s; return *this; } + + Vector2 operator/ (T s) const { T rcp = T(1)/s; + return Vector2(x*rcp, y*rcp); } + Vector2& operator/= (T s) { T rcp = T(1)/s; + x *= rcp; y *= rcp; + return *this; } + + static Vector2 Min(const Vector2& a, const Vector2& b) { return Vector2((a.x < b.x) ? a.x : b.x, + (a.y < b.y) ? a.y : b.y); } + static Vector2 Max(const Vector2& a, const Vector2& b) { return Vector2((a.x > b.x) ? a.x : b.x, + (a.y > b.y) ? a.y : b.y); } + + Vector2 Clamped(T maxMag) const + { + T magSquared = LengthSq(); + if (magSquared <= Sqr(maxMag)) + return *this; + else + return *this * (maxMag / sqrt(magSquared)); + } + + // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance. + bool IsEqual(const Vector2& b, T tolerance =Math::Tolerance()) const + { + return (fabs(b.x-x) <= tolerance) && + (fabs(b.y-y) <= tolerance); + } + bool Compare(const Vector2& b, T tolerance = Math::Tolerance()) const + { + return IsEqual(b, tolerance); + } + + // Access element by index + T& operator[] (int idx) + { + OVR_MATH_ASSERT(0 <= idx && idx < 2); + return *(&x + idx); + } + const T& operator[] (int idx) const + { + OVR_MATH_ASSERT(0 <= idx && idx < 2); + return *(&x + idx); + } + + // Entry-wise product of two vectors + Vector2 EntrywiseMultiply(const Vector2& b) const { return Vector2(x * b.x, y * b.y);} + + + // Multiply and divide operators do entry-wise math. Used Dot() for dot product. + Vector2 operator* (const Vector2& b) const { return Vector2(x * b.x, y * b.y); } + Vector2 operator/ (const Vector2& b) const { return Vector2(x / b.x, y / b.y); } + + // Dot product + // Used to calculate angle q between two vectors among other things, + // as (A dot B) = |a||b|cos(q). + T Dot(const Vector2& b) const { return x*b.x + y*b.y; } + + // Returns the angle from this vector to b, in radians. + T Angle(const Vector2& b) const + { + T div = LengthSq()*b.LengthSq(); + OVR_MATH_ASSERT(div != T(0)); + T result = Acos((this->Dot(b))/sqrt(div)); + return result; + } + + // Return Length of the vector squared. + T LengthSq() const { return (x * x + y * y); } + + // Return vector length. + T Length() const { return sqrt(LengthSq()); } + + // Returns squared distance between two points represented by vectors. + T DistanceSq(const Vector2& b) const { return (*this - b).LengthSq(); } + + // Returns distance between two points represented by vectors. + T Distance(const Vector2& b) const { return (*this - b).Length(); } + + // Determine if this a unit vector. + bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math::Tolerance(); } + + // Normalize, convention vector length to 1. + void Normalize() + { + T s = Length(); + if (s != T(0)) + s = T(1) / s; + *this *= s; + } + + // Returns normalized (unit) version of the vector without modifying itself. + Vector2 Normalized() const + { + T s = Length(); + if (s != T(0)) + s = T(1) / s; + return *this * s; + } + + // Linearly interpolates from this vector to another. + // Factor should be between 0.0 and 1.0, with 0 giving full value to this. + Vector2 Lerp(const Vector2& b, T f) const { return *this*(T(1) - f) + b*f; } + + // Projects this vector onto the argument; in other words, + // A.Project(B) returns projection of vector A onto B. + Vector2 ProjectTo(const Vector2& b) const + { + T l2 = b.LengthSq(); + OVR_MATH_ASSERT(l2 != T(0)); + return b * ( Dot(b) / l2 ); + } + + // returns true if vector b is clockwise from this vector + bool IsClockwise(const Vector2& b) const + { + return (x * b.y - y * b.x) < 0; + } +}; + + +typedef Vector2 Vector2f; +typedef Vector2 Vector2d; +typedef Vector2 Vector2i; + +typedef Vector2 Point2f; +typedef Vector2 Point2d; +typedef Vector2 Point2i; + +//------------------------------------------------------------------------------------- +// ***** Vector3<> - 3D vector of {x, y, z} + +// +// Vector3f (Vector3d) represents a 3-dimensional vector or point in space, +// consisting of coordinates x, y and z. + +template +class Vector3 +{ +public: + typedef T ElementType; + static const size_t ElementCount = 3; + + T x, y, z; + + // FIXME: default initialization of a vector class can be very expensive in a full-blown + // application. A few hundred thousand vector constructions is not unlikely and can add + // up to milliseconds of time on processors like the PS3 PPU. + Vector3() : x(0), y(0), z(0) { } + Vector3(T x_, T y_, T z_ = 0) : x(x_), y(y_), z(z_) { } + explicit Vector3(T s) : x(s), y(s), z(s) { } + explicit Vector3(const Vector3::OtherFloatType> &src) + : x((T)src.x), y((T)src.y), z((T)src.z) { } + + static Vector3 Zero() { return Vector3(0, 0, 0); } + + // C-interop support. + typedef typename CompatibleTypes >::Type CompatibleType; + + Vector3(const CompatibleType& s) : x(s.x), y(s.y), z(s.z) { } + + operator const CompatibleType& () const + { + OVR_MATH_STATIC_ASSERT(sizeof(Vector3) == sizeof(CompatibleType), "sizeof(Vector3) failure"); + return reinterpret_cast(*this); + } + + bool operator== (const Vector3& b) const { return x == b.x && y == b.y && z == b.z; } + bool operator!= (const Vector3& b) const { return x != b.x || y != b.y || z != b.z; } + + Vector3 operator+ (const Vector3& b) const { return Vector3(x + b.x, y + b.y, z + b.z); } + Vector3& operator+= (const Vector3& b) { x += b.x; y += b.y; z += b.z; return *this; } + Vector3 operator- (const Vector3& b) const { return Vector3(x - b.x, y - b.y, z - b.z); } + Vector3& operator-= (const Vector3& b) { x -= b.x; y -= b.y; z -= b.z; return *this; } + Vector3 operator- () const { return Vector3(-x, -y, -z); } + + // Scalar multiplication/division scales vector. + Vector3 operator* (T s) const { return Vector3(x*s, y*s, z*s); } + Vector3& operator*= (T s) { x *= s; y *= s; z *= s; return *this; } + + Vector3 operator/ (T s) const { T rcp = T(1)/s; + return Vector3(x*rcp, y*rcp, z*rcp); } + Vector3& operator/= (T s) { T rcp = T(1)/s; + x *= rcp; y *= rcp; z *= rcp; + return *this; } + + static Vector3 Min(const Vector3& a, const Vector3& b) + { + return Vector3((a.x < b.x) ? a.x : b.x, + (a.y < b.y) ? a.y : b.y, + (a.z < b.z) ? a.z : b.z); + } + static Vector3 Max(const Vector3& a, const Vector3& b) + { + return Vector3((a.x > b.x) ? a.x : b.x, + (a.y > b.y) ? a.y : b.y, + (a.z > b.z) ? a.z : b.z); + } + + Vector3 Clamped(T maxMag) const + { + T magSquared = LengthSq(); + if (magSquared <= Sqr(maxMag)) + return *this; + else + return *this * (maxMag / sqrt(magSquared)); + } + + // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance. + bool IsEqual(const Vector3& b, T tolerance = Math::Tolerance()) const + { + return (fabs(b.x-x) <= tolerance) && + (fabs(b.y-y) <= tolerance) && + (fabs(b.z-z) <= tolerance); + } + bool Compare(const Vector3& b, T tolerance = Math::Tolerance()) const + { + return IsEqual(b, tolerance); + } + + T& operator[] (int idx) + { + OVR_MATH_ASSERT(0 <= idx && idx < 3); + return *(&x + idx); + } + + const T& operator[] (int idx) const + { + OVR_MATH_ASSERT(0 <= idx && idx < 3); + return *(&x + idx); + } + + // Entrywise product of two vectors + Vector3 EntrywiseMultiply(const Vector3& b) const { return Vector3(x * b.x, + y * b.y, + z * b.z);} + + // Multiply and divide operators do entry-wise math + Vector3 operator* (const Vector3& b) const { return Vector3(x * b.x, + y * b.y, + z * b.z); } + + Vector3 operator/ (const Vector3& b) const { return Vector3(x / b.x, + y / b.y, + z / b.z); } + + + // Dot product + // Used to calculate angle q between two vectors among other things, + // as (A dot B) = |a||b|cos(q). + T Dot(const Vector3& b) const { return x*b.x + y*b.y + z*b.z; } + + // Compute cross product, which generates a normal vector. + // Direction vector can be determined by right-hand rule: Pointing index finder in + // direction a and middle finger in direction b, thumb will point in a.Cross(b). + Vector3 Cross(const Vector3& b) const { return Vector3(y*b.z - z*b.y, + z*b.x - x*b.z, + x*b.y - y*b.x); } + + // Returns the angle from this vector to b, in radians. + T Angle(const Vector3& b) const + { + T div = LengthSq()*b.LengthSq(); + OVR_MATH_ASSERT(div != T(0)); + T result = Acos((this->Dot(b))/sqrt(div)); + return result; + } + + // Return Length of the vector squared. + T LengthSq() const { return (x * x + y * y + z * z); } + + // Return vector length. + T Length() const { return (T)sqrt(LengthSq()); } + + // Returns squared distance between two points represented by vectors. + T DistanceSq(Vector3 const& b) const { return (*this - b).LengthSq(); } + + // Returns distance between two points represented by vectors. + T Distance(Vector3 const& b) const { return (*this - b).Length(); } + + bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math::Tolerance(); } + + // Normalize, convention vector length to 1. + void Normalize() + { + T s = Length(); + if (s != T(0)) + s = T(1) / s; + *this *= s; + } + + // Returns normalized (unit) version of the vector without modifying itself. + Vector3 Normalized() const + { + T s = Length(); + if (s != T(0)) + s = T(1) / s; + return *this * s; + } + + // Linearly interpolates from this vector to another. + // Factor should be between 0.0 and 1.0, with 0 giving full value to this. + Vector3 Lerp(const Vector3& b, T f) const { return *this*(T(1) - f) + b*f; } + + // Projects this vector onto the argument; in other words, + // A.Project(B) returns projection of vector A onto B. + Vector3 ProjectTo(const Vector3& b) const + { + T l2 = b.LengthSq(); + OVR_MATH_ASSERT(l2 != T(0)); + return b * ( Dot(b) / l2 ); + } + + // Projects this vector onto a plane defined by a normal vector + Vector3 ProjectToPlane(const Vector3& normal) const { return *this - this->ProjectTo(normal); } +}; + +typedef Vector3 Vector3f; +typedef Vector3 Vector3d; +typedef Vector3 Vector3i; + +OVR_MATH_STATIC_ASSERT((sizeof(Vector3f) == 3*sizeof(float)), "sizeof(Vector3f) failure"); +OVR_MATH_STATIC_ASSERT((sizeof(Vector3d) == 3*sizeof(double)), "sizeof(Vector3d) failure"); +OVR_MATH_STATIC_ASSERT((sizeof(Vector3i) == 3*sizeof(int32_t)), "sizeof(Vector3i) failure"); + +typedef Vector3 Point3f; +typedef Vector3 Point3d; +typedef Vector3 Point3i; + + +//------------------------------------------------------------------------------------- +// ***** Vector4<> - 4D vector of {x, y, z, w} + +// +// Vector4f (Vector4d) represents a 3-dimensional vector or point in space, +// consisting of coordinates x, y, z and w. + +template +class Vector4 +{ +public: + typedef T ElementType; + static const size_t ElementCount = 4; + + T x, y, z, w; + + // FIXME: default initialization of a vector class can be very expensive in a full-blown + // application. A few hundred thousand vector constructions is not unlikely and can add + // up to milliseconds of time on processors like the PS3 PPU. + Vector4() : x(0), y(0), z(0), w(0) { } + Vector4(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) { } + explicit Vector4(T s) : x(s), y(s), z(s), w(s) { } + explicit Vector4(const Vector3& v, const T w_=T(1)) : x(v.x), y(v.y), z(v.z), w(w_) { } + explicit Vector4(const Vector4::OtherFloatType> &src) + : x((T)src.x), y((T)src.y), z((T)src.z), w((T)src.w) { } + + static Vector4 Zero() { return Vector4(0, 0, 0, 0); } + + // C-interop support. + typedef typename CompatibleTypes< Vector4 >::Type CompatibleType; + + Vector4(const CompatibleType& s) : x(s.x), y(s.y), z(s.z), w(s.w) { } + + operator const CompatibleType& () const + { + OVR_MATH_STATIC_ASSERT(sizeof(Vector4) == sizeof(CompatibleType), "sizeof(Vector4) failure"); + return reinterpret_cast(*this); + } + + Vector4& operator= (const Vector3& other) { x=other.x; y=other.y; z=other.z; w=1; return *this; } + bool operator== (const Vector4& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; } + bool operator!= (const Vector4& b) const { return x != b.x || y != b.y || z != b.z || w != b.w; } + + Vector4 operator+ (const Vector4& b) const { return Vector4(x + b.x, y + b.y, z + b.z, w + b.w); } + Vector4& operator+= (const Vector4& b) { x += b.x; y += b.y; z += b.z; w += b.w; return *this; } + Vector4 operator- (const Vector4& b) const { return Vector4(x - b.x, y - b.y, z - b.z, w - b.w); } + Vector4& operator-= (const Vector4& b) { x -= b.x; y -= b.y; z -= b.z; w -= b.w; return *this; } + Vector4 operator- () const { return Vector4(-x, -y, -z, -w); } + + // Scalar multiplication/division scales vector. + Vector4 operator* (T s) const { return Vector4(x*s, y*s, z*s, w*s); } + Vector4& operator*= (T s) { x *= s; y *= s; z *= s; w *= s;return *this; } + + Vector4 operator/ (T s) const { T rcp = T(1)/s; + return Vector4(x*rcp, y*rcp, z*rcp, w*rcp); } + Vector4& operator/= (T s) { T rcp = T(1)/s; + x *= rcp; y *= rcp; z *= rcp; w *= rcp; + return *this; } + + static Vector4 Min(const Vector4& a, const Vector4& b) + { + return Vector4((a.x < b.x) ? a.x : b.x, + (a.y < b.y) ? a.y : b.y, + (a.z < b.z) ? a.z : b.z, + (a.w < b.w) ? a.w : b.w); + } + static Vector4 Max(const Vector4& a, const Vector4& b) + { + return Vector4((a.x > b.x) ? a.x : b.x, + (a.y > b.y) ? a.y : b.y, + (a.z > b.z) ? a.z : b.z, + (a.w > b.w) ? a.w : b.w); + } + + Vector4 Clamped(T maxMag) const + { + T magSquared = LengthSq(); + if (magSquared <= Sqr(maxMag)) + return *this; + else + return *this * (maxMag / sqrt(magSquared)); + } + + // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance. + bool IsEqual(const Vector4& b, T tolerance = Math::Tolerance()) const + { + return (fabs(b.x-x) <= tolerance) && + (fabs(b.y-y) <= tolerance) && + (fabs(b.z-z) <= tolerance) && + (fabs(b.w-w) <= tolerance); + } + bool Compare(const Vector4& b, T tolerance = Math::Tolerance()) const + { + return IsEqual(b, tolerance); + } + + T& operator[] (int idx) + { + OVR_MATH_ASSERT(0 <= idx && idx < 4); + return *(&x + idx); + } + + const T& operator[] (int idx) const + { + OVR_MATH_ASSERT(0 <= idx && idx < 4); + return *(&x + idx); + } + + // Entry wise product of two vectors + Vector4 EntrywiseMultiply(const Vector4& b) const { return Vector4(x * b.x, + y * b.y, + z * b.z, + w * b.w);} + + // Multiply and divide operators do entry-wise math + Vector4 operator* (const Vector4& b) const { return Vector4(x * b.x, + y * b.y, + z * b.z, + w * b.w); } + + Vector4 operator/ (const Vector4& b) const { return Vector4(x / b.x, + y / b.y, + z / b.z, + w / b.w); } + + + // Dot product + T Dot(const Vector4& b) const { return x*b.x + y*b.y + z*b.z + w*b.w; } + + // Return Length of the vector squared. + T LengthSq() const { return (x * x + y * y + z * z + w * w); } + + // Return vector length. + T Length() const { return sqrt(LengthSq()); } + + bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math::Tolerance(); } + + // Normalize, convention vector length to 1. + void Normalize() + { + T s = Length(); + if (s != T(0)) + s = T(1) / s; + *this *= s; + } + + // Returns normalized (unit) version of the vector without modifying itself. + Vector4 Normalized() const + { + T s = Length(); + if (s != T(0)) + s = T(1) / s; + return *this * s; + } + + // Linearly interpolates from this vector to another. + // Factor should be between 0.0 and 1.0, with 0 giving full value to this. + Vector4 Lerp(const Vector4& b, T f) const { return *this*(T(1) - f) + b*f; } +}; + +typedef Vector4 Vector4f; +typedef Vector4 Vector4d; +typedef Vector4 Vector4i; + + +//------------------------------------------------------------------------------------- +// ***** Bounds3 + +// Bounds class used to describe a 3D axis aligned bounding box. + +template +class Bounds3 +{ +public: + Vector3 b[2]; + + Bounds3() + { + } + + Bounds3( const Vector3 & mins, const Vector3 & maxs ) +{ + b[0] = mins; + b[1] = maxs; + } + + void Clear() + { + b[0].x = b[0].y = b[0].z = Math::MaxValue; + b[1].x = b[1].y = b[1].z = -Math::MaxValue; + } + + void AddPoint( const Vector3 & v ) + { + b[0].x = (b[0].x < v.x ? b[0].x : v.x); + b[0].y = (b[0].y < v.y ? b[0].y : v.y); + b[0].z = (b[0].z < v.z ? b[0].z : v.z); + b[1].x = (v.x < b[1].x ? b[1].x : v.x); + b[1].y = (v.y < b[1].y ? b[1].y : v.y); + b[1].z = (v.z < b[1].z ? b[1].z : v.z); + } + + const Vector3 & GetMins() const { return b[0]; } + const Vector3 & GetMaxs() const { return b[1]; } + + Vector3 & GetMins() { return b[0]; } + Vector3 & GetMaxs() { return b[1]; } +}; + +typedef Bounds3 Bounds3f; +typedef Bounds3 Bounds3d; + + +//------------------------------------------------------------------------------------- +// ***** Size + +// Size class represents 2D size with Width, Height components. +// Used to describe distentions of render targets, etc. + +template +class Size +{ +public: + T w, h; + + Size() : w(0), h(0) { } + Size(T w_, T h_) : w(w_), h(h_) { } + explicit Size(T s) : w(s), h(s) { } + explicit Size(const Size::OtherFloatType> &src) + : w((T)src.w), h((T)src.h) { } + + // C-interop support. + typedef typename CompatibleTypes >::Type CompatibleType; + + Size(const CompatibleType& s) : w(s.w), h(s.h) { } + + operator const CompatibleType& () const + { + OVR_MATH_STATIC_ASSERT(sizeof(Size) == sizeof(CompatibleType), "sizeof(Size) failure"); + return reinterpret_cast(*this); + } + + bool operator== (const Size& b) const { return w == b.w && h == b.h; } + bool operator!= (const Size& b) const { return w != b.w || h != b.h; } + + Size operator+ (const Size& b) const { return Size(w + b.w, h + b.h); } + Size& operator+= (const Size& b) { w += b.w; h += b.h; return *this; } + Size operator- (const Size& b) const { return Size(w - b.w, h - b.h); } + Size& operator-= (const Size& b) { w -= b.w; h -= b.h; return *this; } + Size operator- () const { return Size(-w, -h); } + Size operator* (const Size& b) const { return Size(w * b.w, h * b.h); } + Size& operator*= (const Size& b) { w *= b.w; h *= b.h; return *this; } + Size operator/ (const Size& b) const { return Size(w / b.w, h / b.h); } + Size& operator/= (const Size& b) { w /= b.w; h /= b.h; return *this; } + + // Scalar multiplication/division scales both components. + Size operator* (T s) const { return Size(w*s, h*s); } + Size& operator*= (T s) { w *= s; h *= s; return *this; } + Size operator/ (T s) const { return Size(w/s, h/s); } + Size& operator/= (T s) { w /= s; h /= s; return *this; } + + static Size Min(const Size& a, const Size& b) { return Size((a.w < b.w) ? a.w : b.w, + (a.h < b.h) ? a.h : b.h); } + static Size Max(const Size& a, const Size& b) { return Size((a.w > b.w) ? a.w : b.w, + (a.h > b.h) ? a.h : b.h); } + + T Area() const { return w * h; } + + inline Vector2 ToVector() const { return Vector2(w, h); } +}; + + +typedef Size Sizei; +typedef Size Sizeu; +typedef Size Sizef; +typedef Size Sized; + + + +//----------------------------------------------------------------------------------- +// ***** Rect + +// Rect describes a rectangular area for rendering, that includes position and size. +template +class Rect +{ +public: + T x, y; + T w, h; + + Rect() { } + Rect(T x1, T y1, T w1, T h1) : x(x1), y(y1), w(w1), h(h1) { } + Rect(const Vector2& pos, const Size& sz) : x(pos.x), y(pos.y), w(sz.w), h(sz.h) { } + Rect(const Size& sz) : x(0), y(0), w(sz.w), h(sz.h) { } + + // C-interop support. + typedef typename CompatibleTypes >::Type CompatibleType; + + Rect(const CompatibleType& s) : x(s.Pos.x), y(s.Pos.y), w(s.Size.w), h(s.Size.h) { } + + operator const CompatibleType& () const + { + OVR_MATH_STATIC_ASSERT(sizeof(Rect) == sizeof(CompatibleType), "sizeof(Rect) failure"); + return reinterpret_cast(*this); + } + + Vector2 GetPos() const { return Vector2(x, y); } + Size GetSize() const { return Size(w, h); } + void SetPos(const Vector2& pos) { x = pos.x; y = pos.y; } + void SetSize(const Size& sz) { w = sz.w; h = sz.h; } + + bool operator == (const Rect& vp) const + { return (x == vp.x) && (y == vp.y) && (w == vp.w) && (h == vp.h); } + bool operator != (const Rect& vp) const + { return !operator == (vp); } +}; + +typedef Rect Recti; + + +//-------------------------------------------------------------------------------------// +// ***** Quat +// +// Quatf represents a quaternion class used for rotations. +// +// Quaternion multiplications are done in right-to-left order, to match the +// behavior of matrices. + + +template +class Quat +{ +public: + typedef T ElementType; + static const size_t ElementCount = 4; + + // x,y,z = axis*sin(angle), w = cos(angle) + T x, y, z, w; + + Quat() : x(0), y(0), z(0), w(1) { } + Quat(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) { } + explicit Quat(const Quat::OtherFloatType> &src) + : x((T)src.x), y((T)src.y), z((T)src.z), w((T)src.w) + { + // NOTE: Converting a normalized Quat to Quat + // will generally result in an un-normalized quaternion. + // But we don't normalize here in case the quaternion + // being converted is not a normalized rotation quaternion. + } + + typedef typename CompatibleTypes >::Type CompatibleType; + + // C-interop support. + Quat(const CompatibleType& s) : x(s.x), y(s.y), z(s.z), w(s.w) { } + + operator CompatibleType () const + { + CompatibleType result; + result.x = x; + result.y = y; + result.z = z; + result.w = w; + return result; + } + + // Constructs quaternion for rotation around the axis by an angle. + Quat(const Vector3& axis, T angle) + { + // Make sure we don't divide by zero. + if (axis.LengthSq() == T(0)) + { + // Assert if the axis is zero, but the angle isn't + OVR_MATH_ASSERT(angle == T(0)); + x = y = z = T(0); w = T(1); + return; + } + + Vector3 unitAxis = axis.Normalized(); + T sinHalfAngle = sin(angle * T(0.5)); + + w = cos(angle * T(0.5)); + x = unitAxis.x * sinHalfAngle; + y = unitAxis.y * sinHalfAngle; + z = unitAxis.z * sinHalfAngle; + } + + // Constructs quaternion for rotation around one of the coordinate axis by an angle. + Quat(Axis A, T angle, RotateDirection d = Rotate_CCW, HandedSystem s = Handed_R) + { + T sinHalfAngle = s * d *sin(angle * T(0.5)); + T v[3]; + v[0] = v[1] = v[2] = T(0); + v[A] = sinHalfAngle; + + w = cos(angle * T(0.5)); + x = v[0]; + y = v[1]; + z = v[2]; + } + + Quat operator-() { return Quat(-x, -y, -z, -w); } // unary minus + + static Quat Identity() { return Quat(0, 0, 0, 1); } + + // Compute axis and angle from quaternion + void GetAxisAngle(Vector3* axis, T* angle) const + { + if ( x*x + y*y + z*z > Math::Tolerance() * Math::Tolerance() ) { + *axis = Vector3(x, y, z).Normalized(); + *angle = 2 * Acos(w); + if (*angle > ((T)MATH_DOUBLE_PI)) // Reduce the magnitude of the angle, if necessary + { + *angle = ((T)MATH_DOUBLE_TWOPI) - *angle; + *axis = *axis * (-1); + } + } + else + { + *axis = Vector3(1, 0, 0); + *angle= T(0); + } + } + + // Convert a quaternion to a rotation vector, also known as + // Rodrigues vector, AxisAngle vector, SORA vector, exponential map. + // A rotation vector describes a rotation about an axis: + // the axis of rotation is the vector normalized, + // the angle of rotation is the magnitude of the vector. + Vector3 ToRotationVector() const + { + OVR_MATH_ASSERT(IsNormalized() || LengthSq() == 0); + T s = T(0); + T sinHalfAngle = sqrt(x*x + y*y + z*z); + if (sinHalfAngle > T(0)) + { + T cosHalfAngle = w; + T halfAngle = atan2(sinHalfAngle, cosHalfAngle); + + // Ensure minimum rotation magnitude + if (cosHalfAngle < 0) + halfAngle -= T(MATH_DOUBLE_PI); + + s = T(2) * halfAngle / sinHalfAngle; + } + return Vector3(x*s, y*s, z*s); + } + + // Faster version of the above, optimized for use with small rotations, where rotation angle ~= sin(angle) + inline OVR::Vector3 FastToRotationVector() const + { + OVR_MATH_ASSERT(IsNormalized()); + T s; + T sinHalfSquared = x*x + y*y + z*z; + if (sinHalfSquared < T(.0037)) // =~ sin(7/2 degrees)^2 + { + // Max rotation magnitude error is about .062% at 7 degrees rotation, or about .0043 degrees + s = T(2) * Sign(w); + } + else + { + T sinHalfAngle = sqrt(sinHalfSquared); + T cosHalfAngle = w; + T halfAngle = atan2(sinHalfAngle, cosHalfAngle); + + // Ensure minimum rotation magnitude + if (cosHalfAngle < 0) + halfAngle -= T(MATH_DOUBLE_PI); + + s = T(2) * halfAngle / sinHalfAngle; + } + return Vector3(x*s, y*s, z*s); + } + + // Given a rotation vector of form unitRotationAxis * angle, + // returns the equivalent quaternion (unitRotationAxis * sin(angle), cos(Angle)). + static Quat FromRotationVector(const Vector3& v) + { + T angleSquared = v.LengthSq(); + T s = T(0); + T c = T(1); + if (angleSquared > T(0)) + { + T angle = sqrt(angleSquared); + s = sin(angle * T(0.5)) / angle; // normalize + c = cos(angle * T(0.5)); + } + return Quat(s*v.x, s*v.y, s*v.z, c); + } + + // Faster version of above, optimized for use with small rotation magnitudes, where rotation angle =~ sin(angle). + // If normalize is false, small-angle quaternions are returned un-normalized. + inline static Quat FastFromRotationVector(const OVR::Vector3& v, bool normalize = true) + { + T s, c; + T angleSquared = v.LengthSq(); + if (angleSquared < T(0.0076)) // =~ (5 degrees*pi/180)^2 + { + s = T(0.5); + c = T(1.0); + // Max rotation magnitude error (after normalization) is about .064% at 5 degrees rotation, or .0032 degrees + if (normalize && angleSquared > 0) + { + // sin(angle/2)^2 ~= (angle/2)^2 and cos(angle/2)^2 ~= 1 + T invLen = T(1) / sqrt(angleSquared * T(0.25) + T(1)); // normalize + s = s * invLen; + c = c * invLen; + } + } + else + { + T angle = sqrt(angleSquared); + s = sin(angle * T(0.5)) / angle; + c = cos(angle * T(0.5)); + } + return Quat(s*v.x, s*v.y, s*v.z, c); + } + + // Constructs the quaternion from a rotation matrix + explicit Quat(const Matrix4& m) + { + T trace = m.M[0][0] + m.M[1][1] + m.M[2][2]; + + // In almost all cases, the first part is executed. + // However, if the trace is not positive, the other + // cases arise. + if (trace > T(0)) + { + T s = sqrt(trace + T(1)) * T(2); // s=4*qw + w = T(0.25) * s; + x = (m.M[2][1] - m.M[1][2]) / s; + y = (m.M[0][2] - m.M[2][0]) / s; + z = (m.M[1][0] - m.M[0][1]) / s; + } + else if ((m.M[0][0] > m.M[1][1])&&(m.M[0][0] > m.M[2][2])) + { + T s = sqrt(T(1) + m.M[0][0] - m.M[1][1] - m.M[2][2]) * T(2); + w = (m.M[2][1] - m.M[1][2]) / s; + x = T(0.25) * s; + y = (m.M[0][1] + m.M[1][0]) / s; + z = (m.M[2][0] + m.M[0][2]) / s; + } + else if (m.M[1][1] > m.M[2][2]) + { + T s = sqrt(T(1) + m.M[1][1] - m.M[0][0] - m.M[2][2]) * T(2); // S=4*qy + w = (m.M[0][2] - m.M[2][0]) / s; + x = (m.M[0][1] + m.M[1][0]) / s; + y = T(0.25) * s; + z = (m.M[1][2] + m.M[2][1]) / s; + } + else + { + T s = sqrt(T(1) + m.M[2][2] - m.M[0][0] - m.M[1][1]) * T(2); // S=4*qz + w = (m.M[1][0] - m.M[0][1]) / s; + x = (m.M[0][2] + m.M[2][0]) / s; + y = (m.M[1][2] + m.M[2][1]) / s; + z = T(0.25) * s; + } + OVR_MATH_ASSERT(IsNormalized()); // Ensure input matrix is orthogonal + } + + // Constructs the quaternion from a rotation matrix + explicit Quat(const Matrix3& m) + { + T trace = m.M[0][0] + m.M[1][1] + m.M[2][2]; + + // In almost all cases, the first part is executed. + // However, if the trace is not positive, the other + // cases arise. + if (trace > T(0)) + { + T s = sqrt(trace + T(1)) * T(2); // s=4*qw + w = T(0.25) * s; + x = (m.M[2][1] - m.M[1][2]) / s; + y = (m.M[0][2] - m.M[2][0]) / s; + z = (m.M[1][0] - m.M[0][1]) / s; + } + else if ((m.M[0][0] > m.M[1][1])&&(m.M[0][0] > m.M[2][2])) + { + T s = sqrt(T(1) + m.M[0][0] - m.M[1][1] - m.M[2][2]) * T(2); + w = (m.M[2][1] - m.M[1][2]) / s; + x = T(0.25) * s; + y = (m.M[0][1] + m.M[1][0]) / s; + z = (m.M[2][0] + m.M[0][2]) / s; + } + else if (m.M[1][1] > m.M[2][2]) + { + T s = sqrt(T(1) + m.M[1][1] - m.M[0][0] - m.M[2][2]) * T(2); // S=4*qy + w = (m.M[0][2] - m.M[2][0]) / s; + x = (m.M[0][1] + m.M[1][0]) / s; + y = T(0.25) * s; + z = (m.M[1][2] + m.M[2][1]) / s; + } + else + { + T s = sqrt(T(1) + m.M[2][2] - m.M[0][0] - m.M[1][1]) * T(2); // S=4*qz + w = (m.M[1][0] - m.M[0][1]) / s; + x = (m.M[0][2] + m.M[2][0]) / s; + y = (m.M[1][2] + m.M[2][1]) / s; + z = T(0.25) * s; + } + OVR_MATH_ASSERT(IsNormalized()); // Ensure input matrix is orthogonal + } + + bool operator== (const Quat& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; } + bool operator!= (const Quat& b) const { return x != b.x || y != b.y || z != b.z || w != b.w; } + + Quat operator+ (const Quat& b) const { return Quat(x + b.x, y + b.y, z + b.z, w + b.w); } + Quat& operator+= (const Quat& b) { w += b.w; x += b.x; y += b.y; z += b.z; return *this; } + Quat operator- (const Quat& b) const { return Quat(x - b.x, y - b.y, z - b.z, w - b.w); } + Quat& operator-= (const Quat& b) { w -= b.w; x -= b.x; y -= b.y; z -= b.z; return *this; } + + Quat operator* (T s) const { return Quat(x * s, y * s, z * s, w * s); } + Quat& operator*= (T s) { w *= s; x *= s; y *= s; z *= s; return *this; } + Quat operator/ (T s) const { T rcp = T(1)/s; return Quat(x * rcp, y * rcp, z * rcp, w *rcp); } + Quat& operator/= (T s) { T rcp = T(1)/s; w *= rcp; x *= rcp; y *= rcp; z *= rcp; return *this; } + + // Compare two quats for equality within tolerance. Returns true if quats match withing tolerance. + bool IsEqual(const Quat& b, T tolerance = Math::Tolerance()) const + { + return Abs(Dot(b)) >= T(1) - tolerance; + } + + static T Abs(const T v) { return (v >= 0) ? v : -v; } + + // Get Imaginary part vector + Vector3 Imag() const { return Vector3(x,y,z); } + + // Get quaternion length. + T Length() const { return sqrt(LengthSq()); } + + // Get quaternion length squared. + T LengthSq() const { return (x * x + y * y + z * z + w * w); } + + // Simple Euclidean distance in R^4 (not SLERP distance, but at least respects Haar measure) + T Distance(const Quat& q) const + { + T d1 = (*this - q).Length(); + T d2 = (*this + q).Length(); // Antipodal point check + return (d1 < d2) ? d1 : d2; + } + + T DistanceSq(const Quat& q) const + { + T d1 = (*this - q).LengthSq(); + T d2 = (*this + q).LengthSq(); // Antipodal point check + return (d1 < d2) ? d1 : d2; + } + + T Dot(const Quat& q) const + { + return x * q.x + y * q.y + z * q.z + w * q.w; + } + + // Angle between two quaternions in radians + T Angle(const Quat& q) const + { + return T(2) * Acos(Abs(Dot(q))); + } + + // Angle of quaternion + T Angle() const + { + return T(2) * Acos(Abs(w)); + } + + // Normalize + bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math::Tolerance(); } + + void Normalize() + { + T s = Length(); + if (s != T(0)) + s = T(1) / s; + *this *= s; + } + + Quat Normalized() const + { + T s = Length(); + if (s != T(0)) + s = T(1) / s; + return *this * s; + } + + inline void EnsureSameHemisphere(const Quat& o) + { + if (Dot(o) < T(0)) + { + x = -x; + y = -y; + z = -z; + w = -w; + } + } + + // Returns conjugate of the quaternion. Produces inverse rotation if quaternion is normalized. + Quat Conj() const { return Quat(-x, -y, -z, w); } + + // Quaternion multiplication. Combines quaternion rotations, performing the one on the + // right hand side first. + Quat operator* (const Quat& b) const { return Quat(w * b.x + x * b.w + y * b.z - z * b.y, + w * b.y - x * b.z + y * b.w + z * b.x, + w * b.z + x * b.y - y * b.x + z * b.w, + w * b.w - x * b.x - y * b.y - z * b.z); } + const Quat& operator*= (const Quat& b) { *this = *this * b; return *this; } + + // + // this^p normalized; same as rotating by this p times. + Quat PowNormalized(T p) const + { + Vector3 v; + T a; + GetAxisAngle(&v, &a); + return Quat(v, a * p); + } + + // Compute quaternion that rotates v into alignTo: alignTo = Quat::Align(alignTo, v).Rotate(v). + // NOTE: alignTo and v must be normalized. + static Quat Align(const Vector3& alignTo, const Vector3& v) + { + OVR_MATH_ASSERT(alignTo.IsNormalized() && v.IsNormalized()); + Vector3 bisector = (v + alignTo); + bisector.Normalize(); + T cosHalfAngle = v.Dot(bisector); // 0..1 + if (cosHalfAngle > T(0)) + { + Vector3 imag = v.Cross(bisector); + return Quat(imag.x, imag.y, imag.z, cosHalfAngle); + } + else + { + // cosHalfAngle == 0: a 180 degree rotation. + // sinHalfAngle == 1, rotation axis is any axis perpendicular + // to alignTo. Choose axis to include largest magnitude components + if (fabs(v.x) > fabs(v.y)) + { + // x or z is max magnitude component + // = Cross(v, (0,1,0)).Normalized(); + T invLen = sqrt(v.x*v.x + v.z*v.z); + if (invLen > T(0)) + invLen = T(1) / invLen; + return Quat(-v.z*invLen, 0, v.x*invLen, 0); + } + else + { + // y or z is max magnitude component + // = Cross(v, (1,0,0)).Normalized(); + T invLen = sqrt(v.y*v.y + v.z*v.z); + if (invLen > T(0)) + invLen = T(1) / invLen; + return Quat(0, v.z*invLen, -v.y*invLen, 0); + } + } + } + + // Normalized linear interpolation of quaternions + // NOTE: This function is a bad approximation of Slerp() + // when the angle between the *this and b is large. + // Use FastSlerp() or Slerp() instead. + Quat Lerp(const Quat& b, T s) const + { + return (*this * (T(1) - s) + b * (Dot(b) < 0 ? -s : s)).Normalized(); + } + + // Spherical linear interpolation between rotations + Quat Slerp(const Quat& b, T s) const + { + Vector3 delta = (b * this->Inverted()).ToRotationVector(); + return FromRotationVector(delta * s) * *this; + } + + // Spherical linear interpolation: much faster for small rotations, accurate for large rotations. See FastTo/FromRotationVector + Quat FastSlerp(const Quat& b, T s) const + { + Vector3 delta = (b * this->Inverted()).FastToRotationVector(); + return (FastFromRotationVector(delta * s, false) * *this).Normalized(); + } + + // Rotate transforms vector in a manner that matches Matrix rotations (counter-clockwise, + // assuming negative direction of the axis). Standard formula: q(t) * V * q(t)^-1. + Vector3 Rotate(const Vector3& v) const + { + OVR_MATH_ASSERT(isnan(w) || IsNormalized()); + + // rv = q * (v,0) * q' + // Same as rv = v + real * cross(imag,v)*2 + cross(imag, cross(imag,v)*2); + + // uv = 2 * Imag().Cross(v); + T uvx = T(2) * (y*v.z - z*v.y); + T uvy = T(2) * (z*v.x - x*v.z); + T uvz = T(2) * (x*v.y - y*v.x); + + // return v + Real()*uv + Imag().Cross(uv); + return Vector3(v.x + w*uvx + y*uvz - z*uvy, + v.y + w*uvy + z*uvx - x*uvz, + v.z + w*uvz + x*uvy - y*uvx); + } + + // Rotation by inverse of *this + Vector3 InverseRotate(const Vector3& v) const + { + OVR_MATH_ASSERT(IsNormalized()); + + // rv = q' * (v,0) * q + // Same as rv = v + real * cross(-imag,v)*2 + cross(-imag, cross(-imag,v)*2); + // or rv = v - real * cross(imag,v)*2 + cross(imag, cross(imag,v)*2); + + // uv = 2 * Imag().Cross(v); + T uvx = T(2) * (y*v.z - z*v.y); + T uvy = T(2) * (z*v.x - x*v.z); + T uvz = T(2) * (x*v.y - y*v.x); + + // return v - Real()*uv + Imag().Cross(uv); + return Vector3(v.x - w*uvx + y*uvz - z*uvy, + v.y - w*uvy + z*uvx - x*uvz, + v.z - w*uvz + x*uvy - y*uvx); + } + + // Inversed quaternion rotates in the opposite direction. + Quat Inverted() const + { + return Quat(-x, -y, -z, w); + } + + Quat Inverse() const + { + return Quat(-x, -y, -z, w); + } + + // Sets this quaternion to the one rotates in the opposite direction. + void Invert() + { + *this = Quat(-x, -y, -z, w); + } + + // Time integration of constant angular velocity over dt + Quat TimeIntegrate(Vector3 angularVelocity, T dt) const + { + // solution is: this * exp( omega*dt/2 ); FromRotationVector(v) gives exp(v*.5). + return (*this * FastFromRotationVector(angularVelocity * dt, false)).Normalized(); + } + + // Time integration of constant angular acceleration and velocity over dt + // These are the first two terms of the "Magnus expansion" of the solution + // + // o = o * exp( W=(W1 + W2 + W3+...) * 0.5 ); + // + // omega1 = (omega + omegaDot*dt) + // W1 = (omega + omega1)*dt/2 + // W2 = cross(omega, omega1)/12*dt^2 % (= -cross(omega_dot, omega)/12*dt^3) + // Terms 3 and beyond are vanishingly small: + // W3 = cross(omega_dot, cross(omega_dot, omega))/240*dt^5 + // + Quat TimeIntegrate(Vector3 angularVelocity, Vector3 angularAcceleration, T dt) const + { + const Vector3& omega = angularVelocity; + const Vector3& omegaDot = angularAcceleration; + + Vector3 omega1 = (omega + omegaDot * dt); + Vector3 W = ( (omega + omega1) + omega.Cross(omega1) * (dt/T(6)) ) * (dt/T(2)); + + // FromRotationVector(v) is exp(v*.5) + return (*this * FastFromRotationVector(W, false)).Normalized(); + } + + // Decompose rotation into three rotations: + // roll radians about Z axis, then pitch radians about X axis, then yaw radians about Y axis. + // Call with nullptr if a return value is not needed. + void GetYawPitchRoll(T* yaw, T* pitch, T* roll) const + { + return GetEulerAngles(yaw, pitch, roll); + } + + // GetEulerAngles extracts Euler angles from the quaternion, in the specified order of + // axis rotations and the specified coordinate system. Right-handed coordinate system + // is the default, with CCW rotations while looking in the negative axis direction. + // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned. + // Rotation order is c, b, a: + // rotation c around axis A3 + // is followed by rotation b around axis A2 + // is followed by rotation a around axis A1 + // rotations are CCW or CW (D) in LH or RH coordinate system (S) + // + template + void GetEulerAngles(T *a, T *b, T *c) const + { + OVR_MATH_ASSERT(IsNormalized()); + OVR_MATH_STATIC_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3), "(A1 != A2) && (A2 != A3) && (A1 != A3)"); + + T Q[3] = { x, y, z }; //Quaternion components x,y,z + + T ww = w*w; + T Q11 = Q[A1]*Q[A1]; + T Q22 = Q[A2]*Q[A2]; + T Q33 = Q[A3]*Q[A3]; + + T psign = T(-1); + // Determine whether even permutation + if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) + psign = T(1); + + T s2 = psign * T(2) * (psign*w*Q[A2] + Q[A1]*Q[A3]); + + T singularityRadius = Math::SingularityRadius(); + if (s2 < T(-1) + singularityRadius) + { // South pole singularity + if (a) *a = T(0); + if (b) *b = -S*D*((T)MATH_DOUBLE_PIOVER2); + if (c) *c = S*D*atan2(T(2)*(psign*Q[A1] * Q[A2] + w*Q[A3]), ww + Q22 - Q11 - Q33 ); + } + else if (s2 > T(1) - singularityRadius) + { // North pole singularity + if (a) *a = T(0); + if (b) *b = S*D*((T)MATH_DOUBLE_PIOVER2); + if (c) *c = S*D*atan2(T(2)*(psign*Q[A1] * Q[A2] + w*Q[A3]), ww + Q22 - Q11 - Q33); + } + else + { + if (a) *a = -S*D*atan2(T(-2)*(w*Q[A1] - psign*Q[A2] * Q[A3]), ww + Q33 - Q11 - Q22); + if (b) *b = S*D*asin(s2); + if (c) *c = S*D*atan2(T(2)*(w*Q[A3] - psign*Q[A1] * Q[A2]), ww + Q11 - Q22 - Q33); + } + } + + template + void GetEulerAngles(T *a, T *b, T *c) const + { GetEulerAngles(a, b, c); } + + template + void GetEulerAngles(T *a, T *b, T *c) const + { GetEulerAngles(a, b, c); } + + // GetEulerAnglesABA extracts Euler angles from the quaternion, in the specified order of + // axis rotations and the specified coordinate system. Right-handed coordinate system + // is the default, with CCW rotations while looking in the negative axis direction. + // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned. + // rotation a around axis A1 + // is followed by rotation b around axis A2 + // is followed by rotation c around axis A1 + // Rotations are CCW or CW (D) in LH or RH coordinate system (S) + template + void GetEulerAnglesABA(T *a, T *b, T *c) const + { + OVR_MATH_ASSERT(IsNormalized()); + OVR_MATH_STATIC_ASSERT(A1 != A2, "A1 != A2"); + + T Q[3] = {x, y, z}; // Quaternion components + + // Determine the missing axis that was not supplied + int m = 3 - A1 - A2; + + T ww = w*w; + T Q11 = Q[A1]*Q[A1]; + T Q22 = Q[A2]*Q[A2]; + T Qmm = Q[m]*Q[m]; + + T psign = T(-1); + if ((A1 + 1) % 3 == A2) // Determine whether even permutation + { + psign = T(1); + } + + T c2 = ww + Q11 - Q22 - Qmm; + T singularityRadius = Math::SingularityRadius(); + if (c2 < T(-1) + singularityRadius) + { // South pole singularity + if (a) *a = T(0); + if (b) *b = S*D*((T)MATH_DOUBLE_PI); + if (c) *c = S*D*atan2(T(2)*(w*Q[A1] - psign*Q[A2] * Q[m]), + ww + Q22 - Q11 - Qmm); + } + else if (c2 > T(1) - singularityRadius) + { // North pole singularity + if (a) *a = T(0); + if (b) *b = T(0); + if (c) *c = S*D*atan2(T(2)*(w*Q[A1] - psign*Q[A2] * Q[m]), + ww + Q22 - Q11 - Qmm); + } + else + { + if (a) *a = S*D*atan2(psign*w*Q[m] + Q[A1] * Q[A2], + w*Q[A2] -psign*Q[A1]*Q[m]); + if (b) *b = S*D*acos(c2); + if (c) *c = S*D*atan2(-psign*w*Q[m] + Q[A1] * Q[A2], + w*Q[A2] + psign*Q[A1]*Q[m]); + } + } +}; + +typedef Quat Quatf; +typedef Quat Quatd; + +OVR_MATH_STATIC_ASSERT((sizeof(Quatf) == 4*sizeof(float)), "sizeof(Quatf) failure"); +OVR_MATH_STATIC_ASSERT((sizeof(Quatd) == 4*sizeof(double)), "sizeof(Quatd) failure"); + +//------------------------------------------------------------------------------------- +// ***** Pose +// +// Position and orientation combined. +// +// This structure needs to be the same size and layout on 32-bit and 64-bit arch. +// Update OVR_PadCheck.cpp when updating this object. +template +class Pose +{ +public: + typedef typename CompatibleTypes >::Type CompatibleType; + + Pose() { } + Pose(const Quat& orientation, const Vector3& pos) + : Rotation(orientation), Translation(pos) { } + Pose(const Pose& s) + : Rotation(s.Rotation), Translation(s.Translation) { } + Pose(const Matrix3& R, const Vector3& t) + : Rotation((Quat)R), Translation(t) { } + Pose(const CompatibleType& s) + : Rotation(s.Orientation), Translation(s.Position) { } + + explicit Pose(const Pose::OtherFloatType> &s) + : Rotation(s.Rotation), Translation(s.Translation) + { + // Ensure normalized rotation if converting from float to double + if (sizeof(T) > sizeof(typename Math::OtherFloatType)) + Rotation.Normalize(); + } + + static Pose Identity() { return Pose(Quat(0, 0, 0, 1), Vector3(0, 0, 0)); } + + void SetIdentity() { Rotation = Quat(0, 0, 0, 1); Translation = Vector3(0, 0, 0); } + + // used to make things obviously broken if someone tries to use the value + void SetInvalid() { Rotation = Quat(NAN, NAN, NAN, NAN); Translation = Vector3(NAN, NAN, NAN); } + + bool IsEqual(const Pose&b, T tolerance = Math::Tolerance()) const + { + return Translation.IsEqual(b.Translation, tolerance) && Rotation.IsEqual(b.Rotation, tolerance); + } + + operator typename CompatibleTypes >::Type () const + { + typename CompatibleTypes >::Type result; + result.Orientation = Rotation; + result.Position = Translation; + return result; + } + + Quat Rotation; + Vector3 Translation; + + OVR_MATH_STATIC_ASSERT((sizeof(T) == sizeof(double) || sizeof(T) == sizeof(float)), "(sizeof(T) == sizeof(double) || sizeof(T) == sizeof(float))"); + + void ToArray(T* arr) const + { + T temp[7] = { Rotation.x, Rotation.y, Rotation.z, Rotation.w, Translation.x, Translation.y, Translation.z }; + for (int i = 0; i < 7; i++) arr[i] = temp[i]; + } + + static Pose FromArray(const T* v) + { + Quat rotation(v[0], v[1], v[2], v[3]); + Vector3 translation(v[4], v[5], v[6]); + // Ensure rotation is normalized, in case it was originally a float, stored in a .json file, etc. + return Pose(rotation.Normalized(), translation); + } + + Vector3 Rotate(const Vector3& v) const + { + return Rotation.Rotate(v); + } + + Vector3 InverseRotate(const Vector3& v) const + { + return Rotation.InverseRotate(v); + } + + Vector3 Translate(const Vector3& v) const + { + return v + Translation; + } + + Vector3 Transform(const Vector3& v) const + { + return Rotate(v) + Translation; + } + + Vector3 InverseTransform(const Vector3& v) const + { + return InverseRotate(v - Translation); + } + + + Vector3 Apply(const Vector3& v) const + { + return Transform(v); + } + + Pose operator*(const Pose& other) const + { + return Pose(Rotation * other.Rotation, Apply(other.Translation)); + } + + Pose Inverted() const + { + Quat inv = Rotation.Inverted(); + return Pose(inv, inv.Rotate(-Translation)); + } + + // Interpolation between two poses: translation is interpolated with Lerp(), + // and rotations are interpolated with Slerp(). + Pose Lerp(const Pose& b, T s) + { + return Pose(Rotation.Slerp(b.Rotation, s), Translation.Lerp(b.Translation, s)); + } + + // Similar to Lerp above, except faster in case of small rotation differences. See Quat::FastSlerp. + Pose FastLerp(const Pose& b, T s) + { + return Pose(Rotation.FastSlerp(b.Rotation, s), Translation.Lerp(b.Translation, s)); + } + + Pose TimeIntegrate(const Vector3& linearVelocity, const Vector3& angularVelocity, T dt) const + { + return Pose( + (Rotation * Quat::FastFromRotationVector(angularVelocity * dt, false)).Normalized(), + Translation + linearVelocity * dt); + } + + Pose TimeIntegrate(const Vector3& linearVelocity, const Vector3& linearAcceleration, + const Vector3& angularVelocity, const Vector3& angularAcceleration, + T dt) const + { + return Pose(Rotation.TimeIntegrate(angularVelocity, angularAcceleration, dt), + Translation + linearVelocity*dt + linearAcceleration*dt*dt * T(0.5)); + } +}; + +typedef Pose Posef; +typedef Pose Posed; + +OVR_MATH_STATIC_ASSERT((sizeof(Posed) == sizeof(Quatd) + sizeof(Vector3d)), "sizeof(Posed) failure"); +OVR_MATH_STATIC_ASSERT((sizeof(Posef) == sizeof(Quatf) + sizeof(Vector3f)), "sizeof(Posef) failure"); + + +//------------------------------------------------------------------------------------- +// ***** Matrix4 +// +// Matrix4 is a 4x4 matrix used for 3d transformations and projections. +// Translation stored in the last column. +// The matrix is stored in row-major order in memory, meaning that values +// of the first row are stored before the next one. +// +// The arrangement of the matrix is chosen to be in Right-Handed +// coordinate system and counterclockwise rotations when looking down +// the axis +// +// Transformation Order: +// - Transformations are applied from right to left, so the expression +// M1 * M2 * M3 * V means that the vector V is transformed by M3 first, +// followed by M2 and M1. +// +// Coordinate system: Right Handed +// +// Rotations: Counterclockwise when looking down the axis. All angles are in radians. +// +// | sx 01 02 tx | // First column (sx, 10, 20): Axis X basis vector. +// | 10 sy 12 ty | // Second column (01, sy, 21): Axis Y basis vector. +// | 20 21 sz tz | // Third columnt (02, 12, sz): Axis Z basis vector. +// | 30 31 32 33 | +// +// The basis vectors are first three columns. + +template +class Matrix4 +{ +public: + typedef T ElementType; + static const size_t Dimension = 4; + + T M[4][4]; + + enum NoInitType { NoInit }; + + // Construct with no memory initialization. + Matrix4(NoInitType) { } + + // By default, we construct identity matrix. + Matrix4() + { + M[0][0] = M[1][1] = M[2][2] = M[3][3] = T(1); + M[0][1] = M[1][0] = M[2][3] = M[3][1] = T(0); + M[0][2] = M[1][2] = M[2][0] = M[3][2] = T(0); + M[0][3] = M[1][3] = M[2][1] = M[3][0] = T(0); + } + + Matrix4(T m11, T m12, T m13, T m14, + T m21, T m22, T m23, T m24, + T m31, T m32, T m33, T m34, + T m41, T m42, T m43, T m44) + { + M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = m14; + M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = m24; + M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = m34; + M[3][0] = m41; M[3][1] = m42; M[3][2] = m43; M[3][3] = m44; + } + + Matrix4(T m11, T m12, T m13, + T m21, T m22, T m23, + T m31, T m32, T m33) + { + M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = T(0); + M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = T(0); + M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = T(0); + M[3][0] = T(0); M[3][1] = T(0); M[3][2] = T(0); M[3][3] = T(1); + } + + explicit Matrix4(const Matrix3& m) + { + M[0][0] = m.M[0][0]; M[0][1] = m.M[0][1]; M[0][2] = m.M[0][2]; M[0][3] = T(0); + M[1][0] = m.M[1][0]; M[1][1] = m.M[1][1]; M[1][2] = m.M[1][2]; M[1][3] = T(0); + M[2][0] = m.M[2][0]; M[2][1] = m.M[2][1]; M[2][2] = m.M[2][2]; M[2][3] = T(0); + M[3][0] = T(0); M[3][1] = T(0); M[3][2] = T(0); M[3][3] = T(1); + } + + explicit Matrix4(const Quat& q) + { + OVR_MATH_ASSERT(q.IsNormalized()); + T ww = q.w*q.w; + T xx = q.x*q.x; + T yy = q.y*q.y; + T zz = q.z*q.z; + + M[0][0] = ww + xx - yy - zz; M[0][1] = 2 * (q.x*q.y - q.w*q.z); M[0][2] = 2 * (q.x*q.z + q.w*q.y); M[0][3] = T(0); + M[1][0] = 2 * (q.x*q.y + q.w*q.z); M[1][1] = ww - xx + yy - zz; M[1][2] = 2 * (q.y*q.z - q.w*q.x); M[1][3] = T(0); + M[2][0] = 2 * (q.x*q.z - q.w*q.y); M[2][1] = 2 * (q.y*q.z + q.w*q.x); M[2][2] = ww - xx - yy + zz; M[2][3] = T(0); + M[3][0] = T(0); M[3][1] = T(0); M[3][2] = T(0); M[3][3] = T(1); + } + + explicit Matrix4(const Pose& p) + { + Matrix4 result(p.Rotation); + result.SetTranslation(p.Translation); + *this = result; + } + + + // C-interop support + explicit Matrix4(const Matrix4::OtherFloatType> &src) + { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + M[i][j] = (T)src.M[i][j]; + } + + // C-interop support. + Matrix4(const typename CompatibleTypes >::Type& s) + { + OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix4), "sizeof(s) == sizeof(Matrix4)"); + memcpy(M, s.M, sizeof(M)); + } + + operator typename CompatibleTypes >::Type () const + { + typename CompatibleTypes >::Type result; + OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix4), "sizeof(result) == sizeof(Matrix4)"); + memcpy(result.M, M, sizeof(M)); + return result; + } + + void ToString(char* dest, size_t destsize) const + { + size_t pos = 0; + for (int r=0; r<4; r++) + { + for (int c=0; c<4; c++) + { + pos += OVRMath_sprintf(dest+pos, destsize-pos, "%g ", M[r][c]); + } + } + } + + static Matrix4 FromString(const char* src) + { + Matrix4 result; + if (src) + { + for (int r = 0; r < 4; r++) + { + for (int c = 0; c < 4; c++) + { + result.M[r][c] = (T)atof(src); + while (*src && *src != ' ') + { + src++; + } + while (*src && *src == ' ') + { + src++; + } + } + } + } + return result; + } + + static Matrix4 Identity() { return Matrix4(); } + + void SetIdentity() + { + M[0][0] = M[1][1] = M[2][2] = M[3][3] = T(1); + M[0][1] = M[1][0] = M[2][3] = M[3][1] = T(0); + M[0][2] = M[1][2] = M[2][0] = M[3][2] = T(0); + M[0][3] = M[1][3] = M[2][1] = M[3][0] = T(0); + } + + void SetXBasis(const Vector3& v) + { + M[0][0] = v.x; + M[1][0] = v.y; + M[2][0] = v.z; + } + Vector3 GetXBasis() const + { + return Vector3(M[0][0], M[1][0], M[2][0]); + } + + void SetYBasis(const Vector3 & v) + { + M[0][1] = v.x; + M[1][1] = v.y; + M[2][1] = v.z; + } + Vector3 GetYBasis() const + { + return Vector3(M[0][1], M[1][1], M[2][1]); + } + + void SetZBasis(const Vector3 & v) + { + M[0][2] = v.x; + M[1][2] = v.y; + M[2][2] = v.z; + } + Vector3 GetZBasis() const + { + return Vector3(M[0][2], M[1][2], M[2][2]); + } + + bool operator== (const Matrix4& b) const + { + bool isEqual = true; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + isEqual &= (M[i][j] == b.M[i][j]); + + return isEqual; + } + + Matrix4 operator+ (const Matrix4& b) const + { + Matrix4 result(*this); + result += b; + return result; + } + + Matrix4& operator+= (const Matrix4& b) + { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + M[i][j] += b.M[i][j]; + return *this; + } + + Matrix4 operator- (const Matrix4& b) const + { + Matrix4 result(*this); + result -= b; + return result; + } + + Matrix4& operator-= (const Matrix4& b) + { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + M[i][j] -= b.M[i][j]; + return *this; + } + + // Multiplies two matrices into destination with minimum copying. + static Matrix4& Multiply(Matrix4* d, const Matrix4& a, const Matrix4& b) + { + OVR_MATH_ASSERT((d != &a) && (d != &b)); + int i = 0; + do { + d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0] + a.M[i][3] * b.M[3][0]; + d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1] + a.M[i][3] * b.M[3][1]; + d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2] + a.M[i][3] * b.M[3][2]; + d->M[i][3] = a.M[i][0] * b.M[0][3] + a.M[i][1] * b.M[1][3] + a.M[i][2] * b.M[2][3] + a.M[i][3] * b.M[3][3]; + } while((++i) < 4); + + return *d; + } + + Matrix4 operator* (const Matrix4& b) const + { + Matrix4 result(Matrix4::NoInit); + Multiply(&result, *this, b); + return result; + } + + Matrix4& operator*= (const Matrix4& b) + { + return Multiply(this, Matrix4(*this), b); + } + + Matrix4 operator* (T s) const + { + Matrix4 result(*this); + result *= s; + return result; + } + + Matrix4& operator*= (T s) + { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + M[i][j] *= s; + return *this; + } + + + Matrix4 operator/ (T s) const + { + Matrix4 result(*this); + result /= s; + return result; + } + + Matrix4& operator/= (T s) + { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + M[i][j] /= s; + return *this; + } + + Vector3 Transform(const Vector3& v) const + { + const T rcpW = T(1) / (M[3][0] * v.x + M[3][1] * v.y + M[3][2] * v.z + M[3][3]); + return Vector3((M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3]) * rcpW, + (M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3]) * rcpW, + (M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3]) * rcpW); + } + + Vector4 Transform(const Vector4& v) const + { + return Vector4(M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3] * v.w, + M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3] * v.w, + M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3] * v.w, + M[3][0] * v.x + M[3][1] * v.y + M[3][2] * v.z + M[3][3] * v.w); + } + + Matrix4 Transposed() const + { + return Matrix4(M[0][0], M[1][0], M[2][0], M[3][0], + M[0][1], M[1][1], M[2][1], M[3][1], + M[0][2], M[1][2], M[2][2], M[3][2], + M[0][3], M[1][3], M[2][3], M[3][3]); + } + + void Transpose() + { + *this = Transposed(); + } + + + T SubDet (const size_t* rows, const size_t* cols) const + { + return M[rows[0]][cols[0]] * (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]]) + - M[rows[0]][cols[1]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]]) + + M[rows[0]][cols[2]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]); + } + + T Cofactor(size_t I, size_t J) const + { + const size_t indices[4][3] = {{1,2,3},{0,2,3},{0,1,3},{0,1,2}}; + return ((I+J)&1) ? -SubDet(indices[I],indices[J]) : SubDet(indices[I],indices[J]); + } + + T Determinant() const + { + return M[0][0] * Cofactor(0,0) + M[0][1] * Cofactor(0,1) + M[0][2] * Cofactor(0,2) + M[0][3] * Cofactor(0,3); + } + + Matrix4 Adjugated() const + { + return Matrix4(Cofactor(0,0), Cofactor(1,0), Cofactor(2,0), Cofactor(3,0), + Cofactor(0,1), Cofactor(1,1), Cofactor(2,1), Cofactor(3,1), + Cofactor(0,2), Cofactor(1,2), Cofactor(2,2), Cofactor(3,2), + Cofactor(0,3), Cofactor(1,3), Cofactor(2,3), Cofactor(3,3)); + } + + Matrix4 Inverted() const + { + T det = Determinant(); + OVR_MATH_ASSERT(det != 0); + return Adjugated() * (T(1)/det); + } + + void Invert() + { + *this = Inverted(); + } + + // This is more efficient than general inverse, but ONLY works + // correctly if it is a homogeneous transform matrix (rot + trans) + Matrix4 InvertedHomogeneousTransform() const + { + // Make the inverse rotation matrix + Matrix4 rinv = this->Transposed(); + rinv.M[3][0] = rinv.M[3][1] = rinv.M[3][2] = T(0); + // Make the inverse translation matrix + Vector3 tvinv(-M[0][3],-M[1][3],-M[2][3]); + Matrix4 tinv = Matrix4::Translation(tvinv); + return rinv * tinv; // "untranslate", then "unrotate" + } + + // This is more efficient than general inverse, but ONLY works + // correctly if it is a homogeneous transform matrix (rot + trans) + void InvertHomogeneousTransform() + { + *this = InvertedHomogeneousTransform(); + } + + // Matrix to Euler Angles conversion + // a,b,c, are the YawPitchRoll angles to be returned + // rotation a around axis A1 + // is followed by rotation b around axis A2 + // is followed by rotation c around axis A3 + // rotations are CCW or CW (D) in LH or RH coordinate system (S) + template + void ToEulerAngles(T *a, T *b, T *c) const + { + OVR_MATH_STATIC_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3), "(A1 != A2) && (A2 != A3) && (A1 != A3)"); + + T psign = T(-1); + if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) // Determine whether even permutation + psign = T(1); + + T pm = psign*M[A1][A3]; + T singularityRadius = Math::SingularityRadius(); + if (pm < T(-1) + singularityRadius) + { // South pole singularity + *a = T(0); + *b = -S*D*((T)MATH_DOUBLE_PIOVER2); + *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] ); + } + else if (pm > T(1) - singularityRadius) + { // North pole singularity + *a = T(0); + *b = S*D*((T)MATH_DOUBLE_PIOVER2); + *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] ); + } + else + { // Normal case (nonsingular) + *a = S*D*atan2( -psign*M[A2][A3], M[A3][A3] ); + *b = S*D*asin(pm); + *c = S*D*atan2( -psign*M[A1][A2], M[A1][A1] ); + } + } + + // Matrix to Euler Angles conversion + // a,b,c, are the YawPitchRoll angles to be returned + // rotation a around axis A1 + // is followed by rotation b around axis A2 + // is followed by rotation c around axis A1 + // rotations are CCW or CW (D) in LH or RH coordinate system (S) + template + void ToEulerAnglesABA(T *a, T *b, T *c) const + { + OVR_MATH_STATIC_ASSERT(A1 != A2, "A1 != A2"); + + // Determine the axis that was not supplied + int m = 3 - A1 - A2; + + T psign = T(-1); + if ((A1 + 1) % 3 == A2) // Determine whether even permutation + psign = T(1); + + T c2 = M[A1][A1]; + T singularityRadius = Math::SingularityRadius(); + if (c2 < T(-1) + singularityRadius) + { // South pole singularity + *a = T(0); + *b = S*D*((T)MATH_DOUBLE_PI); + *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]); + } + else if (c2 > T(1) - singularityRadius) + { // North pole singularity + *a = T(0); + *b = T(0); + *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]); + } + else + { // Normal case (nonsingular) + *a = S*D*atan2( M[A2][A1],-psign*M[m][A1]); + *b = S*D*acos(c2); + *c = S*D*atan2( M[A1][A2],psign*M[A1][m]); + } + } + + // Creates a matrix that converts the vertices from one coordinate system + // to another. + static Matrix4 AxisConversion(const WorldAxes& to, const WorldAxes& from) + { + // Holds axis values from the 'to' structure + int toArray[3] = { to.XAxis, to.YAxis, to.ZAxis }; + + // The inverse of the toArray + int inv[4]; + inv[0] = inv[abs(to.XAxis)] = 0; + inv[abs(to.YAxis)] = 1; + inv[abs(to.ZAxis)] = 2; + + Matrix4 m(0, 0, 0, + 0, 0, 0, + 0, 0, 0); + + // Only three values in the matrix need to be changed to 1 or -1. + m.M[inv[abs(from.XAxis)]][0] = T(from.XAxis/toArray[inv[abs(from.XAxis)]]); + m.M[inv[abs(from.YAxis)]][1] = T(from.YAxis/toArray[inv[abs(from.YAxis)]]); + m.M[inv[abs(from.ZAxis)]][2] = T(from.ZAxis/toArray[inv[abs(from.ZAxis)]]); + return m; + } + + + // Creates a matrix for translation by vector + static Matrix4 Translation(const Vector3& v) + { + Matrix4 t; + t.M[0][3] = v.x; + t.M[1][3] = v.y; + t.M[2][3] = v.z; + return t; + } + + // Creates a matrix for translation by vector + static Matrix4 Translation(T x, T y, T z = T(0)) + { + Matrix4 t; + t.M[0][3] = x; + t.M[1][3] = y; + t.M[2][3] = z; + return t; + } + + // Sets the translation part + void SetTranslation(const Vector3& v) + { + M[0][3] = v.x; + M[1][3] = v.y; + M[2][3] = v.z; + } + + Vector3 GetTranslation() const + { + return Vector3( M[0][3], M[1][3], M[2][3] ); + } + + // Creates a matrix for scaling by vector + static Matrix4 Scaling(const Vector3& v) + { + Matrix4 t; + t.M[0][0] = v.x; + t.M[1][1] = v.y; + t.M[2][2] = v.z; + return t; + } + + // Creates a matrix for scaling by vector + static Matrix4 Scaling(T x, T y, T z) + { + Matrix4 t; + t.M[0][0] = x; + t.M[1][1] = y; + t.M[2][2] = z; + return t; + } + + // Creates a matrix for scaling by constant + static Matrix4 Scaling(T s) + { + Matrix4 t; + t.M[0][0] = s; + t.M[1][1] = s; + t.M[2][2] = s; + return t; + } + + // Simple L1 distance in R^12 + T Distance(const Matrix4& m2) const + { + T d = fabs(M[0][0] - m2.M[0][0]) + fabs(M[0][1] - m2.M[0][1]); + d += fabs(M[0][2] - m2.M[0][2]) + fabs(M[0][3] - m2.M[0][3]); + d += fabs(M[1][0] - m2.M[1][0]) + fabs(M[1][1] - m2.M[1][1]); + d += fabs(M[1][2] - m2.M[1][2]) + fabs(M[1][3] - m2.M[1][3]); + d += fabs(M[2][0] - m2.M[2][0]) + fabs(M[2][1] - m2.M[2][1]); + d += fabs(M[2][2] - m2.M[2][2]) + fabs(M[2][3] - m2.M[2][3]); + d += fabs(M[3][0] - m2.M[3][0]) + fabs(M[3][1] - m2.M[3][1]); + d += fabs(M[3][2] - m2.M[3][2]) + fabs(M[3][3] - m2.M[3][3]); + return d; + } + + // Creates a rotation matrix rotating around the X axis by 'angle' radians. + // Just for quick testing. Not for final API. Need to remove case. + static Matrix4 RotationAxis(Axis A, T angle, RotateDirection d, HandedSystem s) + { + T sina = s * d *sin(angle); + T cosa = cos(angle); + + switch(A) + { + case Axis_X: + return Matrix4(1, 0, 0, + 0, cosa, -sina, + 0, sina, cosa); + case Axis_Y: + return Matrix4(cosa, 0, sina, + 0, 1, 0, + -sina, 0, cosa); + case Axis_Z: + return Matrix4(cosa, -sina, 0, + sina, cosa, 0, + 0, 0, 1); + default: + return Matrix4(); + } + } + + + // Creates a rotation matrix rotating around the X axis by 'angle' radians. + // Rotation direction is depends on the coordinate system: + // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW), + // while looking in the negative axis direction. This is the + // same as looking down from positive axis values towards origin. + // LHS: Positive angle values rotate clock-wise (CW), while looking in the + // negative axis direction. + static Matrix4 RotationX(T angle) + { + T sina = sin(angle); + T cosa = cos(angle); + return Matrix4(1, 0, 0, + 0, cosa, -sina, + 0, sina, cosa); + } + + // Creates a rotation matrix rotating around the Y axis by 'angle' radians. + // Rotation direction is depends on the coordinate system: + // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW), + // while looking in the negative axis direction. This is the + // same as looking down from positive axis values towards origin. + // LHS: Positive angle values rotate clock-wise (CW), while looking in the + // negative axis direction. + static Matrix4 RotationY(T angle) + { + T sina = (T)sin(angle); + T cosa = (T)cos(angle); + return Matrix4(cosa, 0, sina, + 0, 1, 0, + -sina, 0, cosa); + } + + // Creates a rotation matrix rotating around the Z axis by 'angle' radians. + // Rotation direction is depends on the coordinate system: + // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW), + // while looking in the negative axis direction. This is the + // same as looking down from positive axis values towards origin. + // LHS: Positive angle values rotate clock-wise (CW), while looking in the + // negative axis direction. + static Matrix4 RotationZ(T angle) + { + T sina = sin(angle); + T cosa = cos(angle); + return Matrix4(cosa, -sina, 0, + sina, cosa, 0, + 0, 0, 1); + } + + // LookAtRH creates a View transformation matrix for right-handed coordinate system. + // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up' + // specifying the up vector. The resulting matrix should be used with PerspectiveRH + // projection. + static Matrix4 LookAtRH(const Vector3& eye, const Vector3& at, const Vector3& up) + { + Vector3 z = (eye - at).Normalized(); // Forward + Vector3 x = up.Cross(z).Normalized(); // Right + Vector3 y = z.Cross(x); + + Matrix4 m(x.x, x.y, x.z, -(x.Dot(eye)), + y.x, y.y, y.z, -(y.Dot(eye)), + z.x, z.y, z.z, -(z.Dot(eye)), + 0, 0, 0, 1 ); + return m; + } + + // LookAtLH creates a View transformation matrix for left-handed coordinate system. + // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up' + // specifying the up vector. + static Matrix4 LookAtLH(const Vector3& eye, const Vector3& at, const Vector3& up) + { + Vector3 z = (at - eye).Normalized(); // Forward + Vector3 x = up.Cross(z).Normalized(); // Right + Vector3 y = z.Cross(x); + + Matrix4 m(x.x, x.y, x.z, -(x.Dot(eye)), + y.x, y.y, y.z, -(y.Dot(eye)), + z.x, z.y, z.z, -(z.Dot(eye)), + 0, 0, 0, 1 ); + return m; + } + + // PerspectiveRH creates a right-handed perspective projection matrix that can be + // used with the Oculus sample renderer. + // yfov - Specifies vertical field of view in radians. + // aspect - Screen aspect ration, which is usually width/height for square pixels. + // Note that xfov = yfov * aspect. + // znear - Absolute value of near Z clipping clipping range. + // zfar - Absolute value of far Z clipping clipping range (larger then near). + // Even though RHS usually looks in the direction of negative Z, positive values + // are expected for znear and zfar. + static Matrix4 PerspectiveRH(T yfov, T aspect, T znear, T zfar) + { + Matrix4 m; + T tanHalfFov = tan(yfov * T(0.5)); + + m.M[0][0] = T(1) / (aspect * tanHalfFov); + m.M[1][1] = T(1) / tanHalfFov; + m.M[2][2] = zfar / (znear - zfar); + m.M[3][2] = T(-1); + m.M[2][3] = (zfar * znear) / (znear - zfar); + m.M[3][3] = T(0); + + // Note: Post-projection matrix result assumes Left-Handed coordinate system, + // with Y up, X right and Z forward. This supports positive z-buffer values. + // This is the case even for RHS coordinate input. + return m; + } + + // PerspectiveLH creates a left-handed perspective projection matrix that can be + // used with the Oculus sample renderer. + // yfov - Specifies vertical field of view in radians. + // aspect - Screen aspect ration, which is usually width/height for square pixels. + // Note that xfov = yfov * aspect. + // znear - Absolute value of near Z clipping clipping range. + // zfar - Absolute value of far Z clipping clipping range (larger then near). + static Matrix4 PerspectiveLH(T yfov, T aspect, T znear, T zfar) + { + Matrix4 m; + T tanHalfFov = tan(yfov * T(0.5)); + + m.M[0][0] = T(1) / (aspect * tanHalfFov); + m.M[1][1] = T(1) / tanHalfFov; + //m.M[2][2] = zfar / (znear - zfar); + m.M[2][2] = zfar / (zfar - znear); + m.M[3][2] = T(-1); + m.M[2][3] = (zfar * znear) / (znear - zfar); + m.M[3][3] = T(0); + + // Note: Post-projection matrix result assumes Left-Handed coordinate system, + // with Y up, X right and Z forward. This supports positive z-buffer values. + // This is the case even for RHS coordinate input. + return m; + } + + static Matrix4 Ortho2D(T w, T h) + { + Matrix4 m; + m.M[0][0] = T(2.0)/w; + m.M[1][1] = T(-2.0)/h; + m.M[0][3] = T(-1.0); + m.M[1][3] = T(1.0); + m.M[2][2] = T(0); + return m; + } +}; + +typedef Matrix4 Matrix4f; +typedef Matrix4 Matrix4d; + +//------------------------------------------------------------------------------------- +// ***** Matrix3 +// +// Matrix3 is a 3x3 matrix used for representing a rotation matrix. +// The matrix is stored in row-major order in memory, meaning that values +// of the first row are stored before the next one. +// +// The arrangement of the matrix is chosen to be in Right-Handed +// coordinate system and counterclockwise rotations when looking down +// the axis +// +// Transformation Order: +// - Transformations are applied from right to left, so the expression +// M1 * M2 * M3 * V means that the vector V is transformed by M3 first, +// followed by M2 and M1. +// +// Coordinate system: Right Handed +// +// Rotations: Counterclockwise when looking down the axis. All angles are in radians. + +template +class Matrix3 +{ +public: + typedef T ElementType; + static const size_t Dimension = 3; + + T M[3][3]; + + enum NoInitType { NoInit }; + + // Construct with no memory initialization. + Matrix3(NoInitType) { } + + // By default, we construct identity matrix. + Matrix3() + { + M[0][0] = M[1][1] = M[2][2] = T(1); + M[0][1] = M[1][0] = M[2][0] = T(0); + M[0][2] = M[1][2] = M[2][1] = T(0); + } + + Matrix3(T m11, T m12, T m13, + T m21, T m22, T m23, + T m31, T m32, T m33) + { + M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; + M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; + M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; + } + + // Construction from X, Y, Z basis vectors + Matrix3(const Vector3& xBasis, const Vector3& yBasis, const Vector3& zBasis) + { + M[0][0] = xBasis.x; M[0][1] = yBasis.x; M[0][2] = zBasis.x; + M[1][0] = xBasis.y; M[1][1] = yBasis.y; M[1][2] = zBasis.y; + M[2][0] = xBasis.z; M[2][1] = yBasis.z; M[2][2] = zBasis.z; + } + + explicit Matrix3(const Quat& q) + { + OVR_MATH_ASSERT(q.IsNormalized()); + const T tx = q.x+q.x, ty = q.y+q.y, tz = q.z+q.z; + const T twx = q.w*tx, twy = q.w*ty, twz = q.w*tz; + const T txx = q.x*tx, txy = q.x*ty, txz = q.x*tz; + const T tyy = q.y*ty, tyz = q.y*tz, tzz = q.z*tz; + M[0][0] = T(1) - (tyy + tzz); M[0][1] = txy - twz; M[0][2] = txz + twy; + M[1][0] = txy + twz; M[1][1] = T(1) - (txx + tzz); M[1][2] = tyz - twx; + M[2][0] = txz - twy; M[2][1] = tyz + twx; M[2][2] = T(1) - (txx + tyy); + } + + inline explicit Matrix3(T s) + { + M[0][0] = M[1][1] = M[2][2] = s; + M[0][1] = M[0][2] = M[1][0] = M[1][2] = M[2][0] = M[2][1] = T(0); + } + + Matrix3(T m11, T m22, T m33) + { + M[0][0] = m11; M[0][1] = T(0); M[0][2] = T(0); + M[1][0] = T(0); M[1][1] = m22; M[1][2] = T(0); + M[2][0] = T(0); M[2][1] = T(0); M[2][2] = m33; + } + + explicit Matrix3(const Matrix3::OtherFloatType> &src) + { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + M[i][j] = (T)src.M[i][j]; + } + + // C-interop support. + Matrix3(const typename CompatibleTypes >::Type& s) + { + OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix3), "sizeof(s) == sizeof(Matrix3)"); + memcpy(M, s.M, sizeof(M)); + } + + operator const typename CompatibleTypes >::Type () const + { + typename CompatibleTypes >::Type result; + OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix3), "sizeof(result) == sizeof(Matrix3)"); + memcpy(result.M, M, sizeof(M)); + return result; + } + + T operator()(int i, int j) const { return M[i][j]; } + T& operator()(int i, int j) { return M[i][j]; } + + void ToString(char* dest, size_t destsize) const + { + size_t pos = 0; + for (int r=0; r<3; r++) + { + for (int c=0; c<3; c++) + pos += OVRMath_sprintf(dest+pos, destsize-pos, "%g ", M[r][c]); + } + } + + static Matrix3 FromString(const char* src) + { + Matrix3 result; + if (src) + { + for (int r=0; r<3; r++) + { + for (int c=0; c<3; c++) + { + result.M[r][c] = (T)atof(src); + while (*src && *src != ' ') + src++; + while (*src && *src == ' ') + src++; + } + } + } + return result; + } + + static Matrix3 Identity() { return Matrix3(); } + + void SetIdentity() + { + M[0][0] = M[1][1] = M[2][2] = T(1); + M[0][1] = M[1][0] = M[2][0] = T(0); + M[0][2] = M[1][2] = M[2][1] = T(0); + } + + static Matrix3 Diagonal(T m00, T m11, T m22) + { + return Matrix3(m00, 0, 0, + 0, m11, 0, + 0, 0, m22); + } + static Matrix3 Diagonal(const Vector3& v) { return Diagonal(v.x, v.y, v.z); } + + T Trace() const { return M[0][0] + M[1][1] + M[2][2]; } + + bool operator== (const Matrix3& b) const + { + bool isEqual = true; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + isEqual &= (M[i][j] == b.M[i][j]); + } + + return isEqual; + } + + Matrix3 operator+ (const Matrix3& b) const + { + Matrix3 result(*this); + result += b; + return result; + } + + Matrix3& operator+= (const Matrix3& b) + { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + M[i][j] += b.M[i][j]; + return *this; + } + + void operator= (const Matrix3& b) + { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + M[i][j] = b.M[i][j]; + } + + Matrix3 operator- (const Matrix3& b) const + { + Matrix3 result(*this); + result -= b; + return result; + } + + Matrix3& operator-= (const Matrix3& b) + { + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + M[i][j] -= b.M[i][j]; + } + + return *this; + } + + // Multiplies two matrices into destination with minimum copying. + static Matrix3& Multiply(Matrix3* d, const Matrix3& a, const Matrix3& b) + { + OVR_MATH_ASSERT((d != &a) && (d != &b)); + int i = 0; + do { + d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0]; + d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1]; + d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2]; + } while((++i) < 3); + + return *d; + } + + Matrix3 operator* (const Matrix3& b) const + { + Matrix3 result(Matrix3::NoInit); + Multiply(&result, *this, b); + return result; + } + + Matrix3& operator*= (const Matrix3& b) + { + return Multiply(this, Matrix3(*this), b); + } + + Matrix3 operator* (T s) const + { + Matrix3 result(*this); + result *= s; + return result; + } + + Matrix3& operator*= (T s) + { + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + M[i][j] *= s; + } + + return *this; + } + + Vector3 operator* (const Vector3 &b) const + { + Vector3 result; + result.x = M[0][0]*b.x + M[0][1]*b.y + M[0][2]*b.z; + result.y = M[1][0]*b.x + M[1][1]*b.y + M[1][2]*b.z; + result.z = M[2][0]*b.x + M[2][1]*b.y + M[2][2]*b.z; + + return result; + } + + Matrix3 operator/ (T s) const + { + Matrix3 result(*this); + result /= s; + return result; + } + + Matrix3& operator/= (T s) + { + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + M[i][j] /= s; + } + + return *this; + } + + Vector2 Transform(const Vector2& v) const + { + const T rcpZ = T(1) / (M[2][0] * v.x + M[2][1] * v.y + M[2][2]); + return Vector2((M[0][0] * v.x + M[0][1] * v.y + M[0][2]) * rcpZ, + (M[1][0] * v.x + M[1][1] * v.y + M[1][2]) * rcpZ); + } + + Vector3 Transform(const Vector3& v) const + { + return Vector3(M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z, + M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z, + M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z); + } + + Matrix3 Transposed() const + { + return Matrix3(M[0][0], M[1][0], M[2][0], + M[0][1], M[1][1], M[2][1], + M[0][2], M[1][2], M[2][2]); + } + + void Transpose() + { + *this = Transposed(); + } + + + T SubDet (const size_t* rows, const size_t* cols) const + { + return M[rows[0]][cols[0]] * (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]]) + - M[rows[0]][cols[1]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]]) + + M[rows[0]][cols[2]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]); + } + + + // M += a*b.t() + inline void Rank1Add(const Vector3 &a, const Vector3 &b) + { + M[0][0] += a.x*b.x; M[0][1] += a.x*b.y; M[0][2] += a.x*b.z; + M[1][0] += a.y*b.x; M[1][1] += a.y*b.y; M[1][2] += a.y*b.z; + M[2][0] += a.z*b.x; M[2][1] += a.z*b.y; M[2][2] += a.z*b.z; + } + + // M -= a*b.t() + inline void Rank1Sub(const Vector3 &a, const Vector3 &b) + { + M[0][0] -= a.x*b.x; M[0][1] -= a.x*b.y; M[0][2] -= a.x*b.z; + M[1][0] -= a.y*b.x; M[1][1] -= a.y*b.y; M[1][2] -= a.y*b.z; + M[2][0] -= a.z*b.x; M[2][1] -= a.z*b.y; M[2][2] -= a.z*b.z; + } + + inline Vector3 Col(int c) const + { + return Vector3(M[0][c], M[1][c], M[2][c]); + } + + inline Vector3 Row(int r) const + { + return Vector3(M[r][0], M[r][1], M[r][2]); + } + + inline Vector3 GetColumn(int c) const + { + return Vector3(M[0][c], M[1][c], M[2][c]); + } + + inline Vector3 GetRow(int r) const + { + return Vector3(M[r][0], M[r][1], M[r][2]); + } + + inline void SetColumn(int c, const Vector3& v) + { + M[0][c] = v.x; + M[1][c] = v.y; + M[2][c] = v.z; + } + + inline void SetRow(int r, const Vector3& v) + { + M[r][0] = v.x; + M[r][1] = v.y; + M[r][2] = v.z; + } + + inline T Determinant() const + { + const Matrix3& m = *this; + T d; + + d = m.M[0][0] * (m.M[1][1]*m.M[2][2] - m.M[1][2] * m.M[2][1]); + d -= m.M[0][1] * (m.M[1][0]*m.M[2][2] - m.M[1][2] * m.M[2][0]); + d += m.M[0][2] * (m.M[1][0]*m.M[2][1] - m.M[1][1] * m.M[2][0]); + + return d; + } + + inline Matrix3 Inverse() const + { + Matrix3 a; + const Matrix3& m = *this; + T d = Determinant(); + + OVR_MATH_ASSERT(d != 0); + T s = T(1)/d; + + a.M[0][0] = s * (m.M[1][1] * m.M[2][2] - m.M[1][2] * m.M[2][1]); + a.M[1][0] = s * (m.M[1][2] * m.M[2][0] - m.M[1][0] * m.M[2][2]); + a.M[2][0] = s * (m.M[1][0] * m.M[2][1] - m.M[1][1] * m.M[2][0]); + + a.M[0][1] = s * (m.M[0][2] * m.M[2][1] - m.M[0][1] * m.M[2][2]); + a.M[1][1] = s * (m.M[0][0] * m.M[2][2] - m.M[0][2] * m.M[2][0]); + a.M[2][1] = s * (m.M[0][1] * m.M[2][0] - m.M[0][0] * m.M[2][1]); + + a.M[0][2] = s * (m.M[0][1] * m.M[1][2] - m.M[0][2] * m.M[1][1]); + a.M[1][2] = s * (m.M[0][2] * m.M[1][0] - m.M[0][0] * m.M[1][2]); + a.M[2][2] = s * (m.M[0][0] * m.M[1][1] - m.M[0][1] * m.M[1][0]); + + return a; + } + + // Outer Product of two column vectors: a * b.Transpose() + static Matrix3 OuterProduct(const Vector3& a, const Vector3& b) + { + return Matrix3(a.x*b.x, a.x*b.y, a.x*b.z, + a.y*b.x, a.y*b.y, a.y*b.z, + a.z*b.x, a.z*b.y, a.z*b.z); + } + + // Vector cross product as a premultiply matrix: + // L.Cross(R) = LeftCrossAsMatrix(L) * R + static Matrix3 LeftCrossAsMatrix(const Vector3& L) + { + return Matrix3( + T(0), -L.z, +L.y, + +L.z, T(0), -L.x, + -L.y, +L.x, T(0)); + } + + // Vector cross product as a premultiply matrix: + // L.Cross(R) = RightCrossAsMatrix(R) * L + static Matrix3 RightCrossAsMatrix(const Vector3& R) + { + return Matrix3( + T(0), +R.z, -R.y, + -R.z, T(0), +R.x, + +R.y, -R.x, T(0)); + } + + // Angle in radians of a rotation matrix + // Uses identity trace(a) = 2*cos(theta) + 1 + T Angle() const + { + return Acos((Trace() - T(1)) * T(0.5)); + } + + // Angle in radians between two rotation matrices + T Angle(const Matrix3& b) const + { + // Compute trace of (this->Transposed() * b) + // This works out to sum of products of elements. + T trace = T(0); + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + trace += M[i][j] * b.M[i][j]; + } + } + return Acos((trace - T(1)) * T(0.5)); + } +}; + +typedef Matrix3 Matrix3f; +typedef Matrix3 Matrix3d; + +//------------------------------------------------------------------------------------- +// ***** Matrix2 + +template +class Matrix2 +{ +public: + typedef T ElementType; + static const size_t Dimension = 2; + + T M[2][2]; + + enum NoInitType { NoInit }; + + // Construct with no memory initialization. + Matrix2(NoInitType) { } + + // By default, we construct identity matrix. + Matrix2() + { + M[0][0] = M[1][1] = T(1); + M[0][1] = M[1][0] = T(0); + } + + Matrix2(T m11, T m12, + T m21, T m22) + { + M[0][0] = m11; M[0][1] = m12; + M[1][0] = m21; M[1][1] = m22; + } + + // Construction from X, Y basis vectors + Matrix2(const Vector2& xBasis, const Vector2& yBasis) + { + M[0][0] = xBasis.x; M[0][1] = yBasis.x; + M[1][0] = xBasis.y; M[1][1] = yBasis.y; + } + + explicit Matrix2(T s) + { + M[0][0] = M[1][1] = s; + M[0][1] = M[1][0] = T(0); + } + + Matrix2(T m11, T m22) + { + M[0][0] = m11; M[0][1] = T(0); + M[1][0] = T(0); M[1][1] = m22; + } + + explicit Matrix2(const Matrix2::OtherFloatType> &src) + { + M[0][0] = T(src.M[0][0]); M[0][1] = T(src.M[0][1]); + M[1][0] = T(src.M[1][0]); M[1][1] = T(src.M[1][1]); + } + + // C-interop support + Matrix2(const typename CompatibleTypes >::Type& s) + { + OVR_MATH_STATIC_ASSERT(sizeof(s) == sizeof(Matrix2), "sizeof(s) == sizeof(Matrix2)"); + memcpy(M, s.M, sizeof(M)); + } + + operator const typename CompatibleTypes >::Type() const + { + typename CompatibleTypes >::Type result; + OVR_MATH_STATIC_ASSERT(sizeof(result) == sizeof(Matrix2), "sizeof(result) == sizeof(Matrix2)"); + memcpy(result.M, M, sizeof(M)); + return result; + } + + T operator()(int i, int j) const { return M[i][j]; } + T& operator()(int i, int j) { return M[i][j]; } + const T* operator[](int i) const { return M[i]; } + T* operator[](int i) { return M[i]; } + + static Matrix2 Identity() { return Matrix2(); } + + void SetIdentity() + { + M[0][0] = M[1][1] = T(1); + M[0][1] = M[1][0] = T(0); + } + + static Matrix2 Diagonal(T m00, T m11) + { + return Matrix2(m00, m11); + } + static Matrix2 Diagonal(const Vector2& v) { return Matrix2(v.x, v.y); } + + T Trace() const { return M[0][0] + M[1][1]; } + + bool operator== (const Matrix2& b) const + { + return M[0][0] == b.M[0][0] && M[0][1] == b.M[0][1] && + M[1][0] == b.M[1][0] && M[1][1] == b.M[1][1]; + } + + Matrix2 operator+ (const Matrix2& b) const + { + return Matrix2(M[0][0] + b.M[0][0], M[0][1] + b.M[0][1], + M[1][0] + b.M[1][0], M[1][1] + b.M[1][1]); + } + + Matrix2& operator+= (const Matrix2& b) + { + M[0][0] += b.M[0][0]; M[0][1] += b.M[0][1]; + M[1][0] += b.M[1][0]; M[1][1] += b.M[1][1]; + return *this; + } + + void operator= (const Matrix2& b) + { + M[0][0] = b.M[0][0]; M[0][1] = b.M[0][1]; + M[1][0] = b.M[1][0]; M[1][1] = b.M[1][1]; + } + + Matrix2 operator- (const Matrix2& b) const + { + return Matrix2(M[0][0] - b.M[0][0], M[0][1] - b.M[0][1], + M[1][0] - b.M[1][0], M[1][1] - b.M[1][1]); + } + + Matrix2& operator-= (const Matrix2& b) + { + M[0][0] -= b.M[0][0]; M[0][1] -= b.M[0][1]; + M[1][0] -= b.M[1][0]; M[1][1] -= b.M[1][1]; + return *this; + } + + Matrix2 operator* (const Matrix2& b) const + { + return Matrix2(M[0][0] * b.M[0][0] + M[0][1] * b.M[1][0], M[0][0] * b.M[0][1] + M[0][1] * b.M[1][1], + M[1][0] * b.M[0][0] + M[1][1] * b.M[1][0], M[1][0] * b.M[0][1] + M[1][1] * b.M[1][1]); + } + + Matrix2& operator*= (const Matrix2& b) + { + *this = *this * b; + return *this; + } + + Matrix2 operator* (T s) const + { + return Matrix2(M[0][0] * s, M[0][1] * s, + M[1][0] * s, M[1][1] * s); + } + + Matrix2& operator*= (T s) + { + M[0][0] *= s; M[0][1] *= s; + M[1][0] *= s; M[1][1] *= s; + return *this; + } + + Matrix2 operator/ (T s) const + { + return *this * (T(1) / s); + } + + Matrix2& operator/= (T s) + { + return *this *= (T(1) / s); + } + + Vector2 operator* (const Vector2 &b) const + { + return Vector2(M[0][0] * b.x + M[0][1] * b.y, + M[1][0] * b.x + M[1][1] * b.y); + } + + Vector2 Transform(const Vector2& v) const + { + return Vector2(M[0][0] * v.x + M[0][1] * v.y, + M[1][0] * v.x + M[1][1] * v.y); + } + + Matrix2 Transposed() const + { + return Matrix2(M[0][0], M[1][0], + M[0][1], M[1][1]); + } + + void Transpose() + { + OVRMath_Swap(M[1][0], M[0][1]); + } + + Vector2 GetColumn(int c) const + { + return Vector2(M[0][c], M[1][c]); + } + + Vector2 GetRow(int r) const + { + return Vector2(M[r][0], M[r][1]); + } + + void SetColumn(int c, const Vector2& v) + { + M[0][c] = v.x; + M[1][c] = v.y; + } + + void SetRow(int r, const Vector2& v) + { + M[r][0] = v.x; + M[r][1] = v.y; + } + + T Determinant() const + { + return M[0][0] * M[1][1] - M[0][1] * M[1][0]; + } + + Matrix2 Inverse() const + { + T rcpDet = T(1) / Determinant(); + return Matrix2( M[1][1] * rcpDet, -M[0][1] * rcpDet, + -M[1][0] * rcpDet, M[0][0] * rcpDet); + } + + // Outer Product of two column vectors: a * b.Transpose() + static Matrix2 OuterProduct(const Vector2& a, const Vector2& b) + { + return Matrix2(a.x*b.x, a.x*b.y, + a.y*b.x, a.y*b.y); + } + + // Angle in radians between two rotation matrices + T Angle(const Matrix2& b) const + { + const Matrix2& a = *this; + return Acos(a(0, 0)*b(0, 0) + a(1, 0)*b(1, 0)); + } +}; + +typedef Matrix2 Matrix2f; +typedef Matrix2 Matrix2d; + +//------------------------------------------------------------------------------------- + +template +class SymMat3 +{ +private: + typedef SymMat3 this_type; + +public: + typedef T Value_t; + // Upper symmetric + T v[6]; // _00 _01 _02 _11 _12 _22 + + inline SymMat3() {} + + inline explicit SymMat3(T s) + { + v[0] = v[3] = v[5] = s; + v[1] = v[2] = v[4] = T(0); + } + + inline explicit SymMat3(T a00, T a01, T a02, T a11, T a12, T a22) + { + v[0] = a00; v[1] = a01; v[2] = a02; + v[3] = a11; v[4] = a12; + v[5] = a22; + } + + // Cast to symmetric Matrix3 + operator Matrix3() const + { + return Matrix3(v[0], v[1], v[2], + v[1], v[3], v[4], + v[2], v[4], v[5]); + } + + static inline int Index(unsigned int i, unsigned int j) + { + return (i <= j) ? (3*i - i*(i+1)/2 + j) : (3*j - j*(j+1)/2 + i); + } + + inline T operator()(int i, int j) const { return v[Index(i,j)]; } + + inline T &operator()(int i, int j) { return v[Index(i,j)]; } + + inline this_type& operator+=(const this_type& b) + { + v[0]+=b.v[0]; + v[1]+=b.v[1]; + v[2]+=b.v[2]; + v[3]+=b.v[3]; + v[4]+=b.v[4]; + v[5]+=b.v[5]; + return *this; + } + + inline this_type& operator-=(const this_type& b) + { + v[0]-=b.v[0]; + v[1]-=b.v[1]; + v[2]-=b.v[2]; + v[3]-=b.v[3]; + v[4]-=b.v[4]; + v[5]-=b.v[5]; + + return *this; + } + + inline this_type& operator*=(T s) + { + v[0]*=s; + v[1]*=s; + v[2]*=s; + v[3]*=s; + v[4]*=s; + v[5]*=s; + + return *this; + } + + inline SymMat3 operator*(T s) const + { + SymMat3 d; + d.v[0] = v[0]*s; + d.v[1] = v[1]*s; + d.v[2] = v[2]*s; + d.v[3] = v[3]*s; + d.v[4] = v[4]*s; + d.v[5] = v[5]*s; + + return d; + } + + // Multiplies two matrices into destination with minimum copying. + static SymMat3& Multiply(SymMat3* d, const SymMat3& a, const SymMat3& b) + { + // _00 _01 _02 _11 _12 _22 + + d->v[0] = a.v[0] * b.v[0]; + d->v[1] = a.v[0] * b.v[1] + a.v[1] * b.v[3]; + d->v[2] = a.v[0] * b.v[2] + a.v[1] * b.v[4]; + + d->v[3] = a.v[3] * b.v[3]; + d->v[4] = a.v[3] * b.v[4] + a.v[4] * b.v[5]; + + d->v[5] = a.v[5] * b.v[5]; + + return *d; + } + + inline T Determinant() const + { + const this_type& m = *this; + T d; + + d = m(0,0) * (m(1,1)*m(2,2) - m(1,2) * m(2,1)); + d -= m(0,1) * (m(1,0)*m(2,2) - m(1,2) * m(2,0)); + d += m(0,2) * (m(1,0)*m(2,1) - m(1,1) * m(2,0)); + + return d; + } + + inline this_type Inverse() const + { + this_type a; + const this_type& m = *this; + T d = Determinant(); + + OVR_MATH_ASSERT(d != 0); + T s = T(1)/d; + + a(0,0) = s * (m(1,1) * m(2,2) - m(1,2) * m(2,1)); + + a(0,1) = s * (m(0,2) * m(2,1) - m(0,1) * m(2,2)); + a(1,1) = s * (m(0,0) * m(2,2) - m(0,2) * m(2,0)); + + a(0,2) = s * (m(0,1) * m(1,2) - m(0,2) * m(1,1)); + a(1,2) = s * (m(0,2) * m(1,0) - m(0,0) * m(1,2)); + a(2,2) = s * (m(0,0) * m(1,1) - m(0,1) * m(1,0)); + + return a; + } + + inline T Trace() const { return v[0] + v[3] + v[5]; } + + // M = a*a.t() + inline void Rank1(const Vector3 &a) + { + v[0] = a.x*a.x; v[1] = a.x*a.y; v[2] = a.x*a.z; + v[3] = a.y*a.y; v[4] = a.y*a.z; + v[5] = a.z*a.z; + } + + // M += a*a.t() + inline void Rank1Add(const Vector3 &a) + { + v[0] += a.x*a.x; v[1] += a.x*a.y; v[2] += a.x*a.z; + v[3] += a.y*a.y; v[4] += a.y*a.z; + v[5] += a.z*a.z; + } + + // M -= a*a.t() + inline void Rank1Sub(const Vector3 &a) + { + v[0] -= a.x*a.x; v[1] -= a.x*a.y; v[2] -= a.x*a.z; + v[3] -= a.y*a.y; v[4] -= a.y*a.z; + v[5] -= a.z*a.z; + } +}; + +typedef SymMat3 SymMat3f; +typedef SymMat3 SymMat3d; + +template +inline Matrix3 operator*(const SymMat3& a, const SymMat3& b) +{ + #define AJB_ARBC(r,c) (a(r,0)*b(0,c)+a(r,1)*b(1,c)+a(r,2)*b(2,c)) + return Matrix3( + AJB_ARBC(0,0), AJB_ARBC(0,1), AJB_ARBC(0,2), + AJB_ARBC(1,0), AJB_ARBC(1,1), AJB_ARBC(1,2), + AJB_ARBC(2,0), AJB_ARBC(2,1), AJB_ARBC(2,2)); + #undef AJB_ARBC +} + +template +inline Matrix3 operator*(const Matrix3& a, const SymMat3& b) +{ + #define AJB_ARBC(r,c) (a(r,0)*b(0,c)+a(r,1)*b(1,c)+a(r,2)*b(2,c)) + return Matrix3( + AJB_ARBC(0,0), AJB_ARBC(0,1), AJB_ARBC(0,2), + AJB_ARBC(1,0), AJB_ARBC(1,1), AJB_ARBC(1,2), + AJB_ARBC(2,0), AJB_ARBC(2,1), AJB_ARBC(2,2)); + #undef AJB_ARBC +} + +//------------------------------------------------------------------------------------- +// ***** Angle + +// Cleanly representing the algebra of 2D rotations. +// The operations maintain the angle between -Pi and Pi, the same range as atan2. + +template +class Angle +{ +public: + enum AngularUnits + { + Radians = 0, + Degrees = 1 + }; + + Angle() : a(0) {} + + // Fix the range to be between -Pi and Pi + Angle(T a_, AngularUnits u = Radians) : a((u == Radians) ? a_ : a_*((T)MATH_DOUBLE_DEGREETORADFACTOR)) { FixRange(); } + + T Get(AngularUnits u = Radians) const { return (u == Radians) ? a : a*((T)MATH_DOUBLE_RADTODEGREEFACTOR); } + void Set(const T& x, AngularUnits u = Radians) { a = (u == Radians) ? x : x*((T)MATH_DOUBLE_DEGREETORADFACTOR); FixRange(); } + int Sign() const { if (a == 0) return 0; else return (a > 0) ? 1 : -1; } + T Abs() const { return (a >= 0) ? a : -a; } + + bool operator== (const Angle& b) const { return a == b.a; } + bool operator!= (const Angle& b) const { return a != b.a; } +// bool operator< (const Angle& b) const { return a < a.b; } +// bool operator> (const Angle& b) const { return a > a.b; } +// bool operator<= (const Angle& b) const { return a <= a.b; } +// bool operator>= (const Angle& b) const { return a >= a.b; } +// bool operator= (const T& x) { a = x; FixRange(); } + + // These operations assume a is already between -Pi and Pi. + Angle& operator+= (const Angle& b) { a = a + b.a; FastFixRange(); return *this; } + Angle& operator+= (const T& x) { a = a + x; FixRange(); return *this; } + Angle operator+ (const Angle& b) const { Angle res = *this; res += b; return res; } + Angle operator+ (const T& x) const { Angle res = *this; res += x; return res; } + Angle& operator-= (const Angle& b) { a = a - b.a; FastFixRange(); return *this; } + Angle& operator-= (const T& x) { a = a - x; FixRange(); return *this; } + Angle operator- (const Angle& b) const { Angle res = *this; res -= b; return res; } + Angle operator- (const T& x) const { Angle res = *this; res -= x; return res; } + + T Distance(const Angle& b) { T c = fabs(a - b.a); return (c <= ((T)MATH_DOUBLE_PI)) ? c : ((T)MATH_DOUBLE_TWOPI) - c; } + +private: + + // The stored angle, which should be maintained between -Pi and Pi + T a; + + // Fixes the angle range to [-Pi,Pi], but assumes no more than 2Pi away on either side + inline void FastFixRange() + { + if (a < -((T)MATH_DOUBLE_PI)) + a += ((T)MATH_DOUBLE_TWOPI); + else if (a > ((T)MATH_DOUBLE_PI)) + a -= ((T)MATH_DOUBLE_TWOPI); + } + + // Fixes the angle range to [-Pi,Pi] for any given range, but slower then the fast method + inline void FixRange() + { + // do nothing if the value is already in the correct range, since fmod call is expensive + if (a >= -((T)MATH_DOUBLE_PI) && a <= ((T)MATH_DOUBLE_PI)) + return; + a = fmod(a,((T)MATH_DOUBLE_TWOPI)); + if (a < -((T)MATH_DOUBLE_PI)) + a += ((T)MATH_DOUBLE_TWOPI); + else if (a > ((T)MATH_DOUBLE_PI)) + a -= ((T)MATH_DOUBLE_TWOPI); + } +}; + + +typedef Angle Anglef; +typedef Angle Angled; + + +//------------------------------------------------------------------------------------- +// ***** Plane + +// Consists of a normal vector and distance from the origin where the plane is located. + +template +class Plane +{ +public: + Vector3 N; + T D; + + Plane() : D(0) {} + + // Normals must already be normalized + Plane(const Vector3& n, T d) : N(n), D(d) {} + Plane(T x, T y, T z, T d) : N(x,y,z), D(d) {} + + // construct from a point on the plane and the normal + Plane(const Vector3& p, const Vector3& n) : N(n), D(-(p * n)) {} + + // Find the point to plane distance. The sign indicates what side of the plane the point is on (0 = point on plane). + T TestSide(const Vector3& p) const + { + return (N.Dot(p)) + D; + } + + Plane Flipped() const + { + return Plane(-N, -D); + } + + void Flip() + { + N = -N; + D = -D; + } + + bool operator==(const Plane& rhs) const + { + return (this->D == rhs.D && this->N == rhs.N); + } +}; + +typedef Plane Planef; +typedef Plane Planed; + + + + +//----------------------------------------------------------------------------------- +// ***** ScaleAndOffset2D + +struct ScaleAndOffset2D +{ + Vector2f Scale; + Vector2f Offset; + + ScaleAndOffset2D(float sx = 0.0f, float sy = 0.0f, float ox = 0.0f, float oy = 0.0f) + : Scale(sx, sy), Offset(ox, oy) + { } +}; + + +//----------------------------------------------------------------------------------- +// ***** FovPort + +// FovPort describes Field Of View (FOV) of a viewport. +// This class has values for up, down, left and right, stored in +// tangent of the angle units to simplify calculations. +// +// As an example, for a standard 90 degree vertical FOV, we would +// have: { UpTan = tan(90 degrees / 2), DownTan = tan(90 degrees / 2) }. +// +// CreateFromRadians/Degrees helper functions can be used to +// access FOV in different units. + + +// ***** FovPort + +struct FovPort +{ + float UpTan; + float DownTan; + float LeftTan; + float RightTan; + + FovPort ( float sideTan = 0.0f ) : + UpTan(sideTan), DownTan(sideTan), LeftTan(sideTan), RightTan(sideTan) { } + FovPort ( float u, float d, float l, float r ) : + UpTan(u), DownTan(d), LeftTan(l), RightTan(r) { } + + // C-interop support: FovPort <-> ovrFovPort (implementation in OVR_CAPI.cpp). + FovPort(const ovrFovPort &src) + : UpTan(src.UpTan), DownTan(src.DownTan), LeftTan(src.LeftTan), RightTan(src.RightTan) + { } + + operator ovrFovPort () const + { + ovrFovPort result; + result.LeftTan = LeftTan; + result.RightTan = RightTan; + result.UpTan = UpTan; + result.DownTan = DownTan; + return result; + } + + static FovPort CreateFromRadians(float horizontalFov, float verticalFov) + { + FovPort result; + result.UpTan = tanf ( verticalFov * 0.5f ); + result.DownTan = tanf ( verticalFov * 0.5f ); + result.LeftTan = tanf ( horizontalFov * 0.5f ); + result.RightTan = tanf ( horizontalFov * 0.5f ); + return result; + } + + static FovPort CreateFromDegrees(float horizontalFovDegrees, + float verticalFovDegrees) + { + return CreateFromRadians(DegreeToRad(horizontalFovDegrees), + DegreeToRad(verticalFovDegrees)); + } + + // Get Horizontal/Vertical components of Fov in radians. + float GetVerticalFovRadians() const { return atanf(UpTan) + atanf(DownTan); } + float GetHorizontalFovRadians() const { return atanf(LeftTan) + atanf(RightTan); } + // Get Horizontal/Vertical components of Fov in degrees. + float GetVerticalFovDegrees() const { return RadToDegree(GetVerticalFovRadians()); } + float GetHorizontalFovDegrees() const { return RadToDegree(GetHorizontalFovRadians()); } + + // Compute maximum tangent value among all four sides. + float GetMaxSideTan() const + { + return OVRMath_Max(OVRMath_Max(UpTan, DownTan), OVRMath_Max(LeftTan, RightTan)); + } + + static ScaleAndOffset2D CreateNDCScaleAndOffsetFromFov ( FovPort tanHalfFov ) + { + float projXScale = 2.0f / ( tanHalfFov.LeftTan + tanHalfFov.RightTan ); + float projXOffset = ( tanHalfFov.LeftTan - tanHalfFov.RightTan ) * projXScale * 0.5f; + float projYScale = 2.0f / ( tanHalfFov.UpTan + tanHalfFov.DownTan ); + float projYOffset = ( tanHalfFov.UpTan - tanHalfFov.DownTan ) * projYScale * 0.5f; + + ScaleAndOffset2D result; + result.Scale = Vector2f(projXScale, projYScale); + result.Offset = Vector2f(projXOffset, projYOffset); + // Hey - why is that Y.Offset negated? + // It's because a projection matrix transforms from world coords with Y=up, + // whereas this is from NDC which is Y=down. + + return result; + } + + // Converts Fov Tan angle units to [-1,1] render target NDC space + Vector2f TanAngleToRendertargetNDC(Vector2f const &tanEyeAngle) + { + ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(*this); + return tanEyeAngle * eyeToSourceNDC.Scale + eyeToSourceNDC.Offset; + } + + // Compute per-channel minimum and maximum of Fov. + static FovPort Min(const FovPort& a, const FovPort& b) + { + FovPort fov( OVRMath_Min( a.UpTan , b.UpTan ), + OVRMath_Min( a.DownTan , b.DownTan ), + OVRMath_Min( a.LeftTan , b.LeftTan ), + OVRMath_Min( a.RightTan, b.RightTan ) ); + return fov; + } + + static FovPort Max(const FovPort& a, const FovPort& b) + { + FovPort fov( OVRMath_Max( a.UpTan , b.UpTan ), + OVRMath_Max( a.DownTan , b.DownTan ), + OVRMath_Max( a.LeftTan , b.LeftTan ), + OVRMath_Max( a.RightTan, b.RightTan ) ); + return fov; + } +}; + + +} // Namespace OVR + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +#endif diff --git a/src/external/OculusSDK/LibOVR/Include/Extras/OVR_StereoProjection.h b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_StereoProjection.h new file mode 100644 index 000000000..b4bc3bc77 --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/Extras/OVR_StereoProjection.h @@ -0,0 +1,70 @@ +/************************************************************************************ + +Filename : OVR_StereoProjection.h +Content : Stereo projection functions +Created : November 30, 2013 +Authors : Tom Fosyth + +Copyright : Copyright 2014-2016 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.3 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.3 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +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_StereoProjection_h +#define OVR_StereoProjection_h + + +#include "Extras/OVR_Math.h" + + +namespace OVR { + + +//----------------------------------------------------------------------------------- +// ***** Stereo Enumerations + +// StereoEye specifies which eye we are rendering for; it is used to +// retrieve StereoEyeParams. +enum StereoEye +{ + StereoEye_Left, + StereoEye_Right, + StereoEye_Center +}; + + + +//----------------------------------------------------------------------------------- +// ***** Propjection functions + +Matrix4f CreateProjection ( bool rightHanded, bool isOpenGL, FovPort fov, StereoEye eye, + float zNear = 0.01f, float zFar = 10000.0f, + bool flipZ = false, bool farAtInfinity = false); + +Matrix4f CreateOrthoSubProjection ( bool rightHanded, StereoEye eyeType, + float tanHalfFovX, float tanHalfFovY, + float unitsX, float unitsY, float distanceFromCamera, + float interpupillaryDistance, Matrix4f const &projection, + float zNear = 0.0f, float zFar = 0.0f, + bool flipZ = false, bool farAtInfinity = false); + +ScaleAndOffset2D CreateNDCScaleAndOffsetFromFov ( FovPort fov ); + + +} //namespace OVR + +#endif // OVR_StereoProjection_h diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h new file mode 100644 index 000000000..b1ec3cc0e --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h @@ -0,0 +1,2116 @@ +/********************************************************************************//** +\file OVR_CAPI.h +\brief C Interface to the Oculus PC SDK tracking and rendering library. +\copyright Copyright 2014 Oculus VR, LLC All Rights reserved. +************************************************************************************/ + +#ifndef OVR_CAPI_h // We don't use version numbers within this name, as all versioned variations of this file are currently mutually exclusive. +#define OVR_CAPI_h ///< Header include guard + + +#include "OVR_CAPI_Keys.h" +#include "OVR_Version.h" +#include "OVR_ErrorCode.h" + + +#include + +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4324) // structure was padded due to __declspec(align()) + #pragma warning(disable: 4359) // The alignment specified for a type is less than the alignment of the type of one of its data members +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_OS +// +#if !defined(OVR_OS_WIN32) && defined(_WIN32) + #define OVR_OS_WIN32 +#endif + +#if !defined(OVR_OS_MAC) && defined(__APPLE__) + #define OVR_OS_MAC +#endif + +#if !defined(OVR_OS_LINUX) && defined(__linux__) + #define OVR_OS_LINUX +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP +// +#if !defined(OVR_CPP) + #if defined(__cplusplus) + #define OVR_CPP(x) x + #else + #define OVR_CPP(x) /* Not C++ */ + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_CDECL +// +/// LibOVR calling convention for 32-bit Windows builds. +// +#if !defined(OVR_CDECL) + #if defined(_WIN32) + #define OVR_CDECL __cdecl + #else + #define OVR_CDECL + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_EXTERN_C +// +/// Defined as extern "C" when built from C++ code. +// +#if !defined(OVR_EXTERN_C) + #ifdef __cplusplus + #define OVR_EXTERN_C extern "C" + #else + #define OVR_EXTERN_C + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_PUBLIC_FUNCTION / OVR_PRIVATE_FUNCTION +// +// OVR_PUBLIC_FUNCTION - Functions that externally visible from a shared library. Corresponds to Microsoft __dllexport. +// OVR_PUBLIC_CLASS - C++ structs and classes that are externally visible from a shared library. Corresponds to Microsoft __dllexport. +// OVR_PRIVATE_FUNCTION - Functions that are not visible outside of a shared library. They are private to the shared library. +// OVR_PRIVATE_CLASS - C++ structs and classes that are not visible outside of a shared library. They are private to the shared library. +// +// OVR_DLL_BUILD - Used to indicate that the current compilation unit is of a shared library. +// OVR_DLL_IMPORT - Used to indicate that the current compilation unit is a user of the corresponding shared library. +// OVR_STATIC_BUILD - used to indicate that the current compilation unit is not a shared library but rather statically linked code. +// +#if !defined(OVR_PUBLIC_FUNCTION) + #if defined(OVR_DLL_BUILD) + #if defined(_WIN32) + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __declspec(dllexport) rval OVR_CDECL + #define OVR_PUBLIC_CLASS __declspec(dllexport) + #define OVR_PRIVATE_FUNCTION(rval) rval OVR_CDECL + #define OVR_PRIVATE_CLASS + #else + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __attribute__((visibility("default"))) rval OVR_CDECL /* Requires GCC 4.0+ */ + #define OVR_PUBLIC_CLASS __attribute__((visibility("default"))) /* Requires GCC 4.0+ */ + #define OVR_PRIVATE_FUNCTION(rval) __attribute__((visibility("hidden"))) rval OVR_CDECL + #define OVR_PRIVATE_CLASS __attribute__((visibility("hidden"))) + #endif + #elif defined(OVR_DLL_IMPORT) + #if defined(_WIN32) + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C __declspec(dllimport) rval OVR_CDECL + #define OVR_PUBLIC_CLASS __declspec(dllimport) + #else + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C rval OVR_CDECL + #define OVR_PUBLIC_CLASS + #endif + #define OVR_PRIVATE_FUNCTION(rval) rval OVR_CDECL + #define OVR_PRIVATE_CLASS + #else // OVR_STATIC_BUILD + #define OVR_PUBLIC_FUNCTION(rval) OVR_EXTERN_C rval OVR_CDECL + #define OVR_PUBLIC_CLASS + #define OVR_PRIVATE_FUNCTION(rval) rval OVR_CDECL + #define OVR_PRIVATE_CLASS + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_EXPORT +// +/// Provided for backward compatibility with older versions of this library. +// +#if !defined(OVR_EXPORT) + #ifdef OVR_OS_WIN32 + #define OVR_EXPORT __declspec(dllexport) + #else + #define OVR_EXPORT + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_ALIGNAS +// +#if !defined(OVR_ALIGNAS) + #if defined(__GNUC__) || defined(__clang__) + #define OVR_ALIGNAS(n) __attribute__((aligned(n))) + #elif defined(_MSC_VER) || defined(__INTEL_COMPILER) + #define OVR_ALIGNAS(n) __declspec(align(n)) + #elif defined(__CC_ARM) + #define OVR_ALIGNAS(n) __align(n) + #else + #error Need to define OVR_ALIGNAS + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CC_HAS_FEATURE +// +// This is a portable way to use compile-time feature identification available +// with some compilers in a clean way. Direct usage of __has_feature in preprocessing +// statements of non-supporting compilers results in a preprocessing error. +// +// Example usage: +// #if OVR_CC_HAS_FEATURE(is_pod) +// if(__is_pod(T)) // If the type is plain data then we can safely memcpy it. +// memcpy(&destObject, &srcObject, sizeof(object)); +// #endif +// +#if !defined(OVR_CC_HAS_FEATURE) + #if defined(__clang__) // http://clang.llvm.org/docs/LanguageExtensions.html#id2 + #define OVR_CC_HAS_FEATURE(x) __has_feature(x) + #else + #define OVR_CC_HAS_FEATURE(x) 0 + #endif +#endif + + +// ------------------------------------------------------------------------ +// ***** OVR_STATIC_ASSERT +// +// Portable support for C++11 static_assert(). +// Acts as if the following were declared: +// void OVR_STATIC_ASSERT(bool const_expression, const char* msg); +// +// Example usage: +// OVR_STATIC_ASSERT(sizeof(int32_t) == 4, "int32_t expected to be 4 bytes."); + +#if !defined(OVR_STATIC_ASSERT) + #if !(defined(__cplusplus) && (__cplusplus >= 201103L)) /* Other */ && \ + !(defined(__GXX_EXPERIMENTAL_CXX0X__)) /* GCC */ && \ + !(defined(__clang__) && defined(__cplusplus) && OVR_CC_HAS_FEATURE(cxx_static_assert)) /* clang */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600) && defined(__cplusplus)) /* VS2010+ */ + + #if !defined(OVR_SA_UNUSED) + #if defined(OVR_CC_GNU) || defined(OVR_CC_CLANG) + #define OVR_SA_UNUSED __attribute__((unused)) + #else + #define OVR_SA_UNUSED + #endif + #define OVR_SA_PASTE(a,b) a##b + #define OVR_SA_HELP(a,b) OVR_SA_PASTE(a,b) + #endif + + #if defined(__COUNTER__) + #define OVR_STATIC_ASSERT(expression, msg) typedef char OVR_SA_HELP(compileTimeAssert, __COUNTER__) [((expression) != 0) ? 1 : -1] OVR_SA_UNUSED + #else + #define OVR_STATIC_ASSERT(expression, msg) typedef char OVR_SA_HELP(compileTimeAssert, __LINE__) [((expression) != 0) ? 1 : -1] OVR_SA_UNUSED + #endif + + #else + #define OVR_STATIC_ASSERT(expression, msg) static_assert(expression, msg) + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** Padding +// +/// Defines explicitly unused space for a struct. +/// When used correcly, usage of this macro should not change the size of the struct. +/// Compile-time and runtime behavior with and without this defined should be identical. +/// +#if !defined(OVR_UNUSED_STRUCT_PAD) + #define OVR_UNUSED_STRUCT_PAD(padName, size) char padName[size]; +#endif + + +//----------------------------------------------------------------------------------- +// ***** Word Size +// +/// Specifies the size of a pointer on the given platform. +/// +#if !defined(OVR_PTR_SIZE) + #if defined(__WORDSIZE) + #define OVR_PTR_SIZE ((__WORDSIZE) / 8) + #elif defined(_WIN64) || defined(__LP64__) || defined(_LP64) || defined(_M_IA64) || defined(__ia64__) || defined(__arch64__) || defined(__64BIT__) || defined(__Ptr_Is_64) + #define OVR_PTR_SIZE 8 + #elif defined(__CC_ARM) && (__sizeof_ptr == 8) + #define OVR_PTR_SIZE 8 + #else + #define OVR_PTR_SIZE 4 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_ON32 / OVR_ON64 +// +#if OVR_PTR_SIZE == 8 + #define OVR_ON32(x) + #define OVR_ON64(x) x +#else + #define OVR_ON32(x) x + #define OVR_ON64(x) +#endif + + +//----------------------------------------------------------------------------------- +// ***** ovrBool + +typedef char ovrBool; ///< Boolean type +#define ovrFalse 0 ///< ovrBool value of false. +#define ovrTrue 1 ///< ovrBool value of true. + + +//----------------------------------------------------------------------------------- +// ***** Simple Math Structures + +/// A 2D vector with integer components. +typedef struct OVR_ALIGNAS(4) ovrVector2i_ +{ + int x, y; +} ovrVector2i; + +/// A 2D size with integer components. +typedef struct OVR_ALIGNAS(4) ovrSizei_ +{ + int w, h; +} ovrSizei; + +/// A 2D rectangle with a position and size. +/// All components are integers. +typedef struct OVR_ALIGNAS(4) ovrRecti_ +{ + ovrVector2i Pos; + ovrSizei Size; +} ovrRecti; + +/// A quaternion rotation. +typedef struct OVR_ALIGNAS(4) ovrQuatf_ +{ + float x, y, z, w; +} ovrQuatf; + +/// A 2D vector with float components. +typedef struct OVR_ALIGNAS(4) ovrVector2f_ +{ + float x, y; +} ovrVector2f; + +/// A 3D vector with float components. +typedef struct OVR_ALIGNAS(4) ovrVector3f_ +{ + float x, y, z; +} ovrVector3f; + +/// A 4x4 matrix with float elements. +typedef struct OVR_ALIGNAS(4) ovrMatrix4f_ +{ + float M[4][4]; +} ovrMatrix4f; + + +/// Position and orientation together. +typedef struct OVR_ALIGNAS(4) ovrPosef_ +{ + ovrQuatf Orientation; + ovrVector3f Position; +} ovrPosef; + +/// A full pose (rigid body) configuration with first and second derivatives. +/// +/// Body refers to any object for which ovrPoseStatef is providing data. +/// It can be the HMD, Touch controller, sensor or something else. The context +/// depends on the usage of the struct. +typedef struct OVR_ALIGNAS(8) ovrPoseStatef_ +{ + ovrPosef ThePose; ///< Position and orientation. + ovrVector3f AngularVelocity; ///< Angular velocity in radians per second. + ovrVector3f LinearVelocity; ///< Velocity in meters per second. + ovrVector3f AngularAcceleration; ///< Angular acceleration in radians per second per second. + ovrVector3f LinearAcceleration; ///< Acceleration in meters per second per second. + OVR_UNUSED_STRUCT_PAD(pad0, 4) ///< \internal struct pad. + double TimeInSeconds; ///< Absolute time that this pose refers to. \see ovr_GetTimeInSeconds +} ovrPoseStatef; + +/// Describes the up, down, left, and right angles of the field of view. +/// +/// Field Of View (FOV) tangent of the angle units. +/// \note For a standard 90 degree vertical FOV, we would +/// have: { UpTan = tan(90 degrees / 2), DownTan = tan(90 degrees / 2) }. +typedef struct OVR_ALIGNAS(4) ovrFovPort_ +{ + float UpTan; ///< The tangent of the angle between the viewing vector and the top edge of the field of view. + float DownTan; ///< The tangent of the angle between the viewing vector and the bottom edge of the field of view. + float LeftTan; ///< The tangent of the angle between the viewing vector and the left edge of the field of view. + float RightTan; ///< The tangent of the angle between the viewing vector and the right edge of the field of view. +} ovrFovPort; + + +//----------------------------------------------------------------------------------- +// ***** HMD Types + +/// Enumerates all HMD types that we support. +/// +/// The currently released developer kits are ovrHmd_DK1 and ovrHmd_DK2. The other enumerations are for internal use only. +typedef enum ovrHmdType_ +{ + ovrHmd_None = 0, + ovrHmd_DK1 = 3, + ovrHmd_DKHD = 4, + ovrHmd_DK2 = 6, + ovrHmd_CB = 8, + ovrHmd_Other = 9, + ovrHmd_E3_2015 = 10, + ovrHmd_ES06 = 11, + ovrHmd_ES09 = 12, + ovrHmd_ES11 = 13, + ovrHmd_CV1 = 14, + + ovrHmd_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrHmdType; + + +/// HMD capability bits reported by device. +/// +typedef enum ovrHmdCaps_ +{ + // Read-only flags + ovrHmdCap_DebugDevice = 0x0010, ///< (read only) Specifies that the HMD is a virtual debug device. + + + ovrHmdCap_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrHmdCaps; + + +/// Tracking capability bits reported by the device. +/// Used with ovr_GetTrackingCaps. +typedef enum ovrTrackingCaps_ +{ + ovrTrackingCap_Orientation = 0x0010, ///< Supports orientation tracking (IMU). + ovrTrackingCap_MagYawCorrection = 0x0020, ///< Supports yaw drift correction via a magnetometer or other means. + ovrTrackingCap_Position = 0x0040, ///< Supports positional tracking. + ovrTrackingCap_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrTrackingCaps; + + +/// Specifies which eye is being used for rendering. +/// This type explicitly does not include a third "NoStereo" monoscopic option, as such is +/// not required for an HMD-centered API. +typedef enum ovrEyeType_ +{ + ovrEye_Left = 0, ///< The left eye, from the viewer's perspective. + ovrEye_Right = 1, ///< The right eye, from the viewer's perspective. + ovrEye_Count = 2, ///< \internal Count of enumerated elements. + ovrEye_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrEyeType; + +/// Specifies the coordinate system ovrTrackingState returns tracking poses in. +/// Used with ovr_SetTrackingOriginType() +typedef enum ovrTrackingOrigin_ +{ + /// \brief Tracking system origin reported at eye (HMD) height + /// \details Prefer using this origin when your application requires + /// matching user's current physical head pose to a virtual head pose + /// without any regards to a the height of the floor. Cockpit-based, + /// or 3rd-person experiences are ideal candidates. + /// When used, all poses in ovrTrackingState are reported as an offset + /// transform from the profile calibrated or recentered HMD pose. + /// It is recommended that apps using this origin type call ovr_RecenterTrackingOrigin + /// prior to starting the VR experience, but notify the user before doing so + /// to make sure the user is in a comfortable pose, facing a comfortable + /// direction. + ovrTrackingOrigin_EyeLevel = 0, + /// \brief Tracking system origin reported at floor height + /// \details Prefer using this origin when your application requires the + /// physical floor height to match the virtual floor height, such as + /// standing experiences. + /// When used, all poses in ovrTrackingState are reported as an offset + /// transform from the profile calibrated floor pose. Calling ovr_RecenterTrackingOrigin + /// will recenter the X & Z axes as well as yaw, but the Y-axis (i.e. height) will continue + /// to be reported using the floor height as the origin for all poses. + ovrTrackingOrigin_FloorLevel = 1, + ovrTrackingOrigin_Count = 2, ///< \internal Count of enumerated elements. + ovrTrackingOrigin_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrTrackingOrigin; + +/// Identifies a graphics device in a platform-specific way. +/// For Windows this is a LUID type. +typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrGraphicsLuid_ +{ + // Public definition reserves space for graphics API-specific implementation + char Reserved[8]; +} ovrGraphicsLuid; + + +/// This is a complete descriptor of the HMD. +typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrHmdDesc_ +{ + ovrHmdType Type; ///< The type of HMD. + OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad0, 4)) ///< \internal struct paddding. + char ProductName[64]; ///< UTF8-encoded product identification string (e.g. "Oculus Rift DK1"). + char Manufacturer[64]; ///< UTF8-encoded HMD manufacturer identification string. + short VendorId; ///< HID (USB) vendor identifier of the device. + short ProductId; ///< HID (USB) product identifier of the device. + char SerialNumber[24]; ///< HMD serial number. + short FirmwareMajor; ///< HMD firmware major version. + short FirmwareMinor; ///< HMD firmware minor version. + unsigned int AvailableHmdCaps; ///< Capability bits described by ovrHmdCaps which the HMD currently supports. + unsigned int DefaultHmdCaps; ///< Capability bits described by ovrHmdCaps which are default for the current Hmd. + unsigned int AvailableTrackingCaps; ///< Capability bits described by ovrTrackingCaps which the system currently supports. + unsigned int DefaultTrackingCaps; ///< Capability bits described by ovrTrackingCaps which are default for the current system. + ovrFovPort DefaultEyeFov[ovrEye_Count]; ///< Defines the recommended FOVs for the HMD. + ovrFovPort MaxEyeFov[ovrEye_Count]; ///< Defines the maximum FOVs for the HMD. + ovrSizei Resolution; ///< Resolution of the full HMD screen (both eyes) in pixels. + float DisplayRefreshRate; ///< Nominal refresh rate of the display in cycles per second at the time of HMD creation. + OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad1, 4)) ///< \internal struct paddding. +} ovrHmdDesc; + + +/// Used as an opaque pointer to an OVR session. +typedef struct ovrHmdStruct* ovrSession; + + + +/// Bit flags describing the current status of sensor tracking. +/// The values must be the same as in enum StatusBits +/// +/// \see ovrTrackingState +/// +typedef enum ovrStatusBits_ +{ + ovrStatus_OrientationTracked = 0x0001, ///< Orientation is currently tracked (connected and in use). + ovrStatus_PositionTracked = 0x0002, ///< Position is currently tracked (false if out of range). + ovrStatus_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrStatusBits; + + +/// Specifies the description of a single sensor. +/// +/// \see ovrGetTrackerDesc +/// +typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrTrackerDesc_ +{ + float FrustumHFovInRadians; ///< Sensor frustum horizontal field-of-view (if present). + float FrustumVFovInRadians; ///< Sensor frustum vertical field-of-view (if present). + float FrustumNearZInMeters; ///< Sensor frustum near Z (if present). + float FrustumFarZInMeters; ///< Sensor frustum far Z (if present). +} ovrTrackerDesc; + + +/// Specifies sensor flags. +/// +/// /see ovrTrackerPose +/// +typedef enum ovrTrackerFlags_ +{ + ovrTracker_Connected = 0x0020, ///< The sensor is present, else the sensor is absent or offline. + ovrTracker_PoseTracked = 0x0004 ///< The sensor has a valid pose, else the pose is unavailable. This will only be set if ovrTracker_Connected is set. +} ovrTrackerFlags; + + +/// Specifies the pose for a single sensor. +/// +typedef struct OVR_ALIGNAS(8) _ovrTrackerPose +{ + unsigned int TrackerFlags; ///< ovrTrackerFlags. + ovrPosef Pose; ///< The sensor's pose. This pose includes sensor tilt (roll and pitch). For a leveled coordinate system use LeveledPose. + ovrPosef LeveledPose; ///< The sensor's leveled pose, aligned with gravity. This value includes position and yaw of the sensor, but not roll and pitch. It can be used as a reference point to render real-world objects in the correct location. + OVR_UNUSED_STRUCT_PAD(pad0, 4) ///< \internal struct pad. +} ovrTrackerPose; + + +/// Tracking state at a given absolute time (describes predicted HMD pose, etc.). +/// Returned by ovr_GetTrackingState. +/// +/// \see ovr_GetTrackingState +/// +typedef struct OVR_ALIGNAS(8) ovrTrackingState_ +{ + /// Predicted head pose (and derivatives) at the requested absolute time. + ovrPoseStatef HeadPose; + + /// HeadPose tracking status described by ovrStatusBits. + unsigned int StatusFlags; + + /// The most recent calculated pose for each hand when hand controller tracking is present. + /// HandPoses[ovrHand_Left] refers to the left hand and HandPoses[ovrHand_Right] to the right hand. + /// These values can be combined with ovrInputState for complete hand controller information. + ovrPoseStatef HandPoses[2]; + + /// HandPoses status flags described by ovrStatusBits. + /// Only ovrStatus_OrientationTracked and ovrStatus_PositionTracked are reported. + unsigned int HandStatusFlags[2]; + + /// The pose of the origin captured during calibration. + /// Like all other poses here, this is expressed in the space set by ovr_RecenterTrackingOrigin, + /// and so will change every time that is called. This pose can be used to calculate + /// where the calibrated origin lands in the new recentered space. + /// If an application never calls ovr_RecenterTrackingOrigin, expect this value to be the identity + /// pose and as such will point respective origin based on ovrTrackingOrigin requested when + /// calling ovr_GetTrackingState. + ovrPosef CalibratedOrigin; + +} ovrTrackingState; + + +/// Rendering information for each eye. Computed by ovr_GetRenderDesc() based on the +/// specified FOV. Note that the rendering viewport is not included +/// here as it can be specified separately and modified per frame by +/// passing different Viewport values in the layer structure. +/// +/// \see ovr_GetRenderDesc +/// +typedef struct OVR_ALIGNAS(4) ovrEyeRenderDesc_ +{ + ovrEyeType Eye; ///< The eye index to which this instance corresponds. + ovrFovPort Fov; ///< The field of view. + ovrRecti DistortedViewport; ///< Distortion viewport. + ovrVector2f PixelsPerTanAngleAtCenter; ///< How many display pixels will fit in tan(angle) = 1. + ovrVector3f HmdToEyeOffset; ///< Translation of each eye, in meters. +} ovrEyeRenderDesc; + + +/// Projection information for ovrLayerEyeFovDepth. +/// +/// Use the utility function ovrTimewarpProjectionDesc_FromProjection to +/// generate this structure from the application's projection matrix. +/// +/// \see ovrLayerEyeFovDepth, ovrTimewarpProjectionDesc_FromProjection +/// +typedef struct OVR_ALIGNAS(4) ovrTimewarpProjectionDesc_ +{ + float Projection22; ///< Projection matrix element [2][2]. + float Projection23; ///< Projection matrix element [2][3]. + float Projection32; ///< Projection matrix element [3][2]. +} ovrTimewarpProjectionDesc; + + +/// Contains the data necessary to properly calculate position info for various layer types. +/// - HmdToEyeOffset is the same value pair provided in ovrEyeRenderDesc. +/// - HmdSpaceToWorldScaleInMeters is used to scale player motion into in-application units. +/// In other words, it is how big an in-application unit is in the player's physical meters. +/// For example, if the application uses inches as its units then HmdSpaceToWorldScaleInMeters would be 0.0254. +/// Note that if you are scaling the player in size, this must also scale. So if your application +/// units are inches, but you're shrinking the player to half their normal size, then +/// HmdSpaceToWorldScaleInMeters would be 0.0254*2.0. +/// +/// \see ovrEyeRenderDesc, ovr_SubmitFrame +/// +typedef struct OVR_ALIGNAS(4) ovrViewScaleDesc_ +{ + ovrVector3f HmdToEyeOffset[ovrEye_Count]; ///< Translation of each eye. + float HmdSpaceToWorldScaleInMeters; ///< Ratio of viewer units to meter units. +} ovrViewScaleDesc; + + +//----------------------------------------------------------------------------------- +// ***** Platform-independent Rendering Configuration + +/// The type of texture resource. +/// +/// \see ovrTextureSwapChainDesc +/// +typedef enum ovrTextureType_ +{ + ovrTexture_2D, ///< 2D textures. + ovrTexture_2D_External, ///< External 2D texture. Not used on PC + ovrTexture_Cube, ///< Cube maps. Not currently supported on PC. + ovrTexture_Count, + ovrTexture_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrTextureType; + +/// The bindings required for texture swap chain. +/// +/// All texture swap chains are automatically bindable as shader +/// input resources since the Oculus runtime needs this to read them. +/// +/// \see ovrTextureSwapChainDesc +/// +typedef enum ovrTextureBindFlags_ +{ + ovrTextureBind_None, + ovrTextureBind_DX_RenderTarget = 0x0001, ///< The application can write into the chain with pixel shader + ovrTextureBind_DX_UnorderedAccess = 0x0002, ///< The application can write to the chain with compute shader + ovrTextureBind_DX_DepthStencil = 0x0004, ///< The chain buffers can be bound as depth and/or stencil buffers + + ovrTextureBind_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrTextureBindFlags; + +/// The format of a texture. +/// +/// \see ovrTextureSwapChainDesc +/// +typedef enum ovrTextureFormat_ +{ + OVR_FORMAT_UNKNOWN, + OVR_FORMAT_B5G6R5_UNORM, ///< Not currently supported on PC. Would require a DirectX 11.1 device. + OVR_FORMAT_B5G5R5A1_UNORM, ///< Not currently supported on PC. Would require a DirectX 11.1 device. + OVR_FORMAT_B4G4R4A4_UNORM, ///< Not currently supported on PC. Would require a DirectX 11.1 device. + OVR_FORMAT_R8G8B8A8_UNORM, + OVR_FORMAT_R8G8B8A8_UNORM_SRGB, + OVR_FORMAT_B8G8R8A8_UNORM, + OVR_FORMAT_B8G8R8A8_UNORM_SRGB, ///< Not supported for OpenGL applications + OVR_FORMAT_B8G8R8X8_UNORM, ///< Not supported for OpenGL applications + OVR_FORMAT_B8G8R8X8_UNORM_SRGB, ///< Not supported for OpenGL applications + OVR_FORMAT_R16G16B16A16_FLOAT, + OVR_FORMAT_D16_UNORM, + OVR_FORMAT_D24_UNORM_S8_UINT, + OVR_FORMAT_D32_FLOAT, + OVR_FORMAT_D32_FLOAT_S8X24_UINT, + + OVR_FORMAT_ENUMSIZE = 0x7fffffff ///< \internal Force type int32_t. +} ovrTextureFormat; + +/// Misc flags overriding particular +/// behaviors of a texture swap chain +/// +/// \see ovrTextureSwapChainDesc +/// +typedef enum ovrTextureMiscFlags_ +{ + ovrTextureMisc_None, + + /// DX only: The underlying texture is created with a TYPELESS equivalent of the + /// format specified in the texture desc. The SDK will still access the + /// texture using the format specified in the texture desc, but the app can + /// create views with different formats if this is specified. + ovrTextureMisc_DX_Typeless = 0x0001, + + /// DX only: Allow generation of the mip chain on the GPU via the GenerateMips + /// call. This flag requires that RenderTarget binding also be specified. + ovrTextureMisc_AllowGenerateMips = 0x0002, + + /// Texture swap chain contains protected content, and requires + /// HDCP connection in order to display to HMD. Also prevents + /// mirroring or other redirection of any frame containing this contents + ovrTextureMisc_ProtectedContent = 0x0004, + + ovrTextureMisc_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrTextureFlags; + +/// Description used to create a texture swap chain. +/// +/// \see ovr_CreateTextureSwapChainDX +/// \see ovr_CreateTextureSwapChainGL +/// +typedef struct ovrTextureSwapChainDesc_ +{ + ovrTextureType Type; + ovrTextureFormat Format; + int ArraySize; ///< Only supported with ovrTexture_2D. Not supported on PC at this time. + int Width; + int Height; + int MipLevels; + int SampleCount; ///< Current only supported on depth textures + ovrBool StaticImage; ///< Not buffered in a chain. For images that don't change + unsigned int MiscFlags; ///< ovrTextureFlags + unsigned int BindFlags; ///< ovrTextureBindFlags. Not used for GL. +} ovrTextureSwapChainDesc; + +/// Description used to create a mirror texture. +/// +/// \see ovr_CreateMirrorTextureDX +/// \see ovr_CreateMirrorTextureGL +/// +typedef struct ovrMirrorTextureDesc_ +{ + ovrTextureFormat Format; + int Width; + int Height; + unsigned int MiscFlags; ///< ovrTextureFlags +} ovrMirrorTextureDesc; + +typedef struct ovrTextureSwapChainData* ovrTextureSwapChain; +typedef struct ovrMirrorTextureData* ovrMirrorTexture; + +//----------------------------------------------------------------------------------- + +/// Describes button input types. +/// Button inputs are combined; that is they will be reported as pressed if they are +/// pressed on either one of the two devices. +/// The ovrButton_Up/Down/Left/Right map to both XBox D-Pad and directional buttons. +/// The ovrButton_Enter and ovrButton_Return map to Start and Back controller buttons, respectively. +typedef enum ovrButton_ +{ + ovrButton_A = 0x00000001, + ovrButton_B = 0x00000002, + ovrButton_RThumb = 0x00000004, + ovrButton_RShoulder = 0x00000008, + + // Bit mask of all buttons on the right Touch controller + ovrButton_RMask = ovrButton_A | ovrButton_B | ovrButton_RThumb | ovrButton_RShoulder, + + ovrButton_X = 0x00000100, + ovrButton_Y = 0x00000200, + ovrButton_LThumb = 0x00000400, + ovrButton_LShoulder = 0x00000800, + + // Bit mask of all buttons on the left Touch controller + ovrButton_LMask = ovrButton_X | ovrButton_Y | ovrButton_LThumb | ovrButton_LShoulder, + + // Navigation through DPad. + ovrButton_Up = 0x00010000, + ovrButton_Down = 0x00020000, + ovrButton_Left = 0x00040000, + ovrButton_Right = 0x00080000, + ovrButton_Enter = 0x00100000, // Start on XBox controller. + ovrButton_Back = 0x00200000, // Back on Xbox controller. + ovrButton_VolUp = 0x00400000, // only supported by Remote. + ovrButton_VolDown = 0x00800000, // only supported by Remote. + ovrButton_Home = 0x01000000, + ovrButton_Private = ovrButton_VolUp | ovrButton_VolDown | ovrButton_Home, + + + ovrButton_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrButton; + +/// Describes touch input types. +/// These values map to capacitive touch values reported ovrInputState::Touch. +/// Some of these values are mapped to button bits for consistency. +typedef enum ovrTouch_ +{ + ovrTouch_A = ovrButton_A, + ovrTouch_B = ovrButton_B, + ovrTouch_RThumb = ovrButton_RThumb, + ovrTouch_RIndexTrigger = 0x00000010, + + // Bit mask of all the button touches on the right controller + ovrTouch_RButtonMask = ovrTouch_A | ovrTouch_B | ovrTouch_RThumb | ovrTouch_RIndexTrigger, + + ovrTouch_X = ovrButton_X, + ovrTouch_Y = ovrButton_Y, + ovrTouch_LThumb = ovrButton_LThumb, + ovrTouch_LIndexTrigger = 0x00001000, + + // Bit mask of all the button touches on the left controller + ovrTouch_LButtonMask = ovrTouch_X | ovrTouch_Y | ovrTouch_LThumb | ovrTouch_LIndexTrigger, + + // Finger pose state + // Derived internally based on distance, proximity to sensors and filtering. + ovrTouch_RIndexPointing = 0x00000020, + ovrTouch_RThumbUp = 0x00000040, + + // Bit mask of all right controller poses + ovrTouch_RPoseMask = ovrTouch_RIndexPointing | ovrTouch_RThumbUp, + + ovrTouch_LIndexPointing = 0x00002000, + ovrTouch_LThumbUp = 0x00004000, + + // Bit mask of all left controller poses + ovrTouch_LPoseMask = ovrTouch_LIndexPointing | ovrTouch_LThumbUp, + + ovrTouch_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrTouch; + +/// Specifies which controller is connected; multiple can be connected at once. +typedef enum ovrControllerType_ +{ + ovrControllerType_None = 0x00, + ovrControllerType_LTouch = 0x01, + ovrControllerType_RTouch = 0x02, + ovrControllerType_Touch = 0x03, + ovrControllerType_Remote = 0x04, + ovrControllerType_XBox = 0x10, + + ovrControllerType_Active = 0xff, ///< Operate on or query whichever controller is active. + + ovrControllerType_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrControllerType; + + +/// Provides names for the left and right hand array indexes. +/// +/// \see ovrInputState, ovrTrackingState +/// +typedef enum ovrHandType_ +{ + ovrHand_Left = 0, + ovrHand_Right = 1, + ovrHand_Count = 2, + ovrHand_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrHandType; + + + +/// ovrInputState describes the complete controller input state, including Oculus Touch, +/// and XBox gamepad. If multiple inputs are connected and used at the same time, +/// their inputs are combined. +typedef struct ovrInputState_ +{ + // System type when the controller state was last updated. + double TimeInSeconds; + + // Values for buttons described by ovrButton. + unsigned int Buttons; + + // Touch values for buttons and sensors as described by ovrTouch. + unsigned int Touches; + + // Left and right finger trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f. + float IndexTrigger[ovrHand_Count]; + + // Left and right hand trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f. + float HandTrigger[ovrHand_Count]; + + // Horizontal and vertical thumbstick axis values (ovrHand_Left and ovrHand_Right), in the range -1.0f to 1.0f. + ovrVector2f Thumbstick[ovrHand_Count]; + + // The type of the controller this state is for. + ovrControllerType ControllerType; + +} ovrInputState; + + + +//----------------------------------------------------------------------------------- +// ***** Initialize structures + +/// Initialization flags. +/// +/// \see ovrInitParams, ovr_Initialize +/// +typedef enum ovrInitFlags_ +{ + /// When a debug library is requested, a slower debugging version of the library will + /// run which can be used to help solve problems in the library and debug application code. + ovrInit_Debug = 0x00000001, + + /// When a version is requested, the LibOVR runtime respects the RequestedMinorVersion + /// field and verifies that the RequestedMinorVersion is supported. + ovrInit_RequestVersion = 0x00000004, + + // These bits are writable by user code. + ovrinit_WritableBits = 0x00ffffff, + + ovrInit_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrInitFlags; + + +/// Logging levels +/// +/// \see ovrInitParams, ovrLogCallback +/// +typedef enum ovrLogLevel_ +{ + ovrLogLevel_Debug = 0, ///< Debug-level log event. + ovrLogLevel_Info = 1, ///< Info-level log event. + ovrLogLevel_Error = 2, ///< Error-level log event. + + ovrLogLevel_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrLogLevel; + + +/// Signature of the logging callback function pointer type. +/// +/// \param[in] userData is an arbitrary value specified by the user of ovrInitParams. +/// \param[in] level is one of the ovrLogLevel constants. +/// \param[in] message is a UTF8-encoded null-terminated string. +/// \see ovrInitParams, ovrLogLevel, ovr_Initialize +/// +typedef void (OVR_CDECL* ovrLogCallback)(uintptr_t userData, int level, const char* message); + + +/// Parameters for ovr_Initialize. +/// +/// \see ovr_Initialize +/// +typedef struct OVR_ALIGNAS(8) ovrInitParams_ +{ + /// Flags from ovrInitFlags to override default behavior. + /// Use 0 for the defaults. + uint32_t Flags; + + /// Requests a specific minimum minor version of the LibOVR runtime. + /// Flags must include ovrInit_RequestVersion or this will be ignored + /// and OVR_MINOR_VERSION will be used. + uint32_t RequestedMinorVersion; + + /// User-supplied log callback function, which may be called at any time + /// asynchronously from multiple threads until ovr_Shutdown completes. + /// Use NULL to specify no log callback. + ovrLogCallback LogCallback; + + /// User-supplied data which is passed as-is to LogCallback. Typically this + /// is used to store an application-specific pointer which is read in the + /// callback function. + uintptr_t UserData; + + /// Relative number of milliseconds to wait for a connection to the server + /// before failing. Use 0 for the default timeout. + uint32_t ConnectionTimeoutMS; + + OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad0, 4)) ///< \internal + +} ovrInitParams; + + +#ifdef __cplusplus +extern "C" { +#endif + + +// ----------------------------------------------------------------------------------- +// ***** API Interfaces + +// Overview of the API +// +// Setup: +// - ovr_Initialize(). +// - ovr_Create(&hmd, &graphicsId). +// - Use hmd members and ovr_GetFovTextureSize() to determine graphics configuration +// and ovr_GetRenderDesc() to get per-eye rendering parameters. +// - Allocate texture swap chains with ovr_CreateTextureSwapChainDX() or +// ovr_CreateTextureSwapChainGL(). Create any associated render target views or +// frame buffer objects. +// +// Application Loop: +// - Call ovr_GetPredictedDisplayTime() to get the current frame timing information. +// - Call ovr_GetTrackingState() and ovr_CalcEyePoses() to obtain the predicted +// rendering pose for each eye based on timing. +// - Render the scene content into the current buffer of the texture swapchains +// for each eye and layer you plan to update this frame. If you render into a +// texture swap chain, you must call ovr_CommitTextureSwapChain() on it to commit +// the changes before you reference the chain this frame (otherwise, your latest +// changes won't be picked up). +// - Call ovr_SubmitFrame() to render the distorted layers to and present them on the HMD. +// If ovr_SubmitFrame returns ovrSuccess_NotVisible, there is no need to render the scene +// for the next loop iteration. Instead, just call ovr_SubmitFrame again until it returns +// ovrSuccess. +// +// Shutdown: +// - ovr_Destroy(). +// - ovr_Shutdown(). + + +/// Initializes LibOVR +/// +/// Initialize LibOVR for application usage. This includes finding and loading the LibOVRRT +/// shared library. No LibOVR API functions, other than ovr_GetLastErrorInfo and ovr_Detect, can +/// be called unless ovr_Initialize succeeds. A successful call to ovr_Initialize must be eventually +/// followed by a call to ovr_Shutdown. ovr_Initialize calls are idempotent. +/// Calling ovr_Initialize twice does not require two matching calls to ovr_Shutdown. +/// If already initialized, the return value is ovr_Success. +/// +/// LibOVRRT shared library search order: +/// -# Current working directory (often the same as the application directory). +/// -# Module directory (usually the same as the application directory, +/// but not if the module is a separate shared library). +/// -# Application directory +/// -# Development directory (only if OVR_ENABLE_DEVELOPER_SEARCH is enabled, +/// which is off by default). +/// -# Standard OS shared library search location(s) (OS-specific). +/// +/// \param params Specifies custom initialization options. May be NULL to indicate default options. +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. Example failed results include: +/// - ovrError_Initialize: Generic initialization error. +/// - ovrError_LibLoad: Couldn't load LibOVRRT. +/// - ovrError_LibVersion: LibOVRRT version incompatibility. +/// - ovrError_ServiceConnection: Couldn't connect to the OVR Service. +/// - ovrError_ServiceVersion: OVR Service version incompatibility. +/// - ovrError_IncompatibleOS: The operating system version is incompatible. +/// - ovrError_DisplayInit: Unable to initialize the HMD display. +/// - ovrError_ServerStart: Unable to start the server. Is it already running? +/// - ovrError_Reinitialization: Attempted to re-initialize with a different version. +/// +/// Example code +/// \code{.cpp} +/// ovrResult result = ovr_Initialize(NULL); +/// if(OVR_FAILURE(result)) { +/// ovrErrorInfo errorInfo; +/// ovr_GetLastErrorInfo(&errorInfo); +/// DebugLog("ovr_Initialize failed: %s", errorInfo.ErrorString); +/// return false; +/// } +/// [...] +/// \endcode +/// +/// \see ovr_Shutdown +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_Initialize(const ovrInitParams* params); + + +/// Shuts down LibOVR +/// +/// A successful call to ovr_Initialize must be eventually matched by a call to ovr_Shutdown. +/// After calling ovr_Shutdown, no LibOVR functions can be called except ovr_GetLastErrorInfo +/// or another ovr_Initialize. ovr_Shutdown invalidates all pointers, references, and created objects +/// previously returned by LibOVR functions. The LibOVRRT shared library can be unloaded by +/// ovr_Shutdown. +/// +/// \see ovr_Initialize +/// +OVR_PUBLIC_FUNCTION(void) ovr_Shutdown(); + +/// Returns information about the most recent failed return value by the +/// current thread for this library. +/// +/// This function itself can never generate an error. +/// The last error is never cleared by LibOVR, but will be overwritten by new errors. +/// Do not use this call to determine if there was an error in the last API +/// call as successful API calls don't clear the last ovrErrorInfo. +/// To avoid any inconsistency, ovr_GetLastErrorInfo should be called immediately +/// after an API function that returned a failed ovrResult, with no other API +/// functions called in the interim. +/// +/// \param[out] errorInfo The last ovrErrorInfo for the current thread. +/// +/// \see ovrErrorInfo +/// +OVR_PUBLIC_FUNCTION(void) ovr_GetLastErrorInfo(ovrErrorInfo* errorInfo); + + +/// Returns the version string representing the LibOVRRT version. +/// +/// The returned string pointer is valid until the next call to ovr_Shutdown. +/// +/// Note that the returned version string doesn't necessarily match the current +/// OVR_MAJOR_VERSION, etc., as the returned string refers to the LibOVRRT shared +/// library version and not the locally compiled interface version. +/// +/// The format of this string is subject to change in future versions and its contents +/// should not be interpreted. +/// +/// \return Returns a UTF8-encoded null-terminated version string. +/// +OVR_PUBLIC_FUNCTION(const char*) ovr_GetVersionString(); + + +/// Writes a message string to the LibOVR tracing mechanism (if enabled). +/// +/// This message will be passed back to the application via the ovrLogCallback if +/// it was registered. +/// +/// \param[in] level One of the ovrLogLevel constants. +/// \param[in] message A UTF8-encoded null-terminated string. +/// \return returns the strlen of the message or a negative value if the message is too large. +/// +/// \see ovrLogLevel, ovrLogCallback +/// +OVR_PUBLIC_FUNCTION(int) ovr_TraceMessage(int level, const char* message); + + +//------------------------------------------------------------------------------------- +/// @name HMD Management +/// +/// Handles the enumeration, creation, destruction, and properties of an HMD (head-mounted display). +///@{ + + +/// Returns information about the current HMD. +/// +/// ovr_Initialize must have first been called in order for this to succeed, otherwise ovrHmdDesc::Type +/// will be reported as ovrHmd_None. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create, else NULL in which +/// case this function detects whether an HMD is present and returns its info if so. +/// +/// \return Returns an ovrHmdDesc. If the hmd is NULL and ovrHmdDesc::Type is ovrHmd_None then +/// no HMD is present. +/// +OVR_PUBLIC_FUNCTION(ovrHmdDesc) ovr_GetHmdDesc(ovrSession session); + + +/// Returns the number of sensors. +/// +/// The number of sensors may change at any time, so this function should be called before use +/// as opposed to once on startup. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// +/// \return Returns unsigned int count. +/// +OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetTrackerCount(ovrSession session); + + +/// Returns a given sensor description. +/// +/// It's possible that sensor desc [0] may indicate a unconnnected or non-pose tracked sensor, but +/// sensor desc [1] may be connected. +/// +/// ovr_Initialize must have first been called in order for this to succeed, otherwise the returned +/// trackerDescArray will be zero-initialized. The data returned by this function can change at runtime. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// +/// \param[in] trackerDescIndex Specifies a sensor index. The valid indexes are in the range of 0 to +/// the sensor count returned by ovr_GetTrackerCount. +/// +/// \return Returns ovrTrackerDesc. An empty ovrTrackerDesc will be returned if trackerDescIndex is out of range. +/// +/// \see ovrTrackerDesc, ovr_GetTrackerCount +/// +OVR_PUBLIC_FUNCTION(ovrTrackerDesc) ovr_GetTrackerDesc(ovrSession session, unsigned int trackerDescIndex); + + +/// Creates a handle to a VR session. +/// +/// Upon success the returned ovrSession must be eventually freed with ovr_Destroy when it is no longer needed. +/// A second call to ovr_Create will result in an error return value if the previous Hmd has not been destroyed. +/// +/// \param[out] pSession Provides a pointer to an ovrSession which will be written to upon success. +/// \param[out] luid Provides a system specific graphics adapter identifier that locates which +/// graphics adapter has the HMD attached. This must match the adapter used by the application +/// or no rendering output will be possible. This is important for stability on multi-adapter systems. An +/// application that simply chooses the default adapter will not run reliably on multi-adapter systems. +/// \return Returns an ovrResult indicating success or failure. Upon failure +/// the returned pHmd will be NULL. +/// +/// Example code +/// \code{.cpp} +/// ovrSession session; +/// ovrGraphicsLuid luid; +/// ovrResult result = ovr_Create(&session, &luid); +/// if(OVR_FAILURE(result)) +/// ... +/// \endcode +/// +/// \see ovr_Destroy +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_Create(ovrSession* pSession, ovrGraphicsLuid* pLuid); + + +/// Destroys the HMD. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \see ovr_Create +/// +OVR_PUBLIC_FUNCTION(void) ovr_Destroy(ovrSession session); + + +/// Specifies status information for the current session. +/// +/// \see ovr_GetSessionStatus +/// +typedef struct ovrSessionStatus_ +{ + ovrBool IsVisible; ///< True if the process has VR focus and thus is visible in the HMD. + ovrBool HmdPresent; ///< True if an HMD is present. + ovrBool HmdMounted; ///< True if the HMD is on the user's head. + ovrBool DisplayLost; ///< True if the session is in a display-lost state. See ovr_SubmitFrame. + ovrBool ShouldQuit; ///< True if the application should initiate shutdown. + ovrBool ShouldRecenter; ///< True if UX has requested re-centering. Must call ovr_ClearShouldRecenterFlag or ovr_RecenterTrackingOrigin. +}ovrSessionStatus; + + +/// Returns status information for the application. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[out] sessionStatus Provides an ovrSessionStatus that is filled in. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of +/// failure, use ovr_GetLastErrorInfo to get more information. +// Return values include but aren't limited to: +/// - ovrSuccess: Completed successfully. +/// - ovrError_ServiceConnection: The service connection was lost and the application +// must destroy the session. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetSessionStatus(ovrSession session, ovrSessionStatus* sessionStatus); + + +//@} + + + +//------------------------------------------------------------------------------------- +/// @name Tracking +/// +/// Tracking functions handle the position, orientation, and movement of the HMD in space. +/// +/// All tracking interface functions are thread-safe, allowing tracking state to be sampled +/// from different threads. +/// +///@{ + + + +/// Sets the tracking origin type +/// +/// When the tracking origin is changed, all of the calls that either provide +/// or accept ovrPosef will use the new tracking origin provided. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] origin Specifies an ovrTrackingOrigin to be used for all ovrPosef +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +/// \see ovrTrackingOrigin, ovr_GetTrackingOriginType +OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetTrackingOriginType(ovrSession session, ovrTrackingOrigin origin); + + +/// Gets the tracking origin state +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// +/// \return Returns the ovrTrackingOrigin that was either set by default, or previous set by the application. +/// +/// \see ovrTrackingOrigin, ovr_SetTrackingOriginType +OVR_PUBLIC_FUNCTION(ovrTrackingOrigin) ovr_GetTrackingOriginType(ovrSession session); + + +/// Re-centers the sensor position and orientation. +/// +/// This resets the (x,y,z) positional components and the yaw orientation component. +/// The Roll and pitch orientation components are always determined by gravity and cannot +/// be redefined. All future tracking will report values relative to this new reference position. +/// If you are using ovrTrackerPoses then you will need to call ovr_GetTrackerPose after +/// this, because the sensor position(s) will change as a result of this. +/// +/// The headset cannot be facing vertically upward or downward but rather must be roughly +/// level otherwise this function will fail with ovrError_InvalidHeadsetOrientation. +/// +/// For more info, see the notes on each ovrTrackingOrigin enumeration to understand how +/// recenter will vary slightly in its behavior based on the current ovrTrackingOrigin setting. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. Return values include but aren't limited to: +/// - ovrSuccess: Completed successfully. +/// - ovrError_InvalidHeadsetOrientation: The headset was facing an invalid direction when +/// attempting recentering, such as facing vertically. +/// +/// \see ovrTrackingOrigin, ovr_GetTrackerPose +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_RecenterTrackingOrigin(ovrSession session); + + +/// Clears the ShouldRecenter status bit in ovrSessionStatus. +/// +/// Clears the ShouldRecenter status bit in ovrSessionStatus, allowing further recenter +/// requests to be detected. Since this is automatically done by ovr_RecenterTrackingOrigin, +/// this is only needs to be called when application is doing its own re-centering. +OVR_PUBLIC_FUNCTION(void) ovr_ClearShouldRecenterFlag(ovrSession session); + + +/// Returns tracking state reading based on the specified absolute system time. +/// +/// Pass an absTime value of 0.0 to request the most recent sensor reading. In this case +/// both PredictedPose and SamplePose will have the same value. +/// +/// This may also be used for more refined timing of front buffer rendering logic, and so on. +/// This may be called by multiple threads. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] absTime Specifies the absolute future time to predict the return +/// ovrTrackingState value. Use 0 to request the most recent tracking state. +/// \param[in] latencyMarker Specifies that this call is the point in time where +/// the "App-to-Mid-Photon" latency timer starts from. If a given ovrLayer +/// provides "SensorSampleTimestamp", that will override the value stored here. +/// \return Returns the ovrTrackingState that is predicted for the given absTime. +/// +/// \see ovrTrackingState, ovr_GetEyePoses, ovr_GetTimeInSeconds +/// +OVR_PUBLIC_FUNCTION(ovrTrackingState) ovr_GetTrackingState(ovrSession session, double absTime, ovrBool latencyMarker); + + + +/// Returns the ovrTrackerPose for the given sensor. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] trackerPoseIndex Index of the sensor being requested. +/// +/// \return Returns the requested ovrTrackerPose. An empty ovrTrackerPose will be returned if trackerPoseIndex is out of range. +/// +/// \see ovr_GetTrackerCount +/// +OVR_PUBLIC_FUNCTION(ovrTrackerPose) ovr_GetTrackerPose(ovrSession session, unsigned int trackerPoseIndex); + + + +/// Returns the most recent input state for controllers, without positional tracking info. +/// +/// \param[out] inputState Input state that will be filled in. +/// \param[in] ovrControllerType Specifies which controller the input will be returned for. +/// \return Returns ovrSuccess if the new state was successfully obtained. +/// +/// \see ovrControllerType +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetInputState(ovrSession session, ovrControllerType controllerType, ovrInputState* inputState); + + +/// Returns controller types connected to the system OR'ed together. +/// +/// \return A bitmask of ovrControllerTypes connected to the system. +/// +/// \see ovrControllerType +/// +OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetConnectedControllerTypes(ovrSession session); + + +/// Turns on vibration of the given controller. +/// +/// To disable vibration, call ovr_SetControllerVibration with an amplitude of 0. +/// Vibration automatically stops after a nominal amount of time, so if you want vibration +/// to be continuous over multiple seconds then you need to call this function periodically. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] controllerType Specifies the controller to apply the vibration to. +/// \param[in] frequency Specifies a vibration frequency in the range of 0.0 to 1.0. +/// Currently the only valid values are 0.0, 0.5, and 1.0 and other values will +/// be clamped to one of these. +/// \param[in] amplitude Specifies a vibration amplitude in the range of 0.0 to 1.0. +/// +/// \return Returns ovrSuccess upon success. +/// +/// \see ovrControllerType +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetControllerVibration(ovrSession session, ovrControllerType controllerType, + float frequency, float amplitude); + +///@} + + +//------------------------------------------------------------------------------------- +// @name Layers +// +///@{ + + +/// Specifies the maximum number of layers supported by ovr_SubmitFrame. +/// +/// /see ovr_SubmitFrame +/// +enum { + ovrMaxLayerCount = 16 +}; + +/// Describes layer types that can be passed to ovr_SubmitFrame. +/// Each layer type has an associated struct, such as ovrLayerEyeFov. +/// +/// \see ovrLayerHeader +/// +typedef enum ovrLayerType_ +{ + ovrLayerType_Disabled = 0, ///< Layer is disabled. + ovrLayerType_EyeFov = 1, ///< Described by ovrLayerEyeFov. + ovrLayerType_Quad = 3, ///< Described by ovrLayerQuad. Previously called ovrLayerType_QuadInWorld. + /// enum 4 used to be ovrLayerType_QuadHeadLocked. Instead, use ovrLayerType_Quad with ovrLayerFlag_HeadLocked. + ovrLayerType_EyeMatrix = 5, ///< Described by ovrLayerEyeMatrix. + ovrLayerType_EnumSize = 0x7fffffff ///< Force type int32_t. +} ovrLayerType; + + +/// Identifies flags used by ovrLayerHeader and which are passed to ovr_SubmitFrame. +/// +/// \see ovrLayerHeader +/// +typedef enum ovrLayerFlags_ +{ + /// ovrLayerFlag_HighQuality enables 4x anisotropic sampling during the composition of the layer. + /// The benefits are mostly visible at the periphery for high-frequency & high-contrast visuals. + /// For best results consider combining this flag with an ovrTextureSwapChain that has mipmaps and + /// instead of using arbitrary sized textures, prefer texture sizes that are powers-of-two. + /// Actual rendered viewport and doesn't necessarily have to fill the whole texture. + ovrLayerFlag_HighQuality = 0x01, + + /// ovrLayerFlag_TextureOriginAtBottomLeft: the opposite is TopLeft. + /// Generally this is false for D3D, true for OpenGL. + ovrLayerFlag_TextureOriginAtBottomLeft = 0x02, + + /// Mark this surface as "headlocked", which means it is specified + /// relative to the HMD and moves with it, rather than being specified + /// relative to sensor/torso space and remaining still while the head moves. + /// What used to be ovrLayerType_QuadHeadLocked is now ovrLayerType_Quad plus this flag. + /// However the flag can be applied to any layer type to achieve a similar effect. + ovrLayerFlag_HeadLocked = 0x04 + +} ovrLayerFlags; + + +/// Defines properties shared by all ovrLayer structs, such as ovrLayerEyeFov. +/// +/// ovrLayerHeader is used as a base member in these larger structs. +/// This struct cannot be used by itself except for the case that Type is ovrLayerType_Disabled. +/// +/// \see ovrLayerType, ovrLayerFlags +/// +typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrLayerHeader_ +{ + ovrLayerType Type; ///< Described by ovrLayerType. + unsigned Flags; ///< Described by ovrLayerFlags. +} ovrLayerHeader; + + +/// Describes a layer that specifies a monoscopic or stereoscopic view. +/// This is the kind of layer that's typically used as layer 0 to ovr_SubmitFrame, +/// as it is the kind of layer used to render a 3D stereoscopic view. +/// +/// Three options exist with respect to mono/stereo texture usage: +/// - ColorTexture[0] and ColorTexture[1] contain the left and right stereo renderings, respectively. +/// Viewport[0] and Viewport[1] refer to ColorTexture[0] and ColorTexture[1], respectively. +/// - ColorTexture[0] contains both the left and right renderings, ColorTexture[1] is NULL, +/// and Viewport[0] and Viewport[1] refer to sub-rects with ColorTexture[0]. +/// - ColorTexture[0] contains a single monoscopic rendering, and Viewport[0] and +/// Viewport[1] both refer to that rendering. +/// +/// \see ovrTextureSwapChain, ovr_SubmitFrame +/// +typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrLayerEyeFov_ +{ + /// Header.Type must be ovrLayerType_EyeFov. + ovrLayerHeader Header; + + /// ovrTextureSwapChains for the left and right eye respectively. + /// The second one of which can be NULL for cases described above. + ovrTextureSwapChain ColorTexture[ovrEye_Count]; + + /// Specifies the ColorTexture sub-rect UV coordinates. + /// Both Viewport[0] and Viewport[1] must be valid. + ovrRecti Viewport[ovrEye_Count]; + + /// The viewport field of view. + ovrFovPort Fov[ovrEye_Count]; + + /// Specifies the position and orientation of each eye view, with the position specified in meters. + /// RenderPose will typically be the value returned from ovr_CalcEyePoses, + /// but can be different in special cases if a different head pose is used for rendering. + ovrPosef RenderPose[ovrEye_Count]; + + /// Specifies the timestamp when the source ovrPosef (used in calculating RenderPose) + /// was sampled from the SDK. Typically retrieved by calling ovr_GetTimeInSeconds + /// around the instant the application calls ovr_GetTrackingState + /// The main purpose for this is to accurately track app tracking latency. + double SensorSampleTime; + +} ovrLayerEyeFov; + + + + +/// Describes a layer that specifies a monoscopic or stereoscopic view. +/// This uses a direct 3x4 matrix to map from view space to the UV coordinates. +/// It is essentially the same thing as ovrLayerEyeFov but using a much +/// lower level. This is mainly to provide compatibility with specific apps. +/// Unless the application really requires this flexibility, it is usually better +/// to use ovrLayerEyeFov. +/// +/// Three options exist with respect to mono/stereo texture usage: +/// - ColorTexture[0] and ColorTexture[1] contain the left and right stereo renderings, respectively. +/// Viewport[0] and Viewport[1] refer to ColorTexture[0] and ColorTexture[1], respectively. +/// - ColorTexture[0] contains both the left and right renderings, ColorTexture[1] is NULL, +/// and Viewport[0] and Viewport[1] refer to sub-rects with ColorTexture[0]. +/// - ColorTexture[0] contains a single monoscopic rendering, and Viewport[0] and +/// Viewport[1] both refer to that rendering. +/// +/// \see ovrTextureSwapChain, ovr_SubmitFrame +/// +typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrLayerEyeMatrix_ +{ + /// Header.Type must be ovrLayerType_EyeMatrix. + ovrLayerHeader Header; + + /// ovrTextureSwapChains for the left and right eye respectively. + /// The second one of which can be NULL for cases described above. + ovrTextureSwapChain ColorTexture[ovrEye_Count]; + + /// Specifies the ColorTexture sub-rect UV coordinates. + /// Both Viewport[0] and Viewport[1] must be valid. + ovrRecti Viewport[ovrEye_Count]; + + /// Specifies the position and orientation of each eye view, with the position specified in meters. + /// RenderPose will typically be the value returned from ovr_CalcEyePoses, + /// but can be different in special cases if a different head pose is used for rendering. + ovrPosef RenderPose[ovrEye_Count]; + + /// Specifies the mapping from a view-space vector + /// to a UV coordinate on the textures given above. + /// P = (x,y,z,1)*Matrix + /// TexU = P.x/P.z + /// TexV = P.y/P.z + ovrMatrix4f Matrix[ovrEye_Count]; + + /// Specifies the timestamp when the source ovrPosef (used in calculating RenderPose) + /// was sampled from the SDK. Typically retrieved by calling ovr_GetTimeInSeconds + /// around the instant the application calls ovr_GetTrackingState + /// The main purpose for this is to accurately track app tracking latency. + double SensorSampleTime; + +} ovrLayerEyeMatrix; + + + + + +/// Describes a layer of Quad type, which is a single quad in world or viewer space. +/// It is used for ovrLayerType_Quad. This type of layer represents a single +/// object placed in the world and not a stereo view of the world itself. +/// +/// A typical use of ovrLayerType_Quad is to draw a television screen in a room +/// that for some reason is more convenient to draw as a layer than as part of the main +/// view in layer 0. For example, it could implement a 3D popup GUI that is drawn at a +/// higher resolution than layer 0 to improve fidelity of the GUI. +/// +/// Quad layers are visible from both sides; they are not back-face culled. +/// +/// \see ovrTextureSwapChain, ovr_SubmitFrame +/// +typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) ovrLayerQuad_ +{ + /// Header.Type must be ovrLayerType_Quad. + ovrLayerHeader Header; + + /// Contains a single image, never with any stereo view. + ovrTextureSwapChain ColorTexture; + + /// Specifies the ColorTexture sub-rect UV coordinates. + ovrRecti Viewport; + + /// Specifies the orientation and position of the center point of a Quad layer type. + /// The supplied direction is the vector perpendicular to the quad. + /// The position is in real-world meters (not the application's virtual world, + /// the physical world the user is in) and is relative to the "zero" position + /// set by ovr_RecenterTrackingOrigin unless the ovrLayerFlag_HeadLocked flag is used. + ovrPosef QuadPoseCenter; + + /// Width and height (respectively) of the quad in meters. + ovrVector2f QuadSize; + +} ovrLayerQuad; + + + + +/// Union that combines ovrLayer types in a way that allows them +/// to be used in a polymorphic way. +typedef union ovrLayer_Union_ +{ + ovrLayerHeader Header; + ovrLayerEyeFov EyeFov; + ovrLayerQuad Quad; +} ovrLayer_Union; + + +//@} + + + +/// @name SDK Distortion Rendering +/// +/// All of rendering functions including the configure and frame functions +/// are not thread safe. It is OK to use ConfigureRendering on one thread and handle +/// frames on another thread, but explicit synchronization must be done since +/// functions that depend on configured state are not reentrant. +/// +/// These functions support rendering of distortion by the SDK. +/// +//@{ + +/// TextureSwapChain creation is rendering API-specific. +/// ovr_CreateTextureSwapChainDX and ovr_CreateTextureSwapChainGL can be found in the +/// rendering API-specific headers, such as OVR_CAPI_D3D.h and OVR_CAPI_GL.h + +/// Gets the number of buffers in an ovrTextureSwapChain. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] chain Specifies the ovrTextureSwapChain for which the length should be retrieved. +/// \param[out] out_Length Returns the number of buffers in the specified chain. +/// +/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error. +/// +/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainLength(ovrSession session, ovrTextureSwapChain chain, int* out_Length); + +/// Gets the current index in an ovrTextureSwapChain. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] chain Specifies the ovrTextureSwapChain for which the index should be retrieved. +/// \param[out] out_Index Returns the current (free) index in specified chain. +/// +/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error. +/// +/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainCurrentIndex(ovrSession session, ovrTextureSwapChain chain, int* out_Index); + +/// Gets the description of the buffers in an ovrTextureSwapChain +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] chain Specifies the ovrTextureSwapChain for which the description should be retrieved. +/// \param[out] out_Desc Returns the description of the specified chain. +/// +/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error. +/// +/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainDesc(ovrSession session, ovrTextureSwapChain chain, ovrTextureSwapChainDesc* out_Desc); + +/// Commits any pending changes to an ovrTextureSwapChain, and advances its current index +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] chain Specifies the ovrTextureSwapChain to commit. +/// +/// \note When Commit is called, the texture at the current index is considered ready for use by the +/// runtime, and further writes to it should be avoided. The swap chain's current index is advanced, +/// providing there's room in the chain. The next time the SDK dereferences this texture swap chain, +/// it will synchronize with the app's graphics context and pick up the submitted index, opening up +/// room in the swap chain for further commits. +/// +/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error. +/// Failures include but aren't limited to: +/// - ovrError_TextureSwapChainFull: ovr_CommitTextureSwapChain was called too many times on a texture swapchain without calling submit to use the chain. +/// +/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_CommitTextureSwapChain(ovrSession session, ovrTextureSwapChain chain); + +/// Destroys an ovrTextureSwapChain and frees all the resources associated with it. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] chain Specifies the ovrTextureSwapChain to destroy. If it is NULL then this function has no effect. +/// +/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL +/// +OVR_PUBLIC_FUNCTION(void) ovr_DestroyTextureSwapChain(ovrSession session, ovrTextureSwapChain chain); + + +/// MirrorTexture creation is rendering API-specific. +/// ovr_CreateMirrorTextureDX and ovr_CreateMirrorTextureGL can be found in the +/// rendering API-specific headers, such as OVR_CAPI_D3D.h and OVR_CAPI_GL.h + +/// Destroys a mirror texture previously created by one of the mirror texture creation functions. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] mirrorTexture Specifies the ovrTexture to destroy. If it is NULL then this function has no effect. +/// +/// \see ovr_CreateMirrorTextureDX, ovr_CreateMirrorTextureGL +/// +OVR_PUBLIC_FUNCTION(void) ovr_DestroyMirrorTexture(ovrSession session, ovrMirrorTexture mirrorTexture); + + +/// Calculates the recommended viewport size for rendering a given eye within the HMD +/// with a given FOV cone. +/// +/// Higher FOV will generally require larger textures to maintain quality. +/// Apps packing multiple eye views together on the same texture should ensure there are +/// at least 8 pixels of padding between them to prevent texture filtering and chromatic +/// aberration causing images to leak between the two eye views. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] eye Specifies which eye (left or right) to calculate for. +/// \param[in] fov Specifies the ovrFovPort to use. +/// \param[in] pixelsPerDisplayPixel Specifies the ratio of the number of render target pixels +/// to display pixels at the center of distortion. 1.0 is the default value. Lower +/// values can improve performance, higher values give improved quality. +/// +/// Example code +/// \code{.cpp} +/// ovrHmdDesc hmdDesc = ovr_GetHmdDesc(session); +/// ovrSizei eyeSizeLeft = ovr_GetFovTextureSize(session, ovrEye_Left, hmdDesc.DefaultEyeFov[ovrEye_Left], 1.0f); +/// ovrSizei eyeSizeRight = ovr_GetFovTextureSize(session, ovrEye_Right, hmdDesc.DefaultEyeFov[ovrEye_Right], 1.0f); +/// \endcode +/// +/// \return Returns the texture width and height size. +/// +OVR_PUBLIC_FUNCTION(ovrSizei) ovr_GetFovTextureSize(ovrSession session, ovrEyeType eye, ovrFovPort fov, + float pixelsPerDisplayPixel); + +/// Computes the distortion viewport, view adjust, and other rendering parameters for +/// the specified eye. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] eyeType Specifies which eye (left or right) for which to perform calculations. +/// \param[in] fov Specifies the ovrFovPort to use. +/// +/// \return Returns the computed ovrEyeRenderDesc for the given eyeType and field of view. +/// +/// \see ovrEyeRenderDesc +/// +OVR_PUBLIC_FUNCTION(ovrEyeRenderDesc) ovr_GetRenderDesc(ovrSession session, + ovrEyeType eyeType, ovrFovPort fov); + +/// Submits layers for distortion and display. +/// +/// ovr_SubmitFrame triggers distortion and processing which might happen asynchronously. +/// The function will return when there is room in the submission queue and surfaces +/// are available. Distortion might or might not have completed. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// +/// \param[in] frameIndex Specifies the targeted application frame index, or 0 to refer to one frame +/// after the last time ovr_SubmitFrame was called. +/// +/// \param[in] viewScaleDesc Provides additional information needed only if layerPtrList contains +/// an ovrLayerType_Quad. If NULL, a default version is used based on the current configuration and a 1.0 world scale. +/// +/// \param[in] layerPtrList Specifies a list of ovrLayer pointers, which can include NULL entries to +/// indicate that any previously shown layer at that index is to not be displayed. +/// Each layer header must be a part of a layer structure such as ovrLayerEyeFov or ovrLayerQuad, +/// with Header.Type identifying its type. A NULL layerPtrList entry in the array indicates the +// absence of the given layer. +/// +/// \param[in] layerCount Indicates the number of valid elements in layerPtrList. The maximum +/// supported layerCount is not currently specified, but may be specified in a future version. +/// +/// - Layers are drawn in the order they are specified in the array, regardless of the layer type. +/// +/// - Layers are not remembered between successive calls to ovr_SubmitFrame. A layer must be +/// specified in every call to ovr_SubmitFrame or it won't be displayed. +/// +/// - If a layerPtrList entry that was specified in a previous call to ovr_SubmitFrame is +/// passed as NULL or is of type ovrLayerType_Disabled, that layer is no longer displayed. +/// +/// - A layerPtrList entry can be of any layer type and multiple entries of the same layer type +/// are allowed. No layerPtrList entry may be duplicated (i.e. the same pointer as an earlier entry). +/// +/// Example code +/// \code{.cpp} +/// ovrLayerEyeFov layer0; +/// ovrLayerQuad layer1; +/// ... +/// ovrLayerHeader* layers[2] = { &layer0.Header, &layer1.Header }; +/// ovrResult result = ovr_SubmitFrame(hmd, frameIndex, nullptr, layers, 2); +/// \endcode +/// +/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error and true +/// upon success. Return values include but aren't limited to: +/// - ovrSuccess: rendering completed successfully. +/// - ovrSuccess_NotVisible: rendering completed successfully but was not displayed on the HMD, +/// usually because another application currently has ownership of the HMD. Applications receiving +/// this result should stop rendering new content, but continue to call ovr_SubmitFrame periodically +/// until it returns a value other than ovrSuccess_NotVisible. +/// - ovrError_DisplayLost: The session has become invalid (such as due to a device removal) +/// and the shared resources need to be released (ovr_DestroyTextureSwapChain), the session needs to +/// destroyed (ovr_Destroy) and recreated (ovr_Create), and new resources need to be created +/// (ovr_CreateTextureSwapChainXXX). The application's existing private graphics resources do not +/// need to be recreated unless the new ovr_Create call returns a different GraphicsLuid. +/// - ovrError_TextureSwapChainInvalid: The ovrTextureSwapChain is in an incomplete or inconsistent state. +/// Ensure ovr_CommitTextureSwapChain was called at least once first. +/// +/// \see ovr_GetPredictedDisplayTime, ovrViewScaleDesc, ovrLayerHeader +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitFrame(ovrSession session, long long frameIndex, + const ovrViewScaleDesc* viewScaleDesc, + ovrLayerHeader const * const * layerPtrList, unsigned int layerCount); +///@} + + + +//------------------------------------------------------------------------------------- +/// @name Frame Timing +/// +//@{ + + +/// Gets the time of the specified frame midpoint. +/// +/// Predicts the time at which the given frame will be displayed. The predicted time +/// is the middle of the time period during which the corresponding eye images will +/// be displayed. +/// +/// The application should increment frameIndex for each successively targeted frame, +/// and pass that index to any relevent OVR functions that need to apply to the frame +/// identified by that index. +/// +/// This function is thread-safe and allows for multiple application threads to target +/// their processing to the same displayed frame. +/// +/// In the even that prediction fails due to various reasons (e.g. the display being off +/// or app has yet to present any frames), the return value will be current CPU time. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] frameIndex Identifies the frame the caller wishes to target. +/// A value of zero returns the next frame index. +/// \return Returns the absolute frame midpoint time for the given frameIndex. +/// \see ovr_GetTimeInSeconds +/// +OVR_PUBLIC_FUNCTION(double) ovr_GetPredictedDisplayTime(ovrSession session, long long frameIndex); + + +/// Returns global, absolute high-resolution time in seconds. +/// +/// The time frame of reference for this function is not specified and should not be +/// depended upon. +/// +/// \return Returns seconds as a floating point value. +/// \see ovrPoseStatef, ovrFrameTiming +/// +OVR_PUBLIC_FUNCTION(double) ovr_GetTimeInSeconds(); + + +/// Performance HUD enables the HMD user to see information critical to +/// the real-time operation of the VR application such as latency timing, +/// and CPU & GPU performance metrics +/// +/// App can toggle performance HUD modes as such: +/// \code{.cpp} +/// ovrPerfHudMode PerfHudMode = ovrPerfHud_LatencyTiming; +/// ovr_SetInt(Hmd, OVR_PERF_HUD_MODE, (int)PerfHudMode); +/// \endcode +/// +typedef enum ovrPerfHudMode_ +{ + ovrPerfHud_Off = 0, ///< Turns off the performance HUD + ovrPerfHud_PerfSummary = 1, ///< Shows performance summary and headroom + ovrPerfHud_LatencyTiming = 2, ///< Shows latency related timing info + ovrPerfHud_AppRenderTiming = 3, ///< Shows render timing info for application + ovrPerfHud_CompRenderTiming = 4, ///< Shows render timing info for OVR compositor + ovrPerfHud_VersionInfo = 5, ///< Shows SDK & HMD version Info + ovrPerfHud_Count = 6, ///< \internal Count of enumerated elements. + ovrPerfHud_EnumSize = 0x7fffffff ///< \internal Force type int32_t. +} ovrPerfHudMode; + +/// Layer HUD enables the HMD user to see information about a layer +/// +/// App can toggle layer HUD modes as such: +/// \code{.cpp} +/// ovrLayerHudMode LayerHudMode = ovrLayerHud_Info; +/// ovr_SetInt(Hmd, OVR_LAYER_HUD_MODE, (int)LayerHudMode); +/// \endcode +/// +typedef enum ovrLayerHudMode_ +{ + ovrLayerHud_Off = 0, ///< Turns off the layer HUD + ovrLayerHud_Info = 1, ///< Shows info about a specific layer + ovrLayerHud_EnumSize = 0x7fffffff +} ovrLayerHudMode; + +///@} + +/// Debug HUD is provided to help developers gauge and debug the fidelity of their app's +/// stereo rendering characteristics. Using the provided quad and crosshair guides, +/// the developer can verify various aspects such as VR tracking units (e.g. meters), +/// stereo camera-parallax properties (e.g. making sure objects at infinity are rendered +/// with the proper separation), measuring VR geometry sizes and distances and more. +/// +/// App can toggle the debug HUD modes as such: +/// \code{.cpp} +/// ovrDebugHudStereoMode DebugHudMode = ovrDebugHudStereo_QuadWithCrosshair; +/// ovr_SetInt(Hmd, OVR_DEBUG_HUD_STEREO_MODE, (int)DebugHudMode); +/// \endcode +/// +/// The app can modify the visual properties of the stereo guide (i.e. quad, crosshair) +/// using the ovr_SetFloatArray function. For a list of tweakable properties, +/// see the OVR_DEBUG_HUD_STEREO_GUIDE_* keys in the OVR_CAPI_Keys.h header file. +typedef enum ovrDebugHudStereoMode_ +{ + ovrDebugHudStereo_Off = 0, ///< Turns off the Stereo Debug HUD + ovrDebugHudStereo_Quad = 1, ///< Renders Quad in world for Stereo Debugging + ovrDebugHudStereo_QuadWithCrosshair = 2, ///< Renders Quad+crosshair in world for Stereo Debugging + ovrDebugHudStereo_CrosshairAtInfinity = 3, ///< Renders screen-space crosshair at infinity for Stereo Debugging + ovrDebugHudStereo_Count, ///< \internal Count of enumerated elements + + ovrDebugHudStereo_EnumSize = 0x7fffffff ///< \internal Force type int32_t +} ovrDebugHudStereoMode; + + + + +// ----------------------------------------------------------------------------------- +/// @name Property Access +/// +/// These functions read and write OVR properties. Supported properties +/// are defined in OVR_CAPI_Keys.h +/// +//@{ + +/// Reads a boolean property. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid for only the call. +/// \param[in] defaultVal specifes the value to return if the property couldn't be read. +/// \return Returns the property interpreted as a boolean value. Returns defaultVal if +/// the property doesn't exist. +OVR_PUBLIC_FUNCTION(ovrBool) ovr_GetBool(ovrSession session, const char* propertyName, ovrBool defaultVal); + +/// Writes or creates a boolean property. +/// If the property wasn't previously a boolean property, it is changed to a boolean property. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] value The value to write. +/// \return Returns true if successful, otherwise false. A false result should only occur if the property +/// name is empty or if the property is read-only. +OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetBool(ovrSession session, const char* propertyName, ovrBool value); + + +/// Reads an integer property. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] defaultVal Specifes the value to return if the property couldn't be read. +/// \return Returns the property interpreted as an integer value. Returns defaultVal if +/// the property doesn't exist. +OVR_PUBLIC_FUNCTION(int) ovr_GetInt(ovrSession session, const char* propertyName, int defaultVal); + +/// Writes or creates an integer property. +/// +/// If the property wasn't previously a boolean property, it is changed to an integer property. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] value The value to write. +/// \return Returns true if successful, otherwise false. A false result should only occur if the property +/// name is empty or if the property is read-only. +OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetInt(ovrSession session, const char* propertyName, int value); + + +/// Reads a float property. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] defaultVal specifes the value to return if the property couldn't be read. +/// \return Returns the property interpreted as an float value. Returns defaultVal if +/// the property doesn't exist. +OVR_PUBLIC_FUNCTION(float) ovr_GetFloat(ovrSession session, const char* propertyName, float defaultVal); + +/// Writes or creates a float property. +/// If the property wasn't previously a float property, it's changed to a float property. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] value The value to write. +/// \return Returns true if successful, otherwise false. A false result should only occur if the property +/// name is empty or if the property is read-only. +OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetFloat(ovrSession session, const char* propertyName, float value); + + +/// Reads a float array property. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] values An array of float to write to. +/// \param[in] valuesCapacity Specifies the maximum number of elements to write to the values array. +/// \return Returns the number of elements read, or 0 if property doesn't exist or is empty. +OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetFloatArray(ovrSession session, const char* propertyName, + float values[], unsigned int valuesCapacity); + +/// Writes or creates a float array property. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] values An array of float to write from. +/// \param[in] valuesSize Specifies the number of elements to write. +/// \return Returns true if successful, otherwise false. A false result should only occur if the property +/// name is empty or if the property is read-only. +OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetFloatArray(ovrSession session, const char* propertyName, + const float values[], unsigned int valuesSize); + + +/// Reads a string property. +/// Strings are UTF8-encoded and null-terminated. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] defaultVal Specifes the value to return if the property couldn't be read. +/// \return Returns the string property if it exists. Otherwise returns defaultVal, which can be specified as NULL. +/// The return memory is guaranteed to be valid until next call to ovr_GetString or +/// until the HMD is destroyed, whichever occurs first. +OVR_PUBLIC_FUNCTION(const char*) ovr_GetString(ovrSession session, const char* propertyName, + const char* defaultVal); + +/// Writes or creates a string property. +/// Strings are UTF8-encoded and null-terminated. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] propertyName The name of the property, which needs to be valid only for the call. +/// \param[in] value The string property, which only needs to be valid for the duration of the call. +/// \return Returns true if successful, otherwise false. A false result should only occur if the property +/// name is empty or if the property is read-only. +OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetString(ovrSession session, const char* propertyName, + const char* value); + +///@} + + + +#ifdef __cplusplus +} // extern "C" +#endif + + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + +/// @cond DoxygenIgnore +//----------------------------------------------------------------------------- +// ***** Compiler packing validation +// +// These checks ensure that the compiler settings being used will be compatible +// with with pre-built dynamic library provided with the runtime. + +OVR_STATIC_ASSERT(sizeof(ovrBool) == 1, "ovrBool size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrVector2i) == 4 * 2, "ovrVector2i size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrSizei) == 4 * 2, "ovrSizei size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrRecti) == sizeof(ovrVector2i) + sizeof(ovrSizei), "ovrRecti size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrQuatf) == 4 * 4, "ovrQuatf size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrVector2f) == 4 * 2, "ovrVector2f size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrVector3f) == 4 * 3, "ovrVector3f size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrMatrix4f) == 4 * 16, "ovrMatrix4f size mismatch"); + +OVR_STATIC_ASSERT(sizeof(ovrPosef) == (7 * 4), "ovrPosef size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrPoseStatef) == (22 * 4), "ovrPoseStatef size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrFovPort) == (4 * 4), "ovrFovPort size mismatch"); + +OVR_STATIC_ASSERT(sizeof(ovrHmdCaps) == 4, "ovrHmdCaps size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrTrackingCaps) == 4, "ovrTrackingCaps size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrEyeType) == 4, "ovrEyeType size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrHmdType) == 4, "ovrHmdType size mismatch"); + +OVR_STATIC_ASSERT(sizeof(ovrTrackerDesc) == 4 + 4 + 4 + 4, "ovrTrackerDesc size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrTrackerPose) == 4 + 4 + sizeof(ovrPosef) + sizeof(ovrPosef), "ovrTrackerPose size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrTrackingState) == sizeof(ovrPoseStatef) + 4 + 4 + (sizeof(ovrPoseStatef) * 2) + (sizeof(unsigned int) * 2) + sizeof(ovrPosef) + 4, "ovrTrackingState size mismatch"); + + +//OVR_STATIC_ASSERT(sizeof(ovrTextureHeader) == sizeof(ovrRenderAPIType) + sizeof(ovrSizei), +// "ovrTextureHeader size mismatch"); +//OVR_STATIC_ASSERT(sizeof(ovrTexture) == sizeof(ovrTextureHeader) OVR_ON64(+4) + sizeof(uintptr_t) * 8, +// "ovrTexture size mismatch"); +// +OVR_STATIC_ASSERT(sizeof(ovrStatusBits) == 4, "ovrStatusBits size mismatch"); + +OVR_STATIC_ASSERT(sizeof(ovrSessionStatus) == 6, "ovrSessionStatus size mismatch"); + +OVR_STATIC_ASSERT(sizeof(ovrEyeRenderDesc) == sizeof(ovrEyeType) + sizeof(ovrFovPort) + sizeof(ovrRecti) + + sizeof(ovrVector2f) + sizeof(ovrVector3f), + "ovrEyeRenderDesc size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrTimewarpProjectionDesc) == 4 * 3, "ovrTimewarpProjectionDesc size mismatch"); + +OVR_STATIC_ASSERT(sizeof(ovrInitFlags) == 4, "ovrInitFlags size mismatch"); +OVR_STATIC_ASSERT(sizeof(ovrLogLevel) == 4, "ovrLogLevel size mismatch"); + +OVR_STATIC_ASSERT(sizeof(ovrInitParams) == 4 + 4 + sizeof(ovrLogCallback) + sizeof(uintptr_t) + 4 + 4, + "ovrInitParams size mismatch"); + +OVR_STATIC_ASSERT(sizeof(ovrHmdDesc) == + + sizeof(ovrHmdType) // Type + OVR_ON64(+ 4) // pad0 + + 64 // ProductName + + 64 // Manufacturer + + 2 // VendorId + + 2 // ProductId + + 24 // SerialNumber + + 2 // FirmwareMajor + + 2 // FirmwareMinor + + 4 * 4 // AvailableHmdCaps - DefaultTrackingCaps + + sizeof(ovrFovPort) * 2 // DefaultEyeFov + + sizeof(ovrFovPort) * 2 // MaxEyeFov + + sizeof(ovrSizei) // Resolution + + 4 // DisplayRefreshRate + OVR_ON64(+ 4) // pad1 + , "ovrHmdDesc size mismatch"); + + +// ----------------------------------------------------------------------------------- +// ***** Backward compatibility #includes +// +// This is at the bottom of this file because the following is dependent on the +// declarations above. + +#if !defined(OVR_CAPI_NO_UTILS) + #include "Extras/OVR_CAPI_Util.h" +#endif + +/// @endcond + +#endif // OVR_CAPI_h diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h new file mode 100644 index 000000000..c53448133 --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h @@ -0,0 +1,76 @@ +/********************************************************************************//** +\file OVR_CAPI_Audio.h +\brief CAPI audio functions. +\copyright Copyright 2015 Oculus VR, LLC. All Rights reserved. +************************************************************************************/ + + +#ifndef OVR_CAPI_Audio_h +#define OVR_CAPI_Audio_h + +#ifdef _WIN32 +#include +#include "OVR_CAPI.h" +#define OVR_AUDIO_MAX_DEVICE_STR_SIZE 128 + +/// Gets the ID of the preferred VR audio output device. +/// +/// \param[out] deviceOutId The ID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be WAVE_MAPPER. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutWaveId(UINT* deviceOutId); + +/// Gets the ID of the preferred VR audio input device. +/// +/// \param[out] deviceInId The ID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be WAVE_MAPPER. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInWaveId(UINT* deviceInId); + + +/// Gets the GUID of the preferred VR audio device as a string. +/// +/// \param[out] deviceOutStrBuffer A buffer where the GUID string for the device will copied to. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutGuidStr(WCHAR deviceOutStrBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]); + + +/// Gets the GUID of the preferred VR audio device. +/// +/// \param[out] deviceOutGuid The GUID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be NULL. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceOutGuid(GUID* deviceOutGuid); + + +/// Gets the GUID of the preferred VR microphone device as a string. +/// +/// \param[out] deviceInStrBuffer A buffer where the GUID string for the device will copied to. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuidStr(WCHAR deviceInStrBuffer[OVR_AUDIO_MAX_DEVICE_STR_SIZE]); + + +/// Gets the GUID of the preferred VR microphone device. +/// +/// \param[out] deviceInGuid The GUID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be NULL. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuid(GUID* deviceInGuid); + +#endif //OVR_OS_MS + +#endif // OVR_CAPI_Audio_h diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h new file mode 100644 index 000000000..50806bca1 --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h @@ -0,0 +1,155 @@ +/********************************************************************************//** +\file OVR_CAPI_D3D.h +\brief D3D specific structures used by the CAPI interface. +\copyright Copyright 2014-2016 Oculus VR, LLC All Rights reserved. +************************************************************************************/ + +#ifndef OVR_CAPI_D3D_h +#define OVR_CAPI_D3D_h + +#include "OVR_CAPI.h" +#include "OVR_Version.h" + + +#if defined (_WIN32) +#include + +//----------------------------------------------------------------------------------- +// ***** Direct3D Specific + +/// Create Texture Swap Chain suitable for use with Direct3D 11 and 12. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] d3dPtr Specifies the application's D3D11Device to create resources with or the D3D12CommandQueue +/// which must be the same one the application renders to the eye textures with. +/// \param[in] desc Specifies requested texture properties. See notes for more info about texture format. +/// \param[in] bindFlags Specifies what ovrTextureBindFlags the application requires for this texture chain. +/// \param[out] out_TextureSwapChain Returns the created ovrTextureSwapChain, which will be valid upon a successful return value, else it will be NULL. +/// This texture chain must be eventually destroyed via ovr_DestroyTextureSwapChain before destroying the HMD with ovr_Destroy. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +/// \note The texture format provided in \a desc should be thought of as the format the distortion-compositor will use for the +/// ShaderResourceView when reading the contents of the texture. To that end, it is highly recommended that the application +/// requests texture swapchain formats that are in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the compositor +/// does sRGB-correct rendering. As such, the compositor relies on the GPU's hardware sampler to do the sRGB-to-linear +/// conversion. If the application still prefers to render to a linear format (e.g. OVR_FORMAT_R8G8B8A8_UNORM) while handling the +/// linear-to-gamma conversion via HLSL code, then the application must still request the corresponding sRGB format and also use +/// the \a ovrTextureMisc_DX_Typeless flag in the ovrTextureSwapChainDesc's Flag field. This will allow the application to create +/// a RenderTargetView that is the desired linear format while the compositor continues to treat it as sRGB. Failure to do so +/// will cause the compositor to apply unexpected gamma conversions leading to gamma-curve artifacts. The \a ovrTextureMisc_DX_Typeless +/// flag for depth buffer formats (e.g. OVR_FORMAT_D32_FLOAT) is ignored as they are always converted to be typeless. +/// +/// \see ovr_GetTextureSwapChainLength +/// \see ovr_GetTextureSwapChainCurrentIndex +/// \see ovr_GetTextureSwapChainDesc +/// \see ovr_GetTextureSwapChainBufferDX +/// \see ovr_DestroyTextureSwapChain +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateTextureSwapChainDX(ovrSession session, + IUnknown* d3dPtr, + const ovrTextureSwapChainDesc* desc, + ovrTextureSwapChain* out_TextureSwapChain); + + +/// Get a specific buffer within the chain as any compatible COM interface (similar to QueryInterface) +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] chain Specifies an ovrTextureSwapChain previously returned by ovr_CreateTextureSwapChainDX +/// \param[in] index Specifies the index within the chain to retrieve. Must be between 0 and length (see ovr_GetTextureSwapChainLength), +/// or may pass -1 to get the buffer at the CurrentIndex location. (Saving a call to GetTextureSwapChainCurrentIndex) +/// \param[in] iid Specifies the interface ID of the interface pointer to query the buffer for. +/// \param[out] out_Buffer Returns the COM interface pointer retrieved. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +/// Example code +/// \code{.cpp} +/// ovr_GetTextureSwapChainBufferDX(session, chain, 0, IID_ID3D11Texture2D, &d3d11Texture); +/// ovr_GetTextureSwapChainBufferDX(session, chain, 1, IID_PPV_ARGS(&dxgiResource)); +/// \endcode +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainBufferDX(ovrSession session, + ovrTextureSwapChain chain, + int index, + IID iid, + void** out_Buffer); + + +/// Create Mirror Texture which is auto-refreshed to mirror Rift contents produced by this application. +/// +/// A second call to ovr_CreateMirrorTextureDX for a given ovrSession before destroying the first one +/// is not supported and will result in an error return. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] d3dPtr Specifies the application's D3D11Device to create resources with or the D3D12CommandQueue +/// which must be the same one the application renders to the textures with. +/// \param[in] desc Specifies requested texture properties. See notes for more info about texture format. +/// \param[out] out_MirrorTexture Returns the created ovrMirrorTexture, which will be valid upon a successful return value, else it will be NULL. +/// This texture must be eventually destroyed via ovr_DestroyMirrorTexture before destroying the HMD with ovr_Destroy. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +/// \note The texture format provided in \a desc should be thought of as the format the compositor will use for the RenderTargetView when +/// writing into mirror texture. To that end, it is highly recommended that the application requests a mirror texture format that is +/// in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the compositor does sRGB-correct rendering. If however the application wants +/// to still read the mirror texture as a linear format (e.g. OVR_FORMAT_R8G8B8A8_UNORM) and handle the sRGB-to-linear conversion in +/// HLSL code, then it is recommended the application still requests an sRGB format and also use the \a ovrTextureMisc_DX_Typeless flag in the +/// ovrMirrorTextureDesc's Flags field. This will allow the application to bind a ShaderResourceView that is a linear format while the +/// compositor continues to treat is as sRGB. Failure to do so will cause the compositor to apply unexpected gamma conversions leading to +/// gamma-curve artifacts. +/// +/// +/// Example code +/// \code{.cpp} +/// ovrMirrorTexture mirrorTexture = nullptr; +/// ovrMirrorTextureDesc mirrorDesc = {}; +/// mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; +/// mirrorDesc.Width = mirrorWindowWidth; +/// mirrorDesc.Height = mirrorWindowHeight; +/// ovrResult result = ovr_CreateMirrorTextureDX(session, d3d11Device, &mirrorDesc, &mirrorTexture); +/// [...] +/// // Destroy the texture when done with it. +/// ovr_DestroyMirrorTexture(session, mirrorTexture); +/// mirrorTexture = nullptr; +/// \endcode +/// +/// \see ovr_GetMirrorTextureBufferDX +/// \see ovr_DestroyMirrorTexture +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateMirrorTextureDX(ovrSession session, + IUnknown* d3dPtr, + const ovrMirrorTextureDesc* desc, + ovrMirrorTexture* out_MirrorTexture); + +/// Get a the underlying buffer as any compatible COM interface (similar to QueryInterface) +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] mirrorTexture Specifies an ovrMirrorTexture previously returned by ovr_CreateMirrorTextureDX +/// \param[in] iid Specifies the interface ID of the interface pointer to query the buffer for. +/// \param[out] out_Buffer Returns the COM interface pointer retrieved. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +/// Example code +/// \code{.cpp} +/// ID3D11Texture2D* d3d11Texture = nullptr; +/// ovr_GetMirrorTextureBufferDX(session, mirrorTexture, IID_PPV_ARGS(&d3d11Texture)); +/// d3d11DeviceContext->CopyResource(d3d11TextureBackBuffer, d3d11Texture); +/// d3d11Texture->Release(); +/// dxgiSwapChain->Present(0, 0); +/// \endcode +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetMirrorTextureBufferDX(ovrSession session, + ovrMirrorTexture mirrorTexture, + IID iid, + void** out_Buffer); + + +#endif // _WIN32 + +#endif // OVR_CAPI_D3D_h diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h new file mode 100644 index 000000000..1658ca578 --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h @@ -0,0 +1,99 @@ +/********************************************************************************//** +\file OVR_CAPI_GL.h +\brief OpenGL-specific structures used by the CAPI interface. +\copyright Copyright 2015 Oculus VR, LLC. All Rights reserved. +************************************************************************************/ + +#ifndef OVR_CAPI_GL_h +#define OVR_CAPI_GL_h + +#include "OVR_CAPI.h" + +/// Creates a TextureSwapChain suitable for use with OpenGL. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] desc Specifies the requested texture properties. See notes for more info about texture format. +/// \param[out] out_TextureSwapChain Returns the created ovrTextureSwapChain, which will be valid upon +/// a successful return value, else it will be NULL. This texture swap chain must be eventually +/// destroyed via ovr_DestroyTextureSwapChain before destroying the HMD with ovr_Destroy. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +/// \note The \a format provided should be thought of as the format the distortion compositor will use when reading +/// the contents of the texture. To that end, it is highly recommended that the application requests texture swap chain +/// formats that are in sRGB-space (e.g. OVR_FORMAT_R8G8B8A8_UNORM_SRGB) as the distortion compositor does sRGB-correct +/// rendering. Furthermore, the app should then make sure "glEnable(GL_FRAMEBUFFER_SRGB);" is called before rendering +/// into these textures. Even though it is not recommended, if the application would like to treat the texture as a linear +/// format and do linear-to-gamma conversion in GLSL, then the application can avoid calling "glEnable(GL_FRAMEBUFFER_SRGB);", +/// but should still pass in an sRGB variant for the \a format. Failure to do so will cause the distortion compositor +/// to apply incorrect gamma conversions leading to gamma-curve artifacts. +/// +/// \see ovr_GetTextureSwapChainLength +/// \see ovr_GetTextureSwapChainCurrentIndex +/// \see ovr_GetTextureSwapChainDesc +/// \see ovr_GetTextureSwapChainBufferGL +/// \see ovr_DestroyTextureSwapChain +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateTextureSwapChainGL(ovrSession session, + const ovrTextureSwapChainDesc* desc, + ovrTextureSwapChain* out_TextureSwapChain); + +/// Get a specific buffer within the chain as a GL texture name +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] chain Specifies an ovrTextureSwapChain previously returned by ovr_CreateTextureSwapChainGL +/// \param[in] index Specifies the index within the chain to retrieve. Must be between 0 and length (see ovr_GetTextureSwapChainLength) +/// or may pass -1 to get the buffer at the CurrentIndex location. (Saving a call to GetTextureSwapChainCurrentIndex) +/// \param[out] out_TexId Returns the GL texture object name associated with the specific index requested +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainBufferGL(ovrSession session, + ovrTextureSwapChain chain, + int index, + unsigned int* out_TexId); + + +/// Creates a Mirror Texture which is auto-refreshed to mirror Rift contents produced by this application. +/// +/// A second call to ovr_CreateMirrorTextureGL for a given ovrSession before destroying the first one +/// is not supported and will result in an error return. +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] desc Specifies the requested mirror texture description. +/// \param[out] out_MirrorTexture Specifies the created ovrMirrorTexture, which will be valid upon a successful return value, else it will be NULL. +/// This texture must be eventually destroyed via ovr_DestroyMirrorTexture before destroying the HMD with ovr_Destroy. +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +/// \note The \a format provided should be thought of as the format the distortion compositor will use when writing into the mirror +/// texture. It is highly recommended that mirror textures are requested as sRGB formats because the distortion compositor +/// does sRGB-correct rendering. If the application requests a non-sRGB format (e.g. R8G8B8A8_UNORM) as the mirror texture, +/// then the application might have to apply a manual linear-to-gamma conversion when reading from the mirror texture. +/// Failure to do so can result in incorrect gamma conversions leading to gamma-curve artifacts and color banding. +/// +/// \see ovr_GetMirrorTextureBufferGL +/// \see ovr_DestroyMirrorTexture +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_CreateMirrorTextureGL(ovrSession session, + const ovrMirrorTextureDesc* desc, + ovrMirrorTexture* out_MirrorTexture); + +/// Get a the underlying buffer as a GL texture name +/// +/// \param[in] session Specifies an ovrSession previously returned by ovr_Create. +/// \param[in] mirrorTexture Specifies an ovrMirrorTexture previously returned by ovr_CreateMirrorTextureGL +/// \param[out] out_TexId Specifies the GL texture object name associated with the mirror texture +/// +/// \return Returns an ovrResult indicating success or failure. In the case of failure, use +/// ovr_GetLastErrorInfo to get more information. +/// +OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetMirrorTextureBufferGL(ovrSession session, + ovrMirrorTexture mirrorTexture, + unsigned int* out_TexId); + + +#endif // OVR_CAPI_GL_h diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h new file mode 100644 index 000000000..e3e9d689c --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Keys.h @@ -0,0 +1,53 @@ +/********************************************************************************//** +\file OVR_CAPI.h +\brief Keys for CAPI proprty function calls +\copyright Copyright 2015 Oculus VR, LLC All Rights reserved. +************************************************************************************/ + +#ifndef OVR_CAPI_Keys_h +#define OVR_CAPI_Keys_h + +#include "OVR_Version.h" + + + +#define OVR_KEY_USER "User" // string + +#define OVR_KEY_NAME "Name" // string + +#define OVR_KEY_GENDER "Gender" // string "Male", "Female", or "Unknown" +#define OVR_DEFAULT_GENDER "Unknown" + +#define OVR_KEY_PLAYER_HEIGHT "PlayerHeight" // float meters +#define OVR_DEFAULT_PLAYER_HEIGHT 1.778f + +#define OVR_KEY_EYE_HEIGHT "EyeHeight" // float meters +#define OVR_DEFAULT_EYE_HEIGHT 1.675f + +#define OVR_KEY_NECK_TO_EYE_DISTANCE "NeckEyeDistance" // float[2] meters +#define OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL 0.0805f +#define OVR_DEFAULT_NECK_TO_EYE_VERTICAL 0.075f + + +#define OVR_KEY_EYE_TO_NOSE_DISTANCE "EyeToNoseDist" // float[2] meters + + + + + +#define OVR_PERF_HUD_MODE "PerfHudMode" // int, allowed values are defined in enum ovrPerfHudMode + +#define OVR_LAYER_HUD_MODE "LayerHudMode" // int, allowed values are defined in enum ovrLayerHudMode +#define OVR_LAYER_HUD_CURRENT_LAYER "LayerHudCurrentLayer" // int, The layer to show +#define OVR_LAYER_HUD_SHOW_ALL_LAYERS "LayerHudShowAll" // bool, Hide other layers when the hud is enabled + +#define OVR_DEBUG_HUD_STEREO_MODE "DebugHudStereoMode" // int, allowed values are defined in enum ovrDebugHudStereoMode +#define OVR_DEBUG_HUD_STEREO_GUIDE_INFO_ENABLE "DebugHudStereoGuideInfoEnable" // bool +#define OVR_DEBUG_HUD_STEREO_GUIDE_SIZE "DebugHudStereoGuideSize2f" // float[2] +#define OVR_DEBUG_HUD_STEREO_GUIDE_POSITION "DebugHudStereoGuidePosition3f" // float[3] +#define OVR_DEBUG_HUD_STEREO_GUIDE_YAWPITCHROLL "DebugHudStereoGuideYawPitchRoll3f" // float[3] +#define OVR_DEBUG_HUD_STEREO_GUIDE_COLOR "DebugHudStereoGuideColor4f" // float[4] + + + +#endif // OVR_CAPI_Keys_h diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h b/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h new file mode 100644 index 000000000..ed0be0e70 --- /dev/null +++ b/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h @@ -0,0 +1,209 @@ +/********************************************************************************//** +\file OVR_ErrorCode.h +\brief This header provides LibOVR error code declarations. +\copyright Copyright 2015-2016 Oculus VR, LLC All Rights reserved. +*************************************************************************************/ + +#ifndef OVR_ErrorCode_h +#define OVR_ErrorCode_h + + +#include "OVR_Version.h" +#include + + + + + + + +#ifndef OVR_RESULT_DEFINED +#define OVR_RESULT_DEFINED ///< Allows ovrResult to be independently defined. +/// API call results are represented at the highest level by a single ovrResult. +typedef int32_t ovrResult; +#endif + + +/// \brief Indicates if an ovrResult indicates success. +/// +/// Some functions return additional successful values other than ovrSucces and +/// require usage of this macro to indicate successs. +/// +#if !defined(OVR_SUCCESS) + #define OVR_SUCCESS(result) (result >= 0) +#endif + + +/// \brief Indicates if an ovrResult indicates an unqualified success. +/// +/// This is useful for indicating that the code intentionally wants to +/// check for result == ovrSuccess as opposed to OVR_SUCCESS(), which +/// checks for result >= ovrSuccess. +/// +#if !defined(OVR_UNQUALIFIED_SUCCESS) + #define OVR_UNQUALIFIED_SUCCESS(result) (result == ovrSuccess) +#endif + + +/// \brief Indicates if an ovrResult indicates failure. +/// +#if !defined(OVR_FAILURE) + #define OVR_FAILURE(result) (!OVR_SUCCESS(result)) +#endif + + +// Success is a value greater or equal to 0, while all error types are negative values. +#ifndef OVR_SUCCESS_DEFINED +#define OVR_SUCCESS_DEFINED ///< Allows ovrResult to be independently defined. +typedef enum ovrSuccessType_ +{ + /// This is a general success result. Use OVR_SUCCESS to test for success. + ovrSuccess = 0, + + /// Returned from a call to SubmitFrame. The call succeeded, but what the app + /// rendered will not be visible on the HMD. Ideally the app should continue + /// calling SubmitFrame, but not do any rendering. When the result becomes + /// ovrSuccess, rendering should continue as usual. + ovrSuccess_NotVisible = 1000, + + ovrSuccess_HMDFirmwareMismatch = 4100, ///< The HMD Firmware is out of date but is acceptable. + ovrSuccess_TrackerFirmwareMismatch = 4101, ///< The Tracker Firmware is out of date but is acceptable. + ovrSuccess_ControllerFirmwareMismatch = 4104, ///< The controller firmware is out of date but is acceptable. + ovrSuccess_TrackerDriverNotFound = 4105, ///< The tracker driver interface was not found. Can be a temporary error + +} ovrSuccessType; +#endif + + +typedef enum ovrErrorType_ +{ + /* General errors */ + ovrError_MemoryAllocationFailure = -1000, ///< Failure to allocate memory. + ovrError_SocketCreationFailure = -1001, ///< Failure to create a socket. + ovrError_InvalidSession = -1002, ///< Invalid ovrSession parameter provided. + ovrError_Timeout = -1003, ///< The operation timed out. + ovrError_NotInitialized = -1004, ///< The system or component has not been initialized. + ovrError_InvalidParameter = -1005, ///< Invalid parameter provided. See error info or log for details. + ovrError_ServiceError = -1006, ///< Generic service error. See error info or log for details. + ovrError_NoHmd = -1007, ///< The given HMD doesn't exist. + ovrError_Unsupported = -1009, ///< Function call is not supported on this hardware/software + ovrError_DeviceUnavailable = -1010, ///< Specified device type isn't available. + ovrError_InvalidHeadsetOrientation = -1011, ///< The headset was in an invalid orientation for the requested operation (e.g. vertically oriented during ovr_RecenterPose). + ovrError_ClientSkippedDestroy = -1012, ///< The client failed to call ovr_Destroy on an active session before calling ovr_Shutdown. Or the client crashed. + ovrError_ClientSkippedShutdown = -1013, ///< The client failed to call ovr_Shutdown or the client crashed. + ovrError_ServiceDeadlockDetected = -1014, ///< The service watchdog discovered a deadlock. + + /* Audio error range, reserved for Audio errors. */ + ovrError_AudioReservedBegin = -2000, ///< First Audio error. + ovrError_AudioDeviceNotFound = -2001, ///< Failure to find the specified audio device. + ovrError_AudioComError = -2002, ///< Generic COM error. + ovrError_AudioReservedEnd = -2999, ///< Last Audio error. + + /* Initialization errors. */ + ovrError_Initialize = -3000, ///< Generic initialization error. + ovrError_LibLoad = -3001, ///< Couldn't load LibOVRRT. + ovrError_LibVersion = -3002, ///< LibOVRRT version incompatibility. + ovrError_ServiceConnection = -3003, ///< Couldn't connect to the OVR Service. + ovrError_ServiceVersion = -3004, ///< OVR Service version incompatibility. + ovrError_IncompatibleOS = -3005, ///< The operating system version is incompatible. + ovrError_DisplayInit = -3006, ///< Unable to initialize the HMD display. + ovrError_ServerStart = -3007, ///< Unable to start the server. Is it already running? + ovrError_Reinitialization = -3008, ///< Attempting to re-initialize with a different version. + ovrError_MismatchedAdapters = -3009, ///< Chosen rendering adapters between client and service do not match + ovrError_LeakingResources = -3010, ///< Calling application has leaked resources + ovrError_ClientVersion = -3011, ///< Client version too old to connect to service + ovrError_OutOfDateOS = -3012, ///< The operating system is out of date. + ovrError_OutOfDateGfxDriver = -3013, ///< The graphics driver is out of date. + ovrError_IncompatibleGPU = -3014, ///< The graphics hardware is not supported + ovrError_NoValidVRDisplaySystem = -3015, ///< No valid VR display system found. + ovrError_Obsolete = -3016, ///< Feature or API is obsolete and no longer supported. + ovrError_DisabledOrDefaultAdapter = -3017, ///< No supported VR display system found, but disabled or driverless adapter found. + ovrError_HybridGraphicsNotSupported = -3018, ///< The system is using hybrid graphics (Optimus, etc...), which is not support. + ovrError_DisplayManagerInit = -3019, ///< Initialization of the DisplayManager failed. + ovrError_TrackerDriverInit = -3020, ///< Failed to get the interface for an attached tracker + + /* Hardware errors */ + ovrError_InvalidBundleAdjustment = -4000, ///< Headset has no bundle adjustment data. + ovrError_USBBandwidth = -4001, ///< The USB hub cannot handle the camera frame bandwidth. + ovrError_USBEnumeratedSpeed = -4002, ///< The USB camera is not enumerating at the correct device speed. + ovrError_ImageSensorCommError = -4003, ///< Unable to communicate with the image sensor. + ovrError_GeneralTrackerFailure = -4004, ///< We use this to report various sensor issues that don't fit in an easily classifiable bucket. + ovrError_ExcessiveFrameTruncation = -4005, ///< A more than acceptable number of frames are coming back truncated. + ovrError_ExcessiveFrameSkipping = -4006, ///< A more than acceptable number of frames have been skipped. + ovrError_SyncDisconnected = -4007, ///< The sensor is not receiving the sync signal (cable disconnected?). + ovrError_TrackerMemoryReadFailure = -4008, ///< Failed to read memory from the sensor. + ovrError_TrackerMemoryWriteFailure = -4009, ///< Failed to write memory from the sensor. + ovrError_TrackerFrameTimeout = -4010, ///< Timed out waiting for a camera frame. + ovrError_TrackerTruncatedFrame = -4011, ///< Truncated frame returned from sensor. + ovrError_TrackerDriverFailure = -4012, ///< The sensor driver has encountered a problem. + ovrError_TrackerNRFFailure = -4013, ///< The sensor wireless subsystem has encountered a problem. + ovrError_HardwareGone = -4014, ///< The hardware has been unplugged + ovrError_NordicEnabledNoSync = -4015, ///< The nordic indicates that sync is enabled but it is not sending sync pulses + ovrError_NordicSyncNoFrames = -4016, ///< It looks like we're getting a sync signal, but no camera frames have been received + ovrError_CatastrophicFailure = -4017, ///< A catastrophic failure has occurred. We will attempt to recover by resetting the device + ovrError_CatastrophicTimeout = -4018, ///< The catastrophic recovery has timed out. + ovrError_RepeatCatastrophicFail = -4019, ///< Catastrophic failure has repeated too many times. + ovrError_USBOpenDeviceFailure = -4020, ///< Could not open handle for Rift device (likely already in use by another process). + ovrError_HMDGeneralFailure = -4021, ///< Unexpected HMD issues that don't fit a specific bucket. + + ovrError_HMDFirmwareMismatch = -4100, ///< The HMD Firmware is out of date and is unacceptable. + ovrError_TrackerFirmwareMismatch = -4101, ///< The sensor Firmware is out of date and is unacceptable. + ovrError_BootloaderDeviceDetected = -4102, ///< A bootloader HMD is detected by the service. + ovrError_TrackerCalibrationError = -4103, ///< The sensor calibration is missing or incorrect. + ovrError_ControllerFirmwareMismatch = -4104, ///< The controller firmware is out of date and is unacceptable. + ovrError_DevManDeviceDetected = -4105, ///< A DeviceManagement mode HMD is detected by the service. + ovrError_RebootedBootloaderDevice = -4106, ///< Had to reboot bootloader device, which succeeded. + ovrError_FailedRebootBootloaderDev = -4107, ///< Had to reboot bootloader device, which failed. Device is stuck in bootloader mode. + + ovrError_IMUTooManyLostSamples = -4200, ///< Too many lost IMU samples. + ovrError_IMURateError = -4201, ///< IMU rate is outside of the expected range. + ovrError_FeatureReportFailure = -4202, ///< A feature report has failed. + ovrError_HMDWirelessTimeout = -4203, ///< HMD wireless interface never returned from busy state. + + ovrError_BootloaderAssertLog = -4300, ///< HMD Bootloader Assert Log was not empty. + ovrError_AppAssertLog = -4301, ///< HMD App Assert Log was not empty. + + /* Synchronization errors */ + ovrError_Incomplete = -5000, ///< Requested async work not yet complete. + ovrError_Abandoned = -5001, ///< Requested async work was abandoned and result is incomplete. + + /* Rendering errors */ + ovrError_DisplayLost = -6000, ///< In the event of a system-wide graphics reset or cable unplug this is returned to the app. + ovrError_TextureSwapChainFull = -6001, ///< ovr_CommitTextureSwapChain was called too many times on a texture swapchain without calling submit to use the chain. + ovrError_TextureSwapChainInvalid = -6002, ///< The ovrTextureSwapChain is in an incomplete or inconsistent state. Ensure ovr_CommitTextureSwapChain was called at least once first. + ovrError_GraphicsDeviceReset = -6003, ///< Graphics device has been reset (TDR, etc...) + ovrError_DisplayRemoved = -6004, ///< HMD removed from the display adapter + ovrError_ContentProtectionNotAvailable = -6005,/// Date: Tue, 14 Jun 2016 17:16:20 +0200 Subject: [PATCH 06/11] Move Oculus Rift support to rlgl module --- src/core.c | 386 +------------------------------------------------- src/raylib.h | 19 ++- src/rlgl.c | 390 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/rlgl.h | 9 ++ 4 files changed, 399 insertions(+), 405 deletions(-) diff --git a/src/core.c b/src/core.c index bd49b5494..fb71af211 100644 --- a/src/core.c +++ b/src/core.c @@ -9,7 +9,7 @@ * PLATFORM_ANDROID - Only OpenGL ES 2.0 devices * PLATFORM_RPI - Rapsberry Pi (tested on Raspbian) * PLATFORM_WEB - Emscripten, HTML5 -* PLATFORM_OCULUS - Oculus Rift CV1 (with desktop mirror) +* Oculus Rift CV1 (with desktop mirror) - View [rlgl] module to enable it * * On PLATFORM_DESKTOP, the external lib GLFW3 (www.glfw.com) is used to manage graphic * device, OpenGL context and input on multiple operating systems (Windows, Linux, OSX). @@ -54,14 +54,6 @@ #include // String function definitions, memset() #include // Macros for reporting and retrieving error conditions through error codes -#if defined(PLATFORM_OCULUS) - #define PLATFORM_DESKTOP // Enable PLATFORM_DESKTOP code-base -#endif - -#if defined(PLATFORM_OCULUS) - #include "../examples/oculus_glfw_sample/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL -#endif - #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 #include // GLFW3 library: Windows, OpenGL context and Input management @@ -134,31 +126,7 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -#if defined(PLATFORM_OCULUS) -typedef struct OculusBuffer { - ovrTextureSwapChain textureChain; - GLuint depthId; - GLuint fboId; - int width; - int height; -} OculusBuffer; - -typedef struct OculusMirror { - ovrMirrorTexture texture; - GLuint fboId; - int width; - int height; -} OculusMirror; - -typedef struct OculusLayer { - ovrViewScaleDesc viewScaleDesc; - ovrLayerEyeFov eyeLayer; // layer 0 - //ovrLayerQuad quadLayer; // TODO: layer 1: '2D' quad for GUI - Matrix eyeProjections[2]; - int width; - int height; -} OculusLayer; -#endif +// ... //---------------------------------------------------------------------------------- // Global Variables Definition @@ -213,17 +181,6 @@ static uint64_t baseTime; // Base time measure for hi-res timer static bool windowShouldClose = false; // Flag to set window for closing #endif -#if defined(PLATFORM_OCULUS) -// OVR device variables -static ovrSession session; // Oculus session (pointer to ovrHmdStruct) -static ovrHmdDesc hmdDesc; // Oculus device descriptor parameters -static ovrGraphicsLuid luid; // Oculus locally unique identifier for the program (64 bit) -static OculusLayer layer; // Oculus drawing layer (similar to photoshop) -static OculusBuffer buffer; // Oculus internal buffers (texture chain and fbo) -static OculusMirror mirror; // Oculus mirror texture and fbo -static unsigned int frameIndex = 0; // Oculus frames counter, used to discard frames from chain -#endif - static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...) static int screenWidth, screenHeight; // Screen width and height (used render area) static int renderWidth, renderHeight; // Framebuffer width and height (render area) @@ -233,7 +190,6 @@ static int renderOffsetX = 0; // Offset X from render area (must b static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2) static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) -static Matrix cameraView; // Store camera view matrix (required for Oculus Rift) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) static const char *windowTitle; // Window text title... @@ -332,19 +288,6 @@ static void InitGamepad(void); // Init raw gamepad inpu static void *GamepadThread(void *arg); // Mouse reading thread #endif -#if defined(PLATFORM_OCULUS) -// Oculus Rift functions -static Matrix FromOvrMatrix(ovrMatrix4f ovrM); -static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height); -static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer); -static void SetOculusBuffer(ovrSession session, OculusBuffer buffer); -static void UnsetOculusBuffer(OculusBuffer buffer); -static OculusMirror LoadOculusMirror(ovrSession session, int width, int height); // Load Oculus mirror buffers -static void UnloadOculusMirror(ovrSession session, OculusMirror mirror); // Unload Oculus mirror buffers -static void BlitOculusMirror(ovrSession session, OculusMirror mirror); -static OculusLayer InitOculusLayer(ovrSession session); -#endif - //---------------------------------------------------------------------------------- // Module Functions Definition - Window and OpenGL Context Functions //---------------------------------------------------------------------------------- @@ -393,11 +336,6 @@ void InitWindow(int width, int height, const char *title) //emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenInputCallback); #endif -#if defined(PLATFORM_OCULUS) - // Recenter OVR tracking origin - ovr_RecenterTrackingOrigin(session); -#endif - mousePosition.x = (float)screenWidth/2.0f; mousePosition.y = (float)screenHeight/2.0f; @@ -512,64 +450,6 @@ void CloseWindow(void) TraceLog(INFO, "Window closed successfully"); } -#if defined(PLATFORM_OCULUS) -// Init Oculus Rift device -// NOTE: Device initialization should be done before window creation? -void InitOculusDevice(void) -{ - // Initialize Oculus device - ovrResult result = ovr_Initialize(NULL); - if (OVR_FAILURE(result)) TraceLog(WARNING, "OVR: Could not initialize Oculus device"); - - result = ovr_Create(&session, &luid); - if (OVR_FAILURE(result)) - { - TraceLog(WARNING, "OVR: Could not create Oculus session"); - ovr_Shutdown(); - } - - hmdDesc = ovr_GetHmdDesc(session); - - TraceLog(INFO, "OVR: Product Name: %s", hmdDesc.ProductName); - TraceLog(INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer); - TraceLog(INFO, "OVR: Product ID: %i", hmdDesc.ProductId); - TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type); - //TraceLog(INFO, "OVR: Serial Number: %s", hmdDesc.SerialNumber); - TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); - - // NOTE: Oculus mirror is set to defined screenWidth and screenHeight... - // ...ideally, it should be (hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2) - - // Initialize Oculus Buffers - layer = InitOculusLayer(session); - buffer = LoadOculusBuffer(session, layer.width, layer.height); - mirror = LoadOculusMirror(session, screenWidth, screenHeight); - layer.eyeLayer.ColorTexture[0] = buffer.textureChain; //SetOculusLayerTexture(eyeLayer, buffer.textureChain); -} - -// Close Oculus Rift device -void CloseOculusDevice(void) -{ - UnloadOculusMirror(session, mirror); // Unload Oculus mirror buffer - UnloadOculusBuffer(session, buffer); // Unload Oculus texture buffers - - ovr_Destroy(session); // Free Oculus session data - ovr_Shutdown(); // Close Oculus device connection -} - -// Update Oculus Rift tracking (position and orientation) -void UpdateOculusTracking(void) -{ - frameIndex++; - - ovrPosef eyePoses[2]; - ovr_GetEyePoses(session, frameIndex, ovrTrue, layer.viewScaleDesc.HmdToEyeOffset, eyePoses, &layer.eyeLayer.SensorSampleTime); - - layer.eyeLayer.RenderPose[0] = eyePoses[0]; - layer.eyeLayer.RenderPose[1] = eyePoses[1]; -} -#endif - // Detect if KEY_ESCAPE pressed or Close icon pressed bool WindowShouldClose(void) { @@ -638,10 +518,6 @@ void BeginDrawing(void) currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called updateTime = currentTime - previousTime; previousTime = currentTime; - -#if defined(PLATFORM_OCULUS) - SetOculusBuffer(session, buffer); -#endif rlClearScreenBuffers(); // Clear current framebuffers rlLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -654,49 +530,7 @@ void BeginDrawing(void) // End canvas drawing and Swap Buffers (Double Buffering) void EndDrawing(void) { -#if defined(PLATFORM_OCULUS) - for (int eye = 0; eye < 2; eye++) - { - rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y, layer.eyeLayer.Viewport[eye].Size.w, layer.eyeLayer.Viewport[eye].Size.h); - - Quaternion eyeRPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x, - layer.eyeLayer.RenderPose[eye].Orientation.y, - layer.eyeLayer.RenderPose[eye].Orientation.z, - layer.eyeLayer.RenderPose[eye].Orientation.w }; - QuaternionInvert(&eyeRPose); - Matrix eyeOrientation = QuaternionToMatrix(eyeRPose); - Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x, - -layer.eyeLayer.RenderPose[eye].Position.y, - -layer.eyeLayer.RenderPose[eye].Position.z); - - Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); - Matrix modelEyeView = MatrixMultiply(cameraView, eyeView); // Using internal camera modelview matrix - - SetMatrixModelview(modelEyeView); - SetMatrixProjection(layer.eyeProjections[eye]); -#endif - - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - -#if defined(PLATFORM_OCULUS) - } - - UnsetOculusBuffer(buffer); - - ovr_CommitTextureSwapChain(session, buffer.textureChain); - - ovrLayerHeader *layers = &layer.eyeLayer.Header; - ovr_SubmitFrame(session, frameIndex, &layer.viewScaleDesc, &layers, 1); - - // Blit mirror texture to back buffer - BlitOculusMirror(session, mirror); - - // Get session status information - ovrSessionStatus sessionStatus; - ovr_GetSessionStatus(session, &sessionStatus); - if (sessionStatus.ShouldQuit) TraceLog(WARNING, "OVR: Session should quit..."); - if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session); -#endif + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events @@ -768,7 +602,7 @@ void Begin3dMode(Camera camera) rlLoadIdentity(); // Reset current matrix (MODELVIEW) // Setup Camera view - cameraView = MatrixLookAt(camera.position, camera.target, camera.up); + Matrix cameraView = MatrixLookAt(camera.position, camera.target, camera.up); rlMultMatrixf(MatrixToFloat(cameraView)); // Multiply MODELVIEW matrix by view matrix (camera) rlEnableDepthTest(); // Enable DEPTH_TEST for 3D @@ -1738,9 +1572,7 @@ static void InitDisplay(int width, int height) #endif glfwMakeContextCurrent(window); -#if defined(PLATFORM_OCULUS) - glfwSwapInterval(0); -#endif + glfwSwapInterval(0); // Disable VSync by default #if defined(PLATFORM_DESKTOP) // Load OpenGL 3.3 extensions @@ -2940,214 +2772,6 @@ static void *GamepadThread(void *arg) } #endif - -#if defined(PLATFORM_OCULUS) -// Convert from Oculus ovrMatrix4f struct to raymath Matrix struct -static Matrix FromOvrMatrix(ovrMatrix4f ovrmat) -{ - Matrix rmat; - - rmat.m0 = ovrmat.M[0][0]; - rmat.m1 = ovrmat.M[1][0]; - rmat.m2 = ovrmat.M[2][0]; - rmat.m3 = ovrmat.M[3][0]; - rmat.m4 = ovrmat.M[0][1]; - rmat.m5 = ovrmat.M[1][1]; - rmat.m6 = ovrmat.M[2][1]; - rmat.m7 = ovrmat.M[3][1]; - rmat.m8 = ovrmat.M[0][2]; - rmat.m9 = ovrmat.M[1][2]; - rmat.m10 = ovrmat.M[2][2]; - rmat.m11 = ovrmat.M[3][2]; - rmat.m12 = ovrmat.M[0][3]; - rmat.m13 = ovrmat.M[1][3]; - rmat.m14 = ovrmat.M[2][3]; - rmat.m15 = ovrmat.M[3][3]; - - MatrixTranspose(&rmat); - - return rmat; -} - -// Load Oculus required buffers: texture-swap-chain, fbo, texture-depth -static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) -{ - OculusBuffer buffer; - buffer.width = width; - buffer.height = height; - - // Create OVR texture chain - ovrTextureSwapChainDesc desc = {}; - desc.Type = ovrTexture_2D; - desc.ArraySize = 1; - desc.Width = width; - desc.Height = height; - desc.MipLevels = 1; - desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; // Requires glEnable(GL_FRAMEBUFFER_SRGB); - desc.SampleCount = 1; - desc.StaticImage = ovrFalse; - - ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain); - - if (!OVR_SUCCESS(result)) TraceLog(WARNING, "OVR: Failed to create swap textures buffer"); - - int textureCount = 0; - ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount); - - if (!OVR_SUCCESS(result) || !textureCount) TraceLog(WARNING, "OVR: Unable to count swap chain textures"); - - for (int i = 0; i < textureCount; ++i) - { - GLuint chainTexId; - ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, i, &chainTexId); - glBindTexture(GL_TEXTURE_2D, chainTexId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - glBindTexture(GL_TEXTURE_2D, 0); - - /* - // Setup framebuffer object (using depth texture) - glGenFramebuffers(1, &buffer.fboId); - glGenTextures(1, &buffer.depthId); - glBindTexture(GL_TEXTURE_2D, buffer.depthId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - */ - - // Setup framebuffer object (using depth renderbuffer) - glGenFramebuffers(1, &buffer.fboId); - glGenRenderbuffers(1, &buffer.depthId); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); - glBindRenderbuffer(GL_RENDERBUFFER, buffer.depthId); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, buffer.width, buffer.height); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, buffer.depthId); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - return buffer; -} - -// Unload texture required buffers -static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer) -{ - if (buffer.textureChain) - { - ovr_DestroyTextureSwapChain(session, buffer.textureChain); - buffer.textureChain = NULL; - } - - if (buffer.depthId != 0) glDeleteTextures(1, &buffer.depthId); - if (buffer.fboId != 0) glDeleteFramebuffers(1, &buffer.fboId); -} - -// Set current Oculus buffer -static void SetOculusBuffer(ovrSession session, OculusBuffer buffer) -{ - GLuint currentTexId; - int currentIndex; - - ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, ¤tIndex); - ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, ¤tTexId); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, currentTexId, 0); - //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, buffer.depthId, 0); // Already binded - - //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) - //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Required if OculusBuffer format is OVR_FORMAT_R8G8B8A8_UNORM_SRGB - glEnable(GL_FRAMEBUFFER_SRGB); -} - -// Unset Oculus buffer -static void UnsetOculusBuffer(OculusBuffer buffer) -{ - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - -// Load Oculus mirror buffers -static OculusMirror LoadOculusMirror(ovrSession session, int width, int height) -{ - OculusMirror mirror; - mirror.width = width; - mirror.height = height; - - ovrMirrorTextureDesc mirrorDesc; - memset(&mirrorDesc, 0, sizeof(mirrorDesc)); - mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; - mirrorDesc.Width = mirror.width; - mirrorDesc.Height = mirror.height; - - if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(WARNING, "Could not create mirror texture"); - - glGenFramebuffers(1, &mirror.fboId); - - return mirror; -} - -// Unload Oculus mirror buffers -static void UnloadOculusMirror(ovrSession session, OculusMirror mirror) -{ - if (mirror.fboId != 0) glDeleteFramebuffers(1, &mirror.fboId); - if (mirror.texture) ovr_DestroyMirrorTexture(session, mirror.texture); -} - -static void BlitOculusMirror(ovrSession session, OculusMirror mirror) -{ - GLuint mirrorTextureId; - - ovr_GetMirrorTextureBufferGL(session, mirror.texture, &mirrorTextureId); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fboId); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0); - glBlitFramebuffer(0, 0, mirror.width, mirror.height, 0, mirror.height, mirror.width, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); -} - -// Requires: session, hmdDesc -static OculusLayer InitOculusLayer(ovrSession session) -{ - OculusLayer layer = { 0 }; - - layer.viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; - - memset(&layer.eyeLayer, 0, sizeof(ovrLayerEyeFov)); - layer.eyeLayer.Header.Type = ovrLayerType_EyeFov; - layer.eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; - - ovrEyeRenderDesc eyeRenderDescs[2]; - - for (int eye = 0; eye < 2; eye++) - { - eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]); - ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(eyeRenderDescs[eye].Fov, 0.01f, 10000.0f, ovrProjection_None); //ovrProjection_ClipRangeOpenGL); - layer.eyeProjections[eye] = FromOvrMatrix(ovrPerspectiveProjection); // NOTE: struct ovrMatrix4f { float M[4][4] } --> struct Matrix - - layer.viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset; - layer.eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov; - - ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, layer.eyeLayer.Fov[eye], 1.0f); - layer.eyeLayer.Viewport[eye].Size = eyeSize; - layer.eyeLayer.Viewport[eye].Pos.x = layer.width; - layer.eyeLayer.Viewport[eye].Pos.y = 0; - - layer.height = eyeSize.h; //std::max(renderTargetSize.y, (uint32_t)eyeSize.h); - layer.width += eyeSize.w; - } - - return layer; -} -#endif - // Plays raylib logo appearing animation static void LogoAnimation(void) { diff --git a/src/raylib.h b/src/raylib.h index 9120ddc4b..0c9f0280f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -64,7 +64,7 @@ //#define PLATFORM_ANDROID // Android device //#define PLATFORM_RPI // Raspberry Pi //#define PLATFORM_WEB // HTML5 (emscripten, asm.js) -//#define PLATFORM_OCULUS // Oculus Rift CV1 +//#define RLGL_OCULUS_SUPPORT // Oculus Rift CV1 (complementary to PLATFORM_DESKTOP) // Security check in case no PLATFORM_* defined #if !defined(PLATFORM_DESKTOP) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_RPI) && !defined(PLATFORM_WEB) @@ -545,12 +545,6 @@ void InitWindow(int width, int height, struct android_app *state); // Init Andr void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics #endif -#if defined(PLATFORM_OCULUS) -void InitOculusDevice(void); // Init Oculus Rift device -void CloseOculusDevice(void); // Close Oculus Rift device -void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) -#endif - void CloseWindow(void); // Close Window and Terminate Context bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) @@ -852,6 +846,17 @@ void EndBlendMode(void); // End blend Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool void DestroyLight(Light light); // Destroy a light and take it out of the list +//------------------------------------------------------------------------------------ +// Oculus Rift CV1 Functions (Module: rlgl) +// NOTE: This functions are useless when using OpenGL 1.1 +//------------------------------------------------------------------------------------ +void InitOculusDevice(void); // Init Oculus Rift device +void CloseOculusDevice(void); // Close Oculus Rift device +void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) +void SetOculusMatrix(int eye); // Set internal projection and modelview matrix depending on eyes tracking data +void BeginOculusDrawing(void); // Begin Oculus drawing configuration +void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) + //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) //------------------------------------------------------------------------------------ diff --git a/src/rlgl.c b/src/rlgl.c index 26961ca9e..1e3928895 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -72,6 +72,10 @@ #include "standard_shader.h" // Standard shader to embed #endif +#if defined(RLGL_OCULUS_SUPPORT) + #include "external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -172,6 +176,32 @@ typedef struct { //Guint fboId; } DrawCall; +#if defined(RLGL_OCULUS_SUPPORT) +typedef struct OculusBuffer { + ovrTextureSwapChain textureChain; + GLuint depthId; + GLuint fboId; + int width; + int height; +} OculusBuffer; + +typedef struct OculusMirror { + ovrMirrorTexture texture; + GLuint fboId; + int width; + int height; +} OculusMirror; + +typedef struct OculusLayer { + ovrViewScaleDesc viewScaleDesc; + ovrLayerEyeFov eyeLayer; // layer 0 + //ovrLayerQuad quadLayer; // TODO: layer 1: '2D' quad for GUI + Matrix eyeProjections[2]; + int width; + int height; +} OculusLayer; +#endif + //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -221,6 +251,17 @@ static Light lights[MAX_LIGHTS]; // Lights pool static int lightsCount; // Counts current enabled physic objects #endif +#if defined(RLGL_OCULUS_SUPPORT) +// OVR device variables +static ovrSession session; // Oculus session (pointer to ovrHmdStruct) +static ovrHmdDesc hmdDesc; // Oculus device descriptor parameters +static ovrGraphicsLuid luid; // Oculus locally unique identifier for the program (64 bit) +static OculusLayer layer; // Oculus drawing layer (similar to photoshop) +static OculusBuffer buffer; // Oculus internal buffers (texture chain and fbo) +static OculusMirror mirror; // Oculus mirror texture and fbo +static unsigned int frameIndex = 0; // Oculus frames counter, used to discard frames from chain +#endif + // Compressed textures support flags static bool texCompDXTSupported = false; // DDS texture compression support static bool npotSupported = false; // NPOT textures full support @@ -261,6 +302,16 @@ static void SetShaderLights(Shader shader); // Sets shader uniform values for li static char *ReadTextFile(const char *fileName); #endif +#if defined(RLGL_OCULUS_SUPPORT) // Oculus Rift functions +static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height); // Load Oculus required buffers +static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer); // Unload texture required buffers +static OculusMirror LoadOculusMirror(ovrSession session, int width, int height); // Load Oculus mirror buffers +static void UnloadOculusMirror(ovrSession session, OculusMirror mirror); // Unload Oculus mirror buffers +static void BlitOculusMirror(ovrSession session, OculusMirror mirror); // Copy Oculus screen buffer to mirror texture +static OculusLayer InitOculusLayer(ovrSession session); // Init Oculus layer (similar to photoshop) +static Matrix FromOvrMatrix(ovrMatrix4f ovrM); // Convert from Oculus ovrMatrix4f struct to raymath Matrix struct +#endif + #if defined(GRAPHICS_API_OPENGL_11) static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight); static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight); @@ -872,23 +923,6 @@ int rlGetVersion(void) #endif } -// Load OpenGL extensions -// NOTE: External loader function could be passed as a pointer -void rlglLoadExtensions(void *loader) -{ -#if defined(GRAPHICS_API_OPENGL_33) - // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions - if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); - else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); - - if (GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); - else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); - - // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans - //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object -#endif -} - //---------------------------------------------------------------------------------- // Module Functions Definition - rlgl Functions //---------------------------------------------------------------------------------- @@ -1170,6 +1204,23 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height) TraceLog(INFO, "OpenGL graphic device initialized successfully"); } +// Load OpenGL extensions +// NOTE: External loader function could be passed as a pointer +void rlglLoadExtensions(void *loader) +{ +#if defined(GRAPHICS_API_OPENGL_33) + // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions + if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); + else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); + + if (GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); + else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); + + // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans + //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object +#endif +} + // Get world coordinates from screen coordinates Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view) { @@ -2410,6 +2461,130 @@ void DestroyLight(Light light) #endif } +#if defined(RLGL_OCULUS_SUPPORT) +// Init Oculus Rift device +// NOTE: Device initialization should be done before window creation? +void InitOculusDevice(void) +{ + // Initialize Oculus device + ovrResult result = ovr_Initialize(NULL); + if (OVR_FAILURE(result)) TraceLog(WARNING, "OVR: Could not initialize Oculus device"); + + result = ovr_Create(&session, &luid); + if (OVR_FAILURE(result)) + { + TraceLog(WARNING, "OVR: Could not create Oculus session"); + ovr_Shutdown(); + } + + hmdDesc = ovr_GetHmdDesc(session); + + TraceLog(INFO, "OVR: Product Name: %s", hmdDesc.ProductName); + TraceLog(INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer); + TraceLog(INFO, "OVR: Product ID: %i", hmdDesc.ProductId); + TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type); + //TraceLog(INFO, "OVR: Serial Number: %s", hmdDesc.SerialNumber); + TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); + + // NOTE: Oculus mirror is set to defined screenWidth and screenHeight... + // ...ideally, it should be (hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2) + + // Initialize Oculus Buffers + layer = InitOculusLayer(session); + buffer = LoadOculusBuffer(session, layer.width, layer.height); + mirror = LoadOculusMirror(session, hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2); // NOTE: hardcoded... + layer.eyeLayer.ColorTexture[0] = buffer.textureChain; //SetOculusLayerTexture(eyeLayer, buffer.textureChain); + + // Recenter OVR tracking origin + ovr_RecenterTrackingOrigin(session); +} + +// Close Oculus Rift device +void CloseOculusDevice(void) +{ + UnloadOculusMirror(session, mirror); // Unload Oculus mirror buffer + UnloadOculusBuffer(session, buffer); // Unload Oculus texture buffers + + ovr_Destroy(session); // Free Oculus session data + ovr_Shutdown(); // Close Oculus device connection +} + +// Update Oculus Rift tracking (position and orientation) +void UpdateOculusTracking(void) +{ + frameIndex++; + + ovrPosef eyePoses[2]; + ovr_GetEyePoses(session, frameIndex, ovrTrue, layer.viewScaleDesc.HmdToEyeOffset, eyePoses, &layer.eyeLayer.SensorSampleTime); + + layer.eyeLayer.RenderPose[0] = eyePoses[0]; + layer.eyeLayer.RenderPose[1] = eyePoses[1]; +} + +void SetOculusMatrix(int eye) +{ + rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y, layer.eyeLayer.Viewport[eye].Size.w, layer.eyeLayer.Viewport[eye].Size.h); + + Quaternion eyeRPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x, + layer.eyeLayer.RenderPose[eye].Orientation.y, + layer.eyeLayer.RenderPose[eye].Orientation.z, + layer.eyeLayer.RenderPose[eye].Orientation.w }; + QuaternionInvert(&eyeRPose); + Matrix eyeOrientation = QuaternionToMatrix(eyeRPose); + Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x, + -layer.eyeLayer.RenderPose[eye].Position.y, + -layer.eyeLayer.RenderPose[eye].Position.z); + + Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); + Matrix modelEyeView = MatrixMultiply(modelview, eyeView); // Using internal camera modelview matrix + + SetMatrixModelview(modelEyeView); + SetMatrixProjection(layer.eyeProjections[eye]); +} + +void BeginOculusDrawing(void) +{ + GLuint currentTexId; + int currentIndex; + + ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, ¤tIndex); + ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, ¤tTexId); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, currentTexId, 0); + //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, buffer.depthId, 0); // Already binded + + //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Same as rlClearScreenBuffers() + + // NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA) + // and performs linear-to-gamma conversion in GLSL or does not care about gamma-correction, then: + // - Require OculusBuffer format to be OVR_FORMAT_R8G8B8A8_UNORM_SRGB + // - Do NOT enable GL_FRAMEBUFFER_SRGB + //glEnable(GL_FRAMEBUFFER_SRGB); +} + +void EndOculusDrawing(void) +{ + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + ovr_CommitTextureSwapChain(session, buffer.textureChain); + + ovrLayerHeader *layers = &layer.eyeLayer.Header; + ovr_SubmitFrame(session, frameIndex, &layer.viewScaleDesc, &layers, 1); + + // Blit mirror texture to back buffer + BlitOculusMirror(session, mirror); + + // Get session status information + ovrSessionStatus sessionStatus; + ovr_GetSessionStatus(session, &sessionStatus); + if (sessionStatus.ShouldQuit) TraceLog(WARNING, "OVR: Session should quit..."); + if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session); +} +#endif + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -3390,6 +3565,187 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight) } #endif +#if defined(RLGL_OCULUS_SUPPORT) +// Load Oculus required buffers: texture-swap-chain, fbo, texture-depth +static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) +{ + OculusBuffer buffer; + buffer.width = width; + buffer.height = height; + + // Create OVR texture chain + ovrTextureSwapChainDesc desc = {}; + desc.Type = ovrTexture_2D; + desc.ArraySize = 1; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; // Requires glEnable(GL_FRAMEBUFFER_SRGB); + desc.SampleCount = 1; + desc.StaticImage = ovrFalse; + + ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain); + + if (!OVR_SUCCESS(result)) TraceLog(WARNING, "OVR: Failed to create swap textures buffer"); + + int textureCount = 0; + ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount); + + if (!OVR_SUCCESS(result) || !textureCount) TraceLog(WARNING, "OVR: Unable to count swap chain textures"); + + for (int i = 0; i < textureCount; ++i) + { + GLuint chainTexId; + ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, i, &chainTexId); + glBindTexture(GL_TEXTURE_2D, chainTexId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + glBindTexture(GL_TEXTURE_2D, 0); + + /* + // Setup framebuffer object (using depth texture) + glGenFramebuffers(1, &buffer.fboId); + glGenTextures(1, &buffer.depthId); + glBindTexture(GL_TEXTURE_2D, buffer.depthId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + */ + + // Setup framebuffer object (using depth renderbuffer) + glGenFramebuffers(1, &buffer.fboId); + glGenRenderbuffers(1, &buffer.depthId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); + glBindRenderbuffer(GL_RENDERBUFFER, buffer.depthId); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, buffer.width, buffer.height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, buffer.depthId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + return buffer; +} + +// Unload texture required buffers +static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer) +{ + if (buffer.textureChain) + { + ovr_DestroyTextureSwapChain(session, buffer.textureChain); + buffer.textureChain = NULL; + } + + if (buffer.depthId != 0) glDeleteTextures(1, &buffer.depthId); + if (buffer.fboId != 0) glDeleteFramebuffers(1, &buffer.fboId); +} + +// Load Oculus mirror buffers +static OculusMirror LoadOculusMirror(ovrSession session, int width, int height) +{ + OculusMirror mirror; + mirror.width = width; + mirror.height = height; + + ovrMirrorTextureDesc mirrorDesc; + memset(&mirrorDesc, 0, sizeof(mirrorDesc)); + mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + mirrorDesc.Width = mirror.width; + mirrorDesc.Height = mirror.height; + + if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(WARNING, "Could not create mirror texture"); + + glGenFramebuffers(1, &mirror.fboId); + + return mirror; +} + +// Unload Oculus mirror buffers +static void UnloadOculusMirror(ovrSession session, OculusMirror mirror) +{ + if (mirror.fboId != 0) glDeleteFramebuffers(1, &mirror.fboId); + if (mirror.texture) ovr_DestroyMirrorTexture(session, mirror.texture); +} + +// Copy Oculus screen buffer to mirror texture +static void BlitOculusMirror(ovrSession session, OculusMirror mirror) +{ + GLuint mirrorTextureId; + + ovr_GetMirrorTextureBufferGL(session, mirror.texture, &mirrorTextureId); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fboId); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0); + glBlitFramebuffer(0, 0, mirror.width, mirror.height, 0, mirror.height, mirror.width, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +} + +// Init Oculus layer (similar to photoshop) +static OculusLayer InitOculusLayer(ovrSession session) +{ + OculusLayer layer = { 0 }; + + layer.viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; + + memset(&layer.eyeLayer, 0, sizeof(ovrLayerEyeFov)); + layer.eyeLayer.Header.Type = ovrLayerType_EyeFov; + layer.eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; + + ovrEyeRenderDesc eyeRenderDescs[2]; + + for (int eye = 0; eye < 2; eye++) + { + eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]); + ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(eyeRenderDescs[eye].Fov, 0.01f, 10000.0f, ovrProjection_None); //ovrProjection_ClipRangeOpenGL); + layer.eyeProjections[eye] = FromOvrMatrix(ovrPerspectiveProjection); // NOTE: struct ovrMatrix4f { float M[4][4] } --> struct Matrix + + layer.viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset; + layer.eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov; + + ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, layer.eyeLayer.Fov[eye], 1.0f); + layer.eyeLayer.Viewport[eye].Size = eyeSize; + layer.eyeLayer.Viewport[eye].Pos.x = layer.width; + layer.eyeLayer.Viewport[eye].Pos.y = 0; + + layer.height = eyeSize.h; //std::max(renderTargetSize.y, (uint32_t)eyeSize.h); + layer.width += eyeSize.w; + } + + return layer; +} + +// Convert from Oculus ovrMatrix4f struct to raymath Matrix struct +static Matrix FromOvrMatrix(ovrMatrix4f ovrmat) +{ + Matrix rmat; + + rmat.m0 = ovrmat.M[0][0]; + rmat.m1 = ovrmat.M[1][0]; + rmat.m2 = ovrmat.M[2][0]; + rmat.m3 = ovrmat.M[3][0]; + rmat.m4 = ovrmat.M[0][1]; + rmat.m5 = ovrmat.M[1][1]; + rmat.m6 = ovrmat.M[2][1]; + rmat.m7 = ovrmat.M[3][1]; + rmat.m8 = ovrmat.M[0][2]; + rmat.m9 = ovrmat.M[1][2]; + rmat.m10 = ovrmat.M[2][2]; + rmat.m11 = ovrmat.M[3][2]; + rmat.m12 = ovrmat.M[0][3]; + rmat.m13 = ovrmat.M[1][3]; + rmat.m14 = ovrmat.M[2][3]; + rmat.m15 = ovrmat.M[3][3]; + + MatrixTranspose(&rmat); + + return rmat; +} +#endif + #if defined(RLGL_STANDALONE) // Output a trace log message // NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning diff --git a/src/rlgl.h b/src/rlgl.h index 28c50b8f2..1e77b771e 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -347,6 +347,15 @@ void DestroyLight(Light light); // Destroy a void TraceLog(int msgType, const char *text, ...); #endif +#if defined(RLGL_OCULUS_SUPPORT) +void InitOculusDevice(void); // Init Oculus Rift device +void CloseOculusDevice(void); // Close Oculus Rift device +void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) +void SetOculusMatrix(int eye); // Set internal projection and modelview matrix depending on eyes tracking data +void BeginOculusDrawing(void); // Begin Oculus drawing configuration +void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) +#endif + #ifdef __cplusplus } #endif From 97fc266ad461db9da51877341f6097660cbf305a Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 17:20:00 +0200 Subject: [PATCH 07/11] Updated raylib Oculus example --- examples/core_oculus_rift.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/examples/core_oculus_rift.c b/examples/core_oculus_rift.c index faf15d7f7..2871407b0 100644 --- a/examples/core_oculus_rift.c +++ b/examples/core_oculus_rift.c @@ -47,15 +47,24 @@ int main() BeginDrawing(); ClearBackground(RAYWHITE); + + BeginOculusDrawing(); + + for (int eye = 0; eye < 2; eye++) + { + Begin3dMode(camera); + + SetOculusMatrix(eye); + + DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); + DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); - Begin3dMode(camera); - - DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); - DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); - - DrawGrid(10, 1.0f); - - End3dMode(); + DrawGrid(10, 1.0f); + + End3dMode(); + } + + EndOculusDrawing() EndDrawing(); //---------------------------------------------------------------------------------- From d60dc7c2ebf151481e1148a9a6361b9687c48418 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 17:34:51 +0200 Subject: [PATCH 08/11] Added Oculus Rift library dll --- .gitignore | 4 +++- src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll | Bin 0 -> 964048 bytes 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll diff --git a/.gitignore b/.gitignore index 3a9084548..b221a37b9 100644 --- a/.gitignore +++ b/.gitignore @@ -66,8 +66,10 @@ src/libraylib.a src/libraylib.bc # oculus example -!examples/oculus_glfw_sample/LibOVRRT32_1.dll +!examples/oculus_glfw_sample/ + # external libraries DLLs !src/external/glfw3/lib/win32/glfw3.dll !src/external/openal_soft/lib/win32/OpenAL32.dll +!src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll \ No newline at end of file diff --git a/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll b/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll new file mode 100644 index 0000000000000000000000000000000000000000..70f63f7019536c1a296ddf354cf411c63819f275 GIT binary patch literal 964048 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

4uAaw!P6Dx?b1_!;>H98X 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%0AT7x0TA-V<^Wf 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 z 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 z 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 literal 0 HcmV?d00001 From 56bd9da07cbc6db9806380c79351ab0c5747c8f5 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 18:37:06 +0200 Subject: [PATCH 09/11] Update Oculus sample (will be moved soon) --- .../oculus_glfw_sample/oculus_glfw_sample.c | 50 +-- examples/oculus_glfw_sample/raymath.h | 18 +- examples/oculus_glfw_sample/rlgl.c | 421 +++++++++++++++++- examples/oculus_glfw_sample/rlgl.h | 12 +- examples/oculus_glfw_sample/standard_shader.h | 46 +- 5 files changed, 481 insertions(+), 66 deletions(-) diff --git a/examples/oculus_glfw_sample/oculus_glfw_sample.c b/examples/oculus_glfw_sample/oculus_glfw_sample.c index 73f19883d..8fddf5b93 100644 --- a/examples/oculus_glfw_sample/oculus_glfw_sample.c +++ b/examples/oculus_glfw_sample/oculus_glfw_sample.c @@ -23,8 +23,7 @@ #include #include -#define GLAD_IMPLEMENTATION -#include "glad.h" // Extensions loading library +#include "glad.h" #include // Windows/Context and inputs management #define RLGL_STANDALONE @@ -148,33 +147,34 @@ int main(void) glfwSwapInterval(0); // Load OpenGL 3.3 extensions - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) - { - TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); - return 3; - } - else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); + rlglLoadExtensions(glfwGetProcAddress); + + // Initialize rlgl internal buffers and OpenGL state + rlglInit(); + rlglInitGraphics(0, 0, screenWidth, screenHeight); + rlClearColor(245, 245, 245, 255); // Define clear color + rlEnableDepthTest(); // Enable DEPTH_TEST for 3D //-------------------------------------------------------- #if defined(PLATFORM_OCULUS) ovrResult result = ovr_Initialize(NULL); - if (OVR_FAILURE(result)) TraceLog(LOG_ERROR, "OVR: Could not initialize Oculus device"); + if (OVR_FAILURE(result)) TraceLog(ERROR, "OVR: Could not initialize Oculus device"); result = ovr_Create(&session, &luid); if (OVR_FAILURE(result)) { - TraceLog(LOG_WARNING, "OVR: Could not create Oculus session"); + TraceLog(WARNING, "OVR: Could not create Oculus session"); ovr_Shutdown(); } hmdDesc = ovr_GetHmdDesc(session); - TraceLog(LOG_INFO, "OVR: Product Name: %s", hmdDesc.ProductName); - TraceLog(LOG_INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer); - TraceLog(LOG_INFO, "OVR: Product ID: %i", hmdDesc.ProductId); - TraceLog(LOG_INFO, "OVR: Product Type: %i", hmdDesc.Type); - TraceLog(LOG_INFO, "OVR: Serian Number: %s", hmdDesc.SerialNumber); - TraceLog(LOG_INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); + TraceLog(INFO, "OVR: Product Name: %s", hmdDesc.ProductName); + TraceLog(INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer); + TraceLog(INFO, "OVR: Product ID: %i", hmdDesc.ProductId); + TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type); + TraceLog(INFO, "OVR: Serian Number: %s", hmdDesc.SerialNumber); + TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); //screenWidth = hmdDesc.Resolution.w/2; //screenHeight = hmdDesc.Resolution.h/2; @@ -188,20 +188,14 @@ int main(void) // Recenter OVR tracking origin ovr_RecenterTrackingOrigin(session); #endif - - // Initialize rlgl internal buffers and OpenGL state - rlglInit(); - rlglInitGraphics(0, 0, screenWidth, screenHeight); - rlClearColor(245, 245, 245, 255); // Define clear color - rlEnableDepthTest(); // Enable DEPTH_TEST for 3D - - Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; Camera camera; camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y + + Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; //-------------------------------------------------------------------------------------- // Main game loop @@ -293,7 +287,7 @@ int main(void) // Get session status information ovrSessionStatus sessionStatus; ovr_GetSessionStatus(session, &sessionStatus); - if (sessionStatus.ShouldQuit) TraceLog(LOG_WARNING, "OVR: Session should quit..."); + if (sessionStatus.ShouldQuit) TraceLog(WARNING, "OVR: Session should quit..."); if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session); #endif @@ -581,12 +575,12 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain); - if (!OVR_SUCCESS(result)) TraceLog(LOG_WARNING, "OVR: Failed to create swap textures buffer"); + if (!OVR_SUCCESS(result)) TraceLog(WARNING, "OVR: Failed to create swap textures buffer"); int textureCount = 0; ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount); - if (!OVR_SUCCESS(result) || !textureCount) TraceLog(LOG_WARNING, "OVR: Unable to count swap chain textures"); + if (!OVR_SUCCESS(result) || !textureCount) TraceLog(WARNING, "OVR: Unable to count swap chain textures"); for (int i = 0; i < textureCount; ++i) { @@ -682,7 +676,7 @@ static OculusMirror LoadOculusMirror(ovrSession session, int width, int height) mirrorDesc.Width = mirror.width; mirrorDesc.Height = mirror.height; - if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(LOG_WARNING, "Could not create mirror texture"); + if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(WARNING, "Could not create mirror texture"); glGenFramebuffers(1, &mirror.fboId); diff --git a/examples/oculus_glfw_sample/raymath.h b/examples/oculus_glfw_sample/raymath.h index 4075a1a93..10eabb6be 100644 --- a/examples/oculus_glfw_sample/raymath.h +++ b/examples/oculus_glfw_sample/raymath.h @@ -47,10 +47,16 @@ #include "raylib.h" // Required for structs: Vector3, Matrix #endif +#ifdef __cplusplus + #define RMEXTERN extern "C" // Functions visible from other files (no name mangling of functions in C++) +#else + #define RMEXTERN extern // Functions visible from other files +#endif + #if defined(RAYMATH_EXTERN_INLINE) - #define RMDEF extern inline + #define RMDEF RMEXTERN inline // Functions are embeded inline (compiler generated code) #else - #define RMDEF extern + #define RMDEF RMEXTERN #endif //---------------------------------------------------------------------------------- @@ -105,10 +111,6 @@ typedef struct Quaternion { #ifndef RAYMATH_EXTERN_INLINE -#ifdef __cplusplus -extern "C" { -#endif - //------------------------------------------------------------------------------------ // Functions Declaration to work with Vector3 //------------------------------------------------------------------------------------ @@ -166,10 +168,6 @@ RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle); // Returns RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle); // Returns the rotation angle and axis for a given quaternion RMDEF void QuaternionTransform(Quaternion *q, Matrix mat); // Transform a quaternion given a transformation matrix -#ifdef __cplusplus -} -#endif - #endif // notdef RAYMATH_EXTERN_INLINE #endif // RAYMATH_H diff --git a/examples/oculus_glfw_sample/rlgl.c b/examples/oculus_glfw_sample/rlgl.c index 722256346..1e3928895 100644 --- a/examples/oculus_glfw_sample/rlgl.c +++ b/examples/oculus_glfw_sample/rlgl.c @@ -72,6 +72,10 @@ #include "standard_shader.h" // Standard shader to embed #endif +#if defined(RLGL_OCULUS_SUPPORT) + #include "external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -159,11 +163,45 @@ typedef struct { // Draw call type // NOTE: Used to track required draw-calls, organized by texture typedef struct { - GLuint textureId; int vertexCount; - // TODO: Store draw state -> blending mode, shader + GLuint vaoId; + GLuint textureId; + GLuint shaderId; + + Matrix projection; + Matrix modelview; + + // TODO: Store additional draw state data + //int blendMode; + //Guint fboId; } DrawCall; +#if defined(RLGL_OCULUS_SUPPORT) +typedef struct OculusBuffer { + ovrTextureSwapChain textureChain; + GLuint depthId; + GLuint fboId; + int width; + int height; +} OculusBuffer; + +typedef struct OculusMirror { + ovrMirrorTexture texture; + GLuint fboId; + int width; + int height; +} OculusMirror; + +typedef struct OculusLayer { + ovrViewScaleDesc viewScaleDesc; + ovrLayerEyeFov eyeLayer; // layer 0 + //ovrLayerQuad quadLayer; // TODO: layer 1: '2D' quad for GUI + Matrix eyeProjections[2]; + int width; + int height; +} OculusLayer; +#endif + //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -213,6 +251,17 @@ static Light lights[MAX_LIGHTS]; // Lights pool static int lightsCount; // Counts current enabled physic objects #endif +#if defined(RLGL_OCULUS_SUPPORT) +// OVR device variables +static ovrSession session; // Oculus session (pointer to ovrHmdStruct) +static ovrHmdDesc hmdDesc; // Oculus device descriptor parameters +static ovrGraphicsLuid luid; // Oculus locally unique identifier for the program (64 bit) +static OculusLayer layer; // Oculus drawing layer (similar to photoshop) +static OculusBuffer buffer; // Oculus internal buffers (texture chain and fbo) +static OculusMirror mirror; // Oculus mirror texture and fbo +static unsigned int frameIndex = 0; // Oculus frames counter, used to discard frames from chain +#endif + // Compressed textures support flags static bool texCompDXTSupported = false; // DDS texture compression support static bool npotSupported = false; // NPOT textures full support @@ -228,15 +277,14 @@ static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays; static int blendMode = 0; // White texture useful for plain color polys (required by shader) -// NOTE: It's required in shapes and models modules! -unsigned int whiteTexture; +static unsigned int whiteTexture; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat); -static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id +static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShaderStr); // Load custom shader strings and return program id static Shader LoadDefaultShader(void); // Load default shader (just vertex positioning and texture coloring) static Shader LoadStandardShader(void); // Load standard shader (support materials and lighting) @@ -254,6 +302,16 @@ static void SetShaderLights(Shader shader); // Sets shader uniform values for li static char *ReadTextFile(const char *fileName); #endif +#if defined(RLGL_OCULUS_SUPPORT) // Oculus Rift functions +static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height); // Load Oculus required buffers +static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer); // Unload texture required buffers +static OculusMirror LoadOculusMirror(ovrSession session, int width, int height); // Load Oculus mirror buffers +static void UnloadOculusMirror(ovrSession session, OculusMirror mirror); // Unload Oculus mirror buffers +static void BlitOculusMirror(ovrSession session, OculusMirror mirror); // Copy Oculus screen buffer to mirror texture +static OculusLayer InitOculusLayer(ovrSession session); // Init Oculus layer (similar to photoshop) +static Matrix FromOvrMatrix(ovrMatrix4f ovrM); // Convert from Oculus ovrMatrix4f struct to raymath Matrix struct +#endif + #if defined(GRAPHICS_API_OPENGL_11) static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight); static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight); @@ -1146,6 +1204,23 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height) TraceLog(INFO, "OpenGL graphic device initialized successfully"); } +// Load OpenGL extensions +// NOTE: External loader function could be passed as a pointer +void rlglLoadExtensions(void *loader) +{ +#if defined(GRAPHICS_API_OPENGL_33) + // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions + if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); + else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); + + if (GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); + else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); + + // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans + //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object +#endif +} + // Get world coordinates from screen coordinates Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view) { @@ -1177,11 +1252,13 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma GLuint id = 0; // Check texture format support by OpenGL 1.1 (compressed textures not supported) - if ((rlGetVersion() == OPENGL_11) && (textureFormat >= 8)) +#if defined(GRAPHICS_API_OPENGL_11) + if (textureFormat >= 8) { TraceLog(WARNING, "OpenGL 1.1 does not support GPU compressed texture formats"); return id; } +#endif if ((!texCompDXTSupported) && ((textureFormat == COMPRESSED_DXT1_RGB) || (textureFormat == COMPRESSED_DXT1_RGBA) || (textureFormat == COMPRESSED_DXT3_RGBA) || (textureFormat == COMPRESSED_DXT5_RGBA))) @@ -1795,8 +1872,13 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // NOTE: standard shader specific locations are got at render time to keep Shader struct as simple as possible (with just default shader locations) if (material.shader.id == standardShader.id) { + // Transpose and inverse model transformations matrix for fragment normal calculations + Matrix transInvTransform = transform; + MatrixTranspose(&transInvTransform); + MatrixInvert(&transInvTransform); + // Send model transformations matrix to shader - glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform)); + glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transInvTransform)); // Send view transformation matrix to shader. View matrix 8, 9 and 10 are view direction vector axis values (target - position) glUniform3f(glGetUniformLocation(material.shader.id, "viewDir"), matView.m8, matView.m9, matView.m10); @@ -2095,6 +2177,24 @@ void *rlglReadTexturePixels(Texture2D texture) return pixels; } +/* +// TODO: Record draw calls to be processed in batch +// NOTE: Global state must be kept +void rlglRecordDraw(void) +{ + // TODO: Before adding a new draw, check if anything changed from last stored draw +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + draws[drawsCounter].vaoId = currentState.vaoId; // lines.id, trangles.id, quads.id? + draws[drawsCounter].textureId = currentState.textureId; // whiteTexture? + draws[drawsCounter].shaderId = currentState.shaderId; // defaultShader.id + draws[drawsCounter].projection = projection; + draws[drawsCounter].modelview = modelview; + draws[drawsCounter].vertexCount = currentState.vertexCount; + + drawsCounter++; +#endif +} +*/ //---------------------------------------------------------------------------------- // Module Functions Definition - Shaders Functions @@ -2361,6 +2461,130 @@ void DestroyLight(Light light) #endif } +#if defined(RLGL_OCULUS_SUPPORT) +// Init Oculus Rift device +// NOTE: Device initialization should be done before window creation? +void InitOculusDevice(void) +{ + // Initialize Oculus device + ovrResult result = ovr_Initialize(NULL); + if (OVR_FAILURE(result)) TraceLog(WARNING, "OVR: Could not initialize Oculus device"); + + result = ovr_Create(&session, &luid); + if (OVR_FAILURE(result)) + { + TraceLog(WARNING, "OVR: Could not create Oculus session"); + ovr_Shutdown(); + } + + hmdDesc = ovr_GetHmdDesc(session); + + TraceLog(INFO, "OVR: Product Name: %s", hmdDesc.ProductName); + TraceLog(INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer); + TraceLog(INFO, "OVR: Product ID: %i", hmdDesc.ProductId); + TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type); + //TraceLog(INFO, "OVR: Serial Number: %s", hmdDesc.SerialNumber); + TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); + + // NOTE: Oculus mirror is set to defined screenWidth and screenHeight... + // ...ideally, it should be (hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2) + + // Initialize Oculus Buffers + layer = InitOculusLayer(session); + buffer = LoadOculusBuffer(session, layer.width, layer.height); + mirror = LoadOculusMirror(session, hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2); // NOTE: hardcoded... + layer.eyeLayer.ColorTexture[0] = buffer.textureChain; //SetOculusLayerTexture(eyeLayer, buffer.textureChain); + + // Recenter OVR tracking origin + ovr_RecenterTrackingOrigin(session); +} + +// Close Oculus Rift device +void CloseOculusDevice(void) +{ + UnloadOculusMirror(session, mirror); // Unload Oculus mirror buffer + UnloadOculusBuffer(session, buffer); // Unload Oculus texture buffers + + ovr_Destroy(session); // Free Oculus session data + ovr_Shutdown(); // Close Oculus device connection +} + +// Update Oculus Rift tracking (position and orientation) +void UpdateOculusTracking(void) +{ + frameIndex++; + + ovrPosef eyePoses[2]; + ovr_GetEyePoses(session, frameIndex, ovrTrue, layer.viewScaleDesc.HmdToEyeOffset, eyePoses, &layer.eyeLayer.SensorSampleTime); + + layer.eyeLayer.RenderPose[0] = eyePoses[0]; + layer.eyeLayer.RenderPose[1] = eyePoses[1]; +} + +void SetOculusMatrix(int eye) +{ + rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y, layer.eyeLayer.Viewport[eye].Size.w, layer.eyeLayer.Viewport[eye].Size.h); + + Quaternion eyeRPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x, + layer.eyeLayer.RenderPose[eye].Orientation.y, + layer.eyeLayer.RenderPose[eye].Orientation.z, + layer.eyeLayer.RenderPose[eye].Orientation.w }; + QuaternionInvert(&eyeRPose); + Matrix eyeOrientation = QuaternionToMatrix(eyeRPose); + Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x, + -layer.eyeLayer.RenderPose[eye].Position.y, + -layer.eyeLayer.RenderPose[eye].Position.z); + + Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); + Matrix modelEyeView = MatrixMultiply(modelview, eyeView); // Using internal camera modelview matrix + + SetMatrixModelview(modelEyeView); + SetMatrixProjection(layer.eyeProjections[eye]); +} + +void BeginOculusDrawing(void) +{ + GLuint currentTexId; + int currentIndex; + + ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, ¤tIndex); + ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, ¤tTexId); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, currentTexId, 0); + //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, buffer.depthId, 0); // Already binded + + //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Same as rlClearScreenBuffers() + + // NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA) + // and performs linear-to-gamma conversion in GLSL or does not care about gamma-correction, then: + // - Require OculusBuffer format to be OVR_FORMAT_R8G8B8A8_UNORM_SRGB + // - Do NOT enable GL_FRAMEBUFFER_SRGB + //glEnable(GL_FRAMEBUFFER_SRGB); +} + +void EndOculusDrawing(void) +{ + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + ovr_CommitTextureSwapChain(session, buffer.textureChain); + + ovrLayerHeader *layers = &layer.eyeLayer.Header; + ovr_SubmitFrame(session, frameIndex, &layer.viewScaleDesc, &layers, 1); + + // Blit mirror texture to back buffer + BlitOculusMirror(session, mirror); + + // Get session status information + ovrSessionStatus sessionStatus; + ovr_GetSessionStatus(session, &sessionStatus); + if (sessionStatus.ShouldQuit) TraceLog(WARNING, "OVR: Session should quit..."); + if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session); +} +#endif + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -2403,7 +2627,7 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in } // Load custom shader strings and return program id -static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) +static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShaderStr) { unsigned int program = 0; @@ -3341,6 +3565,187 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight) } #endif +#if defined(RLGL_OCULUS_SUPPORT) +// Load Oculus required buffers: texture-swap-chain, fbo, texture-depth +static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) +{ + OculusBuffer buffer; + buffer.width = width; + buffer.height = height; + + // Create OVR texture chain + ovrTextureSwapChainDesc desc = {}; + desc.Type = ovrTexture_2D; + desc.ArraySize = 1; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; // Requires glEnable(GL_FRAMEBUFFER_SRGB); + desc.SampleCount = 1; + desc.StaticImage = ovrFalse; + + ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain); + + if (!OVR_SUCCESS(result)) TraceLog(WARNING, "OVR: Failed to create swap textures buffer"); + + int textureCount = 0; + ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount); + + if (!OVR_SUCCESS(result) || !textureCount) TraceLog(WARNING, "OVR: Unable to count swap chain textures"); + + for (int i = 0; i < textureCount; ++i) + { + GLuint chainTexId; + ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, i, &chainTexId); + glBindTexture(GL_TEXTURE_2D, chainTexId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + glBindTexture(GL_TEXTURE_2D, 0); + + /* + // Setup framebuffer object (using depth texture) + glGenFramebuffers(1, &buffer.fboId); + glGenTextures(1, &buffer.depthId); + glBindTexture(GL_TEXTURE_2D, buffer.depthId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + */ + + // Setup framebuffer object (using depth renderbuffer) + glGenFramebuffers(1, &buffer.fboId); + glGenRenderbuffers(1, &buffer.depthId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); + glBindRenderbuffer(GL_RENDERBUFFER, buffer.depthId); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, buffer.width, buffer.height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, buffer.depthId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + return buffer; +} + +// Unload texture required buffers +static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer) +{ + if (buffer.textureChain) + { + ovr_DestroyTextureSwapChain(session, buffer.textureChain); + buffer.textureChain = NULL; + } + + if (buffer.depthId != 0) glDeleteTextures(1, &buffer.depthId); + if (buffer.fboId != 0) glDeleteFramebuffers(1, &buffer.fboId); +} + +// Load Oculus mirror buffers +static OculusMirror LoadOculusMirror(ovrSession session, int width, int height) +{ + OculusMirror mirror; + mirror.width = width; + mirror.height = height; + + ovrMirrorTextureDesc mirrorDesc; + memset(&mirrorDesc, 0, sizeof(mirrorDesc)); + mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + mirrorDesc.Width = mirror.width; + mirrorDesc.Height = mirror.height; + + if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(WARNING, "Could not create mirror texture"); + + glGenFramebuffers(1, &mirror.fboId); + + return mirror; +} + +// Unload Oculus mirror buffers +static void UnloadOculusMirror(ovrSession session, OculusMirror mirror) +{ + if (mirror.fboId != 0) glDeleteFramebuffers(1, &mirror.fboId); + if (mirror.texture) ovr_DestroyMirrorTexture(session, mirror.texture); +} + +// Copy Oculus screen buffer to mirror texture +static void BlitOculusMirror(ovrSession session, OculusMirror mirror) +{ + GLuint mirrorTextureId; + + ovr_GetMirrorTextureBufferGL(session, mirror.texture, &mirrorTextureId); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fboId); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0); + glBlitFramebuffer(0, 0, mirror.width, mirror.height, 0, mirror.height, mirror.width, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +} + +// Init Oculus layer (similar to photoshop) +static OculusLayer InitOculusLayer(ovrSession session) +{ + OculusLayer layer = { 0 }; + + layer.viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; + + memset(&layer.eyeLayer, 0, sizeof(ovrLayerEyeFov)); + layer.eyeLayer.Header.Type = ovrLayerType_EyeFov; + layer.eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; + + ovrEyeRenderDesc eyeRenderDescs[2]; + + for (int eye = 0; eye < 2; eye++) + { + eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]); + ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(eyeRenderDescs[eye].Fov, 0.01f, 10000.0f, ovrProjection_None); //ovrProjection_ClipRangeOpenGL); + layer.eyeProjections[eye] = FromOvrMatrix(ovrPerspectiveProjection); // NOTE: struct ovrMatrix4f { float M[4][4] } --> struct Matrix + + layer.viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset; + layer.eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov; + + ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, layer.eyeLayer.Fov[eye], 1.0f); + layer.eyeLayer.Viewport[eye].Size = eyeSize; + layer.eyeLayer.Viewport[eye].Pos.x = layer.width; + layer.eyeLayer.Viewport[eye].Pos.y = 0; + + layer.height = eyeSize.h; //std::max(renderTargetSize.y, (uint32_t)eyeSize.h); + layer.width += eyeSize.w; + } + + return layer; +} + +// Convert from Oculus ovrMatrix4f struct to raymath Matrix struct +static Matrix FromOvrMatrix(ovrMatrix4f ovrmat) +{ + Matrix rmat; + + rmat.m0 = ovrmat.M[0][0]; + rmat.m1 = ovrmat.M[1][0]; + rmat.m2 = ovrmat.M[2][0]; + rmat.m3 = ovrmat.M[3][0]; + rmat.m4 = ovrmat.M[0][1]; + rmat.m5 = ovrmat.M[1][1]; + rmat.m6 = ovrmat.M[2][1]; + rmat.m7 = ovrmat.M[3][1]; + rmat.m8 = ovrmat.M[0][2]; + rmat.m9 = ovrmat.M[1][2]; + rmat.m10 = ovrmat.M[2][2]; + rmat.m11 = ovrmat.M[3][2]; + rmat.m12 = ovrmat.M[0][3]; + rmat.m13 = ovrmat.M[1][3]; + rmat.m14 = ovrmat.M[2][3]; + rmat.m15 = ovrmat.M[3][3]; + + MatrixTranspose(&rmat); + + return rmat; +} +#endif + #if defined(RLGL_STANDALONE) // Output a trace log message // NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning diff --git a/examples/oculus_glfw_sample/rlgl.h b/examples/oculus_glfw_sample/rlgl.h index 9c25f7104..93e155b7f 100644 --- a/examples/oculus_glfw_sample/rlgl.h +++ b/examples/oculus_glfw_sample/rlgl.h @@ -48,7 +48,7 @@ // Choose opengl version here or just define it at compile time: -DGRAPHICS_API_OPENGL_33 //#define GRAPHICS_API_OPENGL_11 // Only available on PLATFORM_DESKTOP -//#define GRAPHICS_API_OPENGL_33 // Only available on PLATFORM_DESKTOP +//#define GRAPHICS_API_OPENGL_33 // Only available on PLATFORM_DESKTOP or Oculus Rift CV1 //#define GRAPHICS_API_OPENGL_ES2 // Only available on PLATFORM_ANDROID or PLATFORM_RPI or PLATFORM_WEB // Security check in case no GRAPHICS_API_OPENGL_* defined @@ -296,6 +296,7 @@ void rlglInit(void); // Initialize rlgl (shaders, VAO void rlglClose(void); // De-init rlgl void rlglDraw(void); // Draw VAO/VBO void rlglInitGraphics(int offsetX, int offsetY, int width, int height); // Initialize Graphics (OpenGL stuff) +void rlglLoadExtensions(void *loader); // Load OpenGL extensions unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments) @@ -346,6 +347,15 @@ void DestroyLight(Light light); // Destroy a void TraceLog(int msgType, const char *text, ...); #endif +#if defined(RLGL_OCULUS_SUPPORT) +void InitOculusDevice(void); // Init Oculus Rift device +void CloseOculusDevice(void); // Close Oculus Rift device +void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) +void SetOculusMatrix(int eye); // Set internal projection and modelview matrix depending on eyes tracking data +void BeginOculusDrawing(void); // Begin Oculus drawing configuration +void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) +#endif + #ifdef __cplusplus } #endif diff --git a/examples/oculus_glfw_sample/standard_shader.h b/examples/oculus_glfw_sample/standard_shader.h index 956b5c32c..a4bc96941 100644 --- a/examples/oculus_glfw_sample/standard_shader.h +++ b/examples/oculus_glfw_sample/standard_shader.h @@ -1,6 +1,6 @@ // Vertex shader definition to embed, no external file required -const static unsigned char vStandardShaderStr[] = +static const char vStandardShaderStr[] = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) @@ -37,7 +37,7 @@ const static unsigned char vStandardShaderStr[] = "} \n"; // Fragment shader definition to embed, no external file required -const static unsigned char fStandardShaderStr[] = +static const char fStandardShaderStr[] = #if defined(GRAPHICS_API_OPENGL_21) "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) @@ -85,13 +85,13 @@ const static unsigned char fStandardShaderStr[] = "{\n" " vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));\n" " vec3 surfaceToLight = l.position - surfacePos;\n" -" float brightness = clamp(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n)), 0, 1);\n" +" float brightness = clamp(float(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n))), 0.0, 1.0);\n" " float diff = 1.0/dot(surfaceToLight/l.radius, surfaceToLight/l.radius)*brightness*l.intensity;\n" " float spec = 0.0;\n" " if (diff > 0.0)\n" " {\n" " vec3 h = normalize(-l.direction + v);\n" -" spec = pow(dot(n, h), 3 + glossiness)*s;\n" +" spec = pow(dot(n, h), 3.0 + glossiness)*s;\n" " }\n" " return (diff*l.diffuse.rgb + spec*colSpecular.rgb);\n" "}\n" @@ -99,23 +99,23 @@ const static unsigned char fStandardShaderStr[] = "vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v, float s)\n" "{\n" " vec3 lightDir = normalize(-l.direction);\n" -" float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity;\n" +" float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity;\n" " float spec = 0.0;\n" " if (diff > 0.0)\n" " {\n" " vec3 h = normalize(lightDir + v);\n" -" spec = pow(dot(n, h), 3 + glossiness)*s;\n" +" spec = pow(dot(n, h), 3.0 + glossiness)*s;\n" " }\n" " return (diff*l.intensity*l.diffuse.rgb + spec*colSpecular.rgb);\n" "}\n" "\n" "vec3 CalcSpotLight(Light l, vec3 n, vec3 v, float s)\n" "{\n" -" vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));\n" +" vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1.0));\n" " vec3 lightToSurface = normalize(surfacePos - l.position);\n" " vec3 lightDir = normalize(-l.direction);\n" -" float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity;\n" -" float attenuation = clamp(dot(n, lightToSurface), 0.0, 1.0);\n" +" float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity;\n" +" float attenuation = clamp(float(dot(n, lightToSurface)), 0.0, 1.0);\n" " attenuation = dot(lightToSurface, -lightDir);\n" " float lightToSurfaceAngle = degrees(acos(attenuation));\n" " if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0;\n" @@ -125,37 +125,45 @@ const static unsigned char fStandardShaderStr[] = " if (diffAttenuation > 0.0)\n" " {\n" " vec3 h = normalize(lightDir + v);\n" -" spec = pow(dot(n, h), 3 + glossiness)*s;\n" +" spec = pow(dot(n, h), 3.0 + glossiness)*s;\n" " }\n" " return (falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb));\n" "}\n" "\n" "void main()\n" "{\n" -" mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));\n" +" mat3 normalMatrix = mat3(modelMatrix);\n" " vec3 normal = normalize(normalMatrix*fragNormal);\n" " vec3 n = normalize(normal);\n" " vec3 v = normalize(viewDir);\n" +#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) +" vec4 texelColor = texture2D(texture0, fragTexCoord);\n" +#elif defined(GRAPHICS_API_OPENGL_33) " vec4 texelColor = texture(texture0, fragTexCoord);\n" +#endif " vec3 lighting = colAmbient.rgb;\n" " if (useNormal == 1)\n" " {\n" +#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) +" n *= texture2D(texture1, fragTexCoord).rgb;\n" +#elif defined(GRAPHICS_API_OPENGL_33) " n *= texture(texture1, fragTexCoord).rgb;\n" +#endif " n = normalize(n);\n" " }\n" " float spec = 1.0;\n" +#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) +" if (useSpecular == 1) spec *= normalize(texture2D(texture2, fragTexCoord).r);\n" +#elif defined(GRAPHICS_API_OPENGL_33) " if (useSpecular == 1) spec *= normalize(texture(texture2, fragTexCoord).r);\n" +#endif " for (int i = 0; i < lightsCount; i++)\n" " {\n" " if (lights[i].enabled == 1)\n" " {\n" -" switch (lights[i].type)\n" -" {\n" -" case 0: lighting += CalcPointLight(lights[i], n, v, spec); break;\n" -" case 1: lighting += CalcDirectionalLight(lights[i], n, v, spec); break;\n" -" case 2: lighting += CalcSpotLight(lights[i], n, v, spec); break;\n" -" default: break;\n" -" }\n" +" if(lights[i].type == 0) lighting += CalcPointLight(lights[i], n, v, spec);\n" +" else if(lights[i].type == 1) lighting += CalcDirectionalLight(lights[i], n, v, spec);\n" +" else if(lights[i].type == 2) lighting += CalcSpotLight(lights[i], n, v, spec);\n" " }\n" " }\n" #if defined(GRAPHICS_API_OPENGL_33) @@ -163,4 +171,4 @@ const static unsigned char fStandardShaderStr[] = #elif defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) " gl_FragColor = vec4(texelColor.rgb*lighting*colDiffuse.rgb, texelColor.a*colDiffuse.a); \n" #endif -"} \n"; \ No newline at end of file +"}\n"; From c91401060662e2e6f828fdbeb41838ad085b436c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 18:37:28 +0200 Subject: [PATCH 10/11] Correct issue on Oculus drawing --- src/rlgl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rlgl.c b/src/rlgl.c index 1e3928895..5d6fd9d7e 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2562,6 +2562,8 @@ void BeginOculusDrawing(void) // - Require OculusBuffer format to be OVR_FORMAT_R8G8B8A8_UNORM_SRGB // - Do NOT enable GL_FRAMEBUFFER_SRGB //glEnable(GL_FRAMEBUFFER_SRGB); + + rlClearScreenBuffers(); // Clear current framebuffer(s) } void EndOculusDrawing(void) From d1a5374ac42e054ca65793f7358fc21bbcf393b9 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 18:38:57 +0200 Subject: [PATCH 11/11] raylib Oculus Rift CV1 example... IT WORKS!!! --- examples/core_oculus_rift.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/core_oculus_rift.c b/examples/core_oculus_rift.c index 2871407b0..865178295 100644 --- a/examples/core_oculus_rift.c +++ b/examples/core_oculus_rift.c @@ -2,6 +2,9 @@ * * raylib [core] example - Oculus Rift CV1 * +* Compile example using: +* gcc -o $(NAME_PART).exe $(FILE_NAME) -L. -L..\src\external\OculusSDK\LibOVR -lLibOVRRT32_1 -lraylib -lglfw3 -lopengl32 -lgdi32 -std=c99 +* * This example has been created using raylib 1.5 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * @@ -21,8 +24,8 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - oculus rift"); InitOculusDevice(); - - // Define the camera to look into our 3d world + + // Define the camera to look into our 3d world Camera camera; camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point @@ -30,8 +33,8 @@ int main() camera.fovy = 45.0f; // Camera field-of-view Y Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; - - SetTargetFPS(90); // Set our game to run at 90 frames-per-second + + //SetTargetFPS(90); // Set our game to run at 90 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -58,13 +61,13 @@ int main() DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); - + DrawGrid(10, 1.0f); End3dMode(); } - EndOculusDrawing() + EndOculusDrawing(); EndDrawing(); //---------------------------------------------------------------------------------- @@ -72,7 +75,7 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- - CloseOculusdevice(); // Close Oculus Rift device + CloseOculusDevice(); // Close Oculus Rift device CloseWindow(); // Close window and OpenGL context //--------------------------------------------------------------------------------------