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