cancel
Showing results for 
Search instead for 
Did you mean: 

Complete "Extended" Mode Modern OpenGL Example (SDK 0.4.3)

tmason101
Honored Guest
Hello,

Thanks to all of the help from the various posters (jherico and nuclear especially) here is a complete "Extended" mode example of using the latest version of the SDK (0.4.3) with Modern OpenGL.

Dependencies:



Tested on Windows but all dependencies and code is cross-platform as far as I can see.

I am sure experts on here can cut this code apart and make it far more efficient but I thought I would give back to those who need help getting started.

Hope someone can figure out why my code below doesn't work in "Direct" mode! But that is for other threads...


Main.h


#ifndef MAIN_H_
#define MAIN_H_

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include <array>

#ifndef OPENGL_INCLUDES_
#define OPENGL_INCLUDES_

#include "GL\glew.h"

#ifndef GLFW_INCLUDES_
#define GLFW_INCLUDES_

#if defined(_WIN32)
#include <Windows.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#elif defined(__linux__)
#include <X11/X.h>
#include <X11/extensions/Xrandr.h>
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif

#include "GLFW\glfw3.h"
#include "GLFW\glfw3native.h"

#endif

#ifndef GLM_INCLUDES_
#define GLM_INCLUDES_

#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

#endif

#ifndef OCULUS_SDK_
#define OCULUS_SDK_

#define OVR_OS_WIN32

#include "OVR_CAPI_GL.h"
#include "Kernel\OVR_Math.h"

#endif

#endif

GLFWwindow* MainWindow;

#ifdef _WIN32

HWND MainWindowWin32Handle = NULL;

#endif

GLint WindowWidth = 1024;
GLint WindowHeight = 768;
GLfloat AspectRatio;

GLulong SizeDivizor = 1;

GLboolean RiftAvailable = false;
GLboolean DirectMode = false;
GLboolean RotateCubes = true;

GLfloat RotationSpeed = 0.001f;
GLfloat RotationDirection = 1.0f;

ovrHmd Main_HMD = NULL;
ovrEyeRenderDesc Main_EyeRenderDesc[2];
ovrRecti Main_EyeRenderViewport[2];
ovrGLConfig Main_HMD_Render_Config;
ovrGLTexture Main_EyeTexture[2];
OVR::Recti Main_HMD_Pos_Res;
ovrFovPort Main_HMD_eyeFov[2];

GLuint Main_HMD_FrameIndex;

OVR::Sizei recommenedLeftEyeSize;
OVR::Sizei recommenedRightEyeSize;
OVR::Sizei finalTextureSize;

GLuint OculusRiftFrameBufferID;
GLuint OculusRiftRenderBufferID;
GLuint OculusRiftDepthBufferID;
GLuint OculusRiftTextureID;

GLuint MainOpenGLShaderProgramID;
GLuint MatricesUniformBlockID;
GLuint MatricesUniformBufferID;

GLuint LightsUniformBlockID;
GLuint LightsUniformBufferID;

GLuint MaterialsUniformBlockID;
GLuint MaterialsUniformBufferID;

glm::mat4 CenterPositionMatrix;
glm::mat4 EyeOrientationMatrix;
glm::mat4 EyePositionMatrix;
glm::mat4 ViewMatrix;
glm::mat4 ViewModelMatrix;
glm::mat4 ProjectionMatrix;
glm::mat4 MVPMatrix;
glm::mat3 NormalMatrix;

class StandardCube;

std::vector<StandardCube> Cubes;

void (*DrawScene)();

int initializeOculusRift();

int initializeGLFWGLEW();

int prepareOpenGL();

int prepareFrameBuffer();

int prepareOculusRiftWindow();

int configureOculusRift();

int configureOculusRiftTracking();

int loadShaders();

int prepareShaderUniforms();

int loadCubes();

int prepareMatrices();

int SetDrawFunctionPointer();

void DrawWindowed();

void DrawOculusRift();

static void GLFWKeyCallback(GLFWwindow* p_Window, GLint p_Key, GLint p_Scancode, GLint p_Action, GLint p_Mods);

static void GLFWWindowResizeCallBack(GLFWwindow* p_Window, GLint width, GLint height);

static void GLFWMouseMovementCallBack(GLFWwindow* p_Window, GLdouble MouseX, GLdouble MouseY);

static void GLFWFramebufferSizeCallback(GLFWwindow* window, GLint width, GLint height);

static void GLFWErrorCallback(GLint error, const char* description);

int main(int argc, char** argv);

#endif



Main.cpp


#include "Main.h"

class StandardCube {

private:

GLfloat* Vertices;
GLfloat* Normals;
GLuint* Indices;

GLuint VAO;

glm::mat4 ModelMatrix;

public:

void LoadIntoOpenGL() {

Vertices = new GLfloat[72]

{
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f
};

Normals = new GLfloat[72] {
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f
};

Indices = new GLuint[36] {0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
8, 9, 10, 10, 11, 8,
12, 13, 14, 14, 15, 12,
16, 17, 18, 18, 19, 16,
20, 21, 22, 22, 23, 20
};

glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

GLuint MeshBufferID;
glGenBuffers(1, &MeshBufferID);
glBindBuffer(GL_ARRAY_BUFFER, MeshBufferID);

GLuint TotalBufferData = (sizeof(GLfloat) * 72) + (sizeof(GLfloat) * 72);

glBufferData(GL_ARRAY_BUFFER, TotalBufferData, NULL, GL_STATIC_DRAW);

glBufferSubData(GL_ARRAY_BUFFER, NULL, sizeof(GLfloat) * 72, Vertices);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glBufferSubData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 72, sizeof(GLfloat) * 72, Normals);

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(GLfloat) * 72));
glEnableVertexAttribArray(1);

GLuint IndexBufferID;
glGenBuffers(1, &IndexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 36, Indices, GL_STATIC_DRAW);

glBindVertexArray(NULL);

ModelMatrix = glm::mat4(1.0f);

}

void DrawMe() {

MVPMatrix = ProjectionMatrix * ViewMatrix * ModelMatrix;
ViewModelMatrix = ViewMatrix * ModelMatrix;
NormalMatrix = glm::transpose(glm::inverse(glm::mat3(MVPMatrix)));

glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

glBufferSubData(GL_UNIFORM_BUFFER, NULL, sizeof(glm::mat4), glm::value_ptr(MVPMatrix));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(ViewModelMatrix));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4) + sizeof(glm::mat4), sizeof(glm::mat3), glm::value_ptr(NormalMatrix));

glBindBuffer(GL_UNIFORM_BUFFER, NULL);

glBindVertexArray(VAO);
glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL, 1);
glBindVertexArray(NULL);

}

void MoveMe(glm::vec3 NewPosition) {

ModelMatrix = glm::translate(ModelMatrix, NewPosition);

}

void RotateMe(GLfloat AmountToRotateBy) {

ModelMatrix = glm::rotate(ModelMatrix, AmountToRotateBy, glm::vec3(0.0f, 1.0f, 0.0f));

}

};

int initializeOculusRift() {

if (!ovr_Initialize()) {

return EXIT_FAILURE;

}

if (!Main_HMD) {

Main_HMD = ovrHmd_Create(0);

if (!Main_HMD)
{

fprintf(stderr, "Oculus Rift not detected.");
RiftAvailable = false;

}
else {

if (Main_HMD->ProductName[0] == '\0')
{

fprintf(stderr, "Rift detected, display not enabled.");
RiftAvailable = false;

}
else {

DirectMode = (Main_HMD->HmdCaps & ovrHmdCap_ExtendDesktop) ? false : true;

Main_HMD_Pos_Res = OVR::Recti(Main_HMD->WindowsPos, Main_HMD->Resolution);

if (DirectMode) {

SizeDivizor = 1;

}

WindowWidth = Main_HMD_Pos_Res.w / SizeDivizor;
WindowHeight = Main_HMD_Pos_Res.h / SizeDivizor;

RiftAvailable = true;

}

}

}

return EXIT_SUCCESS;

}

int initializeGLFWGLEW() {

MainWindow = NULL;

if (!glfwInit())
{

fprintf(stderr, "GLFW failed to initialize.");
glfwTerminate();
return EXIT_FAILURE;

}

/*

Customize this for the OpenGL version you have on your system.

*/

glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

/*

End OpenGL context setup.

*/

glfwSetErrorCallback(GLFWErrorCallback);

if (DirectMode) {

MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Oculus Rift Direct Mode Example", NULL, NULL);

}
else {

if (!RiftAvailable) {

MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Simple OpenGL Example", NULL, NULL);

}
else {

GLint MonitorCount;
GLFWmonitor** GLFW_Monitors = glfwGetMonitors(&MonitorCount);
GLFWmonitor* MonitorToUse;

switch (MonitorCount)
{
case 0:
printf("No monitors found, exiting.\n");
return EXIT_FAILURE;
break;
case 1:
printf("Two monitors expected, found only one, using primary...\n");
MonitorToUse = glfwGetPrimaryMonitor();
break;
case 2:
printf("Two monitors found, using second monitor\n");
MonitorToUse = GLFW_Monitors[1];
break;
default:
printf("More than two monitors found, using second monitor\n");
MonitorToUse = GLFW_Monitors[1];
}

MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Oculus Rift Extended Mode Example", MonitorToUse, NULL);

}

}

if (!MainWindow)
{
fprintf(stderr, "Could not determine OpenGL version; exiting.");
glfwTerminate();
return EXIT_FAILURE;
}

glfwMakeContextCurrent(MainWindow);

glewExperimental = GL_TRUE;
GLenum err = glewInit();

if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return EXIT_FAILURE;

}



glfwSetInputMode(MainWindow, GLFW_STICKY_KEYS, GL_TRUE);

glfwSetKeyCallback(MainWindow, GLFWKeyCallback);
glfwSetWindowSizeCallback(MainWindow, GLFWWindowResizeCallBack);
glfwSetCursorPosCallback(MainWindow, GLFWMouseMovementCallBack);
glfwSetFramebufferSizeCallback(MainWindow, GLFWFramebufferSizeCallback);

glfwSwapBuffers(MainWindow);

glfwPollEvents();

return EXIT_SUCCESS;

}

int prepareOpenGL() {

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_MULTISAMPLE);

return EXIT_SUCCESS;

}

int prepareFrameBuffer() {

if (!RiftAvailable) {

//This process doesn't apply if an Oculus Rift isn't available.

return EXIT_SUCCESS;

}

recommenedLeftEyeSize = ovrHmd_GetFovTextureSize(Main_HMD, ovrEye_Left, Main_HMD->DefaultEyeFov[0], 1.0f);
recommenedRightEyeSize = ovrHmd_GetFovTextureSize(Main_HMD, ovrEye_Right, Main_HMD->DefaultEyeFov[1], 1.0f);

finalTextureSize.w = recommenedLeftEyeSize.w + recommenedRightEyeSize.w;
finalTextureSize.h = std::max(recommenedLeftEyeSize.h, recommenedRightEyeSize.h);

glGenFramebuffers(1, &OculusRiftFrameBufferID);
glBindFramebuffer(GL_FRAMEBUFFER, OculusRiftFrameBufferID);

// The texture we're going to render to...
glGenTextures(1, &OculusRiftTextureID);
// "Bind" the newly created texture : all future texture functions will modify this texture...
glBindTexture(GL_TEXTURE_2D, OculusRiftTextureID);

// Give an empty image to OpenGL (the last "0")
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, finalTextureSize.w, finalTextureSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
// Linear filtering...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Create Depth Buffer...
glGenRenderbuffers(1, &OculusRiftDepthBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, OculusRiftDepthBufferID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, finalTextureSize.w, finalTextureSize.h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, OculusRiftDepthBufferID);

// Set the texture as our colour attachment #0...
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, OculusRiftTextureID, 0);

// Set the list of draw buffers...
GLenum l_GLDrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, l_GLDrawBuffers); // "1" is the size of DrawBuffers

// Check if everything is OK...
GLenum l_Check = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);

if (l_Check != GL_FRAMEBUFFER_COMPLETE)
{
printf("There is a problem with the FBO.\n");
return EXIT_FAILURE;
}

// Unbind...
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

return EXIT_SUCCESS;

}

