cancel
Showing results for 
Search instead for 
Did you mean: 

Simple OpenGL example with GLFW, GLEW and OculusSDK 0.3.1

DoZo1971
Explorer
Hi,

Hope this will save you some headaches (and not cause any more).
Only win32, but with GLFW it shouldn't be too hard to port once the OculusSDK becomes cross-platform.

EDIT
This is a one-page sample, 99% plain C. It is based on the OculusSDK 0.3.1 Preview. OpenGL 3.3 and up, compatibility profile.
For nVidia systems it works as-is.
At the time of writing, for AMD systems, it needs some bug fixes and a rebuild of the SDK libraries. This "patch" is advised for nVidia users as well, but not needed.
Load the Visual Studio solution from OculusSDK/Samples. Depending on your Visual Studio [version]: LibOVR_With_Samples_[version].sln.
In CAPI_GL_DistortionRenderer.cpp (LibOVR/CAPI/GL):
Line 142, replace oColor = Color.r with oColor = vec4(oColor)
Line 349, replace oColor = Color.r with oColor = vec4(oColor)
Line 758, replace (int) DistortionMeshVBs[eyeNum]->GetSize() with (int)DistortionMeshIBs[eyeNum]->GetSize()/2
Line 763, replace (int) DistortionMeshVBs[eyeNum]->GetSize() with (int)DistortionMeshIBs[eyeNum]->GetSize()/2
Rebuild the lib (Debug and/or Release).

Thanks,
Daniel Dekkers


#include <Windows.h>
#include <GL/glew.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <OVR_CAPI.h>
#include <OVR_CAPI_GL.h>
#include <OVR.h>

// =============================================================================

static void ErrorCallback(int p_Error, const char* p_Description)
{
fputs(p_Description, stderr);
}

// =============================================================================

static void KeyCallback(GLFWwindow* p_Window, int p_Key, int p_Scancode, int p_Action, int p_Mods)
{
if (p_Key == GLFW_KEY_ESCAPE && p_Action == GLFW_PRESS)
glfwSetWindowShouldClose(p_Window, GL_TRUE);
}

// =============================================================================

