3D Drawing Example

The 3D Drawing Example illustrates how to access the tracking data in a more “complete” application – in this example a simple GLUT-based window. Because you cannot send drawing commands from a secondary thread, this example uses callbacks to set state variables that the GLUT thread then checks during its idle loop. If a new tracking frame is available, the idle() function calls a GLUT function to signal that a redraw is needed. The example then polls the ExampleConnection object to get the latest frame of data.

The hands are drawn using GLUT primitives at the position of the elbow, the wrist, the palm point, and the end of each bone in the fingers.

  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
 17 int32_t lastDrawnFrameId = 0;
 18 volatile int32_t newestFrameId = 0;
 19 int window; // GLUT window handle
 20
 21 /* Notifies us that a new frame is available. */
 22 void OnFrame(const LEAP_TRACKING_EVENT *frame){
 23   newestFrameId = (int32_t)frame->tracking_frame_id;
 24 }
 25
 26 void display(void)
 27 {
 28   glMatrixMode(GL_MODELVIEW);
 29   glPushMatrix();
 30   glTranslatef(0, -300, -500); //"Camera" viewpoint
 31   glClear(GL_COLOR_BUFFER_BIT);
 32   LEAP_TRACKING_EVENT *frame = GetFrame();
 33   for(uint32_t h = 0; h < frame->nHands; h++){
 34     // Draw the hand
 35     LEAP_HAND *hand = &frame->pHands[h];
 36     //elbow
 37     glPushMatrix();
 38     glTranslatef(hand->arm.prev_joint.x, hand->arm.prev_joint.y, hand->arm.prev_joint.z);
 39     glutWireOctahedron();
 40     glPopMatrix();
 41
 42     //wrist
 43     glPushMatrix();
 44     glTranslatef(hand->arm.next_joint.x, hand->arm.next_joint.y, hand->arm.next_joint.z);
 45     glutWireOctahedron();
 46     glPopMatrix();
 47
 48     //palm position
 49     glPushMatrix();
 50     glTranslatef(hand->palm.position.x, hand->palm.position.y, hand->palm.position.z);
 51     glutWireOctahedron();
 52     glPopMatrix();
 53
 54     //Distal ends of bones for each digit
 55     for(int f = 0; f < 5; f++){
 56       LEAP_DIGIT finger = hand->digits[f];
 57       for(int b = 0; b < 4; b++){
 58         LEAP_BONE bone = finger.bones[b];
 59         glPushMatrix();
 60         glTranslatef(bone.next_joint.x, bone.next_joint.y, bone.next_joint.z);
 61         glutWireOctahedron();
 62         glPopMatrix();
 63       }
 64     }
 65     // End of draw hand
 66   }
 67   glFlush();
 68   glPopMatrix();
 69 }
 70
 71 void reshape(int w, int h)
 72 {
 73   glViewport(0, 0, (GLsizei) w, (GLsizei) h);
 74   glMatrixMode(GL_PROJECTION);
 75   glLoadIdentity();
 76   gluPerspective(60, 640/240, 1.0, 1000);
 77 }
 78
 79 void keyboard(unsigned char key, int x, int y)
 80 {
 81   switch((char)key) {
 82   case 'q':
 83   case 27:  // ESC
 84     glutDestroyWindow(window);
 85     CloseConnection();
 86     exit(0);
 87   default:
 88     break;
 89   }
 90 }
 91
 92 void idle(void){
 93   if(lastDrawnFrameId < newestFrameId){
 94     lastDrawnFrameId = newestFrameId;
 95     glutPostRedisplay();
 96   }
 97 }
 98
 99 int main(int argc, char *argv[])
100 {
101   ConnectionCallbacks.on_frame = OnFrame;
102   OpenConnection();
103
104   while(!IsConnected){
105     millisleep(250);
106   }
107
108   glutInit(&argc, argv);
109   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
110   glutInitWindowSize(640, 240);
111   window = glutCreateWindow("LeapC Example");
112
113   // GLUT callbacks
114   glutIdleFunc(idle);
115   glutReshapeFunc(reshape);
116   glutKeyboardFunc(keyboard);
117   glutDisplayFunc(display);
118
119   // init GL
120   glClearColor(1.0, 1.0, 1.0, 0.0);
121   glColor3f(0.0, 0.0, 0.0);
122   glLineWidth(3.0);
123
124   // Start GLUT loop
125   glutMainLoop();
126
127   CloseConnection();
128   return 0;
129 }
130 //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.

Image Examples

The Ultraleap Tracking Service creates the tracking data provided in a LEAP_TRACKING_EVENT() struct by analyzing a set of stereo images taken by the Ultraleap Hand Tracking Camera. The image set used to create a frame of data can be obtained by calling LeapRequestImages(). LeapC writes the set of stereo images to a buffer that you supply; stacked with the left image on top of the right image. After you call LeapRequestImages(), LeapC dispatches a LEAP_IMAGE_COMLETE_EVENT message through the usual message pump when the image buffer has been completely written. The message struct also contains the image properties.


Back to top