diff --git a/examples/core/core_vr_simulator.c b/examples/core/core_vr_simulator.c index b311b8c08..f0e322a12 100644 --- a/examples/core/core_vr_simulator.c +++ b/examples/core/core_vr_simulator.c @@ -12,9 +12,9 @@ #include "raylib.h" #if defined(PLATFORM_DESKTOP) - #define GLSL_VERSION 330 + #define GLSL_VERSION 330 #else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB - #define GLSL_VERSION 100 + #define GLSL_VERSION 100 #endif int main(void) @@ -51,11 +51,8 @@ int main(void) .chromaAbCorrection[3] = 0.0f, // Chromatic aberration correction parameter 3 }; - // Init VR simulator (Oculus Rift CV1 parameters) - InitVrSimulator(device); - - // Get Vr stereo config parameters for device parameters - VrStereoConfig config = GetVrConfig(device); + // Load VR stereo config for VR device parameteres (Oculus Rift CV1 parameters) + VrStereoConfig config = LoadVrStereoMode(device); // Distortion shader (uses device lens distortion and chroma) Shader distortion = LoadShader(0, TextFormat("resources/distortion%i.fs", GLSL_VERSION)); @@ -104,7 +101,7 @@ int main(void) ClearBackground(RAYWHITE); - BeginVrDrawing(target); + BeginVrStereoMode(target, config); BeginMode3D(camera); DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); @@ -113,7 +110,7 @@ int main(void) DrawGrid(40, 1.0f); EndMode3D(); - EndVrDrawing(); + EndVrStereoMode(); BeginShaderMode(distortion); DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2){ 0.0f, 0.0f }, WHITE); @@ -127,11 +124,11 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- + UnloadVrStereoConfig(config); // Unload stereo config + UnloadRenderTexture(target); // Unload stereo render fbo UnloadShader(distortion); // Unload distortion shader - CloseVrSimulator(); // Close VR simulator - CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/src/config.h b/src/config.h index 0f6ac7a3f..55834fcd5 100644 --- a/src/config.h +++ b/src/config.h @@ -57,8 +57,6 @@ #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 //------------------------------------------------------------------------------------ diff --git a/src/core.c b/src/core.c index 9b76b54fc..744bce49e 100644 --- a/src/core.c +++ b/src/core.c @@ -82,8 +82,6 @@ * #define SUPPORT_DATA_STORAGE * 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) @@ -165,7 +163,7 @@ #include // Required for: sprintf() [Used in OpenURL()] #include // Required for: strrchr(), strcmp(), strlen() #include // Required for: time() [Used in InitTimer()] -#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in InitVrSimulator()] +#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoMode()] #include // Required for: stat() [Used in GetFileModTime()] @@ -480,15 +478,6 @@ 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; //---------------------------------------------------------------------------------- @@ -2035,6 +2024,161 @@ void EndTextureMode(void) CORE.Window.currentFbo.height = CORE.Window.screen.height; } +// Begin custom shader mode +void BeginShaderMode(Shader shader) +{ + rlSetShader(shader); +} + +// End custom shader mode (returns to default shader) +void EndShaderMode(void) +{ + rlSetShader(rlGetShaderDefault()); +} + +// Begin blending mode (alpha, additive, multiplied) +// NOTE: Only 3 blending modes supported, default blend mode is alpha +void BeginBlendMode(int mode) +{ + rlSetBlendMode(mode); +} + +// End blending mode (reset to default: alpha blending) +void EndBlendMode(void) +{ + rlSetBlendMode(BLEND_ALPHA); +} + +// 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) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + + rlEnableScissorTest(); + rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height); +} + +// End scissor mode +void EndScissorMode(void) +{ + rlDrawRenderBatchActive(); // Update and draw internal render batch + rlDisableScissorTest(); +} + +// Begin VR drawing configuration +void BeginVrStereoMode(RenderTexture2D target, VrStereoConfig config) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlEnableFramebuffer(target.id); // Setup framebuffer for stereo rendering + //glEnable(GL_FRAMEBUFFER_SRGB); // Enable SRGB framebuffer (only if required) + rlClearScreenBuffers(); // Clear current framebuffer + + rlEnableStereoRender(); + + // Set stereo render matrices + rlSetMatrixProjectionStereo(config.projection[0], config.projection[1]); + rlSetMatrixViewOffsetStereo(config.viewOffset[0], config.viewOffset[1]); +#endif +} + +// End VR drawing process (and desktop mirror) +void EndVrStereoMode(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlDisableStereoRender(); + + rlDisableFramebuffer(); // Unbind current framebuffer + + // Reset viewport and default projection-modelview matrices + rlViewport(0, 0, GetScreenWidth(), GetScreenHeight()); + rlSetMatrixProjection(MatrixOrtho(0.0, GetScreenWidth(), GetScreenHeight(), 0.0, 0.0, 1.0)); + rlSetMatrixModelview(MatrixIdentity()); + + rlDisableDepthTest(); +#endif +} + +// Load VR stereo config for VR simulator device parameters +VrStereoConfig LoadVrStereoMode(VrDeviceInfo device) +{ + VrStereoConfig config = { 0 }; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // 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; + config.leftLensCenter[0] = 0.25f + lensShift; + config.leftLensCenter[1] = 0.5f; + config.rightLensCenter[0] = 0.75f - lensShift; + config.rightLensCenter[1] = 0.5f; + config.leftScreenCenter[0] = 0.25f; + config.leftScreenCenter[1] = 0.5f; + config.rightScreenCenter[0] = 0.75f; + 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; + config.scaleIn[0] = 2.0f/normScreenWidth; + config.scaleIn[1] = 2.0f/normScreenHeight/aspect; + config.scale[0] = normScreenWidth*0.5f/distortionScale; + 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); + + config.projection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f)); + config.projection[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. + config.viewOffset[0] = MatrixTranslate(-device.interpupillaryDistance*0.5f, 0.075f, 0.045f); + config.viewOffset[1] = MatrixTranslate(device.interpupillaryDistance*0.5f, 0.075f, 0.045f); + + // Compute eyes Viewports + /* + config.eyeViewportRight[0] = 0; + config.eyeViewportRight[1] = 0; + config.eyeViewportRight[2] = device.hResolution/2; + config.eyeViewportRight[3] = device.vResolution; + + config.eyeViewportLeft[0] = device.hResolution/2; + config.eyeViewportLeft[1] = 0; + config.eyeViewportLeft[2] = device.hResolution/2; + config.eyeViewportLeft[3] = device.vResolution; + */ +#else + TRACELOG(LOG_WARNING, "RLGL: VR Simulator not supported on OpenGL 1.1"); +#endif + + return config; +} + +// Unload VR stereo config properties +void UnloadVrStereoConfig(VrStereoConfig config) +{ + //... +} + // Load shader from files and bind default locations // NOTE: If shader string is NULL, using default vertex/fragment shaders Shader LoadShader(const char *vsFileName, const char *fsFileName) @@ -2147,18 +2291,6 @@ void UnloadShader(Shader shader) } } -// Begin custom shader mode -void BeginShaderMode(Shader shader) -{ - rlSetShader(shader); -} - -// End custom shader mode (returns to default shader) -void EndShaderMode(void) -{ - rlSetShader(rlGetShaderDefault()); -} - // Get shader uniform location int GetShaderLocation(Shader shader, const char *uniformName) { @@ -2201,176 +2333,6 @@ void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture) //rlDisableShader(); } -// Begin blending mode (alpha, additive, multiplied) -// NOTE: Only 3 blending modes supported, default blend mode is alpha -void BeginBlendMode(int mode) -{ - rlSetBlendMode(mode); -} - -// End blending mode (reset to default: alpha blending) -void EndBlendMode(void) -{ - rlSetBlendMode(BLEND_ALPHA); -} - -#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, GetScreenWidth(), GetScreenHeight()); - rlSetMatrixProjection(MatrixOrtho(0.0, GetScreenWidth(), GetScreenHeight(), 0.0, 0.0, 1.0)); - rlSetMatrixModelview(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) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - - rlEnableScissorTest(); - rlScissor(x, CORE.Window.currentFbo.height - (y + height), width, height); -} - -// End scissor mode -void EndScissorMode(void) -{ - rlDrawRenderBatchActive(); // Update and draw internal render batch - rlDisableScissorTest(); -} - // Returns a ray trace from mouse position Ray GetMouseRay(Vector2 mouse, Camera camera) { diff --git a/src/raylib.h b/src/raylib.h index 359813668..41a5fbf17 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -463,6 +463,8 @@ typedef struct VrDeviceInfo { // VR Stereo rendering configuration for simulator typedef struct VrStereoConfig { + Matrix projection[2]; // VR projection matrices (per eye) + Matrix viewOffset[2]; // VR view offset matrices (per eye) float leftLensCenter[2]; // VR left lens center float rightLensCenter[2]; // VR right lens center float leftScreenCenter[2]; // VR left screen center @@ -957,12 +959,18 @@ RLAPI void BeginMode3D(Camera3D camera); // Initializes RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing RLAPI void EndTextureMode(void); // Ends drawing to render texture -RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing) -RLAPI void EndScissorMode(void); // End scissor mode RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader) RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) +RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing) +RLAPI void EndScissorMode(void); // End scissor mode +RLAPI void BeginVrStereoMode(RenderTexture2D target, VrStereoConfig config); // Begin stereo rendering (requires VR simulator) +RLAPI void EndVrStereoMode(void); // End stereo rendering (requires VR simulator) + +// VR stereo config functions for VR simulator +RLAPI VrStereoConfig LoadVrStereoMode(VrDeviceInfo device); // Load VR stereo config for VR simulator device parameters +RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR stereo config // Shader management functions // NOTE: Shader functionality is not available on OpenGL 1.1 @@ -1112,17 +1120,6 @@ RLAPI void SetCameraAltControl(int keyAlt); // Set camera alt key to RLAPI void SetCameraSmoothZoomControl(int keySmoothZoom); // Set camera smooth zoom key to combine with mouse (free camera) RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) -//------------------------------------------------------------------------------------ -// VR Simulator Functions (Module: core) -//------------------------------------------------------------------------------------ -RLAPI void InitVrSimulator(VrDeviceInfo device); // Init VR simulator for selected device parameters -RLAPI void CloseVrSimulator(void); // Close VR simulator for current device -RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready -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 - //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) //------------------------------------------------------------------------------------