The Textured Quad example textures a standard OpenGL quad with the image set from the Leap Motion cameras. 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.
14 #include "ExampleConnection.h"
17 LEAP_CONNECTION *connection;
19 LEAP_IMAGE_FRAME_REQUEST_TOKEN *image_token = 0;
20 void* image_buffer = NULL;
21 uint64_t image_size = 1;
22 bool imageRequested = false;
23 bool imageReady = false;
24 bool textureChanged = false;
25 uint32_t image_width = 0;
26 uint32_t image_height = 0;
29 int window; // GLUT window handle
31 /** Callback for when an image request completes. */
32 void OnImages(const LEAP_IMAGE_COMPLETE_EVENT *imageCompleteEvent){
33 if(image_width != imageCompleteEvent->properties->width ||
34 image_height != imageCompleteEvent->properties->height){
35 image_width = imageCompleteEvent->properties->width;
36 image_height = imageCompleteEvent->properties->height;
37 textureChanged = true;
41 imageRequested = false;
45 /** Callback for when an image request fails. */
46 void OnImageError(const LEAP_IMAGE_FRAME_REQUEST_ERROR_EVENT *imageErrorEvent){
47 if(imageErrorEvent->error == eLeapImageRequestError_ImagesDisabled)
48 printf("Warning: Images disabled. Check your control panel settings.");
50 //Resize image buffer if too small
51 if(image_size < imageErrorEvent->required_buffer_len){
52 image_size = imageErrorEvent->required_buffer_len;
53 if(image_buffer) free(image_buffer);
54 image_buffer = malloc((size_t)image_size);
55 printf("Resized image buffer to %lli.\n", (long long int)image_size);
60 imageRequested = false;
64 /* Notifies us that a new frame is available. */
65 void OnFrame(const LEAP_TRACKING_EVENT *frame){
66 if(!imageRequested && !imageReady){
67 imageRequested = true;
68 LEAP_IMAGE_FRAME_DESCRIPTION frameDescription;
69 frameDescription.type = eLeapImageType_Default;
70 frameDescription.frame_id = frame->info.frame_id;
71 frameDescription.buffer_len = image_size;
72 frameDescription.pBuffer = image_buffer;
74 image_token = malloc(sizeof(LEAP_IMAGE_FRAME_REQUEST_TOKEN));
75 eLeapRS result = LeapRequestImages(*connection, &frameDescription, image_token);
76 if(result != eLeapRS_Success)
77 printf("LeapRequestImages call was %s.\n", ResultString(result));
81 // Draw a textured quad displaying the image data
82 void DrawImageQuad(float p1X, float p1Y, float p2X, float p2Y, int width, int height, void* imagedata){
83 glEnable(GL_TEXTURE_2D);
85 textureChanged = false;
86 glDeleteTextures(1, &texture);
87 glGenTextures(1, &texture);
88 glBindTexture(GL_TEXTURE_2D, texture);
89 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
90 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imagedata);
91 checkGLError("Initializing texture.");
92 } else { //update existing texture
93 glBindTexture ( GL_TEXTURE_2D, texture);
94 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, imagedata);
95 checkGLError("Updating texture.");
97 //Draw a texture-mapped quad
99 glTexCoord2f(1, 1); glVertex2f((GLfloat)p1X, (GLfloat)p1Y);
100 glTexCoord2f(0, 1); glVertex2f((GLfloat)p2X, (GLfloat)p1Y);
101 glTexCoord2f(0, 0); glVertex2f((GLfloat)p2X, (GLfloat)p2Y);
102 glTexCoord2f(1, 0); glVertex2f((GLfloat)p1X, (GLfloat)p2Y);
104 checkGLError("Drawing quad.");
105 glDisable(GL_TEXTURE_2D);
111 glMatrixMode(GL_MODELVIEW);
113 glTranslatef(-32, -24, -50); //"Camera" viewpoint
114 glClear(GL_COLOR_BUFFER_BIT);
116 DrawImageQuad(0, 0, 64, 48, image_width, image_height * 2, image_buffer);
124 void reshape(int w, int h)
126 glViewport(0, 0, (GLsizei) w, (GLsizei) h);
127 glMatrixMode(GL_PROJECTION);
129 gluPerspective(60, 640/240, 1.0, 1000);
132 void keyboard(unsigned char key, int x, int y)
137 glutDestroyWindow(window);
139 LeapCancelImageFrameRequest(*connection, *image_token);
140 if(image_buffer) free(image_buffer);
153 int main(int argc, char *argv[])
155 ConnectionCallbacks.on_frame = OnFrame;
156 ConnectionCallbacks.on_image_complete = OnImages;
157 ConnectionCallbacks.on_image_request_error = OnImageError;
159 connection = OpenConnection();
165 glutInit(&argc, argv);
166 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
167 glutInitWindowSize(640, 480);
168 window = glutCreateWindow("LeapC Image Example");
172 glutReshapeFunc(reshape);
173 glutKeyboardFunc(keyboard);
174 glutDisplayFunc(display);
177 glClearColor(0.0, 0.0, 0.0, 0.0);
178 glColor3f(1.0, 1.0, 1.0);
This example is only supported on platforms for which a working version of GLUT exists. It should not be overly difficult to port the example to a different OpenGL-based context, however.