Browse Source

Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop

Joshua Reisenauer 9 years ago
parent
commit
9799856ad4

+ 302 - 296
examples/oculus_glfw_sample/oculus_glfw_sample.c

@@ -17,57 +17,52 @@
 *
 ********************************************************************************************/
 
-#if defined(_WIN32)
-    #define GLFW_EXPOSE_NATIVE_WIN32
-    #define GLFW_EXPOSE_NATIVE_WGL
-    #define OVR_OS_WIN32
-#elif defined(__APPLE__)
-    #define GLFW_EXPOSE_NATIVE_COCOA
-    #define GLFW_EXPOSE_NATIVE_NSGL
-    #define OVR_OS_MAC
-#elif defined(__linux__)
-    #define GLFW_EXPOSE_NATIVE_X11
-    #define GLFW_EXPOSE_NATIVE_GLX
-    #define OVR_OS_LINUX
-#endif
-
-#include "glad.h"      // Extensions loading library
-
-#include <GLFW/glfw3.h>
-#include <GLFW/glfw3native.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
 
-#include "OculusSDK/LibOVR/Include/OVR_CAPI_GL.h"    // Oculus SDK for OpenGL
+#include "glad.h"               // Extensions loading library
+#include <GLFW/glfw3.h>         // Windows/Context and inputs management
 
-//#include "GL/CAPI_GLE.h"        // stripped-down GLEW/GLAD library to manage extensions (really required?)
-//#include "Extras/OVR_Math.h"    // math utilities C++ (really required?)
+#include "OculusSDK/LibOVR/Include/OVR_CAPI_GL.h"    // Oculus SDK for OpenGL
 
 #define RLGL_STANDALONE
 #include "rlgl.h"
 
-#include <stdlib.h>
-#include <stdio.h>
+// OVR device variables
+ovrSession session;
+ovrHmdDesc hmdDesc;
+ovrGraphicsLuid luid;
+
+// OVR OpenGL required variables
+GLuint fbo = 0;
+GLuint depthBuffer = 0;
+ovrTextureSwapChain eyeTexture;
+
+GLuint mirrorFbo = 0;
+ovrMirrorTexture mirrorTexture;
+ovrEyeRenderDesc eyeRenderDescs[2];
+Matrix eyeProjections[2];
+
+ovrLayerEyeFov eyeLayer;
+ovrViewScaleDesc viewScaleDesc;
+
+Vector2 renderTargetSize = { 0, 0 };
+Vector2 mirrorSize;
+unsigned int frame = 0;
+
+// GLFW variables
+GLFWwindow *window = NULL;
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
-typedef struct OculusBuffer {
-    ovrTextureSwapChain textureChain;
-    GLuint depthId;
-    GLuint fboId;
-    int width;
-    int height;
-} OculusBuffer;
-
 typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType;
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
-static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height);
-static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer);
-static void SetOculusBuffer(ovrSession session, OculusBuffer buffer);
-static void UnsetOculusBuffer(OculusBuffer buffer);
-
 static void ErrorCallback(int error, const char* description)
 {
     fputs(description, stderr);
@@ -83,18 +78,15 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i
 
 static void DrawRectangleV(Vector2 position, Vector2 size, Color color);
 static void TraceLog(int msgType, const char *text, ...);
+static Matrix FromOvrMatrix(ovrMatrix4f ovrM);
+void DrawGrid(int slices, float spacing);
+void DrawCube(Vector3 position, float width, float height, float length, Color color);
 
 //----------------------------------------------------------------------------------
 // Main Entry point
 //----------------------------------------------------------------------------------
-int main()
+int main() 
 {
-    // Initialization
-    //--------------------------------------------------------------------------------------
-    ovrSession session;
-    ovrGraphicsLuid luid;   // Useless for OpenGL since SDK 0.7
-    ovrHmdDesc hmdDesc;
-    
     ovrResult result = ovr_Initialize(NULL);
     if (OVR_FAILURE(result)) TraceLog(LOG_ERROR, "OVR: Could not initialize Oculus device");
 
@@ -114,15 +106,37 @@ int main()
     TraceLog(LOG_INFO, "OVR: Serian Number: %s", hmdDesc.SerialNumber);
     TraceLog(LOG_INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h);
     
-    int screenWidth = hmdDesc.Resolution.w/2 + 100;		// Added 100 pixels for testing
-    int screenHeight = hmdDesc.Resolution.h/2 + 100;	// Added 100 pixels for testing
+    
+    viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
+    memset(&eyeLayer, 0, sizeof(ovrLayerEyeFov));
+    eyeLayer.Header.Type = ovrLayerType_EyeFov;
+    eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
+    
+    for (int eye = 0; eye < 2; eye++)
+    {
+        eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]);
+        ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(eyeRenderDescs[eye].Fov, 0.01f, 1000.0f, ovrProjection_ClipRangeOpenGL);
+        // NOTE struct ovrMatrix4f { float M[4][4] }
+        eyeProjections[eye] = FromOvrMatrix(ovrPerspectiveProjection);
+        viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset;
+
+        eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov;
+        ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, eyeLayer.Fov[eye], 1.0f);
+        eyeLayer.Viewport[eye].Size = eyeSize;
+        eyeLayer.Viewport[eye].Pos.x = renderTargetSize.x;
+        eyeLayer.Viewport[eye].Pos.y = 0;
+
+        renderTargetSize.y = eyeSize.h;     //std::max(renderTargetSize.y, (uint32_t)eyeSize.h);
+        renderTargetSize.x += eyeSize.w;
+    }
+    
+    // Make the on screen window 1/2 the resolution of the device
+    mirrorSize.x = hmdDesc.Resolution.w/2;
+    mirrorSize.y = hmdDesc.Resolution.h/2;
 
+    
     // GLFW3 Initialization + OpenGL 3.3 Context + Extensions
     //--------------------------------------------------------
-    GLFWwindow *window;
-    
-    glfwSetErrorCallback(ErrorCallback);
-    
     if (!glfwInit())
     {
         TraceLog(LOG_WARNING, "GLFW3: Can not initialize GLFW");
@@ -133,12 +147,11 @@ int main()
     glfwWindowHint(GLFW_DEPTH_BITS, 16);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
-    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
     glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
-    glfwWindowHint(GLFW_DECORATED, GL_FALSE);   // Mandatory on Oculus Rift to avoid program crash!
+    //glfwWindowHint(GLFW_DECORATED, GL_FALSE);   // Mandatory on Oculus Rift to avoid program crash? --> NO
    
-    window = glfwCreateWindow(screenWidth, screenHeight, "rlgl standalone", NULL, NULL);
+    window = glfwCreateWindow(mirrorSize.x, mirrorSize.y, "raylib oculus sample", NULL, NULL);
     
     if (!window)
     {
@@ -147,6 +160,7 @@ int main()
     }
     else TraceLog(LOG_INFO, "GLFW3: Window created successfully");
     
+    glfwSetErrorCallback(ErrorCallback);
     glfwSetKeyCallback(window, KeyCallback);
     
     glfwMakeContextCurrent(window);
@@ -159,174 +173,132 @@ int main()
     }
     else TraceLog(LOG_INFO, "GLAD: OpenGL extensions loaded successfully");
     
-    rlglInit();
-    rlglInitGraphics(0, 0, screenWidth, screenHeight);
-    rlClearColor(245, 245, 245, 255); // Define clear color
+    // Initialize OVR OpenGL swap chain textures
+    ovrTextureSwapChainDesc desc = {};
+    desc.Type = ovrTexture_2D;
+    desc.ArraySize = 1;
+    desc.Width = renderTargetSize.x;
+    desc.Height = renderTargetSize.y;
+    desc.MipLevels = 1;
+    desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
+    desc.SampleCount = 1;
+    desc.StaticImage = ovrFalse;
     
-    Vector2 position = { screenWidth/2 - 100, screenHeight/2 - 100 };
-    Vector2 size = { 200, 200 };
-    Color color = { 180, 20, 20, 255 };
-    //---------------------------------------------------------------------------
+    result = ovr_CreateTextureSwapChainGL(session, &desc, &eyeTexture);
+    eyeLayer.ColorTexture[0] = eyeTexture;
     
-    OculusBuffer eyeRenderBuffer[2];
-
-    GLuint mirrorFBO = 0;
-    ovrMirrorTexture mirrorTexture = NULL;
-
-    bool isVisible = true;
-    long long frameIndex = 0;
-
-    // Make eyes render buffers
-    ovrSizei recommendedTexSizeLeft = ovr_GetFovTextureSize(session, ovrEye_Left, hmdDesc.DefaultEyeFov[0], 1.0f);
-    eyeRenderBuffer[0] = LoadOculusBuffer(session, recommendedTexSizeLeft.w, recommendedTexSizeLeft.h);
-    ovrSizei recommendedTexSizeRight = ovr_GetFovTextureSize(session, ovrEye_Right, hmdDesc.DefaultEyeFov[1], 1.0f);
-    eyeRenderBuffer[1] = LoadOculusBuffer(session, recommendedTexSizeRight.w, recommendedTexSizeRight.h);
+    if (!OVR_SUCCESS(result)) TraceLog(LOG_WARNING, "Failed to create swap textures");
     
-    // Note: the mirror window can be any size, for this sample we use 1/2 the HMD resolution
-    ovrSizei windowSize = { hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2 };
+    int length = 0;
+    result = ovr_GetTextureSwapChainLength(session, eyeTexture, &length);
+    
+    if (!OVR_SUCCESS(result) || !length) TraceLog(LOG_WARNING, "Unable to count swap chain textures");
 
-    // Define mirror texture descriptor
+    for (int i = 0; i < length; ++i) 
+    {
+        GLuint chainTexId;
+        ovr_GetTextureSwapChainBufferGL(session, eyeTexture, i, &chainTexId);
+        glBindTexture(GL_TEXTURE_2D, chainTexId);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    }
+    
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    // Setup framebuffer object
+    glGenFramebuffers(1, &fbo);
+    glGenRenderbuffers(1, &depthBuffer);
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+    glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, renderTargetSize.x, renderTargetSize.y);
+    glBindRenderbuffer(GL_RENDERBUFFER, 0);
+    glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+
+    // Setup mirror texture
     ovrMirrorTextureDesc mirrorDesc;
     memset(&mirrorDesc, 0, sizeof(mirrorDesc));
-    mirrorDesc.Width = windowSize.w;
-    mirrorDesc.Height = windowSize.h;
     mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
+    mirrorDesc.Width = mirrorSize.x;
+    mirrorDesc.Height = mirrorSize.y;
+    
+    if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirrorTexture))) TraceLog(LOG_WARNING, "Could not create mirror texture");
 
-    // Create mirror texture and an FBO used to copy mirror texture to back buffer
-    result = ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirrorTexture);
-    if (!OVR_SUCCESS(result)) TraceLog(LOG_WARNING, "OVR: Failed to create mirror texture");
-
-    // Configure the mirror read buffer
-    GLuint texId;
-    ovr_GetMirrorTextureBufferGL(session, mirrorTexture, &texId);
+    glGenFramebuffers(1, &mirrorFbo);
 
-    glGenFramebuffers(1, &mirrorFBO);
-    glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
-    glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
-    glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
-    glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
-    
-    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
-    {
-        glDeleteFramebuffers(1, &mirrorFBO);
-        TraceLog(LOG_WARNING, "OVR: Could not initialize mirror framebuffers");
-    }
+    // Recenter OVR tracking origin
+    ovr_RecenterTrackingOrigin(session);
     
-    glClearColor(1.0f, 0.1f, 0.1f, 0.0f);
+    // Initialize rlgl internal buffers and OpenGL state
+    rlglInit();
+    rlglInitGraphics(0, 0, mirrorSize.x, mirrorSize.y);
+    rlClearColor(245, 245, 245, 255); // Define clear color
     glEnable(GL_DEPTH_TEST);
-    ovr_RecenterTrackingOrigin(session);
     
-    // FloorLevel will give tracking poses where the floor height is 0
-    ovr_SetTrackingOriginType(session, ovrTrackingOrigin_FloorLevel);
-    //--------------------------------------------------------------------------------------
+    Vector2 position = { mirrorSize.x/2 - 100, mirrorSize.y/2 - 100 };
+    Vector2 size = { 200, 200 };
+    Color color = { 180, 20, 20, 255 };
+    Vector3 cubePosition = { 0.0f, 0.0f, 0.0f };
 
-    // Main loop
-    while (!glfwWindowShouldClose(window))
+    while (!glfwWindowShouldClose(window)) 
     {
         // Update
         //----------------------------------------------------------------------------------
-        frameIndex++;
-        
-        // TODO: Update game here!
+        frame++;
         
-	    // Call ovr_GetRenderDesc each frame to get the ovrEyeRenderDesc, as the returned values (e.g. HmdToEyeOffset) may change at runtime.
-	    ovrEyeRenderDesc eyeRenderDesc[2];
-	    eyeRenderDesc[0] = ovr_GetRenderDesc(session, ovrEye_Left, hmdDesc.DefaultEyeFov[0]);
-	    eyeRenderDesc[1] = ovr_GetRenderDesc(session, ovrEye_Right, hmdDesc.DefaultEyeFov[1]);
-
-        // Get eye poses, feeding in correct IPD offset
-        ovrPosef eyeRenderPose[2];
-        ovrVector3f hmdToEyeOffset[2] = { eyeRenderDesc[0].HmdToEyeOffset, eyeRenderDesc[1].HmdToEyeOffset };
-
-        double sensorSampleTime;    // sensorSampleTime is fed into the layer later
-        ovr_GetEyePoses(session, frameIndex, ovrTrue, hmdToEyeOffset, eyeRenderPose, &sensorSampleTime);
+        ovrPosef eyePoses[2];
+        ovr_GetEyePoses(session, frame, ovrTrue, viewScaleDesc.HmdToEyeOffset, eyePoses, &eyeLayer.SensorSampleTime);
         //----------------------------------------------------------------------------------
 
         // Draw
         //----------------------------------------------------------------------------------
+        int curIndex;
+        ovr_GetTextureSwapChainCurrentIndex(session, eyeTexture, &curIndex);
+        GLuint curTexId;
+        ovr_GetTextureSwapChainBufferGL(session, eyeTexture, curIndex, &curTexId);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0);
         
