From a76fcaba3ea8092be4b5ee26f6e97948b20129aa Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Mar 2021 18:36:25 +0100 Subject: [PATCH] BIG CHANGE: REDESIGNED: Vr device simulator #1582 Vr simulator has been moved to core module and completely redesigned. Now user is in charge of stereo-render fbo and also in full control of distortion shader. Code is a bit more complex but better aligned with other raylib examples. --- examples/core/core_vr_simulator.c | 90 ++++--- src/config.h | 9 +- src/core.c | 155 ++++++++++- src/raylib.h | 40 +-- src/rlgl.h | 409 +++++------------------------- 5 files changed, 300 insertions(+), 403 deletions(-) diff --git a/examples/core/core_vr_simulator.c b/examples/core/core_vr_simulator.c index 8d0247f83..33e2ed6a4 100644 --- a/examples/core/core_vr_simulator.c +++ b/examples/core/core_vr_simulator.c @@ -2,10 +2,10 @@ * * raylib [core] example - VR Simulator (Oculus Rift CV1 parameters) * -* This example has been created using raylib 1.7 (www.raylib.com) +* This example has been created using raylib 3.6-dev (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2021 Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -25,40 +25,55 @@ int main(void) const int screenHeight = 450; // NOTE: screenWidth/screenHeight should match VR device aspect ratio - - SetConfigFlags(FLAG_MSAA_4X_HINT); InitWindow(screenWidth, screenHeight, "raylib [core] example - vr simulator"); + // VR device parameters definition + VrDeviceInfo device = { + // Oculus Rift CV1 parameters for simulator + .hResolution = 2160, // Horizontal resolution in pixels + .vResolution = 1200, // Vertical resolution in pixels + .hScreenSize = 0.133793f, // Horizontal size in meters + .vScreenSize = 0.0669f, // Vertical size in meters + .vScreenCenter = 0.04678f, // Screen center in meters + .eyeToScreenDistance = 0.041f, // Distance between eye and display in meters + .lensSeparationDistance = 0.07f, // Lens separation distance in meters + .interpupillaryDistance = 0.07f, // IPD (distance between pupils) in meters + + // NOTE: CV1 uses a Fresnel-hybrid-asymmetric lenses with specific distortion compute shaders + // Following parameters are an approximation to distortion stereo rendering but results differ from actual device + .lensDistortionValues[0] = 1.0f, // Lens distortion constant parameter 0 + .lensDistortionValues[1] = 0.22f, // Lens distortion constant parameter 1 + .lensDistortionValues[2] = 0.24f, // Lens distortion constant parameter 2 + .lensDistortionValues[3] = 0.0f, // Lens distortion constant parameter 3 + .chromaAbCorrection[0] = 0.996f, // Chromatic aberration correction parameter 0 + .chromaAbCorrection[1] = -0.004f, // Chromatic aberration correction parameter 1 + .chromaAbCorrection[2] = 1.014f, // Chromatic aberration correction parameter 2 + .chromaAbCorrection[3] = 0.0f, // Chromatic aberration correction parameter 3 + }; + // Init VR simulator (Oculus Rift CV1 parameters) - InitVrSimulator(); - - VrDeviceInfo hmd = { 0 }; // VR device parameters (head-mounted-device) - - // Oculus Rift CV1 parameters for simulator - hmd.hResolution = 2160; // HMD horizontal resolution in pixels - hmd.vResolution = 1200; // HMD vertical resolution in pixels - hmd.hScreenSize = 0.133793f; // HMD horizontal size in meters - hmd.vScreenSize = 0.0669f; // HMD vertical size in meters - hmd.vScreenCenter = 0.04678f; // HMD screen center in meters - hmd.eyeToScreenDistance = 0.041f; // HMD distance between eye and display in meters - hmd.lensSeparationDistance = 0.07f; // HMD lens separation distance in meters - hmd.interpupillaryDistance = 0.07f; // HMD IPD (distance between pupils) in meters - - // NOTE: CV1 uses a Fresnel-hybrid-asymmetric lenses with specific distortion compute shaders. - // Following parameters are an approximation to distortion stereo rendering but results differ from actual device. - hmd.lensDistortionValues[0] = 1.0f; // HMD lens distortion constant parameter 0 - hmd.lensDistortionValues[1] = 0.22f; // HMD lens distortion constant parameter 1 - hmd.lensDistortionValues[2] = 0.24f; // HMD lens distortion constant parameter 2 - hmd.lensDistortionValues[3] = 0.0f; // HMD lens distortion constant parameter 3 - hmd.chromaAbCorrection[0] = 0.996f; // HMD chromatic aberration correction parameter 0 - hmd.chromaAbCorrection[1] = -0.004f; // HMD chromatic aberration correction parameter 1 - hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2 - hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3 + InitVrSimulator(device); + + // Get Vr stereo config parameters for device parameters + VrStereoConfig config = GetVrConfig(device); // Distortion shader (uses device lens distortion and chroma) Shader distortion = LoadShader(0, TextFormat("resources/distortion%i.fs", GLSL_VERSION)); + + // Update distortion shader with lens and distortion-scale parameters + SetShaderValue(distortion, GetShaderLocation(distortion, "leftLensCenter"), config.leftLensCenter, SHADER_UNIFORM_VEC2); + SetShaderValue(distortion, GetShaderLocation(distortion, "rightLensCenter"), config.rightLensCenter, SHADER_UNIFORM_VEC2); + SetShaderValue(distortion, GetShaderLocation(distortion, "leftScreenCenter"), config.leftScreenCenter, SHADER_UNIFORM_VEC2); + SetShaderValue(distortion, GetShaderLocation(distortion, "rightScreenCenter"), config.rightScreenCenter, SHADER_UNIFORM_VEC2); - SetVrConfiguration(hmd, distortion); // Set Vr device parameters for stereo rendering + SetShaderValue(distortion, GetShaderLocation(distortion, "scale"), config.scale, SHADER_UNIFORM_VEC2); + SetShaderValue(distortion, GetShaderLocation(distortion, "scaleIn"), config.scaleIn, SHADER_UNIFORM_VEC2); + SetShaderValue(distortion, GetShaderLocation(distortion, "deviceWarpParam"), device.lensDistortionValues, SHADER_UNIFORM_VEC4); + SetShaderValue(distortion, GetShaderLocation(distortion, "chromaAbParam"), device.chromaAbCorrection, SHADER_UNIFORM_VEC4); + + // Initialize framebuffer for stereo rendering + // NOTE: Screen size should match HMD aspect ratio + RenderTexture2D target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight()); // Define the camera to look into our 3d world Camera camera = { 0 }; @@ -81,8 +96,6 @@ int main(void) // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera); // Update camera (simulator mode) - - if (IsKeyPressed(KEY_SPACE)) ToggleVrMode(); // Toggle VR mode //---------------------------------------------------------------------------------- // Draw @@ -91,8 +104,7 @@ int main(void) ClearBackground(RAYWHITE); - BeginVrDrawing(); - + BeginVrDrawing(target); BeginMode3D(camera); DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); @@ -101,8 +113,11 @@ int main(void) DrawGrid(40, 1.0f); EndMode3D(); - EndVrDrawing(); + + BeginShaderMode(distortion); + DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0.0f, 0.0f }, WHITE); + EndShaderMode(); DrawFPS(10, 10); @@ -112,11 +127,12 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - UnloadShader(distortion); // Unload distortion shader + UnloadRenderTexture(target); // Unload stereo render fbo + UnloadShader(distortion); // Unload distortion shader - CloseVrSimulator(); // Close VR simulator + CloseVrSimulator(); // Close VR simulator - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/src/config.h b/src/config.h index 9513b849b..c29978542 100644 --- a/src/config.h +++ b/src/config.h @@ -57,6 +57,8 @@ #define SUPPORT_COMPRESSION_API 1 // Support saving binary data automatically to a generated storage.data file. This file is managed internally. #define SUPPORT_DATA_STORAGE 1 +// Support VR simulation functionality (stereo rendering) +#define SUPPORT_VR_SIMULATOR 1 // core: Configuration values //------------------------------------------------------------------------------------ @@ -78,12 +80,7 @@ //------------------------------------------------------------------------------------ -// Module: rlgl - Configuration Flags -//------------------------------------------------------------------------------------ -// Support VR simulation functionality (stereo rendering) -#define SUPPORT_VR_SIMULATOR 1 - -// rlgl: Configuration values +// Module: rlgl - Configuration values //------------------------------------------------------------------------------------ #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) #define DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch limits diff --git a/src/core.c b/src/core.c index 664bac024..9be1dc063 100644 --- a/src/core.c +++ b/src/core.c @@ -80,7 +80,10 @@ * for linkage * * #define SUPPORT_DATA_STORAGE -* Support saving binary data automatically to a generated storage.data file. This file is managed internally. +* Support saving binary data automatically to a generated storage.data file. This file is managed internally +* +* #define SUPPORT_VR_SIMULATOR +* Support VR simulation functionality (stereo rendering) * * DEPENDENCIES: * rglfw - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX. FreeBSD, OpenBSD, NetBSD, DragonFly) @@ -473,6 +476,15 @@ typedef struct CoreData { unsigned long long base; // Base time measure for hi-res timer #endif } Time; +#if defined(SUPPORT_VR_SIMULATOR) + struct { + VrStereoConfig config; // VR stereo configuration for simulator + unsigned int stereoFboId; // VR stereo rendering framebuffer id + unsigned int stereoTexId; // VR stereo color texture (attached to framebuffer) + bool simulatorReady; // VR simulator ready flag + bool stereoRender; // VR stereo rendering enabled/disabled flag + } Vr; // VR simulator data +#endif // SUPPORT_VR_SIMULATOR } CoreData; //---------------------------------------------------------------------------------- @@ -2000,6 +2012,147 @@ void EndTextureMode(void) CORE.Window.currentFbo.height = CORE.Window.screen.height; } + +#if defined(SUPPORT_VR_SIMULATOR) +// Init VR simulator for selected device parameters +void InitVrSimulator(VrDeviceInfo device) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Reset CORE.Vr.config for a new values assignment + memset(&CORE.Vr.config, 0, sizeof(VrStereoConfig)); + + // Compute aspect ratio + float aspect = ((float)device.hResolution*0.5f)/(float)device.vResolution; + + // Compute lens parameters + float lensShift = (device.hScreenSize*0.25f - device.lensSeparationDistance*0.5f)/device.hScreenSize; + CORE.Vr.config.leftLensCenter[0] = 0.25f + lensShift; + CORE.Vr.config.leftLensCenter[1] = 0.5f; + CORE.Vr.config.rightLensCenter[0] = 0.75f - lensShift; + CORE.Vr.config.rightLensCenter[1] = 0.5f; + CORE.Vr.config.leftScreenCenter[0] = 0.25f; + CORE.Vr.config.leftScreenCenter[1] = 0.5f; + CORE.Vr.config.rightScreenCenter[0] = 0.75f; + CORE.Vr.config.rightScreenCenter[1] = 0.5f; + + // Compute distortion scale parameters + // NOTE: To get lens max radius, lensShift must be normalized to [-1..1] + float lensRadius = fabsf(-1.0f - 4.0f*lensShift); + float lensRadiusSq = lensRadius*lensRadius; + float distortionScale = device.lensDistortionValues[0] + + device.lensDistortionValues[1]*lensRadiusSq + + device.lensDistortionValues[2]*lensRadiusSq*lensRadiusSq + + device.lensDistortionValues[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq; + + float normScreenWidth = 0.5f; + float normScreenHeight = 1.0f; + CORE.Vr.config.scaleIn[0] = 2.0f/normScreenWidth; + CORE.Vr.config.scaleIn[1] = 2.0f/normScreenHeight/aspect; + CORE.Vr.config.scale[0] = normScreenWidth*0.5f/distortionScale; + CORE.Vr.config.scale[1] = normScreenHeight*0.5f*aspect/distortionScale; + + // Fovy is normally computed with: 2*atan2f(device.vScreenSize, 2*device.eyeToScreenDistance) + // ...but with lens distortion it is increased (see Oculus SDK Documentation) + //float fovy = 2.0f*atan2f(device.vScreenSize*0.5f*distortionScale, device.eyeToScreenDistance); // Really need distortionScale? + float fovy = 2.0f*(float)atan2f(device.vScreenSize*0.5f, device.eyeToScreenDistance); + + // Compute camera projection matrices + float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1] + Matrix proj = MatrixPerspective(fovy, aspect, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + rlSetMatrixProjectionStereo(MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f)), MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f))); + + // Compute camera transformation matrices + // NOTE: Camera movement might seem more natural if we model the head. + // Our axis of rotation is the base of our head, so we might want to add + // some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions. + rlSetMatrixViewOffsetStereo(MatrixTranslate(-device.interpupillaryDistance*0.5f, 0.075f, 0.045f), MatrixTranslate(device.interpupillaryDistance*0.5f, 0.075f, 0.045f)); + + // Compute eyes Viewports + /* + CORE.Vr.config.eyeViewportRight[0] = 0; + CORE.Vr.config.eyeViewportRight[1] = 0; + CORE.Vr.config.eyeViewportRight[2] = device.hResolution/2; + CORE.Vr.config.eyeViewportRight[3] = device.vResolution; + + CORE.Vr.config.eyeViewportLeft[0] = device.hResolution/2; + CORE.Vr.config.eyeViewportLeft[1] = 0; + CORE.Vr.config.eyeViewportLeft[2] = device.hResolution/2; + CORE.Vr.config.eyeViewportLeft[3] = device.vResolution; + */ + + CORE.Vr.simulatorReady = true; +#else + TRACELOG(LOG_WARNING, "RLGL: VR Simulator not supported on OpenGL 1.1"); +#endif +} + +// Update VR tracking (position and orientation) and camera +// NOTE: Camera (position, target, up) gets update with head tracking information +void UpdateVrTracking(Camera *camera) +{ + // TODO: Simulate 1st person camera system +} + +// Close VR simulator for current device +void CloseVrSimulator(void) +{ + CORE.Vr.simulatorReady = false; +} + +// Get stereo rendering configuration parameters +VrStereoConfig GetVrConfig(VrDeviceInfo device) +{ + VrStereoConfig config = { 0 }; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + config = CORE.Vr.config; +#endif + return config; +} + +// Detect if VR simulator is running +bool IsVrSimulatorReady(void) +{ + return CORE.Vr.simulatorReady; +} + +// Begin VR drawing configuration +void BeginVrDrawing(RenderTexture2D target) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (CORE.Vr.simulatorReady) + { + rlEnableFramebuffer(target.id); // Setup framebuffer for stereo rendering + //glEnable(GL_FRAMEBUFFER_SRGB); // Enable SRGB framebuffer (only if required) + + //rlViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) + rlClearScreenBuffers(); // Clear current framebuffer + + rlEnableStereoRender(); + } +#endif +} + +// End VR drawing process (and desktop mirror) +void EndVrDrawing(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (CORE.Vr.simulatorReady) + { + rlDisableStereoRender(); + + rlDisableFramebuffer(); // Unbind current framebuffer + + // Reset viewport and default projection-modelview matrices + rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); + SetMatrixProjection(MatrixOrtho(0.0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, 0.0, 0.0, 1.0)); + SetMatrixModelview(MatrixIdentity()); + + rlDisableDepthTest(); + } +#endif +} +#endif // SUPPORT_VR_SIMULATOR + // Begin scissor mode (define screen area for following drawing) // NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left void BeginScissorMode(int x, int y, int width, int height) diff --git a/src/raylib.h b/src/raylib.h index 0db3f06f9..f3f9d7ec5 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -449,18 +449,28 @@ typedef struct Music { // Head-Mounted-Display device parameters typedef struct VrDeviceInfo { - int hResolution; // HMD horizontal resolution in pixels - int vResolution; // HMD vertical resolution in pixels - float hScreenSize; // HMD horizontal size in meters - float vScreenSize; // HMD vertical size in meters - float vScreenCenter; // HMD screen center in meters - float eyeToScreenDistance; // HMD distance between eye and display in meters - float lensSeparationDistance; // HMD lens separation distance in meters - float interpupillaryDistance; // HMD IPD (distance between pupils) in meters - float lensDistortionValues[4]; // HMD lens distortion constant parameters - float chromaAbCorrection[4]; // HMD chromatic aberration correction parameters + int hResolution; // Horizontal resolution in pixels + int vResolution; // Vertical resolution in pixels + float hScreenSize; // Horizontal size in meters + float vScreenSize; // Vertical size in meters + float vScreenCenter; // Screen center in meters + float eyeToScreenDistance; // Distance between eye and display in meters + float lensSeparationDistance; // Lens separation distance in meters + float interpupillaryDistance; // IPD (distance between pupils) in meters + float lensDistortionValues[4]; // Lens distortion constant parameters + float chromaAbCorrection[4]; // Chromatic aberration correction parameters } VrDeviceInfo; +// VR Stereo rendering configuration for simulator +typedef struct VrStereoConfig { + float leftLensCenter[2]; // VR left lens center + float rightLensCenter[2]; // VR right lens center + float leftScreenCenter[2]; // VR left screen center + float rightScreenCenter[2]; // VR right screen center + float scale[2]; // VR distortion scale + float scaleIn[2]; // VR distortion scale in +} VrStereoConfig; + //---------------------------------------------------------------------------------- // Enumerators Definition //---------------------------------------------------------------------------------- @@ -1441,14 +1451,14 @@ RLAPI void BeginBlendMode(int mode); // Beg RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) // VR control functions -RLAPI void InitVrSimulator(void); // Init VR simulator for selected device parameters +RLAPI void InitVrSimulator(VrDeviceInfo device); // Init VR simulator for selected device parameters RLAPI void CloseVrSimulator(void); // Close VR simulator for current device -RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera -RLAPI void SetVrConfiguration(VrDeviceInfo info, Shader distortion); // Set stereo rendering configuration parameters RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready -RLAPI void ToggleVrMode(void); // Enable/Disable VR experience -RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering +RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera +RLAPI void BeginVrDrawing(RenderTexture2D target); // Begin VR simulator stereo rendering (using provided fbo) RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering +RLAPI VrStereoConfig GetVrConfig(VrDeviceInfo device); // Get stereo rendering configuration parameters +RLAPI Texture2D GetVrTexture(void); // Get VR framebuffer texture //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) diff --git a/src/rlgl.h b/src/rlgl.h index 9f1b9af77..83c2aec85 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -29,8 +29,6 @@ * #define RLGL_STANDALONE * Use rlgl as standalone library (no raylib dependency) * -* #define SUPPORT_VR_SIMULATOR -* Support VR simulation functionality (stereo rendering) * * DEPENDENCIES: * raymath - 3D math functionality (Vector3, Matrix, Quaternion) @@ -327,29 +325,6 @@ typedef enum { float fovy; // Camera field-of-view apperture in Y (degrees) } Camera; - // Head-Mounted-Display device parameters - typedef struct VrDeviceInfo { - int hResolution; // HMD horizontal resolution in pixels - int vResolution; // HMD vertical resolution in pixels - float hScreenSize; // HMD horizontal size in meters - float vScreenSize; // HMD vertical size in meters - float vScreenCenter; // HMD screen center in meters - float eyeToScreenDistance; // HMD distance between eye and display in meters - float lensSeparationDistance; // HMD lens separation distance in meters - float interpupillaryDistance; // HMD IPD (distance between pupils) in meters - float lensDistortionValues[4]; // HMD lens distortion constant parameters - float chromaAbCorrection[4]; // HMD chromatic aberration correction parameters - } VrDeviceInfo; - - // VR Stereo rendering configuration for simulator - typedef struct VrStereoConfig { - Shader distortionShader; // VR stereo rendering distortion shader - Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices - Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices - int eyeViewportRight[4]; // VR stereo rendering right eye viewport [x, y, w, h] - int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h] - } VrStereoConfig; - // TraceLog message types typedef enum { LOG_ALL, @@ -532,6 +507,8 @@ RLAPI void rlSetLineWidth(float width); // Set the line dr RLAPI float rlGetLineWidth(void); // Get the line drawing width RLAPI void rlEnableSmoothLines(void); // Enable line aliasing RLAPI void rlDisableSmoothLines(void); // Disable line aliasing +RLAPI void rlEnableStereoRender(void); // Enable stereo rendering +RLAPI void rlDisableStereoRender(void); // Disable stereo rendering RLAPI void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a); // Clear color buffer with color RLAPI void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth) @@ -564,6 +541,9 @@ RLAPI void rlGenerateMipmaps(Texture2D *texture); // Gen RLAPI void *rlReadTexturePixels(Texture2D texture); // Read texture pixel data RLAPI unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) +RLAPI void rlSetMatrixProjectionStereo(Matrix right, Matrix left); // Set eyes projection matrices for stereo rendering +RLAPI void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left); // Set eyes view offsets matrices for stereo rendering + // Framebuffer management (fbo) RLAPI unsigned int rlLoadFramebuffer(int width, int height); // Load an empty framebuffer RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType); // Attach texture/renderbuffer to a framebuffer @@ -597,14 +577,15 @@ RLAPI Texture2D GetShapesTexture(void); // Get RLAPI Rectangle GetShapesTextureRec(void); // Get texture rectangle to draw shapes // Shader configuration functions -RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location -RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location +RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location +RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector -RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4) +RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4) RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) RLAPI Matrix GetMatrixModelview(void); // Get internal modelview matrix +RLAPI Matrix GetMatrixProjection(void); // Get internal projection matrix // Texture maps generation (PBR) // NOTE: Required shaders should be provided @@ -619,16 +600,6 @@ RLAPI void EndShaderMode(void); // End custom shader dra RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) -// VR control functions -RLAPI void InitVrSimulator(void); // Init VR simulator for selected device parameters -RLAPI void CloseVrSimulator(void); // Close VR simulator for current device -RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera -RLAPI void SetVrConfiguration(VrDeviceInfo info, Shader distortion); // Set stereo rendering configuration parameters -RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready -RLAPI void ToggleVrMode(void); // Enable/Disable VR experience -RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering -RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering - RLAPI char *LoadFileText(const char *fileName); // Load chars array from text file RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data size in bytes (image or texture) #endif @@ -847,17 +818,6 @@ typedef struct RenderBatch { float currentDepth; // Current depth value for next draw } RenderBatch; -#if defined(SUPPORT_VR_SIMULATOR) && !defined(RLGL_STANDALONE) -// VR Stereo rendering configuration for simulator -typedef struct VrStereoConfig { - Shader distortionShader; // VR stereo rendering distortion shader - Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices - Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices - int eyeViewportRight[4]; // VR stereo rendering right eye viewport [x, y, w, h] - int eyeViewportLeft[4]; // VR stereo rendering left eye viewport [x, y, w, h] -} VrStereoConfig; -#endif - #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) typedef struct rlglData { RenderBatch *currentBatch; // Current render batch @@ -881,6 +841,10 @@ typedef struct rlglData { unsigned int defaultFShaderId; // Default fragment shader Id (used by default shader program) Shader defaultShader; // Basic shader, support vertex color and diffuse texture Shader currentShader; // Shader to be used on rendering (by default, defaultShader) + + bool stereoRender; // Stereo rendering flag + Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices + Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices int currentBlendMode; // Blending mode active int glBlendSrcFactor; // Blending source factor @@ -910,15 +874,6 @@ typedef struct rlglData { int maxDepthBits; // Maximum bits for depth component } ExtSupported; // Extensions supported flags -#if defined(SUPPORT_VR_SIMULATOR) - struct { - VrStereoConfig config; // VR stereo configuration for simulator - unsigned int stereoFboId; // VR stereo rendering framebuffer id - unsigned int stereoTexId; // VR stereo color texture (attached to framebuffer) - bool simulatorReady; // VR simulator ready flag - bool stereoRender; // VR stereo rendering enabled/disabled flag - } Vr; // VR simulator data -#endif // SUPPORT_VR_SIMULATOR } rlglData; #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 @@ -961,11 +916,6 @@ static void SetRenderBatchDefault(void); // Set default render ba static void GenDrawCube(void); // Generate and draw cube static void GenDrawQuad(void); // Generate and draw quad - -#if defined(SUPPORT_VR_SIMULATOR) -static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); // Set internal projection and modelview matrix depending on eye -#endif - #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 #if defined(GRAPHICS_API_OPENGL_11) @@ -1469,13 +1419,13 @@ void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); } void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); } // Enable scissor test -RLAPI void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); } +void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); } // Disable scissor test -RLAPI void rlDisableScissorTest(void) { glDisable(GL_SCISSOR_TEST); } +void rlDisableScissorTest(void) { glDisable(GL_SCISSOR_TEST); } // Scissor test -RLAPI void rlScissor(int x, int y, int width, int height) { glScissor(x, y, width, height); } +void rlScissor(int x, int y, int width, int height) { glScissor(x, y, width, height); } // Enable wire mode void rlEnableWireMode(void) @@ -1524,6 +1474,18 @@ void rlDisableSmoothLines(void) #endif } +// Enable stereo rendering +void rlEnableStereoRender(void) +{ + RLGL.State.stereoRender = true; +} + +// Disable stereo rendering +void rlDisableStereoRender(void) +{ + RLGL.State.stereoRender = false; +} + // Unload framebuffer from GPU memory // NOTE: All attached textures/cubemaps/renderbuffers are also deleted void rlUnloadFramebuffer(unsigned int id) @@ -2889,16 +2851,21 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform) } int eyesCount = 1; -#if defined(SUPPORT_VR_SIMULATOR) - if (RLGL.Vr.stereoRender) eyesCount = 2; -#endif + if (RLGL.State.stereoRender) eyesCount = 2; for (int eye = 0; eye < eyesCount; eye++) { if (eyesCount == 1) RLGL.State.modelview = matModelView; - #if defined(SUPPORT_VR_SIMULATOR) - else SetStereoView(eye, matProjection, matModelView); - #endif + else + { + // Setup current eye viewport (half screen width) + rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight); + + // Set current eye view offset to modelview matrix + SetMatrixModelview(MatrixMultiply(matModelView, RLGL.State.eyesViewOffset[eye])); + // Set current eye projection matrix + SetMatrixProjection(RLGL.State.eyesProjection[eye]); + } // Calculate model-view-projection matrix (MVP) Matrix matMVP = MatrixMultiply(RLGL.State.modelview, RLGL.State.projection); // Transform to screen-space coordinates @@ -3145,6 +3112,20 @@ void *rlReadTexturePixels(Texture2D texture) return pixels; } +// Set eyes projection matrices for stereo rendering +void rlSetMatrixProjectionStereo(Matrix right, Matrix left) +{ + RLGL.State.eyesProjection[0] = right; + RLGL.State.eyesProjection[1] = left; +} + +// Set eyes view offsets matrices for stereo rendering +void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left) +{ + RLGL.State.eyesViewOffset[0] = right; + RLGL.State.eyesViewOffset[1] = left; +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Shaders Functions // NOTE: Those functions are exposed directly to the user in raylib.h @@ -3813,250 +3794,6 @@ void EndBlendMode(void) BeginBlendMode(BLEND_ALPHA); } -#if defined(SUPPORT_VR_SIMULATOR) -// Init VR simulator for selected device parameters -// NOTE: It modifies the global variable: RLGL.Vr.stereoFboId -void InitVrSimulator(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Initialize framebuffer and textures for stereo rendering - // NOTE: Screen size should match HMD aspect ratio - RLGL.Vr.stereoFboId = rlLoadFramebuffer(RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); - - // Load color/depth textures to attach to framebuffer - RLGL.Vr.stereoTexId = rlLoadTexture(NULL, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); - unsigned int depthId = rlLoadTextureDepth(RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, true); - - // Attach color texture and depth renderbuffer/texture to FBO - rlFramebufferAttach(RLGL.Vr.stereoFboId, RLGL.Vr.stereoTexId, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D); - rlFramebufferAttach(RLGL.Vr.stereoFboId, depthId, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER); - - RLGL.Vr.simulatorReady = true; -#else - TRACELOG(LOG_WARNING, "RLGL: VR Simulator not supported on OpenGL 1.1"); -#endif -} - -// Update VR tracking (position and orientation) and camera -// NOTE: Camera (position, target, up) gets update with head tracking information -void UpdateVrTracking(Camera *camera) -{ - // TODO: Simulate 1st person camera system -} - -// Close VR simulator for current device -void CloseVrSimulator(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (RLGL.Vr.simulatorReady) - { - rlUnloadTexture(RLGL.Vr.stereoTexId); // Unload color texture - rlUnloadFramebuffer(RLGL.Vr.stereoFboId); // Unload stereo framebuffer and depth texture/renderbuffer - } -#endif -} - -// Set stereo rendering configuration parameters -void SetVrConfiguration(VrDeviceInfo hmd, Shader distortion) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Reset RLGL.Vr.config for a new values assignment - memset(&RLGL.Vr.config, 0, sizeof(RLGL.Vr.config)); - - // Assign distortion shader - RLGL.Vr.config.distortionShader = distortion; - - // Compute aspect ratio - float aspect = ((float)hmd.hResolution*0.5f)/(float)hmd.vResolution; - - // Compute lens parameters - float lensShift = (hmd.hScreenSize*0.25f - hmd.lensSeparationDistance*0.5f)/hmd.hScreenSize; - float leftLensCenter[2] = { 0.25f + lensShift, 0.5f }; - float rightLensCenter[2] = { 0.75f - lensShift, 0.5f }; - float leftScreenCenter[2] = { 0.25f, 0.5f }; - float rightScreenCenter[2] = { 0.75f, 0.5f }; - - // Compute distortion scale parameters - // NOTE: To get lens max radius, lensShift must be normalized to [-1..1] - float lensRadius = fabsf(-1.0f - 4.0f*lensShift); - float lensRadiusSq = lensRadius*lensRadius; - float distortionScale = hmd.lensDistortionValues[0] + - hmd.lensDistortionValues[1]*lensRadiusSq + - hmd.lensDistortionValues[2]*lensRadiusSq*lensRadiusSq + - hmd.lensDistortionValues[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq; - - TRACELOGD("RLGL: VR device configuration:"); - TRACELOGD(" > Distortion Scale: %f", distortionScale); - - float normScreenWidth = 0.5f; - float normScreenHeight = 1.0f; - float scaleIn[2] = { 2.0f/normScreenWidth, 2.0f/normScreenHeight/aspect }; - float scale[2] = { normScreenWidth*0.5f/distortionScale, normScreenHeight*0.5f*aspect/distortionScale }; - - TRACELOGD(" > Distortion Shader: LeftLensCenter = { %f, %f }", leftLensCenter[0], leftLensCenter[1]); - TRACELOGD(" > Distortion Shader: RightLensCenter = { %f, %f }", rightLensCenter[0], rightLensCenter[1]); - TRACELOGD(" > Distortion Shader: Scale = { %f, %f }", scale[0], scale[1]); - TRACELOGD(" > Distortion Shader: ScaleIn = { %f, %f }", scaleIn[0], scaleIn[1]); - - // Fovy is normally computed with: 2*atan2f(hmd.vScreenSize, 2*hmd.eyeToScreenDistance) - // ...but with lens distortion it is increased (see Oculus SDK Documentation) - //float fovy = 2.0f*atan2f(hmd.vScreenSize*0.5f*distortionScale, hmd.eyeToScreenDistance); // Really need distortionScale? - float fovy = 2.0f*(float)atan2f(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance); - - // Compute camera projection matrices - float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1] - Matrix proj = MatrixPerspective(fovy, aspect, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); - RLGL.Vr.config.eyesProjection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f)); - RLGL.Vr.config.eyesProjection[1] = MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f)); - - // Compute camera transformation matrices - // NOTE: Camera movement might seem more natural if we model the head. - // Our axis of rotation is the base of our head, so we might want to add - // some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions. - RLGL.Vr.config.eyesViewOffset[0] = MatrixTranslate(-hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f); - RLGL.Vr.config.eyesViewOffset[1] = MatrixTranslate(hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f); - - // Compute eyes Viewports - RLGL.Vr.config.eyeViewportRight[2] = hmd.hResolution/2; - RLGL.Vr.config.eyeViewportRight[3] = hmd.vResolution; - - RLGL.Vr.config.eyeViewportLeft[0] = hmd.hResolution/2; - RLGL.Vr.config.eyeViewportLeft[1] = 0; - RLGL.Vr.config.eyeViewportLeft[2] = hmd.hResolution/2; - RLGL.Vr.config.eyeViewportLeft[3] = hmd.vResolution; - - if (RLGL.Vr.config.distortionShader.id > 0) - { - // Update distortion shader with lens and distortion-scale parameters - SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "leftLensCenter"), leftLensCenter, SHADER_UNIFORM_VEC2); - SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "rightLensCenter"), rightLensCenter, SHADER_UNIFORM_VEC2); - SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "leftScreenCenter"), leftScreenCenter, SHADER_UNIFORM_VEC2); - SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "rightScreenCenter"), rightScreenCenter, SHADER_UNIFORM_VEC2); - - SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "scale"), scale, SHADER_UNIFORM_VEC2); - SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "scaleIn"), scaleIn, SHADER_UNIFORM_VEC2); - SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "hmdWarpParam"), hmd.lensDistortionValues, SHADER_UNIFORM_VEC4); - SetShaderValue(RLGL.Vr.config.distortionShader, GetShaderLocation(RLGL.Vr.config.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, SHADER_UNIFORM_VEC4); - } -#endif -} - -// Detect if VR simulator is running -bool IsVrSimulatorReady(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - return RLGL.Vr.simulatorReady; -#else - return false; -#endif -} - -// Enable/Disable VR experience (device or simulator) -void ToggleVrMode(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - RLGL.Vr.simulatorReady = !RLGL.Vr.simulatorReady; - - if (!RLGL.Vr.simulatorReady) - { - RLGL.Vr.stereoRender = false; - - // Reset viewport and default projection-modelview matrices - rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); - RLGL.State.projection = MatrixOrtho(0.0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, 0.0, 0.0, 1.0); - RLGL.State.modelview = MatrixIdentity(); - } - else RLGL.Vr.stereoRender = true; -#endif -} - -// Begin VR drawing configuration -void BeginVrDrawing(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (RLGL.Vr.simulatorReady) - { - rlEnableFramebuffer(RLGL.Vr.stereoFboId); // Setup framebuffer for stereo rendering - //glEnable(GL_FRAMEBUFFER_SRGB); // Enable SRGB framebuffer (only if required) - - //rlViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) - rlClearScreenBuffers(); // Clear current framebuffer - - RLGL.Vr.stereoRender = true; - } -#endif -} - -// End VR drawing process (and desktop mirror) -void EndVrDrawing(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (RLGL.Vr.simulatorReady) - { - RLGL.Vr.stereoRender = false; // Disable stereo render - - rlDisableFramebuffer(); // Unbind current framebuffer - - rlClearScreenBuffers(); // Clear current framebuffer - - // Set viewport to default framebuffer size (screen size) - rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); - - // Let rlgl reconfigure internal matrices - rlMatrixMode(RL_PROJECTION); // Enable internal projection matrix - rlLoadIdentity(); // Reset internal projection matrix - rlOrtho(0.0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, 0.0, 0.0, 1.0); // Recalculate internal RLGL.State.projection matrix - rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix - rlLoadIdentity(); // Reset internal modelview matrix - - // Draw stereo framebuffer texture using distortion shader if available - if (RLGL.Vr.config.distortionShader.id > 0) RLGL.State.currentShader = RLGL.Vr.config.distortionShader; - else RLGL.State.currentShader = GetShaderDefault(); - - rlEnableTexture(RLGL.Vr.stereoTexId); - - rlPushMatrix(); - rlBegin(RL_QUADS); - rlColor4ub(255, 255, 255, 255); - rlNormal3f(0.0f, 0.0f, 1.0f); - - // Bottom-left corner for texture and quad - rlTexCoord2f(0.0f, 1.0f); - rlVertex2f(0.0f, 0.0f); - - // Bottom-right corner for texture and quad - rlTexCoord2f(0.0f, 0.0f); - rlVertex2f(0.0f, (float)RLGL.State.framebufferHeight); - - // Top-right corner for texture and quad - rlTexCoord2f(1.0f, 0.0f); - rlVertex2f((float)RLGL.State.framebufferWidth, (float)RLGL.State.framebufferHeight); - - // Top-left corner for texture and quad - rlTexCoord2f(1.0f, 1.0f); - rlVertex2f((float)RLGL.State.framebufferWidth, 0.0f); - rlEnd(); - rlPopMatrix(); - - rlDisableTexture(); - - // Update and draw render texture fbo with distortion to backbuffer - DrawRenderBatch(RLGL.currentBatch); - - // Restore RLGL.State.defaultShader - RLGL.State.currentShader = RLGL.State.defaultShader; - - // Reset viewport and default projection-modelview matrices - rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); - RLGL.State.projection = MatrixOrtho(0.0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight, 0.0, 0.0, 1.0); - RLGL.State.modelview = MatrixIdentity(); - - rlDisableDepthTest(); - } -#endif -} -#endif // SUPPORT_VR_SIMULATOR - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -4475,15 +4212,21 @@ static void DrawRenderBatch(RenderBatch *batch) Matrix matModelView = RLGL.State.modelview; int eyesCount = 1; -#if defined(SUPPORT_VR_SIMULATOR) - if (RLGL.Vr.stereoRender) eyesCount = 2; -#endif + if (RLGL.State.stereoRender) eyesCount = 2; for (int eye = 0; eye < eyesCount; eye++) { -#if defined(SUPPORT_VR_SIMULATOR) - if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView); -#endif + if (eyesCount == 2) + { + // Setup current eye viewport (half screen width) + rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight); + + // Set current eye view offset to modelview matrix + SetMatrixModelview(MatrixMultiply(matModelView, RLGL.State.eyesViewOffset[eye])); + // Set current eye projection matrix + SetMatrixProjection(RLGL.State.eyesProjection[eye]); + } + // Draw buffers if (batch->vertexBuffer[batch->currentBuffer].vCounter > 0) { @@ -4769,28 +4512,6 @@ static void GenDrawCube(void) glDeleteBuffers(1, &cubeVBO); glDeleteVertexArrays(1, &cubeVAO); } - -#if defined(SUPPORT_VR_SIMULATOR) -// Set internal projection and modelview matrix depending on eyes tracking data -static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView) -{ - Matrix eyeProjection = matProjection; - Matrix eyeModelView = matModelView; - - // Setup viewport and projection/modelview matrices using tracking data - rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight); - - // Apply view offset to modelview matrix - eyeModelView = MatrixMultiply(matModelView, RLGL.Vr.config.eyesViewOffset[eye]); - - // Set current eye projection matrix - eyeProjection = RLGL.Vr.config.eyesProjection[eye]; - - SetMatrixModelview(eyeModelView); - SetMatrixProjection(eyeProjection); -} -#endif // SUPPORT_VR_SIMULATOR - #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 #if defined(GRAPHICS_API_OPENGL_11)