LeapUtilGL.cpp
Go to the documentation of this file.
1 /******************************************************************************\
2 * Copyright (C) Leap Motion, Inc. 2011-2013. *
3 * Leap Motion proprietary and confidential. Not for distribution. *
4 * Use subject to the terms of the Leap Motion SDK Agreement available at *
5 * https://developer.leapmotion.com/sdk_agreement, or another agreement between *
6 * Leap Motion and you, your company or other organization. *
7 \******************************************************************************/
8 
9 #include "LeapUtilGL.h"
10 
11 #if !defined(__GLU_H__)
12  #if defined(WIN32)
13  #include <windows.h>
14  #include <GL/glu.h>
15  #elif defined(__MACH__)
16  #include <OpenGL/glu.h>
17  #else
18  #include <GL/glu.h>
19  #endif
20 #endif // !__GL_H__
21 
22 namespace LeapUtilGL {
23 
24 using namespace Leap;
25 using namespace LeapUtil;
26 
27 // create/destroy single global quadric instance for drawing curved surfaces with GLU
28 class Quadric
29 {
30 public:
31  Quadric() {}
32 
34  {
35  if ( s_pQuadric )
36  {
37  gluDeleteQuadric( s_pQuadric );
38  s_pQuadric = NULL;
39  }
40  }
41 
42  operator GLUquadric* ()
43  {
44  if ( !s_pQuadric )
45  {
46  s_pQuadric = gluNewQuadric();
47  }
48 
49  return s_pQuadric;
50  }
51 
52  static GLUquadric* s_pQuadric;
53 };
54 
55 GLUquadric* Quadric::s_pQuadric = NULL;
56 
58 
59 void drawGrid( ePlane plane, unsigned int horizSubdivs, unsigned int vertSubdivs )
60 {
61  const float fHalfGridSize = 0.5f;
62  const float fHGridStep = (fHalfGridSize + fHalfGridSize)/static_cast<float>(Max(horizSubdivs, 1u));
63  const float fVGridStep = (fHalfGridSize + fHalfGridSize)/static_cast<float>(Max(vertSubdivs, 1u));
64  const float fHEndStep = fHalfGridSize + fHGridStep;
65  const float fVEndStep = fHalfGridSize + fVGridStep;
66 
67  GLAttribScope lightingScope( GL_LIGHTING_BIT );
68 
69  glDisable(GL_LIGHTING);
70 
71  glBegin( GL_LINES );
72 
73  switch ( plane )
74  {
75  case kPlane_XY:
76  for ( float x = -fHalfGridSize; x < fHEndStep; x += fHGridStep )
77  {
78  glVertex3f( x, -fHalfGridSize, 0 );
79  glVertex3f( x, fHalfGridSize, 0 );
80  }
81 
82  for ( float y = -fHalfGridSize; y < fVEndStep; y += fVGridStep )
83  {
84  glVertex3f( -fHalfGridSize, y, 0 );
85  glVertex3f( fHalfGridSize, y, 0 );
86  }
87  break;
88 
89  case kPlane_YZ:
90  for ( float y = -fHalfGridSize; y < fHEndStep; y += fHGridStep )
91  {
92  glVertex3f( 0, y, -fHalfGridSize );
93  glVertex3f( 0, y, fHalfGridSize );
94  }
95 
96  for ( float z = -fHalfGridSize; z < fVEndStep; z += fVGridStep )
97  {
98  glVertex3f( 0, -fHalfGridSize, z );
99  glVertex3f( 0, fHalfGridSize, z );
100  }
101  break;
102 
103  case kPlane_ZX:
104  for ( float z = -fHalfGridSize; z < fHEndStep; z += fHGridStep )
105  {
106  glVertex3f( -fHalfGridSize, 0, z );
107  glVertex3f( fHalfGridSize, 0, z );
108  }
109 
110  for ( float x = -fHalfGridSize; x < fVEndStep; x += fVGridStep )
111  {
112  glVertex3f( x, 0, -fHalfGridSize );
113  glVertex3f( x, 0, fHalfGridSize );
114  }
115  break;
116  }
117 
118  glEnd();
119 }
120 
121 void drawSphere( eStyle style )
122 {
123  switch ( style )
124  {
125  case kStyle_Outline:
126  gluQuadricDrawStyle(s_quadric, GLU_SILHOUETTE);
127  glPushAttrib( GL_LIGHTING_BIT );
128  glDisable(GL_LIGHTING);
129  break;
130 
131  case kStyle_Solid:
132  gluQuadricDrawStyle(s_quadric, GLU_FILL);
133  break;
134  }
135 
136  gluSphere( s_quadric, 1.0, 32, 32 );
137 
138  switch ( style )
139  {
140  case kStyle_Outline:
141  glPopAttrib();
142  break;
143 
144  case kStyle_Solid:
145  break;
146  }
147 }
148 
149 void drawQuad( eStyle style, ePlane plane )
150 {
151  switch ( style )
152  {
153  case kStyle_Outline:
154  glPushAttrib( GL_LIGHTING_BIT );
155  glDisable(GL_LIGHTING);
156  break;
157 
158  case kStyle_Solid:
159  break;
160  }
161 
162  switch ( plane )
163  {
164  case kPlane_XY:
165  break;
166  case kPlane_YZ:
167  glPushMatrix();
168  glRotatef( 90.0f, 0, 1, 0 );
169  break;
170  case kPlane_ZX:
171  glPushMatrix();
172  glRotatef( -90.0f, 1, 0, 0 );
173  break;
174  }
175 
176  const float kfHalfSize = 0.5f;
177 
178  glBegin( style == kStyle_Outline ? GL_LINE_LOOP : GL_TRIANGLES );
179  glNormal3f( 0, 0, 1 );
180  glTexCoord2f( 0, 0 );
181  glVertex3f( -kfHalfSize, -kfHalfSize, 0 );
182  glTexCoord2f( 1, 0 );
183  glVertex3f( kfHalfSize, -kfHalfSize, 0 );
184  glTexCoord2f( 1, 1 );
185  glVertex3f( kfHalfSize, kfHalfSize, 0 );
186  glEnd();
187 
188  glBegin( style == kStyle_Outline ? GL_LINE_LOOP : GL_TRIANGLES );
189  glTexCoord2f( 1, 1 );
190  glVertex3f( kfHalfSize, kfHalfSize, 0 );
191  glTexCoord2f( 0, 1 );
192  glVertex3f( -kfHalfSize, kfHalfSize, 0 );
193  glTexCoord2f( 0, 0 );
194  glVertex3f( -kfHalfSize, -kfHalfSize, 0 );
195  glEnd();
196 
197  glBegin( style == kStyle_Outline ? GL_LINE_LOOP : GL_TRIANGLES );
198  glNormal3f( 0, 0, -1 );
199  glTexCoord2f( 0, 0 );
200  glVertex3f( kfHalfSize, -kfHalfSize, 0 );
201  glTexCoord2f( 1, 0 );
202  glVertex3f( -kfHalfSize, -kfHalfSize, 0 );
203  glTexCoord2f( 1, 1 );
204  glVertex3f( -kfHalfSize, kfHalfSize, 0 );
205  glEnd();
206 
207  glBegin( style == kStyle_Outline ? GL_LINE_LOOP : GL_TRIANGLES );
208  glTexCoord2f( 1, 1 );
209  glVertex3f( -kfHalfSize, kfHalfSize, 0 );
210  glTexCoord2f( 0, 1 );
211  glVertex3f( kfHalfSize, kfHalfSize, 0 );
212  glTexCoord2f( 0, 0 );
213  glVertex3f( kfHalfSize, -kfHalfSize, 0 );
214  glEnd();
215 
216  switch ( plane )
217  {
218  case kPlane_XY:
219  break;
220  case kPlane_YZ:
221  case kPlane_ZX:
222  glPopMatrix();
223  break;
224  }
225 
226  switch ( style )
227  {
228  case kStyle_Outline:
229  glPopAttrib();
230  break;
231  case kStyle_Solid:
232  break;
233  }
234 }
235 
236 
237 void drawBox( eStyle style )
238 {
239  static const float s_afCorners[8][3] = {
240  // near face - ccw facing origin from face.
241  {-0.5f, -0.5f, 0.5f},
242  { 0.5f, -0.5f, 0.5f},
243  { 0.5f, 0.5f, 0.5f},
244  {-0.5f, 0.5f, 0.5f},
245 
246  // far face - ccw facing origin from face
247  { 0.5f, -0.5f, -0.5f},
248  {-0.5f, -0.5f, -0.5f},
249  {-0.5f, 0.5f, -0.5f},
250  { 0.5f, 0.5f, -0.5f},
251 
252  };
253 
254  switch ( style )
255  {
256  case kStyle_Outline:
257  glPushAttrib( GL_LIGHTING_BIT );
258  glDisable(GL_LIGHTING);
259  break;
260 
261  case kStyle_Solid:
262  break;
263  }
264 
265  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
266 
267  // near
268  glNormal3f( 0, 0, 1 );
269  glVertex3fv( s_afCorners[0] );
270  glVertex3fv( s_afCorners[1] );
271  glVertex3fv( s_afCorners[2] );
272 
273  glEnd();
274  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
275 
276  glVertex3fv( s_afCorners[2] );
277  glVertex3fv( s_afCorners[3] );
278  glVertex3fv( s_afCorners[0] );
279 
280  glEnd();
281  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
282 
283  // far
284  glNormal3f( 0, 0, -1 );
285  glVertex3fv( s_afCorners[4] );
286  glVertex3fv( s_afCorners[5] );
287  glVertex3fv( s_afCorners[6] );
288 
289  glEnd();
290  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
291 
292  glVertex3fv( s_afCorners[6] );
293  glVertex3fv( s_afCorners[7] );
294  glVertex3fv( s_afCorners[4] );
295 
296  glEnd();
297 
298  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
299 
300  // right
301  glNormal3f( 1, 0, 0 );
302  glVertex3fv( s_afCorners[1] );
303  glVertex3fv( s_afCorners[4] );
304  glVertex3fv( s_afCorners[7] );
305 
306  glEnd();
307  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
308 
309  glVertex3fv( s_afCorners[7] );
310  glVertex3fv( s_afCorners[2] );
311  glVertex3fv( s_afCorners[1] );
312 
313  glEnd();
314  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
315 
316  // left
317  glNormal3f( -1, 0, 0 );
318  glVertex3fv( s_afCorners[5] );
319  glVertex3fv( s_afCorners[0] );
320  glVertex3fv( s_afCorners[3] );
321 
322  glEnd();
323  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
324 
325  glVertex3fv( s_afCorners[3] );
326  glVertex3fv( s_afCorners[6] );
327  glVertex3fv( s_afCorners[5] );
328 
329  glEnd();
330 
331  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
332 
333  // bottom
334  glNormal3f( 0, -1, 0 );
335  glVertex3fv( s_afCorners[0] );
336  glVertex3fv( s_afCorners[5] );
337  glVertex3fv( s_afCorners[4] );
338 
339  glEnd();
340  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
341 
342  glVertex3fv( s_afCorners[4] );
343  glVertex3fv( s_afCorners[1] );
344  glVertex3fv( s_afCorners[0] );
345 
346  glEnd();
347  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
348 
349  // top
350  glNormal3f( 0, 1, 0 );
351  glVertex3fv( s_afCorners[3] );
352  glVertex3fv( s_afCorners[2] );
353  glVertex3fv( s_afCorners[7] );
354 
355  glEnd();
356  glBegin( style == kStyle_Solid ? GL_TRIANGLES : GL_LINE_LOOP );
357 
358  glVertex3fv( s_afCorners[7] );
359  glVertex3fv( s_afCorners[6] );
360  glVertex3fv( s_afCorners[3] );
361 
362  glEnd();
363 
364  switch ( style )
365  {
366  case kStyle_Outline:
367  glPopAttrib();
368  break;
369 
370  case kStyle_Solid:
371  break;
372  }
373 }
374 
375 void drawCylinder( eStyle style, eAxis axis )
376 {
377  GLMatrixScope matrixScope;
378 
379  switch ( style )
380  {
381  case kStyle_Outline:
382  gluQuadricDrawStyle(s_quadric, GLU_SILHOUETTE);
383  glPushAttrib( GL_LIGHTING_BIT );
384  glDisable(GL_LIGHTING);
385  break;
386 
387  case kStyle_Solid:
388  gluQuadricDrawStyle(s_quadric, GLU_FILL);
389  break;
390  }
391 
392  switch ( axis )
393  {
394  case kAxis_X:
395  glRotatef( 90.0f, 0, 1, 0 );
396  break;
397  case kAxis_Y:
398  glRotatef( 90.0f, 1, 0, 0 );
399  break;
400  case kAxis_Z:
401  break;
402  }
403 
404  // draw end caps
405  if ( style != kStyle_Outline )
406  {
407  GLMatrixScope matrixScope;
408 
409  glTranslatef( 0, 0, 0.5f );
410  drawDisk( style, kPlane_XY );
411 
412  glTranslatef( 0, 0, -1.0f );
413  drawDisk( style, kPlane_XY );
414  }
415 
416  glTranslatef( 0, 0, -0.5f );
417 
418  gluCylinder( s_quadric, 0.5f, 0.5f, 1.0f, 32, 32 );
419 
420  switch ( style )
421  {
422  case kStyle_Outline:
423  glPopAttrib();
424  break;
425 
426  case kStyle_Solid:
427  break;
428  }
429 }
430 
431 void drawDisk( eStyle style, ePlane plane )
432 {
433  GLMatrixScope matrixScope;
434 
435  switch ( style )
436  {
437  case kStyle_Outline:
438  gluQuadricDrawStyle(s_quadric, GLU_SILHOUETTE);
439  glPushAttrib( GL_LIGHTING_BIT );
440  glDisable(GL_LIGHTING);
441  break;
442 
443  case kStyle_Solid:
444  gluQuadricDrawStyle(s_quadric, GLU_FILL);
445  break;
446  }
447 
448  switch ( plane )
449  {
450  case kPlane_XY:
451  break;
452  case kPlane_YZ:
453  glRotatef( 90.0f, 0, 1, 0 );
454  break;
455  case kPlane_ZX:
456  glRotatef( -90.0f, 1, 0, 0 );
457  break;
458  }
459 
460  gluDisk(s_quadric, 0, 0.5f, 32, 1);
461  glRotatef( 180.0f, 0, 1, 0 );
462  gluDisk(s_quadric, 0, 0.5f, 32, 1);
463 
464  switch ( style )
465  {
466  case kStyle_Outline:
467  glPopAttrib();
468  break;
469 
470  case kStyle_Solid:
471  break;
472  }
473 }
474 
475 void drawArrow( eAxis axis )
476 {
477  glBegin( GL_LINES );
478 
479  switch ( axis )
480  {
481  case kAxis_X:
482  glVertex3f( 0, 0, 0 );
483  glVertex3f( 1, 0, 0 );
484 
485  glVertex3f( 1, 0, 0 );
486  glVertex3f( 0.8f, 0.2f, 0 );
487 
488  glVertex3f( 1, 0, 0 );
489  glVertex3f( 0.8f, -0.2f, 0 );
490  break;
491 
492  case kAxis_Y:
493  glVertex3f( 0, 0, 0 );
494  glVertex3f( 0, 1, 0 );
495 
496  glVertex3f( 0, 1, 0 );
497  glVertex3f( 0, 0.8f, 0.2f );
498 
499  glVertex3f( 0, 1, 0 );
500  glVertex3f( 0, 0.8f, -0.2f );
501  break;
502 
503  case kAxis_Z:
504  glVertex3f( 0, 0, 0 );
505  glVertex3f( 0, 0, 1 );
506 
507  glVertex3f( 0, 0, 1 );
508  glVertex3f( 0.2f, 0, 0.8f );
509 
510  glVertex3f( 0, 0, 1 );
511  glVertex3f( -0.2f, 0, 0.8f );
512  break;
513  }
514 
515  glEnd();
516 }
517 
518  // draw unit length X, Y, Z axes in red, green and blue.
519  void drawAxes()
520  {
521  GLAttribScope attribScope(GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
522 
523  glDisable(GL_LIGHTING);
524  glDisable(GL_DEPTH_TEST);
525 
526  glColor3f(1, 0, 0);
528 
529  glColor3f(0, 1, 0);
531 
532  glColor3f(0, 0, 1);
534  }
535 
536  // additional sphere/cylinder drawing utilities
537  void drawSphere(eStyle style, const Vector& vCenter, float fRadius)
538  {
539  GLMatrixScope matrixScope;
540 
541  glTranslatef(vCenter.x, vCenter.y, vCenter.z);
542  glScalef(fRadius, fRadius, fRadius);
543 
544  drawSphere(style);
545  }
546 
547  void drawCylinder(eStyle style, const Vector& vBottom, const Vector& vTop, float fRadius)
548  {
549  GLMatrixScope matrixScope;
550 
551  Vector vCenter = (vBottom + vTop) * 0.5f;
552 
553  Vector vDir = (vTop - vBottom).normalized();
554  Vector vRotAxis = Vector::zAxis().cross(vDir);
555  float fRotAngle = Vector::zAxis().angleTo(vDir);
556  float fHeight = vTop.distanceTo(vBottom);
557 
558  glTranslatef(vCenter.x, vCenter.y, vCenter.z);
559  glRotatef(fRotAngle * RAD_TO_DEG, vRotAxis.x, vRotAxis.y, vRotAxis.z);
560  glScalef(fRadius, fRadius, fHeight);
561 
562  drawCylinder(style, kAxis_Z);
563  }
564 
565  // convenience function for drawing skeleton API hand
566  void drawSkeletonHand(const Leap::Hand& hand, const GLVector4fv& vBoneColor, const GLVector4fv& vJointColor) {
567  static const float kfJointRadiusScale = 0.75f;
568  static const float kfBoneRadiusScale = 0.5f;
569  static const float kfPalmRadiusScale = 1.15f;
570 
571  LeapUtilGL::GLAttribScope colorScope( GL_CURRENT_BIT );
572 
573  const Vector vPalm = hand.palmPosition();
574  const Vector vPalmDir = hand.direction();
575  const Vector vPalmNormal = hand.palmNormal();
576  const Vector vPalmSide = vPalmDir.cross(vPalmNormal).normalized();
577 
578  const float fThumbDist = hand.fingers()[Finger::TYPE_THUMB].bone(Bone::TYPE_METACARPAL).prevJoint().distanceTo(hand.palmPosition());
579  const Vector vWrist = vPalm - fThumbDist*(vPalmDir*0.90f + (hand.isLeft() ? -1.0f : 1.0f)*vPalmSide*0.38f);
580 
581  FingerList fingers = hand.fingers();
582 
583  float fRadius = 0.0f;
584  Vector vCurBoxBase;
585  Vector vLastBoxBase = vWrist;
586 
587  for (int i = 0, ei = fingers.count(); i < ei; i++) {
588  const Finger& finger = fingers[i];
589  fRadius = finger.width() * 0.5f;
590 
591  // draw individual fingers
592  for (int j = Bone::TYPE_METACARPAL; j <= Bone::TYPE_DISTAL; j++) {
593  const Bone& bone = finger.bone(static_cast<Bone::Type>(j));
594 
595  // don't draw metacarpal, a box around the metacarpals is draw instead.
596  if (j == Bone::TYPE_METACARPAL) {
597  // cache the top of the metacarpal for the next step in metacarpal box
598  vCurBoxBase = bone.nextJoint();
599  } else {
600  glColor4fv(vBoneColor);
601  drawCylinder(kStyle_Solid, bone.prevJoint(), bone.nextJoint(), kfBoneRadiusScale*fRadius);
602  glColor4fv(vJointColor);
603  drawSphere(kStyle_Solid, bone.nextJoint(), kfJointRadiusScale*fRadius);
604  }
605  }
606 
607  // draw segment of metacarpal box
608  glColor4fv(vBoneColor);
609  drawCylinder(kStyle_Solid, vCurBoxBase, vLastBoxBase, kfBoneRadiusScale*fRadius);
610  glColor4fv(vJointColor);
611  drawSphere(kStyle_Solid, vCurBoxBase, kfJointRadiusScale*fRadius);
612  vLastBoxBase = vCurBoxBase;
613  }
614 
615  // close the metacarpal box
616  fRadius = fingers[Finger::TYPE_THUMB].width() * 0.5f;
617  vCurBoxBase = vWrist;
618  glColor4fv(vBoneColor);
619  drawCylinder(kStyle_Solid, vCurBoxBase, vLastBoxBase, kfBoneRadiusScale*fRadius);
620  glColor4fv(vJointColor);
621  drawSphere(kStyle_Solid, vCurBoxBase, kfJointRadiusScale*fRadius);
622 
623  // draw palm position
624  glColor4fv(vJointColor);
625  drawSphere(kStyle_Solid, vPalm, kfPalmRadiusScale*fRadius);
626  }
627 
628 //GLCamera methods
629 
631 {
632  ResetGLProjection();
633  gluPerspective( GetVerticalFOVDegrees(), GetAspectRatio(), GetNearClip(), GetFarClip() );
634 }
635 
637 {
638  ResetGLView();
639  glMultMatrixf( GetView().toArray4x4() );
640 }
641 
642 } // namespace LeapUtilGL
void drawCylinder(eStyle style, eAxis axis)
Definition: LeapUtilGL.cpp:375
void drawSkeletonHand(const Leap::Hand &hand, const GLVector4fv &vBoneColor, const GLVector4fv &vJointColor)
utility for drawing a skeleton API hand as seen in diagnostic visualizer
Definition: LeapUtilGL.cpp:566
LEAP_EXPORT Vector palmNormal() const
f
void SetupGLView() const
Definition: LeapUtilGL.cpp:636
Vector cross(const Vector &other) const
Definition: LeapMath.h:360
LEAP_EXPORT Vector prevJoint() const
void drawGrid(ePlane plane, unsigned int horizSubdivs, unsigned int vertSubdivs)
grid is drawn with unlit colored lines.
Definition: LeapUtilGL.cpp:59
T Max(T lhs, T rhs)
Definition: LeapUtil.h:52
void drawSphere(eStyle style)
Definition: LeapUtilGL.cpp:121
direction
Definition: Leap.py:790
LEAP_EXPORT Vector nextJoint() const
static GLUquadric * s_pQuadric
Definition: LeapUtilGL.cpp:52
TFSIMD_FORCE_INLINE const tfScalar & y() const
void drawBox(eStyle style)
Definition: LeapUtilGL.cpp:237
static Quadric s_quadric
Definition: LeapUtilGL.cpp:57
Definition: Leap.h:48
static const Vector & zAxis()
Definition: LeapMath.h:123
TFSIMD_FORCE_INLINE Vector3 normalized() const
utility class for caching and restoring GL attributes via the glPushAttrib/glPopAttrib calls...
Definition: LeapUtilGL.h:93
void drawAxes()
Definition: LeapUtilGL.cpp:519
static const float RAD_TO_DEG
Definition: LeapMath.h:36
LEAP_EXPORT Vector palmPosition() const
LEAP_EXPORT Bone bone(Bone::Type boneIx) const
void drawDisk(eStyle style, ePlane plane)
disk is double-side
Definition: LeapUtilGL.cpp:431
TFSIMD_FORCE_INLINE const tfScalar & x() const
float angleTo(const Vector &other) const
Definition: LeapMath.h:247
void drawArrow(eAxis axis)
arrow is drawn with unlit colored lines.
Definition: LeapUtilGL.cpp:475
TFSIMD_FORCE_INLINE const tfScalar & z() const
LEAP_EXPORT bool isLeft() const
LEAP_EXPORT int count() const
float distanceTo(const Vector &other) const
Definition: LeapMath.h:223
void drawQuad(eStyle style, ePlane plane)
quad is double-sided.
Definition: LeapUtilGL.cpp:149
utility class for keeping the gl matrix stack push/pop operations paired up correctly.
Definition: LeapUtilGL.h:81
void SetupGLProjection() const
Definition: LeapUtilGL.cpp:630


leap_motion
Author(s): Florian Lier , Mirza Shah , Isaac IY Saito
autogenerated on Tue Jun 2 2020 03:58:01