-        // Clear screen to red color
-        //glClearColor(1.0f, 0.1f, 0.1f, 0.0f);   
-        //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-        
-        if (isVisible)
-        {
-            for (int eye = 0; eye < 2; ++eye)
-            {
-                SetOculusBuffer(session, eyeRenderBuffer[eye]);
-
-                // TODO: Get view and projection matrices for the eye
-                // Sample using Oculus OVR_Math.h (C++)
-                /*
-                Matrix4f projection[eye] = Matrix4f(ovrMatrix4f_Projection(eyeRenderDesc[eye].Fov, 0.01f, 10000.0f, ovrProjection_None));
-                Matrix4f eyeOrientation[eye] = Matrix4f(Quatf(eyeRenderPose[eye].Orientation).Inverted());
-                Matrix4f eyePose[eye] = Matrix4f::Translation(-Vector3f(eyeRenderPose[eye].Position));
-                Matrix4f mvp = projection[eye]*eyeOrientation[eye]*eyePose[eye];
-				*/
-
-                // Sample using custom raymath.h (C) -INCOMPLETE-
-                /*
-                Matrix projection = MatrixPerspective(eyeRenderDesc[eye].Fov, ((double)screenWidth/(double)screenHeight), 0.01, 1000.0);
-                Matrix eyeOrientation = QuaternionToMatrix((Quaternion){ -eyeRenderPose[eye].Orientation.x, -eyeRenderPose[eye].Orientation.y, 
-                                                                         -eyeRenderPose[eye].Orientation.z, -eyeRenderPose[eye].Orientation.w });
-                Matrix eyePose = MatrixTranslate(-eyeRenderPose[eye].Position.x, -eyeRenderPose[eye].Position.y, -eyeRenderPose[eye].Position.z);
-                Matrix mvp = MatrixMultiply(projection, MatrixMultiply(eyeOrientation, eyePose));
-                */
-                
-                // Render everything
-                // TODO: Pass calculated mvp matrix to default shader to consider projection and orientation! 
-                //DrawRectangleV(position, size, color);
-                //rlglDraw();
-
-                UnsetOculusBuffer(eyeRenderBuffer[eye]);
-                
-                // Commit changes to the textures so they get picked up frame
-                ovr_CommitTextureSwapChain(session, eyeRenderBuffer[eye].textureChain);
-            }
-        }
+        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         
-        // Set up positional data
-        ovrViewScaleDesc viewScaleDesc;
-        viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
-        viewScaleDesc.HmdToEyeOffset[0] = hmdToEyeOffset[0];
-        viewScaleDesc.HmdToEyeOffset[1] = hmdToEyeOffset[1];
-
-        // Create the main eye layer
-        ovrLayerEyeFov eyeLayer;
-        eyeLayer.Header.Type  = ovrLayerType_EyeFov;
-        eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;   // Because OpenGL
-
         for (int eye = 0; eye < 2; eye++)
         {
-            eyeLayer.ColorTexture[eye] = eyeRenderBuffer[eye].textureChain;
-            eyeLayer.Viewport[eye] = (ovrRecti){ eyeRenderBuffer[eye].width, eyeRenderBuffer[eye].height };
-            eyeLayer.Fov[eye] = hmdDesc.DefaultEyeFov[eye];
-            eyeLayer.RenderPose[eye] = eyeRenderPose[eye];
-            eyeLayer.SensorSampleTime = sensorSampleTime;
+            glViewport(eyeLayer.Viewport[eye].Pos.x, eyeLayer.Viewport[eye].Pos.y, 
+                       eyeLayer.Viewport[eye].Size.w, eyeLayer.Viewport[eye].Size.h);
+            eyeLayer.RenderPose[eye] = eyePoses[eye];
+            
+            // Convert struct ovrPosef { ovrQuatf Orientation; ovrVector3f Position; } to Matrix 
+            // TODO: Review maths!
+            Matrix eyeOrientation = QuaternionToMatrix((Quaternion){ -eyePoses[eye].Orientation.x, -eyePoses[eye].Orientation.y, -eyePoses[eye].Orientation.z, -eyePoses[eye].Orientation.w });
+            Matrix eyePosition = MatrixTranslate(-eyePoses[eye].Position.x, -eyePoses[eye].Position.y, -eyePoses[eye].Position.z);
+            Matrix mvp = MatrixMultiply(eyeProjections[eye], MatrixMultiply(eyeOrientation, eyePosition));
+
+            // NOTE: Nothing is drawn until rlglDraw()
+            DrawRectangleV(position, size, color);
+            //DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, color);
+            //DrawGrid(10, 1.0f);
+            
+            // NOTE: rlglDraw() must be modified to support an external modelview-projection matrix
+            // TODO: Still working on it (now uses internal mvp)
+            rlglDraw(mvp);
         }
-
-        // Append all the layers to global list
-        ovrLayerHeader *layerList = &eyeLayer.Header;
-        ovrResult result = ovr_SubmitFrame(session, frameIndex, NULL, &layerList, 1);
         
-        // exit the rendering loop if submit returns an error, will retry on ovrError_DisplayLost
-        if (!OVR_SUCCESS(result)) return 1;
-
-        isVisible = (result == ovrSuccess);
+        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+        ovr_CommitTextureSwapChain(session, eyeTexture);
+        ovrLayerHeader *headerList = &eyeLayer.Header;
+        ovr_SubmitFrame(session, frame, &viewScaleDesc, &headerList, 1);
 
-        // Get session status information
-        ovrSessionStatus sessionStatus;
-        ovr_GetSessionStatus(session, &sessionStatus);
-        if (sessionStatus.ShouldQuit) TraceLog(LOG_WARNING, "OVR: Session should quit.");
-        if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session);
-        
         // Blit mirror texture to back buffer
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-        GLint w = mirrorDesc.Width;
-        GLint h = mirrorDesc.Height;
-        glBlitFramebuffer(0, h, w, 0, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+        GLuint mirrorTextureId;
+        ovr_GetMirrorTextureBufferGL(session, mirrorTexture, &mirrorTextureId);
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFbo);
+        glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0);
+        glBlitFramebuffer(0, 0, mirrorSize.x, mirrorSize.y, 0, mirrorSize.y, mirrorSize.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
         glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+
         
         glfwSwapBuffers(window);
         glfwPollEvents();
@@ -335,10 +307,13 @@ int main()
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    if (mirrorFBO) glDeleteFramebuffers(1, &mirrorFBO);
+    if (mirrorFbo) glDeleteFramebuffers(1, &mirrorFbo);
     if (mirrorTexture) ovr_DestroyMirrorTexture(session, mirrorTexture);
-    for (int eye = 0; eye < 2; eye++) UnloadOculusBuffer(session, eyeRenderBuffer[eye]);
-    
+
+    if (fbo) glDeleteFramebuffers(1, &fbo);
+    if (depthBuffer) glDeleteTextures(1, &depthBuffer);
+    if (eyeTexture) ovr_DestroyTextureSwapChain(session, eyeTexture);
+
     rlglClose();
     
     glfwDestroyWindow(window);
@@ -355,108 +330,6 @@ int main()
 // Module specific Functions Definitions
 //----------------------------------------------------------------------------------
 
-// Load Oculus required buffers: texture-swap-chain, fbo, texture-depth
-static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height)
-{
-    OculusBuffer buffer;
-    buffer.width = width;
-    buffer.height = height;
-    
-    // Create OVR texture chain
-    ovrTextureSwapChainDesc desc = {};
-    desc.Type = ovrTexture_2D;
-    desc.ArraySize = 1;
-    desc.Width = width;
-    desc.Height = height;
-    desc.MipLevels = 1;
-    desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
-    desc.SampleCount = 1;
-    desc.StaticImage = ovrFalse;
-
-    ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain);
-
-    int textureCount = 0;
-    ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount);
-
-    if (OVR_SUCCESS(result))
-    {
-        for (int i = 0; i < textureCount; ++i)
-        {
-            GLuint chainTexId;
-            ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, i, &chainTexId);
-            glBindTexture(GL_TEXTURE_2D, chainTexId);
-            
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-        }
-    }
-    
-    // Generate framebuffer
-    glGenFramebuffers(1, &buffer.fboId);
-
-    // Create Depth texture
-    glGenTextures(1, &buffer.depthId);
-    glBindTexture(GL_TEXTURE_2D, buffer.depthId);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
-
-    return buffer;
-}
-
-// Unload texture required buffers
-static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer)
-{
-    if (buffer.textureChain)
-    {
-        ovr_DestroyTextureSwapChain(session, buffer.textureChain);
-        buffer.textureChain = NULL;
-    }
-
-    if (buffer.depthId)
-    {
-        glDeleteTextures(1, &buffer.depthId);
-        buffer.depthId = 0;
-    }
-
-    if (buffer.fboId)
-    {
-        glDeleteFramebuffers(1, &buffer.fboId);
-        buffer.fboId = 0;
-    }
-}
-
-// Set current Oculus buffer
-static void SetOculusBuffer(ovrSession session, OculusBuffer buffer)
-{
-    GLuint currentTexId;
-    int currentIndex;
-    
-    ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, &currentIndex);
-    ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, &currentTexId);
-
-    glBindFramebuffer(GL_FRAMEBUFFER, buffer.fboId);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, currentTexId, 0);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, buffer.depthId, 0);
-
-    glViewport(0, 0, buffer.width, buffer.height);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-    glEnable(GL_FRAMEBUFFER_SRGB);
-}
-
-// Unset Oculus buffer
-static void UnsetOculusBuffer(OculusBuffer buffer)
-{
-    glBindFramebuffer(GL_FRAMEBUFFER, buffer.fboId);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
-    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
-}
-
 // Draw rectangle using rlgl OpenGL 1.1 style coding (translated to OpenGL 3.3 internally)
 static void DrawRectangleV(Vector2 position, Vector2 size, Color color)
 {
@@ -495,4 +368,137 @@ static void TraceLog(int msgType, const char *text, ...)
     va_end(args);
 
     //if (msgType == LOG_ERROR) exit(1);
-}
+}
+
+static Matrix FromOvrMatrix(ovrMatrix4f ovrmat)
+{
+    Matrix rmat;
+    
+    rmat.m0 = ovrmat.M[0][0];
+    rmat.m1 = ovrmat.M[1][0];
+    rmat.m2 = ovrmat.M[2][0];
+    rmat.m3 = ovrmat.M[3][0];
+    rmat.m4 = ovrmat.M[0][1];
+    rmat.m5 = ovrmat.M[1][1];
+    rmat.m6 = ovrmat.M[2][1];
+    rmat.m7 = ovrmat.M[3][1];
+    rmat.m8 = ovrmat.M[0][2];
+    rmat.m9 = ovrmat.M[1][2];
+    rmat.m10 = ovrmat.M[2][2];
+    rmat.m11 = ovrmat.M[3][2];
+    rmat.m12 = ovrmat.M[0][3];
+    rmat.m13 = ovrmat.M[1][3];
+    rmat.m14 = ovrmat.M[2][3];
+    rmat.m15 = ovrmat.M[3][3];
+    
+    //MatrixTranspose(&rmat);
+    
+    return rmat;
+}
+
+// Draw cube
+// NOTE: Cube position is the center position
+void DrawCube(Vector3 position, float width, float height, float length, Color color)
+{
+    float x = 0.0f;
+    float y = 0.0f;
+    float z = 0.0f;
+
+    rlPushMatrix();
+
+        // NOTE: Be careful! Function order matters (rotate -> scale -> translate)
+        rlTranslatef(position.x, position.y, position.z);
+        //rlScalef(2.0f, 2.0f, 2.0f);
+        //rlRotatef(45, 0, 1, 0);
+
+        rlBegin(RL_TRIANGLES);
+            rlColor4ub(color.r, color.g, color.b, color.a);
+
+            // Front Face -----------------------------------------------------
+            rlVertex3f(x-width/2, y-height/2, z+length/2);  // Bottom Left
+            rlVertex3f(x+width/2, y-height/2, z+length/2);  // Bottom Right
+            rlVertex3f(x-width/2, y+height/2, z+length/2);  // Top Left
+
+            rlVertex3f(x+width/2, y+height/2, z+length/2);  // Top Right
+            rlVertex3f(x-width/2, y+height/2, z+length/2);  // Top Left
+            rlVertex3f(x+width/2, y-height/2, z+length/2);  // Bottom Right
+
+            // Back Face ------------------------------------------------------
+            rlVertex3f(x-width/2, y-height/2, z-length/2);  // Bottom Left
+            rlVertex3f(x-width/2, y+height/2, z-length/2);  // Top Left
+            rlVertex3f(x+width/2, y-height/2, z-length/2);  // Bottom Right
+
+            rlVertex3f(x+width/2, y+height/2, z-length/2);  // Top Right
+            rlVertex3f(x+width/2, y-height/2, z-length/2);  // Bottom Right
+            rlVertex3f(x-width/2, y+height/2, z-length/2);  // Top Left
+
+            // Top Face -------------------------------------------------------
+            rlVertex3f(x-width/2, y+height/2, z-length/2);  // Top Left
+            rlVertex3f(x-width/2, y+height/2, z+length/2);  // Bottom Left
+            rlVertex3f(x+width/2, y+height/2, z+length/2);  // Bottom Right
+
+            rlVertex3f(x+width/2, y+height/2, z-length/2);  // Top Right
+            rlVertex3f(x-width/2, y+height/2, z-length/2);  // Top Left
+            rlVertex3f(x+width/2, y+height/2, z+length/2);  // Bottom Right
+
+            // Bottom Face ----------------------------------------------------
+            rlVertex3f(x-width/2, y-height/2, z-length/2);  // Top Left
+            rlVertex3f(x+width/2, y-height/2, z+length/2);  // Bottom Right
+            rlVertex3f(x-width/2, y-height/2, z+length/2);  // Bottom Left
+
+            rlVertex3f(x+width/2, y-height/2, z-length/2);  // Top Right
+            rlVertex3f(x+width/2, y-height/2, z+length/2);  // Bottom Right
+            rlVertex3f(x-width/2, y-height/2, z-length/2);  // Top Left
+
+            // Right face -----------------------------------------------------
+            rlVertex3f(x+width/2, y-height/2, z-length/2);  // Bottom Right
+            rlVertex3f(x+width/2, y+height/2, z-length/2);  // Top Right
+            rlVertex3f(x+width/2, y+height/2, z+length/2);  // Top Left
+
+            rlVertex3f(x+width/2, y-height/2, z+length/2);  // Bottom Left
+            rlVertex3f(x+width/2, y-height/2, z-length/2);  // Bottom Right
+            rlVertex3f(x+width/2, y+height/2, z+length/2);  // Top Left
+
+            // Left Face ------------------------------------------------------
+            rlVertex3f(x-width/2, y-height/2, z-length/2);  // Bottom Right
+            rlVertex3f(x-width/2, y+height/2, z+length/2);  // Top Left
+            rlVertex3f(x-width/2, y+height/2, z-length/2);  // Top Right
+
+            rlVertex3f(x-width/2, y-height/2, z+length/2);  // Bottom Left
+            rlVertex3f(x-width/2, y+height/2, z+length/2);  // Top Left
+            rlVertex3f(x-width/2, y-height/2, z-length/2);  // Bottom Right
+        rlEnd();
+    rlPopMatrix();
+}
+
+// Draw a grid centered at (0, 0, 0)
+void DrawGrid(int slices, float spacing)
+{
+    int halfSlices = slices / 2;
+
+    rlBegin(RL_LINES);
+        for(int i = -halfSlices; i <= halfSlices; i++)
+        {
+            if (i == 0)
+            {
+                rlColor3f(0.5f, 0.5f, 0.5f);
+                rlColor3f(0.5f, 0.5f, 0.5f);
+                rlColor3f(0.5f, 0.5f, 0.5f);
+                rlColor3f(0.5f, 0.5f, 0.5f);
+            }
+            else
+            {
+                rlColor3f(0.75f, 0.75f, 0.75f);
+                rlColor3f(0.75f, 0.75f, 0.75f);
+                rlColor3f(0.75f, 0.75f, 0.75f);
+                rlColor3f(0.75f, 0.75f, 0.75f);
+            }
+
+            rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing);
+            rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing);
+
+            rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing);
+            rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing);
+        }
+    rlEnd();
+}

