Textured Quad Example

The Textured Quad example textures a standard OpenGL quad with the image set from an Ultraleap Hand Tracking Camera. Both images are included in one texture, with the left image above the right image.

The example uses callbacks to get tracking frames. When a frame becomes available, the example requests the corresponding image. When LeapC calls the image complete callback, the example sets an “imageReady” state variable. The example’s GLUT idle function monitors the imageReady variable, and tells GLUT to redraw the display when the variable evaluates as true. The drawing is then performed when GLUT calls the display() function.

The quad is drawn using the OpenGL fixed function pipeline for simplicity. In all but the simplest cases, you should use the modern shader-based pipeline instead. Using shaders will also give you the ability to correct the image distortion for very little cost.

  1 #undef __cplusplus
  2
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5
  6 #ifdef _WIN32
  7 #include <Windows.h>
  8 #else
  9 #include <unistd.h>
 10 #endif
 11
 12 #include <time.h>
 13 #include <string.h>
 14 #include "LeapC.h"
 15 #include "ExampleConnection.h"
 16 #include "GLutils.h"
 17
 18 void* image_buffer = NULL;
 19 uint64_t image_size = 0;
 20 bool imageReady = false;
 21 bool textureChanged = false;
 22 uint32_t image_width = 0;
 23 uint32_t image_height = 0;
 24 GLuint texture = 0;
 25 int window; // GLUT window handle
 26
 27 /** Callback for when an image is available. */
 28 static void OnImage(const LEAP_IMAGE_EVENT *imageEvent){
 29   const LEAP_IMAGE_PROPERTIES* properties = &imageEvent->image[0].properties;
 30   if (properties->bpp != 1)
 31     return;
 32
 33   if (properties->width*properties->height != image_size) {
 34     void* prev_image_buffer = image_buffer;
 35     image_width = properties->width;
 36     image_height = properties->height;
 37     image_size = image_width*image_height;
 38     image_buffer = malloc(2 * image_size);
 39     if (prev_image_buffer)
 40       free(prev_image_buffer);
 41     textureChanged = true;
 42   }
 43
 44   memcpy(image_buffer, (char*)imageEvent->image[0].data + imageEvent->image[0].offset, image_size);
 45   memcpy((char*)image_buffer + image_size, (char*)imageEvent->image[1].data + imageEvent->image[1].offset, image_size);
 46   imageReady = true;
 47 }
 48
 49 // Draw a textured quad displaying the image data
 50 static void DrawImageQuad(float p1X, float p1Y, float p2X, float p2Y, int width, int height, void* imagedata){
 51   glEnable(GL_TEXTURE_2D);
 52   if(textureChanged){
 53     textureChanged = false;
 54     glDeleteTextures(1, &texture);
 55     glGenTextures(1, &texture);
 56     glBindTexture(GL_TEXTURE_2D, texture);
 57     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 58     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imagedata);
 59     checkGLError("Initializing texture.");
 60   } else { //update existing texture
 61     glBindTexture ( GL_TEXTURE_2D, texture);
 62     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, imagedata);
 63     checkGLError("Updating texture.");
 64   }
 65   //Draw a texture-mapped quad
 66   glBegin(GL_QUADS);
 67     glTexCoord2f(1, 1); glVertex2f((GLfloat)p1X, (GLfloat)p1Y);
 68     glTexCoord2f(0, 1); glVertex2f((GLfloat)p2X, (GLfloat)p1Y);
 69     glTexCoord2f(0, 0); glVertex2f((GLfloat)p2X, (GLfloat)p2Y);
 70     glTexCoord2f(1, 0); glVertex2f((GLfloat)p1X, (GLfloat)p2Y);
 71   glEnd();
 72   checkGLError("Drawing quad.");
 73   glDisable(GL_TEXTURE_2D);
 74 }
 75 // Done drawing quad
 76
 77 static void display(void)
 78 {
 79   glMatrixMode(GL_MODELVIEW);
 80   glPushMatrix();
 81   glTranslatef(-32, -24, -50); //"Camera" viewpoint
 82   glClear(GL_COLOR_BUFFER_BIT);
 83   if(imageReady){
 84     DrawImageQuad(0, 0, 64, 48, image_width, image_height * 2, image_buffer);
 85     imageReady = false;
 86   }
 87   glFlush();
 88   glPopMatrix();
 89   glutSwapBuffers();
 90 }
 91
 92 static void reshape(int w, int h)
 93 {
 94   glViewport(0, 0, (GLsizei) w, (GLsizei) h);
 95   glMatrixMode(GL_PROJECTION);
 96   glLoadIdentity();
 97   gluPerspective(60, 640/240, 1.0, 1000);
 98 }
 99
100 static void keyboard(unsigned char key, int x, int y)
101 {
102   switch((char)key) {
103   case 'q':
104   case 27:  // ESC
105     glutDestroyWindow(window);
106     CloseConnection();
107     if(image_buffer) free(image_buffer);
108     exit(0);
109   default:
110     break;
111   }
112 }
113
114 static void idle(void){
115   if(imageReady)
116     glutPostRedisplay();
117 }
118
119 int main(int argc, char *argv[])
120 {
121   ConnectionCallbacks.on_image = OnImage;
122
123   LEAP_CONNECTION *connection = OpenConnection();
124   LeapSetPolicyFlags(*connection, eLeapPolicyFlag_Images, 0);
125
126   while(!IsConnected){
127     millisleep(250);
128   }
129
130   glutInit(&argc, argv);
131   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
132   glutInitWindowSize(640, 480);
133   window = glutCreateWindow("LeapC Image Example");
134
135   // GLUT callbacks
136   glutIdleFunc(idle);
137   glutReshapeFunc(reshape);
138   glutKeyboardFunc(keyboard);
139   glutDisplayFunc(display);
140
141   // init GL
142   glClearColor(0.0, 0.0, 0.0, 0.0);
143   glColor3f(1.0, 1.0, 1.0);
144
145   // Start GLUT loop
146   glutMainLoop();
147
148   CloseConnection();
149   return 0;
150 }
151 //End-of-Sample

This example is only supported on platforms for which a working version of GLUT exists. However, It should not be overly difficult to port the example to a different OpenGL-based context. Back to top