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

This commit is contained in:
Joshua Reisenauer 2016-05-10 02:00:42 -07:00
commit 9799856ad4
12 changed files with 1887 additions and 1293 deletions

View file

@ -17,57 +17,52 @@
* *
********************************************************************************************/ ********************************************************************************************/
#if defined(_WIN32) #include <stdlib.h>
#define GLFW_EXPOSE_NATIVE_WIN32 #include <stdarg.h>
#define GLFW_EXPOSE_NATIVE_WGL #include <stdio.h>
#define OVR_OS_WIN32 #include <string.h>
#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 "glad.h" // Extensions loading library
#include <GLFW/glfw3.h> // Windows/Context and inputs management
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include "OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL #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 #define RLGL_STANDALONE
#include "rlgl.h" #include "rlgl.h"
#include <stdlib.h> // OVR device variables
#include <stdio.h> 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 // 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; typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // 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) static void ErrorCallback(int error, const char* description)
{ {
fputs(description, stderr); 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 DrawRectangleV(Vector2 position, Vector2 size, Color color);
static void TraceLog(int msgType, const char *text, ...); 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 // 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); ovrResult result = ovr_Initialize(NULL);
if (OVR_FAILURE(result)) TraceLog(LOG_ERROR, "OVR: Could not initialize Oculus device"); 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: Serian Number: %s", hmdDesc.SerialNumber);
TraceLog(LOG_INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); 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 // GLFW3 Initialization + OpenGL 3.3 Context + Extensions
//-------------------------------------------------------- //--------------------------------------------------------
GLFWwindow *window;
glfwSetErrorCallback(ErrorCallback);
if (!glfwInit()) if (!glfwInit())
{ {
TraceLog(LOG_WARNING, "GLFW3: Can not initialize GLFW"); TraceLog(LOG_WARNING, "GLFW3: Can not initialize GLFW");
@ -133,12 +147,11 @@ int main()
glfwWindowHint(GLFW_DEPTH_BITS, 16); glfwWindowHint(GLFW_DEPTH_BITS, 16);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 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_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); 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) if (!window)
{ {
@ -147,6 +160,7 @@ int main()
} }
else TraceLog(LOG_INFO, "GLFW3: Window created successfully"); else TraceLog(LOG_INFO, "GLFW3: Window created successfully");
glfwSetErrorCallback(ErrorCallback);
glfwSetKeyCallback(window, KeyCallback); glfwSetKeyCallback(window, KeyCallback);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
@ -159,174 +173,132 @@ int main()
} }
else TraceLog(LOG_INFO, "GLAD: OpenGL extensions loaded successfully"); else TraceLog(LOG_INFO, "GLAD: OpenGL extensions loaded successfully");
rlglInit(); // Initialize OVR OpenGL swap chain textures
rlglInitGraphics(0, 0, screenWidth, screenHeight); ovrTextureSwapChainDesc desc = {};
rlClearColor(245, 245, 245, 255); // Define clear color 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 }; result = ovr_CreateTextureSwapChainGL(session, &desc, &eyeTexture);
Vector2 size = { 200, 200 }; eyeLayer.ColorTexture[0] = eyeTexture;
Color color = { 180, 20, 20, 255 };
//---------------------------------------------------------------------------
OculusBuffer eyeRenderBuffer[2]; if (!OVR_SUCCESS(result)) TraceLog(LOG_WARNING, "Failed to create swap textures");
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 int length = 0;
ovrSizei windowSize = { hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2 }; result = ovr_GetTextureSwapChainLength(session, eyeTexture, &length);
// 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) if (!OVR_SUCCESS(result) || !length) TraceLog(LOG_WARNING, "Unable to count swap chain textures");
for (int i = 0; i < length; ++i)
{ {
glDeleteFramebuffers(1, &mirrorFBO); GLuint chainTexId;
TraceLog(LOG_WARNING, "OVR: Could not initialize mirror framebuffers"); 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);
} }
glClearColor(1.0f, 0.1f, 0.1f, 0.0f); glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_DEPTH_TEST);
// 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.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");
glGenFramebuffers(1, &mirrorFbo);
// Recenter OVR tracking origin
ovr_RecenterTrackingOrigin(session); ovr_RecenterTrackingOrigin(session);
// FloorLevel will give tracking poses where the floor height is 0 // Initialize rlgl internal buffers and OpenGL state
ovr_SetTrackingOriginType(session, ovrTrackingOrigin_FloorLevel); rlglInit();
//-------------------------------------------------------------------------------------- rlglInitGraphics(0, 0, mirrorSize.x, mirrorSize.y);
rlClearColor(245, 245, 245, 255); // Define clear color
glEnable(GL_DEPTH_TEST);
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 // Update
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
frameIndex++; frame++;
// TODO: Update game here! ovrPosef eyePoses[2];
ovr_GetEyePoses(session, frame, ovrTrue, viewScaleDesc.HmdToEyeOffset, eyePoses, &eyeLayer.SensorSampleTime);
// 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 // 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 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//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++) for (int eye = 0; eye < 2; eye++)
{ {
eyeLayer.ColorTexture[eye] = eyeRenderBuffer[eye].textureChain; glViewport(eyeLayer.Viewport[eye].Pos.x, eyeLayer.Viewport[eye].Pos.y,
eyeLayer.Viewport[eye] = (ovrRecti){ eyeRenderBuffer[eye].width, eyeRenderBuffer[eye].height }; eyeLayer.Viewport[eye].Size.w, eyeLayer.Viewport[eye].Size.h);
eyeLayer.Fov[eye] = hmdDesc.DefaultEyeFov[eye]; eyeLayer.RenderPose[eye] = eyePoses[eye];
eyeLayer.RenderPose[eye] = eyeRenderPose[eye];
eyeLayer.SensorSampleTime = sensorSampleTime; // 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 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
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); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
GLint w = mirrorDesc.Width; ovr_CommitTextureSwapChain(session, eyeTexture);
GLint h = mirrorDesc.Height; ovrLayerHeader *headerList = &eyeLayer.Header;
glBlitFramebuffer(0, h, w, 0, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); ovr_SubmitFrame(session, frame, &viewScaleDesc, &headerList, 1);
// Blit mirror texture to back buffer
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); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glfwSwapBuffers(window); glfwSwapBuffers(window);
glfwPollEvents(); glfwPollEvents();
@ -335,10 +307,13 @@ int main()
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
if (mirrorFBO) glDeleteFramebuffers(1, &mirrorFBO); if (mirrorFbo) glDeleteFramebuffers(1, &mirrorFbo);
if (mirrorTexture) ovr_DestroyMirrorTexture(session, mirrorTexture); 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(); rlglClose();
glfwDestroyWindow(window); glfwDestroyWindow(window);
@ -355,108 +330,6 @@ int main()
// Module specific Functions Definitions // 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) // Draw rectangle using rlgl OpenGL 1.1 style coding (translated to OpenGL 3.3 internally)
static void DrawRectangleV(Vector2 position, Vector2 size, Color color) static void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{ {
@ -495,4 +368,137 @@ static void TraceLog(int msgType, const char *text, ...)
va_end(args); va_end(args);
//if (msgType == LOG_ERROR) exit(1); //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();
}

View file

@ -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);
}