+ 498 - 0
examples/oculus_glfw_sample/oculus_glfw_sample.old.c

@@ -0,0 +1,498 @@
+/*******************************************************************************************
+*
+*   raylib Oculus minimum sample (OpenGL 3.3 Core)
+*
+*   NOTE: This example requires raylib module [rlgl]
+*
+*   Compile rlgl using:
+*   gcc -c rlgl.c -Wall -std=c99 -DRLGL_STANDALONE -DRAYMATH_IMPLEMENTATION -DGRAPHICS_API_OPENGL_33
+*
+*   Compile example using:
+*   gcc -o oculus_glfw_sample.exe oculus_glfw_sample.c rlgl.o glad.o -L. -lLibOVRRT32_1 -lglfw3 -lopengl32 -lgdi32 -std=c99
+*
+*   This example has been created using raylib 1.5 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2015 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#if defined(_WIN32)
+    #define GLFW_EXPOSE_NATIVE_WIN32
+    #define GLFW_EXPOSE_NATIVE_WGL
+    #define OVR_OS_WIN32
+#elif defined(__APPLE__)
+    #define GLFW_EXPOSE_NATIVE_COCOA
+    #define GLFW_EXPOSE_NATIVE_NSGL
+    #define OVR_OS_MAC
+#elif defined(__linux__)
+    #define GLFW_EXPOSE_NATIVE_X11
+    #define GLFW_EXPOSE_NATIVE_GLX
+    #define OVR_OS_LINUX
+#endif
+
+#include "glad.h"      // Extensions loading library
+
+#include <GLFW/glfw3.h>
+#include <GLFW/glfw3native.h>
+
+#include "OculusSDK/LibOVR/Include/OVR_CAPI_GL.h"    // Oculus SDK for OpenGL
+
+//#include "GL/CAPI_GLE.h"        // stripped-down GLEW/GLAD library to manage extensions (really required?)
+//#include "Extras/OVR_Math.h"    // math utilities C++ (really required?)
+
+#define RLGL_STANDALONE
+#include "rlgl.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct OculusBuffer {
+    ovrTextureSwapChain textureChain;
+    GLuint depthId;
+    GLuint fboId;
+    int width;
+    int height;
+} OculusBuffer;
+
+typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType;
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Declaration
+//----------------------------------------------------------------------------------
+static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height);
+static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer);
+static void SetOculusBuffer(ovrSession session, OculusBuffer buffer);
+static void UnsetOculusBuffer(OculusBuffer buffer);
+
+static void ErrorCallback(int error, const char* description)
+{
+    fputs(description, stderr);
+}
+
+static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
+    {
+        glfwSetWindowShouldClose(window, GL_TRUE);
+    }
+}
+
+static void DrawRectangleV(Vector2 position, Vector2 size, Color color);
+static void TraceLog(int msgType, const char *text, ...);
+
+//----------------------------------------------------------------------------------
+// Main Entry point
+//----------------------------------------------------------------------------------
+int main()
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    ovrSession session;
+    ovrGraphicsLuid luid;   // Useless for OpenGL since SDK 0.7
+    ovrHmdDesc hmdDesc;
+    
+    ovrResult result = ovr_Initialize(NULL);
+    if (OVR_FAILURE(result)) TraceLog(LOG_ERROR, "OVR: Could not initialize Oculus device");
+
+    result = ovr_Create(&session, &luid);
+    if (OVR_FAILURE(result))
+    {
+        TraceLog(LOG_WARNING, "OVR: Could not create Oculus session");
+        ovr_Shutdown();
+    }
+
+    hmdDesc = ovr_GetHmdDesc(session);
+    
+    TraceLog(LOG_INFO, "OVR: Product Name: %s", hmdDesc.ProductName);
+    TraceLog(LOG_INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer);
+    TraceLog(LOG_INFO, "OVR: Product ID: %i", hmdDesc.ProductId);
+    TraceLog(LOG_INFO, "OVR: Product Type: %i", hmdDesc.Type);
+    TraceLog(LOG_INFO, "OVR: Serian Number: %s", hmdDesc.SerialNumber);
+    TraceLog(LOG_INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h);
+    
+    int screenWidth = hmdDesc.Resolution.w/2 + 100;		// Added 100 pixels for testing
+    int screenHeight = hmdDesc.Resolution.h/2 + 100;	// Added 100 pixels for testing
+
+    // GLFW3 Initialization + OpenGL 3.3 Context + Extensions
+    //--------------------------------------------------------
+    GLFWwindow *window;
+    
+    glfwSetErrorCallback(ErrorCallback);
+    
+    if (!glfwInit())
+    {
+        TraceLog(LOG_WARNING, "GLFW3: Can not initialize GLFW");
+        exit(EXIT_FAILURE);
+    }
+    else TraceLog(LOG_INFO, "GLFW3: GLFW initialized successfully");
+    
+    glfwWindowHint(GLFW_DEPTH_BITS, 16);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
+    glfwWindowHint(GLFW_DECORATED, GL_FALSE);   // Mandatory on Oculus Rift to avoid program crash!
+   
+    window = glfwCreateWindow(screenWidth, screenHeight, "rlgl standalone", NULL, NULL);
+    
+    if (!window)
+    {
+        glfwTerminate();
+        exit(EXIT_FAILURE);
+    }
+    else TraceLog(LOG_INFO, "GLFW3: Window created successfully");
+    
+    glfwSetKeyCallback(window, KeyCallback);
+    
+    glfwMakeContextCurrent(window);
+    glfwSwapInterval(0);
+
+    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
+    {
+        TraceLog(LOG_WARNING, "GLAD: Cannot load OpenGL extensions");
+        exit(1);
+    }
+    else TraceLog(LOG_INFO, "GLAD: OpenGL extensions loaded successfully");
+    
+    rlglInit();
+    rlglInitGraphics(0, 0, screenWidth, screenHeight);
+    rlClearColor(245, 245, 245, 255); // Define clear color
+    
+    Vector2 position = { screenWidth/2 - 100, screenHeight/2 - 100 };
+    Vector2 size = { 200, 200 };
+    Color color = { 180, 20, 20, 255 };
+    //---------------------------------------------------------------------------
+    
+    OculusBuffer eyeRenderBuffer[2];
+
+    GLuint mirrorFBO = 0;
+    ovrMirrorTexture mirrorTexture = NULL;
+
+    bool isVisible = true;
+    long long frameIndex = 0;
+
+    // Make eyes render buffers
+    ovrSizei recommendedTexSizeLeft = ovr_GetFovTextureSize(session, ovrEye_Left, hmdDesc.DefaultEyeFov[0], 1.0f);
+    eyeRenderBuffer[0] = LoadOculusBuffer(session, recommendedTexSizeLeft.w, recommendedTexSizeLeft.h);
+    ovrSizei recommendedTexSizeRight = ovr_GetFovTextureSize(session, ovrEye_Right, hmdDesc.DefaultEyeFov[1], 1.0f);
+    eyeRenderBuffer[1] = LoadOculusBuffer(session, recommendedTexSizeRight.w, recommendedTexSizeRight.h);
+    
+    // Note: the mirror window can be any size, for this sample we use 1/2 the HMD resolution
+    ovrSizei windowSize = { hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2 };
+
+    // Define mirror texture descriptor
+    ovrMirrorTextureDesc mirrorDesc;
+    memset(&mirrorDesc, 0, sizeof(mirrorDesc));
+    mirrorDesc.Width = windowSize.w;
+    mirrorDesc.Height = windowSize.h;
+    mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
+
+    // Create mirror texture and an FBO used to copy mirror texture to back buffer
+    result = ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirrorTexture);
+    if (!OVR_SUCCESS(result)) TraceLog(LOG_WARNING, "OVR: Failed to create mirror texture");
+
+    // Configure the mirror read buffer
+    GLuint texId;
+    ovr_GetMirrorTextureBufferGL(session, mirrorTexture, &texId);
+
+    glGenFramebuffers(1, &mirrorFBO);
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
+    glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
+    glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+    
+    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+    {
+        glDeleteFramebuffers(1, &mirrorFBO);
+        TraceLog(LOG_WARNING, "OVR: Could not initialize mirror framebuffers");
+    }
+    
+    glClearColor(1.0f, 0.1f, 0.1f, 0.0f);
+    glEnable(GL_DEPTH_TEST);
+    ovr_RecenterTrackingOrigin(session);
+    
+    // FloorLevel will give tracking poses where the floor height is 0
+    ovr_SetTrackingOriginType(session, ovrTrackingOrigin_FloorLevel);
+    //--------------------------------------------------------------------------------------
+
+    // Main loop
+    while (!glfwWindowShouldClose(window))
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        frameIndex++;
+        
+        // TODO: Update game here!
+        
+	    // Call ovr_GetRenderDesc each frame to get the ovrEyeRenderDesc, as the returned values (e.g. HmdToEyeOffset) may change at runtime.
+	    ovrEyeRenderDesc eyeRenderDesc[2];
+	    eyeRenderDesc[0] = ovr_GetRenderDesc(session, ovrEye_Left, hmdDesc.DefaultEyeFov[0]);
+	    eyeRenderDesc[1] = ovr_GetRenderDesc(session, ovrEye_Right, hmdDesc.DefaultEyeFov[1]);
+
+        // Get eye poses, feeding in correct IPD offset
+        ovrPosef eyeRenderPose[2];
+        ovrVector3f hmdToEyeOffset[2] = { eyeRenderDesc[0].HmdToEyeOffset, eyeRenderDesc[1].HmdToEyeOffset };
+
+        double sensorSampleTime;    // sensorSampleTime is fed into the layer later
+        ovr_GetEyePoses(session, frameIndex, ovrTrue, hmdToEyeOffset, eyeRenderPose, &sensorSampleTime);
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        
+        // Clear screen to red color
+        glClearColor(1.0f, 0.1f, 0.1f, 0.0f);   
+        //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+        
+        if (isVisible)
+        {
+            for (int eye = 0; eye < 2; ++eye)
+            {
+                SetOculusBuffer(session, eyeRenderBuffer[eye]);
+
+                // TODO: Get view and projection matrices for the eye
+                // Sample using Oculus OVR_Math.h (C++)
+                /*
+                Matrix4f projection[eye] = Matrix4f(ovrMatrix4f_Projection(eyeRenderDesc[eye].Fov, 0.01f, 10000.0f, ovrProjection_None));
+                Matrix4f eyeOrientation[eye] = Matrix4f(Quatf(eyeRenderPose[eye].Orientation).Inverted());
+                Matrix4f eyePose[eye] = Matrix4f::Translation(-Vector3f(eyeRenderPose[eye].Position));
+                Matrix4f mvp = projection[eye]*eyeOrientation[eye]*eyePose[eye];
+				*/
+
+                // Sample using custom raymath.h (C) -INCOMPLETE-
+                /*
+                Matrix projection = MatrixPerspective(eyeRenderDesc[eye].Fov, ((double)screenWidth/(double)screenHeight), 0.01, 1000.0);
+                Matrix eyeOrientation = QuaternionToMatrix((Quaternion){ -eyeRenderPose[eye].Orientation.x, -eyeRenderPose[eye].Orientation.y, 
+                                                                         -eyeRenderPose[eye].Orientation.z, -eyeRenderPose[eye].Orientation.w });
+                Matrix eyePose = MatrixTranslate(-eyeRenderPose[eye].Position.x, -eyeRenderPose[eye].Position.y, -eyeRenderPose[eye].Position.z);
+                Matrix mvp = MatrixMultiply(projection, MatrixMultiply(eyeOrientation, eyePose));
+                */
+                
+                // Render everything
+                // TODO: Pass calculated mvp matrix to default shader to consider projection and orientation! 
+                //DrawRectangleV(position, size, color);
+                //rlglDraw();
+
+                UnsetOculusBuffer(eyeRenderBuffer[eye]);
+                
+                // Commit changes to the textures so they get picked up frame
+                ovr_CommitTextureSwapChain(session, eyeRenderBuffer[eye].textureChain);
+            }
+        }
+        
+        // Set up positional data
+        ovrViewScaleDesc viewScaleDesc;
+        viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
+        viewScaleDesc.HmdToEyeOffset[0] = hmdToEyeOffset[0];
+        viewScaleDesc.HmdToEyeOffset[1] = hmdToEyeOffset[1];
+
+        // Create the main eye layer
+        ovrLayerEyeFov eyeLayer;
+        eyeLayer.Header.Type  = ovrLayerType_EyeFov;
+        eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;   // Because OpenGL
+
+        for (int eye = 0; eye < 2; eye++)
+        {
+            eyeLayer.ColorTexture[eye] = eyeRenderBuffer[eye].textureChain;
+            eyeLayer.Viewport[eye] = (ovrRecti){ eyeRenderBuffer[eye].width, eyeRenderBuffer[eye].height };
+            eyeLayer.Fov[eye] = hmdDesc.DefaultEyeFov[eye];
+            eyeLayer.RenderPose[eye] = eyeRenderPose[eye];
+            eyeLayer.SensorSampleTime = sensorSampleTime;
+        }
+
+        // Append all the layers to global list
+        ovrLayerHeader *layerList = &eyeLayer.Header;
+        ovrResult result = ovr_SubmitFrame(session, frameIndex, NULL, &layerList, 1);
+        
+        // exit the rendering loop if submit returns an error, will retry on ovrError_DisplayLost
+        if (!OVR_SUCCESS(result)) return 1;
+
+        isVisible = (result == ovrSuccess);
+
+        // Get session status information
+        ovrSessionStatus sessionStatus;
+        ovr_GetSessionStatus(session, &sessionStatus);
+        if (sessionStatus.ShouldQuit) TraceLog(LOG_WARNING, "OVR: Session should quit.");
+        if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session);
+        
+        // Blit mirror texture to back buffer
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
+        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+        GLint w = mirrorDesc.Width;
+        GLint h = mirrorDesc.Height;
+        glBlitFramebuffer(0, h, w, 0, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+        
+        glfwSwapBuffers(window);
+        glfwPollEvents();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    if (mirrorFBO) glDeleteFramebuffers(1, &mirrorFBO);
+    if (mirrorTexture) ovr_DestroyMirrorTexture(session, mirrorTexture);
+    for (int eye = 0; eye < 2; eye++) UnloadOculusBuffer(session, eyeRenderBuffer[eye]);
+    
+    rlglClose();
+    
+    glfwDestroyWindow(window);
+    glfwTerminate();
+    
+    ovr_Destroy(session);   // Must be called after glfwTerminate()
+    ovr_Shutdown();
+    //--------------------------------------------------------------------------------------
+    
+    return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Definitions
+//----------------------------------------------------------------------------------
+
+// Load Oculus required buffers: texture-swap-chain, fbo, texture-depth
+static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height)
+{
+    OculusBuffer buffer;
+    buffer.width = width;
+    buffer.height = height;
+    
+    // Create OVR texture chain
+    ovrTextureSwapChainDesc desc = {};
+    desc.Type = ovrTexture_2D;
+    desc.ArraySize = 1;
+    desc.Width = width;
+    desc.Height = height;
+    desc.MipLevels = 1;
+    desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
+    desc.SampleCount = 1;
+    desc.StaticImage = ovrFalse;
+
+    ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain);
+
+    int textureCount = 0;
+    ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount);
+
+    if (OVR_SUCCESS(result))
+    {
+        for (int i = 0; i < textureCount; ++i)
+        {
+            GLuint chainTexId;
+            ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, i, &chainTexId);
+            glBindTexture(GL_TEXTURE_2D, chainTexId);
+            
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        }
+    }
+    
+    // Generate framebuffer
+    glGenFramebuffers(1, &buffer.fboId);
+
+    // Create Depth texture
+    glGenTextures(1, &buffer.depthId);
+    glBindTexture(GL_TEXTURE_2D, buffer.depthId);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+
+    return buffer;
+}
+
+// Unload texture required buffers
+static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer)
+{
+    if (buffer.textureChain)
+    {
+        ovr_DestroyTextureSwapChain(session, buffer.textureChain);
+        buffer.textureChain = NULL;
+    }
+
+    if (buffer.depthId)
+    {
+        glDeleteTextures(1, &buffer.depthId);
+        buffer.depthId = 0;
+    }
+
+    if (buffer.fboId)
+    {
+        glDeleteFramebuffers(1, &buffer.fboId);
+        buffer.fboId = 0;
+    }
+}
+
+// Set current Oculus buffer
+static void SetOculusBuffer(ovrSession session, OculusBuffer buffer)
+{
+    GLuint currentTexId;
+    int currentIndex;
+    
+    ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, &currentIndex);
+    ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, &currentTexId);
+
+    glBindFramebuffer(GL_FRAMEBUFFER, buffer.fboId);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, currentTexId, 0);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, buffer.depthId, 0);
+
+    glViewport(0, 0, buffer.width, buffer.height);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    glEnable(GL_FRAMEBUFFER_SRGB);
+}
+
+// Unset Oculus buffer
+static void UnsetOculusBuffer(OculusBuffer buffer)
+{
+    glBindFramebuffer(GL_FRAMEBUFFER, buffer.fboId);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
+}
+
+// Draw rectangle using rlgl OpenGL 1.1 style coding (translated to OpenGL 3.3 internally)
+static void DrawRectangleV(Vector2 position, Vector2 size, Color color)
+{
+    rlBegin(RL_TRIANGLES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        rlVertex2i(position.x, position.y);
+        rlVertex2i(position.x, position.y + size.y);
+        rlVertex2i(position.x + size.x, position.y + size.y);
+
+        rlVertex2i(position.x, position.y);
+        rlVertex2i(position.x + size.x, position.y + size.y);
+        rlVertex2i(position.x + size.x, position.y);
+    rlEnd();
+}
+
+// Output a trace log message
+// NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning
+static void TraceLog(int msgType, const char *text, ...)
+{
+    va_list args;
+    va_start(args, text);
+
+    switch(msgType)
+    {
+        case LOG_INFO: fprintf(stdout, "INFO: "); break;
+        case LOG_ERROR: fprintf(stdout, "ERROR: "); break;
+        case LOG_WARNING: fprintf(stdout, "WARNING: "); break;
+        case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break;
+        default: break;
+    }
+
+    vfprintf(stdout, text, args);
+    fprintf(stdout, "\n");
+
+    va_end(args);
+
+    //if (msgType == LOG_ERROR) exit(1);
+}

+ 0 - 280
examples/oculus_glfw_sample/oculus_glfw_sample_new.c

@@ -1,280 +0,0 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "glad.h"      // Extensions loading library
-#include <GLFW/glfw3.h>
-
-#include "OculusSDK/LibOVR/Include/OVR_CAPI_GL.h"    // Oculus SDK for OpenGL
-
-#define FAIL(X) printf(X);
-
-typedef struct Vector2 {
-    float x;
-    float y;
-} Vector2;
-
-typedef struct Matrix {
-    float m0, m4, m8, m12;
-    float m1, m5, m9, m13;
-    float m2, m6, m10, m14;
-    float m3, m7, m11, m15;
-} Matrix;
-
-// RiftManagerApp class
-ovrSession session;
-ovrHmdDesc hmdDesc;
-ovrGraphicsLuid luid;
-
-// RiftApp class
-GLuint fbo = 0;
-GLuint depthBuffer = 0;
-ovrTextureSwapChain eyeTexture;
-
-GLuint mirrorFbo = 0;
-ovrMirrorTexture mirrorTexture;
-ovrEyeRenderDesc eyeRenderDescs[2];
-Matrix eyeProjections[2];
-
-ovrLayerEyeFov eyeLayer;
-ovrViewScaleDesc viewScaleDesc;
-
-Vector2 renderTargetSize;
-Vector2 mirrorSize;
-
-// GlfwApp class
-GLFWwindow *window = NULL;
-unsigned int frame = 0;
-
-static void ErrorCallback(int error, const char* description)
-{
-    fputs(description, stderr);
-}
-
-static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
-{
-    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
-    {
-        glfwSetWindowShouldClose(window, GL_TRUE);
-    }
-}
-
-// Execute our example class
-int main() 
-{
-    if (!OVR_SUCCESS(ovr_Initialize(NULL))) FAIL("Failed to initialize the Oculus SDK\n");
-    
-    //result = ExampleApp().run();      // class ExampleApp : public RiftApp : public GlfwApp, public RiftManagerApp
-    
-    if (!OVR_SUCCESS(ovr_Create(&session, &luid))) FAIL("Unable to create HMD session\n");
-    hmdDesc = ovr_GetHmdDesc(session);
-    
-    // RiftApp() constructor
-    viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
-    memset(&eyeLayer, 0, sizeof(ovrLayerEyeFov));
-    eyeLayer.Header.Type = ovrLayerType_EyeFov;
-    eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
-
-    //ovr::for_each_eye([&](ovrEyeType eye) 
-    for (int eye = 0; eye < 2; eye++)
-    {
-        eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]);
-        ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(eyeRenderDescs[eye].Fov, 0.01f, 1000.0f, ovrProjection_ClipRangeOpenGL);
-        //eyeProjections[eye] = ovr::toGlm(ovrPerspectiveProjection);
-        viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset;
-
-        eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov;
-        ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, eyeLayer.Fov[eye], 1.0f);
-        eyeLayer.Viewport[eye].Size = eyeSize;
-        eyeLayer.Viewport[eye].Pos.x = renderTargetSize.x;
-        eyeLayer.Viewport[eye].Pos.y = 0;
-
-        renderTargetSize.y = renderTargetSize.y; // std::max(renderTargetSize.y, (uint32_t)eyeSize.h);
-        renderTargetSize.x += eyeSize.w;
-    }
-    
-    // Make the on screen window 1/4 the resolution of the render target
-    mirrorSize = renderTargetSize;
-    mirrorSize.x /= 2;
-    mirrorSize.y /= 2;
-
-    // GLFWApp() constructor
-    if (!glfwInit()) FAIL("Failed to initialize GLFW\n"); // Initialize the GLFW system for creating and positioning windows
-    glfwSetErrorCallback(ErrorCallback);
-    
-    ////preCreate();
-    glfwWindowHint(GLFW_DEPTH_BITS, 16);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
-    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
-
-    //***************window = createRenderingTarget(windowSize, windowPosition);    //GLFWwindow *createRenderingTarget(uvec2 & size, ivec2 & pos) = 0; //glfw::createWindow(_mirrorSize);
-    /*
-    GLFWwindow *createWindow(const uvec2 &size, const ivec2 &position = ivec2(INT_MIN))
-    {
-        GLFWwindow *window = glfwCreateWindow(size.x, size.y, "glfw", NULL, NULL);  // size = mirrorSize
-        
-        if (!window) FAIL("Unable to create rendering window\n");
-
-        if ((position.x > INT_MIN) && (position.y > INT_MIN)) // INT_MIN = -32767   // #define INT_MIN (-2147483647 - 1)
-        {
-            glfwSetWindowPos(window, position.x, position.y);
-        }
-        
-        return window;
-    }
-    */
-    
-    window = glfwCreateWindow(mirrorSize.x, mirrorSize.y, "glfw", NULL, NULL);
-
-    if (!window) FAIL("Unable to create OpenGL window\n");
-
-    ////postCreate();
-    //glfwSetWindowUserPointer(window, this);  //// Useful to hack input callbacks
-    glfwSetKeyCallback(window, KeyCallback);
-    glfwMakeContextCurrent(window);
-
-    // Initialize the OpenGL extensions
-    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) FAIL("GLAD failed\n");
-    /*
-    glewExperimental = GL_TRUE;
-    if (0 != glewInit()) FAIL("Failed to initialize GLEW\n");
-    glGetError();
-
-    if (GLEW_KHR_debug) 
-    {
-        GLint v;
-        glGetIntegerv(GL_CONTEXT_FLAGS, &v);
-        if (v & GL_CONTEXT_FLAG_DEBUG_BIT) glDebugMessageCallback(glDebugCallbackHandler, this);
-    }
-    */
-
-    ////initGl();
-    {
-        // RiftApp::InitGL() ----->
-            //GlfwApp::initGl();    // virtual
-
-        // Disable the v-sync for buffer swap
-        glfwSwapInterval(0);
-
-        ovrTextureSwapChainDesc desc = {};
-        desc.Type = ovrTexture_2D;
-        desc.ArraySize = 1;
-        desc.Width = renderTargetSize.x;
-        desc.Height = renderTargetSize.y;
-        desc.MipLevels = 1;
-        desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
-        desc.SampleCount = 1;
-        desc.StaticImage = ovrFalse;
-        
-        ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &eyeTexture);
-        eyeLayer.ColorTexture[0] = eyeTexture;
-        
-        if (!OVR_SUCCESS(result)) FAIL("Failed to create swap textures");
-        
-        int length = 0;
-        result = ovr_GetTextureSwapChainLength(session, eyeTexture, &length);
-        
-        if (!OVR_SUCCESS(result) || !length) FAIL("Unable to count swap chain textures");
-
-        for (int i = 0; i < length; ++i) 
-        {
-            GLuint chainTexId;
-            ovr_GetTextureSwapChainBufferGL(session, eyeTexture, i, &chainTexId);
-            glBindTexture(GL_TEXTURE_2D, chainTexId);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-        }
-        
-        glBindTexture(GL_TEXTURE_2D, 0);
-
-        // Set up the framebuffer object
-        glGenFramebuffers(1, &fbo);
-        glGenRenderbuffers(1, &depthBuffer);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
-        glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
-        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, renderTargetSize.x, renderTargetSize.y);
-        glBindRenderbuffer(GL_RENDERBUFFER, 0);
-        glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-
-        ovrMirrorTextureDesc mirrorDesc;
-        memset(&mirrorDesc, 0, sizeof(mirrorDesc));
-        mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
-        mirrorDesc.Width = mirrorSize.x;
-        mirrorDesc.Height = mirrorSize.y;
-        
-        if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirrorTexture))) FAIL("Could not create mirror texture");
-
-        glGenFramebuffers(1, &mirrorFbo);
-
-        // RiftApp::InitGL() <------
-        
-        glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
-        glEnable(GL_DEPTH_TEST);
-        ovr_RecenterTrackingOrigin(session);
-        
-        // TODO: Init cube scene --> cubeScene = std::shared_ptr<ColorCubeScene>(new ColorCubeScene());
-    }
-
-    while (!glfwWindowShouldClose(window)) 
-    {
-        frame++;
-        glfwPollEvents();
-        
-        //update();
-        
-        //draw(); ------>
-        ovrPosef eyePoses[2];
-        ovr_GetEyePoses(session, frame, ovrTrue, viewScaleDesc.HmdToEyeOffset, eyePoses, &eyeLayer.SensorSampleTime);
-
-        int curIndex;
-        ovr_GetTextureSwapChainCurrentIndex(session, eyeTexture, &curIndex);
-        GLuint curTexId;
-        ovr_GetTextureSwapChainBufferGL(session, eyeTexture, curIndex, &curTexId);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
-        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, curTexId, 0);
-        
-        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-        
-        for (int eye = 0; eye < 2; eye++)
-        {
-            glViewport(eyeLayer.Viewport[eye].Pos.x, eyeLayer.Viewport[eye].Pos.y, 
-                       eyeLayer.Viewport[eye].Size.w, eyeLayer.Viewport[eye].Size.h);
-            eyeLayer.RenderPose[eye] = eyePoses[eye];
-            
-            //renderScene(_eyeProjections[eye], ovr::toGlm(eyePoses[eye])); -->  cubeScene->render(projection, glm::inverse(headPose));
-        }
-        
-        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
-        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-        ovr_CommitTextureSwapChain(session, eyeTexture);
-        ovrLayerHeader *headerList = &eyeLayer.Header;
-        
-        ovr_SubmitFrame(session, frame, &viewScaleDesc, &headerList, 1);
-
-        GLuint mirrorTextureId;
-        ovr_GetMirrorTextureBufferGL(session, mirrorTexture, &mirrorTextureId);
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFbo);
-        glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0);
-        glBlitFramebuffer(0, 0, mirrorSize.x, mirrorSize.y, 0, mirrorSize.y, mirrorSize.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
-        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
-        //draw() <-------------
-        
-        glfwSwapBuffers(window); //finishFrame();
-    }
-
-    //shutdownGl();        // Delete scene:  cubeScene.reset();
-    
-    glfwDestroyWindow(window);
-    glfwTerminate();
-
-    ovr_Destroy(session);
-    ovr_Shutdown();
-    
-    return 0;
-}