static void RenderCube(float p_Size)
{
const float l_SizeDiv2 = p_Size*0.5f;

// A cube...
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glVertex3f( l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f,-1.0f);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f( 0.0f, 1.0f, 0.0f);
glVertex3f( l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f( l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f( 0.0f,-1.0f, 0.0f);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f( 1.0f, 0.0f, 0.0f);
glVertex3f( l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f(-1.0f, 0.0f, 0.0f);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glEnd();
}

// ============================================================================

static void SetOpenGLState(void)
{
// Some state...
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// Some (stationary) lights...
GLfloat l_Light0Position[] = { 5.0f, 6.0f, 3.0f, 0.0f };
GLfloat l_Light0Diffuse[] = { 1.0f, 0.8f, 0.6f, 1.0f };
glLightfv(GL_LIGHT0, GL_POSITION, l_Light0Position);
glLightfv(GL_LIGHT0, GL_DIFFUSE, l_Light0Diffuse);
glEnable(GL_LIGHT0);

GLfloat l_Light1Position[] = { -5.0f, -6.0f, 5.0f, 0.0f };
GLfloat l_Light1Diffuse[] = { 0.6f, 0.8f, 1.0f, 1.0f };
glLightfv(GL_LIGHT1, GL_POSITION, l_Light1Position);
glLightfv(GL_LIGHT1, GL_DIFFUSE, l_Light1Diffuse);
glEnable(GL_LIGHT1);

// Material...
GLfloat l_MaterialSpecular[] = { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat l_MaterialShininess[] = { 10.0f };
glMaterialfv(GL_FRONT, GL_SPECULAR, l_MaterialSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, l_MaterialShininess);
}

// =============================================================================

int main(void)
{
// Initialize LibOVR...
ovr_Initialize();

ovrHmd l_Hmd = ovrHmd_Create(0);
if (!l_Hmd) l_Hmd = ovrHmd_CreateDebug(ovrHmd_DK1);

ovrHmdDesc l_HmdDesc;
ovrHmd_GetDesc(l_Hmd, &l_HmdDesc);

ovrHmd_StartSensor(l_Hmd, ovrHmdCap_Orientation, 0);

GLFWwindow* l_Window;

glfwSetErrorCallback(ErrorCallback);

if (!glfwInit()) exit(EXIT_FAILURE);

ovrSizei l_ClientSize;
l_ClientSize.w = l_HmdDesc.Resolution.w; // 1280 for DK1...
l_ClientSize.h = l_HmdDesc.Resolution.h; // 800 for DK1...
// Create a fullscreen window with the Oculus Rift resolution...
l_Window = glfwCreateWindow(l_ClientSize.w, l_ClientSize.h, "GLFW Oculus Rift Test", glfwGetPrimaryMonitor(), NULL);
if (!l_Window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}

// Print the OpenGL version we are using...
int l_Major = glfwGetWindowAttrib(l_Window, GLFW_CONTEXT_VERSION_MAJOR);
int l_Minor = glfwGetWindowAttrib(l_Window, GLFW_CONTEXT_VERSION_MINOR);
printf("OpenGL: %d.%d\n", l_Major, l_Minor);

// Make the context current for this window...
glfwMakeContextCurrent(l_Window);

// Create some lights, materials, etc...
SetOpenGLState();

// Don't forget to initialize Glew...
glewInit();

// We will do some offscreen rendering, setup FBO...
ovrSizei l_TextureSizeLeft = ovrHmd_GetFovTextureSize(l_Hmd, ovrEye_Left, l_HmdDesc.DefaultEyeFov[0], 1.0f);
ovrSizei l_TextureSizeRight = ovrHmd_GetFovTextureSize(l_Hmd, ovrEye_Right, l_HmdDesc.DefaultEyeFov[1], 1.0f);
ovrSizei l_TextureSize;
l_TextureSize.w = l_TextureSizeLeft.w + l_TextureSizeRight.w;
l_TextureSize.h = (l_TextureSizeLeft.h>l_TextureSizeRight.h ? l_TextureSizeLeft.h : l_TextureSizeRight.h);

// Create FBO...
GLuint l_FBOId;
glGenFramebuffers(1, &l_FBOId);
glBindFramebuffer(GL_FRAMEBUFFER, l_FBOId);

// The texture we're going to render to...
GLuint l_TextureId;
glGenTextures(1, &l_TextureId);
// "Bind" the newly created texture : all future texture functions will modify this texture...
glBindTexture(GL_TEXTURE_2D, l_TextureId);
// Give an empty image to OpenGL (the last "0")
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, l_TextureSize.w, l_TextureSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// 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...
GLuint l_DepthBufferId;
glGenRenderbuffers(1, &l_DepthBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, l_DepthBufferId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, l_TextureSize.w, l_TextureSize.h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, l_DepthBufferId);

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

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

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

// Oculus Rift eye configurations...
ovrEyeDesc l_Eyes[2];
l_Eyes[0].Eye = ovrEye_Left;
l_Eyes[1].Eye = ovrEye_Right;
l_Eyes[0].Fov = l_HmdDesc.DefaultEyeFov[0];
l_Eyes[1].Fov = l_HmdDesc.DefaultEyeFov[1];
l_Eyes[0].TextureSize.w = l_TextureSize.w;
l_Eyes[0].TextureSize.h = l_TextureSize.h;
l_Eyes[1].TextureSize.w = l_TextureSize.w;
l_Eyes[1].TextureSize.h = l_TextureSize.h;
l_Eyes[0].RenderViewport.Pos.x = 0;
l_Eyes[0].RenderViewport.Pos.y = 0;
l_Eyes[1].RenderViewport.Pos.x = (l_TextureSize.w+1)/2;
l_Eyes[1].RenderViewport.Pos.y = 0;
l_Eyes[0].RenderViewport.Size.w = l_TextureSize.w/2;
l_Eyes[0].RenderViewport.Size.h = l_TextureSize.h;
l_Eyes[1].RenderViewport.Size.w = l_Eyes[0].RenderViewport.Size.w;
l_Eyes[1].RenderViewport.Size.h = l_Eyes[0].RenderViewport.Size.h;

ovrGLConfig l_Cfg;
l_Cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
l_Cfg.OGL.Header.Multisample = 0;
l_Cfg.OGL.Header.RTSize.w = l_ClientSize.w;
l_Cfg.OGL.Header.RTSize.h = l_ClientSize.h;
l_Cfg.OGL.WglContext = glfwGetWGLContext(l_Window);
l_Cfg.OGL.Window = glfwGetWin32Window(l_Window);
l_Cfg.OGL.GdiDc = GetDC(l_Cfg.OGL.Window);

int l_RenderCaps = 0;
int l_DistortionCaps = ovrDistortion_Chromatic | ovrDistortion_TimeWarp;
ovrEyeRenderDesc l_EyeRenderDesc[2];
ovrHmd_ConfigureRendering(l_Hmd, &l_Cfg.Config, l_RenderCaps, l_DistortionCaps, l_Eyes, l_EyeRenderDesc);

ovrGLTexture l_EyeTexture[2];
l_EyeTexture[0].OGL.Header.API = ovrRenderAPI_OpenGL;
l_EyeTexture[0].OGL.Header.TextureSize.w = l_TextureSize.w;
l_EyeTexture[0].OGL.Header.TextureSize.h = l_TextureSize.h;
l_EyeTexture[0].OGL.Header.RenderViewport = l_Eyes[0].RenderViewport;
l_EyeTexture[0].OGL.TexId = l_TextureId;

// Right eye uses the same texture, but a different rendering viewport...
l_EyeTexture[1] = l_EyeTexture[0];
l_EyeTexture[1].OGL.Header.RenderViewport = l_Eyes[1].RenderViewport;

glfwSetKeyCallback(l_Window, KeyCallback);

GLfloat l_SpinX;
GLfloat l_SpinY;

while (!glfwWindowShouldClose(l_Window))
{
l_SpinX = (GLfloat) fmod(glfwGetTime()*17.0, 360.0);
l_SpinY = (GLfloat) fmod(glfwGetTime()*23.0, 360.0);

ovrFrameTiming m_HmdFrameTiming = ovrHmd_BeginFrame(l_Hmd, 0);

// Bind the FBO...
glBindFramebuffer(GL_FRAMEBUFFER, l_FBOId);
// Clear...
glClearColor(0.2f, 0.3f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

for (int l_EyeIndex=0; l_EyeIndex<ovrEye_Count; l_EyeIndex++)
{
ovrEyeType l_Eye = l_HmdDesc.EyeRenderOrder[l_EyeIndex];
ovrPosef l_EyePose = ovrHmd_BeginEyeRender(l_Hmd, l_Eye);

glViewport(l_EyeRenderDesc[l_Eye].Desc.RenderViewport.Pos.x, // StartX
l_EyeRenderDesc[l_Eye].Desc.RenderViewport.Pos.y, // StartY
l_EyeRenderDesc[l_Eye].Desc.RenderViewport.Size.w, // Width
l_EyeRenderDesc[l_Eye].Desc.RenderViewport.Size.h // Height
);

// Get Projection and ModelView matrici from the device...
OVR::Matrix4f l_ProjectionMatrix = ovrMatrix4f_Projection(
l_EyeRenderDesc[l_Eye].Desc.Fov, 0.3f, 100.0f, true);
OVR::Quatf l_Orientation = OVR::Quatf(l_EyePose.Orientation);
OVR::Matrix4f l_ModelViewMatrix = OVR::Matrix4f(l_Orientation.Inverted());

// Pass matrici on to OpenGL...
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(&(l_ProjectionMatrix.Transposed().M[0][0]));
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Translate for specific eye based on IPD...
glTranslatef(l_EyeRenderDesc[l_Eye].ViewAdjust.x,
l_EyeRenderDesc[l_Eye].ViewAdjust.y,
l_EyeRenderDesc[l_Eye].ViewAdjust.z);
// Multiply with orientation retrieved from sensor...
glMultMatrixf(&(l_ModelViewMatrix.Transposed().M[0][0]));
// Move back a bit to show scene in front of us...
glTranslatef(0.0f, 0.0f, -3.0f);
// Make the cube spin...
glRotatef(l_SpinX, 1.0f, 0.0f, 0.0f);
glRotatef(l_SpinY, 0.0f, 1.0f, 0.0f);

// Render...
RenderCube(1.0f);

ovrHmd_EndEyeRender(l_Hmd, l_Eye, l_EyePose, &l_EyeTexture[l_Eye].Texture);
}

// Unbind the FBO, back to normal drawing...
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// Oculus wants CW orientations, avoid the problem by turning of culling...
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
ovrHmd_EndFrame(l_Hmd);
// Restore state after Oculus did it's work (-sigh-)...
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glClearDepth(1);
glUseProgramObjectARB(0);

glfwPollEvents();
}

glfwDestroyWindow(l_Window);

glfwTerminate();

ovrHmd_Destroy(l_Hmd);
ovr_Shutdown();

exit(EXIT_SUCCESS);
}
62 REPLIES 62

jherico
Adventurer
Good job on this. It's nice to see the whole set of functionality in one file like that.

You're using an odd mix of new OpenGL and deprecated code, but that's understandable considering the overhead of putting shaders and vertex buffers, index buffers and vertex arrays.

I would suggest you consider making the cube smaller and moving it closer to the user, so that the per-eye view offset is more apparent.


float ipd = abs(l_EyeRenderDesc[l_Eye].ViewAdjust.x * 2);
static const float SIZE = ipd * 5;
static float A[6][3] = {
{ 0, 0, SIZE },
{ 0, SIZE, 0 },
{ SIZE, 0, 0 },
{ 0, 0, -SIZE },
{ 0, -SIZE, 0 },
{ -SIZE, 0, 0 },
};
for (int i = 0; i < 6; ++i) {
glPushMatrix();
// Move back a bit to show scene in front of us...
glTranslatef(A[i][0], A[i][1], A[i][2]);
// Make the cube spin...
glRotatef(l_SpinX, 1.0f, 0.0f, 0.0f);
glRotatef(l_SpinY, 0.0f, 1.0f, 0.0f);
// Render...
RenderCube(ipd);
glPopMatrix();
}


I'd also suggest that you color the sides of the cube to increase the contrast.

In SetOpenGLState

...
glEnable(GL_COLOR_MATERIAL);
...


And in RenderCube()


glColor3f(1, 0, 0);
glBegin(GL_QUADS);
...
... and a different color for each face

DoZo1971
Explorer
You're using an odd mix of new OpenGL and deprecated code, but that's understandable considering the overhead of putting shaders and vertex buffers, index buffers and vertex arrays.


Some good old fixed function never harmed anyone. 😉
Although the glBegin()/glEnd() stuff is really bad. I think I'll combine with:

making the cube smaller and moving it closer to the user, so that the per-eye view offset is more apparent.


... and make a grid of (smaller) cubes surrounding the viewer. Some near, some far. I'll put that geometry in vertex arrays.

Thanks,
Daniel

ckoeber
Honored Guest
Hello,

When I used the posted example code, the project compiles fine in VC++ 2013 but I get an access violation on the noted part below.

Any idea why?

Thank you for your time.



[...]

GLuint l_DepthBufferId;
glGenRenderbuffers(1, &l_DepthBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, l_DepthBufferId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, l_TextureSize.w, l_TextureSize.h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, l_DepthBufferId);

// Set the texture as our colour attachment #0...
/*

Access Violation here!!!

*/

glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, l_TextureId, 0);

/*

End Access Violation

*/

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

[...]

DoZo1971
Explorer
Did Glew initialize properly?

You could change


// Don't forget to initialize Glew...
glewInit();

to


// Don't forget to initialize Glew...
GLenum l_Result = glewInit();
if (l_Result!=GLEW_OK)
{
printf("glewInit() error.\n");
exit(EXIT_FAILURE);
}

and check.

seac02developer
Honored Guest
Which version of glfw are you using??

It does not work with the 3.x version!

DoZo1971
Explorer
I'm using glfw-3.0.4. Windows 7, 32-bit, Visual Studio 2012.
Could you be a bit more specific than "It's not working"?

ckoeber
Honored Guest
My problem from earlier is that, as seac02developer mentioned, this doesn't work on the OpenGL 3.1 specification.

So I switched to an OpenGL 4.4 supporting AMD R9 280x card but now I get the following screen where the code executes but it doesn't look good at all.

See the attached image.

What gives?

DoZo1971
Explorer
Interesting image you've got there.
Did you make the GLFWwindow windowed? It should be full screen, without window decorations.
Is this a complete screenshot? It looks like the right 1/4 part is missing.
There is some distortion going on, the right part actually looks ok. Don't know what is happening to the "left eye" part.

On my AMD machine, ovrHmd_Configure(...) asserts when it is trying to compile the shaders, and I really don't want to edit their code. It works for me on my nVidia machine though, with OpenGL 4.3.

If you take the code below, you can toggle fullscreen or not. And resize. Maybe then it is more visible what it is going on:


#include <Windows.h>
#include <GL/glew.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#define GLFW_EXPOSE_NATIVE_WGL
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <OVR_CAPI.h>
#include <OVR_CAPI_GL.h>
#include <OVR.h>

const bool l_FullScreen = true;

ovrHmd l_Hmd;
ovrHmdDesc l_HmdDesc;
ovrEyeDesc l_Eyes[2];
ovrGLConfig l_Cfg;

// =============================================================================

static void ErrorCallback(int p_Error, const char* p_Description)
{
fputs(p_Description, stderr);
}

// =============================================================================

static void KeyCallback(GLFWwindow* p_Window, int p_Key, int p_Scancode, int p_Action, int p_Mods)
{
if (p_Key == GLFW_KEY_ESCAPE && p_Action == GLFW_PRESS)
glfwSetWindowShouldClose(p_Window, GL_TRUE);
}

// =============================================================================

static void WindowSizeCallback(GLFWwindow* p_Window, int p_Width, int p_Height)
{
l_Cfg.OGL.Header.RTSize.w = p_Width;
l_Cfg.OGL.Header.RTSize.h = p_Height;

int l_RenderCaps = 0;
int l_DistortionCaps = ovrDistortion_Chromatic | ovrDistortion_TimeWarp;
ovrEyeRenderDesc l_EyeRenderDesc[2];
ovrHmd_ConfigureRendering(l_Hmd, &l_Cfg.Config, l_RenderCaps, l_DistortionCaps, l_Eyes, l_EyeRenderDesc);
}

// =============================================================================

static void RenderCube(float p_Size)
{
const float l_SizeDiv2 = p_Size*0.5f;

// A cube...
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glVertex3f( l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f,-1.0f);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f( 0.0f, 1.0f, 0.0f);
glVertex3f( l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f( l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f( 0.0f,-1.0f, 0.0f);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f( 1.0f, 0.0f, 0.0f);
glVertex3f( l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glVertex3f( l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f( l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glEnd();

glBegin(GL_QUADS);
glNormal3f(-1.0f, 0.0f, 0.0f);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2,-l_SizeDiv2);
glVertex3f(-l_SizeDiv2,-l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2, l_SizeDiv2);
glVertex3f(-l_SizeDiv2, l_SizeDiv2,-l_SizeDiv2);
glEnd();
}

// ============================================================================

static void SetOpenGLState(void)
{
// Some state...
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// Some (stationary) lights...
GLfloat l_Light0Position[] = { 5.0f, 6.0f, 3.0f, 0.0f };
GLfloat l_Light0Diffuse[] = { 1.0f, 0.8f, 0.6f, 1.0f };
glLightfv(GL_LIGHT0, GL_POSITION, l_Light0Position);
glLightfv(GL_LIGHT0, GL_DIFFUSE, l_Light0Diffuse);
glEnable(GL_LIGHT0);

GLfloat l_Light1Position[] = { -5.0f, -6.0f, 5.0f, 0.0f };
GLfloat l_Light1Diffuse[] = { 0.6f, 0.8f, 1.0f, 1.0f };
glLightfv(GL_LIGHT1, GL_POSITION, l_Light1Position);
glLightfv(GL_LIGHT1, GL_DIFFUSE, l_Light1Diffuse);
glEnable(GL_LIGHT1);

// Material...
GLfloat l_MaterialSpecular[] = { 0.3f, 0.3f, 0.3f, 1.0f };
GLfloat l_MaterialShininess[] = { 10.0f };
glMaterialfv(GL_FRONT, GL_SPECULAR, l_MaterialSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, l_MaterialShininess);
}

// =============================================================================

int main(void)
{
// Initialize LibOVR...
ovr_Initialize();

l_Hmd = ovrHmd_Create(0);
if (!l_Hmd) l_Hmd = ovrHmd_CreateDebug(ovrHmd_DK1);

ovrHmd_GetDesc(l_Hmd, &l_HmdDesc);

ovrHmd_StartSensor(l_Hmd, ovrHmdCap_Orientation, 0);

GLFWwindow* l_Window;

glfwSetErrorCallback(ErrorCallback);

if (!glfwInit()) exit(EXIT_FAILURE);

ovrSizei l_ClientSize;
if (l_FullScreen)
{
l_ClientSize.w = l_HmdDesc.Resolution.w; // 1280 for DK1...
l_ClientSize.h = l_HmdDesc.Resolution.h; // 800 for DK1...
// Create a fullscreen window with the Oculus Rift resolution...
l_Window = glfwCreateWindow(l_ClientSize.w, l_ClientSize.h, "GLFW Oculus Rift Test", glfwGetPrimaryMonitor(), NULL);
}
else
{
l_ClientSize.w = 640;
l_ClientSize.h = 480;
// Create a window with the size of your likings...
l_Window = glfwCreateWindow(l_ClientSize.w, l_ClientSize.h, "GLFW Oculus Rift Test", NULL, NULL);
}

if (!l_Window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}

// Print the OpenGL version we are using...
int l_Major = glfwGetWindowAttrib(l_Window, GLFW_CONTEXT_VERSION_MAJOR);
int l_Minor = glfwGetWindowAttrib(l_Window, GLFW_CONTEXT_VERSION_MINOR);
printf("OpenGL: %d.%d\n", l_Major, l_Minor);

// Make the context current for this window...
glfwMakeContextCurrent(l_Window);

// Create some lights, materials, etc...
SetOpenGLState();

// Don't forget to initialize Glew...
GLenum l_Result = glewInit();
if (l_Result!=GLEW_OK)
{
printf("glewInit() error.\n");
exit(EXIT_FAILURE);
}

// We will do some offscreen rendering, setup FBO...
ovrSizei l_TextureSizeLeft = ovrHmd_GetFovTextureSize(l_Hmd, ovrEye_Left, l_HmdDesc.DefaultEyeFov[0], 1.0f);
ovrSizei l_TextureSizeRight = ovrHmd_GetFovTextureSize(l_Hmd, ovrEye_Right, l_HmdDesc.DefaultEyeFov[1], 1.0f);
ovrSizei l_TextureSize;
l_TextureSize.w = l_TextureSizeLeft.w + l_TextureSizeRight.w;
l_TextureSize.h = (l_TextureSizeLeft.h>l_TextureSizeRight.h ? l_TextureSizeLeft.h : l_TextureSizeRight.h);

// Create FBO...
GLuint l_FBOId;
glGenFramebuffers(1, &l_FBOId);
glBindFramebuffer(GL_FRAMEBUFFER, l_FBOId);

// The texture we're going to render to...
GLuint l_TextureId;
glGenTextures(1, &l_TextureId);
// "Bind" the newly created texture : all future texture functions will modify this texture...
glBindTexture(GL_TEXTURE_2D, l_TextureId);
// Give an empty image to OpenGL (the last "0")
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, l_TextureSize.w, l_TextureSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// 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...
GLuint l_DepthBufferId;
glGenRenderbuffers(1, &l_DepthBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, l_DepthBufferId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, l_TextureSize.w, l_TextureSize.h);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, l_DepthBufferId);

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

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

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

// Oculus Rift eye configurations...
l_Eyes[0].Eye = ovrEye_Left;
l_Eyes[1].Eye = ovrEye_Right;
l_Eyes[0].Fov = l_HmdDesc.DefaultEyeFov[0];
l_Eyes[1].Fov = l_HmdDesc.DefaultEyeFov[1];
l_Eyes[0].TextureSize.w = l_TextureSize.w;
l_Eyes[0].TextureSize.h = l_TextureSize.h;
l_Eyes[1].TextureSize.w = l_TextureSize.w;
l_Eyes[1].TextureSize.h = l_TextureSize.h;
l_Eyes[0].RenderViewport.Pos.x = 0;
l_Eyes[0].RenderViewport.Pos.y = 0;
l_Eyes[1].RenderViewport.Pos.x = (l_TextureSize.w+1)/2;
l_Eyes[1].RenderViewport.Pos.y = 0;
l_Eyes[0].RenderViewport.Size.w = l_TextureSize.w/2;
l_Eyes[0].RenderViewport.Size.h = l_TextureSize.h;
l_Eyes[1].RenderViewport.Size.w = l_Eyes[0].RenderViewport.Size.w;
l_Eyes[1].RenderViewport.Size.h = l_Eyes[0].RenderViewport.Size.h;

l_Cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
l_Cfg.OGL.Header.Multisample = 0;
l_Cfg.OGL.Header.RTSize.w = l_ClientSize.w;
l_Cfg.OGL.Header.RTSize.h = l_ClientSize.h;
l_Cfg.OGL.WglContext = glfwGetWGLContext(l_Window);
l_Cfg.OGL.Window = glfwGetWin32Window(l_Window);
l_Cfg.OGL.GdiDc = GetDC(l_Cfg.OGL.Window);

int l_RenderCaps = 0;
int l_DistortionCaps = ovrDistortion_Chromatic | ovrDistortion_TimeWarp;
ovrEyeRenderDesc l_EyeRenderDesc[2];
ovrHmd_ConfigureRendering(l_Hmd, &l_Cfg.Config, l_RenderCaps, l_DistortionCaps, l_Eyes, l_EyeRenderDesc);

ovrGLTexture l_EyeTexture[2];
l_EyeTexture[0].OGL.Header.API = ovrRenderAPI_OpenGL;
l_EyeTexture[0].OGL.Header.TextureSize.w = l_TextureSize.w;
l_EyeTexture[0].OGL.Header.TextureSize.h = l_TextureSize.h;
l_EyeTexture[0].OGL.Header.RenderViewport = l_Eyes[0].RenderViewport;
l_EyeTexture[0].OGL.TexId = l_TextureId;

// Right eye uses the same texture, but a different rendering viewport...
l_EyeTexture[1] = l_EyeTexture[0];
l_EyeTexture[1].OGL.Header.RenderViewport = l_Eyes[1].RenderViewport;

glfwSetKeyCallback(l_Window, KeyCallback);
glfwSetWindowSizeCallback(l_Window, WindowSizeCallback);

GLfloat l_SpinX;
GLfloat l_SpinY;

while (!glfwWindowShouldClose(l_Window))
{
l_SpinX = (GLfloat) fmod(glfwGetTime()*17.0, 360.0);
l_SpinY = (GLfloat) fmod(glfwGetTime()*23.0, 360.0);

ovrFrameTiming m_HmdFrameTiming = ovrHmd_BeginFrame(l_Hmd, 0);

// Bind the FBO...
glBindFramebuffer(GL_FRAMEBUFFER, l_FBOId);
// Clear...
glClearColor(0.2f, 0.3f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

for (int l_EyeIndex=0; l_EyeIndex<ovrEye_Count; l_EyeIndex++)
{
ovrEyeType l_Eye = l_HmdDesc.EyeRenderOrder[l_EyeIndex];
ovrPosef l_EyePose = ovrHmd_BeginEyeRender(l_Hmd, l_Eye);

glViewport(l_EyeRenderDesc[l_Eye].Desc.RenderViewport.Pos.x, // StartX
l_EyeRenderDesc[l_Eye].Desc.RenderViewport.Pos.y, // StartY
l_EyeRenderDesc[l_Eye].Desc.RenderViewport.Size.w, // Width
l_EyeRenderDesc[l_Eye].Desc.RenderViewport.Size.h // Height
);

// Get Projection and ModelView matrici from the device...
OVR::Matrix4f l_ProjectionMatrix = ovrMatrix4f_Projection(
l_EyeRenderDesc[l_Eye].Desc.Fov, 0.3f, 100.0f, true);
OVR::Quatf l_Orientation = OVR::Quatf(l_EyePose.Orientation);
OVR::Matrix4f l_ModelViewMatrix = OVR::Matrix4f(l_Orientation.Inverted());

// Pass matrici on to OpenGL...
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(&(l_ProjectionMatrix.Transposed().M[0][0]));
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Translate for specific eye based on IPD...
glTranslatef(l_EyeRenderDesc[l_Eye].ViewAdjust.x,
l_EyeRenderDesc[l_Eye].ViewAdjust.y,
l_EyeRenderDesc[l_Eye].ViewAdjust.z);
// Multiply with orientation retrieved from sensor...
glMultMatrixf(&(l_ModelViewMatrix.Transposed().M[0][0]));
// Move back a bit to show scene in front of us...
glTranslatef(0.0f, 0.0f, -0.5f);
// Make the cube spin...
glRotatef(l_SpinX, 1.0f, 0.0f, 0.0f);
glRotatef(l_SpinY, 0.0f, 1.0f, 0.0f);

// Render...
RenderCube(0.2f);

ovrHmd_EndEyeRender(l_Hmd, l_Eye, l_EyePose, &l_EyeTexture[l_Eye].Texture);
}

// Unbind the FBO, back to normal drawing...
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// Oculus wants CW orientations, avoid the problem by turning of culling...
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
ovrHmd_EndFrame(l_Hmd);
// Restore state after Oculus did its work (-sigh-)...
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glClearDepth(1);
glUseProgramObjectARB(0);

glfwPollEvents();
}

glfwDestroyWindow(l_Window);

glfwTerminate();

ovrHmd_Destroy(l_Hmd);
ovr_Shutdown();

exit(EXIT_SUCCESS);
}

DoZo1971
Explorer
This is what you *should* see (in windowed mode).
The image is a bit too high, something going on between GLFW and Oculus and window decorations. In full screen mode it is centered correctly.

Oculus.png