int prepareFrameBuffer() {

if (!RiftAvailable) {



//This process doesn't apply if an Oculus Rift isn't available.



return EXIT_SUCCESS;

}

recommenedLeftEyeSize = ovrHmd_GetFovTextureSize(Main_HMD, ovrEye_Left, Main_HMD->DefaultEyeFov[0], 1.0f);
recommenedRightEyeSize = ovrHmd_GetFovTextureSize(Main_HMD, ovrEye_Right, Main_HMD->DefaultEyeFov[1], 1.0f);

finalTextureSize.w = recommenedLeftEyeSize.w + recommenedRightEyeSize.w;
finalTextureSize.h = std::max(recommenedLeftEyeSize.h, recommenedRightEyeSize.h);

glGenTextures(1, &OculusRiftTextureID);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OculusRiftTextureID);

GLint MaximumSamples;
glGetIntegerv(GL_MAX_SAMPLES, &MaximumSamples);

glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MaximumSamples,
GL_RGBA, finalTextureSize.w, finalTextureSize.h, false);

glGenFramebuffers(1, &OculusRiftFrameBufferID);
glBindFramebuffer(GL_FRAMEBUFFER, OculusRiftFrameBufferID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, OculusRiftTextureID, 0);

glGenRenderbuffers(1, &OculusRiftRenderBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, OculusRiftRenderBufferID);

glRenderbufferStorageMultisample(GL_RENDERBUFFER, MaximumSamples,
GL_RGBA, finalTextureSize.w, finalTextureSize.h);

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OculusRiftRenderBufferID);

glGenRenderbuffers(1, &OculusRiftDepthBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, OculusRiftDepthBufferID);

glRenderbufferStorageMultisample(GL_RENDERBUFFER, MaximumSamples,
GL_DEPTH24_STENCIL8, finalTextureSize.w, finalTextureSize.h);

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, OculusRiftDepthBufferID);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OculusRiftDepthBufferID);

GLenum DrawBufferStatusCheck_ENUM = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);

if (DrawBufferStatusCheck_ENUM != GL_FRAMEBUFFER_COMPLETE) {
switch (DrawBufferStatusCheck_ENUM)
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
break;
default:
break;
}

glBindRenderbuffer(GL_RENDERBUFFER, NULL);
glBindTexture(GL_TEXTURE_2D, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, NULL);
return EXIT_FAILURE;

}
else {

glBindRenderbuffer(GL_RENDERBUFFER, NULL);
glBindTexture(GL_TEXTURE_2D, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, NULL);
return EXIT_SUCCESS;

}

}

*/

int prepareOculusRiftWindow() {

if (!RiftAvailable) {

//This process doesn't apply if an Oculus Rift isn't available.

return EXIT_SUCCESS;

}

#ifdef _WIN32

if (RiftAvailable) {

MainWindowWin32Handle = glfwGetWin32Window(MainWindow);

if (DirectMode) {

ovrHmd_AttachToWindow(Main_HMD, MainWindowWin32Handle, NULL, NULL);

}

return EXIT_SUCCESS;

}
else {

return EXIT_FAILURE;

}

#endif

}

int configureOculusRift() {

if (!RiftAvailable) {

return EXIT_SUCCESS;

}

Main_HMD_eyeFov[ovrEye_Left] = Main_HMD->DefaultEyeFov[ovrEye_Left];
Main_HMD_eyeFov[ovrEye_Right] = Main_HMD->DefaultEyeFov[ovrEye_Right];

Main_HMD_Render_Config.OGL.Window = MainWindowWin32Handle;

HDC MainHDC = GetDC(Main_HMD_Render_Config.OGL.Window);
Main_HMD_Render_Config.OGL.DC = MainHDC;
Main_HMD_Render_Config.OGL.Header.API = ovrRenderAPI_OpenGL;
Main_HMD_Render_Config.OGL.Header.Multisample = 1;
Main_HMD_Render_Config.OGL.Header.RTSize = OVR::Sizei(Main_HMD->Resolution.w, Main_HMD->Resolution.h);

Main_EyeRenderViewport[ovrEye_Left].Pos = OVR::Vector2i(0, 0);
Main_EyeRenderViewport[ovrEye_Left].Size = OVR::Sizei(finalTextureSize.w / 2, finalTextureSize.h);
Main_EyeRenderViewport[ovrEye_Right].Pos = OVR::Vector2i((finalTextureSize.w + 1) / 2, 0);
Main_EyeRenderViewport[ovrEye_Right].Size = Main_EyeRenderViewport[ovrEye_Left].Size;

Main_EyeTexture[ovrEye_Left].OGL.Header.API = ovrRenderAPI_OpenGL;
Main_EyeTexture[ovrEye_Left].OGL.Header.RenderViewport = Main_EyeRenderViewport[ovrEye_Left];
Main_EyeTexture[ovrEye_Left].OGL.Header.TextureSize = finalTextureSize;
Main_EyeTexture[ovrEye_Left].OGL.TexId = OculusRiftTextureID;
Main_EyeTexture[ovrEye_Left].Texture.Header.API = ovrRenderAPI_OpenGL;
Main_EyeTexture[ovrEye_Left].Texture.Header.RenderViewport = Main_EyeRenderViewport[ovrEye_Left];
Main_EyeTexture[ovrEye_Left].Texture.Header.TextureSize = finalTextureSize;

Main_EyeTexture[ovrEye_Right] = Main_EyeTexture[ovrEye_Left];
Main_EyeTexture[ovrEye_Right].OGL.Header.RenderViewport = Main_EyeRenderViewport[ovrEye_Right];
Main_EyeTexture[ovrEye_Right].Texture.Header.RenderViewport = Main_EyeRenderViewport[ovrEye_Right];

if (!ovrHmd_ConfigureRendering(Main_HMD, &Main_HMD_Render_Config.Config,
ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette |
ovrDistortionCap_TimeWarp | ovrDistortionCap_Overdrive,
Main_HMD_eyeFov,
Main_EyeRenderDesc)) {

return EXIT_FAILURE;

}

ovrHmd_SetEnabledCaps(Main_HMD, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);

return EXIT_SUCCESS;

}

int configureOculusRiftTracking() {

if (!RiftAvailable) {

return EXIT_SUCCESS;

}

if (!ovrHmd_ConfigureTracking(Main_HMD, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position, NULL)) {

return EXIT_FAILURE;

}

return EXIT_SUCCESS;

}

int loadShaders() {

// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

// Compile Vertex Shader
printf("Compiling Vertext Shader.\n\n");
char const * VertexSource = "#version 330 \n\n\
layout(std140) uniform Matrices{\n\
mat4 m_pvm;\n\
mat4 m_viewModel;\n\
mat3 m_normal;\n\
};\n\
layout(std140) uniform Lights{\n\
vec3 l_dir; \n\
};\n\
layout (location=0) in vec4 position;\n\
layout (location=1) in vec3 normal;\n\
\n\
\n\
out Data{\n\
vec3 normal;\n\
vec4 eye;\n\
} DataOut;\n\
\n\
void main() {\n\
\n\
DataOut.normal = normalize(m_normal * normal);\n\
DataOut.eye = -(m_viewModel * position);\n\
\n\
gl_Position = m_pvm * position;\n\
}\n\
\n";

glShaderSource(VertexShaderID, 1, &VertexSource, NULL);
glCompileShader(VertexShaderID);

// Check Vertex Shader

GLint Result = GL_FALSE;
int InfoLogLength;

glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);

if (InfoLogLength > 0){

std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
std::string ErrorMessage = std::string(&VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);

}

printf("Compiling Fragment Shader.\n\n");
char const * FragmentSource = "#version 330\n\
\
layout(std140) uniform Matrices{\n\
mat4 m_pvm;\n\
mat4 m_viewModel;\n\
mat3 m_normal;\n\
};\n\
\
layout(std140) uniform Materials{\n\
vec4 diffuse;\n\
vec4 ambient;\n\
vec4 specular;\n\
vec4 emissive;\n\
float shininess;\n\
int texCount;\n\
};\
\n\
layout(std140) uniform Lights{\n\
vec3 l_dir; \n\
};\
\n\
in Data{\n\
vec3 normal;\n\
vec4 eye;\n\
} DataIn;\n\
\n\
out vec4 colorOut;\
\n\
void main() {\n\
\n\
vec4 spec = vec4(0.0);\n\
\n\
vec3 n = normalize(DataIn.normal);\n\
vec3 e = normalize(vec3(DataIn.eye));\n\
\n\
float intensity = max(dot(n, l_dir), 0.0);\n\
\n\
if (intensity > 0.0) {\n\
vec3 h = normalize(l_dir + e);\n\
\n\
float intSpec = max(dot(h, n), 0.0);\n\
spec = specular * pow(intSpec, shininess);\n\
}\n\
\n\
colorOut = max(intensity * diffuse + spec, ambient);\n\
}";

glShaderSource(FragmentShaderID, 1, &FragmentSource, NULL);
glCompileShader(FragmentShaderID);

// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0){

std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
std::string ErrorMessage = std::string(&FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);

}

// Link the program
printf("Linking shader program.\n\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);

// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0){

std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
std::string ErrorMessage = std::string(&ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);

}

glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);

MainOpenGLShaderProgramID = ProgramID;

return EXIT_SUCCESS;

}

int prepareShaderUniforms() {

glUseProgram(MainOpenGLShaderProgramID);

MatricesUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Matrices");
glUniformBlockBinding(MainOpenGLShaderProgramID, MatricesUniformBlockID, 1);
glGenBuffers(1, &MatricesUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, MatricesUniformBufferID);
GLsizeiptr TotalBufferSize = sizeof(glm::mat4) + sizeof(glm::mat4);
TotalBufferSize += sizeof(glm::mat3);

glBufferData(GL_UNIFORM_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);

LightsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Lights");
glUniformBlockBinding(MainOpenGLShaderProgramID, LightsUniformBlockID, 2);
glGenBuffers(1, &LightsUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, LightsUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, LightsUniformBufferID);

GLfloat LightDirection[3] = {-4.0f, -3.0f, -3.0f};

glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDirection), &LightDirection, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);

MaterialsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Materials");
glUniformBlockBinding(MainOpenGLShaderProgramID, MaterialsUniformBlockID, 3);
glGenBuffers(1, &MaterialsUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, MaterialsUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 3, MaterialsUniformBufferID);

GLfloat Material[18];

//Diffuse
Material[0] = 0.5f;
Material[1] = 0.0f;
Material[2] = 0.0f;
Material[3] = 1.0f;

//Ambient
Material[4] = 0.2f;
Material[5] = 0.2f;
Material[6] = 0.2f;
Material[7] = 1.0f;

//Specular
Material[8] = 1.0f;
Material[9] = 1.0f;
Material[10] = 1.0f;
Material[11] = 1.0f;

//Emissive
Material[12] = 0.0f;
Material[13] = 0.0f;
Material[14] = 0.0f;
Material[15] = 1.0f;

//Shininess
Material[16] = 5.0f;

//Texture Count
Material[17] = 0.0f;

glBufferData(GL_UNIFORM_BUFFER, sizeof(Material), &Material, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);

return EXIT_SUCCESS;

}

int loadCubes() {

StandardCube FrontCube;

FrontCube.LoadIntoOpenGL();

FrontCube.MoveMe(glm::vec3(0.0f, -1.0f, -2.0f));

Cubes.push_back(FrontCube);

return EXIT_SUCCESS;

}

int prepareMatricies() {

AspectRatio = (GLfloat)(WindowWidth) / (GLfloat)(WindowHeight);

ProjectionMatrix = glm::perspective(45.0f, AspectRatio, 1.0f, 1000.0f);

ViewMatrix = glm::lookAt(
glm::vec3(0.0f, 6.0f, 6.0f), // camera is at (4,3,3), in world space - Where the camera is inside world.
glm::vec3(0.0f, 0.0f, -3.0f), // and looks at the origin - What point the camera is looking at inside world.
glm::vec3(0.0f, 1.0f, 0.0f) // head is up(set to 0,1,0) - the direction of up for camera.
);

glViewport(0, 0, WindowWidth, WindowHeight);

return EXIT_SUCCESS;

}

int SetDrawFunctionPointer() {

if (!RiftAvailable) {

DrawScene = DrawWindowed;

}
else {

DrawScene = DrawOculusRift;

}

return EXIT_SUCCESS;

}

