Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

Paths

Paths

Paths simply store the current and previous frame for a specific Contact.

See FWHID_Path.h for reference

Paths Example Code

The example code is a finger painting program that draws on the screen using the previous and current contact from the Path data. The color of the line being drawn is determined by FWHID_Path::final_finger_id.

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


Generated on Fri Dec 10 10:08:12 2004 for FingerWorks Hand Tracking SDK by doxygen 1.3.8