BIN
examples/oculus_glfw_sample/raylib_OculusRiftCV1.png


+ 167 - 172
examples/oculus_glfw_sample/rlgl.c

@@ -196,23 +196,20 @@ static DrawMode currentDrawMode;
 
 static float currentDepth = -1.0f;
 
-// Vertex arrays for lines, triangles and quads
+// Default vertex buffers for lines, triangles and quads
 static VertexPositionColorBuffer lines;         // No texture support
 static VertexPositionColorBuffer triangles;     // No texture support
 static VertexPositionColorTextureIndexBuffer quads;
 
-// Shader Programs
-static Shader defaultShader;
-static Shader currentShader;                    // By default, defaultShader
-
-// Vertex Array Objects (VAO)
+// Default vertex buffers VAOs (if supported)
 static GLuint vaoLines, vaoTriangles, vaoQuads;
 
-// Vertex Buffer Objects (VBO)
-static GLuint linesBuffer[2];
-static GLuint trianglesBuffer[2];
-static GLuint quadsBuffer[4];
+// Default vertex buffers VBOs
+static GLuint linesBuffer[2];           // Lines buffers (position, color)
+static GLuint trianglesBuffer[2];       // Triangles buffers (position, color)
+static GLuint quadsBuffer[4];           // Quads buffers (position, texcoord, color, index)
 