void DrawWindowed() {

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

for (auto & C : Cubes) {

if (RotateCubes) {

C.RotateMe(RotationSpeed * RotationDirection);

}

C.DrawMe();

}

glfwSwapBuffers(MainWindow);

glfwPollEvents();

}

void DrawOculusRift() {

ovrFrameTiming Current_Frame = ovrHmd_BeginFrame(Main_HMD, Main_HMD_FrameIndex);

static ovrPosef Main_HMD_eyeRenderPose[2];
static ovrMatrix4f OculusRiftProjection[2];
static ovrMatrix4f OculusRiftView[2];
static OVR::Vector3f Main_HMD_HeadPos(0.0f, 1.6f, -5.0f);
static ovrTrackingState HmdState;

ovrVector3f hmdToEyeViewOffset[2] = { Main_EyeRenderDesc[0].HmdToEyeViewOffset, Main_EyeRenderDesc[1].HmdToEyeViewOffset };
ovrHmd_GetEyePoses(Main_HMD, Main_HMD_FrameIndex, hmdToEyeViewOffset, Main_HMD_eyeRenderPose, &HmdState);

Main_HMD_HeadPos.y = ovrHmd_GetFloat(Main_HMD, OVR_KEY_EYE_HEIGHT, Main_HMD_HeadPos.y);

if (RotateCubes) {

for (auto & C : Cubes) {

C.RotateMe(RotationSpeed * RotationDirection);

}

}

glBindFramebuffer(GL_FRAMEBUFFER, OculusRiftFrameBufferID);

glUseProgram(MainOpenGLShaderProgramID);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

for (GLint CurrentEyeIndex = 0; CurrentEyeIndex < ovrEye_Count; ++CurrentEyeIndex)
{

ovrEyeType CurrentEye = Main_HMD->EyeRenderOrder[CurrentEyeIndex];

glViewport(
Main_EyeTexture[CurrentEyeIndex].Texture.Header.RenderViewport.Pos.x,
Main_EyeTexture[CurrentEyeIndex].Texture.Header.RenderViewport.Pos.y,
Main_EyeTexture[CurrentEyeIndex].Texture.Header.RenderViewport.Size.w,
Main_EyeTexture[CurrentEyeIndex].Texture.Header.RenderViewport.Size.h
);

OculusRiftProjection[CurrentEyeIndex] = ovrMatrix4f_Projection(Main_EyeRenderDesc[CurrentEyeIndex].Fov,
0.1f, 1000.0f, true);

for (int o = 0; o < 4; o++) {
for (int i = 0; i < 4; i++) {
ProjectionMatrix[o][i] = OculusRiftProjection[CurrentEyeIndex].M[o][i];
}
}

ProjectionMatrix = glm::transpose(ProjectionMatrix);

CenterPositionMatrix = glm::translate(glm::mat4(1.0f),
-glm::vec3(Main_HMD_eyeRenderPose[CurrentEyeIndex].Position.x,
Main_HMD_eyeRenderPose[CurrentEyeIndex].Position.y,
Main_HMD_eyeRenderPose[CurrentEyeIndex].Position.z));

EyeOrientationMatrix = glm::toMat4(glm::quat(
Main_HMD_eyeRenderPose[CurrentEyeIndex].Orientation.w,
-Main_HMD_eyeRenderPose[CurrentEyeIndex].Orientation.x,
-Main_HMD_eyeRenderPose[CurrentEyeIndex].Orientation.y,
-Main_HMD_eyeRenderPose[CurrentEyeIndex].Orientation.z
));

EyePositionMatrix = glm::translate(glm::mat4(1.0f),
glm::vec3(
Main_EyeRenderDesc[CurrentEyeIndex].HmdToEyeViewOffset.x,
Main_EyeRenderDesc[CurrentEyeIndex].HmdToEyeViewOffset.y,
Main_EyeRenderDesc[CurrentEyeIndex].HmdToEyeViewOffset.z
));

ViewMatrix = EyePositionMatrix * EyeOrientationMatrix * CenterPositionMatrix;

for (auto & C : Cubes) {

C.DrawMe();

}

}

ovrHmd_EndFrame(Main_HMD, Main_HMD_eyeRenderPose, &Main_EyeTexture[0].Texture);

Main_HMD_FrameIndex += 1;

glfwPollEvents();

}

static void GLFWKeyCallback(GLFWwindow* p_Window, GLint p_Key, GLint p_Scancode, GLint p_Action, GLint p_Mods) {

if (RiftAvailable) {

ovrHSWDisplayState l_HasWarningState;

ovrHmd_GetHSWDisplayState(Main_HMD, &l_HasWarningState);

if (l_HasWarningState.Displayed) {

ovrHmd_DismissHSWDisplay(Main_HMD);

}

}

if (p_Key == GLFW_KEY_ESCAPE && p_Action == GLFW_PRESS) {

glfwSetWindowShouldClose(p_Window, GL_TRUE);
}

if (p_Key == GLFW_KEY_O && p_Action == GLFW_PRESS) {

glClearColor(0.2f, 0.1f, 0.3f, 1.0f);

}

if (p_Key == GLFW_KEY_I && p_Action == GLFW_PRESS) {

glClearColor(1.0f, 0.5f, 0.5f, 1.0f);

}

if (p_Key == GLFW_KEY_R && p_Action == GLFW_PRESS) {

RotateCubes = !RotateCubes;

}

if (p_Key == GLFW_KEY_PAGE_UP && (p_Action == GLFW_PRESS || p_Action == GLFW_REPEAT)) {

RotationSpeed += 0.001f;

}

if (p_Key == GLFW_KEY_PAGE_DOWN && (p_Action == GLFW_PRESS || p_Action == GLFW_REPEAT)) {

RotationSpeed -= 0.001f;

if (RotationSpeed < 0.001f) {

RotationSpeed = 0.001f;

}

}

if (p_Key == GLFW_KEY_SPACE && p_Action == GLFW_PRESS) {

RotationDirection *= -1.0f;

}

}

static void GLFWWindowResizeCallBack(GLFWwindow* p_Window, GLint width, GLint height) {

//CurrentGLFWApplication->WindowResizeCallBack(p_Window, width, height);

}

static void GLFWMouseMovementCallBack(GLFWwindow* p_Window, GLdouble MouseX, GLdouble MouseY) {

//CurrentGLFWApplication->MouseMovementCallBack(p_Window, MouseX, MouseY);

}

static void GLFWFramebufferSizeCallback(GLFWwindow* window, GLint width, GLint height)
{
AspectRatio = (GLfloat)(width) / (GLfloat)(height);

ProjectionMatrix = glm::perspective(45.0f, AspectRatio, 0.1f, 1000.0f);

glViewport(0, 0, width, height);

}

static void GLFWErrorCallback(GLint error, const char* description)
{

fputs(description, stderr);

}

