See FWHID_Path.h for reference
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\paths\path_example.cpp
For a Mac example see sdk path\FWHID_HandTracking\examples\ContactPaths.xcode
/********************************************************************** * Fingerpainting Program using the Paths from the FW Hand Tracking SDK * * To compile the code you must include the following libraries: * fwtrack.lib, setupapi.lib, hid.lib, opengl32.lib, glu32.lib * * Press 'q' to quit and 'c' to clear the screen * * File: path_example.cpp * Author: James Orr * Created: Fri. Aug. 27, 2004 * Last Modified: Mon. Aug. 30, 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_Path gDeviceFrames[kMAX_DEVICES][kFWHID_MAX_CONTACT_PATHS]; //General Prototypes void glInit(void); void MyPaint(void); void SetupPixelFormat(HDC hdc); void initializeColorLUT(); void drawLine(float x0, float y0, float x1, float y1, GLfloat w, GLfloat *clr); //Callback prototypes void DeviceCreationCallback(FWMultiTouchDevicePtr fwdevice, void *targetData); void DeviceDisposalCallback(FWMultiTouchDevicePtr fwdevice, void *targetData); void DevicePathFrameCompleteCallback(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; //Set the Path Frame Callback for the device FWHID_setPathFrameCallback(gDevices[gTotalDevices],DevicePathFrameCompleteCallback); gTotalDevices++; } } //This is called after every frame void DevicePathFrameCompleteCallback(FWMultiTouchDevicePtr fwdevice, void *targetData){ //Find which MultiTouch device this is int i=0,k=0; FWHID_Path path; while(fwdevice != gDevices[i] && i < gTotalDevices) i++; if(i == gTotalDevices) return; //Device not found in tracking list //Found which device this frame belongs to //Get the surface dimensions of the device so that I can scale the coordinates of contacts FWSurfaceRectangle surface_dim = FWHID_getSurfaceDimensions(gDevices[i]); //Enumerate through the possible paths of the device for(k=0;k < kFWHID_MAX_CONTACT_PATHS;k++){ //get the path data path = FWHID_getPath(gDevices[i],k); //check to see if the path is active if(FWHID_isPathIdentityCurrent(&path)) //Since it is active - draw a line from the previous contact to the //current contact using the finger_id as the index into the color LUT drawLine((float)(path.previous_contact.xpos - surface_dim.left_edge) / (float)surface_dim.width_cm*2.0-1.0, (float)(path.previous_contact.ypos - surface_dim.bottom_edge) / (float)surface_dim.height_cm*2.0-1.0, (float)(path.current_contact.xpos - surface_dim.left_edge) / (float)surface_dim.width_cm*2.0-1.0, (float)(path.current_contact.ypos - surface_dim.bottom_edge) / (float)surface_dim.height_cm*2.0-1.0, path.current_contact.proximity*2, &gFingerColors[path.final_finger_id][0] ); } } //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){ //Find which MultiTouch device is being removed and remove it from the tracking list 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 the device is not the last one in the list remove it and shift the rest down if(i+1 < kMAX_DEVICES) memmove(&gDevices[i],&gDevices[i+1],sizeof(FWMultiTouchDevicePtr)*(gTotalDevices-i+1)); //decrement the number of devices in the list gTotalDevices--; } //This function just swaps the buffers void MyPaint(void){ wglMakeCurrent(gHdc, gHrc); glFlush(); SwapBuffers(gHdc); wglMakeCurrent(gHdc, NULL); } //This function clears budfers and the screen void ClearBuffers(){ wglMakeCurrent(gHdc, gHrc); glClear(GL_COLOR_BUFFER_BIT); glFlush(); SwapBuffers(gHdc); glClear(GL_COLOR_BUFFER_BIT); wglMakeCurrent(gHdc, NULL); } // 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); 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: //Swap the buffers MyPaint(); break; case WM_SETFOCUS: //Start the timer when the app gets the focus SetTimer(hwnd, // handle to main window 0, // timer identifier 33, // 33-msecond interval (TIMERPROC) NULL); // no timer callback break; case WM_KILLFOCUS: //Stop the timer when the app does not have the focus KillTimer(hwnd,0); break; case WM_CHAR: //This handles keys //'q' - to quit //'c' - to clear the screen switch (wParam) { case 'q': case 'Q': gQuit =true; break; case 'c': case 'C': ClearBuffers(); break; } break; } //This is required for the FW Handtracking 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; // 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 = "FingerPaintClass"; // Register the window class RegisterClass(&wndclass); //The following code makes window go full screen 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 full screen changes if(ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){ screenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN); } //Hide the Cursor ShowCursor(false); // Create a window based on the window class hwnd = CreateWindow("FingerPaintClass", "FW Fingerpaint", WS_POPUP, 0, 0, kSCREEN_WIDTH, kSCREEN_HEIGHT, NULL, NULL, hInstance, NULL); // Display the window on the screen ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); //Initialze OpenGL glInit(); //clear screen buffers ClearBuffers(); //Fill out the Color LUT initializeColorLUT(); //*****Initialize FingerWorks Handtracking SDK******** //Set the callbacks for device creation and disposal FWHID_setDeviceCreationCallback(DeviceCreationCallback); FWHID_setDeviceDisposalCallback(DeviceDisposalCallback); //Now register this app to receive device notifications FWHID_registerMultiTouchDevices(hwnd); //Main windows message loop while (!gQuit) { GetMessage (&msg, NULL, 0, 0); TranslateMessage (&msg); DispatchMessage (&msg); } //Release the Devices - does internal cleanup in the SDK FWHID_releaseMultiTouchDevices(); return (int)msg.wParam; } //OpenGL initialization code 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); glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); } void SetupPixelFormat(HDC hdc) { static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, 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; } void drawLine(float x0, float y0, float x1, float y1, GLfloat w, GLfloat *clr){ //Set the current Rendering context wglMakeCurrent(gHdc, gHrc); //Set the drawing color glColor3fv(clr); //set the width of the 'brush' glLineWidth(w); glPointSize(w); //draw the lone glBegin(GL_LINES); glVertex2f(x0,y0); glVertex2f(x1,y1); glEnd(); //Draw the end caps glBegin(GL_POINTS); glVertex2f(x0,y0); glVertex2f(x1,y1); glEnd(); //release the context - the context stuff is only neccessary //because multiple threads do drawing - the better soln is to //have multiple contexts but that involves more code and this //is not a lesson in OpenGL wglMakeCurrent(gHdc, NULL); }
Previous: Contacts Next: Hand Motion Up to FingerWorks Hand Tracking SDK