+// Default buffers draw calls
 static DrawCall *draws;
 static int drawsCounter;
 
@@ -221,11 +218,14 @@ static Vector3 *tempBuffer;
 static int tempBufferCount = 0;
 static bool useTempBuffer = false;
 
+// Shader Programs
+static Shader defaultShader;
+static Shader currentShader;            // By default, defaultShader
+
 // Flags for supported extensions
 static bool vaoSupported = false;   // VAO support (OpenGL ES2 could not support VAO extension)
 
 // Compressed textures support flags
-//static bool texCompDXTSupported = false;     // DDS texture compression support
 static bool texCompETC1Supported = false;    // ETC1 texture compression support
 static bool texCompETC2Supported = false;    // ETC2/EAC texture compression support
 static bool texCompPVRTSupported = false;    // PVR texture compression support
@@ -233,8 +233,8 @@ static bool texCompASTCSupported = false;    // ASTC texture compression support
 #endif
 
 // Compressed textures support flags
-static bool texCompDXTSupported = false;   // DDS texture compression support
-static bool npotSupported = false;         // NPOT textures full support
+static bool texCompDXTSupported = false;     // DDS texture compression support
+static bool npotSupported = false;           // NPOT textures full support
 
 #if defined(GRAPHICS_API_OPENGL_ES2)
 // NOTE: VAO functionality is exposed through extensions (OES)
@@ -254,14 +254,17 @@ unsigned int whiteTexture;
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat);
+
 static Shader LoadDefaultShader(void);
 static void LoadDefaultShaderLocations(Shader *shader);
-static void InitializeBuffers(void);
-static void InitializeBuffersGPU(void);
-static void UpdateBuffers(void);
-static char *TextFileRead(char *fn);
+static void UnloadDefaultShader(void);
 
-static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat);
+static void LoadDefaultBuffers(void);
+static void UpdateDefaultBuffers(void);
+static void UnloadDefaultBuffers(void);
+
+static char *ReadTextFile(const char *fileName);
 #endif
 
 #if defined(GRAPHICS_API_OPENGL_11)
@@ -274,20 +277,6 @@ static void TraceLog(int msgType, const char *text, ...);
 float *MatrixToFloat(Matrix mat);   // Converts Matrix to float array
 #endif
 
-#if defined(GRAPHICS_API_OPENGL_ES2)
-// NOTE: strdup() functions replacement (not C99, POSIX function, not available on emscripten)
-// Duplicates a string, returning an identical malloc'd string
-char *mystrdup(const char *str)
-{
-  size_t len = strlen(str) + 1;
-  void *newstr = malloc(len);
-
-  if (newstr == NULL) return NULL;
-
-  return (char *)memcpy(newstr, str, len);
-}
-#endif
-
 //----------------------------------------------------------------------------------
 // Module Functions Definition - Matrix operations
 //----------------------------------------------------------------------------------
@@ -919,13 +908,18 @@ void rlglInit(void)
     
     // NOTE: We have to duplicate string because glGetString() returns a const value
     // If not duplicated, it fails in some systems (Raspberry Pi)
-    char *extensionsDup = mystrdup(extensions);
+    // Equivalent to function: char *strdup(const char *str)
+    char *extensionsDup;
+    size_t len = strlen(extensions) + 1;
+    void *newstr = malloc(len);
+    if (newstr == NULL) extensionsDup = NULL;
+    extensionsDup = (char *)memcpy(newstr, extensions, len);
     
     // NOTE: String could be splitted using strtok() function (string.h)
     // NOTE: strtok() modifies the received string, it can not be const
     
     char *extList[512];     // Allocate 512 strings pointers (2 KB)
-
+    
     extList[numExt] = strtok(extensionsDup, " ");
 
     while (extList[numExt] != NULL)
@@ -969,10 +963,12 @@ void rlglInit(void)
         
         // DDS texture compression support
         if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
+            (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) ||
             (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) texCompDXTSupported = true; 
         
         // ETC1 texture compression support
-        if (strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) texCompETC1Supported = true;
+        if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) ||
+            (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) texCompETC1Supported = true;
 
         // ETC2/EAC texture compression support
         if (strcmp(extList[i], (const char *)"GL_ARB_ES3_compatibility") == 0) texCompETC2Supported = true;
@@ -1022,12 +1018,9 @@ void rlglInit(void)
 
     // Init default Shader (customized for GL 3.3 and ES2)
     defaultShader = LoadDefaultShader();
-    //customShader = LoadShader("custom.vs", "custom.fs");     // Works ok
-    
     currentShader = defaultShader;
 
-    InitializeBuffers();        // Init vertex arrays
-    InitializeBuffersGPU();     // Init VBO and VAO
+    LoadDefaultBuffers();        // Initialize default vertex arrays buffers (lines, triangles, quads)
 
     // Init temp vertex buffer, used when transformation required (translate, rotate, scale)
     tempBuffer = (Vector3 *)malloc(sizeof(Vector3)*TEMP_VERTEX_BUFFER_SIZE);
@@ -1052,54 +1045,10 @@ void rlglInit(void)
 void rlglClose(void)
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    // Unbind everything
-    if (vaoSupported) glBindVertexArray(0);
-    glDisableVertexAttribArray(0);
-    glDisableVertexAttribArray(1);
-    glDisableVertexAttribArray(2);
-    glDisableVertexAttribArray(3);
-    glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-
-    glUseProgram(0);
-
-    // Delete VBOs
-    glDeleteBuffers(1, &linesBuffer[0]);
-    glDeleteBuffers(1, &linesBuffer[1]);
-    glDeleteBuffers(1, &trianglesBuffer[0]);
-    glDeleteBuffers(1, &trianglesBuffer[1]);
-    glDeleteBuffers(1, &quadsBuffer[0]);
-    glDeleteBuffers(1, &quadsBuffer[1]);
-    glDeleteBuffers(1, &quadsBuffer[2]);
-    glDeleteBuffers(1, &quadsBuffer[3]);
-
-    if (vaoSupported)
-    {
-        // Delete VAOs
-        glDeleteVertexArrays(1, &vaoLines);
-        glDeleteVertexArrays(1, &vaoTriangles);
-        glDeleteVertexArrays(1, &vaoQuads);
-    }
-
-    //glDetachShader(defaultShaderProgram, vertexShader);
-    //glDetachShader(defaultShaderProgram, fragmentShader);
-    //glDeleteShader(vertexShader);     // Already deleted on shader compilation
-    //glDeleteShader(fragmentShader);   // Already deleted on sahder compilation
-    glDeleteProgram(defaultShader.id);
-
-    // Free vertex arrays memory
-    free(lines.vertices);
-    free(lines.colors);
-
-    free(triangles.vertices);
-    free(triangles.colors);
-
-    free(quads.vertices);
-    free(quads.texcoords);
-    free(quads.colors);
-    free(quads.indices);
-
-    // Free GPU texture
+    UnloadDefaultShader();
+    UnloadDefaultBuffers();
+    
+    // Delete default white texture
     glDeleteTextures(1, &whiteTexture);
     TraceLog(INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture);
 
@@ -1108,18 +1057,18 @@ void rlglClose(void)
 }
 
 // Drawing batches: triangles, quads, lines
-void rlglDraw(void)
+void rlglDraw(Matrix mvp)
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    UpdateBuffers();
+    UpdateDefaultBuffers();
 
     if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0))
     {
         glUseProgram(currentShader.id);
         
-        Matrix matMVP = MatrixMultiply(modelview, projection);        // Create modelview-projection matrix
+        Matrix mvp2 = MatrixMultiply(modelview, projection);        // Create modelview-projection matrix
 
-        glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP));
+        glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(mvp2));
         glUniform1i(currentShader.mapDiffuseLoc, 0);
         glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f);
     }
@@ -1348,14 +1297,14 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro
     glBindTexture(GL_TEXTURE_2D, model.material.texDiffuse.id);
     glUniform1i(model.material.shader.mapDiffuseLoc, 0);        // Texture fits in active texture unit 0
     