int main(int argc, char** argv) {

if (initializeOculusRift() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (initializeGLFWGLEW() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareOpenGL() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareFrameBuffer() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareOculusRiftWindow() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (configureOculusRift() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}



if (configureOculusRiftTracking() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (loadShaders() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareShaderUniforms() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (loadCubes() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareMatricies() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (SetDrawFunctionPointer() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

while (!glfwWindowShouldClose(MainWindow))

{

DrawScene();

}

exit(EXIT_SUCCESS);

}
29 REPLIES 29

dudeman21
Honored Guest
glGetError() should totally be called in a loop.

https://www.opengl.org/sdk/docs/man/html/glGetError.xhtml

The relevant part:
To allow for distributed implementations, there may be several error flags. If any single error flag has recorded an error, the value of that flag is returned and that flag is reset to GL_NO_ERROR when glGetError is called. If more than one flag has recorded an error, glGetError returns and clears an arbitrary error flag value. Thus, glGetError should always be called in a loop, until it returns GL_NO_ERROR, if all error flags are to be reset.

Anonymous
Not applicable
"tmason101" wrote:
HOWEVER, with "Direct" mode the Rift itself never activates. As mentioned, the tracking and orientation works but the light stays orange on the Rift.

Is your rift working with other demos in direct mode ?

tmason101
Honored Guest
"ockiller" wrote:
"tmason101" wrote:
HOWEVER, with "Direct" mode the Rift itself never activates. As mentioned, the tracking and orientation works but the light stays orange on the Rift.

Is your rift working with other demos in direct mode ?


All of my DirectX demos work; nada on OpenGL.

I would really like to know if anyone has tried the code I wrote above and whether THAT worked in "Direct" mode or is it simply folks own projects that worked in Direct Mode in OpenGL.

I am not implying my project is better in any way; I just need to know whether it is my code that I am writing or my machine.

Here's to hoping someone tried the OP code and if that worked in Direct Mode...

jherico
Adventurer
I'll try it when I get home.

jherico
Adventurer
I'm able to get the provided demo running, but there's a few issues.


if (UseApplicationWindowFrame) {
SizeDivizor = 2;
}


For DirectX, there doesn't seem to be any relationship between the onscreen window size and the actual Rift resolution. However for OpenGL, at least on my setup, the GLFW window must be of the same resolution as the Rift, or the image gets cut off. Changing SizeDivizor here to 1 solved the problem.

If I disable rift mode, I actually don't get any rendering output.

Inside your per-eye loop you're doing this:



for (auto & C : Cubes) {
if (RotateCubes) {
C.RotateMe(0.001f);
}
C.DrawMe();
}


This is an incredibly bad idea. You need to divide your state modification from your rendering. In particular this bit of code being inside the per-eye loop means that the left and right eyes will see different rotations of the a given object. Updating state should happen once per frame while rendering should happen twice per frame in Rift mode and once per frame in non-Rift mode.

I don't get the point of calling glDrawElementsInstanced to draw one instance.

jherico
Adventurer
I've created my own version of this which uses classes to break down the responsibilities and hopefully show more clearly exactly what the interactions with the Oculus API's are. It's available as a Gist on Github.


#include <iostream>
#include <string>
#include <memory>
#include <exception>

///////////////////////////////////////////////////////////////////////////////
//
// GLM is a C++ math library meant to mirror the syntax of GLSL
//

#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

// Import the most commonly used types into the default namespace
using glm::ivec3;
using glm::ivec2;
using glm::uvec2;
using glm::mat3;
using glm::mat4;
using glm::vec2;
using glm::vec3;
using glm::vec4;
using glm::quat;

///////////////////////////////////////////////////////////////////////////////
//
// GLEW gives cross platform access to OpenGL 3.x+ functionality.
//

#include <GL/glew.h>

//////////////////////////////////////////////////////////////////////
//
// OGLplus is a set of wrapper classes for giving OpenGL a more object
// oriented interface
//

#pragma warning( disable : 4068 4244 4267 4065)
#include <oglplus/config/gl.hpp>
#include <oglplus/all.hpp>
#include <oglplus/interop/glm.hpp>
#include <oglplus/bound/texture.hpp>
#include <oglplus/bound/framebuffer.hpp>
#include <oglplus/bound/renderbuffer.hpp>
#include <oglplus/bound/buffer.hpp>
#pragma warning( default : 4068 4244 4267 4065)

// A wrapper for constructing and using a
struct FboWrapper {
oglplus::Framebuffer fbo;
oglplus::Texture color;
oglplus::Renderbuffer depth;

void init(const glm::uvec2 & size) {
using namespace oglplus;
Context::Bound(Texture::Target::_2D, color)
.MinFilter(TextureMinFilter::Linear)
.MagFilter(TextureMagFilter::Linear)
.WrapS(TextureWrap::ClampToEdge)
.WrapT(TextureWrap::ClampToEdge)
.Image2D(
0, PixelDataInternalFormat::RGBA8,
size.x, size.y,
0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
);

Context::Bound(Renderbuffer::Target::Renderbuffer, depth)
.Storage(
PixelDataInternalFormat::DepthComponent,
size.x, size.y
);

Context::Bound(Framebuffer::Target::Draw, fbo)
.AttachTexture(FramebufferAttachment::Color, color, 0)
.AttachRenderbuffer(FramebufferAttachment::Depth, depth)
.Complete();
}
};

typedef std::shared_ptr<FboWrapper> fbo_wrapper_ptr;

static const GLuint CUBE_VERTEX_COUNT = 6 * 2 * 3;

static const GLfloat CUBE_VERTEX_DATA[8][3] = {
{ -0.5f, -0.5f, +0.5f },
{ -0.5f, -0.5f, -0.5f },
{ -0.5f, +0.5f, -0.5f },
{ -0.5f, +0.5f, +0.5f },
{ +0.5f, -0.5f, +0.5f },
{ +0.5f, -0.5f, -0.5f },
{ +0.5f, +0.5f, -0.5f },
{ +0.5f, +0.5f, +0.5f }
};

static const GLfloat CUBE_VERTICES[CUBE_VERTEX_COUNT * 3] = {
CUBE_VERTEX_DATA[0][0], CUBE_VERTEX_DATA[0][1], CUBE_VERTEX_DATA[0][2],
CUBE_VERTEX_DATA[2][0], CUBE_VERTEX_DATA[2][1], CUBE_VERTEX_DATA[2][2],
CUBE_VERTEX_DATA[1][0], CUBE_VERTEX_DATA[1][1], CUBE_VERTEX_DATA[1][2],
CUBE_VERTEX_DATA[0][0], CUBE_VERTEX_DATA[0][1], CUBE_VERTEX_DATA[0][2],
CUBE_VERTEX_DATA[3][0], CUBE_VERTEX_DATA[3][1], CUBE_VERTEX_DATA[3][2],
CUBE_VERTEX_DATA[2][0], CUBE_VERTEX_DATA[2][1], CUBE_VERTEX_DATA[2][2],
CUBE_VERTEX_DATA[0][0], CUBE_VERTEX_DATA[0][1], CUBE_VERTEX_DATA[0][2],
CUBE_VERTEX_DATA[1][0], CUBE_VERTEX_DATA[1][1], CUBE_VERTEX_DATA[1][2],
CUBE_VERTEX_DATA[4][0], CUBE_VERTEX_DATA[4][1], CUBE_VERTEX_DATA[4][2],
CUBE_VERTEX_DATA[1][0], CUBE_VERTEX_DATA[1][1], CUBE_VERTEX_DATA[1][2],
CUBE_VERTEX_DATA[5][0], CUBE_VERTEX_DATA[5][1], CUBE_VERTEX_DATA[5][2],
CUBE_VERTEX_DATA[4][0], CUBE_VERTEX_DATA[4][1], CUBE_VERTEX_DATA[4][2],
CUBE_VERTEX_DATA[1][0], CUBE_VERTEX_DATA[1][1], CUBE_VERTEX_DATA[1][2],
CUBE_VERTEX_DATA[2][0], CUBE_VERTEX_DATA[2][1], CUBE_VERTEX_DATA[2][2],
CUBE_VERTEX_DATA[5][0], CUBE_VERTEX_DATA[5][1], CUBE_VERTEX_DATA[5][2],
CUBE_VERTEX_DATA[2][0], CUBE_VERTEX_DATA[2][1], CUBE_VERTEX_DATA[2][2],
CUBE_VERTEX_DATA[6][0], CUBE_VERTEX_DATA[6][1], CUBE_VERTEX_DATA[6][2],
CUBE_VERTEX_DATA[5][0], CUBE_VERTEX_DATA[5][1], CUBE_VERTEX_DATA[5][2],
CUBE_VERTEX_DATA[4][0], CUBE_VERTEX_DATA[4][1], CUBE_VERTEX_DATA[4][2],
CUBE_VERTEX_DATA[5][0], CUBE_VERTEX_DATA[5][1], CUBE_VERTEX_DATA[5][2],
CUBE_VERTEX_DATA[6][0], CUBE_VERTEX_DATA[6][1], CUBE_VERTEX_DATA[6][2],
CUBE_VERTEX_DATA[4][0], CUBE_VERTEX_DATA[4][1], CUBE_VERTEX_DATA[4][2],
CUBE_VERTEX_DATA[6][0], CUBE_VERTEX_DATA[6][1], CUBE_VERTEX_DATA[6][2],
CUBE_VERTEX_DATA[7][0], CUBE_VERTEX_DATA[7][1], CUBE_VERTEX_DATA[7][2],
CUBE_VERTEX_DATA[2][0], CUBE_VERTEX_DATA[2][1], CUBE_VERTEX_DATA[2][2],
CUBE_VERTEX_DATA[3][0], CUBE_VERTEX_DATA[3][1], CUBE_VERTEX_DATA[3][2],
CUBE_VERTEX_DATA[7][0], CUBE_VERTEX_DATA[7][1], CUBE_VERTEX_DATA[7][2],
CUBE_VERTEX_DATA[2][0], CUBE_VERTEX_DATA[2][1], CUBE_VERTEX_DATA[2][2],
CUBE_VERTEX_DATA[7][0], CUBE_VERTEX_DATA[7][1], CUBE_VERTEX_DATA[7][2],
CUBE_VERTEX_DATA[6][0], CUBE_VERTEX_DATA[6][1], CUBE_VERTEX_DATA[6][2],
CUBE_VERTEX_DATA[0][0], CUBE_VERTEX_DATA[0][1], CUBE_VERTEX_DATA[0][2],
CUBE_VERTEX_DATA[4][0], CUBE_VERTEX_DATA[4][1], CUBE_VERTEX_DATA[4][2],
CUBE_VERTEX_DATA[3][0], CUBE_VERTEX_DATA[3][1], CUBE_VERTEX_DATA[3][2],
CUBE_VERTEX_DATA[3][0], CUBE_VERTEX_DATA[3][1], CUBE_VERTEX_DATA[3][2],
CUBE_VERTEX_DATA[4][0], CUBE_VERTEX_DATA[4][1], CUBE_VERTEX_DATA[4][2],
CUBE_VERTEX_DATA[7][0], CUBE_VERTEX_DATA[7][1], CUBE_VERTEX_DATA[7][2]
};

static const GLfloat CUBE_NORMALS[6][3] = {
{ -1.0f, 0.0f, 0.0f },
{ 0.0f, -1.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f },
{ 1.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f }
};

static const char * VERTEX_SHADER =
"#version 330\n"
"uniform mat4 ProjectionMatrix, CameraMatrix;"
"in vec4 Position;"
"in vec3 Normal;"
"out vec3 vertNormal;"
"void main(void)"
"{"
" vertNormal = Normal;"
" gl_Position = ProjectionMatrix *"
" CameraMatrix *"
" Position;"
"}";

static const char * FRAGMENT_SHADER =
"#version 330\n"
"in vec3 vertNormal;"
"out vec4 fragColor;"
"void main(void)"
"{"
" fragColor = vec4(abs(vertNormal), 1.0);"
"}";

// a class for encapsulating building and rendering an RGB cube
struct ColorCubeScene {

// Program
oglplus::Program prog;

// A vertex array object for the rendered cube
oglplus::VertexArray cube;

// VBOs for the cube's vertices and normals
oglplus::Buffer verts;
oglplus::Buffer normals;

public:
ColorCubeScene() {
using namespace oglplus;
Context::ClearColor(0.2f, 0.2f, 0.2f, 0.0f);
Context::ClearDepth(1.0f);
Context::Enable(Capability::DepthTest);
// attach the shaders to the program
prog.AttachShader(VertexShader().Source(GLSLSource(std::string(VERTEX_SHADER))).Compile());
prog.AttachShader(FragmentShader().Source(GLSLSource(std::string(FRAGMENT_SHADER))).Compile());

// link and use it
prog.Link();
prog.Use();

// bind the VAO for the cube
cube.Bind();

// bind the VBO for the cube vertices
verts.Bind(Buffer::Target::Array);
// upload the data
Buffer::Data(
Buffer::Target::Array,
CUBE_VERTEX_COUNT * 3,
CUBE_VERTICES
);

// setup the vertex attribs array for the vertices
VertexArrayAttrib vert_attr(prog, "Position");
vert_attr.Setup<Vec3f>();
vert_attr.Enable();
GLfloat cube_normals[CUBE_VERTEX_COUNT * 3];
for (GLuint f = 0; f != 6; ++f)
for (GLuint v = 0; v != 6; ++v)
for (GLuint ci = 0; ci != 3; ++ci)
cube_normals[(f * 6 + v) * 3 + ci] = CUBE_NORMALS[f][ci];
// bind the VBO for the cube normals
normals.Bind(Buffer::Target::Array);
// upload the data
Buffer::Data(
Buffer::Target::Array,
CUBE_VERTEX_COUNT * 3,
cube_normals
);
// setup the vertex attribs array for the vertices
VertexArrayAttrib normal_attr(prog, "Normal");
normal_attr.Setup<Vec3f>();
normal_attr.Enable();
}

virtual void render(const mat4 & projection, const mat4 & modelview) {
using namespace oglplus;
prog.Use();
Uniform<mat4>(prog, "CameraMatrix").Set(modelview);
Uniform<mat4>(prog, "ProjectionMatrix").Set(projection);

cube.Bind();
Context::DrawArrays(PrimitiveType::Triangles, 0, 6 * 2 * 3);
}
};

//////////////////////////////////////////////////////////////////////
//
// The OVR types header contains the OS detection macros:
// OVR_OS_WIN32, OVR_OS_MAC, OVR_OS_LINUX (and others)
//

#include <Kernel/OVR_Types.h>

#define FAIL(X) throw std::runtime_error(X)

#if defined(OVR_OS_WIN32)
#define ON_WINDOWS(runnable) runnable()
#define NOT_ON_WINDOWS(runnable)
#else
#define ON_WINDOWS(runnable)
#define NOT_ON_WINDOWS(runnable) runnable()
#endif

#if defined(OVR_OS_MAC)
#define ON_MAC(runnable) runnable()
#define NOT_ON_MAC(runnable)
#else
#define ON_MAC(runnable)
#define NOT_ON_MAC(runnable) runnable()
#endif

#if defined(OVR_OS_LINUX)
#define ON_LINUX(runnable) runnable()
#define NOT_ON_LINUX(runnable)
#else
#define ON_LINUX(runnable)
#define NOT_ON_LINUX(runnable) runnable()
#endif

#ifdef OVR_OS_WIN32
#define MAIN_DECL int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
#else
#define MAIN_DECL int main(int argc, char ** argv)
#endif

//////////////////////////////////////////////////////////////////////
//
// GLFW provides cross platform window creation
//

#include <GLFW/glfw3.h>

namespace glfw {
inline uvec2 getSize(GLFWmonitor * monitor) {
const GLFWvidmode * mode = glfwGetVideoMode(monitor);
return uvec2(mode->width, mode->height);
}

inline ivec2 getPosition(GLFWmonitor * monitor) {
ivec2 result;
glfwGetMonitorPos(monitor, &result.x, &result.y);
return result;
}

inline ivec2 getSecondaryScreenPosition(const uvec2 & size) {
GLFWmonitor * primary = glfwGetPrimaryMonitor();
int monitorCount;
GLFWmonitor ** monitors = glfwGetMonitors(&monitorCount);
GLFWmonitor * best = nullptr;
uvec2 bestSize;
for (int i = 0; i < monitorCount; ++i) {
GLFWmonitor * cur = monitors[i];
if (cur == primary) {
continue;
}
uvec2 curSize = getSize(cur);
if (best == nullptr || (bestSize.x < curSize.x && bestSize.y < curSize.y)) {
best = cur;
bestSize = curSize;
}
}
if (nullptr == best) {
best = primary;
bestSize = getSize(best);
}
ivec2 pos = getPosition(best);
if (bestSize.x > size.x) {
pos.x += (bestSize.x - size.x) / 2;
}

if (bestSize.y > size.y) {
pos.y += (bestSize.y - size.y) / 2;
}

return pos;
}

inline GLFWmonitor * getMonitorAtPosition(const ivec2 & position) {
int count;
GLFWmonitor ** monitors = glfwGetMonitors(&count);
for (int i = 0; i < count; ++i) {
ivec2 candidatePosition;
glfwGetMonitorPos(monitors[i], &candidatePosition.x, &candidatePosition.y);
if (candidatePosition == position) {
return monitors[i];
}
}
return nullptr;
}

inline GLFWwindow * createWindow(const uvec2 & size, const ivec2 & position = ivec2(INT_MIN)) {
GLFWwindow * window = glfwCreateWindow(size.x, size.y, "glfw", nullptr, nullptr);
if (!window) {
FAIL("Unable to create rendering window");
}
if ((position.x > INT_MIN) && (position.y > INT_MIN)) {
glfwSetWindowPos(window, position.x, position.y);
}
return window;
}

inline GLFWwindow * createWindow(int w, int h, int x = INT_MIN, int y = INT_MIN) {
return createWindow(uvec2(w, h), ivec2(x, y));
}

inline GLFWwindow * createFullscreenWindow(const uvec2 & size, GLFWmonitor * targetMonitor) {
return glfwCreateWindow(size.x, size.y, "glfw", targetMonitor, nullptr);
}

inline GLFWwindow * createSecondaryScreenWindow(const uvec2 & size) {
return createWindow(size, glfw::getSecondaryScreenPosition(size));
}
}

// A class to encapsulate using GLFW to handle input and render a scene
class GlfwApp {
uvec2 windowSize;
ivec2 windowPosition;
GLFWwindow * window{ nullptr };

protected:
oglplus::Context gl;
unsigned int frame{ 0 };

public:
GlfwApp() {
// Initialize the GLFW system for creating and positioning windows
if (!glfwInit()) {
FAIL("Failed to initialize GLFW");
}
glfwSetErrorCallback(ErrorCallback);
}

virtual ~GlfwApp() {
if (nullptr != window) {
glfwDestroyWindow(window);
}
glfwTerminate();
}

virtual int run() {
preCreate();

window = createRenderingTarget(windowSize, windowPosition);

if (!window) {
std::cout << "Unable to create OpenGL window" << std::endl;
return -1;
}

postCreate();

initGl();

while (!glfwWindowShouldClose(window)) {
++frame;
glfwPollEvents();
update();
draw();
finishFrame();
}

return 0;
}


protected:
virtual GLFWwindow * createRenderingTarget(uvec2 & size, ivec2 & pos) = 0;

virtual void draw() = 0;

void preCreate() {
glfwWindowHint(GLFW_DEPTH_BITS, 16);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Without this line we get
// FATAL (86): NSGL: The targeted version of OS X only supports OpenGL 3.2 and later versions if they are forward-compatible
ON_MAC([]{
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
});
#ifdef DEBUG_BUILD
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
#endif
}

void postCreate() {
glfwSetWindowUserPointer(window, this);
glfwSetKeyCallback(window, KeyCallback);
glfwSetMouseButtonCallback(window, MouseButtonCallback);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);

// Initialize the OpenGL bindings
// For some reason we have to set this experminetal flag to properly
// init GLEW if we use a core context.
glewExperimental = GL_TRUE;
if (0 != glewInit()) {
FAIL("Failed to initialize GLEW");
}
}

virtual void initGl() {
glDisable(GL_DITHER);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
}

virtual void finishFrame() {
glfwSwapBuffers(window);
}

virtual void destroyWindow() {
glfwSetKeyCallback(window, nullptr);
glfwSetMouseButtonCallback(window, nullptr);
glfwDestroyWindow(window);
}

virtual void onKey(int key, int scancode, int action, int mods) {
if (GLFW_PRESS != action) {
return;
}

switch (key) {
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, 1);
return;
}
}

virtual void update() { }

virtual void onMouseButton(int button, int action, int mods) { }

protected:
virtual void viewport(const ivec2 & pos, const uvec2 & size) {
gl.Viewport(pos.x, pos.y, size.x, size.y);
}

private:

static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
GlfwApp * instance = (GlfwApp *)glfwGetWindowUserPointer(window);
instance->onKey(key, scancode, action, mods);
}

static void MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {
GlfwApp * instance = (GlfwApp *)glfwGetWindowUserPointer(window);
instance->onMouseButton(button, action, mods);
}

static void ErrorCallback(int error, const char* description) {
FAIL(description);
}
};

#if defined(OVR_OS_WIN32)
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#elif defined(OVR_OS_MAC)
#define GLFW_EXPOSE_NATIVE_COCOA
#define GLFW_EXPOSE_NATIVE_NSGL
#elif defined(OVR_OS_LINUX)
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif

// For some interaction with the Oculus SDK we'll need the native
// window handle
#include <GLFW/glfw3native.h>


//////////////////////////////////////////////////////////////////////
//
// The Oculus VR C API provides access to information about the HMD
// and SDK based distortion.
//
#include <OVR_CAPI_GL.h>

// Convenience method for looping over each eye with a lambda
template <typename Function>
void for_each_eye(Function function) {
for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
eye < ovrEyeType::ovrEye_Count;
eye = static_cast<ovrEyeType>(eye + 1)) {
function(eye);
}
}

namespace ovr {
inline mat4 toGlm(const ovrMatrix4f & om) {
return glm::transpose(glm::make_mat4(&om.M[0][0]));
}

inline mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
}

inline vec3 toGlm(const ovrVector3f & ov) {
return glm::make_vec3(&ov.x);
}

inline vec2 toGlm(const ovrVector2f & ov) {
return glm::make_vec2(&ov.x);
}

inline uvec2 toGlm(const ovrSizei & ov) {
return uvec2(ov.w, ov.h);
}

inline quat toGlm(const ovrQuatf & oq) {
return glm::make_quat(&oq.x);
}

inline mat4 toGlm(const ovrPosef & op) {
mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
mat4 translation = glm::translate(mat4(), ovr::toGlm(op.Position));
return translation * orientation;
}

inline ovrMatrix4f fromGlm(const mat4 & m) {
ovrMatrix4f result;
mat4 transposed(glm::transpose(m));
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
return result;
}

inline ovrVector3f fromGlm(const vec3 & v) {
ovrVector3f result;
result.x = v.x;
result.y = v.y;
result.z = v.z;
return result;
}

inline ovrVector2f fromGlm(const vec2 & v) {
ovrVector2f result;
result.x = v.x;
result.y = v.y;
return result;
}

inline ovrSizei fromGlm(const uvec2 & v) {
ovrSizei result;
result.w = v.x;
result.h = v.y;
return result;
}

inline ovrQuatf fromGlm(const quat & q) {
ovrQuatf result;
result.x = q.x;
result.y = q.y;
result.z = q.z;
result.w = q.w;
return result;
}
}

class RiftManagerApp {
protected:
ovrHmd hmd;

uvec2 hmdNativeResolution;
ivec2 hmdDesktopPosition;

public:
RiftManagerApp(ovrHmdType defaultHmdType = ovrHmd_DK2) {
hmd = ovrHmd_Create(0);
if (nullptr == hmd) {
hmd = ovrHmd_CreateDebug(defaultHmdType);
hmdDesktopPosition = ivec2(100, 100);
}
else {
hmdDesktopPosition = ivec2(hmd->WindowsPos.x, hmd->WindowsPos.y);
}
hmdNativeResolution = ivec2(hmd->Resolution.w, hmd->Resolution.h);
}

virtual ~RiftManagerApp() {
ovrHmd_Destroy(hmd);
hmd = nullptr;
}

int getEnabledCaps() {
return ovrHmd_GetEnabledCaps(hmd);
}

void enableCaps(int caps) {
ovrHmd_SetEnabledCaps(hmd, getEnabledCaps() | caps);
}

void toggleCaps(ovrHmdCaps cap) {
if (cap & getEnabledCaps()) {
disableCaps(cap);
}
else {
enableCaps(cap);
}
}

void disableCaps(int caps) {
ovrHmd_SetEnabledCaps(hmd, getEnabledCaps() & ~caps);
}
};

/**
A class that takes care of the basic duties of putting an OpenGL
window on the desktop in the correct position so that it's visible
through the Rift.
*/
class RiftGlfwApp : public GlfwApp, public RiftManagerApp {

public:
RiftGlfwApp() {
}

virtual ~RiftGlfwApp() {
}


virtual GLFWwindow * createRenderingTarget(uvec2 & size, ivec2 & pos) {
size = hmdNativeResolution;
pos = hmdDesktopPosition;

bool directHmdMode = false;
ON_WINDOWS([&]{
directHmdMode = (0 == (ovrHmdCap_ExtendDesktop & ovrHmd_GetEnabledCaps(hmd)));
});

GLFWwindow * result;
if (directHmdMode) {
// In direct mode, try to put the output window on a secondary screen
// (for easier debugging, assuming your dev environment is on the primary)
result = glfw::createSecondaryScreenWindow(size);
} else {
glfwWindowHint(GLFW_DECORATED, 0);
result = glfw::createWindow(size, pos);
}

ON_WINDOWS([&]{
if (directHmdMode) {
// If we're in direct mode, attach to the window
ovrHmd_AttachToWindow(hmd, glfwGetWin32Window(result), nullptr, nullptr);
}
});

return result;
}
};

class RiftApp : public RiftGlfwApp {
public:

protected:
ovrTexture eyeTextures[2];
ovrVector3f eyeOffsets[2];

private:
ovrEyeRenderDesc eyeRenderDescs[2];
mat4 projections[2];
ovrPosef eyePoses[2];
ovrEyeType currentEye;
fbo_wrapper_ptr eyeFbos[2];


public:

RiftApp() {
if (!ovrHmd_ConfigureTracking(hmd,
ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0)) {
FAIL("Could not attach to sensor device");
}

memset(eyeTextures, 0, 2 * sizeof(ovrGLTexture));

for_each_eye([&](ovrEyeType eye){
ovrSizei eyeTextureSize = ovrHmd_GetFovTextureSize(hmd, eye, hmd->MaxEyeFov[eye], 1.0f);
ovrTextureHeader & eyeTextureHeader = eyeTextures[eye].Header;
eyeTextureHeader.TextureSize = eyeTextureSize;
eyeTextureHeader.RenderViewport.Size = eyeTextureSize;
eyeTextureHeader.API = ovrRenderAPI_OpenGL;
});
}

virtual ~RiftApp() {
//ovrHmd_StopSensor(hmd);
}

protected:
virtual void initGl() {
RiftGlfwApp::initGl();

ovrGLConfig cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
cfg.OGL.Header.RTSize = ovr::fromGlm(hmdNativeResolution);
cfg.OGL.Header.Multisample = 0;

int distortionCaps = 0
| ovrDistortionCap_Vignette
| ovrDistortionCap_Chromatic
| ovrDistortionCap_TimeWarp
;

int configResult = ovrHmd_ConfigureRendering(hmd, &cfg.Config,
distortionCaps, hmd->MaxEyeFov, eyeRenderDescs);


for_each_eye([&](ovrEyeType eye){
const ovrEyeRenderDesc & erd = eyeRenderDescs[eye];
ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, 0.01f, 100000.0f, true);
projections[eye] = ovr::toGlm(ovrPerspectiveProjection);
eyeOffsets[eye] = erd.HmdToEyeViewOffset;

// Allocate the frameBuffer that will hold the scene, and then be
// re-rendered to the screen with distortion
auto & eyeTextureHeader = eyeTextures[eye];
eyeFbos[eye] = fbo_wrapper_ptr(new FboWrapper());
eyeFbos[eye]->init(ovr::toGlm(eyeTextureHeader.Header.TextureSize));
// Get the actual OpenGL texture ID
((ovrGLTexture&)eyeTextureHeader).OGL.TexId = oglplus::GetName(eyeFbos[eye]->color);
});
}


// Override the base class to prevent the swap buffer call, because OVR does it in end frame
virtual void finishFrame() {
}

virtual void onKey(int key, int scancode, int action, int mods) {
if (GLFW_PRESS == action) switch (key) {
case GLFW_KEY_R:
ovrHmd_RecenterPose(hmd);
return;
}

RiftGlfwApp::onKey(key, scancode, action, mods);
}

virtual void draw() final {
ovrHmd_GetEyePoses(hmd, frame, eyeOffsets, eyePoses, nullptr);

ovrHmd_BeginFrame(hmd, frame);
for (int i = 0; i < 2; ++i) {
ovrEyeType eye = currentEye = hmd->EyeRenderOrder[i];
const ovrRecti & vp = eyeTextures[eye].Header.RenderViewport;

// Render the scene to an offscreen buffer
eyeFbos[eye]->fbo.Bind(oglplus::Framebuffer::Target::Draw);
gl.Viewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h);
renderScene(projections[eye], ovr::toGlm(eyePoses[eye]));
}
oglplus::DefaultFramebuffer().Bind(oglplus::Framebuffer::Target::Draw);
ovrHmd_EndFrame(hmd, eyePoses, eyeTextures);
}

