diff --git a/examples/oculus_glfw_sample/base.vs b/examples/oculus_glfw_sample/base.vs new file mode 100644 index 00000000..638cb8ae --- /dev/null +++ b/examples/oculus_glfw_sample/base.vs @@ -0,0 +1,26 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexColor; + +// Input uniform values +uniform mat4 mvpMatrix; + +// Output vertex attributes (to fragment shader) +out vec2 fragTexCoord; +out vec4 fragColor; + +// NOTE: Add here your custom variables + +void main() +{ + // Send vertex attributes to fragment shader + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + + // Calculate final vertex position + gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); +} \ No newline at end of file diff --git a/examples/oculus_glfw_sample/distortion.fs b/examples/oculus_glfw_sample/distortion.fs new file mode 100644 index 00000000..a9932651 --- /dev/null +++ b/examples/oculus_glfw_sample/distortion.fs @@ -0,0 +1,64 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; + +// Input uniform values +uniform sampler2D texture0; + +// Output fragment color +out vec4 finalColor; + +// NOTE: Add here your custom variables +const vec2 LeftLensCenter = vec2(0.2863248, 0.5); +const vec2 RightLensCenter = vec2(0.7136753, 0.5); +const vec2 LeftScreenCenter = vec2(0.25, 0.5); +const vec2 RightScreenCenter = vec2(0.75, 0.5); +const vec2 Scale = vec2(0.25, 0.45); //vec2(0.1469278, 0.2350845); +const vec2 ScaleIn = vec2(4, 2.2222); +const vec4 HmdWarpParam = vec4(1, 0.22, 0.24, 0); + +/* +// Another set of default values +ChromaAbCorrection = {1.0, 0.0, 1.0, 0} +DistortionK = {1.0, 0.22, 0.24, 0} +Scale = {0.25, 0.5*AspectRatio, 0, 0} +ScaleIn = {4.0, 2/AspectRatio, 0, 0} +Left Screen Center = {0.25, 0.5, 0, 0} +Left Lens Center = {0.287994117, 0.5, 0, 0} +Right Screen Center = {0.75, 0.5, 0, 0} +Right Lens Center = {0.712005913, 0.5, 0, 0} +*/ + +// Scales input texture coordinates for distortion. +vec2 HmdWarp(vec2 in01, vec2 LensCenter) +{ + vec2 theta = (in01 - LensCenter) * ScaleIn; // Scales to [-1, 1] + float rSq = theta.x * theta.x + theta.y * theta.y; + vec2 rvector = theta * (HmdWarpParam.x + HmdWarpParam.y * rSq + HmdWarpParam.z * rSq * rSq + HmdWarpParam.w * rSq * rSq * rSq); + + return LensCenter + Scale * rvector; +} + +void main() +{ + // SOURCE: http://www.mtbs3d.com/phpbb/viewtopic.php?f=140&t=17081 + + // The following two variables need to be set per eye + vec2 LensCenter = gl_FragCoord.x < 540 ? LeftLensCenter : RightLensCenter; + vec2 ScreenCenter = gl_FragCoord.x < 540 ? LeftScreenCenter : RightScreenCenter; + + //vec2 oTexCoord = (gl_FragCoord.xy + vec2(0.5, 0.5)) / vec2(1280, 800); //Uncomment if using BGE's built-in stereo rendering + + vec2 tc = HmdWarp(fragTexCoord, LensCenter); + + if (any(bvec2(clamp(tc,ScreenCenter-vec2(0.25,0.5), ScreenCenter+vec2(0.25,0.5)) - tc))) + { + gl_FragColor = vec4(vec3(0.0), 1.0); + } + else + { + //tc.x = gl_FragCoord.x < 640 ? (2.0 * tc.x) : (2.0 * (tc.x - 0.5)); //Uncomment if using BGE's built-in stereo rendering + gl_FragColor = texture2D(texture0, tc); + } +} \ No newline at end of file diff --git a/examples/oculus_glfw_sample/rlgl_standalone_stereo.c b/examples/oculus_glfw_sample/rlgl_standalone_stereo.c index 8582adb4..1955d11e 100644 --- a/examples/oculus_glfw_sample/rlgl_standalone_stereo.c +++ b/examples/oculus_glfw_sample/rlgl_standalone_stereo.c @@ -24,11 +24,26 @@ #define RLGL_STANDALONE #include "rlgl.h" // rlgl library: OpenGL 1.1 immediate-mode style coding +#include // Required for: abs() + #define RED (Color){ 230, 41, 55, 255 } // Red #define MAROON (Color){ 190, 33, 55, 255 } // Maroon #define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo) #define DARKGRAY (Color){ 80, 80, 80, 255 } // Dark Gray +#define WHITE (Color){ 255, 255, 255, 255 } // White + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +// Rectangle type +typedef struct Rectangle { + int x; + int y; + int width; + int height; +} Rectangle; //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -41,6 +56,8 @@ static void DrawGrid(int slices, float spacing); static void DrawCube(Vector3 position, float width, float height, float length, Color color); static void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); static void DrawRectangleV(Vector2 position, Vector2 size, Color color); +static void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); +static void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); //---------------------------------------------------------------------------------- // Main Entry point @@ -52,7 +69,6 @@ int main(void) const int screenWidth = 1080; const int screenHeight = 600; - // GLFW3 Initialization + OpenGL 3.3 Context + Extensions //-------------------------------------------------------- glfwSetErrorCallback(ErrorCallback); @@ -100,6 +116,14 @@ int main(void) rlClearColor(245, 245, 245, 255); // Define clear color rlEnableDepthTest(); // Enable DEPTH_TEST for 3D + Shader distortion = LoadShader("base.vs", "distortion.fs"); + + // TODO: Upload to distortion shader configuration parameters (screen size, etc.) + //SetShaderValue(Shader shader, int uniformLoc, float *value, int size); + + // Create a RenderTexture2D to be used for render to texture + RenderTexture2D target = rlglLoadRenderTexture(screenWidth, screenHeight); + Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; Camera camera; @@ -119,51 +143,75 @@ int main(void) // Draw //---------------------------------------------------------------------------------- + rlEnableRenderTexture(target.id); // Enable render target + rlClearScreenBuffers(); // Clear current framebuffer + + for (int i = 0; i < 2; i++) + { + rlViewport(i*screenWidth/2, 0, screenWidth/2, screenHeight); + + // Calculate projection matrix (from perspective) and view matrix from camera look at + // TODO: Consider every eye fovy + Matrix matProj = MatrixPerspective(camera.fovy, (double)(screenWidth/2)/(double)screenHeight, 0.01, 1000.0); + MatrixTranspose(&matProj); + + // TODO: Recalculate view matrix considering IPD (inter-pupillary-distance) + Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + + SetMatrixModelview(matView); // Replace internal modelview matrix by a custom one + SetMatrixProjection(matProj); // Replace internal projection matrix by a custom one + + DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); + DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, RAYWHITE); + DrawGrid(10, 1.0f); + + // NOTE: Internal buffers drawing (3D data) + rlglDraw(); + + // Draw '2D' elements in the scene (GUI) +#define RLGL_CREATE_MATRIX_MANUALLY +#if defined(RLGL_CREATE_MATRIX_MANUALLY) + + matProj = MatrixOrtho(0.0, screenWidth/2, screenHeight, 0.0, 0.0, 1.0); + MatrixTranspose(&matProj); + matView = MatrixIdentity(); + + SetMatrixModelview(matView); // Replace internal modelview matrix by a custom one + SetMatrixProjection(matProj); // Replace internal projection matrix by a custom one + +#else // Let rlgl generate and multiply matrix internally + + rlMatrixMode(RL_PROJECTION); // Enable internal projection matrix + rlLoadIdentity(); // Reset internal projection matrix + rlOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0); // Recalculate internal projection matrix + rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix + rlLoadIdentity(); // Reset internal modelview matrix +#endif + // TODO: 2D not drawing properly on stereo rendering + //DrawRectangleV((Vector2){ 10.0f, 10.0f }, (Vector2){ 500.0f, 20.0f }, DARKGRAY); + + // NOTE: Internal buffers drawing (2D data) + rlglDraw(); + } - for (int i = 0; i < 2; i++) - { - rlViewport(i*screenWidth/2, 0, screenWidth/2, screenHeight); + rlDisableRenderTexture(); // Disable render target + + // Set viewport to default framebuffer size (screen size) + rlViewport(0, 0, screenWidth, screenHeight); - // Calculate projection matrix (from perspective) and view matrix from camera look at - Matrix matProj = MatrixPerspective(camera.fovy, (double)(screenWidth/2)/(double)screenHeight, 0.01, 1000.0); - MatrixTranspose(&matProj); - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - - SetMatrixModelview(matView); // Replace internal modelview matrix by a custom one - SetMatrixProjection(matProj); // Replace internal projection matrix by a custom one - - DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); - DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, RAYWHITE); - DrawGrid(10, 1.0f); - - // NOTE: Internal buffers drawing (3D data) - rlglDraw(); - - // Draw '2D' elements in the scene (GUI) - #define RLGL_CREATE_MATRIX_MANUALLY - #if defined(RLGL_CREATE_MATRIX_MANUALLY) - - matProj = MatrixOrtho(0.0, screenWidth/2, screenHeight, 0.0, 0.0, 1.0); - MatrixTranspose(&matProj); - matView = MatrixIdentity(); - - SetMatrixModelview(matView); // Replace internal modelview matrix by a custom one - SetMatrixProjection(matProj); // Replace internal projection matrix by a custom one - - #else // Let rlgl generate and multiply matrix internally - - rlMatrixMode(RL_PROJECTION); // Enable internal projection matrix - rlLoadIdentity(); // Reset internal projection matrix - rlOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0); // Recalculate internal projection matrix - rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix - rlLoadIdentity(); // Reset internal modelview matrix - #endif - DrawRectangleV((Vector2){ 10.0f, 10.0f }, (Vector2){ 600.0f, 20.0f }, DARKGRAY); - - // NOTE: Internal buffers drawing (2D data) - rlglDraw(); - } + // Let rlgl reconfigure internal matrices using OpenGL 1.1 style coding + rlMatrixMode(RL_PROJECTION); // Enable internal projection matrix + rlLoadIdentity(); // Reset internal projection matrix + rlOrtho(0.0, screenWidth, screenHeight, 0.0, 0.0, 1.0); // Recalculate internal projection matrix + rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix + rlLoadIdentity(); // Reset internal modelview matrix + + // Draw RenderTexture (fbo) using distortion shader + BeginShaderMode(distortion); + // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) + DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE); + EndShaderMode(); glfwSwapBuffers(window); glfwPollEvents(); @@ -172,7 +220,9 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - rlglClose(); // Unload rlgl internal buffers and default shader/texture + UnloadShader(distortion); + + rlglClose(); // Unload rlgl internal buffers and default shader/texture glfwDestroyWindow(window); glfwTerminate(); @@ -392,3 +442,55 @@ void DrawCubeWires(Vector3 position, float width, float height, float length, Co rlEnd(); rlPopMatrix(); } + +// Draw a part of a texture (defined by a rectangle) +static void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) +{ + Rectangle destRec = { (int)position.x, (int)position.y, abs(sourceRec.width), abs(sourceRec.height) }; + Vector2 origin = { 0, 0 }; + + DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint); +} + +// Draw a part of a texture (defined by a rectangle) with 'pro' parameters +// NOTE: origin is relative to destination rectangle size +static void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint) +{ + // Check if texture is valid + if (texture.id != 0) + { + if (sourceRec.width < 0) sourceRec.x -= sourceRec.width; + if (sourceRec.height < 0) sourceRec.y -= sourceRec.height; + + rlEnableTexture(texture.id); + + rlPushMatrix(); + rlTranslatef(destRec.x, destRec.y, 0); + rlRotatef(rotation, 0, 0, 1); + rlTranslatef(-origin.x, -origin.y, 0); + + rlBegin(RL_QUADS); + rlColor4ub(tint.r, tint.g, tint.b, tint.a); + rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer + + // Bottom-left corner for texture and quad + rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height); + rlVertex2f(0.0f, 0.0f); + + // Bottom-right corner for texture and quad + rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); + rlVertex2f(0.0f, destRec.height); + + // Top-right corner for texture and quad + rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); + rlVertex2f(destRec.width, destRec.height); + + // Top-left corner for texture and quad + rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); + rlVertex2f(destRec.width, 0.0f); + rlEnd(); + rlPopMatrix(); + + rlDisableTexture(); + } +}