Leap Motion C API  3.1
The API to the LeapC library.
Rectifying with a Shader Example

To rectify an image with a shader, you can upload both the image data and the distortion maps and apply them as textures to an object such as a quad. Instead of sampling the image data directly, your fragment shader instead samples the distortion map texture. You then use the texture coordinates from the distortion texture to look up the brightness value in the image texture. See Rectifying with a Shader for more information about the distortion map texture and the fragment shader to use it.

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 "LeapC.h"
14 #include "ExampleConnection.h"
15 #include "GLutils.h"
16 #include <math.h>
17 #include <string.h>
18 
19 static const char* GLSL_VERT = STRINGIFY(
20  \n#version 120\n
21 
22  void main()
23  {
24  gl_Position = ftransform();
25  gl_TexCoord[0]=gl_MultiTexCoord0;
26  }
27 );
28 static const char* GLSL_FRAG = STRINGIFY(
29  \n#version 120\n
30  uniform sampler2D rawTexture;
31  uniform sampler2D distortionTexture;
32 
33  void main()
34  {
35  vec2 distortionIndex = texture2D(distortionTexture, gl_TexCoord[0].st).xy;
36  float hIndex = distortionIndex.r;
37  float vIndex = distortionIndex.g;
38 
39  if(vIndex > 0.0 && vIndex < 1.0 && hIndex > 0.0 && hIndex < 1.0)
40  {
41  gl_FragColor = vec4(texture2D(rawTexture, distortionIndex).rrr, 1.0);
42  }
43  else
44  {
45  gl_FragColor = vec4(0.2, 0.0, 0.0, 1.0);
46  }
47  }
48 );
49 
50 LEAP_CONNECTION *connection;
51 
52 LEAP_IMAGE_FRAME_REQUEST_TOKEN *image_token = 0;
53 GLsizei image_width;
54 GLsizei image_height;
55 void* image_buffer = NULL;
56 float* distortion_buffer_left = NULL;
57 float* distortion_buffer_right = NULL;
58 uint64_t image_size = 1;
59 bool imageRequested = false;
60 bool imageReady = false;
61 uint64_t currentDistortionId = 0;
62 
63 int window; // GLUT window handle
64 int windowWidth = 800;
65 int windowHeight = 400;
66 
67 GLuint vertShader, fragShader, program;
68 GLuint rawTextureLeft = 0;
69 GLuint rawTextureRight = 0;
70 GLuint distortionTextureLeft = 0;
71 GLuint distortionTextureRight = 0;
72 
73 /** Callback for when an image request completes. */
74 void OnImages(const LEAP_IMAGE_COMPLETE_EVENT *imageCompleteEvent){
75  free(image_token);
76  image_token = 0;
77  imageRequested = false;
78  imageReady = true;
79  image_width = imageCompleteEvent->properties->width;
80  image_height = imageCompleteEvent->properties->height;
81 
82  //Save the distortion data if it's version id changes
83  if(currentDistortionId != imageCompleteEvent->matrix_version){
84  size_t distortion_size = 64 * 64 * 2;
85  distortion_buffer_left = malloc(sizeof(float) * distortion_size);
86  distortion_buffer_right = malloc(sizeof(float) * distortion_size);
87  memcpy(distortion_buffer_left, imageCompleteEvent->distortion_matrix[0], sizeof(float) * distortion_size);
88  memcpy(distortion_buffer_right, imageCompleteEvent->distortion_matrix[1], sizeof(float) * distortion_size);
89  currentDistortionId = imageCompleteEvent->matrix_version;
90  }
91 }
92 
93 /** Callback for when an image request fails. */
94 void OnImageError(const LEAP_IMAGE_FRAME_REQUEST_ERROR_EVENT *imageErrorEvent){
95  if(imageErrorEvent->error == eLeapImageRequestError_ImagesDisabled)
96  printf("Warning: Images disabled. Check your control panel settings.");
97 
98  //Resize image buffer if too small
99  if(image_size < imageErrorEvent->required_buffer_len){
100  image_size = imageErrorEvent->required_buffer_len;
101  if(image_buffer) free(image_buffer);
102  image_buffer = malloc((size_t)image_size);
103  printf("Resized image buffer to %lli.\n", (long long int)image_size);
104  }
105 
106  free(image_token);
107  image_token = NULL;
108  imageRequested = false;
109  imageReady = false;
110 }
111 
112 /* Notifies us that a new frame is available. */
113 void OnFrame(const LEAP_TRACKING_EVENT *frame){
114  if(!imageRequested && !imageReady){
115  imageRequested = true;
116  LEAP_IMAGE_FRAME_DESCRIPTION frameDescription;
117  frameDescription.type = eLeapImageType_Default;
118  frameDescription.frame_id = frame->info.frame_id;
119  frameDescription.buffer_len = image_size;
120  frameDescription.pBuffer = image_buffer;
121 
122  image_token = malloc(sizeof(LEAP_IMAGE_FRAME_REQUEST_TOKEN));
123  eLeapRS result = LeapRequestImages(*connection, &frameDescription, image_token);
124  if(result != eLeapRS_Success)
125  printf("LeapRequestImages call was %s.\n", ResultString(result));
126  }
127 }
128 
129 void display(void)
130 {
131  glMatrixMode(GL_MODELVIEW);
132  glLoadIdentity();
133 
134  glPushMatrix();
135  glClearColor(1.0f, 1.0f, 1.0f, 1.0f );
136  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
137 
138  if(imageReady){
139  //Setup perspective and view matrices
140  glMatrixMode(GL_PROJECTION);
141  checkGLError("set matrix mode");
142  glLoadIdentity();
143  setPerspectiveFrustrum(96, windowWidth/windowHeight, 1, 20);
144  checkGLError("set frustrum");
145 
146  glMatrixMode(GL_MODELVIEW);
147  glPushMatrix();
148  glTranslatef(1.05f, 0.0, -1.01f);
149 
150  glEnable(GL_TEXTURE_2D);
151  glUseProgram(program);
152 
153  // Left camera image
154  glActiveTexture(GL_TEXTURE0);
155  glBindTexture(GL_TEXTURE_2D, rawTextureLeft);
156  glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, image_width, image_height, 0, GL_RED, GL_UNSIGNED_BYTE, image_buffer);
157  checkGLError("Initializing raw texture");
158 
159  glActiveTexture(GL_TEXTURE1);
160  glBindTexture(GL_TEXTURE_2D, distortionTextureLeft);
161  glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, 64, 64, 0, GL_RG, GL_FLOAT, distortion_buffer_left);
162  checkGLError("Initializing distortion texture");
163 
164  glBegin(GL_QUADS); // Draw A Quad for camera image
165  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
166  glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
167  glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f); // Bottom Right
168  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
169  glEnd();
170 
171  // Right camera image
172  glActiveTexture(GL_TEXTURE0);
173  glBindTexture(GL_TEXTURE_2D, rawTextureRight);
174  glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, image_width, image_height, 0, GL_RED, GL_UNSIGNED_BYTE,
175  (GLvoid*)((size_t)(image_buffer) + (image_width * image_height)));
176  checkGLError("Updating raw texture with right image");
177 
178  glActiveTexture(GL_TEXTURE1);
179  glBindTexture(GL_TEXTURE_2D, distortionTextureRight);
180  glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, 64, 64, 0, GL_RG, GL_FLOAT, distortion_buffer_right);
181  checkGLError("Updating distortion texture with right distortion map");
182 
183  glTranslatef(-2.01f, 0.0, 0.0);
184  glBegin(GL_QUADS);
185  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
186  glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
187  glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
188  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
189  glEnd();
190 
191  glPopMatrix();
192 
193  imageReady = false;
194  }
195  glFlush();
196  glPopMatrix();
197  glutSwapBuffers();
198 }
199 
200 void reshape(int w, int h)
201 {
202  glViewport(0, 0, (GLsizei) w, (GLsizei) h);
203 }
204 
205 void keyboard(unsigned char key, int x, int y)
206 {
207  switch((char)key) {
208  case 'q':
209  case 27: // ESC
210  glutDestroyWindow(window);
211  if(imageRequested)
212  LeapCancelImageFrameRequest(*connection, *image_token);
213  if(image_buffer) free(image_buffer);
214  CloseConnection();
215  exit(0);
216  default:
217  break;
218  }
219 }
220 
221 void idle(void){
222  if(imageReady)
223  glutPostRedisplay();
224 }
225 
226 int main(int argc, char *argv[])
227 {
228  ConnectionCallbacks.on_frame = OnFrame;
229  ConnectionCallbacks.on_image_complete = OnImages;
230  ConnectionCallbacks.on_image_request_error = OnImageError;
231 
232  connection = OpenConnection();
233  while(!IsConnected){
234  millisleep(250);
235  }
236 
237  glutInit(&argc, argv);
238  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
239  glutInitWindowSize(windowWidth, windowHeight);
240  window = glutCreateWindow("LeapC Distortion Shader Example");
241 
242 #if defined(GLEW_VERSION)
243  GLenum err = glewInit();
244  if (err != GLEW_OK) {
245  /* Problem: glewInit failed, something is seriously wrong. */
246  fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
247  return 1;
248  }
249 #endif
250 
251  // GLUT callbacks
252  glutIdleFunc(idle);
253  glutReshapeFunc(reshape);
254  glutKeyboardFunc(keyboard);
255  glutDisplayFunc(display);
256 
257  // init GL
258  glClearColor(0.0, 0.0, 0.0, 0.0);
259  glColor3f(1.0, 1.0, 1.0);
260 
261  // init shader and textures
262 
263  //Create the shader program
264  program = createProgram(GLSL_VERT, GLSL_FRAG);
265  glUseProgram(program);
266  GLuint rawSampler = glGetUniformLocation(program, "rawTexture");
267  GLuint distortionSampler = glGetUniformLocation(program, "distortionTexture");
268  glUniform1i(rawSampler, 0);
269  glUniform1i(distortionSampler, 1);
270 
271  //Create textures
272  rawTextureLeft = createTextureReference();
273  distortionTextureLeft = createTextureReference();
274  rawTextureRight = createTextureReference();
275  distortionTextureRight = createTextureReference();
276 
277  // Start GLUT loop
278  glutMainLoop();
279 
280  CloseConnection();
281  free(distortion_buffer_left);
282  free(distortion_buffer_right);
283  return 0;
284 }
285 //End-of-Sample

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.