virtual void renderScene(const glm::mat4 & projection, const glm::mat4 & headPose) = 0;
};

// An example application that renders a simple cube
class ExampleApp : public RiftApp {
mat4 modelview;
float ipd{ OVR_DEFAULT_IPD };
std::unique_ptr<ColorCubeScene> cubeScene;

public:
ExampleApp() {
modelview = glm::lookAt(glm::vec3(0, 0, OVR_DEFAULT_IPD * 5.0f), glm::vec3(0), glm::vec3(0, 1, 0));
}

protected:
virtual void initGl() {
RiftApp::initGl();
cubeScene = std::unique_ptr<ColorCubeScene>(new ColorCubeScene());
}

virtual void update() {
RiftApp::update();
// Update stuff
}

void renderScene(const glm::mat4 & projection, const glm::mat4 & headPose) {
// Clear the scene
oglplus::Context::Clear().ColorBuffer().DepthBuffer();
// apply the head pose to the current modelview matrix
glm::mat4 modelview = glm::inverse(headPose) * this->modelview;
// Scale the size of the cube to the distance between the eyes
modelview = glm::scale(modelview, glm::vec3(ipd));
// Render the cube
cubeScene->render(projection, modelview);
}
};

// Execute our example class
MAIN_DECL{
int result = -1;
try {
if (!ovr_Initialize()) {
FAIL("Failed to initialize the Oculus SDK");
}
result = ExampleApp().run();
} catch (std::exception & error) {
std::cerr << error.what() << std::endl;
}
ovr_Shutdown();
return result;
}