-    if (model.material.texNormal.id != 0)
+    if ((model.material.texNormal.id != 0) && (model.material.shader.mapNormalLoc != -1))
     {
         glActiveTexture(GL_TEXTURE1);
         glBindTexture(GL_TEXTURE_2D, model.material.texNormal.id);
         glUniform1i(model.material.shader.mapNormalLoc, 1);     // Texture fits in active texture unit 1
     }
     
-    if (model.material.texSpecular.id != 0)
+    if ((model.material.texSpecular.id != 0) && (model.material.shader.mapSpecularLoc != -1))
     {
         glActiveTexture(GL_TEXTURE2);
         glBindTexture(GL_TEXTURE_2D, model.material.texSpecular.id);
@@ -1844,7 +1793,9 @@ void rlglGenerateMipmaps(Texture2D texture)
         // NOTE: Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data
         free(data);
         
-#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+#endif
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
         glGenerateMipmap(GL_TEXTURE_2D);    // Generate mipmaps automatically
         TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture.id);
 
@@ -2114,8 +2065,8 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
 
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     // Shaders loading from external text file
-    char *vShaderStr = TextFileRead(vsFileName);
-    char *fShaderStr = TextFileRead(fsFileName);
+    char *vShaderStr = ReadTextFile(vsFileName);
+    char *fShaderStr = ReadTextFile(fsFileName);
     
     if ((vShaderStr != NULL) && (fShaderStr != NULL))
     {
@@ -2123,17 +2074,13 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
 
         // After shader loading, we try to load default location names
         if (shader.id != 0) LoadDefaultShaderLocations(&shader);
-        else
-        {
-            TraceLog(WARNING, "Custom shader could not be loaded");
-            shader = defaultShader;
-        }
         
         // Shader strings must be freed
         free(vShaderStr);
         free(fShaderStr);
     }
-    else
+    
+    if (shader.id == 0)
     {
         TraceLog(WARNING, "Custom shader could not be loaded");
         shader = defaultShader;
@@ -2259,7 +2206,7 @@ void SetCustomShader(Shader shader)
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     if (currentShader.id != shader.id)
     {
-        rlglDraw();
+        //rlglDraw();
         currentShader = shader;
     }
 #endif
@@ -2365,7 +2312,7 @@ void SetBlendMode(int mode)
 {
     if ((blendMode != mode) && (mode < 3))
     {
-        rlglDraw();
+        //rlglDraw();
         
         switch (mode)
         {
@@ -2379,18 +2326,6 @@ void SetBlendMode(int mode)
     }
 }
 
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-void PrintProjectionMatrix(void)
-{
-    PrintMatrix(projection);
-}
-
-void PrintModelviewMatrix(void)
-{
-    PrintMatrix(modelview);
-}
-#endif
-
 //----------------------------------------------------------------------------------
 // Module specific Functions Definition
 //----------------------------------------------------------------------------------
@@ -2432,7 +2367,7 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in
     }
 }
 
-// Load Shader (Vertex and Fragment)
+// Load default shader (Vertex and Fragment)
 // NOTE: This shader program is used for batch buffers (lines, triangles, quads)
 static Shader LoadDefaultShader(void)
 {
@@ -2492,7 +2427,7 @@ static Shader LoadDefaultShader(void)
     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);
 
-    LoadDefaultShaderLocations(&shader);
+    if (shader.id != 0) LoadDefaultShaderLocations(&shader);
 
     return shader;
 }
@@ -2517,43 +2452,24 @@ static void LoadDefaultShaderLocations(Shader *shader)
     shader->mapSpecularLoc = glGetUniformLocation(shader->id, "texture2");
 }
 
-// Read text file
-// NOTE: text chars array should be freed manually
-static char *TextFileRead(char *fileName)
+// Unload default shader 
+static void UnloadDefaultShader(void)
 {
-    FILE *textFile;
-    char *text = NULL;
-
-    int count = 0;
-
-    if (fileName != NULL)
-    {
-        textFile = fopen(fileName,"rt");
-
-        if (textFile != NULL)
-        {
-            fseek(textFile, 0, SEEK_END);
-            count = ftell(textFile);
-            rewind(textFile);
-
-            if (count > 0)
-            {
-                text = (char *)malloc(sizeof(char)*(count + 1));
-                count = fread(text, sizeof(char), count, textFile);
-                text[count] = '\0';
-            }
-
-            fclose(textFile);
-        }
-        else TraceLog(WARNING, "[%s] Text file could not be opened", fileName);
-    }
+    glUseProgram(0);
 
-    return text;
+    //glDetachShader(defaultShaderProgram, vertexShader);
+    //glDetachShader(defaultShaderProgram, fragmentShader);
+    //glDeleteShader(vertexShader);     // Already deleted on shader compilation
+    //glDeleteShader(fragmentShader);   // Already deleted on sahder compilation
+    glDeleteProgram(defaultShader.id);
 }
 
-// Allocate and initialize float array buffers to store vertex data (lines, triangles, quads)
-static void InitializeBuffers(void)
+// Load default internal buffers (lines, triangles, quads)
+static void LoadDefaultBuffers(void)
 {
+    // [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads)
+    //--------------------------------------------------------------------------------------------
+    
     // Initialize lines arrays (vertex position and color data)
     lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH);        // 3 float by vertex, 2 vertex by line
     lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH);  // 4 float by color, 2 colors by line
@@ -2607,13 +2523,14 @@ static void InitializeBuffers(void)
     quads.tcCounter = 0;
     quads.cCounter = 0;
 
-    TraceLog(INFO, "CPU buffers (lines, triangles, quads) initialized successfully");
-}
-
-// Initialize Vertex Array Objects (Contain VBO)
-// NOTE: lines, triangles and quads buffers use currentShader
-static void InitializeBuffersGPU(void)
-{
+    TraceLog(INFO, "Default buffers initialized successfully in CPU (lines, triangles, quads)");
+    //--------------------------------------------------------------------------------------------
+    
+    // [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads)
+    // NOTE: Default buffers are linked to use currentShader (defaultShader)
+    //--------------------------------------------------------------------------------------------
+    
+    // Upload and link lines vertex buffers
     if (vaoSupported)
     {
         // Initialize Lines VAO
@@ -2636,10 +2553,10 @@ static void InitializeBuffersGPU(void)
     glEnableVertexAttribArray(currentShader.colorLoc);
     glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
 
-    if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Lines VAO initialized successfully", vaoLines);
-    else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Lines VBOs initialized successfully", linesBuffer[0], linesBuffer[1]);
-    //--------------------------------------------------------------
+    if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (lines) VAO initialized successfully", vaoLines);
+    else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers (lines) VBOs initialized successfully", linesBuffer[0], linesBuffer[1]);
 
+    // Upload and link triangles vertex buffers
     if (vaoSupported)
     {
         // Initialize Triangles VAO
@@ -2661,10 +2578,10 @@ static void InitializeBuffersGPU(void)
     glEnableVertexAttribArray(currentShader.colorLoc);
     glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
 
-    if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Triangles VAO initialized successfully", vaoTriangles);
-    else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Triangles VBOs initialized successfully", trianglesBuffer[0], trianglesBuffer[1]);
-    //--------------------------------------------------------------
+    if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (triangles) VAO initialized successfully", vaoTriangles);
+    else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers (triangles) VBOs initialized successfully", trianglesBuffer[0], trianglesBuffer[1]);
 
+    // Upload and link quads vertex buffers
     if (vaoSupported)
     {
         // Initialize Quads VAO
@@ -2699,18 +2616,20 @@ static void InitializeBuffersGPU(void)
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
 #endif
 
-    if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Quads VAO initialized successfully", vaoQuads);
-    else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Quads VBOs initialized successfully", quadsBuffer[0], quadsBuffer[1], quadsBuffer[2], quadsBuffer[3]);
+    if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (quads) VAO initialized successfully", vaoQuads);
+    else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers (quads) VBOs initialized successfully", quadsBuffer[0], quadsBuffer[1], quadsBuffer[2], quadsBuffer[3]);
 
     // Unbind the current VAO
     if (vaoSupported) glBindVertexArray(0);
+    //--------------------------------------------------------------------------------------------
 }
 
-// Update VBOs with vertex array data
+// Update default buffers (VAOs/VBOs) with vertex array data
 // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0)
-// TODO: If no data changed on the CPU arrays --> No need to update GPU arrays (change flag required)
-static void UpdateBuffers(void)
+// TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required)
+static void UpdateDefaultBuffers(void)
 {
+    // Update lines vertex buffers
     if (lines.vCounter > 0)
     {
         // Activate Lines VAO
@@ -2726,8 +2645,8 @@ static void UpdateBuffers(void)
         //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
         glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*lines.cCounter, lines.colors);
     }
-    //--------------------------------------------------------------
 
+    // Update triangles vertex buffers
     if (triangles.vCounter > 0)
     {
         // Activate Triangles VAO
@@ -2743,8 +2662,8 @@ static void UpdateBuffers(void)
         //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
         glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*triangles.cCounter, triangles.colors);
     }
-    //--------------------------------------------------------------
 
+    // Update quads vertex buffers
     if (quads.vCounter > 0)
     {
         // Activate Quads VAO
@@ -2766,7 +2685,7 @@ static void UpdateBuffers(void)
         glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*quads.vCounter, quads.colors);
 
         // Another option would be using buffer mapping...
-        //triangles.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
+        //quads.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
         // Now we can modify vertices
         //glUnmapBuffer(GL_ARRAY_BUFFER);
     }
@@ -2775,6 +2694,83 @@ static void UpdateBuffers(void)
     // Unbind the current VAO
     if (vaoSupported) glBindVertexArray(0);
 }
+
+// Unload default buffers vertex data from CPU and GPU
+static void UnloadDefaultBuffers(void)
+{
+    // Unbind everything
+    if (vaoSupported) glBindVertexArray(0);
+    glDisableVertexAttribArray(0);
+    glDisableVertexAttribArray(1);
+    glDisableVertexAttribArray(2);
+    glDisableVertexAttribArray(3);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+    // Delete VBOs from GPU (VRAM)
+    glDeleteBuffers(1, &linesBuffer[0]);
+    glDeleteBuffers(1, &linesBuffer[1]);
+    glDeleteBuffers(1, &trianglesBuffer[0]);
+    glDeleteBuffers(1, &trianglesBuffer[1]);
+    glDeleteBuffers(1, &quadsBuffer[0]);
+    glDeleteBuffers(1, &quadsBuffer[1]);
+    glDeleteBuffers(1, &quadsBuffer[2]);
+    glDeleteBuffers(1, &quadsBuffer[3]);
+
+    if (vaoSupported)
+    {
+        // Delete VAOs from GPU (VRAM)
+        glDeleteVertexArrays(1, &vaoLines);
+        glDeleteVertexArrays(1, &vaoTriangles);
+        glDeleteVertexArrays(1, &vaoQuads);
+    }
+
+    // Free vertex arrays memory from CPU (RAM)
+    free(lines.vertices);
+    free(lines.colors);
+
+    free(triangles.vertices);
+    free(triangles.colors);
+
+    free(quads.vertices);
+    free(quads.texcoords);
+    free(quads.colors);
+    free(quads.indices);
+}
+
+// Read text data from file
+// NOTE: text chars array should be freed manually
+static char *ReadTextFile(const char *fileName)
+{
+    FILE *textFile;
+    char *text = NULL;
+
+    int count = 0;
+
+    if (fileName != NULL)
+    {
+        textFile = fopen(fileName,"rt");
+
+        if (textFile != NULL)
+        {
+            fseek(textFile, 0, SEEK_END);
+            count = ftell(textFile);
+            rewind(textFile);
+
+            if (count > 0)
+            {
+                text = (char *)malloc(sizeof(char)*(count + 1));
+                count = fread(text, sizeof(char), count, textFile);
+                text[count] = '\0';
+            }
+
+            fclose(textFile);
+        }
+        else TraceLog(WARNING, "[%s] Text file could not be opened", fileName);
+    }
+
+    return text;
+}
 #endif //defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
 
 #if defined(GRAPHICS_API_OPENGL_11)
@@ -2905,7 +2901,6 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight)
 #endif
 
 #if defined(RLGL_STANDALONE)
-
 // Output a trace log message
 // NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning
 static void TraceLog(int msgType, const char *text, ...)

+ 5 - 13
examples/oculus_glfw_sample/rlgl.h

@@ -273,7 +273,7 @@ int rlGetVersion(void);                         // Returns current OpenGL versio
 //------------------------------------------------------------------------------------
 void rlglInit(void);                            // Initialize rlgl (shaders, VAO, VBO...)
 void rlglClose(void);                           // De-init rlgl
-void rlglDraw(void);                            // Draw VAO/VBO
+void rlglDraw(Matrix mvp);                      // Draw VAO/VBO
 void rlglInitGraphics(int offsetX, int offsetY, int width, int height);  // Initialize Graphics (OpenGL stuff)
 
 unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount);    // Load texture in GPU
@@ -292,11 +292,6 @@ Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view);    // Get world
 unsigned char *rlglReadScreenPixels(int width, int height);         // Read screen pixel data (color buffer)
 void *rlglReadTexturePixels(Texture2D texture);                     // Read texture pixel data
 
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-void PrintProjectionMatrix(void);       // DEBUG: Print projection matrix
-void PrintModelviewMatrix(void);        // DEBUG: Print modelview matrix
-#endif
-
 #if defined(RLGL_STANDALONE)
 //------------------------------------------------------------------------------------
 // Shaders System Functions (Module: rlgl)
@@ -309,13 +304,10 @@ void SetCustomShader(Shader shader);                                // Set custo
 void SetDefaultShader(void);                                        // Set default shader to be used in batch draw
 void SetModelShader(Model *model, Shader shader);                   // Link a shader to a model
 
