See FWHID_Contact.h for struture and function references pertaining to Contacts.
To build the code you need to include the additional following libraries when linking: opengl32.lib and glu32.lib (see also Setting up the Compile and Linking Environment). The following code can be found at sdk_path\FWHID_HandTracking\examples\contacts\contact_example.cpp.
For a Mac example see sdk path\FWHID_HandTracking\examples\ContactPaths.xcode
/********************************************************************** * A Program that visually illustrates the Contact information from * the FW Hand Tracking SDK * * To compile this code you must include the following libraries: * fwtrack.lib, setupapi.lib, hid.lib, opengl32.lib, glu32.lib * * Press 'q' to quit * * File: contact_example.cpp * Author: James Orr * Created: Mon. Aug. 23, 2004 * Last Modified: Tues. Aug. 31, 2004 * ***********************************************************************/ /* * Copyright (c) 2004 FingerWorks, Inc. All rights reserved. * This FingerWorks software is supplied to you by FingerWorks, Inc. ("FingerWorks") in consideration of your agreement to the following terms, and your use, installation, or modification of this FingerWorks software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install or modify this FingerWorks software. In consideration of your agreement to abide by the following terms, and subject to these terms, FingerWorks grants you a personal, non-exclusive license, under FingerWorks's copyrights in this original FingerWorks software (the "FingerWorks Software"), to use, reproduce, and modify the FingerWorks Software for personal, academic, research, or artistic purposes. You may NOT distribute this FingerWorks Software, with or without modifications, in either source or binary form. Neither the name, trademarks, service marks or logos of FingerWorks, Inc. may be used to endorse or promote products derived from the FingerWorks Software without specific prior written permission from FingerWorks. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by FingerWorks herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the FingerWorks Software may be incorporated. Disclaimer: The FingerWorks Software is provided by FingerWorks on an "AS IS" basis. FINGERWORKS MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE FINGERWORKS SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL FINGERWORKS BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE FINGERWORKS SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF FINGERWORKS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <Windows.h> #include "FWHID_MultiTouchDevice.h" #include <gl/gl.h> #include <gl/glu.h> //Constants #define kSCREEN_WIDTH 1024 #define kSCREEN_HEIGHT 768 #define kREFRESH_RATE 75 #define kMAX_DEVICES 3 #define kCIRCLE_SIZE .05 //Globals HGLRC gHrc = NULL; //Window Rendering Context HDC gHdc; // A global handle to the device context bool gQuit = false; float gFingerColors[kFWHID_MAX_CONTACTS_PER_HAND][3]; //Globals specific to the SDK FWMultiTouchDevicePtr gDevices[kMAX_DEVICES]; int gTotalDevices=0; FWHID_ContactFrame gDeviceFrames[kMAX_DEVICES]; //Prototypes void glInit(void); void MyPaint(void); void SetupPixelFormat(HDC hdc); void initializeColorLUT(); void drawContact(FWHID_ContactPtr pContact, FWSurfaceRectanglePtr surface_dim); //Callback prototypes void DeviceCreationCallback(FWMultiTouchDevicePtr fwdevice, void *targetData); void DeviceDisposalCallback(FWMultiTouchDevicePtr fwdevice, void *targetData); void DeviceFrameCompleteCallback(FWMultiTouchDevicePtr fwdevice, void *targetData); //The Device Creation Callback is called for every FW device found in the system void DeviceCreationCallback(FWMultiTouchDevicePtr fwdevice, void *targetData){ if(gTotalDevices < kMAX_DEVICES){ FWHID_enableStreams(fwdevice,kFW_ContactPathStream); gDevices[gTotalDevices] = fwdevice; FWHID_setContactFrameCallback(gDevices[gTotalDevices],DeviceFrameCompleteCallback); gTotalDevices++; } } //This is called after every frame void DeviceFrameCompleteCallback(FWMultiTouchDevicePtr fwdevice, void *targetData){ //Find which MultiTouch device this is int i=0; while(fwdevice != gDevices[i] && i < gTotalDevices) i++; if(i == gTotalDevices) return; //Device not found in tracking list FWHID_getContactFrame(gDevices[i],&gDeviceFrames[i]); } //Called everytime a FW device is removed. //Note: If a device is plugged in all devices are removed and then rediscovered void DeviceDisposalCallback(FWMultiTouchDevicePtr fwdevice, void *targetData){ int i=0; while(fwdevice != gDevices[i] && i < gTotalDevices) i++; if(i == gTotalDevices) return; //device removed was not found in devices I am keeping track of FWHID_disableStreams(fwdevice,kFW_ContactPathStream); if(i+1 < kMAX_DEVICES) memmove(&gDevices[i],&gDevices[i+1],sizeof(FWMultiTouchDevicePtr)*(gTotalDevices-i+1)); gTotalDevices--; } //This function draws the contacts onto the screen void MyPaint(void){ int i,k; glClear(GL_COLOR_BUFFER_BIT); //Enumerates throught the device list and then enumerates through the valid contacts for(i=0;i<gTotalDevices;i++){ FWSurfaceRectangle dim = FWHID_getSurfaceDimensions(gDevices[i]); for(k=0;k < gDeviceFrames[i].contact_count;k++){ if(gDeviceFrames[i].contacts[k].identity_active) drawContact(&gDeviceFrames[i].contacts[k],&dim); } } glFlush(); SwapBuffers(gHdc); } // Window procedure - the message handler LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc = NULL; PAINTSTRUCT ps; switch (msg) { case WM_CREATE: // Get a handle to the device context hdc = BeginPaint(hwnd, &ps); gHdc = hdc; // Setup pixel format for the device context SetupPixelFormat(hdc); // Create a rendering context associated to the device context gHrc = wglCreateContext(hdc); // Make the rendering context current wglMakeCurrent(hdc, gHrc); //return 0; break; case WM_CLOSE: // De-select the rendering context wglMakeCurrent(hdc, NULL); // Release the rendering context wglDeleteContext(gHrc); // Release the device context EndPaint(hwnd, &ps); break; case WM_TIMER: MyPaint(); break; case WM_SETFOCUS: SetTimer(hwnd, // handle to main window 0, // timer identifier 33, // 33-msecond interval (TIMERPROC) NULL); // no timer callback break; case WM_KILLFOCUS: KillTimer(hwnd,0); break; case WM_CHAR: switch (wParam) { case 'q': case 'Q': gQuit =true; break; } break; } //This is required for the FW Hand Tracking SDK if(FWHID_WndProc(hwnd, msg, wParam,lParam)) return TRUE; return DefWindowProc(hwnd, msg, wParam, lParam); } // WinMain function - the entry point int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int iCmdShow) { HWND hwnd; MSG msg; WNDCLASS wndclass; int i; // Specify a window class wndclass.style = 0; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "VisualContact"; // Register the window class RegisterClass(&wndclass); DEVMODE screenSettings; // Specify values for relevant data fields screenSettings.dmPelsWidth = kSCREEN_WIDTH; screenSettings.dmPelsHeight = kSCREEN_HEIGHT; screenSettings.dmBitsPerPel = 32; screenSettings.dmDisplayFrequency = kREFRESH_RATE; // Indicate which fields are manually initialized screenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; // Apply changes if(ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){ screenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN); } ShowCursor(false);//Hide the Cursor // Create a window based on the window class hwnd = CreateWindow("VisualContact", "FW VisualContact", WS_POPUP, 0, 0, kSCREEN_WIDTH, kSCREEN_HEIGHT, NULL, NULL, hInstance, NULL); // Display the window on the screen ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); glInit(); initializeColorLUT(); //Initialize FingerWorks Handtracking SDK FWHID_setDeviceCreationCallback(DeviceCreationCallback); FWHID_setDeviceDisposalCallback(DeviceDisposalCallback); FWHID_registerMultiTouchDevices(hwnd); while (!gQuit) { GetMessage (&msg, NULL, 0, 0); TranslateMessage (&msg); DispatchMessage (&msg); } FWHID_releaseMultiTouchDevices(); return (int)msg.wParam; } void glInit(){ glClearColor(1, 1, 1, 0.0); // White Background glEnable(GL_NORMALIZE); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void SetupPixelFormat(HDC hdc) { static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, //PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; int index = ChoosePixelFormat(hdc, &pfd); SetPixelFormat(hdc, index, &pfd); } //Initializes the Color Look Up Table void initializeColorLUT(){ int i; for(i=0; i < kFWHID_MAX_CONTACTS_PER_HAND; i++){ gFingerColors[i][0] = ((float)i+1.0)/((float)kFWHID_MAX_CONTACTS_PER_HAND+1.0); gFingerColors[i][1] = gFingerColors[i][0]; gFingerColors[i][2] = 1; } //red gFingerColors[kFWHIDthumb][0] = 1; gFingerColors[kFWHIDthumb][2] = 0; //green gFingerColors[kFWHIDindex][1] = 1; gFingerColors[kFWHIDindex][2] = 0; //yellow gFingerColors[kFWHIDring][1] = 1; gFingerColors[kFWHIDring][0] = 1; gFingerColors[kFWHIDring][2] = 0; //pink gFingerColors[kFWHIDmiddle][0] = 1; //cyan gFingerColors[kFWHIDpinky][1] = 1; } //Draws a contact on the screen using the xpos,ypos, eccentricity, orientation, and proximity data void drawContact(FWHID_ContactPtr pContact,FWSurfaceRectanglePtr surface_dim){ static bool init = true; static GLUquadricObj *quad; if (init) { init = false; quad = gluNewQuadric(); } glColor3fv(gFingerColors[pContact->finger_id]); glPushMatrix(); glLoadIdentity(); glTranslatef((float)(pContact->xpos - surface_dim->left_edge) / (float)surface_dim->width_cm*2.0-1.0,(float)(pContact->ypos - surface_dim->bottom_edge) / (float)surface_dim->height_cm*2.0-1.0,0); glRotatef(pContact->orientation-90,0,0,1); //Subtract 90 b/c the nominal value is 90 glScalef(pContact->proximity,pContact->eccentricity*pContact->proximity,1); gluDisk(quad,0,kCIRCLE_SIZE,100,1); glPopMatrix(); }
Previous: Device and Stream Setup Next: Paths Up to FingerWorks Hand Tracking SDK