View file

@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

View file

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

View file

@ -273,7 +273,7 @@ int rlGetVersion(void); // Returns current OpenGL versio
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
void rlglInit(void); // Initialize rlgl (shaders, VAO, VBO...) void rlglInit(void); // Initialize rlgl (shaders, VAO, VBO...)
void rlglClose(void); // De-init rlgl 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) 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 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) unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
void *rlglReadTexturePixels(Texture2D texture); // Read texture pixel data 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) #if defined(RLGL_STANDALONE)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Shaders System Functions (Module: rlgl) // 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 SetDefaultShader(void); // Set default shader to be used in batch draw
void SetModelShader(Model *model, Shader shader); // Link a shader to a model void SetModelShader(Model *model, Shader shader); // Link a shader to a model
int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location 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 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 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 SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
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
void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied)
#endif #endif

View file

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

View file

@ -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! 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 // 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_FORWARD_COMPAT, GL_FALSE); // Fordward Compatibility Hint: Only 3.3 and above!
//glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
} }
if (fullscreen) if (fullscreen)

View file

@ -55,7 +55,9 @@ extern unsigned int whiteTexture;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // 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 GenMeshHeightmap(Image image, Vector3 size);
static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
@ -542,24 +544,19 @@ void DrawGizmo(Vector3 position)
Model LoadModel(const char *fileName) Model LoadModel(const char *fileName)
{ {
Model model = { 0 }; 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); 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 (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
if (mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
else else
{ {
// NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() rlglLoadMesh(&model.mesh); // Upload vertex data to GPU
model = rlglLoadModel(mesh); // Upload vertex data to GPU
model.transform = MatrixIdentity();
// NOTE: Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM model.material = LoadDefaultMaterial();
// 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
} }
return model; return model;
@ -568,22 +565,111 @@ Model LoadModel(const char *fileName)
// Load a 3d model (from vertex data) // Load a 3d model (from vertex data)
Model LoadModelEx(Mesh data) Model LoadModelEx(Mesh data)
{ {
Model model; Model model = { 0 };
// NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() rlglLoadMesh(&data); // Upload vertex data to GPU
model = rlglLoadModel(data); // Upload vertex data to GPU
// NOTE: Vertex data is managed externally, must be deallocated manually model.transform = MatrixIdentity();
model.material = LoadDefaultMaterial();
return model; 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 // Load a heightmap image as a 3d model
// NOTE: model map size is defined in generic units // NOTE: model map size is defined in generic units
Model LoadHeightmap(Image heightmap, Vector3 size) Model LoadHeightmap(Image heightmap, Vector3 size)
{ {
Mesh mesh = GenMeshHeightmap(heightmap, size); Model model = { 0 };
Model model = rlglLoadModel(mesh);
model.mesh = GenMeshHeightmap(heightmap, size);
rlglLoadMesh(&model.mesh);
model.transform = MatrixIdentity();
model.material = LoadDefaultMaterial();
return model; return model;
} }
@ -591,8 +677,14 @@ Model LoadHeightmap(Image heightmap, Vector3 size)
// Load a map image as a 3d model (cubes based) // Load a map image as a 3d model (cubes based)
Model LoadCubicmap(Image cubicmap) Model LoadCubicmap(Image cubicmap)
{ {
Mesh mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f }); Model model = { 0 };
Model model = rlglLoadModel(mesh);
model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f });
rlglLoadMesh(&model.mesh);
model.transform = MatrixIdentity();
model.material = LoadDefaultMaterial();
return model; return model;
} }
@ -603,23 +695,54 @@ void UnloadModel(Model model)
// Unload mesh data // Unload mesh data
free(model.mesh.vertices); free(model.mesh.vertices);
free(model.mesh.texcoords); free(model.mesh.texcoords);
free(model.mesh.normals); if (model.mesh.normals != NULL) free(model.mesh.normals);
free(model.mesh.colors); if (model.mesh.colors != NULL) free(model.mesh.colors);
//if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); // Not used if (model.mesh.tangents != NULL) free(model.mesh.tangents);
//if (model.mesh.tangents != NULL) free(model.mesh.tangents); // Not used if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2);
TraceLog(INFO, "Unloaded model data from RAM (CPU)"); TraceLog(INFO, "Unloaded model data from RAM (CPU)");
rlDeleteBuffers(model.mesh.vboId[0]); // vertex rlDeleteBuffers(model.mesh.vboId[0]); // vertex
rlDeleteBuffers(model.mesh.vboId[1]); // texcoords rlDeleteBuffers(model.mesh.vboId[1]); // texcoords
rlDeleteBuffers(model.mesh.vboId[2]); // normals rlDeleteBuffers(model.mesh.vboId[2]); // normals
//rlDeleteBuffers(model.mesh.vboId[3]); // texcoords2 (NOT USED) rlDeleteBuffers(model.mesh.vboId[3]); // colors
//rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) rlDeleteBuffers(model.mesh.vboId[4]); // tangents
//rlDeleteBuffers(model.mesh.vboId[5]); // colors (NOT USED) rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2
rlDeleteVertexArrays(model.mesh.vaoId); 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 // Link a texture to a model
void SetModelTexture(Model *model, Texture2D texture) 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) #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3)
Mesh mesh; Mesh mesh = { 0 };
int mapX = heightmap.width; int mapX = heightmap.width;
int mapZ = heightmap.height; 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.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
mesh.normals = (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.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 vCounter = 0; // Used to count vertices float by float
int tcCounter = 0; // Used to count texcoords 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); 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; return mesh;
} }
static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
{ {
Mesh mesh; Mesh mesh = { 0 };
Color *cubicmapPixels = GetImageData(cubicmap); 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.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
mesh.normals = (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.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float));
mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char)); // Not used... mesh.colors = NULL;
// 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;
int fCounter = 0; int fCounter = 0;
@ -1100,31 +1215,59 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint)
{ {
Vector3 vScale = { scale, scale, scale }; Vector3 vScale = { scale, scale, scale };
Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint); DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint);
} }
// Draw a model with extended parameters // Draw a model with extended parameters
void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) 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() // Calculate transformation matrix from function parameters
rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, false); // 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) // 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 vScale = { scale, scale, scale };
Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; 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 // 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) 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() // Calculate transformation matrix from function parameters
rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, true); // 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 // Draw a billboard
@ -1742,7 +1885,7 @@ static Mesh LoadOBJ(const char *fileName)
mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float));
mesh.normals = (float *)malloc(mesh.vertexCount*3*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 vCounter = 0; // Used to count vertices float by float
int tcCounter = 0; // Used to count texcoords 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 // 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; 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 // Now we can free temp mid* arrays
free(midVertices); free(midVertices);
@ -1856,3 +1995,163 @@ static Mesh LoadOBJ(const char *fileName)
return mesh; 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;
}