-int GetShaderLocation(Shader shader, const char *uniformName);                          // Get shader uniform location
-void SetShaderValue(Shader shader, int uniformLoc, float *value, int size);             // Set shader uniform value (float)
-void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size);              // Set shader uniform value (int)
-void SetShaderMapDiffuse(Shader *shader, Texture2D texture);                            // Default diffuse shader map texture assignment
-void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture);    // Normal map texture shader assignment
-void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture);  // Specular map texture shader assignment
-void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textureUnit); // TODO: Generic shader map assignment
+int GetShaderLocation(Shader shader, const char *uniformName);              // Get shader uniform location
+void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)
+void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size);  // Set shader uniform value (int)
+void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);       // Set shader uniform value (matrix 4x4)
 
 void SetBlendMode(int mode);                                        // Set blending mode (alpha, additive, multiplied)
 #endif

+ 2 - 2
examples/shaders_model_shader.c

@@ -37,8 +37,8 @@ int main()
     Shader shader = LoadShader("resources/shaders/glsl330/base.vs", 
                                "resources/shaders/glsl330/grayscale.fs");   // Load model shader
 
-    SetModelShader(&dwarf, shader);         // Set shader effect to 3d model
-    SetModelTexture(&dwarf, texture);       // Bind texture to model
+    dwarf.material.shader = shader;            // Set shader effect to 3d model
+    dwarf.material.texDiffuse = texture;       // Bind texture to model
     
     Vector3 position = { 0.0f, 0.0f, 0.0f };   // Set model position
     

+ 1 - 0
src/core.c

@@ -1448,6 +1448,7 @@ static void InitDisplay(int width, int height)
         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above!
                                                                        // Other values: GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
         glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); // Fordward Compatibility Hint: Only 3.3 and above!
+        //glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
     }
 
     if (fullscreen)

+ 351 - 52
src/models.c

@@ -55,7 +55,9 @@ extern unsigned int whiteTexture;
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
-static Mesh LoadOBJ(const char *fileName);
+static Mesh LoadOBJ(const char *fileName);      // Load OBJ mesh data
+static Material LoadMTL(const char *fileName);  // Load MTL material data
+
 static Mesh GenMeshHeightmap(Image image, Vector3 size);
 static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
 
@@ -542,24 +544,19 @@ void DrawGizmo(Vector3 position)
 Model LoadModel(const char *fileName)
 {
     Model model = { 0 };
-    Mesh mesh = { 0 };
     
-    // NOTE: Initialize default data for model in case loading fails, maybe a cube?
+    // TODO: Initialize default data for model in case loading fails, maybe a cube?
 
-    if (strcmp(GetExtension(fileName),"obj") == 0) mesh = LoadOBJ(fileName);
+    if (strcmp(GetExtension(fileName),"obj") == 0) model.mesh = LoadOBJ(fileName);
     else TraceLog(WARNING, "[%s] Model extension not recognized, it can't be loaded", fileName);
 
-    // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct
-    
-    if (mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
+    if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
     else
     {
-        // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel()
-        model = rlglLoadModel(mesh);     // Upload vertex data to GPU
-
-        // NOTE: Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM
-        // We don't need CPU vertex data on OpenGL 3.3 or ES2... for static meshes...
-        // ...but we could keep CPU vertex data in case we need to update the mesh
+        rlglLoadMesh(&model.mesh);     // Upload vertex data to GPU
+        
+        model.transform = MatrixIdentity();
+        model.material = LoadDefaultMaterial();
     }
 
     return model;
@@ -568,22 +565,111 @@ Model LoadModel(const char *fileName)
 // Load a 3d model (from vertex data)
 Model LoadModelEx(Mesh data)
 {
-    Model model;
+    Model model = { 0 };
 
-    // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel()
-    model = rlglLoadModel(data);     // Upload vertex data to GPU
+    rlglLoadMesh(&data);     // Upload vertex data to GPU
     
-    // NOTE: Vertex data is managed externally, must be deallocated manually
+    model.transform = MatrixIdentity();
+    model.material = LoadDefaultMaterial();
     
     return model;
 }
 
+// Load a 3d model from rRES file (raylib Resource)
+Model LoadModelFromRES(const char *rresName, int resId)
+{
+    Model model = { 0 };
+    bool found = false;
+
+    char id[4];             // rRES file identifier
+    unsigned char version;  // rRES file version and subversion
+    char useless;           // rRES header reserved data
+    short numRes;
+
+    ResInfoHeader infoHeader;
+
+    FILE *rresFile = fopen(rresName, "rb");
+
+    if (rresFile == NULL)
+    {
+        TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName);
+    }
+    else
+    {
+        // Read rres file (basic file check - id)
+        fread(&id[0], sizeof(char), 1, rresFile);
+        fread(&id[1], sizeof(char), 1, rresFile);
+        fread(&id[2], sizeof(char), 1, rresFile);
+        fread(&id[3], sizeof(char), 1, rresFile);
+        fread(&version, sizeof(char), 1, rresFile);
+        fread(&useless, sizeof(char), 1, rresFile);
+
+        if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
+        {
+            TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
+        }
+        else
+        {
+            // Read number of resources embedded
+            fread(&numRes, sizeof(short), 1, rresFile);
+
+            for (int i = 0; i < numRes; i++)
+            {
+                fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
+
+                if (infoHeader.id == resId)
+                {
+                    found = true;
+
+                    // Check data is of valid MODEL type
+                    if (infoHeader.type == 8)
+                    {
+                        // TODO: Load model data
+                    }
+                    else
+                    {
+                        TraceLog(WARNING, "[%s] Required resource do not seem to be a valid MODEL resource", rresName);
+                    }
+                }
+                else
+                {
+                    // Depending on type, skip the right amount of parameters
+                    switch (infoHeader.type)
+                    {
+                        case 0: fseek(rresFile, 6, SEEK_CUR); break;    // IMAGE: Jump 6 bytes of parameters
+                        case 1: fseek(rresFile, 6, SEEK_CUR); break;    // SOUND: Jump 6 bytes of parameters
+                        case 2: fseek(rresFile, 5, SEEK_CUR); break;    // MODEL: Jump 5 bytes of parameters (TODO: Review)
+                        case 3: break;                                  // TEXT: No parameters
+                        case 4: break;                                  // RAW: No parameters
+                        default: break;
+                    }
+
+                    // Jump DATA to read next infoHeader
+                    fseek(rresFile, infoHeader.size, SEEK_CUR);
+                }
+            }
+        }
+
+        fclose(rresFile);
+    }
+
+    if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
+
+    return model;
+}
+
 // Load a heightmap image as a 3d model
 // NOTE: model map size is defined in generic units
 Model LoadHeightmap(Image heightmap, Vector3 size)
 {
-    Mesh mesh = GenMeshHeightmap(heightmap, size);
-    Model model = rlglLoadModel(mesh);
+    Model model = { 0 };
+    
+    model.mesh = GenMeshHeightmap(heightmap, size);
+    
+    rlglLoadMesh(&model.mesh);
+    
+    model.transform = MatrixIdentity();
+    model.material = LoadDefaultMaterial();
 
     return model;
 }
@@ -591,8 +677,14 @@ Model LoadHeightmap(Image heightmap, Vector3 size)
 // Load a map image as a 3d model (cubes based)
 Model LoadCubicmap(Image cubicmap)
 {
-    Mesh mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f });
-    Model model = rlglLoadModel(mesh);
+    Model model = { 0 };
+    
+    model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f });
+    
+    rlglLoadMesh(&model.mesh);
+    
+    model.transform = MatrixIdentity();
+    model.material = LoadDefaultMaterial();
 
     return model;
 }
@@ -603,23 +695,54 @@ void UnloadModel(Model model)
     // Unload mesh data
     free(model.mesh.vertices);
     free(model.mesh.texcoords);
-    free(model.mesh.normals);
-    free(model.mesh.colors);
-    //if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); // Not used
-    //if (model.mesh.tangents != NULL) free(model.mesh.tangents); // Not used
+    if (model.mesh.normals != NULL) free(model.mesh.normals);
+    if (model.mesh.colors != NULL) free(model.mesh.colors);
+    if (model.mesh.tangents != NULL) free(model.mesh.tangents);
+    if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2);
     
     TraceLog(INFO, "Unloaded model data from RAM (CPU)");
     
     rlDeleteBuffers(model.mesh.vboId[0]);   // vertex
     rlDeleteBuffers(model.mesh.vboId[1]);   // texcoords
     rlDeleteBuffers(model.mesh.vboId[2]);   // normals
-    //rlDeleteBuffers(model.mesh.vboId[3]);   // texcoords2 (NOT USED)
-    //rlDeleteBuffers(model.mesh.vboId[4]);   // tangents (NOT USED)
-    //rlDeleteBuffers(model.mesh.vboId[5]);   // colors (NOT USED)
+    rlDeleteBuffers(model.mesh.vboId[3]);   // colors
+    rlDeleteBuffers(model.mesh.vboId[4]);   // tangents
+    rlDeleteBuffers(model.mesh.vboId[5]);   // texcoords2
 
     rlDeleteVertexArrays(model.mesh.vaoId);
 }
 
+// Load material data (from file)
+Material LoadMaterial(const char *fileName)
+{
+    Material material = { 0 };
+    
+    if (strcmp(GetExtension(fileName),"mtl") == 0) material = LoadMTL(fileName);
+    else TraceLog(WARNING, "[%s] Material extension not recognized, it can't be loaded", fileName);
+    
+    return material;
+}
+
+// Load default material (uses default models shader)
+Material LoadDefaultMaterial(void)
+{
+    Material material = { 0 };
+    
+    material.shader = GetDefaultShader();
+    material.texDiffuse = GetDefaultTexture();      // White texture (1x1 pixel)
+    //material.texNormal;           // NOTE: By default, not set
+    //material.texSpecular;         // NOTE: By default, not set
+    
+    material.colDiffuse = WHITE;    // Diffuse color
+    material.colAmbient = WHITE;    // Ambient color
+    material.colSpecular = WHITE;   // Specular color
+    
+    material.glossiness = 100.0f;   // Glossiness level
+    material.normalDepth = 1.0f;    // Normal map depth
+    
+    return material;
+}
+
 // Link a texture to a model
 void SetModelTexture(Model *model, Texture2D texture)
 {
@@ -632,7 +755,7 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
 {
     #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3)
     
-    Mesh mesh;
+    Mesh mesh = { 0 };
 
     int mapX = heightmap.width;
     int mapZ = heightmap.height;
@@ -647,7 +770,7 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
     mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
     mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
     mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float));
-    mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char)); // Not used...
+    mesh.colors = NULL;
 
     int vCounter = 0;       // Used to count vertices float by float
     int tcCounter = 0;      // Used to count texcoords float by float
@@ -730,16 +853,12 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
     
     free(pixels);
 
-    // Fill color data
-    // NOTE: Not used any more... just one plain color defined at DrawModel()
-    for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255;
-
     return mesh;
 }
 
 static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
 {
-    Mesh mesh;
+    Mesh mesh = { 0 };
 
     Color *cubicmapPixels = GetImageData(cubicmap);
     
@@ -1048,11 +1167,7 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
     mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
     mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
     mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float));
-    mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char));  // Not used...
-
-    // Fill color data
-    // NOTE: Not used any more... just one plain color defined at DrawModel()
-    for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255;
+    mesh.colors = NULL;
 
     int fCounter = 0;
 
@@ -1100,31 +1215,59 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint)
 {
     Vector3 vScale = { scale, scale, scale };
     Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
-
+    
     DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
 }
 
 // Draw a model with extended parameters
 void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
 {
-    // NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel()
-    rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, false);
+    // Calculate transformation matrix from function parameters
+    // Get transform matrix (rotation -> scale -> translation)
+    Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
+    Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
+    Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
+    
+    // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
+    //Matrix matModel = MatrixMultiply(model.transform, matTransform);    // Transform to world-space coordinates
+    
+    model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
+    model.material.colDiffuse = tint;
+    
+    rlglDrawEx(model.mesh, model.material, model.transform, false);
 }
 
 // Draw a model wires (with texture if set)
-void DrawModelWires(Model model, Vector3 position, float scale, Color color)
+void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
 {
     Vector3 vScale = { scale, scale, scale };
     Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
 
-    rlglDrawModel(model, position, rotationAxis, 0.0f, vScale, color, true);
+    // Calculate transformation matrix from function parameters
+    // Get transform matrix (rotation -> scale -> translation)
+    Matrix matRotation = MatrixRotate(rotationAxis, 0.0f);
+    Matrix matScale = MatrixScale(vScale.x, vScale.y, vScale.z);
+    Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
+    
+    model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
+    model.material.colDiffuse = tint;
+    
+    rlglDrawEx(model.mesh, model.material, model.transform, true);
 }
 
 // Draw a model wires (with texture if set) with extended parameters
 void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
 {
-    // NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel()
-    rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, true);
+    // Calculate transformation matrix from function parameters
+    // Get transform matrix (rotation -> scale -> translation)
+    Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
+    Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
+    Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
+    
+    model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
+    model.material.colDiffuse = tint;
+    
+    rlglDrawEx(model.mesh, model.material, model.transform, true);
 }
 
 // Draw a billboard
@@ -1742,7 +1885,7 @@ static Mesh LoadOBJ(const char *fileName)
     mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
     mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float));
     mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
-    mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char));
+    mesh.colors = NULL;
 
     int vCounter = 0;       // Used to count vertices float by float
     int tcCounter = 0;      // Used to count texcoords float by float
@@ -1841,10 +1984,6 @@ static Mesh LoadOBJ(const char *fileName)
 
     // Security check, just in case no normals or no texcoords defined in OBJ
     if (numTexCoords == 0) for (int i = 0; i < (2*mesh.vertexCount); i++) mesh.texcoords[i] = 0.0f;