tmason101
Honored Guest
"jherico" wrote:
I've created my own version of this which uses classes to break down the responsibilities and hopefully show more clearly exactly what the interactions with the Oculus API's are.


Hey Jherico!

First off, thanks so much for trying out my example and also building your own! This helps the community tremendously.

I tried your example and I ensured that I included everything but in Windows at least it doesn't build.

Perhaps there is a problem with my includes but I was sure to download the latest version of OGLPlus from here (http://oglplus.org/)

See the pictures below; basically it doesn't recognize everything even though I did the includes.

Mac\Linux only?



My include setup:

tmason101
Honored Guest
"jherico" wrote:
I'm able to get the provided demo running, but there's a few issues.


if (UseApplicationWindowFrame) {
SizeDivizor = 2;
}


For DirectX, there doesn't seem to be any relationship between the onscreen window size and the actual Rift resolution. However for OpenGL, at least on my setup, the GLFW window must be of the same resolution as the Rift, or the image gets cut off. Changing SizeDivizor here to 1 solved the problem.



I see. Makes sense. I tried this on Windows but no dice.


"jherico" wrote:

If I disable rift mode, I actually don't get any rendering output.


Must be a Mac/Linux vs. Windows thing? On Windows as mentioned before I get the Extended mode with no problems but Direct Mode is where I still get the crash with GLFW.

"jherico" wrote:

Inside your per-eye loop you're doing this:



for (auto & C : Cubes) {
if (RotateCubes) {
C.RotateMe(0.001f);
}
C.DrawMe();
}


This is an incredibly bad idea. You need to divide your state modification from your rendering. In particular this bit of code being inside the per-eye loop means that the left and right eyes will see different rotations of the a given object. Updating state should happen once per frame while rendering should happen twice per frame in Rift mode and once per frame in non-Rift mode.


Fixed in the latest code. I'll update the OP as well as put it below.

"jherico" wrote:

I don't get the point of calling glDrawElementsInstanced to draw one instance.


Just what I am used to; I could switch the code out to be just glDrawElements if that makes things easier to understand.

New Code:

Main.h


#ifndef MAIN_H_
#define MAIN_H_

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include <array>

#ifndef OPENGL_INCLUDES_
#define OPENGL_INCLUDES_

#include "GL\glew.h"

#ifndef GLFW_INCLUDES_
#define GLFW_INCLUDES_

#if defined(_WIN32)
#include <Windows.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#elif defined(__linux__)
#include <X11/X.h>
#include <X11/extensions/Xrandr.h>
#define GLFW_EXPOSE_NATIVE_X11
#define GLFW_EXPOSE_NATIVE_GLX
#endif

#include "GLFW\glfw3.h"
#include "GLFW\glfw3native.h"

#endif

#ifndef GLM_INCLUDES_
#define GLM_INCLUDES_

#include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

#endif

#ifndef OCULUS_SDK_
#define OCULUS_SDK_

#define OVR_OS_WIN32

#include "OVR_CAPI_GL.h"
#include "Kernel\OVR_Math.h"

#endif

#endif

GLFWwindow* MainWindow;

#ifdef _WIN32

HWND MainWindowWin32Handle = NULL;

#endif

GLint WindowWidth = 1024;
GLint WindowHeight = 768;
GLfloat AspectRatio;

GLulong SizeDivizor = 1;

GLboolean RiftAvailable = false;
GLboolean DirectMode = false;
GLboolean RotateCubes = true;

GLfloat RotationSpeed = 0.001f;
GLfloat RotationDirection = 1.0f;

ovrHmd Main_HMD = NULL;
ovrEyeRenderDesc Main_EyeRenderDesc[2];
ovrRecti Main_EyeRenderViewport[2];
ovrGLConfig Main_HMD_Render_Config;
ovrGLTexture Main_EyeTexture[2];
OVR::Recti Main_HMD_Pos_Res;
ovrFovPort Main_HMD_eyeFov[2];

GLuint Main_HMD_FrameIndex;

OVR::Sizei recommenedLeftEyeSize;
OVR::Sizei recommenedRightEyeSize;
OVR::Sizei finalTextureSize;

GLuint OculusRiftFrameBufferID;
GLuint OculusRiftRenderBufferID;
GLuint OculusRiftDepthBufferID;
GLuint OculusRiftTextureID;

GLuint MainOpenGLShaderProgramID;
GLuint MatricesUniformBlockID;
GLuint MatricesUniformBufferID;

GLuint LightsUniformBlockID;
GLuint LightsUniformBufferID;

GLuint MaterialsUniformBlockID;
GLuint MaterialsUniformBufferID;

glm::mat4 CenterPositionMatrix;
glm::mat4 EyeOrientationMatrix;
glm::mat4 EyePositionMatrix;
glm::mat4 ViewMatrix;
glm::mat4 ViewModelMatrix;
glm::mat4 ProjectionMatrix;
glm::mat4 MVPMatrix;
glm::mat3 NormalMatrix;

class StandardCube;

std::vector<StandardCube> Cubes;

void (*DrawScene)();

int initializeOculusRift();

int initializeGLFWGLEW();

int prepareOpenGL();

int prepareFrameBuffer();

int prepareOculusRiftWindow();

int configureOculusRift();

int configureOculusRiftTracking();

int loadShaders();

int prepareShaderUniforms();

int loadCubes();

int prepareMatrices();

int SetDrawFunctionPointer();

void DrawWindowed();

void DrawOculusRift();

static void GLFWKeyCallback(GLFWwindow* p_Window, GLint p_Key, GLint p_Scancode, GLint p_Action, GLint p_Mods);

static void GLFWWindowResizeCallBack(GLFWwindow* p_Window, GLint width, GLint height);

static void GLFWMouseMovementCallBack(GLFWwindow* p_Window, GLdouble MouseX, GLdouble MouseY);

static void GLFWFramebufferSizeCallback(GLFWwindow* window, GLint width, GLint height);

static void GLFWErrorCallback(GLint error, const char* description);

int main(int argc, char** argv);

#endif



Main.cpp


#include "Main.h"

class StandardCube {

private:

GLfloat* Vertices;
GLfloat* Normals;
GLuint* Indices;

GLuint VAO;

glm::mat4 ModelMatrix;

public:

void LoadIntoOpenGL() {

Vertices = new GLfloat[72]

{
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f
};

Normals = new GLfloat[72] {
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f
};

Indices = new GLuint[36] {0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
8, 9, 10, 10, 11, 8,
12, 13, 14, 14, 15, 12,
16, 17, 18, 18, 19, 16,
20, 21, 22, 22, 23, 20
};

glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

GLuint MeshBufferID;
glGenBuffers(1, &MeshBufferID);
glBindBuffer(GL_ARRAY_BUFFER, MeshBufferID);

GLuint TotalBufferData = (sizeof(GLfloat) * 72) + (sizeof(GLfloat) * 72);

glBufferData(GL_ARRAY_BUFFER, TotalBufferData, NULL, GL_STATIC_DRAW);

glBufferSubData(GL_ARRAY_BUFFER, NULL, sizeof(GLfloat) * 72, Vertices);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glBufferSubData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 72, sizeof(GLfloat) * 72, Normals);

glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(GLfloat) * 72));
glEnableVertexAttribArray(1);

GLuint IndexBufferID;
glGenBuffers(1, &IndexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 36, Indices, GL_STATIC_DRAW);

glBindVertexArray(NULL);

ModelMatrix = glm::mat4(1.0f);

}

void DrawMe() {

MVPMatrix = ProjectionMatrix * ViewMatrix * ModelMatrix;
ViewModelMatrix = ViewMatrix * ModelMatrix;
NormalMatrix = glm::transpose(glm::inverse(glm::mat3(MVPMatrix)));

glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);

glBufferSubData(GL_UNIFORM_BUFFER, NULL, sizeof(glm::mat4), glm::value_ptr(MVPMatrix));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(ViewModelMatrix));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4) + sizeof(glm::mat4), sizeof(glm::mat3), glm::value_ptr(NormalMatrix));

glBindBuffer(GL_UNIFORM_BUFFER, NULL);

glBindVertexArray(VAO);
glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL, 1);
glBindVertexArray(NULL);

}

void MoveMe(glm::vec3 NewPosition) {

ModelMatrix = glm::translate(ModelMatrix, NewPosition);

}

void RotateMe(GLfloat AmountToRotateBy) {

ModelMatrix = glm::rotate(ModelMatrix, AmountToRotateBy, glm::vec3(0.0f, 1.0f, 0.0f));

}

};

int initializeOculusRift() {

if (!ovr_Initialize()) {

return EXIT_FAILURE;

}

if (!Main_HMD) {

Main_HMD = ovrHmd_Create(0);

if (!Main_HMD)
{

fprintf(stderr, "Oculus Rift not detected.");
RiftAvailable = false;

}
else {

if (Main_HMD->ProductName[0] == '\0')
{

fprintf(stderr, "Rift detected, display not enabled.");
RiftAvailable = false;

}
else {

DirectMode = (Main_HMD->HmdCaps & ovrHmdCap_ExtendDesktop) ? false : true;

Main_HMD_Pos_Res = OVR::Recti(Main_HMD->WindowsPos, Main_HMD->Resolution);

if (DirectMode) {

SizeDivizor = 1;

}

WindowWidth = Main_HMD_Pos_Res.w / SizeDivizor;
WindowHeight = Main_HMD_Pos_Res.h / SizeDivizor;

RiftAvailable = true;

}

}

}

return EXIT_SUCCESS;

}

int initializeGLFWGLEW() {

MainWindow = NULL;

if (!glfwInit())
{

fprintf(stderr, "GLFW failed to initialize.");
glfwTerminate();
return EXIT_FAILURE;

}

/*

Customize this for the OpenGL version you have on your system.

*/

glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

/*

End OpenGL context setup.

*/

glfwSetErrorCallback(GLFWErrorCallback);

if (DirectMode) {

MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Oculus Rift Direct Mode Example", NULL, NULL);

}
else {

if (!RiftAvailable) {

MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Simple OpenGL Example", NULL, NULL);

}
else {

GLint MonitorCount;
GLFWmonitor** GLFW_Monitors = glfwGetMonitors(&MonitorCount);
GLFWmonitor* MonitorToUse;

switch (MonitorCount)
{
case 0:
printf("No monitors found, exiting.\n");
return EXIT_FAILURE;
break;
case 1:
printf("Two monitors expected, found only one, using primary...\n");
MonitorToUse = glfwGetPrimaryMonitor();
break;
case 2:
printf("Two monitors found, using second monitor\n");
MonitorToUse = GLFW_Monitors[1];
break;
default:
printf("More than two monitors found, using second monitor\n");
MonitorToUse = GLFW_Monitors[1];
}

MainWindow = glfwCreateWindow(WindowWidth, WindowHeight, "Oculus Rift Extended Mode Example", MonitorToUse, NULL);

}

}

if (!MainWindow)
{
fprintf(stderr, "Could not determine OpenGL version; exiting.");
glfwTerminate();
return EXIT_FAILURE;
}

glfwMakeContextCurrent(MainWindow);

glewExperimental = GL_TRUE;
GLenum err = glewInit();

if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return EXIT_FAILURE;

}



