Skip to main content
Up and Coming
April 27, 2014

Simple OpenGL example with GLFW, GLEW and OculusSDK 0.3.1

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

    Up and Coming
    May 4, 2014
    "DoZo1971" wrote:

    @ckoeber: what happens if you try to "force" a 4.3 context?
    By adding

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);

    before

    glfwCreateWindow(...)



    Here you go:

    Up and Coming
    May 4, 2014
    "rsato" wrote:
    Hello,
    I used this program on another workstation which natively support OpenGL 4.4 and the program worked fine without Rift.
    This sample apparently does not work with OpenGL 3.3.

    Thank you for your help!


    The first workstation I tired comes with Quadro FX 3800 and it does not seem to support OpenGL 4.X even with the latest driver.


    I am using an AMD Radeon R9 290x which supports OpenGL 4.4; this seems to be an issue with a specific function call that the Oculus Rift is making which works for only some video cards, etc.

    Let's keep at this, folks; there has to be a solution.
    DoZo1971Author
    Up and Coming
    May 4, 2014
    Ok...

    At least I can confirm it's an AMD thing. On my AMD system I've loaded the LibOVR_With_Samples_XXX.sln solution in Visual Studio and fixed the cast errors in CAPI_GL_DistortionRenderer.cpp ("oColor = Color.r" -> "oColor = vec4(Color.r)", 2x) which caused the shaders to not compile until now. Rebuilt the solution (debug and release) and ran the test:

    Same behavior.
    Now to fix.
    Ehm...
    DoZo1971Author
    Up and Coming
    May 4, 2014
    Solved!

    I've changed the lines as mentioned by cybereality in the thread you started in the report issues section.

    So:


    renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
    NULL, 0, (int)DistortionMeshVBs[eyeNum]->GetSize(), Prim_Triangles, true);


    should be changed to


    renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
    NULL, 0, (int)DistortionMeshIBs[eyeNum]->GetSize()/2, Prim_Triangles, true);


    twice in CAPI_GL_DistortionRenderer.cpp. Somewhere around line 760 (I did some editing, don't know the exact line)
    Rebuild the libs. Presto.

    See attach. Note the vendor printed in the console. ;-)
    Inspiring
    May 4, 2014
    That's a good catch. It looks like in initBuffersAndShaders() in the GL distortion rendering code, they drop the number of indices on the floor, rather than record it in a local structure, and then they attempt to use the buffer size to replace it, except a) they're using the wrong buffer and b) not accounting for the difference between buffer size in bytes and index size in shorts.
    Brad Davis - Developer for High Fidelity Co-author of Oculus Rift in Action
    Up and Coming
    May 4, 2014
    Thanks so much, @DoZo1971!

    One last question; did you experience at one point the "missing headers" issue when compiling the standard solution from Oculus?

    How did you solve that one?
    Up and Coming
    May 4, 2014
    "ckoeber" wrote:
    Thanks so much, @DoZo1971!

    One last question; did you experience at one point the "missing headers" issue when compiling the standard solution from Oculus?

    How did you solve that one?


    Never mind; the problem was that I didn't have VC++ 2010 runtime libraries. Installed them and I got the headers to compile.
    New Participant
    May 5, 2014
    Thank you, DoZo1971

    I changed the line you mentioned above and now it works perfect with OpenGL 3.3 :D
    Up and Coming
    May 9, 2014
    This is some great sample code! And some nice fixes! Thanks guys!

    Thanks to this, the JRift library is now up and running with 0.3.1 on Windows; and I've got a test app shamelessly ripped from this code, ported to Java, and running with LWJGL.

    JRift on 0.3.1 (still WIP): HERE

    Hopefully this may be of use - here's some (possibly ropey) sample code for Java (including getting the required GL pointers from LWJGL):
    (FBO class ripped from Minecrift FBOParams class) HERE

    // GLFWOculusRiftTest
    // (c) cThrough 2014 (Daniel Dekkers)
    // Version 2014050100
    // Java port StellaArtois 2014
    import de.fruitfly.ovr.EyeRenderParams;
    import de.fruitfly.ovr.OculusRift;
    import de.fruitfly.ovr.enums.EyeType;
    import de.fruitfly.ovr.structs.*;
    import org.lwjgl.BufferUtils;
    import org.lwjgl.LWJGLException;
    import org.lwjgl.LWJGLUtil;
    import org.lwjgl.input.Keyboard;
    import org.lwjgl.input.Mouse;
    import org.lwjgl.opengl.*;
    import org.newdawn.slick.opengl.Texture;
    import org.newdawn.slick.opengl.TextureLoader;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.nio.FloatBuffer;
    import java.nio.IntBuffer;
    import java.text.DecimalFormat;

    public class JRiftTest
    {
    OculusRift or = new OculusRift();

    public static void main(String[] argv)
    {
    JRiftTest example = new JRiftTest();
    example.start();
    }

    public void start()
    {
    int width = 640;
    int height = 480;
    Sizei windowRes = new Sizei(width, height);
    boolean fullscreen = false;

    try
    {
    // Init JRift
    OculusRift.LoadLibrary();
    if (!or.init())
    throw new Exception("Failed to initialise OR lib");

    // Get HMD configuration
    HmdDesc hmdDesc = or.getHmdDesc();
    System.out.println(hmdDesc);

    // init LWJGL display
    createDisplay(windowRes, hmdDesc.Resolution, fullscreen);

    // Get recommended render target size
    Sizei renderTargetSize = or.getFovTextureSize();

    // Setup FBO
    FBO renderTarget = new FBO("renderTarget",
    GL11.GL_TEXTURE_2D, GL11.GL_RGBA8, GL11.GL_RGBA, GL11.GL_INT, renderTargetSize.w, renderTargetSize.h);

    // Get Gl pointer info from LWJGL
    GLConfig glConfig = getGlInfo();
    glConfig.TexId = renderTarget.getColorTextureId();

    // Setup oculus SDK rendering
    EyeRenderParams er = or.configureRendering(renderTargetSize,
    fullscreen ? hmdDesc.Resolution : windowRes,
    glConfig,
    true); // Enable Vsync

    // Setup OpenGL lighting etc.
    SetOpenGLState();

    // Render loop - ESC or close window to exit
    while (!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE))
    {
    l_SpinX = ((((float)(System.currentTimeMillis() - startTime) / 1000f) * 17.0f) % 360.0f);
    l_SpinY = ((((float)(System.currentTimeMillis() - startTime) / 1000f) * 23.0f) % 360.0f);

    // Mark the beginning of the frame
    FrameTiming frameTiming = or.beginFrame();

    // Bind render target
    renderTarget.bindRenderTarget();
    GL11.glEnable(GL11.GL_TEXTURE_2D);
    renderTarget.bindTexture();

    // Clear the screen and depth buffer
    GL11.glClearColor(0.2f, 0.3f, 0.4f, 1.0f);
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

    // Get sensorstate at the appropriate time in the future
    SensorState ss = or.poll(frameTiming.ScanoutMidpointSeconds);

    // Render each eye view in order specified by hmdDesc
    for (int eyeIndex = 0; eyeIndex < EyeType.ovrEye_Count.value(); eyeIndex++)
    {
    EyeType eye = hmdDesc.EyeRenderOrder[eyeIndex];

    // Mark begin eye render
    Posef eyeRenderPose = or.beginEyeRender(eye);

    // Set viewport
    GL11.glViewport(er.Eyes[eye.value()].Desc.RenderViewport.Pos.x,
    er.Eyes[eye.value()].Desc.RenderViewport.Pos.y,
    er.Eyes[eye.value()].Desc.RenderViewport.Size.w,
    er.Eyes[eye.value()].Desc.RenderViewport.Size.h
    );

    // Get projection
    Matrix4f l_ProjectionMatrix = or.getMatrix4fProjection(er.Eyes[eye.value()].Desc.Fov, 0.3f, 100.0f);
    Quatf l_Orientation = eyeRenderPose.Orientation;
    Matrix4f l_ModelViewMatrix = new Matrix4f(l_Orientation.inverted());

    // Pass matrici on to OpenGL...
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GL11.glMultMatrix(l_ProjectionMatrix.transposed().toFloatBuffer());
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glLoadIdentity();
    // Translate for specific eye based on IPD and position...
    GL11.glTranslatef(er.Eyes[eye.value()].ViewAdjust.x,
    er.Eyes[eye.value()].ViewAdjust.y,
    er.Eyes[eye.value()].ViewAdjust.z);
    // Multiply with orientation retrieved from sensor...
    GL11.glMultMatrix(l_ModelViewMatrix.transposed().toFloatBuffer());
    // Move back a bit to show scene in front of us...
    GL11.glTranslatef(0.0f, 0.0f, -2.0f);
    // Make the cube spin...
    GL11.glRotatef(l_SpinX, 1.0f, 0.0f, 0.0f);
    GL11.glRotatef(l_SpinY, 0.0f, 1.0f, 0.0f);

    // Render...
    RenderCubeFixedFunction();
    //RenderCubeVertexArrays(); // Broken?

    // Mark end eye render
    or.endEyeRender(eye);
    }

    // Unbind the FBO, back to normal drawing...
    renderTarget.unbindFBORenderTarget();

    GL11.glDisable(GL11.GL_CULL_FACE); // Oculus wants CW orientations, avoid the problem by turning off culling...
    GL11.glDisable(GL11.GL_DEPTH_TEST); // Nothing is drawn with depth test on...

    // End the frame
    or.endFrame();

    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); // Unbind GL_ARRAY_BUFFER for my own vertex arrays to work...
    GL11.glEnable(GL11.GL_CULL_FACE); // Turn back on...
    GL11.glEnable(GL11.GL_DEPTH_TEST); // Turn back on...
    GL11.glClearDepth(1); // Oculus set this to 0 (the near plane), return to normal...
    ARBShaderObjects.glUseProgramObjectARB(0); // Oculus shader is still active, turn it off...

    // Process display messages ONLY - don't do Display.update()
    Display.processMessages();
    }

    or.destroy();

    texture.release();
    Display.destroy();
    }
    catch (Exception e)
    {
    e.printStackTrace();
    System.exit(0);
    }
    }

    private GLConfig getGlInfo()
    {
    // TODO: For LWJGL 3.0, this function may well be screwed...

    // We need to retrieve certain pointers / handles from LWJGL
    // for the Oculus SDK. However, these are not exposed by
    // LWJGL, so use reflection to get hold of the data we need.

    boolean isWindows = false;
    GLConfig glConfig = new GLConfig();

    try
    {
    switch(LWJGLUtil.getPlatform())
    {
    case LWJGLUtil.PLATFORM_WINDOWS:
    isWindows = true;
    break;
    }

    if (!isWindows)
    throw new Exception ("Currently only the Windows platform is supported!");

    Object displayImpl = null;
    Object contextGL = null;
    Object winContextImpl = null;
    Object contextHandle = null;

    // Get HWND and HDC pointers...

    // Get underlying display implementation
    Method displayMethod = Display.class.getDeclaredMethod("getImplementation");
    displayMethod.setAccessible(true);
    displayImpl = displayMethod.invoke(null, null);

    // Get hwnd field
    Field fHwnd = displayImpl.getClass().getDeclaredField("hwnd");
    fHwnd.setAccessible(true);
    glConfig.Window = (Long) fHwnd.get(displayImpl);

    // Get hdc field
    Field fhdc = displayImpl.getClass().getDeclaredField("hdc");
    fhdc.setAccessible(true);
    glConfig.GdiDc = (Long)fhdc.get(displayImpl);

    // Get HGLRC pointer...

    // get GLContext instance from GLContext.getCurrentContext()
    Class<?> contextGLClass = Class.forName("org.lwjgl.opengl.ContextGL");
    Method getCurrentContext = contextGLClass.getDeclaredMethod("getCurrentContext");
    getCurrentContext.setAccessible(true);
    contextGL = getCurrentContext.invoke(null, null);

    // Get context handle
    Method getHandle = contextGL.getClass().getDeclaredMethod("getHandle");
    getHandle.setAccessible(true);
    contextHandle = getHandle.invoke(contextGL, null);

    // Get windows implementation instance
    Field implementation = contextGL.getClass().getDeclaredField("implementation");
    implementation.setAccessible(true);
    winContextImpl = implementation.get(contextGL);

    // Get HGLRC from win impl class, passing previously retrieved context handle
    // getHGLRC is a native call
    Class<?> winContextImplClass = Class.forName("org.lwjgl.opengl.WindowsContextImplementation");
    Method[] winContextImplMethods = winContextImplClass.getDeclaredMethods();
    for (Method m : winContextImplMethods)
    {
    if (m.getName().equals("getHGLRC"))
    {
    m.setAccessible(true);
    glConfig.WglContext = (Long)m.invoke(winContextImpl, contextHandle);
    break;
    }
    }

    System.out.println(String.format("hWnd: 0x%X", new Object[] {glConfig.Window}));
    System.out.println(String.format("hdC: 0x%X", new Object[] {glConfig.GdiDc}));
    System.out.println(String.format("hGLRC: 0x%X", new Object[] {glConfig.WglContext}));
    }
    catch (Exception ex)
    {
    ex.printStackTrace();
    glConfig = null;
    }

    return glConfig;
    }

    private void dumpPose(SensorState ss)
    {
    Vector3f euler = or.getEulerAngles(ss.Recorded.Pose.Orientation,
    1.0f,
    OculusRift.HANDED_L,
    OculusRift.ROTATE_CCW);
    Vector3f pos = ss.Predicted.Pose.Position;

    DecimalFormat fmt = new DecimalFormat("+000.0000;-000.0000");
    String dump = String.format("Yaw: %s, Pitch: %s, Roll: %s, PosX: %s, PosY: %s, PosZ: %s",
    new Object[] {fmt.format(euler.y), fmt.format(euler.x), fmt.format(euler.z), fmt.format(pos.x), fmt.format(pos.y), fmt.format(pos.z)});
    System.out.println(dump);
    }

    void RenderCubeFixedFunction()
    {
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture.getTextureID());

    GL11.glBegin(GL11.GL_QUADS);
    GL11.glNormal3f(0.0f, 0.0f, 1.0f);
    GL11.glVertex3f(0.5f, 0.5f, 0.5f);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(-0.5f, 0.5f, 0.5f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(-0.5f, -0.5f, 0.5f);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(0.5f, -0.5f, 0.5f);
    GL11.glTexCoord2f(1, 1);
    GL11.glEnd();

    GL11.glBegin(GL11.GL_QUADS);
    GL11.glNormal3f(0.0f, 0.0f, -1.0f);
    GL11.glVertex3f(-0.5f, -0.5f, -0.5f);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(-0.5f, 0.5f, -0.5f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(0.5f, 0.5f, -0.5f);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(0.5f, -0.5f, -0.5f);
    GL11.glTexCoord2f(1, 1);
    GL11.glEnd();

    GL11.glBegin(GL11.GL_QUADS);
    GL11.glNormal3f(0.0f, 1.0f, 0.0f);
    GL11.glVertex3f(0.5f, 0.5f, 0.5f);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(0.5f, 0.5f, -0.5f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(-0.5f, 0.5f, -0.5f);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(-0.5f, 0.5f, 0.5f);
    GL11.glTexCoord2f(1, 1);
    GL11.glEnd();

    GL11.glBegin(GL11.GL_QUADS);
    GL11.glNormal3f(0.0f, -1.0f, 0.0f);
    GL11.glVertex3f(-0.5f, -0.5f, -0.5f);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(0.5f, -0.5f, -0.5f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(0.5f, -0.5f, 0.5f);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(-0.5f, -0.5f, 0.5f);
    GL11.glTexCoord2f(1, 1);
    GL11.glEnd();

    GL11.glBegin(GL11.GL_QUADS);
    GL11.glNormal3f(1.0f, 0.0f, 0.0f);
    GL11.glVertex3f(0.5f, 0.5f, 0.5f);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(0.5f, -0.5f, 0.5f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(0.5f, -0.5f, -0.5f);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(0.5f, 0.5f, -0.5f);
    GL11.glTexCoord2f(1, 1);
    GL11.glEnd();

    GL11.glBegin(GL11.GL_QUADS);
    GL11.glNormal3f(-1.0f, 0.0f, 0.0f);
    GL11.glVertex3f(-0.5f, -0.5f, -0.5f);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex3f(-0.5f, -0.5f, 0.5f);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex3f(-0.5f, 0.5f, 0.5f);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex3f(-0.5f, 0.5f, -0.5f);
    GL11.glTexCoord2f(1, 1);
    GL11.glEnd();

    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
    }

    void RenderCubeVertexArrays()
    {
    GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
    GL11.glVertexPointer(3, GL11.GL_FLOAT, l_VAPoints);
    GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
    GL11.glNormalPointer(GL11.GL_FLOAT, l_VANormals);
    GL11.glDrawElements(GL11.GL_QUADS, l_VAIndici);
    GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
    GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
    }

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

    // Some (stationary) lights...
    FloatBuffer l_Light0Position = (FloatBuffer)BufferUtils.createFloatBuffer(4).put(new float[]{5.0f, 6.0f, 3.0f, 0.0f}).flip();
    FloatBuffer l_Light0Diffuse = (FloatBuffer)BufferUtils.createFloatBuffer(4).put(new float[] { 1.0f, 0.8f, 0.6f, 1.0f }).flip();
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, l_Light0Position);
    GL11.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, l_Light0Diffuse);
    GL11.glEnable(GL11.GL_LIGHT0);

    FloatBuffer l_Light1Position = (FloatBuffer)BufferUtils.createFloatBuffer(4).put(new float[]{-5.0f, -6.0f, 5.0f, 0.0f}).flip();
    FloatBuffer l_Light1Diffuse = (FloatBuffer)BufferUtils.createFloatBuffer(4).put(new float[]{0.6f, 0.8f, 1.0f, 1.0f}).flip();
    GL11.glLight(GL11.GL_LIGHT1, GL11.GL_POSITION, l_Light1Position);
    GL11.glLight(GL11.GL_LIGHT1, GL11.GL_DIFFUSE, l_Light1Diffuse);
    GL11.glEnable(GL11.GL_LIGHT1);

    // Material...
    FloatBuffer l_MaterialSpecular = (FloatBuffer)BufferUtils.createFloatBuffer(4).put(new float[]{0.3f, 0.3f, 0.3f, 1.0f}).flip();
    FloatBuffer l_MaterialShininess = (FloatBuffer)BufferUtils.createFloatBuffer(4).put(new float[]{10.0f, 0.0f, 0.0f, 0.0f}).flip();
    GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, l_MaterialSpecular);
    GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SHININESS, l_MaterialShininess);

    // Texture... (Power of 2! - 256X256)
    texture = TextureLoader.getTexture("PNG", new FileInputStream(new File("res/logo.png")));
    }

    void createDisplay(Sizei windowRes, Sizei hmdRes, boolean fullscreen) throws LWJGLException
    {
    if (fullscreen) {
    Display.setDisplayModeAndFullscreen(getDisplayMode(hmdRes));
    Display.setVSyncEnabled(true);
    }
    else {
    Display.setDisplayMode(getDisplayMode(windowRes));
    }
    Display.create();

    if (fullscreen)
    Mouse.setGrabbed(true);
    }

    DisplayMode getDisplayMode(Sizei res) throws LWJGLException
    {
    DisplayMode displayMode = null;
    DisplayMode[] modes = Display.getAvailableDisplayModes();

    for (int i = 0; i < modes.length; i++)
    {
    if (modes[i].getWidth() == res.w
    && modes[i].getHeight() == res.h
    && modes[i].isFullscreenCapable())
    {
    displayMode = modes[i];
    }
    }

    if (displayMode == null)
    {
    displayMode = new DisplayMode(res.w, res.h);
    }

    return displayMode;
    }

    FloatBuffer l_VAPoints = (FloatBuffer)BufferUtils.createFloatBuffer(72).put(new float[]
    {
    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,
    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,
    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
    }).flip();

    FloatBuffer l_VANormals = (FloatBuffer)BufferUtils.createFloatBuffer(72).put(new float[]
    {
    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
    }).flip();

    IntBuffer l_VAIndici = (IntBuffer)BufferUtils.createIntBuffer(24).put(new int[]
    {
    0, 1, 2, 3,
    4, 5, 6, 7,
    8, 9, 10, 11,
    12, 13, 14, 15,
    16, 17, 18, 19,
    20, 21, 22, 23
    }).flip();

    float l_SpinX;
    float l_SpinY;
    final long startTime = System.currentTimeMillis();
    Texture texture;
    }


    JRift031.jpg
    Participant
    May 13, 2014
    Hi everyone, sorry if this question is trivial, I've just been stuck on this for a while:

    I'm trying to adapt the opengl-tutorial.org tutorials to dispaly on the Rift. Specifically the last tutorial, the one on particles and instancing: http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/particles-instancing/

    I've been trying to adapt the code here for this purpose, but I've hit a problem: I can't figure out how to send an OVR::Matrix4f matrix to the shaders. Apparently OVR::Matrix4f doesn't support the [] operator, so this line for example doesn't work:

    OVR::Matrix4f l_ViewProjectionMatrix = l_ProjectionMatrix * l_ModelViewMatrix;
    glUniformMatrix4fv(ViewProjMatrixID, 1, GL_FALSE, &l_ViewProjectionMatrix[0][0]);


    Any ideas how to deal with this?

    Thanks!