-    
-    // NOTE: We set all vertex colors to white
-    // NOTE: Not used any more... just one plain color defined at DrawModel()
-    for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255;
 
     // Now we can free temp mid* arrays
     free(midVertices);
@@ -1856,3 +1995,163 @@ static Mesh LoadOBJ(const char *fileName)
 
     return mesh;
 }
+
+// Load MTL material data (specs: http://paulbourke.net/dataformats/mtl/)
+// NOTE: Texture map parameters are not supported
+static Material LoadMTL(const char *fileName)
+{
+    #define MAX_BUFFER_SIZE     128
+    
+    Material material = { 0 };  // LoadDefaultMaterial();
+    
+    char buffer[MAX_BUFFER_SIZE];
+    Vector3 color = { 1.0f, 1.0f, 1.0f };
+    char *mapFileName;
+
+    FILE *mtlFile;
+
+    mtlFile = fopen(fileName, "rt");
+
+    if (mtlFile == NULL)
+    {
+        TraceLog(WARNING, "[%s] MTL file could not be opened", fileName);
+        return material;
+    }
+
+    while(!feof(mtlFile))
+    {
+        fgets(buffer, MAX_BUFFER_SIZE, mtlFile);
+        
+        switch (buffer[0])
+        {
+            case 'n':   // newmtl string    Material name. Begins a new material description.
+            {
+                // TODO: Support multiple materials in a single .mtl
+                sscanf(buffer, "newmtl %s", mapFileName);
+                
+                TraceLog(INFO, "[%s] Loading material...", mapFileName);
+            }
+            case 'i':   // illum int        Illumination model
+            {
+                // illum = 1 if specular disabled
+                // illum = 2 if specular enabled (lambertian model)
+                // ...
+            }
+            case 'K':   // Ka, Kd, Ks, Ke
+            {
+                switch (buffer[1])
+                {
+                    case 'a':   // Ka float float float    Ambient color (RGB)
+                    {
+                        sscanf(buffer, "Ka %f %f %f", &color.x, &color.y, &color.z);
+                        material.colAmbient.r = (unsigned char)(color.x*255);
+                        material.colAmbient.g = (unsigned char)(color.y*255);
+                        material.colAmbient.b = (unsigned char)(color.z*255);
+                    } break;
+                    case 'd':   // Kd float float float     Diffuse color (RGB)
+                    {
+                        sscanf(buffer, "Kd %f %f %f", &color.x, &color.y, &color.z);
+                        material.colDiffuse.r = (unsigned char)(color.x*255);
+                        material.colDiffuse.g = (unsigned char)(color.y*255);
+                        material.colDiffuse.b = (unsigned char)(color.z*255);
+                    } break;
+                    case 's':   // Ks float float float     Specular color (RGB)
+                    {
+                        sscanf(buffer, "Ks %f %f %f", &color.x, &color.y, &color.z);
+                        material.colSpecular.r = (unsigned char)(color.x*255);
+                        material.colSpecular.g = (unsigned char)(color.y*255);
+                        material.colSpecular.b = (unsigned char)(color.z*255);
+                    } break;
+                    case 'e':   // Ke float float float     Emmisive color (RGB)
+                    {
+                        // TODO: Support Ke ?
+                    } break;
+                    default: break;
+                }
+            } break;
+            case 'N':   // Ns, Ni
+            {
+                if (buffer[1] == 's')       // Ns int   Shininess (specular exponent). Ranges from 0 to 1000.
+                {
+                    sscanf(buffer, "Ns %i", &material.glossiness);
+                }
+                else if (buffer[1] == 'i')  // Ni int   Refraction index.
+                {
+                    // Not supported...
+                }
+            } break;
+            case 'm':   // map_Kd, map_Ks, map_Ka, map_Bump, map_d
+            {
+                switch (buffer[4])
+                {
+                    case 'K':   // Color texture maps
+                    {
+                        if (buffer[5] == 'd')       // map_Kd string    Diffuse color texture map.
+                        {
+                            sscanf(buffer, "map_Kd %s", mapFileName);
+                            if (mapFileName != NULL) material.texDiffuse = LoadTexture(mapFileName);
+                        }
+                        else if (buffer[5] == 's')  // map_Ks string    Specular color texture map.
+                        {
+                            sscanf(buffer, "map_Ks %s", mapFileName);
+                            if (mapFileName != NULL) material.texSpecular = LoadTexture(mapFileName);
+                        }
+                        else if (buffer[5] == 'a')  // map_Ka string    Ambient color texture map.
+                        {
+                            // Not supported...
+                        }
+                    } break;
+                    case 'B':       // map_Bump string      Bump texture map.
+                    {
+                        sscanf(buffer, "map_Bump %s", mapFileName);
+                        if (mapFileName != NULL) material.texNormal = LoadTexture(mapFileName);
+                    } break;
+                    case 'b':       // map_bump string      Bump texture map.
+                    {
+                        sscanf(buffer, "map_bump %s", mapFileName);
+                        if (mapFileName != NULL) material.texNormal = LoadTexture(mapFileName);
+                    } break;
+                    case 'd':       // map_d string         Opacity texture map.
+                    {
+                        // Not supported...
+                    } break;
+                    default: break;
+                }
+            } break;
+            case 'd':   // d, disp
+            {
+                if (buffer[1] == ' ')       // d float      Dissolve factor. d is inverse of Tr
+                {
+                    float alpha = 1.0f;
+                    sscanf(buffer, "d %f", &alpha);
+                    material.colDiffuse.a = (unsigned char)(alpha*255);
+                }
+                else if (buffer[1] == 'i')  // disp string  Displacement map
+                {
+                    // Not supported...
+                }
+            } break;
+            case 'b':   // bump string      Bump texture map
+            {
+                sscanf(buffer, "bump %s", mapFileName);
+                if (mapFileName != NULL) material.texNormal = LoadTexture(mapFileName);
+            } break;
+            case 'T':   // Tr float         Transparency Tr (alpha). Tr is inverse of d
+            {
+                float ialpha = 0.0f;
+                sscanf(buffer, "Tr %f", &ialpha);
+                material.colDiffuse.a = (unsigned char)((1.0f - ialpha)*255);
+                
+            } break;
+            case 'r':   // refl string      Reflection texture map
+            default: break;
+        }
+    }
+
+    fclose(mtlFile);
+
+    // NOTE: At this point we have all material data
+    TraceLog(INFO, "[%s] Material loaded successfully", fileName);
+    
+    return material;
+}

+ 26 - 21
src/raylib.h

@@ -369,12 +369,12 @@ typedef struct BoundingBox {
 // Vertex data definning a mesh
 typedef struct Mesh {
     int vertexCount;            // num vertices
-    float *vertices;            // vertex position (XYZ - 3 components per vertex)
-    float *texcoords;           // vertex texture coordinates (UV - 2 components per vertex)
-    float *texcoords2;          // vertex second texture coordinates (useful for lightmaps)
-    float *normals;             // vertex normals (XYZ - 3 components per vertex)
-    float *tangents;            // vertex tangents (XYZ - 3 components per vertex)
-    unsigned char *colors;      // vertex colors (RGBA - 4 components per vertex)
+    float *vertices;            // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
+    float *texcoords;           // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
+    float *texcoords2;          // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
+    float *normals;             // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
+    float *tangents;            // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4)
+    unsigned char *colors;      // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
     
     BoundingBox bounds;         // mesh limits defined by min and max points
     
@@ -386,11 +386,13 @@ typedef struct Mesh {
 typedef struct Shader {
     unsigned int id;      // Shader program id
     
-    // Variable attributes locations
-    int vertexLoc;        // Vertex attribute location point (vertex shader)
-    int texcoordLoc;      // Texcoord attribute location point (vertex shader)
-    int normalLoc;        // Normal attribute location point (vertex shader)
-    int colorLoc;         // Color attibute location point (vertex shader)
+    // Vertex attributes locations (default locations)
+    int vertexLoc;        // Vertex attribute location point (default-location = 0)
+    int texcoordLoc;      // Texcoord attribute location point (default-location = 1)
+    int normalLoc;        // Normal attribute location point (default-location = 2)
+    int colorLoc;         // Color attibute location point (default-location = 3)
+    int tangentLoc;       // Tangent attribute location point (default-location = 4)
+    int texcoord2Loc;     // Texcoord2 attribute location point (default-location = 5)
 
     // Uniform locations
     int mvpLoc;           // ModelView-Projection matrix uniform location point (vertex shader)
@@ -801,17 +803,20 @@ void DrawGizmo(Vector3 position);
 //------------------------------------------------------------------------------------
 // Model 3d Loading and Drawing Functions (Module: models)
 //------------------------------------------------------------------------------------
-Model LoadModel(const char *fileName);                                                             // Load a 3d model (.OBJ)
-Model LoadModelEx(Mesh data);                                                                      // Load a 3d model (from mesh data)
-//Model LoadModelFromRES(const char *rresName, int resId);                                         // TODO: Load a 3d model from rRES file (raylib Resource)
-Model LoadHeightmap(Image heightmap, Vector3 size);                                                // Load a heightmap image as a 3d model
-Model LoadCubicmap(Image cubicmap);                                                                // Load a map image as a 3d model (cubes based)
-void UnloadModel(Model model);                                                                     // Unload 3d model from memory
-void SetModelTexture(Model *model, Texture2D texture);                                             // Link a texture to a model
+Model LoadModel(const char *fileName);                          // Load a 3d model (.OBJ)
+Model LoadModelEx(Mesh data);                                   // Load a 3d model (from mesh data)
+Model LoadModelFromRES(const char *rresName, int resId);        // Load a 3d model from rRES file (raylib Resource)
+Model LoadHeightmap(Image heightmap, Vector3 size);             // Load a heightmap image as a 3d model
+Model LoadCubicmap(Image cubicmap);                             // Load a map image as a 3d model (cubes based)
+void UnloadModel(Model model);                                  // Unload 3d model from memory
+void SetModelTexture(Model *model, Texture2D texture);          // Link a texture to a model
+
+Material LoadMaterial(const char *fileName);                    // Load material data (from file)
+Material LoadDefaultMaterial(void);                             // Load default material (uses default models shader)
 
 void DrawModel(Model model, Vector3 position, float scale, Color tint);                            // Draw a model (with texture if set)
 void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint);      // Draw a model with extended parameters
-void DrawModelWires(Model model, Vector3 position, float scale, Color color);                      // Draw a model wires (with texture if set)
+void DrawModelWires(Model model, Vector3 position, float scale, Color tint);                      // Draw a model wires (with texture if set)
 void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
 void DrawBoundingBox(BoundingBox box, Color color);                                                // Draw bounding box (wires)
 
@@ -832,11 +837,11 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p
 // NOTE: This functions are useless when using OpenGL 1.1
 //------------------------------------------------------------------------------------
 Shader LoadShader(char *vsFileName, char *fsFileName);              // Load a custom shader and bind default locations
-unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shaders strings and return program id
 void UnloadShader(Shader shader);                                   // Unload a custom shader from memory
 void SetDefaultShader(void);                                        // Set default shader to be used in batch draw
 void SetCustomShader(Shader shader);                                // Set custom shader to be used in batch draw
-void SetModelShader(Model *model, Shader shader);                   // Link a shader to a model
+Shader GetDefaultShader(void);                                      // Get default shader
+Texture2D GetDefaultTexture(void);                                  // Get default texture
 
 int GetShaderLocation(Shader shader, const char *uniformName);              // Get shader uniform location
 void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)

File diff suppressed because it is too large
+ 379 - 464
src/rlgl.c


+ 7 - 8
src/rlgl.h

@@ -280,29 +280,28 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
 RenderTexture2D rlglLoadRenderTexture(int width, int height);   // Load a texture to be used for rendering (fbo with color and depth attachments)
 void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data);         // Update GPU texture with new data
 void rlglGenerateMipmaps(Texture2D texture);                             // Generate mipmap data for selected texture
-
-// NOTE: There is a set of shader related functions that are available to end user,
-// to avoid creating function wrappers through core module, they have been directly declared in raylib.h
-
-Model rlglLoadModel(Mesh mesh);           // Upload vertex data into GPU and provided VAO/VBO ids
-void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires);
+void rlglLoadMesh(Mesh *mesh);           // Upload vertex data into GPU and provided VAO/VBO ids
+void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires);
 
 Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view);    // Get world coordinates from screen coordinates
 
 unsigned char *rlglReadScreenPixels(int width, int height);         // Read screen pixel data (color buffer)
 void *rlglReadTexturePixels(Texture2D texture);                     // Read texture pixel data
 
+// NOTE: There is a set of shader related functions that are available to end user,
+// to avoid creating function wrappers through core module, they have been directly declared in raylib.h
+
 #if defined(RLGL_STANDALONE)
 //------------------------------------------------------------------------------------
 // Shaders System Functions (Module: rlgl)
 // NOTE: This functions are useless when using OpenGL 1.1
 //------------------------------------------------------------------------------------
 Shader LoadShader(char *vsFileName, char *fsFileName);              // Load a custom shader and bind default locations
-unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id
 void UnloadShader(Shader shader);                                   // Unload a custom shader from memory
 void SetCustomShader(Shader shader);                                // Set custom shader to be used in batch draw
 void SetDefaultShader(void);                                        // Set default shader to be used in batch draw
-void SetModelShader(Model *model, Shader shader);                   // Link a shader to a model
+Shader GetDefaultShader(void);                                      // Get default shader
+Texture2D GetDefaultTexture(void);                                  // Get default texture
 
 int GetShaderLocation(Shader shader, const char *uniformName);              // Get shader uniform location
 void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)

Some files were not shown because too many files changed in this diff