diff options
| author | victorfisac <[email protected]> | 2016-07-05 11:57:05 +0200 |
|---|---|---|
| committer | victorfisac <[email protected]> | 2016-07-05 11:57:05 +0200 |
| commit | 1aecd5be072083e27e4289499865b5681f1ea656 (patch) | |
| tree | 808159aa95df9b2be5509d83791aa6cad4ddf6b8 /src/rlgl.c | |
| parent | 1b0996fb0bcf68e2a14bc6260c6f2c5366ab033f (diff) | |
| parent | 2ff2096b36d80078cbda5e61ff77d7fedeeeaeb5 (diff) | |
| download | raylib-1aecd5be072083e27e4289499865b5681f1ea656.tar.gz raylib-1aecd5be072083e27e4289499865b5681f1ea656.zip | |
Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop
Diffstat (limited to 'src/rlgl.c')
| -rw-r--r-- | src/rlgl.c | 981 |
1 files changed, 636 insertions, 345 deletions
@@ -31,6 +31,7 @@ #include <stdio.h> // Required for: fopen(), fclose(), fread()... [Used only on ReadTextFile()] #include <stdlib.h> // Required for: malloc(), free(), rand() #include <string.h> // Required for: strcmp(), strlen(), strtok() +#include <math.h> // Required for: atan() #ifndef RLGL_STANDALONE #include "raymath.h" // Required for Vector3 and Matrix functions @@ -44,6 +45,10 @@ #endif #endif +#if defined(GRAPHICS_API_OPENGL_21) + #define GRAPHICS_API_OPENGL_33 +#endif + #if defined(GRAPHICS_API_OPENGL_33) #ifdef __APPLE__ #include <OpenGL/gl3.h> // OpenGL 3 library for OSX @@ -68,10 +73,11 @@ #include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()] #endif -#if !defined(GRAPHICS_API_OPENGL_11) +#if !defined(GRAPHICS_API_OPENGL_11) && !defined(RLGL_NO_STANDARD_SHADER) #include "standard_shader.h" // Standard shader to embed #endif +//#define RLGL_OCULUS_SUPPORT // Enable Oculus Rift code #if defined(RLGL_OCULUS_SUPPORT) #include "external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL #endif @@ -130,6 +136,12 @@ #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #endif +#if defined(GRAPHICS_API_OPENGL_ES2) + #define glClearDepth glClearDepthf + #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER + #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER +#endif + // Default vertex attribute names on shader to set location points #define DEFAULT_ATTRIB_POSITION_NAME "vertexPosition" // shader-location = 0 #define DEFAULT_ATTRIB_TEXCOORD_NAME "vertexTexCoord" // shader-location = 1 @@ -235,7 +247,7 @@ static bool useTempBuffer = false; static Shader defaultShader; static Shader standardShader; // Lazy initialization when GetStandardShader() static Shader currentShader; // By default, defaultShader -static bool standardShaderLoaded = false; +static bool standardShaderLoaded = false; // Flag to track if standard shader has been loaded // Flags for supported extensions static bool vaoSupported = false; // VAO support (OpenGL ES2 could not support VAO extension) @@ -262,6 +274,14 @@ static OculusMirror mirror; // Oculus mirror texture and fbo static unsigned int frameIndex = 0; // Oculus frames counter, used to discard frames from chain #endif +static bool oculusReady = false; // Oculus device ready flag +static bool oculusSimulator = false; // Oculus device simulator +static bool vrEnabled = false; // VR experience enabled (Oculus device or simulator) +static bool vrControl = true; // VR controlled by user code, instead of internally + +static RenderTexture2D stereoFbo; +static Shader distortionShader; + // Compressed textures support flags static bool texCompDXTSupported = false; // DDS texture compression support static bool npotSupported = false; // NPOT textures full support @@ -274,11 +294,15 @@ static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays; //static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted #endif -static int blendMode = 0; +static int blendMode = 0; // Track current blending mode // White texture useful for plain color polys (required by shader) static unsigned int whiteTexture; +// Default framebuffer size (required by Oculus device) +static int screenWidth; // Default framebuffer width +static int screenHeight; // Default framebuffer height + //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- @@ -294,15 +318,18 @@ static void UnloadStandardShader(void); // Unload standard shader static void LoadDefaultBuffers(void); // Load default internal buffers (lines, triangles, quads) static void UpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data -static void DrawDefaultBuffers(void); // Draw default internal buffers vertex data +static void DrawDefaultBuffers(int eyesCount); // Draw default internal buffers vertex data static void UnloadDefaultBuffers(void); // Unload default internal buffers vertex data from CPU and GPU +// Set internal projection and modelview matrix depending on eyes tracking data +static void SetOculusView(int eye, Matrix matProjection, Matrix matModelView); + static void SetShaderLights(Shader shader); // Sets shader uniform values for lights array static char *ReadTextFile(const char *fileName); #endif -#if defined(RLGL_OCULUS_SUPPORT) // Oculus Rift functions +#if defined(RLGL_OCULUS_SUPPORT) 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 @@ -465,7 +492,8 @@ void rlOrtho(double left, double right, double bottom, double top, double near, #endif -// Set the viewport area (trasnformation from normalized device coordinates to window coordinates) +// Set the viewport area (transformation from normalized device coordinates to window coordinates) +// NOTE: Updates global variables: screenWidth, screenHeight void rlViewport(int x, int y, int width, int height) { glViewport(x, y, width, height); @@ -857,6 +885,8 @@ void rlDeleteRenderTextures(RenderTexture2D target) if (target.id != 0) glDeleteFramebuffers(1, &target.id); if (target.texture.id != 0) glDeleteTextures(1, &target.texture.id); if (target.depth.id != 0) glDeleteTextures(1, &target.depth.id); + + TraceLog(INFO, "[FBO ID %i] Unloaded render texture data from VRAM (GPU)", target.id); #endif } @@ -916,6 +946,8 @@ int rlGetVersion(void) { #if defined(GRAPHICS_API_OPENGL_11) return OPENGL_11; +#elif defined(GRAPHICS_API_OPENGL_21) + return OPENGL_21; #elif defined(GRAPHICS_API_OPENGL_33) return OPENGL_33; #elif defined(GRAPHICS_API_OPENGL_ES2) @@ -927,8 +959,8 @@ int rlGetVersion(void) // Module Functions Definition - rlgl Functions //---------------------------------------------------------------------------------- -// Init OpenGL 3.3+ required data -void rlglInit(void) +// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states +void rlglInit(int width, int height) { // Check OpenGL information and capabilities //------------------------------------------------------------------------------ @@ -1074,18 +1106,7 @@ void rlglInit(void) // Initialize buffers, default shaders and default textures //---------------------------------------------------------- - // Set default draw mode - currentDrawMode = RL_TRIANGLES; - - // Reset projection and modelview matrices - projection = MatrixIdentity(); - modelview = MatrixIdentity(); - currentMatrix = &modelview; - - // Initialize matrix stack - for (int i = 0; i < MATRIX_STACK_SIZE; i++) stack[i] = MatrixIdentity(); - - // Create default white texture for plain colors (required by shader) + // Init default white texture unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes) whiteTexture = rlglLoadTexture(pixels, 1, 1, UNCOMPRESSED_R8G8B8A8, 1); @@ -1097,7 +1118,8 @@ void rlglInit(void) defaultShader = LoadDefaultShader(); currentShader = defaultShader; - LoadDefaultBuffers(); // Initialize default vertex arrays buffers (lines, triangles, quads) + // Init default vertex arrays buffers (lines, triangles, quads) + LoadDefaultBuffers(); // Init temp vertex buffer, used when transformation required (translate, rotate, scale) tempBuffer = (Vector3 *)malloc(sizeof(Vector3)*TEMP_VERTEX_BUFFER_SIZE); @@ -1115,7 +1137,50 @@ void rlglInit(void) drawsCounter = 1; draws[drawsCounter - 1].textureId = whiteTexture; + currentDrawMode = RL_TRIANGLES; // Set default draw mode + + // Init internal matrix stack (emulating OpenGL 1.1) + for (int i = 0; i < MATRIX_STACK_SIZE; i++) stack[i] = MatrixIdentity(); + + // Init internal projection and modelview matrices + projection = MatrixIdentity(); + modelview = MatrixIdentity(); + currentMatrix = &modelview; +#endif // defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + + // Initialize OpenGL default states + //---------------------------------------------------------- + + // Init state: Depth test + glDepthFunc(GL_LEQUAL); // Type of depth testing to apply + glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D) + + // Init state: Blending mode + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed) + glEnable(GL_BLEND); // Enable color blending (required to work with transparencies) + + // Init state: Culling + // NOTE: All shapes/models triangles are drawn CCW + glCullFace(GL_BACK); // Cull the back face (default) + glFrontFace(GL_CCW); // Front face are defined counter clockwise (default) + glEnable(GL_CULL_FACE); // Enable backface culling + +#if defined(GRAPHICS_API_OPENGL_11) + // Init state: Color hints (deprecated in OpenGL 3.0+) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation + glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) #endif + + // Init state: Color/Depth buffers clear + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black) + glClearDepth(1.0f); // Set clear depth value (default) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D) + + // Store screen size into global variables + screenWidth = width; + screenHeight = height; + + TraceLog(INFO, "OpenGL default states initialized successfully"); } // Vertex Buffer Object deinitialization (memory free) @@ -1145,76 +1210,32 @@ void rlglClose(void) void rlglDraw(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -/* - for (int i = 0; i < modelsCount; i++) - { - rlglDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform); - } -*/ - // NOTE: Default buffers always drawn at the end - UpdateDefaultBuffers(); - DrawDefaultBuffers(); -#endif -} - -// Initialize Graphics Device (OpenGL stuff) -// NOTE: Stores global variables screenWidth and screenHeight -void rlglInitGraphics(int offsetX, int offsetY, int width, int height) -{ - // NOTE: Required! viewport must be recalculated if screen resized! - glViewport(offsetX/2, offsetY/2, width - offsetX, height - offsetY); // Set viewport width and height - - // NOTE: Don't confuse glViewport with the transformation matrix - // NOTE: glViewport just defines the area of the context that you will actually draw to. - - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black) - //glClearDepth(1.0f); // Clear depth buffer (default) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers, depth buffer is used for 3D - - glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D) - glDepthFunc(GL_LEQUAL); // Type of depth testing to apply - - glEnable(GL_BLEND); // Enable color blending (required to work with transparencies) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed) - -#if defined(GRAPHICS_API_OPENGL_11) - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation (Deprecated in OGL 3.0) - // Other options: GL_FASTEST, GL_DONT_CARE (default) -#endif - - rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix - rlLoadIdentity(); // Reset current matrix (PROJECTION) - - rlOrtho(0, width - offsetX, height - offsetY, 0, 0.0f, 1.0f); // Config orthographic mode: top-left corner --> (0,0) - - rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - - // NOTE: All shapes/models triangles are drawn CCW - - glEnable(GL_CULL_FACE); // Enable backface culling (Disabled by default) - //glCullFace(GL_BACK); // Cull the Back face (default) - //glFrontFace(GL_CCW); // Front face are defined counter clockwise (default) + // NOTE: In a future version, models could be stored in a stack... + //for (int i = 0; i < modelsCount; i++) rlglDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform); -#if defined(GRAPHICS_API_OPENGL_11) - glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) (Deprecated on OpenGL 3.3+) - // Possible options: GL_SMOOTH (Color interpolation) or GL_FLAT (no interpolation) + // NOTE: Default buffers upload and draw + UpdateDefaultBuffers(); + + if (vrEnabled && vrControl) DrawDefaultBuffers(2); + else DrawDefaultBuffers(1); #endif - - 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 defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_33) + // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions) 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"); + +#if defined(GRAPHICS_API_OPENGL_21) + if (GLAD_GL_VERSION_2_1) TraceLog(INFO, "OpenGL 2.1 profile supported"); +#elif defined(GRAPHICS_API_OPENGL_33) + if(GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); +#endif // 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 @@ -1628,8 +1649,8 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic) int drawHint = GL_STATIC_DRAW; if (dynamic) drawHint = GL_DYNAMIC_DRAW; - GLuint vaoId = 0; // Vertex Array Objects (VAO) - GLuint vboId[7]; // Vertex Buffer Objects (VBOs) + GLuint vaoId = 0; // Vertex Array Objects (VAO) + GLuint vboId[7] = { 0 }; // Vertex Buffer Objects (VBOs) if (vaoSupported) { @@ -1725,7 +1746,6 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic) glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*mesh->triangleCount*3, mesh->indices, GL_STATIC_DRAW); } - mesh->vboId[0] = vboId[0]; // Vertex position VBO mesh->vboId[1] = vboId[1]; // Texcoords VBO mesh->vboId[2] = vboId[2]; // Normals VBO @@ -1848,26 +1868,23 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + int eyesCount = 1; + if (vrEnabled) eyesCount = 2; + glUseProgram(material.shader.id); + // Upload to shader material.colDiffuse + float vColorDiffuse[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 }; + glUniform4fv(material.shader.tintColorLoc, 1, vColorDiffuse); + // At this point the modelview matrix just contains the view matrix (camera) // That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix() Matrix matView = modelview; // View matrix (camera) Matrix matProjection = projection; // Projection matrix (perspective) - + // Calculate model-view matrix combining matModel and matView Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates - // Calculate model-view-projection matrix (MVP) - Matrix matMVP = MatrixMultiply(matModelView, matProjection); // Transform to screen-space coordinates - - // Send combined model-view-projection matrix to shader - glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - - // Upload to shader material.colDiffuse - float vColorDiffuse[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 }; - glUniform4fv(material.shader.tintColorLoc, 1, vColorDiffuse); - // Check if using standard shader to get location points // 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) @@ -1895,12 +1912,12 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Upload to shader glossiness glUniform1f(glGetUniformLocation(material.shader.id, "glossiness"), material.glossiness); } - + // Set shader textures (diffuse, normal, specular) glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id); glUniform1i(material.shader.mapTexture0Loc, 0); // Diffuse texture fits in active texture unit 0 - + if ((material.texNormal.id != 0) && (material.shader.mapTexture1Loc != -1)) { // Upload to shader specular map flag @@ -1920,7 +1937,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glBindTexture(GL_TEXTURE_2D, material.texSpecular.id); glUniform1i(material.shader.mapTexture2Loc, 2); // Specular texture fits in active texture unit 2 } - + if (vaoSupported) { glBindVertexArray(mesh.vaoId); @@ -1945,12 +1962,22 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glEnableVertexAttribArray(material.shader.normalLoc); } - // Bind mesh VBO data: vertex colors (shader-location = 3, if available) , tangents, texcoords2 (if available) + // Bind mesh VBO data: vertex colors (shader-location = 3, if available) if (material.shader.colorLoc != -1) { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]); - glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(material.shader.colorLoc); + if (mesh.vboId[3] != 0) + { + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]); + glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(material.shader.colorLoc); + } + else + { + // Set default value for unused attribute + // NOTE: Required when using default shader and no VAO support + glVertexAttrib4f(material.shader.colorLoc, 1.0f, 1.0f, 1.0f, 1.0f); + glDisableVertexAttribArray(material.shader.colorLoc); + } } // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) @@ -1972,9 +1999,21 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); } - // Draw call! - if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw - else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); + for (int eye = 0; eye < eyesCount; eye++) + { + if (eyesCount == 2) SetOculusView(eye, matProjection, matModelView); + else modelview = matModelView; + + // Calculate model-view-projection matrix (MVP) + Matrix matMVP = MatrixMultiply(modelview, projection); // Transform to screen-space coordinates + + // Send combined model-view-projection matrix to shader + glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + + // Draw call! + if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw + else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); + } if (material.texNormal.id != 0) { @@ -1999,6 +2038,10 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) } glUseProgram(0); // Unbind shader program + + // Restore projection/modelview matrices + projection = matProjection; + modelview = matView; #endif } @@ -2293,7 +2336,7 @@ Shader GetDefaultShader(void) Shader GetStandardShader(void) { Shader shader = { 0 }; - + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) if (standardShaderLoaded) shader = standardShader; else @@ -2314,7 +2357,7 @@ int GetShaderLocation(Shader shader, const char *uniformName) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) location = glGetUniformLocation(shader.id, uniformName); - if (location == -1) TraceLog(WARNING, "[SHDR ID %i] Shader location for %s could not be found", shader.id, uniformName); + if (location == -1) TraceLog(DEBUG, "[SHDR ID %i] Shader location for %s could not be found", shader.id, uniformName); #endif return location; } @@ -2461,131 +2504,348 @@ void DestroyLight(Light light) #endif } -#if defined(RLGL_OCULUS_SUPPORT) -// Init Oculus Rift device -// NOTE: Device initialization should be done before window creation? +// Init Oculus Rift device (or Oculus device simulator) void InitOculusDevice(void) { +#if defined(RLGL_OCULUS_SUPPORT) // 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(); + TraceLog(WARNING, "OVR: Could not initialize Oculus device"); + oculusReady = false; } + else + { + result = ovr_Create(&session, &luid); + if (OVR_FAILURE(result)) + { + TraceLog(WARNING, "OVR: Could not create Oculus session"); + ovr_Shutdown(); + oculusReady = false; + } + else + { + 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); + + oculusReady = true; + vrEnabled = true; + } + } +#else + oculusReady = false; +#endif - 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); + if (!oculusReady) + { + TraceLog(WARNING, "VR: Initializing Oculus simulator"); + + // Initialize framebuffer and textures for stereo rendering + stereoFbo = rlglLoadRenderTexture(screenWidth, screenHeight); + + // Load oculus-distortion shader (oculus parameters setup internally) + // TODO: Embed coulus distortion shader (in this function like default shader?) + distortionShader = LoadShader("resources/shaders/glsl330/base.vs", "resources/shaders/glsl330/distortion.fs"); + + oculusSimulator = true; + vrEnabled = true; + } } -// Close Oculus Rift device +// Close Oculus Rift device (or Oculus device simulator) void CloseOculusDevice(void) { - UnloadOculusMirror(session, mirror); // Unload Oculus mirror buffer - UnloadOculusBuffer(session, buffer); // Unload Oculus texture buffers +#if defined(RLGL_OCULUS_SUPPORT) + if (oculusReady) + { + 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 + } + else +#endif + { + // Unload stereo framebuffer and texture + rlDeleteRenderTextures(stereoFbo); + + // Unload oculus-distortion shader + UnloadShader(distortionShader); + } + + oculusReady = false; +} + +// Detect if oculus device is available +bool IsOculusReady(void) +{ + return (oculusReady || oculusSimulator) && vrEnabled; +} - ovr_Destroy(session); // Free Oculus session data - ovr_Shutdown(); // Close Oculus device connection +// Enable/Disable VR experience (Oculus device or simulator) +void ToggleVR(void) +{ + vrEnabled = !vrEnabled; } // Update Oculus Rift tracking (position and orientation) void UpdateOculusTracking(void) { - frameIndex++; +#if defined(RLGL_OCULUS_SUPPORT) + if (oculusReady) + { + 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]; + 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]; + + // 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); + //if (sessionStatus.HmdPresent) // HMD is present. + //if (sessionStatus.DisplayLost) // HMD was unplugged or the display driver was manually disabled or encountered a TDR. + //if (sessionStatus.HmdMounted) // HMD is on the user's head. + //if (sessionStatus.IsVisible) // the game or experience has VR focus and is visible in the HMD. + } + else +#endif + { + // TODO: Use alternative inputs (mouse, keyboard) to simulate tracking data (eyes position/orientation) + } } -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); +// Set internal projection and modelview matrix depending on eyes tracking data +static void SetOculusView(int eye, Matrix matProjection, Matrix matModelView) +{ + if (vrEnabled) + { + Matrix eyeProjection = matProjection; + Matrix eyeModelView = matModelView; + +#if defined(RLGL_OCULUS_SUPPORT) + if (oculusReady) + { + 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 eyeRenderPose = (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(&eyeRenderPose); + Matrix eyeOrientation = QuaternionToMatrix(eyeRenderPose); + 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 containing eye-head movement + eyeModelView = MatrixMultiply(matModelView, eyeView); // Combine internal camera matrix (modelview) wih eye-head movement + + eyeProjection = layer.eyeProjections[eye]; + } + else +#endif + { + // Setup viewport and projection/modelview matrices using tracking data + rlViewport(eye*screenWidth/2, 0, screenWidth/2, screenHeight); + + static float IPD = 0.064f; // InterpupillaryDistance + float HScreenSize = 0.14976f; + float VScreenSize = 0.0936f; // HScreenSize/(1280.0f/800.0f) + float VScreenCenter = 0.04675f; + float EyeToScreenDistance = 0.041f; + float LensSeparationDistance = 0.064f; //0.0635f (DK1) + + // NOTE: fovy value obtained from device parameters (Oculus Rift CV1) + float halfScreenDistance = VScreenSize/2.0f; + float fovy = 2.0f*atan(halfScreenDistance/EyeToScreenDistance)*RAD2DEG; + + float viewCenter = (float)HScreenSize*0.25f; + float eyeProjectionShift = viewCenter - LensSeparationDistance*0.5f; + float projectionCenterOffset = eyeProjectionShift/(float)HScreenSize; //4.0f*eyeProjectionShift/(float)HScreenSize; +/* + static float scale[2] = { 0.25, 0.45 }; + + if (IsKeyDown(KEY_RIGHT)) scale[0] += 0.01; + else if (IsKeyDown(KEY_LEFT)) scale[0] -= 0.01; + else if (IsKeyDown(KEY_UP)) scale[1] += 0.01; + else if (IsKeyDown(KEY_DOWN)) scale[1] -= 0.01; + + SetShaderValue(distortionShader, GetShaderLocation(distortionShader, "Scale"), scale, 2); + + if (IsKeyDown(KEY_N)) IPD += 0.02; + else if (IsKeyDown(KEY_M)) IPD -= 0.02; +*/ + // The matrixes for offsetting the projection and view for each eye, to achieve stereo effect + Vector3 projectionOffset = { -projectionCenterOffset, 0.0f, 0.0f }; + + // 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. + Vector3 viewOffset = { -IPD/2.0f, 0.075f, 0.045f }; + + // Negate the left eye versions + if (eye == 0) + { + projectionOffset.x *= -1.0f; + viewOffset.x *= -1.0f; + } - 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); + // Adjust the view and projection matrixes + // View matrix is translated based on the eye offset + Matrix projCenter = MatrixPerspective(fovy, (double)((float)screenWidth*0.5f)/(double)screenHeight, 0.01, 1000.0); - Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); - Matrix modelEyeView = MatrixMultiply(modelview, eyeView); // Using internal camera modelview matrix + Matrix projTranslation = MatrixTranslate(projectionOffset.x, projectionOffset.y, projectionOffset.z); + Matrix viewTranslation = MatrixTranslate(viewOffset.x, viewOffset.y, viewOffset.z); - SetMatrixModelview(modelEyeView); - SetMatrixProjection(layer.eyeProjections[eye]); + eyeProjection = MatrixMultiply(projCenter, projTranslation); // projection + eyeModelView = MatrixMultiply(matModelView, viewTranslation); // modelview + + MatrixTranspose(&eyeProjection); + } + + SetMatrixModelview(eyeModelView); // ERROR! We are modifying modelview for next eye!!! + SetMatrixProjection(eyeProjection); + } } +// Begin Oculus drawing configuration void BeginOculusDrawing(void) { - GLuint currentTexId; - int currentIndex; - - ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, ¤tIndex); - ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, ¤tTexId); +#if defined(RLGL_OCULUS_SUPPORT) + if (oculusReady) + { + 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 + 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 + } + else +#endif + { + // Setup framebuffer for stereo rendering + rlEnableRenderTexture(stereoFbo.id); + } - //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); + //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) rlClearScreenBuffers(); // Clear current framebuffer(s) + + vrControl = true; } +// End Oculus drawing process (and desktop mirror) 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); +#if defined(RLGL_OCULUS_SUPPORT) + if (oculusReady) + { + // Unbind current framebuffer (Oculus buffer) + 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); + // Blit mirror texture to back buffer + BlitOculusMirror(session, mirror); + } + else +#endif + { + // Unbind current framebuffer + rlDisableRenderTexture(); + + rlClearScreenBuffers(); // Clear current framebuffer + + // Set viewport to default framebuffer size (screen size) + rlViewport(0, 0, screenWidth, screenHeight); + + // Let rlgl reconfigure internal matrices + 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 (stereoFbo) using distortion shader + currentShader = distortionShader; + + rlEnableTexture(stereoFbo.texture.id); + + 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, stereoFbo.texture.height); - // 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); + // Top-right corner for texture and quad + rlTexCoord2f(1.0f, 0.0f); + rlVertex2f(stereoFbo.texture.width, stereoFbo.texture.height); + + // Top-left corner for texture and quad + rlTexCoord2f(1.0f, 1.0f); + rlVertex2f(stereoFbo.texture.width, 0.0f); + rlEnd(); + rlPopMatrix(); + + rlDisableTexture(); + + UpdateDefaultBuffers(); + DrawDefaultBuffers(1); + + currentShader = defaultShader; + } + + rlDisableDepthTest(); + + vrControl = false; } -#endif //---------------------------------------------------------------------------------- // Module specific Functions Definition @@ -2746,55 +3006,65 @@ static Shader LoadDefaultShader(void) Shader shader; // Vertex shader directly defined, no external file required -#if defined(GRAPHICS_API_OPENGL_33) - char vShaderStr[] = "#version 330 \n" - "in vec3 vertexPosition; \n" - "in vec2 vertexTexCoord; \n" - "in vec4 vertexColor; \n" - "out vec2 fragTexCoord; \n" - "out vec4 fragColor; \n" + char vDefaultShaderStr[] = +#if defined(GRAPHICS_API_OPENGL_21) + "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) - char vShaderStr[] = "#version 100 \n" - "attribute vec3 vertexPosition; \n" - "attribute vec2 vertexTexCoord; \n" - "attribute vec4 vertexColor; \n" - "varying vec2 fragTexCoord; \n" - "varying vec4 fragColor; \n" -#endif - "uniform mat4 mvpMatrix; \n" - "void main() \n" - "{ \n" - " fragTexCoord = vertexTexCoord; \n" - " fragColor = vertexColor; \n" - " gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n" - "} \n"; + "#version 100 \n" +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) + "attribute vec3 vertexPosition; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" +#elif defined(GRAPHICS_API_OPENGL_33) + "#version 330 \n" + "in vec3 vertexPosition; \n" + "in vec2 vertexTexCoord; \n" + "in vec4 vertexColor; \n" + "out vec2 fragTexCoord; \n" + "out vec4 fragColor; \n" +#endif + "uniform mat4 mvpMatrix; \n" + "void main() \n" + "{ \n" + " fragTexCoord = vertexTexCoord; \n" + " fragColor = vertexColor; \n" + " gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n" + "} \n"; // Fragment shader directly defined, no external file required -#if defined(GRAPHICS_API_OPENGL_33) - char fShaderStr[] = "#version 330 \n" - "in vec2 fragTexCoord; \n" - "in vec4 fragColor; \n" - "out vec4 finalColor; \n" + char fDefaultShaderStr[] = +#if defined(GRAPHICS_API_OPENGL_21) + "#version 120 \n" #elif defined(GRAPHICS_API_OPENGL_ES2) - char fShaderStr[] = "#version 100 \n" - "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) - "varying vec2 fragTexCoord; \n" - "varying vec4 fragColor; \n" -#endif - "uniform sampler2D texture0; \n" - "uniform vec4 colDiffuse; \n" - "void main() \n" - "{ \n" -#if defined(GRAPHICS_API_OPENGL_33) - " vec4 texelColor = texture(texture0, fragTexCoord); \n" - " finalColor = texelColor*colDiffuse*fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) - " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0 - " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "#version 100 \n" + "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" +#elif defined(GRAPHICS_API_OPENGL_33) + "#version 330 \n" + "in vec2 fragTexCoord; \n" + "in vec4 fragColor; \n" + "out vec4 finalColor; \n" +#endif + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" +#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0 + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" +#elif defined(GRAPHICS_API_OPENGL_33) + " vec4 texelColor = texture(texture0, fragTexCoord); \n" + " finalColor = texelColor*colDiffuse*fragColor; \n" #endif - "} \n"; + "} \n"; - shader.id = LoadShaderProgram(vShaderStr, fShaderStr); + shader.id = LoadShaderProgram(vDefaultShaderStr, fDefaultShaderStr); if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Default shader loaded successfully", shader.id); else TraceLog(WARNING, "[SHDR ID %i] Default shader could not be loaded", shader.id); @@ -2813,6 +3083,7 @@ static Shader LoadStandardShader(void) { Shader shader; +#if !defined(RLGL_NO_STANDARD_SHADER) // Load standard shader (embeded in standard_shader.h) shader.id = LoadShaderProgram(vStandardShaderStr, fStandardShaderStr); @@ -2828,6 +3099,10 @@ static Shader LoadStandardShader(void) TraceLog(WARNING, "[SHDR ID %i] Standard shader could not be loaded, using default shader", shader.id); shader = GetDefaultShader(); } +#else + shader = defaultShader; + TraceLog(WARNING, "[SHDR ID %i] Standard shader not available, using default shader", shader.id); +#endif return shader; } @@ -2878,12 +3153,13 @@ static void UnloadDefaultShader(void) static void UnloadStandardShader(void) { glUseProgram(0); - +#if !defined(RLGL_NO_STANDARD_SHADER) //glDetachShader(defaultShader, vertexShader); //glDetachShader(defaultShader, fragmentShader); //glDeleteShader(vertexShader); // Already deleted on shader compilation //glDeleteShader(fragmentShader); // Already deleted on shader compilation glDeleteProgram(standardShader.id); +#endif } @@ -3009,7 +3285,7 @@ static void LoadDefaultBuffers(void) glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (triangles)", triangles.vaoId); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully(triangles)", triangles.vboId[0], triangles.vboId[1]); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (triangles)", triangles.vboId[0], triangles.vboId[1]); // Upload and link quads vertex buffers if (vaoSupported) @@ -3131,146 +3407,154 @@ static void UpdateDefaultBuffers(void) // Draw default internal buffers vertex data // NOTE: We draw in this order: lines, triangles, quads -static void DrawDefaultBuffers(void) +static void DrawDefaultBuffers(int eyesCount) { - // Set current shader and upload current MVP matrix - if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) - { - glUseProgram(currentShader.id); - - // Create modelview-projection matrix - Matrix matMVP = MatrixMultiply(modelview, projection); - - glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); - glUniform1i(currentShader.mapTexture0Loc, 0); - - // NOTE: Additional map textures not considered for default buffers drawing - } - - // Draw lines buffers - if (lines.vCounter > 0) + Matrix matProjection = projection; + Matrix matModelView = modelview; + + for (int eye = 0; eye < eyesCount; eye++) { - glBindTexture(GL_TEXTURE_2D, whiteTexture); + if (eyesCount == 2) SetOculusView(eye, matProjection, matModelView); - if (vaoSupported) + // Set current shader and upload current MVP matrix + if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) { - glBindVertexArray(lines.vaoId); + glUseProgram(currentShader.id); + + // Create modelview-projection matrix + Matrix matMVP = MatrixMultiply(modelview, projection); + + glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); + glUniform1i(currentShader.mapTexture0Loc, 0); + + // NOTE: Additional map textures not considered for default buffers drawing } - else + + // Draw lines buffers + if (lines.vCounter > 0) { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - } + glBindTexture(GL_TEXTURE_2D, whiteTexture); - glDrawArrays(GL_LINES, 0, lines.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } + if (vaoSupported) + { + glBindVertexArray(lines.vaoId); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + } - // Draw triangles buffers - if (triangles.vCounter > 0) - { - glBindTexture(GL_TEXTURE_2D, whiteTexture); + glDrawArrays(GL_LINES, 0, lines.vCounter); - if (vaoSupported) - { - glBindVertexArray(triangles.vaoId); - } - else - { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); + if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); } - glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); + // Draw triangles buffers + if (triangles.vCounter > 0) + { + glBindTexture(GL_TEXTURE_2D, whiteTexture); - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } + if (vaoSupported) + { + glBindVertexArray(triangles.vaoId); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + } - // Draw quads buffers - if (quads.vCounter > 0) - { - int quadsCount = 0; - int numIndicesToProcess = 0; - int indicesOffset = 0; + glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); - if (vaoSupported) - { - glBindVertexArray(quads.vaoId); + if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); } - else + + // Draw quads buffers + if (quads.vCounter > 0) { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - // Bind vertex attrib: texcoord (shader-location = 1) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); - glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.texcoordLoc); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); - } + int quadsCount = 0; + int numIndicesToProcess = 0; + int indicesOffset = 0; - //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); + if (vaoSupported) + { + glBindVertexArray(quads.vaoId); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: texcoord (shader-location = 1) + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); + glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.texcoordLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); + } - for (int i = 0; i < drawsCounter; i++) - { - quadsCount = draws[i].vertexCount/4; - numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad + //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); - //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); + for (int i = 0; i < drawsCounter; i++) + { + quadsCount = draws[i].vertexCount/4; + numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad - glBindTexture(GL_TEXTURE_2D, draws[i].textureId); + //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); - // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process -#if defined(GRAPHICS_API_OPENGL_33) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*indicesOffset)); -#elif defined(GRAPHICS_API_OPENGL_ES2) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*indicesOffset)); -#endif - //GLenum err; - //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! + glBindTexture(GL_TEXTURE_2D, draws[i].textureId); - indicesOffset += draws[i].vertexCount/4*6; - } + // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process + #if defined(GRAPHICS_API_OPENGL_33) + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*indicesOffset)); + #elif defined(GRAPHICS_API_OPENGL_ES2) + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*indicesOffset)); + #endif + //GLenum err; + //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! - if (!vaoSupported) - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } + indicesOffset += draws[i].vertexCount/4*6; + } - glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures - } + if (!vaoSupported) + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } - if (vaoSupported) glBindVertexArray(0); // Unbind VAO + glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures + } - glUseProgram(0); // Unbind shader program + if (vaoSupported) glBindVertexArray(0); // Unbind VAO + glUseProgram(0); // Unbind shader program + } + // Reset draws counter drawsCounter = 1; draws[0].textureId = whiteTexture; @@ -3287,6 +3571,10 @@ static void DrawDefaultBuffers(void) // Reset depth for next draw currentDepth = -1.0f; + + // Restore projection/modelview matrices + projection = matProjection; + modelview = matModelView; } // Unload default internal buffers vertex data from CPU and GPU @@ -3682,7 +3970,10 @@ static void BlitOculusMirror(ovrSession session, OculusMirror mirror) glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fboId); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0); +#if defined(GRAPHICS_API_OPENGL_33) + // NOTE: glBlitFramebuffer() requires extension: GL_EXT_framebuffer_blit (not available in OpenGL ES 2.0) glBlitFramebuffer(0, 0, mirror.width, mirror.height, 0, mirror.height, mirror.width, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); +#endif glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); } |