glfwSetInputMode(MainWindow, GLFW_STICKY_KEYS, GL_TRUE);

glfwSetKeyCallback(MainWindow, GLFWKeyCallback);
glfwSetWindowSizeCallback(MainWindow, GLFWWindowResizeCallBack);
glfwSetCursorPosCallback(MainWindow, GLFWMouseMovementCallBack);
glfwSetFramebufferSizeCallback(MainWindow, GLFWFramebufferSizeCallback);

glfwSwapBuffers(MainWindow);

glfwPollEvents();

return EXIT_SUCCESS;

}

int prepareOpenGL() {

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_MULTISAMPLE);

return EXIT_SUCCESS;

}

int prepareFrameBuffer() {

if (!RiftAvailable) {

//This process doesn't apply if an Oculus Rift isn't available.

return EXIT_SUCCESS;

}

recommenedLeftEyeSize = ovrHmd_GetFovTextureSize(Main_HMD, ovrEye_Left, Main_HMD->DefaultEyeFov[0], 1.0f);
recommenedRightEyeSize = ovrHmd_GetFovTextureSize(Main_HMD, ovrEye_Right, Main_HMD->DefaultEyeFov[1], 1.0f);

finalTextureSize.w = recommenedLeftEyeSize.w + recommenedRightEyeSize.w;
finalTextureSize.h = std::max(recommenedLeftEyeSize.h, recommenedRightEyeSize.h);

glGenFramebuffers(1, &OculusRiftFrameBufferID);
glBindFramebuffer(GL_FRAMEBUFFER, OculusRiftFrameBufferID);

// The texture we're going to render to...
glGenTextures(1, &OculusRiftTextureID);
// "Bind" the newly created texture : all future texture functions will modify this texture...
glBindTexture(GL_TEXTURE_2D, OculusRiftTextureID);

// Give an empty image to OpenGL (the last "0")
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, finalTextureSize.w, finalTextureSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
// Linear filtering...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Create Depth Buffer...
glGenRenderbuffers(1, &OculusRiftDepthBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, OculusRiftDepthBufferID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, finalTextureSize.w, finalTextureSize.h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, OculusRiftDepthBufferID);

// Set the texture as our colour attachment #0...
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, OculusRiftTextureID, 0);

// Set the list of draw buffers...
GLenum l_GLDrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, l_GLDrawBuffers); // "1" is the size of DrawBuffers

// Check if everything is OK...
GLenum l_Check = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);

if (l_Check != GL_FRAMEBUFFER_COMPLETE)
{
printf("There is a problem with the FBO.\n");
return EXIT_FAILURE;
}

// Unbind...
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

return EXIT_SUCCESS;

}

int prepareFrameBuffer() {

if (!RiftAvailable) {



//This process doesn't apply if an Oculus Rift isn't available.



return EXIT_SUCCESS;

}

recommenedLeftEyeSize = ovrHmd_GetFovTextureSize(Main_HMD, ovrEye_Left, Main_HMD->DefaultEyeFov[0], 1.0f);
recommenedRightEyeSize = ovrHmd_GetFovTextureSize(Main_HMD, ovrEye_Right, Main_HMD->DefaultEyeFov[1], 1.0f);

finalTextureSize.w = recommenedLeftEyeSize.w + recommenedRightEyeSize.w;
finalTextureSize.h = std::max(recommenedLeftEyeSize.h, recommenedRightEyeSize.h);

glGenTextures(1, &OculusRiftTextureID);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OculusRiftTextureID);

GLint MaximumSamples;
glGetIntegerv(GL_MAX_SAMPLES, &MaximumSamples);

glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MaximumSamples,
GL_RGBA, finalTextureSize.w, finalTextureSize.h, false);

glGenFramebuffers(1, &OculusRiftFrameBufferID);
glBindFramebuffer(GL_FRAMEBUFFER, OculusRiftFrameBufferID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, OculusRiftTextureID, 0);

glGenRenderbuffers(1, &OculusRiftRenderBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, OculusRiftRenderBufferID);

glRenderbufferStorageMultisample(GL_RENDERBUFFER, MaximumSamples,
GL_RGBA, finalTextureSize.w, finalTextureSize.h);

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OculusRiftRenderBufferID);

glGenRenderbuffers(1, &OculusRiftDepthBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, OculusRiftDepthBufferID);

glRenderbufferStorageMultisample(GL_RENDERBUFFER, MaximumSamples,
GL_DEPTH24_STENCIL8, finalTextureSize.w, finalTextureSize.h);

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, OculusRiftDepthBufferID);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OculusRiftDepthBufferID);

GLenum DrawBufferStatusCheck_ENUM = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);

if (DrawBufferStatusCheck_ENUM != GL_FRAMEBUFFER_COMPLETE) {
switch (DrawBufferStatusCheck_ENUM)
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
break;
default:
break;
}

glBindRenderbuffer(GL_RENDERBUFFER, NULL);
glBindTexture(GL_TEXTURE_2D, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, NULL);
return EXIT_FAILURE;

}
else {

glBindRenderbuffer(GL_RENDERBUFFER, NULL);
glBindTexture(GL_TEXTURE_2D, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, NULL);
return EXIT_SUCCESS;

}

}

*/

int prepareOculusRiftWindow() {

if (!RiftAvailable) {

//This process doesn't apply if an Oculus Rift isn't available.

return EXIT_SUCCESS;

}

#ifdef _WIN32

if (RiftAvailable) {

MainWindowWin32Handle = glfwGetWin32Window(MainWindow);

if (DirectMode) {

ovrHmd_AttachToWindow(Main_HMD, MainWindowWin32Handle, NULL, NULL);

}

return EXIT_SUCCESS;

}
else {

return EXIT_FAILURE;

}

#endif

}

int configureOculusRift() {

if (!RiftAvailable) {

return EXIT_SUCCESS;

}

Main_HMD_eyeFov[ovrEye_Left] = Main_HMD->DefaultEyeFov[ovrEye_Left];
Main_HMD_eyeFov[ovrEye_Right] = Main_HMD->DefaultEyeFov[ovrEye_Right];

Main_HMD_Render_Config.OGL.Window = MainWindowWin32Handle;

HDC MainHDC = GetDC(Main_HMD_Render_Config.OGL.Window);
Main_HMD_Render_Config.OGL.DC = MainHDC;
Main_HMD_Render_Config.OGL.Header.API = ovrRenderAPI_OpenGL;
Main_HMD_Render_Config.OGL.Header.Multisample = 1;
Main_HMD_Render_Config.OGL.Header.RTSize = OVR::Sizei(Main_HMD->Resolution.w, Main_HMD->Resolution.h);

Main_EyeRenderViewport[ovrEye_Left].Pos = OVR::Vector2i(0, 0);
Main_EyeRenderViewport[ovrEye_Left].Size = OVR::Sizei(finalTextureSize.w / 2, finalTextureSize.h);
Main_EyeRenderViewport[ovrEye_Right].Pos = OVR::Vector2i((finalTextureSize.w + 1) / 2, 0);
Main_EyeRenderViewport[ovrEye_Right].Size = Main_EyeRenderViewport[ovrEye_Left].Size;

Main_EyeTexture[ovrEye_Left].OGL.Header.API = ovrRenderAPI_OpenGL;
Main_EyeTexture[ovrEye_Left].OGL.Header.RenderViewport = Main_EyeRenderViewport[ovrEye_Left];
Main_EyeTexture[ovrEye_Left].OGL.Header.TextureSize = finalTextureSize;
Main_EyeTexture[ovrEye_Left].OGL.TexId = OculusRiftTextureID;
Main_EyeTexture[ovrEye_Left].Texture.Header.API = ovrRenderAPI_OpenGL;
Main_EyeTexture[ovrEye_Left].Texture.Header.RenderViewport = Main_EyeRenderViewport[ovrEye_Left];
Main_EyeTexture[ovrEye_Left].Texture.Header.TextureSize = finalTextureSize;

Main_EyeTexture[ovrEye_Right] = Main_EyeTexture[ovrEye_Left];
Main_EyeTexture[ovrEye_Right].OGL.Header.RenderViewport = Main_EyeRenderViewport[ovrEye_Right];
Main_EyeTexture[ovrEye_Right].Texture.Header.RenderViewport = Main_EyeRenderViewport[ovrEye_Right];

if (!ovrHmd_ConfigureRendering(Main_HMD, &Main_HMD_Render_Config.Config,
ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette |
ovrDistortionCap_TimeWarp | ovrDistortionCap_Overdrive,
Main_HMD_eyeFov,
Main_EyeRenderDesc)) {

return EXIT_FAILURE;

}

ovrHmd_SetEnabledCaps(Main_HMD, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);

return EXIT_SUCCESS;

}

int configureOculusRiftTracking() {

if (!RiftAvailable) {

return EXIT_SUCCESS;

}

if (!ovrHmd_ConfigureTracking(Main_HMD, ovrTrackingCap_Orientation | ovrTrackingCap_MagYawCorrection | ovrTrackingCap_Position, NULL)) {

return EXIT_FAILURE;

}

return EXIT_SUCCESS;

}

int loadShaders() {

// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

// Compile Vertex Shader
printf("Compiling Vertext Shader.\n\n");
char const * VertexSource = "#version 330 \n\n\
layout(std140) uniform Matrices{\n\
mat4 m_pvm;\n\
mat4 m_viewModel;\n\
mat3 m_normal;\n\
};\n\
layout(std140) uniform Lights{\n\
vec3 l_dir; \n\
};\n\
layout (location=0) in vec4 position;\n\
layout (location=1) in vec3 normal;\n\
\n\
\n\
out Data{\n\
vec3 normal;\n\
vec4 eye;\n\
} DataOut;\n\
\n\
void main() {\n\
\n\
DataOut.normal = normalize(m_normal * normal);\n\
DataOut.eye = -(m_viewModel * position);\n\
\n\
gl_Position = m_pvm * position;\n\
}\n\
\n";

glShaderSource(VertexShaderID, 1, &VertexSource, NULL);
glCompileShader(VertexShaderID);

// Check Vertex Shader

GLint Result = GL_FALSE;
int InfoLogLength;

glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);

if (InfoLogLength > 0){

std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
std::string ErrorMessage = std::string(&VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);

}

printf("Compiling Fragment Shader.\n\n");
char const * FragmentSource = "#version 330\n\
\
layout(std140) uniform Matrices{\n\
mat4 m_pvm;\n\
mat4 m_viewModel;\n\
mat3 m_normal;\n\
};\n\
\
layout(std140) uniform Materials{\n\
vec4 diffuse;\n\
vec4 ambient;\n\
vec4 specular;\n\
vec4 emissive;\n\
float shininess;\n\
int texCount;\n\
};\
\n\
layout(std140) uniform Lights{\n\
vec3 l_dir; \n\
};\
\n\
in Data{\n\
vec3 normal;\n\
vec4 eye;\n\
} DataIn;\n\
\n\
out vec4 colorOut;\
\n\
void main() {\n\
\n\
vec4 spec = vec4(0.0);\n\
\n\
vec3 n = normalize(DataIn.normal);\n\
vec3 e = normalize(vec3(DataIn.eye));\n\
\n\
float intensity = max(dot(n, l_dir), 0.0);\n\
\n\
if (intensity > 0.0) {\n\
vec3 h = normalize(l_dir + e);\n\
\n\
float intSpec = max(dot(h, n), 0.0);\n\
spec = specular * pow(intSpec, shininess);\n\
}\n\
\n\
colorOut = max(intensity * diffuse + spec, ambient);\n\
}";

glShaderSource(FragmentShaderID, 1, &FragmentSource, NULL);
glCompileShader(FragmentShaderID);

// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0){

std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
std::string ErrorMessage = std::string(&FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);

}

// Link the program
printf("Linking shader program.\n\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);

// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0){

std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
std::string ErrorMessage = std::string(&ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);

}

glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);

MainOpenGLShaderProgramID = ProgramID;

return EXIT_SUCCESS;

}

int prepareShaderUniforms() {

glUseProgram(MainOpenGLShaderProgramID);

MatricesUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Matrices");
glUniformBlockBinding(MainOpenGLShaderProgramID, MatricesUniformBlockID, 1);
glGenBuffers(1, &MatricesUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, MatricesUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, MatricesUniformBufferID);
GLsizeiptr TotalBufferSize = sizeof(glm::mat4) + sizeof(glm::mat4);
TotalBufferSize += sizeof(glm::mat3);

glBufferData(GL_UNIFORM_BUFFER, TotalBufferSize, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);

LightsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Lights");
glUniformBlockBinding(MainOpenGLShaderProgramID, LightsUniformBlockID, 2);
glGenBuffers(1, &LightsUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, LightsUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 2, LightsUniformBufferID);

GLfloat LightDirection[3] = {-4.0f, -3.0f, -3.0f};

glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDirection), &LightDirection, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);

MaterialsUniformBlockID = glGetUniformBlockIndex(MainOpenGLShaderProgramID, "Materials");
glUniformBlockBinding(MainOpenGLShaderProgramID, MaterialsUniformBlockID, 3);
glGenBuffers(1, &MaterialsUniformBufferID);
glBindBuffer(GL_UNIFORM_BUFFER, MaterialsUniformBufferID);
glBindBufferBase(GL_UNIFORM_BUFFER, 3, MaterialsUniformBufferID);

GLfloat Material[18];

//Diffuse
Material[0] = 0.5f;
Material[1] = 0.0f;
Material[2] = 0.0f;
Material[3] = 1.0f;

//Ambient
Material[4] = 0.2f;
Material[5] = 0.2f;
Material[6] = 0.2f;
Material[7] = 1.0f;

//Specular
Material[8] = 1.0f;
Material[9] = 1.0f;
Material[10] = 1.0f;
Material[11] = 1.0f;

//Emissive
Material[12] = 0.0f;
Material[13] = 0.0f;
Material[14] = 0.0f;
Material[15] = 1.0f;

//Shininess
Material[16] = 5.0f;

//Texture Count
Material[17] = 0.0f;

glBufferData(GL_UNIFORM_BUFFER, sizeof(Material), &Material, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, NULL);

return EXIT_SUCCESS;

}

int loadCubes() {

StandardCube FrontCube;

FrontCube.LoadIntoOpenGL();

FrontCube.MoveMe(glm::vec3(0.0f, -1.0f, -2.0f));

Cubes.push_back(FrontCube);

return EXIT_SUCCESS;

}

int prepareMatricies() {

AspectRatio = (GLfloat)(WindowWidth) / (GLfloat)(WindowHeight);

ProjectionMatrix = glm::perspective(45.0f, AspectRatio, 1.0f, 1000.0f);

ViewMatrix = glm::lookAt(
glm::vec3(0.0f, 6.0f, 6.0f), // camera is at (4,3,3), in world space - Where the camera is inside world.
glm::vec3(0.0f, 0.0f, -3.0f), // and looks at the origin - What point the camera is looking at inside world.
glm::vec3(0.0f, 1.0f, 0.0f) // head is up(set to 0,1,0) - the direction of up for camera.
);

glViewport(0, 0, WindowWidth, WindowHeight);

return EXIT_SUCCESS;

}

int SetDrawFunctionPointer() {

if (!RiftAvailable) {

DrawScene = DrawWindowed;

}
else {

DrawScene = DrawOculusRift;

}

return EXIT_SUCCESS;

}

void DrawWindowed() {

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

for (auto & C : Cubes) {

if (RotateCubes) {

C.RotateMe(RotationSpeed * RotationDirection);

}

C.DrawMe();

}

glfwSwapBuffers(MainWindow);

glfwPollEvents();

}

void DrawOculusRift() {

ovrFrameTiming Current_Frame = ovrHmd_BeginFrame(Main_HMD, Main_HMD_FrameIndex);

static ovrPosef Main_HMD_eyeRenderPose[2];
static ovrMatrix4f OculusRiftProjection[2];
static ovrMatrix4f OculusRiftView[2];
static OVR::Vector3f Main_HMD_HeadPos(0.0f, 1.6f, -5.0f);
static ovrTrackingState HmdState;

ovrVector3f hmdToEyeViewOffset[2] = { Main_EyeRenderDesc[0].HmdToEyeViewOffset, Main_EyeRenderDesc[1].HmdToEyeViewOffset };
ovrHmd_GetEyePoses(Main_HMD, Main_HMD_FrameIndex, hmdToEyeViewOffset, Main_HMD_eyeRenderPose, &HmdState);

Main_HMD_HeadPos.y = ovrHmd_GetFloat(Main_HMD, OVR_KEY_EYE_HEIGHT, Main_HMD_HeadPos.y);

if (RotateCubes) {

for (auto & C : Cubes) {

C.RotateMe(RotationSpeed * RotationDirection);

}

}

glBindFramebuffer(GL_FRAMEBUFFER, OculusRiftFrameBufferID);

glUseProgram(MainOpenGLShaderProgramID);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

for (GLint CurrentEyeIndex = 0; CurrentEyeIndex < ovrEye_Count; ++CurrentEyeIndex)
{

ovrEyeType CurrentEye = Main_HMD->EyeRenderOrder[CurrentEyeIndex];

glViewport(
Main_EyeTexture[CurrentEyeIndex].Texture.Header.RenderViewport.Pos.x,
Main_EyeTexture[CurrentEyeIndex].Texture.Header.RenderViewport.Pos.y,
Main_EyeTexture[CurrentEyeIndex].Texture.Header.RenderViewport.Size.w,
Main_EyeTexture[CurrentEyeIndex].Texture.Header.RenderViewport.Size.h
);

OculusRiftProjection[CurrentEyeIndex] = ovrMatrix4f_Projection(Main_EyeRenderDesc[CurrentEyeIndex].Fov,
0.1f, 1000.0f, true);

for (int o = 0; o < 4; o++) {
for (int i = 0; i < 4; i++) {
ProjectionMatrix[o][i] = OculusRiftProjection[CurrentEyeIndex].M[o][i];
}
}

ProjectionMatrix = glm::transpose(ProjectionMatrix);

CenterPositionMatrix = glm::translate(glm::mat4(1.0f),
-glm::vec3(Main_HMD_eyeRenderPose[CurrentEyeIndex].Position.x,
Main_HMD_eyeRenderPose[CurrentEyeIndex].Position.y,
Main_HMD_eyeRenderPose[CurrentEyeIndex].Position.z));

EyeOrientationMatrix = glm::toMat4(glm::quat(
Main_HMD_eyeRenderPose[CurrentEyeIndex].Orientation.w,
-Main_HMD_eyeRenderPose[CurrentEyeIndex].Orientation.x,
-Main_HMD_eyeRenderPose[CurrentEyeIndex].Orientation.y,
-Main_HMD_eyeRenderPose[CurrentEyeIndex].Orientation.z
));

EyePositionMatrix = glm::translate(glm::mat4(1.0f),
glm::vec3(
Main_EyeRenderDesc[CurrentEyeIndex].HmdToEyeViewOffset.x,
Main_EyeRenderDesc[CurrentEyeIndex].HmdToEyeViewOffset.y,
Main_EyeRenderDesc[CurrentEyeIndex].HmdToEyeViewOffset.z
));

ViewMatrix = EyePositionMatrix * EyeOrientationMatrix * CenterPositionMatrix;

for (auto & C : Cubes) {

C.DrawMe();

}

}

ovrHmd_EndFrame(Main_HMD, Main_HMD_eyeRenderPose, &Main_EyeTexture[0].Texture);

Main_HMD_FrameIndex += 1;

glfwPollEvents();

}

static void GLFWKeyCallback(GLFWwindow* p_Window, GLint p_Key, GLint p_Scancode, GLint p_Action, GLint p_Mods) {

if (RiftAvailable) {

ovrHSWDisplayState l_HasWarningState;

ovrHmd_GetHSWDisplayState(Main_HMD, &l_HasWarningState);

if (l_HasWarningState.Displayed) {

ovrHmd_DismissHSWDisplay(Main_HMD);

}

}

if (p_Key == GLFW_KEY_ESCAPE && p_Action == GLFW_PRESS) {

glfwSetWindowShouldClose(p_Window, GL_TRUE);
}

if (p_Key == GLFW_KEY_O && p_Action == GLFW_PRESS) {

glClearColor(0.2f, 0.1f, 0.3f, 1.0f);

}

if (p_Key == GLFW_KEY_I && p_Action == GLFW_PRESS) {

glClearColor(1.0f, 0.5f, 0.5f, 1.0f);

}

if (p_Key == GLFW_KEY_R && p_Action == GLFW_PRESS) {

RotateCubes = !RotateCubes;

}

if (p_Key == GLFW_KEY_PAGE_UP && (p_Action == GLFW_PRESS || p_Action == GLFW_REPEAT)) {

RotationSpeed += 0.001f;

}

if (p_Key == GLFW_KEY_PAGE_DOWN && (p_Action == GLFW_PRESS || p_Action == GLFW_REPEAT)) {

RotationSpeed -= 0.001f;

if (RotationSpeed < 0.001f) {

RotationSpeed = 0.001f;

}

}

if (p_Key == GLFW_KEY_SPACE && p_Action == GLFW_PRESS) {

RotationDirection *= -1.0f;

}

}

static void GLFWWindowResizeCallBack(GLFWwindow* p_Window, GLint width, GLint height) {

//CurrentGLFWApplication->WindowResizeCallBack(p_Window, width, height);

}

static void GLFWMouseMovementCallBack(GLFWwindow* p_Window, GLdouble MouseX, GLdouble MouseY) {

//CurrentGLFWApplication->MouseMovementCallBack(p_Window, MouseX, MouseY);

}

static void GLFWFramebufferSizeCallback(GLFWwindow* window, GLint width, GLint height)
{
AspectRatio = (GLfloat)(width) / (GLfloat)(height);

ProjectionMatrix = glm::perspective(45.0f, AspectRatio, 0.1f, 1000.0f);

glViewport(0, 0, width, height);

}

static void GLFWErrorCallback(GLint error, const char* description)
{

fputs(description, stderr);

}

int main(int argc, char** argv) {

if (initializeOculusRift() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (initializeGLFWGLEW() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareOpenGL() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareFrameBuffer() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareOculusRiftWindow() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (configureOculusRift() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}



if (configureOculusRiftTracking() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (loadShaders() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareShaderUniforms() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (loadCubes() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (prepareMatricies() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

if (SetDrawFunctionPointer() == EXIT_FAILURE) {

exit(EXIT_FAILURE);

}

while (!glfwWindowShouldClose(MainWindow))

{

DrawScene();

}

exit(EXIT_SUCCESS);

}

jherico
Adventurer
"tmason101" wrote:
Perhaps there is a problem with my includes but I was sure to download the latest version of OGLPlus from here (http://oglplus.org/)


Installation of OGLPlus requires a build step so it can identify the locally supported C++ feature set. OGLPlus is a nice encapsulation of GL, but this one bit of setup is something of a pain.

Additionally, you must add include paths for oglplus/implement plus wherever CMake put the site.hpp file it creates. Let me know if that helps.

tmason101
Honored Guest
"jherico" wrote:
"tmason101" wrote:
Perhaps there is a problem with my includes but I was sure to download the latest version of OGLPlus from here (http://oglplus.org/)


Installation of OGLPlus requires a build step so it can identify the locally supported C++ feature set. OGLPlus is a nice encapsulation of GL, but this one bit of setup is something of a pain.

Additionally, you must add include paths for oglplus/implement plus wherever CMake put the site.hpp file it creates. Let me know if that helps.


OK, will try this out; let's see if I can get "Direct" mode then.

I'd really like to see a rep from Oculus respond on this as well; getting "Direct" mode with OpenGL should be a priority instead of this one-off project it seems to be for them.