View file

@ -369,12 +369,12 @@ typedef struct BoundingBox {
// Vertex data definning a mesh // Vertex data definning a mesh
typedef struct Mesh { typedef struct Mesh {
int vertexCount; // num vertices int vertexCount; // num vertices
float *vertices; // vertex position (XYZ - 3 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) float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // vertex second texture coordinates (useful for lightmaps) float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // vertex normals (XYZ - 3 components per vertex) float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // vertex tangents (XYZ - 3 components per vertex) float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4)
unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
BoundingBox bounds; // mesh limits defined by min and max points BoundingBox bounds; // mesh limits defined by min and max points
@ -386,11 +386,13 @@ typedef struct Mesh {
typedef struct Shader { typedef struct Shader {
unsigned int id; // Shader program id unsigned int id; // Shader program id
// Variable attributes locations // Vertex attributes locations (default locations)
int vertexLoc; // Vertex attribute location point (vertex shader) int vertexLoc; // Vertex attribute location point (default-location = 0)
int texcoordLoc; // Texcoord attribute location point (vertex shader) int texcoordLoc; // Texcoord attribute location point (default-location = 1)
int normalLoc; // Normal attribute location point (vertex shader) int normalLoc; // Normal attribute location point (default-location = 2)
int colorLoc; // Color attibute location point (vertex shader) 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 // Uniform locations
int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) 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 3d Loading and Drawing Functions (Module: models)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) Model LoadModel(const char *fileName); // Load a 3d model (.OBJ)
Model LoadModelEx(Mesh data); // Load a 3d model (from mesh data) 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 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 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) Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based)
void UnloadModel(Model model); // Unload 3d model from memory void UnloadModel(Model model); // Unload 3d model from memory
void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model 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 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 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 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) 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 // NOTE: This functions are useless when using OpenGL 1.1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations 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 UnloadShader(Shader shader); // Unload a custom shader from memory
void SetDefaultShader(void); // Set default shader to be used in batch draw 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 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 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 SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)

File diff suppressed because it is too large Load diff

View file

@ -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) 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 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 void rlglGenerateMipmaps(Texture2D texture); // Generate mipmap data for selected texture
void rlglLoadMesh(Mesh *mesh); // Upload vertex data into GPU and provided VAO/VBO ids
// NOTE: There is a set of shader related functions that are available to end user, void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires);
// 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);
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates 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) unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
void *rlglReadTexturePixels(Texture2D texture); // Read texture pixel data 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) #if defined(RLGL_STANDALONE)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Shaders System Functions (Module: rlgl) // Shaders System Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1 // NOTE: This functions are useless when using OpenGL 1.1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations 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 UnloadShader(Shader shader); // Unload a custom shader from memory
void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw 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 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 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 SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)